@askexenow/exe-os 0.8.61 → 0.8.63

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 (62) hide show
  1. package/dist/bin/backfill-conversations.js +2 -3
  2. package/dist/bin/backfill-responses.js +3 -4
  3. package/dist/bin/backfill-vectors.js +0 -1
  4. package/dist/bin/cleanup-stale-review-tasks.js +0 -1
  5. package/dist/bin/cli.js +1654 -397
  6. package/dist/bin/exe-assign.js +0 -1
  7. package/dist/bin/exe-boot.js +61 -84
  8. package/dist/bin/exe-cloud.js +28 -60
  9. package/dist/bin/exe-dispatch.js +0 -1
  10. package/dist/bin/exe-doctor.js +0 -1
  11. package/dist/bin/exe-export-behaviors.js +1 -2
  12. package/dist/bin/exe-forget.js +0 -1
  13. package/dist/bin/exe-gateway.js +16 -17
  14. package/dist/bin/exe-heartbeat.js +1 -2
  15. package/dist/bin/exe-kill.js +2 -3
  16. package/dist/bin/exe-launch-agent.js +1 -2
  17. package/dist/bin/exe-link.js +49 -78
  18. package/dist/bin/exe-pending-messages.js +1 -2
  19. package/dist/bin/exe-pending-notifications.js +0 -1
  20. package/dist/bin/exe-pending-reviews.js +1 -2
  21. package/dist/bin/exe-review.js +0 -1
  22. package/dist/bin/exe-search.js +2 -3
  23. package/dist/bin/exe-session-cleanup.js +4 -5
  24. package/dist/bin/exe-status.js +0 -1
  25. package/dist/bin/exe-team.js +0 -1
  26. package/dist/bin/git-sweep.js +0 -1
  27. package/dist/bin/graph-backfill.js +5 -6
  28. package/dist/bin/graph-export.js +0 -1
  29. package/dist/bin/scan-tasks.js +0 -1
  30. package/dist/bin/setup.js +1460 -115
  31. package/dist/bin/shard-migrate.js +0 -1
  32. package/dist/bin/wiki-sync.js +0 -1
  33. package/dist/gateway/index.js +16 -17
  34. package/dist/hooks/bug-report-worker.js +11 -12
  35. package/dist/hooks/commit-complete.js +0 -1
  36. package/dist/hooks/error-recall.js +2 -3
  37. package/dist/hooks/ingest-worker.js +14 -15
  38. package/dist/hooks/instructions-loaded.js +0 -1
  39. package/dist/hooks/notification.js +0 -1
  40. package/dist/hooks/post-compact.js +0 -1
  41. package/dist/hooks/pre-compact.js +2 -3
  42. package/dist/hooks/pre-tool-use.js +0 -1
  43. package/dist/hooks/prompt-ingest-worker.js +2 -3
  44. package/dist/hooks/prompt-submit.js +6 -7
  45. package/dist/hooks/response-ingest-worker.js +2 -3
  46. package/dist/hooks/session-end.js +3 -4
  47. package/dist/hooks/session-start.js +2 -3
  48. package/dist/hooks/stop.js +2 -3
  49. package/dist/hooks/subagent-stop.js +0 -1
  50. package/dist/hooks/summary-worker.js +51 -74
  51. package/dist/index.js +7 -8
  52. package/dist/lib/cloud-sync.js +21 -12
  53. package/dist/lib/consolidation.js +0 -1
  54. package/dist/lib/exe-daemon.js +33 -65
  55. package/dist/lib/hybrid-search.js +2 -3
  56. package/dist/lib/keychain.js +19 -58
  57. package/dist/lib/schedules.js +2 -3
  58. package/dist/lib/store.js +0 -1
  59. package/dist/mcp/server.js +29 -30
  60. package/dist/runtime/index.js +2 -3
  61. package/dist/tui/App.js +24 -56
  62. package/package.json +1 -1
@@ -976,7 +976,6 @@ import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
976
976
  import { existsSync } from "fs";
977
977
  import path from "path";
978
978
  import os from "os";
979
- import crypto from "crypto";
980
979
  function getKeyDir() {
981
980
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
982
981
  }
@@ -1041,65 +1040,34 @@ async function deleteMasterKey() {
1041
1040
  await unlink(keyPath);
1042
1041
  }
1043
1042
  }
