@warmhub/cli 0.64.0 → 0.65.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 +105 -28
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -27353,7 +27353,7 @@ function findSystemComponent(componentId) {
27353
27353
  // ../../packages/sdk-ts/package.json
27354
27354
  var package_default = {
27355
27355
  name: "@warmhub/sdk-ts",
27356
- version: "0.63.0",
27356
+ version: "0.64.0",
27357
27357
  private: false,
27358
27358
  type: "module",
27359
27359
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -32744,17 +32744,37 @@ function escapeTerminalTextForDisplay(value) {
32744
32744
  var escapeInlineTerminalText = escapeFieldNameForDisplay;
32745
32745
  function renderWarningLine(out, c, chars, op) {
32746
32746
  const warnings = op.warnings;
32747
- if (!warnings || warnings.undeclaredFields.length === 0)
32747
+ if (!warnings)
32748
+ return;
32749
+ renderUndeclaredFieldsWarning(out, c, chars, op.name, warnings);
32750
+ renderCoalescedWrefsWarning(out, c, chars, warnings);
32751
+ }
32752
+ function renderUndeclaredFieldsWarning(out, c, chars, opName, warnings) {
32753
+ const undeclaredFields = warnings.undeclaredFields;
32754
+ if (!undeclaredFields || undeclaredFields.length === 0)
32748
32755
  return;
32749
- const shapeName = extractShapeName(op.name);
32750
- const total = warnings.totalUndeclared ?? warnings.undeclaredFields.length;
32756
+ const shapeName = extractShapeName(opName);
32757
+ const total = warnings.totalUndeclared ?? undeclaredFields.length;
32751
32758
  const noun = total === 1 ? "field" : "fields";
32752
32759
  const shapeLabel = shapeName ? ` ${shapeName}` : "";
32753
- const remaining = warnings.undeclaredFieldsTruncated ? total - warnings.undeclaredFields.length : 0;
32754
- const fieldsList = warnings.undeclaredFields.map(escapeInlineTerminalText).join(", ");
32760
+ const remaining = warnings.undeclaredFieldsTruncated ? total - undeclaredFields.length : 0;
32761
+ const fieldsList = undeclaredFields.map(escapeInlineTerminalText).join(", ");
32755
32762
  const moreSuffix = remaining > 0 ? ` ${c.dim}(+${remaining} more)${c.reset}` : "";
32756
32763
  out(` ${c.yellow}${chars.warn}${c.reset} ${total} ${noun} not declared in shape${shapeLabel}: ${c.dim}${fieldsList}${c.reset}${moreSuffix}`);
32757
32764
  }
32765
+ function renderCoalescedWrefsWarning(out, c, chars, warnings) {
32766
+ const coalescedWrefs = warnings.coalescedWrefs;
32767
+ if (!coalescedWrefs || coalescedWrefs.length === 0)
32768
+ return;
32769
+ for (const entry of coalescedWrefs) {
32770
+ out(` ${c.yellow}${chars.warn}${c.reset} coalesced wref ${escapeInlineTerminalText(entry.fieldPath)}: ${c.dim}${escapeInlineTerminalText(entry.wref)}${c.reset} (${escapeInlineTerminalText(entry.reason)})`);
32771
+ }
32772
+ const total = warnings.totalCoalescedWrefs ?? coalescedWrefs.length;
32773
+ const remaining = warnings.coalescedWrefsTruncated ? total - coalescedWrefs.length : 0;
32774
+ if (remaining > 0) {
32775
+ out(` ${c.dim}(+${remaining} more coalesced wrefs)${c.reset}`);
32776
+ }
32777
+ }
32758
32778
  function renderCommitterEcho(out, c, committer) {
32759
32779
  if (!committer)
32760
32780
  return;
@@ -37882,6 +37902,24 @@ function isInstallSnapshotCacheShape(value) {
37882
37902
  if (!Array.isArray(component.methods))
37883
37903
  return false;
37884
37904
  }
37905
+ if (!isPlainObject2(value.installs))
37906
+ return false;
37907
+ const installs = value.installs;
37908
+ for (const entry of Object.values(installs)) {
37909
+ if (!isPlainObject2(entry))
37910
+ return false;
37911
+ const install = entry;
37912
+ if (typeof install.ref !== "string")
37913
+ return false;
37914
+ if (typeof install.version !== "string")
37915
+ return false;
37916
+ if (install.latestVersion !== undefined && typeof install.latestVersion !== "string") {
37917
+ return false;
37918
+ }
37919
+ if (install.updateAvailable !== undefined && typeof install.updateAvailable !== "boolean") {
37920
+ return false;
37921
+ }
37922
+ }
37885
37923
  return true;
37886
37924
  }
37887
37925
 
@@ -37955,6 +37993,7 @@ async function refreshInstallSnapshotCache(repoSlug, client, opts) {
37955
37993
  }
37956
37994
  async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now, previousCache) {
37957
37995
  const components = {};
37996
+ const installs = {};
37958
37997
  let detailReadFailures = 0;
37959
37998
  for (const item of activeItems) {
37960
37999
  if (!item.ref)
@@ -37974,6 +38013,12 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37974
38013
  const manifest = extractInstalledManifest(detail.install.data);
37975
38014
  if (!manifest)
37976
38015
  continue;
38016
+ installs[item.componentName] = {
38017
+ ref: itemRef,
38018
+ version: manifest.component.version ?? item.version ?? "",
38019
+ latestVersion: item.latestVersion,
38020
+ updateAvailable: item.updateAvailable
38021
+ };
37977
38022
  const methods = manifest.cli?.methods ?? [];
37978
38023
  if (methods.length === 0)
37979
38024
  continue;
@@ -37987,7 +38032,9 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37987
38032
  version: manifest.component.version ?? item.version ?? "",
37988
38033
  description: manifest.cli?.description,
37989
38034
  manifestHash: item.manifestHash ?? "",
37990
- methods
38035
+ methods,
38036
+ latestVersion: item.latestVersion,
38037
+ updateAvailable: item.updateAvailable
37991
38038
  };
37992
38039
  }
37993
38040
  if (activeItems.length > 0 && detailReadFailures === activeItems.length) {
@@ -37999,7 +38046,8 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37999
38046
  const cache = {
38000
38047
  cachedAt: now,
38001
38048
  repoSlug,
38002
- components
38049
+ components,
38050
+ installs
38003
38051
  };
38004
38052
  writeInstallSnapshotCache(repoSlug, cache);
38005
38053
  return cache;
@@ -38365,6 +38413,13 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
38365
38413
  const cache = await ensureFreshInstallSnapshotCache(installRepo, ctx.client);
38366
38414
  const entry = cache.components[componentName];
38367
38415
  if (!entry) {
38416
+ const install = cache.installs[componentName];
38417
+ if (install?.updateAvailable && install.latestVersion) {
38418
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is installed at ${install.version || "an older version"} in ${installRepo}, which exposes no CLI method${methodName ? ` '${methodName}'` : "s"}.`, undefined, `Version ${install.latestVersion} is available — run 'wh component update ${install.ref} --repo ${installRepo}', then 'wh component exec ${componentName} --help' to see its methods.`);
38419
+ }
38420
+ if (install) {
38421
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is installed in ${installRepo} but exposes no CLI methods.`);
38422
+ }
38368
38423
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is not installed in ${installRepo}.`, undefined, `Run 'wh component install <ref> --repo ${installRepo}' first.`);
38369
38424
  }
38370
38425
  if (!methodName) {
@@ -38376,7 +38431,9 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
38376
38431
  }
38377
38432
  const method = entry.methods.find((m) => m.name === methodName);
38378
38433
  if (!method) {
38379
- 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.`);
38434
+ const available = entry.methods.map((m) => m.name).join(", ");
38435
+ const updateHint = entry.updateAvailable && entry.latestVersion ? `Version ${entry.latestVersion} is available — run wh component update ${entry.ref} --repo ${installRepo} for newer methods.` : `Run wh component update ${entry.ref} --repo ${installRepo} if you expect a newer method.`;
38436
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Method '${methodName}' not found on component '${componentName}'.`, undefined, `Available: ${available}. ${updateHint}`);
38380
38437
  }
38381
38438
  if (helpRequested) {
38382
38439
  renderMethodHelp(ctx, componentName, method);
@@ -39025,7 +39082,8 @@ var handleView3 = async (ctx, { args }) => {
39025
39082
  writeOutput(ctx, viewData, () => {
39026
39083
  const c = ctx.colors;
39027
39084
  ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${viewData.ref ?? ref}${c.reset}`);
39028
- ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}`);
39085
+ const update = viewData.updateAvailable && viewData.latestVersion ? ` ${c.yellow}(${viewData.latestVersion} available — run wh component update ${viewData.ref ?? ref} --repo ${org}/${repo})${c.reset}` : "";
39086
+ ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}${update}`);
39029
39087
  ctx.out(`${c.bold}State:${c.reset} ${viewData.state ?? "-"}`);
