@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
@@ -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);
@@ -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());
@@ -3958,7 +3970,7 @@ init_memory();
3958
3970
  init_database();
3959
3971
 
3960
3972
  // src/lib/keychain.ts
3961
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3973
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
3962
3974
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3963
3975
  import { execSync as execSync3 } from "child_process";
3964
3976
  import path6 from "path";
@@ -3997,12 +4009,14 @@ function linuxSecretAvailable() {
3997
4009
  function isRootOnlyTrustedServerKeyFile(keyPath) {
3998
4010
  if (process.platform !== "linux") return false;
3999
4011
  try {
4000
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4001
4012
  const st = statSync3(keyPath);
4002
4013
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4014
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4003
4015
  if (uid === 0) return true;
4004
4016
  const exeOsDir = process.env.EXE_OS_DIR;
4005
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4017
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4018
+ if (!linuxSecretAvailable()) return true;
4019
+ return false;
4006
4020
  } catch {
4007
4021
  return false;
4008
4022
  }
@@ -4153,15 +4167,25 @@ async function writeMachineBoundFileFallback(b64) {
4153
4167
  await mkdir3(dir, { recursive: true });
4154
4168
  const keyPath = getKeyPath();
4155
4169
  const machineKey = deriveMachineKey();
4156
- if (machineKey) {
4157
- const encrypted = encryptWithMachineKey(b64, machineKey);
4158
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4159
- await chmod2(keyPath, 384);
4160
- return "encrypted";
4170
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4171
+ const result = machineKey ? "encrypted" : "plaintext";
4172
+ const tmpPath = keyPath + ".tmp";
4173
+ try {
4174
+ if (existsSync7(keyPath)) {
4175
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4176
+ });
4177
+ }
4178
+ await writeFile3(tmpPath, content, "utf-8");
4179
+ await chmod2(tmpPath, 384);
4180
+ await rename(tmpPath, keyPath);
4181
+ } catch (err) {
4182
+ try {
4183
+ await unlink(tmpPath);
4184
+ } catch {
4185
+ }
4186
+ throw err;
4161
4187
  }
4162
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4163
- await chmod2(keyPath, 384);
4164
- return "plaintext";
4188
+ return result;
4165
4189
  }
4166
4190
  async function getMasterKey() {
4167
4191
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4228,7 +4252,7 @@ async function getMasterKey() {
4228
4252
  b64Value = content;
4229
4253
  }
4230
4254
  const key = Buffer.from(b64Value, "base64");
4231
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4255
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4232
4256
  return key;
4233
4257
  }
4234
4258
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -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());
@@ -4082,7 +4094,7 @@ init_memory();
4082
4094
  init_database();
4083
4095
 
4084
4096
  // src/lib/keychain.ts
4085
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4097
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4086
4098
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4087
4099
  import { execSync as execSync3 } from "child_process";
4088
4100
  import path6 from "path";
@@ -4121,12 +4133,14 @@ function linuxSecretAvailable() {
4121
4133
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4122
4134
  if (process.platform !== "linux") return false;
4123
4135
  try {
4124
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4125
4136
  const st = statSync3(keyPath);
4126
4137
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4138
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4127
4139
  if (uid === 0) return true;
4128
4140
  const exeOsDir = process.env.EXE_OS_DIR;
4129
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4141
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4142
+ if (!linuxSecretAvailable()) return true;
4143
+ return false;
4130
4144
  } catch {
4131
4145
  return false;
4132
4146
  }
@@ -4277,15 +4291,25 @@ async function writeMachineBoundFileFallback(b64) {
4277
4291
  await mkdir3(dir, { recursive: true });
4278
4292
  const keyPath = getKeyPath();
4279
4293
  const machineKey = deriveMachineKey();
4280
- if (machineKey) {
4281
- const encrypted = encryptWithMachineKey(b64, machineKey);
4282
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4283
- await chmod2(keyPath, 384);
4284
- return "encrypted";
4294
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4295
+ const result = machineKey ? "encrypted" : "plaintext";
4296
+ const tmpPath = keyPath + ".tmp";
4297
+ try {
4298
+ if (existsSync7(keyPath)) {
4299
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4300
+ });
4301
+ }
4302
+ await writeFile3(tmpPath, content, "utf-8");
4303
+ await chmod2(tmpPath, 384);
4304
+ await rename(tmpPath, keyPath);
4305
+ } catch (err) {
4306
+ try {
4307
+ await unlink(tmpPath);
4308
+ } catch {
4309
+ }
4310
+ throw err;
4285
4311
  }
4286
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4287
- await chmod2(keyPath, 384);
4288
- return "plaintext";
4312
+ return result;
4289
4313
  }
