@askexenow/exe-os 0.9.113 → 0.9.115

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 (86) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +36 -12
  2. package/dist/bin/agentic-reflection-backfill.js +36 -12
  3. package/dist/bin/agentic-semantic-label.js +36 -12
  4. package/dist/bin/backfill-conversations.js +36 -12
  5. package/dist/bin/backfill-responses.js +36 -12
  6. package/dist/bin/backfill-vectors.js +36 -12
  7. package/dist/bin/bulk-sync-postgres.js +36 -12
  8. package/dist/bin/cleanup-stale-review-tasks.js +470 -113
  9. package/dist/bin/cli.js +413 -62
  10. package/dist/bin/exe-agent.js +27 -0
  11. package/dist/bin/exe-assign.js +36 -12
  12. package/dist/bin/exe-boot.js +246 -54
  13. package/dist/bin/exe-call.js +8 -0
  14. package/dist/bin/exe-cloud.js +47 -12
  15. package/dist/bin/exe-dispatch.js +348 -53
  16. package/dist/bin/exe-doctor.js +51 -13
  17. package/dist/bin/exe-export-behaviors.js +37 -12
  18. package/dist/bin/exe-forget.js +36 -12
  19. package/dist/bin/exe-gateway.js +348 -53
  20. package/dist/bin/exe-heartbeat.js +471 -113
  21. package/dist/bin/exe-kill.js +36 -12
  22. package/dist/bin/exe-launch-agent.js +117 -18
  23. package/dist/bin/exe-new-employee.js +9 -1
  24. package/dist/bin/exe-pending-messages.js +452 -95
  25. package/dist/bin/exe-pending-notifications.js +452 -95
  26. package/dist/bin/exe-pending-reviews.js +452 -95
  27. package/dist/bin/exe-rename.js +36 -12
  28. package/dist/bin/exe-review.js +36 -12
  29. package/dist/bin/exe-search.js +37 -12
  30. package/dist/bin/exe-session-cleanup.js +348 -53
  31. package/dist/bin/exe-settings.js +12 -0
  32. package/dist/bin/exe-start-codex.js +46 -13
  33. package/dist/bin/exe-start-opencode.js +46 -13
  34. package/dist/bin/exe-status.js +460 -114
  35. package/dist/bin/exe-support.js +12 -0
  36. package/dist/bin/exe-team.js +36 -12
  37. package/dist/bin/git-sweep.js +348 -53
  38. package/dist/bin/graph-backfill.js +36 -12
  39. package/dist/bin/graph-export.js +36 -12
  40. package/dist/bin/install.js +9 -1
  41. package/dist/bin/intercom-check.js +255 -53
  42. package/dist/bin/scan-tasks.js +348 -53
  43. package/dist/bin/setup.js +74 -12
  44. package/dist/bin/shard-migrate.js +36 -12
  45. package/dist/gateway/index.js +348 -53
  46. package/dist/hooks/bug-report-worker.js +348 -53
  47. package/dist/hooks/codex-stop-task-finalizer.js +308 -37
  48. package/dist/hooks/commit-complete.js +348 -53
  49. package/dist/hooks/error-recall.js +37 -12
  50. package/dist/hooks/ingest.js +363 -54
  51. package/dist/hooks/instructions-loaded.js +36 -12
  52. package/dist/hooks/notification.js +36 -12
  53. package/dist/hooks/post-compact.js +426 -72
  54. package/dist/hooks/post-tool-combined.js +501 -146
  55. package/dist/hooks/pre-compact.js +348 -53
  56. package/dist/hooks/pre-tool-use.js +92 -13
  57. package/dist/hooks/prompt-submit.js +348 -53
  58. package/dist/hooks/session-end.js +158 -53
  59. package/dist/hooks/session-start.js +66 -13
  60. package/dist/hooks/stop.js +420 -72
  61. package/dist/hooks/subagent-stop.js +419 -72
  62. package/dist/hooks/summary-worker.js +442 -121
  63. package/dist/index.js +375 -53
  64. package/dist/lib/agent-config.js +8 -0
  65. package/dist/lib/cloud-sync.js +35 -12
  66. package/dist/lib/config.js +13 -0
  67. package/dist/lib/consolidation.js +9 -1
  68. package/dist/lib/embedder.js +13 -0
  69. package/dist/lib/employees.js +8 -0
  70. package/dist/lib/exe-daemon.js +524 -60
  71. package/dist/lib/hybrid-search.js +37 -12
  72. package/dist/lib/keychain.js +25 -13
  73. package/dist/lib/messaging.js +395 -74
  74. package/dist/lib/schedules.js +36 -12
  75. package/dist/lib/skill-learning.js +21 -0
  76. package/dist/lib/store.js +36 -12
  77. package/dist/lib/tasks.js +324 -41
  78. package/dist/lib/tmux-routing.js +324 -41
  79. package/dist/mcp/server.js +374 -54
  80. package/dist/mcp/tools/create-task.js +324 -41
  81. package/dist/mcp/tools/list-tasks.js +406 -57
  82. package/dist/mcp/tools/send-message.js +395 -74
  83. package/dist/mcp/tools/update-task.js +324 -41
  84. package/dist/runtime/index.js +375 -53
  85. package/dist/tui/App.js +377 -55
  86. package/package.json +1 -1
