@askexenow/exe-os 0.9.30 → 0.9.32

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 (64) hide show
  1. package/dist/bin/backfill-conversations.js +135 -7
  2. package/dist/bin/backfill-responses.js +135 -7
  3. package/dist/bin/backfill-vectors.js +135 -7
  4. package/dist/bin/cleanup-stale-review-tasks.js +139 -11
  5. package/dist/bin/cli.js +812 -486
  6. package/dist/bin/exe-assign.js +135 -7
  7. package/dist/bin/exe-boot.js +422 -113
  8. package/dist/bin/exe-cloud.js +160 -9
  9. package/dist/bin/exe-dispatch.js +136 -8
  10. package/dist/bin/exe-doctor.js +255 -13
  11. package/dist/bin/exe-export-behaviors.js +136 -8
  12. package/dist/bin/exe-forget.js +136 -8
  13. package/dist/bin/exe-gateway.js +171 -24
  14. package/dist/bin/exe-heartbeat.js +141 -13
  15. package/dist/bin/exe-kill.js +140 -12
  16. package/dist/bin/exe-launch-agent.js +143 -15
  17. package/dist/bin/exe-link.js +357 -48
  18. package/dist/bin/exe-pending-messages.js +136 -8
  19. package/dist/bin/exe-pending-notifications.js +136 -8
  20. package/dist/bin/exe-pending-reviews.js +138 -10
  21. package/dist/bin/exe-review.js +136 -8
  22. package/dist/bin/exe-search.js +155 -20
  23. package/dist/bin/exe-session-cleanup.js +166 -38
  24. package/dist/bin/exe-start-codex.js +142 -14
  25. package/dist/bin/exe-start-opencode.js +140 -12
  26. package/dist/bin/exe-status.js +148 -20
  27. package/dist/bin/exe-team.js +136 -8
  28. package/dist/bin/git-sweep.js +138 -10
  29. package/dist/bin/graph-backfill.js +135 -7
  30. package/dist/bin/graph-export.js +136 -8
  31. package/dist/bin/intercom-check.js +153 -25
  32. package/dist/bin/scan-tasks.js +138 -10
  33. package/dist/bin/setup.js +447 -121
  34. package/dist/bin/shard-migrate.js +135 -7
  35. package/dist/gateway/index.js +151 -23
  36. package/dist/hooks/bug-report-worker.js +151 -23
  37. package/dist/hooks/codex-stop-task-finalizer.js +145 -17
  38. package/dist/hooks/commit-complete.js +138 -10
  39. package/dist/hooks/error-recall.js +159 -24
  40. package/dist/hooks/ingest.js +142 -14
  41. package/dist/hooks/instructions-loaded.js +136 -8
  42. package/dist/hooks/notification.js +136 -8
  43. package/dist/hooks/post-compact.js +136 -8
  44. package/dist/hooks/post-tool-combined.js +159 -24
  45. package/dist/hooks/pre-compact.js +136 -8
  46. package/dist/hooks/pre-tool-use.js +144 -16
  47. package/dist/hooks/prompt-submit.js +195 -55
  48. package/dist/hooks/session-end.js +141 -13
  49. package/dist/hooks/session-start.js +165 -30
  50. package/dist/hooks/stop.js +136 -8
  51. package/dist/hooks/subagent-stop.js +136 -8
  52. package/dist/hooks/summary-worker.js +374 -65
  53. package/dist/index.js +136 -8
  54. package/dist/lib/cloud-sync.js +355 -46
  55. package/dist/lib/consolidation.js +1 -0
  56. package/dist/lib/exe-daemon.js +469 -127
  57. package/dist/lib/hybrid-search.js +155 -20
  58. package/dist/lib/keychain.js +191 -7
  59. package/dist/lib/schedules.js +138 -10
  60. package/dist/lib/store.js +135 -7
  61. package/dist/mcp/server.js +706 -213
  62. package/dist/runtime/index.js +136 -8
  63. package/dist/tui/App.js +208 -31
  64. package/package.json +1 -1
