@keepgoingdev/cli 1.2.0 → 1.2.2
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 +104 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -60,7 +60,8 @@ function findGitRoot(startPath) {
|
|
|
60
60
|
const toplevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
61
61
|
cwd: startPath,
|
|
62
62
|
encoding: "utf-8",
|
|
63
|
-
timeout: 5e3
|
|
63
|
+
timeout: 5e3,
|
|
64
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
64
65
|
}).trim();
|
|
65
66
|
return toplevel || startPath;
|
|
66
67
|
} catch {
|
|
@@ -77,12 +78,14 @@ function resolveStorageRoot(startPath) {
|
|
|
77
78
|
const toplevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
78
79
|
cwd: startPath,
|
|
79
80
|
encoding: "utf-8",
|
|
80
|
-
timeout: 5e3
|
|
81
|
+
timeout: 5e3,
|
|
82
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
81
83
|
}).trim();
|
|
82
84
|
const commonDir = execFileSync("git", ["rev-parse", "--git-common-dir"], {
|
|
83
85
|
cwd: startPath,
|
|
84
86
|
encoding: "utf-8",
|
|
85
|
-
timeout: 5e3
|
|
87
|
+
timeout: 5e3,
|
|
88
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
86
89
|
}).trim();
|
|
87
90
|
const absoluteCommonDir = path.resolve(toplevel, commonDir);
|
|
88
91
|
const mainRoot = path.dirname(absoluteCommonDir);
|
|
@@ -1096,7 +1099,14 @@ function getLicenseForFeature(feature) {
|
|
|
1096
1099
|
return features?.includes(feature);
|
|
1097
1100
|
});
|
|
1098
1101
|
}
|
|
1102
|
+
function getAllLicensesNeedingRevalidation() {
|
|
1103
|
+
return getActiveLicenses().filter((l) => needsRevalidation(l));
|
|
1104
|
+
}
|
|
1099
1105
|
var REVALIDATION_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
|
|
1106
|
+
function needsRevalidation(entry) {
|
|
1107
|
+
const lastValidated = new Date(entry.lastValidatedAt).getTime();
|
|
1108
|
+
return Date.now() - lastValidated > REVALIDATION_THRESHOLD_MS;
|
|
1109
|
+
}
|
|
1100
1110
|
|
|
1101
1111
|
// ../../packages/shared/src/featureGate.ts
|
|
1102
1112
|
var DefaultFeatureGate = class {
|
|
@@ -1429,12 +1439,14 @@ var SESSION_END_HOOK = {
|
|
|
1429
1439
|
}
|
|
1430
1440
|
]
|
|
1431
1441
|
};
|
|
1432
|
-
var KEEPGOING_RULES_VERSION =
|
|
1442
|
+
var KEEPGOING_RULES_VERSION = 2;
|
|
1433
1443
|
var KEEPGOING_RULES_CONTENT = `<!-- @keepgoingdev/mcp-server v${KEEPGOING_RULES_VERSION} -->
|
|
1434
1444
|
## KeepGoing
|
|
1435
1445
|
|
|
1446
|
+
When you see KeepGoing momentum data in your session context (from a SessionStart hook), share a brief welcome with the user that includes: what was last worked on, the suggested next step, and any blockers.
|
|
1447
|
+
|
|
1436
1448
|
After completing a task or meaningful piece of work, call the \`save_checkpoint\` MCP tool with:
|
|
1437
|
-
- \`summary\`: 1-2 sentences. What changed and why
|
|
1449
|
+
- \`summary\`: 1-2 sentences. What changed and why, no file paths, no implementation details (those are captured from git).
|
|
1438
1450
|
- \`nextStep\`: What to do next
|
|
1439
1451
|
- \`blocker\`: Any blocker (if applicable)
|
|
1440
1452
|
`;
|
|
@@ -1560,7 +1572,7 @@ function setupProject(options) {
|
|
|
1560
1572
|
messages.push(`Warning: ${conflict}`);
|
|
1561
1573
|
}
|
|
1562
1574
|
}
|
|
1563
|
-
|
|
1575
|
+
{
|
|
1564
1576
|
const needsUpdate = settings.statusLine?.command && statusline?.isLegacy?.(settings.statusLine.command);
|
|
1565
1577
|
if (!settings.statusLine || needsUpdate) {
|
|
1566
1578
|
settings.statusLine = {
|
|
@@ -1568,7 +1580,7 @@ function setupProject(options) {
|
|
|
1568
1580
|
command: STATUSLINE_CMD
|
|
1569
1581
|
};
|
|
1570
1582
|
settingsChanged = true;
|
|
1571
|
-
messages.push(needsUpdate ? "Statusline: Migrated to auto-updating npx command" :
|
|
1583
|
+
messages.push(needsUpdate ? "Statusline: Migrated to auto-updating npx command" : `Statusline: Added to ${scopeLabel}`);
|
|
1572
1584
|
} else {
|
|
1573
1585
|
messages.push("Statusline: Already configured in settings, skipped");
|
|
1574
1586
|
}
|
|
@@ -1690,6 +1702,39 @@ async function activateLicense(licenseKey, instanceName, options) {
|
|
|
1690
1702
|
return { valid: false, error: message };
|
|
1691
1703
|
}
|
|
1692
1704
|
}
|
|
1705
|
+
async function validateLicense(licenseKey, instanceId, options) {
|
|
1706
|
+
try {
|
|
1707
|
+
const res = await fetchWithTimeout(`${BASE_URL}/validate`, {
|
|
1708
|
+
method: "POST",
|
|
1709
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1710
|
+
body: new URLSearchParams({ license_key: licenseKey, instance_id: instanceId })
|
|
1711
|
+
});
|
|
1712
|
+
const data = await safeJson(res);
|
|
1713
|
+
if (!res.ok || !data?.valid) {
|
|
1714
|
+
return { valid: false, isNetworkError: false, error: data?.error || `Validation failed (${res.status})` };
|
|
1715
|
+
}
|
|
1716
|
+
if (!options?.allowTestMode && data.license_key?.test_mode) {
|
|
1717
|
+
return { valid: false, isNetworkError: false, error: "This is a test license key. Please use a production license key from your purchase confirmation." };
|
|
1718
|
+
}
|
|
1719
|
+
if (!options?.allowTestMode) {
|
|
1720
|
+
const productError = validateProductIdentity(data.meta);
|
|
1721
|
+
if (productError) {
|
|
1722
|
+
return { valid: false, isNetworkError: false, error: productError };
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
return {
|
|
1726
|
+
valid: true,
|
|
1727
|
+
licenseKey: data.license_key?.key,
|
|
1728
|
+
customerName: data.meta?.customer_name,
|
|
1729
|
+
productName: data.meta?.product_name,
|
|
1730
|
+
variantId: data.meta?.variant_id,
|
|
1731
|
+
variantName: data.meta?.variant_name
|
|
1732
|
+
};
|
|
1733
|
+
} catch (err) {
|
|
1734
|
+
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";
|
|
1735
|
+
return { valid: false, isNetworkError: true, error: message };
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1693
1738
|
async function deactivateLicense(licenseKey, instanceId) {
|
|
1694
1739
|
try {
|
|
1695
1740
|
const res = await fetchWithTimeout(`${BASE_URL}/deactivate`, {
|
|
@@ -1708,6 +1753,52 @@ async function deactivateLicense(licenseKey, instanceId) {
|
|
|
1708
1753
|
}
|
|
1709
1754
|
}
|
|
1710
1755
|
|
|
1756
|
+
// ../../packages/shared/src/licenseRevalidation.ts
|
|
1757
|
+
async function revalidateStaleLicenses(options) {
|
|
1758
|
+
const stale = getAllLicensesNeedingRevalidation();
|
|
1759
|
+
const result = { checked: stale.length, refreshed: 0, revoked: 0, skippedNetworkError: 0 };
|
|
1760
|
+
if (stale.length === 0) return result;
|
|
1761
|
+
const updates = /* @__PURE__ */ new Map();
|
|
1762
|
+
for (const entry of stale) {
|
|
1763
|
+
const vResult = await validateLicense(entry.licenseKey, entry.instanceId, {
|
|
1764
|
+
allowTestMode: options?.allowTestMode
|
|
1765
|
+
});
|
|
1766
|
+
if (vResult.valid) {
|
|
1767
|
+
const patch = {
|
|
1768
|
+
lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1769
|
+
};
|
|
1770
|
+
if (vResult.customerName) patch.customerName = vResult.customerName;
|
|
1771
|
+
updates.set(entry.licenseKey, patch);
|
|
1772
|
+
result.refreshed++;
|
|
1773
|
+
} else if (vResult.isNetworkError) {
|
|
1774
|
+
result.skippedNetworkError++;
|
|
1775
|
+
} else {
|
|
1776
|
+
updates.set(entry.licenseKey, { status: "inactive" });
|
|
1777
|
+
result.revoked++;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
if (updates.size > 0) {
|
|
1781
|
+
const store = readLicenseStore();
|
|
1782
|
+
for (const [key, patch] of updates) {
|
|
1783
|
+
const idx = store.licenses.findIndex((l) => l.licenseKey === key);
|
|
1784
|
+
if (idx >= 0) {
|
|
1785
|
+
Object.assign(store.licenses[idx], patch);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
writeLicenseStore(store);
|
|
1789
|
+
}
|
|
1790
|
+
return result;
|
|
1791
|
+
}
|
|
1792
|
+
async function getLicenseForFeatureWithRevalidation(feature, options) {
|
|
1793
|
+
const license = getLicenseForFeature(feature);
|
|
1794
|
+
if (!license) return void 0;
|
|
1795
|
+
if (needsRevalidation(license)) {
|
|
1796
|
+
await revalidateStaleLicenses(options);
|
|
1797
|
+
return getLicenseForFeature(feature);
|
|
1798
|
+
}
|
|
1799
|
+
return license;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1711
1802
|
// src/render.ts
|
|
1712
1803
|
var RESET = "\x1B[0m";
|
|
1713
1804
|
var BOLD = "\x1B[1m";
|
|
@@ -2023,7 +2114,7 @@ import { spawn } from "child_process";
|
|
|
2023
2114
|
import { readFileSync, existsSync } from "fs";
|
|
2024
2115
|
import path9 from "path";
|
|
2025
2116
|
import os4 from "os";
|
|
2026
|
-
var CLI_VERSION = "1.2.
|
|
2117
|
+
var CLI_VERSION = "1.2.2";
|
|
2027
2118
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@keepgoingdev/cli/latest";
|
|
2028
2119
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
2029
2120
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -2743,7 +2834,7 @@ async function decisionsCommand(opts) {
|
|
|
2743
2834
|
}
|
|
2744
2835
|
return;
|
|
2745
2836
|
}
|
|
2746
|
-
if (process.env.KEEPGOING_PRO_BYPASS !== "1" && !
|
|
2837
|
+
if (process.env.KEEPGOING_PRO_BYPASS !== "1" && !await getLicenseForFeatureWithRevalidation("decisions")) {
|
|
2747
2838
|
console.error(
|
|
2748
2839
|
'Decision Detection requires a Pro license.\nRun "keepgoing activate <key>" or visit https://keepgoing.dev/add-ons to purchase.'
|
|
2749
2840
|
);
|
|
@@ -2947,8 +3038,8 @@ function renderGrouped(sessions, showStat) {
|
|
|
2947
3038
|
}
|
|
2948
3039
|
}
|
|
2949
3040
|
}
|
|
2950
|
-
function logDecisions(reader, opts) {
|
|
2951
|
-
const license =
|
|
3041
|
+
async function logDecisions(reader, opts) {
|
|
3042
|
+
const license = await getLicenseForFeatureWithRevalidation("decisions");
|
|
2952
3043
|
if (!license) {
|
|
2953
3044
|
console.log("Decision tracking requires a Pro license. Run: keepgoing activate <key>");
|
|
2954
3045
|
return;
|
|
@@ -2994,7 +3085,7 @@ async function logCommand(opts) {
|
|
|
2994
3085
|
return;
|
|
2995
3086
|
}
|
|
2996
3087
|
if (opts.subcommand === "decisions") {
|
|
2997
|
-
logDecisions(reader, opts);
|
|
3088
|
+
await logDecisions(reader, opts);
|
|
2998
3089
|
} else {
|
|
2999
3090
|
logSessions(reader, opts);
|
|
3000
3091
|
}
|
|
@@ -3477,7 +3568,7 @@ async function main() {
|
|
|
3477
3568
|
}
|
|
3478
3569
|
break;
|
|
3479
3570
|
case "version":
|
|
3480
|
-
console.log(`keepgoing v${"1.2.
|
|
3571
|
+
console.log(`keepgoing v${"1.2.2"}`);
|
|
3481
3572
|
break;
|
|
3482
3573
|
case "activate":
|
|
3483
3574
|
await activateCommand({ licenseKey: subcommand });
|