@askexenow/exe-os 0.8.37 → 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 +112 -70
- package/dist/bin/backfill-responses.js +53 -18
- package/dist/bin/backfill-vectors.js +43 -16
- package/dist/bin/cleanup-stale-review-tasks.js +38 -16
- package/dist/bin/cli.js +790 -468
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +46 -13
- package/dist/bin/exe-boot.js +288 -129
- package/dist/bin/exe-call.js +20 -10
- package/dist/bin/exe-cloud.js +135 -30
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +38 -16
- package/dist/bin/exe-export-behaviors.js +43 -21
- package/dist/bin/exe-forget.js +39 -17
- package/dist/bin/exe-gateway.js +159 -50
- package/dist/bin/exe-heartbeat.js +53 -31
- package/dist/bin/exe-kill.js +40 -18
- package/dist/bin/exe-launch-agent.js +109 -36
- package/dist/bin/exe-link.js +196 -87
- package/dist/bin/exe-new-employee.js +56 -17
- package/dist/bin/exe-pending-messages.js +47 -25
- package/dist/bin/exe-pending-notifications.js +38 -16
- package/dist/bin/exe-pending-reviews.js +51 -29
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +41 -13
- package/dist/bin/exe-search.js +57 -21
- package/dist/bin/exe-session-cleanup.js +67 -31
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +35 -13
- package/dist/bin/exe-team.js +35 -13
- package/dist/bin/git-sweep.js +45 -17
- package/dist/bin/graph-backfill.js +38 -16
- package/dist/bin/graph-export.js +38 -16
- package/dist/bin/install.js +10 -1
- package/dist/bin/scan-tasks.js +47 -19
- package/dist/bin/setup.js +444 -259
- package/dist/bin/shard-migrate.js +38 -16
- package/dist/bin/wiki-sync.js +40 -17
- package/dist/gateway/index.js +113 -48
- package/dist/hooks/bug-report-worker.js +66 -39
- package/dist/hooks/commit-complete.js +45 -17
- package/dist/hooks/error-recall.js +60 -20
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +174 -45
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +46 -17
- package/dist/hooks/notification.js +44 -15
- package/dist/hooks/post-compact.js +44 -15
- package/dist/hooks/pre-compact.js +42 -14
- package/dist/hooks/pre-tool-use.js +59 -22
- package/dist/hooks/prompt-ingest-worker.js +75 -14
- package/dist/hooks/prompt-submit.js +75 -32
- package/dist/hooks/response-ingest-worker.js +76 -15
- package/dist/hooks/session-end.js +54 -22
- package/dist/hooks/session-start.js +57 -20
- package/dist/hooks/stop.js +44 -15
- package/dist/hooks/subagent-stop.js +44 -15
- package/dist/hooks/summary-worker.js +339 -106
- package/dist/index.js +94 -23
- package/dist/lib/cloud-sync.js +191 -80
- 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/employee-templates.js +5 -0
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +95 -36
- package/dist/lib/hybrid-search.js +57 -21
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +56 -6
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +38 -16
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +44 -16
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +280 -155
- 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 +36 -28
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +42 -8
- package/dist/tui/App.js +220 -99
- package/package.json +5 -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");
|
|
@@ -280,7 +283,7 @@ __export(shard_manager_exports, {
|
|
|
280
283
|
shardExists: () => shardExists
|
|
281
284
|
});
|
|
282
285
|
import path4 from "path";
|
|
283
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
286
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
284
287
|
import { createClient as createClient2 } from "@libsql/client";
|
|
285
288
|
function initShardManager(encryptionKey) {
|
|
286
289
|
_encryptionKey = encryptionKey;
|
|
@@ -319,7 +322,6 @@ function shardExists(projectName) {
|
|
|
319
322
|
}
|
|
320
323
|
function listShards() {
|
|
321
324
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
322
|
-
const { readdirSync } = __require("fs");
|
|
323
325
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
324
326
|
}
|
|
325
327
|
async function ensureShardSchema(client) {
|
|
@@ -517,6 +519,10 @@ import path8 from "path";
|
|
|
517
519
|
import { fileURLToPath } from "url";
|
|
518
520
|
function handleData(chunk) {
|
|
519
521
|
_buffer += chunk.toString();
|
|
522
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
523
|
+
_buffer = "";
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
520
526
|
let newlineIdx;
|
|
521
527
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
522
528
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -824,7 +830,7 @@ function disconnectClient() {
|
|
|
824
830
|
entry.resolve({ error: "Client disconnected" });
|
|
825
831
|
}
|
|
826
832
|
}
|
|
827
|
-
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;
|
|
828
834
|
var init_exe_daemon_client = __esm({
|
|
829
835
|
"src/lib/exe-daemon-client.ts"() {
|
|
830
836
|
"use strict";
|
|
@@ -841,6 +847,7 @@ var init_exe_daemon_client = __esm({
|
|
|
841
847
|
_requestCount = 0;
|
|
842
848
|
HEALTH_CHECK_INTERVAL = 100;
|
|
843
849
|
_pending = /* @__PURE__ */ new Map();
|
|
850
|
+
MAX_BUFFER = 1e7;
|
|
844
851
|
}
|
|
845
852
|
});
|
|
846
853
|
|
|
@@ -1046,6 +1053,7 @@ async function ensureSchema() {
|
|
|
1046
1053
|
const client = getRawClient();
|
|
1047
1054
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1048
1055
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1056
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
1049
1057
|
try {
|
|
1050
1058
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1051
1059
|
} catch {
|
|
@@ -1839,11 +1847,12 @@ async function ensureSchema() {
|
|
|
1839
1847
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1840
1848
|
import { existsSync } from "fs";
|
|
1841
1849
|
import path2 from "path";
|
|
1850
|
+
import os from "os";
|
|
1842
1851
|
import crypto from "crypto";
|
|
1843
1852
|
var SERVICE = "exe-mem";
|
|
1844
1853
|
var ACCOUNT = "master-key";
|
|
1845
1854
|
function getKeyDir() {
|
|
1846
|
-
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");
|
|
1847
1856
|
}
|
|
1848
1857
|
function getKeyPath() {
|
|
1849
1858
|
return path2.join(getKeyDir(), "master.key");
|
|
@@ -1880,6 +1889,30 @@ async function getMasterKey() {
|
|
|
1880
1889
|
|
|
1881
1890
|
// src/lib/store.ts
|
|
1882
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
|
+
}
|
|
1883
1916
|
var _pendingRecords = [];
|
|
1884
1917
|
var _batchSize = 20;
|
|
1885
1918
|
var _flushIntervalMs = 1e4;
|
|
@@ -1914,14 +1947,17 @@ async function initStore(options) {
|
|
|
1914
1947
|
dbPath,
|
|
1915
1948
|
encryptionKey: hexKey
|
|
1916
1949
|
});
|
|
1917
|
-
await ensureSchema();
|
|
1950
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1918
1951
|
try {
|
|
1919
1952
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1920
1953
|
initShardManager2(hexKey);
|
|
1921
1954
|
} catch {
|
|
1922
1955
|
}
|
|
1923
1956
|
const client = getClient();
|
|
1924
|
-
const vResult = await
|
|
1957
|
+
const vResult = await retryOnBusy2(
|
|
1958
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1959
|
+
"version-query"
|
|
1960
|
+
);
|
|
1925
1961
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1926
1962
|
}
|
|
1927
1963
|
function classifyTier(record) {
|
|
@@ -1964,6 +2000,12 @@ async function writeMemory(record) {
|
|
|
1964
2000
|
supersedes_id: record.supersedes_id ?? null
|
|
1965
2001
|
};
|
|
1966
2002
|
_pendingRecords.push(dbRow);
|
|
2003
|
+
const MAX_PENDING = 1e3;
|
|
2004
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
2005
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
2006
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
2007
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
2008
|
+
}
|
|
1967
2009
|
if (_flushTimer === null) {
|
|
1968
2010
|
_flushTimer = setInterval(() => {
|
|
1969
2011
|
void flushBatch();
|
|
@@ -2134,6 +2176,15 @@ var LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
|
2134
2176
|
var CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
2135
2177
|
var DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
2136
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
|
+
}
|
|
2137
2188
|
var LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
2138
2189
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
2139
2190
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -2225,7 +2276,7 @@ function cacheResponse(token) {
|
|
|
2225
2276
|
async function validateLicense(apiKey, deviceId) {
|
|
2226
2277
|
const did = deviceId ?? loadDeviceId();
|
|
2227
2278
|
try {
|
|
2228
|
-
const res = await
|
|
2279
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2229
2280
|
method: "POST",
|
|
2230
2281
|
headers: { "Content-Type": "application/json" },
|
|
2231
2282
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -2260,14 +2311,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
2260
2311
|
} catch {
|
|
2261
2312
|
const cached = await getCachedLicense();
|
|
2262
2313
|
if (cached) return cached;
|
|
2263
|
-
return FREE_LICENSE;
|
|
2314
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
2318
|
+
function getCacheAgeMs() {
|
|
2319
|
+
try {
|
|
2320
|
+
const { statSync: statSync2 } = __require("fs");
|
|
2321
|
+
const s = statSync2(CACHE_PATH);
|
|
2322
|
+
return Date.now() - s.mtimeMs;
|
|
2323
|
+
} catch {
|
|
2324
|
+
return Infinity;
|
|
2264
2325
|
}
|
|
2265
2326
|
}
|
|
2266
2327
|
async function checkLicense() {
|
|
2267
2328
|
const key = loadLicense();
|
|
2268
2329
|
if (!key) return FREE_LICENSE;
|
|
2269
2330
|
const cached = await getCachedLicense();
|
|
2270
|
-
if (cached) return cached;
|
|
2331
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
2271
2332
|
const deviceId = loadDeviceId();
|
|
2272
2333
|
return validateLicense(key, deviceId);
|
|
2273
2334
|
}
|
|
@@ -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");
|
|
@@ -1235,7 +1240,7 @@ __export(shard_manager_exports, {
|
|
|
1235
1240
|
shardExists: () => shardExists
|
|
1236
1241
|
});
|
|
1237
1242
|
import path3 from "path";
|
|
1238
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
1243
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
1239
1244
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1240
1245
|
function initShardManager(encryptionKey) {
|
|
1241
1246
|
_encryptionKey = encryptionKey;
|
|
@@ -1274,8 +1279,7 @@ function shardExists(projectName) {
|
|
|
1274
1279
|
}
|
|
1275
1280
|
function listShards() {
|
|
1276
1281
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1277
|
-
|
|
1278
|
-
return readdirSync5(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1282
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1279
1283
|
}
|
|
1280
1284
|
async function ensureShardSchema(client) {
|
|
1281
1285
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -1480,6 +1484,28 @@ __export(store_exports, {
|
|
|
1480
1484
|
vectorToBlob: () => vectorToBlob,
|
|
1481
1485
|
writeMemory: () => writeMemory
|
|
1482
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
|
+
}
|
|
1483
1509
|
async function initStore(options) {
|
|
1484
1510
|
if (_flushTimer !== null) {
|
|
1485
1511
|
clearInterval(_flushTimer);
|
|
@@ -1508,14 +1534,17 @@ async function initStore(options) {
|
|
|
1508
1534
|
dbPath,
|
|
1509
1535
|
encryptionKey: hexKey
|
|
1510
1536
|
});
|
|
1511
|
-
await ensureSchema();
|
|
1537
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1512
1538
|
try {
|
|
1513
1539
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1514
1540
|
initShardManager2(hexKey);
|
|
1515
1541
|
} catch {
|
|
1516
1542
|
}
|
|
1517
1543
|
const client = getClient();
|
|
1518
|
-
const vResult = await
|
|
1544
|
+
const vResult = await retryOnBusy2(
|
|
1545
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1546
|
+
"version-query"
|
|
1547
|
+
);
|
|
1519
1548
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1520
1549
|
}
|
|
1521
1550
|
function classifyTier(record) {
|
|
@@ -1558,6 +1587,12 @@ async function writeMemory(record) {
|
|
|
1558
1587
|
supersedes_id: record.supersedes_id ?? null
|
|
1559
1588
|
};
|
|
1560
1589
|
_pendingRecords.push(dbRow);
|
|
1590
|
+
const MAX_PENDING = 1e3;
|
|
1591
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1592
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1593
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1594
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1595
|
+
}
|
|
1561
1596
|
if (_flushTimer === null) {
|
|
1562
1597
|
_flushTimer = setInterval(() => {
|
|
1563
1598
|
void flushBatch();
|
|
@@ -1889,7 +1924,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1889
1924
|
return 0;
|
|
1890
1925
|
}
|
|
1891
1926
|
}
|
|
1892
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1927
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1893
1928
|
var init_store = __esm({
|
|
1894
1929
|
"src/lib/store.ts"() {
|
|
1895
1930
|
"use strict";
|
|
@@ -1897,6 +1932,8 @@ var init_store = __esm({
|
|
|
1897
1932
|
init_database();
|
|
1898
1933
|
init_keychain();
|
|
1899
1934
|
init_config();
|
|
1935
|
+
INIT_MAX_RETRIES = 3;
|
|
1936
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1900
1937
|
_pendingRecords = [];
|
|
1901
1938
|
_batchSize = 20;
|
|
1902
1939
|
_flushIntervalMs = 1e4;
|
|
@@ -2004,6 +2041,10 @@ import path4 from "path";
|
|
|
2004
2041
|
import { fileURLToPath } from "url";
|
|
2005
2042
|
function handleData(chunk) {
|
|
2006
2043
|
_buffer += chunk.toString();
|
|
2044
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
2045
|
+
_buffer = "";
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2007
2048
|
let newlineIdx;
|
|
2008
2049
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
2009
2050
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2311,7 +2352,7 @@ function disconnectClient() {
|
|
|
2311
2352
|
entry.resolve({ error: "Client disconnected" });
|
|
2312
2353
|
}
|
|
2313
2354
|
}
|
|
2314
|
-
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;
|
|
2315
2356
|
var init_exe_daemon_client = __esm({
|
|
2316
2357
|
"src/lib/exe-daemon-client.ts"() {
|
|
2317
2358
|
"use strict";
|
|
@@ -2328,6 +2369,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2328
2369
|
_requestCount = 0;
|
|
2329
2370
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2330
2371
|
_pending = /* @__PURE__ */ new Map();
|
|
2372
|
+
MAX_BUFFER = 1e7;
|
|
2331
2373
|
}
|
|
2332
2374
|
});
|
|
2333
2375
|
|
|
@@ -2456,7 +2498,7 @@ __export(file_grep_exports, {
|
|
|
2456
2498
|
grepProjectFiles: () => grepProjectFiles
|
|
2457
2499
|
});
|
|
2458
2500
|
import { execSync as execSync2 } from "child_process";
|
|
2459
|
-
import { readFileSync as readFileSync3, readdirSync, statSync as statSync2, existsSync as existsSync5 } from "fs";
|
|
2501
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync5 } from "fs";
|
|
2460
2502
|
import path6 from "path";
|
|
2461
2503
|
import crypto2 from "crypto";
|
|
2462
2504
|
function hasRipgrep() {
|
|
@@ -2601,7 +2643,7 @@ function collectFiles(root, patterns) {
|
|
|
2601
2643
|
const basename = path6.basename(dir);
|
|
2602
2644
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
2603
2645
|
try {
|
|
2604
|
-
const entries =
|
|
2646
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
2605
2647
|
for (const entry of entries) {
|
|
2606
2648
|
if (files.length >= MAX_FILES) return;
|
|
2607
2649
|
const rel = path6.join(relative, entry.name);
|
|
@@ -2819,7 +2861,7 @@ var init_session_key = __esm({
|
|
|
2819
2861
|
// src/lib/session-registry.ts
|
|
2820
2862
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "fs";
|
|
2821
2863
|
import path9 from "path";
|
|
2822
|
-
import
|
|
2864
|
+
import os3 from "os";
|
|
2823
2865
|
function registerSession(entry) {
|
|
2824
2866
|
const dir = path9.dirname(REGISTRY_PATH);
|
|
2825
2867
|
if (!existsSync7(dir)) {
|
|
@@ -2846,7 +2888,7 @@ var REGISTRY_PATH;
|
|
|
2846
2888
|
var init_session_registry = __esm({
|
|
2847
2889
|
"src/lib/session-registry.ts"() {
|
|
2848
2890
|
"use strict";
|
|
2849
|
-
REGISTRY_PATH = path9.join(
|
|
2891
|
+
REGISTRY_PATH = path9.join(os3.homedir(), ".exe-os", "session-registry.json");
|
|
2850
2892
|
}
|
|
2851
2893
|
});
|
|
2852
2894
|
|
|
@@ -3048,7 +3090,7 @@ __export(intercom_queue_exports, {
|
|
|
3048
3090
|
});
|
|
3049
3091
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
3050
3092
|
import path10 from "path";
|
|
3051
|
-
import
|
|
3093
|
+
import os4 from "os";
|
|
3052
3094
|
function ensureDir() {
|
|
3053
3095
|
const dir = path10.dirname(QUEUE_PATH);
|
|
3054
3096
|
if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -3147,10 +3189,10 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
|
3147
3189
|
var init_intercom_queue = __esm({
|
|
3148
3190
|
"src/lib/intercom-queue.ts"() {
|
|
3149
3191
|
"use strict";
|
|
3150
|
-
QUEUE_PATH = path10.join(
|
|
3192
|
+
QUEUE_PATH = path10.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
3151
3193
|
MAX_RETRIES2 = 5;
|
|
3152
3194
|
TTL_MS = 60 * 60 * 1e3;
|
|
3153
|
-
INTERCOM_LOG = path10.join(
|
|
3195
|
+
INTERCOM_LOG = path10.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
3154
3196
|
}
|
|
3155
3197
|
});
|
|
3156
3198
|
|
|
@@ -3287,7 +3329,7 @@ var init_plan_limits = __esm({
|
|
|
3287
3329
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
3288
3330
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
3289
3331
|
import path14 from "path";
|
|
3290
|
-
import
|
|
3332
|
+
import os5 from "os";
|
|
3291
3333
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3292
3334
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
3293
3335
|
function spawnLockPath(sessionName) {
|
|
@@ -3559,7 +3601,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3559
3601
|
const transport = getTransport();
|
|
3560
3602
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3561
3603
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3562
|
-
const logDir = path14.join(
|
|
3604
|
+
const logDir = path14.join(os5.homedir(), ".exe-os", "session-logs");
|
|
3563
3605
|
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3564
3606
|
if (!existsSync12(logDir)) {
|
|
3565
3607
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -3575,7 +3617,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3575
3617
|
} catch {
|
|
3576
3618
|
}
|
|
3577
3619
|
try {
|
|
3578
|
-
const claudeJsonPath = path14.join(
|
|
3620
|
+
const claudeJsonPath = path14.join(os5.homedir(), ".claude.json");
|
|
3579
3621
|
let claudeJson = {};
|
|
3580
3622
|
try {
|
|
3581
3623
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3590,7 +3632,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3590
3632
|
} catch {
|
|
3591
3633
|
}
|
|
3592
3634
|
try {
|
|
3593
|
-
const settingsDir = path14.join(
|
|
3635
|
+
const settingsDir = path14.join(os5.homedir(), ".claude", "projects");
|
|
3594
3636
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3595
3637
|
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
3596
3638
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
@@ -3638,7 +3680,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3638
3680
|
let legacyFallbackWarned = false;
|
|
3639
3681
|
if (!useExeAgent && !useBinSymlink) {
|
|
3640
3682
|
const identityPath = path14.join(
|
|
3641
|
-
|
|
3683
|
+
os5.homedir(),
|
|
3642
3684
|
".exe-os",
|
|
3643
3685
|
"identity",
|
|
3644
3686
|
`${employeeName}.md`
|
|
@@ -3668,7 +3710,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3668
3710
|
}
|
|
3669
3711
|
let sessionContextFlag = "";
|
|
3670
3712
|
try {
|
|
3671
|
-
const ctxDir = path14.join(
|
|
3713
|
+
const ctxDir = path14.join(os5.homedir(), ".exe-os", "session-cache");
|
|
3672
3714
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3673
3715
|
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3674
3716
|
const ctxContent = [
|
|
@@ -3779,11 +3821,11 @@ var init_tmux_routing = __esm({
|
|
|
3779
3821
|
init_provider_table();
|
|
3780
3822
|
init_intercom_queue();
|
|
3781
3823
|
init_plan_limits();
|
|
3782
|
-
SPAWN_LOCK_DIR = path14.join(
|
|
3783
|
-
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");
|
|
3784
3826
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3785
3827
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3786
|
-
INTERCOM_LOG2 = path14.join(
|
|
3828
|
+
INTERCOM_LOG2 = path14.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
3787
3829
|
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3788
3830
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3789
3831
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4043,10 +4085,10 @@ var init_messaging = __esm({
|
|
|
4043
4085
|
// src/lib/notifications.ts
|
|
4044
4086
|
import crypto4 from "crypto";
|
|
4045
4087
|
import path15 from "path";
|
|
4046
|
-
import
|
|
4088
|
+
import os6 from "os";
|
|
4047
4089
|
import {
|
|
4048
4090
|
readFileSync as readFileSync11,
|
|
4049
|
-
readdirSync as
|
|
4091
|
+
readdirSync as readdirSync4,
|
|
4050
4092
|
unlinkSync as unlinkSync4,
|
|
4051
4093
|
existsSync as existsSync13,
|
|
4052
4094
|
rmdirSync
|
|
@@ -4304,7 +4346,7 @@ __export(tasks_review_exports, {
|
|
|
4304
4346
|
listPendingReviews: () => listPendingReviews
|
|
4305
4347
|
});
|
|
4306
4348
|
import path17 from "path";
|
|
4307
|
-
import { existsSync as existsSync15, readdirSync as
|
|
4349
|
+
import { existsSync as existsSync15, readdirSync as readdirSync5, unlinkSync as unlinkSync5 } from "fs";
|
|
4308
4350
|
async function countPendingReviews() {
|
|
4309
4351
|
const client = getClient();
|
|
4310
4352
|
const result = await client.execute({
|
|
@@ -4516,7 +4558,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
4516
4558
|
try {
|
|
4517
4559
|
const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
|
|
4518
4560
|
if (existsSync15(cacheDir)) {
|
|
4519
|
-
for (const f of
|
|
4561
|
+
for (const f of readdirSync5(cacheDir)) {
|
|
4520
4562
|
if (f.startsWith("review-notified-")) {
|
|
4521
4563
|
unlinkSync5(path17.join(cacheDir, f));
|
|
4522
4564
|
}
|
|
@@ -4906,7 +4948,7 @@ async function recentRecords(agentId, options, limit) {
|
|
|
4906
4948
|
|
|
4907
4949
|
// src/adapters/claude/active-agent.ts
|
|
4908
4950
|
init_config();
|
|
4909
|
-
import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as
|
|
4951
|
+
import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as readdirSync3 } from "fs";
|
|
4910
4952
|
import { execSync as execSync4 } from "child_process";
|
|
4911
4953
|
import path8 from "path";
|
|
4912
4954
|
|
|
@@ -5006,10 +5048,11 @@ var timeout = setTimeout(() => {
|
|
|
5006
5048
|
process.exit(0);
|
|
5007
5049
|
}, 5e3);
|
|
5008
5050
|
timeout.unref();
|
|
5051
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
5009
5052
|
var input = "";
|
|
5010
5053
|
process.stdin.setEncoding("utf8");
|
|
5011
5054
|
process.stdin.on("data", (chunk) => {
|
|
5012
|
-
input += chunk;
|
|
5055
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
5013
5056
|
});
|
|
5014
5057
|
process.stdin.on("end", async () => {
|
|
5015
5058
|
try {
|