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