@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
@@ -62,7 +62,8 @@ async function gqlRequest(query, variables) {
62
62
  "Content-Type": "application/json",
63
63
  Authorization: `Bearer ${config.apiToken}`
64
64
  },
65
- body: JSON.stringify({ query, variables })
65
+ body: JSON.stringify({ query, variables }),
66
+ signal: AbortSignal.timeout(3e4)
66
67
  });
67
68
  if (!res.ok) {
68
69
  throw new Error(`CRM GraphQL request failed: ${res.status} ${res.statusText}`);
@@ -369,6 +370,7 @@ async function ensureSchema() {
369
370
  const client = getRawClient();
370
371
  await client.execute("PRAGMA journal_mode = WAL");
371
372
  await client.execute("PRAGMA busy_timeout = 30000");
373
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
372
374
  try {
373
375
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
374
376
  } catch {
@@ -1201,7 +1203,7 @@ __export(config_exports, {
1201
1203
  migrateConfig: () => migrateConfig,
1202
1204
  saveConfig: () => saveConfig
1203
1205
  });
1204
- import { readFile, writeFile, mkdir } from "fs/promises";
1206
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
1205
1207
  import { readFileSync, existsSync, renameSync } from "fs";
1206
1208
  import path from "path";
1207
1209
  import os from "os";
@@ -1327,6 +1329,9 @@ async function saveConfig(config2) {
1327
1329
  await mkdir(dir, { recursive: true });
1328
1330
  const configPath = path.join(dir, "config.json");
1329
1331
  await writeFile(configPath, JSON.stringify(config2, null, 2) + "\n");
1332
+ if (config2.cloud?.apiKey) {
1333
+ await chmod(configPath, 384);
1334
+ }
1330
1335
  }
1331
1336
  async function loadConfigFrom(configPath) {
1332
1337
  const raw = await readFile(configPath, "utf-8");
@@ -1437,6 +1442,10 @@ import path2 from "path";
1437
1442
  import { fileURLToPath } from "url";
1438
1443
  function handleData(chunk) {
1439
1444
  _buffer += chunk.toString();
1445
+ if (_buffer.length > MAX_BUFFER) {
1446
+ _buffer = "";
1447
+ return;
1448
+ }
1440
1449
  let newlineIdx;
1441
1450
  while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
1442
1451
  const line = _buffer.slice(0, newlineIdx).trim();
@@ -1744,7 +1753,7 @@ function disconnectClient() {
1744
1753
  entry.resolve({ error: "Client disconnected" });
1745
1754
  }
1746
1755
  }
1747
- 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;
1756
+ 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;
1748
1757
  var init_exe_daemon_client = __esm({
1749
1758
  "src/lib/exe-daemon-client.ts"() {
1750
1759
  "use strict";
@@ -1761,6 +1770,7 @@ var init_exe_daemon_client = __esm({
1761
1770
  _requestCount = 0;
1762
1771
  HEALTH_CHECK_INTERVAL = 100;
1763
1772
  _pending = /* @__PURE__ */ new Map();
1773
+ MAX_BUFFER = 1e7;
1764
1774
  }
1765
1775
  });
1766
1776
 
@@ -1833,12 +1843,13 @@ var init_embedder = __esm({
1833
1843
  });
1834
1844
 
1835
1845
  // src/lib/keychain.ts
1836
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
1846
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
1837
1847
  import { existsSync as existsSync3 } from "fs";
1838
1848
  import path3 from "path";
1849
+ import os2 from "os";
1839
1850
  import crypto from "crypto";
1840
1851
  function getKeyDir() {
1841
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(process.env.HOME ?? "/tmp", ".exe-os");
1852
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
1842
1853
  }
1843
1854
  function getKeyPath() {
1844
1855
  return path3.join(getKeyDir(), "master.key");
@@ -1895,7 +1906,7 @@ __export(shard_manager_exports, {
1895
1906
  shardExists: () => shardExists
1896
1907
  });
1897
1908
  import path4 from "path";
1898
- import { existsSync as existsSync4, mkdirSync } from "fs";
1909
+ import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
1899
1910
  import { createClient as createClient2 } from "@libsql/client";
1900
1911
  function initShardManager(encryptionKey) {
1901
1912
  _encryptionKey = encryptionKey;
@@ -1934,8 +1945,7 @@ function shardExists(projectName) {
1934
1945
  }
1935
1946
  function listShards() {
1936
1947
  if (!existsSync4(SHARDS_DIR)) return [];
1937
- const { readdirSync: readdirSync3 } = __require("fs");
1938
- return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1948
+ return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1939
1949
  }
1940
1950
  async function ensureShardSchema(client) {
1941
1951
  await client.execute("PRAGMA journal_mode = WAL");
@@ -2140,6 +2150,28 @@ __export(store_exports, {
2140
2150
  vectorToBlob: () => vectorToBlob,
2141
2151
  writeMemory: () => writeMemory
2142
2152
  });
2153
+ function isBusyError2(err) {
2154
+ if (err instanceof Error) {
2155
+ const msg = err.message.toLowerCase();
2156
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
2157
+ }
2158
+ return false;
2159
+ }
2160
+ async function retryOnBusy2(fn, label) {
2161
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
2162
+ try {
2163
+ return await fn();
2164
+ } catch (err) {
2165
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
2166
+ process.stderr.write(
2167
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
2168
+ `
2169
+ );
2170
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
2171
+ }
2172
+ }
2173
+ throw new Error("unreachable");
2174
+ }
2143
2175
  async function initStore(options) {
2144
2176
  if (_flushTimer !== null) {
2145
2177
  clearInterval(_flushTimer);
@@ -2168,14 +2200,17 @@ async function initStore(options) {
2168
2200
  dbPath,
2169
2201
  encryptionKey: hexKey
2170
2202
  });
2171
- await ensureSchema();
2203
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
2172
2204
  try {
2173
2205
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
2174
2206
  initShardManager2(hexKey);
2175
2207
  } catch {
2176
2208
  }
2177
2209
  const client = getClient();
2178
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
2210
+ const vResult = await retryOnBusy2(
2211
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
2212
+ "version-query"
2213
+ );
2179
2214
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
2180
2215
  }
2181
2216
  function classifyTier(record) {
@@ -2218,6 +2253,12 @@ async function writeMemory(record) {
2218
2253
  supersedes_id: record.supersedes_id ?? null
2219
2254
  };
2220
2255
  _pendingRecords.push(dbRow);
2256
+ const MAX_PENDING = 1e3;
2257
+ if (_pendingRecords.length > MAX_PENDING) {
2258
+ const dropped = _pendingRecords.length - MAX_PENDING;
2259
+ _pendingRecords = _pendingRecords.slice(-MAX_PENDING);
2260
+ console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
2261
+ }
2221
2262
  if (_flushTimer === null) {
2222
2263
  _flushTimer = setInterval(() => {
2223
2264
  void flushBatch();
@@ -2549,7 +2590,7 @@ async function getMemoryCardinality(agentId) {
2549
2590
  return 0;
2550
2591
  }
2551
2592
  }
2552
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2593
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
2553
2594
  var init_store = __esm({
2554
2595
  "src/lib/store.ts"() {
2555
2596
  "use strict";
@@ -2557,6 +2598,8 @@ var init_store = __esm({
2557
2598
  init_database();
2558
2599
  init_keychain();
2559
2600
  init_config();
2601
+ INIT_MAX_RETRIES = 3;
2602
+ INIT_RETRY_DELAY_MS = 1e3;
2560
2603
  _pendingRecords = [];
2561
2604
  _batchSize = 20;
2562
2605
  _flushIntervalMs = 1e4;
@@ -2584,12 +2627,30 @@ async function wikiFetch(config2, path20, method = "GET", body) {
2584
2627
  const controller = new AbortController();
2585
2628
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
2586
2629
  try {
2587
- const response = await fetch(url, {
2588
- method,
2589
- headers,
2590
- body: body ? JSON.stringify(body) : void 0,
2591
- signal: controller.signal
2592
- });
2630
+ let response;
2631
+ try {
2632
+ response = await fetch(url, {
2633
+ method,
2634
+ headers,
2635
+ body: body ? JSON.stringify(body) : void 0,
2636
+ signal: controller.signal
2637
+ });
2638
+ } catch {
2639
+ clearTimeout(timeout);
2640
+ const retryController = new AbortController();
2641
+ const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
2642
+ try {
2643
+ await new Promise((r) => setTimeout(r, 500));
2644
+ response = await fetch(url, {
2645
+ method,
2646
+ headers,
2647
+ body: body ? JSON.stringify(body) : void 0,
2648
+ signal: retryController.signal
2649
+ });
2650
+ } finally {
2651
+ clearTimeout(retryTimeout);
2652
+ }
2653
+ }
2593
2654
  if (!response.ok) {
2594
2655
  throw new Error(`Wiki API ${method} ${path20}: ${response.status} ${response.statusText}`);
2595
2656
  }
@@ -2703,12 +2764,22 @@ __export(license_exports, {
2703
2764
  loadLicense: () => loadLicense,
2704
2765
  mirrorLicenseKey: () => mirrorLicenseKey,
2705
2766
  saveLicense: () => saveLicense,
2767
+ startLicenseRevalidation: () => startLicenseRevalidation,
2768
+ stopLicenseRevalidation: () => stopLicenseRevalidation,
2706
2769
  validateLicense: () => validateLicense
2707
2770
  });
2708
2771
  import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
2709
2772
  import { randomUUID as randomUUID2 } from "crypto";
2710
2773
  import path5 from "path";
2711
2774
  import { jwtVerify, importSPKI } from "jose";
2775
+ async function fetchRetry(url, init) {
2776
+ try {
2777
+ return await fetch(url, init);
2778
+ } catch {
2779
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
2780
+ return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
2781
+ }
2782
+ }
2712
2783
  function loadDeviceId() {
2713
2784
  const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
2714
2785
  try {
@@ -2740,7 +2811,7 @@ function loadLicense() {
2740
2811
  }
2741
2812
  function saveLicense(apiKey) {
2742
2813
  mkdirSync2(EXE_AI_DIR, { recursive: true });
2743
- writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
2814
+ writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2744
2815
  }
2745
2816
  async function verifyLicenseJwt(token) {
2746
2817
  try {
@@ -2792,7 +2863,7 @@ function cacheResponse(token) {
2792
2863
  async function validateLicense(apiKey, deviceId) {
2793
2864
  const did = deviceId ?? loadDeviceId();
2794
2865
  try {
2795
- const res = await fetch(`${API_BASE}/auth/activate`, {
2866
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
2796
2867
  method: "POST",
2797
2868
  headers: { "Content-Type": "application/json" },
2798
2869
  body: JSON.stringify({ apiKey, deviceId: did }),
@@ -2827,14 +2898,23 @@ async function validateLicense(apiKey, deviceId) {
2827
2898
  } catch {
2828
2899
  const cached = await getCachedLicense();
2829
2900
  if (cached) return cached;
2830
- return FREE_LICENSE;
2901
+ return { ...FREE_LICENSE, valid: false, error: "offline" };
2902
+ }
2903
+ }
2904
+ function getCacheAgeMs() {
2905
+ try {
2906
+ const { statSync: statSync2 } = __require("fs");
2907
+ const s = statSync2(CACHE_PATH);
2908
+ return Date.now() - s.mtimeMs;
2909
+ } catch {
2910
+ return Infinity;
2831
2911
  }
2832
2912
  }
2833
2913
  async function checkLicense() {
2834
2914
  const key = loadLicense();
2835
2915
  if (!key) return FREE_LICENSE;
2836
2916
  const cached = await getCachedLicense();
2837
- if (cached) return cached;
2917
+ if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
2838
2918
  const deviceId = loadDeviceId();
2839
2919
  return validateLicense(key, deviceId);
2840
2920
  }
@@ -2874,7 +2954,7 @@ async function assertVpsLicense(opts) {
2874
2954
  let explicitRejection = false;
2875
2955
  let transientFailure = false;
2876
2956
  try {
2877
- const res = await fetch(`${API_BASE}/auth/activate`, {
2957
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
2878
2958
  method: "POST",
2879
2959
  headers: { "Content-Type": "application/json" },
2880
2960
  body: JSON.stringify({ apiKey, deviceId }),
@@ -2955,7 +3035,28 @@ async function assertVpsLicense(opts) {
2955
3035
  `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
2956
3036
  );
2957
3037
  }
2958
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE;
3038
+ function startLicenseRevalidation(intervalMs = 36e5) {
3039
+ if (_revalTimer) return;
3040
+ _revalTimer = setInterval(async () => {
3041
+ try {
3042
+ const license = await checkLicense();
3043
+ if (!license.valid) {
3044
+ process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
3045
+ }
3046
+ } catch {
3047
+ }
3048
+ }, intervalMs);
3049
+ if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
3050
+ _revalTimer.unref();
3051
+ }
3052
+ }
3053
+ function stopLicenseRevalidation() {
3054
+ if (_revalTimer) {
3055
+ clearInterval(_revalTimer);
3056
+ _revalTimer = null;
3057
+ }
3058
+ }
3059
+ 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, _revalTimer;
2959
3060
  var init_license = __esm({
2960
3061
  "src/lib/license.ts"() {
2961
3062
  "use strict";
@@ -2964,6 +3065,7 @@ var init_license = __esm({
2964
3065
  CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
2965
3066
  DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
2966
3067
  API_BASE = "https://askexe.com/cloud";
3068
+ RETRY_DELAY_MS = 500;
2967
3069
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
2968
3070
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2969
3071
  4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
@@ -2985,6 +3087,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2985
3087
  employeeLimit: 1,
2986
3088
  memoryLimit: 5e3
2987
3089
  };
3090
+ CACHE_MAX_AGE_MS = 36e5;
3091
+ _revalTimer = null;
2988
3092
  }
2989
3093
  });
2990
3094
 
@@ -3813,6 +3917,7 @@ __export(imessage_exports, {
3813
3917
  });
3814
3918
  import { execFile } from "child_process";
3815
3919
  import { promisify } from "util";
3920
+ import os3 from "os";
3816
3921
  import path6 from "path";
3817
3922
  var execFileAsync, POLL_INTERVAL_MS, MESSAGES_DB_PATH, IMessageAdapter;
3818
3923
  var init_imessage = __esm({
@@ -3821,7 +3926,7 @@ var init_imessage = __esm({
3821
3926
  execFileAsync = promisify(execFile);
3822
3927
  POLL_INTERVAL_MS = 5e3;
3823
3928
  MESSAGES_DB_PATH = path6.join(
3824
- process.env.HOME ?? "/Users",
3929
+ process.env.HOME ?? os3.homedir(),
3825
3930
  "Library/Messages/chat.db"
3826
3931
  );
3827
3932
  IMessageAdapter = class {
@@ -4287,7 +4392,7 @@ var init_whatsapp_accounts = __esm({
4287
4392
  // src/lib/session-registry.ts
4288
4393
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
4289
4394
  import path7 from "path";
4290
- import os2 from "os";
4395
+ import os4 from "os";
4291
4396
  function registerSession(entry) {
4292
4397
  const dir = path7.dirname(REGISTRY_PATH);
4293
4398
  if (!existsSync6(dir)) {
@@ -4314,7 +4419,7 @@ var REGISTRY_PATH;
4314
4419
  var init_session_registry = __esm({
4315
4420
  "src/lib/session-registry.ts"() {
4316
4421
  "use strict";
4317
- REGISTRY_PATH = path7.join(os2.homedir(), ".exe-os", "session-registry.json");
4422
+ REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
4318
4423
  }
4319
4424
  });
4320
4425
 
@@ -4536,7 +4641,7 @@ var init_provider_table = __esm({
4536
4641
  // src/lib/intercom-queue.ts
4537
4642
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
4538
4643
  import path8 from "path";
4539
- import os3 from "os";
4644
+ import os5 from "os";
4540
4645
  function ensureDir() {
4541
4646
  const dir = path8.dirname(QUEUE_PATH);
4542
4647
  if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
@@ -4576,9 +4681,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
4576
4681
  var init_intercom_queue = __esm({
4577
4682
  "src/lib/intercom-queue.ts"() {
4578
4683
  "use strict";
4579
- QUEUE_PATH = path8.join(os3.homedir(), ".exe-os", "intercom-queue.json");
4684
+ QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
4580
4685
  TTL_MS = 60 * 60 * 1e3;
4581
- INTERCOM_LOG = path8.join(os3.homedir(), ".exe-os", "intercom.log");
4686
+ INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
4582
4687
  }
4583
4688
  });
4584
4689
 
@@ -4696,7 +4801,7 @@ var init_plan_limits = __esm({
4696
4801
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
4697
4802
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, existsSync as existsSync10, appendFileSync } from "fs";
4698
4803
  import path11 from "path";
4699
- import os4 from "os";
4804
+ import os6 from "os";
4700
4805
  import { fileURLToPath as fileURLToPath2 } from "url";
4701
4806
  import { unlinkSync as unlinkSync2 } from "fs";
4702
4807
  function spawnLockPath(sessionName) {
@@ -5001,7 +5106,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5001
5106
  const transport = getTransport();
5002
5107
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
5003
5108
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
5004
- const logDir = path11.join(os4.homedir(), ".exe-os", "session-logs");
5109
+ const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
5005
5110
  const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5006
5111
  if (!existsSync10(logDir)) {
5007
5112
  mkdirSync6(logDir, { recursive: true });
@@ -5017,7 +5122,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5017
5122
  } catch {
5018
5123
  }
5019
5124
  try {
5020
- const claudeJsonPath = path11.join(os4.homedir(), ".claude.json");
5125
+ const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
5021
5126
  let claudeJson = {};
5022
5127
  try {
5023
5128
  claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
@@ -5032,7 +5137,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5032
5137
  } catch {
5033
5138
  }
5034
5139
  try {
5035
- const settingsDir = path11.join(os4.homedir(), ".claude", "projects");
5140
+ const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
5036
5141
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
5037
5142
  const projSettingsDir = path11.join(settingsDir, normalizedKey);
5038
5143
  const settingsPath = path11.join(projSettingsDir, "settings.json");
@@ -5080,7 +5185,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5080
5185
  let legacyFallbackWarned = false;
5081
5186
  if (!useExeAgent && !useBinSymlink) {
5082
5187
  const identityPath = path11.join(
5083
- os4.homedir(),
5188
+ os6.homedir(),
5084
5189
  ".exe-os",
5085
5190
  "identity",
5086
5191
  `${employeeName}.md`
@@ -5110,7 +5215,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5110
5215
  }
5111
5216
  let sessionContextFlag = "";
5112
5217
  try {
5113
- const ctxDir = path11.join(os4.homedir(), ".exe-os", "session-cache");
5218
+ const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
5114
5219
  mkdirSync6(ctxDir, { recursive: true });
5115
5220
  const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
5116
5221
  const ctxContent = [
@@ -5221,11 +5326,11 @@ var init_tmux_routing = __esm({
5221
5326
  init_provider_table();
5222
5327
  init_intercom_queue();
5223
5328
  init_plan_limits();
5224
- SPAWN_LOCK_DIR = path11.join(os4.homedir(), ".exe-os", "spawn-locks");
5225
- SESSION_CACHE = path11.join(os4.homedir(), ".exe-os", "session-cache");
5329
+ SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
5330
+ SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
5226
5331
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5227
5332
  INTERCOM_DEBOUNCE_MS = 3e4;
5228
- INTERCOM_LOG2 = path11.join(os4.homedir(), ".exe-os", "intercom.log");
5333
+ INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
5229
5334
  DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
5230
5335
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5231
5336
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -5485,10 +5590,10 @@ var init_messaging = __esm({
5485
5590
  // src/lib/notifications.ts
5486
5591
  import crypto4 from "crypto";
5487
5592
  import path12 from "path";
5488
- import os5 from "os";
5593
+ import os7 from "os";
5489
5594
  import {
5490
5595
  readFileSync as readFileSync10,
5491
- readdirSync,
5596
+ readdirSync as readdirSync2,
5492
5597
  unlinkSync as unlinkSync3,
5493
5598
  existsSync as existsSync11,
5494
5599
  rmdirSync
@@ -5937,7 +6042,7 @@ var init_tasks_crud = __esm({
5937
6042
 
5938
6043
  // src/lib/tasks-review.ts
5939
6044
  import path14 from "path";
5940
- import { existsSync as existsSync13, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
6045
+ import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
5941
6046
  async function countPendingReviews() {
5942
6047
  const client = getClient();
5943
6048
  const result = await client.execute({
@@ -6059,7 +6164,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
6059
6164
  try {
6060
6165
  const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
6061
6166
  if (existsSync13(cacheDir)) {
6062
- for (const f of readdirSync2(cacheDir)) {
6167
+ for (const f of readdirSync3(cacheDir)) {
6063
6168
  if (f.startsWith("review-notified-")) {
6064
6169
  unlinkSync4(path14.join(cacheDir, f));
6065
6170
  }
@@ -6802,7 +6907,7 @@ var init_tasks = __esm({
6802
6907
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
6803
6908
  import { randomUUID as randomUUID7 } from "crypto";
6804
6909
  import path18 from "path";
6805
- import os6 from "os";
6910
+ import os8 from "os";
6806
6911
  function substituteTemplate(template, record) {
6807
6912
  return template.replace(
6808
6913
  /\{\{(\w+(?:\.\w+)*)\}\}/g,
@@ -6880,7 +6985,7 @@ async function executeSendWhatsapp(params) {
6880
6985
  const message = params.message ?? params.text;
6881
6986
  if (!to || !message)
6882
6987
  throw new Error("send_whatsapp requires 'to' and 'message' params");
6883
- const url = `https://graph.facebook.com/v21.0/${account.phoneNumberId}/messages`;
6988
+ const url = `https://graph.facebook.com/${GRAPH_API_VERSION}/${account.phoneNumberId}/messages`;
6884
6989
  const res = await fetch(url, {
6885
6990
  method: "POST",
6886
6991
  headers: {
@@ -6892,7 +6997,8 @@ async function executeSendWhatsapp(params) {
6892
6997
  to,
6893
6998
  type: "text",
6894
6999
  text: { body: message }
6895
- })
7000
+ }),
7001
+ signal: AbortSignal.timeout(3e4)
6896
7002
  });
6897
7003
  if (!res.ok) {
6898
7004
  const errBody = await res.text();
@@ -7087,11 +7193,12 @@ async function processCRMEvent(event, executor, triggersOverride) {
7087
7193
  }
7088
7194
  return logs;
7089
7195
  }
7090
- var TRIGGERS_PATH;
7196
+ var TRIGGERS_PATH, GRAPH_API_VERSION;
7091
7197
  var init_trigger_engine = __esm({
7092
7198
  "src/automation/trigger-engine.ts"() {
7093
7199
  "use strict";
7094
- TRIGGERS_PATH = path18.join(os6.homedir(), ".exe-os", "triggers.json");
7200
+ TRIGGERS_PATH = path18.join(os8.homedir(), ".exe-os", "triggers.json");
7201
+ GRAPH_API_VERSION = "v21.0";
7095
7202
  }
7096
7203
  });
7097
7204
 
@@ -7155,7 +7262,7 @@ var init_crm_webhook = __esm({
7155
7262
  // src/bin/exe-gateway.ts
7156
7263
  import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
7157
7264
  import path19 from "path";
7158
- import os7 from "os";
7265
+ import os9 from "os";
7159
7266
 
7160
7267
  // src/gateway/webhook-server.ts
7161
7268
  import {
@@ -7979,7 +8086,7 @@ var BotRegistry = class {
7979
8086
  };
7980
8087
 
7981
8088
  // src/bin/exe-gateway.ts
7982
- var CONFIG_DIR = path19.join(os7.homedir(), ".exe-os");
8089
+ var CONFIG_DIR = path19.join(os9.homedir(), ".exe-os");
7983
8090
  var CONFIG_PATH3 = path19.join(CONFIG_DIR, "gateway.json");
7984
8091
  var DEFAULT_PORT = 3100;
7985
8092
  function loadConfig2() {
@@ -8135,6 +8242,8 @@ async function main() {
8135
8242
  console.log(`[exe-gateway] Ready on port ${port}`);
8136
8243
  }
8137
8244
  main().catch((err) => {
8138
- console.error("[exe-gateway] Fatal:", err);
8245
+ const msg = err instanceof Error ? err.message : String(err);
8246
+ console.error(`[exe-gateway] Fatal: ${msg}`);
8247
+ if (process.env.DEBUG) console.error(err);
8139
8248
  process.exit(1);
8140
8249
  });