@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-search.js
CHANGED
|
@@ -106,6 +106,7 @@ async function ensureSchema() {
|
|
|
106
106
|
const client = getRawClient();
|
|
107
107
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
108
108
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
109
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
109
110
|
try {
|
|
110
111
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
111
112
|
} catch {
|
|
@@ -917,9 +918,10 @@ var init_database = __esm({
|
|
|
917
918
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
918
919
|
import { existsSync } from "fs";
|
|
919
920
|
import path from "path";
|
|
921
|
+
import os from "os";
|
|
920
922
|
import crypto from "crypto";
|
|
921
923
|
function getKeyDir() {
|
|
922
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
924
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
923
925
|
}
|
|
924
926
|
function getKeyPath() {
|
|
925
927
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -978,15 +980,15 @@ __export(config_exports, {
|
|
|
978
980
|
migrateConfig: () => migrateConfig,
|
|
979
981
|
saveConfig: () => saveConfig
|
|
980
982
|
});
|
|
981
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
983
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
982
984
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
983
985
|
import path2 from "path";
|
|
984
|
-
import
|
|
986
|
+
import os2 from "os";
|
|
985
987
|
function resolveDataDir() {
|
|
986
988
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
987
989
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
988
|
-
const newDir = path2.join(
|
|
989
|
-
const legacyDir = path2.join(
|
|
990
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
991
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
990
992
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
991
993
|
try {
|
|
992
994
|
renameSync(legacyDir, newDir);
|
|
@@ -1073,7 +1075,7 @@ async function loadConfig() {
|
|
|
1073
1075
|
normalizeAutoUpdate(migratedCfg);
|
|
1074
1076
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1075
1077
|
if (config.dbPath.startsWith("~")) {
|
|
1076
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1078
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1077
1079
|
}
|
|
1078
1080
|
return config;
|
|
1079
1081
|
} catch {
|
|
@@ -1104,6 +1106,9 @@ async function saveConfig(config) {
|
|
|
1104
1106
|
await mkdir2(dir, { recursive: true });
|
|
1105
1107
|
const configPath = path2.join(dir, "config.json");
|
|
1106
1108
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1109
|
+
if (config.cloud?.apiKey) {
|
|
1110
|
+
await chmod2(configPath, 384);
|
|
1111
|
+
}
|
|
1107
1112
|
}
|
|
1108
1113
|
async function loadConfigFrom(configPath) {
|
|
1109
1114
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1463,6 +1468,28 @@ __export(store_exports, {
|
|
|
1463
1468
|
vectorToBlob: () => vectorToBlob,
|
|
1464
1469
|
writeMemory: () => writeMemory
|
|
1465
1470
|
});
|
|
1471
|
+
function isBusyError2(err) {
|
|
1472
|
+
if (err instanceof Error) {
|
|
1473
|
+
const msg = err.message.toLowerCase();
|
|
1474
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1475
|
+
}
|
|
1476
|
+
return false;
|
|
1477
|
+
}
|
|
1478
|
+
async function retryOnBusy2(fn, label) {
|
|
1479
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1480
|
+
try {
|
|
1481
|
+
return await fn();
|
|
1482
|
+
} catch (err) {
|
|
1483
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1484
|
+
process.stderr.write(
|
|
1485
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1486
|
+
`
|
|
1487
|
+
);
|
|
1488
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
throw new Error("unreachable");
|
|
1492
|
+
}
|
|
1466
1493
|
async function initStore(options) {
|
|
1467
1494
|
if (_flushTimer !== null) {
|
|
1468
1495
|
clearInterval(_flushTimer);
|
|
@@ -1491,14 +1518,17 @@ async function initStore(options) {
|
|
|
1491
1518
|
dbPath,
|
|
1492
1519
|
encryptionKey: hexKey
|
|
1493
1520
|
});
|
|
1494
|
-
await ensureSchema();
|
|
1521
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1495
1522
|
try {
|
|
1496
1523
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1497
1524
|
initShardManager2(hexKey);
|
|
1498
1525
|
} catch {
|
|
1499
1526
|
}
|
|
1500
1527
|
const client = getClient();
|
|
1501
|
-
const vResult = await
|
|
1528
|
+
const vResult = await retryOnBusy2(
|
|
1529
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1530
|
+
"version-query"
|
|
1531
|
+
);
|
|
1502
1532
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1503
1533
|
}
|
|
1504
1534
|
function classifyTier(record) {
|
|
@@ -1878,7 +1908,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1878
1908
|
return 0;
|
|
1879
1909
|
}
|
|
1880
1910
|
}
|
|
1881
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1911
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1882
1912
|
var init_store = __esm({
|
|
1883
1913
|
"src/lib/store.ts"() {
|
|
1884
1914
|
"use strict";
|
|
@@ -1886,6 +1916,8 @@ var init_store = __esm({
|
|
|
1886
1916
|
init_database();
|
|
1887
1917
|
init_keychain();
|
|
1888
1918
|
init_config();
|
|
1919
|
+
INIT_MAX_RETRIES = 3;
|
|
1920
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1889
1921
|
_pendingRecords = [];
|
|
1890
1922
|
_batchSize = 20;
|
|
1891
1923
|
_flushIntervalMs = 1e4;
|
|
@@ -1993,6 +2025,10 @@ import path4 from "path";
|
|
|
1993
2025
|
import { fileURLToPath } from "url";
|
|
1994
2026
|
function handleData(chunk) {
|
|
1995
2027
|
_buffer += chunk.toString();
|
|
2028
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
2029
|
+
_buffer = "";
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
1996
2032
|
let newlineIdx;
|
|
1997
2033
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1998
2034
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2300,7 +2336,7 @@ function disconnectClient() {
|
|
|
2300
2336
|
entry.resolve({ error: "Client disconnected" });
|
|
2301
2337
|
}
|
|
2302
2338
|
}
|
|
2303
|
-
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;
|
|
2339
|
+
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;
|
|
2304
2340
|
var init_exe_daemon_client = __esm({
|
|
2305
2341
|
"src/lib/exe-daemon-client.ts"() {
|
|
2306
2342
|
"use strict";
|
|
@@ -2317,6 +2353,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2317
2353
|
_requestCount = 0;
|
|
2318
2354
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2319
2355
|
_pending = /* @__PURE__ */ new Map();
|
|
2356
|
+
MAX_BUFFER = 1e7;
|
|
2320
2357
|
}
|
|
2321
2358
|
});
|
|
2322
2359
|
|
|
@@ -117,6 +117,7 @@ async function ensureSchema() {
|
|
|
117
117
|
const client = getRawClient();
|
|
118
118
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
119
119
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
120
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
120
121
|
try {
|
|
121
122
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
122
123
|
} catch {
|
|
@@ -932,15 +933,15 @@ __export(config_exports, {
|
|
|
932
933
|
migrateConfig: () => migrateConfig,
|
|
933
934
|
saveConfig: () => saveConfig
|
|
934
935
|
});
|
|
935
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
936
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
936
937
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
937
938
|
import path2 from "path";
|
|
938
|
-
import
|
|
939
|
+
import os2 from "os";
|
|
939
940
|
function resolveDataDir() {
|
|
940
941
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
941
942
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
942
|
-
const newDir = path2.join(
|
|
943
|
-
const legacyDir = path2.join(
|
|
943
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
944
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
944
945
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
945
946
|
try {
|
|
946
947
|
renameSync(legacyDir, newDir);
|
|
@@ -1027,7 +1028,7 @@ async function loadConfig() {
|
|
|
1027
1028
|
normalizeAutoUpdate(migratedCfg);
|
|
1028
1029
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1029
1030
|
if (config.dbPath.startsWith("~")) {
|
|
1030
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1031
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1031
1032
|
}
|
|
1032
1033
|
return config;
|
|
1033
1034
|
} catch {
|
|
@@ -1058,6 +1059,9 @@ async function saveConfig(config) {
|
|
|
1058
1059
|
await mkdir2(dir, { recursive: true });
|
|
1059
1060
|
const configPath = path2.join(dir, "config.json");
|
|
1060
1061
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1062
|
+
if (config.cloud?.apiKey) {
|
|
1063
|
+
await chmod2(configPath, 384);
|
|
1064
|
+
}
|
|
1061
1065
|
}
|
|
1062
1066
|
async function loadConfigFrom(configPath) {
|
|
1063
1067
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1451,6 +1455,10 @@ import path5 from "path";
|
|
|
1451
1455
|
import { fileURLToPath } from "url";
|
|
1452
1456
|
function handleData(chunk) {
|
|
1453
1457
|
_buffer += chunk.toString();
|
|
1458
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1459
|
+
_buffer = "";
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1454
1462
|
let newlineIdx;
|
|
1455
1463
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1456
1464
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1758,7 +1766,7 @@ function disconnectClient() {
|
|
|
1758
1766
|
entry.resolve({ error: "Client disconnected" });
|
|
1759
1767
|
}
|
|
1760
1768
|
}
|
|
1761
|
-
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;
|
|
1769
|
+
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;
|
|
1762
1770
|
var init_exe_daemon_client = __esm({
|
|
1763
1771
|
"src/lib/exe-daemon-client.ts"() {
|
|
1764
1772
|
"use strict";
|
|
@@ -1775,6 +1783,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1775
1783
|
_requestCount = 0;
|
|
1776
1784
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1777
1785
|
_pending = /* @__PURE__ */ new Map();
|
|
1786
|
+
MAX_BUFFER = 1e7;
|
|
1778
1787
|
}
|
|
1779
1788
|
});
|
|
1780
1789
|
|
|
@@ -1877,7 +1886,7 @@ var init_employees = __esm({
|
|
|
1877
1886
|
// src/lib/notifications.ts
|
|
1878
1887
|
import crypto2 from "crypto";
|
|
1879
1888
|
import path7 from "path";
|
|
1880
|
-
import
|
|
1889
|
+
import os3 from "os";
|
|
1881
1890
|
import {
|
|
1882
1891
|
readFileSync as readFileSync4,
|
|
1883
1892
|
readdirSync as readdirSync2,
|
|
@@ -2129,12 +2138,12 @@ var init_tasks_crud = __esm({
|
|
|
2129
2138
|
|
|
2130
2139
|
// src/lib/session-registry.ts
|
|
2131
2140
|
import path9 from "path";
|
|
2132
|
-
import
|
|
2141
|
+
import os4 from "os";
|
|
2133
2142
|
var REGISTRY_PATH;
|
|
2134
2143
|
var init_session_registry = __esm({
|
|
2135
2144
|
"src/lib/session-registry.ts"() {
|
|
2136
2145
|
"use strict";
|
|
2137
|
-
REGISTRY_PATH = path9.join(
|
|
2146
|
+
REGISTRY_PATH = path9.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
2138
2147
|
}
|
|
2139
2148
|
});
|
|
2140
2149
|
|
|
@@ -2312,7 +2321,7 @@ var init_provider_table = __esm({
|
|
|
2312
2321
|
// src/lib/intercom-queue.ts
|
|
2313
2322
|
import { readFileSync as readFileSync6, writeFileSync, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync2 } from "fs";
|
|
2314
2323
|
import path10 from "path";
|
|
2315
|
-
import
|
|
2324
|
+
import os5 from "os";
|
|
2316
2325
|
function ensureDir() {
|
|
2317
2326
|
const dir = path10.dirname(QUEUE_PATH);
|
|
2318
2327
|
if (!existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
@@ -2352,9 +2361,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2352
2361
|
var init_intercom_queue = __esm({
|
|
2353
2362
|
"src/lib/intercom-queue.ts"() {
|
|
2354
2363
|
"use strict";
|
|
2355
|
-
QUEUE_PATH = path10.join(
|
|
2364
|
+
QUEUE_PATH = path10.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2356
2365
|
TTL_MS = 60 * 60 * 1e3;
|
|
2357
|
-
INTERCOM_LOG = path10.join(
|
|
2366
|
+
INTERCOM_LOG = path10.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2358
2367
|
}
|
|
2359
2368
|
});
|
|
2360
2369
|
|
|
@@ -2392,7 +2401,7 @@ var init_plan_limits = __esm({
|
|
|
2392
2401
|
// src/lib/tmux-routing.ts
|
|
2393
2402
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2394
2403
|
import path13 from "path";
|
|
2395
|
-
import
|
|
2404
|
+
import os6 from "os";
|
|
2396
2405
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2397
2406
|
function getParentExe(sessionKey) {
|
|
2398
2407
|
try {
|
|
@@ -2515,10 +2524,10 @@ var init_tmux_routing = __esm({
|
|
|
2515
2524
|
init_provider_table();
|
|
2516
2525
|
init_intercom_queue();
|
|
2517
2526
|
init_plan_limits();
|
|
2518
|
-
SPAWN_LOCK_DIR = path13.join(
|
|
2519
|
-
SESSION_CACHE = path13.join(
|
|
2527
|
+
SPAWN_LOCK_DIR = path13.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
2528
|
+
SESSION_CACHE = path13.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2520
2529
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2521
|
-
INTERCOM_LOG2 = path13.join(
|
|
2530
|
+
INTERCOM_LOG2 = path13.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2522
2531
|
DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2523
2532
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2524
2533
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -2993,11 +3002,12 @@ init_database();
|
|
|
2993
3002
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
2994
3003
|
import { existsSync } from "fs";
|
|
2995
3004
|
import path from "path";
|
|
3005
|
+
import os from "os";
|
|
2996
3006
|
import crypto from "crypto";
|
|
2997
3007
|
var SERVICE = "exe-mem";
|
|
2998
3008
|
var ACCOUNT = "master-key";
|
|
2999
3009
|
function getKeyDir() {
|
|
3000
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
3010
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
3001
3011
|
}
|
|
3002
3012
|
function getKeyPath() {
|
|
3003
3013
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -3034,6 +3044,30 @@ async function getMasterKey() {
|
|
|
3034
3044
|
|
|
3035
3045
|
// src/lib/store.ts
|
|
3036
3046
|
init_config();
|
|
3047
|
+
var INIT_MAX_RETRIES = 3;
|
|
3048
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
3049
|
+
function isBusyError2(err) {
|
|
3050
|
+
if (err instanceof Error) {
|
|
3051
|
+
const msg = err.message.toLowerCase();
|
|
3052
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
3053
|
+
}
|
|
3054
|
+
return false;
|
|
3055
|
+
}
|
|
3056
|
+
async function retryOnBusy2(fn, label) {
|
|
3057
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
3058
|
+
try {
|
|
3059
|
+
return await fn();
|
|
3060
|
+
} catch (err) {
|
|
3061
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
3062
|
+
process.stderr.write(
|
|
3063
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
3064
|
+
`
|
|
3065
|
+
);
|
|
3066
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
throw new Error("unreachable");
|
|
3070
|
+
}
|
|
3037
3071
|
var _pendingRecords = [];
|
|
3038
3072
|
var _batchSize = 20;
|
|
3039
3073
|
var _flushIntervalMs = 1e4;
|
|
@@ -3068,14 +3102,17 @@ async function initStore(options) {
|
|
|
3068
3102
|
dbPath,
|
|
3069
3103
|
encryptionKey: hexKey
|
|
3070
3104
|
});
|
|
3071
|
-
await ensureSchema();
|
|
3105
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
3072
3106
|
try {
|
|
3073
3107
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
3074
3108
|
initShardManager2(hexKey);
|
|
3075
3109
|
} catch {
|
|
3076
3110
|
}
|
|
3077
3111
|
const client = getClient();
|
|
3078
|
-
const vResult = await
|
|
3112
|
+
const vResult = await retryOnBusy2(
|
|
3113
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
3114
|
+
"version-query"
|
|
3115
|
+
);
|
|
3079
3116
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
3080
3117
|
}
|
|
3081
3118
|
function classifyTier(record) {
|
package/dist/bin/exe-settings.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createInterface } from "readline";
|
|
3
3
|
|
|
4
4
|
// src/lib/config.ts
|
|
5
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
5
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
6
6
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import os from "os";
|
|
@@ -188,6 +188,9 @@ async function saveConfig(config) {
|
|
|
188
188
|
await mkdir(dir, { recursive: true });
|
|
189
189
|
const configPath = path.join(dir, "config.json");
|
|
190
190
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
191
|
+
if (config.cloud?.apiKey) {
|
|
192
|
+
await chmod(configPath, 384);
|
|
193
|
+
}
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
// src/lib/is-main.ts
|
|
@@ -204,6 +207,62 @@ function isMainModule(importMetaUrl) {
|
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
|
|
210
|
+
// src/lib/cloud-sync.ts
|
|
211
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
|
|
212
|
+
import path5 from "path";
|
|
213
|
+
import { homedir } from "os";
|
|
214
|
+
|
|
215
|
+
// src/lib/database.ts
|
|
216
|
+
import { createClient } from "@libsql/client";
|
|
217
|
+
|
|
218
|
+
// src/lib/crypto.ts
|
|
219
|
+
import crypto from "crypto";
|
|
220
|
+
|
|
221
|
+
// src/lib/compress.ts
|
|
222
|
+
import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
|
|
223
|
+
|
|
224
|
+
// src/lib/plan-limits.ts
|
|
225
|
+
import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
|
|
226
|
+
import path4 from "path";
|
|
227
|
+
|
|
228
|
+
// src/lib/employees.ts
|
|
229
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
230
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
231
|
+
import { execSync } from "child_process";
|
|
232
|
+
import path2 from "path";
|
|
233
|
+
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
234
|
+
|
|
235
|
+
// src/lib/license.ts
|
|
236
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
|
|
237
|
+
import { randomUUID } from "crypto";
|
|
238
|
+
import path3 from "path";
|
|
239
|
+
import { jwtVerify, importSPKI } from "jose";
|
|
240
|
+
var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
|
|
241
|
+
var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
|
|
242
|
+
var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
|
|
243
|
+
|
|
244
|
+
// src/lib/plan-limits.ts
|
|
245
|
+
var CACHE_PATH2 = path4.join(EXE_AI_DIR, "license-cache.json");
|
|
246
|
+
|
|
247
|
+
// src/lib/cloud-sync.ts
|
|
248
|
+
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
249
|
+
var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
|
|
250
|
+
function assertSecureEndpoint(endpoint) {
|
|
251
|
+
if (endpoint.startsWith("https://")) return;
|
|
252
|
+
if (endpoint.startsWith("http://")) {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = new URL(endpoint);
|
|
255
|
+
if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
|
|
256
|
+
} catch {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Insecure cloud endpoint rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost.`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
var ROSTER_DELETIONS_PATH = path5.join(EXE_AI_DIR, "roster-deletions.json");
|
|
265
|
+
|
|
207
266
|
// src/bin/exe-settings.ts
|
|
208
267
|
function label(value) {
|
|
209
268
|
return value ? "ON" : "OFF";
|
|
@@ -315,9 +374,11 @@ async function main() {
|
|
|
315
374
|
const endpoint = ep.trim() || "https://askexe.com/cloud";
|
|
316
375
|
console.log(" Validating...");
|
|
317
376
|
try {
|
|
377
|
+
assertSecureEndpoint(endpoint);
|
|
318
378
|
const resp = await fetch(`${endpoint}/auth/verify`, {
|
|
319
379
|
method: "POST",
|
|
320
|
-
headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" }
|
|
380
|
+
headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" },
|
|
381
|
+
signal: AbortSignal.timeout(3e4)
|
|
321
382
|
});
|
|
322
383
|
if (resp.ok) {
|
|
323
384
|
config.cloud = { apiKey: key, endpoint };
|
package/dist/bin/exe-status.js
CHANGED
|
@@ -10,7 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
15
15
|
import path from "path";
|
|
16
16
|
import os from "os";
|
|
@@ -545,6 +545,7 @@ async function ensureSchema() {
|
|
|
545
545
|
const client = getRawClient();
|
|
546
546
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
547
547
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
548
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
548
549
|
try {
|
|
549
550
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
550
551
|
} catch {
|
|
@@ -1335,14 +1336,15 @@ async function ensureSchema() {
|
|
|
1335
1336
|
}
|
|
1336
1337
|
|
|
1337
1338
|
// src/lib/keychain.ts
|
|
1338
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
|
|
1339
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1339
1340
|
import { existsSync as existsSync3 } from "fs";
|
|
1340
1341
|
import path3 from "path";
|
|
1342
|
+
import os2 from "os";
|
|
1341
1343
|
import crypto from "crypto";
|
|
1342
1344
|
var SERVICE = "exe-mem";
|
|
1343
1345
|
var ACCOUNT = "master-key";
|
|
1344
1346
|
function getKeyDir() {
|
|
1345
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1347
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1346
1348
|
}
|
|
1347
1349
|
function getKeyPath() {
|
|
1348
1350
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1379,6 +1381,30 @@ async function getMasterKey() {
|
|
|
1379
1381
|
|
|
1380
1382
|
// src/lib/store.ts
|
|
1381
1383
|
init_config();
|
|
1384
|
+
var INIT_MAX_RETRIES = 3;
|
|
1385
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1386
|
+
function isBusyError2(err) {
|
|
1387
|
+
if (err instanceof Error) {
|
|
1388
|
+
const msg = err.message.toLowerCase();
|
|
1389
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1390
|
+
}
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
async function retryOnBusy2(fn, label) {
|
|
1394
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1395
|
+
try {
|
|
1396
|
+
return await fn();
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1399
|
+
process.stderr.write(
|
|
1400
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1401
|
+
`
|
|
1402
|
+
);
|
|
1403
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
throw new Error("unreachable");
|
|
1407
|
+
}
|
|
1382
1408
|
var _pendingRecords = [];
|
|
1383
1409
|
var _batchSize = 20;
|
|
1384
1410
|
var _flushIntervalMs = 1e4;
|
|
@@ -1413,14 +1439,17 @@ async function initStore(options) {
|
|
|
1413
1439
|
dbPath,
|
|
1414
1440
|
encryptionKey: hexKey
|
|
1415
1441
|
});
|
|
1416
|
-
await ensureSchema();
|
|
1442
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1417
1443
|
try {
|
|
1418
1444
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1419
1445
|
initShardManager2(hexKey);
|
|
1420
1446
|
} catch {
|
|
1421
1447
|
}
|
|
1422
1448
|
const client = getClient();
|
|
1423
|
-
const vResult = await
|
|
1449
|
+
const vResult = await retryOnBusy2(
|
|
1450
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1451
|
+
"version-query"
|
|
1452
|
+
);
|
|
1424
1453
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1425
1454
|
}
|
|
1426
1455
|
|
package/dist/bin/exe-team.js
CHANGED
|
@@ -10,7 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
15
15
|
import path from "path";
|
|
16
16
|
import os from "os";
|
|
@@ -545,6 +545,7 @@ async function ensureSchema() {
|
|
|
545
545
|
const client = getRawClient();
|
|
546
546
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
547
547
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
548
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
548
549
|
try {
|
|
549
550
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
550
551
|
} catch {
|
|
@@ -1335,14 +1336,15 @@ async function ensureSchema() {
|
|
|
1335
1336
|
}
|
|
1336
1337
|
|
|
1337
1338
|
// src/lib/keychain.ts
|
|
1338
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
|
|
1339
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1339
1340
|
import { existsSync as existsSync3 } from "fs";
|
|
1340
1341
|
import path3 from "path";
|
|
1342
|
+
import os2 from "os";
|
|
1341
1343
|
import crypto from "crypto";
|
|
1342
1344
|
var SERVICE = "exe-mem";
|
|
1343
1345
|
var ACCOUNT = "master-key";
|
|
1344
1346
|
function getKeyDir() {
|
|
1345
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1347
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1346
1348
|
}
|
|
1347
1349
|
function getKeyPath() {
|
|
1348
1350
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1379,6 +1381,30 @@ async function getMasterKey() {
|
|
|
1379
1381
|
|
|
1380
1382
|
// src/lib/store.ts
|
|
1381
1383
|
init_config();
|
|
1384
|
+
var INIT_MAX_RETRIES = 3;
|
|
1385
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1386
|
+
function isBusyError2(err) {
|
|
1387
|
+
if (err instanceof Error) {
|
|
1388
|
+
const msg = err.message.toLowerCase();
|
|
1389
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1390
|
+
}
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
async function retryOnBusy2(fn, label) {
|
|
1394
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1395
|
+
try {
|
|
1396
|
+
return await fn();
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1399
|
+
process.stderr.write(
|
|
1400
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1401
|
+
`
|
|
1402
|
+
);
|
|
1403
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
throw new Error("unreachable");
|
|
1407
|
+
}
|
|
1382
1408
|
var _pendingRecords = [];
|
|
1383
1409
|
var _batchSize = 20;
|
|
1384
1410
|
var _flushIntervalMs = 1e4;
|
|
@@ -1413,14 +1439,17 @@ async function initStore(options) {
|
|
|
1413
1439
|
dbPath,
|
|
1414
1440
|
encryptionKey: hexKey
|
|
1415
1441
|
});
|
|
1416
|
-
await ensureSchema();
|
|
1442
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1417
1443
|
try {
|
|
1418
1444
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1419
1445
|
initShardManager2(hexKey);
|
|
1420
1446
|
} catch {
|
|
1421
1447
|
}
|
|
1422
1448
|
const client = getClient();
|
|
1423
|
-
const vResult = await
|
|
1449
|
+
const vResult = await retryOnBusy2(
|
|
1450
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1451
|
+
"version-query"
|
|
1452
|
+
);
|
|
1424
1453
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1425
1454
|
}
|
|
1426
1455
|
|