1044
- function exportMnemonic(key) {
1045
- if (key.length !== 32) {
1046
- throw new Error(`Key must be 32 bytes, got ${key.length}`);
1047
- }
1048
- const hash = crypto.createHash("sha256").update(key).digest();
1049
- const checksumByte = hash[0];
1050
- let bits = "";
1051
- for (const byte of key) {
1052
- bits += byte.toString(2).padStart(8, "0");
1053
- }
1054
- bits += checksumByte.toString(2).padStart(8, "0");
1055
- const words = [];
1056
- let wordlist;
1043
+ async function loadBip39() {
1057
1044
  try {
1058
- const bip39 = __require("bip39");
1059
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
1060
- if (!wordlist) throw new Error("no wordlist");
1045
+ return await import("bip39");
1061
1046
  } catch {
1062
- throw new Error("bip39 package required. Install with: npm install bip39");
1047
+ throw new Error(
1048
+ "bip39 package not found. Run: npm install -g bip39\nOr reinstall exe-os: npm install -g @askexenow/exe-os"
1049
+ );
1063
1050
  }
1064
- for (let i = 0; i < 264; i += 11) {
1065
- const index = parseInt(bits.slice(i, i + 11), 2);
1066
- words.push(wordlist[index]);
1051
+ }
1052
+ async function exportMnemonic(key) {
1053
+ if (key.length !== 32) {
1054
+ throw new Error(`Key must be 32 bytes, got ${key.length}`);
1067
1055
  }
1068
- return words.join(" ");
1056
+ const { entropyToMnemonic } = await loadBip39();
1057
+ return entropyToMnemonic(key.toString("hex"));
1069
1058
  }
1070
- function importMnemonic(mnemonic) {
1071
- const words = mnemonic.trim().split(/\s+/);
1059
+ async function importMnemonic(mnemonic) {
1060
+ const trimmed = mnemonic.trim();
1061
+ const words = trimmed.split(/\s+/);
1072
1062
  if (words.length !== 24) {
1073
1063
  throw new Error(`Expected 24 words, got ${words.length}`);
1074
1064
  }
1075
- let wordlist;
1076
- try {
1077
- const bip39 = __require("bip39");
1078
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
1079
- if (!wordlist) throw new Error("no wordlist");
1080
- } catch {
1081
- throw new Error("bip39 package required. Install with: npm install bip39");
1082
- }
1083
- let bits = "";
1084
- for (const word of words) {
1085
- const index = wordlist.indexOf(word.toLowerCase());
1086
- if (index === -1) {
1087
- throw new Error(`Invalid BIP39 word: "${word}"`);
1088
- }
1089
- bits += index.toString(2).padStart(11, "0");
1090
- }
1091
- const entropyBits = bits.slice(0, 256);
1092
- const checksumBits = bits.slice(256, 264);
1093
- const key = Buffer.alloc(32);
1094
- for (let i = 0; i < 32; i++) {
1095
- key[i] = parseInt(entropyBits.slice(i * 8, (i + 1) * 8), 2);
1065
+ const { validateMnemonic, mnemonicToEntropy } = await loadBip39();
1066
+ if (!validateMnemonic(trimmed)) {
1067
+ throw new Error("Invalid mnemonic \u2014 check for typos or missing words");
1096
1068
  }
1097
- const hash = crypto.createHash("sha256").update(key).digest();
1098
- const expectedChecksum = hash[0].toString(2).padStart(8, "0");
1099
- if (checksumBits !== expectedChecksum) {
1100
- throw new Error("Invalid mnemonic checksum");
1101
- }
1102
- return key;
1069
+ const entropy = mnemonicToEntropy(trimmed);
1070
+ return Buffer.from(entropy, "hex");
1103
1071
  }
1104
1072
  var SERVICE, ACCOUNT;
1105
1073
  var init_keychain = __esm({
@@ -1836,7 +1804,7 @@ ${p.content}`).join("\n\n");
1836
1804
  });
1837
1805
 
1838
1806
  // src/lib/notifications.ts
1839
- import crypto2 from "crypto";
1807
+ import crypto from "crypto";
1840
1808
  import path4 from "path";
1841
1809
  import os3 from "os";
1842
1810
  import {
@@ -1849,7 +1817,7 @@ import {
1849
1817
  async function writeNotification(notification) {
1850
1818
  try {
1851
1819
  const client = getClient();
1852
- const id = crypto2.randomUUID();
1820
+ const id = crypto.randomUUID();
1853
1821
  const now = (/* @__PURE__ */ new Date()).toISOString();
1854
1822
  await client.execute({
1855
1823
  sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
@@ -3258,13 +3226,13 @@ __export(crypto_exports, {
3258
3226
  initSyncCrypto: () => initSyncCrypto,
3259
3227
  isSyncCryptoInitialized: () => isSyncCryptoInitialized
3260
3228
  });
3261
- import crypto3 from "crypto";
3229
+ import crypto2 from "crypto";
3262
3230
  function initSyncCrypto(masterKey) {
3263
3231
  if (masterKey.length !== 32) {
3264
3232
  throw new Error(`Master key must be 32 bytes, got ${masterKey.length}`);
3265
3233
  }
3266
3234
  _syncKey = Buffer.from(
3267
- crypto3.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
3235
+ crypto2.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
3268
3236
  );
3269
3237
  }
3270
3238
  function isSyncCryptoInitialized() {
@@ -3278,8 +3246,8 @@ function requireSyncKey() {
3278
3246
  }
3279
3247
  function encryptSyncBlob(data) {
3280
3248
  const key = requireSyncKey();
3281
- const iv = crypto3.randomBytes(IV_LENGTH);
3282
- const cipher = crypto3.createCipheriv(ALGORITHM, key, iv);
3249
+ const iv = crypto2.randomBytes(IV_LENGTH);
3250
+ const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
3283
3251
  const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
3284
3252
  const tag = cipher.getAuthTag();
3285
3253
  return Buffer.concat([iv, encrypted, tag]).toString("base64");
@@ -3293,7 +3261,7 @@ function decryptSyncBlob(ciphertext) {
3293
3261
  const iv = combined.subarray(0, IV_LENGTH);
3294
3262
  const tag = combined.subarray(combined.length - TAG_LENGTH);
3295
3263
  const encrypted = combined.subarray(IV_LENGTH, combined.length - TAG_LENGTH);
3296
- const decipher = crypto3.createDecipheriv(ALGORITHM, key, iv);
3264
+ const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
3297
3265
  decipher.setAuthTag(tag);
3298
3266
  return Buffer.concat([decipher.update(encrypted), decipher.final()]);
3299
3267
  }
@@ -3358,7 +3326,7 @@ __export(cloud_sync_exports, {
3358
3326
  recordRosterDeletion: () => recordRosterDeletion
3359
3327
  });
3360
3328
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, existsSync as existsSync12, readdirSync as readdirSync4, mkdirSync as mkdirSync6, appendFileSync as appendFileSync2, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
3361
- import crypto4 from "crypto";
3329
+ import crypto3 from "crypto";
3362
3330
  import path13 from "path";
3363
3331
  import { homedir } from "os";
3364
3332
  function sqlSafe(v) {
@@ -3741,7 +3709,7 @@ function buildRosterBlob(paths) {
3741
3709
  }
3742
3710
  const deletedNames = consumeRosterDeletions();
3743
3711
  const content = JSON.stringify({ roster, identities, config, deletedNames });
3744
- const hash = crypto4.createHash("sha256").update(content).digest("hex").slice(0, 16);
3712
+ const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
3745
3713
  return { roster, identities, config, deletedNames, version: hash };
3746
3714
  }
3747
3715
  async function cloudPushRoster(config) {
@@ -3831,21 +3799,30 @@ async function mergeRosterFromRemote(remote, paths) {
3831
3799
  const localEmployees = await loadEmployees(rosterPath);
3832
3800
  const localNames = new Set(localEmployees.map((e) => e.name));
3833
3801
  let added = 0;
3802
+ let identitiesUpdated = 0;
3834
3803
  for (const remoteEmp of remote.roster) {
3835
- if (localNames.has(remoteEmp.name)) continue;
3836
- localEmployees.push(remoteEmp);
3837
- localNames.add(remoteEmp.name);
3838
- added++;
3839
- if (remote.identities[`${remoteEmp.name}.md`]) {
3804
+ if (!localNames.has(remoteEmp.name)) {
3805
+ localEmployees.push(remoteEmp);
3806
+ localNames.add(remoteEmp.name);
3807
+ added++;
3808
+ try {
3809
+ registerBinSymlinks(remoteEmp.name);
3810
+ } catch {
3811
+ }
3812
+ }
3813
+ const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
3814
+ if (remoteIdentity) {
3840
3815
  if (!existsSync12(identityDir)) mkdirSync6(identityDir, { recursive: true });
3841
3816
  const idPath = path13.join(identityDir, `${remoteEmp.name}.md`);
3842
- if (!existsSync12(idPath)) {
3843
- writeFileSync5(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
3817
+ let localIdentity = null;
3818
+ try {
3819
+ localIdentity = existsSync12(idPath) ? readFileSync9(idPath, "utf-8") : null;
3820
+ } catch {
3821
+ }
3822
+ if (localIdentity !== remoteIdentity) {
3823
+ writeFileSync5(idPath, remoteIdentity, "utf-8");
3824
+ identitiesUpdated++;
3844
3825
  }
3845
- }
3846
- try {
3847
- registerBinSymlinks(remoteEmp.name);
3848
- } catch {
3849
3826
  }
3850
3827
  }
3851
3828
  let removed = 0;
@@ -3867,7 +3844,7 @@ async function mergeRosterFromRemote(remote, paths) {
3867
3844
  } catch {
3868
3845
  }
3869
3846
  }
3870
- return { added };
3847
+ return { added, identitiesUpdated };
3871
3848
  });
3872
3849
  }
3873
3850
  async function cloudPushBlob(route, data, metaKey, config) {
@@ -4592,7 +4569,7 @@ function vectorToBlob(vector) {
4592
4569
  init_database();
4593
4570
  init_notifications();
4594
4571
  init_task_scope();
4595
- import crypto5 from "crypto";
4572
+ import crypto4 from "crypto";
4596
4573
  import { execSync as execSync4 } from "child_process";
4597
4574
  import { existsSync as existsSync13, mkdirSync as mkdirSync7, openSync as openSync3, closeSync as closeSync3 } from "fs";
4598
4575
  import path14 from "path";
@@ -4666,7 +4643,7 @@ async function main() {
4666
4643
  process.exit(0);
4667
4644
  }
4668
4645
  await writeMemory({
4669
- id: crypto5.randomUUID(),
4646
+ id: crypto4.randomUUID(),
4670
4647
  agent_id: agentId,
4671
4648
  agent_role: agentRole,
4672
4649
  session_id: `auto-summary-${Date.now()}`,
package/dist/index.js CHANGED
@@ -4219,7 +4219,6 @@ import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4
4219
4219
  import { existsSync as existsSync11 } from "fs";
4220
4220
  import path15 from "path";
4221
4221
  import os7 from "os";
4222
- import crypto6 from "crypto";
4223
4222
  function getKeyDir() {
4224
4223
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path15.join(os7.homedir(), ".exe-os");
4225
4224
  }
@@ -5379,7 +5378,7 @@ __export(error_detector_exports, {
5379
5378
  errorFingerprint: () => errorFingerprint,
5380
5379
  isExeOsError: () => isExeOsError
5381
5380
  });
5382
- import crypto7 from "crypto";
5381
+ import crypto6 from "crypto";
5383
5382
  function isRealStderr(stderr) {
5384
5383
  const lines = stderr.trim().split("\n");
5385
5384
  const meaningful = lines.filter(
@@ -5450,7 +5449,7 @@ function classifyError(errorText) {
5450
5449
  }
5451
5450
  function errorFingerprint(toolName, errorText) {
5452
5451
  const normalized = errorText.replace(/\d{4}-\d{2}-\d{2}T[\d:.]+Z/g, "TIMESTAMP").replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "UUID").replace(/\/Users\/[^\s]+/g, "PATH").replace(/:\d+:\d+/g, ":LINE:COL").slice(0, 200);
5453
- return crypto7.createHash("sha256").update(`${toolName}:${normalized}`).digest("hex").slice(0, 16);
5452
+ return crypto6.createHash("sha256").update(`${toolName}:${normalized}`).digest("hex").slice(0, 16);
5454
5453
  }
5455
5454
  var ERROR_PATTERNS, FILE_CONTENT_TOOLS, STDERR_IGNORE_PATTERNS, USER_ERROR_PATTERNS, SYSTEM_BUG_PATTERNS;
5456
5455
  var init_error_detector = __esm({
@@ -6399,10 +6398,10 @@ __export(messaging_exports, {
6399
6398
  sendMessage: () => sendMessage,
6400
6399
  setWsClientSend: () => setWsClientSend
6401
6400
  });
6402
- import crypto9 from "crypto";
6401
+ import crypto8 from "crypto";
6403
6402
  function generateUlid() {
6404
6403
  const timestamp = Date.now().toString(36).padStart(10, "0");
6405
- const random = crypto9.randomBytes(10).toString("hex").slice(0, 16);
6404
+ const random = crypto8.randomBytes(10).toString("hex").slice(0, 16);
6406
6405
  return (timestamp + random).toUpperCase();
6407
6406
  }
6408
6407
  function rowToMessage(row) {
@@ -9088,11 +9087,11 @@ init_crm_bridge();
9088
9087
 
9089
9088
  // src/lib/pipeline-router.ts
9090
9089
  init_database();
9091
- import crypto8 from "crypto";
9090
+ import crypto7 from "crypto";
9092
9091
  async function sinkConversationStore(msg, agentResponse, agentName) {
9093
9092
  try {
9094
9093
  const client = getClient();
9095
- const id = crypto8.randomUUID();
9094
+ const id = crypto7.randomUUID();
9096
9095
  const mediaJson = msg.media ? JSON.stringify(msg.media) : null;
9097
9096
  await client.execute({
9098
9097
  sql: `INSERT INTO conversations
@@ -9142,7 +9141,7 @@ async function sinkMemory(msg, agentResponse, agentName) {
9142
9141
  ].filter(Boolean).join("\n");
9143
9142
  const vector = await embed2(rawText);
9144
9143
  await writeMemory2({
9145
- id: crypto8.randomUUID(),
9144
+ id: crypto7.randomUUID(),
9146
9145
  agent_id: agentName ?? "gateway",
9147
9146
  agent_role: "gateway",
9148
9147
  session_id: `gateway-${msg.platform}`,
@@ -725,21 +725,30 @@ async function mergeRosterFromRemote(remote, paths) {
725
725
  const localEmployees = await loadEmployees(rosterPath);
726
726
  const localNames = new Set(localEmployees.map((e) => e.name));
727
727
  let added = 0;
728
+ let identitiesUpdated = 0;
728
729
  for (const remoteEmp of remote.roster) {
729
- if (localNames.has(remoteEmp.name)) continue;
730
- localEmployees.push(remoteEmp);
731
- localNames.add(remoteEmp.name);
732
- added++;
733
- if (remote.identities[`${remoteEmp.name}.md`]) {
730
+ if (!localNames.has(remoteEmp.name)) {
731
+ localEmployees.push(remoteEmp);
732
+ localNames.add(remoteEmp.name);
733
+ added++;
734
+ try {
735
+ registerBinSymlinks(remoteEmp.name);
736
+ } catch {
737
+ }
738
+ }
739
+ const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
740
+ if (remoteIdentity) {
734
741
  if (!existsSync4(identityDir)) mkdirSync2(identityDir, { recursive: true });
735
742
  const idPath = path4.join(identityDir, `${remoteEmp.name}.md`);
736
- if (!existsSync4(idPath)) {
737
- writeFileSync2(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
743
+ let localIdentity = null;
744
+ try {
745
+ localIdentity = existsSync4(idPath) ? readFileSync4(idPath, "utf-8") : null;
746
+ } catch {
747
+ }
748
+ if (localIdentity !== remoteIdentity) {
749
+ writeFileSync2(idPath, remoteIdentity, "utf-8");
750
+ identitiesUpdated++;
738
751
  }
739
- }
740
- try {
741
- registerBinSymlinks(remoteEmp.name);
742
- } catch {
743
752
  }
744
753
  }
745
754
  let removed = 0;
@@ -761,7 +770,7 @@ async function mergeRosterFromRemote(remote, paths) {
761
770
  } catch {
762
771
  }
763
772
  }
764
- return { added };
773
+ return { added, identitiesUpdated };
765
774
  });
766
775
  }
767
776
  async function cloudPushBlob(route, data, metaKey, config) {
@@ -127,7 +127,6 @@ import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
127
127
  import { existsSync } from "fs";
128
128
  import path from "path";
129
129
  import os from "os";
130
- import crypto from "crypto";
131
130
 
132
131
  // src/lib/store.ts
133
132
  init_config();
@@ -5135,7 +5135,6 @@ import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4
5135
5135
  import { existsSync as existsSync13 } from "fs";
5136
5136
  import path15 from "path";
5137
5137
  import os7 from "os";
5138
- import crypto6 from "crypto";
5139
5138
  function getKeyDir() {
5140
5139
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path15.join(os7.homedir(), ".exe-os");
5141
5140
  }
@@ -5200,65 +5199,34 @@ async function deleteMasterKey() {
5200
5199
  await unlink(keyPath);
5201
5200
  }
5202
5201
  }
5203
- function exportMnemonic(key) {
5204
- if (key.length !== 32) {
5205
- throw new Error(`Key must be 32 bytes, got ${key.length}`);
5206
- }
5207
- const hash = crypto6.createHash("sha256").update(key).digest();
5208
- const checksumByte = hash[0];
5209
- let bits = "";
5210
- for (const byte of key) {
5211
- bits += byte.toString(2).padStart(8, "0");
5212
- }
5213
- bits += checksumByte.toString(2).padStart(8, "0");
5214
- const words = [];
5215
- let wordlist;
5202
+ async function loadBip39() {
5216
5203
  try {
5217
- const bip39 = __require("bip39");
5218
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
5219
- if (!wordlist) throw new Error("no wordlist");
5204
+ return await import("bip39");
5220
5205
  } catch {
5221
- throw new Error("bip39 package required. Install with: npm install bip39");
5206
+ throw new Error(
5207
+ "bip39 package not found. Run: npm install -g bip39\nOr reinstall exe-os: npm install -g @askexenow/exe-os"
5208
+ );
5222
5209
  }
5223
- for (let i = 0; i < 264; i += 11) {
5224
- const index = parseInt(bits.slice(i, i + 11), 2);
5225
- words.push(wordlist[index]);
5210
+ }
5211
+ async function exportMnemonic(key) {
5212
+ if (key.length !== 32) {
5213
+ throw new Error(`Key must be 32 bytes, got ${key.length}`);
5226
5214
  }
5227
- return words.join(" ");
5215
+ const { entropyToMnemonic } = await loadBip39();
5216
+ return entropyToMnemonic(key.toString("hex"));
5228
5217
  }
5229
- function importMnemonic(mnemonic) {
5230
- const words = mnemonic.trim().split(/\s+/);
5218
+ async function importMnemonic(mnemonic) {
5219
+ const trimmed = mnemonic.trim();
5220
+ const words = trimmed.split(/\s+/);
5231
5221
  if (words.length !== 24) {
5232
5222
  throw new Error(`Expected 24 words, got ${words.length}`);
5233
5223
  }
5234
- let wordlist;
5235
- try {
5236
- const bip39 = __require("bip39");
5237
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
5238
- if (!wordlist) throw new Error("no wordlist");
5239
- } catch {
5240
- throw new Error("bip39 package required. Install with: npm install bip39");
5224
+ const { validateMnemonic, mnemonicToEntropy } = await loadBip39();
5225
+ if (!validateMnemonic(trimmed)) {
5226
+ throw new Error("Invalid mnemonic \u2014 check for typos or missing words");
5241
5227
  }
5242
- let bits = "";
5243
- for (const word of words) {
5244
- const index = wordlist.indexOf(word.toLowerCase());
5245
- if (index === -1) {
5246
- throw new Error(`Invalid BIP39 word: "${word}"`);
5247
- }
5248
- bits += index.toString(2).padStart(11, "0");
5249
- }
5250
- const entropyBits = bits.slice(0, 256);
5251
- const checksumBits = bits.slice(256, 264);
5252
- const key = Buffer.alloc(32);
5253
- for (let i = 0; i < 32; i++) {
5254
- key[i] = parseInt(entropyBits.slice(i * 8, (i + 1) * 8), 2);
5255
- }
5256
- const hash = crypto6.createHash("sha256").update(key).digest();
5257
- const expectedChecksum = hash[0].toString(2).padStart(8, "0");
5258
- if (checksumBits !== expectedChecksum) {
5259
- throw new Error("Invalid mnemonic checksum");
5260
- }
5261
- return key;
5228
+ const entropy = mnemonicToEntropy(trimmed);
5229
+ return Buffer.from(entropy, "hex");
5262
5230
  }
5263
5231
  var SERVICE, ACCOUNT;
5264
5232
  var init_keychain = __esm({
@@ -7354,13 +7322,13 @@ __export(graph_rag_exports, {
7354
7322
  resolveAlias: () => resolveAlias,
7355
7323
  storeExtraction: () => storeExtraction
7356
7324
  });
7357
- import crypto7 from "crypto";
7325
+ import crypto6 from "crypto";
7358
7326
  function normalizeEntityName(name) {
7359
7327
  return name.replace(/\s*\([^)]*\)\s*/g, "").trim().toLowerCase();
7360
7328
  }
7361
7329
  function entityId(name, type) {
7362
7330
  const normalized = normalizeEntityName(name);
7363
- return crypto7.createHash("sha256").update(`${normalized}::${type.toLowerCase()}`).digest("hex").slice(0, 16);
7331
+ return crypto6.createHash("sha256").update(`${normalized}::${type.toLowerCase()}`).digest("hex").slice(0, 16);
7364
7332
  }
7365
7333
  async function resolveAlias(client, name) {
7366
7334
  const normalized = normalizeEntityName(name);
@@ -7595,7 +7563,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
7595
7563
  const targetAlias = await resolveAlias(client, r.target);
7596
7564
  const sourceId = sourceAlias ?? entityId(r.source, r.sourceType);
7597
7565
  const targetId = targetAlias ?? entityId(r.target, r.targetType);
7598
- const relId = crypto7.randomUUID().slice(0, 16);
7566
+ const relId = crypto6.randomUUID().slice(0, 16);
7599
7567
  try {
7600
7568
  await client.execute({
7601
7569
  sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen)
@@ -7641,7 +7609,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
7641
7609
  }
7642
7610
  }
7643
7611
  for (const h of extraction.hyperedges) {
7644
- const hId = crypto7.randomUUID().slice(0, 16);
7612
+ const hId = crypto6.randomUUID().slice(0, 16);
7645
7613
  try {
7646
7614
  await client.execute({
7647
7615
  sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
@@ -7705,7 +7673,7 @@ async function extractBatch(client, batchSize = 50, model = "claude-haiku-4-5-20
7705
7673
  totalEntities += stored.entitiesStored;
7706
7674
  totalRelationships += stored.relationshipsStored;
7707
7675
  }
7708
- const contentHash = crypto7.createHash("sha256").update(rawContent).digest("hex").slice(0, 32);
7676
+ const contentHash = crypto6.createHash("sha256").update(rawContent).digest("hex").slice(0, 32);
7709
7677
  await client.execute({
7710
7678
  sql: "UPDATE memories SET graph_extracted = 1, content_hash = ?, graph_extracted_hash = ? WHERE id = ?",
7711
7679
  args: [contentHash, contentHash, memoryId]
@@ -7994,16 +7962,16 @@ __export(ws_auth_exports, {
7994
7962
  deriveWsAuthToken: () => deriveWsAuthToken,
7995
7963
  hashAuthToken: () => hashAuthToken
7996
7964
  });
7997
- import crypto8 from "crypto";
7965
+ import crypto7 from "crypto";
7998
7966
  function deriveWsAuthToken(masterKey) {
7999
- return Buffer.from(crypto8.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
7967
+ return Buffer.from(crypto7.hkdfSync("sha256", masterKey, "", WS_AUTH_HKDF_INFO, 32));
8000
7968
  }
8001
7969
  function deriveOrgId(masterKey) {
8002
- const raw = Buffer.from(crypto8.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
8003
- return crypto8.createHash("sha256").update(raw).digest("hex").slice(0, 32);
7970
+ const raw = Buffer.from(crypto7.hkdfSync("sha256", masterKey, "", ORG_ID_HKDF_INFO, 32));
7971
+ return crypto7.createHash("sha256").update(raw).digest("hex").slice(0, 32);
8004
7972
  }
8005
7973
  function hashAuthToken(token) {
8006
- return crypto8.createHash("sha256").update(token).digest("hex");
7974
+ return crypto7.createHash("sha256").update(token).digest("hex");
8007
7975
  }
8008
7976
  var WS_AUTH_HKDF_INFO, ORG_ID_HKDF_INFO;
8009
7977
  var init_ws_auth = __esm({
@@ -8021,7 +7989,7 @@ __export(device_registry_exports, {
8021
7989
  resolveTargetDevice: () => resolveTargetDevice,
8022
7990
  setFriendlyName: () => setFriendlyName
8023
7991
  });
8024
- import crypto9 from "crypto";
7992
+ import crypto8 from "crypto";
8025
7993
  import os8 from "os";
8026
7994
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync16 } from "fs";
8027
7995
  import path19 from "path";
@@ -8038,7 +8006,7 @@ function getDeviceInfo() {
8038
8006
  }
8039
8007
  const hostname = os8.hostname();
8040
8008
  const info = {
8041
- deviceId: crypto9.randomUUID(),
8009
+ deviceId: crypto8.randomUUID(),
8042
8010
  friendlyName: hostname.replace(/\./g, "-").toLowerCase(),
8043
8011
  hostname
8044
8012
  };
@@ -8286,10 +8254,10 @@ __export(messaging_exports, {
8286
8254
  sendMessage: () => sendMessage,
8287
8255
  setWsClientSend: () => setWsClientSend
8288
8256
  });
8289
- import crypto10 from "crypto";
8257
+ import crypto9 from "crypto";
8290
8258
  function generateUlid() {
8291
8259
  const timestamp = Date.now().toString(36).padStart(10, "0");
8292
- const random = crypto10.randomBytes(10).toString("hex").slice(0, 16);
8260
+ const random = crypto9.randomBytes(10).toString("hex").slice(0, 16);
8293
8261
  return (timestamp + random).toUpperCase();
8294
8262
  }
8295
8263
  function rowToMessage(row) {
@@ -937,7 +937,6 @@ import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
937
937
  import { existsSync } from "fs";
938
938
  import path from "path";
939
939
  import os from "os";
940
- import crypto from "crypto";
941
940
  function getKeyDir() {
942
941
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
943
942
  }
@@ -2752,7 +2751,7 @@ __export(file_grep_exports, {
2752
2751
  import { execSync as execSync2 } from "child_process";
2753
2752
  import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync5 } from "fs";
2754
2753
  import path6 from "path";
2755
- import crypto2 from "crypto";
2754
+ import crypto from "crypto";
2756
2755
  function hasRipgrep() {
2757
2756
  if (_hasRg === null) {
2758
2757
  try {
@@ -2785,7 +2784,7 @@ async function grepProjectFiles(query, projectRoot, options) {
2785
2784
  const chunkCtx = getChunkContext(hit.filePath, hit.lineNumber);
2786
2785
  const prefix = chunkCtx ? `[file: ${hit.filePath}:${hit.lineNumber} in ${chunkCtx}]` : `[file: ${hit.filePath}:${hit.lineNumber}]`;
2787
2786
  return {
2788
- id: crypto2.createHash("sha256").update(`${hit.filePath}:${hit.lineNumber}`).digest("hex").slice(0, 36),
2787
+ id: crypto.createHash("sha256").update(`${hit.filePath}:${hit.lineNumber}`).digest("hex").slice(0, 36),
2789
2788
  agent_id: "project",
2790
2789
  agent_role: "file",
2791
2790
  session_id: "file-grep",
@@ -1,16 +1,8 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/lib/keychain.ts
9
2
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
10
3
  import { existsSync } from "fs";
11
4
  import path from "path";
12
5
  import os from "os";
13
- import crypto from "crypto";
14
6
  var SERVICE = "exe-mem";
15
7
  var ACCOUNT = "master-key";
16
8
  function getKeyDir() {
@@ -77,65 +69,34 @@ async function deleteMasterKey() {
77
69
  await unlink(keyPath);
78
70
  }
79
71
  }
80
- function exportMnemonic(key) {
81
- if (key.length !== 32) {
82
- throw new Error(`Key must be 32 bytes, got ${key.length}`);
83
- }
84
- const hash = crypto.createHash("sha256").update(key).digest();
85
- const checksumByte = hash[0];
86
- let bits = "";
87
- for (const byte of key) {
88
- bits += byte.toString(2).padStart(8, "0");
89
- }
90
- bits += checksumByte.toString(2).padStart(8, "0");
91
- const words = [];
92
- let wordlist;
72
+ async function loadBip39() {
93
73
  try {
94
- const bip39 = __require("bip39");
95
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
96
- if (!wordlist) throw new Error("no wordlist");
74
+ return await import("bip39");
97
75
  } catch {
98
- throw new Error("bip39 package required. Install with: npm install bip39");
76
+ throw new Error(
77
+ "bip39 package not found. Run: npm install -g bip39\nOr reinstall exe-os: npm install -g @askexenow/exe-os"
78
+ );
99
79
  }
100
- for (let i = 0; i < 264; i += 11) {
101
- const index = parseInt(bits.slice(i, i + 11), 2);
102
- words.push(wordlist[index]);
80
+ }
81
+ async function exportMnemonic(key) {
82
+ if (key.length !== 32) {
83
+ throw new Error(`Key must be 32 bytes, got ${key.length}`);
103
84
  }
104
- return words.join(" ");
85
+ const { entropyToMnemonic } = await loadBip39();
86
+ return entropyToMnemonic(key.toString("hex"));
105
87
  }
106
- function importMnemonic(mnemonic) {
107
- const words = mnemonic.trim().split(/\s+/);
88
+ async function importMnemonic(mnemonic) {
89
+ const trimmed = mnemonic.trim();
90
+ const words = trimmed.split(/\s+/);
108
91
  if (words.length !== 24) {
109
92
  throw new Error(`Expected 24 words, got ${words.length}`);
110
93
  }
111
- let wordlist;
112
- try {
113
- const bip39 = __require("bip39");
114
- wordlist = bip39.wordlists?.english ?? bip39.default?.wordlists?.english;
115
- if (!wordlist) throw new Error("no wordlist");
116
- } catch {
117
- throw new Error("bip39 package required. Install with: npm install bip39");
118
- }
119
- let bits = "";
120
- for (const word of words) {
121
- const index = wordlist.indexOf(word.toLowerCase());
122
- if (index === -1) {
123
- throw new Error(`Invalid BIP39 word: "${word}"`);
124
- }
125
- bits += index.toString(2).padStart(11, "0");
126
- }
127
- const entropyBits = bits.slice(0, 256);
128
- const checksumBits = bits.slice(256, 264);
129
- const key = Buffer.alloc(32);
130
- for (let i = 0; i < 32; i++) {
131
- key[i] = parseInt(entropyBits.slice(i * 8, (i + 1) * 8), 2);
132
- }
133
- const hash = crypto.createHash("sha256").update(key).digest();
134
- const expectedChecksum = hash[0].toString(2).padStart(8, "0");
135
- if (checksumBits !== expectedChecksum) {
136
- throw new Error("Invalid mnemonic checksum");
94
+ const { validateMnemonic, mnemonicToEntropy } = await loadBip39();
95
+ if (!validateMnemonic(trimmed)) {
96
+ throw new Error("Invalid mnemonic \u2014 check for typos or missing words");
137
97
  }
138
- return key;
98
+ const entropy = mnemonicToEntropy(trimmed);
99
+ return Buffer.from(entropy, "hex");
139
100
  }
140
101
  export {
141
102
  deleteMasterKey,