@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
|
@@ -39,15 +39,15 @@ __export(config_exports, {
|
|
|
39
39
|
migrateConfig: () => migrateConfig,
|
|
40
40
|
saveConfig: () => saveConfig
|
|
41
41
|
});
|
|
42
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
42
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
43
43
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
44
44
|
import path3 from "path";
|
|
45
|
-
import
|
|
45
|
+
import os2 from "os";
|
|
46
46
|
function resolveDataDir() {
|
|
47
47
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
48
48
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
49
|
-
const newDir = path3.join(
|
|
50
|
-
const legacyDir = path3.join(
|
|
49
|
+
const newDir = path3.join(os2.homedir(), ".exe-os");
|
|
50
|
+
const legacyDir = path3.join(os2.homedir(), ".exe-mem");
|
|
51
51
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
52
52
|
try {
|
|
53
53
|
renameSync(legacyDir, newDir);
|
|
@@ -134,7 +134,7 @@ async function loadConfig() {
|
|
|
134
134
|
normalizeAutoUpdate(migratedCfg);
|
|
135
135
|
const config = { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db"), ...migratedCfg };
|
|
136
136
|
if (config.dbPath.startsWith("~")) {
|
|
137
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
137
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
138
138
|
}
|
|
139
139
|
return config;
|
|
140
140
|
} catch {
|
|
@@ -165,6 +165,9 @@ async function saveConfig(config) {
|
|
|
165
165
|
await mkdir2(dir, { recursive: true });
|
|
166
166
|
const configPath = path3.join(dir, "config.json");
|
|
167
167
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
168
|
+
if (config.cloud?.apiKey) {
|
|
169
|
+
await chmod2(configPath, 384);
|
|
170
|
+
}
|
|
168
171
|
}
|
|
169
172
|
async function loadConfigFrom(configPath) {
|
|
170
173
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -516,6 +519,10 @@ import path8 from "path";
|
|
|
516
519
|
import { fileURLToPath } from "url";
|
|
517
520
|
function handleData(chunk) {
|
|
518
521
|
_buffer += chunk.toString();
|
|
522
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
523
|
+
_buffer = "";
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
519
526
|
let newlineIdx;
|
|
520
527
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
521
528
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -823,7 +830,7 @@ function disconnectClient() {
|
|
|
823
830
|
entry.resolve({ error: "Client disconnected" });
|
|
824
831
|
}
|
|
825
832
|
}
|
|
826
|
-
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;
|
|
833
|
+
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;
|
|
827
834
|
var init_exe_daemon_client = __esm({
|
|
828
835
|
"src/lib/exe-daemon-client.ts"() {
|
|
829
836
|
"use strict";
|
|
@@ -840,6 +847,7 @@ var init_exe_daemon_client = __esm({
|
|
|
840
847
|
_requestCount = 0;
|
|
841
848
|
HEALTH_CHECK_INTERVAL = 100;
|
|
842
849
|
_pending = /* @__PURE__ */ new Map();
|
|
850
|
+
MAX_BUFFER = 1e7;
|
|
843
851
|
}
|
|
844
852
|
});
|
|
845
853
|
|
|
@@ -1045,6 +1053,7 @@ async function ensureSchema() {
|
|
|
1045
1053
|
const client = getRawClient();
|
|
1046
1054
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1047
1055
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1056
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
1048
1057
|
try {
|
|
1049
1058
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1050
1059
|
} catch {
|
|
@@ -1838,11 +1847,12 @@ async function ensureSchema() {
|
|
|
1838
1847
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1839
1848
|
import { existsSync } from "fs";
|
|
1840
1849
|
import path2 from "path";
|
|
1850
|
+
import os from "os";
|
|
1841
1851
|
import crypto from "crypto";
|
|
1842
1852
|
var SERVICE = "exe-mem";
|
|
1843
1853
|
var ACCOUNT = "master-key";
|
|
1844
1854
|
function getKeyDir() {
|
|
1845
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(
|
|
1855
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(os.homedir(), ".exe-os");
|
|
1846
1856
|
}
|
|
1847
1857
|
function getKeyPath() {
|
|
1848
1858
|
return path2.join(getKeyDir(), "master.key");
|
|
@@ -1879,6 +1889,30 @@ async function getMasterKey() {
|
|
|
1879
1889
|
|
|
1880
1890
|
// src/lib/store.ts
|
|
1881
1891
|
init_config();
|
|
1892
|
+
var INIT_MAX_RETRIES = 3;
|
|
1893
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1894
|
+
function isBusyError2(err) {
|
|
1895
|
+
if (err instanceof Error) {
|
|
1896
|
+
const msg = err.message.toLowerCase();
|
|
1897
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1898
|
+
}
|
|
1899
|
+
return false;
|
|
1900
|
+
}
|
|
1901
|
+
async function retryOnBusy2(fn, label) {
|
|
1902
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1903
|
+
try {
|
|
1904
|
+
return await fn();
|
|
1905
|
+
} catch (err) {
|
|
1906
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1907
|
+
process.stderr.write(
|
|
1908
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1909
|
+
`
|
|
1910
|
+
);
|
|
1911
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
throw new Error("unreachable");
|
|
1915
|
+
}
|
|
1882
1916
|
var _pendingRecords = [];
|
|
1883
1917
|
var _batchSize = 20;
|
|
1884
1918
|
var _flushIntervalMs = 1e4;
|
|
@@ -1913,14 +1947,17 @@ async function initStore(options) {
|
|
|
1913
1947
|
dbPath,
|
|
1914
1948
|
encryptionKey: hexKey
|
|
1915
1949
|
});
|
|
1916
|
-
await ensureSchema();
|
|
1950
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1917
1951
|
try {
|
|
1918
1952
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1919
1953
|
initShardManager2(hexKey);
|
|
1920
1954
|
} catch {
|
|
1921
1955
|
}
|
|
1922
1956
|
const client = getClient();
|
|
1923
|
-
const vResult = await
|
|
1957
|
+
const vResult = await retryOnBusy2(
|
|
1958
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1959
|
+
"version-query"
|
|
1960
|
+
);
|
|
1924
1961
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1925
1962
|
}
|
|
1926
1963
|
function classifyTier(record) {
|
|
@@ -2139,6 +2176,15 @@ var LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
|
2139
2176
|
var CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
2140
2177
|
var DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
2141
2178
|
var API_BASE = "https://askexe.com/cloud";
|
|
2179
|
+
var RETRY_DELAY_MS = 500;
|
|
2180
|
+
async function fetchRetry(url, init) {
|
|
2181
|
+
try {
|
|
2182
|
+
return await fetch(url, init);
|
|
2183
|
+
} catch {
|
|
2184
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
2185
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2142
2188
|
var LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
2143
2189
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
2144
2190
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -2230,7 +2276,7 @@ function cacheResponse(token) {
|
|
|
2230
2276
|
async function validateLicense(apiKey, deviceId) {
|
|
2231
2277
|
const did = deviceId ?? loadDeviceId();
|
|
2232
2278
|
try {
|
|
2233
|
-
const res = await
|
|
2279
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2234
2280
|
method: "POST",
|
|
2235
2281
|
headers: { "Content-Type": "application/json" },
|
|
2236
2282
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -41,7 +41,7 @@ __export(config_exports, {
|
|
|
41
41
|
migrateConfig: () => migrateConfig,
|
|
42
42
|
saveConfig: () => saveConfig
|
|
43
43
|
});
|
|
44
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
44
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
45
45
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
46
46
|
import path from "path";
|
|
47
47
|
import os from "os";
|
|
@@ -167,6 +167,9 @@ async function saveConfig(config) {
|
|
|
167
167
|
await mkdir(dir, { recursive: true });
|
|
168
168
|
const configPath = path.join(dir, "config.json");
|
|
169
169
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
170
|
+
if (config.cloud?.apiKey) {
|
|
171
|
+
await chmod(configPath, 384);
|
|
172
|
+
}
|
|
170
173
|
}
|
|
171
174
|
async function loadConfigFrom(configPath) {
|
|
172
175
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -365,6 +368,7 @@ async function ensureSchema() {
|
|
|
365
368
|
const client = getRawClient();
|
|
366
369
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
367
370
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
371
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
368
372
|
try {
|
|
369
373
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
370
374
|
} catch {
|
|
@@ -1173,12 +1177,13 @@ var init_database = __esm({
|
|
|
1173
1177
|
});
|
|
1174
1178
|
|
|
1175
1179
|
// src/lib/keychain.ts
|
|
1176
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1180
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1177
1181
|
import { existsSync as existsSync2 } from "fs";
|
|
1178
1182
|
import path2 from "path";
|
|
1183
|
+
import os2 from "os";
|
|
1179
1184
|
import crypto from "crypto";
|
|
1180
1185
|
function getKeyDir() {
|
|
1181
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(
|
|
1186
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(os2.homedir(), ".exe-os");
|
|
1182
1187
|
}
|
|
1183
1188
|
function getKeyPath() {
|
|
1184
1189
|
return path2.join(getKeyDir(), "master.key");
|
|
@@ -1479,6 +1484,28 @@ __export(store_exports, {
|
|
|
1479
1484
|
vectorToBlob: () => vectorToBlob,
|
|
1480
1485
|
writeMemory: () => writeMemory
|
|
1481
1486
|
});
|
|
1487
|
+
function isBusyError2(err) {
|
|
1488
|
+
if (err instanceof Error) {
|
|
1489
|
+
const msg = err.message.toLowerCase();
|
|
1490
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1491
|
+
}
|
|
1492
|
+
return false;
|
|
1493
|
+
}
|
|
1494
|
+
async function retryOnBusy2(fn, label) {
|
|
1495
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1496
|
+
try {
|
|
1497
|
+
return await fn();
|
|
1498
|
+
} catch (err) {
|
|
1499
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1500
|
+
process.stderr.write(
|
|
1501
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1502
|
+
`
|
|
1503
|
+
);
|
|
1504
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
throw new Error("unreachable");
|
|
1508
|
+
}
|
|
1482
1509
|
async function initStore(options) {
|
|
1483
1510
|
if (_flushTimer !== null) {
|
|
1484
1511
|
clearInterval(_flushTimer);
|
|
@@ -1507,14 +1534,17 @@ async function initStore(options) {
|
|
|
1507
1534
|
dbPath,
|
|
1508
1535
|
encryptionKey: hexKey
|
|
1509
1536
|
});
|
|
1510
|
-
await ensureSchema();
|
|
1537
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1511
1538
|
try {
|
|
1512
1539
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1513
1540
|
initShardManager2(hexKey);
|
|
1514
1541
|
} catch {
|
|
1515
1542
|
}
|
|
1516
1543
|
const client = getClient();
|
|
1517
|
-
const vResult = await
|
|
1544
|
+
const vResult = await retryOnBusy2(
|
|
1545
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1546
|
+
"version-query"
|
|
1547
|
+
);
|
|
1518
1548
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1519
1549
|
}
|
|
1520
1550
|
function classifyTier(record) {
|
|
@@ -1894,7 +1924,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1894
1924
|
return 0;
|
|
1895
1925
|
}
|
|
1896
1926
|
}
|
|
1897
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1927
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1898
1928
|
var init_store = __esm({
|
|
1899
1929
|
"src/lib/store.ts"() {
|
|
1900
1930
|
"use strict";
|
|
@@ -1902,6 +1932,8 @@ var init_store = __esm({
|
|
|
1902
1932
|
init_database();
|
|
1903
1933
|
init_keychain();
|
|
1904
1934
|
init_config();
|
|
1935
|
+
INIT_MAX_RETRIES = 3;
|
|
1936
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1905
1937
|
_pendingRecords = [];
|
|
1906
1938
|
_batchSize = 20;
|
|
1907
1939
|
_flushIntervalMs = 1e4;
|
|
@@ -2009,6 +2041,10 @@ import path4 from "path";
|
|
|
2009
2041
|
import { fileURLToPath } from "url";
|
|
2010
2042
|
function handleData(chunk) {
|
|
2011
2043
|
_buffer += chunk.toString();
|
|
2044
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
2045
|
+
_buffer = "";
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2012
2048
|
let newlineIdx;
|
|
2013
2049
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
2014
2050
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2316,7 +2352,7 @@ function disconnectClient() {
|
|
|
2316
2352
|
entry.resolve({ error: "Client disconnected" });
|
|
2317
2353
|
}
|
|
2318
2354
|
}
|
|
2319
|
-
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;
|
|
2355
|
+
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;
|
|
2320
2356
|
var init_exe_daemon_client = __esm({
|
|
2321
2357
|
"src/lib/exe-daemon-client.ts"() {
|
|
2322
2358
|
"use strict";
|
|
@@ -2333,6 +2369,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2333
2369
|
_requestCount = 0;
|
|
2334
2370
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2335
2371
|
_pending = /* @__PURE__ */ new Map();
|
|
2372
|
+
MAX_BUFFER = 1e7;
|
|
2336
2373
|
}
|
|
2337
2374
|
});
|
|
2338
2375
|
|
|
@@ -2824,7 +2861,7 @@ var init_session_key = __esm({
|
|
|
2824
2861
|
// src/lib/session-registry.ts
|
|
2825
2862
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "fs";
|
|
2826
2863
|
import path9 from "path";
|
|
2827
|
-
import
|
|
2864
|
+
import os3 from "os";
|
|
2828
2865
|
function registerSession(entry) {
|
|
2829
2866
|
const dir = path9.dirname(REGISTRY_PATH);
|
|
2830
2867
|
if (!existsSync7(dir)) {
|
|
@@ -2851,7 +2888,7 @@ var REGISTRY_PATH;
|
|
|
2851
2888
|
var init_session_registry = __esm({
|
|
2852
2889
|
"src/lib/session-registry.ts"() {
|
|
2853
2890
|
"use strict";
|
|
2854
|
-
REGISTRY_PATH = path9.join(
|
|
2891
|
+
REGISTRY_PATH = path9.join(os3.homedir(), ".exe-os", "session-registry.json");
|
|
2855
2892
|
}
|
|
2856
2893
|
});
|
|
2857
2894
|
|
|
@@ -3053,7 +3090,7 @@ __export(intercom_queue_exports, {
|
|
|
3053
3090
|
});
|
|
3054
3091
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
3055
3092
|
import path10 from "path";
|
|
3056
|
-
import
|
|
3093
|
+
import os4 from "os";
|
|
3057
3094
|
function ensureDir() {
|
|
3058
3095
|
const dir = path10.dirname(QUEUE_PATH);
|
|
3059
3096
|
if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -3152,10 +3189,10 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
|
3152
3189
|
var init_intercom_queue = __esm({
|
|
3153
3190
|
"src/lib/intercom-queue.ts"() {
|
|
3154
3191
|
"use strict";
|
|
3155
|
-
QUEUE_PATH = path10.join(
|
|
3192
|
+
QUEUE_PATH = path10.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
3156
3193
|
MAX_RETRIES2 = 5;
|
|
3157
3194
|
TTL_MS = 60 * 60 * 1e3;
|
|
3158
|
-
INTERCOM_LOG = path10.join(
|
|
3195
|
+
INTERCOM_LOG = path10.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
3159
3196
|
}
|
|
3160
3197
|
});
|
|
3161
3198
|
|
|
@@ -3292,7 +3329,7 @@ var init_plan_limits = __esm({
|
|
|
3292
3329
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
3293
3330
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
3294
3331
|
import path14 from "path";
|
|
3295
|
-
import
|
|
3332
|
+
import os5 from "os";
|
|
3296
3333
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3297
3334
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
3298
3335
|
function spawnLockPath(sessionName) {
|
|
@@ -3564,7 +3601,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3564
3601
|
const transport = getTransport();
|
|
3565
3602
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3566
3603
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3567
|
-
const logDir = path14.join(
|
|
3604
|
+
const logDir = path14.join(os5.homedir(), ".exe-os", "session-logs");
|
|
3568
3605
|
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3569
3606
|
if (!existsSync12(logDir)) {
|
|
3570
3607
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -3580,7 +3617,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3580
3617
|
} catch {
|
|
3581
3618
|
}
|
|
3582
3619
|
try {
|
|
3583
|
-
const claudeJsonPath = path14.join(
|
|
3620
|
+
const claudeJsonPath = path14.join(os5.homedir(), ".claude.json");
|
|
3584
3621
|
let claudeJson = {};
|
|
3585
3622
|
try {
|
|
3586
3623
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3595,7 +3632,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3595
3632
|
} catch {
|
|
3596
3633
|
}
|
|
3597
3634
|
try {
|
|
3598
|
-
const settingsDir = path14.join(
|
|
3635
|
+
const settingsDir = path14.join(os5.homedir(), ".claude", "projects");
|
|
3599
3636
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3600
3637
|
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
3601
3638
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
@@ -3643,7 +3680,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3643
3680
|
let legacyFallbackWarned = false;
|
|
3644
3681
|
if (!useExeAgent && !useBinSymlink) {
|
|
3645
3682
|
const identityPath = path14.join(
|
|
3646
|
-
|
|
3683
|
+
os5.homedir(),
|
|
3647
3684
|
".exe-os",
|
|
3648
3685
|
"identity",
|
|
3649
3686
|
`${employeeName}.md`
|
|
@@ -3673,7 +3710,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3673
3710
|
}
|
|
3674
3711
|
let sessionContextFlag = "";
|
|
3675
3712
|
try {
|
|
3676
|
-
const ctxDir = path14.join(
|
|
3713
|
+
const ctxDir = path14.join(os5.homedir(), ".exe-os", "session-cache");
|
|
3677
3714
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3678
3715
|
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3679
3716
|
const ctxContent = [
|
|
@@ -3784,11 +3821,11 @@ var init_tmux_routing = __esm({
|
|
|
3784
3821
|
init_provider_table();
|
|
3785
3822
|
init_intercom_queue();
|
|
3786
3823
|
init_plan_limits();
|
|
3787
|
-
SPAWN_LOCK_DIR = path14.join(
|
|
3788
|
-
SESSION_CACHE = path14.join(
|
|
3824
|
+
SPAWN_LOCK_DIR = path14.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
3825
|
+
SESSION_CACHE = path14.join(os5.homedir(), ".exe-os", "session-cache");
|
|
3789
3826
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3790
3827
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3791
|
-
INTERCOM_LOG2 = path14.join(
|
|
3828
|
+
INTERCOM_LOG2 = path14.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
3792
3829
|
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3793
3830
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3794
3831
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4048,7 +4085,7 @@ var init_messaging = __esm({
|
|
|
4048
4085
|
// src/lib/notifications.ts
|
|
4049
4086
|
import crypto4 from "crypto";
|
|
4050
4087
|
import path15 from "path";
|
|
4051
|
-
import
|
|
4088
|
+
import os6 from "os";
|
|
4052
4089
|
import {
|
|
4053
4090
|
readFileSync as readFileSync11,
|
|
4054
4091
|
readdirSync as readdirSync4,
|
|
@@ -5011,10 +5048,11 @@ var timeout = setTimeout(() => {
|
|
|
5011
5048
|
process.exit(0);
|
|
5012
5049
|
}, 5e3);
|
|
5013
5050
|
timeout.unref();
|
|
5051
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
5014
5052
|
var input = "";
|
|
5015
5053
|
process.stdin.setEncoding("utf8");
|
|
5016
5054
|
process.stdin.on("data", (chunk) => {
|
|
5017
|
-
input += chunk;
|
|
5055
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
5018
5056
|
});
|
|
5019
5057
|
process.stdin.on("end", async () => {
|
|
5020
5058
|
try {
|
|
@@ -114,6 +114,7 @@ async function ensureSchema() {
|
|
|
114
114
|
const client = getRawClient();
|
|
115
115
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
116
116
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
117
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
117
118
|
try {
|
|
118
119
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
119
120
|
} catch {
|
|
@@ -929,15 +930,15 @@ __export(config_exports, {
|
|
|
929
930
|
migrateConfig: () => migrateConfig,
|
|
930
931
|
saveConfig: () => saveConfig
|
|
931
932
|
});
|
|
932
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
933
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
933
934
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
934
935
|
import path3 from "path";
|
|
935
|
-
import
|
|
936
|
+
import os2 from "os";
|
|
936
937
|
function resolveDataDir() {
|
|
937
938
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
938
939
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
939
|
-
const newDir = path3.join(
|
|
940
|
-
const legacyDir = path3.join(
|
|
940
|
+
const newDir = path3.join(os2.homedir(), ".exe-os");
|
|
941
|
+
const legacyDir = path3.join(os2.homedir(), ".exe-mem");
|
|
941
942
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
942
943
|
try {
|
|
943
944
|
renameSync(legacyDir, newDir);
|
|
@@ -1024,7 +1025,7 @@ async function loadConfig() {
|
|
|
1024
1025
|
normalizeAutoUpdate(migratedCfg);
|
|
1025
1026
|
const config = { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db"), ...migratedCfg };
|
|
1026
1027
|
if (config.dbPath.startsWith("~")) {
|
|
1027
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1028
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1028
1029
|
}
|
|
1029
1030
|
return config;
|
|
1030
1031
|
} catch {
|
|
@@ -1055,6 +1056,9 @@ async function saveConfig(config) {
|
|
|
1055
1056
|
await mkdir2(dir, { recursive: true });
|
|
1056
1057
|
const configPath = path3.join(dir, "config.json");
|
|
1057
1058
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1059
|
+
if (config.cloud?.apiKey) {
|
|
1060
|
+
await chmod2(configPath, 384);
|
|
1061
|
+
}
|
|
1058
1062
|
}
|
|
1059
1063
|
async function loadConfigFrom(configPath) {
|
|
1060
1064
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1406,6 +1410,10 @@ import path5 from "path";
|
|
|
1406
1410
|
import { fileURLToPath } from "url";
|
|
1407
1411
|
function handleData(chunk) {
|
|
1408
1412
|
_buffer += chunk.toString();
|
|
1413
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1414
|
+
_buffer = "";
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1409
1417
|
let newlineIdx;
|
|
1410
1418
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1411
1419
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1713,7 +1721,7 @@ function disconnectClient() {
|
|
|
1713
1721
|
entry.resolve({ error: "Client disconnected" });
|
|
1714
1722
|
}
|
|
1715
1723
|
}
|
|
1716
|
-
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;
|
|
1724
|
+
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;
|
|
1717
1725
|
var init_exe_daemon_client = __esm({
|
|
1718
1726
|
"src/lib/exe-daemon-client.ts"() {
|
|
1719
1727
|
"use strict";
|
|
@@ -1730,6 +1738,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1730
1738
|
_requestCount = 0;
|
|
1731
1739
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1732
1740
|
_pending = /* @__PURE__ */ new Map();
|
|
1741
|
+
MAX_BUFFER = 1e7;
|
|
1733
1742
|
}
|
|
1734
1743
|
});
|
|
1735
1744
|
|
|
@@ -1831,6 +1840,14 @@ import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync6
|
|
|
1831
1840
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1832
1841
|
import path7 from "path";
|
|
1833
1842
|
import { jwtVerify, importSPKI } from "jose";
|
|
1843
|
+
async function fetchRetry(url, init) {
|
|
1844
|
+
try {
|
|
1845
|
+
return await fetch(url, init);
|
|
1846
|
+
} catch {
|
|
1847
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
1848
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1834
1851
|
function loadDeviceId() {
|
|
1835
1852
|
const deviceJsonPath = path7.join(EXE_AI_DIR, "device.json");
|
|
1836
1853
|
try {
|
|
@@ -1901,7 +1918,7 @@ function cacheResponse(token) {
|
|
|
1901
1918
|
async function validateLicense(apiKey, deviceId) {
|
|
1902
1919
|
const did = deviceId ?? loadDeviceId();
|
|
1903
1920
|
try {
|
|
1904
|
-
const res = await
|
|
1921
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
1905
1922
|
method: "POST",
|
|
1906
1923
|
headers: { "Content-Type": "application/json" },
|
|
1907
1924
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -1966,7 +1983,7 @@ function isFeatureAllowed(license, feature) {
|
|
|
1966
1983
|
return license.plan === "team" || license.plan === "agency" || license.plan === "enterprise";
|
|
1967
1984
|
}
|
|
1968
1985
|
}
|
|
1969
|
-
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;
|
|
1986
|
+
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;
|
|
1970
1987
|
var init_license = __esm({
|
|
1971
1988
|
"src/lib/license.ts"() {
|
|
1972
1989
|
"use strict";
|
|
@@ -1975,6 +1992,7 @@ var init_license = __esm({
|
|
|
1975
1992
|
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
1976
1993
|
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1977
1994
|
API_BASE = "https://askexe.com/cloud";
|
|
1995
|
+
RETRY_DELAY_MS = 500;
|
|
1978
1996
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
1979
1997
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
1980
1998
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -2174,11 +2192,12 @@ init_database();
|
|
|
2174
2192
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
2175
2193
|
import { existsSync } from "fs";
|
|
2176
2194
|
import path2 from "path";
|
|
2195
|
+
import os from "os";
|
|
2177
2196
|
import crypto from "crypto";
|
|
2178
2197
|
var SERVICE = "exe-mem";
|
|
2179
2198
|
var ACCOUNT = "master-key";
|
|
2180
2199
|
function getKeyDir() {
|
|
2181
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(
|
|
2200
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(os.homedir(), ".exe-os");
|
|
2182
2201
|
}
|
|
2183
2202
|
function getKeyPath() {
|
|
2184
2203
|
return path2.join(getKeyDir(), "master.key");
|
|
@@ -2215,6 +2234,30 @@ async function getMasterKey() {
|
|
|
2215
2234
|
|
|
2216
2235
|
// src/lib/store.ts
|
|
2217
2236
|
init_config();
|
|
2237
|
+
var INIT_MAX_RETRIES = 3;
|
|
2238
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
2239
|
+
function isBusyError2(err) {
|
|
2240
|
+
if (err instanceof Error) {
|
|
2241
|
+
const msg = err.message.toLowerCase();
|
|
2242
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2243
|
+
}
|
|
2244
|
+
return false;
|
|
2245
|
+
}
|
|
2246
|
+
async function retryOnBusy2(fn, label) {
|
|
2247
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2248
|
+
try {
|
|
2249
|
+
return await fn();
|
|
2250
|
+
} catch (err) {
|
|
2251
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2252
|
+
process.stderr.write(
|
|
2253
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2254
|
+
`
|
|
2255
|
+
);
|
|
2256
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
throw new Error("unreachable");
|
|
2260
|
+
}
|
|
2218
2261
|
var _pendingRecords = [];
|
|
2219
2262
|
var _batchSize = 20;
|
|
2220
2263
|
var _flushIntervalMs = 1e4;
|
|
@@ -2249,14 +2292,17 @@ async function initStore(options) {
|
|
|
2249
2292
|
dbPath,
|
|
2250
2293
|
encryptionKey: hexKey
|
|
2251
2294
|
});
|
|
2252
|
-
await ensureSchema();
|
|
2295
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2253
2296
|
try {
|
|
2254
2297
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2255
2298
|
initShardManager2(hexKey);
|
|
2256
2299
|
} catch {
|
|
2257
2300
|
}
|
|
2258
2301
|
const client = getClient();
|
|
2259
|
-
const vResult = await
|
|
2302
|
+
const vResult = await retryOnBusy2(
|
|
2303
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2304
|
+
"version-query"
|
|
2305
|
+
);
|
|
2260
2306
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2261
2307
|
}
|
|
2262
2308
|
function classifyTier(record) {
|