@keepgoingdev/cli 1.2.0 → 1.2.1

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/index.js +92 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1096,7 +1096,14 @@ function getLicenseForFeature(feature) {
1096
1096
  return features?.includes(feature);
1097
1097
  });
1098
1098
  }
1099
+ function getAllLicensesNeedingRevalidation() {
1100
+ return getActiveLicenses().filter((l) => needsRevalidation(l));
1101
+ }
1099
1102
  var REVALIDATION_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
1103
+ function needsRevalidation(entry) {
1104
+ const lastValidated = new Date(entry.lastValidatedAt).getTime();
1105
+ return Date.now() - lastValidated > REVALIDATION_THRESHOLD_MS;
1106
+ }
1100
1107
 
1101
1108
  // ../../packages/shared/src/featureGate.ts
1102
1109
  var DefaultFeatureGate = class {
@@ -1690,6 +1697,39 @@ async function activateLicense(licenseKey, instanceName, options) {
1690
1697
  return { valid: false, error: message };
1691
1698
  }
1692
1699
  }
1700
+ async function validateLicense(licenseKey, instanceId, options) {
1701
+ try {
1702
+ const res = await fetchWithTimeout(`${BASE_URL}/validate`, {
1703
+ method: "POST",
1704
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
1705
+ body: new URLSearchParams({ license_key: licenseKey, instance_id: instanceId })
1706
+ });
1707
+ const data = await safeJson(res);
1708
+ if (!res.ok || !data?.valid) {
1709
+ return { valid: false, isNetworkError: false, error: data?.error || `Validation failed (${res.status})` };
1710
+ }
1711
+ if (!options?.allowTestMode && data.license_key?.test_mode) {
1712
+ return { valid: false, isNetworkError: false, error: "This is a test license key. Please use a production license key from your purchase confirmation." };
1713
+ }
1714
+ if (!options?.allowTestMode) {
1715
+ const productError = validateProductIdentity(data.meta);
1716
+ if (productError) {
1717
+ return { valid: false, isNetworkError: false, error: productError };
1718
+ }
1719
+ }
1720
+ return {
1721
+ valid: true,
1722
+ licenseKey: data.license_key?.key,
1723
+ customerName: data.meta?.customer_name,
1724
+ productName: data.meta?.product_name,
1725
+ variantId: data.meta?.variant_id,
1726
+ variantName: data.meta?.variant_name
1727
+ };
1728
+ } catch (err) {
1729
+ const message = err instanceof Error && err.name === "AbortError" ? "Request timed out. Please check your network connection and try again." : err instanceof Error ? err.message : "Network error";
1730
+ return { valid: false, isNetworkError: true, error: message };
1731
+ }
1732
+ }
1693
1733
  async function deactivateLicense(licenseKey, instanceId) {
1694
1734
  try {
1695
1735
  const res = await fetchWithTimeout(`${BASE_URL}/deactivate`, {
@@ -1708,6 +1748,52 @@ async function deactivateLicense(licenseKey, instanceId) {
1708
1748
  }
1709
1749
  }
1710
1750
 
1751
+ // ../../packages/shared/src/licenseRevalidation.ts
1752
+ async function revalidateStaleLicenses(options) {
1753
+ const stale = getAllLicensesNeedingRevalidation();
1754
+ const result = { checked: stale.length, refreshed: 0, revoked: 0, skippedNetworkError: 0 };
1755
+ if (stale.length === 0) return result;
1756
+ const updates = /* @__PURE__ */ new Map();
1757
+ for (const entry of stale) {
1758
+ const vResult = await validateLicense(entry.licenseKey, entry.instanceId, {
1759
+ allowTestMode: options?.allowTestMode
1760
+ });
1761
+ if (vResult.valid) {
1762
+ const patch = {
1763
+ lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString()
1764
+ };
1765
+ if (vResult.customerName) patch.customerName = vResult.customerName;
1766
+ updates.set(entry.licenseKey, patch);
1767
+ result.refreshed++;
1768
+ } else if (vResult.isNetworkError) {
1769
+ result.skippedNetworkError++;
1770
+ } else {
1771
+ updates.set(entry.licenseKey, { status: "inactive" });
1772
+ result.revoked++;
1773
+ }
1774
+ }
1775
+ if (updates.size > 0) {
1776
+ const store = readLicenseStore();
1777
+ for (const [key, patch] of updates) {
1778
+ const idx = store.licenses.findIndex((l) => l.licenseKey === key);
1779
+ if (idx >= 0) {
1780
+ Object.assign(store.licenses[idx], patch);
1781
+ }
1782
+ }
1783
+ writeLicenseStore(store);
1784
+ }
1785
+ return result;
1786
+ }
1787
+ async function getLicenseForFeatureWithRevalidation(feature, options) {
1788
+ const license = getLicenseForFeature(feature);
1789
+ if (!license) return void 0;
1790
+ if (needsRevalidation(license)) {
1791
+ await revalidateStaleLicenses(options);
1792
+ return getLicenseForFeature(feature);
1793
+ }
1794
+ return license;
1795
+ }
1796
+
1711
1797
  // src/render.ts
1712
1798
  var RESET = "\x1B[0m";
1713
1799
  var BOLD = "\x1B[1m";
@@ -2023,7 +2109,7 @@ import { spawn } from "child_process";
2023
2109
  import { readFileSync, existsSync } from "fs";
2024
2110
  import path9 from "path";
2025
2111
  import os4 from "os";
2026
- var CLI_VERSION = "1.2.0";
2112
+ var CLI_VERSION = "1.2.1";
2027
2113
  var NPM_REGISTRY_URL = "https://registry.npmjs.org/@keepgoingdev/cli/latest";
2028
2114
  var FETCH_TIMEOUT_MS = 5e3;
2029
2115
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -2743,7 +2829,7 @@ async function decisionsCommand(opts) {
2743
2829
  }
2744
2830
  return;
2745
2831
  }
2746
- if (process.env.KEEPGOING_PRO_BYPASS !== "1" && !getLicenseForFeature("decisions")) {
2832
+ if (process.env.KEEPGOING_PRO_BYPASS !== "1" && !await getLicenseForFeatureWithRevalidation("decisions")) {
2747
2833
  console.error(
2748
2834
  'Decision Detection requires a Pro license.\nRun "keepgoing activate <key>" or visit https://keepgoing.dev/add-ons to purchase.'
2749
2835
  );
@@ -2947,8 +3033,8 @@ function renderGrouped(sessions, showStat) {
2947
3033
  }
2948
3034
  }
2949
3035
  }
2950
- function logDecisions(reader, opts) {
2951
- const license = getLicenseForFeature("decisions");
3036
+ async function logDecisions(reader, opts) {
3037
+ const license = await getLicenseForFeatureWithRevalidation("decisions");
2952
3038
  if (!license) {
2953
3039
  console.log("Decision tracking requires a Pro license. Run: keepgoing activate <key>");
2954
3040
  return;
@@ -2994,7 +3080,7 @@ async function logCommand(opts) {
2994
3080
  return;
2995
3081
  }
2996
3082
  if (opts.subcommand === "decisions") {
2997
- logDecisions(reader, opts);
3083
+ await logDecisions(reader, opts);
2998
3084
  } else {
2999
3085
  logSessions(reader, opts);
3000
3086
  }
@@ -3477,7 +3563,7 @@ async function main() {
3477
3563
  }
3478
3564
  break;
3479
3565
  case "version":
3480
- console.log(`keepgoing v${"1.2.0"}`);
3566
+ console.log(`keepgoing v${"1.2.1"}`);
3481
3567
  break;
3482
3568
  case "activate":
3483
3569
  await activateCommand({ licenseKey: subcommand });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keepgoingdev/cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Terminal CLI for KeepGoing. Resume side projects without the mental friction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",