4290
4314
  async function getMasterKey() {
4291
4315
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4352,7 +4376,7 @@ async function getMasterKey() {
4352
4376
  b64Value = content;
4353
4377
  }
4354
4378
  const key = Buffer.from(b64Value, "base64");
4355
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4379
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4356
4380
  return key;
4357
4381
  }
4358
4382
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -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());
@@ -4534,7 +4546,7 @@ init_memory();
4534
4546
  init_database();
4535
4547
 
4536
4548
  // src/lib/keychain.ts
4537
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4549
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4538
4550
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4539
4551
  import { execSync as execSync3 } from "child_process";
4540
4552
  import path6 from "path";
@@ -4573,12 +4585,14 @@ function linuxSecretAvailable() {
4573
4585
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4574
4586
  if (process.platform !== "linux") return false;
4575
4587
  try {
4576
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4577
4588
  const st = statSync3(keyPath);
4578
4589
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4590
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4579
4591
  if (uid === 0) return true;
4580
4592
  const exeOsDir = process.env.EXE_OS_DIR;
4581
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4593
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4594
+ if (!linuxSecretAvailable()) return true;
4595
+ return false;
4582
4596
  } catch {
4583
4597
  return false;
4584
4598
  }
@@ -4729,15 +4743,25 @@ async function writeMachineBoundFileFallback(b64) {
4729
4743
  await mkdir3(dir, { recursive: true });
4730
4744
  const keyPath = getKeyPath();
4731
4745
  const machineKey = deriveMachineKey();
4732
- if (machineKey) {
4733
- const encrypted = encryptWithMachineKey(b64, machineKey);
4734
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4735
- await chmod2(keyPath, 384);
4736
- return "encrypted";
4746
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4747
+ const result = machineKey ? "encrypted" : "plaintext";
4748
+ const tmpPath = keyPath + ".tmp";
4749
+ try {
4750
+ if (existsSync7(keyPath)) {
4751
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4752
+ });
4753
+ }
4754
+ await writeFile3(tmpPath, content, "utf-8");
4755
+ await chmod2(tmpPath, 384);
4756
+ await rename(tmpPath, keyPath);
4757
+ } catch (err) {
4758
+ try {
4759
+ await unlink(tmpPath);
4760
+ } catch {
4761
+ }
4762
+ throw err;
4737
4763
  }
4738
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4739
- await chmod2(keyPath, 384);
4740
- return "plaintext";
4764
+ return result;
4741
4765
  }
4742
4766
  async function getMasterKey() {
4743
4767
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4804,7 +4828,7 @@ async function getMasterKey() {
4804
4828
  b64Value = content;
4805
4829
  }
4806
4830
  const key = Buffer.from(b64Value, "base64");
4807
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4831
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4808
4832
  return key;
4809
4833
  }
4810
4834
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -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());
@@ -4533,7 +4545,7 @@ init_memory();
4533
4545
  init_database();
4534
4546
 
4535
4547
  // src/lib/keychain.ts
4536
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4548
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4537
4549
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4538
4550
  import { execSync as execSync3 } from "child_process";
