@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
|
@@ -10,15 +10,15 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
15
15
|
import path2 from "path";
|
|
16
|
-
import
|
|
16
|
+
import os2 from "os";
|
|
17
17
|
function resolveDataDir() {
|
|
18
18
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
19
19
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
20
|
-
const newDir = path2.join(
|
|
21
|
-
const legacyDir = path2.join(
|
|
20
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
21
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
22
22
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
23
23
|
try {
|
|
24
24
|
renameSync(legacyDir, newDir);
|
|
@@ -105,7 +105,7 @@ async function loadConfig() {
|
|
|
105
105
|
normalizeAutoUpdate(migratedCfg);
|
|
106
106
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
107
107
|
if (config.dbPath.startsWith("~")) {
|
|
108
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
108
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
109
109
|
}
|
|
110
110
|
return config;
|
|
111
111
|
} catch {
|
|
@@ -526,6 +526,7 @@ async function ensureSchema() {
|
|
|
526
526
|
const client = getRawClient();
|
|
527
527
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
528
528
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
529
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
529
530
|
try {
|
|
530
531
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
531
532
|
} catch {
|
|
@@ -1327,11 +1328,12 @@ async function disposeDatabase() {
|
|
|
1327
1328
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1328
1329
|
import { existsSync } from "fs";
|
|
1329
1330
|
import path from "path";
|
|
1331
|
+
import os from "os";
|
|
1330
1332
|
import crypto from "crypto";
|
|
1331
1333
|
var SERVICE = "exe-mem";
|
|
1332
1334
|
var ACCOUNT = "master-key";
|
|
1333
1335
|
function getKeyDir() {
|
|
1334
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1336
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1335
1337
|
}
|
|
1336
1338
|
function getKeyPath() {
|
|
1337
1339
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1368,6 +1370,30 @@ async function getMasterKey() {
|
|
|
1368
1370
|
|
|
1369
1371
|
// src/lib/store.ts
|
|
1370
1372
|
init_config();
|
|
1373
|
+
var INIT_MAX_RETRIES = 3;
|
|
1374
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1375
|
+
function isBusyError2(err) {
|
|
1376
|
+
if (err instanceof Error) {
|
|
1377
|
+
const msg = err.message.toLowerCase();
|
|
1378
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1379
|
+
}
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
async function retryOnBusy2(fn, label) {
|
|
1383
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1384
|
+
try {
|
|
1385
|
+
return await fn();
|
|
1386
|
+
} catch (err) {
|
|
1387
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1388
|
+
process.stderr.write(
|
|
1389
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1390
|
+
`
|
|
1391
|
+
);
|
|
1392
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
throw new Error("unreachable");
|
|
1396
|
+
}
|
|
1371
1397
|
var _pendingRecords = [];
|
|
1372
1398
|
var _batchSize = 20;
|
|
1373
1399
|
var _flushIntervalMs = 1e4;
|
|
@@ -1402,14 +1428,17 @@ async function initStore(options) {
|
|
|
1402
1428
|
dbPath,
|
|
1403
1429
|
encryptionKey: hexKey
|
|
1404
1430
|
});
|
|
1405
|
-
await ensureSchema();
|
|
1431
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1406
1432
|
try {
|
|
1407
1433
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1408
1434
|
initShardManager2(hexKey);
|
|
1409
1435
|
} catch {
|
|
1410
1436
|
}
|
|
1411
1437
|
const client = getClient();
|
|
1412
|
-
const vResult = await
|
|
1438
|
+
const vResult = await retryOnBusy2(
|
|
1439
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1440
|
+
"version-query"
|
|
1441
|
+
);
|
|
1413
1442
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1414
1443
|
}
|
|
1415
1444
|
async function flushBatch() {
|
package/dist/bin/wiki-sync.js
CHANGED
|
@@ -10,15 +10,15 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
15
15
|
import path2 from "path";
|
|
16
|
-
import
|
|
16
|
+
import os2 from "os";
|
|
17
17
|
function resolveDataDir() {
|
|
18
18
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
19
19
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
20
|
-
const newDir = path2.join(
|
|
21
|
-
const legacyDir = path2.join(
|
|
20
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
21
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
22
22
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
23
23
|
try {
|
|
24
24
|
renameSync(legacyDir, newDir);
|
|
@@ -105,7 +105,7 @@ async function loadConfig() {
|
|
|
105
105
|
normalizeAutoUpdate(migratedCfg);
|
|
106
106
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
107
107
|
if (config.dbPath.startsWith("~")) {
|
|
108
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
108
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
109
109
|
}
|
|
110
110
|
return config;
|
|
111
111
|
} catch {
|
|
@@ -526,6 +526,7 @@ async function ensureSchema() {
|
|
|
526
526
|
const client = getRawClient();
|
|
527
527
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
528
528
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
529
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
529
530
|
try {
|
|
530
531
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
531
532
|
} catch {
|
|
@@ -1327,11 +1328,12 @@ async function disposeDatabase() {
|
|
|
1327
1328
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1328
1329
|
import { existsSync } from "fs";
|
|
1329
1330
|
import path from "path";
|
|
1331
|
+
import os from "os";
|
|
1330
1332
|
import crypto from "crypto";
|
|
1331
1333
|
var SERVICE = "exe-mem";
|
|
1332
1334
|
var ACCOUNT = "master-key";
|
|
1333
1335
|
function getKeyDir() {
|
|
1334
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1336
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1335
1337
|
}
|
|
1336
1338
|
function getKeyPath() {
|
|
1337
1339
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1368,6 +1370,30 @@ async function getMasterKey() {
|
|
|
1368
1370
|
|
|
1369
1371
|
// src/lib/store.ts
|
|
1370
1372
|
init_config();
|
|
1373
|
+
var INIT_MAX_RETRIES = 3;
|
|
1374
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1375
|
+
function isBusyError2(err) {
|
|
1376
|
+
if (err instanceof Error) {
|
|
1377
|
+
const msg = err.message.toLowerCase();
|
|
1378
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1379
|
+
}
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
async function retryOnBusy2(fn, label) {
|
|
1383
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1384
|
+
try {
|
|
1385
|
+
return await fn();
|
|
1386
|
+
} catch (err) {
|
|
1387
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1388
|
+
process.stderr.write(
|
|
1389
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1390
|
+
`
|
|
1391
|
+
);
|
|
1392
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
throw new Error("unreachable");
|
|
1396
|
+
}
|
|
1371
1397
|
var _pendingRecords = [];
|
|
1372
1398
|
var _batchSize = 20;
|
|
1373
1399
|
var _flushIntervalMs = 1e4;
|
|
@@ -1402,14 +1428,17 @@ async function initStore(options) {
|
|
|
1402
1428
|
dbPath,
|
|
1403
1429
|
encryptionKey: hexKey
|
|
1404
1430
|
});
|
|
1405
|
-
await ensureSchema();
|
|
1431
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1406
1432
|
try {
|
|
1407
1433
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1408
1434
|
initShardManager2(hexKey);
|
|
1409
1435
|
} catch {
|
|
1410
1436
|
}
|
|
1411
1437
|
const client = getClient();
|
|
1412
|
-
const vResult = await
|
|
1438
|
+
const vResult = await retryOnBusy2(
|
|
1439
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1440
|
+
"version-query"
|
|
1441
|
+
);
|
|
1413
1442
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1414
1443
|
}
|
|
1415
1444
|
async function flushBatch() {
|
|
@@ -1570,7 +1599,8 @@ async function wikiRequest(config, path4, method = "GET", body) {
|
|
|
1570
1599
|
const response = await fetch(url, {
|
|
1571
1600
|
method,
|
|
1572
1601
|
headers,
|
|
1573
|
-
body: body ? JSON.stringify(body) : void 0
|
|
1602
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
1603
|
+
signal: AbortSignal.timeout(3e4)
|
|
1574
1604
|
});
|
|
1575
1605
|
if (!response.ok) {
|
|
1576
1606
|
throw new Error(`Wiki API ${method} ${path4}: ${response.status} ${response.statusText}`);
|
package/dist/gateway/index.js
CHANGED
|
@@ -55,7 +55,8 @@ async function gqlRequest(query, variables) {
|
|
|
55
55
|
"Content-Type": "application/json",
|
|
56
56
|
Authorization: `Bearer ${config.apiToken}`
|
|
57
57
|
},
|
|
58
|
-
body: JSON.stringify({ query, variables })
|
|
58
|
+
body: JSON.stringify({ query, variables }),
|
|
59
|
+
signal: AbortSignal.timeout(3e4)
|
|
59
60
|
});
|
|
60
61
|
if (!res.ok) {
|
|
61
62
|
throw new Error(`CRM GraphQL request failed: ${res.status} ${res.statusText}`);
|
|
@@ -362,6 +363,7 @@ async function ensureSchema() {
|
|
|
362
363
|
const client = getRawClient();
|
|
363
364
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
364
365
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
366
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
365
367
|
try {
|
|
366
368
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
367
369
|
} catch {
|
|
@@ -1194,7 +1196,7 @@ __export(config_exports, {
|
|
|
1194
1196
|
migrateConfig: () => migrateConfig,
|
|
1195
1197
|
saveConfig: () => saveConfig
|
|
1196
1198
|
});
|
|
1197
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
1199
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
1198
1200
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
1199
1201
|
import path from "path";
|
|
1200
1202
|
import os from "os";
|
|
@@ -1320,6 +1322,9 @@ async function saveConfig(config2) {
|
|
|
1320
1322
|
await mkdir(dir, { recursive: true });
|
|
1321
1323
|
const configPath = path.join(dir, "config.json");
|
|
1322
1324
|
await writeFile(configPath, JSON.stringify(config2, null, 2) + "\n");
|
|
1325
|
+
if (config2.cloud?.apiKey) {
|
|
1326
|
+
await chmod(configPath, 384);
|
|
1327
|
+
}
|
|
1323
1328
|
}
|
|
1324
1329
|
async function loadConfigFrom(configPath) {
|
|
1325
1330
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -1430,6 +1435,10 @@ import path2 from "path";
|
|
|
1430
1435
|
import { fileURLToPath } from "url";
|
|
1431
1436
|
function handleData(chunk) {
|
|
1432
1437
|
_buffer += chunk.toString();
|
|
1438
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1439
|
+
_buffer = "";
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1433
1442
|
let newlineIdx;
|
|
1434
1443
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1435
1444
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1737,7 +1746,7 @@ function disconnectClient() {
|
|
|
1737
1746
|
entry.resolve({ error: "Client disconnected" });
|
|
1738
1747
|
}
|
|
1739
1748
|
}
|
|
1740
|
-
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;
|
|
1749
|
+
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;
|
|
1741
1750
|
var init_exe_daemon_client = __esm({
|
|
1742
1751
|
"src/lib/exe-daemon-client.ts"() {
|
|
1743
1752
|
"use strict";
|
|
@@ -1754,6 +1763,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1754
1763
|
_requestCount = 0;
|
|
1755
1764
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1756
1765
|
_pending = /* @__PURE__ */ new Map();
|
|
1766
|
+
MAX_BUFFER = 1e7;
|
|
1757
1767
|
}
|
|
1758
1768
|
});
|
|
1759
1769
|
|
|
@@ -1826,12 +1836,13 @@ var init_embedder = __esm({
|
|
|
1826
1836
|
});
|
|
1827
1837
|
|
|
1828
1838
|
// src/lib/keychain.ts
|
|
1829
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1839
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1830
1840
|
import { existsSync as existsSync3 } from "fs";
|
|
1831
1841
|
import path3 from "path";
|
|
1842
|
+
import os2 from "os";
|
|
1832
1843
|
import crypto from "crypto";
|
|
1833
1844
|
function getKeyDir() {
|
|
1834
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1845
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1835
1846
|
}
|
|
1836
1847
|
function getKeyPath() {
|
|
1837
1848
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -2132,6 +2143,28 @@ __export(store_exports, {
|
|
|
2132
2143
|
vectorToBlob: () => vectorToBlob,
|
|
2133
2144
|
writeMemory: () => writeMemory
|
|
2134
2145
|
});
|
|
2146
|
+
function isBusyError2(err) {
|
|
2147
|
+
if (err instanceof Error) {
|
|
2148
|
+
const msg = err.message.toLowerCase();
|
|
2149
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2150
|
+
}
|
|
2151
|
+
return false;
|
|
2152
|
+
}
|
|
2153
|
+
async function retryOnBusy2(fn, label) {
|
|
2154
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2155
|
+
try {
|
|
2156
|
+
return await fn();
|
|
2157
|
+
} catch (err) {
|
|
2158
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2159
|
+
process.stderr.write(
|
|
2160
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2161
|
+
`
|
|
2162
|
+
);
|
|
2163
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
throw new Error("unreachable");
|
|
2167
|
+
}
|
|
2135
2168
|
async function initStore(options) {
|
|
2136
2169
|
if (_flushTimer !== null) {
|
|
2137
2170
|
clearInterval(_flushTimer);
|
|
@@ -2160,14 +2193,17 @@ async function initStore(options) {
|
|
|
2160
2193
|
dbPath,
|
|
2161
2194
|
encryptionKey: hexKey
|
|
2162
2195
|
});
|
|
2163
|
-
await ensureSchema();
|
|
2196
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2164
2197
|
try {
|
|
2165
2198
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2166
2199
|
initShardManager2(hexKey);
|
|
2167
2200
|
} catch {
|
|
2168
2201
|
}
|
|
2169
2202
|
const client = getClient();
|
|
2170
|
-
const vResult = await
|
|
2203
|
+
const vResult = await retryOnBusy2(
|
|
2204
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2205
|
+
"version-query"
|
|
2206
|
+
);
|
|
2171
2207
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2172
2208
|
}
|
|
2173
2209
|
function classifyTier(record) {
|
|
@@ -2547,7 +2583,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
2547
2583
|
return 0;
|
|
2548
2584
|
}
|
|
2549
2585
|
}
|
|
2550
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2586
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2551
2587
|
var init_store = __esm({
|
|
2552
2588
|
"src/lib/store.ts"() {
|
|
2553
2589
|
"use strict";
|
|
@@ -2555,6 +2591,8 @@ var init_store = __esm({
|
|
|
2555
2591
|
init_database();
|
|
2556
2592
|
init_keychain();
|
|
2557
2593
|
init_config();
|
|
2594
|
+
INIT_MAX_RETRIES = 3;
|
|
2595
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
2558
2596
|
_pendingRecords = [];
|
|
2559
2597
|
_batchSize = 20;
|
|
2560
2598
|
_flushIntervalMs = 1e4;
|
|
@@ -2582,12 +2620,30 @@ async function wikiFetch(config2, path19, method = "GET", body) {
|
|
|
2582
2620
|
const controller = new AbortController();
|
|
2583
2621
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
2584
2622
|
try {
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2623
|
+
let response;
|
|
2624
|
+
try {
|
|
2625
|
+
response = await fetch(url, {
|
|
2626
|
+
method,
|
|
2627
|
+
headers,
|
|
2628
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2629
|
+
signal: controller.signal
|
|
2630
|
+
});
|
|
2631
|
+
} catch {
|
|
2632
|
+
clearTimeout(timeout);
|
|
2633
|
+
const retryController = new AbortController();
|
|
2634
|
+
const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
|
|
2635
|
+
try {
|
|
2636
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2637
|
+
response = await fetch(url, {
|
|
2638
|
+
method,
|
|
2639
|
+
headers,
|
|
2640
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2641
|
+
signal: retryController.signal
|
|
2642
|
+
});
|
|
2643
|
+
} finally {
|
|
2644
|
+
clearTimeout(retryTimeout);
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2591
2647
|
if (!response.ok) {
|
|
2592
2648
|
throw new Error(`Wiki API ${method} ${path19}: ${response.status} ${response.statusText}`);
|
|
2593
2649
|
}
|
|
@@ -2745,7 +2801,7 @@ var init_whatsapp_accounts = __esm({
|
|
|
2745
2801
|
// src/lib/session-registry.ts
|
|
2746
2802
|
import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
|
|
2747
2803
|
import path6 from "path";
|
|
2748
|
-
import
|
|
2804
|
+
import os4 from "os";
|
|
2749
2805
|
function registerSession(entry) {
|
|
2750
2806
|
const dir = path6.dirname(REGISTRY_PATH);
|
|
2751
2807
|
if (!existsSync5(dir)) {
|
|
@@ -2772,7 +2828,7 @@ var REGISTRY_PATH;
|
|
|
2772
2828
|
var init_session_registry = __esm({
|
|
2773
2829
|
"src/lib/session-registry.ts"() {
|
|
2774
2830
|
"use strict";
|
|
2775
|
-
REGISTRY_PATH = path6.join(
|
|
2831
|
+
REGISTRY_PATH = path6.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
2776
2832
|
}
|
|
2777
2833
|
});
|
|
2778
2834
|
|
|
@@ -2994,7 +3050,7 @@ var init_provider_table = __esm({
|
|
|
2994
3050
|
// src/lib/intercom-queue.ts
|
|
2995
3051
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
2996
3052
|
import path7 from "path";
|
|
2997
|
-
import
|
|
3053
|
+
import os5 from "os";
|
|
2998
3054
|
function ensureDir() {
|
|
2999
3055
|
const dir = path7.dirname(QUEUE_PATH);
|
|
3000
3056
|
if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -3034,9 +3090,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
3034
3090
|
var init_intercom_queue = __esm({
|
|
3035
3091
|
"src/lib/intercom-queue.ts"() {
|
|
3036
3092
|
"use strict";
|
|
3037
|
-
QUEUE_PATH = path7.join(
|
|
3093
|
+
QUEUE_PATH = path7.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
3038
3094
|
TTL_MS = 60 * 60 * 1e3;
|
|
3039
|
-
INTERCOM_LOG = path7.join(
|
|
3095
|
+
INTERCOM_LOG = path7.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
3040
3096
|
}
|
|
3041
3097
|
});
|
|
3042
3098
|
|
|
@@ -3177,7 +3233,7 @@ var init_plan_limits = __esm({
|
|
|
3177
3233
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
3178
3234
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, existsSync as existsSync10, appendFileSync } from "fs";
|
|
3179
3235
|
import path11 from "path";
|
|
3180
|
-
import
|
|
3236
|
+
import os6 from "os";
|
|
3181
3237
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3182
3238
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
3183
3239
|
function spawnLockPath(sessionName) {
|
|
@@ -3482,7 +3538,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3482
3538
|
const transport = getTransport();
|
|
3483
3539
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3484
3540
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3485
|
-
const logDir = path11.join(
|
|
3541
|
+
const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
|
|
3486
3542
|
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3487
3543
|
if (!existsSync10(logDir)) {
|
|
3488
3544
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -3498,7 +3554,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3498
3554
|
} catch {
|
|
3499
3555
|
}
|
|
3500
3556
|
try {
|
|
3501
|
-
const claudeJsonPath = path11.join(
|
|
3557
|
+
const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
|
|
3502
3558
|
let claudeJson = {};
|
|
3503
3559
|
try {
|
|
3504
3560
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -3513,7 +3569,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3513
3569
|
} catch {
|
|
3514
3570
|
}
|
|
3515
3571
|
try {
|
|
3516
|
-
const settingsDir = path11.join(
|
|
3572
|
+
const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
|
|
3517
3573
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3518
3574
|
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
3519
3575
|
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
@@ -3561,7 +3617,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3561
3617
|
let legacyFallbackWarned = false;
|
|
3562
3618
|
if (!useExeAgent && !useBinSymlink) {
|
|
3563
3619
|
const identityPath = path11.join(
|
|
3564
|
-
|
|
3620
|
+
os6.homedir(),
|
|
3565
3621
|
".exe-os",
|
|
3566
3622
|
"identity",
|
|
3567
3623
|
`${employeeName}.md`
|
|
@@ -3591,7 +3647,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3591
3647
|
}
|
|
3592
3648
|
let sessionContextFlag = "";
|
|
3593
3649
|
try {
|
|
3594
|
-
const ctxDir = path11.join(
|
|
3650
|
+
const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3595
3651
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3596
3652
|
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3597
3653
|
const ctxContent = [
|
|
@@ -3702,11 +3758,11 @@ var init_tmux_routing = __esm({
|
|
|
3702
3758
|
init_provider_table();
|
|
3703
3759
|
init_intercom_queue();
|
|
3704
3760
|
init_plan_limits();
|
|
3705
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
3706
|
-
SESSION_CACHE = path11.join(
|
|
3761
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
3762
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3707
3763
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3708
3764
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3709
|
-
INTERCOM_LOG2 = path11.join(
|
|
3765
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
3710
3766
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3711
3767
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3712
3768
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -3966,7 +4022,7 @@ var init_messaging = __esm({
|
|
|
3966
4022
|
// src/lib/notifications.ts
|
|
3967
4023
|
import crypto4 from "crypto";
|
|
3968
4024
|
import path12 from "path";
|
|
3969
|
-
import
|
|
4025
|
+
import os7 from "os";
|
|
3970
4026
|
import {
|
|
3971
4027
|
readFileSync as readFileSync10,
|
|
3972
4028
|
readdirSync as readdirSync2,
|
|
@@ -6683,7 +6739,8 @@ var OllamaProvider = class {
|
|
|
6683
6739
|
const res = await fetch(`${this.host}/api/chat`, {
|
|
6684
6740
|
method: "POST",
|
|
6685
6741
|
headers: { "Content-Type": "application/json" },
|
|
6686
|
-
body: JSON.stringify(body)
|
|
6742
|
+
body: JSON.stringify(body),
|
|
6743
|
+
signal: AbortSignal.timeout(3e4)
|
|
6687
6744
|
});
|
|
6688
6745
|
if (!res.ok) {
|
|
6689
6746
|
throw new Error(`Ollama API error: ${res.status} ${await res.text()}`);
|
|
@@ -7111,7 +7168,7 @@ var SignalAdapter = class {
|
|
|
7111
7168
|
if (/^https?:\/\//i.test(trimmed)) {
|
|
7112
7169
|
return trimmed.replace(/\/+$/, "");
|
|
7113
7170
|
}
|
|
7114
|
-
return `
|
|
7171
|
+
return `https://${trimmed}`.replace(/\/+$/, "");
|
|
7115
7172
|
}
|
|
7116
7173
|
async connect(config2) {
|
|
7117
7174
|
this.baseUrl = this.normalizeBaseUrl(
|
|
@@ -7533,9 +7590,15 @@ var WebChatAdapter = class {
|
|
|
7533
7590
|
res.end(JSON.stringify({ error: "Not found" }));
|
|
7534
7591
|
}
|
|
7535
7592
|
async handleChatRequest(req, res) {
|
|
7593
|
+
const MAX_BODY_SIZE = 1048576;
|
|
7536
7594
|
let body = "";
|
|
7537
7595
|
for await (const chunk of req) {
|
|
7538
7596
|
body += chunk;
|
|
7597
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
7598
|
+
res.writeHead(413, { "Content-Type": "application/json" });
|
|
7599
|
+
res.end(JSON.stringify({ error: "Request body too large" }));
|
|
7600
|
+
return;
|
|
7601
|
+
}
|
|
7539
7602
|
}
|
|
7540
7603
|
let parsed;
|
|
7541
7604
|
try {
|
|
@@ -8015,12 +8078,12 @@ var SlackAdapter = class {
|
|
|
8015
8078
|
// src/gateway/adapters/imessage.ts
|
|
8016
8079
|
import { execFile } from "child_process";
|
|
8017
8080
|
import { promisify } from "util";
|
|
8018
|
-
import
|
|
8081
|
+
import os3 from "os";
|
|
8019
8082
|
import path5 from "path";
|
|
8020
8083
|
var execFileAsync = promisify(execFile);
|
|
8021
8084
|
var POLL_INTERVAL_MS = 5e3;
|
|
8022
8085
|
var MESSAGES_DB_PATH = path5.join(
|
|
8023
|
-
process.env.HOME ??
|
|
8086
|
+
process.env.HOME ?? os3.homedir(),
|
|
8024
8087
|
"Library/Messages/chat.db"
|
|
8025
8088
|
);
|
|
8026
8089
|
var IMessageAdapter = class {
|
|
@@ -8866,8 +8929,9 @@ async function ensureCRMContact(info) {
|
|
|
8866
8929
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
|
|
8867
8930
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
8868
8931
|
import path18 from "path";
|
|
8869
|
-
import
|
|
8870
|
-
var TRIGGERS_PATH = path18.join(
|
|
8932
|
+
import os8 from "os";
|
|
8933
|
+
var TRIGGERS_PATH = path18.join(os8.homedir(), ".exe-os", "triggers.json");
|
|
8934
|
+
var GRAPH_API_VERSION = "v21.0";
|
|
8871
8935
|
function substituteTemplate(template, record) {
|
|
8872
8936
|
return template.replace(
|
|
8873
8937
|
/\{\{(\w+(?:\.\w+)*)\}\}/g,
|
|
@@ -8945,7 +9009,7 @@ async function executeSendWhatsapp(params) {
|
|
|
8945
9009
|
const message = params.message ?? params.text;
|
|
8946
9010
|
if (!to || !message)
|
|
8947
9011
|
throw new Error("send_whatsapp requires 'to' and 'message' params");
|
|
8948
|
-
const url = `https://graph.facebook.com
|
|
9012
|
+
const url = `https://graph.facebook.com/${GRAPH_API_VERSION}/${account.phoneNumberId}/messages`;
|
|
8949
9013
|
const res = await fetch(url, {
|
|
8950
9014
|
method: "POST",
|
|
8951
9015
|
headers: {
|
|
@@ -8957,7 +9021,8 @@ async function executeSendWhatsapp(params) {
|
|
|
8957
9021
|
to,
|
|
8958
9022
|
type: "text",
|
|
8959
9023
|
text: { body: message }
|
|
8960
|
-
})
|
|
9024
|
+
}),
|
|
9025
|
+
signal: AbortSignal.timeout(3e4)
|
|
8961
9026
|
});
|
|
8962
9027
|
if (!res.ok) {
|
|
8963
9028
|
const errBody = await res.text();
|