@@ -18,6 +18,7 @@ var __export = (target, all) => {
18
18
  // src/lib/keychain.ts
19
19
  import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
20
20
  import { existsSync } from "fs";
21
+ import { execSync } from "child_process";
21
22
  import path from "path";
22
23
  import os from "os";
23
24
  function getKeyDir() {
@@ -26,6 +27,59 @@ function getKeyDir() {
26
27
  function getKeyPath() {
27
28
  return path.join(getKeyDir(), "master.key");
28
29
  }
30
+ function macKeychainGet() {
31
+ if (process.platform !== "darwin") return null;
32
+ try {
33
+ return execSync(
34
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
35
+ { encoding: "utf-8", timeout: 5e3 }
36
+ ).trim();
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ function macKeychainSet(value) {
42
+ if (process.platform !== "darwin") return false;
43
+ try {
44
+ try {
45
+ execSync(
46
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
47
+ { timeout: 5e3 }
48
+ );
49
+ } catch {
50
+ }
51
+ execSync(
52
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
53
+ { timeout: 5e3 }
54
+ );
55
+ return true;
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+ function linuxSecretGet() {
61
+ if (process.platform !== "linux") return null;
62
+ try {
63
+ return execSync(
64
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
65
+ { encoding: "utf-8", timeout: 5e3 }
66
+ ).trim();
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+ function linuxSecretSet(value) {
72
+ if (process.platform !== "linux") return false;
73
+ try {
74
+ execSync(
75
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
76
+ { timeout: 5e3 }
77
+ );
78
+ return true;
79
+ } catch {
80
+ return false;
81
+ }
82
+ }
29
83
  async function tryKeytar() {
30
84
  try {
31
85
  return await import("keytar");
@@ -33,13 +87,72 @@ async function tryKeytar() {
33
87
  return null;
34
88
  }
35
89
  }
90
+ function deriveMachineKey() {
91
+ try {
92
+ const crypto4 = __require("crypto");
93
+ const material = [
94
+ os.hostname(),
95
+ os.userInfo().username,
96
+ os.arch(),
97
+ os.platform(),
98
+ // Machine ID on Linux (stable across reboots)
99
+ process.platform === "linux" ? readMachineId() : ""
100
+ ].join("|");
101
+ return crypto4.createHash("sha256").update(material).digest();
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
106
+ function readMachineId() {
107
+ try {
108
+ const { readFileSync: readFileSync6 } = __require("fs");
109
+ return readFileSync6("/etc/machine-id", "utf-8").trim();
110
+ } catch {
111
+ return "";
112
+ }
113
+ }
114
+ function encryptWithMachineKey(plaintext, machineKey) {
115
+ const crypto4 = __require("crypto");
116
+ const iv = crypto4.randomBytes(12);
117
+ const cipher = crypto4.createCipheriv("aes-256-gcm", machineKey, iv);
118
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
119
+ encrypted += cipher.final("base64");
120
+ const authTag = cipher.getAuthTag().toString("base64");
121
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
122
+ }
123
+ function decryptWithMachineKey(encrypted, machineKey) {
124
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
125
+ try {
126
+ const crypto4 = __require("crypto");
127
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
128
+ if (parts.length !== 3) return null;
129
+ const [ivB64, tagB64, cipherB64] = parts;
130
+ const iv = Buffer.from(ivB64, "base64");
131
+ const authTag = Buffer.from(tagB64, "base64");
132
+ const decipher = crypto4.createDecipheriv("aes-256-gcm", machineKey, iv);
133
+ decipher.setAuthTag(authTag);
134
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
135
+ decrypted += decipher.final("utf-8");
136
+ return decrypted;
137
+ } catch {
138
+ return null;
139
+ }
140
+ }
36
141
  async function getMasterKey() {
142
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
143
+ if (nativeValue) {
144
+ return Buffer.from(nativeValue, "base64");
145
+ }
37
146
  const keytar = await tryKeytar();
38
147
  if (keytar) {
39
148
  try {
40
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
41
- if (stored) {
42
- return Buffer.from(stored, "base64");
149
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
150
+ if (keytarValue) {
151
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
152
+ if (migrated) {
153
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
154
+ }
155
+ return Buffer.from(keytarValue, "base64");
43
156
  }
44
157
  } catch {
45
158
  }
@@ -53,8 +166,31 @@ async function getMasterKey() {
53
166
  return null;
54
167
  }
55
168
  try {
56
- const content = await readFile(keyPath, "utf-8");
57
- return Buffer.from(content.trim(), "base64");
169
+ const content = (await readFile(keyPath, "utf-8")).trim();
170
+ let b64Value;
171
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
172
+ const machineKey = deriveMachineKey();
173
+ if (!machineKey) {
174
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
175
+ return null;
176
+ }
177
+ const decrypted = decryptWithMachineKey(content, machineKey);
178
+ if (!decrypted) {
179
+ process.stderr.write(
180
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
181
+ );
182
+ return null;
183
+ }
184
+ b64Value = decrypted;
185
+ } else {
186
+ b64Value = content;
187
+ }
188
+ const key = Buffer.from(b64Value, "base64");
189
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
190
+ if (migrated) {
191
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
192
+ }
193
+ return key;
58
194
  } catch (err) {
59
195
  process.stderr.write(
60
196
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -65,6 +201,9 @@ async function getMasterKey() {
65
201
  }
66
202
  async function setMasterKey(key) {
67
203
  const b64 = key.toString("base64");
204
+ if (macKeychainSet(b64) || linuxSecretSet(b64)) {
205
+ return;
206
+ }
68
207
  const keytar = await tryKeytar();
69
208
  if (keytar) {
70
209
  try {
@@ -76,8 +215,19 @@ async function setMasterKey(key) {
76
215
  const dir = getKeyDir();
77
216
  await mkdir(dir, { recursive: true });
78
217
  const keyPath = getKeyPath();
79
- await writeFile(keyPath, b64 + "\n", "utf-8");
80
- await chmod(keyPath, 384);
218
+ const machineKey = deriveMachineKey();
219
+ if (machineKey) {
220
+ const encrypted = encryptWithMachineKey(b64, machineKey);
221
+ await writeFile(keyPath, encrypted + "\n", "utf-8");
222
+ await chmod(keyPath, 384);
223
+ process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
224
+ } else {
225
+ await writeFile(keyPath, b64 + "\n", "utf-8");
226
+ await chmod(keyPath, 384);
227
+ process.stderr.write(
228
+ "[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
229
+ );
230
+ }
81
231
  }
82
232
  async function loadBip39() {
83
233
  try {
@@ -108,12 +258,13 @@ async function importMnemonic(mnemonic) {
108
258
  const entropy = mnemonicToEntropy(trimmed);
109
259
  return Buffer.from(entropy, "hex");
110
260
  }
111
- var SERVICE, ACCOUNT;
261
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
112
262
  var init_keychain = __esm({
113
263
  "src/lib/keychain.ts"() {
114
264
  "use strict";
115
265
  SERVICE = "exe-mem";
116
266
  ACCOUNT = "master-key";
267
+ ENCRYPTED_PREFIX = "enc:";
117
268
  }
118
269
  });
119
270
 
@@ -344,7 +495,7 @@ var init_db_retry = __esm({
344
495
  // src/lib/employees.ts
345
496
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
346
497
  import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
347
- import { execSync } from "child_process";
498
+ import { execSync as execSync2 } from "child_process";
348
499
  import path3 from "path";
349
500
  import os3 from "os";
350
501
  var EMPLOYEES_PATH, IDENTITY_DIR;
@@ -1619,8 +1619,8 @@ function findPackageRoot() {
1619
1619
  function getAvailableMemoryGB() {
1620
1620
  if (process.platform === "darwin") {
1621
1621
  try {
1622
- const { execSync: execSync7 } = __require("child_process");
1623
- const vmstat = execSync7("vm_stat", { encoding: "utf8" });
1622
+ const { execSync: execSync8 } = __require("child_process");
1623
+ const vmstat = execSync8("vm_stat", { encoding: "utf8" });
1624
1624
  const pageSize = 16384;
1625
1625
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1626
1626
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -6514,6 +6514,7 @@ var init_tmux_routing = __esm({
6514
6514
  // src/lib/keychain.ts
6515
6515
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
6516
6516
  import { existsSync as existsSync15 } from "fs";
6517
+ import { execSync as execSync7 } from "child_process";
6517
6518
  import path18 from "path";
6518
6519
  import os11 from "os";
6519
6520
  function getKeyDir() {
@@ -6522,6 +6523,59 @@ function getKeyDir() {
6522
6523
  function getKeyPath() {
6523
6524
  return path18.join(getKeyDir(), "master.key");
6524
6525
  }
6526
+ function macKeychainGet() {
6527
+ if (process.platform !== "darwin") return null;
6528
+ try {
6529
+ return execSync7(
6530
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
6531
+ { encoding: "utf-8", timeout: 5e3 }
6532
+ ).trim();
6533
+ } catch {
6534
+ return null;
6535
+ }
6536
+ }
6537
+ function macKeychainSet(value) {
6538
+ if (process.platform !== "darwin") return false;
6539
+ try {
6540
+ try {
6541
+ execSync7(
6542
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
6543
+ { timeout: 5e3 }
6544
+ );
6545
+ } catch {
6546
+ }
6547
+ execSync7(
6548
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
6549
+ { timeout: 5e3 }
6550
+ );
6551
+ return true;
6552
+ } catch {
6553
+ return false;
6554
+ }
6555
+ }
6556
+ function linuxSecretGet() {
6557
+ if (process.platform !== "linux") return null;
6558
+ try {
6559
+ return execSync7(
6560
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
6561
+ { encoding: "utf-8", timeout: 5e3 }
6562
+ ).trim();
6563
+ } catch {
6564
+ return null;
6565
+ }
6566
+ }
6567
+ function linuxSecretSet(value) {
6568
+ if (process.platform !== "linux") return false;
6569
+ try {
6570
+ execSync7(
6571
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
6572
+ { timeout: 5e3 }
6573
+ );
6574
+ return true;
6575
+ } catch {
6576
+ return false;
6577
+ }
6578
+ }
6525
6579
  async function tryKeytar() {
6526
6580
  try {
6527
6581
  return await import("keytar");
@@ -6529,13 +6583,63 @@ async function tryKeytar() {
6529
6583
  return null;
6530
6584
  }
6531
6585
  }
6586
+ function deriveMachineKey() {
6587
+ try {
6588
+ const crypto7 = __require("crypto");
6589
+ const material = [
6590
+ os11.hostname(),
6591
+ os11.userInfo().username,
6592
+ os11.arch(),
6593
+ os11.platform(),
6594
+ // Machine ID on Linux (stable across reboots)
6595
+ process.platform === "linux" ? readMachineId() : ""
6596
+ ].join("|");
6597
+ return crypto7.createHash("sha256").update(material).digest();
6598
+ } catch {
6599
+ return null;
6600
+ }
6601
+ }
6602
+ function readMachineId() {
6603
+ try {
6604
+ const { readFileSync: readFileSync13 } = __require("fs");
6605
+ return readFileSync13("/etc/machine-id", "utf-8").trim();
6606
+ } catch {
6607
+ return "";
6608
+ }
6609
+ }
6610
+ function decryptWithMachineKey(encrypted, machineKey) {
6611
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
6612
+ try {
6613
+ const crypto7 = __require("crypto");
6614
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
6615
+ if (parts.length !== 3) return null;
6616
+ const [ivB64, tagB64, cipherB64] = parts;
6617
+ const iv = Buffer.from(ivB64, "base64");
6618
+ const authTag = Buffer.from(tagB64, "base64");
6619
+ const decipher = crypto7.createDecipheriv("aes-256-gcm", machineKey, iv);
6620
+ decipher.setAuthTag(authTag);
6621
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
6622
+ decrypted += decipher.final("utf-8");
6623
+ return decrypted;
6624
+ } catch {
6625
+ return null;
6626
+ }
6627
+ }
6532
6628
  async function getMasterKey() {
6629
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
6630
+ if (nativeValue) {
6631
+ return Buffer.from(nativeValue, "base64");
6632
+ }
6533
6633
  const keytar = await tryKeytar();
6534
6634
  if (keytar) {
6535
6635
  try {
6536
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
6537
- if (stored) {
6538
- return Buffer.from(stored, "base64");
6636
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
6637
+ if (keytarValue) {
6638
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
6639
+ if (migrated) {
6640
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
6641
+ }
6642
+ return Buffer.from(keytarValue, "base64");
6539
6643
  }
6540
6644
  } catch {
6541
6645
  }
@@ -6549,8 +6653,31 @@ async function getMasterKey() {
6549
6653
  return null;
6550
6654
  }
6551
6655
  try {
6552
- const content = await readFile4(keyPath, "utf-8");
6553
- return Buffer.from(content.trim(), "base64");
6656
+ const content = (await readFile4(keyPath, "utf-8")).trim();
6657
+ let b64Value;
6658
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
6659
+ const machineKey = deriveMachineKey();
6660
+ if (!machineKey) {
6661
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
6662
+ return null;
6663
+ }
6664
+ const decrypted = decryptWithMachineKey(content, machineKey);
6665
+ if (!decrypted) {
6666
+ process.stderr.write(
6667
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
6668
+ );
6669
+ return null;
6670
+ }
6671
+ b64Value = decrypted;
6672
+ } else {
6673
+ b64Value = content;
6674
+ }
6675
+ const key = Buffer.from(b64Value, "base64");
6676
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
6677
+ if (migrated) {
6678
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
6679
+ }
6680
+ return key;
6554
6681
  } catch (err) {
6555
6682
  process.stderr.write(
6556
6683
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -6559,12 +6686,13 @@ async function getMasterKey() {
6559
6686
  return null;
6560
6687
  }
6561
6688
  }
6562
- var SERVICE, ACCOUNT;
6689
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
6563
6690
  var init_keychain = __esm({
6564
6691
  "src/lib/keychain.ts"() {
6565
6692
  "use strict";
6566
6693
  SERVICE = "exe-mem";
6567
6694
  ACCOUNT = "master-key";
6695
+ ENCRYPTED_PREFIX = "enc:";
6568
6696
  }
6569
6697
  });
6570
6698