4539
4551
  import path6 from "path";
@@ -4572,12 +4584,14 @@ function linuxSecretAvailable() {
4572
4584
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4573
4585
  if (process.platform !== "linux") return false;
4574
4586
  try {
4575
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4576
4587
  const st = statSync3(keyPath);
4577
4588
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4589
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4578
4590
  if (uid === 0) return true;
4579
4591
  const exeOsDir = process.env.EXE_OS_DIR;
4580
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4592
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4593
+ if (!linuxSecretAvailable()) return true;
4594
+ return false;
4581
4595
  } catch {
4582
4596
  return false;
4583
4597
  }
@@ -4728,15 +4742,25 @@ async function writeMachineBoundFileFallback(b64) {
4728
4742
  await mkdir3(dir, { recursive: true });
4729
4743
  const keyPath = getKeyPath();
4730
4744
  const machineKey = deriveMachineKey();
4731
- if (machineKey) {
4732
- const encrypted = encryptWithMachineKey(b64, machineKey);
4733
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4734
- await chmod2(keyPath, 384);
4735
- return "encrypted";
4745
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4746
+ const result = machineKey ? "encrypted" : "plaintext";
4747
+ const tmpPath = keyPath + ".tmp";
4748
+ try {
4749
+ if (existsSync7(keyPath)) {
4750
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4751
+ });
4752
+ }
4753
+ await writeFile3(tmpPath, content, "utf-8");
4754
+ await chmod2(tmpPath, 384);
4755
+ await rename(tmpPath, keyPath);
4756
+ } catch (err) {
4757
+ try {
4758
+ await unlink(tmpPath);
4759
+ } catch {
4760
+ }
4761
+ throw err;
4736
4762
  }
4737
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4738
- await chmod2(keyPath, 384);
4739
- return "plaintext";
4763
+ return result;
4740
4764
  }
4741
4765
  async function getMasterKey() {
4742
4766
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4803,7 +4827,7 @@ async function getMasterKey() {
4803
4827
  b64Value = content;
4804
4828
  }
4805
4829
  const key = Buffer.from(b64Value, "base64");
4806
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4830
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4807
4831
  return key;
4808
4832
  }
4809
4833
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -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());
@@ -4080,7 +4092,7 @@ init_memory();
4080
4092
  init_database();
4081
4093
 
4082
4094
  // src/lib/keychain.ts
4083
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
4095
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
4084
4096
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
4085
4097
  import { execSync as execSync3 } from "child_process";
4086
4098
  import path6 from "path";
@@ -4119,12 +4131,14 @@ function linuxSecretAvailable() {
4119
4131
  function isRootOnlyTrustedServerKeyFile(keyPath) {
4120
4132
  if (process.platform !== "linux") return false;
4121
4133
  try {
4122
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4123
4134
  const st = statSync3(keyPath);
4124
4135
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
4136
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
4125
4137
  if (uid === 0) return true;
4126
4138
  const exeOsDir = process.env.EXE_OS_DIR;
4127
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
4139
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
4140
+ if (!linuxSecretAvailable()) return true;
4141
+ return false;
4128
4142
  } catch {
4129
4143
  return false;
4130
4144
  }
@@ -4275,15 +4289,25 @@ async function writeMachineBoundFileFallback(b64) {
4275
4289
  await mkdir3(dir, { recursive: true });
4276
4290
  const keyPath = getKeyPath();
4277
4291
  const machineKey = deriveMachineKey();
4278
- if (machineKey) {
4279
- const encrypted = encryptWithMachineKey(b64, machineKey);
4280
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
4281
- await chmod2(keyPath, 384);
4282
- return "encrypted";
4292
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
4293
+ const result = machineKey ? "encrypted" : "plaintext";
4294
+ const tmpPath = keyPath + ".tmp";
4295
+ try {
4296
+ if (existsSync7(keyPath)) {
4297
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
4298
+ });
4299
+ }
4300
+ await writeFile3(tmpPath, content, "utf-8");
4301
+ await chmod2(tmpPath, 384);
4302
+ await rename(tmpPath, keyPath);
4303
+ } catch (err) {
4304
+ try {
4305
+ await unlink(tmpPath);
4306
+ } catch {
4307
+ }
4308
+ throw err;
4283
4309
  }
4284
- await writeFile3(keyPath, b64 + "\n", "utf-8");
4285
- await chmod2(keyPath, 384);
4286
- return "plaintext";
4310
+ return result;
4287
4311
  }
4288
4312
  async function getMasterKey() {
4289
4313
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -4350,7 +4374,7 @@ async function getMasterKey() {
4350
4374
  b64Value = content;
4351
4375
  }
4352
4376
  const key = Buffer.from(b64Value, "base64");
4353
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
4377
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
4354
4378
  return key;
4355
4379
  }
4356
4380
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
@@ -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());
@@ -3101,7 +3113,7 @@ var init_database = __esm({
3101
3113
  });
