@warmhub/cli 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/wh.js +248 -38
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -19358,7 +19358,7 @@ function findSystemComponent(componentId) {
19358
19358
  // ../../packages/sdk-ts/package.json
19359
19359
  var package_default = {
19360
19360
  name: "@warmhub/sdk-ts",
19361
- version: "0.43.0",
19361
+ version: "0.44.1",
19362
19362
  private: false,
19363
19363
  type: "module",
19364
19364
  homepage: "https://docs.warmhub.ai",
@@ -19852,13 +19852,15 @@ class WarmHubError extends Error {
19852
19852
  status;
19853
19853
  hint;
19854
19854
  retryAfter;
19855
- constructor(code, message, status, hint, retryAfter) {
19855
+ backendCode;
19856
+ constructor(code, message, status, hint, retryAfter, backendCode) {
19856
19857
  super(message);
19857
19858
  this.name = "WarmHubError";
19858
19859
  this.code = code;
19859
19860
  this.status = status;
19860
19861
  this.hint = hint;
19861
19862
  this.retryAfter = retryAfter;
19863
+ this.backendCode = backendCode;
19862
19864
  }
19863
19865
  get kind() {
19864
19866
  return this.code;
@@ -19881,13 +19883,14 @@ function toWarmHubError(error) {
19881
19883
  return error.cause;
19882
19884
  }
19883
19885
  const data = error.data;
19886
+ const wireCode = data?.warmhub?.code;
19884
19887
  const message = data?.warmhub?.message ?? sanitizeErrorMessage(error.message);
19885
- return new WarmHubError(data?.warmhub?.code ?? "BACKEND", message, data?.warmhub?.status, data?.warmhub?.hint, data?.warmhub?.retryAfter);
19888
+ return new WarmHubError(wireCode ?? "BACKEND", message, data?.warmhub?.status, data?.warmhub?.hint, data?.warmhub?.retryAfter, wireCode);
19886
19889
  }
19887
19890
  if (error instanceof Error) {
19888
19891
  const warmhubLike = error;
19889
19892
  if (error.name === "WarmHubError" && typeof warmhubLike.code === "string") {
19890
- return new WarmHubError(warmhubLike.code, sanitizeErrorMessage(error.message), typeof warmhubLike.status === "number" ? warmhubLike.status : undefined, typeof warmhubLike.hint === "string" ? warmhubLike.hint : undefined, typeof warmhubLike.retryAfter === "number" ? warmhubLike.retryAfter : undefined);
19893
+ return new WarmHubError(warmhubLike.code, sanitizeErrorMessage(error.message), typeof warmhubLike.status === "number" ? warmhubLike.status : undefined, typeof warmhubLike.hint === "string" ? warmhubLike.hint : undefined, typeof warmhubLike.retryAfter === "number" ? warmhubLike.retryAfter : undefined, typeof warmhubLike.backendCode === "string" ? warmhubLike.backendCode : undefined);
19891
19894
  }
19892
19895
  if (error.name === "AbortError") {
19893
19896
  return new WarmHubError("CANCELLED", error.message);
@@ -20547,6 +20550,18 @@ class WarmHubClient {
20547
20550
  } catch (error) {
20548
20551
  throw toWarmHubError(error);
20549
20552
  }
20553
+ },
20554
+ index: {
20555
+ describe: async (orgName, repoName) => {
20556
+ try {
20557
+ return await this.trpc.repo.index.describe.query({
20558
+ orgName,
20559
+ repoName
20560
+ });
20561
+ } catch (error) {
20562
+ throw toWarmHubError(error);
20563
+ }
20564
+ }
20550
20565
  }
20551
20566
  };
20552
20567
  shape = {
@@ -20869,7 +20884,8 @@ class WarmHubClient {
20869
20884
  cursor: opts?.cursor,
20870
20885
  componentId: opts?.componentId,
20871
20886
  excludeComponents: opts?.excludeComponents,
20872
- excludeInfraShapes: opts?.excludeInfraShapes
20887
+ excludeInfraShapes: opts?.excludeInfraShapes,
20888
+ where: opts?.where
20873
20889
  });
20874
20890
  } catch (error) {
20875
20891
  throw toWarmHubError(error);
@@ -21002,7 +21018,8 @@ class WarmHubClient {
21002
21018
  depth: opts?.depth,
21003
21019
  resolveCollections: opts?.resolveCollections,
21004
21020
  limit: opts?.limit,
21005
- cursor: opts?.cursor
21021
+ cursor: opts?.cursor,
21022
+ where: opts?.where
21006
21023
  });
21007
21024
  } catch (error) {
21008
21025
  throw toWarmHubError(error);
@@ -21031,7 +21048,8 @@ class WarmHubClient {
21031
21048
  cursor: opts?.cursor,
21032
21049
  componentId: opts?.componentId,
21033
21050
  excludeComponents: opts?.excludeComponents,
21034
- excludeInfraShapes: opts?.excludeInfraShapes
21051
+ excludeInfraShapes: opts?.excludeInfraShapes,
21052
+ where: opts?.where
21035
21053
  });
21036
21054
  } catch (error) {
21037
21055
  throw toWarmHubError(error);
@@ -21082,7 +21100,8 @@ class WarmHubClient {
21082
21100
  resolveCollections: opts?.resolveCollections,
21083
21101
  componentId: opts?.componentId,
21084
21102
  excludeComponents: opts?.excludeComponents,
21085
- excludeInfraShapes: opts?.excludeInfraShapes
21103
+ excludeInfraShapes: opts?.excludeInfraShapes,
21104
+ where: opts?.where
21086
21105
  });
21087
21106
  } catch (error) {
21088
21107
  throw toWarmHubError(error);
@@ -21120,7 +21139,8 @@ class WarmHubClient {
21120
21139
  dataMode: opts?.dataMode,
21121
21140
  limit: opts?.limit,
21122
21141
  cursor: opts?.cursor,
21123
- includeRetracted: opts?.includeRetracted
21142
+ includeRetracted: opts?.includeRetracted,
21143
+ where: opts?.where
21124
21144
  }), onUpdate);
