@askexenow/exe-os 0.8.82 → 0.8.85

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 (97) hide show
  1. package/dist/bin/backfill-conversations.js +746 -595
  2. package/dist/bin/backfill-responses.js +745 -594
  3. package/dist/bin/backfill-vectors.js +312 -226
  4. package/dist/bin/cleanup-stale-review-tasks.js +97 -2
  5. package/dist/bin/cli.js +14360 -12525
  6. package/dist/bin/exe-agent.js +97 -88
  7. package/dist/bin/exe-assign.js +1003 -854
  8. package/dist/bin/exe-boot.js +1260 -323
  9. package/dist/bin/exe-call.js +10 -0
  10. package/dist/bin/exe-cloud.js +32 -9
  11. package/dist/bin/exe-dispatch.js +212 -36
  12. package/dist/bin/exe-doctor.js +403 -6
  13. package/dist/bin/exe-export-behaviors.js +175 -72
  14. package/dist/bin/exe-forget.js +97 -2
  15. package/dist/bin/exe-gateway.js +553 -174
  16. package/dist/bin/exe-healthcheck.js +1 -0
  17. package/dist/bin/exe-heartbeat.js +100 -5
  18. package/dist/bin/exe-kill.js +175 -72
  19. package/dist/bin/exe-launch-agent.js +189 -76
  20. package/dist/bin/exe-link.js +902 -80
  21. package/dist/bin/exe-new-employee.js +41 -11
  22. package/dist/bin/exe-pending-messages.js +96 -2
  23. package/dist/bin/exe-pending-notifications.js +97 -2
  24. package/dist/bin/exe-pending-reviews.js +98 -3
  25. package/dist/bin/exe-rename.js +577 -33
  26. package/dist/bin/exe-review.js +231 -73
  27. package/dist/bin/exe-search.js +989 -226
  28. package/dist/bin/exe-session-cleanup.js +4806 -1665
  29. package/dist/bin/exe-settings.js +20 -5
  30. package/dist/bin/exe-status.js +97 -2
  31. package/dist/bin/exe-team.js +97 -2
  32. package/dist/bin/git-sweep.js +901 -209
  33. package/dist/bin/graph-backfill.js +175 -72
  34. package/dist/bin/graph-export.js +175 -72
  35. package/dist/bin/install.js +38 -7
  36. package/dist/bin/list-providers.js +1 -0
  37. package/dist/bin/scan-tasks.js +906 -213
  38. package/dist/bin/setup.js +870 -271
  39. package/dist/bin/shard-migrate.js +175 -72
  40. package/dist/bin/update.js +4 -3
  41. package/dist/bin/wiki-sync.js +175 -72
  42. package/dist/gateway/index.js +550 -168
  43. package/dist/hooks/bug-report-worker.js +210 -25
  44. package/dist/hooks/commit-complete.js +899 -207
  45. package/dist/hooks/error-recall.js +988 -226
  46. package/dist/hooks/ingest-worker.js +1639 -1195
  47. package/dist/hooks/ingest.js +3 -0
  48. package/dist/hooks/instructions-loaded.js +707 -97
  49. package/dist/hooks/notification.js +699 -89
  50. package/dist/hooks/post-compact.js +714 -104
  51. package/dist/hooks/pre-compact.js +899 -207
  52. package/dist/hooks/pre-tool-use.js +742 -123
  53. package/dist/hooks/prompt-ingest-worker.js +245 -104
  54. package/dist/hooks/prompt-submit.js +995 -233
  55. package/dist/hooks/response-ingest-worker.js +245 -104
  56. package/dist/hooks/session-end.js +3941 -400
  57. package/dist/hooks/session-start.js +1001 -226
  58. package/dist/hooks/stop.js +725 -115
  59. package/dist/hooks/subagent-stop.js +714 -104
  60. package/dist/hooks/summary-worker.js +1970 -1336
  61. package/dist/index.js +1653 -1055
  62. package/dist/lib/cloud-sync.js +907 -86
  63. package/dist/lib/consolidation.js +2 -1
  64. package/dist/lib/database.js +642 -87
  65. package/dist/lib/db-daemon-client.js +503 -0
  66. package/dist/lib/device-registry.js +547 -7
  67. package/dist/lib/embedder.js +14 -28
  68. package/dist/lib/employee-templates.js +84 -74
  69. package/dist/lib/employees.js +9 -0
  70. package/dist/lib/exe-daemon-client.js +16 -29
  71. package/dist/lib/exe-daemon.js +1957 -924
  72. package/dist/lib/hybrid-search.js +988 -226
  73. package/dist/lib/identity.js +87 -67
  74. package/dist/lib/keychain.js +9 -1
  75. package/dist/lib/license.js +3 -3
  76. package/dist/lib/messaging.js +8 -1
  77. package/dist/lib/reminders.js +91 -74
  78. package/dist/lib/schedules.js +96 -2
  79. package/dist/lib/skill-learning.js +103 -85
  80. package/dist/lib/store.js +234 -73
  81. package/dist/lib/tasks.js +113 -24
  82. package/dist/lib/tmux-routing.js +122 -33
  83. package/dist/lib/token-spend.js +273 -0
  84. package/dist/lib/ws-client.js +11 -0
  85. package/dist/mcp/server.js +10874 -5546
  86. package/dist/mcp/tools/complete-reminder.js +94 -77
  87. package/dist/mcp/tools/create-reminder.js +94 -77
  88. package/dist/mcp/tools/create-task.js +810 -27
  89. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  90. package/dist/mcp/tools/list-reminders.js +94 -77
  91. package/dist/mcp/tools/list-tasks.js +31 -1
  92. package/dist/mcp/tools/send-message.js +8 -1
  93. package/dist/mcp/tools/update-task.js +39 -10
  94. package/dist/runtime/index.js +913 -221
  95. package/dist/tui/App.js +1000 -298
  96. package/package.json +6 -1
  97. package/src/commands/exe/build-adv.md +2 -2