39030
39088
  ctx.out(`${c.bold}Source:${c.reset} ${viewData.source ?? "-"}`);
39031
39089
  if (viewData.ownedShapes.length > 0) {
@@ -39282,6 +39340,22 @@ async function doctorComponent(client, org, repo, componentId) {
39282
39340
  });
39283
39341
  }
39284
39342
  }
39343
+ try {
39344
+ const detail = await client.component.get(org, repo, registeredComponentRef);
39345
+ if (detail.updateAvailable === true && detail.latestVersion) {
39346
+ findings.push({
39347
+ resource: "version",
39348
+ status: "warning",
39349
+ message: `Installed ${detail.version ?? "version"}; ${detail.latestVersion} available — run wh component update ${registeredComponentRef} --repo ${org}/${repo}`
39350
+ });
39351
+ } else if (detail.updateAvailable === false && detail.version) {
39352
+ findings.push({
39353
+ resource: "version",
39354
+ status: "ok",
39355
+ message: `Up to date (${detail.version})`
39356
+ });
39357
+ }
39358
+ } catch {}
39285
39359
  const hasMissing = findings.some((f) => f.status === "missing");
39286
39360
  const hasInactive = findings.some((f) => f.status === "inactive" && !f.resource.startsWith("sub:"));
39287
39361
  const hasShapeDrift = findings.some((f) => f.resource.startsWith("shape:") && f.status === "warning" && f.message.includes("differs from installed manifest"));
