@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.
Files changed (93) hide show
  1. package/README.md +17 -8
  2. package/dist/bin/backfill-conversations.js +112 -70
  3. package/dist/bin/backfill-responses.js +53 -18
  4. package/dist/bin/backfill-vectors.js +43 -16
  5. package/dist/bin/cleanup-stale-review-tasks.js +38 -16
  6. package/dist/bin/cli.js +790 -468
  7. package/dist/bin/exe-agent.js +19 -4
  8. package/dist/bin/exe-assign.js +46 -13
  9. package/dist/bin/exe-boot.js +288 -129
  10. package/dist/bin/exe-call.js +20 -10
  11. package/dist/bin/exe-cloud.js +135 -30
  12. package/dist/bin/exe-dispatch.js +1 -1
  13. package/dist/bin/exe-doctor.js +38 -16
  14. package/dist/bin/exe-export-behaviors.js +43 -21
  15. package/dist/bin/exe-forget.js +39 -17
  16. package/dist/bin/exe-gateway.js +159 -50
  17. package/dist/bin/exe-heartbeat.js +53 -31
  18. package/dist/bin/exe-kill.js +40 -18
  19. package/dist/bin/exe-launch-agent.js +109 -36
  20. package/dist/bin/exe-link.js +196 -87
  21. package/dist/bin/exe-new-employee.js +56 -17
  22. package/dist/bin/exe-pending-messages.js +47 -25
  23. package/dist/bin/exe-pending-notifications.js +38 -16
  24. package/dist/bin/exe-pending-reviews.js +51 -29
  25. package/dist/bin/exe-rename.js +21 -7
  26. package/dist/bin/exe-review.js +41 -13
  27. package/dist/bin/exe-search.js +57 -21
  28. package/dist/bin/exe-session-cleanup.js +67 -31
  29. package/dist/bin/exe-settings.js +63 -2
  30. package/dist/bin/exe-status.js +35 -13
  31. package/dist/bin/exe-team.js +35 -13
  32. package/dist/bin/git-sweep.js +45 -17
  33. package/dist/bin/graph-backfill.js +38 -16
  34. package/dist/bin/graph-export.js +38 -16
  35. package/dist/bin/install.js +10 -1
  36. package/dist/bin/scan-tasks.js +47 -19
  37. package/dist/bin/setup.js +444 -259
  38. package/dist/bin/shard-migrate.js +38 -16
  39. package/dist/bin/wiki-sync.js +40 -17
  40. package/dist/gateway/index.js +113 -48
  41. package/dist/hooks/bug-report-worker.js +66 -39
  42. package/dist/hooks/commit-complete.js +45 -17
  43. package/dist/hooks/error-recall.js +60 -20
  44. package/dist/hooks/exe-heartbeat-hook.js +3 -2
  45. package/dist/hooks/ingest-worker.js +174 -45
  46. package/dist/hooks/ingest.js +74 -28
  47. package/dist/hooks/instructions-loaded.js +46 -17
  48. package/dist/hooks/notification.js +44 -15
  49. package/dist/hooks/post-compact.js +44 -15
  50. package/dist/hooks/pre-compact.js +42 -14
  51. package/dist/hooks/pre-tool-use.js +59 -22
  52. package/dist/hooks/prompt-ingest-worker.js +75 -14
  53. package/dist/hooks/prompt-submit.js +75 -32
  54. package/dist/hooks/response-ingest-worker.js +76 -15
  55. package/dist/hooks/session-end.js +54 -22
  56. package/dist/hooks/session-start.js +57 -20
  57. package/dist/hooks/stop.js +44 -15
  58. package/dist/hooks/subagent-stop.js +44 -15
  59. package/dist/hooks/summary-worker.js +339 -106
  60. package/dist/index.js +94 -23
  61. package/dist/lib/cloud-sync.js +191 -80
  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/employee-templates.js +5 -0
  68. package/dist/lib/employees.js +11 -6
  69. package/dist/lib/exe-daemon-client.js +6 -1
  70. package/dist/lib/exe-daemon.js +95 -36
  71. package/dist/lib/hybrid-search.js +57 -21
  72. package/dist/lib/identity-templates.js +16 -7
  73. package/dist/lib/identity.js +1 -1
  74. package/dist/lib/keychain.js +2 -1
  75. package/dist/lib/license.js +56 -6
  76. package/dist/lib/messaging.js +1 -1
  77. package/dist/lib/reminders.js +2 -2
  78. package/dist/lib/schedules.js +38 -16
  79. package/dist/lib/skill-learning.js +1 -1
  80. package/dist/lib/store.js +44 -16
  81. package/dist/lib/tasks.js +1 -1
  82. package/dist/lib/tmux-routing.js +1 -1
  83. package/dist/mcp/server.js +280 -155
  84. package/dist/mcp/tools/complete-reminder.js +1 -1
  85. package/dist/mcp/tools/create-task.js +14 -6
  86. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  87. package/dist/mcp/tools/list-reminders.js +1 -1
  88. package/dist/mcp/tools/list-tasks.js +36 -28
  89. package/dist/mcp/tools/send-message.js +1 -1
  90. package/dist/mcp/tools/update-task.js +1 -1
  91. package/dist/runtime/index.js +42 -8
  92. package/dist/tui/App.js +220 -99
  93. 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 os from "os";
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(os.homedir(), ".exe-os");
50
- const legacyDir = path3.join(os.homedir(), ".exe-mem");
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(/^~/, os.homedir());
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(process.env.HOME ?? "/tmp", ".exe-os");
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 client.execute("SELECT MAX(version) as max_v FROM memories");
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 fetch(`${API_BASE}/auth/activate`, {
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(process.env.HOME ?? "/tmp", ".exe-os");
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
- const { readdirSync: readdirSync5 } = __require("fs");
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 client.execute("SELECT MAX(version) as max_v FROM memories");
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 = readdirSync(dir, { withFileTypes: true });
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 os2 from "os";
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(os2.homedir(), ".exe-os", "session-registry.json");
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 os3 from "os";
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(os3.homedir(), ".exe-os", "intercom-queue.json");
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(os3.homedir(), ".exe-os", "intercom.log");
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 os4 from "os";
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(os4.homedir(), ".exe-os", "session-logs");
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(os4.homedir(), ".claude.json");
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(os4.homedir(), ".claude", "projects");
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
- os4.homedir(),
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(os4.homedir(), ".exe-os", "session-cache");
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(os4.homedir(), ".exe-os", "spawn-locks");
3783
- SESSION_CACHE = path14.join(os4.homedir(), ".exe-os", "session-cache");
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(os4.homedir(), ".exe-os", "intercom.log");
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 os5 from "os";
4088
+ import os6 from "os";
4047
4089
  import {
4048
4090
  readFileSync as readFileSync11,
4049
- readdirSync as readdirSync3,
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 readdirSync4, unlinkSync as unlinkSync5 } from "fs";
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 readdirSync4(cacheDir)) {
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 readdirSync2 } from "fs";
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 {