@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/lib/schedules.js
CHANGED
|
@@ -1028,8 +1028,8 @@ function findPackageRoot() {
|
|
|
1028
1028
|
function getAvailableMemoryGB() {
|
|
1029
1029
|
if (process.platform === "darwin") {
|
|
1030
1030
|
try {
|
|
1031
|
-
const { execSync:
|
|
1032
|
-
const vmstat =
|
|
1031
|
+
const { execSync: execSync4 } = __require("child_process");
|
|
1032
|
+
const vmstat = execSync4("vm_stat", { encoding: "utf8" });
|
|
1033
1033
|
const pageSize = 16384;
|
|
1034
1034
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1035
1035
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3135,7 +3135,7 @@ ${p.content}`).join("\n\n");
|
|
|
3135
3135
|
// src/lib/schedules.ts
|
|
3136
3136
|
init_database();
|
|
3137
3137
|
import crypto2 from "crypto";
|
|
3138
|
-
import { execSync as
|
|
3138
|
+
import { execSync as execSync3 } from "child_process";
|
|
3139
3139
|
|
|
3140
3140
|
// src/lib/store.ts
|
|
3141
3141
|
init_memory();
|
|
@@ -3145,6 +3145,7 @@ import { createHash } from "crypto";
|
|
|
3145
3145
|
// src/lib/keychain.ts
|
|
3146
3146
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3147
3147
|
import { existsSync as existsSync6 } from "fs";
|
|
3148
|
+
import { execSync as execSync2 } from "child_process";
|
|
3148
3149
|
import path6 from "path";
|
|
3149
3150
|
import os5 from "os";
|
|
3150
3151
|
var SERVICE = "exe-mem";
|
|
@@ -3155,6 +3156,59 @@ function getKeyDir() {
|
|
|
3155
3156
|
function getKeyPath() {
|
|
3156
3157
|
return path6.join(getKeyDir(), "master.key");
|
|
3157
3158
|
}
|
|
3159
|
+
function macKeychainGet() {
|
|
3160
|
+
if (process.platform !== "darwin") return null;
|
|
3161
|
+
try {
|
|
3162
|
+
return execSync2(
|
|
3163
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3164
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3165
|
+
).trim();
|
|
3166
|
+
} catch {
|
|
3167
|
+
return null;
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
function macKeychainSet(value) {
|
|
3171
|
+
if (process.platform !== "darwin") return false;
|
|
3172
|
+
try {
|
|
3173
|
+
try {
|
|
3174
|
+
execSync2(
|
|
3175
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3176
|
+
{ timeout: 5e3 }
|
|
3177
|
+
);
|
|
3178
|
+
} catch {
|
|
3179
|
+
}
|
|
3180
|
+
execSync2(
|
|
3181
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3182
|
+
{ timeout: 5e3 }
|
|
3183
|
+
);
|
|
3184
|
+
return true;
|
|
3185
|
+
} catch {
|
|
3186
|
+
return false;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
function linuxSecretGet() {
|
|
3190
|
+
if (process.platform !== "linux") return null;
|
|
3191
|
+
try {
|
|
3192
|
+
return execSync2(
|
|
3193
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3194
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3195
|
+
).trim();
|
|
3196
|
+
} catch {
|
|
3197
|
+
return null;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
function linuxSecretSet(value) {
|
|
3201
|
+
if (process.platform !== "linux") return false;
|
|
3202
|
+
try {
|
|
3203
|
+
execSync2(
|
|
3204
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3205
|
+
{ timeout: 5e3 }
|
|
3206
|
+
);
|
|
3207
|
+
return true;
|
|
3208
|
+
} catch {
|
|
3209
|
+
return false;
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3158
3212
|
async function tryKeytar() {
|
|
3159
3213
|
try {
|
|
3160
3214
|
return await import("keytar");
|
|
@@ -3162,13 +3216,64 @@ async function tryKeytar() {
|
|
|
3162
3216
|
return null;
|
|
3163
3217
|
}
|
|
3164
3218
|
}
|
|
3219
|
+
var ENCRYPTED_PREFIX = "enc:";
|
|
3220
|
+
function deriveMachineKey() {
|
|
3221
|
+
try {
|
|
3222
|
+
const crypto3 = __require("crypto");
|
|
3223
|
+
const material = [
|
|
3224
|
+
os5.hostname(),
|
|
3225
|
+
os5.userInfo().username,
|
|
3226
|
+
os5.arch(),
|
|
3227
|
+
os5.platform(),
|
|
3228
|
+
// Machine ID on Linux (stable across reboots)
|
|
3229
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3230
|
+
].join("|");
|
|
3231
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
3232
|
+
} catch {
|
|
3233
|
+
return null;
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
function readMachineId() {
|
|
3237
|
+
try {
|
|
3238
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
3239
|
+
return readFileSync5("/etc/machine-id", "utf-8").trim();
|
|
3240
|
+
} catch {
|
|
3241
|
+
return "";
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3245
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3246
|
+
try {
|
|
3247
|
+
const crypto3 = __require("crypto");
|
|
3248
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3249
|
+
if (parts.length !== 3) return null;
|
|
3250
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3251
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3252
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3253
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3254
|
+
decipher.setAuthTag(authTag);
|
|
3255
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3256
|
+
decrypted += decipher.final("utf-8");
|
|
3257
|
+
return decrypted;
|
|
3258
|
+
} catch {
|
|
3259
|
+
return null;
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3165
3262
|
async function getMasterKey() {
|
|
3263
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3264
|
+
if (nativeValue) {
|
|
3265
|
+
return Buffer.from(nativeValue, "base64");
|
|
3266
|
+
}
|
|
3166
3267
|
const keytar = await tryKeytar();
|
|
3167
3268
|
if (keytar) {
|
|
3168
3269
|
try {
|
|
3169
|
-
const
|
|
3170
|
-
if (
|
|
3171
|
-
|
|
3270
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3271
|
+
if (keytarValue) {
|
|
3272
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3273
|
+
if (migrated) {
|
|
3274
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3275
|
+
}
|
|
3276
|
+
return Buffer.from(keytarValue, "base64");
|
|
3172
3277
|
}
|
|
3173
3278
|
} catch {
|
|
3174
3279
|
}
|
|
@@ -3182,8 +3287,31 @@ async function getMasterKey() {
|
|
|
3182
3287
|
return null;
|
|
3183
3288
|
}
|
|
3184
3289
|
try {
|
|
3185
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3186
|
-
|
|
3290
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3291
|
+
let b64Value;
|
|
3292
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3293
|
+
const machineKey = deriveMachineKey();
|
|
3294
|
+
if (!machineKey) {
|
|
3295
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3296
|
+
return null;
|
|
3297
|
+
}
|
|
3298
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3299
|
+
if (!decrypted) {
|
|
3300
|
+
process.stderr.write(
|
|
3301
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3302
|
+
);
|
|
3303
|
+
return null;
|
|
3304
|
+
}
|
|
3305
|
+
b64Value = decrypted;
|
|
3306
|
+
} else {
|
|
3307
|
+
b64Value = content;
|
|
3308
|
+
}
|
|
3309
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3310
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3311
|
+
if (migrated) {
|
|
3312
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3313
|
+
}
|
|
3314
|
+
return key;
|
|
3187
3315
|
} catch (err) {
|
|
3188
3316
|
process.stderr.write(
|
|
3189
3317
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3492,7 +3620,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
3492
3620
|
const cwd = projectDir ? `cd ${JSON.stringify(projectDir)} && ` : "";
|
|
3493
3621
|
const escapedPrompt = prompt.replace(/"/g, '\\"');
|
|
3494
3622
|
const entry = `${cron} ${cwd}claude -p --dangerously-skip-permissions "${escapedPrompt}" # exe-schedule:${id}`;
|
|
3495
|
-
|
|
3623
|
+
execSync3(
|
|
3496
3624
|
`(crontab -l 2>/dev/null; echo ${JSON.stringify(entry)}) | crontab -`,
|
|
3497
3625
|
{ timeout: 5e3, stdio: "ignore" }
|
|
3498
3626
|
);
|
|
@@ -3503,7 +3631,7 @@ function addToCrontab(id, cron, prompt, projectDir) {
|
|
|
3503
3631
|
function removeFromCrontab(id) {
|
|
3504
3632
|
if (!isValidScheduleId(id)) return;
|
|
3505
3633
|
try {
|
|
3506
|
-
|
|
3634
|
+
execSync3(
|
|
3507
3635
|
`crontab -l 2>/dev/null | grep -v "exe-schedule:${id}" | crontab -`,
|
|
3508
3636
|
{ timeout: 5e3, stdio: "ignore" }
|
|
3509
3637
|
);
|
package/dist/lib/store.js
CHANGED
|
@@ -1028,8 +1028,8 @@ function findPackageRoot() {
|
|
|
1028
1028
|
function getAvailableMemoryGB() {
|
|
1029
1029
|
if (process.platform === "darwin") {
|
|
1030
1030
|
try {
|
|
1031
|
-
const { execSync:
|
|
1032
|
-
const vmstat =
|
|
1031
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
1032
|
+
const vmstat = execSync3("vm_stat", { encoding: "utf8" });
|
|
1033
1033
|
const pageSize = 16384;
|
|
1034
1034
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1035
1035
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3140,6 +3140,7 @@ import { createHash } from "crypto";
|
|
|
3140
3140
|
// src/lib/keychain.ts
|
|
3141
3141
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3142
3142
|
import { existsSync as existsSync6 } from "fs";
|
|
3143
|
+
import { execSync as execSync2 } from "child_process";
|
|
3143
3144
|
import path6 from "path";
|
|
3144
3145
|
import os5 from "os";
|
|
3145
3146
|
var SERVICE = "exe-mem";
|
|
@@ -3150,6 +3151,59 @@ function getKeyDir() {
|
|
|
3150
3151
|
function getKeyPath() {
|
|
3151
3152
|
return path6.join(getKeyDir(), "master.key");
|
|
3152
3153
|
}
|
|
3154
|
+
function macKeychainGet() {
|
|
3155
|
+
if (process.platform !== "darwin") return null;
|
|
3156
|
+
try {
|
|
3157
|
+
return execSync2(
|
|
3158
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3159
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3160
|
+
).trim();
|
|
3161
|
+
} catch {
|
|
3162
|
+
return null;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function macKeychainSet(value) {
|
|
3166
|
+
if (process.platform !== "darwin") return false;
|
|
3167
|
+
try {
|
|
3168
|
+
try {
|
|
3169
|
+
execSync2(
|
|
3170
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3171
|
+
{ timeout: 5e3 }
|
|
3172
|
+
);
|
|
3173
|
+
} catch {
|
|
3174
|
+
}
|
|
3175
|
+
execSync2(
|
|
3176
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3177
|
+
{ timeout: 5e3 }
|
|
3178
|
+
);
|
|
3179
|
+
return true;
|
|
3180
|
+
} catch {
|
|
3181
|
+
return false;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
function linuxSecretGet() {
|
|
3185
|
+
if (process.platform !== "linux") return null;
|
|
3186
|
+
try {
|
|
3187
|
+
return execSync2(
|
|
3188
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3189
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3190
|
+
).trim();
|
|
3191
|
+
} catch {
|
|
3192
|
+
return null;
|
|
3193
|
+
}
|
|
3194
|
+
}
|
|
3195
|
+
function linuxSecretSet(value) {
|
|
3196
|
+
if (process.platform !== "linux") return false;
|
|
3197
|
+
try {
|
|
3198
|
+
execSync2(
|
|
3199
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3200
|
+
{ timeout: 5e3 }
|
|
3201
|
+
);
|
|
3202
|
+
return true;
|
|
3203
|
+
} catch {
|
|
3204
|
+
return false;
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3153
3207
|
async function tryKeytar() {
|
|
3154
3208
|
try {
|
|
3155
3209
|
return await import("keytar");
|
|
@@ -3157,13 +3211,64 @@ async function tryKeytar() {
|
|
|
3157
3211
|
return null;
|
|
3158
3212
|
}
|
|
3159
3213
|
}
|
|
3214
|
+
var ENCRYPTED_PREFIX = "enc:";
|
|
3215
|
+
function deriveMachineKey() {
|
|
3216
|
+
try {
|
|
3217
|
+
const crypto2 = __require("crypto");
|
|
3218
|
+
const material = [
|
|
3219
|
+
os5.hostname(),
|
|
3220
|
+
os5.userInfo().username,
|
|
3221
|
+
os5.arch(),
|
|
3222
|
+
os5.platform(),
|
|
3223
|
+
// Machine ID on Linux (stable across reboots)
|
|
3224
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3225
|
+
].join("|");
|
|
3226
|
+
return crypto2.createHash("sha256").update(material).digest();
|
|
3227
|
+
} catch {
|
|
3228
|
+
return null;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
function readMachineId() {
|
|
3232
|
+
try {
|
|
3233
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
3234
|
+
return readFileSync5("/etc/machine-id", "utf-8").trim();
|
|
3235
|
+
} catch {
|
|
3236
|
+
return "";
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3240
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3241
|
+
try {
|
|
3242
|
+
const crypto2 = __require("crypto");
|
|
3243
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3244
|
+
if (parts.length !== 3) return null;
|
|
3245
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3246
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3247
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3248
|
+
const decipher = crypto2.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3249
|
+
decipher.setAuthTag(authTag);
|
|
3250
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3251
|
+
decrypted += decipher.final("utf-8");
|
|
3252
|
+
return decrypted;
|
|
3253
|
+
} catch {
|
|
3254
|
+
return null;
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3160
3257
|
async function getMasterKey() {
|
|
3258
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3259
|
+
if (nativeValue) {
|
|
3260
|
+
return Buffer.from(nativeValue, "base64");
|
|
3261
|
+
}
|
|
3161
3262
|
const keytar = await tryKeytar();
|
|
3162
3263
|
if (keytar) {
|
|
3163
3264
|
try {
|
|
3164
|
-
const
|
|
3165
|
-
if (
|
|
3166
|
-
|
|
3265
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3266
|
+
if (keytarValue) {
|
|
3267
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3268
|
+
if (migrated) {
|
|
3269
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3270
|
+
}
|
|
3271
|
+
return Buffer.from(keytarValue, "base64");
|
|
3167
3272
|
}
|
|
3168
3273
|
} catch {
|
|
3169
3274
|
}
|
|
@@ -3177,8 +3282,31 @@ async function getMasterKey() {
|
|
|
3177
3282
|
return null;
|
|
3178
3283
|
}
|
|
3179
3284
|
try {
|
|
3180
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3181
|
-
|
|
3285
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3286
|
+
let b64Value;
|
|
3287
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3288
|
+
const machineKey = deriveMachineKey();
|
|
3289
|
+
if (!machineKey) {
|
|
3290
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3291
|
+
return null;
|
|
3292
|
+
}
|
|
3293
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3294
|
+
if (!decrypted) {
|
|
3295
|
+
process.stderr.write(
|
|
3296
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3297
|
+
);
|
|
3298
|
+
return null;
|
|
3299
|
+
}
|
|
3300
|
+
b64Value = decrypted;
|
|
3301
|
+
} else {
|
|
3302
|
+
b64Value = content;
|
|
3303
|
+
}
|
|
3304
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3305
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3306
|
+
if (migrated) {
|
|
3307
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3308
|
+
}
|
|
3309
|
+
return key;
|
|
3182
3310
|
} catch (err) {
|
|
3183
3311
|
process.stderr.write(
|
|
3184
3312
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|