@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/exe-daemon.js
CHANGED
|
@@ -2086,8 +2086,8 @@ function findPackageRoot() {
|
|
|
2086
2086
|
function getAvailableMemoryGB() {
|
|
2087
2087
|
if (process.platform === "darwin") {
|
|
2088
2088
|
try {
|
|
2089
|
-
const { execSync:
|
|
2090
|
-
const vmstat =
|
|
2089
|
+
const { execSync: execSync13 } = __require("child_process");
|
|
2090
|
+
const vmstat = execSync13("vm_stat", { encoding: "utf8" });
|
|
2091
2091
|
const pageSize = 16384;
|
|
2092
2092
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
2093
2093
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -3715,6 +3715,7 @@ __export(keychain_exports, {
|
|
|
3715
3715
|
});
|
|
3716
3716
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3717
3717
|
import { existsSync as existsSync10 } from "fs";
|
|
3718
|
+
import { execSync as execSync2 } from "child_process";
|
|
3718
3719
|
import path10 from "path";
|
|
3719
3720
|
import os6 from "os";
|
|
3720
3721
|
function getKeyDir() {
|
|
@@ -3723,6 +3724,83 @@ function getKeyDir() {
|
|
|
3723
3724
|
function getKeyPath() {
|
|
3724
3725
|
return path10.join(getKeyDir(), "master.key");
|
|
3725
3726
|
}
|
|
3727
|
+
function macKeychainGet() {
|
|
3728
|
+
if (process.platform !== "darwin") return null;
|
|
3729
|
+
try {
|
|
3730
|
+
return execSync2(
|
|
3731
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
3732
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3733
|
+
).trim();
|
|
3734
|
+
} catch {
|
|
3735
|
+
return null;
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
function macKeychainSet(value) {
|
|
3739
|
+
if (process.platform !== "darwin") return false;
|
|
3740
|
+
try {
|
|
3741
|
+
try {
|
|
3742
|
+
execSync2(
|
|
3743
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3744
|
+
{ timeout: 5e3 }
|
|
3745
|
+
);
|
|
3746
|
+
} catch {
|
|
3747
|
+
}
|
|
3748
|
+
execSync2(
|
|
3749
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
3750
|
+
{ timeout: 5e3 }
|
|
3751
|
+
);
|
|
3752
|
+
return true;
|
|
3753
|
+
} catch {
|
|
3754
|
+
return false;
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
function macKeychainDelete() {
|
|
3758
|
+
if (process.platform !== "darwin") return false;
|
|
3759
|
+
try {
|
|
3760
|
+
execSync2(
|
|
3761
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
3762
|
+
{ timeout: 5e3 }
|
|
3763
|
+
);
|
|
3764
|
+
return true;
|
|
3765
|
+
} catch {
|
|
3766
|
+
return false;
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
function linuxSecretGet() {
|
|
3770
|
+
if (process.platform !== "linux") return null;
|
|
3771
|
+
try {
|
|
3772
|
+
return execSync2(
|
|
3773
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3774
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
3775
|
+
).trim();
|
|
3776
|
+
} catch {
|
|
3777
|
+
return null;
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
function linuxSecretSet(value) {
|
|
3781
|
+
if (process.platform !== "linux") return false;
|
|
3782
|
+
try {
|
|
3783
|
+
execSync2(
|
|
3784
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
3785
|
+
{ timeout: 5e3 }
|
|
3786
|
+
);
|
|
3787
|
+
return true;
|
|
3788
|
+
} catch {
|
|
3789
|
+
return false;
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
function linuxSecretDelete() {
|
|
3793
|
+
if (process.platform !== "linux") return false;
|
|
3794
|
+
try {
|
|
3795
|
+
execSync2(
|
|
3796
|
+
`secret-tool clear service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
3797
|
+
{ timeout: 5e3 }
|
|
3798
|
+
);
|
|
3799
|
+
return true;
|
|
3800
|
+
} catch {
|
|
3801
|
+
return false;
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3726
3804
|
async function tryKeytar() {
|
|
3727
3805
|
try {
|
|
3728
3806
|
return await import("keytar");
|
|
@@ -3730,13 +3808,72 @@ async function tryKeytar() {
|
|
|
3730
3808
|
return null;
|
|
3731
3809
|
}
|
|
3732
3810
|
}
|
|
3811
|
+
function deriveMachineKey() {
|
|
3812
|
+
try {
|
|
3813
|
+
const crypto14 = __require("crypto");
|
|
3814
|
+
const material = [
|
|
3815
|
+
os6.hostname(),
|
|
3816
|
+
os6.userInfo().username,
|
|
3817
|
+
os6.arch(),
|
|
3818
|
+
os6.platform(),
|
|
3819
|
+
// Machine ID on Linux (stable across reboots)
|
|
3820
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
3821
|
+
].join("|");
|
|
3822
|
+
return crypto14.createHash("sha256").update(material).digest();
|
|
3823
|
+
} catch {
|
|
3824
|
+
return null;
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
function readMachineId() {
|
|
3828
|
+
try {
|
|
3829
|
+
const { readFileSync: readFileSync22 } = __require("fs");
|
|
3830
|
+
return readFileSync22("/etc/machine-id", "utf-8").trim();
|
|
3831
|
+
} catch {
|
|
3832
|
+
return "";
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
function encryptWithMachineKey(plaintext, machineKey) {
|
|
3836
|
+
const crypto14 = __require("crypto");
|
|
3837
|
+
const iv = crypto14.randomBytes(12);
|
|
3838
|
+
const cipher = crypto14.createCipheriv("aes-256-gcm", machineKey, iv);
|
|
3839
|
+
let encrypted = cipher.update(plaintext, "utf-8", "base64");
|
|
3840
|
+
encrypted += cipher.final("base64");
|
|
3841
|
+
const authTag = cipher.getAuthTag().toString("base64");
|
|
3842
|
+
return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
|
|
3843
|
+
}
|
|
3844
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
3845
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
3846
|
+
try {
|
|
3847
|
+
const crypto14 = __require("crypto");
|
|
3848
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
3849
|
+
if (parts.length !== 3) return null;
|
|
3850
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
3851
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
3852
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
3853
|
+
const decipher = crypto14.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
3854
|
+
decipher.setAuthTag(authTag);
|
|
3855
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
3856
|
+
decrypted += decipher.final("utf-8");
|
|
3857
|
+
return decrypted;
|
|
3858
|
+
} catch {
|
|
3859
|
+
return null;
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3733
3862
|
async function getMasterKey() {
|
|
3863
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3864
|
+
if (nativeValue) {
|
|
3865
|
+
return Buffer.from(nativeValue, "base64");
|
|
3866
|
+
}
|
|
3734
3867
|
const keytar = await tryKeytar();
|
|
3735
3868
|
if (keytar) {
|
|
3736
3869
|
try {
|
|
3737
|
-
const
|
|
3738
|
-
if (
|
|
3739
|
-
|
|
3870
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3871
|
+
if (keytarValue) {
|
|
3872
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
3873
|
+
if (migrated) {
|
|
3874
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3875
|
+
}
|
|
3876
|
+
return Buffer.from(keytarValue, "base64");
|
|
3740
3877
|
}
|
|
3741
3878
|
} catch {
|
|
3742
3879
|
}
|
|
@@ -3750,8 +3887,31 @@ async function getMasterKey() {
|
|
|
3750
3887
|
return null;
|
|
3751
3888
|
}
|
|
3752
3889
|
try {
|
|
3753
|
-
const content = await readFile3(keyPath, "utf-8");
|
|
3754
|
-
|
|
3890
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3891
|
+
let b64Value;
|
|
3892
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3893
|
+
const machineKey = deriveMachineKey();
|
|
3894
|
+
if (!machineKey) {
|
|
3895
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
3896
|
+
return null;
|
|
3897
|
+
}
|
|
3898
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3899
|
+
if (!decrypted) {
|
|
3900
|
+
process.stderr.write(
|
|
3901
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
3902
|
+
);
|
|
3903
|
+
return null;
|
|
3904
|
+
}
|
|
3905
|
+
b64Value = decrypted;
|
|
3906
|
+
} else {
|
|
3907
|
+
b64Value = content;
|
|
3908
|
+
}
|
|
3909
|
+
const key = Buffer.from(b64Value, "base64");
|
|
3910
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3911
|
+
if (migrated) {
|
|
3912
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
3913
|
+
}
|
|
3914
|
+
return key;
|
|
3755
3915
|
} catch (err) {
|
|
3756
3916
|
process.stderr.write(
|
|
3757
3917
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -3762,6 +3922,9 @@ async function getMasterKey() {
|
|
|
3762
3922
|
}
|
|
3763
3923
|
async function setMasterKey(key) {
|
|
3764
3924
|
const b64 = key.toString("base64");
|
|
3925
|
+
if (macKeychainSet(b64) || linuxSecretSet(b64)) {
|
|
3926
|
+
return;
|
|
3927
|
+
}
|
|
3765
3928
|
const keytar = await tryKeytar();
|
|
3766
3929
|
if (keytar) {
|
|
3767
3930
|
try {
|
|
@@ -3773,10 +3936,23 @@ async function setMasterKey(key) {
|
|
|
3773
3936
|
const dir = getKeyDir();
|
|
3774
3937
|
await mkdir3(dir, { recursive: true });
|
|
3775
3938
|
const keyPath = getKeyPath();
|
|
3776
|
-
|
|
3777
|
-
|
|
3939
|
+
const machineKey = deriveMachineKey();
|
|
3940
|
+
if (machineKey) {
|
|
3941
|
+
const encrypted = encryptWithMachineKey(b64, machineKey);
|
|
3942
|
+
await writeFile3(keyPath, encrypted + "\n", "utf-8");
|
|
3943
|
+
await chmod2(keyPath, 384);
|
|
3944
|
+
process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
|
|
3945
|
+
} else {
|
|
3946
|
+
await writeFile3(keyPath, b64 + "\n", "utf-8");
|
|
3947
|
+
await chmod2(keyPath, 384);
|
|
3948
|
+
process.stderr.write(
|
|
3949
|
+
"[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
|
|
3950
|
+
);
|
|
3951
|
+
}
|
|
3778
3952
|
}
|
|
3779
3953
|
async function deleteMasterKey() {
|
|
3954
|
+
macKeychainDelete();
|
|
3955
|
+
linuxSecretDelete();
|
|
3780
3956
|
const keytar = await tryKeytar();
|
|
3781
3957
|
if (keytar) {
|
|
3782
3958
|
try {
|
|
@@ -3818,12 +3994,13 @@ async function importMnemonic(mnemonic) {
|
|
|
3818
3994
|
const entropy = mnemonicToEntropy(trimmed);
|
|
3819
3995
|
return Buffer.from(entropy, "hex");
|
|
3820
3996
|
}
|
|
3821
|
-
var SERVICE, ACCOUNT;
|
|
3997
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3822
3998
|
var init_keychain = __esm({
|
|
3823
3999
|
"src/lib/keychain.ts"() {
|
|
3824
4000
|
"use strict";
|
|
3825
4001
|
SERVICE = "exe-mem";
|
|
3826
4002
|
ACCOUNT = "master-key";
|
|
4003
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
3827
4004
|
}
|
|
3828
4005
|
});
|
|
3829
4006
|
|
|
@@ -4827,7 +5004,7 @@ __export(session_registry_exports, {
|
|
|
4827
5004
|
registerSession: () => registerSession
|
|
4828
5005
|
});
|
|
4829
5006
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3, existsSync as existsSync12 } from "fs";
|
|
4830
|
-
import { execSync as
|
|
5007
|
+
import { execSync as execSync3 } from "child_process";
|
|
4831
5008
|
import path12 from "path";
|
|
4832
5009
|
import os7 from "os";
|
|
4833
5010
|
function registerSession(entry) {
|
|
@@ -4867,7 +5044,7 @@ function pruneStaleSessions() {
|
|
|
4867
5044
|
if (sessions.length === 0) return 0;
|
|
4868
5045
|
let liveSessions = [];
|
|
4869
5046
|
try {
|
|
4870
|
-
liveSessions =
|
|
5047
|
+
liveSessions = execSync3("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
4871
5048
|
encoding: "utf8"
|
|
4872
5049
|
}).trim().split("\n").filter(Boolean);
|
|
4873
5050
|
} catch {
|
|
@@ -4890,7 +5067,7 @@ var init_session_registry = __esm({
|
|
|
4890
5067
|
});
|
|
4891
5068
|
|
|
4892
5069
|
// src/lib/session-key.ts
|
|
4893
|
-
import { execSync as
|
|
5070
|
+
import { execSync as execSync4 } from "child_process";
|
|
4894
5071
|
function normalizeCommand(command) {
|
|
4895
5072
|
const trimmed = command.trim().toLowerCase();
|
|
4896
5073
|
const parts = trimmed.split(/[\\/]/);
|
|
@@ -4909,7 +5086,7 @@ function resolveRuntimeProcess() {
|
|
|
4909
5086
|
let pid = process.ppid;
|
|
4910
5087
|
for (let i = 0; i < 10; i++) {
|
|
4911
5088
|
try {
|
|
4912
|
-
const info =
|
|
5089
|
+
const info = execSync4(`ps -p ${pid} -o ppid=,comm=`, {
|
|
4913
5090
|
encoding: "utf8",
|
|
4914
5091
|
timeout: 2e3
|
|
4915
5092
|
}).trim();
|
|
@@ -5083,14 +5260,14 @@ var init_transport = __esm({
|
|
|
5083
5260
|
});
|
|
5084
5261
|
|
|
5085
5262
|
// src/lib/cc-agent-support.ts
|
|
5086
|
-
import { execSync as
|
|
5263
|
+
import { execSync as execSync5 } from "child_process";
|
|
5087
5264
|
function _resetCcAgentSupportCache() {
|
|
5088
5265
|
_cachedSupport = null;
|
|
5089
5266
|
}
|
|
5090
5267
|
function claudeSupportsAgentFlag() {
|
|
5091
5268
|
if (_cachedSupport !== null) return _cachedSupport;
|
|
5092
5269
|
try {
|
|
5093
|
-
const helpOutput =
|
|
5270
|
+
const helpOutput = execSync5("claude --help 2>&1", {
|
|
5094
5271
|
encoding: "utf-8",
|
|
5095
5272
|
timeout: 5e3
|
|
5096
5273
|
});
|
|
@@ -5568,7 +5745,7 @@ var init_session_kill_telemetry = __esm({
|
|
|
5568
5745
|
});
|
|
5569
5746
|
|
|
5570
5747
|
// src/lib/project-name.ts
|
|
5571
|
-
import { execSync as
|
|
5748
|
+
import { execSync as execSync6 } from "child_process";
|
|
5572
5749
|
import path17 from "path";
|
|
5573
5750
|
function getProjectName(cwd) {
|
|
5574
5751
|
const dir = cwd ?? process.cwd();
|
|
@@ -5576,7 +5753,7 @@ function getProjectName(cwd) {
|
|
|
5576
5753
|
try {
|
|
5577
5754
|
let repoRoot;
|
|
5578
5755
|
try {
|
|
5579
|
-
const gitCommonDir =
|
|
5756
|
+
const gitCommonDir = execSync6("git rev-parse --path-format=absolute --git-common-dir", {
|
|
5580
5757
|
cwd: dir,
|
|
5581
5758
|
encoding: "utf8",
|
|
5582
5759
|
timeout: 2e3,
|
|
@@ -5584,7 +5761,7 @@ function getProjectName(cwd) {
|
|
|
5584
5761
|
}).trim();
|
|
5585
5762
|
repoRoot = path17.dirname(gitCommonDir);
|
|
5586
5763
|
} catch {
|
|
5587
|
-
repoRoot =
|
|
5764
|
+
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
5588
5765
|
cwd: dir,
|
|
5589
5766
|
encoding: "utf8",
|
|
5590
5767
|
timeout: 2e3,
|
|
@@ -5675,7 +5852,7 @@ var init_session_scope = __esm({
|
|
|
5675
5852
|
import crypto5 from "crypto";
|
|
5676
5853
|
import path18 from "path";
|
|
5677
5854
|
import os11 from "os";
|
|
5678
|
-
import { execSync as
|
|
5855
|
+
import { execSync as execSync7 } from "child_process";
|
|
5679
5856
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
5680
5857
|
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
5681
5858
|
async function writeCheckpoint(input) {
|
|
@@ -6020,14 +6197,14 @@ function isTmuxSessionAlive(identifier) {
|
|
|
6020
6197
|
if (!identifier || identifier === "unknown") return true;
|
|
6021
6198
|
try {
|
|
6022
6199
|
if (identifier.startsWith("%")) {
|
|
6023
|
-
const output =
|
|
6200
|
+
const output = execSync7("tmux list-panes -a -F '#{pane_id}'", {
|
|
6024
6201
|
timeout: 2e3,
|
|
6025
6202
|
encoding: "utf8",
|
|
6026
6203
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6027
6204
|
});
|
|
6028
6205
|
return output.split("\n").some((l) => l.trim() === identifier);
|
|
6029
6206
|
} else {
|
|
6030
|
-
|
|
6207
|
+
execSync7(`tmux has-session -t ${JSON.stringify(identifier)}`, {
|
|
6031
6208
|
timeout: 2e3,
|
|
6032
6209
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6033
6210
|
});
|
|
@@ -6036,7 +6213,7 @@ function isTmuxSessionAlive(identifier) {
|
|
|
6036
6213
|
} catch {
|
|
6037
6214
|
if (identifier.startsWith("%")) return true;
|
|
6038
6215
|
try {
|
|
6039
|
-
|
|
6216
|
+
execSync7("tmux list-sessions", {
|
|
6040
6217
|
timeout: 2e3,
|
|
6041
6218
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6042
6219
|
});
|
|
@@ -6051,12 +6228,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
6051
6228
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
6052
6229
|
try {
|
|
6053
6230
|
const since = new Date(taskCreatedAt).toISOString();
|
|
6054
|
-
const branch =
|
|
6231
|
+
const branch = execSync7(
|
|
6055
6232
|
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
6056
6233
|
{ encoding: "utf8", timeout: 3e3 }
|
|
6057
6234
|
).trim();
|
|
6058
6235
|
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
6059
|
-
const commitCount =
|
|
6236
|
+
const commitCount = execSync7(
|
|
6060
6237
|
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
6061
6238
|
{ encoding: "utf8", timeout: 5e3 }
|
|
6062
6239
|
).trim();
|
|
@@ -6794,10 +6971,10 @@ async function disposeEmbedder() {
|
|
|
6794
6971
|
async function embedDirect(text) {
|
|
6795
6972
|
const llamaCpp = await import("node-llama-cpp");
|
|
6796
6973
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6797
|
-
const { existsSync:
|
|
6798
|
-
const
|
|
6799
|
-
const modelPath =
|
|
6800
|
-
if (!
|
|
6974
|
+
const { existsSync: existsSync27 } = await import("fs");
|
|
6975
|
+
const path32 = await import("path");
|
|
6976
|
+
const modelPath = path32.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
6977
|
+
if (!existsSync27(modelPath)) {
|
|
6801
6978
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
6802
6979
|
}
|
|
6803
6980
|
const llama = await llamaCpp.getLlama();
|
|
@@ -7654,7 +7831,7 @@ __export(tmux_routing_exports, {
|
|
|
7654
7831
|
spawnEmployee: () => spawnEmployee,
|
|
7655
7832
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
7656
7833
|
});
|
|
7657
|
-
import { execFileSync as execFileSync2, execSync as
|
|
7834
|
+
import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
|
|
7658
7835
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, mkdirSync as mkdirSync7, existsSync as existsSync19, appendFileSync as appendFileSync2, readdirSync as readdirSync4 } from "fs";
|
|
7659
7836
|
import path22 from "path";
|
|
7660
7837
|
import os12 from "os";
|
|
@@ -8364,7 +8541,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8364
8541
|
let booted = false;
|
|
8365
8542
|
for (let i = 0; i < 30; i++) {
|
|
8366
8543
|
try {
|
|
8367
|
-
|
|
8544
|
+
execSync8("sleep 0.5");
|
|
8368
8545
|
} catch {
|
|
8369
8546
|
}
|
|
8370
8547
|
try {
|
|
@@ -8484,7 +8661,7 @@ __export(review_polling_exports, {
|
|
|
8484
8661
|
createRealDeps: () => createRealDeps,
|
|
8485
8662
|
pollPendingReviews: () => pollPendingReviews
|
|
8486
8663
|
});
|
|
8487
|
-
import { execSync as
|
|
8664
|
+
import { execSync as execSync9 } from "child_process";
|
|
8488
8665
|
async function pollPendingReviews(deps, _state) {
|
|
8489
8666
|
let sessions;
|
|
8490
8667
|
try {
|
|
@@ -8591,7 +8768,7 @@ async function pollPendingReviews(deps, _state) {
|
|
|
8591
8768
|
function createRealDeps(getClient2) {
|
|
8592
8769
|
return {
|
|
8593
8770
|
listTmuxSessions: () => {
|
|
8594
|
-
return
|
|
8771
|
+
return execSync9("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
8595
8772
|
encoding: "utf8",
|
|
8596
8773
|
timeout: 3e3
|
|
8597
8774
|
}).trim().split("\n").filter(Boolean);
|
|
@@ -8698,13 +8875,13 @@ __export(tmux_status_exports, {
|
|
|
8698
8875
|
parseActivity: () => parseActivity,
|
|
8699
8876
|
parseContextPercentage: () => parseContextPercentage
|
|
8700
8877
|
});
|
|
8701
|
-
import { execSync as
|
|
8878
|
+
import { execSync as execSync10 } from "child_process";
|
|
8702
8879
|
function inTmux() {
|
|
8703
8880
|
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
8704
8881
|
const term = process.env.TERM ?? "";
|
|
8705
8882
|
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
8706
8883
|
try {
|
|
8707
|
-
|
|
8884
|
+
execSync10("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
8708
8885
|
encoding: "utf8",
|
|
8709
8886
|
timeout: 2e3
|
|
8710
8887
|
});
|
|
@@ -8714,12 +8891,12 @@ function inTmux() {
|
|
|
8714
8891
|
try {
|
|
8715
8892
|
let pid = process.ppid;
|
|
8716
8893
|
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
8717
|
-
const comm =
|
|
8894
|
+
const comm = execSync10(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
8718
8895
|
encoding: "utf8",
|
|
8719
8896
|
timeout: 1e3
|
|
8720
8897
|
}).trim();
|
|
8721
8898
|
if (/tmux/.test(comm)) return true;
|
|
8722
|
-
const ppid =
|
|
8899
|
+
const ppid = execSync10(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
8723
8900
|
encoding: "utf8",
|
|
8724
8901
|
timeout: 1e3
|
|
8725
8902
|
}).trim();
|
|
@@ -8732,7 +8909,7 @@ function inTmux() {
|
|
|
8732
8909
|
}
|
|
8733
8910
|
function listTmuxSessions() {
|
|
8734
8911
|
try {
|
|
8735
|
-
const out =
|
|
8912
|
+
const out = execSync10("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
8736
8913
|
encoding: "utf8",
|
|
8737
8914
|
timeout: 3e3
|
|
8738
8915
|
});
|
|
@@ -8743,7 +8920,7 @@ function listTmuxSessions() {
|
|
|
8743
8920
|
}
|
|
8744
8921
|
function capturePaneLines(windowName, lines = 10) {
|
|
8745
8922
|
try {
|
|
8746
|
-
const out =
|
|
8923
|
+
const out = execSync10(
|
|
8747
8924
|
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
8748
8925
|
{ encoding: "utf8", timeout: 3e3 }
|
|
8749
8926
|
);
|
|
@@ -8754,7 +8931,7 @@ function capturePaneLines(windowName, lines = 10) {
|
|
|
8754
8931
|
}
|
|
8755
8932
|
function getPaneCwd(windowName) {
|
|
8756
8933
|
try {
|
|
8757
|
-
const out =
|
|
8934
|
+
const out = execSync10(
|
|
8758
8935
|
`tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
|
|
8759
8936
|
{ encoding: "utf8", timeout: 3e3 }
|
|
8760
8937
|
);
|
|
@@ -8765,7 +8942,7 @@ function getPaneCwd(windowName) {
|
|
|
8765
8942
|
}
|
|
8766
8943
|
function projectFromPath(dir) {
|
|
8767
8944
|
try {
|
|
8768
|
-
const root =
|
|
8945
|
+
const root = execSync10("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
|
|
8769
8946
|
encoding: "utf8",
|
|
8770
8947
|
timeout: 3e3
|
|
8771
8948
|
}).trim();
|
|
@@ -8834,7 +9011,7 @@ function getEmployeeStatuses(employeeNames) {
|
|
|
8834
9011
|
}
|
|
8835
9012
|
let paneAlive = true;
|
|
8836
9013
|
try {
|
|
8837
|
-
const paneStatus =
|
|
9014
|
+
const paneStatus = execSync10(
|
|
8838
9015
|
`tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
|
|
8839
9016
|
{ encoding: "utf8", timeout: 3e3 }
|
|
8840
9017
|
).trim();
|
|
@@ -9080,7 +9257,7 @@ __export(daemon_orchestration_exports, {
|
|
|
9080
9257
|
shouldKillSession: () => shouldKillSession,
|
|
9081
9258
|
shouldNudgeEmployee: () => shouldNudgeEmployee
|
|
9082
9259
|
});
|
|
9083
|
-
import { execSync as
|
|
9260
|
+
import { execSync as execSync11 } from "child_process";
|
|
9084
9261
|
import { existsSync as existsSync21, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
9085
9262
|
import { homedir } from "os";
|
|
9086
9263
|
import { join } from "path";
|
|
@@ -9398,7 +9575,7 @@ function createSessionTTLRealDeps(getClient2) {
|
|
|
9398
9575
|
},
|
|
9399
9576
|
getSessionCreatedEpoch: (sessionName) => {
|
|
9400
9577
|
try {
|
|
9401
|
-
const out =
|
|
9578
|
+
const out = execSync11(
|
|
9402
9579
|
`tmux display-message -t ${JSON.stringify(sessionName)} -p '#{session_created}' 2>/dev/null`,
|
|
9403
9580
|
{ encoding: "utf8", timeout: 3e3 }
|
|
9404
9581
|
).trim();
|
|
@@ -9625,7 +9802,7 @@ function reapOrphanedMcpProcesses(deps) {
|
|
|
9625
9802
|
function createOrphanReaperRealDeps() {
|
|
9626
9803
|
return {
|
|
9627
9804
|
listProcesses: () => {
|
|
9628
|
-
const output =
|
|
9805
|
+
const output = execSync11("ps -eo pid,ppid,args", {
|
|
9629
9806
|
encoding: "utf8",
|
|
9630
9807
|
timeout: 5e3
|
|
9631
9808
|
});
|
|
@@ -10079,6 +10256,109 @@ var init_consolidation = __esm({
|
|
|
10079
10256
|
}
|
|
10080
10257
|
});
|
|
10081
10258
|
|
|
10259
|
+
// src/lib/db-backup.ts
|
|
10260
|
+
var db_backup_exports = {};
|
|
10261
|
+
__export(db_backup_exports, {
|
|
10262
|
+
createBackup: () => createBackup,
|
|
10263
|
+
findActiveDb: () => findActiveDb,
|
|
10264
|
+
getBackupDir: () => getBackupDir,
|
|
10265
|
+
getLatestBackup: () => getLatestBackup,
|
|
10266
|
+
hasBackupToday: () => hasBackupToday,
|
|
10267
|
+
listBackups: () => listBackups,
|
|
10268
|
+
rotateBackups: () => rotateBackups
|
|
10269
|
+
});
|
|
10270
|
+
import { copyFileSync, existsSync as existsSync22, mkdirSync as mkdirSync8, readdirSync as readdirSync5, unlinkSync as unlinkSync8, statSync as statSync3 } from "fs";
|
|
10271
|
+
import path24 from "path";
|
|
10272
|
+
function findActiveDb() {
|
|
10273
|
+
for (const name of DB_NAMES) {
|
|
10274
|
+
const p = path24.join(EXE_AI_DIR, name);
|
|
10275
|
+
if (existsSync22(p)) return p;
|
|
10276
|
+
}
|
|
10277
|
+
return null;
|
|
10278
|
+
}
|
|
10279
|
+
function createBackup(reason = "manual") {
|
|
10280
|
+
const dbPath = findActiveDb();
|
|
10281
|
+
if (!dbPath) return null;
|
|
10282
|
+
mkdirSync8(BACKUP_DIR, { recursive: true });
|
|
10283
|
+
const dbName = path24.basename(dbPath, ".db");
|
|
10284
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
10285
|
+
const backupName = `${dbName}-${reason}-${timestamp}.db`;
|
|
10286
|
+
const backupPath = path24.join(BACKUP_DIR, backupName);
|
|
10287
|
+
copyFileSync(dbPath, backupPath);
|
|
10288
|
+
const walPath = dbPath + "-wal";
|
|
10289
|
+
if (existsSync22(walPath)) {
|
|
10290
|
+
try {
|
|
10291
|
+
copyFileSync(walPath, backupPath + "-wal");
|
|
10292
|
+
} catch {
|
|
10293
|
+
}
|
|
10294
|
+
}
|
|
10295
|
+
const shmPath = dbPath + "-shm";
|
|
10296
|
+
if (existsSync22(shmPath)) {
|
|
10297
|
+
try {
|
|
10298
|
+
copyFileSync(shmPath, backupPath + "-shm");
|
|
10299
|
+
} catch {
|
|
10300
|
+
}
|
|
10301
|
+
}
|
|
10302
|
+
return backupPath;
|
|
10303
|
+
}
|
|
10304
|
+
function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
10305
|
+
if (!existsSync22(BACKUP_DIR)) return 0;
|
|
10306
|
+
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
10307
|
+
let deleted = 0;
|
|
10308
|
+
try {
|
|
10309
|
+
const files = readdirSync5(BACKUP_DIR);
|
|
10310
|
+
for (const file of files) {
|
|
10311
|
+
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
10312
|
+
const filePath = path24.join(BACKUP_DIR, file);
|
|
10313
|
+
try {
|
|
10314
|
+
const stat = statSync3(filePath);
|
|
10315
|
+
if (stat.mtimeMs < cutoff) {
|
|
10316
|
+
unlinkSync8(filePath);
|
|
10317
|
+
deleted++;
|
|
10318
|
+
}
|
|
10319
|
+
} catch {
|
|
10320
|
+
}
|
|
10321
|
+
}
|
|
10322
|
+
} catch {
|
|
10323
|
+
}
|
|
10324
|
+
return deleted;
|
|
10325
|
+
}
|
|
10326
|
+
function listBackups() {
|
|
10327
|
+
if (!existsSync22(BACKUP_DIR)) return [];
|
|
10328
|
+
try {
|
|
10329
|
+
const files = readdirSync5(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
10330
|
+
return files.map((name) => {
|
|
10331
|
+
const p = path24.join(BACKUP_DIR, name);
|
|
10332
|
+
const stat = statSync3(p);
|
|
10333
|
+
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
10334
|
+
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
10335
|
+
} catch {
|
|
10336
|
+
return [];
|
|
10337
|
+
}
|
|
10338
|
+
}
|
|
10339
|
+
function hasBackupToday(reason) {
|
|
10340
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
10341
|
+
const backups = listBackups();
|
|
10342
|
+
return backups.some((b) => b.name.includes(reason) && b.name.includes(today.replace(/-/g, "-")));
|
|
10343
|
+
}
|
|
10344
|
+
function getLatestBackup() {
|
|
10345
|
+
const backups = listBackups();
|
|
10346
|
+
return backups.length > 0 ? backups[0].path : null;
|
|
10347
|
+
}
|
|
10348
|
+
function getBackupDir() {
|
|
10349
|
+
return BACKUP_DIR;
|
|
10350
|
+
}
|
|
10351
|
+
var BACKUP_DIR, DEFAULT_KEEP_DAYS, DB_NAMES;
|
|
10352
|
+
var init_db_backup = __esm({
|
|
10353
|
+
"src/lib/db-backup.ts"() {
|
|
10354
|
+
"use strict";
|
|
10355
|
+
init_config();
|
|
10356
|
+
BACKUP_DIR = path24.join(EXE_AI_DIR, "backups");
|
|
10357
|
+
DEFAULT_KEEP_DAYS = 3;
|
|
10358
|
+
DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
|
|
10359
|
+
}
|
|
10360
|
+
});
|
|
10361
|
+
|
|
10082
10362
|
// src/lib/crypto.ts
|
|
10083
10363
|
import crypto8 from "crypto";
|
|
10084
10364
|
function initSyncCrypto(masterKey) {
|
|
@@ -10170,8 +10450,8 @@ __export(crdt_sync_exports, {
|
|
|
10170
10450
|
rebuildFromDb: () => rebuildFromDb
|
|
10171
10451
|
});
|
|
10172
10452
|
import * as Y from "yjs";
|
|
10173
|
-
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as
|
|
10174
|
-
import
|
|
10453
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync23, mkdirSync as mkdirSync9, unlinkSync as unlinkSync9 } from "fs";
|
|
10454
|
+
import path25 from "path";
|
|
10175
10455
|
import { homedir as homedir2 } from "os";
|
|
10176
10456
|
function getStatePath() {
|
|
10177
10457
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -10183,14 +10463,14 @@ function initCrdtDoc() {
|
|
|
10183
10463
|
if (doc) return doc;
|
|
10184
10464
|
doc = new Y.Doc();
|
|
10185
10465
|
const sp = getStatePath();
|
|
10186
|
-
if (
|
|
10466
|
+
if (existsSync23(sp)) {
|
|
10187
10467
|
try {
|
|
10188
10468
|
const state = readFileSync17(sp);
|
|
10189
10469
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
10190
10470
|
} catch {
|
|
10191
10471
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
10192
10472
|
try {
|
|
10193
|
-
|
|
10473
|
+
unlinkSync9(sp);
|
|
10194
10474
|
} catch {
|
|
10195
10475
|
}
|
|
10196
10476
|
rebuildFromDb().catch((err) => {
|
|
@@ -10327,8 +10607,8 @@ function persistState() {
|
|
|
10327
10607
|
if (!doc) return;
|
|
10328
10608
|
try {
|
|
10329
10609
|
const sp = getStatePath();
|
|
10330
|
-
const dir =
|
|
10331
|
-
if (!
|
|
10610
|
+
const dir = path25.dirname(sp);
|
|
10611
|
+
if (!existsSync23(dir)) mkdirSync9(dir, { recursive: true });
|
|
10332
10612
|
const state = Y.encodeStateAsUpdate(doc);
|
|
10333
10613
|
writeFileSync11(sp, Buffer.from(state));
|
|
10334
10614
|
} catch {
|
|
@@ -10371,7 +10651,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
10371
10651
|
var init_crdt_sync = __esm({
|
|
10372
10652
|
"src/lib/crdt-sync.ts"() {
|
|
10373
10653
|
"use strict";
|
|
10374
|
-
DEFAULT_STATE_PATH =
|
|
10654
|
+
DEFAULT_STATE_PATH = path25.join(homedir2(), ".exe-os", "crdt-state.bin");
|
|
10375
10655
|
_statePathOverride = null;
|
|
10376
10656
|
doc = null;
|
|
10377
10657
|
}
|
|
@@ -10406,16 +10686,16 @@ __export(cloud_sync_exports, {
|
|
|
10406
10686
|
pushToPostgres: () => pushToPostgres,
|
|
10407
10687
|
recordRosterDeletion: () => recordRosterDeletion
|
|
10408
10688
|
});
|
|
10409
|
-
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as
|
|
10689
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, existsSync as existsSync24, readdirSync as readdirSync6, mkdirSync as mkdirSync10, appendFileSync as appendFileSync3, unlinkSync as unlinkSync10, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
10410
10690
|
import crypto9 from "crypto";
|
|
10411
|
-
import
|
|
10691
|
+
import path26 from "path";
|
|
10412
10692
|
import { homedir as homedir3 } from "os";
|
|
10413
10693
|
function sqlSafe(v) {
|
|
10414
10694
|
return v === void 0 ? null : v;
|
|
10415
10695
|
}
|
|
10416
10696
|
function logError(msg) {
|
|
10417
10697
|
try {
|
|
10418
|
-
const logPath =
|
|
10698
|
+
const logPath = path26.join(homedir3(), ".exe-os", "workers.log");
|
|
10419
10699
|
appendFileSync3(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
10420
10700
|
`);
|
|
10421
10701
|
} catch {
|
|
@@ -10424,10 +10704,10 @@ function logError(msg) {
|
|
|
10424
10704
|
function loadPgClient() {
|
|
10425
10705
|
if (_pgFailed) return null;
|
|
10426
10706
|
const postgresUrl = process.env.DATABASE_URL;
|
|
10427
|
-
const configPath =
|
|
10707
|
+
const configPath = path26.join(EXE_AI_DIR, "config.json");
|
|
10428
10708
|
let cloudPostgresUrl;
|
|
10429
10709
|
try {
|
|
10430
|
-
if (
|
|
10710
|
+
if (existsSync24(configPath)) {
|
|
10431
10711
|
const cfg = JSON.parse(readFileSync18(configPath, "utf8"));
|
|
10432
10712
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
10433
10713
|
if (cfg.cloud?.syncToPostgres === false) {
|
|
@@ -10446,8 +10726,8 @@ function loadPgClient() {
|
|
|
10446
10726
|
_pgPromise = (async () => {
|
|
10447
10727
|
const { createRequire: createRequire4 } = await import("module");
|
|
10448
10728
|
const { pathToFileURL: pathToFileURL4 } = await import("url");
|
|
10449
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
10450
|
-
const req = createRequire4(
|
|
10729
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path26.join(homedir3(), "exe-db");
|
|
10730
|
+
const req = createRequire4(path26.join(exeDbRoot, "package.json"));
|
|
10451
10731
|
const entry = req.resolve("@prisma/client");
|
|
10452
10732
|
const mod = await import(pathToFileURL4(entry).href);
|
|
10453
10733
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -10500,7 +10780,7 @@ async function withRosterLock(fn) {
|
|
|
10500
10780
|
if (Date.now() - ts2 < LOCK_STALE_MS) {
|
|
10501
10781
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
10502
10782
|
}
|
|
10503
|
-
|
|
10783
|
+
unlinkSync10(ROSTER_LOCK_PATH);
|
|
10504
10784
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
10505
10785
|
closeSync2(fd);
|
|
10506
10786
|
writeFileSync12(ROSTER_LOCK_PATH, String(Date.now()));
|
|
@@ -10516,7 +10796,7 @@ async function withRosterLock(fn) {
|
|
|
10516
10796
|
return await fn();
|
|
10517
10797
|
} finally {
|
|
10518
10798
|
try {
|
|
10519
|
-
|
|
10799
|
+
unlinkSync10(ROSTER_LOCK_PATH);
|
|
10520
10800
|
} catch {
|
|
10521
10801
|
}
|
|
10522
10802
|
}
|
|
@@ -10887,13 +11167,42 @@ async function cloudSync(config) {
|
|
|
10887
11167
|
try {
|
|
10888
11168
|
const employees = await loadEmployees();
|
|
10889
11169
|
rosterResult.employees = employees.length;
|
|
10890
|
-
const idDir =
|
|
10891
|
-
if (
|
|
10892
|
-
rosterResult.identities =
|
|
11170
|
+
const idDir = path26.join(EXE_AI_DIR, "identity");
|
|
11171
|
+
if (existsSync24(idDir)) {
|
|
11172
|
+
rosterResult.identities = readdirSync6(idDir).filter((f) => f.endsWith(".md")).length;
|
|
10893
11173
|
}
|
|
10894
11174
|
} catch {
|
|
10895
11175
|
}
|
|
10896
11176
|
const totalMemories = await countRows("SELECT COUNT(*) as cnt FROM memories WHERE status = 'active' OR status IS NULL");
|
|
11177
|
+
try {
|
|
11178
|
+
const { getLatestBackup: getLatestBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
|
|
11179
|
+
const { statSync: statFile } = await import("fs");
|
|
11180
|
+
const latestBackup = getLatestBackup2();
|
|
11181
|
+
if (latestBackup) {
|
|
11182
|
+
const backupSize = statFile(latestBackup).size;
|
|
11183
|
+
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
11184
|
+
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
11185
|
+
const backupData = readFileSync18(latestBackup);
|
|
11186
|
+
const deviceId = loadDeviceId() ?? "unknown";
|
|
11187
|
+
const encrypted = encryptSyncBlob(backupData);
|
|
11188
|
+
const backupRes = await fetchWithRetry(`${config.endpoint}/sync/push-db-backup`, {
|
|
11189
|
+
method: "POST",
|
|
11190
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
|
|
11191
|
+
body: JSON.stringify({
|
|
11192
|
+
device_id: deviceId,
|
|
11193
|
+
filename: path26.basename(latestBackup),
|
|
11194
|
+
blob: encrypted,
|
|
11195
|
+
size: backupData.length
|
|
11196
|
+
})
|
|
11197
|
+
});
|
|
11198
|
+
if (backupRes && !backupRes.ok) {
|
|
11199
|
+
logError(`[cloud-sync] DB backup upload failed: ${backupRes.status}`);
|
|
11200
|
+
}
|
|
11201
|
+
}
|
|
11202
|
+
}
|
|
11203
|
+
} catch (err) {
|
|
11204
|
+
logError(`[cloud-sync] DB backup upload error: ${err instanceof Error ? err.message : String(err)}`);
|
|
11205
|
+
}
|
|
10897
11206
|
return {
|
|
10898
11207
|
pushed,
|
|
10899
11208
|
pulled,
|
|
@@ -10909,7 +11218,7 @@ async function cloudSync(config) {
|
|
|
10909
11218
|
function recordRosterDeletion(name) {
|
|
10910
11219
|
let deletions = [];
|
|
10911
11220
|
try {
|
|
10912
|
-
if (
|
|
11221
|
+
if (existsSync24(ROSTER_DELETIONS_PATH)) {
|
|
10913
11222
|
deletions = JSON.parse(readFileSync18(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
10914
11223
|
}
|
|
10915
11224
|
} catch {
|
|
@@ -10919,7 +11228,7 @@ function recordRosterDeletion(name) {
|
|
|
10919
11228
|
}
|
|
10920
11229
|
function consumeRosterDeletions() {
|
|
10921
11230
|
try {
|
|
10922
|
-
if (!
|
|
11231
|
+
if (!existsSync24(ROSTER_DELETIONS_PATH)) return [];
|
|
10923
11232
|
const deletions = JSON.parse(readFileSync18(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
10924
11233
|
writeFileSync12(ROSTER_DELETIONS_PATH, "[]");
|
|
10925
11234
|
return deletions;
|
|
@@ -10928,35 +11237,35 @@ function consumeRosterDeletions() {
|
|
|
10928
11237
|
}
|
|
10929
11238
|
}
|
|
10930
11239
|
function buildRosterBlob(paths) {
|
|
10931
|
-
const rosterPath = paths?.rosterPath ??
|
|
10932
|
-
const identityDir = paths?.identityDir ??
|
|
10933
|
-
const configPath = paths?.configPath ??
|
|
11240
|
+
const rosterPath = paths?.rosterPath ?? path26.join(EXE_AI_DIR, "exe-employees.json");
|
|
11241
|
+
const identityDir = paths?.identityDir ?? path26.join(EXE_AI_DIR, "identity");
|
|
11242
|
+
const configPath = paths?.configPath ?? path26.join(EXE_AI_DIR, "config.json");
|
|
10934
11243
|
let roster = [];
|
|
10935
|
-
if (
|
|
11244
|
+
if (existsSync24(rosterPath)) {
|
|
10936
11245
|
try {
|
|
10937
11246
|
roster = JSON.parse(readFileSync18(rosterPath, "utf-8"));
|
|
10938
11247
|
} catch {
|
|
10939
11248
|
}
|
|
10940
11249
|
}
|
|
10941
11250
|
const identities = {};
|
|
10942
|
-
if (
|
|
10943
|
-
for (const file of
|
|
11251
|
+
if (existsSync24(identityDir)) {
|
|
11252
|
+
for (const file of readdirSync6(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
10944
11253
|
try {
|
|
10945
|
-
identities[file] = readFileSync18(
|
|
11254
|
+
identities[file] = readFileSync18(path26.join(identityDir, file), "utf-8");
|
|
10946
11255
|
} catch {
|
|
10947
11256
|
}
|
|
10948
11257
|
}
|
|
10949
11258
|
}
|
|
10950
11259
|
let config;
|
|
10951
|
-
if (
|
|
11260
|
+
if (existsSync24(configPath)) {
|
|
10952
11261
|
try {
|
|
10953
11262
|
config = JSON.parse(readFileSync18(configPath, "utf-8"));
|
|
10954
11263
|
} catch {
|
|
10955
11264
|
}
|
|
10956
11265
|
}
|
|
10957
11266
|
let agentConfig;
|
|
10958
|
-
const agentConfigPath =
|
|
10959
|
-
if (
|
|
11267
|
+
const agentConfigPath = path26.join(EXE_AI_DIR, "agent-config.json");
|
|
11268
|
+
if (existsSync24(agentConfigPath)) {
|
|
10960
11269
|
try {
|
|
10961
11270
|
agentConfig = JSON.parse(readFileSync18(agentConfigPath, "utf-8"));
|
|
10962
11271
|
} catch {
|
|
@@ -11034,16 +11343,16 @@ async function cloudPullRoster(config) {
|
|
|
11034
11343
|
}
|
|
11035
11344
|
}
|
|
11036
11345
|
function mergeConfig(remoteConfig, configPath) {
|
|
11037
|
-
const cfgPath = configPath ??
|
|
11346
|
+
const cfgPath = configPath ?? path26.join(EXE_AI_DIR, "config.json");
|
|
11038
11347
|
let local = {};
|
|
11039
|
-
if (
|
|
11348
|
+
if (existsSync24(cfgPath)) {
|
|
11040
11349
|
try {
|
|
11041
11350
|
local = JSON.parse(readFileSync18(cfgPath, "utf-8"));
|
|
11042
11351
|
} catch {
|
|
11043
11352
|
}
|
|
11044
11353
|
}
|
|
11045
11354
|
const merged = { ...remoteConfig, ...local };
|
|
11046
|
-
const dir =
|
|
11355
|
+
const dir = path26.dirname(cfgPath);
|
|
11047
11356
|
ensurePrivateDirSync(dir);
|
|
11048
11357
|
writeFileSync12(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
11049
11358
|
enforcePrivateFileSync(cfgPath);
|
|
@@ -11051,7 +11360,7 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
11051
11360
|
async function mergeRosterFromRemote(remote, paths) {
|
|
11052
11361
|
return withRosterLock(async () => {
|
|
11053
11362
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
11054
|
-
const identityDir = paths?.identityDir ??
|
|
11363
|
+
const identityDir = paths?.identityDir ?? path26.join(EXE_AI_DIR, "identity");
|
|
11055
11364
|
const localEmployees = await loadEmployees(rosterPath);
|
|
11056
11365
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
11057
11366
|
let added = 0;
|
|
@@ -11072,11 +11381,11 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
11072
11381
|
) ?? lookupKey;
|
|
11073
11382
|
const remoteIdentity = remote.identities[matchedKey];
|
|
11074
11383
|
if (remoteIdentity) {
|
|
11075
|
-
if (!
|
|
11076
|
-
const idPath =
|
|
11384
|
+
if (!existsSync24(identityDir)) mkdirSync10(identityDir, { recursive: true });
|
|
11385
|
+
const idPath = path26.join(identityDir, `${remoteEmp.name}.md`);
|
|
11077
11386
|
let localIdentity = null;
|
|
11078
11387
|
try {
|
|
11079
|
-
localIdentity =
|
|
11388
|
+
localIdentity = existsSync24(idPath) ? readFileSync18(idPath, "utf-8") : null;
|
|
11080
11389
|
} catch {
|
|
11081
11390
|
}
|
|
11082
11391
|
if (localIdentity !== remoteIdentity) {
|
|
@@ -11106,16 +11415,16 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
11106
11415
|
}
|
|
11107
11416
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
11108
11417
|
try {
|
|
11109
|
-
const agentConfigPath =
|
|
11418
|
+
const agentConfigPath = path26.join(EXE_AI_DIR, "agent-config.json");
|
|
11110
11419
|
let local = {};
|
|
11111
|
-
if (
|
|
11420
|
+
if (existsSync24(agentConfigPath)) {
|
|
11112
11421
|
try {
|
|
11113
11422
|
local = JSON.parse(readFileSync18(agentConfigPath, "utf-8"));
|
|
11114
11423
|
} catch {
|
|
11115
11424
|
}
|
|
11116
11425
|
}
|
|
11117
11426
|
const merged = { ...remote.agentConfig, ...local };
|
|
11118
|
-
ensurePrivateDirSync(
|
|
11427
|
+
ensurePrivateDirSync(path26.dirname(agentConfigPath));
|
|
11119
11428
|
writeFileSync12(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
11120
11429
|
enforcePrivateFileSync(agentConfigPath);
|
|
11121
11430
|
} catch {
|
|
@@ -11556,11 +11865,11 @@ var init_cloud_sync = __esm({
|
|
|
11556
11865
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
11557
11866
|
FETCH_TIMEOUT_MS = 3e4;
|
|
11558
11867
|
PUSH_BATCH_SIZE = 5e3;
|
|
11559
|
-
ROSTER_LOCK_PATH =
|
|
11868
|
+
ROSTER_LOCK_PATH = path26.join(EXE_AI_DIR, "roster-merge.lock");
|
|
11560
11869
|
LOCK_STALE_MS = 3e4;
|
|
11561
11870
|
_pgPromise = null;
|
|
11562
11871
|
_pgFailed = false;
|
|
11563
|
-
ROSTER_DELETIONS_PATH =
|
|
11872
|
+
ROSTER_DELETIONS_PATH = path26.join(EXE_AI_DIR, "roster-deletions.json");
|
|
11564
11873
|
}
|
|
11565
11874
|
});
|
|
11566
11875
|
|
|
@@ -12259,7 +12568,7 @@ __export(token_spend_exports, {
|
|
|
12259
12568
|
import { readdir } from "fs/promises";
|
|
12260
12569
|
import { createReadStream } from "fs";
|
|
12261
12570
|
import { createInterface } from "readline";
|
|
12262
|
-
import
|
|
12571
|
+
import path27 from "path";
|
|
12263
12572
|
import os14 from "os";
|
|
12264
12573
|
function getPricing(model) {
|
|
12265
12574
|
if (MODEL_PRICING[model]) return MODEL_PRICING[model];
|
|
@@ -12287,18 +12596,18 @@ async function getAgentSpend(period = "7d") {
|
|
|
12287
12596
|
for (const row of dbResult.rows) {
|
|
12288
12597
|
sessionAgent.set(row.session_uuid, row.agent_id);
|
|
12289
12598
|
}
|
|
12290
|
-
const claudeDir =
|
|
12599
|
+
const claudeDir = path27.join(os14.homedir(), ".claude", "projects");
|
|
12291
12600
|
let projectDirs = [];
|
|
12292
12601
|
try {
|
|
12293
12602
|
const entries = await readdir(claudeDir);
|
|
12294
|
-
projectDirs = entries.map((e) =>
|
|
12603
|
+
projectDirs = entries.map((e) => path27.join(claudeDir, e));
|
|
12295
12604
|
} catch {
|
|
12296
12605
|
return [];
|
|
12297
12606
|
}
|
|
12298
12607
|
const agentTotals = /* @__PURE__ */ new Map();
|
|
12299
12608
|
for (const [sessionUuid, agentId] of sessionAgent) {
|
|
12300
12609
|
for (const dir of projectDirs) {
|
|
12301
|
-
const jsonlPath =
|
|
12610
|
+
const jsonlPath = path27.join(dir, `${sessionUuid}.jsonl`);
|
|
12302
12611
|
try {
|
|
12303
12612
|
const usage = await extractSessionUsage(jsonlPath);
|
|
12304
12613
|
if (usage.input === 0 && usage.output === 0) continue;
|
|
@@ -12431,7 +12740,7 @@ __export(task_enforcement_exports, {
|
|
|
12431
12740
|
sendNudge: () => sendNudge
|
|
12432
12741
|
});
|
|
12433
12742
|
import { writeFileSync as writeFileSync13 } from "fs";
|
|
12434
|
-
import
|
|
12743
|
+
import path28 from "path";
|
|
12435
12744
|
function writeAuditEntry(entry) {
|
|
12436
12745
|
try {
|
|
12437
12746
|
const line = JSON.stringify(entry) + "\n";
|
|
@@ -12606,7 +12915,7 @@ var init_task_enforcement = __esm({
|
|
|
12606
12915
|
"What do you need?"
|
|
12607
12916
|
];
|
|
12608
12917
|
MANAGER_ROLES = ["COO", "CTO"];
|
|
12609
|
-
AUDIT_LOG_PATH =
|
|
12918
|
+
AUDIT_LOG_PATH = path28.join(
|
|
12610
12919
|
process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
|
|
12611
12920
|
".exe-os",
|
|
12612
12921
|
"enforcement-audit.jsonl"
|
|
@@ -12622,17 +12931,17 @@ __export(update_check_exports, {
|
|
|
12622
12931
|
getLocalVersion: () => getLocalVersion,
|
|
12623
12932
|
getRemoteVersion: () => getRemoteVersion
|
|
12624
12933
|
});
|
|
12625
|
-
import { execSync as
|
|
12934
|
+
import { execSync as execSync12 } from "child_process";
|
|
12626
12935
|
import { readFileSync as readFileSync19 } from "fs";
|
|
12627
|
-
import
|
|
12936
|
+
import path29 from "path";
|
|
12628
12937
|
function getLocalVersion(packageRoot) {
|
|
12629
|
-
const pkgPath =
|
|
12938
|
+
const pkgPath = path29.join(packageRoot, "package.json");
|
|
12630
12939
|
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
12631
12940
|
return pkg.version;
|
|
12632
12941
|
}
|
|
12633
12942
|
function getRemoteVersion() {
|
|
12634
12943
|
try {
|
|
12635
|
-
const output =
|
|
12944
|
+
const output = execSync12("npm view @askexenow/exe-os version", {
|
|
12636
12945
|
encoding: "utf-8",
|
|
12637
12946
|
timeout: 15e3,
|
|
12638
12947
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12699,10 +13008,10 @@ __export(device_registry_exports, {
|
|
|
12699
13008
|
});
|
|
12700
13009
|
import crypto12 from "crypto";
|
|
12701
13010
|
import os15 from "os";
|
|
12702
|
-
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, mkdirSync as
|
|
12703
|
-
import
|
|
13011
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync14, mkdirSync as mkdirSync11, existsSync as existsSync25 } from "fs";
|
|
13012
|
+
import path30 from "path";
|
|
12704
13013
|
function getDeviceInfo() {
|
|
12705
|
-
if (
|
|
13014
|
+
if (existsSync25(DEVICE_JSON_PATH)) {
|
|
12706
13015
|
try {
|
|
12707
13016
|
const raw = readFileSync20(DEVICE_JSON_PATH, "utf8");
|
|
12708
13017
|
const data = JSON.parse(raw);
|
|
@@ -12718,7 +13027,7 @@ function getDeviceInfo() {
|
|
|
12718
13027
|
friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
|
|
12719
13028
|
hostname
|
|
12720
13029
|
};
|
|
12721
|
-
|
|
13030
|
+
mkdirSync11(path30.dirname(DEVICE_JSON_PATH), { recursive: true });
|
|
12722
13031
|
writeFileSync14(DEVICE_JSON_PATH, JSON.stringify(info, null, 2));
|
|
12723
13032
|
return info;
|
|
12724
13033
|
}
|
|
@@ -12759,7 +13068,7 @@ var init_device_registry = __esm({
|
|
|
12759
13068
|
"src/lib/device-registry.ts"() {
|
|
12760
13069
|
"use strict";
|
|
12761
13070
|
init_config();
|
|
12762
|
-
DEVICE_JSON_PATH =
|
|
13071
|
+
DEVICE_JSON_PATH = path30.join(EXE_AI_DIR, "device.json");
|
|
12763
13072
|
}
|
|
12764
13073
|
});
|
|
12765
13074
|
|
|
@@ -13246,8 +13555,8 @@ init_daemon_protocol();
|
|
|
13246
13555
|
init_daemon_auth();
|
|
13247
13556
|
import os16 from "os";
|
|
13248
13557
|
import net2 from "net";
|
|
13249
|
-
import { writeFileSync as writeFileSync15, unlinkSync as
|
|
13250
|
-
import
|
|
13558
|
+
import { writeFileSync as writeFileSync15, unlinkSync as unlinkSync11, mkdirSync as mkdirSync12, existsSync as existsSync26, readFileSync as readFileSync21, chmodSync as chmodSync2 } from "fs";
|
|
13559
|
+
import path31 from "path";
|
|
13251
13560
|
import { getLlama } from "node-llama-cpp";
|
|
13252
13561
|
|
|
13253
13562
|
// src/lib/orchestration-metrics.ts
|
|
@@ -13319,8 +13628,8 @@ function initMetrics() {
|
|
|
13319
13628
|
}
|
|
13320
13629
|
|
|
13321
13630
|
// src/lib/exe-daemon.ts
|
|
13322
|
-
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
13323
|
-
var PID_PATH2 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
13631
|
+
var SOCKET_PATH2 = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path31.join(EXE_AI_DIR, "exed.sock");
|
|
13632
|
+
var PID_PATH2 = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path31.join(EXE_AI_DIR, "exed.pid");
|
|
13324
13633
|
var MODEL_FILE = "jina-embeddings-v5-small-q4_k_m.gguf";
|
|
13325
13634
|
var IDLE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
13326
13635
|
var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
@@ -13348,8 +13657,8 @@ function enqueue(queue, entry) {
|
|
|
13348
13657
|
queue.push(entry);
|
|
13349
13658
|
}
|
|
13350
13659
|
async function loadModel() {
|
|
13351
|
-
const modelPath =
|
|
13352
|
-
if (!
|
|
13660
|
+
const modelPath = path31.join(MODELS_DIR, MODEL_FILE);
|
|
13661
|
+
if (!existsSync26(modelPath)) {
|
|
13353
13662
|
process.stderr.write(`[exed] FATAL: model not found at ${modelPath}
|
|
13354
13663
|
`);
|
|
13355
13664
|
process.exit(1);
|
|
@@ -13446,11 +13755,11 @@ async function shutdown() {
|
|
|
13446
13755
|
}
|
|
13447
13756
|
_llama = null;
|
|
13448
13757
|
try {
|
|
13449
|
-
|
|
13758
|
+
unlinkSync11(SOCKET_PATH2);
|
|
13450
13759
|
} catch {
|
|
13451
13760
|
}
|
|
13452
13761
|
try {
|
|
13453
|
-
|
|
13762
|
+
unlinkSync11(PID_PATH2);
|
|
13454
13763
|
} catch {
|
|
13455
13764
|
}
|
|
13456
13765
|
process.stderr.write("[exed] Shutdown complete.\n");
|
|
@@ -13704,14 +14013,14 @@ function startMemoryQueueDrain() {
|
|
|
13704
14013
|
`);
|
|
13705
14014
|
}
|
|
13706
14015
|
function startServer() {
|
|
13707
|
-
|
|
14016
|
+
mkdirSync12(path31.dirname(SOCKET_PATH2), { recursive: true });
|
|
13708
14017
|
try {
|
|
13709
|
-
chmodSync2(
|
|
14018
|
+
chmodSync2(path31.dirname(SOCKET_PATH2), 448);
|
|
13710
14019
|
} catch {
|
|
13711
14020
|
}
|
|
13712
14021
|
_daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV2] ?? null);
|
|
13713
14022
|
for (const oldFile of ["embed.sock", "embed.pid"]) {
|
|
13714
|
-
const oldPath =
|
|
14023
|
+
const oldPath = path31.join(path31.dirname(SOCKET_PATH2), oldFile);
|
|
13715
14024
|
try {
|
|
13716
14025
|
if (oldFile.endsWith(".pid")) {
|
|
13717
14026
|
const pid = parseInt(readFileSync21(oldPath, "utf8").trim(), 10);
|
|
@@ -13720,12 +14029,12 @@ function startServer() {
|
|
|
13720
14029
|
} catch {
|
|
13721
14030
|
}
|
|
13722
14031
|
}
|
|
13723
|
-
|
|
14032
|
+
unlinkSync11(oldPath);
|
|
13724
14033
|
} catch {
|
|
13725
14034
|
}
|
|
13726
14035
|
}
|
|
13727
14036
|
try {
|
|
13728
|
-
|
|
14037
|
+
unlinkSync11(SOCKET_PATH2);
|
|
13729
14038
|
} catch {
|
|
13730
14039
|
}
|
|
13731
14040
|
const server = net2.createServer((socket) => {
|
|
@@ -13972,6 +14281,11 @@ function startConsolidation() {
|
|
|
13972
14281
|
embedFn = embed2;
|
|
13973
14282
|
} catch {
|
|
13974
14283
|
}
|
|
14284
|
+
try {
|
|
14285
|
+
const { createBackup: createBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
|
|
14286
|
+
createBackup2("pre-consolidation");
|
|
14287
|
+
} catch {
|
|
14288
|
+
}
|
|
13975
14289
|
process.stderr.write(`[exed] Starting consolidation (${count} unconsolidated memories)...
|
|
13976
14290
|
`);
|
|
13977
14291
|
const result = await runConsolidation2(client, {
|
|
@@ -14094,7 +14408,7 @@ function startGraphExtraction() {
|
|
|
14094
14408
|
`);
|
|
14095
14409
|
}
|
|
14096
14410
|
var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
|
|
14097
|
-
var AGENT_STATS_PATH =
|
|
14411
|
+
var AGENT_STATS_PATH = path31.join(EXE_AI_DIR, "agent-stats.json");
|
|
14098
14412
|
async function writeAgentStats() {
|
|
14099
14413
|
fired("agent_stats");
|
|
14100
14414
|
if (!await ensureStoreForPolling()) return;
|
|
@@ -14199,6 +14513,33 @@ function startConfidenceDecay() {
|
|
|
14199
14513
|
process.stderr.write(`[exed] Confidence decay started (every 24h)
|
|
14200
14514
|
`);
|
|
14201
14515
|
}
|
|
14516
|
+
var DB_BACKUP_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
14517
|
+
function startDatabaseBackup() {
|
|
14518
|
+
const tick = () => {
|
|
14519
|
+
fired("db_backup");
|
|
14520
|
+
try {
|
|
14521
|
+
const { createBackup: createBackup2, rotateBackups: rotateBackups2, hasBackupToday: hasBackupToday2 } = (init_db_backup(), __toCommonJS(db_backup_exports));
|
|
14522
|
+
if (hasBackupToday2("daily")) return;
|
|
14523
|
+
const backupPath = createBackup2("daily");
|
|
14524
|
+
if (backupPath) {
|
|
14525
|
+
acted("db_backup");
|
|
14526
|
+
const deleted = rotateBackups2();
|
|
14527
|
+
process.stderr.write(
|
|
14528
|
+
`[exed] DB backup: ${backupPath.split("/").pop()}${deleted > 0 ? ` (rotated ${deleted} old)` : ""}
|
|
14529
|
+
`
|
|
14530
|
+
);
|
|
14531
|
+
}
|
|
14532
|
+
} catch (err) {
|
|
14533
|
+
process.stderr.write(`[exed] DB backup error: ${err instanceof Error ? err.message : String(err)}
|
|
14534
|
+
`);
|
|
14535
|
+
}
|
|
14536
|
+
};
|
|
14537
|
+
tick();
|
|
14538
|
+
const timer = setInterval(tick, DB_BACKUP_INTERVAL_MS);
|
|
14539
|
+
timer.unref();
|
|
14540
|
+
process.stderr.write(`[exed] Database backup started (daily, keep 3 days)
|
|
14541
|
+
`);
|
|
14542
|
+
}
|
|
14202
14543
|
var QUEUE_DRAIN_INTERVAL_MS = 15e3;
|
|
14203
14544
|
function startIntercomQueueDrain() {
|
|
14204
14545
|
const tick = () => {
|
|
@@ -14209,12 +14550,12 @@ function startIntercomQueueDrain() {
|
|
|
14209
14550
|
const hasInProgressTask = (session) => {
|
|
14210
14551
|
try {
|
|
14211
14552
|
const { baseAgentName: ban } = (init_employees(), __toCommonJS(employees_exports));
|
|
14212
|
-
const
|
|
14213
|
-
const { existsSync:
|
|
14553
|
+
const path32 = __require("path");
|
|
14554
|
+
const { existsSync: existsSync27 } = __require("fs");
|
|
14214
14555
|
const os17 = __require("os");
|
|
14215
14556
|
const agent = ban(session.split("-")[0] ?? session);
|
|
14216
|
-
const markerPath =
|
|
14217
|
-
return
|
|
14557
|
+
const markerPath = path32.join(os17.homedir(), ".exe-os", "session-cache", `current-task-${agent}.json`);
|
|
14558
|
+
return existsSync27(markerPath);
|
|
14218
14559
|
} catch {
|
|
14219
14560
|
return false;
|
|
14220
14561
|
}
|
|
@@ -14378,7 +14719,7 @@ process.on("SIGINT", () => void shutdown());
|
|
|
14378
14719
|
process.on("SIGTERM", () => void shutdown());
|
|
14379
14720
|
function checkExistingDaemon() {
|
|
14380
14721
|
try {
|
|
14381
|
-
if (!
|
|
14722
|
+
if (!existsSync26(PID_PATH2)) return false;
|
|
14382
14723
|
const pid = parseInt(readFileSync21(PID_PATH2, "utf8").trim(), 10);
|
|
14383
14724
|
if (!pid || isNaN(pid)) return false;
|
|
14384
14725
|
process.kill(pid, 0);
|
|
@@ -14392,7 +14733,7 @@ function checkExistingDaemon() {
|
|
|
14392
14733
|
return true;
|
|
14393
14734
|
}
|
|
14394
14735
|
try {
|
|
14395
|
-
|
|
14736
|
+
unlinkSync11(PID_PATH2);
|
|
14396
14737
|
} catch {
|
|
14397
14738
|
}
|
|
14398
14739
|
return false;
|
|
@@ -14417,8 +14758,8 @@ function startAutoUpdateCheck() {
|
|
|
14417
14758
|
);
|
|
14418
14759
|
if (autoInstall) {
|
|
14419
14760
|
process.stderr.write("[exed] Auto-installing update...\n");
|
|
14420
|
-
const { execSync:
|
|
14421
|
-
|
|
14761
|
+
const { execSync: execSync13 } = await import("child_process");
|
|
14762
|
+
execSync13("npm install -g @askexenow/exe-os@latest", {
|
|
14422
14763
|
timeout: 12e4,
|
|
14423
14764
|
stdio: ["pipe", "pipe", "pipe"]
|
|
14424
14765
|
});
|
|
@@ -14472,6 +14813,7 @@ try {
|
|
|
14472
14813
|
startMemoryQueueDrain();
|
|
14473
14814
|
startIntercomQueueDrain();
|
|
14474
14815
|
startConfidenceDecay();
|
|
14816
|
+
startDatabaseBackup();
|
|
14475
14817
|
startAutoUpdateCheck();
|
|
14476
14818
|
startRssWatchdog();
|
|
14477
14819
|
startTaskEnforcementScanner();
|
|
@@ -14570,11 +14912,11 @@ try {
|
|
|
14570
14912
|
process.stderr.write(`[exed] FATAL: ${err instanceof Error ? err.message : String(err)}
|
|
14571
14913
|
`);
|
|
14572
14914
|
try {
|
|
14573
|
-
|
|
14915
|
+
unlinkSync11(SOCKET_PATH2);
|
|
14574
14916
|
} catch {
|
|
14575
14917
|
}
|
|
14576
14918
|
try {
|
|
14577
|
-
|
|
14919
|
+
unlinkSync11(PID_PATH2);
|
|
14578
14920
|
} catch {
|
|
14579
14921
|
}
|
|
14580
14922
|
process.exit(1);
|