@@ -227,6 +227,19 @@ var init_database = __esm({
227
227
  }
228
228
  });
229
229
 
230
+ // src/lib/crdt-sync.ts
231
+ import * as Y from "yjs";
232
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
233
+ import path4 from "path";
234
+ import { homedir } from "os";
235
+ var DEFAULT_STATE_PATH;
236
+ var init_crdt_sync = __esm({
237
+ "src/lib/crdt-sync.ts"() {
238
+ "use strict";
239
+ DEFAULT_STATE_PATH = path4.join(homedir(), ".exe-os", "crdt-state.bin");
240
+ }
241
+ });
242
+
230
243
  // src/bin/exe-settings.ts
231
244
  init_config();
232
245
  import { createInterface } from "readline";
@@ -236,6 +249,7 @@ import { realpathSync } from "fs";
236
249
  import { fileURLToPath } from "url";
237
250
  function isMainModule(importMetaUrl) {
238
251
  if (process.argv[1] == null) return false;
252
+ if (process.argv[1].includes("mcp/server")) return false;
239
253
  try {
240
254
  const scriptPath = realpathSync(process.argv[1]);
241
255
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -247,10 +261,10 @@ function isMainModule(importMetaUrl) {
247
261
 
248
262
  // src/lib/cloud-sync.ts
249
263
  init_database();
250
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync as unlinkSync2, openSync, closeSync } from "fs";
264
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
251
265
  import crypto2 from "crypto";
252
- import path4 from "path";
253
- import { homedir } from "os";
266
+ import path5 from "path";
267
+ import { homedir as homedir2 } from "os";
254
268
 
255
269
  // src/lib/crypto.ts
256
270
  import crypto from "crypto";
@@ -270,9 +284,10 @@ var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
270
284
 
271
285
  // src/lib/cloud-sync.ts
272
286
  init_config();
287
+ init_crdt_sync();
273
288
  init_employees();
274
289
  var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
275
- var ROSTER_LOCK_PATH = path4.join(EXE_AI_DIR, "roster-merge.lock");
290
+ var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
276
291
  function assertSecureEndpoint(endpoint) {
277
292
  if (endpoint.startsWith("https://")) return;
278
293
  if (endpoint.startsWith("http://")) {
@@ -287,7 +302,7 @@ function assertSecureEndpoint(endpoint) {
287
302
  );
288
303
  }
289
304
  }
290
- var ROSTER_DELETIONS_PATH = path4.join(EXE_AI_DIR, "roster-deletions.json");
305
+ var ROSTER_DELETIONS_PATH = path5.join(EXE_AI_DIR, "roster-deletions.json");
291
306
 
292
307
  // src/bin/exe-settings.ts
293
308
  function label(value) {
@@ -327,6 +327,12 @@ function getClient() {
327
327
  if (!_resilientClient) {
328
328
  throw new Error("Database client not initialized. Call initDatabase() first.");
329
329
  }
330
+ if (process.env.EXE_IS_DAEMON === "1") {
331
+ return _resilientClient;
332
+ }
333
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
334
+ return _daemonClient;
335
+ }
330
336
  return _resilientClient;
331
337
  }
332
338
  function getRawClient() {
@@ -815,6 +821,12 @@ async function ensureSchema() {
815
821
  } catch {
816
822
  }
817
823
  }
824
+ try {
825
+ await client.execute(
826
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
827
+ );
828
+ } catch {
829
+ }
818
830
  await client.executeMultiple(`
819
831
  CREATE TABLE IF NOT EXISTS entities (
820
832
  id TEXT PRIMARY KEY,
@@ -867,7 +879,30 @@ async function ensureSchema() {
867
879
  entity_id TEXT NOT NULL,
868
880
  PRIMARY KEY (hyperedge_id, entity_id)
869
881
  );
882
+
883
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
884
+ name,
885
+ content=entities,
886
+ content_rowid=rowid
887
+ );
888
+
889
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
890
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
891
+ END;
892
+
893
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
894
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
895
+ END;
896
+
897
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
898
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
899
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
900
+ END;
870
901
  `);
902
+ try {
903
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
904
+ } catch {
905
+ }
871
906
  await client.executeMultiple(`
872
907
  CREATE TABLE IF NOT EXISTS entity_aliases (
873
908
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1048,6 +1083,33 @@ async function ensureSchema() {
1048
1083
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1049
1084
  ON conversations(channel_id);
1050
1085
  `);
1086
+ await client.executeMultiple(`
1087
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1088
+ session_uuid TEXT PRIMARY KEY,
1089
+ agent_id TEXT NOT NULL,
1090
+ session_name TEXT,
1091
+ task_id TEXT,
1092
+ project_name TEXT,
1093
+ started_at TEXT NOT NULL
1094
+ );
1095
+
1096
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1097
+ ON session_agent_map(agent_id);
1098
+ `);
1099
+ try {
1100
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1101
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1102
+ await client.execute({
1103
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1104
+ SELECT session_id, agent_id, '', MIN(timestamp)
1105
+ FROM memories
1106
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1107
+ GROUP BY session_id, agent_id`,
1108
+ args: []
1109
+ });
1110
+ }
1111
+ } catch {
1112
+ }
1051
1113
  try {
1052
1114
  await client.execute({
1053
1115
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1181,8 +1243,30 @@ async function ensureSchema() {
1181
1243
  });
1182
1244
  } catch {
1183
1245
  }
1246
+ for (const col of [
1247
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1248
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1249
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1250
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1251
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1252
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1253
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1254
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1255
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1256
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1257
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1258
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1259
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1260
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1261
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1262
+ ]) {
1263
+ try {
1264
+ await client.execute(col);
1265
+ } catch {
1266
+ }
1267
+ }
1184
1268
  }
1185
- var _client, _resilientClient, initTurso;
1269
+ var _client, _resilientClient, _daemonClient, initTurso;
1186
1270
  var init_database = __esm({
1187
1271
  "src/lib/database.ts"() {
1188
1272
  "use strict";
@@ -1190,6 +1274,7 @@ var init_database = __esm({
1190
1274
  init_employees();
1191
1275
  _client = null;
1192
1276
  _resilientClient = null;
1277
+ _daemonClient = null;
1193
1278
  initTurso = initDatabase;
1194
1279
  }
1195
1280
  });
@@ -1986,6 +2071,7 @@ var init_task_scope = __esm({
1986
2071
  init_employees();
1987
2072
 
1988
2073
  // src/lib/store.ts
2074
+ import { createHash } from "crypto";
1989
2075
  init_database();
1990
2076
 
1991
2077
  // src/lib/keychain.ts
@@ -2021,12 +2107,20 @@ async function getMasterKey() {
2021
2107
  }
2022
2108
  const keyPath = getKeyPath();
2023
2109
  if (!existsSync3(keyPath)) {
2110
+ process.stderr.write(
2111
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2112
+ `
2113
+ );
2024
2114
  return null;
2025
2115
  }
2026
2116
  try {
2027
2117
  const content = await readFile3(keyPath, "utf-8");
2028
2118
  return Buffer.from(content.trim(), "base64");
2029
- } catch {
2119
+ } catch (err) {
2120
+ process.stderr.write(
2121
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
2122
+ `
2123
+ );
2030
2124
  return null;
2031
2125
  }
2032
2126
  }
@@ -2340,6 +2434,7 @@ import { realpathSync } from "fs";
2340
2434
  import { fileURLToPath } from "url";
2341
2435
  function isMainModule(importMetaUrl) {
2342
2436
  if (process.argv[1] == null) return false;
2437
+ if (process.argv[1].includes("mcp/server")) return false;
2343
2438
  try {
2344
2439
  const scriptPath = realpathSync(process.argv[1]);
2345
2440
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));
@@ -316,6 +316,12 @@ function getClient() {
316
316
  if (!_resilientClient) {
317
317
  throw new Error("Database client not initialized. Call initDatabase() first.");
318
318
  }
319
+ if (process.env.EXE_IS_DAEMON === "1") {
320
+ return _resilientClient;
321
+ }
322
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
323
+ return _daemonClient;
324
+ }
319
325
  return _resilientClient;
320
326
  }
321
327
  function getRawClient() {
@@ -804,6 +810,12 @@ async function ensureSchema() {
804
810
  } catch {
805
811
  }
806
812
  }
813
+ try {
814
+ await client.execute(
815
+ `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
816
+ );
817
+ } catch {
818
+ }
807
819
  await client.executeMultiple(`
808
820
  CREATE TABLE IF NOT EXISTS entities (
809
821
  id TEXT PRIMARY KEY,
@@ -856,7 +868,30 @@ async function ensureSchema() {
856
868
  entity_id TEXT NOT NULL,
857
869
  PRIMARY KEY (hyperedge_id, entity_id)
858
870
  );
871
+
872
+ CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
873
+ name,
874
+ content=entities,
875
+ content_rowid=rowid
876
+ );
877
+
878
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
879
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
880
+ END;
881
+
882
+ CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
883
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
884
+ END;
885
+
886
+ CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
887
+ INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
888
+ INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
889
+ END;
859
890
  `);
891
+ try {
892
+ await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
893
+ } catch {
894
+ }
860
895
  await client.executeMultiple(`
861
896
  CREATE TABLE IF NOT EXISTS entity_aliases (
862
897
  alias TEXT NOT NULL PRIMARY KEY,
@@ -1037,6 +1072,33 @@ async function ensureSchema() {
1037
1072
  CREATE INDEX IF NOT EXISTS idx_conversations_channel
1038
1073
  ON conversations(channel_id);
1039
1074
  `);
1075
+ await client.executeMultiple(`
1076
+ CREATE TABLE IF NOT EXISTS session_agent_map (
1077
+ session_uuid TEXT PRIMARY KEY,
1078
+ agent_id TEXT NOT NULL,
1079
+ session_name TEXT,
1080
+ task_id TEXT,
1081
+ project_name TEXT,
1082
+ started_at TEXT NOT NULL
1083
+ );
1084
+
1085
+ CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
1086
+ ON session_agent_map(agent_id);
1087
+ `);
1088
+ try {
1089
+ const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
1090
+ if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
1091
+ await client.execute({
1092
+ sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
1093
+ SELECT session_id, agent_id, '', MIN(timestamp)
1094
+ FROM memories
1095
+ WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
1096
+ GROUP BY session_id, agent_id`,
1097
+ args: []
1098
+ });
1099
+ }
1100
+ } catch {
1101
+ }
1040
1102
  try {
1041
1103
  await client.execute({
1042
1104
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
@@ -1170,8 +1232,30 @@ async function ensureSchema() {
1170
1232
  });
1171
1233
  } catch {
1172
1234
  }
1235
+ for (const col of [
1236
+ "ALTER TABLE memories ADD COLUMN intent TEXT",
1237
+ "ALTER TABLE memories ADD COLUMN outcome TEXT",
1238
+ "ALTER TABLE memories ADD COLUMN domain TEXT",
1239
+ "ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
1240
+ "ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
1241
+ "ALTER TABLE memories ADD COLUMN chain_position TEXT",
1242
+ "ALTER TABLE memories ADD COLUMN review_status TEXT",
1243
+ "ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
1244
+ "ALTER TABLE memories ADD COLUMN file_paths TEXT",
1245
+ "ALTER TABLE memories ADD COLUMN commit_hash TEXT",
1246
+ "ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
1247
+ "ALTER TABLE memories ADD COLUMN token_cost REAL",
1248
+ "ALTER TABLE memories ADD COLUMN audience TEXT",
1249
+ "ALTER TABLE memories ADD COLUMN language_type TEXT",
1250
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
1251
+ ]) {
1252
+ try {
1253
+ await client.execute(col);
1254
+ } catch {
1255
+ }
1256
+ }
1173
1257
  }
1174
- var _client, _resilientClient, initTurso;
1258
+ var _client, _resilientClient, _daemonClient, initTurso;
1175
1259
  var init_database = __esm({
1176
1260
  "src/lib/database.ts"() {
1177
1261
  "use strict";
@@ -1179,6 +1263,7 @@ var init_database = __esm({
1179
1263
  init_employees();
1180
1264
  _client = null;
1181
1265
  _resilientClient = null;
1266
+ _daemonClient = null;
1182
1267
  initTurso = initDatabase;
1183
1268
  }
1184
1269
  });
@@ -1613,6 +1698,7 @@ ${p.content}`).join("\n\n");
1613
1698
  init_employees();
1614
1699
 
1615
1700
  // src/lib/store.ts
1701
+ import { createHash } from "crypto";
1616
1702
  init_database();
1617
1703
 
1618
1704
  // src/lib/keychain.ts
@@ -1648,12 +1734,20 @@ async function getMasterKey() {
1648
1734
  }
1649
1735
  const keyPath = getKeyPath();
1650
1736
  if (!existsSync3(keyPath)) {
1737
+ process.stderr.write(
1738
+ `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1739
+ `
1740
+ );
1651
1741
  return null;
1652
1742
  }
1653
1743
  try {
1654
1744
  const content = await readFile3(keyPath, "utf-8");
1655
1745
  return Buffer.from(content.trim(), "base64");
1656
- } catch {
1746
+ } catch (err) {
1747
+ process.stderr.write(
1748
+ `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
1749
+ `
1750
+ );
1657
1751
  return null;
1658
1752
  }
1659
1753
  }
@@ -1796,6 +1890,7 @@ import { realpathSync } from "fs";
1796
1890
  import { fileURLToPath } from "url";
1797
1891
  function isMainModule(importMetaUrl) {
1798
1892
  if (process.argv[1] == null) return false;
1893
+ if (process.argv[1].includes("mcp/server")) return false;
1799
1894
  try {
1800
1895
  const scriptPath = realpathSync(process.argv[1]);
1801
1896
  const modulePath = realpathSync(fileURLToPath(importMetaUrl));