@askexenow/exe-os 0.9.66 → 0.9.67

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 (99) hide show
  1. package/deploy/stack-manifests/v0.9.json +54 -5
  2. package/dist/bin/age-ontology-load.js +61 -0
  3. package/dist/bin/agentic-ontology-backfill.js +4708 -0
  4. package/dist/bin/agentic-reflection-backfill.js +4144 -0
  5. package/dist/bin/{exe-link.js → agentic-semantic-label.js} +1523 -2275
  6. package/dist/bin/backfill-conversations.js +506 -20
  7. package/dist/bin/backfill-responses.js +506 -20
  8. package/dist/bin/backfill-vectors.js +233 -20
  9. package/dist/bin/bulk-sync-postgres.js +4876 -0
  10. package/dist/bin/cleanup-stale-review-tasks.js +507 -21
  11. package/dist/bin/cli.js +2450 -1530
  12. package/dist/bin/exe-assign.js +506 -20
  13. package/dist/bin/exe-boot.js +410 -60
  14. package/dist/bin/exe-cloud.js +795 -105
  15. package/dist/bin/exe-dispatch.js +516 -22
  16. package/dist/bin/exe-doctor.js +587 -30
  17. package/dist/bin/exe-export-behaviors.js +518 -24
  18. package/dist/bin/exe-forget.js +507 -21
  19. package/dist/bin/exe-gateway.js +571 -25
  20. package/dist/bin/exe-heartbeat.js +518 -24
  21. package/dist/bin/exe-kill.js +507 -21
  22. package/dist/bin/exe-launch-agent.js +2312 -1069
  23. package/dist/bin/exe-new-employee.js +197 -165
  24. package/dist/bin/exe-pending-messages.js +507 -21
  25. package/dist/bin/exe-pending-notifications.js +507 -21
  26. package/dist/bin/exe-pending-reviews.js +507 -21
  27. package/dist/bin/exe-rename.js +507 -21
  28. package/dist/bin/exe-review.js +507 -21
  29. package/dist/bin/exe-search.js +518 -24
  30. package/dist/bin/exe-session-cleanup.js +516 -22
  31. package/dist/bin/exe-settings.js +4 -0
  32. package/dist/bin/exe-start-codex.js +682 -143
  33. package/dist/bin/exe-start-opencode.js +627 -79
  34. package/dist/bin/exe-status.js +507 -21
  35. package/dist/bin/exe-team.js +507 -21
  36. package/dist/bin/git-sweep.js +516 -22
  37. package/dist/bin/graph-backfill.js +558 -21
  38. package/dist/bin/graph-export.js +507 -21
  39. package/dist/bin/graph-layer-benchmark.js +109 -0
  40. package/dist/bin/install.js +305 -288
  41. package/dist/bin/intercom-check.js +516 -22
  42. package/dist/bin/postgres-agentic-reflection-backfill.js +187 -0
  43. package/dist/bin/postgres-agentic-semantic-backfill.js +237 -0
  44. package/dist/bin/scan-tasks.js +516 -22
  45. package/dist/bin/setup.js +412 -62
  46. package/dist/bin/shard-migrate.js +506 -20
  47. package/dist/gateway/index.js +569 -23
  48. package/dist/hooks/bug-report-worker.js +519 -25
  49. package/dist/hooks/codex-stop-task-finalizer.js +516 -22
  50. package/dist/hooks/commit-complete.js +516 -22
  51. package/dist/hooks/error-recall.js +518 -24
  52. package/dist/hooks/ingest.js +516 -22
  53. package/dist/hooks/instructions-loaded.js +507 -21
  54. package/dist/hooks/notification.js +507 -21
  55. package/dist/hooks/post-compact.js +507 -21
  56. package/dist/hooks/post-tool-combined.js +519 -25
  57. package/dist/hooks/pre-compact.js +516 -22
  58. package/dist/hooks/pre-tool-use.js +507 -21
  59. package/dist/hooks/prompt-submit.js +519 -25
  60. package/dist/hooks/session-end.js +516 -22
  61. package/dist/hooks/session-start.js +520 -26
  62. package/dist/hooks/stop.js +517 -23
  63. package/dist/hooks/subagent-stop.js +507 -21
  64. package/dist/hooks/summary-worker.js +411 -61
  65. package/dist/index.js +569 -23
  66. package/dist/lib/cloud-sync.js +391 -53
  67. package/dist/lib/config.js +13 -1
  68. package/dist/lib/consolidation.js +1 -1
  69. package/dist/lib/database.js +124 -0
  70. package/dist/lib/db.js +124 -0
  71. package/dist/lib/device-registry.js +124 -0
  72. package/dist/lib/embedder.js +13 -1
  73. package/dist/lib/exe-daemon.js +2184 -561
  74. package/dist/lib/hybrid-search.js +518 -24
  75. package/dist/lib/identity.js +3 -0
  76. package/dist/lib/keychain.js +178 -22
  77. package/dist/lib/messaging.js +3 -0
  78. package/dist/lib/reminders.js +3 -0
  79. package/dist/lib/schedules.js +233 -20
  80. package/dist/lib/skill-learning.js +16 -1
  81. package/dist/lib/store.js +506 -20
  82. package/dist/lib/tasks.js +16 -1
  83. package/dist/lib/tmux-routing.js +16 -1
  84. package/dist/lib/token-spend.js +3 -0
  85. package/dist/mcp/server.js +1757 -428
  86. package/dist/mcp/tools/complete-reminder.js +3 -0
  87. package/dist/mcp/tools/create-reminder.js +3 -0
  88. package/dist/mcp/tools/create-task.js +16 -1
  89. package/dist/mcp/tools/deactivate-behavior.js +3 -0
  90. package/dist/mcp/tools/list-reminders.js +3 -0
  91. package/dist/mcp/tools/list-tasks.js +3 -0
  92. package/dist/mcp/tools/send-message.js +3 -0
  93. package/dist/mcp/tools/update-task.js +16 -1
  94. package/dist/runtime/index.js +516 -22
  95. package/dist/tui/App.js +594 -29
  96. package/package.json +8 -5
  97. package/src/commands/exe/cloud.md +6 -10
  98. package/stack.release.json +3 -3
  99. package/src/commands/exe/link.md +0 -18