@@ -39294,21 +39368,23 @@ async function doctorComponent(client, org, repo, componentId) {
39294
39368
  } else {
39295
39369
  state = "ready";
39296
39370
  }
39297
- try {
39298
- await client.commit.apply(org, repo, `Doctor: update ${componentName} state to ${state}`, [
39299
- {
39300
- operation: "revise",
39301
- kind: "thing",
39302
- name: `ComponentInstall/${componentId}`,
39303
- data: { ...installData, state, checkedAt: new Date().toISOString() }
39304
- }
39305
- ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
39306
- } catch {
39307
- findings.push({
39308
- resource: "state-update",
39309
- status: "warning",
39310
- message: "Failed to persist computed state"
39311
- });
39371
+ if (state !== existingState) {
39372
+ try {
39373
+ await client.commit.apply(org, repo, `Doctor: update ${componentName} state to ${state}`, [
39374
+ {
39375
+ operation: "revise",
39376
+ kind: "thing",
39377
+ name: `ComponentInstall/${componentId}`,
39378
+ data: { ...installData, state }
39379
+ }
39380
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
39381
+ } catch {
39382
+ findings.push({
39383
+ resource: "state-update",
39384
+ status: "warning",
39385
+ message: "Failed to persist computed state"
39386
+ });
39387
+ }
39312
39388
  }
39313
39389
  return { componentId, componentName, state, findings };
39314
39390
  }
@@ -39426,7 +39502,8 @@ var handleList2 = async (ctx, { flags }) => {
39426
39502
  const state = item.state ?? "unknown";
39427
39503
  const source = item.source ?? "-";
39428
39504
  const stateColor = stateToColor2(c, state);
39429
- ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
39505
+ const update = item.updateAvailable && item.latestVersion ? ` ${c.yellow}(${item.latestVersion} available)${c.reset}` : "";
39506
+ ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset}${update} ${source}`);
39430
39507
  }
39431
39508
  });
39432
39509
  };
@@ -45761,7 +45838,7 @@ function resolveLogLevel(flags, env) {
45761
45838
  // package.json
45762
45839
  var package_default3 = {
45763
45840
  name: "@warmhub/cli",
45764
- version: "0.64.0",
45841
+ version: "0.65.0",
45765
45842
  private: false,
45766
45843
  type: "module",
45767
45844
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -46416,4 +46493,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
46416
46493
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
46417
46494
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
46418
46495
 
46419
- //# debugId=7FF3388CDD4F972C64756E2164756E21
46496
+ //# debugId=B70D5B946B8CF0E364756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.64.0",
3
+ "version": "0.65.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",