@keepgoingdev/cli 1.3.1 → 1.3.3
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 +49 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -616,6 +616,7 @@ import os from "os";
|
|
|
616
616
|
import path3 from "path";
|
|
617
617
|
var LICENSE_FILE = "license.json";
|
|
618
618
|
var DEVICE_ID_FILE = "device-id";
|
|
619
|
+
var SIGNING_KEY_FILE = "signing-key";
|
|
619
620
|
function getGlobalLicenseDir() {
|
|
620
621
|
return path3.join(os.homedir(), ".keepgoing");
|
|
621
622
|
}
|
|
@@ -637,6 +638,37 @@ function getDeviceId() {
|
|
|
637
638
|
fs.writeFileSync(filePath, id, "utf-8");
|
|
638
639
|
return id;
|
|
639
640
|
}
|
|
641
|
+
function getSigningKey() {
|
|
642
|
+
const dir = getGlobalLicenseDir();
|
|
643
|
+
const keyPath = path3.join(dir, SIGNING_KEY_FILE);
|
|
644
|
+
try {
|
|
645
|
+
const existing = fs.readFileSync(keyPath, "utf-8").trim();
|
|
646
|
+
if (existing) return existing;
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
649
|
+
const key = crypto.randomBytes(32).toString("hex");
|
|
650
|
+
if (!fs.existsSync(dir)) {
|
|
651
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
652
|
+
}
|
|
653
|
+
fs.writeFileSync(keyPath, key, "utf-8");
|
|
654
|
+
return key;
|
|
655
|
+
}
|
|
656
|
+
function computeSignature(licenses) {
|
|
657
|
+
const sorted = [...licenses].sort((a, b) => a.licenseKey.localeCompare(b.licenseKey));
|
|
658
|
+
const payload = JSON.stringify(sorted);
|
|
659
|
+
return crypto.createHmac("sha256", getSigningKey()).update(payload).digest("hex");
|
|
660
|
+
}
|
|
661
|
+
function verifySignature(store) {
|
|
662
|
+
if (!store.signature) return false;
|
|
663
|
+
try {
|
|
664
|
+
const expected = Buffer.from(computeSignature(store.licenses), "hex");
|
|
665
|
+
const actual = Buffer.from(store.signature, "hex");
|
|
666
|
+
if (actual.length !== expected.length) return false;
|
|
667
|
+
return crypto.timingSafeEqual(actual, expected);
|
|
668
|
+
} catch {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
640
672
|
var DECISION_DETECTION_VARIANT_ID = 1361527;
|
|
641
673
|
var SESSION_AWARENESS_VARIANT_ID = 1366510;
|
|
642
674
|
var TEST_DECISION_DETECTION_VARIANT_ID = 1345647;
|
|
@@ -675,6 +707,13 @@ function readLicenseStore() {
|
|
|
675
707
|
const data = JSON.parse(raw);
|
|
676
708
|
if (data?.version === 2 && Array.isArray(data.licenses)) {
|
|
677
709
|
store = data;
|
|
710
|
+
if (store.signature && !verifySignature(store)) {
|
|
711
|
+
store = {
|
|
712
|
+
version: 2,
|
|
713
|
+
licenses: store.licenses.map((l) => ({ ...l, status: "inactive" }))
|
|
714
|
+
// Omit signature so the next writeLicenseStore() re-signs cleanly
|
|
715
|
+
};
|
|
716
|
+
}
|
|
678
717
|
} else {
|
|
679
718
|
store = { version: 2, licenses: [] };
|
|
680
719
|
}
|
|
@@ -691,6 +730,7 @@ function writeLicenseStore(store) {
|
|
|
691
730
|
if (!fs.existsSync(dirPath)) {
|
|
692
731
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
693
732
|
}
|
|
733
|
+
store.signature = computeSignature(store.licenses);
|
|
694
734
|
const licensePath = path3.join(dirPath, LICENSE_FILE);
|
|
695
735
|
fs.writeFileSync(licensePath, JSON.stringify(store, null, 2), "utf-8");
|
|
696
736
|
_cachedStore = store;
|
|
@@ -724,7 +764,7 @@ function getLicenseForFeature(feature) {
|
|
|
724
764
|
function getAllLicensesNeedingRevalidation() {
|
|
725
765
|
return getActiveLicenses().filter((l) => needsRevalidation(l));
|
|
726
766
|
}
|
|
727
|
-
var REVALIDATION_THRESHOLD_MS =
|
|
767
|
+
var REVALIDATION_THRESHOLD_MS = 6 * 60 * 60 * 1e3;
|
|
728
768
|
function needsRevalidation(entry) {
|
|
729
769
|
const lastValidated = new Date(entry.lastValidatedAt).getTime();
|
|
730
770
|
return Date.now() - lastValidated > REVALIDATION_THRESHOLD_MS;
|
|
@@ -790,7 +830,7 @@ function registerProject(projectPath, projectName) {
|
|
|
790
830
|
data.projects.push({ path: projectPath, name, lastSeen: now });
|
|
791
831
|
}
|
|
792
832
|
const cutoff = Date.now() - STALE_PROJECT_MS;
|
|
793
|
-
data.projects = data.projects.filter((p) => new Date(p.lastSeen).getTime() > cutoff);
|
|
833
|
+
data.projects = data.projects.filter((p) => new Date(p.lastSeen).getTime() > cutoff && fs2.existsSync(p.path));
|
|
794
834
|
writeKnownProjects(data);
|
|
795
835
|
} catch {
|
|
796
836
|
}
|
|
@@ -811,14 +851,15 @@ function pruneStaleTasks(tasks) {
|
|
|
811
851
|
});
|
|
812
852
|
}
|
|
813
853
|
var KeepGoingWriter = class {
|
|
854
|
+
mainRoot;
|
|
814
855
|
storagePath;
|
|
815
856
|
sessionsFilePath;
|
|
816
857
|
stateFilePath;
|
|
817
858
|
metaFilePath;
|
|
818
859
|
currentTasksFilePath;
|
|
819
860
|
constructor(workspacePath) {
|
|
820
|
-
|
|
821
|
-
this.storagePath = path5.join(mainRoot, STORAGE_DIR);
|
|
861
|
+
this.mainRoot = resolveStorageRoot(workspacePath);
|
|
862
|
+
this.storagePath = path5.join(this.mainRoot, STORAGE_DIR);
|
|
822
863
|
this.sessionsFilePath = path5.join(this.storagePath, SESSIONS_FILE);
|
|
823
864
|
this.stateFilePath = path5.join(this.storagePath, STATE_FILE);
|
|
824
865
|
this.metaFilePath = path5.join(this.storagePath, META_FILE);
|
|
@@ -860,8 +901,7 @@ var KeepGoingWriter = class {
|
|
|
860
901
|
};
|
|
861
902
|
fs3.writeFileSync(this.stateFilePath, JSON.stringify(state, null, 2), "utf-8");
|
|
862
903
|
this.updateMeta(checkpoint.timestamp);
|
|
863
|
-
|
|
864
|
-
registerProject(mainRoot, projectName);
|
|
904
|
+
registerProject(this.mainRoot, projectName);
|
|
865
905
|
}
|
|
866
906
|
updateMeta(timestamp) {
|
|
867
907
|
let meta;
|
|
@@ -928,8 +968,7 @@ var KeepGoingWriter = class {
|
|
|
928
968
|
upsertSession(update) {
|
|
929
969
|
this.ensureDir();
|
|
930
970
|
this.upsertSessionCore(update);
|
|
931
|
-
|
|
932
|
-
registerProject(mainRoot);
|
|
971
|
+
registerProject(this.mainRoot);
|
|
933
972
|
}
|
|
934
973
|
/** Core upsert logic: merges the update into current-tasks.json and returns the pruned task list. */
|
|
935
974
|
upsertSessionCore(update) {
|
|
@@ -2399,7 +2438,7 @@ import { spawn } from "child_process";
|
|
|
2399
2438
|
import { readFileSync, existsSync } from "fs";
|
|
2400
2439
|
import path10 from "path";
|
|
2401
2440
|
import os4 from "os";
|
|
2402
|
-
var CLI_VERSION = "1.3.
|
|
2441
|
+
var CLI_VERSION = "1.3.3";
|
|
2403
2442
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@keepgoingdev/cli/latest";
|
|
2404
2443
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
2405
2444
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -3940,7 +3979,7 @@ async function main() {
|
|
|
3940
3979
|
}
|
|
3941
3980
|
break;
|
|
3942
3981
|
case "version":
|
|
3943
|
-
console.log(`keepgoing v${"1.3.
|
|
3982
|
+
console.log(`keepgoing v${"1.3.3"}`);
|
|
3944
3983
|
break;
|
|
3945
3984
|
case "activate":
|
|
3946
3985
|
await activateCommand({ licenseKey: subcommand });
|