@whop/cli 0.0.5 → 0.1.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.
package/dist/index.js CHANGED
@@ -8,9 +8,12 @@ import {
8
8
  Profile,
9
9
  PromptCancelledError,
10
10
  apiBaseUrl,
11
+ buildTarget,
11
12
  chooseAuthMethod,
13
+ configDir,
12
14
  createWhopFetch,
13
15
  deriveProfileName,
16
+ detectChannel,
14
17
  filterSpecByTag,
15
18
  getActiveProfile,
16
19
  getSecret,
@@ -20,6 +23,7 @@ import {
20
23
  performOAuthLogin,
21
24
  promptApiKey,
22
25
  readConfig,
26
+ removeAllProfiles,
23
27
  removeProfile,
24
28
  resolveActiveCompanyId,
25
29
  selectProfile,
@@ -27,10 +31,10 @@ import {
27
31
  switchProfile,
28
32
  upsertProfile,
29
33
  validateApiKey
30
- } from "./chunk-O66TV7ZF.js";
34
+ } from "./chunk-ET6QSHSA.js";
31
35
  import {
32
36
  external_exports
33
- } from "./chunk-TZPTBY4K.js";
37
+ } from "./chunk-KFCNNWPI.js";
34
38
 
35
39
  // src/api/groups.json
