@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
@@ -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
  };
@@ -15,7 +9,7 @@ var __export = (target, all) => {
15
9
  };
16
10
 
17
11
  // src/lib/config.ts
18
- import { readFile, writeFile, mkdir } from "fs/promises";
12
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
19
13
  import { readFileSync, existsSync, renameSync } from "fs";
20
14
  import path from "path";
21
15
  import os from "os";
@@ -314,6 +308,7 @@ async function ensureSchema() {
314
308
  const client = getRawClient();
315
309
  await client.execute("PRAGMA journal_mode = WAL");
316
310
  await client.execute("PRAGMA busy_timeout = 30000");
311
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
317
312
  try {
318
313
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
319
314
  } catch {
@@ -1122,12 +1117,13 @@ var init_database = __esm({
1122
1117
  });
1123
1118
 
1124
1119
  // src/lib/keychain.ts
1125
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1120
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1126
1121
  import { existsSync as existsSync2 } from "fs";
1127
1122
  import path3 from "path";
1123
+ import os2 from "os";
1128
1124
  import crypto from "crypto";
1129
1125
  function getKeyDir() {
1130
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1126
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1131
1127
  }
1132
1128
  function getKeyPath() {
1133
1129
  return path3.join(getKeyDir(), "master.key");
@@ -1184,7 +1180,7 @@ __export(shard_manager_exports, {
1184
1180
  shardExists: () => shardExists
1185
1181
  });
1186
1182
  import path4 from "path";
1187
- import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1183
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } 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: readdirSync2 } = __require("fs");
1227
1222
  return readdirSync2(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;
@@ -1953,10 +1981,11 @@ var timeout = setTimeout(() => {
1953
1981
  process.exit(0);
1954
1982
  }, 5e3);
1955
1983
  timeout.unref();
1984
+ var MAX_INPUT_SIZE = 1e6;
1956
1985
  var input = "";
1957
1986
  process.stdin.setEncoding("utf8");
1958
1987
  process.stdin.on("data", (chunk) => {
1959
- input += chunk;
1988
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
1960
1989
  });
1961
1990
  process.stdin.on("end", async () => {
1962
1991
  try {
@@ -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
  };
@@ -15,7 +9,7 @@ var __export = (target, all) => {
15
9
  };
16
10
 
17
11
  // src/lib/config.ts
18
- import { readFile, writeFile, mkdir } from "fs/promises";
12
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
19
13
  import { readFileSync, existsSync, renameSync } from "fs";
20
14
  import path from "path";
21
15
  import os from "os";
@@ -314,6 +308,7 @@ async function ensureSchema() {
314
308
  const client = getRawClient();
315
309
  await client.execute("PRAGMA journal_mode = WAL");
316
310
  await client.execute("PRAGMA busy_timeout = 30000");
311
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
317
312
  try {
318
313
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
319
314
  } catch {
@@ -1122,12 +1117,13 @@ var init_database = __esm({
1122
1117
  });
1123
1118
 
1124
1119
  // src/lib/keychain.ts
1125
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1120
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1126
1121
  import { existsSync as existsSync2 } from "fs";
1127
1122
  import path3 from "path";
1123
+ import os2 from "os";
1128
1124
  import crypto from "crypto";
1129
1125
  function getKeyDir() {
1130
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1126
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1131
1127
  }
1132
1128
  function getKeyPath() {
1133
1129
  return path3.join(getKeyDir(), "master.key");
@@ -1184,7 +1180,7 @@ __export(shard_manager_exports, {
1184
1180
  shardExists: () => shardExists
1185
1181
  });
1186
1182
  import path4 from "path";
1187
- import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1183
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } 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: readdirSync2 } = __require("fs");
1227
1222
  return readdirSync2(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
  };
@@ -15,7 +9,7 @@ var __export = (target, all) => {
15
9
  };
16
10
 
17
11
  // src/lib/config.ts
18
- import { readFile, writeFile, mkdir } from "fs/promises";
12
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
19
13
  import { readFileSync, existsSync, renameSync } from "fs";
20
14
  import path from "path";
21
15
  import os from "os";
@@ -305,6 +299,7 @@ async function ensureSchema() {
305
299
  const client = getRawClient();
306
300
  await client.execute("PRAGMA journal_mode = WAL");
307
301
  await client.execute("PRAGMA busy_timeout = 30000");
302
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
308
303
  try {
309
304
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
310
305
  } catch {
@@ -1199,15 +1194,20 @@ function addEmployee(employees, employee) {
1199
1194
  }
1200
1195
  return [...employees, normalized];
1201
1196
  }
1197
+ function findExeBin() {
1198
+ try {
1199
+ return execSync3(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
1200
+ } catch {
1201
+ return null;
1202
+ }
1203
+ }
1202
1204
  function registerBinSymlinks(name) {
1203
1205
  const created = [];
1204
1206
  const skipped = [];
1205
1207
  const errors = [];
1206
- let exeBinPath;
1207
- try {
1208
- exeBinPath = execSync3("which exe", { encoding: "utf-8" }).trim();
1209
- } catch {
1210
- errors.push("Could not find 'exe' in PATH");
1208
+ const exeBinPath = findExeBin();
1209
+ if (!exeBinPath) {
1210
+ errors.push("Could not find 'exe-os' in PATH");
1211
1211
  return { created, skipped, errors };
1212
1212
  }
1213
1213
  const binDir = path3.dirname(exeBinPath);
@@ -1426,12 +1426,13 @@ var init_memory = __esm({
1426
1426
  });
1427
1427
 
1428
1428
  // src/lib/keychain.ts
1429
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
1429
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
1430
1430
  import { existsSync as existsSync4 } from "fs";
1431
1431
  import path5 from "path";
1432
+ import os3 from "os";
1432
1433
  import crypto from "crypto";
1433
1434
  function getKeyDir() {
1434
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(process.env.HOME ?? "/tmp", ".exe-os");
1435
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os3.homedir(), ".exe-os");
1435
1436
  }
1436
1437
  function getKeyPath() {
1437
1438
  return path5.join(getKeyDir(), "master.key");
@@ -1488,7 +1489,7 @@ __export(shard_manager_exports, {
1488
1489
  shardExists: () => shardExists
1489
1490
  });
1490
1491
  import path6 from "path";
1491
- import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
1492
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "fs";
1492
1493
  import { createClient as createClient2 } from "@libsql/client";
1493
1494
  function initShardManager(encryptionKey) {
1494
1495
  _encryptionKey = encryptionKey;
@@ -1527,7 +1528,6 @@ function shardExists(projectName) {
1527
1528
  }
1528
1529
  function listShards() {
1529
1530
  if (!existsSync5(SHARDS_DIR)) return [];
1530
- const { readdirSync: readdirSync2 } = __require("fs");
1531
1531
  return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1532
1532
  }
1533
1533
  async function ensureShardSchema(client) {
@@ -1733,6 +1733,28 @@ __export(store_exports, {
1733
1733
  vectorToBlob: () => vectorToBlob,
1734
1734
  writeMemory: () => writeMemory
1735
1735
  });
1736
+ function isBusyError2(err) {
1737
+ if (err instanceof Error) {
1738
+ const msg = err.message.toLowerCase();
1739
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
1740
+ }
1741
+ return false;
1742
+ }
1743
+ async function retryOnBusy2(fn, label) {
1744
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
1745
+ try {
1746
+ return await fn();
1747
+ } catch (err) {
1748
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
1749
+ process.stderr.write(
1750
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
1751
+ `
1752
+ );
1753
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
1754
+ }
1755
+ }
1756
+ throw new Error("unreachable");
1757
+ }
1736
1758
  async function initStore(options) {
1737
1759
  if (_flushTimer !== null) {
1738
1760
  clearInterval(_flushTimer);
@@ -1761,14 +1783,17 @@ async function initStore(options) {
1761
1783
  dbPath,
1762
1784
  encryptionKey: hexKey
1763
1785
  });
1764
- await ensureSchema();
1786
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
1765
1787
  try {
1766
1788
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
1767
1789
  initShardManager2(hexKey);
1768
1790
  } catch {
1769
1791
  }
1770
1792
  const client = getClient();
1771
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
1793
+ const vResult = await retryOnBusy2(
1794
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
1795
+ "version-query"
1796
+ );
1772
1797
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
1773
1798
  }
1774
1799
  function classifyTier(record) {
@@ -1811,6 +1836,12 @@ async function writeMemory(record) {
1811
1836
  supersedes_id: record.supersedes_id ?? null
1812
1837
  };
1813
1838
  _pendingRecords.push(dbRow);
1839
+ const MAX_PENDING = 1e3;
1840
+ if (_pendingRecords.length > MAX_PENDING) {
1841
+ const dropped = _pendingRecords.length - MAX_PENDING;
1842
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
1843
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
1844
+ }
1814
1845
  if (_flushTimer === null) {
1815
1846
  _flushTimer = setInterval(() => {
1816
1847
  void flushBatch();
@@ -2142,7 +2173,7 @@ async function getMemoryCardinality(agentId) {
2142
2173
  return 0;
2143
2174
  }
2144
2175
  }
2145
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2176
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2146
2177
  var init_store = __esm({
2147
2178
  "src/lib/store.ts"() {
2148
2179
  "use strict";
@@ -2150,6 +2181,8 @@ var init_store = __esm({
2150
2181
  init_database();
2151
2182
  init_keychain();
2152
2183
  init_config();
2184
+ INIT_MAX_RETRIES = 3;
2185
+ INIT_RETRY_DELAY_MS = 1e3;
2153
2186
  _pendingRecords = [];
2154
2187
  _batchSize = 20;
2155
2188
  _flushIntervalMs = 1e4;
@@ -2421,16 +2454,20 @@ function countTomSessions() {
2421
2454
  return 0;
2422
2455
  }
2423
2456
  }
2457
+ var MAX_INPUT_SIZE = 1e6;
2424
2458
  var input = "";
2425
2459
  process.stdin.setEncoding("utf8");
2426
2460
  process.stdin.on("data", (chunk) => {
2427
- input += chunk;
2461
+ if (input.length < MAX_INPUT_SIZE) input += chunk;
2428
2462
  });
2429
2463
  process.stdin.on("end", async () => {
2430
2464
  try {
2465
+ if (input.length >= MAX_INPUT_SIZE) {
2466
+ process.exit(0);
2467
+ }
2431
2468
  const data = JSON.parse(input);
2432
2469
  const agent = getActiveAgent();
2433
- if (/^(Write|Edit)$/.test(data.tool_name) && agent.agentId !== "exe" && agent.agentId !== "default") {
2470
+ if (/^(Write|Edit)$/.test(data.tool_name) && agent.agentRole !== "COO" && agent.agentId !== "default") {
2434
2471
  const filePath = data.tool_input?.file_path ?? "";
2435
2472
  const exeMatch = filePath.match(/exe\/([^/]+)\//);
2436
2473
  if (exeMatch && exeMatch[1] !== agent.agentId && exeMatch[1] !== "output") {
@@ -2484,7 +2521,7 @@ This write was prevented. Do NOT retry.`
2484
2521
  if (/^(Write|Edit|Read)$/.test(data.tool_name)) {
2485
2522
  const filePath = data.tool_input?.file_path ?? "";
2486
2523
  const sensitivePatterns = /\/(\.env\.local|\.env\.production|id_rsa|id_ed25519|credentials\.json|\.ssh\/config)$/;
2487
- if (sensitivePatterns.test(filePath) && agent.agentId !== "exe") {
2524
+ if (sensitivePatterns.test(filePath) && agent.agentRole !== "COO") {
2488
2525
  const output = JSON.stringify({
2489
2526
  hookSpecificOutput: {
2490
2527
  permissionDecision: "ask"