3102
3114
 
3103
3115
  // src/lib/keychain.ts
3104
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3116
+ import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
3105
3117
  import { existsSync as existsSync7, statSync as statSync3 } from "fs";
3106
3118
  import { execSync as execSync3 } from "child_process";
3107
3119
  import path6 from "path";
@@ -3136,12 +3148,14 @@ function linuxSecretAvailable() {
3136
3148
  function isRootOnlyTrustedServerKeyFile(keyPath) {
3137
3149
  if (process.platform !== "linux") return false;
3138
3150
  try {
3139
- const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3140
3151
  const st = statSync3(keyPath);
3141
3152
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3153
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3142
3154
  if (uid === 0) return true;
3143
3155
  const exeOsDir = process.env.EXE_OS_DIR;
3144
- return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
3156
+ if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
3157
+ if (!linuxSecretAvailable()) return true;
3158
+ return false;
3145
3159
  } catch {
3146
3160
  return false;
3147
3161
  }
@@ -3291,15 +3305,25 @@ async function writeMachineBoundFileFallback(b64) {
3291
3305
  await mkdir3(dir, { recursive: true });
3292
3306
  const keyPath = getKeyPath();
3293
3307
  const machineKey = deriveMachineKey();
3294
- if (machineKey) {
3295
- const encrypted = encryptWithMachineKey(b64, machineKey);
3296
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
3297
- await chmod2(keyPath, 384);
3298
- return "encrypted";
3308
+ const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
3309
+ const result = machineKey ? "encrypted" : "plaintext";
3310
+ const tmpPath = keyPath + ".tmp";
3311
+ try {
3312
+ if (existsSync7(keyPath)) {
3313
+ await copyFile(keyPath, keyPath + ".bak").catch(() => {
3314
+ });
3315
+ }
3316
+ await writeFile3(tmpPath, content, "utf-8");
3317
+ await chmod2(tmpPath, 384);
3318
+ await rename(tmpPath, keyPath);
3319
+ } catch (err) {
3320
+ try {
3321
+ await unlink(tmpPath);
3322
+ } catch {
3323
+ }
3324
+ throw err;
3299
3325
  }
3300
- await writeFile3(keyPath, b64 + "\n", "utf-8");
3301
- await chmod2(keyPath, 384);
3302
- return "plaintext";
3326
+ return result;
3303
3327
  }
3304
3328
  async function getMasterKey() {
3305
3329
  let nativeValue = macKeychainGet() ?? linuxSecretGet();
@@ -3366,7 +3390,7 @@ async function getMasterKey() {
3366
3390
  b64Value = content;
3367
3391
  }
3368
3392
  const key = Buffer.from(b64Value, "base64");
3369
- if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
3393
+ if (isRootOnlyTrustedServerKeyFile(keyPath)) {
3370
3394
  return key;
3371
3395
  }
3372
3396
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);