@@ -222,6 +222,10 @@ async function loadConfig() {
222
222
  if (config.dbPath.startsWith("~")) {
223
223
  config.dbPath = config.dbPath.replace(/^~/, os.homedir());
224
224
  }
225
+ const envDbPath = path.join(dir, "memories.db");
226
+ if (process.env.EXE_OS_DIR && config.dbPath !== envDbPath && !existsSync2(config.dbPath) && existsSync2(envDbPath)) {
227
+ config.dbPath = envDbPath;
228
+ }
225
229
  return config;
226
230
  } catch {
227
231
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
@@ -1665,6 +1669,9 @@ function getClient() {
1665
1669
  if (_daemonClient && _daemonClient._isDaemonActive()) {
1666
1670
  return _daemonClient;
1667
1671
  }
1672
+ if (!_resilientClient) {
1673
+ return _adapterClient;
1674
+ }
1668
1675
  return _resilientClient;
1669
1676
  }
1670
1677
  async function initDaemonClient() {
@@ -2697,6 +2704,127 @@ async function ensureSchema() {
2697
2704
  VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2698
2705
  END;
2699
2706
  `);
2707
+ await client.executeMultiple(`
2708
+ CREATE TABLE IF NOT EXISTS agent_sessions (
2709
+ id TEXT PRIMARY KEY,
2710
+ agent_id TEXT NOT NULL,
2711
+ project_name TEXT,
2712
+ started_at TEXT NOT NULL,
2713
+ last_event_at TEXT NOT NULL,
2714
+ event_count INTEGER NOT NULL DEFAULT 0,
2715
+ properties TEXT DEFAULT '{}'
2716
+ );
2717
+
2718
+ CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time
2719
+ ON agent_sessions(agent_id, started_at);
2720
+
2721
+ CREATE TABLE IF NOT EXISTS agent_goals (
2722
+ id TEXT PRIMARY KEY,
2723
+ statement TEXT NOT NULL,
2724
+ owner_agent_id TEXT,
2725
+ project_name TEXT,
2726
+ status TEXT NOT NULL DEFAULT 'open',
2727
+ priority INTEGER NOT NULL DEFAULT 5,
2728
+ success_criteria TEXT,
2729
+ parent_goal_id TEXT,
2730
+ due_at TEXT,
2731
+ achieved_at TEXT,
2732
+ supersedes_id TEXT,
2733
+ created_at TEXT NOT NULL,
2734
+ updated_at TEXT NOT NULL,
2735
+ source_memory_id TEXT
2736
+ );
2737
+
2738
+ CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status
2739
+ ON agent_goals(project_name, status, priority);
2740
+
2741
+ CREATE TABLE IF NOT EXISTS agent_events (
2742
+ id TEXT PRIMARY KEY,
2743
+ event_type TEXT NOT NULL,
2744
+ occurred_at TEXT NOT NULL,
2745
+ sequence_index INTEGER NOT NULL,
2746
+ actor_agent_id TEXT,
2747
+ agent_role TEXT,
2748
+ project_name TEXT,
2749
+ session_id TEXT,
2750
+ task_id TEXT,
2751
+ goal_id TEXT,
2752
+ parent_event_id TEXT,
2753
+ intention TEXT,
2754
+ outcome TEXT,
2755
+ evidence_memory_id TEXT,
2756
+ impact TEXT,
2757
+ payload TEXT DEFAULT '{}',
2758
+ created_at TEXT NOT NULL
2759
+ );
2760
+
2761
+ CREATE INDEX IF NOT EXISTS idx_agent_events_time
2762
+ ON agent_events(occurred_at, sequence_index);
2763
+
2764
+ CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq
2765
+ ON agent_events(session_id, sequence_index);
2766
+
2767
+ CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time
2768
+ ON agent_events(goal_id, occurred_at);
2769
+
2770
+ CREATE INDEX IF NOT EXISTS idx_agent_events_memory
2771
+ ON agent_events(evidence_memory_id);
2772
+
2773
+ CREATE TABLE IF NOT EXISTS agent_goal_links (
2774
+ id TEXT PRIMARY KEY,
2775
+ goal_id TEXT NOT NULL,
2776
+ link_type TEXT NOT NULL,
2777
+ target_id TEXT NOT NULL,
2778
+ target_type TEXT NOT NULL,
2779
+ created_at TEXT NOT NULL
2780
+ );
2781
+
2782
+ CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal
2783
+ ON agent_goal_links(goal_id, target_type);
2784
+
2785
+ CREATE TABLE IF NOT EXISTS agent_semantic_labels (
2786
+ id TEXT PRIMARY KEY,
2787
+ source_memory_id TEXT NOT NULL,
2788
+ event_id TEXT,
2789
+ labeler TEXT NOT NULL,
2790
+ schema_version INTEGER NOT NULL DEFAULT 1,
2791
+ confidence REAL NOT NULL DEFAULT 0,
2792
+ labels TEXT NOT NULL,
2793
+ created_at TEXT NOT NULL,
2794
+ updated_at TEXT NOT NULL
2795
+ );
2796
+
2797
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory
2798
+ ON agent_semantic_labels(source_memory_id, labeler);
2799
+
2800
+ CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event
2801
+ ON agent_semantic_labels(event_id);
2802
+
2803
+ CREATE TABLE IF NOT EXISTS agent_reflection_checkpoints (
2804
+ id TEXT PRIMARY KEY,
2805
+ project_name TEXT,
2806
+ session_id TEXT,
2807
+ window_start_at TEXT NOT NULL,
2808
+ window_end_at TEXT NOT NULL,
2809
+ event_count INTEGER NOT NULL DEFAULT 0,
2810
+ goal_count INTEGER NOT NULL DEFAULT 0,
2811
+ success_count INTEGER NOT NULL DEFAULT 0,
2812
+ failure_count INTEGER NOT NULL DEFAULT 0,
2813
+ risk_count INTEGER NOT NULL DEFAULT 0,
2814
+ summary TEXT NOT NULL,
2815
+ learnings TEXT NOT NULL DEFAULT '[]',
2816
+ next_actions TEXT NOT NULL DEFAULT '[]',
2817
+ evidence_event_ids TEXT NOT NULL DEFAULT '[]',
2818
+ confidence REAL NOT NULL DEFAULT 0,
2819
+ created_at TEXT NOT NULL
2820
+ );
2821
+
2822
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time
2823
+ ON agent_reflection_checkpoints(project_name, window_end_at);
2824
+
2825
+ CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time
2826
+ ON agent_reflection_checkpoints(session_id, window_end_at);
2827
+ `);
2700
2828
  try {
2701
2829
  await client.execute({
2702
2830
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -2860,7 +2988,7 @@ __export(shard_manager_exports, {
2860
2988
  shardExists: () => shardExists
2861
2989
  });
2862
2990
  import path7 from "path";
2863
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
2991
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
2864
2992
  import { createClient as createClient2 } from "@libsql/client";
2865
2993
  function initShardManager(encryptionKey) {
2866
2994
  _encryptionKey = encryptionKey;
@@ -2924,7 +3052,7 @@ async function auditShardHealth(options = {}) {
2924
3052
  const shards = [];
2925
3053
  for (const name of names) {
2926
3054
  const dbPath = path7.join(SHARDS_DIR, `${name}.db`);
2927
- const stat = statSync2(dbPath);
3055
+ const stat = statSync3(dbPath);
2928
3056
  const item = {
2929
3057
  name,
2930
3058
  path: dbPath,
@@ -3177,7 +3305,7 @@ async function getReadyShardClient(projectName) {
3177
3305
  _shardLastAccess.delete(safeName);
3178
3306
  const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3179
3307
  if (existsSync7(dbPath)) {
3180
- const stat = statSync2(dbPath);
3308
+ const stat = statSync3(dbPath);
3181
3309
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3182
3310
  const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3183
3311
  renameSync3(dbPath, archivedPath);
@@ -3532,11 +3660,12 @@ init_database();
3532
3660
 
3533
3661
  // src/lib/keychain.ts
3534
3662
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3535
- import { existsSync as existsSync6 } from "fs";
3663
+ import { existsSync as existsSync6, statSync as statSync2 } from "fs";
3536
3664
  import { execSync as execSync2 } from "child_process";
3537
3665
  import path6 from "path";
3538
3666
  import os5 from "os";
3539
- var SERVICE = "exe-mem";
3667
+ var SERVICE = "exe-os";
3668
+ var LEGACY_SERVICE = "exe-mem";
3540
3669
  var ACCOUNT = "master-key";
3541
3670
  function getKeyDir() {
3542
3671
  return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
@@ -3544,29 +3673,79 @@ function getKeyDir() {
3544
3673
  function getKeyPath() {
3545
3674
  return path6.join(getKeyDir(), "master.key");
3546
3675
  }
3547
- function macKeychainGet() {
3676
+ function nativeKeychainAllowed() {
3677
+ return process.env.EXE_OS_DISABLE_NATIVE_KEYCHAIN !== "1";
3678
+ }
3679
+ var linuxSecretAvailability = null;
3680
+ function linuxSecretAvailable() {
3681
+ if (!nativeKeychainAllowed()) return false;
3682
+ if (process.platform !== "linux") return false;
3683
+ if (linuxSecretAvailability !== null) return linuxSecretAvailability;
3684
+ try {
3685
+ execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
3686
+ } catch {
3687
+ linuxSecretAvailability = false;
3688
+ return false;
3689
+ }
3690
+ try {
3691
+ execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
3692
+ linuxSecretAvailability = true;
3693
+ } catch {
3694
+ linuxSecretAvailability = false;
3695
+ }
3696
+ return linuxSecretAvailability;
3697
+ }
3698
+ function isRootOnlyTrustedServerKeyFile(keyPath) {
3699
+ if (process.platform !== "linux") return false;
3700
+ try {
3701
+ const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3702
+ const st = statSync2(keyPath);
3703
+ if (!st.isFile() || (st.mode & 63) !== 0) return false;
3704
+ if (uid === 0) return true;
3705
+ const exeOsDir = process.env.EXE_OS_DIR;
3706
+ return Boolean(exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep));
3707
+ } catch {
3708
+ return false;
3709
+ }
3710
+ }
3711
+ function macKeychainGet(service = SERVICE) {
3712
+ if (!nativeKeychainAllowed()) return null;
3548
3713
  if (process.platform !== "darwin") return null;
3549
3714
  try {
3550
3715
  return execSync2(
3551
- `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
3716
+ `security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
3552
3717
  { encoding: "utf-8", timeout: 5e3 }
3553
3718
  ).trim();
3554
3719
  } catch {
3555
3720
  return null;
3556
3721
  }
3557
3722
  }
3558
- function macKeychainSet(value) {
3723
+ function macKeychainSet(value, service = SERVICE) {
3724
+ if (!nativeKeychainAllowed()) return false;
3559
3725
  if (process.platform !== "darwin") return false;
3560
3726
  try {
3561
3727
  try {
3562
3728
  execSync2(
3563
- `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
3729
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3564
3730
  { timeout: 5e3 }
3565
3731
  );
3566
3732
  } catch {
3567
3733
  }
3568
3734
  execSync2(
3569
- `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
3735
+ `security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
3736
+ { timeout: 5e3 }
3737
+ );
3738
+ return true;
3739
+ } catch {
3740
+ return false;
3741
+ }
3742
+ }
3743
+ function macKeychainDelete(service = SERVICE) {
3744
+ if (!nativeKeychainAllowed()) return false;
3745
+ if (process.platform !== "darwin") return false;
3746
+ try {
3747
+ execSync2(
3748
+ `security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
3570
3749
  { timeout: 5e3 }
3571
3750
  );
3572
3751
  return true;
@@ -3574,22 +3753,35 @@ function macKeychainSet(value) {
3574
3753
  return false;
3575
3754
  }
3576
3755
  }
3577
- function linuxSecretGet() {
3578
- if (process.platform !== "linux") return null;
3756
+ function linuxSecretGet(service = SERVICE) {
3757
+ if (!linuxSecretAvailable()) return null;
3579
3758
  try {
3580
3759
  return execSync2(
3581
- `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
3760
+ `secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3582
3761
  { encoding: "utf-8", timeout: 5e3 }
3583
3762
  ).trim();
3584
3763
  } catch {
3585
3764
  return null;
3586
3765
  }
3587
3766
  }
3588
- function linuxSecretSet(value) {
3767
+ function linuxSecretSet(value, service = SERVICE) {
3768
+ if (!linuxSecretAvailable()) return false;
3769
+ try {
3770
+ execSync2(
3771
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3772
+ { timeout: 5e3 }
3773
+ );
3774
+ return true;
3775
+ } catch {
3776
+ return false;
3777
+ }
3778
+ }
3779
+ function linuxSecretDelete(service = SERVICE) {
3780
+ if (!nativeKeychainAllowed()) return false;
3589
3781
  if (process.platform !== "linux") return false;
3590
3782
  try {
3591
3783
  execSync2(
3592
- `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
3784
+ `secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
3593
3785
  { timeout: 5e3 }
3594
3786
  );
3595
3787
  return true;
@@ -3598,6 +3790,7 @@ function linuxSecretSet(value) {
3598
3790
  }
3599
3791
  }
3600
3792
  async function tryKeytar() {
3793
+ if (!nativeKeychainAllowed()) return null;
3601
3794
  try {
3602
3795
  return await import("keytar");
3603
3796
  } catch {
@@ -3672,7 +3865,19 @@ async function writeMachineBoundFileFallback(b64) {
3672
3865
  return "plaintext";
3673
3866
  }
3674
3867
  async function getMasterKey() {
3675
- const nativeValue = macKeychainGet() ?? linuxSecretGet();
3868
+ let nativeValue = macKeychainGet() ?? linuxSecretGet();
3869
+ if (!nativeValue) {
3870
+ const legacyValue = macKeychainGet(LEGACY_SERVICE) ?? linuxSecretGet(LEGACY_SERVICE);
3871
+ if (legacyValue) {
3872
+ const migrated = macKeychainSet(legacyValue) || linuxSecretSet(legacyValue);
3873
+ if (migrated) {
3874
+ macKeychainDelete(LEGACY_SERVICE);
3875
+ linuxSecretDelete(LEGACY_SERVICE);
3876
+ process.stderr.write("[keychain] Migrated keychain service from exe-mem to exe-os.\n");
3877
+ }
3878
+ nativeValue = legacyValue;
3879
+ }
3880
+ }
3676
3881
  if (nativeValue) {
3677
3882
  return Buffer.from(nativeValue, "base64");
3678
3883
  }
@@ -3680,12 +3885,17 @@ async function getMasterKey() {
3680
3885
  if (keytar) {
3681
3886
  try {
3682
3887
  const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
3683
- if (keytarValue) {
3684
- const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
3888
+ const legacyKeytarValue = keytarValue ?? await keytar.getPassword(LEGACY_SERVICE, ACCOUNT);
3889
+ if (legacyKeytarValue) {
3890
+ const migrated = macKeychainSet(legacyKeytarValue) || linuxSecretSet(legacyKeytarValue);
3685
3891
  if (migrated) {
3686
3892
  process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
3893
+ try {
3894
+ await keytar.deletePassword(LEGACY_SERVICE, ACCOUNT);
3895
+ } catch {
3896
+ }
3687
3897
  }
3688
- return Buffer.from(keytarValue, "base64");
3898
+ return Buffer.from(legacyKeytarValue, "base64");
3689
3899
  }
3690
3900
  } catch {
3691
3901
  }
@@ -3710,7 +3920,7 @@ async function getMasterKey() {
3710
3920
  const decrypted = decryptWithMachineKey(content, machineKey);
3711
3921
  if (!decrypted) {
3712
3922
  process.stderr.write(
3713
- "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
3923
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase during setup: exe-os setup\n"
3714
3924
  );
3715
3925
  return null;
3716
3926
  }
@@ -3719,6 +3929,9 @@ async function getMasterKey() {
3719
3929
  b64Value = content;
3720
3930
  }
3721
3931
  const key = Buffer.from(b64Value, "base64");
3932
+ if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
3933
+ return key;
3934
+ }
3722
3935
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3723
3936
  if (migrated) {
3724
3937
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");