@@ -129,6 +129,17 @@ function normalizeOrchestration(raw) {
129
129
  const userOrg = raw.orchestration ?? {};
130
130
  raw.orchestration = { ...defaultOrg, ...userOrg };
131
131
  }
132
+ function normalizeCloudEndpoint(raw) {
133
+ const cloud = raw.cloud;
134
+ if (!cloud?.endpoint) return;
135
+ const ep = String(cloud.endpoint);
136
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
137
+ cloud.endpoint = "https://cloud.askexe.com";
138
+ process.stderr.write(
139
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
140
+ );
141
+ }
142
+ }
132
143
  async function loadConfig() {
133
144
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
134
145
  await ensurePrivateDir(dir);
@@ -154,6 +165,7 @@ async function loadConfig() {
154
165
  normalizeSessionLifecycle(migratedCfg);
155
166
  normalizeAutoUpdate(migratedCfg);
156
167
  normalizeOrchestration(migratedCfg);
168
+ normalizeCloudEndpoint(migratedCfg);
157
169
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
158
170
  if (config.dbPath.startsWith("~")) {
159
171
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -729,7 +741,7 @@ __export(keychain_exports, {
729
741
  importMnemonic: () => importMnemonic,
730
742
  setMasterKey: () => setMasterKey
731
743
  });
732
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
744
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2, rename, copyFile } from "fs/promises";
733
745
  import { existsSync as existsSync4, statSync as statSync2 } from "fs";
734
746
  import { execSync } from "child_process";
735
747
  import path3 from "path";
@@ -764,12 +776,14 @@ function linuxSecretAvailable() {
764
776
  function isRootOnlyTrustedServerKeyFile(keyPath) {
765
777
  if (process.platform !== "linux") return false;
766
778
  try {
767
- const uid = typeof os2.userInfo().uid === "number" ? os2.userInfo().uid : -1;
768
779
  const st = statSync2(keyPath);
769
780
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
781
+ const uid = typeof os2.userInfo().uid === "number" ? os2.userInfo().uid : -1;
770
782
  if (uid === 0) return true;
771
783
  const exeOsDir = process.env.EXE_OS_DIR;
772
- return Boolean(exeOsDir && path3.resolve(keyPath).startsWith(path3.resolve(exeOsDir) + path3.sep));
784
+ if (exeOsDir && path3.resolve(keyPath).startsWith(path3.resolve(exeOsDir) + path3.sep)) return true;
785
+ if (!linuxSecretAvailable()) return true;
786
+ return false;
773
787
  } catch {
774
788
  return false;
775
789
  }
@@ -919,15 +933,25 @@ async function writeMachineBoundFileFallback(b64) {
919
933
  await mkdir2(dir, { recursive: true });
920
934
  const keyPath = getKeyPath();
921
935
  const machineKey = deriveMachineKey();
922
- if (machineKey) {
923
- const encrypted = encryptWithMachineKey(b64, machineKey);
924
- await writeFile2(keyPath, encrypted + "\n", "utf-8");
925
- await chmod2(keyPath, 384);
926
- return "encrypted";
936
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
937
+ const result = machineKey ? "encrypted" : "plaintext";
938
+ const tmpPath = keyPath + ".tmp";
939
+ try {
940
+ if (existsSync4(keyPath)) {
941
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
942
+ });
943
+ }
944
+ await writeFile2(tmpPath, content, "utf-8");
945
+ await chmod2(tmpPath, 384);
946
+ await rename(tmpPath, keyPath);
947
+ } catch (err) {
948
+ try {
949
+ await unlink(tmpPath);
950
+ } catch {
951
+ }
952
+ throw err;
927
953
  }
928
- await writeFile2(keyPath, b64 + "\n", "utf-8");
929
- await chmod2(keyPath, 384);
930
- return "plaintext";
954
+ return result;
931
955
  }
932
956
  async function getMasterKey() {
933
957
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -994,7 +1018,7 @@ async function getMasterKey() {
994
1018
  b64Value = content;
995
1019
  }
996
1020
  const key = Buffer.from(b64Value, "base64");
997
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
1021
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
998
1022
  return key;
999
1023
  }
1000
1024
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -1279,7 +1303,21 @@ function tryAcquireWorkerSlot() {
1279
1303
  for (const f of files) {
1280
1304
  if (!f.endsWith(".pid")) continue;
1281
1305
  if (f.startsWith("res-")) {
1282
- alive++;
1306
+ const resParts = f.replace(".pid", "").split("-");
1307
+ const resPid = parseInt(resParts[1] ?? "", 10);
1308
+ if (!isNaN(resPid) && resPid > 0) {
1309
+ try {
1310
+ process.kill(resPid, 0);
1311
+ alive++;
1312
+ } catch {
1313
+ try {
1314
+ unlinkSync(path5.join(WORKER_PID_DIR, f));
1315
+ } catch {
1316
+ }
1317
+ }
1318
+ } else {
1319
+ alive++;
1320
+ }
1283
1321
  continue;
1284
1322
  }
1285
1323
  const dashIdx = f.lastIndexOf("-");
@@ -219,6 +219,17 @@ function normalizeOrchestration(raw) {
219
219
  const userOrg = raw.orchestration ?? {};
220
220
  raw.orchestration = { ...defaultOrg, ...userOrg };
221
221
  }
222
+ function normalizeCloudEndpoint(raw) {
223
+ const cloud = raw.cloud;
224
+ if (!cloud?.endpoint) return;
225
+ const ep = String(cloud.endpoint);
226
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
227
+ cloud.endpoint = "https://cloud.askexe.com";
228
+ process.stderr.write(
229
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
230
+ );
231
+ }
232
+ }
222
233
  async function loadConfig() {
223
234
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
224
235
  await ensurePrivateDir(dir);
@@ -244,6 +255,7 @@ async function loadConfig() {
244
255
  normalizeSessionLifecycle(migratedCfg);
245
256
  normalizeAutoUpdate(migratedCfg);
246
257
  normalizeOrchestration(migratedCfg);
258
+ normalizeCloudEndpoint(migratedCfg);
247
259
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
248
260
  if (config.dbPath.startsWith("~")) {
249
261
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -272,6 +284,7 @@ function loadConfigSync() {
272
284
  normalizeSessionLifecycle(migratedCfg);
273
285
  normalizeAutoUpdate(migratedCfg);
274
286
  normalizeOrchestration(migratedCfg);
287
+ normalizeCloudEndpoint(migratedCfg);
275
288
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
276
289
  if (config.dbPath.startsWith("~")) {
277
290
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -3392,7 +3405,7 @@ var init_database = __esm({
3392
3405
  });
3393
3406
 
3394
3407
  // src/lib/keychain.ts
3395
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3408
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
3396
3409
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3397
3410
  import { execSync as execSync3 } from "child_process";
3398
3411
  import path6 from "path";
@@ -3427,12 +3440,14 @@ function linuxSecretAvailable() {
3427
3440
  function isRootOnlyTrustedServerKeyFile(keyPath) {
3428
3441
  if (process.platform !== "linux") return false;
3429
3442
  try {
3430
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3431
3443
  const st = statSync3(keyPath);
3432
3444
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3445
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3433
3446
  if (uid === 0) return true;
3434
3447
  const exeOsDir = process.env.EXE_OS_DIR;
3435
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
3448
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
3449
+ if (!linuxSecretAvailable()) return true;
3450
+ return false;
3436
3451
  } catch {
3437
3452
  return false;
3438
3453
  }
@@ -3582,15 +3597,25 @@ async function writeMachineBoundFileFallback(b64) {
3582
3597
  await mkdir3(dir, { recursive: true });
3583
3598
  const keyPath = getKeyPath();
3584
3599
  const machineKey = deriveMachineKey();
3585
- if (machineKey) {
3586
- const encrypted = encryptWithMachineKey(b64, machineKey);
3587
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
3588
- await chmod2(keyPath, 384);
3589
- return "encrypted";
3600
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
3601
+ const result = machineKey ? "encrypted" : "plaintext";
3602
+ const tmpPath = keyPath + ".tmp";
3603
+ try {
3604
+ if (existsSync7(keyPath)) {
3605
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
3606
+ });
3607
+ }
3608
+ await writeFile3(tmpPath, content, "utf-8");
3609
+ await chmod2(tmpPath, 384);
3610
+ await rename(tmpPath, keyPath);
3611
+ } catch (err) {
3612
+ try {
3613
+ await unlink(tmpPath);
3614
+ } catch {
3615
+ }
3616
+ throw err;
3590
3617
  }
3591
- await writeFile3(keyPath, b64 + "\n", "utf-8");
3592
- await chmod2(keyPath, 384);
3593
- return "plaintext";
3618
+ return result;
3594
3619
  }
3595
3620
  async function getMasterKey() {
3596
3621
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -3657,7 +3682,7 @@ async function getMasterKey() {
3657
3682
  b64Value = content;
3658
3683
  }
3659
3684
  const key = Buffer.from(b64Value, "base64");
3660
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
3685
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
3661
3686
  return key;
3662
3687
  }
3663
3688
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -184,6 +184,17 @@ function normalizeOrchestration(raw) {
184
184
  const userOrg = raw.orchestration ?? {};
185
185
  raw.orchestration = { ...defaultOrg, ...userOrg };
186
186
  }
187
+ function normalizeCloudEndpoint(raw) {
188
+ const cloud = raw.cloud;
189
+ if (!cloud?.endpoint) return;
190
+ const ep = String(cloud.endpoint);
191
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
192
+ cloud.endpoint = "https://cloud.askexe.com";
193
+ process.stderr.write(
194
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
195
+ );
196
+ }
197
+ }
187
198
  async function loadConfig() {
188
199
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
189
200
  await ensurePrivateDir(dir);
@@ -209,6 +220,7 @@ async function loadConfig() {
209
220
  normalizeSessionLifecycle(migratedCfg);
210
221
  normalizeAutoUpdate(migratedCfg);
211
222
  normalizeOrchestration(migratedCfg);
223
+ normalizeCloudEndpoint(migratedCfg);
212
224
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
213
225
  if (config.dbPath.startsWith("~")) {
214
226
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -3316,7 +3328,7 @@ var init_database = __esm({
3316
3328
  });
3317
3329
 
3318
3330
  // src/lib/keychain.ts
3319
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3331
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
3320
3332
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3321
3333
  import { execSync as execSync3 } from "child_process";
3322
3334
  import path6 from "path";
@@ -3351,12 +3363,14 @@ function linuxSecretAvailable() {
3351
3363
  function isRootOnlyTrustedServerKeyFile(keyPath) {
3352
3364
  if (process.platform !== "linux") return false;
3353
3365
  try {
3354
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3355
3366
  const st = statSync3(keyPath);
3356
3367
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3368
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3357
3369
  if (uid === 0) return true;
3358
3370
  const exeOsDir = process.env.EXE_OS_DIR;
3359
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
3371
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
3372
+ if (!linuxSecretAvailable()) return true;
3373
+ return false;
3360
3374
  } catch {
3361
3375
  return false;
3362
3376
  }
@@ -3506,15 +3520,25 @@ async function writeMachineBoundFileFallback(b64) {
3506
3520
  await mkdir3(dir, { recursive: true });
3507
3521
  const keyPath = getKeyPath();
3508
3522
  const machineKey = deriveMachineKey();
3509
- if (machineKey) {
3510
- const encrypted = encryptWithMachineKey(b64, machineKey);
3511
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
3512
- await chmod2(keyPath, 384);
3513
- return "encrypted";
3523
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
3524
+ const result = machineKey ? "encrypted" : "plaintext";
3525
+ const tmpPath = keyPath + ".tmp";
3526
+ try {
3527
+ if (existsSync7(keyPath)) {
3528
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
3529
+ });
3530
+ }
3531
+ await writeFile3(tmpPath, content, "utf-8");
3532
+ await chmod2(tmpPath, 384);
3533
+ await rename(tmpPath, keyPath);
3534
+ } catch (err) {
3535
+ try {
3536
+ await unlink(tmpPath);
3537
+ } catch {
3538
+ }
3539
+ throw err;
3514
3540
  }
3515
- await writeFile3(keyPath, b64 + "\n", "utf-8");
3516
- await chmod2(keyPath, 384);
3517
- return "plaintext";
3541
+ return result;
3518
3542
  }
3519
3543
  async function getMasterKey() {
3520
3544
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -3581,7 +3605,7 @@ async function getMasterKey() {
3581
3605
  b64Value = content;
3582
3606
  }
3583
3607
  const key = Buffer.from(b64Value, "base64");
3584
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
3608
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
3585
3609
  return key;
3586
3610
  }
3587
3611
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);