@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.
Files changed (91) hide show
  1. package/README.md +17 -8
  2. package/dist/bin/backfill-conversations.js +46 -10
  3. package/dist/bin/backfill-responses.js +46 -10
  4. package/dist/bin/backfill-vectors.js +42 -8
  5. package/dist/bin/cleanup-stale-review-tasks.js +37 -8
  6. package/dist/bin/cli.js +281 -154
  7. package/dist/bin/exe-agent.js +19 -4
  8. package/dist/bin/exe-assign.js +39 -5
  9. package/dist/bin/exe-boot.js +237 -111
  10. package/dist/bin/exe-call.js +11 -6
  11. package/dist/bin/exe-cloud.js +99 -28
  12. package/dist/bin/exe-dispatch.js +1 -1
  13. package/dist/bin/exe-doctor.js +37 -8
  14. package/dist/bin/exe-export-behaviors.js +39 -10
  15. package/dist/bin/exe-forget.js +38 -9
  16. package/dist/bin/exe-gateway.js +109 -42
  17. package/dist/bin/exe-heartbeat.js +49 -20
  18. package/dist/bin/exe-kill.js +39 -10
  19. package/dist/bin/exe-launch-agent.js +58 -22
  20. package/dist/bin/exe-link.js +184 -85
  21. package/dist/bin/exe-new-employee.js +21 -7
  22. package/dist/bin/exe-pending-messages.js +46 -17
  23. package/dist/bin/exe-pending-notifications.js +37 -8
  24. package/dist/bin/exe-pending-reviews.js +47 -18
  25. package/dist/bin/exe-rename.js +21 -7
  26. package/dist/bin/exe-review.js +34 -5
  27. package/dist/bin/exe-search.js +47 -10
  28. package/dist/bin/exe-session-cleanup.js +56 -19
  29. package/dist/bin/exe-settings.js +63 -2
  30. package/dist/bin/exe-status.js +34 -5
  31. package/dist/bin/exe-team.js +34 -5
  32. package/dist/bin/git-sweep.js +38 -9
  33. package/dist/bin/graph-backfill.js +37 -8
  34. package/dist/bin/graph-export.js +37 -8
  35. package/dist/bin/install.js +1 -1
  36. package/dist/bin/scan-tasks.js +40 -11
  37. package/dist/bin/setup.js +58 -24
  38. package/dist/bin/shard-migrate.js +37 -8
  39. package/dist/bin/wiki-sync.js +39 -9
  40. package/dist/gateway/index.js +102 -37
  41. package/dist/hooks/bug-report-worker.js +62 -28
  42. package/dist/hooks/commit-complete.js +38 -9
  43. package/dist/hooks/error-recall.js +49 -8
  44. package/dist/hooks/exe-heartbeat-hook.js +3 -2
  45. package/dist/hooks/ingest-worker.js +151 -37
  46. package/dist/hooks/ingest.js +74 -28
  47. package/dist/hooks/instructions-loaded.js +39 -9
  48. package/dist/hooks/notification.js +37 -7
  49. package/dist/hooks/post-compact.js +37 -7
  50. package/dist/hooks/pre-compact.js +35 -6
  51. package/dist/hooks/pre-tool-use.js +52 -14
  52. package/dist/hooks/prompt-ingest-worker.js +56 -10
  53. package/dist/hooks/prompt-submit.js +61 -23
  54. package/dist/hooks/response-ingest-worker.js +57 -11
  55. package/dist/hooks/session-end.js +43 -10
  56. package/dist/hooks/session-start.js +46 -8
  57. package/dist/hooks/stop.js +37 -7
  58. package/dist/hooks/subagent-stop.js +37 -7
  59. package/dist/hooks/summary-worker.js +317 -99
  60. package/dist/index.js +87 -22
  61. package/dist/lib/cloud-sync.js +172 -78
  62. package/dist/lib/config.js +4 -1
  63. package/dist/lib/consolidation.js +5 -4
  64. package/dist/lib/database.js +1 -0
  65. package/dist/lib/device-registry.js +2 -1
  66. package/dist/lib/embedder.js +9 -1
  67. package/dist/lib/employees.js +11 -6
  68. package/dist/lib/exe-daemon-client.js +6 -1
  69. package/dist/lib/exe-daemon.js +71 -28
  70. package/dist/lib/hybrid-search.js +47 -10
  71. package/dist/lib/identity.js +1 -1
  72. package/dist/lib/keychain.js +2 -1
  73. package/dist/lib/license.js +13 -4
  74. package/dist/lib/messaging.js +1 -1
  75. package/dist/lib/reminders.js +2 -2
  76. package/dist/lib/schedules.js +37 -8
  77. package/dist/lib/skill-learning.js +1 -1
  78. package/dist/lib/store.js +37 -8
  79. package/dist/lib/tasks.js +1 -1
  80. package/dist/lib/tmux-routing.js +1 -1
  81. package/dist/mcp/server.js +97 -43
  82. package/dist/mcp/tools/complete-reminder.js +1 -1
  83. package/dist/mcp/tools/create-task.js +14 -6
  84. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  85. package/dist/mcp/tools/list-reminders.js +1 -1
  86. package/dist/mcp/tools/list-tasks.js +1 -1
  87. package/dist/mcp/tools/send-message.js +1 -1
  88. package/dist/mcp/tools/update-task.js +1 -1
  89. package/dist/runtime/index.js +35 -6
  90. package/dist/tui/App.js +177 -95
  91. package/package.json +3 -3
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  };
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";
@@ -308,6 +308,7 @@ async function ensureSchema() {
308
308
  const client = getRawClient();
309
309
  await client.execute("PRAGMA journal_mode = WAL");
310
310
  await client.execute("PRAGMA busy_timeout = 30000");
311
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
311
312
  try {
312
313
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
313
314
  } catch {
@@ -1116,12 +1117,13 @@ var init_database = __esm({
1116
1117
  });
1117
1118
 
1118
1119
  // src/lib/keychain.ts
1119
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1120
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1120
1121
  import { existsSync as existsSync2 } from "fs";
1121
1122
  import path3 from "path";
1123
+ import os2 from "os";
1122
1124
  import crypto from "crypto";
1123
1125
  function getKeyDir() {
1124
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1126
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1125
1127
  }
1126
1128
  function getKeyPath() {
1127
1129
  return path3.join(getKeyDir(), "master.key");
@@ -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 client.execute("SELECT MAX(version) as max_v FROM memories");
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;
@@ -1868,7 +1897,7 @@ __export(notifications_exports, {
1868
1897
  });
1869
1898
  import crypto2 from "crypto";
1870
1899
  import path5 from "path";
1871
- import os2 from "os";
1900
+ import os3 from "os";
1872
1901
  import {
1873
1902
  readFileSync as readFileSync3,
1874
1903
  readdirSync as readdirSync3,
@@ -2009,7 +2038,7 @@ function formatNotifications(notifications) {
2009
2038
  return lines.join("\n");
2010
2039
  }
2011
2040
  async function migrateJsonNotifications() {
2012
- const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path5.join(os2.homedir(), ".exe-os");
2041
+ const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path5.join(os3.homedir(), ".exe-os");
2013
2042
  const notifDir = path5.join(base, "notifications");
2014
2043
  if (!existsSync4(notifDir)) return 0;
2015
2044
  let migrated = 0;
@@ -2193,13 +2222,17 @@ var timeout = setTimeout(() => {
2193
2222
  process.exit(0);
2194
2223
  }, 5e3);
2195
2224
  timeout.unref();
2225
+ var MAX_INPUT_SIZE = 1e6;
2196
2226
  var input = "";
2197
2227
  process.stdin.setEncoding("utf8");
2198
2228
  process.stdin.on("data", (chunk) => {
2199
- input += chunk;
2229
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
2200
2230
  });
2201
2231
  process.stdin.on("end", async () => {
2202
2232
  try {
2233
+ if (input.length >= MAX_INPUT_SIZE) {
2234
+ process.exit(0);
2235
+ }
2203
2236
  const data = JSON.parse(input);
2204
2237
  const agent = getActiveAgent();
2205
2238
  if (agent.agentId !== "default") {
@@ -2229,7 +2262,7 @@ Orphaned tasks at session end: ${orphanResult.rows.map((r) => `"${String(r.title
2229
2262
  vector: null
2230
2263
  });
2231
2264
  await flushBatch2();
2232
- if (agent.agentId !== "exe") {
2265
+ if (agent.agentRole !== "COO") {
2233
2266
  const inProgress = orphanResult.rows.filter((r) => String(r.status) === "in_progress");
2234
2267
  if (inProgress.length > 0) {
2235
2268
  const titles = inProgress.map((r) => `"${String(r.title)}"`).join(", ");
@@ -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 crypto from "crypto";
1163
1168
  function getKeyDir() {
1164
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path2.join(process.env.HOME ?? "/tmp", ".exe-os");
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 client.execute("SELECT MAX(version) as max_v FROM memories");
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
 
@@ -3236,10 +3273,11 @@ var timeout = setTimeout(() => {
3236
3273
  process.exit(0);
3237
3274
  }, 5e3);
3238
3275
  timeout.unref();
3276
+ var MAX_INPUT_SIZE = 1e6;
3239
3277
  var input = "";
3240
3278
  process.stdin.setEncoding("utf8");
3241
3279
  process.stdin.on("data", (chunk) => {
3242
- input += chunk;
3280
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
3243
3281
  });
3244
3282
  process.stdin.on("end", async () => {
3245
3283
  try {
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  };
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";
@@ -327,6 +327,7 @@ async function ensureSchema() {
327
327
  const client = getRawClient();
328
328
  await client.execute("PRAGMA journal_mode = WAL");
329
329
  await client.execute("PRAGMA busy_timeout = 30000");
330
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
330
331
  try {
331
332
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
332
333
  } catch {
@@ -1135,12 +1136,13 @@ var init_database = __esm({
1135
1136
  });
1136
1137
 
1137
1138
  // src/lib/keychain.ts
1138
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1139
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1139
1140
  import { existsSync as existsSync2 } from "fs";
1140
1141
  import path3 from "path";
1142
+ import os2 from "os";
1141
1143
  import crypto from "crypto";
1142
1144
  function getKeyDir() {
1143
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1145
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1144
1146
  }
1145
1147
  function getKeyPath() {
1146
1148
  return path3.join(getKeyDir(), "master.key");
@@ -1441,6 +1443,28 @@ __export(store_exports, {
1441
1443
  vectorToBlob: () => vectorToBlob,
1442
1444
  writeMemory: () => writeMemory
1443
1445
  });
1446
+ function isBusyError2(err) {
1447
+ if (err instanceof Error) {
1448
+ const msg = err.message.toLowerCase();
1449
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
1450
+ }
1451
+ return false;
1452
+ }
1453
+ async function retryOnBusy2(fn, label) {
1454
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
1455
+ try {
1456
+ return await fn();
1457
+ } catch (err) {
1458
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
1459
+ process.stderr.write(
1460
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
1461
+ `
1462
+ );
1463
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
1464
+ }
1465
+ }
1466
+ throw new Error("unreachable");
1467
+ }
1444
1468
  async function initStore(options) {
1445
1469
  if (_flushTimer !== null) {
1446
1470
  clearInterval(_flushTimer);
@@ -1469,14 +1493,17 @@ async function initStore(options) {
1469
1493
  dbPath,
1470
1494
  encryptionKey: hexKey
1471
1495
  });
1472
- await ensureSchema();
1496
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1473
1497
  try {
1474
1498
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1475
1499
  initShardManager2(hexKey);
1476
1500
  } catch {
1477
1501
  }
1478
1502
  const client = getClient();
1479
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
1503
+ const vResult = await retryOnBusy2(
1504
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
1505
+ "version-query"
1506
+ );
1480
1507
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1481
1508
  }
1482
1509
  function classifyTier(record) {
@@ -1856,7 +1883,7 @@ async function getMemoryCardinality(agentId) {
1856
1883
  return 0;
1857
1884
  }
1858
1885
  }
1859
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1886
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1860
1887
  var init_store = __esm({
1861
1888
  "src/lib/store.ts"() {
1862
1889
  "use strict";
@@ -1864,6 +1891,8 @@ var init_store = __esm({
1864
1891
  init_database();
1865
1892
  init_keychain();
1866
1893
  init_config();
1894
+ INIT_MAX_RETRIES = 3;
1895
+ INIT_RETRY_DELAY_MS = 1e3;
1867
1896
  _pendingRecords = [];
1868
1897
  _batchSize = 20;
1869
1898
  _flushIntervalMs = 1e4;
@@ -1991,10 +2020,11 @@ var timeout = setTimeout(() => {
1991
2020
  process.exit(0);
1992
2021
  }, 5e3);
1993
2022
  timeout.unref();
2023
+ var MAX_INPUT_SIZE = 1e6;
1994
2024
  var input = "";
1995
2025
  process.stdin.setEncoding("utf8");
1996
2026
  process.stdin.on("data", (chunk) => {
1997
- input += chunk;
2027
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
1998
2028
  });
1999
2029
  process.stdin.on("end", () => {
2000
2030
  try {
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  };
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";
@@ -308,6 +308,7 @@ async function ensureSchema() {
308
308
  const client = getRawClient();
309
309
  await client.execute("PRAGMA journal_mode = WAL");
310
310
  await client.execute("PRAGMA busy_timeout = 30000");
311
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
311
312
  try {
312
313
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
313
314
  } catch {
@@ -1116,12 +1117,13 @@ var init_database = __esm({
1116
1117
  });
1117
1118
 
1118
1119
  // src/lib/keychain.ts
1119
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1120
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1120
1121
  import { existsSync as existsSync2 } from "fs";
1121
1122
  import path3 from "path";
1123
+ import os2 from "os";
1122
1124
  import crypto from "crypto";
1123
1125
  function getKeyDir() {
1124
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1126
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1125
1127
  }
1126
1128
  function getKeyPath() {
1127
1129
  return path3.join(getKeyDir(), "master.key");
@@ -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 client.execute("SELECT MAX(version) as max_v FROM memories");
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;
@@ -1952,10 +1981,11 @@ var timeout = setTimeout(() => {
1952
1981
  process.exit(0);
1953
1982
  }, 5e3);
1954
1983
  timeout.unref();
1984
+ var MAX_INPUT_SIZE = 1e6;
1955
1985
  var input = "";
1956
1986
  process.stdin.setEncoding("utf8");
1957
1987
  process.stdin.on("data", (chunk) => {
1958
- input += chunk;
1988
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
1959
1989
  });
1960
1990
  process.stdin.on("end", async () => {
1961
1991
  try {