@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
|
@@ -107,6 +107,7 @@ async function ensureSchema() {
|
|
|
107
107
|
const client = getRawClient();
|
|
108
108
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
109
109
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
110
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
110
111
|
try {
|
|
111
112
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
112
113
|
} catch {
|
|
@@ -907,15 +908,15 @@ var init_database = __esm({
|
|
|
907
908
|
});
|
|
908
909
|
|
|
909
910
|
// src/lib/config.ts
|
|
910
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
911
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
911
912
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
912
913
|
import path2 from "path";
|
|
913
|
-
import
|
|
914
|
+
import os2 from "os";
|
|
914
915
|
function resolveDataDir() {
|
|
915
916
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
916
917
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
917
|
-
const newDir = path2.join(
|
|
918
|
-
const legacyDir = path2.join(
|
|
918
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
919
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
919
920
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
920
921
|
try {
|
|
921
922
|
renameSync(legacyDir, newDir);
|
|
@@ -1002,7 +1003,7 @@ async function loadConfig() {
|
|
|
1002
1003
|
normalizeAutoUpdate(migratedCfg);
|
|
1003
1004
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1004
1005
|
if (config.dbPath.startsWith("~")) {
|
|
1005
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1006
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1006
1007
|
}
|
|
1007
1008
|
return config;
|
|
1008
1009
|
} catch {
|
|
@@ -1339,7 +1340,7 @@ var init_shard_manager = __esm({
|
|
|
1339
1340
|
// src/lib/notifications.ts
|
|
1340
1341
|
import crypto2 from "crypto";
|
|
1341
1342
|
import path4 from "path";
|
|
1342
|
-
import
|
|
1343
|
+
import os3 from "os";
|
|
1343
1344
|
import {
|
|
1344
1345
|
readFileSync as readFileSync2,
|
|
1345
1346
|
readdirSync as readdirSync2,
|
|
@@ -1652,15 +1653,20 @@ function addEmployee(employees, employee) {
|
|
|
1652
1653
|
}
|
|
1653
1654
|
return [...employees, normalized];
|
|
1654
1655
|
}
|
|
1656
|
+
function findExeBin() {
|
|
1657
|
+
try {
|
|
1658
|
+
return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
1659
|
+
} catch {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1655
1663
|
function registerBinSymlinks(name) {
|
|
1656
1664
|
const created = [];
|
|
1657
1665
|
const skipped = [];
|
|
1658
1666
|
const errors = [];
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
} catch {
|
|
1663
|
-
errors.push("Could not find 'exe' in PATH");
|
|
1667
|
+
const exeBinPath = findExeBin();
|
|
1668
|
+
if (!exeBinPath) {
|
|
1669
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
1664
1670
|
return { created, skipped, errors };
|
|
1665
1671
|
}
|
|
1666
1672
|
const binDir = path6.dirname(exeBinPath);
|
|
@@ -1700,7 +1706,7 @@ var init_employees = __esm({
|
|
|
1700
1706
|
// src/lib/session-registry.ts
|
|
1701
1707
|
import { readFileSync as readFileSync5, writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync7 } from "fs";
|
|
1702
1708
|
import path7 from "path";
|
|
1703
|
-
import
|
|
1709
|
+
import os4 from "os";
|
|
1704
1710
|
function registerSession(entry) {
|
|
1705
1711
|
const dir = path7.dirname(REGISTRY_PATH);
|
|
1706
1712
|
if (!existsSync7(dir)) {
|
|
@@ -1727,7 +1733,7 @@ var REGISTRY_PATH;
|
|
|
1727
1733
|
var init_session_registry = __esm({
|
|
1728
1734
|
"src/lib/session-registry.ts"() {
|
|
1729
1735
|
"use strict";
|
|
1730
|
-
REGISTRY_PATH = path7.join(
|
|
1736
|
+
REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
1731
1737
|
}
|
|
1732
1738
|
});
|
|
1733
1739
|
|
|
@@ -1949,7 +1955,7 @@ var init_provider_table = __esm({
|
|
|
1949
1955
|
// src/lib/intercom-queue.ts
|
|
1950
1956
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
|
|
1951
1957
|
import path8 from "path";
|
|
1952
|
-
import
|
|
1958
|
+
import os5 from "os";
|
|
1953
1959
|
function ensureDir() {
|
|
1954
1960
|
const dir = path8.dirname(QUEUE_PATH);
|
|
1955
1961
|
if (!existsSync8(dir)) mkdirSync3(dir, { recursive: true });
|
|
@@ -1989,9 +1995,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
1989
1995
|
var init_intercom_queue = __esm({
|
|
1990
1996
|
"src/lib/intercom-queue.ts"() {
|
|
1991
1997
|
"use strict";
|
|
1992
|
-
QUEUE_PATH = path8.join(
|
|
1998
|
+
QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
1993
1999
|
TTL_MS = 60 * 60 * 1e3;
|
|
1994
|
-
INTERCOM_LOG = path8.join(
|
|
2000
|
+
INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1995
2001
|
}
|
|
1996
2002
|
});
|
|
1997
2003
|
|
|
@@ -2100,7 +2106,7 @@ var init_plan_limits = __esm({
|
|
|
2100
2106
|
import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
|
|
2101
2107
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2102
2108
|
import path11 from "path";
|
|
2103
|
-
import
|
|
2109
|
+
import os6 from "os";
|
|
2104
2110
|
import { fileURLToPath } from "url";
|
|
2105
2111
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
2106
2112
|
function spawnLockPath(sessionName) {
|
|
@@ -2372,7 +2378,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2372
2378
|
const transport = getTransport();
|
|
2373
2379
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
2374
2380
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
2375
|
-
const logDir = path11.join(
|
|
2381
|
+
const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
|
|
2376
2382
|
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
2377
2383
|
if (!existsSync11(logDir)) {
|
|
2378
2384
|
mkdirSync5(logDir, { recursive: true });
|
|
@@ -2388,7 +2394,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2388
2394
|
} catch {
|
|
2389
2395
|
}
|
|
2390
2396
|
try {
|
|
2391
|
-
const claudeJsonPath = path11.join(
|
|
2397
|
+
const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
|
|
2392
2398
|
let claudeJson = {};
|
|
2393
2399
|
try {
|
|
2394
2400
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -2403,7 +2409,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2403
2409
|
} catch {
|
|
2404
2410
|
}
|
|
2405
2411
|
try {
|
|
2406
|
-
const settingsDir = path11.join(
|
|
2412
|
+
const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
|
|
2407
2413
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
2408
2414
|
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
2409
2415
|
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
@@ -2451,7 +2457,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2451
2457
|
let legacyFallbackWarned = false;
|
|
2452
2458
|
if (!useExeAgent && !useBinSymlink) {
|
|
2453
2459
|
const identityPath = path11.join(
|
|
2454
|
-
|
|
2460
|
+
os6.homedir(),
|
|
2455
2461
|
".exe-os",
|
|
2456
2462
|
"identity",
|
|
2457
2463
|
`${employeeName}.md`
|
|
@@ -2481,7 +2487,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2481
2487
|
}
|
|
2482
2488
|
let sessionContextFlag = "";
|
|
2483
2489
|
try {
|
|
2484
|
-
const ctxDir = path11.join(
|
|
2490
|
+
const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2485
2491
|
mkdirSync5(ctxDir, { recursive: true });
|
|
2486
2492
|
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
2487
2493
|
const ctxContent = [
|
|
@@ -2592,11 +2598,11 @@ var init_tmux_routing = __esm({
|
|
|
2592
2598
|
init_provider_table();
|
|
2593
2599
|
init_intercom_queue();
|
|
2594
2600
|
init_plan_limits();
|
|
2595
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
2596
|
-
SESSION_CACHE = path11.join(
|
|
2601
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
2602
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2597
2603
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
2598
2604
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2599
|
-
INTERCOM_LOG2 = path11.join(
|
|
2605
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2600
2606
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2601
2607
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2602
2608
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -2825,11 +2831,12 @@ init_database();
|
|
|
2825
2831
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
2826
2832
|
import { existsSync } from "fs";
|
|
2827
2833
|
import path from "path";
|
|
2834
|
+
import os from "os";
|
|
2828
2835
|
import crypto from "crypto";
|
|
2829
2836
|
var SERVICE = "exe-mem";
|
|
2830
2837
|
var ACCOUNT = "master-key";
|
|
2831
2838
|
function getKeyDir() {
|
|
2832
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
2839
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
2833
2840
|
}
|
|
2834
2841
|
function getKeyPath() {
|
|
2835
2842
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -2866,6 +2873,30 @@ async function getMasterKey() {
|
|
|
2866
2873
|
|
|
2867
2874
|
// src/lib/store.ts
|
|
2868
2875
|
init_config();
|
|
2876
|
+
var INIT_MAX_RETRIES = 3;
|
|
2877
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
2878
|
+
function isBusyError2(err) {
|
|
2879
|
+
if (err instanceof Error) {
|
|
2880
|
+
const msg = err.message.toLowerCase();
|
|
2881
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2882
|
+
}
|
|
2883
|
+
return false;
|
|
2884
|
+
}
|
|
2885
|
+
async function retryOnBusy2(fn, label) {
|
|
2886
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2887
|
+
try {
|
|
2888
|
+
return await fn();
|
|
2889
|
+
} catch (err) {
|
|
2890
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2891
|
+
process.stderr.write(
|
|
2892
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2893
|
+
`
|
|
2894
|
+
);
|
|
2895
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
throw new Error("unreachable");
|
|
2899
|
+
}
|
|
2869
2900
|
var _pendingRecords = [];
|
|
2870
2901
|
var _batchSize = 20;
|
|
2871
2902
|
var _flushIntervalMs = 1e4;
|
|
@@ -2900,14 +2931,17 @@ async function initStore(options) {
|
|
|
2900
2931
|
dbPath,
|
|
2901
2932
|
encryptionKey: hexKey
|
|
2902
2933
|
});
|
|
2903
|
-
await ensureSchema();
|
|
2934
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2904
2935
|
try {
|
|
2905
2936
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2906
2937
|
initShardManager2(hexKey);
|
|
2907
2938
|
} catch {
|
|
2908
2939
|
}
|
|
2909
2940
|
const client = getClient();
|
|
2910
|
-
const vResult = await
|
|
2941
|
+
const vResult = await retryOnBusy2(
|
|
2942
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2943
|
+
"version-query"
|
|
2944
|
+
);
|
|
2911
2945
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2912
2946
|
}
|
|
2913
2947
|
|
|
@@ -119,6 +119,7 @@ async function ensureSchema() {
|
|
|
119
119
|
const client = getRawClient();
|
|
120
120
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
121
121
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
122
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
122
123
|
try {
|
|
123
124
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
124
125
|
} catch {
|
|
@@ -930,9 +931,10 @@ var init_database = __esm({
|
|
|
930
931
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
931
932
|
import { existsSync } from "fs";
|
|
932
933
|
import path from "path";
|
|
934
|
+
import os from "os";
|
|
933
935
|
import crypto from "crypto";
|
|
934
936
|
function getKeyDir() {
|
|
935
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
937
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
936
938
|
}
|
|
937
939
|
function getKeyPath() {
|
|
938
940
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -976,15 +978,15 @@ var init_keychain = __esm({
|
|
|
976
978
|
});
|
|
977
979
|
|
|
978
980
|
// src/lib/config.ts
|
|
979
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
981
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
980
982
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
981
983
|
import path2 from "path";
|
|
982
|
-
import
|
|
984
|
+
import os2 from "os";
|
|
983
985
|
function resolveDataDir() {
|
|
984
986
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
985
987
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
986
|
-
const newDir = path2.join(
|
|
987
|
-
const legacyDir = path2.join(
|
|
988
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
989
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
988
990
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
989
991
|
try {
|
|
990
992
|
renameSync(legacyDir, newDir);
|
|
@@ -1071,7 +1073,7 @@ async function loadConfig() {
|
|
|
1071
1073
|
normalizeAutoUpdate(migratedCfg);
|
|
1072
1074
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1073
1075
|
if (config.dbPath.startsWith("~")) {
|
|
1074
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1076
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1075
1077
|
}
|
|
1076
1078
|
return config;
|
|
1077
1079
|
} catch {
|
|
@@ -1422,6 +1424,28 @@ __export(store_exports, {
|
|
|
1422
1424
|
vectorToBlob: () => vectorToBlob,
|
|
1423
1425
|
writeMemory: () => writeMemory
|
|
1424
1426
|
});
|
|
1427
|
+
function isBusyError2(err) {
|
|
1428
|
+
if (err instanceof Error) {
|
|
1429
|
+
const msg = err.message.toLowerCase();
|
|
1430
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1431
|
+
}
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
async function retryOnBusy2(fn, label) {
|
|
1435
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1436
|
+
try {
|
|
1437
|
+
return await fn();
|
|
1438
|
+
} catch (err) {
|
|
1439
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1440
|
+
process.stderr.write(
|
|
1441
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1442
|
+
`
|
|
1443
|
+
);
|
|
1444
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
throw new Error("unreachable");
|
|
1448
|
+
}
|
|
1425
1449
|
async function initStore(options) {
|
|
1426
1450
|
if (_flushTimer !== null) {
|
|
1427
1451
|
clearInterval(_flushTimer);
|
|
@@ -1450,14 +1474,17 @@ async function initStore(options) {
|
|
|
1450
1474
|
dbPath,
|
|
1451
1475
|
encryptionKey: hexKey
|
|
1452
1476
|
});
|
|
1453
|
-
await ensureSchema();
|
|
1477
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1454
1478
|
try {
|
|
1455
1479
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1456
1480
|
initShardManager2(hexKey);
|
|
1457
1481
|
} catch {
|
|
1458
1482
|
}
|
|
1459
1483
|
const client = getClient();
|
|
1460
|
-
const vResult = await
|
|
1484
|
+
const vResult = await retryOnBusy2(
|
|
1485
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1486
|
+
"version-query"
|
|
1487
|
+
);
|
|
1461
1488
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1462
1489
|
}
|
|
1463
1490
|
function classifyTier(record) {
|
|
@@ -1837,7 +1864,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1837
1864
|
return 0;
|
|
1838
1865
|
}
|
|
1839
1866
|
}
|
|
1840
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1867
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1841
1868
|
var init_store = __esm({
|
|
1842
1869
|
"src/lib/store.ts"() {
|
|
1843
1870
|
"use strict";
|
|
@@ -1845,6 +1872,8 @@ var init_store = __esm({
|
|
|
1845
1872
|
init_database();
|
|
1846
1873
|
init_keychain();
|
|
1847
1874
|
init_config();
|
|
1875
|
+
INIT_MAX_RETRIES = 3;
|
|
1876
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1848
1877
|
_pendingRecords = [];
|
|
1849
1878
|
_batchSize = 20;
|
|
1850
1879
|
_flushIntervalMs = 1e4;
|
|
@@ -24,7 +24,7 @@ __export(config_exports, {
|
|
|
24
24
|
migrateConfig: () => migrateConfig,
|
|
25
25
|
saveConfig: () => saveConfig
|
|
26
26
|
});
|
|
27
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
27
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
28
28
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import os from "os";
|
|
@@ -150,6 +150,9 @@ async function saveConfig(config) {
|
|
|
150
150
|
await mkdir(dir, { recursive: true });
|
|
151
151
|
const configPath = path.join(dir, "config.json");
|
|
152
152
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
153
|
+
if (config.cloud?.apiKey) {
|
|
154
|
+
await chmod(configPath, 384);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
async function loadConfigFrom(configPath) {
|
|
155
158
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -348,6 +351,7 @@ async function ensureSchema() {
|
|
|
348
351
|
const client = getRawClient();
|
|
349
352
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
350
353
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
354
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
351
355
|
try {
|
|
352
356
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
353
357
|
} catch {
|
|
@@ -1156,12 +1160,13 @@ var init_database = __esm({
|
|
|
1156
1160
|
});
|
|
1157
1161
|
|
|
1158
1162
|
// src/lib/keychain.ts
|
|
1159
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1163
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1160
1164
|
import { existsSync as existsSync2 } from "fs";
|
|
1161
1165
|
import path2 from "path";
|
|
1166
|
+
import os2 from "os";
|
|
1162
1167
|
import crypto2 from "crypto";
|
|
1163
1168
|
function getKeyDir() {
|
|
1164
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(
|
|
1169
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(os2.homedir(), ".exe-os");
|
|
1165
1170
|
}
|
|
1166
1171
|
function getKeyPath() {
|
|
1167
1172
|
return path2.join(getKeyDir(), "master.key");
|
|
@@ -1462,6 +1467,28 @@ __export(store_exports, {
|
|
|
1462
1467
|
vectorToBlob: () => vectorToBlob,
|
|
1463
1468
|
writeMemory: () => writeMemory
|
|
1464
1469
|
});
|
|
1470
|
+
function isBusyError2(err) {
|
|
1471
|
+
if (err instanceof Error) {
|
|
1472
|
+
const msg = err.message.toLowerCase();
|
|
1473
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1474
|
+
}
|
|
1475
|
+
return false;
|
|
1476
|
+
}
|
|
1477
|
+
async function retryOnBusy2(fn, label) {
|
|
1478
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1479
|
+
try {
|
|
1480
|
+
return await fn();
|
|
1481
|
+
} catch (err) {
|
|
1482
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1483
|
+
process.stderr.write(
|
|
1484
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1485
|
+
`
|
|
1486
|
+
);
|
|
1487
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
throw new Error("unreachable");
|
|
1491
|
+
}
|
|
1465
1492
|
async function initStore(options) {
|
|
1466
1493
|
if (_flushTimer !== null) {
|
|
1467
1494
|
clearInterval(_flushTimer);
|
|
@@ -1490,14 +1517,17 @@ async function initStore(options) {
|
|
|
1490
1517
|
dbPath,
|
|
1491
1518
|
encryptionKey: hexKey
|
|
1492
1519
|
});
|
|
1493
|
-
await ensureSchema();
|
|
1520
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1494
1521
|
try {
|
|
1495
1522
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1496
1523
|
initShardManager2(hexKey);
|
|
1497
1524
|
} catch {
|
|
1498
1525
|
}
|
|
1499
1526
|
const client = getClient();
|
|
1500
|
-
const vResult = await
|
|
1527
|
+
const vResult = await retryOnBusy2(
|
|
1528
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1529
|
+
"version-query"
|
|
1530
|
+
);
|
|
1501
1531
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1502
1532
|
}
|
|
1503
1533
|
function classifyTier(record) {
|
|
@@ -1877,7 +1907,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
1877
1907
|
return 0;
|
|
1878
1908
|
}
|
|
1879
1909
|
}
|
|
1880
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1910
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1881
1911
|
var init_store = __esm({
|
|
1882
1912
|
"src/lib/store.ts"() {
|
|
1883
1913
|
"use strict";
|
|
@@ -1885,6 +1915,8 @@ var init_store = __esm({
|
|
|
1885
1915
|
init_database();
|
|
1886
1916
|
init_keychain();
|
|
1887
1917
|
init_config();
|
|
1918
|
+
INIT_MAX_RETRIES = 3;
|
|
1919
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1888
1920
|
_pendingRecords = [];
|
|
1889
1921
|
_batchSize = 20;
|
|
1890
1922
|
_flushIntervalMs = 1e4;
|
|
@@ -1992,6 +2024,10 @@ import path4 from "path";
|
|
|
1992
2024
|
import { fileURLToPath } from "url";
|
|
1993
2025
|
function handleData(chunk) {
|
|
1994
2026
|
_buffer += chunk.toString();
|
|
2027
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
2028
|
+
_buffer = "";
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
1995
2031
|
let newlineIdx;
|
|
1996
2032
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1997
2033
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2299,7 +2335,7 @@ function disconnectClient() {
|
|
|
2299
2335
|
entry.resolve({ error: "Client disconnected" });
|
|
2300
2336
|
}
|
|
2301
2337
|
}
|
|
2302
|
-
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;
|
|
2338
|
+
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;
|
|
2303
2339
|
var init_exe_daemon_client = __esm({
|
|
2304
2340
|
"src/lib/exe-daemon-client.ts"() {
|
|
2305
2341
|
"use strict";
|
|
@@ -2316,6 +2352,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2316
2352
|
_requestCount = 0;
|
|
2317
2353
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2318
2354
|
_pending = /* @__PURE__ */ new Map();
|
|
2355
|
+
MAX_BUFFER = 1e7;
|
|
2319
2356
|
}
|
|
2320
2357
|
});
|
|
2321
2358
|
|
|
@@ -3340,13 +3377,17 @@ var timeout = setTimeout(() => {
|
|
|
3340
3377
|
process.exit(0);
|
|
3341
3378
|
}, 5e3);
|
|
3342
3379
|
timeout.unref();
|
|
3380
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
3343
3381
|
var input = "";
|
|
3344
3382
|
process.stdin.setEncoding("utf8");
|
|
3345
3383
|
process.stdin.on("data", (chunk) => {
|
|
3346
|
-
input += chunk;
|
|
3384
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
3347
3385
|
});
|
|
3348
3386
|
process.stdin.on("end", async () => {
|
|
3349
3387
|
try {
|
|
3388
|
+
if (input.length >= MAX_INPUT_SIZE) {
|
|
3389
|
+
process.exit(0);
|
|
3390
|
+
}
|
|
3350
3391
|
const data = JSON.parse(input);
|
|
3351
3392
|
if (!detectError(data)) {
|
|
3352
3393
|
process.exit(0);
|
|
@@ -9,7 +9,7 @@ import { execSync as execSync2 } from "child_process";
|
|
|
9
9
|
import path2 from "path";
|
|
10
10
|
|
|
11
11
|
// src/lib/config.ts
|
|
12
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
12
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
13
13
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
14
14
|
import path from "path";
|
|
15
15
|
import os from "os";
|
|
@@ -188,10 +188,11 @@ var CLI_TIMEOUT_MS = 4e3;
|
|
|
188
188
|
var EXE_AGENT_ID = "exe";
|
|
189
189
|
var watchdog = setTimeout(() => process.exit(0), HOOK_TIMEOUT_MS);
|
|
190
190
|
watchdog.unref();
|
|
191
|
+
var MAX_INPUT_SIZE = 1e6;
|
|
191
192
|
var input = "";
|
|
192
193
|
process.stdin.setEncoding("utf8");
|
|
193
194
|
process.stdin.on("data", (chunk) => {
|
|
194
|
-
input += chunk;
|
|
195
|
+
if (input.length < MAX_INPUT_SIZE) input += chunk;
|
|
195
196
|
});
|
|
196
197
|
process.stdin.on("end", () => {
|
|
197
198
|
void input;
|