@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
|
@@ -1128,8 +1128,8 @@ function findPackageRoot() {
|
|
|
1128
1128
|
function getAvailableMemoryGB() {
|
|
1129
1129
|
if (process.platform === "darwin") {
|
|
1130
1130
|
try {
|
|
1131
|
-
const { execSync:
|
|
1132
|
-
const vmstat =
|
|
1131
|
+
const { execSync: execSync11 } = __require("child_process");
|
|
1132
|
+
const vmstat = execSync11("vm_stat", { encoding: "utf8" });
|
|
1133
1133
|
const pageSize = 16384;
|
|
1134
1134
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
1135
1135
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -2813,6 +2813,7 @@ var init_database = __esm({
|
|
|
2813
2813
|
// src/lib/keychain.ts
|
|
2814
2814
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2815
2815
|
import { existsSync as existsSync6 } from "fs";
|
|
2816
|
+
import { execSync as execSync2 } from "child_process";
|
|
2816
2817
|
import path6 from "path";
|
|
2817
2818
|
import os5 from "os";
|
|
2818
2819
|
function getKeyDir() {
|
|
@@ -2821,6 +2822,59 @@ function getKeyDir() {
|
|
|
2821
2822
|
function getKeyPath() {
|
|
2822
2823
|
return path6.join(getKeyDir(), "master.key");
|
|
2823
2824
|
}
|
|
2825
|
+
function macKeychainGet() {
|
|
2826
|
+
if (process.platform !== "darwin") return null;
|
|
2827
|
+
try {
|
|
2828
|
+
return execSync2(
|
|
2829
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2830
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2831
|
+
).trim();
|
|
2832
|
+
} catch {
|
|
2833
|
+
return null;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
function macKeychainSet(value) {
|
|
2837
|
+
if (process.platform !== "darwin") return false;
|
|
2838
|
+
try {
|
|
2839
|
+
try {
|
|
2840
|
+
execSync2(
|
|
2841
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2842
|
+
{ timeout: 5e3 }
|
|
2843
|
+
);
|
|
2844
|
+
} catch {
|
|
2845
|
+
}
|
|
2846
|
+
execSync2(
|
|
2847
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2848
|
+
{ timeout: 5e3 }
|
|
2849
|
+
);
|
|
2850
|
+
return true;
|
|
2851
|
+
} catch {
|
|
2852
|
+
return false;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
function linuxSecretGet() {
|
|
2856
|
+
if (process.platform !== "linux") return null;
|
|
2857
|
+
try {
|
|
2858
|
+
return execSync2(
|
|
2859
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2860
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
2861
|
+
).trim();
|
|
2862
|
+
} catch {
|
|
2863
|
+
return null;
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
function linuxSecretSet(value) {
|
|
2867
|
+
if (process.platform !== "linux") return false;
|
|
2868
|
+
try {
|
|
2869
|
+
execSync2(
|
|
2870
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
2871
|
+
{ timeout: 5e3 }
|
|
2872
|
+
);
|
|
2873
|
+
return true;
|
|
2874
|
+
} catch {
|
|
2875
|
+
return false;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2824
2878
|
async function tryKeytar() {
|
|
2825
2879
|
try {
|
|
2826
2880
|
return await import("keytar");
|
|
@@ -2828,13 +2882,63 @@ async function tryKeytar() {
|
|
|
2828
2882
|
return null;
|
|
2829
2883
|
}
|
|
2830
2884
|
}
|
|
2885
|
+
function deriveMachineKey() {
|
|
2886
|
+
try {
|
|
2887
|
+
const crypto8 = __require("crypto");
|
|
2888
|
+
const material = [
|
|
2889
|
+
os5.hostname(),
|
|
2890
|
+
os5.userInfo().username,
|
|
2891
|
+
os5.arch(),
|
|
2892
|
+
os5.platform(),
|
|
2893
|
+
// Machine ID on Linux (stable across reboots)
|
|
2894
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
2895
|
+
].join("|");
|
|
2896
|
+
return crypto8.createHash("sha256").update(material).digest();
|
|
2897
|
+
} catch {
|
|
2898
|
+
return null;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
function readMachineId() {
|
|
2902
|
+
try {
|
|
2903
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
2904
|
+
return readFileSync14("/etc/machine-id", "utf-8").trim();
|
|
2905
|
+
} catch {
|
|
2906
|
+
return "";
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
2910
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
2911
|
+
try {
|
|
2912
|
+
const crypto8 = __require("crypto");
|
|
2913
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
2914
|
+
if (parts.length !== 3) return null;
|
|
2915
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
2916
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
2917
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
2918
|
+
const decipher = crypto8.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
2919
|
+
decipher.setAuthTag(authTag);
|
|
2920
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
2921
|
+
decrypted += decipher.final("utf-8");
|
|
2922
|
+
return decrypted;
|
|
2923
|
+
} catch {
|
|
2924
|
+
return null;
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2831
2927
|
async function getMasterKey() {
|
|
2928
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
2929
|
+
if (nativeValue) {
|
|
2930
|
+
return Buffer.from(nativeValue, "base64");
|
|
2931
|
+
}
|
|
2832
2932
|
const keytar = await tryKeytar();
|
|
2833
2933
|
if (keytar) {
|
|
2834
2934
|
try {
|
|
2835
|
-
const
|
|
2836
|
-
if (
|
|
2837
|
-
|
|
2935
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
2936
|
+
if (keytarValue) {
|
|
2937
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
2938
|
+
if (migrated) {
|
|
2939
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
2940
|
+
}
|
|
2941
|
+
return Buffer.from(keytarValue, "base64");
|
|
2838
2942
|
}
|
|
2839
2943
|
} catch {
|
|
2840
2944
|
}
|
|
@@ -2848,8 +2952,31 @@ async function getMasterKey() {
|
|
|
2848
2952
|
return null;
|
|
2849
2953
|
}
|
|
2850
2954
|
try {
|
|
2851
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
2852
|
-
|
|
2955
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
2956
|
+
let b64Value;
|
|
2957
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
2958
|
+
const machineKey = deriveMachineKey();
|
|
2959
|
+
if (!machineKey) {
|
|
2960
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
2961
|
+
return null;
|
|
2962
|
+
}
|
|
2963
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
2964
|
+
if (!decrypted) {
|
|
2965
|
+
process.stderr.write(
|
|
2966
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
2967
|
+
);
|
|
2968
|
+
return null;
|
|
2969
|
+
}
|
|
2970
|
+
b64Value = decrypted;
|
|
2971
|
+
} else {
|
|
2972
|
+
b64Value = content;
|
|
2973
|
+
}
|
|
2974
|
+
const key = Buffer.from(b64Value, "base64");
|
|
2975
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
2976
|
+
if (migrated) {
|
|
2977
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
2978
|
+
}
|
|
2979
|
+
return key;
|
|
2853
2980
|
} catch (err) {
|
|
2854
2981
|
process.stderr.write(
|
|
2855
2982
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -2858,12 +2985,13 @@ async function getMasterKey() {
|
|
|
2858
2985
|
return null;
|
|
2859
2986
|
}
|
|
2860
2987
|
}
|
|
2861
|
-
var SERVICE, ACCOUNT;
|
|
2988
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
2862
2989
|
var init_keychain = __esm({
|
|
2863
2990
|
"src/lib/keychain.ts"() {
|
|
2864
2991
|
"use strict";
|
|
2865
2992
|
SERVICE = "exe-mem";
|
|
2866
2993
|
ACCOUNT = "master-key";
|
|
2994
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
2867
2995
|
}
|
|
2868
2996
|
});
|
|
2869
2997
|
|
|
@@ -4129,7 +4257,7 @@ var init_session_registry = __esm({
|
|
|
4129
4257
|
});
|
|
4130
4258
|
|
|
4131
4259
|
// src/lib/session-key.ts
|
|
4132
|
-
import { execSync as
|
|
4260
|
+
import { execSync as execSync3 } from "child_process";
|
|
4133
4261
|
function normalizeCommand(command) {
|
|
4134
4262
|
const trimmed = command.trim().toLowerCase();
|
|
4135
4263
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -4148,7 +4276,7 @@ function resolveRuntimeProcess() {
|
|
|
4148
4276
|
let pid = process.ppid;
|
|
4149
4277
|
for (let i = 0; i < 10; i++) {
|
|
4150
4278
|
try {
|
|
4151
|
-
const info =
|
|
4279
|
+
const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
|
|
4152
4280
|
encoding: "utf8",
|
|
4153
4281
|
timeout: 2e3
|
|
4154
4282
|
}).trim();
|
|
@@ -4314,14 +4442,14 @@ var init_transport = __esm({
|
|
|
4314
4442
|
});
|
|
4315
4443
|
|
|
4316
4444
|
// src/lib/cc-agent-support.ts
|
|
4317
|
-
import { execSync as
|
|
4445
|
+
import { execSync as execSync4 } from "child_process";
|
|
4318
4446
|
function _resetCcAgentSupportCache() {
|
|
4319
4447
|
_cachedSupport = null;
|
|
4320
4448
|
}
|
|
4321
4449
|
function claudeSupportsAgentFlag() {
|
|
4322
4450
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
4323
4451
|
try {
|
|
4324
|
-
const helpOutput =
|
|
4452
|
+
const helpOutput = execSync4("claude --help 2>&1", {
|
|
4325
4453
|
encoding: "utf-8",
|
|
4326
4454
|
timeout: 5e3
|
|
4327
4455
|
});
|
|
@@ -4770,7 +4898,7 @@ var init_session_kill_telemetry = __esm({
|
|
|
4770
4898
|
});
|
|
4771
4899
|
|
|
4772
4900
|
// src/lib/project-name.ts
|
|
4773
|
-
import { execSync as
|
|
4901
|
+
import { execSync as execSync5 } from "child_process";
|
|
4774
4902
|
import path14 from "path";
|
|
4775
4903
|
function getProjectName(cwd) {
|
|
4776
4904
|
const dir = cwd ?? process.cwd();
|
|
@@ -4778,7 +4906,7 @@ function getProjectName(cwd) {
|
|
|
4778
4906
|
try {
|
|
4779
4907
|
let repoRoot;
|
|
4780
4908
|
try {
|
|
4781
|
-
const gitCommonDir =
|
|
4909
|
+
const gitCommonDir = execSync5("git rev-parse --path-format=absolute --git-common-dir", {
|
|
4782
4910
|
cwd: dir,
|
|
4783
4911
|
encoding: "utf8",
|
|
4784
4912
|
timeout: 2e3,
|
|
@@ -4786,7 +4914,7 @@ function getProjectName(cwd) {
|
|
|
4786
4914
|
}).trim();
|
|
4787
4915
|
repoRoot = path14.dirname(gitCommonDir);
|
|
4788
4916
|
} catch {
|
|
4789
|
-
repoRoot =
|
|
4917
|
+
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
4790
4918
|
cwd: dir,
|
|
4791
4919
|
encoding: "utf8",
|
|
4792
4920
|
timeout: 2e3,
|
|
@@ -4893,7 +5021,7 @@ __export(tasks_crud_exports, {
|
|
|
4893
5021
|
import crypto4 from "crypto";
|
|
4894
5022
|
import path15 from "path";
|
|
4895
5023
|
import os10 from "os";
|
|
4896
|
-
import { execSync as
|
|
5024
|
+
import { execSync as execSync6 } from "child_process";
|
|
4897
5025
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
4898
5026
|
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
4899
5027
|
async function writeCheckpoint(input) {
|
|
@@ -5238,14 +5366,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
5238
5366
|
if (!identifier || identifier === "unknown") return true;
|
|
5239
5367
|
try {
|
|
5240
5368
|
if (identifier.startsWith("%")) {
|
|
5241
|
-
const output =
|
|
5369
|
+
const output = execSync6("tmux list-panes -a -F '#{pane_id}'", {
|
|
5242
5370
|
timeout: 2e3,
|
|
5243
5371
|
encoding: "utf8",
|
|
5244
5372
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5245
5373
|
});
|
|
5246
5374
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
5247
5375
|
} else {
|
|
5248
|
-
|
|
5376
|
+
execSync6(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
5249
5377
|
timeout: 2e3,
|
|
5250
5378
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5251
5379
|
});
|
|
@@ -5254,7 +5382,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
5254
5382
|
} catch {
|
|
5255
5383
|
if (identifier.startsWith("%")) return true;
|
|
5256
5384
|
try {
|
|
5257
|
-
|
|
5385
|
+
execSync6("tmux list-sessions", {
|
|
5258
5386
|
timeout: 2e3,
|
|
5259
5387
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5260
5388
|
});
|
|
@@ -5269,12 +5397,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
5269
5397
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
5270
5398
|
try {
|
|
5271
5399
|
const since = new Date(taskCreatedAt).toISOString();
|
|
5272
|
-
const branch =
|
|
5400
|
+
const branch = execSync6(
|
|
5273
5401
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
5274
5402
|
{ encoding: "utf8", timeout: 3e3 }
|
|
5275
5403
|
).trim();
|
|
5276
5404
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
5277
|
-
const commitCount =
|
|
5405
|
+
const commitCount = execSync6(
|
|
5278
5406
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
5279
5407
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5280
5408
|
).trim();
|
|
@@ -6872,7 +7000,7 @@ __export(tmux_routing_exports, {
|
|
|
6872
7000
|
spawnEmployee: () => spawnEmployee,
|
|
6873
7001
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
6874
7002
|
});
|
|
6875
|
-
import { execFileSync as execFileSync2, execSync as
|
|
7003
|
+
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
6876
7004
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync4 } from "fs";
|
|
6877
7005
|
import path19 from "path";
|
|
6878
7006
|
import os11 from "os";
|
|
@@ -7582,7 +7710,7 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
|
|
|
7582
7710
|
let booted = false;
|
|
7583
7711
|
for (let i = 0; i < 30; i++) {
|
|
7584
7712
|
try {
|
|
7585
|
-
|
|
7713
|
+
execSync7("sleep 0.5");
|
|
7586
7714
|
} catch {
|
|
7587
7715
|
}
|
|
7588
7716
|
try {
|
|
@@ -7699,7 +7827,7 @@ __export(git_task_sweep_exports, {
|
|
|
7699
7827
|
matchScore: () => matchScore,
|
|
7700
7828
|
sweepTasks: () => sweepTasks
|
|
7701
7829
|
});
|
|
7702
|
-
import { execSync as
|
|
7830
|
+
import { execSync as execSync8 } from "child_process";
|
|
7703
7831
|
function extractKeywords(text) {
|
|
7704
7832
|
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length >= 3 && !STOP_WORDS.has(w));
|
|
7705
7833
|
}
|
|
@@ -7728,7 +7856,7 @@ function matchScore(task, commitMessage, changedFiles) {
|
|
|
7728
7856
|
function getRecentCommits(limit = DEFAULT_COMMIT_LIMIT) {
|
|
7729
7857
|
try {
|
|
7730
7858
|
const SEPARATOR = "<<SEP>>";
|
|
7731
|
-
const output =
|
|
7859
|
+
const output = execSync8(
|
|
7732
7860
|
`git log --format="%h${SEPARATOR}%s${SEPARATOR}%aI" --name-only -n ${limit} -z`,
|
|
7733
7861
|
{ encoding: "utf8", timeout: 1e4 }
|
|
7734
7862
|
);
|
|
@@ -7919,12 +8047,12 @@ __export(worktree_exports, {
|
|
|
7919
8047
|
worktreeBranch: () => worktreeBranch,
|
|
7920
8048
|
worktreePath: () => worktreePath
|
|
7921
8049
|
});
|
|
7922
|
-
import { execSync as
|
|
8050
|
+
import { execSync as execSync9 } from "child_process";
|
|
7923
8051
|
import { existsSync as existsSync17, readFileSync as readFileSync13, appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, realpathSync } from "fs";
|
|
7924
8052
|
import path20 from "path";
|
|
7925
8053
|
function getGitRoot(dir) {
|
|
7926
8054
|
try {
|
|
7927
|
-
const root =
|
|
8055
|
+
const root = execSync9("git rev-parse --show-toplevel", {
|
|
7928
8056
|
cwd: dir,
|
|
7929
8057
|
encoding: "utf-8",
|
|
7930
8058
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -7937,7 +8065,7 @@ function getGitRoot(dir) {
|
|
|
7937
8065
|
}
|
|
7938
8066
|
function getMainRepoRoot(dir) {
|
|
7939
8067
|
try {
|
|
7940
|
-
const commonDir =
|
|
8068
|
+
const commonDir = execSync9(
|
|
7941
8069
|
"git rev-parse --path-format=absolute --git-common-dir",
|
|
7942
8070
|
{ cwd: dir, encoding: "utf-8", timeout: GIT_TIMEOUT_MS, stdio: ["pipe", "pipe", "pipe"] }
|
|
7943
8071
|
).trim();
|
|
@@ -7968,7 +8096,7 @@ function ensureWorktree(projectDir, employeeName, instance) {
|
|
|
7968
8096
|
mkdirSync8(worktreesDir, { recursive: true });
|
|
7969
8097
|
ensureGitignoreEntry(repoRoot, "/.worktrees/");
|
|
7970
8098
|
try {
|
|
7971
|
-
|
|
8099
|
+
execSync9("git worktree prune", {
|
|
7972
8100
|
cwd: repoRoot,
|
|
7973
8101
|
encoding: "utf-8",
|
|
7974
8102
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -7979,14 +8107,14 @@ function ensureWorktree(projectDir, employeeName, instance) {
|
|
|
7979
8107
|
const branchExists = branchExistsLocally(repoRoot, branch);
|
|
7980
8108
|
try {
|
|
7981
8109
|
if (branchExists) {
|
|
7982
|
-
|
|
8110
|
+
execSync9(`git worktree add "${wtPath}" "${branch}"`, {
|
|
7983
8111
|
cwd: repoRoot,
|
|
7984
8112
|
encoding: "utf-8",
|
|
7985
8113
|
timeout: GIT_TIMEOUT_MS,
|
|
7986
8114
|
stdio: ["pipe", "pipe", "pipe"]
|
|
7987
8115
|
});
|
|
7988
8116
|
} else {
|
|
7989
|
-
|
|
8117
|
+
execSync9(`git worktree add "${wtPath}" -b "${branch}" HEAD`, {
|
|
7990
8118
|
cwd: repoRoot,
|
|
7991
8119
|
encoding: "utf-8",
|
|
7992
8120
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8004,7 +8132,7 @@ function ensureWorktree(projectDir, employeeName, instance) {
|
|
|
8004
8132
|
}
|
|
8005
8133
|
function isWorktreeDirty(wtPath) {
|
|
8006
8134
|
try {
|
|
8007
|
-
const status =
|
|
8135
|
+
const status = execSync9("git status --porcelain", {
|
|
8008
8136
|
cwd: wtPath,
|
|
8009
8137
|
encoding: "utf-8",
|
|
8010
8138
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8034,7 +8162,7 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
8034
8162
|
return { cleaned: false, reason: `branch ${branch} not merged into ${mainBranch}` };
|
|
8035
8163
|
}
|
|
8036
8164
|
try {
|
|
8037
|
-
|
|
8165
|
+
execSync9(`git worktree remove "${wtPath}"`, {
|
|
8038
8166
|
cwd: repoRoot,
|
|
8039
8167
|
encoding: "utf-8",
|
|
8040
8168
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8047,7 +8175,7 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
8047
8175
|
};
|
|
8048
8176
|
}
|
|
8049
8177
|
try {
|
|
8050
|
-
|
|
8178
|
+
execSync9(`git branch -d "${branch}"`, {
|
|
8051
8179
|
cwd: repoRoot,
|
|
8052
8180
|
encoding: "utf-8",
|
|
8053
8181
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8059,7 +8187,7 @@ function cleanupWorktree(projectDir, employeeName, instance) {
|
|
|
8059
8187
|
}
|
|
8060
8188
|
function branchExistsLocally(repoRoot, branch) {
|
|
8061
8189
|
try {
|
|
8062
|
-
|
|
8190
|
+
execSync9(`git rev-parse --verify "refs/heads/${branch}"`, {
|
|
8063
8191
|
cwd: repoRoot,
|
|
8064
8192
|
encoding: "utf-8",
|
|
8065
8193
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8078,7 +8206,7 @@ function detectMainBranch(repoRoot) {
|
|
|
8078
8206
|
}
|
|
8079
8207
|
function isBranchMerged(repoRoot, branch, into) {
|
|
8080
8208
|
try {
|
|
8081
|
-
const merged =
|
|
8209
|
+
const merged = execSync9(`git branch --merged "${into}"`, {
|
|
8082
8210
|
cwd: repoRoot,
|
|
8083
8211
|
encoding: "utf-8",
|
|
8084
8212
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -8125,7 +8253,7 @@ init_database();
|
|
|
8125
8253
|
init_task_scope();
|
|
8126
8254
|
init_project_name();
|
|
8127
8255
|
import crypto7 from "crypto";
|
|
8128
|
-
import { execSync as
|
|
8256
|
+
import { execSync as execSync10 } from "child_process";
|
|
8129
8257
|
var agentName = process.argv[2];
|
|
8130
8258
|
var exeSession = process.argv[3];
|
|
8131
8259
|
if (!agentName) process.exit(0);
|
|
@@ -8298,7 +8426,7 @@ try {
|
|
|
8298
8426
|
}
|
|
8299
8427
|
const msg = `session-ended: ${agentName} session terminated. ${parts.join(". ")}`;
|
|
8300
8428
|
try {
|
|
8301
|
-
|
|
8429
|
+
execSync10(`tmux send-keys -t ${JSON.stringify(exeSession)} ${JSON.stringify(msg)} Enter`, {
|
|
8302
8430
|
timeout: 3e3
|
|
8303
8431
|
});
|
|
8304
8432
|
} catch {
|
|
@@ -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: execSync6 } = __require("child_process");
|
|
1055
|
+
const vmstat = execSync6("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;
|
|
@@ -3183,7 +3183,7 @@ var init_runtime_table = __esm({
|
|
|
3183
3183
|
});
|
|
3184
3184
|
|
|
3185
3185
|
// src/lib/session-key.ts
|
|
3186
|
-
import { execSync as
|
|
3186
|
+
import { execSync as execSync3 } from "child_process";
|
|
3187
3187
|
function normalizeCommand(command) {
|
|
3188
3188
|
const trimmed = command.trim().toLowerCase();
|
|
3189
3189
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -3202,7 +3202,7 @@ function resolveRuntimeProcess() {
|
|
|
3202
3202
|
let pid = process.ppid;
|
|
3203
3203
|
for (let i = 0; i < 10; i++) {
|
|
3204
3204
|
try {
|
|
3205
|
-
const info =
|
|
3205
|
+
const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
|
|
3206
3206
|
encoding: "utf8",
|
|
3207
3207
|
timeout: 2e3
|
|
3208
3208
|
}).trim();
|
|
@@ -3261,7 +3261,7 @@ __export(active_agent_exports, {
|
|
|
3261
3261
|
writeActiveAgent: () => writeActiveAgent
|
|
3262
3262
|
});
|
|
3263
3263
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
3264
|
-
import { execSync as
|
|
3264
|
+
import { execSync as execSync4 } from "child_process";
|
|
3265
3265
|
import path9 from "path";
|
|
3266
3266
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
3267
3267
|
if (candidate === baseName) return true;
|
|
@@ -3353,7 +3353,7 @@ function getActiveAgent() {
|
|
|
3353
3353
|
} catch {
|
|
3354
3354
|
}
|
|
3355
3355
|
try {
|
|
3356
|
-
const sessionName =
|
|
3356
|
+
const sessionName = execSync4(
|
|
3357
3357
|
"tmux display-message -p '#{session_name}' 2>/dev/null",
|
|
3358
3358
|
{ encoding: "utf8", timeout: 2e3 }
|
|
3359
3359
|
).trim();
|
|
@@ -3482,7 +3482,7 @@ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdi
|
|
|
3482
3482
|
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
3483
3483
|
import path12 from "path";
|
|
3484
3484
|
import os9 from "os";
|
|
3485
|
-
import { execSync as
|
|
3485
|
+
import { execSync as execSync5 } from "child_process";
|
|
3486
3486
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3487
3487
|
function resolvePackageRoot() {
|
|
3488
3488
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
@@ -3946,6 +3946,7 @@ import { createHash } from "crypto";
|
|
|
3946
3946
|
// src/lib/keychain.ts
|
|
3947
3947
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3948
3948
|
import { existsSync as existsSync6 } from "fs";
|
|
3949
|
+
import { execSync as execSync2 } from "child_process";
|
|
3949
3950
|
import path6 from "path";
|
|
3950
3951
|
import os5 from "os";
|
|
3951
3952
|
var SERVICE = "exe-mem";
|
|
@@ -3956,6 +3957,59 @@ function getKeyDir() {
|
|
|
3956
3957
|
function getKeyPath() {
|
|
3957
3958
|
return path6.join(getKeyDir(), "master.key");
|
|
3958
3959
|
}
|
|
3960
|
+
function macKeychainGet() {
|
|
3961
|
+
if (process.platform !== "darwin") return null;
|
|
3962
|
+
try {
|
|
3963
|
+
return execSync2(
|
|
3964
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3965
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3966
|
+
).trim();
|
|
3967
|
+
} catch {
|
|
3968
|
+
return null;
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
function macKeychainSet(value) {
|
|
3972
|
+
if (process.platform !== "darwin") return false;
|
|
3973
|
+
try {
|
|
3974
|
+
try {
|
|
3975
|
+
execSync2(
|
|
3976
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3977
|
+
{ timeout: 5e3 }
|
|
3978
|
+
);
|
|
3979
|
+
} catch {
|
|
3980
|
+
}
|
|
3981
|
+
execSync2(
|
|
3982
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3983
|
+
{ timeout: 5e3 }
|
|
3984
|
+
);
|
|
3985
|
+
return true;
|
|
3986
|
+
} catch {
|
|
3987
|
+
return false;
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
function linuxSecretGet() {
|
|
3991
|
+
if (process.platform !== "linux") return null;
|
|
3992
|
+
try {
|
|
3993
|
+
return execSync2(
|
|
3994
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3995
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3996
|
+
).trim();
|
|
3997
|
+
} catch {
|
|
3998
|
+
return null;
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
function linuxSecretSet(value) {
|
|
4002
|
+
if (process.platform !== "linux") return false;
|
|
4003
|
+
try {
|
|
4004
|
+
execSync2(
|
|
4005
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
4006
|
+
{ timeout: 5e3 }
|
|
4007
|
+
);
|
|
4008
|
+
return true;
|
|
4009
|
+
} catch {
|
|
4010
|
+
return false;
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
3959
4013
|
async function tryKeytar() {
|
|
3960
4014
|
try {
|
|
3961
4015
|
return await import("keytar");
|
|
@@ -3963,13 +4017,64 @@ async function tryKeytar() {
|
|
|
3963
4017
|
return null;
|
|
3964
4018
|
}
|
|
3965
4019
|
}
|
|
4020
|
+
var ENCRYPTED_PREFIX = "enc:";
|
|
4021
|
+
function deriveMachineKey() {
|
|
4022
|
+
try {
|
|
4023
|
+
const crypto3 = __require("crypto");
|
|
4024
|
+
const material = [
|
|
4025
|
+
os5.hostname(),
|
|
4026
|
+
os5.userInfo().username,
|
|
4027
|
+
os5.arch(),
|
|
4028
|
+
os5.platform(),
|
|
4029
|
+
// Machine ID on Linux (stable across reboots)
|
|
4030
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
4031
|
+
].join("|");
|
|
4032
|
+
return crypto3.createHash("sha256").update(material).digest();
|
|
4033
|
+
} catch {
|
|
4034
|
+
return null;
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
function readMachineId() {
|
|
4038
|
+
try {
|
|
4039
|
+
const { readFileSync: readFileSync10 } = __require("fs");
|
|
4040
|
+
return readFileSync10("/etc/machine-id", "utf-8").trim();
|
|
4041
|
+
} catch {
|
|
4042
|
+
return "";
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
4046
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
4047
|
+
try {
|
|
4048
|
+
const crypto3 = __require("crypto");
|
|
4049
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
4050
|
+
if (parts.length !== 3) return null;
|
|
4051
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
4052
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
4053
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
4054
|
+
const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
4055
|
+
decipher.setAuthTag(authTag);
|
|
4056
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
4057
|
+
decrypted += decipher.final("utf-8");
|
|
4058
|
+
return decrypted;
|
|
4059
|
+
} catch {
|
|
4060
|
+
return null;
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
3966
4063
|
async function getMasterKey() {
|
|
4064
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
4065
|
+
if (nativeValue) {
|
|
4066
|
+
return Buffer.from(nativeValue, "base64");
|
|
4067
|
+
}
|
|
3967
4068
|
const keytar = await tryKeytar();
|
|
3968
4069
|
if (keytar) {
|
|
3969
4070
|
try {
|
|
3970
|
-
const
|
|
3971
|
-
if (
|
|
3972
|
-
|
|
4071
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
4072
|
+
if (keytarValue) {
|
|
4073
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
4074
|
+
if (migrated) {
|
|
4075
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
4076
|
+
}
|
|
4077
|
+
return Buffer.from(keytarValue, "base64");
|
|
3973
4078
|
}
|
|
3974
4079
|
} catch {
|
|
3975
4080
|
}
|
|
@@ -3983,8 +4088,31 @@ async function getMasterKey() {
|
|
|
3983
4088
|
return null;
|
|
3984
4089
|
}
|
|
3985
4090
|
try {
|
|
3986
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3987
|
-
|
|
4091
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
4092
|
+
let b64Value;
|
|
4093
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
4094
|
+
const machineKey = deriveMachineKey();
|
|
4095
|
+
if (!machineKey) {
|
|
4096
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
4097
|
+
return null;
|
|
4098
|
+
}
|
|
4099
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
4100
|
+
if (!decrypted) {
|
|
4101
|
+
process.stderr.write(
|
|
4102
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
4103
|
+
);
|
|
4104
|
+
return null;
|
|
4105
|
+
}
|
|
4106
|
+
b64Value = decrypted;
|
|
4107
|
+
} else {
|
|
4108
|
+
b64Value = content;
|
|
4109
|
+
}
|
|
4110
|
+
const key = Buffer.from(b64Value, "base64");
|
|
4111
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
4112
|
+
if (migrated) {
|
|
4113
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
4114
|
+
}
|
|
4115
|
+
return key;
|
|
3988
4116
|
} catch (err) {
|
|
3989
4117
|
process.stderr.write(
|
|
3990
4118
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -4538,8 +4666,8 @@ async function main() {
|
|
|
4538
4666
|
}
|
|
4539
4667
|
if (!process.env[CODEX.apiKeyEnv]) {
|
|
4540
4668
|
try {
|
|
4541
|
-
const { execSync:
|
|
4542
|
-
const status =
|
|
4669
|
+
const { execSync: execSync6 } = await import("child_process");
|
|
4670
|
+
const status = execSync6("codex login status 2>&1", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
4543
4671
|
if (!status.toLowerCase().includes("logged in")) {
|
|
4544
4672
|
process.stderr.write(
|
|
4545
4673
|
`exe-start-codex: not authenticated. Run \`codex login\` or set ${CODEX.apiKeyEnv}.
|