@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
package/dist/bin/setup.js CHANGED
@@ -144,6 +144,17 @@ function normalizeOrchestration(raw) {
144
144
  const userOrg = raw.orchestration ?? {};
145
145
  raw.orchestration = { ...defaultOrg, ...userOrg };
146
146
  }
147
+ function normalizeCloudEndpoint(raw) {
148
+ const cloud = raw.cloud;
149
+ if (!cloud?.endpoint) return;
150
+ const ep = String(cloud.endpoint);
151
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
152
+ cloud.endpoint = "https://cloud.askexe.com";
153
+ process.stderr.write(
154
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
155
+ );
156
+ }
157
+ }
147
158
  async function loadConfig() {
148
159
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
149
160
  await ensurePrivateDir(dir);
@@ -169,6 +180,7 @@ async function loadConfig() {
169
180
  normalizeSessionLifecycle(migratedCfg);
170
181
  normalizeAutoUpdate(migratedCfg);
171
182
  normalizeOrchestration(migratedCfg);
183
+ normalizeCloudEndpoint(migratedCfg);
172
184
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
173
185
  if (config.dbPath.startsWith("~")) {
174
186
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -197,6 +209,7 @@ function loadConfigSync() {
197
209
  normalizeSessionLifecycle(migratedCfg);
198
210
  normalizeAutoUpdate(migratedCfg);
199
211
  normalizeOrchestration(migratedCfg);
212
+ normalizeCloudEndpoint(migratedCfg);
200
213
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
201
214
  if (config.dbPath.startsWith("~")) {
202
215
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -330,7 +343,7 @@ __export(keychain_exports, {
330
343
  importMnemonic: () => importMnemonic,
331
344
  setMasterKey: () => setMasterKey
332
345
  });
333
- import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
346
+ import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2, rename, copyFile } from "fs/promises";
334
347
  import { existsSync as existsSync3, statSync } from "fs";
335
348
  import { execSync } from "child_process";
336
349
  import path2 from "path";
@@ -365,12 +378,14 @@ function linuxSecretAvailable() {
365
378
  function isRootOnlyTrustedServerKeyFile(keyPath) {
366
379
  if (process.platform !== "linux") return false;
367
380
  try {
368
- const uid = typeof os2.userInfo().uid === "number" ? os2.userInfo().uid : -1;
369
381
  const st = statSync(keyPath);
370
382
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
383
+ const uid = typeof os2.userInfo().uid === "number" ? os2.userInfo().uid : -1;
371
384
  if (uid === 0) return true;
372
385
  const exeOsDir = process.env.EXE_OS_DIR;
373
- return Boolean(exeOsDir && path2.resolve(keyPath).startsWith(path2.resolve(exeOsDir) + path2.sep));
386
+ if (exeOsDir && path2.resolve(keyPath).startsWith(path2.resolve(exeOsDir) + path2.sep)) return true;
387
+ if (!linuxSecretAvailable()) return true;
388
+ return false;
374
389
  } catch {
375
390
  return false;
376
391
  }
@@ -520,15 +535,25 @@ async function writeMachineBoundFileFallback(b64) {
520
535
  await mkdir2(dir, { recursive: true });
521
536
  const keyPath = getKeyPath();
522
537
  const machineKey = deriveMachineKey();
523
- if (machineKey) {
524
- const encrypted = encryptWithMachineKey(b64, machineKey);
525
- await writeFile2(keyPath, encrypted + "\n", "utf-8");
526
- await chmod2(keyPath, 384);
527
- return "encrypted";
538
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
539
+ const result = machineKey ? "encrypted" : "plaintext";
540
+ const tmpPath = keyPath + ".tmp";
541
+ try {
542
+ if (existsSync3(keyPath)) {
543
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
544
+ });
545
+ }
546
+ await writeFile2(tmpPath, content, "utf-8");
547
+ await chmod2(tmpPath, 384);
548
+ await rename(tmpPath, keyPath);
549
+ } catch (err) {
550
+ try {
551
+ await unlink(tmpPath);
552
+ } catch {
553
+ }
554
+ throw err;
528
555
  }
529
- await writeFile2(keyPath, b64 + "\n", "utf-8");
530
- await chmod2(keyPath, 384);
531
- return "plaintext";
556
+ return result;
532
557
  }
533
558
  async function getMasterKey() {
534
559
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -595,7 +620,7 @@ async function getMasterKey() {
595
620
  b64Value = content;
596
621
  }
597
622
  const key = Buffer.from(b64Value, "base64");
598
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
623
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
599
624
  return key;
600
625
  }
601
626
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -1963,6 +1988,7 @@ __export(agent_config_exports, {
1963
1988
  clearAgentRuntime: () => clearAgentRuntime,
1964
1989
  getAgentRuntime: () => getAgentRuntime,
1965
1990
  loadAgentConfig: () => loadAgentConfig,
1991
+ normalizeCcModelName: () => normalizeCcModelName,
1966
1992
  saveAgentConfig: () => saveAgentConfig,
1967
1993
  setAgentMcps: () => setAgentMcps,
1968
1994
  setAgentRuntime: () => setAgentRuntime
@@ -1991,6 +2017,13 @@ function getAgentRuntime(agentId) {
1991
2017
  if (orgDefault) return orgDefault;
1992
2018
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
1993
2019
  }
2020
+ function normalizeCcModelName(model) {
2021
+ let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
2022
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
2023
+ ccModel += "[1m]";
2024
+ }
2025
+ return ccModel;
2026
+ }
1994
2027
  function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
1995
2028
  const knownModels = KNOWN_RUNTIMES[runtime];
1996
2029
  if (!knownModels) {
@@ -5151,6 +5184,7 @@ __export(cloud_sync_exports, {
5151
5184
  markCloudReuploadRequired: () => markCloudReuploadRequired,
5152
5185
  mergeConfig: () => mergeConfig,
5153
5186
  mergeRosterFromRemote: () => mergeRosterFromRemote,
5187
+ migrateEndpoint: () => migrateEndpoint,
5154
5188
  pushToPostgres: () => pushToPostgres,
5155
5189
  recordRosterDeletion: () => recordRosterDeletion
5156
5190
  });
@@ -5321,6 +5355,15 @@ async function fetchWithRetry(url, init) {
5321
5355
  }
5322
5356
  throw lastError;
5323
5357
  }
5358
+ function migrateEndpoint(endpoint) {
5359
+ if (endpoint === "https://askexe.com/cloud" || endpoint === "https://askexe.com/cloud/") {
5360
+ process.stderr.write(
5361
+ "[cloud-sync] Auto-migrating endpoint from askexe.com/cloud to cloud.askexe.com (bypasses Cloudflare WAF for datacenter IPs)\n"
5362
+ );
5363
+ return "https://cloud.askexe.com";
5364
+ }
5365
+ return endpoint;
5366
+ }
5324
5367
  function assertSecureEndpoint(endpoint) {
5325
5368
  if (endpoint.startsWith("https://")) return;
5326
5369
  if (endpoint.startsWith("http://")) {
@@ -5458,6 +5501,7 @@ async function markCloudReuploadRequired(client = getClient()) {
5458
5501
  await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
5459
5502
  }
5460
5503
  async function cloudSync(config) {
5504
+ config = { ...config, endpoint: migrateEndpoint(config.endpoint) };
5461
5505
  if (!isSyncCryptoInitialized()) {
5462
5506
  try {
5463
5507
  const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
@@ -8796,6 +8840,24 @@ async function runSetupWizard(opts = {}) {
8796
8840
  log("");
8797
8841
  log("=== exe-os Setup ===");
8798
8842
  log("");
8843
+ if (process.platform === "darwin") {
8844
+ const currentShell = process.env.SHELL ?? "";
8845
+ if (currentShell.includes("bash")) {
8846
+ log(" \u26A0 Your default shell is bash.");
8847
+ log(" macOS uses zsh by default since Catalina (2019).");
8848
+ log(" exe-os works with bash, but switching to zsh is recommended:");
8849
+ log(" chsh -s /bin/zsh");
8850
+ log(" Then restart your terminal.");
8851
+ log("");
8852
+ const cont = await ask(rl, " Continue with bash? (y/n, default: y): ");
8853
+ if (cont.toLowerCase() === "n") {
8854
+ log(" Run `chsh -s /bin/zsh`, restart your terminal, then run setup again.");
8855
+ rl.close();
8856
+ return;
8857
+ }
8858
+ log("");
8859
+ }
8860
+ }
8799
8861
  log("What are you setting up?");
8800
8862
  log("");
8801
8863
  log(" [1] First device / brand new Exe OS memory");
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
193
193
  const userOrg = raw.orchestration ?? {};
194
194
  raw.orchestration = { ...defaultOrg, ...userOrg };
195
195
  }
196
+ function normalizeCloudEndpoint(raw) {
197
+ const cloud = raw.cloud;
198
+ if (!cloud?.endpoint) return;
199
+ const ep = String(cloud.endpoint);
200
+ if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
201
+ cloud.endpoint = "https://cloud.askexe.com";
202
+ process.stderr.write(
203
+ "[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
204
+ );
205
+ }
206
+ }
196
207
  async function loadConfig() {
197
208
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
198
209
  await ensurePrivateDir(dir);
@@ -218,6 +229,7 @@ async function loadConfig() {
218
229
  normalizeSessionLifecycle(migratedCfg);
219
230
  normalizeAutoUpdate(migratedCfg);
220
231
  normalizeOrchestration(migratedCfg);
232
+ normalizeCloudEndpoint(migratedCfg);
221
233
  const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
222
234
  if (config.dbPath.startsWith("~")) {
223
235
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
@@ -4385,7 +4397,7 @@ init_memory();
4385
4397
  init_database();
4386
4398
 
4387
4399
  // src/lib/keychain.ts
4388
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4400
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4389
4401
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4390
4402
  import { execSync as execSync3 } from "child_process";
4391
4403
  import path6 from "path";
@@ -4424,12 +4436,14 @@ function linuxSecretAvailable() {
4424
4436
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4425
4437
  if (process.platform !== "linux") return false;
4426
4438
  try {
4427
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4428
4439
  const st = statSync3(keyPath);
4429
4440
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4441
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4430
4442
  if (uid === 0) return true;
4431
4443
  const exeOsDir = process.env.EXE_OS_DIR;
4432
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4444
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4445
+ if (!linuxSecretAvailable()) return true;
4446
+ return false;
4433
4447
  } catch {
4434
4448
  return false;
4435
4449
  }
@@ -4580,15 +4594,25 @@ async function writeMachineBoundFileFallback(b64) {
4580
4594
  await mkdir3(dir, { recursive: true });
4581
4595
  const keyPath = getKeyPath();
4582
4596
  const machineKey = deriveMachineKey();
4583
- if (machineKey) {
4584
- const encrypted = encryptWithMachineKey(b64, machineKey);
4585
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4586
- await chmod2(keyPath, 384);
4587
- return "encrypted";
4597
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4598
+ const result = machineKey ? "encrypted" : "plaintext";
4599
+ const tmpPath = keyPath + ".tmp";
4600
+ try {
4601
+ if (existsSync7(keyPath)) {
4602
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4603
+ });
4604
+ }
4605
+ await writeFile3(tmpPath, content, "utf-8");
4606
+ await chmod2(tmpPath, 384);
4607
+ await rename(tmpPath, keyPath);
4608
+ } catch (err) {
4609
+ try {
4610
+ await unlink(tmpPath);
4611
+ } catch {
4612
+ }
4613
+ throw err;
4588
4614
  }
4589
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4590
- await chmod2(keyPath, 384);
4591
- return "plaintext";
4615
+ return result;
4592
4616
  }
4593
4617
  async function getMasterKey() {
4594
4618
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4655,7 +4679,7 @@ async function getMasterKey() {
4655
4679
  b64Value = content;
4656
4680
  }
4657
4681
  const key = Buffer.from(b64Value, "base64");
4658
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4682
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4659
4683
  return key;
4660
4684
  }
4661
4685
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);