@askexenow/exe-os 0.9.113 → 0.9.114

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 (79) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +24 -12
  2. package/dist/bin/agentic-reflection-backfill.js +24 -12
  3. package/dist/bin/agentic-semantic-label.js +24 -12
  4. package/dist/bin/backfill-conversations.js +24 -12
  5. package/dist/bin/backfill-responses.js +24 -12
  6. package/dist/bin/backfill-vectors.js +24 -12
  7. package/dist/bin/bulk-sync-postgres.js +24 -12
  8. package/dist/bin/cleanup-stale-review-tasks.js +24 -12
  9. package/dist/bin/cli.js +96 -22
  10. package/dist/bin/exe-agent.js +27 -0
  11. package/dist/bin/exe-assign.js +24 -12
  12. package/dist/bin/exe-boot.js +44 -15
  13. package/dist/bin/exe-call.js +8 -0
  14. package/dist/bin/exe-cloud.js +34 -11
  15. package/dist/bin/exe-dispatch.js +34 -16
  16. package/dist/bin/exe-doctor.js +24 -12
  17. package/dist/bin/exe-export-behaviors.js +24 -12
  18. package/dist/bin/exe-forget.js +24 -12
  19. package/dist/bin/exe-gateway.js +33 -15
  20. package/dist/bin/exe-heartbeat.js +24 -12
  21. package/dist/bin/exe-kill.js +24 -12
  22. package/dist/bin/exe-launch-agent.js +103 -17
  23. package/dist/bin/exe-new-employee.js +9 -1
  24. package/dist/bin/exe-pending-messages.js +24 -12
  25. package/dist/bin/exe-pending-notifications.js +24 -12
  26. package/dist/bin/exe-pending-reviews.js +24 -12
  27. package/dist/bin/exe-rename.js +24 -12
  28. package/dist/bin/exe-review.js +24 -12
  29. package/dist/bin/exe-search.js +24 -12
  30. package/dist/bin/exe-session-cleanup.js +33 -15
  31. package/dist/bin/exe-start-codex.js +33 -13
  32. package/dist/bin/exe-start-opencode.js +33 -13
  33. package/dist/bin/exe-status.js +24 -12
  34. package/dist/bin/exe-team.js +24 -12
  35. package/dist/bin/git-sweep.js +34 -16
  36. package/dist/bin/graph-backfill.js +24 -12
  37. package/dist/bin/graph-export.js +24 -12
  38. package/dist/bin/install.js +9 -1
  39. package/dist/bin/intercom-check.js +33 -15
  40. package/dist/bin/scan-tasks.js +34 -16
  41. package/dist/bin/setup.js +60 -11
  42. package/dist/bin/shard-migrate.js +24 -12
  43. package/dist/gateway/index.js +33 -15
  44. package/dist/hooks/bug-report-worker.js +33 -15
  45. package/dist/hooks/codex-stop-task-finalizer.js +32 -12
  46. package/dist/hooks/commit-complete.js +34 -16
  47. package/dist/hooks/error-recall.js +24 -12
  48. package/dist/hooks/ingest.js +33 -15
  49. package/dist/hooks/instructions-loaded.js +24 -12
  50. package/dist/hooks/notification.js +24 -12
  51. package/dist/hooks/post-compact.js +24 -12
  52. package/dist/hooks/post-tool-combined.js +24 -12
  53. package/dist/hooks/pre-compact.js +34 -16
  54. package/dist/hooks/pre-tool-use.js +58 -11
  55. package/dist/hooks/prompt-submit.js +33 -15
  56. package/dist/hooks/session-end.js +34 -16
  57. package/dist/hooks/session-start.js +32 -12
  58. package/dist/hooks/stop.js +24 -12
  59. package/dist/hooks/subagent-stop.js +24 -12
  60. package/dist/hooks/summary-worker.js +34 -11
  61. package/dist/index.js +60 -15
  62. package/dist/lib/agent-config.js +8 -0
  63. package/dist/lib/cloud-sync.js +34 -11
  64. package/dist/lib/consolidation.js +9 -1
  65. package/dist/lib/employees.js +8 -0
  66. package/dist/lib/exe-daemon.js +174 -17
  67. package/dist/lib/hybrid-search.js +24 -12
  68. package/dist/lib/keychain.js +24 -12
  69. package/dist/lib/schedules.js +24 -12
  70. package/dist/lib/skill-learning.js +8 -0
  71. package/dist/lib/store.js +24 -12
  72. package/dist/lib/tasks.js +10 -4
  73. package/dist/lib/tmux-routing.js +10 -4
  74. package/dist/mcp/server.js +44 -15
  75. package/dist/mcp/tools/create-task.js +10 -4
  76. package/dist/mcp/tools/update-task.js +10 -4
  77. package/dist/runtime/index.js +60 -15
  78. package/dist/tui/App.js +61 -16
  79. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -368,6 +368,7 @@ __export(agent_config_exports, {
368
368
  clearAgentRuntime: () => clearAgentRuntime,
369
369
  getAgentRuntime: () => getAgentRuntime,
370
370
  loadAgentConfig: () => loadAgentConfig,
371
+ normalizeCcModelName: () => normalizeCcModelName,
371
372
  saveAgentConfig: () => saveAgentConfig,
372
373
  setAgentMcps: () => setAgentMcps,
373
374
  setAgentRuntime: () => setAgentRuntime
@@ -396,6 +397,13 @@ function getAgentRuntime(agentId) {
396
397
  if (orgDefault) return orgDefault;
397
398
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
398
399
  }
400
+ function normalizeCcModelName(model) {
401
+ let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
402
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
403
+ ccModel += "[1m]";
404
+ }
405
+ return ccModel;
406
+ }
399
407
  function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
400
408
  const knownModels = KNOWN_RUNTIMES[runtime];
401
409
  if (!knownModels) {
@@ -896,7 +904,7 @@ function readOrCreateDaemonToken(homeDir = os5.homedir()) {
896
904
  function buildMcpHttpHeaders(homeDir = os5.homedir(), opts = {}) {
897
905
  const agentId = opts.useShellPlaceholders ? "${AGENT_ID:-exe}" : opts.agentId ?? DEFAULT_MCP_HTTP_AGENT_ID;
898
906
  const agentRole = opts.useShellPlaceholders ? "${AGENT_ROLE:-COO}" : opts.agentRole ?? DEFAULT_MCP_HTTP_AGENT_ROLE;
899
- const sessionName = opts.useShellPlaceholders ? "$(tmux display-message -p '#{session_name}' 2>/dev/null || echo '')" : process.env.EXE_SESSION_NAME ?? "";
907
+ const sessionName = opts.useShellPlaceholders ? "" : process.env.EXE_SESSION_NAME ?? "";
900
908
  const headers = {
901
909
  Authorization: `Bearer ${readOrCreateDaemonToken(homeDir)}`,
902
910
  "X-Agent-Id": agentId,
@@ -2555,7 +2563,7 @@ __export(keychain_exports, {
2555
2563
  importMnemonic: () => importMnemonic,
2556
2564
  setMasterKey: () => setMasterKey
2557
2565
  });
2558
- import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
2566
+ import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2, rename, copyFile } from "fs/promises";
2559
2567
  import { existsSync as existsSync10, statSync } from "fs";
2560
2568
  import { execSync as execSync3 } from "child_process";
2561
2569
  import path9 from "path";
@@ -2590,12 +2598,14 @@ function linuxSecretAvailable() {
2590
2598
  function isRootOnlyTrustedServerKeyFile(keyPath) {
2591
2599
  if (process.platform !== "linux") return false;
2592
2600
  try {
2593
- const uid = typeof os8.userInfo().uid === "number" ? os8.userInfo().uid : -1;
2594
2601
  const st = statSync(keyPath);
2595
2602
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
2603
+ const uid = typeof os8.userInfo().uid === "number" ? os8.userInfo().uid : -1;
2596
2604
  if (uid === 0) return true;
2597
2605
  const exeOsDir = process.env.EXE_OS_DIR;
2598
- return Boolean(exeOsDir && path9.resolve(keyPath).startsWith(path9.resolve(exeOsDir) + path9.sep));
2606
+ if (exeOsDir && path9.resolve(keyPath).startsWith(path9.resolve(exeOsDir) + path9.sep)) return true;
2607
+ if (!linuxSecretAvailable()) return true;
2608
+ return false;
2599
2609
  } catch {
2600
2610
  return false;
2601
2611
  }
@@ -2745,15 +2755,25 @@ async function writeMachineBoundFileFallback(b64) {
2745
2755
  await mkdir4(dir, { recursive: true });
2746
2756
  const keyPath = getKeyPath();
2747
2757
  const machineKey = deriveMachineKey();
2748
- if (machineKey) {
2749
- const encrypted = encryptWithMachineKey(b64, machineKey);
2750
- await writeFile4(keyPath, encrypted + "\n", "utf-8");
2751
- await chmod2(keyPath, 384);
2752
- return "encrypted";
2758
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
2759
+ const result = machineKey ? "encrypted" : "plaintext";
2760
+ const tmpPath = keyPath + ".tmp";
2761
+ try {
2762
+ if (existsSync10(keyPath)) {
2763
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
2764
+ });
2765
+ }
2766
+ await writeFile4(tmpPath, content, "utf-8");
2767
+ await chmod2(tmpPath, 384);
2768
+ await rename(tmpPath, keyPath);
2769
+ } catch (err) {
2770
+ try {
2771
+ await unlink(tmpPath);
2772
+ } catch {
2773
+ }
2774
+ throw err;
2753
2775
  }
2754
- await writeFile4(keyPath, b64 + "\n", "utf-8");
2755
- await chmod2(keyPath, 384);
2756
- return "plaintext";
2776
+ return result;
2757
2777
  }
2758
2778
  async function getMasterKey() {
2759
2779
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -6999,6 +7019,7 @@ __export(cloud_sync_exports, {
6999
7019
  markCloudReuploadRequired: () => markCloudReuploadRequired,
7000
7020
  mergeConfig: () => mergeConfig,
7001
7021
  mergeRosterFromRemote: () => mergeRosterFromRemote,
7022
+ migrateEndpoint: () => migrateEndpoint,
7002
7023
  pushToPostgres: () => pushToPostgres,
7003
7024
  recordRosterDeletion: () => recordRosterDeletion
7004
7025
  });
@@ -7169,6 +7190,15 @@ async function fetchWithRetry(url, init) {
7169
7190
  }
7170
7191
  throw lastError;
7171
7192
  }
7193
+ function migrateEndpoint(endpoint) {
7194
+ if (endpoint === "https://askexe.com/cloud" || endpoint === "https://askexe.com/cloud/") {
7195
+ process.stderr.write(
7196
+ "[cloud-sync] Auto-migrating endpoint from askexe.com/cloud to cloud.askexe.com (bypasses Cloudflare WAF for datacenter IPs)\n"
7197
+ );
7198
+ return "https://cloud.askexe.com";
7199
+ }
7200
+ return endpoint;
7201
+ }
7172
7202
  function assertSecureEndpoint(endpoint) {
7173
7203
  if (endpoint.startsWith("https://")) return;
7174
7204
  if (endpoint.startsWith("http://")) {
@@ -7306,6 +7336,7 @@ async function markCloudReuploadRequired(client = getClient()) {
7306
7336
  await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
7307
7337
  }
7308
7338
  async function cloudSync(config) {
7339
+ config = { ...config, endpoint: migrateEndpoint(config.endpoint) };
7309
7340
  if (!isSyncCryptoInitialized()) {
7310
7341
  try {
7311
7342
  const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
@@ -17135,10 +17166,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
17135
17166
  }
17136
17167
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
17137
17168
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
17138
- let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
17139
- if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
17140
- ccModel += "[1m]";
17141
- }
17169
+ const { normalizeCcModelName: normalizeCcModelName2 } = (init_agent_config(), __toCommonJS(agent_config_exports));
17170
+ const ccModel = normalizeCcModelName2(agentRtConfig.model);
17142
17171
  envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
17143
17172
  }
17144
17173
  }
@@ -20483,6 +20512,24 @@ async function runSetupWizard(opts = {}) {
20483
20512
  log("");
20484
20513
  log("=== exe-os Setup ===");
20485
20514
  log("");
20515
+ if (process.platform === "darwin") {
20516
+ const currentShell = process.env.SHELL ?? "";
20517
+ if (currentShell.includes("bash")) {
20518
+ log(" \u26A0 Your default shell is bash.");
20519
+ log(" macOS uses zsh by default since Catalina (2019).");
20520
+ log(" exe-os works with bash, but switching to zsh is recommended:");
20521
+ log(" chsh -s /bin/zsh");
20522
+ log(" Then restart your terminal.");
20523
+ log("");
20524
+ const cont = await ask3(rl, " Continue with bash? (y/n, default: y): ");
20525
+ if (cont.toLowerCase() === "n") {
20526
+ log(" Run `chsh -s /bin/zsh`, restart your terminal, then run setup again.");
20527
+ rl.close();
20528
+ return;
20529
+ }
20530
+ log("");
20531
+ }
20532
+ }
20486
20533
  log("What are you setting up?");
20487
20534
  log("");
20488
20535
  log(" [1] First device / brand new Exe OS memory");
@@ -21155,7 +21202,7 @@ var init_setup_wizard = __esm({
21155
21202
  });
21156
21203
 
21157
21204
  // src/lib/update-backup.ts
21158
- import { copyFile, readFile as readFile6, readdir as readdir3, writeFile as writeFile7, rm as rm2, mkdir as mkdir7, cp } from "fs/promises";
21205
+ import { copyFile as copyFile2, readFile as readFile6, readdir as readdir3, writeFile as writeFile7, rm as rm2, mkdir as mkdir7, cp } from "fs/promises";
21159
21206
  import { existsSync as existsSync36 } from "fs";
21160
21207
  import path42 from "path";
21161
21208
  import os20 from "os";
@@ -21191,7 +21238,7 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
21191
21238
  if (!existsSync36(src)) continue;
21192
21239
  const dest = path42.join(backupDir, target.name);
21193
21240
  if (target.type === "file") {
21194
- await copyFile(src, dest);
21241
+ await copyFile2(src, dest);
21195
21242
  } else {
21196
21243
  await cp(src, dest, { recursive: true });
21197
21244
  }
@@ -21202,7 +21249,7 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
21202
21249
  if (entry.isFile() && entry.name.endsWith(".db") && entry.name !== BACKUP_DIR_NAME) {
21203
21250
  const src = path42.join(dir, entry.name);
21204
21251
  const dest = path42.join(backupDir, entry.name);
21205
- await copyFile(src, dest);
21252
+ await copyFile2(src, dest);
21206
21253
  backedUpFiles.push(entry.name);
21207
21254
  }
21208
21255
  }
@@ -21211,7 +21258,7 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
21211
21258
  for (const target of externalBackupTargets(homeDir)) {
21212
21259
  if (!existsSync36(target.path)) continue;
21213
21260
  await mkdir7(externalDir, { recursive: true });
21214
- await copyFile(target.path, path42.join(externalDir, target.name));
21261
+ await copyFile2(target.path, path42.join(externalDir, target.name));
21215
21262
  externalFiles.push(target);
21216
21263
  }
21217
21264
  const manifest = {
@@ -21246,14 +21293,14 @@ async function restoreFromBackup(dataDir2) {
21246
21293
  if (stat2.isDirectory()) {
21247
21294
  await cp(src, dest, { recursive: true, force: true });
21248
21295
  } else {
21249
- await copyFile(src, dest);
21296
+ await copyFile2(src, dest);
21250
21297
  }
21251
21298
  }
21252
21299
  for (const external of manifest.externalFiles ?? []) {
21253
21300
  const src = path42.join(backupDir, "external", external.name);
21254
21301
  if (!existsSync36(src)) continue;
21255
21302
  await mkdir7(path42.dirname(external.path), { recursive: true });
21256
- await copyFile(src, external.path);
21303
+ await copyFile2(src, external.path);
21257
21304
  }
21258
21305
  return manifest;
21259
21306
  }
@@ -32121,6 +32168,33 @@ var init_dangerous_patterns = __esm({
32121
32168
  regex: /\bkill\s+-9\b/,
32122
32169
  severity: "warning",
32123
32170
  reason: "Force kill signal"
32171
+ },
32172
+ // MCP bypass — agents must use MCP tools, never access the DB directly.
32173
+ // These patterns catch attempts to work around a disconnected MCP server.
32174
+ {
32175
+ regex: /\bsqlite3\b.*\bmemories\.db\b/,
32176
+ severity: "critical",
32177
+ reason: "Direct SQLite access bypasses MCP contract boundary \u2014 use MCP tools"
32178
+ },
32179
+ {
32180
+ regex: /\bsqlite3\b.*\.exe-os\b/,
32181
+ severity: "critical",
32182
+ reason: "Direct SQLite access to exe-os database \u2014 use MCP tools"
32183
+ },
32184
+ {
32185
+ regex: /\bnode\s+-e\b.*\b(better-sqlite3|libsql|sqlite3)\b/,
32186
+ severity: "critical",
32187
+ reason: "Inline Node.js script accessing SQLite directly \u2014 use MCP tools"
32188
+ },
32189
+ {
32190
+ regex: /\brequire\s*\(\s*['"].*memories\.db['"]\s*\)/,
32191
+ severity: "critical",
32192
+ reason: "Direct require of memories database \u2014 use MCP tools"
32193
+ },
32194
+ {
32195
+ regex: /\bcat\b.*\bmemories\.db\b/,
32196
+ severity: "warning",
32197
+ reason: "Reading raw database file \u2014 encrypted data, use MCP tools instead"
32124
32198
  }
32125
32199
  ];
32126
32200
  }
@@ -1861,6 +1861,33 @@ var DANGEROUS_PATTERNS = [
1861
1861
  regex: /\bkill\s+-9\b/,
1862
1862
  severity: "warning",
1863
1863
  reason: "Force kill signal"
1864
+ },
1865
+ // MCP bypass — agents must use MCP tools, never access the DB directly.
1866
+ // These patterns catch attempts to work around a disconnected MCP server.
1867
+ {
1868
+ regex: /\bsqlite3\b.*\bmemories\.db\b/,
1869
+ severity: "critical",
1870
+ reason: "Direct SQLite access bypasses MCP contract boundary \u2014 use MCP tools"
1871
+ },
1872
+ {
1873
+ regex: /\bsqlite3\b.*\.exe-os\b/,
1874
+ severity: "critical",
1875
+ reason: "Direct SQLite access to exe-os database \u2014 use MCP tools"
1876
+ },
1877
+ {
1878
+ regex: /\bnode\s+-e\b.*\b(better-sqlite3|libsql|sqlite3)\b/,
1879
+ severity: "critical",
1880
+ reason: "Inline Node.js script accessing SQLite directly \u2014 use MCP tools"
1881
+ },
1882
+ {
1883
+ regex: /\brequire\s*\(\s*['"].*memories\.db['"]\s*\)/,
1884
+ severity: "critical",
1885
+ reason: "Direct require of memories database \u2014 use MCP tools"
1886
+ },
1887
+ {
1888
+ regex: /\bcat\b.*\bmemories\.db\b/,
1889
+ severity: "warning",
1890
+ reason: "Reading raw database file \u2014 encrypted data, use MCP tools instead"
1864
1891
  }
1865
1892
  ];
1866
1893
  function checkDangerousPatterns(command) {
@@ -4681,7 +4681,7 @@ init_memory();
4681
4681
  init_database();
4682
4682
 
4683
4683
  // src/lib/keychain.ts
4684
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4684
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4685
4685
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4686
4686
  import { execSync as execSync3 } from "child_process";
4687
4687
  import path6 from "path";
@@ -4720,12 +4720,14 @@ function linuxSecretAvailable() {
4720
4720
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4721
4721
  if (process.platform !== "linux") return false;
4722
4722
  try {
4723
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4724
4723
  const st = statSync3(keyPath);
4725
4724
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4725
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4726
4726
  if (uid === 0) return true;
4727
4727
  const exeOsDir = process.env.EXE_OS_DIR;
4728
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4728
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4729
+ if (!linuxSecretAvailable()) return true;
4730
+ return false;
4729
4731
  } catch {
4730
4732
  return false;
4731
4733
  }
@@ -4876,15 +4878,25 @@ async function writeMachineBoundFileFallback(b64) {
4876
4878
  await mkdir3(dir, { recursive: true });
4877
4879
  const keyPath = getKeyPath();
4878
4880
  const machineKey = deriveMachineKey();
4879
- if (machineKey) {
4880
- const encrypted = encryptWithMachineKey(b64, machineKey);
4881
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4882
- await chmod2(keyPath, 384);
4883
- return "encrypted";
4884
- }
4885
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4886
- await chmod2(keyPath, 384);
4887
- return "plaintext";
4881
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4882
+ const result = machineKey ? "encrypted" : "plaintext";
4883
+ const tmpPath = keyPath + ".tmp";
4884
+ try {
4885
+ if (existsSync7(keyPath)) {
4886
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4887
+ });
4888
+ }
4889
+ await writeFile3(tmpPath, content, "utf-8");
4890
+ await chmod2(tmpPath, 384);
4891
+ await rename(tmpPath, keyPath);
4892
+ } catch (err) {
4893
+ try {
4894
+ await unlink(tmpPath);
4895
+ } catch {
4896
+ }
4897
+ throw err;
4898
+ }
4899
+ return result;
4888
4900
  }
4889
4901
  async function getMasterKey() {
4890
4902
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -368,6 +368,7 @@ __export(agent_config_exports, {
368
368
  clearAgentRuntime: () => clearAgentRuntime,
369
369
  getAgentRuntime: () => getAgentRuntime,
370
370
  loadAgentConfig: () => loadAgentConfig,
371
+ normalizeCcModelName: () => normalizeCcModelName,
371
372
  saveAgentConfig: () => saveAgentConfig,
372
373
  setAgentMcps: () => setAgentMcps,
373
374
  setAgentRuntime: () => setAgentRuntime
@@ -396,6 +397,13 @@ function getAgentRuntime(agentId) {
396
397
  if (orgDefault) return orgDefault;
397
398
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
398
399
  }
400
+ function normalizeCcModelName(model) {
401
+ let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
402
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
403
+ ccModel += "[1m]";
404
+ }
405
+ return ccModel;
406
+ }
399
407
  function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
400
408
  const knownModels = KNOWN_RUNTIMES[runtime];
401
409
  if (!knownModels) {
@@ -4060,7 +4068,7 @@ __export(keychain_exports, {
4060
4068
  importMnemonic: () => importMnemonic,
4061
4069
  setMasterKey: () => setMasterKey
4062
4070
  });
4063
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4071
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4064
4072
  import { existsSync as existsSync8, statSync as statSync3 } from "fs";
4065
4073
  import { execSync as execSync3 } from "child_process";
4066
4074
  import path7 from "path";
@@ -4095,12 +4103,14 @@ function linuxSecretAvailable() {
4095
4103
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4096
4104
  if (process.platform !== "linux") return false;
4097
4105
  try {
4098
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4099
4106
  const st = statSync3(keyPath);
4100
4107
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4108
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4101
4109
  if (uid === 0) return true;
4102
4110
  const exeOsDir = process.env.EXE_OS_DIR;
4103
- return Boolean(exeOsDir && path7.resolve(keyPath).startsWith(path7.resolve(exeOsDir) + path7.sep));
4111
+ if (exeOsDir && path7.resolve(keyPath).startsWith(path7.resolve(exeOsDir) + path7.sep)) return true;
4112
+ if (!linuxSecretAvailable()) return true;
4113
+ return false;
4104
4114
  } catch {
4105
4115
  return false;
4106
4116
  }
@@ -4250,15 +4260,25 @@ async function writeMachineBoundFileFallback(b64) {
4250
4260
  await mkdir3(dir, { recursive: true });
4251
4261
  const keyPath = getKeyPath();
4252
4262
  const machineKey = deriveMachineKey();
4253
- if (machineKey) {
4254
- const encrypted = encryptWithMachineKey(b64, machineKey);
4255
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4256
- await chmod2(keyPath, 384);
4257
- return "encrypted";
4263
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4264
+ const result = machineKey ? "encrypted" : "plaintext";
4265
+ const tmpPath = keyPath + ".tmp";
4266
+ try {
4267
+ if (existsSync8(keyPath)) {
4268
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4269
+ });
4270
+ }
4271
+ await writeFile3(tmpPath, content, "utf-8");
4272
+ await chmod2(tmpPath, 384);
4273
+ await rename(tmpPath, keyPath);
4274
+ } catch (err) {
4275
+ try {
4276
+ await unlink(tmpPath);
4277
+ } catch {
4278
+ }
4279
+ throw err;
4258
4280
  }
4259
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4260
- await chmod2(keyPath, 384);
4261
- return "plaintext";
4281
+ return result;
4262
4282
  }
4263
4283
  async function getMasterKey() {
4264
4284
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -9401,10 +9421,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9401
9421
  }
9402
9422
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
9403
9423
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
9404
- let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
9405
- if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
9406
- ccModel += "[1m]";
9407
- }
9424
+ const { normalizeCcModelName: normalizeCcModelName2 } = (init_agent_config(), __toCommonJS(agent_config_exports));
9425
+ const ccModel = normalizeCcModelName2(agentRtConfig.model);
9408
9426
  envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
9409
9427
  }
9410
9428
  }
@@ -10151,6 +10169,7 @@ __export(cloud_sync_exports, {
10151
10169
  markCloudReuploadRequired: () => markCloudReuploadRequired,
10152
10170
  mergeConfig: () => mergeConfig,
10153
10171
  mergeRosterFromRemote: () => mergeRosterFromRemote,
10172
+ migrateEndpoint: () => migrateEndpoint,
10154
10173
  pushToPostgres: () => pushToPostgres,
10155
10174
  recordRosterDeletion: () => recordRosterDeletion
10156
10175
  });
@@ -10321,6 +10340,15 @@ async function fetchWithRetry(url, init) {
10321
10340
  }
10322
10341
  throw lastError;
10323
10342
  }
10343
+ function migrateEndpoint(endpoint) {
10344
+ if (endpoint === "https://askexe.com/cloud" || endpoint === "https://askexe.com/cloud/") {
10345
+ process.stderr.write(
10346
+ "[cloud-sync] Auto-migrating endpoint from askexe.com/cloud to cloud.askexe.com (bypasses Cloudflare WAF for datacenter IPs)\n"
10347
+ );
10348
+ return "https://cloud.askexe.com";
10349
+ }
10350
+ return endpoint;
10351
+ }
10324
10352
  function assertSecureEndpoint(endpoint) {
10325
10353
  if (endpoint.startsWith("https://")) return;
10326
10354
  if (endpoint.startsWith("http://")) {
@@ -10458,6 +10486,7 @@ async function markCloudReuploadRequired(client = getClient()) {
10458
10486
  await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
10459
10487
  }
10460
10488
  async function cloudSync(config) {
10489
+ config = { ...config, endpoint: migrateEndpoint(config.endpoint) };
10461
10490
  if (!isSyncCryptoInitialized()) {
10462
10491
  try {
10463
10492
  const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
@@ -1263,6 +1263,7 @@ __export(agent_config_exports, {
1263
1263
  clearAgentRuntime: () => clearAgentRuntime,
1264
1264
  getAgentRuntime: () => getAgentRuntime,
1265
1265
  loadAgentConfig: () => loadAgentConfig,
1266
+ normalizeCcModelName: () => normalizeCcModelName,
1266
1267
  saveAgentConfig: () => saveAgentConfig,
1267
1268
  setAgentMcps: () => setAgentMcps,
1268
1269
  setAgentRuntime: () => setAgentRuntime
@@ -1291,6 +1292,13 @@ function getAgentRuntime(agentId) {
1291
1292
  if (orgDefault) return orgDefault;
1292
1293
  return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
1293
1294
  }
1295
+ function normalizeCcModelName(model) {
1296
+ let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
1297
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
1298
+ ccModel += "[1m]";
1299
+ }
1300
+ return ccModel;
1301
+ }
1294
1302
  function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
1295
1303
  const knownModels = KNOWN_RUNTIMES[runtime];
1296
1304
  if (!knownModels) {
@@ -25,7 +25,7 @@ __export(keychain_exports, {
25
25
  importMnemonic: () => importMnemonic,
26
26
  setMasterKey: () => setMasterKey
27
27
  });
28
- import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
28
+ import { readFile, writeFile, unlink, mkdir, chmod, rename, copyFile } from "fs/promises";
29
29
  import { existsSync, statSync } from "fs";
30
30
  import { execSync } from "child_process";
31
31
  import path from "path";
@@ -60,12 +60,14 @@ function linuxSecretAvailable() {
60
60
  function isRootOnlyTrustedServerKeyFile(keyPath) {
61
61
  if (process.platform !== "linux") return false;
62
62
  try {
63
- const uid = typeof os.userInfo().uid === "number" ? os.userInfo().uid : -1;
64
63
  const st = statSync(keyPath);
65
64
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
65
+ const uid = typeof os.userInfo().uid === "number" ? os.userInfo().uid : -1;
66
66
  if (uid === 0) return true;
67
67
  const exeOsDir = process.env.EXE_OS_DIR;
68
- return Boolean(exeOsDir && path.resolve(keyPath).startsWith(path.resolve(exeOsDir) + path.sep));
68
+ if (exeOsDir && path.resolve(keyPath).startsWith(path.resolve(exeOsDir) + path.sep)) return true;
69
+ if (!linuxSecretAvailable()) return true;
70
+ return false;
69
71
  } catch {
70
72
  return false;
71
73
  }
@@ -215,15 +217,25 @@ async function writeMachineBoundFileFallback(b64) {
215
217
  await mkdir(dir, { recursive: true });
216
218
  const keyPath = getKeyPath();
217
219
  const machineKey = deriveMachineKey();
218
- if (machineKey) {
219
- const encrypted = encryptWithMachineKey(b64, machineKey);
220
- await writeFile(keyPath, encrypted + "\n", "utf-8");
221
- await chmod(keyPath, 384);
222
- return "encrypted";
220
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
221
+ const result = machineKey ? "encrypted" : "plaintext";
222
+ const tmpPath = keyPath + ".tmp";
223
+ try {
224
+ if (existsSync(keyPath)) {
225
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
226
+ });
227
+ }
228
+ await writeFile(tmpPath, content, "utf-8");
229
+ await chmod(tmpPath, 384);
230
+ await rename(tmpPath, keyPath);
231
+ } catch (err) {
232
+ try {
233
+ await unlink(tmpPath);
234
+ } catch {
235
+ }
236
+ throw err;
223
237
  }
224
- await writeFile(keyPath, b64 + "\n", "utf-8");
225
- await chmod(keyPath, 384);
226
- return "plaintext";
238
+ return result;
227
239
  }
228
240
  async function getMasterKey() {
229
241
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4761,6 +4773,7 @@ __export(cloud_sync_exports, {
4761
4773
  markCloudReuploadRequired: () => markCloudReuploadRequired,
4762
4774
  mergeConfig: () => mergeConfig,
4763
4775
  mergeRosterFromRemote: () => mergeRosterFromRemote,
4776
+ migrateEndpoint: () => migrateEndpoint,
4764
4777
  pushToPostgres: () => pushToPostgres,
4765
4778
  recordRosterDeletion: () => recordRosterDeletion
4766
4779
  });
@@ -4931,6 +4944,15 @@ async function fetchWithRetry(url, init) {
4931
4944
  }
4932
4945
  throw lastError;
4933
4946
  }
4947
+ function migrateEndpoint(endpoint) {
4948
+ if (endpoint === "https://askexe.com/cloud" || endpoint === "https://askexe.com/cloud/") {
4949
+ process.stderr.write(
4950
+ "[cloud-sync] Auto-migrating endpoint from askexe.com/cloud to cloud.askexe.com (bypasses Cloudflare WAF for datacenter IPs)\n"
4951
+ );
4952
+ return "https://cloud.askexe.com";
4953
+ }
4954
+ return endpoint;
4955
+ }
4934
4956
  function assertSecureEndpoint(endpoint) {
4935
4957
  if (endpoint.startsWith("https://")) return;
4936
4958
  if (endpoint.startsWith("http://")) {
@@ -5068,6 +5090,7 @@ async function markCloudReuploadRequired(client = getClient()) {
5068
5090
  await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
5069
5091
  }
5070
5092
  async function cloudSync(config) {
5093
+ config = { ...config, endpoint: migrateEndpoint(config.endpoint) };
5071
5094
  if (!isSyncCryptoInitialized()) {
5072
5095
  try {
5073
5096
  const { getMasterKey: getMasterKey2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));