@askexenow/exe-os 0.9.30 → 0.9.32
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/bin/backfill-conversations.js +135 -7
- package/dist/bin/backfill-responses.js +135 -7
- package/dist/bin/backfill-vectors.js +135 -7
- package/dist/bin/cleanup-stale-review-tasks.js +139 -11
- package/dist/bin/cli.js +812 -486
- package/dist/bin/exe-assign.js +135 -7
- package/dist/bin/exe-boot.js +422 -113
- package/dist/bin/exe-cloud.js +160 -9
- package/dist/bin/exe-dispatch.js +136 -8
- package/dist/bin/exe-doctor.js +255 -13
- package/dist/bin/exe-export-behaviors.js +136 -8
- package/dist/bin/exe-forget.js +136 -8
- package/dist/bin/exe-gateway.js +171 -24
- package/dist/bin/exe-heartbeat.js +141 -13
- package/dist/bin/exe-kill.js +140 -12
- package/dist/bin/exe-launch-agent.js +143 -15
- package/dist/bin/exe-link.js +357 -48
- package/dist/bin/exe-pending-messages.js +136 -8
- package/dist/bin/exe-pending-notifications.js +136 -8
- package/dist/bin/exe-pending-reviews.js +138 -10
- package/dist/bin/exe-review.js +136 -8
- package/dist/bin/exe-search.js +155 -20
- package/dist/bin/exe-session-cleanup.js +166 -38
- package/dist/bin/exe-start-codex.js +142 -14
- package/dist/bin/exe-start-opencode.js +140 -12
- package/dist/bin/exe-status.js +148 -20
- package/dist/bin/exe-team.js +136 -8
- package/dist/bin/git-sweep.js +138 -10
- package/dist/bin/graph-backfill.js +135 -7
- package/dist/bin/graph-export.js +136 -8
- package/dist/bin/intercom-check.js +153 -25
- package/dist/bin/scan-tasks.js +138 -10
- package/dist/bin/setup.js +447 -121
- package/dist/bin/shard-migrate.js +135 -7
- package/dist/gateway/index.js +151 -23
- package/dist/hooks/bug-report-worker.js +151 -23
- package/dist/hooks/codex-stop-task-finalizer.js +145 -17
- package/dist/hooks/commit-complete.js +138 -10
- package/dist/hooks/error-recall.js +159 -24
- package/dist/hooks/ingest.js +142 -14
- package/dist/hooks/instructions-loaded.js +136 -8
- package/dist/hooks/notification.js +136 -8
- package/dist/hooks/post-compact.js +136 -8
- package/dist/hooks/post-tool-combined.js +159 -24
- package/dist/hooks/pre-compact.js +136 -8
- package/dist/hooks/pre-tool-use.js +144 -16
- package/dist/hooks/prompt-submit.js +195 -55
- package/dist/hooks/session-end.js +141 -13
- package/dist/hooks/session-start.js +165 -30
- package/dist/hooks/stop.js +136 -8
- package/dist/hooks/subagent-stop.js +136 -8
- package/dist/hooks/summary-worker.js +374 -65
- package/dist/index.js +136 -8
- package/dist/lib/cloud-sync.js +355 -46
- package/dist/lib/consolidation.js +1 -0
- package/dist/lib/exe-daemon.js +469 -127
- package/dist/lib/hybrid-search.js +155 -20
- package/dist/lib/keychain.js +191 -7
- package/dist/lib/schedules.js +138 -10
- package/dist/lib/store.js +135 -7
- package/dist/mcp/server.js +706 -213
- package/dist/runtime/index.js +136 -8
- package/dist/tui/App.js +208 -31
- package/package.json +1 -1
package/dist/hooks/ingest.js
CHANGED
|
@@ -1411,8 +1411,8 @@ function findPackageRoot() {
|
|
|
1411
1411
|
function getAvailableMemoryGB() {
|
|
1412
1412
|
if (process.platform === "darwin") {
|
|
1413
1413
|
try {
|
|
1414
|
-
const { execSync:
|
|
1415
|
-
const vmstat =
|
|
1414
|
+
const { execSync: execSync7 } = __require("child_process");
|
|
1415
|
+
const vmstat = execSync7("vm_stat", { encoding: "utf8" });
|
|
1416
1416
|
const pageSize = 16384;
|
|
1417
1417
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1418
1418
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2947,6 +2947,7 @@ var init_database = __esm({
|
|
|
2947
2947
|
// src/lib/keychain.ts
|
|
2948
2948
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2949
2949
|
import { existsSync as existsSync9 } from "fs";
|
|
2950
|
+
import { execSync as execSync4 } from "child_process";
|
|
2950
2951
|
import path10 from "path";
|
|
2951
2952
|
import os6 from "os";
|
|
2952
2953
|
function getKeyDir() {
|
|
@@ -2955,6 +2956,59 @@ function getKeyDir() {
|
|
|
2955
2956
|
function getKeyPath() {
|
|
2956
2957
|
return path10.join(getKeyDir(), "master.key");
|
|
2957
2958
|
}
|
|
2959
|
+
function macKeychainGet() {
|
|
2960
|
+
if (process.platform !== "darwin") return null;
|
|
2961
|
+
try {
|
|
2962
|
+
return execSync4(
|
|
2963
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2964
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2965
|
+
).trim();
|
|
2966
|
+
} catch {
|
|
2967
|
+
return null;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
function macKeychainSet(value) {
|
|
2971
|
+
if (process.platform !== "darwin") return false;
|
|
2972
|
+
try {
|
|
2973
|
+
try {
|
|
2974
|
+
execSync4(
|
|
2975
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2976
|
+
{ timeout: 5e3 }
|
|
2977
|
+
);
|
|
2978
|
+
} catch {
|
|
2979
|
+
}
|
|
2980
|
+
execSync4(
|
|
2981
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2982
|
+
{ timeout: 5e3 }
|
|
2983
|
+
);
|
|
2984
|
+
return true;
|
|
2985
|
+
} catch {
|
|
2986
|
+
return false;
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
function linuxSecretGet() {
|
|
2990
|
+
if (process.platform !== "linux") return null;
|
|
2991
|
+
try {
|
|
2992
|
+
return execSync4(
|
|
2993
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2994
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2995
|
+
).trim();
|
|
2996
|
+
} catch {
|
|
2997
|
+
return null;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
function linuxSecretSet(value) {
|
|
3001
|
+
if (process.platform !== "linux") return false;
|
|
3002
|
+
try {
|
|
3003
|
+
execSync4(
|
|
3004
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3005
|
+
{ timeout: 5e3 }
|
|
3006
|
+
);
|
|
3007
|
+
return true;
|
|
3008
|
+
} catch {
|
|
3009
|
+
return false;
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
2958
3012
|
async function tryKeytar() {
|
|
2959
3013
|
try {
|
|
2960
3014
|
return await import("keytar");
|
|
@@ -2962,13 +3016,63 @@ async function tryKeytar() {
|
|
|
2962
3016
|
return null;
|
|
2963
3017
|
}
|
|
2964
3018
|
}
|
|
3019
|
+
function deriveMachineKey() {
|
|
3020
|
+
try {
|
|
3021
|
+
const crypto3 = __require("crypto");
|
|
3022
|
+
const material = [
|
|
3023
|
+
os6.hostname(),
|
|
3024
|
+
os6.userInfo().username,
|
|
3025
|
+
os6.arch(),
|
|
3026
|
+
os6.platform(),
|
|
3027
|
+
// Machine ID on Linux (stable across reboots)
|
|
3028
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3029
|
+
].join("|");
|
|
3030
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
3031
|
+
} catch {
|
|
3032
|
+
return null;
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
function readMachineId() {
|
|
3036
|
+
try {
|
|
3037
|
+
const { readFileSync: readFileSync9 } = __require("fs");
|
|
3038
|
+
return readFileSync9("/etc/machine-id", "utf-8").trim();
|
|
3039
|
+
} catch {
|
|
3040
|
+
return "";
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3044
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3045
|
+
try {
|
|
3046
|
+
const crypto3 = __require("crypto");
|
|
3047
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3048
|
+
if (parts.length !== 3) return null;
|
|
3049
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3050
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3051
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3052
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3053
|
+
decipher.setAuthTag(authTag);
|
|
3054
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3055
|
+
decrypted += decipher.final("utf-8");
|
|
3056
|
+
return decrypted;
|
|
3057
|
+
} catch {
|
|
3058
|
+
return null;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
2965
3061
|
async function getMasterKey() {
|
|
3062
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3063
|
+
if (nativeValue) {
|
|
3064
|
+
return Buffer.from(nativeValue, "base64");
|
|
3065
|
+
}
|
|
2966
3066
|
const keytar = await tryKeytar();
|
|
2967
3067
|
if (keytar) {
|
|
2968
3068
|
try {
|
|
2969
|
-
const
|
|
2970
|
-
if (
|
|
2971
|
-
|
|
3069
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3070
|
+
if (keytarValue) {
|
|
3071
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3072
|
+
if (migrated) {
|
|
3073
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3074
|
+
}
|
|
3075
|
+
return Buffer.from(keytarValue, "base64");
|
|
2972
3076
|
}
|
|
2973
3077
|
} catch {
|
|
2974
3078
|
}
|
|
@@ -2982,8 +3086,31 @@ async function getMasterKey() {
|
|
|
2982
3086
|
return null;
|
|
2983
3087
|
}
|
|
2984
3088
|
try {
|
|
2985
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
2986
|
-
|
|
3089
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3090
|
+
let b64Value;
|
|
3091
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3092
|
+
const machineKey = deriveMachineKey();
|
|
3093
|
+
if (!machineKey) {
|
|
3094
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3095
|
+
return null;
|
|
3096
|
+
}
|
|
3097
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3098
|
+
if (!decrypted) {
|
|
3099
|
+
process.stderr.write(
|
|
3100
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3101
|
+
);
|
|
3102
|
+
return null;
|
|
3103
|
+
}
|
|
3104
|
+
b64Value = decrypted;
|
|
3105
|
+
} else {
|
|
3106
|
+
b64Value = content;
|
|
3107
|
+
}
|
|
3108
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3109
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3110
|
+
if (migrated) {
|
|
3111
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3112
|
+
}
|
|
3113
|
+
return key;
|
|
2987
3114
|
} catch (err) {
|
|
2988
3115
|
process.stderr.write(
|
|
2989
3116
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2992,12 +3119,13 @@ async function getMasterKey() {
|
|
|
2992
3119
|
return null;
|
|
2993
3120
|
}
|
|
2994
3121
|
}
|
|
2995
|
-
var SERVICE, ACCOUNT;
|
|
3122
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
2996
3123
|
var init_keychain = __esm({
|
|
2997
3124
|
"src/lib/keychain.ts"() {
|
|
2998
3125
|
"use strict";
|
|
2999
3126
|
SERVICE = "exe-mem";
|
|
3000
3127
|
ACCOUNT = "master-key";
|
|
3128
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3001
3129
|
}
|
|
3002
3130
|
});
|
|
3003
3131
|
|
|
@@ -4235,11 +4363,11 @@ __export(git_staleness_exports, {
|
|
|
4235
4363
|
detectStaleFiles: () => detectStaleFiles,
|
|
4236
4364
|
recordFileRead: () => recordFileRead
|
|
4237
4365
|
});
|
|
4238
|
-
import { execSync as
|
|
4366
|
+
import { execSync as execSync5 } from "child_process";
|
|
4239
4367
|
import path12 from "path";
|
|
4240
4368
|
function getHeadCommit(cwd) {
|
|
4241
4369
|
try {
|
|
4242
|
-
return
|
|
4370
|
+
return execSync5("git rev-parse --short HEAD", {
|
|
4243
4371
|
cwd,
|
|
4244
4372
|
timeout: GIT_TIMEOUT_MS,
|
|
4245
4373
|
encoding: "utf-8"
|
|
@@ -4302,7 +4430,7 @@ async function detectStaleFiles(agentId, cwd) {
|
|
|
4302
4430
|
const readAt = String(record.read_at ?? "");
|
|
4303
4431
|
if (!filePath || !readAt) continue;
|
|
4304
4432
|
try {
|
|
4305
|
-
const gitSummary =
|
|
4433
|
+
const gitSummary = execSync5(
|
|
4306
4434
|
`git log -1 --oneline --after=${JSON.stringify(readAt)} --format="%h %an: %s" -- ${JSON.stringify(filePath)}`,
|
|
4307
4435
|
{
|
|
4308
4436
|
cwd,
|
|
@@ -4539,7 +4667,7 @@ __export(project_name_exports, {
|
|
|
4539
4667
|
_resetCache: () => _resetCache,
|
|
4540
4668
|
getProjectName: () => getProjectName
|
|
4541
4669
|
});
|
|
4542
|
-
import { execSync as
|
|
4670
|
+
import { execSync as execSync6 } from "child_process";
|
|
4543
4671
|
import path13 from "path";
|
|
4544
4672
|
function getProjectName(cwd) {
|
|
4545
4673
|
const dir = cwd ?? process.cwd();
|
|
@@ -4547,7 +4675,7 @@ function getProjectName(cwd) {
|
|
|
4547
4675
|
try {
|
|
4548
4676
|
let repoRoot;
|
|
4549
4677
|
try {
|
|
4550
|
-
const gitCommonDir =
|
|
4678
|
+
const gitCommonDir = execSync6("git rev-parse --path-format=absolute --git-common-dir", {
|
|
4551
4679
|
cwd: dir,
|
|
4552
4680
|
encoding: "utf8",
|
|
4553
4681
|
timeout: 2e3,
|
|
@@ -4555,7 +4683,7 @@ function getProjectName(cwd) {
|
|
|
4555
4683
|
}).trim();
|
|
4556
4684
|
repoRoot = path13.dirname(gitCommonDir);
|
|
4557
4685
|
} catch {
|
|
4558
|
-
repoRoot =
|
|
4686
|
+
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
4559
4687
|
cwd: dir,
|
|
4560
4688
|
encoding: "utf8",
|
|
4561
4689
|
timeout: 2e3,
|
|
@@ -1042,8 +1042,8 @@ function findPackageRoot() {
|
|
|
1042
1042
|
function getAvailableMemoryGB() {
|
|
1043
1043
|
if (process.platform === "darwin") {
|
|
1044
1044
|
try {
|
|
1045
|
-
const { execSync:
|
|
1046
|
-
const vmstat =
|
|
1045
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1046
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1047
1047
|
const pageSize = 16384;
|
|
1048
1048
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1049
1049
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2782,6 +2782,7 @@ var init_database = __esm({
|
|
|
2782
2782
|
// src/lib/keychain.ts
|
|
2783
2783
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2784
2784
|
import { existsSync as existsSync7 } from "fs";
|
|
2785
|
+
import { execSync as execSync4 } from "child_process";
|
|
2785
2786
|
import path8 from "path";
|
|
2786
2787
|
import os5 from "os";
|
|
2787
2788
|
function getKeyDir() {
|
|
@@ -2790,6 +2791,59 @@ function getKeyDir() {
|
|
|
2790
2791
|
function getKeyPath() {
|
|
2791
2792
|
return path8.join(getKeyDir(), "master.key");
|
|
2792
2793
|
}
|
|
2794
|
+
function macKeychainGet() {
|
|
2795
|
+
if (process.platform !== "darwin") return null;
|
|
2796
|
+
try {
|
|
2797
|
+
return execSync4(
|
|
2798
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2799
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2800
|
+
).trim();
|
|
2801
|
+
} catch {
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
function macKeychainSet(value) {
|
|
2806
|
+
if (process.platform !== "darwin") return false;
|
|
2807
|
+
try {
|
|
2808
|
+
try {
|
|
2809
|
+
execSync4(
|
|
2810
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2811
|
+
{ timeout: 5e3 }
|
|
2812
|
+
);
|
|
2813
|
+
} catch {
|
|
2814
|
+
}
|
|
2815
|
+
execSync4(
|
|
2816
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2817
|
+
{ timeout: 5e3 }
|
|
2818
|
+
);
|
|
2819
|
+
return true;
|
|
2820
|
+
} catch {
|
|
2821
|
+
return false;
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
function linuxSecretGet() {
|
|
2825
|
+
if (process.platform !== "linux") return null;
|
|
2826
|
+
try {
|
|
2827
|
+
return execSync4(
|
|
2828
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2829
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2830
|
+
).trim();
|
|
2831
|
+
} catch {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
function linuxSecretSet(value) {
|
|
2836
|
+
if (process.platform !== "linux") return false;
|
|
2837
|
+
try {
|
|
2838
|
+
execSync4(
|
|
2839
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
2840
|
+
{ timeout: 5e3 }
|
|
2841
|
+
);
|
|
2842
|
+
return true;
|
|
2843
|
+
} catch {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2793
2847
|
async function tryKeytar() {
|
|
2794
2848
|
try {
|
|
2795
2849
|
return await import("keytar");
|
|
@@ -2797,13 +2851,63 @@ async function tryKeytar() {
|
|
|
2797
2851
|
return null;
|
|
2798
2852
|
}
|
|
2799
2853
|
}
|
|
2854
|
+
function deriveMachineKey() {
|
|
2855
|
+
try {
|
|
2856
|
+
const crypto2 = __require("crypto");
|
|
2857
|
+
const material = [
|
|
2858
|
+
os5.hostname(),
|
|
2859
|
+
os5.userInfo().username,
|
|
2860
|
+
os5.arch(),
|
|
2861
|
+
os5.platform(),
|
|
2862
|
+
// Machine ID on Linux (stable across reboots)
|
|
2863
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
2864
|
+
].join("|");
|
|
2865
|
+
return crypto2.createHash("sha256").update(material).digest();
|
|
2866
|
+
} catch {
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
function readMachineId() {
|
|
2871
|
+
try {
|
|
2872
|
+
const { readFileSync: readFileSync7 } = __require("fs");
|
|
2873
|
+
return readFileSync7("/etc/machine-id", "utf-8").trim();
|
|
2874
|
+
} catch {
|
|
2875
|
+
return "";
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
2879
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
2880
|
+
try {
|
|
2881
|
+
const crypto2 = __require("crypto");
|
|
2882
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
2883
|
+
if (parts.length !== 3) return null;
|
|
2884
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
2885
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
2886
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
2887
|
+
const decipher = crypto2.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
2888
|
+
decipher.setAuthTag(authTag);
|
|
2889
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
2890
|
+
decrypted += decipher.final("utf-8");
|
|
2891
|
+
return decrypted;
|
|
2892
|
+
} catch {
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2800
2896
|
async function getMasterKey() {
|
|
2897
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
2898
|
+
if (nativeValue) {
|
|
2899
|
+
return Buffer.from(nativeValue, "base64");
|
|
2900
|
+
}
|
|
2801
2901
|
const keytar = await tryKeytar();
|
|
2802
2902
|
if (keytar) {
|
|
2803
2903
|
try {
|
|
2804
|
-
const
|
|
2805
|
-
if (
|
|
2806
|
-
|
|
2904
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
2905
|
+
if (keytarValue) {
|
|
2906
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
2907
|
+
if (migrated) {
|
|
2908
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
2909
|
+
}
|
|
2910
|
+
return Buffer.from(keytarValue, "base64");
|
|
2807
2911
|
}
|
|
2808
2912
|
} catch {
|
|
2809
2913
|
}
|
|
@@ -2817,8 +2921,31 @@ async function getMasterKey() {
|
|
|
2817
2921
|
return null;
|
|
2818
2922
|
}
|
|
2819
2923
|
try {
|
|
2820
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
2821
|
-
|
|
2924
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
2925
|
+
let b64Value;
|
|
2926
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
2927
|
+
const machineKey = deriveMachineKey();
|
|
2928
|
+
if (!machineKey) {
|
|
2929
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
2930
|
+
return null;
|
|
2931
|
+
}
|
|
2932
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
2933
|
+
if (!decrypted) {
|
|
2934
|
+
process.stderr.write(
|
|
2935
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
2936
|
+
);
|
|
2937
|
+
return null;
|
|
2938
|
+
}
|
|
2939
|
+
b64Value = decrypted;
|
|
2940
|
+
} else {
|
|
2941
|
+
b64Value = content;
|
|
2942
|
+
}
|
|
2943
|
+
const key = Buffer.from(b64Value, "base64");
|
|
2944
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
2945
|
+
if (migrated) {
|
|
2946
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
2947
|
+
}
|
|
2948
|
+
return key;
|
|
2822
2949
|
} catch (err) {
|
|
2823
2950
|
process.stderr.write(
|
|
2824
2951
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2827,12 +2954,13 @@ async function getMasterKey() {
|
|
|
2827
2954
|
return null;
|
|
2828
2955
|
}
|
|
2829
2956
|
}
|
|
2830
|
-
var SERVICE, ACCOUNT;
|
|
2957
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
2831
2958
|
var init_keychain = __esm({
|
|
2832
2959
|
"src/lib/keychain.ts"() {
|
|
2833
2960
|
"use strict";
|
|
2834
2961
|
SERVICE = "exe-mem";
|
|
2835
2962
|
ACCOUNT = "master-key";
|
|
2963
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
2836
2964
|
}
|
|
2837
2965
|
});
|
|
2838
2966
|
|
|
@@ -1042,8 +1042,8 @@ function findPackageRoot() {
|
|
|
1042
1042
|
function getAvailableMemoryGB() {
|
|
1043
1043
|
if (process.platform === "darwin") {
|
|
1044
1044
|
try {
|
|
1045
|
-
const { execSync:
|
|
1046
|
-
const vmstat =
|
|
1045
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1046
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1047
1047
|
const pageSize = 16384;
|
|
1048
1048
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1049
1049
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2782,6 +2782,7 @@ var init_database = __esm({
|
|
|
2782
2782
|
// src/lib/keychain.ts
|
|
2783
2783
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2784
2784
|
import { existsSync as existsSync6 } from "fs";
|
|
2785
|
+
import { execSync as execSync4 } from "child_process";
|
|
2785
2786
|
import path7 from "path";
|
|
2786
2787
|
import os5 from "os";
|
|
2787
2788
|
function getKeyDir() {
|
|
@@ -2790,6 +2791,59 @@ function getKeyDir() {
|
|
|
2790
2791
|
function getKeyPath() {
|
|
2791
2792
|
return path7.join(getKeyDir(), "master.key");
|
|
2792
2793
|
}
|
|
2794
|
+
function macKeychainGet() {
|
|
2795
|
+
if (process.platform !== "darwin") return null;
|
|
2796
|
+
try {
|
|
2797
|
+
return execSync4(
|
|
2798
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2799
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2800
|
+
).trim();
|
|
2801
|
+
} catch {
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
function macKeychainSet(value) {
|
|
2806
|
+
if (process.platform !== "darwin") return false;
|
|
2807
|
+
try {
|
|
2808
|
+
try {
|
|
2809
|
+
execSync4(
|
|
2810
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2811
|
+
{ timeout: 5e3 }
|
|
2812
|
+
);
|
|
2813
|
+
} catch {
|
|
2814
|
+
}
|
|
2815
|
+
execSync4(
|
|
2816
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2817
|
+
{ timeout: 5e3 }
|
|
2818
|
+
);
|
|
2819
|
+
return true;
|
|
2820
|
+
} catch {
|
|
2821
|
+
return false;
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
function linuxSecretGet() {
|
|
2825
|
+
if (process.platform !== "linux") return null;
|
|
2826
|
+
try {
|
|
2827
|
+
return execSync4(
|
|
2828
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2829
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2830
|
+
).trim();
|
|
2831
|
+
} catch {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
function linuxSecretSet(value) {
|
|
2836
|
+
if (process.platform !== "linux") return false;
|
|
2837
|
+
try {
|
|
2838
|
+
execSync4(
|
|
2839
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
2840
|
+
{ timeout: 5e3 }
|
|
2841
|
+
);
|
|
2842
|
+
return true;
|
|
2843
|
+
} catch {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2793
2847
|
async function tryKeytar() {
|
|
2794
2848
|
try {
|
|
2795
2849
|
return await import("keytar");
|
|
@@ -2797,13 +2851,63 @@ async function tryKeytar() {
|
|
|
2797
2851
|
return null;
|
|
2798
2852
|
}
|
|
2799
2853
|
}
|
|
2854
|
+
function deriveMachineKey() {
|
|
2855
|
+
try {
|
|
2856
|
+
const crypto2 = __require("crypto");
|
|
2857
|
+
const material = [
|
|
2858
|
+
os5.hostname(),
|
|
2859
|
+
os5.userInfo().username,
|
|
2860
|
+
os5.arch(),
|
|
2861
|
+
os5.platform(),
|
|
2862
|
+
// Machine ID on Linux (stable across reboots)
|
|
2863
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
2864
|
+
].join("|");
|
|
2865
|
+
return crypto2.createHash("sha256").update(material).digest();
|
|
2866
|
+
} catch {
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
function readMachineId() {
|
|
2871
|
+
try {
|
|
2872
|
+
const { readFileSync: readFileSync6 } = __require("fs");
|
|
2873
|
+
return readFileSync6("/etc/machine-id", "utf-8").trim();
|
|
2874
|
+
} catch {
|
|
2875
|
+
return "";
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
2879
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
2880
|
+
try {
|
|
2881
|
+
const crypto2 = __require("crypto");
|
|
2882
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
2883
|
+
if (parts.length !== 3) return null;
|
|
2884
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
2885
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
2886
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
2887
|
+
const decipher = crypto2.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
2888
|
+
decipher.setAuthTag(authTag);
|
|
2889
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
2890
|
+
decrypted += decipher.final("utf-8");
|
|
2891
|
+
return decrypted;
|
|
2892
|
+
} catch {
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2800
2896
|
async function getMasterKey() {
|
|
2897
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
2898
|
+
if (nativeValue) {
|
|
2899
|
+
return Buffer.from(nativeValue, "base64");
|
|
2900
|
+
}
|
|
2801
2901
|
const keytar = await tryKeytar();
|
|
2802
2902
|
if (keytar) {
|
|
2803
2903
|
try {
|
|
2804
|
-
const
|
|
2805
|
-
if (
|
|
2806
|
-
|
|
2904
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
2905
|
+
if (keytarValue) {
|
|
2906
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
2907
|
+
if (migrated) {
|
|
2908
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
2909
|
+
}
|
|
2910
|
+
return Buffer.from(keytarValue, "base64");
|
|
2807
2911
|
}
|
|
2808
2912
|
} catch {
|
|
2809
2913
|
}
|
|
@@ -2817,8 +2921,31 @@ async function getMasterKey() {
|
|
|
2817
2921
|
return null;
|
|
2818
2922
|
}
|
|
2819
2923
|
try {
|
|
2820
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
2821
|
-
|
|
2924
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
2925
|
+
let b64Value;
|
|
2926
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
2927
|
+
const machineKey = deriveMachineKey();
|
|
2928
|
+
if (!machineKey) {
|
|
2929
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
2930
|
+
return null;
|
|
2931
|
+
}
|
|
2932
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
2933
|
+
if (!decrypted) {
|
|
2934
|
+
process.stderr.write(
|
|
2935
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
2936
|
+
);
|
|
2937
|
+
return null;
|
|
2938
|
+
}
|
|
2939
|
+
b64Value = decrypted;
|
|
2940
|
+
} else {
|
|
2941
|
+
b64Value = content;
|
|
2942
|
+
}
|
|
2943
|
+
const key = Buffer.from(b64Value, "base64");
|
|
2944
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
2945
|
+
if (migrated) {
|
|
2946
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
2947
|
+
}
|
|
2948
|
+
return key;
|
|
2822
2949
|
} catch (err) {
|
|
2823
2950
|
process.stderr.write(
|
|
2824
2951
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2827,12 +2954,13 @@ async function getMasterKey() {
|
|
|
2827
2954
|
return null;
|
|
2828
2955
|
}
|
|
2829
2956
|
}
|
|
2830
|
-
var SERVICE, ACCOUNT;
|
|
2957
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
2831
2958
|
var init_keychain = __esm({
|
|
2832
2959
|
"src/lib/keychain.ts"() {
|
|
2833
2960
|
"use strict";
|
|
2834
2961
|
SERVICE = "exe-mem";
|
|
2835
2962
|
ACCOUNT = "master-key";
|
|
2963
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
2836
2964
|
}
|
|
2837
2965
|
});
|
|
2838
2966
|
|