21125
21145
  },
21126
21146
  thingHistory: async (orgName, repoName, opts, onUpdate) => {
@@ -21457,6 +21477,7 @@ class WarmHubClient {
21457
21477
  if (!response.ok) {
21458
21478
  let message = `Request failed with status ${response.status}`;
21459
21479
  let code = httpStatusToWarmHubCode(response.status);
21480
+ let backendCode;
21460
21481
  let hint;
21461
21482
  let retryAfter;
21462
21483
  try {
@@ -21466,6 +21487,7 @@ class WarmHubClient {
21466
21487
  }
21467
21488
  if (typeof body.error?.code === "string") {
21468
21489
  code = body.error.code;
21490
+ backendCode = body.error.code;
21469
21491
  }
21470
21492
  if (typeof body.error?.hint === "string") {
21471
21493
  hint = body.error.hint;
@@ -21474,7 +21496,7 @@ class WarmHubClient {
21474
21496
  retryAfter = body.error.retryAfter;
21475
21497
  }
21476
21498
  } catch {}
21477
- throw new WarmHubError(code, message, response.status, hint, retryAfter);
21499
+ throw new WarmHubError(code, message, response.status, hint, retryAfter, backendCode);
21478
21500
  }
21479
21501
  return response;
21480
21502
  }
@@ -21592,13 +21614,15 @@ class CliError extends Error {
21592
21614
  kind;
21593
21615
  cause;
21594
21616
  hint;
21617
+ backendCode;
21595
21618
  context;
21596
- constructor(code, kind, message, cause, hint, context) {
21619
+ constructor(code, kind, message, cause, hint, context, backendCode) {
21597
21620
  super(message);
21598
21621
  this.code = code;
21599
21622
  this.kind = kind;
21600
21623
  this.cause = cause;
21601
21624
  this.hint = hint;
21625
+ this.backendCode = backendCode;
21602
21626
  this.context = context;
21603
21627
  }
21604
21628
  }
@@ -21624,24 +21648,33 @@ function conflictHint(message) {
21624
21648
  }
21625
21649
  return "Resolve the conflicting existing state and try again.";
21626
21650
  }
21651
+ function isFieldIndexErrorCode(code) {
21652
+ return code === "FIELD_INDEX_UNAVAILABLE" || code === "FIELD_NOT_INDEXABLE" || code === "FIELD_TYPE_AMBIGUOUS";
21653
+ }
21654
+ function fromWh(exit, kind, err, hint = err.hint) {
21655
+ return new CliError(exit, kind, err.message, err, hint, undefined, err.backendCode);
21656
+ }
21627
21657
  function toCliError(err) {
21628
21658
  if (err instanceof CliError)
21629
21659
  return err;
21630
21660
  if (err instanceof WarmHubError) {
21631
21661
  if (err.kind === "VALIDATION_ERROR" || err.kind === "SHAPE_MISMATCH" || err.kind === "NOT_FOUND") {
21632
- return new CliError(2 /* UserInput */, "USER_INPUT", err.message, err, err.hint);
21662
+ return fromWh(2 /* UserInput */, "USER_INPUT", err);
21633
21663
  }
21634
21664
  if (err.kind === "UNAUTHENTICATED" || err.kind === "FORBIDDEN") {
21635
- const hint = err.hint ?? unauthenticatedHint(err.message);
21636
- return new CliError(3 /* Config */, "AUTH", err.message, err, hint);
21665
+ return fromWh(3 /* Config */, "AUTH", err, err.hint ?? unauthenticatedHint(err.message));
21666
+ }
21667
+ if (isFieldIndexErrorCode(err.code)) {
21668
+ const exit = err.code === "FIELD_NOT_INDEXABLE" ? 2 /* UserInput */ : 4 /* Backend */;
21669
+ return fromWh(exit, err.code, err);
21637
21670
  }
21638
21671
  if ((err.code === "CONFLICT" || err.code === "ARCHIVED") && err.status === undefined) {
21639
- return new CliError(2 /* UserInput */, "CONFLICT", err.message, err, err.hint ?? conflictHint(err.message));
21672
+ return fromWh(2 /* UserInput */, "CONFLICT", err, err.hint ?? conflictHint(err.message));
21640
21673
  }
21641
21674
  if (err.status) {
21642
- return new CliError(4 /* Backend */, "BACKEND", err.message, err, err.hint);
21675
+ return fromWh(4 /* Backend */, "BACKEND", err);
21643
21676
  }
21644
- return new CliError(4 /* Backend */, "BACKEND", err.message, err, err.hint ?? "Check that the API URL and backend are reachable.");
21677
+ return fromWh(4 /* Backend */, "BACKEND", err, err.hint ?? "Check that the API URL and backend are reachable.");
21645
21678
  }
21646
21679
  if (err instanceof TypeError && err.message.includes("fetch")) {
21647
21680
  return new CliError(4 /* Backend */, "BACKEND", "Network error connecting to backend", err, "Check WARMHUB_API_URL or --api-url.");
@@ -21738,6 +21771,30 @@ function generateSuggestions(code, message, context) {
21738
21771
  });
21739
21772
  }
21740
21773
  }
21774
+ if (code === "FIELD_NOT_INDEXABLE") {
21775
+ suggestions.push({
21776
+ action: "Inspect indexed field state for the repo",
21777
+ command: "wh repo describe --indexed-fields"
21778
+ });
21779
+ suggestions.push({
21780
+ action: "Use a shape-declared, indexable scalar field in --where"
21781
+ });
21782
+ }
21783
+ if (code === "FIELD_INDEX_UNAVAILABLE") {
21784
+ suggestions.push({
21785
+ action: "Retry after the field index finishes building"
21786
+ });
21787
+ suggestions.push({
21788
+ action: "Inspect indexed field state for the repo",
21789
+ command: "wh repo describe --indexed-fields"
21790
+ });
21791
+ }
21792
+ if (code === "FIELD_TYPE_AMBIGUOUS") {
21793
+ suggestions.push({
21794
+ action: "Inspect indexed field state for heterogeneous field types",
21795
+ command: "wh repo describe --indexed-fields"
21796
+ });
21797
+ }
21741
21798
  if (code === "AUTH") {
21742
21799
  suggestions.push({
21743
21800
  action: "Re-authenticate",
@@ -21771,6 +21828,11 @@ function shouldLogToErrorTier(err) {
21771
21828
  case "AUTH":
21772
21829
  case "UNKNOWN":
21773
21830
  return true;
21831
+ case "FIELD_NOT_INDEXABLE":
21832
+ return false;
21833
+ case "FIELD_INDEX_UNAVAILABLE":
21834
+ case "FIELD_TYPE_AMBIGUOUS":
21835
+ return true;
21774
21836
  case "BACKEND": {
21775
21837
  const status = err.cause?.status;
21776
21838
  if (typeof status === "number" && status >= 400 && status < 500) {
@@ -21787,7 +21849,7 @@ function cliErrorFromOpFailure(failure) {
21787
21849
  const message = failure.error?.message ?? `Operation on "${failure.name}" failed`;
21788
21850
  const exit = code === "FORBIDDEN" || code === "UNAUTHENTICATED" ? 5 /* Auth */ : code === "VALIDATION_ERROR" || code === "SHAPE_MISMATCH" || code === "NOT_FOUND" || code === "KIND_MISMATCH" || code === "ALREADY_RETRACTED" || code === "CONFLICT" ? 2 /* UserInput */ : 4 /* Backend */;
21789
21851
  const kind = exit === 5 /* Auth */ ? "AUTH" : exit === 2 /* UserInput */ ? code === "CONFLICT" ? "CONFLICT" : "USER_INPUT" : "BACKEND";
21790
- return new CliError(exit, kind, message);
21852
+ return new CliError(exit, kind, message, undefined, undefined, undefined, failure.error?.code);
21791
21853
  }
21792
21854
  function cliErrorFromAllFailed(failures) {
21793
21855
  const exitPriority = (failure) => {
@@ -21826,6 +21888,7 @@ function printCliError(err, errWriter, opts = {}) {
21826
21888
  const envelope = {
21827
21889
  error: {
21828
21890
  code: err.kind,
21891
+ ...err.backendCode ? { backendCode: err.backendCode } : {},
21829
21892
  message: err.message,
21830
21893
  ...err.hint ? { hint: err.hint } : {},
21831
21894
  ...suggestions.length > 0 ? { suggestions } : {},
@@ -24533,10 +24596,64 @@ async function readContentInput(filePath, inline, stdinStream) {
24533
24596
  function usageError(usage, example) {
24534
24597
  throw new CliError(2 /* UserInput */, "USER_INPUT", usage, undefined, `Example: ${example}`);
24535
24598
  }
24599
+ var WHERE_USAGE_HINT = 'Example: --where state=NC --where "employees>=100" --where "state?"';
24600
+ function requireWhereFieldPath(raw, fieldPath) {
24601
+ const normalized = fieldPath.trim();
24602
+ if (!normalized) {
24603
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Malformed --where predicate: "${raw}". Field path cannot be empty.`, undefined, WHERE_USAGE_HINT);
24604
+ }
24605
+ return normalized;
24606
+ }
24607
+ function parseWhereFlag(raw) {
24608
+ const opMatch = raw.match(/^(.+?)\s*(>=|<=|!=|=|>|<)\s*(.*)$/);
24609
+ if (opMatch) {
24610
+ const fieldPath = requireWhereFieldPath(raw, opMatch[1]);
24611
+ const opStr = opMatch[2];
24612
+ const rhsStr = (opMatch[3] ?? "").trim();
24613
+ const op = opStr === "=" ? "eq" : opStr === "!=" ? "ne" : opStr === ">=" ? "gte" : opStr === "<=" ? "lte" : opStr === ">" ? "gt" : "lt";
24614
+ const rhs = coerceValue(rhsStr);
24615
+ return { fieldPath, op, rhs };
24616
+ }
24617
+ const inMatch = raw.match(/^(.+?)\s+in:\[(.*)?\]$/);
24618
+ if (inMatch) {
24619
+ const fieldPath = requireWhereFieldPath(raw, inMatch[1]);
24620
+ const valueStr = inMatch[2] ?? "";
24621
+ if (valueStr.trim() === "") {
24622
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --where "${raw}": in:[] requires at least one value`, undefined, 'Example: --where "state in:[NC,VA]"');
24623
+ }
24624
+ const rhs = valueStr.split(",").map((v) => coerceValue(v.trim()));
24625
+ if (rhs.length > MAX_WHERE_IN_VALUES) {
24626
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --where "${raw}": in:[...] supports at most ${MAX_WHERE_IN_VALUES} values`, undefined, `Split the query into smaller batches of at most ${MAX_WHERE_IN_VALUES} values.`);
24627
+ }
24628
+ return { fieldPath, op: "in", rhs };
24629
+ }
24630
+ const prefixMatch = raw.match(/^(.+?)~(.+)$/);
24631
+ if (prefixMatch) {
24632
+ const fieldPath = requireWhereFieldPath(raw, prefixMatch[1]);
24633
+ const rhs = coerceValue(prefixMatch[2].replace(/\*$/, ""));
24634
+ return { fieldPath, op: "prefix", rhs };
24635
+ }
24636
+ if (raw.endsWith("?")) {
24637
+ const fieldPath = requireWhereFieldPath(raw, raw.slice(0, -1));
24638
+ return { fieldPath, op: "exists" };
24639
+ }
24640
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Malformed --where predicate: "${raw}". Supported operators: =, !=, >, >=, <, <=, ~, in:[...], ?`, undefined, WHERE_USAGE_HINT);
24641
+ }
24642
+ function coerceValue(s) {
24643
+ if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
24644
+ return s.slice(1, -1);
24645
+ }
24646
+ if (s === "true")
24647
+ return true;
24648
+ if (s === "false")
24649
+ return false;
24650
+ return s;
24651
+ }
24536
24652
  var DEFAULT_PAGE_LIMIT = 50;
24537
24653
  var DEFAULT_SEARCH_LIMIT = 25;
24538
24654
  var MAX_PAGE_LIMIT = 500;
24539
24655
  var AUTO_PAGE_LIMIT = MAX_PAGE_LIMIT;
24656
+ var MAX_WHERE_IN_VALUES = 1000;
24540
24657
  async function handleCount(ctx, org, repo, opts) {
24541
24658
  const result = await ctx.client.thing.count(org, repo, opts);
24542
24659
  writeOutput(ctx, result, () => ctx.out(`${result.count}`));
@@ -24778,6 +24895,10 @@ var headFlags = {
24778
24895
  }),
24779
24896
  "exclude-components": flag.boolean({
24780
24897
  description: "Exclude component-owned things from results"
24898
+ }),
24899
+ where: flag.string({
24900
+ multiple: true,
24901
+ description: `Field-value WHERE predicate (repeatable). Syntax: field=val, field>=val, field~prefix*, field in:[a,b] (max ${MAX_WHERE_IN_VALUES} values), field? (exists). Predicates are served by the typed field index; unservable fields return a machine-readable field-index error instead of scanning JSONB bodies.`
24781
24902
  })
24782
24903
  };
24783
24904
  var handleHead = async (ctx, { flags, args }) => {
@@ -24790,6 +24911,8 @@ var handleHead = async (ctx, { flags, args }) => {
24790
24911
  const match = flags.match;
24791
24912
  const count = flags.count;
24792
24913
  const includeRetracted = flags["include-retracted"];
24914
+ const whereRaw = flags.where ?? [];
24915
+ const where = whereRaw.map(parseWhereFlag);
24793
24916
  if (count) {
24794
24917
  if (cursor || all || limit || ctx.liveMode) {
24795
24918
  usageError("Usage: wh thing list --count [--shape SHAPE] [--kind KIND] [--match PATTERN]", "wh thing list --shape Player --count");
@@ -24804,7 +24927,8 @@ var handleHead = async (ctx, { flags, args }) => {
24804
24927
  includeRetracted,
24805
24928
  componentId: componentId2,
24806
24929
  excludeComponents: strictExclude2,
24807
- excludeInfraShapes: !strictExclude2 && !shape
24930
+ excludeInfraShapes: !strictExclude2 && !shape,
24931
+ where: where.length > 0 ? where : undefined
24808
24932
  });
24809
24933
  }
24810
24934
  if (cursor && !limit) {
@@ -24830,7 +24954,8 @@ var handleHead = async (ctx, { flags, args }) => {
24830
24954
  cursor,
24831
24955
  componentId,
24832
24956
  excludeComponents,
24833
- excludeInfraShapes
24957
+ excludeInfraShapes,
24958
+ where: where.length > 0 ? where : undefined
24834
24959
  };
24835
24960
  if (ctx.liveMode) {
24836
24961
  await runLive({
@@ -24860,7 +24985,8 @@ var handleHead = async (ctx, { flags, args }) => {
24860
24985
  cursor,
24861
24986
  componentId,
24862
24987
  excludeComponents,
24863
- excludeInfraShapes
24988
+ excludeInfraShapes,
24989
+ where: where.length > 0 ? where : undefined
24864
24990
  }) : await ctx.client.thing.head(org, repo, {
24865
24991
  shape,
24866
24992
  kind,
@@ -24870,7 +24996,8 @@ var handleHead = async (ctx, { flags, args }) => {
24870
24996
  cursor,
24871
24997
  componentId,
24872
24998
  excludeComponents,
24873
- excludeInfraShapes
24999
+ excludeInfraShapes,
25000
+ where: where.length > 0 ? where : undefined
24874
25001
  });
24875
25002
  writeOutput(ctx, result, () => renderHead(ctx.out, ctx.colors, ctx.chars, result, org, repo, shape, kind));
24876
25003
  };
@@ -24887,7 +25014,8 @@ async function fetchAllHeadPages(ctx, org, repo, opts) {
24887
25014
  cursor,
24888
25015
  componentId: opts.componentId,
24889
25016
  excludeComponents: opts.excludeComponents,
24890
- excludeInfraShapes: opts.excludeInfraShapes
25017
+ excludeInfraShapes: opts.excludeInfraShapes,
25018
+ where: opts.where
24891
25019
  });
24892
25020
  items.push(...page.items ?? []);
24893
25021
  if (!page.nextCursor)
@@ -25333,6 +25461,10 @@ var queryFlags = {
25333
25461
  }),
25334
25462
  "exclude-components": flag.boolean({
25335
25463
  description: "Exclude component-owned things from results"
25464
+ }),
25465
+ where: flag.string({
25466
+ multiple: true,
25467
+ description: `Field-value WHERE predicate (repeatable). Syntax: field=val, field>=val, field~prefix*, field in:[a,b] (max ${MAX_WHERE_IN_VALUES} values), field? (exists). Predicates are served by the typed field index; unservable fields return a machine-readable field-index error instead of scanning JSONB bodies.`
25336
25468
  })
25337
25469
  };
25338
25470
  var handleQuery = async (ctx, { flags }) => {
@@ -25354,6 +25486,8 @@ var handleQuery = async (ctx, { flags }) => {
25354
25486
  const excludeComponents = strictExclude;
25355
25487
  const excludeInfraShapes = !strictExclude && !hasShape;
25356
25488
  const c = ctx.colors;
25489
+ const whereRaw = flags.where ?? [];
25490
+ const where = whereRaw.map(parseWhereFlag);
25357
25491
  if (count) {
25358
25492
  if (cursor || all || limit || ctx.liveMode) {
25359
25493
  usageError("Usage: wh thing query --count [--shape SHAPE] [--about WREF] [--kind KIND] [--match PATTERN]", "wh thing query --kind assertion --about Player/alice --count");
@@ -25367,7 +25501,8 @@ var handleQuery = async (ctx, { flags }) => {
25367
25501
  resolveCollections,
25368
25502
  componentId,
25369
25503
  excludeComponents,
25370
- excludeInfraShapes
25504
+ excludeInfraShapes,
25505
+ where: where.length > 0 ? where : undefined
25371
25506
  });
25372
25507
  }
25373
25508
  if (cursor && !limit) {
@@ -25389,7 +25524,8 @@ var handleQuery = async (ctx, { flags }) => {
25389
25524
  cursor,
25390
25525
  componentId,
25391
25526
  excludeComponents,
25392
- excludeInfraShapes
25527
+ excludeInfraShapes,
25528
+ where: where.length > 0 ? where : undefined
25393
25529
  };
25394
25530
  if (ctx.liveMode) {
25395
25531
  await runLive({
@@ -25421,7 +25557,8 @@ var handleQuery = async (ctx, { flags }) => {
25421
25557
  cursor,
25422
25558
  componentId,
25423
25559
  excludeComponents,
25424
- excludeInfraShapes
25560
+ excludeInfraShapes,
25561
+ where: where.length > 0 ? where : undefined
25425
25562
  }) : await ctx.client.thing.query(org, repo, {
25426
25563
  shape,
25427
25564
  about,
@@ -25433,7 +25570,8 @@ var handleQuery = async (ctx, { flags }) => {
25433
25570
  cursor,
25434
25571
  componentId,
25435
25572
  excludeComponents,
25436
- excludeInfraShapes
25573
+ excludeInfraShapes,
25574
+ where: where.length > 0 ? where : undefined
25437
25575
  });
25438
25576
  writeOutput(ctx, result, () => renderQueryResults(ctx.out, c, result));
25439
25577
  };
@@ -25452,7 +25590,8 @@ async function fetchAllQueryPages(ctx, org, repo, opts) {
25452
25590
  cursor,
25453
25591
  componentId: opts.componentId,
25454
25592
  excludeComponents: opts.excludeComponents,
25455
- excludeInfraShapes: opts.excludeInfraShapes
25593
+ excludeInfraShapes: opts.excludeInfraShapes,
25594
+ where: opts.where
25456
25595
  });
25457
25596
  items.push(...page.items ?? []);
25458
25597
  if (!page.nextCursor)
@@ -33437,20 +33576,36 @@ var handleUpdate3 = async (ctx, { args, flags }) => {
33437
33576
  ctx.out(`${c.green}Updated${c.reset} ${c.cyan}${orgName}/${repoName}${c.reset} description`);
33438
33577
  });
33439
33578
  };
33440
- var handleDescribe = async (ctx, { args }) => {
33579
+ var describeFlags = {
33580
+ "indexed-fields": flag.boolean({
33581
+ description: "Show typed field index state (building, ready, failed) for each shape"
33582
+ })
33583
+ };
33584
+ var handleDescribe = async (ctx, { args, flags }) => {
33441
33585
  const repoRef = args[0];
33442
33586
  const { org, repo } = parseOrgRepo(repoRef, ctx.config);
33443
33587
  const c = ctx.colors;
33444
- const [repoInfo, shapesPage, stats] = await Promise.all([
33588
+ const showIndexedFields = flags["indexed-fields"] === true;
33589
+ const [repoInfo, shapesPage, stats, indexedFields] = await Promise.all([
33445
33590
  ctx.client.repo.get(org, repo),
33446
33591
  ctx.client.shape.list(org, repo),
33447
- ctx.client.repo.getStats(org, repo)
33592
+ ctx.client.repo.getStats(org, repo),
33593
+ showIndexedFields ? ctx.client.repo.index.describe(org, repo) : null
33448
33594
  ]);
33449
33595
  const shapes = shapesPage.items;
33450
33596
  const byShape = Object.fromEntries([
33451
33597
  ...shapes.map((shape) => shape.name).filter((name) => typeof name === "string").map((name) => [name, 0]),
33452
33598
  ...Object.entries(stats.byShape)
33453
33599
  ]);
33600
+ function stripShapeThingId(bucket) {
33601
+ return bucket.map(({ shapeThingId: _omit, ...rest }) => rest);
33602
+ }
33603
+ const indexedFieldsPublic = indexedFields ? {
33604
+ building: stripShapeThingId(indexedFields.building),
33605
+ ready: stripShapeThingId(indexedFields.ready),
33606
+ failed: stripShapeThingId(indexedFields.failed),
33607
+ other: stripShapeThingId(indexedFields.other)
33608
+ } : null;
33454
33609
  const payload = {
33455
33610
  org,
33456
33611
  repo,
@@ -33470,7 +33625,8 @@ var handleDescribe = async (ctx, { args }) => {
33470
33625
  description: typeof data?.description === "string" ? data.description : null,
33471
33626
  fields: Object.fromEntries(Object.entries(fields).map(([k, v]) => [k, displayFieldEntry(v)]))
33472
33627
  };
33473
- })
33628
+ }),
33629
+ ...indexedFieldsPublic ? { indexedFields: indexedFieldsPublic } : {}
33474
33630
  };
33475
33631
  writeOutput(ctx, payload, () => {
33476
33632
  ctx.out(`${c.bold}${org}/${repo}${c.reset}`);
@@ -33521,6 +33677,52 @@ var handleDescribe = async (ctx, { args }) => {
33521
33677
  }
33522
33678
  ctx.out("");
33523
33679
  }
33680
+ if (indexedFieldsPublic) {
33681
+ const allEntries = [
33682
+ ...indexedFieldsPublic.building,
33683
+ ...indexedFieldsPublic.ready,
33684
+ ...indexedFieldsPublic.failed,
33685
+ ...indexedFieldsPublic.other
33686
+ ];
33687
+ if (allEntries.length === 0) {
33688
+ ctx.out(`${c.bold}Indexed Fields${c.reset} ${c.dim}none${c.reset}`);
33689
+ } else {
33690
+ ctx.out(`${c.bold}Indexed Fields${c.reset} (${allEntries.length})`);
33691
+ ctx.out("");
33692
+ const stateColor = (state) => {
33693
+ switch (state) {
33694
+ case "ready":
33695
+ return c.green;
33696
+ case "building":
33697
+ return c.yellow;
33698
+ case "failed":
33699
+ return c.red;
33700
+ default:
33701
+ return c.dim;
33702
+ }
33703
+ };
33704
+ const maxShape = allEntries.reduce((m, e) => Math.max(m, e.shapeName.length), 0);
33705
+ const maxField = allEntries.reduce((m, e) => Math.max(m, e.fieldPath.length), 0);
33706
+ const maxState = allEntries.reduce((m, e) => Math.max(m, e.state.length), 0);
33707
+ for (const entry of allEntries) {
33708
+ const shapeLabel = entry.shapeName.padEnd(maxShape);
33709
+ const fieldLabel = entry.fieldPath.padEnd(maxField);
33710
+ const stateLabel = entry.state.padEnd(maxState);
33711
+ const sc = stateColor(entry.state);
33712
+ let line = ` ${c.cyan}${shapeLabel}${c.reset} ${c.dim}${fieldLabel}${c.reset} ${sc}${stateLabel}${c.reset}`;
33713
+ if (entry.state === "building" && entry.backfillTotal != null && entry.backfillTotal > 0) {
33714
+ const pct = Math.round(entry.backfillDone / entry.backfillTotal * 100);
33715
+ line += ` ${c.dim}${entry.backfillDone}/${entry.backfillTotal} (${pct}%)${c.reset}`;
33716
+ } else if (entry.state === "building") {
33717
+ line += ` ${c.dim}${entry.backfillDone} rows${c.reset}`;
33718
+ } else if (entry.state === "failed" && entry.failureReason) {
33719
+ line += ` ${c.dim}${entry.failureReason}${c.reset}`;
33720
+ }
33721
+ ctx.out(line);
33722
+ }
33723
+ ctx.out("");
33724
+ }
33725
+ }
33524
33726
  });
33525
33727
  };
33526
33728
  var confirmFlags2 = {
@@ -33790,7 +33992,12 @@ var REPO_DOMAIN = defineDomain({
33790
33992
  prime: true,
33791
33993
  summary: "Describe repo schema: shapes, fields, and inline descriptions",
33792
33994
  args: "[org/repo]",
33793
- examples: ["wh repo describe", "wh repo describe acme/world"],
33995
+ flags: describeFlags,
33996
+ examples: [
33997
+ "wh repo describe",
33998
+ "wh repo describe acme/world",
33999
+ "wh repo describe acme/world --indexed-fields"
34000
+ ],
33794
34001
  handler: handleDescribe
33795
34002
  },
33796
34003
  visibility: {
@@ -35860,7 +36067,7 @@ function resolveLogLevel(flags, env) {
35860
36067
  // package.json
35861
36068
  var package_default3 = {
35862
36069
  name: "@warmhub/cli",
35863
- version: "0.44.0",
36070
+ version: "0.45.0",
35864
36071
  private: false,
35865
36072
  type: "module",
35866
36073
  homepage: "https://docs.warmhub.ai",
@@ -36094,8 +36301,11 @@ async function resolveRegisteredInstall(args) {
36094
36301
  try {
36095
36302
  return await args.client.component.registry.resolve(ownerOrg, componentName, args.installRepo);
36096
36303
  } catch (error) {
36097
- if (error instanceof WarmHubError && error.kind === "NOT_FOUND") {
36098
- throw new CliError(2 /* UserInput */, "USER_INPUT", `No component registered as ${args.componentRef}`, undefined, `If you meant a local path, prefix it with ./${args.componentRef}`);
36304
+ if (error instanceof WarmHubError && error.backendCode === "NOT_FOUND") {
36305
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `No component registered as ${args.componentRef}`, undefined, `If you meant a local path, prefix it with ./${args.componentRef}`, undefined, error.backendCode);
36306
+ }
36307
+ if (error instanceof WarmHubError && error.status === 404 && error.backendCode === undefined) {
36308
+ throw new CliError(4 /* Backend */, "BACKEND", error.message, error, "The backend may not expose the component-registry routes. Confirm the API URL points at a deployment that supports `wh component install`, or check for a proxy/path mismatch.");
36099
36309
  }
36100
36310
  throw toCliError2(error);
36101
36311
  }
@@ -36186,7 +36396,7 @@ async function handleRegisteredInstall(args) {
36186
36396
  });
36187
36397
  } catch (error) {
36188
36398
  if (isMissingManifestPermissionError(error)) {
36189
- throw new CliError(2 /* UserInput */, "USER_INPUT", error.message, undefined, "Ask an org owner/admin to grant the missing permissions on the install repo, then re-run install.");
36399
+ throw new CliError(2 /* UserInput */, "USER_INPUT", error.message, undefined, "Ask an org owner/admin to grant the missing permissions on the install repo, then re-run install.", undefined, error.backendCode);
36190
36400
  }
36191
36401
  throw error;
36192
36402
  }
@@ -36805,4 +37015,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
36805
37015
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
36806
37016
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
36807
37017
 
36808
- //# debugId=2257A8F0A0546F4F64756E2164756E21
37018
+ //# debugId=3F3232411E7711A864756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "homepage": "https://docs.warmhub.ai",