@askexenow/exe-os 0.9.8 → 0.9.9

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 (101) hide show
  1. package/dist/bin/backfill-conversations.js +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
@@ -70,9 +70,34 @@ var init_db_retry = __esm({
70
70
  }
71
71
  });
72
72
 
73
+ // src/lib/secure-files.ts
74
+ import { chmodSync, existsSync, mkdirSync } from "fs";
75
+ import { chmod, mkdir } from "fs/promises";
76
+ async function ensurePrivateDir(dirPath) {
77
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
78
+ try {
79
+ await chmod(dirPath, PRIVATE_DIR_MODE);
80
+ } catch {
81
+ }
82
+ }
83
+ async function enforcePrivateFile(filePath) {
84
+ try {
85
+ await chmod(filePath, PRIVATE_FILE_MODE);
86
+ } catch {
87
+ }
88
+ }
89
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
90
+ var init_secure_files = __esm({
91
+ "src/lib/secure-files.ts"() {
92
+ "use strict";
93
+ PRIVATE_DIR_MODE = 448;
94
+ PRIVATE_FILE_MODE = 384;
95
+ }
96
+ });
97
+
73
98
  // src/lib/config.ts
74
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
75
- import { readFileSync, existsSync, renameSync } from "fs";
99
+ import { readFile, writeFile } from "fs/promises";
100
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
76
101
  import path from "path";
77
102
  import os from "os";
