@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
|
@@ -1439,8 +1439,8 @@ function findPackageRoot() {
|
|
|
1439
1439
|
function getAvailableMemoryGB() {
|
|
1440
1440
|
if (process.platform === "darwin") {
|
|
1441
1441
|
try {
|
|
1442
|
-
const { execSync:
|
|
1443
|
-
const vmstat =
|
|
1442
|
+
const { execSync: execSync8 } = __require("child_process");
|
|
1443
|
+
const vmstat = execSync8("vm_stat", { encoding: "utf8" });
|
|
1444
1444
|
const pageSize = 16384;
|
|
1445
1445
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1446
1446
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3179,6 +3179,7 @@ var init_database = __esm({
|
|
|
3179
3179
|
// src/lib/keychain.ts
|
|
3180
3180
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3181
3181
|
import { existsSync as existsSync7 } from "fs";
|
|
3182
|
+
import { execSync as execSync2 } from "child_process";
|
|
3182
3183
|
import path7 from "path";
|
|
3183
3184
|
import os5 from "os";
|
|
3184
3185
|
function getKeyDir() {
|
|
@@ -3187,6 +3188,59 @@ function getKeyDir() {
|
|
|
3187
3188
|
function getKeyPath() {
|
|
3188
3189
|
return path7.join(getKeyDir(), "master.key");
|
|
3189
3190
|
}
|
|
3191
|
+
function macKeychainGet() {
|
|
3192
|
+
if (process.platform !== "darwin") return null;
|
|
3193
|
+
try {
|
|
3194
|
+
return execSync2(
|
|
3195
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3196
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3197
|
+
).trim();
|
|
3198
|
+
} catch {
|
|
3199
|
+
return null;
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
function macKeychainSet(value) {
|
|
3203
|
+
if (process.platform !== "darwin") return false;
|
|
3204
|
+
try {
|
|
3205
|
+
try {
|
|
3206
|
+
execSync2(
|
|
3207
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3208
|
+
{ timeout: 5e3 }
|
|
3209
|
+
);
|
|
3210
|
+
} catch {
|
|
3211
|
+
}
|
|
3212
|
+
execSync2(
|
|
3213
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3214
|
+
{ timeout: 5e3 }
|
|
3215
|
+
);
|
|
3216
|
+
return true;
|
|
3217
|
+
} catch {
|
|
3218
|
+
return false;
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
function linuxSecretGet() {
|
|
3222
|
+
if (process.platform !== "linux") return null;
|
|
3223
|
+
try {
|
|
3224
|
+
return execSync2(
|
|
3225
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3226
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3227
|
+
).trim();
|
|
3228
|
+
} catch {
|
|
3229
|
+
return null;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
function linuxSecretSet(value) {
|
|
3233
|
+
if (process.platform !== "linux") return false;
|
|
3234
|
+
try {
|
|
3235
|
+
execSync2(
|
|
3236
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3237
|
+
{ timeout: 5e3 }
|
|
3238
|
+
);
|
|
3239
|
+
return true;
|
|
3240
|
+
} catch {
|
|
3241
|
+
return false;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3190
3244
|
async function tryKeytar() {
|
|
3191
3245
|
try {
|
|
3192
3246
|
return await import("keytar");
|
|
@@ -3194,13 +3248,63 @@ async function tryKeytar() {
|
|
|
3194
3248
|
return null;
|
|
3195
3249
|
}
|
|
3196
3250
|
}
|
|
3251
|
+
function deriveMachineKey() {
|
|
3252
|
+
try {
|
|
3253
|
+
const crypto7 = __require("crypto");
|
|
3254
|
+
const material = [
|
|
3255
|
+
os5.hostname(),
|
|
3256
|
+
os5.userInfo().username,
|
|
3257
|
+
os5.arch(),
|
|
3258
|
+
os5.platform(),
|
|
3259
|
+
// Machine ID on Linux (stable across reboots)
|
|
3260
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3261
|
+
].join("|");
|
|
3262
|
+
return crypto7.createHash("sha256").update(material).digest();
|
|
3263
|
+
} catch {
|
|
3264
|
+
return null;
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
function readMachineId() {
|
|
3268
|
+
try {
|
|
3269
|
+
const { readFileSync: readFileSync13 } = __require("fs");
|
|
3270
|
+
return readFileSync13("/etc/machine-id", "utf-8").trim();
|
|
3271
|
+
} catch {
|
|
3272
|
+
return "";
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3276
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3277
|
+
try {
|
|
3278
|
+
const crypto7 = __require("crypto");
|
|
3279
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3280
|
+
if (parts.length !== 3) return null;
|
|
3281
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3282
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3283
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3284
|
+
const decipher = crypto7.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3285
|
+
decipher.setAuthTag(authTag);
|
|
3286
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3287
|
+
decrypted += decipher.final("utf-8");
|
|
3288
|
+
return decrypted;
|
|
3289
|
+
} catch {
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3197
3293
|
async function getMasterKey() {
|
|
3294
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3295
|
+
if (nativeValue) {
|
|
3296
|
+
return Buffer.from(nativeValue, "base64");
|
|
3297
|
+
}
|
|
3198
3298
|
const keytar = await tryKeytar();
|
|
3199
3299
|
if (keytar) {
|
|
3200
3300
|
try {
|
|
3201
|
-
const
|
|
3202
|
-
if (
|
|
3203
|
-
|
|
3301
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3302
|
+
if (keytarValue) {
|
|
3303
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3304
|
+
if (migrated) {
|
|
3305
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3306
|
+
}
|
|
3307
|
+
return Buffer.from(keytarValue, "base64");
|
|
3204
3308
|
}
|
|
3205
3309
|
} catch {
|
|
3206
3310
|
}
|
|
@@ -3214,8 +3318,31 @@ async function getMasterKey() {
|
|
|
3214
3318
|
return null;
|
|
3215
3319
|
}
|
|
3216
3320
|
try {
|
|
3217
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3218
|
-
|
|
3321
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3322
|
+
let b64Value;
|
|
3323
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3324
|
+
const machineKey = deriveMachineKey();
|
|
3325
|
+
if (!machineKey) {
|
|
3326
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3327
|
+
return null;
|
|
3328
|
+
}
|
|
3329
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3330
|
+
if (!decrypted) {
|
|
3331
|
+
process.stderr.write(
|
|
3332
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3333
|
+
);
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
b64Value = decrypted;
|
|
3337
|
+
} else {
|
|
3338
|
+
b64Value = content;
|
|
3339
|
+
}
|
|
3340
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3341
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3342
|
+
if (migrated) {
|
|
3343
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3344
|
+
}
|
|
3345
|
+
return key;
|
|
3219
3346
|
} catch (err) {
|
|
3220
3347
|
process.stderr.write(
|
|
3221
3348
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3224,12 +3351,13 @@ async function getMasterKey() {
|
|
|
3224
3351
|
return null;
|
|
3225
3352
|
}
|
|
3226
3353
|
}
|
|
3227
|
-
var SERVICE, ACCOUNT;
|
|
3354
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3228
3355
|
var init_keychain = __esm({
|
|
3229
3356
|
"src/lib/keychain.ts"() {
|
|
3230
3357
|
"use strict";
|
|
3231
3358
|
SERVICE = "exe-mem";
|
|
3232
3359
|
ACCOUNT = "master-key";
|
|
3360
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3233
3361
|
}
|
|
3234
3362
|
});
|
|
3235
3363
|
|
|
@@ -4495,7 +4623,7 @@ var init_session_registry = __esm({
|
|
|
4495
4623
|
});
|
|
4496
4624
|
|
|
4497
4625
|
// src/lib/session-key.ts
|
|
4498
|
-
import { execSync as
|
|
4626
|
+
import { execSync as execSync3 } from "child_process";
|
|
4499
4627
|
function normalizeCommand(command) {
|
|
4500
4628
|
const trimmed = command.trim().toLowerCase();
|
|
4501
4629
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -4514,7 +4642,7 @@ function resolveRuntimeProcess() {
|
|
|
4514
4642
|
let pid = process.ppid;
|
|
4515
4643
|
for (let i = 0; i < 10; i++) {
|
|
4516
4644
|
try {
|
|
4517
|
-
const info =
|
|
4645
|
+
const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
|
|
4518
4646
|
encoding: "utf8",
|
|
4519
4647
|
timeout: 2e3
|
|
4520
4648
|
}).trim();
|
|
@@ -4680,14 +4808,14 @@ var init_transport = __esm({
|
|
|
4680
4808
|
});
|
|
4681
4809
|
|
|
4682
4810
|
// src/lib/cc-agent-support.ts
|
|
4683
|
-
import { execSync as
|
|
4811
|
+
import { execSync as execSync4 } from "child_process";
|
|
4684
4812
|
function _resetCcAgentSupportCache() {
|
|
4685
4813
|
_cachedSupport = null;
|
|
4686
4814
|
}
|
|
4687
4815
|
function claudeSupportsAgentFlag() {
|
|
4688
4816
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
4689
4817
|
try {
|
|
4690
|
-
const helpOutput =
|
|
4818
|
+
const helpOutput = execSync4("claude --help 2>&1", {
|
|
4691
4819
|
encoding: "utf-8",
|
|
4692
4820
|
timeout: 5e3
|
|
4693
4821
|
});
|
|
@@ -5634,7 +5762,7 @@ __export(tmux_routing_exports, {
|
|
|
5634
5762
|
spawnEmployee: () => spawnEmployee,
|
|
5635
5763
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
5636
5764
|
});
|
|
5637
|
-
import { execFileSync as execFileSync2, execSync as
|
|
5765
|
+
import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
|
|
5638
5766
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
5639
5767
|
import path14 from "path";
|
|
5640
5768
|
import os9 from "os";
|
|
@@ -6344,7 +6472,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6344
6472
|
let booted = false;
|
|
6345
6473
|
for (let i = 0; i < 30; i++) {
|
|
6346
6474
|
try {
|
|
6347
|
-
|
|
6475
|
+
execSync5("sleep 0.5");
|
|
6348
6476
|
} catch {
|
|
6349
6477
|
}
|
|
6350
6478
|
try {
|
|
@@ -6510,7 +6638,7 @@ var init_notifications = __esm({
|
|
|
6510
6638
|
});
|
|
6511
6639
|
|
|
6512
6640
|
// src/lib/project-name.ts
|
|
6513
|
-
import { execSync as
|
|
6641
|
+
import { execSync as execSync6 } from "child_process";
|
|
6514
6642
|
import path16 from "path";
|
|
6515
6643
|
function getProjectName(cwd) {
|
|
6516
6644
|
const dir = cwd ?? process.cwd();
|
|
@@ -6518,7 +6646,7 @@ function getProjectName(cwd) {
|
|
|
6518
6646
|
try {
|
|
6519
6647
|
let repoRoot;
|
|
6520
6648
|
try {
|
|
6521
|
-
const gitCommonDir =
|
|
6649
|
+
const gitCommonDir = execSync6("git rev-parse --path-format=absolute --git-common-dir", {
|
|
6522
6650
|
cwd: dir,
|
|
6523
6651
|
encoding: "utf8",
|
|
6524
6652
|
timeout: 2e3,
|
|
@@ -6526,7 +6654,7 @@ function getProjectName(cwd) {
|
|
|
6526
6654
|
}).trim();
|
|
6527
6655
|
repoRoot = path16.dirname(gitCommonDir);
|
|
6528
6656
|
} catch {
|
|
6529
|
-
repoRoot =
|
|
6657
|
+
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
6530
6658
|
cwd: dir,
|
|
6531
6659
|
encoding: "utf8",
|
|
6532
6660
|
timeout: 2e3,
|
|
@@ -6617,7 +6745,7 @@ var init_session_scope = __esm({
|
|
|
6617
6745
|
import crypto4 from "crypto";
|
|
6618
6746
|
import path17 from "path";
|
|
6619
6747
|
import os11 from "os";
|
|
6620
|
-
import { execSync as
|
|
6748
|
+
import { execSync as execSync7 } from "child_process";
|
|
6621
6749
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
6622
6750
|
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
6623
6751
|
async function writeCheckpoint(input) {
|
|
@@ -6962,14 +7090,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
6962
7090
|
if (!identifier || identifier === "unknown") return true;
|
|
6963
7091
|
try {
|
|
6964
7092
|
if (identifier.startsWith("%")) {
|
|
6965
|
-
const output =
|
|
7093
|
+
const output = execSync7("tmux list-panes -a -F '#{pane_id}'", {
|
|
6966
7094
|
timeout: 2e3,
|
|
6967
7095
|
encoding: "utf8",
|
|
6968
7096
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6969
7097
|
});
|
|
6970
7098
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
6971
7099
|
} else {
|
|
6972
|
-
|
|
7100
|
+
execSync7(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
6973
7101
|
timeout: 2e3,
|
|
6974
7102
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6975
7103
|
});
|
|
@@ -6978,7 +7106,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
6978
7106
|
} catch {
|
|
6979
7107
|
if (identifier.startsWith("%")) return true;
|
|
6980
7108
|
try {
|
|
6981
|
-
|
|
7109
|
+
execSync7("tmux list-sessions", {
|
|
6982
7110
|
timeout: 2e3,
|
|
6983
7111
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6984
7112
|
});
|
|
@@ -6993,12 +7121,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
6993
7121
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
6994
7122
|
try {
|
|
6995
7123
|
const since = new Date(taskCreatedAt).toISOString();
|
|
6996
|
-
const branch =
|
|
7124
|
+
const branch = execSync7(
|
|
6997
7125
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
6998
7126
|
{ encoding: "utf8", timeout: 3e3 }
|
|
6999
7127
|
).trim();
|
|
7000
7128
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
7001
|
-
const commitCount =
|
|
7129
|
+
const commitCount = execSync7(
|
|
7002
7130
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
7003
7131
|
{ encoding: "utf8", timeout: 5e3 }
|
|
7004
7132
|
).trim();
|
|
@@ -1123,8 +1123,8 @@ function findPackageRoot() {
|
|
|
1123
1123
|
function getAvailableMemoryGB() {
|
|
1124
1124
|
if (process.platform === "darwin") {
|
|
1125
1125
|
try {
|
|
1126
|
-
const { execSync:
|
|
1127
|
-
const vmstat =
|
|
1126
|
+
const { execSync: execSync6 } = __require("child_process");
|
|
1127
|
+
const vmstat = execSync6("vm_stat", { encoding: "utf8" });
|
|
1128
1128
|
const pageSize = 16384;
|
|
1129
1129
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1130
1130
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2863,6 +2863,7 @@ var init_database = __esm({
|
|
|
2863
2863
|
// src/lib/keychain.ts
|
|
2864
2864
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2865
2865
|
import { existsSync as existsSync6 } from "fs";
|
|
2866
|
+
import { execSync as execSync2 } from "child_process";
|
|
2866
2867
|
import path6 from "path";
|
|
2867
2868
|
import os5 from "os";
|
|
2868
2869
|
function getKeyDir() {
|
|
@@ -2871,6 +2872,59 @@ function getKeyDir() {
|
|
|
2871
2872
|
function getKeyPath() {
|
|
2872
2873
|
return path6.join(getKeyDir(), "master.key");
|
|
2873
2874
|
}
|
|
2875
|
+
function macKeychainGet() {
|
|
2876
|
+
if (process.platform !== "darwin") return null;
|
|
2877
|
+
try {
|
|
2878
|
+
return execSync2(
|
|
2879
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2880
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2881
|
+
).trim();
|
|
2882
|
+
} catch {
|
|
2883
|
+
return null;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
function macKeychainSet(value) {
|
|
2887
|
+
if (process.platform !== "darwin") return false;
|
|
2888
|
+
try {
|
|
2889
|
+
try {
|
|
2890
|
+
execSync2(
|
|
2891
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2892
|
+
{ timeout: 5e3 }
|
|
2893
|
+
);
|
|
2894
|
+
} catch {
|
|
2895
|
+
}
|
|
2896
|
+
execSync2(
|
|
2897
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2898
|
+
{ timeout: 5e3 }
|
|
2899
|
+
);
|
|
2900
|
+
return true;
|
|
2901
|
+
} catch {
|
|
2902
|
+
return false;
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
function linuxSecretGet() {
|
|
2906
|
+
if (process.platform !== "linux") return null;
|
|
2907
|
+
try {
|
|
2908
|
+
return execSync2(
|
|
2909
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2910
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2911
|
+
).trim();
|
|
2912
|
+
} catch {
|
|
2913
|
+
return null;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
function linuxSecretSet(value) {
|
|
2917
|
+
if (process.platform !== "linux") return false;
|
|
2918
|
+
try {
|
|
2919
|
+
execSync2(
|
|
2920
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
2921
|
+
{ timeout: 5e3 }
|
|
2922
|
+
);
|
|
2923
|
+
return true;
|
|
2924
|
+
} catch {
|
|
2925
|
+
return false;
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2874
2928
|
async function tryKeytar() {
|
|
2875
2929
|
try {
|
|
2876
2930
|
return await import("keytar");
|
|
@@ -2878,13 +2932,63 @@ async function tryKeytar() {
|
|
|
2878
2932
|
return null;
|
|
2879
2933
|
}
|
|
2880
2934
|
}
|
|
2935
|
+
function deriveMachineKey() {
|
|
2936
|
+
try {
|
|
2937
|
+
const crypto6 = __require("crypto");
|
|
2938
|
+
const material = [
|
|
2939
|
+
os5.hostname(),
|
|
2940
|
+
os5.userInfo().username,
|
|
2941
|
+
os5.arch(),
|
|
2942
|
+
os5.platform(),
|
|
2943
|
+
// Machine ID on Linux (stable across reboots)
|
|
2944
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
2945
|
+
].join("|");
|
|
2946
|
+
return crypto6.createHash("sha256").update(material).digest();
|
|
2947
|
+
} catch {
|
|
2948
|
+
return null;
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
function readMachineId() {
|
|
2952
|
+
try {
|
|
2953
|
+
const { readFileSync: readFileSync12 } = __require("fs");
|
|
2954
|
+
return readFileSync12("/etc/machine-id", "utf-8").trim();
|
|
2955
|
+
} catch {
|
|
2956
|
+
return "";
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
2960
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
2961
|
+
try {
|
|
2962
|
+
const crypto6 = __require("crypto");
|
|
2963
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
2964
|
+
if (parts.length !== 3) return null;
|
|
2965
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
2966
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
2967
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
2968
|
+
const decipher = crypto6.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
2969
|
+
decipher.setAuthTag(authTag);
|
|
2970
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
2971
|
+
decrypted += decipher.final("utf-8");
|
|
2972
|
+
return decrypted;
|
|
2973
|
+
} catch {
|
|
2974
|
+
return null;
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2881
2977
|
async function getMasterKey() {
|
|
2978
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
2979
|
+
if (nativeValue) {
|
|
2980
|
+
return Buffer.from(nativeValue, "base64");
|
|
2981
|
+
}
|
|
2882
2982
|
const keytar = await tryKeytar();
|
|
2883
2983
|
if (keytar) {
|
|
2884
2984
|
try {
|
|
2885
|
-
const
|
|
2886
|
-
if (
|
|
2887
|
-
|
|
2985
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
2986
|
+
if (keytarValue) {
|
|
2987
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
2988
|
+
if (migrated) {
|
|
2989
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
2990
|
+
}
|
|
2991
|
+
return Buffer.from(keytarValue, "base64");
|
|
2888
2992
|
}
|
|
2889
2993
|
} catch {
|
|
2890
2994
|
}
|
|
@@ -2898,8 +3002,31 @@ async function getMasterKey() {
|
|
|
2898
3002
|
return null;
|
|
2899
3003
|
}
|
|
2900
3004
|
try {
|
|
2901
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
2902
|
-
|
|
3005
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3006
|
+
let b64Value;
|
|
3007
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3008
|
+
const machineKey = deriveMachineKey();
|
|
3009
|
+
if (!machineKey) {
|
|
3010
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3011
|
+
return null;
|
|
3012
|
+
}
|
|
3013
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3014
|
+
if (!decrypted) {
|
|
3015
|
+
process.stderr.write(
|
|
3016
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3017
|
+
);
|
|
3018
|
+
return null;
|
|
3019
|
+
}
|
|
3020
|
+
b64Value = decrypted;
|
|
3021
|
+
} else {
|
|
3022
|
+
b64Value = content;
|
|
3023
|
+
}
|
|
3024
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3025
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3026
|
+
if (migrated) {
|
|
3027
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3028
|
+
}
|
|
3029
|
+
return key;
|
|
2903
3030
|
} catch (err) {
|
|
2904
3031
|
process.stderr.write(
|
|
2905
3032
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2908,12 +3035,13 @@ async function getMasterKey() {
|
|
|
2908
3035
|
return null;
|
|
2909
3036
|
}
|
|
2910
3037
|
}
|
|
2911
|
-
var SERVICE, ACCOUNT;
|
|
3038
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
2912
3039
|
var init_keychain = __esm({
|
|
2913
3040
|
"src/lib/keychain.ts"() {
|
|
2914
3041
|
"use strict";
|
|
2915
3042
|
SERVICE = "exe-mem";
|
|
2916
3043
|
ACCOUNT = "master-key";
|
|
3044
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
2917
3045
|
}
|
|
2918
3046
|
});
|
|
2919
3047
|
|
|
@@ -4156,7 +4284,7 @@ var init_session_registry = __esm({
|
|
|
4156
4284
|
});
|
|
4157
4285
|
|
|
4158
4286
|
// src/lib/session-key.ts
|
|
4159
|
-
import { execSync as
|
|
4287
|
+
import { execSync as execSync3 } from "child_process";
|
|
4160
4288
|
function normalizeCommand(command) {
|
|
4161
4289
|
const trimmed = command.trim().toLowerCase();
|
|
4162
4290
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -4175,7 +4303,7 @@ function resolveRuntimeProcess() {
|
|
|
4175
4303
|
let pid = process.ppid;
|
|
4176
4304
|
for (let i = 0; i < 10; i++) {
|
|
4177
4305
|
try {
|
|
4178
|
-
const info =
|
|
4306
|
+
const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
|
|
4179
4307
|
encoding: "utf8",
|
|
4180
4308
|
timeout: 2e3
|
|
4181
4309
|
}).trim();
|
|
@@ -4341,7 +4469,7 @@ var init_transport = __esm({
|
|
|
4341
4469
|
});
|
|
4342
4470
|
|
|
4343
4471
|
// src/lib/cc-agent-support.ts
|
|
4344
|
-
import { execSync as
|
|
4472
|
+
import { execSync as execSync4 } from "child_process";
|
|
4345
4473
|
var init_cc_agent_support = __esm({
|
|
4346
4474
|
"src/lib/cc-agent-support.ts"() {
|
|
4347
4475
|
"use strict";
|
|
@@ -4954,7 +5082,7 @@ var init_notifications = __esm({
|
|
|
4954
5082
|
import crypto3 from "crypto";
|
|
4955
5083
|
import path15 from "path";
|
|
4956
5084
|
import os11 from "os";
|
|
4957
|
-
import { execSync as
|
|
5085
|
+
import { execSync as execSync5 } from "child_process";
|
|
4958
5086
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
4959
5087
|
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
4960
5088
|
async function writeCheckpoint(input) {
|
|
@@ -5096,14 +5224,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
5096
5224
|
if (!identifier || identifier === "unknown") return true;
|
|
5097
5225
|
try {
|
|
5098
5226
|
if (identifier.startsWith("%")) {
|
|
5099
|
-
const output =
|
|
5227
|
+
const output = execSync5("tmux list-panes -a -F '#{pane_id}'", {
|
|
5100
5228
|
timeout: 2e3,
|
|
5101
5229
|
encoding: "utf8",
|
|
5102
5230
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5103
5231
|
});
|
|
5104
5232
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
5105
5233
|
} else {
|
|
5106
|
-
|
|
5234
|
+
execSync5(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
5107
5235
|
timeout: 2e3,
|
|
5108
5236
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5109
5237
|
});
|
|
@@ -5112,7 +5240,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
5112
5240
|
} catch {
|
|
5113
5241
|
if (identifier.startsWith("%")) return true;
|
|
5114
5242
|
try {
|
|
5115
|
-
|
|
5243
|
+
execSync5("tmux list-sessions", {
|
|
5116
5244
|
timeout: 2e3,
|
|
5117
5245
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5118
5246
|
});
|
|
@@ -5127,12 +5255,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
5127
5255
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
5128
5256
|
try {
|
|
5129
5257
|
const since = new Date(taskCreatedAt).toISOString();
|
|
5130
|
-
const branch =
|
|
5258
|
+
const branch = execSync5(
|
|
5131
5259
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
5132
5260
|
{ encoding: "utf8", timeout: 3e3 }
|
|
5133
5261
|
).trim();
|
|
5134
5262
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
5135
|
-
const commitCount =
|
|
5263
|
+
const commitCount = execSync5(
|
|
5136
5264
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
5137
5265
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5138
5266
|
).trim();
|