@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
@@ -2,12 +2,6 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
- }) : x)(function(x) {
8
- if (typeof require !== "undefined") return require.apply(this, arguments);
9
- throw Error('Dynamic require of "' + x + '" is not supported');
10
- });
11
5
  var __esm = (fn, res) => function __init() {
12
6
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
13
7
  };
@@ -113,6 +107,7 @@ async function ensureSchema() {
113
107
  const client = getRawClient();
114
108
  await client.execute("PRAGMA journal_mode = WAL");
115
109
  await client.execute("PRAGMA busy_timeout = 30000");
110
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
116
111
  try {
117
112
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
118
113
  } catch {
@@ -913,15 +908,15 @@ var init_database = __esm({
913
908
  });
914
909
 
915
910
  // src/lib/config.ts
916
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
911
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
917
912
  import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
918
913
  import path2 from "path";
919
- import os from "os";
914
+ import os2 from "os";
920
915
  function resolveDataDir() {
921
916
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
922
917
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
923
- const newDir = path2.join(os.homedir(), ".exe-os");
924
- const legacyDir = path2.join(os.homedir(), ".exe-mem");
918
+ const newDir = path2.join(os2.homedir(), ".exe-os");
919
+ const legacyDir = path2.join(os2.homedir(), ".exe-mem");
925
920
  if (!existsSync2(newDir) && existsSync2(legacyDir)) {
926
921
  try {
927
922
  renameSync(legacyDir, newDir);
@@ -1008,7 +1003,7 @@ async function loadConfig() {
1008
1003
  normalizeAutoUpdate(migratedCfg);
1009
1004
  const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
1010
1005
  if (config.dbPath.startsWith("~")) {
1011
- config.dbPath = config.dbPath.replace(/^~/, os.homedir());
1006
+ config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
1012
1007
  }
1013
1008
  return config;
1014
1009
  } catch {
@@ -1115,7 +1110,7 @@ __export(shard_manager_exports, {
1115
1110
  shardExists: () => shardExists
1116
1111
  });
1117
1112
  import path3 from "path";
1118
- import { existsSync as existsSync3, mkdirSync } from "fs";
1113
+ import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
1119
1114
  import { createClient as createClient2 } from "@libsql/client";
1120
1115
  function initShardManager(encryptionKey) {
1121
1116
  _encryptionKey = encryptionKey;
@@ -1154,8 +1149,7 @@ function shardExists(projectName) {
1154
1149
  }
1155
1150
  function listShards() {
1156
1151
  if (!existsSync3(SHARDS_DIR)) return [];
1157
- const { readdirSync: readdirSync3 } = __require("fs");
1158
- return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1152
+ return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1159
1153
  }
1160
1154
  async function ensureShardSchema(client) {
1161
1155
  await client.execute("PRAGMA journal_mode = WAL");
@@ -1346,10 +1340,10 @@ var init_shard_manager = __esm({
1346
1340
  // src/lib/notifications.ts
1347
1341
  import crypto2 from "crypto";
1348
1342
  import path4 from "path";
1349
- import os2 from "os";
1343
+ import os3 from "os";
1350
1344
  import {
1351
1345
  readFileSync as readFileSync2,
1352
- readdirSync,
1346
+ readdirSync as readdirSync2,
1353
1347
  unlinkSync,
1354
1348
  existsSync as existsSync4,
1355
1349
  rmdirSync
@@ -1659,15 +1653,20 @@ function addEmployee(employees, employee) {
1659
1653
  }
1660
1654
  return [...employees, normalized];
1661
1655
  }
1656
+ function findExeBin() {
1657
+ try {
1658
+ return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
1659
+ } catch {
1660
+ return null;
1661
+ }
1662
+ }
1662
1663
  function registerBinSymlinks(name) {
1663
1664
  const created = [];
1664
1665
  const skipped = [];
1665
1666
  const errors = [];
1666
- let exeBinPath;
1667
- try {
1668
- exeBinPath = execSync2("which exe", { encoding: "utf-8" }).trim();
1669
- } catch {
1670
- errors.push("Could not find 'exe' in PATH");
1667
+ const exeBinPath = findExeBin();
1668
+ if (!exeBinPath) {
1669
+ errors.push("Could not find 'exe-os' in PATH");
1671
1670
  return { created, skipped, errors };
1672
1671
  }
1673
1672
  const binDir = path6.dirname(exeBinPath);
@@ -1707,7 +1706,7 @@ var init_employees = __esm({
1707
1706
  // src/lib/session-registry.ts
1708
1707
  import { readFileSync as readFileSync5, writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync7 } from "fs";
1709
1708
  import path7 from "path";
1710
- import os3 from "os";
1709
+ import os4 from "os";
1711
1710
  function registerSession(entry) {
1712
1711
  const dir = path7.dirname(REGISTRY_PATH);
1713
1712
  if (!existsSync7(dir)) {
@@ -1734,7 +1733,7 @@ var REGISTRY_PATH;
1734
1733
  var init_session_registry = __esm({
1735
1734
  "src/lib/session-registry.ts"() {
1736
1735
  "use strict";
1737
- REGISTRY_PATH = path7.join(os3.homedir(), ".exe-os", "session-registry.json");
1736
+ REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
1738
1737
  }
1739
1738
  });
1740
1739
 
@@ -1956,7 +1955,7 @@ var init_provider_table = __esm({
1956
1955
  // src/lib/intercom-queue.ts
1957
1956
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
1958
1957
  import path8 from "path";
1959
- import os4 from "os";
1958
+ import os5 from "os";
1960
1959
  function ensureDir() {
1961
1960
  const dir = path8.dirname(QUEUE_PATH);
1962
1961
  if (!existsSync8(dir)) mkdirSync3(dir, { recursive: true });
@@ -1996,9 +1995,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
1996
1995
  var init_intercom_queue = __esm({
1997
1996
  "src/lib/intercom-queue.ts"() {
1998
1997
  "use strict";
1999
- QUEUE_PATH = path8.join(os4.homedir(), ".exe-os", "intercom-queue.json");
1998
+ QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
2000
1999
  TTL_MS = 60 * 60 * 1e3;
2001
- INTERCOM_LOG = path8.join(os4.homedir(), ".exe-os", "intercom.log");
2000
+ INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
2002
2001
  }
2003
2002
  });
2004
2003
 
@@ -2107,7 +2106,7 @@ var init_plan_limits = __esm({
2107
2106
  import { execFileSync as execFileSync2, execSync as execSync5 } from "child_process";
2108
2107
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
2109
2108
  import path11 from "path";
2110
- import os5 from "os";
2109
+ import os6 from "os";
2111
2110
  import { fileURLToPath } from "url";
2112
2111
  import { unlinkSync as unlinkSync2 } from "fs";
2113
2112
  function spawnLockPath(sessionName) {
@@ -2379,7 +2378,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2379
2378
  const transport = getTransport();
2380
2379
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
2381
2380
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
2382
- const logDir = path11.join(os5.homedir(), ".exe-os", "session-logs");
2381
+ const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
2383
2382
  const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
2384
2383
  if (!existsSync11(logDir)) {
2385
2384
  mkdirSync5(logDir, { recursive: true });
@@ -2395,7 +2394,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2395
2394
  } catch {
2396
2395
  }
2397
2396
  try {
2398
- const claudeJsonPath = path11.join(os5.homedir(), ".claude.json");
2397
+ const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
2399
2398
  let claudeJson = {};
2400
2399
  try {
2401
2400
  claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
@@ -2410,7 +2409,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2410
2409
  } catch {
2411
2410
  }
2412
2411
  try {
2413
- const settingsDir = path11.join(os5.homedir(), ".claude", "projects");
2412
+ const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
2414
2413
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
2415
2414
  const projSettingsDir = path11.join(settingsDir, normalizedKey);
2416
2415
  const settingsPath = path11.join(projSettingsDir, "settings.json");
@@ -2458,7 +2457,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2458
2457
  let legacyFallbackWarned = false;
2459
2458
  if (!useExeAgent && !useBinSymlink) {
2460
2459
  const identityPath = path11.join(
2461
- os5.homedir(),
2460
+ os6.homedir(),
2462
2461
  ".exe-os",
2463
2462
  "identity",
2464
2463
  `${employeeName}.md`
@@ -2488,7 +2487,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2488
2487
  }
2489
2488
  let sessionContextFlag = "";
2490
2489
  try {
2491
- const ctxDir = path11.join(os5.homedir(), ".exe-os", "session-cache");
2490
+ const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
2492
2491
  mkdirSync5(ctxDir, { recursive: true });
2493
2492
  const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
2494
2493
  const ctxContent = [
@@ -2599,11 +2598,11 @@ var init_tmux_routing = __esm({
2599
2598
  init_provider_table();
2600
2599
  init_intercom_queue();
2601
2600
  init_plan_limits();
2602
- SPAWN_LOCK_DIR = path11.join(os5.homedir(), ".exe-os", "spawn-locks");
2603
- SESSION_CACHE = path11.join(os5.homedir(), ".exe-os", "session-cache");
2601
+ SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
2602
+ SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
2604
2603
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
2605
2604
  INTERCOM_DEBOUNCE_MS = 3e4;
2606
- INTERCOM_LOG2 = path11.join(os5.homedir(), ".exe-os", "intercom.log");
2605
+ INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
2607
2606
  DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
2608
2607
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
2609
2608
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -2612,7 +2611,7 @@ var init_tmux_routing = __esm({
2612
2611
 
2613
2612
  // src/lib/tasks-review.ts
2614
2613
  import path12 from "path";
2615
- import { existsSync as existsSync12, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
2614
+ import { existsSync as existsSync12, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
2616
2615
  var init_tasks_review = __esm({
2617
2616
  "src/lib/tasks-review.ts"() {
2618
2617
  "use strict";
@@ -2832,11 +2831,12 @@ init_database();
2832
2831
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
2833
2832
  import { existsSync } from "fs";
2834
2833
  import path from "path";
2834
+ import os from "os";
2835
2835
  import crypto from "crypto";
2836
2836
  var SERVICE = "exe-mem";
2837
2837
  var ACCOUNT = "master-key";
2838
2838
  function getKeyDir() {
2839
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(process.env.HOME ?? "/tmp", ".exe-os");
2839
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
2840
2840
  }
2841
2841
  function getKeyPath() {
2842
2842
  return path.join(getKeyDir(), "master.key");
@@ -2873,6 +2873,30 @@ async function getMasterKey() {
2873
2873
 
2874
2874
  // src/lib/store.ts
2875
2875
  init_config();
2876
+ var INIT_MAX_RETRIES = 3;
2877
+ var INIT_RETRY_DELAY_MS = 1e3;
2878
+ function isBusyError2(err) {
2879
+ if (err instanceof Error) {
2880
+ const msg = err.message.toLowerCase();
2881
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
2882
+ }
2883
+ return false;
2884
+ }
2885
+ async function retryOnBusy2(fn, label) {
2886
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
2887
+ try {
2888
+ return await fn();
2889
+ } catch (err) {
2890
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
2891
+ process.stderr.write(
2892
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
2893
+ `
2894
+ );
2895
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
2896
+ }
2897
+ }
2898
+ throw new Error("unreachable");
2899
+ }
2876
2900
  var _pendingRecords = [];
2877
2901
  var _batchSize = 20;
2878
2902
  var _flushIntervalMs = 1e4;
@@ -2907,14 +2931,17 @@ async function initStore(options) {
2907
2931
  dbPath,
2908
2932
  encryptionKey: hexKey
2909
2933
  });
2910
- await ensureSchema();
2934
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
2911
2935
  try {
2912
2936
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
2913
2937
  initShardManager2(hexKey);
2914
2938
  } catch {
2915
2939
  }
2916
2940
  const client = getClient();
2917
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
2941
+ const vResult = await retryOnBusy2(
2942
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
2943
+ "version-query"
2944
+ );
2918
2945
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
2919
2946
  }
2920
2947
 
@@ -1,11 +1,5 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
- }) : x)(function(x) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x + '" is not supported');
8
- });
9
3
  var __esm = (fn, res) => function __init() {
10
4
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
5
  };
@@ -125,6 +119,7 @@ async function ensureSchema() {
125
119
  const client = getRawClient();
126
120
  await client.execute("PRAGMA journal_mode = WAL");
127
121
  await client.execute("PRAGMA busy_timeout = 30000");
122
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
128
123
  try {
129
124
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
130
125
  } catch {
@@ -936,9 +931,10 @@ var init_database = __esm({
936
931
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
937
932
  import { existsSync } from "fs";
938
933
  import path from "path";
934
+ import os from "os";
939
935
  import crypto from "crypto";
940
936
  function getKeyDir() {
941
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(process.env.HOME ?? "/tmp", ".exe-os");
937
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
942
938
  }
943
939
  function getKeyPath() {
944
940
  return path.join(getKeyDir(), "master.key");
@@ -982,15 +978,15 @@ var init_keychain = __esm({
982
978
  });
983
979
 
984
980
  // src/lib/config.ts
985
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
981
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
986
982
  import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
987
983
  import path2 from "path";
988
- import os from "os";
984
+ import os2 from "os";
989
985
  function resolveDataDir() {
990
986
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
991
987
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
992
- const newDir = path2.join(os.homedir(), ".exe-os");
993
- const legacyDir = path2.join(os.homedir(), ".exe-mem");
988
+ const newDir = path2.join(os2.homedir(), ".exe-os");
989
+ const legacyDir = path2.join(os2.homedir(), ".exe-mem");
994
990
  if (!existsSync2(newDir) && existsSync2(legacyDir)) {
995
991
  try {
996
992
  renameSync(legacyDir, newDir);
@@ -1077,7 +1073,7 @@ async function loadConfig() {
1077
1073
  normalizeAutoUpdate(migratedCfg);
1078
1074
  const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
1079
1075
  if (config.dbPath.startsWith("~")) {
1080
- config.dbPath = config.dbPath.replace(/^~/, os.homedir());
1076
+ config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
1081
1077
  }
1082
1078
  return config;
1083
1079
  } catch {
@@ -1184,7 +1180,7 @@ __export(shard_manager_exports, {
1184
1180
  shardExists: () => shardExists
1185
1181
  });
1186
1182
  import path3 from "path";
1187
- import { existsSync as existsSync3, mkdirSync } from "fs";
1183
+ import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
1188
1184
  import { createClient as createClient2 } from "@libsql/client";
1189
1185
  function initShardManager(encryptionKey) {
1190
1186
  _encryptionKey = encryptionKey;
@@ -1223,7 +1219,6 @@ function shardExists(projectName) {
1223
1219
  }
1224
1220
  function listShards() {
1225
1221
  if (!existsSync3(SHARDS_DIR)) return [];
1226
- const { readdirSync } = __require("fs");
1227
1222
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1228
1223
  }
1229
1224
  async function ensureShardSchema(client) {
@@ -1429,6 +1424,28 @@ __export(store_exports, {
1429
1424
  vectorToBlob: () => vectorToBlob,
1430
1425
  writeMemory: () => writeMemory
1431
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
+ }
1432
1449
  async function initStore(options) {
1433
1450
  if (_flushTimer !== null) {
1434
1451
  clearInterval(_flushTimer);
@@ -1457,14 +1474,17 @@ async function initStore(options) {
1457
1474
  dbPath,
1458
1475
  encryptionKey: hexKey
1459
1476
  });
1460
- await ensureSchema();
1477
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1461
1478
  try {
1462
1479
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1463
1480
  initShardManager2(hexKey);
1464
1481
  } catch {
1465
1482
  }
1466
1483
  const client = getClient();
1467
- 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
+ );
1468
1488
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1469
1489
  }
1470
1490
  function classifyTier(record) {
@@ -1507,6 +1527,12 @@ async function writeMemory(record) {
1507
1527
  supersedes_id: record.supersedes_id ?? null
1508
1528
  };
1509
1529
  _pendingRecords.push(dbRow);
1530
+ const MAX_PENDING = 1e3;
1531
+ if (_pendingRecords.length > MAX_PENDING) {
1532
+ const dropped = _pendingRecords.length - MAX_PENDING;
1533
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
1534
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
1535
+ }
1510
1536
  if (_flushTimer === null) {
1511
1537
  _flushTimer = setInterval(() => {
1512
1538
  void flushBatch();
@@ -1838,7 +1864,7 @@ async function getMemoryCardinality(agentId) {
1838
1864
  return 0;
1839
1865
  }
1840
1866
  }
1841
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1867
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1842
1868
  var init_store = __esm({
1843
1869
  "src/lib/store.ts"() {
1844
1870
  "use strict";
@@ -1846,6 +1872,8 @@ var init_store = __esm({
1846
1872
  init_database();
1847
1873
  init_keychain();
1848
1874
  init_config();
1875
+ INIT_MAX_RETRIES = 3;
1876
+ INIT_RETRY_DELAY_MS = 1e3;
1849
1877
  _pendingRecords = [];
1850
1878
  _batchSize = 20;
1851
1879
  _flushIntervalMs = 1e4;
@@ -1,11 +1,5 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
- }) : x)(function(x) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x + '" is not supported');
8
- });
9
3
  var __esm = (fn, res) => function __init() {
10
4
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
5
  };
@@ -30,7 +24,7 @@ __export(config_exports, {
30
24
  migrateConfig: () => migrateConfig,
31
25
  saveConfig: () => saveConfig
32
26
  });
33
- import { readFile, writeFile, mkdir } from "fs/promises";
27
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
34
28
  import { readFileSync, existsSync, renameSync } from "fs";
35
29
  import path from "path";
36
30
  import os from "os";
@@ -156,6 +150,9 @@ async function saveConfig(config) {
156
150
  await mkdir(dir, { recursive: true });
157
151
  const configPath = path.join(dir, "config.json");
158
152
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
153
+ if (config.cloud?.apiKey) {
154
+ await chmod(configPath, 384);
155
+ }
159
156
  }
160
157
  async function loadConfigFrom(configPath) {
161
158
  const raw = await readFile(configPath, "utf-8");
@@ -354,6 +351,7 @@ async function ensureSchema() {
354
351
  const client = getRawClient();
355
352
  await client.execute("PRAGMA journal_mode = WAL");
356
353
  await client.execute("PRAGMA busy_timeout = 30000");
354
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
357
355
  try {
358
356
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
359
357
  } catch {
@@ -1162,12 +1160,13 @@ var init_database = __esm({
1162
1160
  });
1163
1161
 
1164
1162
  // src/lib/keychain.ts
1165
- 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";
1166
1164
  import { existsSync as existsSync2 } from "fs";
1167
1165
  import path2 from "path";
1166
+ import os2 from "os";
1168
1167
  import crypto2 from "crypto";
1169
1168
  function getKeyDir() {
1170
- 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");
1171
1170
  }
1172
1171
  function getKeyPath() {
1173
1172
  return path2.join(getKeyDir(), "master.key");
@@ -1224,7 +1223,7 @@ __export(shard_manager_exports, {
1224
1223
  shardExists: () => shardExists
1225
1224
  });
1226
1225
  import path3 from "path";
1227
- import { existsSync as existsSync3, mkdirSync } from "fs";
1226
+ import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
1228
1227
  import { createClient as createClient2 } from "@libsql/client";
1229
1228
  function initShardManager(encryptionKey) {
1230
1229
  _encryptionKey = encryptionKey;
@@ -1263,8 +1262,7 @@ function shardExists(projectName) {
1263
1262
  }
1264
1263
  function listShards() {
1265
1264
  if (!existsSync3(SHARDS_DIR)) return [];
1266
- const { readdirSync: readdirSync3 } = __require("fs");
1267
- return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1265
+ return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1268
1266
  }
1269
1267
  async function ensureShardSchema(client) {
1270
1268
  await client.execute("PRAGMA journal_mode = WAL");
@@ -1469,6 +1467,28 @@ __export(store_exports, {
1469
1467
  vectorToBlob: () => vectorToBlob,
1470
1468
  writeMemory: () => writeMemory
1471
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
+ }
1472
1492
  async function initStore(options) {
1473
1493
  if (_flushTimer !== null) {
1474
1494
  clearInterval(_flushTimer);
@@ -1497,14 +1517,17 @@ async function initStore(options) {
1497
1517
  dbPath,
1498
1518
  encryptionKey: hexKey
1499
1519
  });
1500
- await ensureSchema();
1520
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1501
1521
  try {
1502
1522
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1503
1523
  initShardManager2(hexKey);
1504
1524
  } catch {
1505
1525
  }
1506
1526
  const client = getClient();
1507
- 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
+ );
1508
1531
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1509
1532
  }
1510
1533
  function classifyTier(record) {
@@ -1547,6 +1570,12 @@ async function writeMemory(record) {
1547
1570
  supersedes_id: record.supersedes_id ?? null
1548
1571
  };
1549
1572
  _pendingRecords.push(dbRow);
1573
+ const MAX_PENDING = 1e3;
1574
+ if (_pendingRecords.length > MAX_PENDING) {
1575
+ const dropped = _pendingRecords.length - MAX_PENDING;
1576
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
1577
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
1578
+ }
1550
1579
  if (_flushTimer === null) {
1551
1580
  _flushTimer = setInterval(() => {
1552
1581
  void flushBatch();
@@ -1878,7 +1907,7 @@ async function getMemoryCardinality(agentId) {
1878
1907
  return 0;
1879
1908
  }
1880
1909
  }
1881
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1910
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
1882
1911
  var init_store = __esm({
1883
1912
  "src/lib/store.ts"() {
1884
1913
  "use strict";
@@ -1886,6 +1915,8 @@ var init_store = __esm({
1886
1915
  init_database();
1887
1916
  init_keychain();
1888
1917
  init_config();
1918
+ INIT_MAX_RETRIES = 3;
1919
+ INIT_RETRY_DELAY_MS = 1e3;
1889
1920
  _pendingRecords = [];
1890
1921
  _batchSize = 20;
1891
1922
  _flushIntervalMs = 1e4;
@@ -1993,6 +2024,10 @@ import path4 from "path";
1993
2024
  import { fileURLToPath } from "url";
1994
2025
  function handleData(chunk) {
1995
2026
  _buffer += chunk.toString();
2027
+ if (_buffer.length > MAX_BUFFER) {
2028
+ _buffer = "";
2029
+ return;
2030
+ }
1996
2031
  let newlineIdx;
1997
2032
  while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
1998
2033
  const line = _buffer.slice(0, newlineIdx).trim();
@@ -2300,7 +2335,7 @@ function disconnectClient() {
2300
2335
  entry.resolve({ error: "Client disconnected" });
2301
2336
  }
2302
2337
  }
2303
- 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;
2304
2339
  var init_exe_daemon_client = __esm({
2305
2340
  "src/lib/exe-daemon-client.ts"() {
2306
2341
  "use strict";
@@ -2317,6 +2352,7 @@ var init_exe_daemon_client = __esm({
2317
2352
  _requestCount = 0;
2318
2353
  HEALTH_CHECK_INTERVAL = 100;
2319
2354
  _pending = /* @__PURE__ */ new Map();
2355
+ MAX_BUFFER = 1e7;
2320
2356
  }
2321
2357
  });
2322
2358
 
@@ -2445,7 +2481,7 @@ __export(file_grep_exports, {
2445
2481
  grepProjectFiles: () => grepProjectFiles
2446
2482
  });
2447
2483
  import { execSync as execSync2 } from "child_process";
2448
- import { readFileSync as readFileSync3, readdirSync, statSync as statSync2, existsSync as existsSync5 } from "fs";
2484
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync5 } from "fs";
2449
2485
  import path6 from "path";
2450
2486
  import crypto3 from "crypto";
2451
2487
  function hasRipgrep() {
@@ -2590,7 +2626,7 @@ function collectFiles(root, patterns) {
2590
2626
  const basename = path6.basename(dir);
2591
2627
  if (EXCLUDE_DIRS.includes(basename)) return;
2592
2628
  try {
2593
- const entries = readdirSync(dir, { withFileTypes: true });
2629
+ const entries = readdirSync2(dir, { withFileTypes: true });
2594
2630
  for (const entry of entries) {
2595
2631
  if (files.length >= MAX_FILES) return;
2596
2632
  const rel = path6.join(relative, entry.name);
@@ -3242,7 +3278,7 @@ init_database();
3242
3278
 
3243
3279
  // src/adapters/claude/active-agent.ts
3244
3280
  init_config();
3245
- import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as readdirSync2 } from "fs";
3281
+ import { readFileSync as readFileSync4, writeFileSync, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync as readdirSync3 } from "fs";
3246
3282
  import { execSync as execSync4 } from "child_process";
3247
3283
  import path8 from "path";
3248
3284
 
@@ -3341,13 +3377,17 @@ var timeout = setTimeout(() => {
3341
3377
  process.exit(0);
3342
3378
  }, 5e3);
3343
3379
  timeout.unref();
3380
+ var MAX_INPUT_SIZE = 1e6;
3344
3381
  var input = "";
3345
3382
  process.stdin.setEncoding("utf8");
3346
3383
  process.stdin.on("data", (chunk) => {
3347
- input += chunk;
3384
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
3348
3385
  });
3349
3386
  process.stdin.on("end", async () => {
3350
3387
  try {
3388
+ if (input.length >= MAX_INPUT_SIZE) {
3389
+ process.exit(0);
3390
+ }
3351
3391
  const data = JSON.parse(input);
3352
3392
  if (!detectError(data)) {
3353
3393
  process.exit(0);
@@ -9,7 +9,7 @@ import { execSync as execSync2 } from "child_process";
9
9
  import path2 from "path";
10
10
 
11
11
  // src/lib/config.ts
12
- import { readFile, writeFile, mkdir } from "fs/promises";
12
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
13
13
  import { readFileSync, existsSync, renameSync } from "fs";
14
14
  import path from "path";
15
15
  import os from "os";
@@ -188,10 +188,11 @@ var CLI_TIMEOUT_MS = 4e3;
188
188
  var EXE_AGENT_ID = "exe";
189
189
  var watchdog = setTimeout(() => process.exit(0), HOOK_TIMEOUT_MS);
190
190
  watchdog.unref();
191
+ var MAX_INPUT_SIZE = 1e6;
191
192
  var input = "";
192
193
  process.stdin.setEncoding("utf8");
193
194
  process.stdin.on("data", (chunk) => {
194
- input += chunk;
195
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
195
196
  });
196
197
  process.stdin.on("end", () => {
197
198
  void input;