78
103
  function resolveDataDir() {
@@ -80,7 +105,7 @@ function resolveDataDir() {
80
105
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
81
106
  const newDir = path.join(os.homedir(), ".exe-os");
82
107
  const legacyDir = path.join(os.homedir(), ".exe-mem");
83
- if (!existsSync(newDir) && existsSync(legacyDir)) {
108
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
84
109
  try {
85
110
  renameSync(legacyDir, newDir);
86
111
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -143,9 +168,9 @@ function normalizeAutoUpdate(raw) {
143
168
  }
144
169
  async function loadConfig() {
145
170
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
146
- await mkdir(dir, { recursive: true });
171
+ await ensurePrivateDir(dir);
147
172
  const configPath = path.join(dir, "config.json");
148
- if (!existsSync(configPath)) {
173
+ if (!existsSync2(configPath)) {
149
174
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
150
175
  }
151
176
  const raw = await readFile(configPath, "utf-8");
@@ -158,6 +183,7 @@ async function loadConfig() {
158
183
  `);
159
184
  try {
160
185
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
186
+ await enforcePrivateFile(configPath);
161
187
  } catch {
162
188
  }
163
189
  }
@@ -177,6 +203,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
177
203
  var init_config = __esm({
178
204
  "src/lib/config.ts"() {
179
205
  "use strict";
206
+ init_secure_files();
180
207
  EXE_AI_DIR = resolveDataDir();
181
208
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
182
209
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -255,7 +282,7 @@ var init_config = __esm({
255
282
 
256
283
  // src/lib/employees.ts
257
284
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
258
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
285
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
259
286
  import { execSync } from "child_process";
260
287
  import path2 from "path";
261
288
  import os2 from "os";
@@ -272,7 +299,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
272
299
  return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
273
300
  }
274
301
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
275
- if (!existsSync2(employeesPath)) return [];
302
+ if (!existsSync3(employeesPath)) return [];
276
303
  try {
277
304
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
278
305
  } catch {
@@ -1217,6 +1244,7 @@ async function ensureSchema() {
1217
1244
  project TEXT NOT NULL,
1218
1245
  summary TEXT NOT NULL,
1219
1246
  task_file TEXT,
1247
+ session_scope TEXT,
1220
1248
  read INTEGER NOT NULL DEFAULT 0,
1221
1249
  created_at TEXT NOT NULL
1222
1250
  );
@@ -1225,7 +1253,7 @@ async function ensureSchema() {
1225
1253
  ON notifications(read);
1226
1254
 
1227
1255
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
1228
- ON notifications(agent_id);
1256
+ ON notifications(agent_id, session_scope);
1229
1257
 
1230
1258
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
1231
1259
  ON notifications(task_file);
@@ -1263,6 +1291,7 @@ async function ensureSchema() {
1263
1291
  target_agent TEXT NOT NULL,
1264
1292
  target_project TEXT,
1265
1293
  target_device TEXT NOT NULL DEFAULT 'local',
1294
+ session_scope TEXT,
1266
1295
  content TEXT NOT NULL,
1267
1296
  priority TEXT DEFAULT 'normal',
1268
1297
  status TEXT DEFAULT 'pending',
@@ -1276,10 +1305,31 @@ async function ensureSchema() {
1276
1305
  );
1277
1306
 
1278
1307
  CREATE INDEX IF NOT EXISTS idx_messages_target
1279
- ON messages(target_agent, status);
1308
+ ON messages(target_agent, session_scope, status);
1280
1309
 
1281
1310
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
1282
- ON messages(target_agent, from_agent, server_seq);
1311
+ ON messages(target_agent, session_scope, from_agent, server_seq);
1312
+ `);
1313
+ try {
1314
+ await client.execute({
1315
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
1316
+ args: []
1317
+ });
1318
+ } catch {
1319
+ }
1320
+ try {
1321
+ await client.execute({
1322
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
1323
+ args: []
1324
+ });
1325
+ } catch {
1326
+ }
1327
+ await client.executeMultiple(`
1328
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
1329
+ ON notifications(agent_id, session_scope, read, created_at);
1330
+
1331
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
1332
+ ON messages(target_agent, session_scope, status, created_at);
1283
1333
  `);
1284
1334
  try {
1285
1335
  await client.execute({
@@ -1863,6 +1913,13 @@ async function ensureSchema() {
1863
1913
  } catch {
1864
1914
  }
1865
1915
  }
1916
+ try {
1917
+ await client.execute({
1918
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
1919
+ args: []
1920
+ });
1921
+ } catch {
1922
+ }
1866
1923
  }
1867
1924
  var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso;
1868
1925
  var init_database = __esm({
@@ -1885,6 +1942,7 @@ var shard_manager_exports = {};
1885
1942
  __export(shard_manager_exports, {
1886
1943
  disposeShards: () => disposeShards,
1887
1944
  ensureShardSchema: () => ensureShardSchema,
1945
+ getOpenShardCount: () => getOpenShardCount,
1888
1946
  getReadyShardClient: () => getReadyShardClient,
1889
1947
  getShardClient: () => getShardClient,
1890
1948
  getShardsDir: () => getShardsDir,
@@ -1894,14 +1952,17 @@ __export(shard_manager_exports, {
1894
1952
  shardExists: () => shardExists
1895
1953
  });
1896
1954
  import path5 from "path";
1897
- import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
1955
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
1898
1956
  import { createClient as createClient2 } from "@libsql/client";
1899
1957
  function initShardManager(encryptionKey) {
1900
1958
  _encryptionKey = encryptionKey;
1901
- if (!existsSync4(SHARDS_DIR)) {
1902
- mkdirSync(SHARDS_DIR, { recursive: true });
1959
+ if (!existsSync5(SHARDS_DIR)) {
1960
+ mkdirSync2(SHARDS_DIR, { recursive: true });
1903
1961
  }
1904
1962
  _shardingEnabled = true;
1963
+ if (_evictionTimer) clearInterval(_evictionTimer);
1964
+ _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
1965
+ _evictionTimer.unref();
1905
1966
  }
1906
1967
  function isShardingEnabled() {
1907
1968
  return _shardingEnabled;
@@ -1918,21 +1979,28 @@ function getShardClient(projectName) {
1918
1979
  throw new Error(`Invalid project name for shard: "${projectName}"`);
1919
1980
  }
1920
1981
  const cached = _shards.get(safeName);
1921
- if (cached) return cached;
1982
+ if (cached) {
1983
+ _shardLastAccess.set(safeName, Date.now());
1984
+ return cached;
1985
+ }
1986
+ while (_shards.size >= MAX_OPEN_SHARDS) {
1987
+ evictLRU();
1988
+ }
1922
1989
  const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
1923
1990
  const client = createClient2({
1924
1991
  url: `file:${dbPath}`,
1925
1992
  encryptionKey: _encryptionKey
1926
1993
  });
1927
1994
  _shards.set(safeName, client);
1995
+ _shardLastAccess.set(safeName, Date.now());
1928
1996
  return client;
1929
1997
  }
1930
1998
  function shardExists(projectName) {
1931
1999
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
1932
- return existsSync4(path5.join(SHARDS_DIR, `${safeName}.db`));
2000
+ return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
1933
2001
  }
1934
2002
  function listShards() {
1935
- if (!existsSync4(SHARDS_DIR)) return [];
2003
+ if (!existsSync5(SHARDS_DIR)) return [];
1936
2004
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1937
2005
  }
1938
2006
  async function ensureShardSchema(client) {
@@ -1984,6 +2052,8 @@ async function ensureShardSchema(client) {
1984
2052
  for (const col of [
1985
2053
  "ALTER TABLE memories ADD COLUMN task_id TEXT",
1986
2054
  "ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
2055
+ "ALTER TABLE memories ADD COLUMN author_device_id TEXT",
2056
+ "ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
1987
2057
  "ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
1988
2058
  "ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
1989
2059
  "ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
@@ -2121,21 +2191,69 @@ async function getReadyShardClient(projectName) {
2121
2191
  await ensureShardSchema(client);
2122
2192
  return client;
2123
2193
  }
2194
+ function evictLRU() {
2195
+ let oldest = null;
2196
+ let oldestTime = Infinity;
2197
+ for (const [name, time] of _shardLastAccess) {
2198
+ if (time < oldestTime) {
2199
+ oldestTime = time;
2200
+ oldest = name;
2201
+ }
2202
+ }
2203
+ if (oldest) {
2204
+ const client = _shards.get(oldest);
2205
+ if (client) {
2206
+ client.close();
2207
+ }
2208
+ _shards.delete(oldest);
2209
+ _shardLastAccess.delete(oldest);
2210
+ }
2211
+ }
2212
+ function evictIdleShards() {
2213
+ const now = Date.now();
2214
+ const toEvict = [];
2215
+ for (const [name, lastAccess] of _shardLastAccess) {
2216
+ if (now - lastAccess > SHARD_IDLE_MS) {
2217
+ toEvict.push(name);
2218
+ }
2219
+ }
2220
+ for (const name of toEvict) {
2221
+ const client = _shards.get(name);
2222
+ if (client) {
2223
+ client.close();
2224
+ }
2225
+ _shards.delete(name);
2226
+ _shardLastAccess.delete(name);
2227
+ }
2228
+ }
2229
+ function getOpenShardCount() {
2230
+ return _shards.size;
2231
+ }
2124
2232
  function disposeShards() {
2233
+ if (_evictionTimer) {
2234
+ clearInterval(_evictionTimer);
2235
+ _evictionTimer = null;
2236
+ }
2125
2237
  for (const [, client] of _shards) {
2126
2238
  client.close();
2127
2239
  }
2128
2240
  _shards.clear();
2241
+ _shardLastAccess.clear();
2129
2242
  _shardingEnabled = false;
2130
2243
  _encryptionKey = null;
2131
2244
  }
2132
- var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
2245
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
2133
2246
  var init_shard_manager = __esm({
2134
2247
  "src/lib/shard-manager.ts"() {
2135
2248
  "use strict";
2136
2249
  init_config();
2137
2250
  SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
2251
+ SHARD_IDLE_MS = 5 * 60 * 1e3;
2252
+ MAX_OPEN_SHARDS = 10;
2253
+ EVICTION_INTERVAL_MS = 60 * 1e3;
2138
2254
  _shards = /* @__PURE__ */ new Map();
2255
+ _shardLastAccess = /* @__PURE__ */ new Map();
2256
+ _evictionTimer = null;
2139
2257
  _encryptionKey = null;
2140
2258
  _shardingEnabled = false;
2141
2259
  }
@@ -2338,11 +2456,11 @@ __export(worker_gate_exports, {
2338
2456
  tryAcquireBackfillLock: () => tryAcquireBackfillLock,
2339
2457
  tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
2340
2458
  });
2341
- import { readdirSync as readdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
2459
+ import { readdirSync as readdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3, existsSync as existsSync6 } from "fs";
2342
2460
  import path6 from "path";
2343
2461
  function tryAcquireWorkerSlot() {
2344
2462
  try {
2345
- mkdirSync2(WORKER_PID_DIR, { recursive: true });
2463
+ mkdirSync3(WORKER_PID_DIR, { recursive: true });
2346
2464
  const reservationId = `res-${process.pid}-${Date.now()}`;
2347
2465
  const reservationPath = path6.join(WORKER_PID_DIR, `${reservationId}.pid`);
2348
2466
  writeFileSync2(reservationPath, String(process.pid));
@@ -2385,7 +2503,7 @@ function tryAcquireWorkerSlot() {
2385
2503
  }
2386
2504
  function registerWorkerPid(pid) {
2387
2505
  try {
2388
- mkdirSync2(WORKER_PID_DIR, { recursive: true });
2506
+ mkdirSync3(WORKER_PID_DIR, { recursive: true });
2389
2507
  writeFileSync2(path6.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
2390
2508
  } catch {
2391
2509
  }
@@ -2398,8 +2516,8 @@ function cleanupWorkerPid() {
2398
2516
  }
2399
2517
  function tryAcquireBackfillLock() {
2400
2518
  try {
2401
- mkdirSync2(WORKER_PID_DIR, { recursive: true });
2402
- if (existsSync5(BACKFILL_LOCK)) {
2519
+ mkdirSync3(WORKER_PID_DIR, { recursive: true });
2520
+ if (existsSync6(BACKFILL_LOCK)) {
2403
2521
  try {
2404
2522
  const pid = parseInt(
2405
2523
  __require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
@@ -2447,7 +2565,7 @@ init_database();
2447
2565
 
2448
2566
  // src/lib/keychain.ts
2449
2567
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2450
- import { existsSync as existsSync3 } from "fs";
2568
+ import { existsSync as existsSync4 } from "fs";
2451
2569
  import path4 from "path";
2452
2570
  import os4 from "os";
2453
2571
  var SERVICE = "exe-mem";
@@ -2477,7 +2595,7 @@ async function getMasterKey() {
2477
2595
  }
2478
2596
  }
2479
2597
  const keyPath = getKeyPath();
2480
- if (!existsSync3(keyPath)) {
2598
+ if (!existsSync4(keyPath)) {
2481
2599
  process.stderr.write(
2482
2600
  `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2483
2601
  `
@@ -2647,7 +2765,7 @@ function isMainModule(importMetaUrl) {
2647
2765
  }
2648
2766
 
2649
2767
  // src/bin/exe-doctor.ts
2650
- import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
2768
+ import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
2651
2769
  import { spawn } from "child_process";
2652
2770
  import path7 from "path";
2653
2771
  import { randomUUID as randomUUID2 } from "crypto";
@@ -3052,7 +3170,7 @@ async function auditOrphanedProjects(client) {
3052
3170
  for (const row of result.rows) {
3053
3171
  const name = row.project_name;
3054
3172
  const count = Number(row.cnt);
3055
- const exists = existsSync6(path7.join(home, name)) || existsSync6(path7.join(home, "..", name)) || existsSync6(path7.join(process.cwd(), "..", name));
3173
+ const exists = existsSync7(path7.join(home, name)) || existsSync7(path7.join(home, "..", name)) || existsSync7(path7.join(process.cwd(), "..", name));
3056
3174
  if (!exists) {
3057
3175
  orphans.push({ project_name: name, count });
3058
3176
  }
@@ -3066,7 +3184,7 @@ function auditHookHealth() {
3066
3184
  "logs",
3067
3185
  "hooks.log"
3068
3186
  );
3069
- if (!existsSync6(logPath)) {
3187
+ if (!existsSync7(logPath)) {
3070
3188
  return { logExists: false, totalLines: 0, errorsLastHour: 0, topPatterns: [] };
3071
3189
  }
3072
3190
  let content;