@warmhub/cli 0.58.0 → 0.60.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 +442 -120
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -18531,6 +18531,12 @@ var DEFAULT_MAX_OPS_PER_STREAM = 1e6;
18531
18531
  var DEFAULT_STREAM_APPEND_CHUNK_SIZE = 1000;
18532
18532
  var MAX_STREAM_APPEND_OPERATION_COUNT = 1e4;
18533
18533
  // ../../packages/rules/src/commit-types.ts
18534
+ var COMMIT_OPERATION_KINDS = [
18535
+ "shape",
18536
+ "thing",
18537
+ "assertion",
18538
+ "collection"
18539
+ ];
18534
18540
  function inferOperationKind(op) {
18535
18541
  if (op.kind === "shape" || op.kind === "thing" || op.kind === "assertion" || op.kind === "collection") {
18536
18542
  return op.kind;
@@ -21379,6 +21385,15 @@ function nestedObjectFields(typeDef) {
21379
21385
  }
21380
21386
  return fields;
21381
21387
  }
21388
+ // ../../packages/rules/src/subscribable-events.ts
21389
+ var COMMIT_EVENT_TYPE = "commit";
21390
+ var REPO_RENAMED_EVENT_TYPE = "repo.renamed";
21391
+ var ORG_RENAMED_EVENT_TYPE = "org.renamed";
21392
+ var SUBSCRIBABLE_EVENT_TYPES = [
21393
+ COMMIT_EVENT_TYPE,
21394
+ REPO_RENAMED_EVENT_TYPE,
21395
+ ORG_RENAMED_EVENT_TYPE
21396
+ ];
21382
21397
  // ../../packages/rules/src/system-components/system.ts
21383
21398
  var SYSTEM_COMPONENT_ID = "com.warmhub.system";
21384
21399
  var SYSTEM_REGISTERED_COMPONENT_REF = "warmhub/system";
@@ -21442,7 +21457,7 @@ function findSystemComponent(componentId) {
21442
21457
  // ../../packages/sdk-ts/package.json
21443
21458
  var package_default = {
21444
21459
  name: "@warmhub/sdk-ts",
21445
- version: "0.58.0",
21460
+ version: "0.60.0",
21446
21461
  private: false,
21447
21462
  type: "module",
21448
21463
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -21563,6 +21578,14 @@ function toBackendStreamOperation(operation) {
21563
21578
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
21564
21579
  };
21565
21580
  }
21581
+ if (operation.operation === "rename") {
21582
+ return {
21583
+ operation: "rename",
21584
+ name: operation.name,
21585
+ newName: operation.newName,
21586
+ ...operation.kind ? { kind: operation.kind } : {}
21587
+ };
21588
+ }
21566
21589
  if (operation.operation === "revise") {
21567
21590
  const name = operation.name ?? operation.wref;
21568
21591
  if (!name) {
@@ -21955,7 +21978,7 @@ function toSubmittedStreamResult(writeResult, committer, createdByEmail, message
21955
21978
  operations: results.map((result) => ({
21956
21979
  ...result.opIndex !== undefined ? { opIndex: result.opIndex } : {},
21957
21980
  name: result.name ?? "",
21958
- operation: result.operation === "revise" || result.operation === "retract" || result.operation === "noop" ? result.operation : "add",
21981
+ operation: result.operation === "revise" || result.operation === "retract" || result.operation === "rename" || result.operation === "noop" ? result.operation : "add",
21959
21982
  dataHash: result.dataHash ?? "",
21960
21983
  version: result.version ?? 0,
21961
21984
  status: streamAppendResultStatus(result),
@@ -22052,6 +22075,27 @@ function chunkArray(items, chunkSize) {
22052
22075
  }
22053
22076
  return chunks;
22054
22077
  }
22078
+ function toSubscriptionRef(args) {
22079
+ const [first, repoName, name] = args;
22080
+ return typeof first === "string" ? { orgName: first, repoName, name } : first;
22081
+ }
22082
+ function toSubscriptionListRef(args) {
22083
+ const [first, repoName] = args;
22084
+ return typeof first === "string" ? { orgName: first, repoName } : first;
22085
+ }
22086
+ function toSubscriptionBindRef(args) {
22087
+ const [first, repoName, subscriptionName, credentialSetName] = args;
22088
+ return typeof first === "string" ? {
22089
+ orgName: first,
22090
+ repoName,
22091
+ subscriptionName,
22092
+ credentialSetName
22093
+ } : first;
22094
+ }
22095
+ function toSubscriptionUnbindRef(args) {
22096
+ const [first, repoName, subscriptionName] = args;
22097
+ return typeof first === "string" ? { orgName: first, repoName, subscriptionName } : first;
22098
+ }
22055
22099
  function sanitizeSubscriptionCreateInput(input) {
22056
22100
  const {
22057
22101
  actionContainer: _actionContainer,
@@ -23019,35 +23063,24 @@ class WarmHubClient {
23019
23063
  throw toWarmHubError(error);
23020
23064
  }
23021
23065
  },
23022
- get: async (orgName, repoName, name) => {
23066
+ get: async (...args) => {
23023
23067
  try {
23024
- const result = await this.trpc.subscription.get.query({
23025
- orgName,
23026
- repoName,
23027
- name
23028
- });
23068
+ const result = await this.trpc.subscription.get.query(toSubscriptionRef(args));
23029
23069
  return normalizeSubscriptionInfo(result);
23030
23070
  } catch (error) {
23031
23071
  throw toWarmHubError(error);
23032
23072
  }
23033
23073
  },
23034
- reveal: async (orgName, repoName, name) => {
23074
+ reveal: async (...args) => {
23035
23075
  try {
23036
- return await this.trpc.subscription.reveal.query({
23037
- orgName,
23038
- repoName,
23039
- name
23040
- });
23076
+ return await this.trpc.subscription.reveal.query(toSubscriptionRef(args));
23041
23077
  } catch (error) {
23042
23078
  throw toWarmHubError(error);
23043
23079
  }
23044
23080
  },
23045
- list: async (orgName, repoName) => {
23081
+ list: async (...args) => {
23046
23082
  try {
23047
- const result = await this.trpc.subscription.list.query({
23048
- orgName,
23049
- repoName
23050
- });
23083
+ const result = await this.trpc.subscription.list.query(toSubscriptionListRef(args));
23051
23084
  return normalizeSubscriptionList(result);
23052
23085
  } catch (error) {
23053
23086
  throw toWarmHubError(error);
@@ -23061,58 +23094,37 @@ class WarmHubClient {
23061
23094
  throw toWarmHubError(error);
23062
23095
  }
23063
23096
  },
23064
- pause: async (orgName, repoName, name) => {
23097
+ pause: async (...args) => {
23065
23098
  try {
23066
- return await this.trpc.subscription.pause.mutate({
23067
- orgName,
23068
- repoName,
23069
- name
23070
- });
23099
+ return await this.trpc.subscription.pause.mutate(toSubscriptionRef(args));
23071
23100
  } catch (error) {
23072
23101
  throw toWarmHubError(error);
23073
23102
  }
23074
23103
  },
23075
- resume: async (orgName, repoName, name) => {
23104
+ resume: async (...args) => {
23076
23105
  try {
23077
- return await this.trpc.subscription.resume.mutate({
23078
- orgName,
23079
- repoName,
23080
- name
23081
- });
23106
+ return await this.trpc.subscription.resume.mutate(toSubscriptionRef(args));
23082
23107
  } catch (error) {
23083
23108
  throw toWarmHubError(error);
23084
23109
  }
23085
23110
  },
23086
- remove: async (orgName, repoName, name) => {
23111
+ remove: async (...args) => {
23087
23112
  try {
23088
- return await this.trpc.subscription.remove.mutate({
23089
- orgName,
23090
- repoName,
23091
- name
23092
- });
23113
+ return await this.trpc.subscription.remove.mutate(toSubscriptionRef(args));
23093
23114
  } catch (error) {
23094
23115
  throw toWarmHubError(error);
23095
23116
  }
23096
23117
  },
23097
- bindCredentials: async (orgName, repoName, subscriptionName, credentialSetName) => {
23118
+ bindCredentials: async (...args) => {
23098
23119
  try {
23099
- return await this.trpc.subscription.bindCredentials.mutate({
23100
- orgName,
23101
- repoName,
23102
- subscriptionName,
23103
- credentialSetName
23104
- });
23120
+ return await this.trpc.subscription.bindCredentials.mutate(toSubscriptionBindRef(args));
23105
23121
  } catch (error) {
23106
23122
  throw toWarmHubError(error);
23107
23123
  }
23108
23124
  },
23109
- unbindCredentials: async (orgName, repoName, subscriptionName) => {
23125
+ unbindCredentials: async (...args) => {
23110
23126
  try {
23111
- return await this.trpc.subscription.unbindCredentials.mutate({
23112
- orgName,
23113
- repoName,
23114
- subscriptionName
23115
- });
23127
+ return await this.trpc.subscription.unbindCredentials.mutate(toSubscriptionUnbindRef(args));
23116
23128
  } catch (error) {
23117
23129
  throw toWarmHubError(error);
23118
23130
  }
@@ -24186,6 +24198,9 @@ function toCliError(err) {
24186
24198
  const defaultHint = typeof retryAfter === "number" ? `Rate limited. Retry after ${retryAfter}s.` : "Rate limited. Wait for the Retry-After window before retrying.";
24187
24199
  return fromWh(4 /* Backend */, "RATE_LIMITED", err, err.hint ?? defaultHint);
24188
24200
  }
24201
+ if (err.code === "QUERY_TOO_EXPENSIVE") {
24202
+ return fromWh(2 /* UserInput */, "QUERY_TOO_EXPENSIVE", err, err.hint ?? "Narrow the query with a more selective field predicate or retry with a shallower page.");
24203
+ }
24189
24204
  if (err.status) {
24190
24205
  return fromWh(4 /* Backend */, "BACKEND", err);
24191
24206
  }
@@ -24342,6 +24357,14 @@ function generateSuggestions(code, message, context, errorCode) {
24342
24357
  command: "wh repo describe --indexed-fields"
24343
24358
  });
24344
24359
  }
24360
+ if (code === "QUERY_TOO_EXPENSIVE") {
24361
+ suggestions.push({
24362
+ action: "Narrow the query with a more selective field predicate"
24363
+ });
24364
+ suggestions.push({
24365
+ action: "Retry with a shallower page or smaller result window"
24366
+ });
24367
+ }
24345
24368
  if (code === "AUTH") {
24346
24369
  suggestions.push({
24347
24370
  action: "Re-authenticate",
@@ -24376,6 +24399,7 @@ function shouldLogToErrorTier(err) {
24376
24399
  case "UNKNOWN":
24377
24400
  case "RATE_LIMITED":
24378
24401
  return true;
24402
+ case "QUERY_TOO_EXPENSIVE":
24379
24403
  case "FIELD_NOT_INDEXABLE":
24380
24404
  return false;
24381
24405
  case "FIELD_INDEX_UNAVAILABLE":
@@ -24427,6 +24451,9 @@ function cliErrorFromOpFailure(failure) {
24427
24451
  if (code === "RATE_LIMITED") {
24428
24452
  return make(4 /* Backend */, "RATE_LIMITED", "Rate limited. Wait for the Retry-After window before retrying.");
24429
24453
  }
24454
+ if (code === "QUERY_TOO_EXPENSIVE") {
24455
+ return make(2 /* UserInput */, "QUERY_TOO_EXPENSIVE", "Narrow the query with a more selective field predicate or retry with a shallower page.");
24456
+ }
24430
24457
  return make(4 /* Backend */, "BACKEND");
24431
24458
  }
24432
24459
  function cliErrorFromAllFailed(failures) {
@@ -26640,16 +26667,16 @@ function renderThing(out, c, result) {
26640
26667
  out(` ${c.dim}about:${c.reset} ${String(aboutWref)}`);
26641
26668
  }
26642
26669
  const meta = result.metadata;
26643
- if (meta?.durableId || meta?.thingCreatedAt || meta?.versionCreatedAt) {
26670
+ if (meta?.durableId || meta?.createdOn || meta?.revisedOn) {
26644
26671
  const now = Date.now();
26645
26672
  if (meta.durableId) {
26646
26673
  out(` ${c.dim}durableId:${c.reset} ${meta.durableId}`);
26647
26674
  }
26648
- if (meta.thingCreatedAt) {
26649
- out(` ${c.dim}thingCreated:${c.reset} ${formatTime(meta.thingCreatedAt, now)}`);
26675
+ if (meta.createdOn) {
26676
+ out(` ${c.dim}createdOn:${c.reset} ${formatTime(meta.createdOn, now)}`);
26650
26677
  }
26651
- if (meta.versionCreatedAt) {
26652
- out(` ${c.dim}versionCreated:${c.reset}${formatTime(meta.versionCreatedAt, now)}`);
26678
+ if (meta.revisedOn) {
26679
+ out(` ${c.dim}revisedOn:${c.reset} ${formatTime(meta.revisedOn, now)}`);
26653
26680
  }
26654
26681
  }
26655
26682
  const fields = shapeName && result.data ? collectionFields(shapeName, result.data) : null;
@@ -26762,8 +26789,8 @@ function renderHistory(out, c, result) {
26762
26789
  const wref = ver.wref ?? ver.thingName;
26763
26790
  const wrefStr = wref ? pinnedWref(c, wref, ver.version) : "";
26764
26791
  const by = ver.committerWref ? ` ${c.dim}by${c.reset} ${pinnedWref(c, ver.committerWref)}` : "";
26765
- const thingCreatedAt = ver.metadata?.thingCreatedAt;
26766
- const thingCreatedStr = thingCreatedAt ? ` ${c.dim}born:${formatTime(thingCreatedAt, now)}${c.reset}` : "";
26792
+ const createdOn = ver.metadata?.createdOn;
26793
+ const thingCreatedStr = createdOn ? ` ${c.dim}born:${formatTime(createdOn, now)}${c.reset}` : "";
26767
26794
  out(` ${wrefStr} ${op} ${c.dim}${time}${c.reset}${by}${thingCreatedStr}`);
26768
26795
  }
26769
26796
  }
@@ -31087,7 +31114,7 @@ var handleTemplate = async (ctx, { flags, args }) => {
31087
31114
  if (operationType !== "add" && operationType !== "revise" && operationType !== "retract") {
31088
31115
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --operation "${operationType}". Must be "add", "revise", or "retract".`);
31089
31116
  }
31090
- const validKinds = operationType === "retract" ? ["thing", "assertion", "shape", "collection"] : ["thing", "assertion"];
31117
+ const validKinds = operationType === "retract" ? COMMIT_OPERATION_KINDS : ["thing", "assertion"];
31091
31118
  if (!validKinds.includes(flags.kind ?? "thing")) {
31092
31119
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind "${flags.kind}". Must be one of: ${validKinds.join(", ")}.`);
31093
31120
  }
@@ -31432,7 +31459,11 @@ var GLOBAL_FLAGS = [
31432
31459
  description: "Output mode: pretty|json (default: pretty)"
31433
31460
  },
31434
31461
  { long: "json", type: "boolean", description: "Alias for --format json" },
31435
- { long: "live", type: "boolean", description: "Reactive WebSocket mode" },
31462
+ {
31463
+ long: "live",
31464
+ type: "boolean",
31465
+ description: "Live mode (polls for updates)"
31466
+ },
31436
31467
  {
31437
31468
  long: "max-updates",
31438
31469
  type: "number",
@@ -33820,7 +33851,7 @@ async function collectChecks(ctx) {
33820
33851
  name: "compatibility",
33821
33852
  status: "fail",
33822
33853
  message: `SDK v${SDK_VERSION} is older than minimum supported ${caps.minSupportedSdk} (apiVersion: ${caps.apiVersion})`,
33823
- fix: "Update with: bun install @warmhub/cli@latest"
33854
+ fix: "Update with: wh update --yes"
33824
33855
  });
33825
33856
  } else {
33826
33857
  checks.push({
@@ -36471,10 +36502,19 @@ function renderSubscriptionLog(out, statusOut, c, subscriptionName, result) {
36471
36502
  }
36472
36503
  }
36473
36504
  }
36505
+ var orgScopeFlag = flag.string({
36506
+ description: "Org slug for an org-scoped subscription (org.renamed); use instead of --repo"
36507
+ });
36474
36508
  var createFlags8 = {
36475
36509
  on: flag.string({
36476
36510
  description: "Shape to subscribe to"
36477
36511
  }),
36512
+ event: flag.string({
36513
+ description: "Event to watch: commit (default), repo.renamed, or org.renamed"
36514
+ }),
36515
+ org: flag.string({
36516
+ description: "Org slug for an org-scoped subscription (org.renamed)"
36517
+ }),
36478
36518
  kind: flag.string({
36479
36519
  description: "Subscription kind (webhook; the default)"
36480
36520
  }),
@@ -36519,18 +36559,34 @@ var updateFlags4 = {
36519
36559
  description: "Clear the fallback webhook URL"
36520
36560
  }),
36521
36561
  "allow-trace-reentry": createFlags8["allow-trace-reentry"],
36522
- name: createFlags8.name
36562
+ name: createFlags8.name,
36563
+ org: orgScopeFlag
36523
36564
  };
36524
36565
  var logFlags = {
36525
36566
  limit: flag.number({ description: "Max deliveries to return" })
36526
36567
  };
36527
36568
  var listFlags5 = {
36528
- limit: flag.number({ description: "Max subscriptions to return" })
36569
+ limit: flag.number({ description: "Max subscriptions to return" }),
36570
+ org: orgScopeFlag
36571
+ };
36572
+ function resolveSubScope(ctx, flags) {
36573
+ if (typeof flags.org === "string" && flags.org) {
36574
+ return { orgName: flags.org };
36575
+ }
36576
+ const { org, repo } = resolveRepoContext(ctx);
36577
+ return { orgName: org, repoName: repo };
36578
+ }
36579
+ function scopeLabel(scope) {
36580
+ return scope.repoName ? `${scope.orgName}/${scope.repoName}` : scope.orgName;
36581
+ }
36582
+ var scopeFlags = {
36583
+ org: orgScopeFlag
36529
36584
  };
36530
36585
  var viewFlags5 = {
36531
36586
  "show-secrets": flag.boolean({
36532
36587
  description: "Reveal the raw webhook URL(s) instead of the redacted origin (audit-logged)"
36533
- })
36588
+ }),
36589
+ org: orgScopeFlag
36534
36590
  };
36535
36591
  function buildSubscriptionPatchArgs(flags, usage, example) {
36536
36592
  const args = {};
@@ -36576,22 +36632,83 @@ function buildSubscriptionMutationArgs(flags, usage, example) {
36576
36632
  }
36577
36633
  return mutationArgs;
36578
36634
  }
36635
+ function parseEventType(raw, _usage, example) {
36636
+ if (raw === undefined) {
36637
+ return COMMIT_EVENT_TYPE;
36638
+ }
36639
+ if (SUBSCRIBABLE_EVENT_TYPES.includes(raw)) {
36640
+ return raw;
36641
+ }
36642
+ usageError(`--event must be one of: ${SUBSCRIBABLE_EVENT_TYPES.join(", ")}`, example);
36643
+ }
36644
+ function rejectCommitFlags(flags, eventType) {
36645
+ for (const f of ["on", "filter", "source"]) {
36646
+ const v = flags[f];
36647
+ if (typeof v === "string" && v.length > 0) {
36648
+ usageError(`--${f} is not valid for ${eventType} subscriptions — rename events have no shape or filter`, `wh sub create rename-hook --event ${eventType} --webhook-url https://example.com/hook`);
36649
+ }
36650
+ }
36651
+ }
36579
36652
  var handleCreate7 = async (ctx, { flags, args }) => {
36580
36653
  const name = args[0] ?? flags.name;
36581
- const usage = "Usage: wh sub create <name> --repo org/repo [--kind webhook] [options]";
36654
+ const usage = "Usage: wh sub create <name> (--repo org/repo | --org org) [--event commit|repo.renamed|org.renamed] [options]";
36582
36655
  const example = `wh sub create signal-hook --repo myorg/myrepo --on Signal --filter '{"shape":"Signal"}' --webhook-url https://example.com/hook`;
36583
36656
  if (!name) {
36584
36657
  usageError(usage, example);
36585
36658
  }
36586
36659
  rejectRemovedCronFlags(flags);
36587
36660
  const kind = parseKind(flags.kind, usage, example);
36588
- const { org, repo } = resolveRepoContext(ctx);
36589
- const createArgs = buildSubscriptionMutationArgs(flags, usage, example);
36590
- const sourceRepoRef = typeof flags.source === "string" ? flags.source : undefined;
36591
- const webhookUrl = createArgs.webhookUrl;
36661
+ const eventType = parseEventType(flags.event, usage, example);
36662
+ const webhookUrl = typeof flags["webhook-url"] === "string" ? flags["webhook-url"] : typeof flags.url === "string" ? flags.url : undefined;
36592
36663
  if (!webhookUrl) {
36593
36664
  usageError(usage, example);
36594
36665
  }
36666
+ const fallbackWebhookUrl = typeof flags["fallback-webhook-url"] === "string" ? flags["fallback-webhook-url"] : undefined;
36667
+ const allowTraceReentry = flags["allow-trace-reentry"] === true;
36668
+ const renameExtras = {
36669
+ ...fallbackWebhookUrl ? { fallbackWebhookUrl } : {},
36670
+ ...allowTraceReentry ? { allowTraceReentry: true } : {}
36671
+ };
36672
+ if (eventType === "org.renamed") {
36673
+ const orgName = typeof flags.org === "string" ? flags.org : undefined;
36674
+ if (!orgName) {
36675
+ usageError("org.renamed subscriptions are org-scoped — pass --org <org> (not --repo)", "wh sub create org-rename-hook --org myorg --event org.renamed --webhook-url https://example.com/hook");
36676
+ }
36677
+ rejectCommitFlags(flags, eventType);
36678
+ const result2 = await ctx.client.subscription.create({
36679
+ orgName,
36680
+ name,
36681
+ eventType,
36682
+ kind,
36683
+ webhookUrl,
36684
+ ...renameExtras
36685
+ });
36686
+ writeOutput(ctx, result2, () => {
36687
+ const c = ctx.colors;
36688
+ ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on org ${c.cyan}${orgName}${c.reset} (org.renamed)`);
36689
+ });
36690
+ return;
36691
+ }
36692
+ const { org, repo } = resolveRepoContext(ctx);
36693
+ if (eventType === "repo.renamed") {
36694
+ rejectCommitFlags(flags, eventType);
36695
+ const result2 = await ctx.client.subscription.create({
36696
+ orgName: org,
36697
+ repoName: repo,
36698
+ name,
36699
+ eventType,
36700
+ kind,
36701
+ webhookUrl,
36702
+ ...renameExtras
36703
+ });
36704
+ writeOutput(ctx, result2, () => {
36705
+ const c = ctx.colors;
36706
+ ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset} (repo.renamed)`);
36707
+ });
36708
+ return;
36709
+ }
36710
+ const createArgs = buildSubscriptionMutationArgs(flags, usage, example);
36711
+ const sourceRepoRef = typeof flags.source === "string" ? flags.source : undefined;
36595
36712
  const result = await ctx.client.subscription.create({
36596
36713
  orgName: org,
36597
36714
  repoName: repo,
@@ -36611,24 +36728,24 @@ var handleCreate7 = async (ctx, { flags, args }) => {
36611
36728
  };
36612
36729
  var handleUpdate4 = async (ctx, { flags, args }) => {
36613
36730
  const name = args[0] ?? flags.name;
36614
- const usage = "Usage: wh sub update <name> --repo org/repo [options]";
36731
+ const usage = "Usage: wh sub update <name> (--repo org/repo | --org org) [options]";
36615
36732
  const example = "wh sub update signal-hook --repo myorg/myrepo";
36616
36733
  if (!name) {
36617
36734
  usageError(usage, example);
36618
36735
  }
36619
36736
  rejectRemovedCronFlags(flags);
36620
- const { org, repo } = resolveRepoContext(ctx);
36621
- const existing = await ctx.client.subscription.get(org, repo, name);
36737
+ const scope = resolveSubScope(ctx, flags);
36738
+ const scopeArg = scope.repoName ? `--repo ${scopeLabel(scope)}` : `--org ${scope.orgName}`;
36739
+ const existing = await ctx.client.subscription.get({ ...scope, name });
36622
36740
  if (existing.kind !== "webhook") {
36623
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Subscription "${name}" has kind "${existing.kind}", which is no longer supported and cannot be updated`, undefined, `Delete it with: wh sub delete ${name} --repo ${org}/${repo}`);
36741
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Subscription "${name}" has kind "${existing.kind}", which is no longer supported and cannot be updated`, undefined, `Delete it with: wh sub delete ${name} ${scopeArg}`);
36624
36742
  }
36625
36743
  if (flags.kind && flags.kind !== existing.kind) {
36626
36744
  usageError(usage, example);
36627
36745
  }
36628
36746
  const patchArgs = buildSubscriptionPatchArgs(flags, usage, example);
36629
36747
  const result = await ctx.client.subscription.update({
36630
- orgName: org,
36631
- repoName: repo,
36748
+ ...scope,
36632
36749
  name,
36633
36750
  ...patchArgs.shapeName != null ? { shapeName: patchArgs.shapeName } : {},
36634
36751
  ...patchArgs.filterJson != null ? {
@@ -36642,17 +36759,17 @@ var handleUpdate4 = async (ctx, { flags, args }) => {
36642
36759
  });
36643
36760
  writeOutput(ctx, result, () => {
36644
36761
  const c = ctx.colors;
36645
- ctx.status(`${c.green}Updated subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset}`);
36762
+ ctx.status(`${c.green}Updated subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${scopeLabel(scope)}${c.reset}`);
36646
36763
  });
36647
36764
  };
36648
36765
  var handleView8 = async (ctx, { args, flags }) => {
36649
36766
  const name = args[0];
36650
36767
  if (!name) {
36651
- usageError("Usage: wh sub view <name> [--show-secrets] [--repo org/repo]", "wh sub view signal-hook --repo myorg/myrepo");
36768
+ usageError("Usage: wh sub view <name> [--show-secrets] (--repo org/repo | --org org)", "wh sub view signal-hook --repo myorg/myrepo");
36652
36769
  }
36653
- const { org, repo } = resolveRepoContext(ctx);
36654
- const sub = await ctx.client.subscription.get(org, repo, name);
36655
- const revealed = flags["show-secrets"] ? await ctx.client.subscription.reveal(org, repo, name) : undefined;
36770
+ const scope = resolveSubScope(ctx, flags);
36771
+ const sub = await ctx.client.subscription.get({ ...scope, name });
36772
+ const revealed = flags["show-secrets"] ? await ctx.client.subscription.reveal({ ...scope, name }) : undefined;
36656
36773
  writeOutput(ctx, revealed ? { ...sub, ...revealed } : sub, () => {
36657
36774
  const c = ctx.colors;
36658
36775
  ctx.out(`${c.bold}${sub.name}${c.reset}`);
@@ -36679,16 +36796,17 @@ var handleView8 = async (ctx, { args, flags }) => {
36679
36796
  });
36680
36797
  };
36681
36798
  var handleList7 = async (ctx, { flags }) => {
36682
- const { org, repo } = resolveRepoContext(ctx);
36683
- const all = await ctx.client.subscription.list(org, repo);
36799
+ const scope = resolveSubScope(ctx, flags);
36800
+ const label = scopeLabel(scope);
36801
+ const all = await ctx.client.subscription.list(scope);
36684
36802
  const items = all.slice(0, flags.limit ?? all.length);
36685
36803
  writePageOutput(ctx, items, { limit: flags.limit ?? all.length, nextCursor: null }, () => {
36686
36804
  const c = ctx.colors;
36687
36805
  if (!items.length) {
36688
- ctx.status(`${c.dim}No subscriptions in ${org}/${repo}${c.reset}`);
36806
+ ctx.status(`${c.dim}No subscriptions in ${label}${c.reset}`);
36689
36807
  return;
36690
36808
  }
36691
- ctx.out(`${c.bold}Subscriptions:${c.reset} ${c.cyan}${org}/${repo}${c.reset}`);
36809
+ ctx.out(`${c.bold}Subscriptions:${c.reset} ${c.cyan}${label}${c.reset}`);
36692
36810
  for (const sub of items) {
36693
36811
  const active = sub.active ? `${c.green}active` : `${c.yellow}paused`;
36694
36812
  let line = ` ${c.cyan}${sub.name}${c.reset} ${c.dim}[${sub.kind}]${c.reset} ${active}${c.reset}`;
@@ -36699,37 +36817,37 @@ var handleList7 = async (ctx, { flags }) => {
36699
36817
  }
36700
36818
  });
36701
36819
  };
36702
- var handlePause = async (ctx, { args }) => {
36820
+ var handlePause = async (ctx, { args, flags }) => {
36703
36821
  const name = args[0];
36704
36822
  if (!name) {
36705
- usageError("Usage: wh sub pause <name> [--repo org/repo]", "wh sub pause signal-hook --repo myorg/myrepo");
36823
+ usageError("Usage: wh sub pause <name> (--repo org/repo | --org org)", "wh sub pause signal-hook --repo myorg/myrepo");
36706
36824
  }
36707
- const { org, repo } = resolveRepoContext(ctx);
36708
- const result = await ctx.client.subscription.pause(org, repo, name);
36825
+ const scope = resolveSubScope(ctx, flags);
36826
+ const result = await ctx.client.subscription.pause({ ...scope, name });
36709
36827
  writeOutput(ctx, result, () => {
36710
36828
  const c = ctx.colors;
36711
36829
  ctx.status(`${c.yellow}Paused subscription${c.reset} ${c.cyan}${name}${c.reset}`);
36712
36830
  });
36713
36831
  };
36714
- var handleResume = async (ctx, { args }) => {
36832
+ var handleResume = async (ctx, { args, flags }) => {
36715
36833
  const name = args[0];
36716
36834
  if (!name) {
36717
- usageError("Usage: wh sub resume <name> [--repo org/repo]", "wh sub resume signal-hook --repo myorg/myrepo");
36835
+ usageError("Usage: wh sub resume <name> (--repo org/repo | --org org)", "wh sub resume signal-hook --repo myorg/myrepo");
36718
36836
  }
36719
- const { org, repo } = resolveRepoContext(ctx);
36720
- const result = await ctx.client.subscription.resume(org, repo, name);
36837
+ const scope = resolveSubScope(ctx, flags);
36838
+ const result = await ctx.client.subscription.resume({ ...scope, name });
36721
36839
  writeOutput(ctx, result, () => {
36722
36840
  const c = ctx.colors;
36723
36841
  ctx.status(`${c.green}Resumed subscription${c.reset} ${c.cyan}${name}${c.reset}`);
36724
36842
  });
36725
36843
  };
36726
- var handleDelete3 = async (ctx, { args }) => {
36844
+ var handleDelete3 = async (ctx, { args, flags }) => {
36727
36845
  const name = args[0];
36728
36846
  if (!name) {
36729
- usageError("Usage: wh sub delete <name> [--repo org/repo]", "wh sub delete signal-hook --repo myorg/myrepo");
36847
+ usageError("Usage: wh sub delete <name> (--repo org/repo | --org org)", "wh sub delete signal-hook --repo myorg/myrepo");
36730
36848
  }
36731
- const { org, repo } = resolveRepoContext(ctx);
36732
- const result = await ctx.client.subscription.remove(org, repo, name);
36849
+ const scope = resolveSubScope(ctx, flags);
36850
+ const result = await ctx.client.subscription.remove({ ...scope, name });
36733
36851
  writeOutput(ctx, result, () => {
36734
36852
  const c = ctx.colors;
36735
36853
  ctx.status(`${c.red}Deleted subscription${c.reset} ${c.cyan}${name}${c.reset}`);
@@ -36738,28 +36856,36 @@ var handleDelete3 = async (ctx, { args }) => {
36738
36856
  var bindFlags = {
36739
36857
  credentials: flag.string({
36740
36858
  description: "Name of the credential set to bind"
36741
- })
36859
+ }),
36860
+ org: orgScopeFlag
36742
36861
  };
36743
36862
  var handleBind = async (ctx, { flags, args }) => {
36744
36863
  const name = args[0];
36745
36864
  const setName = flags.credentials;
36746
36865
  if (!name || !setName) {
36747
- usageError("Usage: wh sub bind <name> --credentials <setName> [--repo org/repo]", "wh sub bind signal-hook --credentials webhook-keys --repo myorg/myrepo");
36866
+ usageError("Usage: wh sub bind <name> --credentials <setName> (--repo org/repo | --org org)", "wh sub bind signal-hook --credentials webhook-keys --repo myorg/myrepo");
36748
36867
  }
36749
- const { org, repo } = resolveRepoContext(ctx);
36750
- const result = await ctx.client.subscription.bindCredentials(org, repo, name, setName);
36868
+ const scope = resolveSubScope(ctx, flags);
36869
+ const result = await ctx.client.subscription.bindCredentials({
36870
+ ...scope,
36871
+ subscriptionName: name,
36872
+ credentialSetName: setName
36873
+ });
36751
36874
  writeOutput(ctx, result, () => {
36752
36875
  const c = ctx.colors;
36753
36876
  ctx.status(`${c.green}Bound${c.reset} ${c.cyan}${setName}${c.reset} to ${c.cyan}${name}${c.reset}`);
36754
36877
  });
36755
36878
  };
36756
- var handleUnbind = async (ctx, { args }) => {
36879
+ var handleUnbind = async (ctx, { args, flags }) => {
36757
36880
  const name = args[0];
36758
36881
  if (!name) {
36759
- usageError("Usage: wh sub unbind <name> [--repo org/repo]", "wh sub unbind signal-hook --repo myorg/myrepo");
36882
+ usageError("Usage: wh sub unbind <name> (--repo org/repo | --org org)", "wh sub unbind signal-hook --repo myorg/myrepo");
36760
36883
  }
36761
- const { org, repo } = resolveRepoContext(ctx);
36762
- const result = await ctx.client.subscription.unbindCredentials(org, repo, name);
36884
+ const scope = resolveSubScope(ctx, flags);
36885
+ const result = await ctx.client.subscription.unbindCredentials({
36886
+ ...scope,
36887
+ subscriptionName: name
36888
+ });
36763
36889
  writeOutput(ctx, result, () => {
36764
36890
  const c = ctx.colors;
36765
36891
  ctx.status(`${c.yellow}Unbound${c.reset} credentials from ${c.cyan}${name}${c.reset}`);
@@ -36844,6 +36970,12 @@ var SUB_DOMAIN = defineDomain({
36844
36970
  "# Subscribe to shape retracts only",
36845
36971
  ` $ wh sub create shape-retracts --repo myorg/myrepo --kind webhook --filter '{"all":[{"kind":"shape"},{"operation":"retract"}]}' --webhook-url https://hooks.example.com/shapes`,
36846
36972
  "",
36973
+ "# Subscribe to repo renames (metadata event — no shape/filter)",
36974
+ " $ wh sub create repo-rename-hook --repo myorg/myrepo --event repo.renamed --webhook-url https://example.com/hook",
36975
+ "",
36976
+ "# Subscribe to org renames (org-scoped — use --org, not --repo)",
36977
+ " $ wh sub create org-rename-hook --org myorg --event org.renamed --webhook-url https://example.com/hook",
36978
+ "",
36847
36979
  "# Webhook auth: create a credential set with WEBHOOK_* keys, then bind it to the subscription.",
36848
36980
  "# See `wh credential set --help` for supported key names and `wh sub bind --help`.",
36849
36981
  " $ wh credential create webhook-keys --repo myorg/myrepo",
@@ -36860,7 +36992,9 @@ var SUB_DOMAIN = defineDomain({
36860
36992
  flags: updateFlags4,
36861
36993
  examples: [
36862
36994
  "# Update only the webhook URL",
36863
- " $ wh sub update signal-hook --repo myorg/myrepo --webhook-url https://example.com/v2/hook"
36995
+ " $ wh sub update signal-hook --repo myorg/myrepo --webhook-url https://example.com/v2/hook",
36996
+ "# Repoint an org-scoped (org.renamed) rename hook in place",
36997
+ " $ wh sub update org-rename-hook --org myorg --webhook-url https://example.com/v2/hook"
36864
36998
  ],
36865
36999
  handler: handleUpdate4
36866
37000
  },
@@ -36872,7 +37006,9 @@ var SUB_DOMAIN = defineDomain({
36872
37006
  flags: viewFlags5,
36873
37007
  examples: [
36874
37008
  "wh sub view signal-hook --repo myorg/myrepo",
36875
- "wh sub view signal-hook --show-secrets --repo myorg/myrepo"
37009
+ "wh sub view signal-hook --show-secrets --repo myorg/myrepo",
37010
+ "# Org-scoped (org.renamed) subscription",
37011
+ " $ wh sub view org-rename-hook --org myorg"
36876
37012
  ],
36877
37013
  handler: handleView8
36878
37014
  },
@@ -36882,7 +37018,12 @@ var SUB_DOMAIN = defineDomain({
36882
37018
  summary: "List all subscriptions",
36883
37019
  args: "",
36884
37020
  flags: listFlags5,
36885
- examples: ["wh sub list --repo myorg/myrepo", "wh sub list --limit 10"],
37021
+ examples: [
37022
+ "wh sub list --repo myorg/myrepo",
37023
+ "wh sub list --limit 10",
37024
+ "# Org-scoped (org.renamed) subscriptions",
37025
+ " $ wh sub list --org myorg"
37026
+ ],
36886
37027
  handler: handleList7
36887
37028
  },
36888
37029
  log: {
@@ -36922,7 +37063,12 @@ var SUB_DOMAIN = defineDomain({
36922
37063
  prime: true,
36923
37064
  summary: "Pause a subscription",
36924
37065
  args: "<name>",
36925
- examples: ["wh sub pause signal-hook --repo myorg/myrepo"],
37066
+ flags: scopeFlags,
37067
+ examples: [
37068
+ "wh sub pause signal-hook --repo myorg/myrepo",
37069
+ "# Org-scoped (org.renamed) subscription",
37070
+ " $ wh sub pause org-rename-hook --org myorg"
37071
+ ],
36926
37072
  handler: handlePause
36927
37073
  },
36928
37074
  resume: {
@@ -36930,7 +37076,11 @@ var SUB_DOMAIN = defineDomain({
36930
37076
  prime: true,
36931
37077
  summary: "Resume a paused subscription",
36932
37078
  args: "<name>",
36933
- examples: ["wh sub resume signal-hook --repo myorg/myrepo"],
37079
+ flags: scopeFlags,
37080
+ examples: [
37081
+ "wh sub resume signal-hook --repo myorg/myrepo",
37082
+ " $ wh sub resume org-rename-hook --org myorg"
37083
+ ],
36934
37084
  handler: handleResume
36935
37085
  },
36936
37086
  bind: {
@@ -36941,7 +37091,9 @@ var SUB_DOMAIN = defineDomain({
36941
37091
  flags: bindFlags,
36942
37092
  examples: [
36943
37093
  "# Bind credentials to inject auth headers on webhook delivery",
36944
- " $ wh sub bind signal-hook --credentials webhook-keys --repo myorg/myrepo"
37094
+ " $ wh sub bind signal-hook --credentials webhook-keys --repo myorg/myrepo",
37095
+ "# Org-scoped (org.renamed) subscription + org-scoped credential set",
37096
+ " $ wh sub bind org-rename-hook --credentials org-webhook-keys --org myorg"
36945
37097
  ],
36946
37098
  handler: handleBind
36947
37099
  },
@@ -36950,7 +37102,11 @@ var SUB_DOMAIN = defineDomain({
36950
37102
  prime: true,
36951
37103
  summary: "Remove credential binding from a subscription",
36952
37104
  args: "<name>",
36953
- examples: ["wh sub unbind signal-hook --repo myorg/myrepo"],
37105
+ flags: scopeFlags,
37106
+ examples: [
37107
+ "wh sub unbind signal-hook --repo myorg/myrepo",
37108
+ " $ wh sub unbind org-rename-hook --org myorg"
37109
+ ],
36954
37110
  handler: handleUnbind
36955
37111
  },
36956
37112
  delete: {
@@ -36958,7 +37114,11 @@ var SUB_DOMAIN = defineDomain({
36958
37114
  prime: true,
36959
37115
  summary: "Delete a subscription",
36960
37116
  args: "<name>",
36961
- examples: ["wh sub delete signal-hook --repo myorg/myrepo"],
37117
+ flags: scopeFlags,
37118
+ examples: [
37119
+ "wh sub delete signal-hook --repo myorg/myrepo",
37120
+ " $ wh sub delete org-rename-hook --org myorg"
37121
+ ],
36962
37122
  handler: handleDelete3
36963
37123
  }
36964
37124
  }
@@ -37249,7 +37409,7 @@ var TOKEN_DOMAIN = defineDomain({
37249
37409
 
37250
37410
  // ../../packages/warmhub-cli/src/domains/update.ts
37251
37411
  import { spawnSync as spawnSync2 } from "node:child_process";
37252
- import { existsSync as existsSync7, readFileSync as readFileSync10 } from "node:fs";
37412
+ import { existsSync as existsSync7, readFileSync as readFileSync10, realpathSync } from "node:fs";
37253
37413
  import { homedir as homedir6 } from "node:os";
37254
37414
  import { dirname as dirname8, resolve as resolve4 } from "node:path";
37255
37415
 
@@ -37398,10 +37558,144 @@ var resolveUpdateStatus = async (currentVersion, deps = {}) => {
37398
37558
  cacheHit
37399
37559
  };
37400
37560
  };
37401
- var defaultRunInstall = (latestVersion, registry2) => {
37402
- const proc = spawnSync2("npm", ["install", "-g", `@warmhub/cli@${latestVersion}`, "--registry", registry2], { stdio: "inherit", timeout: 120000 });
37561
+ var normalizePath = (path2) => path2 ? path2.replaceAll("\\", "/") : "";
37562
+ var pathStartsWith = (path2, prefix) => {
37563
+ if (!prefix)
37564
+ return false;
37565
+ const normalizedPath = normalizePath(path2);
37566
+ const normalizedPrefix = normalizePath(prefix).replace(/\/+$/, "");
37567
+ return normalizedPath === normalizedPrefix || normalizedPath.startsWith(`${normalizedPrefix}/`);
37568
+ };
37569
+ var homeRelative = (homePath, suffix) => `${homePath.replace(/\/+$/, "")}/${suffix.replace(/^\/+/, "")}`;
37570
+ var getActiveWhLookupCommand = (platform2 = process.platform) => platform2 === "win32" ? { command: "where.exe", args: ["wh"] } : { command: "sh", args: ["-lc", "command -v wh"] };
37571
+ var resolveActiveWh = (deps = {}) => {
37572
+ const env = deps.env ?? process.env;
37573
+ const lookup = getActiveWhLookupCommand(deps.platform);
37574
+ const spawn = deps.spawn ?? spawnSync2;
37575
+ const realpath = deps.realpath ?? realpathSync.native;
37576
+ const proc = spawn(lookup.command, lookup.args, {
37577
+ encoding: "utf8",
37578
+ env,
37579
+ timeout: 5000
37580
+ });
37581
+ const activePath = proc.status === 0 ? proc.stdout.split(/\r?\n/).map((line) => line.trim()).find(Boolean) : undefined;
37582
+ let realPath;
37583
+ if (activePath) {
37584
+ try {
37585
+ realPath = realpath(activePath);
37586
+ } catch {
37587
+ realPath = activePath;
37588
+ }
37589
+ }
37590
+ return { activePath, realPath };
37591
+ };
37592
+ var classifyActiveInstallManager = ({
37593
+ activePath,
37594
+ realPath,
37595
+ env = process.env,
37596
+ homePath = homedir6()
37597
+ }) => {
37598
+ if (!activePath)
37599
+ return;
37600
+ const active = normalizePath(activePath);
37601
+ const real = normalizePath(realPath ?? activePath);
37602
+ const paths = [active, real];
37603
+ const bunInstall = env.BUN_INSTALL ?? homeRelative(homePath, ".bun");
37604
+ const pnpmHome = env.PNPM_HOME;
37605
+ const windowsPnpmHome = env.LOCALAPPDATA ? `${env.LOCALAPPDATA}/pnpm` : undefined;
37606
+ const npmPrefix = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
37607
+ const windowsNpmHome = env.APPDATA ? `${env.APPDATA}/npm` : undefined;
37608
+ if (paths.some((path2) => pathStartsWith(path2, homeRelative(homePath, ".bun/bin")) || pathStartsWith(path2, homeRelative(homePath, ".bun/install/global")) || pathStartsWith(path2, `${bunInstall}/bin`) || pathStartsWith(path2, `${bunInstall}/install/global`))) {
37609
+ return "bun";
37610
+ }
37611
+ if (paths.some((path2) => pathStartsWith(path2, pnpmHome) || pathStartsWith(path2, windowsPnpmHome) || path2.includes("/pnpm-global/") || path2.includes("/.local/share/pnpm/") || path2.includes("/Library/pnpm/") || path2.includes("/AppData/Local/pnpm/") || path2.includes("/node_modules/.pnpm/"))) {
37612
+ return "pnpm";
37613
+ }
37614
+ if (paths.some((path2) => pathStartsWith(path2, npmPrefix) || pathStartsWith(path2, windowsNpmHome) || path2.includes("/lib/node_modules/@warmhub/cli/") || path2.includes("/AppData/Roaming/npm/") || path2.includes("/node_modules/@warmhub/cli/"))) {
37615
+ return "npm";
37616
+ }
37617
+ return;
37618
+ };
37619
+ var buildManualCommand = (manager, latestVersion, registry2) => {
37620
+ const spec = `${WH_CACHE_PACKAGE_NAME}@${latestVersion}`;
37621
+ switch (manager) {
37622
+ case "bun":
37623
+ return `bun add -g ${spec} --registry ${registry2}`;
37624
+ case "pnpm":
37625
+ return `pnpm add -g ${spec} --registry ${registry2}`;
37626
+ case "npm":
37627
+ return `npm install -g ${spec} --registry ${registry2}`;
37628
+ }
37629
+ };
37630
+ var buildInstallPlan = (manager, latestVersion, registry2, activePath, realPath) => {
37631
+ const spec = `${WH_CACHE_PACKAGE_NAME}@${latestVersion}`;
37632
+ const manualCommand = buildManualCommand(manager, latestVersion, registry2);
37633
+ switch (manager) {
37634
+ case "bun":
37635
+ return {
37636
+ manager,
37637
+ activePath,
37638
+ realPath,
37639
+ command: "bun",
37640
+ args: ["add", "-g", spec, "--registry", registry2],
37641
+ manualCommand
37642
+ };
37643
+ case "pnpm":
37644
+ return {
37645
+ manager,
37646
+ activePath,
37647
+ realPath,
37648
+ command: "pnpm",
37649
+ args: ["add", "-g", spec, "--registry", registry2],
37650
+ manualCommand
37651
+ };
37652
+ case "npm":
37653
+ return {
37654
+ manager,
37655
+ activePath,
37656
+ realPath,
37657
+ command: "npm",
37658
+ args: ["install", "-g", spec, "--registry", registry2],
37659
+ manualCommand
37660
+ };
37661
+ }
37662
+ };
37663
+ var defaultRunInstall = (plan) => {
37664
+ const proc = spawnSync2(plan.command, plan.args, {
37665
+ stdio: "inherit",
37666
+ timeout: 120000
37667
+ });
37403
37668
  return { status: proc.status, signal: proc.signal, error: proc.error };
37404
37669
  };
37670
+ var verifyActiveVersion = (activePath, deps = {}) => {
37671
+ const platform2 = deps.platform ?? process.platform;
37672
+ const spawn = deps.spawn ?? spawnSync2;
37673
+ const shell = platform2 === "win32" && /\.(?:cmd|bat)$/i.test(normalizePath(activePath));
37674
+ const proc = spawn(activePath, ["--version"], {
37675
+ encoding: "utf8",
37676
+ timeout: 15000,
37677
+ ...shell ? { shell: true } : {}
37678
+ });
37679
+ return {
37680
+ status: proc.status,
37681
+ signal: proc.signal,
37682
+ error: proc.error,
37683
+ stdout: proc.stdout,
37684
+ stderr: proc.stderr
37685
+ };
37686
+ };
37687
+ var defaultVerifyActiveVersion = (activePath) => verifyActiveVersion(activePath);
37688
+ var parseVersionOutput = (output) => output?.match(/\b\d+\.\d+\.\d+(?:[-+][^\s]+)?\b/)?.[0];
37689
+ var formatInstallFailureMessage = (plan, result) => result.error ? `${plan.manager} install failed: ${result.error.message}` : result.signal ? `${plan.manager} install terminated by signal ${result.signal}` : `${plan.manager} install exited with status ${result.status}`;
37690
+ var formatUnknownInstallHint = (activePath, realPath, latestVersion, registry2) => [
37691
+ activePath ? `Active wh path: ${activePath}` : "Active wh path: (not found)",
37692
+ realPath && realPath !== activePath ? `Resolved path: ${realPath}` : "",
37693
+ "Install manually with the package manager that owns that path:",
37694
+ ` ${buildManualCommand("npm", latestVersion, registry2)}`,
37695
+ ` ${buildManualCommand("bun", latestVersion, registry2)}`,
37696
+ ` ${buildManualCommand("pnpm", latestVersion, registry2)}`
37697
+ ].filter(Boolean).join(`
37698
+ `);
37405
37699
  var isDevInstall = (scriptPath) => {
37406
37700
  if (!scriptPath)
37407
37701
  return false;
@@ -37461,6 +37755,8 @@ var runUpdate = async (ctx, { flags, args }, deps = {}) => {
37461
37755
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument: '${args[0]}'`, undefined, "'wh update' takes no positional arguments");
37462
37756
  }
37463
37757
  const runInstall = deps.runInstall ?? defaultRunInstall;
37758
+ const verifyActiveVersion2 = deps.verifyActiveVersion ?? defaultVerifyActiveVersion;
37759
+ const resolveActiveInstall = deps.resolveActiveInstall ?? (() => resolveActiveWh({ env: deps.statusDeps?.env }));
37464
37760
  const isDev = deps.isDev ?? isDevInstall;
37465
37761
  const markNotified = deps.markNotified ?? ((latestVersion) => markUpdateNoticeShown({ latestVersion }));
37466
37762
  const scriptPath = deps.scriptPath ?? process.argv[1];
@@ -37486,6 +37782,19 @@ var runUpdate = async (ctx, { flags, args }, deps = {}) => {
37486
37782
  });
37487
37783
  return;
37488
37784
  }
37785
+ const activeInstall = resolveActiveInstall();
37786
+ const activePath = activeInstall.activePath;
37787
+ const realPath = activeInstall.realPath ?? activePath;
37788
+ const manager = classifyActiveInstallManager({
37789
+ activePath,
37790
+ realPath,
37791
+ env: deps.statusDeps?.env,
37792
+ homePath: deps.statusDeps?.homePath
37793
+ });
37794
+ if (!manager || !activePath || !realPath) {
37795
+ throw new CliError(1 /* Runtime */, "UNKNOWN", "Unable to determine which package manager owns the active wh binary.", undefined, formatUnknownInstallHint(activePath, realPath, status.latestVersion, status.registry));
37796
+ }
37797
+ const installPlan = buildInstallPlan(manager, status.latestVersion, status.registry, activePath, realPath);
37489
37798
  if (!flags.yes) {
37490
37799
  const ok = await ctx.confirm?.(`Update @warmhub/cli ${currentVersion} -> ${status.latestVersion}?`);
37491
37800
  if (!ok) {
@@ -37493,9 +37802,22 @@ var runUpdate = async (ctx, { flags, args }, deps = {}) => {
37493
37802
  return;
37494
37803
  }
37495
37804
  }
37496
- const result = runInstall(status.latestVersion, status.registry);
37805
+ const result = runInstall(installPlan);
37497
37806
  if (result.error || result.signal !== null || result.status !== 0 && result.status !== null) {
37498
- throw new CliError(1 /* Runtime */, "UNKNOWN", result.error ? `npm install failed: ${result.error.message}` : result.signal ? `npm install terminated by signal ${result.signal}` : `npm install exited with status ${result.status}`, result.error, `Try running manually: npm install -g @warmhub/cli@${status.latestVersion} --registry ${status.registry}`);
37807
+ throw new CliError(1 /* Runtime */, "UNKNOWN", formatInstallFailureMessage(installPlan, result), result.error, `Try running manually: ${installPlan.manualCommand}`);
37808
+ }
37809
+ const verify = verifyActiveVersion2(activePath);
37810
+ const observedVersion = parseVersionOutput([verify.stdout, verify.stderr].filter(Boolean).join(`
37811
+ `));
37812
+ if (verify.error || verify.signal !== null || verify.status !== 0 && verify.status !== null || observedVersion !== status.latestVersion) {
37813
+ throw new CliError(1 /* Runtime */, "UNKNOWN", observedVersion ? `Updated install, but active wh reports ${observedVersion} instead of ${status.latestVersion}.` : "Updated install, but active wh version could not be verified.", verify.error, [
37814
+ `Active wh path: ${activePath}`,
37815
+ realPath !== activePath ? `Resolved path: ${realPath}` : "",
37816
+ observedVersion ? `Observed version: ${observedVersion}` : "",
37817
+ `Expected version: ${status.latestVersion}`,
37818
+ `Manual command: ${installPlan.manualCommand}`
37819
+ ].filter(Boolean).join(`
37820
+ `));
37499
37821
  }
37500
37822
  markNotified(status.latestVersion);
37501
37823
  ctx.status(`Updated to ${status.latestVersion}.`);
@@ -37671,7 +37993,7 @@ async function checkCompatibility(ctx, domainPath, canonicalVerb, args) {
37671
37993
  try {
37672
37994
  const caps = await ctx.client.diagnostics.capabilities();
37673
37995
  if (isNewerVersion(caps.minSupportedSdk, SDK_VERSION)) {
37674
- throw new CliError(4 /* Backend */, "BACKEND", `Your CLI (SDK v${SDK_VERSION}) is older than the minimum supported version (${caps.minSupportedSdk}).`, undefined, "Update with: bun install @warmhub/cli@latest");
37996
+ throw new CliError(4 /* Backend */, "BACKEND", `Your CLI (SDK v${SDK_VERSION}) is older than the minimum supported version (${caps.minSupportedSdk}).`, undefined, "Update with: wh update --yes");
37675
37997
  }
37676
37998
  } catch (err) {
37677
37999
  if (err instanceof CliError)
@@ -37714,7 +38036,7 @@ var GLOBAL_FLAGS2 = [
37714
38036
  {
37715
38037
  long: "live",
37716
38038
  type: "boolean",
37717
- description: "Reactive WebSocket mode"
38039
+ description: "Live mode (polls for updates)"
37718
38040
  },
37719
38041
  {
37720
38042
  long: "max-updates",
@@ -38737,7 +39059,7 @@ function resolveLogLevel(flags, env) {
38737
39059
  // package.json
38738
39060
  var package_default3 = {
38739
39061
  name: "@warmhub/cli",
38740
- version: "0.58.0",
39062
+ version: "0.60.0",
38741
39063
  private: false,
38742
39064
  type: "module",
38743
39065
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -39378,4 +39700,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
39378
39700
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
39379
39701
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
39380
39702
 
39381
- //# debugId=53E5AABF4D88726F64756E2164756E21
39703
+ //# debugId=E83ADE028217301D64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.58.0",
3
+ "version": "0.60.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.",