36
40
  var groups_default = [
@@ -90,6 +94,14 @@ var groups_default = [
90
94
  "referrals",
91
95
  "Referrals"
92
96
  ],
97
+ [
98
+ "people",
99
+ "People"
100
+ ],
101
+ [
102
+ "events",
103
+ "Events"
104
+ ],
93
105
  [
94
106
  "ads",
95
107
  "Ads"
@@ -132,10 +144,11 @@ var loginOutput = external_exports.object({
132
144
  identity: Identity.describe("The authenticated account or user identity")
133
145
  });
134
146
  var logoutOptions = external_exports.object({
135
- profile: external_exports.string().optional().describe("Profile to remove (defaults to the active profile)")
147
+ profile: external_exports.string().optional().describe("Profile to remove (defaults to the active profile)"),
148
+ all: external_exports.boolean().optional().describe("Remove every profile and its stored secret (full reset)")
136
149
  });
137
150
  var logoutOutput = external_exports.object({
138
- removed: external_exports.string().describe("The removed profile name"),
151
+ removed: external_exports.array(external_exports.string()).describe("The removed profile name(s)"),
139
152
  newActive: external_exports.string().nullable().describe("The profile that is now active, if any")
140
153
  });
141
154
  var statusOutput = external_exports.object({
@@ -297,9 +310,9 @@ async function loginAdapter(c2) {
297
310
  const companyId = getActiveProfile()?.companyId ?? "";
298
311
  if (companyId) {
299
312
  try {
300
- const { createWhopFetch: createWhopFetch2 } = await import("./api-NBD5G47Q.js");
301
- const fetch2 = createWhopFetch2();
302
- const res = await fetch2(
313
+ const { createWhopFetch: createWhopFetch2 } = await import("./api-3MQ6MQGV.js");
314
+ const fetch3 = createWhopFetch2();
315
+ const res = await fetch3(
303
316
  new Request(
304
317
  `https://api.whop.com/products?company_id=${companyId}&first=1`
305
318
  )
@@ -346,6 +359,36 @@ async function loginAdapter(c2) {
346
359
  });
347
360
  }
348
361
  function logoutAdapter(c2) {
362
+ if (c2.options.all) {
363
+ if (c2.options.profile) {
364
+ return c2.error({
365
+ code: "CONFLICTING_OPTIONS",
366
+ message: "--all removes every profile \u2014 don't combine it with --profile.",
367
+ retryable: true
368
+ });
369
+ }
370
+ const removed2 = removeAllProfiles();
371
+ if (removed2.length === 0) {
372
+ return c2.error({
373
+ code: "NO_PROFILES",
374
+ message: "No profiles to remove.",
375
+ retryable: false,
376
+ cta: {
377
+ description: "Log in first:",
378
+ commands: [{ command: "auth login", description: "Log in to Whop" }]
379
+ }
380
+ });
381
+ }
382
+ return c2.ok(
383
+ { removed: removed2, newActive: null },
384
+ {
385
+ cta: {
386
+ description: `Removed ${removed2.length} profile${removed2.length === 1 ? "" : "s"}. To authenticate again:`,
387
+ commands: [{ command: "auth login", description: "Log in to Whop" }]
388
+ }
389
+ }
390
+ );
391
+ }
349
392
  const target = c2.options.profile ?? getActiveProfile()?.name;
350
393
  if (!target) {
351
394
  return c2.error({
@@ -367,7 +410,7 @@ function logoutAdapter(c2) {
367
410
  });
368
411
  }
369
412
  return c2.ok(
370
- { removed: target, newActive },
413
+ { removed: [target], newActive },
371
414
  newActive ? {
372
415
  cta: {
373
416
  description: `Now using "${newActive}".`,
@@ -396,10 +439,17 @@ function buildAuthGroup() {
396
439
  run: (c2) => loginAdapter(c2)
397
440
  });
398
441
  auth.command("logout", {
399
- description: "Log out \u2014 remove a saved profile",
442
+ description: "Log out \u2014 remove a saved profile, or all with --all",
400
443
  aliases: ["remove", "rm"],
401
444
  options: logoutOptions,
402
445
  output: logoutOutput,
446
+ examples: [
447
+ { description: "Remove the active profile" },
448
+ {
449
+ options: { all: true },
450
+ description: "Remove every profile (full reset)"
451
+ }
452
+ ],
403
453
  run: (c2) => logoutAdapter(c2)
404
454
  });
405
455
  auth.command("switch", {
@@ -545,10 +595,10 @@ import { text, isCancel } from "@clack/prompts";
545
595
  // src/commerce/client.ts
546
596
  var PLACEHOLDER = "https://api.whop.com";
547
597
  var whopFetch = createWhopFetch();
548
- async function makeWhopRequest(method, path, body) {
598
+ async function makeWhopRequest(method, path3, body) {
549
599
  const init = { method };
550
600
  if (body !== void 0) init.body = JSON.stringify(body);
551
- const res = await whopFetch(new Request(`${PLACEHOLDER}${path}`, init));
601
+ const res = await whopFetch(new Request(`${PLACEHOLDER}${path3}`, init));
552
602
  if (!res.ok) {
553
603
  const payload = await res.json().catch(() => null);
554
604
  throw new Error(payload?.message ?? res.statusText);
@@ -590,13 +640,13 @@ function registerListCommand(group, config) {
590
640
  });
591
641
  }
592
642
  function registerItemCommands(group, config) {
593
- const { path, noun, idLabel, schema, updateOptions, transformBody } = config;
643
+ const { path: path3, noun, idLabel, schema, updateOptions, transformBody } = config;
594
644
  const idArg = external_exports.object({ id: external_exports.string().describe(idLabel) });
595
645
  group.command("get", {
596
646
  description: `Get a ${noun} by ID`,
597
647
  args: idArg,
598
648
  output: schema,
599
- run: (c2) => makeWhopRequest(`GET`, `${path}/${c2.args.id}`)
649
+ run: (c2) => makeWhopRequest(`GET`, `${path3}/${c2.args.id}`)
600
650
  });
601
651
  if (updateOptions) {
602
652
  group.command("update", {
@@ -606,14 +656,14 @@ function registerItemCommands(group, config) {
606
656
  output: schema,
607
657
  run: (c2) => {
608
658
  const body = buildBody(c2.options);
609
- return makeWhopRequest("PATCH", `${path}/${c2.args.id}`, transformBody ? transformBody(body) : body);
659
+ return makeWhopRequest("PATCH", `${path3}/${c2.args.id}`, transformBody ? transformBody(body) : body);
610
660
  }
611
661
  });
612
662
  }
613
663
  group.command("delete", {
614
664
  description: `Delete a ${noun}`,
615
665
  args: idArg,
616
- run: (c2) => makeWhopRequest("DELETE", `${path}/${c2.args.id}`)
666
+ run: (c2) => makeWhopRequest("DELETE", `${path3}/${c2.args.id}`)
617
667
  });
618
668
  }
619
669
 
@@ -1495,6 +1545,479 @@ ${c.success("\u2713 Your store is fully set up.")}`);
1495
1545
  console.log("");
1496
1546
  }
1497
1547
 
1548
+ // package.json
1549
+ var package_default = {
1550
+ name: "@whop/cli",
1551
+ version: "0.1.0",
1552
+ description: "The Whop CLI \u2014 build and manage Whop apps from your terminal. Human and agent friendly.",
1553
+ keywords: [
1554
+ "agent",
1555
+ "apps",
1556
+ "cli",
1557
+ "developer",
1558
+ "whop"
1559
+ ],
1560
+ homepage: "https://whop.com/developers/",
1561
+ bugs: "https://github.com/whopio/whop-public-cli/issues",
1562
+ license: "MIT",
1563
+ repository: {
1564
+ type: "git",
1565
+ url: "git+https://github.com/whopio/whop-public-cli.git"
1566
+ },
1567
+ bin: {
1568
+ whop: "dist/index.js",
1569
+ "whop-cli": "dist/index.js"
1570
+ },
1571
+ files: [
1572
+ "dist"
1573
+ ],
1574
+ type: "module",
1575
+ publishConfig: {
1576
+ access: "public"
1577
+ },
1578
+ scripts: {
1579
+ build: "tsx scripts/sync-spec.ts && pnpm run clean && tsup",
1580
+ "build:binary": "tsx scripts/build-binary.ts",
1581
+ clean: "rm -rf dist",
1582
+ dev: "tsx scripts/sync-spec.ts && tsx src/index.ts",
1583
+ start: "node dist/index.js",
1584
+ "check-types": "tsx scripts/sync-spec.ts && tsc --noEmit",
1585
+ lint: "oxlint .",
1586
+ "lint:fix": "oxlint --fix --fix-suggestions && oxfmt",
1587
+ "ci:lint": "oxlint -f github .",
1588
+ format: "oxfmt",
1589
+ "sync-spec": "tsx scripts/sync-spec.ts",
1590
+ test: "tsx --test scripts/*.test.ts"
1591
+ },
1592
+ dependencies: {
1593
+ "@clack/prompts": "^1.5.1",
1594
+ "@napi-rs/keyring": "^1.3.0",
1595
+ "@whop/sdk": "^0.0.40",
1596
+ chalk: "5.4.1",
1597
+ yaml: "2.8.0"
1598
+ },
1599
+ devDependencies: {
1600
+ "@types/node": "25.3.5",
1601
+ incur: "github:whopio/incur#5ca60d5",
1602
+ tsup: "8.5.0",
1603
+ tsx: "4.19.4",
1604
+ typescript: "5.9.3"
1605
+ },
1606
+ engines: {
1607
+ node: ">=22"
1608
+ },
1609
+ packageManager: "pnpm@10.23.0"
1610
+ };
1611
+
1612
+ // src/lib/update/check.ts
1613
+ import fs from "fs";
1614
+ import path from "path";
1615
+ import { spawn } from "child_process";
1616
+
1617
+ // src/lib/colorize-output.ts
1618
+ var SECTION_HEADERS = /* @__PURE__ */ new Set([
1619
+ "Usage",
1620
+ "Arguments",
1621
+ "Options",
1622
+ "Examples",
1623
+ "Environment Variables",
1624
+ "Global Options",
1625
+ "Integrations",
1626
+ "Commands",
1627
+ "Aliases"
1628
+ ]);
1629
+ var FORMAT_FLAGS = ["--json", "--format", "--full-output", "--schema", "--llms", "--llms-full", "--mcp", "--token-count", "--token-limit", "--token-offset"];
1630
+ function hasStructuredOutputFlag(argv2) {
1631
+ return argv2.some((a) => FORMAT_FLAGS.includes(a) || a.startsWith("--format="));
1632
+ }
1633
+ function shouldColorize(argv2) {
1634
+ if (!process.stdout.isTTY) return false;
1635
+ return !hasStructuredOutputFlag(argv2);
1636
+ }
1637
+ function paintFlag(flag) {
1638
+ return flag.replace(/(<[^>]+>)/g, (m) => c.muted(m)).replace(/(--[\w-]+|-[\w])/g, (m) => c.flag(m));
1639
+ }
1640
+ var COMMAND_ROW = /^(\s+)(whop\s+\S.*?)(\s{2,}#\s.*)?$/;
1641
+ function highlightUrls(text3) {
1642
+ return text3.replace(/https?:\/\/[^\s)]+/g, (m) => c.link(m));
1643
+ }
1644
+ function colorizeLine(line, section, nextLine) {
1645
+ const errMatch = line.match(/^(Error(?: \([^)]+\))?:)(.*)$/);
1646
+ if (errMatch) return { line: c.error(errMatch[1]) + highlightUrls(errMatch[2]), section };
1647
+ if (line.startsWith("Run `")) return { line: c.heading(line), section };
1648
+ const header = line.match(/^([A-Z][A-Za-z ]+):(.*)$/);
1649
+ if (header && SECTION_HEADERS.has(header[1])) {
1650
+ const rest = header[2].replace(/(whop[\w\s-]*)/g, (m) => c.command(m));
1651
+ return { line: c.heading(`${header[1]}:`) + rest, section: header[1] };
1652
+ }
1653
+ const cmd = line.match(COMMAND_ROW);
1654
+ if (cmd) {
1655
+ return { line: `${cmd[1]}${c.command(cmd[2])}${cmd[3] ? c.description(cmd[3]) : ""}`, section };
1656
+ }
1657
+ if (line.trim().endsWith(":") && nextLine !== void 0 && COMMAND_ROW.test(nextLine)) {
1658
+ return { line: c.heading(line), section };
1659
+ }
1660
+ if (line.trim() === "") return { line, section: null };
1661
+ if (section === "Options" || section === "Global Options" || section === "Environment Variables") {
1662
+ const m = line.match(/^(\s+)(\S.*?)(\s{2,})(.*)$/);
1663
+ if (m) return { line: `${m[1]}${paintFlag(m[2])}${m[3]}${c.description(m[4])}`, section };
1664
+ }
1665
+ if (section === "Commands" || section === "Integrations" || section === "Aliases") {
1666
+ const m = line.match(/^(\s+)(\S+)(\s{2,})(.*)$/);
1667
+ if (m) return { line: `${m[1]}${c.command(m[2])}${m[3]}${c.description(m[4])}`, section };
1668
+ }
1669
+ if (section === "Arguments") {
1670
+ const m = line.match(/^(\s+)(\S+)(\s{2,})(.*)$/);
1671
+ if (m) return { line: `${m[1]}${c.id(m[2])}${m[3]}${c.description(m[4])}`, section };
1672
+ }
1673
+ return { line: highlightUrls(line), section };
1674
+ }
1675
+ function colorizeOutput(text3) {
1676
+ let section = null;
1677
+ const lines = text3.split("\n");
1678
+ return lines.map((line, i) => {
1679
+ const result = colorizeLine(line, section, lines[i + 1]);
1680
+ section = result.section;
1681
+ return result.line;
1682
+ }).join("\n");
1683
+ }
1684
+
1685
+ // src/lib/update/check.ts
1686
+ var DEFAULT_MANIFEST_URL = "https://github.com/whopio/whop-public-cli/releases/latest/download/manifest.json";
1687
+ function manifestUrl(env = process.env) {
1688
+ return env.WHOP_CLI_MANIFEST_URL?.trim() || DEFAULT_MANIFEST_URL;
1689
+ }
1690
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
1691
+ function cachePath(env) {
1692
+ return path.join(configDir(env), "update-check.json");
1693
+ }
1694
+ function readUpdateCache(env = process.env) {
1695
+ try {
1696
+ const parsed = JSON.parse(
1697
+ fs.readFileSync(cachePath(env), "utf8")
1698
+ );
1699
+ if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) {
1700
+ return parsed;
1701
+ }
1702
+ } catch {
1703
+ }
1704
+ return {};
1705
+ }
1706
+ function writeUpdateCache(cache, env = process.env) {
1707
+ try {
1708
+ fs.mkdirSync(configDir(env), { recursive: true, mode: 448 });
1709
+ fs.writeFileSync(cachePath(env), `${JSON.stringify(cache, null, 2)}
1710
+ `, {
1711
+ mode: 384
1712
+ });
1713
+ } catch {
1714
+ }
1715
+ }
1716
+ function isNewerVersion(candidate, current) {
1717
+ const parse = (v) => v.replace(/^v/, "").split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
1718
+ const a = parse(candidate);
1719
+ const b = parse(current);
1720
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
1721
+ if ((a[i] ?? 0) > (b[i] ?? 0)) return true;
1722
+ if ((a[i] ?? 0) < (b[i] ?? 0)) return false;
1723
+ }
1724
+ return false;
1725
+ }
1726
+ function upgradeCommandFor(channel) {
1727
+ switch (channel) {
1728
+ case "npm":
1729
+ return "npm install -g @whop/cli";
1730
+ case "brew":
1731
+ return "brew upgrade whop";
1732
+ default:
1733
+ return "whop upgrade";
1734
+ }
1735
+ }
1736
+ function updateCheckSuppressed(argv2, env = process.env, stderrIsTty = process.stderr.isTTY ?? false) {
1737
+ if (env.WHOP_CLI_NO_UPDATE_CHECK) return true;
1738
+ if (env.CI) return true;
1739
+ if (!stderrIsTty) return true;
1740
+ if (hasStructuredOutputFlag(argv2)) return true;
1741
+ const first = argv2[0];
1742
+ if (first === "upgrade" || first === "mcp" || first === "completions" || first?.startsWith("--")) {
1743
+ return true;
1744
+ }
1745
+ return false;
1746
+ }
1747
+ function spawnBackgroundCheck() {
1748
+ const args = detectChannel() === "standalone" || detectChannel() === "brew" ? ["upgrade", "--background"] : [process.argv[1], "upgrade", "--background"];
1749
+ try {
1750
+ spawn(process.execPath, args, {
1751
+ detached: true,
1752
+ stdio: "ignore"
1753
+ }).unref();
1754
+ } catch {
1755
+ }
1756
+ }
1757
+ function scheduleUpdateNotice(argv2, currentVersion, env = process.env) {
1758
+ const channel = detectChannel(env);
1759
+ if (channel === "dev") return;
1760
+ if (updateCheckSuppressed(argv2, env)) return;
1761
+ const cache = readUpdateCache(env);
1762
+ if (cache.updatedTo && cache.updatedTo === currentVersion) {
1763
+ writeUpdateCache({ ...cache, updatedTo: void 0 }, env);
1764
+ process.on("exit", () => {
1765
+ process.stderr.write(
1766
+ `
1767
+ whop was updated to v${currentVersion} automatically.
1768
+ `
1769
+ );
1770
+ });
1771
+ return;
1772
+ }
1773
+ if (cache.latestVersion && isNewerVersion(cache.latestVersion, currentVersion)) {
1774
+ const latest = cache.latestVersion;
1775
+ process.on("exit", () => {
1776
+ process.stderr.write(
1777
+ `
1778
+ A new version of whop is available: v${currentVersion} \u2192 v${latest}
1779
+ Run \`${upgradeCommandFor(channel)}\` to update.
1780
+ `
1781
+ );
1782
+ });
1783
+ }
1784
+ const lastChecked = cache.lastCheckedAt ? new Date(cache.lastCheckedAt).getTime() : 0;
1785
+ if (Date.now() - lastChecked > CHECK_INTERVAL_MS) {
1786
+ writeUpdateCache({ ...cache, lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString() }, env);
1787
+ spawnBackgroundCheck();
1788
+ }
1789
+ }
1790
+
1791
+ // src/lib/update/self-update.ts
1792
+ import crypto from "crypto";
1793
+ import fs2 from "fs";
1794
+ import path2 from "path";
1795
+ var SelfUpdateError = class extends Error {
1796
+ constructor(code, message) {
1797
+ super(message);
1798
+ this.code = code;
1799
+ }
1800
+ };
1801
+ async function fetchManifest(env = process.env) {
1802
+ const url = manifestUrl(env);
1803
+ let response;
1804
+ try {
1805
+ response = await fetch(url, {
1806
+ signal: AbortSignal.timeout(1e4),
1807
+ redirect: "follow"
1808
+ });
1809
+ } catch {
1810
+ throw new SelfUpdateError(
1811
+ "MANIFEST_UNREACHABLE",
1812
+ `Could not reach the update manifest at ${url}.`
1813
+ );
1814
+ }
1815
+ if (!response.ok) {
1816
+ throw new SelfUpdateError(
1817
+ "MANIFEST_UNAVAILABLE",
1818
+ `Update manifest request failed with HTTP ${response.status}.`
1819
+ );
1820
+ }
1821
+ let parsed;
1822
+ try {
1823
+ parsed = await response.json();
1824
+ } catch {
1825
+ throw new SelfUpdateError(
1826
+ "MANIFEST_INVALID",
1827
+ "Update manifest is not valid JSON."
1828
+ );
1829
+ }
1830
+ const manifest = parsed;
1831
+ if (typeof manifest?.version !== "string" || manifest.assets == null || typeof manifest.assets !== "object") {
1832
+ throw new SelfUpdateError(
1833
+ "MANIFEST_INVALID",
1834
+ "Update manifest is missing version or assets."
1835
+ );
1836
+ }
1837
+ return manifest;
1838
+ }
1839
+ function assetForThisBinary(manifest) {
1840
+ if (!buildTarget) {
1841
+ throw new SelfUpdateError(
1842
+ "NOT_A_STANDALONE_BUILD",
1843
+ "This build has no compile target \u2014 self-update only applies to standalone binaries."
1844
+ );
1845
+ }
1846
+ const asset = manifest.assets[buildTarget];
1847
+ if (!asset?.url || !asset.sha256) {
1848
+ throw new SelfUpdateError(
1849
+ "NO_ASSET_FOR_TARGET",
1850
+ `The latest release has no binary for ${buildTarget}.`
1851
+ );
1852
+ }
1853
+ return { ...asset, target: buildTarget };
1854
+ }
1855
+ async function downloadAndSwap(asset, execPath = process.execPath) {
1856
+ let response;
1857
+ try {
1858
+ response = await fetch(asset.url, {
1859
+ signal: AbortSignal.timeout(12e4),
1860
+ redirect: "follow"
1861
+ });
1862
+ } catch {
1863
+ throw new SelfUpdateError(
1864
+ "DOWNLOAD_FAILED",
1865
+ `Could not download ${asset.url}.`
1866
+ );
1867
+ }
1868
+ if (!response.ok) {
1869
+ throw new SelfUpdateError(
1870
+ "DOWNLOAD_FAILED",
1871
+ `Binary download failed with HTTP ${response.status}.`
1872
+ );
1873
+ }
1874
+ const bytes = Buffer.from(await response.arrayBuffer());
1875
+ const digest = crypto.createHash("sha256").update(bytes).digest("hex");
1876
+ if (digest !== asset.sha256.toLowerCase()) {
1877
+ throw new SelfUpdateError(
1878
+ "CHECKSUM_MISMATCH",
1879
+ `Downloaded binary checksum ${digest} does not match the manifest \u2014 aborting.`
1880
+ );
1881
+ }
1882
+ const dir = path2.dirname(execPath);
1883
+ const tmp = path2.join(dir, `.${path2.basename(execPath)}.${process.pid}.new`);
1884
+ try {
1885
+ fs2.writeFileSync(tmp, bytes, { mode: 493 });
1886
+ fs2.renameSync(tmp, execPath);
1887
+ } catch (err) {
1888
+ try {
1889
+ fs2.rmSync(tmp, { force: true });
1890
+ } catch {
1891
+ }
1892
+ const code = err.code;
1893
+ if (code === "EACCES" || code === "EPERM" || code === "EROFS") {
1894
+ throw new SelfUpdateError(
1895
+ "PERMISSION_DENIED",
1896
+ `No write access to ${dir}. Re-run with elevated permissions (e.g. \`sudo whop upgrade\`) or reinstall.`
1897
+ );
1898
+ }
1899
+ throw err;
1900
+ }
1901
+ }
1902
+
1903
+ // src/lib/update/command.ts
1904
+ var upgradeOptions = external_exports.object({
1905
+ check: external_exports.boolean().optional().describe("Only check for a newer version, don't install it"),
1906
+ background: external_exports.boolean().optional().describe(
1907
+ "Internal: refresh the update cache silently (spawned by the automatic check)"
1908
+ )
1909
+ });
1910
+ var upgradeOutput = external_exports.object({
1911
+ status: external_exports.enum(["up-to-date", "update-available", "updated"]).describe("Result of the upgrade check"),
1912
+ current: external_exports.string().describe("The version currently running"),
1913
+ latest: external_exports.string().describe("The latest released version"),
1914
+ channel: external_exports.enum(["npm", "brew", "standalone", "dev"]).describe("How this CLI was installed"),
1915
+ upgradeCommand: external_exports.string().optional().describe("Run this shell command to install the available update")
1916
+ });
1917
+ async function runBackground(env) {
1918
+ const manifest = await fetchManifest(env);
1919
+ const cache = readUpdateCache(env);
1920
+ writeUpdateCache(
1921
+ {
1922
+ ...cache,
1923
+ lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
1924
+ latestVersion: manifest.version
1925
+ },
1926
+ env
1927
+ );
1928
+ if (detectChannel(env) === "standalone" && env.WHOP_CLI_AUTO_UPDATE !== "0" && isNewerVersion(manifest.version, package_default.version)) {
1929
+ await downloadAndSwap(assetForThisBinary(manifest));
1930
+ writeUpdateCache(
1931
+ {
1932
+ lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
1933
+ latestVersion: manifest.version,
1934
+ updatedTo: manifest.version
1935
+ },
1936
+ env
1937
+ );
1938
+ }
1939
+ }
1940
+ async function runUpgrade(c2, env = process.env) {
1941
+ if (c2.options.background) {
1942
+ try {
1943
+ await runBackground(env);
1944
+ } catch {
1945
+ }
1946
+ return c2.ok({
1947
+ status: "up-to-date",
1948
+ current: package_default.version,
1949
+ latest: package_default.version,
1950
+ channel: detectChannel(env)
1951
+ });
1952
+ }
1953
+ const channel = detectChannel(env);
1954
+ let manifest;
1955
+ try {
1956
+ manifest = await fetchManifest(env);
1957
+ } catch (err) {
1958
+ if (err instanceof SelfUpdateError) {
1959
+ return c2.error({ code: err.code, message: err.message, retryable: true });
1960
+ }
1961
+ throw err;
1962
+ }
1963
+ writeUpdateCache(
1964
+ {
1965
+ ...readUpdateCache(env),
1966
+ lastCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
1967
+ latestVersion: manifest.version
1968
+ },
1969
+ env
1970
+ );
1971
+ const base = { current: package_default.version, latest: manifest.version, channel };
1972
+ if (!isNewerVersion(manifest.version, package_default.version)) {
1973
+ return c2.ok({ status: "up-to-date", ...base });
1974
+ }
1975
+ if (channel === "npm" || channel === "brew") {
1976
+ return c2.ok({
1977
+ status: "update-available",
1978
+ ...base,
1979
+ upgradeCommand: upgradeCommandFor(channel)
1980
+ });
1981
+ }
1982
+ if (channel === "dev") {
1983
+ return c2.error({
1984
+ code: "DEV_BUILD",
1985
+ message: "Running from source \u2014 pull the latest instead of upgrading.",
1986
+ retryable: false
1987
+ });
1988
+ }
1989
+ if (c2.options.check) {
1990
+ return c2.ok(
1991
+ {
1992
+ status: "update-available",
1993
+ ...base,
1994
+ upgradeCommand: upgradeCommandFor(channel)
1995
+ },
1996
+ {
1997
+ cta: {
1998
+ description: `v${manifest.version} is available (you have v${package_default.version}). To update:`,
1999
+ commands: [
2000
+ { command: "upgrade", description: "Install the latest version" }
2001
+ ]
2002
+ }
2003
+ }
2004
+ );
2005
+ }
2006
+ try {
2007
+ await downloadAndSwap(assetForThisBinary(manifest));
2008
+ } catch (err) {
2009
+ if (err instanceof SelfUpdateError) {
2010
+ return c2.error({
2011
+ code: err.code,
2012
+ message: err.message,
2013
+ retryable: err.code !== "PERMISSION_DENIED"
2014
+ });
2015
+ }
2016
+ throw err;
2017
+ }
2018
+ return c2.ok({ status: "updated", ...base });
2019
+ }
2020
+
1498
2021
  // src/commands.ts
1499
2022
  var HANDWRITTEN_GROUPS = [
1500
2023
  {
@@ -1539,6 +2062,24 @@ var HANDWRITTEN_GROUPS = [
1539
2062
  section: "commerce",
1540
2063
  register: (cli2) => cli2.command(buildCheckoutGroup())
1541
2064
  },
2065
+ {
2066
+ name: "upgrade",
2067
+ description: "Update the CLI to the latest version",
2068
+ section: "get-started",
2069
+ register: (cli2) => cli2.command("upgrade", {
2070
+ description: "Update the whop CLI to the latest version",
2071
+ options: upgradeOptions,
2072
+ output: upgradeOutput,
2073
+ examples: [
2074
+ { description: "Update to the latest version" },
2075
+ {
2076
+ options: { check: true },
2077
+ description: "Check for a newer version without installing"
2078
+ }
2079
+ ],
2080
+ run: (c2) => runUpgrade(c2)
2081
+ })
2082
+ },
1542
2083
  {
1543
2084
  name: "auth",
1544
2085
  description: "Manage authentication",
@@ -1595,69 +2136,6 @@ async function setupAgents(cli2) {
1595
2136
  }
1596
2137
  }
1597
2138
 
1598
- // package.json
1599
- var package_default = {
1600
- name: "@whop/cli",
1601
- version: "0.0.5",
1602
- description: "The Whop CLI \u2014 build and manage Whop apps from your terminal. Human and agent friendly.",
1603
- keywords: [
1604
- "agent",
1605
- "apps",
1606
- "cli",
1607
- "developer",
1608
- "whop"
1609
- ],
1610
- homepage: "https://whop.com/developers/",
1611
- bugs: "https://github.com/whopio/whop-sdk-ts/issues",
1612
- license: "MIT",
1613
- repository: {
1614
- type: "git",
1615
- url: "git+https://github.com/whopio/whop-sdk-ts.git",
1616
- directory: "packages/cli"
1617
- },
1618
- bin: {
1619
- whop: "dist/index.js",
1620
- "whop-cli": "dist/index.js"
1621
- },
1622
- files: [
1623
- "dist"
1624
- ],
1625
- type: "module",
1626
- publishConfig: {
1627
- access: "public"
1628
- },
1629
- scripts: {
1630
- build: "tsx scripts/sync-spec.ts && pnpm run clean && tsup",
1631
- clean: "rm -rf dist",
1632
- dev: "tsx scripts/sync-spec.ts && tsx src/index.ts",
1633
- start: "node dist/index.js",
1634
- "check-types": "tsx scripts/sync-spec.ts && tsc --noEmit",
1635
- lint: "oxlint .",
1636
- "lint:fix": "oxlint --fix --fix-suggestions && oxfmt",
1637
- "ci:lint": "oxlint -f github .",
1638
- format: "oxfmt",
1639
- "sync-spec": "tsx scripts/sync-spec.ts",
1640
- test: "tsx --test scripts/*.test.ts"
1641
- },
1642
- dependencies: {
1643
- "@clack/prompts": "^1.5.1",
1644
- "@napi-rs/keyring": "^1.3.0",
1645
- "@whop/sdk": "^0.0.40",
1646
- chalk: "5.4.1"
1647
- },
1648
- devDependencies: {
1649
- "@types/node": "25.3.5",
1650
- incur: "github:whopio/incur#ea62f88",
1651
- tsup: "8.5.0",
1652
- tsx: "4.19.4",
1653
- typescript: "5.9.3"
1654
- },
1655
- engines: {
1656
- node: ">=22"
1657
- },
1658
- packageManager: "pnpm@10.23.0"
1659
- };
1660
-
1661
2139
  // src/lib/renderer.ts
1662
2140
  var MAX_CELL_WIDTH = 40;
1663
2141
  function isPlainObject(value) {
@@ -1742,8 +2220,8 @@ var cli = Cli_exports.create("whop", {
1742
2220
  }
1743
2221
  });
1744
2222
  var spec = (tag) => filterSpecByTag(native_spec_default, tag);
1745
- var fetch = createWhopFetch();
1746
- var isAuthExempt = (cmd) => !cmd || cmd === "login" || cmd === "logout" || cmd === "completions" || cmd.startsWith("auth") || cmd.startsWith("mcp");
2223
+ var fetch2 = createWhopFetch();
2224
+ var isAuthExempt = (cmd) => !cmd || cmd === "login" || cmd === "logout" || cmd === "completions" || cmd === "upgrade" || cmd.startsWith("auth") || cmd.startsWith("mcp");
1747
2225
  cli.use(async (c2, next) => {
1748
2226
  if (isAuthExempt(c2.command)) return next();
1749
2227
  if (getActiveProfile()) return next();
@@ -1783,7 +2261,7 @@ cli.use(async (c2, next) => {
1783
2261
  });
1784
2262
  registerHandwrittenGroups(cli);
1785
2263
  for (const { name, tag } of API_GROUPS) {
1786
- cli.command(name, { fetch, openapi: spec(tag) });
2264
+ cli.command(name, { fetch: fetch2, openapi: spec(tag) });
1787
2265
  }
1788
2266
  var cli_default = cli;
1789
2267
 
@@ -1820,6 +2298,13 @@ var api_structure_default = [
1820
2298
  "Referrals"
1821
2299
  ]
1822
2300
  },
2301
+ {
2302
+ group: "Tracking",
2303
+ tags: [
2304
+ "People",
2305
+ "Events"
2306
+ ]
2307
+ },
1823
2308
  {
1824
2309
  group: "Ads",
1825
2310
  tags: [
@@ -1957,73 +2442,9 @@ function buildGroupedHelp(version, description) {
1957
2442
  return lines.join("\n");
1958
2443
  }
1959
2444
 
1960
- // src/lib/colorize-output.ts
1961
- var SECTION_HEADERS = /* @__PURE__ */ new Set([
1962
- "Usage",
1963
- "Arguments",
1964
- "Options",
1965
- "Examples",
1966
- "Environment Variables",
1967
- "Global Options",
1968
- "Integrations",
1969
- "Commands",
1970
- "Aliases"
1971
- ]);
1972
- var FORMAT_FLAGS = ["--json", "--format", "--full-output", "--schema", "--llms", "--llms-full", "--mcp", "--token-count", "--token-limit", "--token-offset"];
1973
- function shouldColorize(argv2) {
1974
- if (!process.stdout.isTTY) return false;
1975
- return !argv2.some((a) => FORMAT_FLAGS.includes(a) || a.startsWith("--format="));
1976
- }
1977
- function paintFlag(flag) {
1978
- return flag.replace(/(<[^>]+>)/g, (m) => c.muted(m)).replace(/(--[\w-]+|-[\w])/g, (m) => c.flag(m));
1979
- }
1980
- var COMMAND_ROW = /^(\s+)(whop\s+\S.*?)(\s{2,}#\s.*)?$/;
1981
- function highlightUrls(text3) {
1982
- return text3.replace(/https?:\/\/[^\s)]+/g, (m) => c.link(m));
1983
- }
1984
- function colorizeLine(line, section, nextLine) {
1985
- const errMatch = line.match(/^(Error(?: \([^)]+\))?:)(.*)$/);
1986
- if (errMatch) return { line: c.error(errMatch[1]) + highlightUrls(errMatch[2]), section };
1987
- if (line.startsWith("Run `")) return { line: c.heading(line), section };
1988
- const header = line.match(/^([A-Z][A-Za-z ]+):(.*)$/);
1989
- if (header && SECTION_HEADERS.has(header[1])) {
1990
- const rest = header[2].replace(/(whop[\w\s-]*)/g, (m) => c.command(m));
1991
- return { line: c.heading(`${header[1]}:`) + rest, section: header[1] };
1992
- }
1993
- const cmd = line.match(COMMAND_ROW);
1994
- if (cmd) {
1995
- return { line: `${cmd[1]}${c.command(cmd[2])}${cmd[3] ? c.description(cmd[3]) : ""}`, section };
1996
- }
1997
- if (line.trim().endsWith(":") && nextLine !== void 0 && COMMAND_ROW.test(nextLine)) {
1998
- return { line: c.heading(line), section };
1999
- }
2000
- if (line.trim() === "") return { line, section: null };
2001
- if (section === "Options" || section === "Global Options" || section === "Environment Variables") {
2002
- const m = line.match(/^(\s+)(\S.*?)(\s{2,})(.*)$/);
2003
- if (m) return { line: `${m[1]}${paintFlag(m[2])}${m[3]}${c.description(m[4])}`, section };
2004
- }
2005
- if (section === "Commands" || section === "Integrations" || section === "Aliases") {
2006
- const m = line.match(/^(\s+)(\S+)(\s{2,})(.*)$/);
2007
- if (m) return { line: `${m[1]}${c.command(m[2])}${m[3]}${c.description(m[4])}`, section };
2008
- }
2009
- if (section === "Arguments") {
2010
- const m = line.match(/^(\s+)(\S+)(\s{2,})(.*)$/);
2011
- if (m) return { line: `${m[1]}${c.id(m[2])}${m[3]}${c.description(m[4])}`, section };
2012
- }
2013
- return { line: highlightUrls(line), section };
2014
- }
2015
- function colorizeOutput(text3) {
2016
- let section = null;
2017
- const lines = text3.split("\n");
2018
- return lines.map((line, i) => {
2019
- const result = colorizeLine(line, section, lines[i + 1]);
2020
- section = result.section;
2021
- return result.line;
2022
- }).join("\n");
2023
- }
2024
-
2025
2445
  // src/index.ts
2026
2446
  var argv = process.argv.slice(2);
2447
+ scheduleUpdateNotice(argv, package_default.version);
2027
2448
  async function serve(argv2) {
2028
2449
  if (shouldColorize(argv2)) {
2029
2450
  await cli_default.serve(argv2, {
@@ -2046,8 +2467,4 @@ if (argv.length === 0 && !getActiveProfile() && !process.env.WHOP_API_KEY) {
2046
2467
  } else {
2047
2468
  await serve(argv);
2048
2469
  }
2049
- var index_default = cli_default;
2050
- export {
2051
- index_default as default
2052
- };
2053
2470
  //# sourceMappingURL=index.js.map