@askexenow/exe-os 0.8.38 → 0.8.39
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/README.md +17 -8
- package/dist/bin/backfill-conversations.js +46 -10
- package/dist/bin/backfill-responses.js +46 -10
- package/dist/bin/backfill-vectors.js +42 -8
- package/dist/bin/cleanup-stale-review-tasks.js +37 -8
- package/dist/bin/cli.js +281 -154
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +39 -5
- package/dist/bin/exe-boot.js +237 -111
- package/dist/bin/exe-call.js +11 -6
- package/dist/bin/exe-cloud.js +99 -28
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +37 -8
- package/dist/bin/exe-export-behaviors.js +39 -10
- package/dist/bin/exe-forget.js +38 -9
- package/dist/bin/exe-gateway.js +109 -42
- package/dist/bin/exe-heartbeat.js +49 -20
- package/dist/bin/exe-kill.js +39 -10
- package/dist/bin/exe-launch-agent.js +58 -22
- package/dist/bin/exe-link.js +184 -85
- package/dist/bin/exe-new-employee.js +21 -7
- package/dist/bin/exe-pending-messages.js +46 -17
- package/dist/bin/exe-pending-notifications.js +37 -8
- package/dist/bin/exe-pending-reviews.js +47 -18
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +34 -5
- package/dist/bin/exe-search.js +47 -10
- package/dist/bin/exe-session-cleanup.js +56 -19
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +34 -5
- package/dist/bin/exe-team.js +34 -5
- package/dist/bin/git-sweep.js +38 -9
- package/dist/bin/graph-backfill.js +37 -8
- package/dist/bin/graph-export.js +37 -8
- package/dist/bin/install.js +1 -1
- package/dist/bin/scan-tasks.js +40 -11
- package/dist/bin/setup.js +58 -24
- package/dist/bin/shard-migrate.js +37 -8
- package/dist/bin/wiki-sync.js +39 -9
- package/dist/gateway/index.js +102 -37
- package/dist/hooks/bug-report-worker.js +62 -28
- package/dist/hooks/commit-complete.js +38 -9
- package/dist/hooks/error-recall.js +49 -8
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +151 -37
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +39 -9
- package/dist/hooks/notification.js +37 -7
- package/dist/hooks/post-compact.js +37 -7
- package/dist/hooks/pre-compact.js +35 -6
- package/dist/hooks/pre-tool-use.js +52 -14
- package/dist/hooks/prompt-ingest-worker.js +56 -10
- package/dist/hooks/prompt-submit.js +61 -23
- package/dist/hooks/response-ingest-worker.js +57 -11
- package/dist/hooks/session-end.js +43 -10
- package/dist/hooks/session-start.js +46 -8
- package/dist/hooks/stop.js +37 -7
- package/dist/hooks/subagent-stop.js +37 -7
- package/dist/hooks/summary-worker.js +317 -99
- package/dist/index.js +87 -22
- package/dist/lib/cloud-sync.js +172 -78
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +71 -28
- package/dist/lib/hybrid-search.js +47 -10
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +13 -4
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +37 -8
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +37 -8
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +97 -43
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +1 -1
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +35 -6
- package/dist/tui/App.js +177 -95
- package/package.json +3 -3
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -62,7 +62,8 @@ async function gqlRequest(query, variables) {
|
|
|
62
62
|
"Content-Type": "application/json",
|
|
63
63
|
Authorization: `Bearer ${config.apiToken}`
|
|
64
64
|
},
|
|
65
|
-
body: JSON.stringify({ query, variables })
|
|
65
|
+
body: JSON.stringify({ query, variables }),
|
|
66
|
+
signal: AbortSignal.timeout(3e4)
|
|
66
67
|
});
|
|
67
68
|
if (!res.ok) {
|
|
68
69
|
throw new Error(`CRM GraphQL request failed: ${res.status} ${res.statusText}`);
|
|
@@ -369,6 +370,7 @@ async function ensureSchema() {
|
|
|
369
370
|
const client = getRawClient();
|
|
370
371
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
371
372
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
373
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
372
374
|
try {
|
|
373
375
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
374
376
|
} catch {
|
|
@@ -1201,7 +1203,7 @@ __export(config_exports, {
|
|
|
1201
1203
|
migrateConfig: () => migrateConfig,
|
|
1202
1204
|
saveConfig: () => saveConfig
|
|
1203
1205
|
});
|
|
1204
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
1206
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
1205
1207
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
1206
1208
|
import path from "path";
|
|
1207
1209
|
import os from "os";
|
|
@@ -1327,6 +1329,9 @@ async function saveConfig(config2) {
|
|
|
1327
1329
|
await mkdir(dir, { recursive: true });
|
|
1328
1330
|
const configPath = path.join(dir, "config.json");
|
|
1329
1331
|
await writeFile(configPath, JSON.stringify(config2, null, 2) + "\n");
|
|
1332
|
+
if (config2.cloud?.apiKey) {
|
|
1333
|
+
await chmod(configPath, 384);
|
|
1334
|
+
}
|
|
1330
1335
|
}
|
|
1331
1336
|
async function loadConfigFrom(configPath) {
|
|
1332
1337
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -1437,6 +1442,10 @@ import path2 from "path";
|
|
|
1437
1442
|
import { fileURLToPath } from "url";
|
|
1438
1443
|
function handleData(chunk) {
|
|
1439
1444
|
_buffer += chunk.toString();
|
|
1445
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1446
|
+
_buffer = "";
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1440
1449
|
let newlineIdx;
|
|
1441
1450
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1442
1451
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1744,7 +1753,7 @@ function disconnectClient() {
|
|
|
1744
1753
|
entry.resolve({ error: "Client disconnected" });
|
|
1745
1754
|
}
|
|
1746
1755
|
}
|
|
1747
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending;
|
|
1756
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
|
|
1748
1757
|
var init_exe_daemon_client = __esm({
|
|
1749
1758
|
"src/lib/exe-daemon-client.ts"() {
|
|
1750
1759
|
"use strict";
|
|
@@ -1761,6 +1770,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1761
1770
|
_requestCount = 0;
|
|
1762
1771
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1763
1772
|
_pending = /* @__PURE__ */ new Map();
|
|
1773
|
+
MAX_BUFFER = 1e7;
|
|
1764
1774
|
}
|
|
1765
1775
|
});
|
|
1766
1776
|
|
|
@@ -1833,12 +1843,13 @@ var init_embedder = __esm({
|
|
|
1833
1843
|
});
|
|
1834
1844
|
|
|
1835
1845
|
// src/lib/keychain.ts
|
|
1836
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1846
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1837
1847
|
import { existsSync as existsSync3 } from "fs";
|
|
1838
1848
|
import path3 from "path";
|
|
1849
|
+
import os2 from "os";
|
|
1839
1850
|
import crypto from "crypto";
|
|
1840
1851
|
function getKeyDir() {
|
|
1841
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1852
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1842
1853
|
}
|
|
1843
1854
|
function getKeyPath() {
|
|
1844
1855
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -2139,6 +2150,28 @@ __export(store_exports, {
|
|
|
2139
2150
|
vectorToBlob: () => vectorToBlob,
|
|
2140
2151
|
writeMemory: () => writeMemory
|
|
2141
2152
|
});
|
|
2153
|
+
function isBusyError2(err) {
|
|
2154
|
+
if (err instanceof Error) {
|
|
2155
|
+
const msg = err.message.toLowerCase();
|
|
2156
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2157
|
+
}
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
async function retryOnBusy2(fn, label) {
|
|
2161
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2162
|
+
try {
|
|
2163
|
+
return await fn();
|
|
2164
|
+
} catch (err) {
|
|
2165
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2166
|
+
process.stderr.write(
|
|
2167
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2168
|
+
`
|
|
2169
|
+
);
|
|
2170
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
throw new Error("unreachable");
|
|
2174
|
+
}
|
|
2142
2175
|
async function initStore(options) {
|
|
2143
2176
|
if (_flushTimer !== null) {
|
|
2144
2177
|
clearInterval(_flushTimer);
|
|
@@ -2167,14 +2200,17 @@ async function initStore(options) {
|
|
|
2167
2200
|
dbPath,
|
|
2168
2201
|
encryptionKey: hexKey
|
|
2169
2202
|
});
|
|
2170
|
-
await ensureSchema();
|
|
2203
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2171
2204
|
try {
|
|
2172
2205
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2173
2206
|
initShardManager2(hexKey);
|
|
2174
2207
|
} catch {
|
|
2175
2208
|
}
|
|
2176
2209
|
const client = getClient();
|
|
2177
|
-
const vResult = await
|
|
2210
|
+
const vResult = await retryOnBusy2(
|
|
2211
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2212
|
+
"version-query"
|
|
2213
|
+
);
|
|
2178
2214
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2179
2215
|
}
|
|
2180
2216
|
function classifyTier(record) {
|
|
@@ -2554,7 +2590,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
2554
2590
|
return 0;
|
|
2555
2591
|
}
|
|
2556
2592
|
}
|
|
2557
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2593
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2558
2594
|
var init_store = __esm({
|
|
2559
2595
|
"src/lib/store.ts"() {
|
|
2560
2596
|
"use strict";
|
|
@@ -2562,6 +2598,8 @@ var init_store = __esm({
|
|
|
2562
2598
|
init_database();
|
|
2563
2599
|
init_keychain();
|
|
2564
2600
|
init_config();
|
|
2601
|
+
INIT_MAX_RETRIES = 3;
|
|
2602
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
2565
2603
|
_pendingRecords = [];
|
|
2566
2604
|
_batchSize = 20;
|
|
2567
2605
|
_flushIntervalMs = 1e4;
|
|
@@ -2589,12 +2627,30 @@ async function wikiFetch(config2, path20, method = "GET", body) {
|
|
|
2589
2627
|
const controller = new AbortController();
|
|
2590
2628
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
2591
2629
|
try {
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2630
|
+
let response;
|
|
2631
|
+
try {
|
|
2632
|
+
response = await fetch(url, {
|
|
2633
|
+
method,
|
|
2634
|
+
headers,
|
|
2635
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2636
|
+
signal: controller.signal
|
|
2637
|
+
});
|
|
2638
|
+
} catch {
|
|
2639
|
+
clearTimeout(timeout);
|
|
2640
|
+
const retryController = new AbortController();
|
|
2641
|
+
const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
|
|
2642
|
+
try {
|
|
2643
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2644
|
+
response = await fetch(url, {
|
|
2645
|
+
method,
|
|
2646
|
+
headers,
|
|
2647
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2648
|
+
signal: retryController.signal
|
|
2649
|
+
});
|
|
2650
|
+
} finally {
|
|
2651
|
+
clearTimeout(retryTimeout);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2598
2654
|
if (!response.ok) {
|
|
2599
2655
|
throw new Error(`Wiki API ${method} ${path20}: ${response.status} ${response.statusText}`);
|
|
2600
2656
|
}
|
|
@@ -2716,6 +2772,14 @@ import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5
|
|
|
2716
2772
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2717
2773
|
import path5 from "path";
|
|
2718
2774
|
import { jwtVerify, importSPKI } from "jose";
|
|
2775
|
+
async function fetchRetry(url, init) {
|
|
2776
|
+
try {
|
|
2777
|
+
return await fetch(url, init);
|
|
2778
|
+
} catch {
|
|
2779
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
2780
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2719
2783
|
function loadDeviceId() {
|
|
2720
2784
|
const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
|
|
2721
2785
|
try {
|
|
@@ -2747,7 +2811,7 @@ function loadLicense() {
|
|
|
2747
2811
|
}
|
|
2748
2812
|
function saveLicense(apiKey) {
|
|
2749
2813
|
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
2750
|
-
writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
|
|
2814
|
+
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
2751
2815
|
}
|
|
2752
2816
|
async function verifyLicenseJwt(token) {
|
|
2753
2817
|
try {
|
|
@@ -2799,7 +2863,7 @@ function cacheResponse(token) {
|
|
|
2799
2863
|
async function validateLicense(apiKey, deviceId) {
|
|
2800
2864
|
const did = deviceId ?? loadDeviceId();
|
|
2801
2865
|
try {
|
|
2802
|
-
const res = await
|
|
2866
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2803
2867
|
method: "POST",
|
|
2804
2868
|
headers: { "Content-Type": "application/json" },
|
|
2805
2869
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -2890,7 +2954,7 @@ async function assertVpsLicense(opts) {
|
|
|
2890
2954
|
let explicitRejection = false;
|
|
2891
2955
|
let transientFailure = false;
|
|
2892
2956
|
try {
|
|
2893
|
-
const res = await
|
|
2957
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2894
2958
|
method: "POST",
|
|
2895
2959
|
headers: { "Content-Type": "application/json" },
|
|
2896
2960
|
body: JSON.stringify({ apiKey, deviceId }),
|
|
@@ -2992,7 +3056,7 @@ function stopLicenseRevalidation() {
|
|
|
2992
3056
|
_revalTimer = null;
|
|
2993
3057
|
}
|
|
2994
3058
|
}
|
|
2995
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
|
|
3059
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
|
|
2996
3060
|
var init_license = __esm({
|
|
2997
3061
|
"src/lib/license.ts"() {
|
|
2998
3062
|
"use strict";
|
|
@@ -3001,6 +3065,7 @@ var init_license = __esm({
|
|
|
3001
3065
|
CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
|
|
3002
3066
|
DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
|
|
3003
3067
|
API_BASE = "https://askexe.com/cloud";
|
|
3068
|
+
RETRY_DELAY_MS = 500;
|
|
3004
3069
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
3005
3070
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
3006
3071
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -3852,7 +3917,7 @@ __export(imessage_exports, {
|
|
|
3852
3917
|
});
|
|
3853
3918
|
import { execFile } from "child_process";
|
|
3854
3919
|
import { promisify } from "util";
|
|
3855
|
-
import
|
|
3920
|
+
import os3 from "os";
|
|
3856
3921
|
import path6 from "path";
|
|
3857
3922
|
var execFileAsync, POLL_INTERVAL_MS, MESSAGES_DB_PATH, IMessageAdapter;
|
|
3858
3923
|
var init_imessage = __esm({
|
|
@@ -3861,7 +3926,7 @@ var init_imessage = __esm({
|
|
|
3861
3926
|
execFileAsync = promisify(execFile);
|
|
3862
3927
|
POLL_INTERVAL_MS = 5e3;
|
|
3863
3928
|
MESSAGES_DB_PATH = path6.join(
|
|
3864
|
-
process.env.HOME ??
|
|
3929
|
+
process.env.HOME ?? os3.homedir(),
|
|
3865
3930
|
"Library/Messages/chat.db"
|
|
3866
3931
|
);
|
|
3867
3932
|
IMessageAdapter = class {
|
|
@@ -4327,7 +4392,7 @@ var init_whatsapp_accounts = __esm({
|
|
|
4327
4392
|
// src/lib/session-registry.ts
|
|
4328
4393
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
|
|
4329
4394
|
import path7 from "path";
|
|
4330
|
-
import
|
|
4395
|
+
import os4 from "os";
|
|
4331
4396
|
function registerSession(entry) {
|
|
4332
4397
|
const dir = path7.dirname(REGISTRY_PATH);
|
|
4333
4398
|
if (!existsSync6(dir)) {
|
|
@@ -4354,7 +4419,7 @@ var REGISTRY_PATH;
|
|
|
4354
4419
|
var init_session_registry = __esm({
|
|
4355
4420
|
"src/lib/session-registry.ts"() {
|
|
4356
4421
|
"use strict";
|
|
4357
|
-
REGISTRY_PATH = path7.join(
|
|
4422
|
+
REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
4358
4423
|
}
|
|
4359
4424
|
});
|
|
4360
4425
|
|
|
@@ -4576,7 +4641,7 @@ var init_provider_table = __esm({
|
|
|
4576
4641
|
// src/lib/intercom-queue.ts
|
|
4577
4642
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
4578
4643
|
import path8 from "path";
|
|
4579
|
-
import
|
|
4644
|
+
import os5 from "os";
|
|
4580
4645
|
function ensureDir() {
|
|
4581
4646
|
const dir = path8.dirname(QUEUE_PATH);
|
|
4582
4647
|
if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
|
|
@@ -4616,9 +4681,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
4616
4681
|
var init_intercom_queue = __esm({
|
|
4617
4682
|
"src/lib/intercom-queue.ts"() {
|
|
4618
4683
|
"use strict";
|
|
4619
|
-
QUEUE_PATH = path8.join(
|
|
4684
|
+
QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
4620
4685
|
TTL_MS = 60 * 60 * 1e3;
|
|
4621
|
-
INTERCOM_LOG = path8.join(
|
|
4686
|
+
INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
4622
4687
|
}
|
|
4623
4688
|
});
|
|
4624
4689
|
|
|
@@ -4736,7 +4801,7 @@ var init_plan_limits = __esm({
|
|
|
4736
4801
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
4737
4802
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, existsSync as existsSync10, appendFileSync } from "fs";
|
|
4738
4803
|
import path11 from "path";
|
|
4739
|
-
import
|
|
4804
|
+
import os6 from "os";
|
|
4740
4805
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4741
4806
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
4742
4807
|
function spawnLockPath(sessionName) {
|
|
@@ -5041,7 +5106,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5041
5106
|
const transport = getTransport();
|
|
5042
5107
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
5043
5108
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
5044
|
-
const logDir = path11.join(
|
|
5109
|
+
const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
|
|
5045
5110
|
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
5046
5111
|
if (!existsSync10(logDir)) {
|
|
5047
5112
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -5057,7 +5122,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5057
5122
|
} catch {
|
|
5058
5123
|
}
|
|
5059
5124
|
try {
|
|
5060
|
-
const claudeJsonPath = path11.join(
|
|
5125
|
+
const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
|
|
5061
5126
|
let claudeJson = {};
|
|
5062
5127
|
try {
|
|
5063
5128
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -5072,7 +5137,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5072
5137
|
} catch {
|
|
5073
5138
|
}
|
|
5074
5139
|
try {
|
|
5075
|
-
const settingsDir = path11.join(
|
|
5140
|
+
const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
|
|
5076
5141
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
5077
5142
|
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
5078
5143
|
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
@@ -5120,7 +5185,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5120
5185
|
let legacyFallbackWarned = false;
|
|
5121
5186
|
if (!useExeAgent && !useBinSymlink) {
|
|
5122
5187
|
const identityPath = path11.join(
|
|
5123
|
-
|
|
5188
|
+
os6.homedir(),
|
|
5124
5189
|
".exe-os",
|
|
5125
5190
|
"identity",
|
|
5126
5191
|
`${employeeName}.md`
|
|
@@ -5150,7 +5215,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5150
5215
|
}
|
|
5151
5216
|
let sessionContextFlag = "";
|
|
5152
5217
|
try {
|
|
5153
|
-
const ctxDir = path11.join(
|
|
5218
|
+
const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5154
5219
|
mkdirSync6(ctxDir, { recursive: true });
|
|
5155
5220
|
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
5156
5221
|
const ctxContent = [
|
|
@@ -5261,11 +5326,11 @@ var init_tmux_routing = __esm({
|
|
|
5261
5326
|
init_provider_table();
|
|
5262
5327
|
init_intercom_queue();
|
|
5263
5328
|
init_plan_limits();
|
|
5264
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
5265
|
-
SESSION_CACHE = path11.join(
|
|
5329
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
5330
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5266
5331
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5267
5332
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5268
|
-
INTERCOM_LOG2 = path11.join(
|
|
5333
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
5269
5334
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
5270
5335
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
5271
5336
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -5525,7 +5590,7 @@ var init_messaging = __esm({
|
|
|
5525
5590
|
// src/lib/notifications.ts
|
|
5526
5591
|
import crypto4 from "crypto";
|
|
5527
5592
|
import path12 from "path";
|
|
5528
|
-
import
|
|
5593
|
+
import os7 from "os";
|
|
5529
5594
|
import {
|
|
5530
5595
|
readFileSync as readFileSync10,
|
|
5531
5596
|
readdirSync as readdirSync2,
|
|
@@ -6842,7 +6907,7 @@ var init_tasks = __esm({
|
|
|
6842
6907
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
|
|
6843
6908
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
6844
6909
|
import path18 from "path";
|
|
6845
|
-
import
|
|
6910
|
+
import os8 from "os";
|
|
6846
6911
|
function substituteTemplate(template, record) {
|
|
6847
6912
|
return template.replace(
|
|
6848
6913
|
/\{\{(\w+(?:\.\w+)*)\}\}/g,
|
|
@@ -6920,7 +6985,7 @@ async function executeSendWhatsapp(params) {
|
|
|
6920
6985
|
const message = params.message ?? params.text;
|
|
6921
6986
|
if (!to || !message)
|
|
6922
6987
|
throw new Error("send_whatsapp requires 'to' and 'message' params");
|
|
6923
|
-
const url = `https://graph.facebook.com
|
|
6988
|
+
const url = `https://graph.facebook.com/${GRAPH_API_VERSION}/${account.phoneNumberId}/messages`;
|
|
6924
6989
|
const res = await fetch(url, {
|
|
6925
6990
|
method: "POST",
|
|
6926
6991
|
headers: {
|
|
@@ -6932,7 +6997,8 @@ async function executeSendWhatsapp(params) {
|
|
|
6932
6997
|
to,
|
|
6933
6998
|
type: "text",
|
|
6934
6999
|
text: { body: message }
|
|
6935
|
-
})
|
|
7000
|
+
}),
|
|
7001
|
+
signal: AbortSignal.timeout(3e4)
|
|
6936
7002
|
});
|
|
6937
7003
|
if (!res.ok) {
|
|
6938
7004
|
const errBody = await res.text();
|
|
@@ -7127,11 +7193,12 @@ async function processCRMEvent(event, executor, triggersOverride) {
|
|
|
7127
7193
|
}
|
|
7128
7194
|
return logs;
|
|
7129
7195
|
}
|
|
7130
|
-
var TRIGGERS_PATH;
|
|
7196
|
+
var TRIGGERS_PATH, GRAPH_API_VERSION;
|
|
7131
7197
|
var init_trigger_engine = __esm({
|
|
7132
7198
|
"src/automation/trigger-engine.ts"() {
|
|
7133
7199
|
"use strict";
|
|
7134
|
-
TRIGGERS_PATH = path18.join(
|
|
7200
|
+
TRIGGERS_PATH = path18.join(os8.homedir(), ".exe-os", "triggers.json");
|
|
7201
|
+
GRAPH_API_VERSION = "v21.0";
|
|
7135
7202
|
}
|
|
7136
7203
|
});
|
|
7137
7204
|
|
|
@@ -7195,7 +7262,7 @@ var init_crm_webhook = __esm({
|
|
|
7195
7262
|
// src/bin/exe-gateway.ts
|
|
7196
7263
|
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
7197
7264
|
import path19 from "path";
|
|
7198
|
-
import
|
|
7265
|
+
import os9 from "os";
|
|
7199
7266
|
|
|
7200
7267
|
// src/gateway/webhook-server.ts
|
|
7201
7268
|
import {
|
|
@@ -8019,7 +8086,7 @@ var BotRegistry = class {
|
|
|
8019
8086
|
};
|
|
8020
8087
|
|
|
8021
8088
|
// src/bin/exe-gateway.ts
|
|
8022
|
-
var CONFIG_DIR = path19.join(
|
|
8089
|
+
var CONFIG_DIR = path19.join(os9.homedir(), ".exe-os");
|
|
8023
8090
|
var CONFIG_PATH3 = path19.join(CONFIG_DIR, "gateway.json");
|
|
8024
8091
|
var DEFAULT_PORT = 3100;
|
|
8025
8092
|
function loadConfig2() {
|
|
@@ -97,6 +97,7 @@ async function ensureSchema() {
|
|
|
97
97
|
const client = getRawClient();
|
|
98
98
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
99
99
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
100
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
100
101
|
try {
|
|
101
102
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
102
103
|
} catch {
|
|
@@ -897,15 +898,15 @@ var init_database = __esm({
|
|
|
897
898
|
});
|
|
898
899
|
|
|
899
900
|
// src/lib/config.ts
|
|
900
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
901
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
901
902
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
902
903
|
import path2 from "path";
|
|
903
|
-
import
|
|
904
|
+
import os2 from "os";
|
|
904
905
|
function resolveDataDir() {
|
|
905
906
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
906
907
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
907
|
-
const newDir = path2.join(
|
|
908
|
-
const legacyDir = path2.join(
|
|
908
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
909
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
909
910
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
910
911
|
try {
|
|
911
912
|
renameSync(legacyDir, newDir);
|
|
@@ -992,7 +993,7 @@ async function loadConfig() {
|
|
|
992
993
|
normalizeAutoUpdate(migratedCfg);
|
|
993
994
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
994
995
|
if (config.dbPath.startsWith("~")) {
|
|
995
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
996
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
996
997
|
}
|
|
997
998
|
return config;
|
|
998
999
|
} catch {
|
|
@@ -1362,7 +1363,7 @@ var init_employees = __esm({
|
|
|
1362
1363
|
// src/lib/notifications.ts
|
|
1363
1364
|
import crypto2 from "crypto";
|
|
1364
1365
|
import path5 from "path";
|
|
1365
|
-
import
|
|
1366
|
+
import os3 from "os";
|
|
1366
1367
|
import {
|
|
1367
1368
|
readFileSync as readFileSync3,
|
|
1368
1369
|
readdirSync as readdirSync2,
|
|
@@ -1392,12 +1393,12 @@ var init_tasks_crud = __esm({
|
|
|
1392
1393
|
|
|
1393
1394
|
// src/lib/session-registry.ts
|
|
1394
1395
|
import path7 from "path";
|
|
1395
|
-
import
|
|
1396
|
+
import os4 from "os";
|
|
1396
1397
|
var REGISTRY_PATH;
|
|
1397
1398
|
var init_session_registry = __esm({
|
|
1398
1399
|
"src/lib/session-registry.ts"() {
|
|
1399
1400
|
"use strict";
|
|
1400
|
-
REGISTRY_PATH = path7.join(
|
|
1401
|
+
REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
1401
1402
|
}
|
|
1402
1403
|
});
|
|
1403
1404
|
|
|
@@ -1448,14 +1449,14 @@ var init_provider_table = __esm({
|
|
|
1448
1449
|
// src/lib/intercom-queue.ts
|
|
1449
1450
|
import { readFileSync as readFileSync5, writeFileSync, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
|
|
1450
1451
|
import path8 from "path";
|
|
1451
|
-
import
|
|
1452
|
+
import os5 from "os";
|
|
1452
1453
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
1453
1454
|
var init_intercom_queue = __esm({
|
|
1454
1455
|
"src/lib/intercom-queue.ts"() {
|
|
1455
1456
|
"use strict";
|
|
1456
|
-
QUEUE_PATH = path8.join(
|
|
1457
|
+
QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
1457
1458
|
TTL_MS = 60 * 60 * 1e3;
|
|
1458
|
-
INTERCOM_LOG = path8.join(
|
|
1459
|
+
INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1459
1460
|
}
|
|
1460
1461
|
});
|
|
1461
1462
|
|
|
@@ -1492,7 +1493,7 @@ var init_plan_limits = __esm({
|
|
|
1492
1493
|
|
|
1493
1494
|
// src/lib/tmux-routing.ts
|
|
1494
1495
|
import path11 from "path";
|
|
1495
|
-
import
|
|
1496
|
+
import os6 from "os";
|
|
1496
1497
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1497
1498
|
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
1498
1499
|
var init_tmux_routing = __esm({
|
|
@@ -1506,9 +1507,9 @@ var init_tmux_routing = __esm({
|
|
|
1506
1507
|
init_provider_table();
|
|
1507
1508
|
init_intercom_queue();
|
|
1508
1509
|
init_plan_limits();
|
|
1509
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
1510
|
-
SESSION_CACHE = path11.join(
|
|
1511
|
-
INTERCOM_LOG2 = path11.join(
|
|
1510
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
1511
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
1512
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
1512
1513
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1513
1514
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1514
1515
|
}
|
|
@@ -1543,7 +1544,7 @@ var init_tasks_review = __esm({
|
|
|
1543
1544
|
// src/bin/exe-heartbeat.ts
|
|
1544
1545
|
import { createHash } from "crypto";
|
|
1545
1546
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
1546
|
-
import
|
|
1547
|
+
import os7 from "os";
|
|
1547
1548
|
import path13 from "path";
|
|
1548
1549
|
|
|
1549
1550
|
// src/lib/store.ts
|
|
@@ -1553,11 +1554,12 @@ init_database();
|
|
|
1553
1554
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1554
1555
|
import { existsSync } from "fs";
|
|
1555
1556
|
import path from "path";
|
|
1557
|
+
import os from "os";
|
|
1556
1558
|
import crypto from "crypto";
|
|
1557
1559
|
var SERVICE = "exe-mem";
|
|
1558
1560
|
var ACCOUNT = "master-key";
|
|
1559
1561
|
function getKeyDir() {
|
|
1560
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1562
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1561
1563
|
}
|
|
1562
1564
|
function getKeyPath() {
|
|
1563
1565
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1594,6 +1596,30 @@ async function getMasterKey() {
|
|
|
1594
1596
|
|
|
1595
1597
|
// src/lib/store.ts
|
|
1596
1598
|
init_config();
|
|
1599
|
+
var INIT_MAX_RETRIES = 3;
|
|
1600
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1601
|
+
function isBusyError2(err) {
|
|
1602
|
+
if (err instanceof Error) {
|
|
1603
|
+
const msg = err.message.toLowerCase();
|
|
1604
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1605
|
+
}
|
|
1606
|
+
return false;
|
|
1607
|
+
}
|
|
1608
|
+
async function retryOnBusy2(fn, label) {
|
|
1609
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1610
|
+
try {
|
|
1611
|
+
return await fn();
|
|
1612
|
+
} catch (err) {
|
|
1613
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1614
|
+
process.stderr.write(
|
|
1615
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1616
|
+
`
|
|
1617
|
+
);
|
|
1618
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
throw new Error("unreachable");
|
|
1622
|
+
}
|
|
1597
1623
|
var _pendingRecords = [];
|
|
1598
1624
|
var _batchSize = 20;
|
|
1599
1625
|
var _flushIntervalMs = 1e4;
|
|
@@ -1628,14 +1654,17 @@ async function initStore(options) {
|
|
|
1628
1654
|
dbPath,
|
|
1629
1655
|
encryptionKey: hexKey
|
|
1630
1656
|
});
|
|
1631
|
-
await ensureSchema();
|
|
1657
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1632
1658
|
try {
|
|
1633
1659
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1634
1660
|
initShardManager2(hexKey);
|
|
1635
1661
|
} catch {
|
|
1636
1662
|
}
|
|
1637
1663
|
const client = getClient();
|
|
1638
|
-
const vResult = await
|
|
1664
|
+
const vResult = await retryOnBusy2(
|
|
1665
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1666
|
+
"version-query"
|
|
1667
|
+
);
|
|
1639
1668
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1640
1669
|
}
|
|
1641
1670
|
|
|
@@ -1670,7 +1699,7 @@ var MESSAGE_PREVIEW_CHARS = 80;
|
|
|
1670
1699
|
var MARKER_FILENAME = "exe-heartbeat-marker.json";
|
|
1671
1700
|
var SESSION_CACHE_SUBDIR = "session-cache";
|
|
1672
1701
|
function resolveExeOsDir() {
|
|
1673
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(
|
|
1702
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(os7.homedir(), ".exe-os");
|
|
1674
1703
|
}
|
|
1675
1704
|
function getMarkerDir() {
|
|
1676
1705
|
return path13.join(resolveExeOsDir(), SESSION_CACHE_SUBDIR);
|