@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
|
@@ -1050,8 +1050,8 @@ function findPackageRoot() {
|
|
|
1050
1050
|
function getAvailableMemoryGB() {
|
|
1051
1051
|
if (process.platform === "darwin") {
|
|
1052
1052
|
try {
|
|
1053
|
-
const { execSync:
|
|
1054
|
-
const vmstat =
|
|
1053
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1054
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1055
1055
|
const pageSize = 16384;
|
|
1056
1056
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1057
1057
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3199,6 +3199,7 @@ var init_task_scope = __esm({
|
|
|
3199
3199
|
// src/lib/keychain.ts
|
|
3200
3200
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3201
3201
|
import { existsSync as existsSync11 } from "fs";
|
|
3202
|
+
import { execSync as execSync4 } from "child_process";
|
|
3202
3203
|
import path12 from "path";
|
|
3203
3204
|
import os9 from "os";
|
|
3204
3205
|
function getKeyDir() {
|
|
@@ -3207,6 +3208,59 @@ function getKeyDir() {
|
|
|
3207
3208
|
function getKeyPath() {
|
|
3208
3209
|
return path12.join(getKeyDir(), "master.key");
|
|
3209
3210
|
}
|
|
3211
|
+
function macKeychainGet() {
|
|
3212
|
+
if (process.platform !== "darwin") return null;
|
|
3213
|
+
try {
|
|
3214
|
+
return execSync4(
|
|
3215
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3216
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3217
|
+
).trim();
|
|
3218
|
+
} catch {
|
|
3219
|
+
return null;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
function macKeychainSet(value) {
|
|
3223
|
+
if (process.platform !== "darwin") return false;
|
|
3224
|
+
try {
|
|
3225
|
+
try {
|
|
3226
|
+
execSync4(
|
|
3227
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3228
|
+
{ timeout: 5e3 }
|
|
3229
|
+
);
|
|
3230
|
+
} catch {
|
|
3231
|
+
}
|
|
3232
|
+
execSync4(
|
|
3233
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3234
|
+
{ timeout: 5e3 }
|
|
3235
|
+
);
|
|
3236
|
+
return true;
|
|
3237
|
+
} catch {
|
|
3238
|
+
return false;
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
function linuxSecretGet() {
|
|
3242
|
+
if (process.platform !== "linux") return null;
|
|
3243
|
+
try {
|
|
3244
|
+
return execSync4(
|
|
3245
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3246
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3247
|
+
).trim();
|
|
3248
|
+
} catch {
|
|
3249
|
+
return null;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
function linuxSecretSet(value) {
|
|
3253
|
+
if (process.platform !== "linux") return false;
|
|
3254
|
+
try {
|
|
3255
|
+
execSync4(
|
|
3256
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3257
|
+
{ timeout: 5e3 }
|
|
3258
|
+
);
|
|
3259
|
+
return true;
|
|
3260
|
+
} catch {
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3210
3264
|
async function tryKeytar() {
|
|
3211
3265
|
try {
|
|
3212
3266
|
return await import("keytar");
|
|
@@ -3214,13 +3268,63 @@ async function tryKeytar() {
|
|
|
3214
3268
|
return null;
|
|
3215
3269
|
}
|
|
3216
3270
|
}
|
|
3271
|
+
function deriveMachineKey() {
|
|
3272
|
+
try {
|
|
3273
|
+
const crypto3 = __require("crypto");
|
|
3274
|
+
const material = [
|
|
3275
|
+
os9.hostname(),
|
|
3276
|
+
os9.userInfo().username,
|
|
3277
|
+
os9.arch(),
|
|
3278
|
+
os9.platform(),
|
|
3279
|
+
// Machine ID on Linux (stable across reboots)
|
|
3280
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3281
|
+
].join("|");
|
|
3282
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
3283
|
+
} catch {
|
|
3284
|
+
return null;
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
function readMachineId() {
|
|
3288
|
+
try {
|
|
3289
|
+
const { readFileSync: readFileSync10 } = __require("fs");
|
|
3290
|
+
return readFileSync10("/etc/machine-id", "utf-8").trim();
|
|
3291
|
+
} catch {
|
|
3292
|
+
return "";
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3296
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3297
|
+
try {
|
|
3298
|
+
const crypto3 = __require("crypto");
|
|
3299
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3300
|
+
if (parts.length !== 3) return null;
|
|
3301
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3302
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3303
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3304
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3305
|
+
decipher.setAuthTag(authTag);
|
|
3306
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3307
|
+
decrypted += decipher.final("utf-8");
|
|
3308
|
+
return decrypted;
|
|
3309
|
+
} catch {
|
|
3310
|
+
return null;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3217
3313
|
async function getMasterKey() {
|
|
3314
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3315
|
+
if (nativeValue) {
|
|
3316
|
+
return Buffer.from(nativeValue, "base64");
|
|
3317
|
+
}
|
|
3218
3318
|
const keytar = await tryKeytar();
|
|
3219
3319
|
if (keytar) {
|
|
3220
3320
|
try {
|
|
3221
|
-
const
|
|
3222
|
-
if (
|
|
3223
|
-
|
|
3321
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3322
|
+
if (keytarValue) {
|
|
3323
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3324
|
+
if (migrated) {
|
|
3325
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3326
|
+
}
|
|
3327
|
+
return Buffer.from(keytarValue, "base64");
|
|
3224
3328
|
}
|
|
3225
3329
|
} catch {
|
|
3226
3330
|
}
|
|
@@ -3234,8 +3338,31 @@ async function getMasterKey() {
|
|
|
3234
3338
|
return null;
|
|
3235
3339
|
}
|
|
3236
3340
|
try {
|
|
3237
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3238
|
-
|
|
3341
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3342
|
+
let b64Value;
|
|
3343
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3344
|
+
const machineKey = deriveMachineKey();
|
|
3345
|
+
if (!machineKey) {
|
|
3346
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3347
|
+
return null;
|
|
3348
|
+
}
|
|
3349
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3350
|
+
if (!decrypted) {
|
|
3351
|
+
process.stderr.write(
|
|
3352
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3353
|
+
);
|
|
3354
|
+
return null;
|
|
3355
|
+
}
|
|
3356
|
+
b64Value = decrypted;
|
|
3357
|
+
} else {
|
|
3358
|
+
b64Value = content;
|
|
3359
|
+
}
|
|
3360
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3361
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3362
|
+
if (migrated) {
|
|
3363
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3364
|
+
}
|
|
3365
|
+
return key;
|
|
3239
3366
|
} catch (err) {
|
|
3240
3367
|
process.stderr.write(
|
|
3241
3368
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3244,12 +3371,13 @@ async function getMasterKey() {
|
|
|
3244
3371
|
return null;
|
|
3245
3372
|
}
|
|
3246
3373
|
}
|
|
3247
|
-
var SERVICE, ACCOUNT;
|
|
3374
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3248
3375
|
var init_keychain = __esm({
|
|
3249
3376
|
"src/lib/keychain.ts"() {
|
|
3250
3377
|
"use strict";
|
|
3251
3378
|
SERVICE = "exe-mem";
|
|
3252
3379
|
ACCOUNT = "master-key";
|
|
3380
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3253
3381
|
}
|
|
3254
3382
|
});
|
|
3255
3383
|
|
|
@@ -1051,8 +1051,8 @@ function findPackageRoot() {
|
|
|
1051
1051
|
function getAvailableMemoryGB() {
|
|
1052
1052
|
if (process.platform === "darwin") {
|
|
1053
1053
|
try {
|
|
1054
|
-
const { execSync:
|
|
1055
|
-
const vmstat =
|
|
1054
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1055
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1056
1056
|
const pageSize = 16384;
|
|
1057
1057
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1058
1058
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3265,6 +3265,7 @@ var init_notifications = __esm({
|
|
|
3265
3265
|
// src/lib/keychain.ts
|
|
3266
3266
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3267
3267
|
import { existsSync as existsSync12 } from "fs";
|
|
3268
|
+
import { execSync as execSync4 } from "child_process";
|
|
3268
3269
|
import path13 from "path";
|
|
3269
3270
|
import os10 from "os";
|
|
3270
3271
|
function getKeyDir() {
|
|
@@ -3273,6 +3274,59 @@ function getKeyDir() {
|
|
|
3273
3274
|
function getKeyPath() {
|
|
3274
3275
|
return path13.join(getKeyDir(), "master.key");
|
|
3275
3276
|
}
|
|
3277
|
+
function macKeychainGet() {
|
|
3278
|
+
if (process.platform !== "darwin") return null;
|
|
3279
|
+
try {
|
|
3280
|
+
return execSync4(
|
|
3281
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3282
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3283
|
+
).trim();
|
|
3284
|
+
} catch {
|
|
3285
|
+
return null;
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
function macKeychainSet(value) {
|
|
3289
|
+
if (process.platform !== "darwin") return false;
|
|
3290
|
+
try {
|
|
3291
|
+
try {
|
|
3292
|
+
execSync4(
|
|
3293
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3294
|
+
{ timeout: 5e3 }
|
|
3295
|
+
);
|
|
3296
|
+
} catch {
|
|
3297
|
+
}
|
|
3298
|
+
execSync4(
|
|
3299
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3300
|
+
{ timeout: 5e3 }
|
|
3301
|
+
);
|
|
3302
|
+
return true;
|
|
3303
|
+
} catch {
|
|
3304
|
+
return false;
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
function linuxSecretGet() {
|
|
3308
|
+
if (process.platform !== "linux") return null;
|
|
3309
|
+
try {
|
|
3310
|
+
return execSync4(
|
|
3311
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3312
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3313
|
+
).trim();
|
|
3314
|
+
} catch {
|
|
3315
|
+
return null;
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
function linuxSecretSet(value) {
|
|
3319
|
+
if (process.platform !== "linux") return false;
|
|
3320
|
+
try {
|
|
3321
|
+
execSync4(
|
|
3322
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3323
|
+
{ timeout: 5e3 }
|
|
3324
|
+
);
|
|
3325
|
+
return true;
|
|
3326
|
+
} catch {
|
|
3327
|
+
return false;
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3276
3330
|
async function tryKeytar() {
|
|
3277
3331
|
try {
|
|
3278
3332
|
return await import("keytar");
|
|
@@ -3280,13 +3334,63 @@ async function tryKeytar() {
|
|
|
3280
3334
|
return null;
|
|
3281
3335
|
}
|
|
3282
3336
|
}
|
|
3337
|
+
function deriveMachineKey() {
|
|
3338
|
+
try {
|
|
3339
|
+
const crypto3 = __require("crypto");
|
|
3340
|
+
const material = [
|
|
3341
|
+
os10.hostname(),
|
|
3342
|
+
os10.userInfo().username,
|
|
3343
|
+
os10.arch(),
|
|
3344
|
+
os10.platform(),
|
|
3345
|
+
// Machine ID on Linux (stable across reboots)
|
|
3346
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3347
|
+
].join("|");
|
|
3348
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
3349
|
+
} catch {
|
|
3350
|
+
return null;
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
function readMachineId() {
|
|
3354
|
+
try {
|
|
3355
|
+
const { readFileSync: readFileSync11 } = __require("fs");
|
|
3356
|
+
return readFileSync11("/etc/machine-id", "utf-8").trim();
|
|
3357
|
+
} catch {
|
|
3358
|
+
return "";
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3362
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3363
|
+
try {
|
|
3364
|
+
const crypto3 = __require("crypto");
|
|
3365
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3366
|
+
if (parts.length !== 3) return null;
|
|
3367
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3368
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3369
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3370
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3371
|
+
decipher.setAuthTag(authTag);
|
|
3372
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3373
|
+
decrypted += decipher.final("utf-8");
|
|
3374
|
+
return decrypted;
|
|
3375
|
+
} catch {
|
|
3376
|
+
return null;
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3283
3379
|
async function getMasterKey() {
|
|
3380
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3381
|
+
if (nativeValue) {
|
|
3382
|
+
return Buffer.from(nativeValue, "base64");
|
|
3383
|
+
}
|
|
3284
3384
|
const keytar = await tryKeytar();
|
|
3285
3385
|
if (keytar) {
|
|
3286
3386
|
try {
|
|
3287
|
-
const
|
|
3288
|
-
if (
|
|
3289
|
-
|
|
3387
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3388
|
+
if (keytarValue) {
|
|
3389
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3390
|
+
if (migrated) {
|
|
3391
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3392
|
+
}
|
|
3393
|
+
return Buffer.from(keytarValue, "base64");
|
|
3290
3394
|
}
|
|
3291
3395
|
} catch {
|
|
3292
3396
|
}
|
|
@@ -3300,8 +3404,31 @@ async function getMasterKey() {
|
|
|
3300
3404
|
return null;
|
|
3301
3405
|
}
|
|
3302
3406
|
try {
|
|
3303
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3304
|
-
|
|
3407
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3408
|
+
let b64Value;
|
|
3409
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3410
|
+
const machineKey = deriveMachineKey();
|
|
3411
|
+
if (!machineKey) {
|
|
3412
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3413
|
+
return null;
|
|
3414
|
+
}
|
|
3415
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3416
|
+
if (!decrypted) {
|
|
3417
|
+
process.stderr.write(
|
|
3418
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3419
|
+
);
|
|
3420
|
+
return null;
|
|
3421
|
+
}
|
|
3422
|
+
b64Value = decrypted;
|
|
3423
|
+
} else {
|
|
3424
|
+
b64Value = content;
|
|
3425
|
+
}
|
|
3426
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3427
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3428
|
+
if (migrated) {
|
|
3429
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3430
|
+
}
|
|
3431
|
+
return key;
|
|
3305
3432
|
} catch (err) {
|
|
3306
3433
|
process.stderr.write(
|
|
3307
3434
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3310,12 +3437,13 @@ async function getMasterKey() {
|
|
|
3310
3437
|
return null;
|
|
3311
3438
|
}
|
|
3312
3439
|
}
|
|
3313
|
-
var SERVICE, ACCOUNT;
|
|
3440
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3314
3441
|
var init_keychain = __esm({
|
|
3315
3442
|
"src/lib/keychain.ts"() {
|
|
3316
3443
|
"use strict";
|
|
3317
3444
|
SERVICE = "exe-mem";
|
|
3318
3445
|
ACCOUNT = "master-key";
|
|
3446
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3319
3447
|
}
|
|
3320
3448
|
});
|
|
3321
3449
|
|
|
@@ -1051,8 +1051,8 @@ function findPackageRoot() {
|
|
|
1051
1051
|
function getAvailableMemoryGB() {
|
|
1052
1052
|
if (process.platform === "darwin") {
|
|
1053
1053
|
try {
|
|
1054
|
-
const { execSync:
|
|
1055
|
-
const vmstat =
|
|
1054
|
+
const { execSync: execSync5 } = __require("child_process");
|
|
1055
|
+
const vmstat = execSync5("vm_stat", { encoding: "utf8" });
|
|
1056
1056
|
const pageSize = 16384;
|
|
1057
1057
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1058
1058
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3359,6 +3359,7 @@ var init_tasks_review = __esm({
|
|
|
3359
3359
|
// src/lib/keychain.ts
|
|
3360
3360
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3361
3361
|
import { existsSync as existsSync13 } from "fs";
|
|
3362
|
+
import { execSync as execSync4 } from "child_process";
|
|
3362
3363
|
import path14 from "path";
|
|
3363
3364
|
import os10 from "os";
|
|
3364
3365
|
function getKeyDir() {
|
|
@@ -3367,6 +3368,59 @@ function getKeyDir() {
|
|
|
3367
3368
|
function getKeyPath() {
|
|
3368
3369
|
return path14.join(getKeyDir(), "master.key");
|
|
3369
3370
|
}
|
|
3371
|
+
function macKeychainGet() {
|
|
3372
|
+
if (process.platform !== "darwin") return null;
|
|
3373
|
+
try {
|
|
3374
|
+
return execSync4(
|
|
3375
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3376
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3377
|
+
).trim();
|
|
3378
|
+
} catch {
|
|
3379
|
+
return null;
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
function macKeychainSet(value) {
|
|
3383
|
+
if (process.platform !== "darwin") return false;
|
|
3384
|
+
try {
|
|
3385
|
+
try {
|
|
3386
|
+
execSync4(
|
|
3387
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3388
|
+
{ timeout: 5e3 }
|
|
3389
|
+
);
|
|
3390
|
+
} catch {
|
|
3391
|
+
}
|
|
3392
|
+
execSync4(
|
|
3393
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3394
|
+
{ timeout: 5e3 }
|
|
3395
|
+
);
|
|
3396
|
+
return true;
|
|
3397
|
+
} catch {
|
|
3398
|
+
return false;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
function linuxSecretGet() {
|
|
3402
|
+
if (process.platform !== "linux") return null;
|
|
3403
|
+
try {
|
|
3404
|
+
return execSync4(
|
|
3405
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3406
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3407
|
+
).trim();
|
|
3408
|
+
} catch {
|
|
3409
|
+
return null;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
function linuxSecretSet(value) {
|
|
3413
|
+
if (process.platform !== "linux") return false;
|
|
3414
|
+
try {
|
|
3415
|
+
execSync4(
|
|
3416
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3417
|
+
{ timeout: 5e3 }
|
|
3418
|
+
);
|
|
3419
|
+
return true;
|
|
3420
|
+
} catch {
|
|
3421
|
+
return false;
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3370
3424
|
async function tryKeytar() {
|
|
3371
3425
|
try {
|
|
3372
3426
|
return await import("keytar");
|
|
@@ -3374,13 +3428,63 @@ async function tryKeytar() {
|
|
|
3374
3428
|
return null;
|
|
3375
3429
|
}
|
|
3376
3430
|
}
|
|
3431
|
+
function deriveMachineKey() {
|
|
3432
|
+
try {
|
|
3433
|
+
const crypto3 = __require("crypto");
|
|
3434
|
+
const material = [
|
|
3435
|
+
os10.hostname(),
|
|
3436
|
+
os10.userInfo().username,
|
|
3437
|
+
os10.arch(),
|
|
3438
|
+
os10.platform(),
|
|
3439
|
+
// Machine ID on Linux (stable across reboots)
|
|
3440
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3441
|
+
].join("|");
|
|
3442
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
3443
|
+
} catch {
|
|
3444
|
+
return null;
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
function readMachineId() {
|
|
3448
|
+
try {
|
|
3449
|
+
const { readFileSync: readFileSync11 } = __require("fs");
|
|
3450
|
+
return readFileSync11("/etc/machine-id", "utf-8").trim();
|
|
3451
|
+
} catch {
|
|
3452
|
+
return "";
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3456
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3457
|
+
try {
|
|
3458
|
+
const crypto3 = __require("crypto");
|
|
3459
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3460
|
+
if (parts.length !== 3) return null;
|
|
3461
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3462
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3463
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3464
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3465
|
+
decipher.setAuthTag(authTag);
|
|
3466
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3467
|
+
decrypted += decipher.final("utf-8");
|
|
3468
|
+
return decrypted;
|
|
3469
|
+
} catch {
|
|
3470
|
+
return null;
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3377
3473
|
async function getMasterKey() {
|
|
3474
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3475
|
+
if (nativeValue) {
|
|
3476
|
+
return Buffer.from(nativeValue, "base64");
|
|
3477
|
+
}
|
|
3378
3478
|
const keytar = await tryKeytar();
|
|
3379
3479
|
if (keytar) {
|
|
3380
3480
|
try {
|
|
3381
|
-
const
|
|
3382
|
-
if (
|
|
3383
|
-
|
|
3481
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3482
|
+
if (keytarValue) {
|
|
3483
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3484
|
+
if (migrated) {
|
|
3485
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3486
|
+
}
|
|
3487
|
+
return Buffer.from(keytarValue, "base64");
|
|
3384
3488
|
}
|
|
3385
3489
|
} catch {
|
|
3386
3490
|
}
|
|
@@ -3394,8 +3498,31 @@ async function getMasterKey() {
|
|
|
3394
3498
|
return null;
|
|
3395
3499
|
}
|
|
3396
3500
|
try {
|
|
3397
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3398
|
-
|
|
3501
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3502
|
+
let b64Value;
|
|
3503
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3504
|
+
const machineKey = deriveMachineKey();
|
|
3505
|
+
if (!machineKey) {
|
|
3506
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3507
|
+
return null;
|
|
3508
|
+
}
|
|
3509
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3510
|
+
if (!decrypted) {
|
|
3511
|
+
process.stderr.write(
|
|
3512
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3513
|
+
);
|
|
3514
|
+
return null;
|
|
3515
|
+
}
|
|
3516
|
+
b64Value = decrypted;
|
|
3517
|
+
} else {
|
|
3518
|
+
b64Value = content;
|
|
3519
|
+
}
|
|
3520
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3521
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3522
|
+
if (migrated) {
|
|
3523
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3524
|
+
}
|
|
3525
|
+
return key;
|
|
3399
3526
|
} catch (err) {
|
|
3400
3527
|
process.stderr.write(
|
|
3401
3528
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3404,12 +3531,13 @@ async function getMasterKey() {
|
|
|
3404
3531
|
return null;
|
|
3405
3532
|
}
|
|
3406
3533
|
}
|
|
3407
|
-
var SERVICE, ACCOUNT;
|
|
3534
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3408
3535
|
var init_keychain = __esm({
|
|
3409
3536
|
"src/lib/keychain.ts"() {
|
|
3410
3537
|
"use strict";
|
|
3411
3538
|
SERVICE = "exe-mem";
|
|
3412
3539
|
ACCOUNT = "master-key";
|
|
3540
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3413
3541
|
}
|
|
3414
3542
|
});
|
|
3415
3543
|
|
|
@@ -4675,8 +4803,8 @@ async function main() {
|
|
|
4675
4803
|
let sessionScope = process.env.EXE_SESSION ? extractRootExe(process.env.EXE_SESSION) ?? void 0 : void 0;
|
|
4676
4804
|
if (!sessionScope) {
|
|
4677
4805
|
try {
|
|
4678
|
-
const { execSync:
|
|
4679
|
-
const tmuxSession =
|
|
4806
|
+
const { execSync: execSync5 } = await import("child_process");
|
|
4807
|
+
const tmuxSession = execSync5("tmux display-message -p '#{session_name}'", { encoding: "utf8", timeout: 2e3 }).trim();
|
|
4680
4808
|
if (isExeSession(tmuxSession)) sessionScope = tmuxSession;
|
|
4681
4809
|
} catch {
|
|
4682
4810
|
}
|