@askexenow/exe-os 0.9.102 → 0.9.104

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 (92) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +334 -100
  2. package/dist/bin/agentic-reflection-backfill.js +328 -97
  3. package/dist/bin/agentic-semantic-label.js +328 -97
  4. package/dist/bin/backfill-conversations.js +332 -97
  5. package/dist/bin/backfill-responses.js +332 -97
  6. package/dist/bin/backfill-vectors.js +337 -106
  7. package/dist/bin/bulk-sync-postgres.js +335 -101
  8. package/dist/bin/cleanup-stale-review-tasks.js +356 -108
  9. package/dist/bin/cli.js +653 -405
  10. package/dist/bin/exe-agent.js +21 -3
  11. package/dist/bin/exe-assign.js +338 -94
  12. package/dist/bin/exe-boot.js +472 -239
  13. package/dist/bin/exe-call.js +22 -5
  14. package/dist/bin/exe-cloud.js +404 -158
  15. package/dist/bin/exe-dispatch.js +390 -142
  16. package/dist/bin/exe-doctor.js +349 -103
  17. package/dist/bin/exe-export-behaviors.js +351 -105
  18. package/dist/bin/exe-forget.js +352 -103
  19. package/dist/bin/exe-gateway.js +420 -172
  20. package/dist/bin/exe-heartbeat.js +361 -113
  21. package/dist/bin/exe-kill.js +344 -98
  22. package/dist/bin/exe-launch-agent.js +375 -129
  23. package/dist/bin/exe-new-employee.js +83 -67
  24. package/dist/bin/exe-pending-messages.js +356 -108
  25. package/dist/bin/exe-pending-notifications.js +358 -110
  26. package/dist/bin/exe-pending-reviews.js +359 -111
  27. package/dist/bin/exe-rename.js +354 -108
  28. package/dist/bin/exe-review.js +343 -97
  29. package/dist/bin/exe-search.js +363 -113
  30. package/dist/bin/exe-session-cleanup.js +403 -155
  31. package/dist/bin/exe-settings.js +14 -9
  32. package/dist/bin/exe-start-codex.js +365 -131
  33. package/dist/bin/exe-start-opencode.js +359 -125
  34. package/dist/bin/exe-status.js +356 -108
  35. package/dist/bin/exe-team.js +343 -97
  36. package/dist/bin/git-sweep.js +390 -142
  37. package/dist/bin/graph-backfill.js +334 -100
  38. package/dist/bin/graph-export.js +346 -100
  39. package/dist/bin/install.js +1 -0
  40. package/dist/bin/intercom-check.js +403 -155
  41. package/dist/bin/pre-publish.js +12 -0
  42. package/dist/bin/scan-tasks.js +393 -145
  43. package/dist/bin/setup.js +331 -159
  44. package/dist/bin/shard-migrate.js +328 -94
  45. package/dist/gateway/index.js +406 -158
  46. package/dist/hooks/bug-report-worker.js +396 -148
  47. package/dist/hooks/codex-stop-task-finalizer.js +374 -126
  48. package/dist/hooks/commit-complete.js +390 -142
  49. package/dist/hooks/error-recall.js +365 -115
  50. package/dist/hooks/ingest.js +357 -111
  51. package/dist/hooks/instructions-loaded.js +351 -105
  52. package/dist/hooks/notification.js +343 -97
  53. package/dist/hooks/post-compact.js +358 -110
  54. package/dist/hooks/post-tool-combined.js +384 -132
  55. package/dist/hooks/pre-compact.js +391 -143
  56. package/dist/hooks/pre-tool-use.js +362 -114
  57. package/dist/hooks/prompt-submit.js +422 -170
  58. package/dist/hooks/session-end.js +393 -145
  59. package/dist/hooks/session-start.js +390 -138
  60. package/dist/hooks/stop.js +361 -113
  61. package/dist/hooks/subagent-stop.js +354 -106
  62. package/dist/hooks/summary-worker.js +418 -185
  63. package/dist/index.js +400 -152
  64. package/dist/lib/cloud-sync.js +291 -131
  65. package/dist/lib/consolidation.js +8 -2
  66. package/dist/lib/database.js +233 -73
  67. package/dist/lib/db.js +233 -73
  68. package/dist/lib/device-registry.js +237 -77
  69. package/dist/lib/employee-templates.js +19 -1
  70. package/dist/lib/exe-daemon.js +705 -409
  71. package/dist/lib/hybrid-search.js +363 -113
  72. package/dist/lib/identity.js +9 -5
  73. package/dist/lib/messaging.js +26 -20
  74. package/dist/lib/reminders.js +5 -1
  75. package/dist/lib/schedules.js +320 -89
  76. package/dist/lib/skill-learning.js +28 -24
  77. package/dist/lib/store.js +342 -96
  78. package/dist/lib/tasks.js +82 -76
  79. package/dist/lib/tmux-routing.js +74 -68
  80. package/dist/lib/token-spend.js +5 -1
  81. package/dist/mcp/server.js +628 -355
  82. package/dist/mcp/tools/complete-reminder.js +5 -1
  83. package/dist/mcp/tools/create-reminder.js +5 -1
  84. package/dist/mcp/tools/create-task.js +89 -83
  85. package/dist/mcp/tools/deactivate-behavior.js +7 -3
  86. package/dist/mcp/tools/list-reminders.js +5 -1
  87. package/dist/mcp/tools/list-tasks.js +28 -21
  88. package/dist/mcp/tools/send-message.js +28 -22
  89. package/dist/mcp/tools/update-task.js +89 -83
  90. package/dist/runtime/index.js +390 -142
  91. package/dist/tui/App.js +437 -189
  92. package/package.json +1 -1
package/dist/tui/App.js CHANGED
@@ -2494,9 +2494,79 @@ __export(database_exports, {
2494
2494
  isInitialized: () => isInitialized,
2495
2495
  setExternalClient: () => setExternalClient
2496
2496
  });
2497
- import { chmodSync as chmodSync2 } from "fs";
2497
+ import { chmodSync as chmodSync2, existsSync as existsSync10, statSync as statSync2, copyFileSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync4 } from "fs";
2498
2498
  import { createClient } from "@libsql/client";
2499
+ import { homedir } from "os";
2500
+ import { join } from "path";
2501
+ function logCatchDebug(context, err) {
2502
+ if (_debugDb) {
2503
+ process.stderr.write(
2504
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
2505
+ `
2506
+ );
2507
+ }
2508
+ }
2509
+ function acquireDbLock() {
2510
+ mkdirSync4(join(homedir(), ".exe-os"), { recursive: true });
2511
+ try {
2512
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
2513
+ } catch (err) {
2514
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
2515
+ try {
2516
+ const lockStat = statSync2(DB_LOCK_PATH);
2517
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
2518
+ unlinkSync3(DB_LOCK_PATH);
2519
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
2520
+ return;
2521
+ }
2522
+ } catch (e) {
2523
+ logCatchDebug("stale lock check", e);
2524
+ }
2525
+ process.stderr.write(
2526
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
2527
+ );
2528
+ return;
2529
+ }
2530
+ throw err;
2531
+ }
2532
+ }
2533
+ function releaseDbLock() {
2534
+ if (_lockFd !== null) {
2535
+ try {
2536
+ closeSync2(_lockFd);
2537
+ } catch (e) {
2538
+ logCatchDebug("lock close", e);
2539
+ }
2540
+ _lockFd = null;
2541
+ }
2542
+ try {
2543
+ unlinkSync3(DB_LOCK_PATH);
2544
+ } catch (e) {
2545
+ logCatchDebug("lock unlink", e);
2546
+ }
2547
+ }
2499
2548
  async function initDatabase(config) {
2549
+ acquireDbLock();
2550
+ if (existsSync10(config.dbPath)) {
2551
+ const dbStat = statSync2(config.dbPath);
2552
+ if (dbStat.size === 0) {
2553
+ const walPath = config.dbPath + "-wal";
2554
+ if (existsSync10(walPath) && statSync2(walPath).size > 0) {
2555
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
2556
+ copyFileSync(config.dbPath, backupPath);
2557
+ unlinkSync3(config.dbPath);
2558
+ process.stderr.write(
2559
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
2560
+ `
2561
+ );
2562
+ } else {
2563
+ process.stderr.write(
2564
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
2565
+ `
2566
+ );
2567
+ }
2568
+ }
2569
+ }
2500
2570
  if (_walCheckpointTimer) {
2501
2571
  clearInterval(_walCheckpointTimer);
2502
2572
  _walCheckpointTimer = null;
@@ -2523,10 +2593,8 @@ async function initDatabase(config) {
2523
2593
  _client = createClient(opts);
2524
2594
  _resilientClient = wrapWithRetry(_client);
2525
2595
  _adapterClient = _resilientClient;
2526
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
2527
- });
2528
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
2529
- });
2596
+ await _client.execute("PRAGMA busy_timeout = 30000");
2597
+ await _client.execute("PRAGMA journal_mode = WAL");
2530
2598
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
2531
2599
  _walCheckpointTimer = setInterval(() => {
2532
2600
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -2541,11 +2609,16 @@ async function initDatabase(config) {
2541
2609
  for (const suffix of ["-wal", "-shm"]) {
2542
2610
  try {
2543
2611
  chmodSync2(config.dbPath + suffix, 384);
2544
- } catch {
2612
+ } catch (chmodErr) {
2613
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
2614
+ `);
2545
2615
  }
2546
2616
  }
2547
- } catch {
2617
+ } catch (chmodErr) {
2618
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
2619
+ `);
2548
2620
  }
2621
+ releaseDbLock();
2549
2622
  }
2550
2623
  function isInitialized() {
2551
2624
  return _adapterClient !== null || _client !== null;
@@ -2600,7 +2673,8 @@ async function ensureSchema() {
2600
2673
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
2601
2674
  try {
2602
2675
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
2603
- } catch {
2676
+ } catch (e) {
2677
+ logCatchDebug("migration", e);
2604
2678
  }
2605
2679
  await client.executeMultiple(`
2606
2680
  CREATE TABLE IF NOT EXISTS memories (
@@ -2665,6 +2739,23 @@ async function ensureSchema() {
2665
2739
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
2666
2740
  END;
2667
2741
  `);
2742
+ try {
2743
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
2744
+ } catch (ftsErr) {
2745
+ process.stderr.write(
2746
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
2747
+ `
2748
+ );
2749
+ try {
2750
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
2751
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
2752
+ } catch (rebuildErr) {
2753
+ process.stderr.write(
2754
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
2755
+ `
2756
+ );
2757
+ }
2758
+ }
2668
2759
  await client.executeMultiple(`
2669
2760
  CREATE TABLE IF NOT EXISTS sync_meta (
2670
2761
  key TEXT PRIMARY KEY,
@@ -2723,35 +2814,40 @@ async function ensureSchema() {
2723
2814
  });
2724
2815
  }
2725
2816
  }
2726
- } catch {
2817
+ } catch (seedErr) {
2818
+ logCatchDebug("behavior seed", seedErr);
2727
2819
  }
2728
2820
  try {
2729
2821
  await client.execute({
2730
2822
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
2731
2823
  args: []
2732
2824
  });
2733
- } catch {
2825
+ } catch (e) {
2826
+ logCatchDebug("migration", e);
2734
2827
  }
2735
2828
  try {
2736
2829
  await client.execute({
2737
2830
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
2738
2831
  args: []
2739
2832
  });
2740
- } catch {
2833
+ } catch (e) {
2834
+ logCatchDebug("migration", e);
2741
2835
  }
2742
2836
  try {
2743
2837
  await client.execute({
2744
2838
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
2745
2839
  args: []
2746
2840
  });
2747
- } catch {
2841
+ } catch (e) {
2842
+ logCatchDebug("migration", e);
2748
2843
  }
2749
2844
  try {
2750
2845
  await client.execute({
2751
2846
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
2752
2847
  args: []
2753
2848
  });
2754
- } catch {
2849
+ } catch (e) {
2850
+ logCatchDebug("migration", e);
2755
2851
  }
2756
2852
  try {
2757
2853
  await client.execute({
@@ -2760,98 +2856,112 @@ async function ensureSchema() {
2760
2856
  WHERE parent_task_id IS NOT NULL`,
2761
2857
  args: []
2762
2858
  });
2763
- } catch {
2859
+ } catch (e) {
2860
+ logCatchDebug("migration", e);
2764
2861
  }
2765
2862
  try {
2766
2863
  await client.execute({
2767
2864
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
2768
2865
  args: []
2769
2866
  });
2770
- } catch {
2867
+ } catch (e) {
2868
+ logCatchDebug("migration", e);
2771
2869
  }
2772
2870
  try {
2773
2871
  await client.execute({
2774
2872
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
2775
2873
  args: []
2776
2874
  });
2777
- } catch {
2875
+ } catch (e) {
2876
+ logCatchDebug("migration", e);
2778
2877
  }
2779
2878
  try {
2780
2879
  await client.execute({
2781
2880
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
2782
2881
  args: []
2783
2882
  });
2784
- } catch {
2883
+ } catch (e) {
2884
+ logCatchDebug("migration", e);
2785
2885
  }
2786
2886
  try {
2787
2887
  await client.execute({
2788
2888
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
2789
2889
  args: []
2790
2890
  });
2791
- } catch {
2891
+ } catch (e) {
2892
+ logCatchDebug("migration", e);
2792
2893
  }
2793
2894
  try {
2794
2895
  await client.execute({
2795
2896
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
2796
2897
  args: []
2797
2898
  });
2798
- } catch {
2899
+ } catch (e) {
2900
+ logCatchDebug("migration", e);
2799
2901
  }
2800
2902
  try {
2801
2903
  await client.execute({
2802
2904
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
2803
2905
  args: []
2804
2906
  });
2805
- } catch {
2907
+ } catch (e) {
2908
+ logCatchDebug("migration", e);
2806
2909
  }
2807
2910
  try {
2808
2911
  await client.execute({
2809
2912
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
2810
2913
  args: []
2811
2914
  });
2812
- } catch {
2915
+ } catch (e) {
2916
+ logCatchDebug("migration", e);
2813
2917
  }
2814
2918
  try {
2815
2919
  await client.execute({
2816
2920
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
2817
2921
  args: []
2818
2922
  });
2819
- } catch {
2923
+ } catch (e) {
2924
+ logCatchDebug("migration", e);
2820
2925
  }
2821
2926
  try {
2822
2927
  await client.execute({
2823
2928
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2824
2929
  args: []
2825
2930
  });
2826
- } catch {
2931
+ } catch (e) {
2932
+ logCatchDebug("migration", e);
2827
2933
  }
2828
2934
  try {
2829
2935
  await client.execute({
2830
2936
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2831
2937
  args: []
2832
2938
  });
2833
- } catch {
2939
+ } catch (e) {
2940
+ logCatchDebug("migration", e);
2834
2941
  }
2835
2942
  try {
2836
2943
  await client.execute({
2837
2944
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2838
2945
  args: []
2839
2946
  });
2840
- } catch {
2947
+ } catch (e) {
2948
+ logCatchDebug("migration", e);
2841
2949
  }
2842
2950
  try {
2843
2951
  await client.execute({
2844
2952
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2845
2953
  args: []
2846
2954
  });
2847
- } catch {
2955
+ } catch (e) {
2956
+ logCatchDebug("migration", e);
2848
2957
  }
2849
2958
  try {
2850
2959
  await client.execute({
2851
2960
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2852
2961
  args: []
2853
2962
  });
2854
- } catch {
2963
+ } catch (e) {
2964
+ logCatchDebug("migration", e);
2855
2965
  }
2856
2966
  await client.executeMultiple(`
2857
2967
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2956,14 +3066,16 @@ async function ensureSchema() {
2956
3066
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2957
3067
  args: []
2958
3068
  });
2959
- } catch {
3069
+ } catch (e) {
3070
+ logCatchDebug("migration", e);
2960
3071
  }
2961
3072
  try {
2962
3073
  await client.execute({
2963
3074
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2964
3075
  args: []
2965
3076
  });
2966
- } catch {
3077
+ } catch (e) {
3078
+ logCatchDebug("migration", e);
2967
3079
  }
2968
3080
  await client.executeMultiple(`
2969
3081
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2989,7 +3101,8 @@ async function ensureSchema() {
2989
3101
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2990
3102
  args: []
2991
3103
  });
2992
- } catch {
3104
+ } catch (e) {
3105
+ logCatchDebug("migration", e);
2993
3106
  }
2994
3107
  await client.executeMultiple(`
2995
3108
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -3013,7 +3126,8 @@ async function ensureSchema() {
3013
3126
  `);
3014
3127
  try {
3015
3128
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
3016
- } catch {
3129
+ } catch (e) {
3130
+ logCatchDebug("migration", e);
3017
3131
  }
3018
3132
  await client.executeMultiple(`
3019
3133
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -3050,63 +3164,72 @@ async function ensureSchema() {
3050
3164
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
3051
3165
  args: []
3052
3166
  });
3053
- } catch {
3167
+ } catch (e) {
3168
+ logCatchDebug("migration", e);
3054
3169
  }
3055
3170
  try {
3056
3171
  await client.execute({
3057
3172
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
3058
3173
  args: []
3059
3174
  });
3060
- } catch {
3175
+ } catch (e) {
3176
+ logCatchDebug("migration", e);
3061
3177
  }
3062
3178
  try {
3063
3179
  await client.execute({
3064
3180
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
3065
3181
  args: []
3066
3182
  });
3067
- } catch {
3183
+ } catch (e) {
3184
+ logCatchDebug("migration", e);
3068
3185
  }
3069
3186
  try {
3070
3187
  await client.execute({
3071
3188
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
3072
3189
  args: []
3073
3190
  });
3074
- } catch {
3191
+ } catch (e) {
3192
+ logCatchDebug("migration", e);
3075
3193
  }
3076
3194
  try {
3077
3195
  await client.execute({
3078
3196
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
3079
3197
  args: []
3080
3198
  });
3081
- } catch {
3199
+ } catch (e) {
3200
+ logCatchDebug("migration", e);
3082
3201
  }
3083
3202
  try {
3084
3203
  await client.execute({
3085
3204
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
3086
3205
  args: []
3087
3206
  });
3088
- } catch {
3207
+ } catch (e) {
3208
+ logCatchDebug("migration", e);
3089
3209
  }
3090
3210
  try {
3091
3211
  await client.execute({
3092
3212
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
3093
3213
  args: []
3094
3214
  });
3095
- } catch {
3215
+ } catch (e) {
3216
+ logCatchDebug("migration", e);
3096
3217
  }
3097
3218
  try {
3098
3219
  await client.execute({
3099
3220
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
3100
3221
  args: []
3101
3222
  });
3102
- } catch {
3223
+ } catch (e) {
3224
+ logCatchDebug("migration", e);
3103
3225
  }
3104
3226
  try {
3105
3227
  await client.execute({
3106
3228
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
3107
3229
  args: []
3108
3230
  });
3109
- } catch {
3231
+ } catch (e) {
3232
+ logCatchDebug("migration", e);
3110
3233
  }
3111
3234
  for (const col of [
3112
3235
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -3114,14 +3237,16 @@ async function ensureSchema() {
3114
3237
  ]) {
3115
3238
  try {
3116
3239
  await client.execute(col);
3117
- } catch {
3240
+ } catch (e) {
3241
+ logCatchDebug("migration", e);
3118
3242
  }
3119
3243
  }
3120
3244
  try {
3121
3245
  await client.execute(
3122
3246
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
3123
3247
  );
3124
- } catch {
3248
+ } catch (e) {
3249
+ logCatchDebug("migration", e);
3125
3250
  }
3126
3251
  try {
3127
3252
  await client.execute(
@@ -3129,7 +3254,8 @@ async function ensureSchema() {
3129
3254
  ON memories(content_hash, agent_id, project_name, memory_type)
3130
3255
  WHERE content_hash IS NOT NULL`
3131
3256
  );
3132
- } catch {
3257
+ } catch (e) {
3258
+ logCatchDebug("migration", e);
3133
3259
  }
3134
3260
  await client.executeMultiple(`
3135
3261
  CREATE TABLE IF NOT EXISTS entities (
@@ -3205,7 +3331,8 @@ async function ensureSchema() {
3205
3331
  `);
3206
3332
  try {
3207
3333
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
3208
- } catch {
3334
+ } catch (e) {
3335
+ logCatchDebug("migration", e);
3209
3336
  }
3210
3337
  await client.executeMultiple(`
3211
3338
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -3220,14 +3347,16 @@ async function ensureSchema() {
3220
3347
  ]) {
3221
3348
  try {
3222
3349
  await client.execute(col);
3223
- } catch {
3350
+ } catch (e) {
3351
+ logCatchDebug("migration", e);
3224
3352
  }
3225
3353
  }
3226
3354
  try {
3227
3355
  await client.execute(
3228
3356
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
3229
3357
  );
3230
- } catch {
3358
+ } catch (e) {
3359
+ logCatchDebug("migration", e);
3231
3360
  }
3232
3361
  await client.executeMultiple(`
3233
3362
  CREATE TABLE IF NOT EXISTS identity (
@@ -3326,7 +3455,8 @@ async function ensureSchema() {
3326
3455
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
3327
3456
  args: []
3328
3457
  });
3329
- } catch {
3458
+ } catch (e) {
3459
+ logCatchDebug("migration", e);
3330
3460
  }
3331
3461
  }
3332
3462
  for (const col of [
@@ -3335,7 +3465,8 @@ async function ensureSchema() {
3335
3465
  ]) {
3336
3466
  try {
3337
3467
  await client.execute(col);
3338
- } catch {
3468
+ } catch (e) {
3469
+ logCatchDebug("migration", e);
3339
3470
  }
3340
3471
  }
3341
3472
  await client.executeMultiple(`
@@ -3520,56 +3651,64 @@ async function ensureSchema() {
3520
3651
  args: []
3521
3652
  });
3522
3653
  }
3523
- } catch {
3654
+ } catch (e) {
3655
+ logCatchDebug("session_agent_map backfill", e);
3524
3656
  }
3525
3657
  try {
3526
3658
  await client.execute({
3527
3659
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
3528
3660
  args: []
3529
3661
  });
3530
- } catch {
3662
+ } catch (e) {
3663
+ logCatchDebug("migration", e);
3531
3664
  }
3532
3665
  try {
3533
3666
  await client.execute({
3534
3667
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
3535
3668
  args: []
3536
3669
  });
3537
- } catch {
3670
+ } catch (e) {
3671
+ logCatchDebug("migration", e);
3538
3672
  }
3539
3673
  try {
3540
3674
  await client.execute({
3541
3675
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
3542
3676
  args: []
3543
3677
  });
3544
- } catch {
3678
+ } catch (e) {
3679
+ logCatchDebug("migration", e);
3545
3680
  }
3546
3681
  try {
3547
3682
  await client.execute({
3548
3683
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
3549
3684
  args: []
3550
3685
  });
3551
- } catch {
3686
+ } catch (e) {
3687
+ logCatchDebug("migration", e);
3552
3688
  }
3553
3689
  try {
3554
3690
  await client.execute({
3555
3691
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
3556
3692
  args: []
3557
3693
  });
3558
- } catch {
3694
+ } catch (e) {
3695
+ logCatchDebug("migration", e);
3559
3696
  }
3560
3697
  try {
3561
3698
  await client.execute({
3562
3699
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
3563
3700
  args: []
3564
3701
  });
3565
- } catch {
3702
+ } catch (e) {
3703
+ logCatchDebug("migration", e);
3566
3704
  }
3567
3705
  try {
3568
3706
  await client.execute({
3569
3707
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
3570
3708
  args: []
3571
3709
  });
3572
- } catch {
3710
+ } catch (e) {
3711
+ logCatchDebug("migration", e);
3573
3712
  }
3574
3713
  await client.executeMultiple(`
3575
3714
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -3768,13 +3907,15 @@ async function ensureSchema() {
3768
3907
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
3769
3908
  args: []
3770
3909
  });
3771
- } catch {
3910
+ } catch (e) {
3911
+ logCatchDebug("migration", e);
3772
3912
  }
3773
3913
  try {
3774
3914
  await client.execute(
3775
3915
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
3776
3916
  );
3777
- } catch {
3917
+ } catch (e) {
3918
+ logCatchDebug("migration", e);
3778
3919
  }
3779
3920
  try {
3780
3921
  await client.execute({
@@ -3785,20 +3926,23 @@ async function ensureSchema() {
3785
3926
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
3786
3927
  args: []
3787
3928
  });
3788
- } catch {
3929
+ } catch (e) {
3930
+ logCatchDebug("migration", e);
3789
3931
  }
3790
3932
  try {
3791
3933
  await client.execute({
3792
3934
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
3793
3935
  args: []
3794
3936
  });
3795
- } catch {
3937
+ } catch (e) {
3938
+ logCatchDebug("migration", e);
3796
3939
  }
3797
3940
  try {
3798
3941
  await client.execute(
3799
3942
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
3800
3943
  );
3801
- } catch {
3944
+ } catch (e) {
3945
+ logCatchDebug("migration", e);
3802
3946
  }
3803
3947
  for (const col of [
3804
3948
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -3806,7 +3950,8 @@ async function ensureSchema() {
3806
3950
  ]) {
3807
3951
  try {
3808
3952
  await client.execute(col);
3809
- } catch {
3953
+ } catch (e) {
3954
+ logCatchDebug("migration", e);
3810
3955
  }
3811
3956
  }
3812
3957
  try {
@@ -3814,13 +3959,15 @@ async function ensureSchema() {
3814
3959
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
3815
3960
  args: []
3816
3961
  });
3817
- } catch {
3962
+ } catch (e) {
3963
+ logCatchDebug("migration", e);
3818
3964
  }
3819
3965
  try {
3820
3966
  await client.execute(
3821
3967
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3822
3968
  );
3823
- } catch {
3969
+ } catch (e) {
3970
+ logCatchDebug("migration", e);
3824
3971
  }
3825
3972
  for (const col of [
3826
3973
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3828,7 +3975,8 @@ async function ensureSchema() {
3828
3975
  ]) {
3829
3976
  try {
3830
3977
  await client.execute(col);
3831
- } catch {
3978
+ } catch (e) {
3979
+ logCatchDebug("migration", e);
3832
3980
  }
3833
3981
  }
3834
3982
  try {
@@ -3836,27 +3984,31 @@ async function ensureSchema() {
3836
3984
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3837
3985
  args: []
3838
3986
  });
3839
- } catch {
3987
+ } catch (e) {
3988
+ logCatchDebug("migration", e);
3840
3989
  }
3841
3990
  try {
3842
3991
  await client.execute({
3843
3992
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3844
3993
  args: []
3845
3994
  });
3846
- } catch {
3995
+ } catch (e) {
3996
+ logCatchDebug("migration", e);
3847
3997
  }
3848
3998
  try {
3849
3999
  await client.execute(
3850
4000
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3851
4001
  );
3852
- } catch {
4002
+ } catch (e) {
4003
+ logCatchDebug("migration", e);
3853
4004
  }
3854
4005
  try {
3855
4006
  await client.execute({
3856
4007
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3857
4008
  args: []
3858
4009
  });
3859
- } catch {
4010
+ } catch (e) {
4011
+ logCatchDebug("migration", e);
3860
4012
  }
3861
4013
  for (const col of [
3862
4014
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3877,7 +4029,8 @@ async function ensureSchema() {
3877
4029
  ]) {
3878
4030
  try {
3879
4031
  await client.execute(col);
3880
- } catch {
4032
+ } catch (e) {
4033
+ logCatchDebug("migration", e);
3881
4034
  }
3882
4035
  }
3883
4036
  try {
@@ -3885,14 +4038,16 @@ async function ensureSchema() {
3885
4038
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3886
4039
  args: []
3887
4040
  });
3888
- } catch {
4041
+ } catch (e) {
4042
+ logCatchDebug("migration", e);
3889
4043
  }
3890
4044
  try {
3891
4045
  await client.execute({
3892
4046
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3893
4047
  args: []
3894
4048
  });
3895
- } catch {
4049
+ } catch (e) {
4050
+ logCatchDebug("migration", e);
3896
4051
  }
3897
4052
  }
3898
4053
  async function disposeDatabase() {
@@ -3903,7 +4058,8 @@ async function disposeDatabase() {
3903
4058
  if (_client) {
3904
4059
  try {
3905
4060
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3906
- } catch {
4061
+ } catch (e) {
4062
+ logCatchDebug("WAL checkpoint", e);
3907
4063
  }
3908
4064
  }
3909
4065
  if (_daemonClient) {
@@ -3919,8 +4075,9 @@ async function disposeDatabase() {
3919
4075
  _client = null;
3920
4076
  _resilientClient = null;
3921
4077
  }
4078
+ releaseDbLock();
3922
4079
  }
3923
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
4080
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3924
4081
  var init_database = __esm({
3925
4082
  "src/lib/database.ts"() {
3926
4083
  "use strict";
@@ -3928,11 +4085,14 @@ var init_database = __esm({
3928
4085
  init_employees();
3929
4086
  init_database_adapter();
3930
4087
  init_memory();
4088
+ _debugDb = process.env.EXE_DEBUG === "1";
3931
4089
  _client = null;
3932
4090
  _resilientClient = null;
3933
4091
  _walCheckpointTimer = null;
3934
4092
  _daemonClient = null;
3935
4093
  _adapterClient = null;
4094
+ _lockFd = null;
4095
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3936
4096
  initTurso = initDatabase;
3937
4097
  SOFT_DELETE_RETENTION_DAYS = 7;
3938
4098
  disposeTurso = disposeDatabase;
@@ -3957,7 +4117,7 @@ __export(license_exports, {
3957
4117
  stopLicenseRevalidation: () => stopLicenseRevalidation,
3958
4118
  validateLicense: () => validateLicense
3959
4119
  });
3960
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
4120
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
3961
4121
  import { randomUUID as randomUUID2 } from "crypto";
3962
4122
  import { createRequire as createRequire2 } from "module";
3963
4123
  import { pathToFileURL as pathToFileURL2 } from "url";
@@ -3975,34 +4135,34 @@ async function fetchRetry(url, init) {
3975
4135
  function loadDeviceId() {
3976
4136
  const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
3977
4137
  try {
3978
- if (existsSync10(deviceJsonPath)) {
4138
+ if (existsSync11(deviceJsonPath)) {
3979
4139
  const data = JSON.parse(readFileSync9(deviceJsonPath, "utf8"));
3980
4140
  if (data.deviceId) return data.deviceId;
3981
4141
  }
3982
4142
  } catch {
3983
4143
  }
3984
4144
  try {
3985
- if (existsSync10(DEVICE_ID_PATH)) {
4145
+ if (existsSync11(DEVICE_ID_PATH)) {
3986
4146
  const id2 = readFileSync9(DEVICE_ID_PATH, "utf8").trim();
3987
4147
  if (id2) return id2;
3988
4148
  }
3989
4149
  } catch {
3990
4150
  }
3991
4151
  const id = randomUUID2();
3992
- mkdirSync4(EXE_AI_DIR, { recursive: true });
4152
+ mkdirSync5(EXE_AI_DIR, { recursive: true });
3993
4153
  writeFileSync6(DEVICE_ID_PATH, id, "utf8");
3994
4154
  return id;
3995
4155
  }
3996
4156
  function loadLicense() {
3997
4157
  try {
3998
- if (!existsSync10(LICENSE_PATH)) return null;
4158
+ if (!existsSync11(LICENSE_PATH)) return null;
3999
4159
  return readFileSync9(LICENSE_PATH, "utf8").trim();
4000
4160
  } catch {
4001
4161
  return null;
4002
4162
  }
4003
4163
  }
4004
4164
  function saveLicense(apiKey) {
4005
- mkdirSync4(EXE_AI_DIR, { recursive: true });
4165
+ mkdirSync5(EXE_AI_DIR, { recursive: true });
4006
4166
  writeFileSync6(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4007
4167
  }
4008
4168
  async function verifyLicenseJwt(token) {
@@ -4029,7 +4189,7 @@ async function verifyLicenseJwt(token) {
4029
4189
  }
4030
4190
  async function getCachedLicense() {
4031
4191
  try {
4032
- if (!existsSync10(CACHE_PATH)) return null;
4192
+ if (!existsSync11(CACHE_PATH)) return null;
4033
4193
  const raw = JSON.parse(readFileSync9(CACHE_PATH, "utf8"));
4034
4194
  if (!raw.token || typeof raw.token !== "string") return null;
4035
4195
  return await verifyLicenseJwt(raw.token);
@@ -4039,7 +4199,7 @@ async function getCachedLicense() {
4039
4199
  }
4040
4200
  function readCachedLicenseToken() {
4041
4201
  try {
4042
- if (!existsSync10(CACHE_PATH)) return null;
4202
+ if (!existsSync11(CACHE_PATH)) return null;
4043
4203
  const raw = JSON.parse(readFileSync9(CACHE_PATH, "utf8"));
4044
4204
  return typeof raw.token === "string" ? raw.token : null;
4045
4205
  } catch {
@@ -4083,7 +4243,7 @@ function loadPrismaForLicense() {
4083
4243
  const dbUrl = process.env.DATABASE_URL;
4084
4244
  if (!dbUrl) {
4085
4245
  const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os7.homedir(), "exe-db");
4086
- if (!existsSync10(path9.join(exeDbRoot, "package.json"))) {
4246
+ if (!existsSync11(path9.join(exeDbRoot, "package.json"))) {
4087
4247
  _prismaFailed = true;
4088
4248
  return null;
4089
4249
  }
@@ -4187,7 +4347,7 @@ async function validateLicense(apiKey, deviceId) {
4187
4347
  const cached = await getCachedLicense();
4188
4348
  if (cached) return cached;
4189
4349
  try {
4190
- if (existsSync10(CACHE_PATH)) {
4350
+ if (existsSync11(CACHE_PATH)) {
4191
4351
  const raw = JSON.parse(readFileSync9(CACHE_PATH, "utf8"));
4192
4352
  if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
4193
4353
  return raw.pgLicense;
@@ -4201,8 +4361,8 @@ async function validateLicense(apiKey, deviceId) {
4201
4361
  }
4202
4362
  function getCacheAgeMs() {
4203
4363
  try {
4204
- const { statSync: statSync4 } = __require("fs");
4205
- const s = statSync4(CACHE_PATH);
4364
+ const { statSync: statSync5 } = __require("fs");
4365
+ const s = statSync5(CACHE_PATH);
4206
4366
  return Date.now() - s.mtimeMs;
4207
4367
  } catch {
4208
4368
  return Infinity;
@@ -4213,7 +4373,7 @@ async function checkLicense() {
4213
4373
  if (!key) {
4214
4374
  try {
4215
4375
  const configPath = path9.join(EXE_AI_DIR, "config.json");
4216
- if (existsSync10(configPath)) {
4376
+ if (existsSync11(configPath)) {
4217
4377
  const raw = JSON.parse(readFileSync9(configPath, "utf8"));
4218
4378
  const cloud = raw.cloud;
4219
4379
  if (cloud?.apiKey) {
@@ -4407,11 +4567,11 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
4407
4567
  });
4408
4568
 
4409
4569
  // src/lib/plan-limits.ts
4410
- import { readFileSync as readFileSync10, existsSync as existsSync11 } from "fs";
4570
+ import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
4411
4571
  import path10 from "path";
4412
4572
  function getLicenseSync() {
4413
4573
  try {
4414
- if (!existsSync11(CACHE_PATH2)) return freeLicense();
4574
+ if (!existsSync12(CACHE_PATH2)) return freeLicense();
4415
4575
  const raw = JSON.parse(readFileSync10(CACHE_PATH2, "utf8"));
4416
4576
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
4417
4577
  const parts = raw.token.split(".");
@@ -4450,7 +4610,7 @@ function assertEmployeeLimitSync(rosterPath) {
4450
4610
  const filePath = rosterPath ?? EMPLOYEES_PATH;
4451
4611
  let count = 0;
4452
4612
  try {
4453
- if (existsSync11(filePath)) {
4613
+ if (existsSync12(filePath)) {
4454
4614
  const raw = readFileSync10(filePath, "utf8");
4455
4615
  const employees = JSON.parse(raw);
4456
4616
  count = Array.isArray(employees) ? employees.length : 0;
@@ -4488,9 +4648,9 @@ var init_plan_limits = __esm({
4488
4648
  import os8 from "os";
4489
4649
  import path11 from "path";
4490
4650
  import {
4491
- existsSync as existsSync12,
4651
+ existsSync as existsSync13,
4492
4652
  lstatSync,
4493
- mkdirSync as mkdirSync5,
4653
+ mkdirSync as mkdirSync6,
4494
4654
  readlinkSync as readlinkSync2,
4495
4655
  symlinkSync as symlinkSync2
4496
4656
  } from "fs";
@@ -4506,8 +4666,8 @@ function claudeAgentLinkPath(homeDir, agentId) {
4506
4666
  function ensureAgentSymlink(agentId, homeDir = os8.homedir()) {
4507
4667
  const target = identitySourcePath(homeDir, agentId);
4508
4668
  const link = claudeAgentLinkPath(homeDir, agentId);
4509
- mkdirSync5(claudeAgentsDir(homeDir), { recursive: true });
4510
- if (existsSync12(link)) {
4669
+ mkdirSync6(claudeAgentsDir(homeDir), { recursive: true });
4670
+ if (existsSync13(link)) {
4511
4671
  let stat;
4512
4672
  try {
4513
4673
  stat = lstatSync(link);
@@ -4555,8 +4715,8 @@ import os9 from "os";
4555
4715
  import {
4556
4716
  readFileSync as readFileSync11,
4557
4717
  readdirSync,
4558
- unlinkSync as unlinkSync3,
4559
- existsSync as existsSync13,
4718
+ unlinkSync as unlinkSync4,
4719
+ existsSync as existsSync14,
4560
4720
  rmdirSync
4561
4721
  } from "fs";
4562
4722
  async function writeNotification(notification) {
@@ -4820,7 +4980,7 @@ import path14 from "path";
4820
4980
  import os10 from "os";
4821
4981
  import { execSync as execSync7 } from "child_process";
4822
4982
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
4823
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
4983
+ import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
4824
4984
  async function writeCheckpoint(input) {
4825
4985
  const client = getClient();
4826
4986
  const row = await resolveTask(client, input.taskId);
@@ -5061,7 +5221,7 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
5061
5221
  const EXE_OS_DIR = path14.join(os10.homedir(), ".exe-os");
5062
5222
  const mdPath = path14.join(EXE_OS_DIR, taskFile);
5063
5223
  const mdDir = path14.dirname(mdPath);
5064
- if (!existsSync14(mdDir)) await mkdir3(mdDir, { recursive: true });
5224
+ if (!existsSync15(mdDir)) await mkdir3(mdDir, { recursive: true });
5065
5225
  const reviewer = input.reviewer ?? input.assignedBy;
5066
5226
  const mdContent = `# ${input.title}
5067
5227
 
@@ -5367,7 +5527,7 @@ async function deleteTaskCore(taskId, _baseDir) {
5367
5527
  async function ensureArchitectureDoc(baseDir, projectName) {
5368
5528
  const archPath = path14.join(baseDir, "exe", "ARCHITECTURE.md");
5369
5529
  try {
5370
- if (existsSync14(archPath)) return;
5530
+ if (existsSync15(archPath)) return;
5371
5531
  const template = [
5372
5532
  `# ${projectName} \u2014 System Architecture`,
5373
5533
  "",
@@ -5402,7 +5562,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
5402
5562
  async function ensureGitignoreExe(baseDir) {
5403
5563
  const gitignorePath = path14.join(baseDir, ".gitignore");
5404
5564
  try {
5405
- if (existsSync14(gitignorePath)) {
5565
+ if (existsSync15(gitignorePath)) {
5406
5566
  const content = readFileSync12(gitignorePath, "utf-8");
5407
5567
  if (/^\/?exe\/?$/m.test(content)) return;
5408
5568
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
@@ -5447,7 +5607,7 @@ __export(tasks_review_exports, {
5447
5607
  listPendingReviews: () => listPendingReviews
5448
5608
  });
5449
5609
  import path15 from "path";
5450
- import { existsSync as existsSync15, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
5610
+ import { existsSync as existsSync16, readdirSync as readdirSync2, unlinkSync as unlinkSync5 } from "fs";
5451
5611
  function formatAge(isoTimestamp) {
5452
5612
  if (!isoTimestamp) return "";
5453
5613
  const ms = Date.now() - new Date(isoTimestamp).getTime();
@@ -5717,10 +5877,10 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
5717
5877
  }
5718
5878
  try {
5719
5879
  const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
5720
- if (existsSync15(cacheDir)) {
5880
+ if (existsSync16(cacheDir)) {
5721
5881
  for (const f of readdirSync2(cacheDir)) {
5722
5882
  if (f.startsWith("review-notified-")) {
5723
- unlinkSync4(path15.join(cacheDir, f));
5883
+ unlinkSync5(path15.join(cacheDir, f));
5724
5884
  }
5725
5885
  }
5726
5886
  }
@@ -5943,10 +6103,10 @@ async function disposeEmbedder() {
5943
6103
  async function embedDirect(text) {
5944
6104
  const llamaCpp = await import("node-llama-cpp");
5945
6105
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5946
- const { existsSync: existsSync19 } = await import("fs");
6106
+ const { existsSync: existsSync20 } = await import("fs");
5947
6107
  const path29 = await import("path");
5948
6108
  const modelPath = path29.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
5949
- if (!existsSync19(modelPath)) {
6109
+ if (!existsSync20(modelPath)) {
5950
6110
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
5951
6111
  }
5952
6112
  const llama = await llamaCpp.getLlama();
@@ -6313,7 +6473,7 @@ __export(tasks_exports, {
6313
6473
  writeCheckpoint: () => writeCheckpoint
6314
6474
  });
6315
6475
  import path17 from "path";
6316
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
6476
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6 } from "fs";
6317
6477
  async function createTask(input) {
6318
6478
  const result = await createTaskCore(input);
6319
6479
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -6335,11 +6495,11 @@ async function updateTask(input) {
6335
6495
  const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
6336
6496
  const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
6337
6497
  if (input.status === "in_progress") {
6338
- mkdirSync6(cacheDir, { recursive: true });
6498
+ mkdirSync7(cacheDir, { recursive: true });
6339
6499
  writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
6340
6500
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
6341
6501
  try {
6342
- unlinkSync5(cachePath);
6502
+ unlinkSync6(cachePath);
6343
6503
  } catch {
6344
6504
  }
6345
6505
  }
@@ -6807,11 +6967,11 @@ __export(tmux_routing_exports, {
6807
6967
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
6808
6968
  });
6809
6969
  import { execFileSync as execFileSync3, execSync as execSync8 } from "child_process";
6810
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync3 } from "fs";
6970
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync17, appendFileSync, readdirSync as readdirSync3 } from "fs";
6811
6971
  import path18 from "path";
6812
6972
  import os11 from "os";
6813
6973
  import { fileURLToPath as fileURLToPath2 } from "url";
6814
- import { unlinkSync as unlinkSync6 } from "fs";
6974
+ import { unlinkSync as unlinkSync7 } from "fs";
6815
6975
  function spawnLockPath(sessionName) {
6816
6976
  return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6817
6977
  }
@@ -6824,11 +6984,11 @@ function isProcessAlive(pid) {
6824
6984
  }
6825
6985
  }
6826
6986
  function acquireSpawnLock2(sessionName) {
6827
- if (!existsSync16(SPAWN_LOCK_DIR)) {
6828
- mkdirSync7(SPAWN_LOCK_DIR, { recursive: true });
6987
+ if (!existsSync17(SPAWN_LOCK_DIR)) {
6988
+ mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
6829
6989
  }
6830
6990
  const lockFile = spawnLockPath(sessionName);
6831
- if (existsSync16(lockFile)) {
6991
+ if (existsSync17(lockFile)) {
6832
6992
  try {
6833
6993
  const lock = JSON.parse(readFileSync13(lockFile, "utf8"));
6834
6994
  const age = Date.now() - lock.timestamp;
@@ -6843,7 +7003,7 @@ function acquireSpawnLock2(sessionName) {
6843
7003
  }
6844
7004
  function releaseSpawnLock2(sessionName) {
6845
7005
  try {
6846
- unlinkSync6(spawnLockPath(sessionName));
7006
+ unlinkSync7(spawnLockPath(sessionName));
6847
7007
  } catch {
6848
7008
  }
6849
7009
  }
@@ -6856,7 +7016,7 @@ function resolveBehaviorsExporterScript() {
6856
7016
  "bin",
6857
7017
  "exe-export-behaviors.js"
6858
7018
  );
6859
- return existsSync16(scriptPath) ? scriptPath : null;
7019
+ return existsSync17(scriptPath) ? scriptPath : null;
6860
7020
  } catch {
6861
7021
  return null;
6862
7022
  }
@@ -6922,8 +7082,8 @@ function extractRootExe(name) {
6922
7082
  return parts.length > 0 ? parts[parts.length - 1] : null;
6923
7083
  }
6924
7084
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6925
- if (!existsSync16(SESSION_CACHE)) {
6926
- mkdirSync7(SESSION_CACHE, { recursive: true });
7085
+ if (!existsSync17(SESSION_CACHE)) {
7086
+ mkdirSync8(SESSION_CACHE, { recursive: true });
6927
7087
  }
6928
7088
  const rootExe = extractRootExe(parentExe) ?? parentExe;
6929
7089
  const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
@@ -6953,11 +7113,13 @@ function getDispatchedBy(sessionKey) {
6953
7113
  }
6954
7114
  }
6955
7115
  function resolveExeSession() {
6956
- if (process.env.EXE_SESSION_NAME) {
6957
- return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
6958
- }
6959
7116
  const mySession = getMySession();
6960
- if (!mySession) return null;
7117
+ if (!mySession) {
7118
+ if (process.env.EXE_SESSION_NAME) {
7119
+ return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
7120
+ }
7121
+ return null;
7122
+ }
6961
7123
  const fromSessionName = extractRootExe(mySession);
6962
7124
  let candidate = null;
6963
7125
  try {
@@ -7052,7 +7214,7 @@ async function verifyPaneAtCapacity(sessionName) {
7052
7214
  }
7053
7215
  function readDebounceState() {
7054
7216
  try {
7055
- if (!existsSync16(DEBOUNCE_FILE)) return {};
7217
+ if (!existsSync17(DEBOUNCE_FILE)) return {};
7056
7218
  const raw = JSON.parse(readFileSync13(DEBOUNCE_FILE, "utf8"));
7057
7219
  const state = {};
7058
7220
  for (const [key, val] of Object.entries(raw)) {
@@ -7069,7 +7231,7 @@ function readDebounceState() {
7069
7231
  }
7070
7232
  function writeDebounceState(state) {
7071
7233
  try {
7072
- if (!existsSync16(SESSION_CACHE)) mkdirSync7(SESSION_CACHE, { recursive: true });
7234
+ if (!existsSync17(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
7073
7235
  writeFileSync8(DEBOUNCE_FILE, JSON.stringify(state));
7074
7236
  } catch {
7075
7237
  }
@@ -7170,7 +7332,7 @@ function sendIntercom(targetSession) {
7170
7332
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7171
7333
  const agent = baseAgentName(rawAgent);
7172
7334
  const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
7173
- if (existsSync16(markerPath)) {
7335
+ if (existsSync17(markerPath)) {
7174
7336
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker + not idle \u2014 will auto-chain)`);
7175
7337
  return "debounced";
7176
7338
  }
@@ -7181,7 +7343,7 @@ function sendIntercom(targetSession) {
7181
7343
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7182
7344
  const agent = baseAgentName(rawAgent);
7183
7345
  const taskDir = path18.join(process.cwd(), "exe", agent);
7184
- if (existsSync16(taskDir)) {
7346
+ if (existsSync17(taskDir)) {
7185
7347
  const files = readdirSync3(taskDir).filter(
7186
7348
  (f) => f.endsWith(".md") && f !== "DONE.txt"
7187
7349
  );
@@ -7342,15 +7504,15 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7342
7504
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
7343
7505
  const logDir = path18.join(os11.homedir(), ".exe-os", "session-logs");
7344
7506
  const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
7345
- if (!existsSync16(logDir)) {
7346
- mkdirSync7(logDir, { recursive: true });
7507
+ if (!existsSync17(logDir)) {
7508
+ mkdirSync8(logDir, { recursive: true });
7347
7509
  }
7348
7510
  transport.kill(sessionName);
7349
7511
  let cleanupSuffix = "";
7350
7512
  try {
7351
7513
  const thisFile = fileURLToPath2(import.meta.url);
7352
7514
  const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
7353
- if (existsSync16(cleanupScript)) {
7515
+ if (existsSync17(cleanupScript)) {
7354
7516
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
7355
7517
  }
7356
7518
  } catch {
@@ -7405,7 +7567,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7405
7567
  if (changed) {
7406
7568
  perms.allow = allow;
7407
7569
  settings.permissions = perms;
7408
- mkdirSync7(projSettingsDir, { recursive: true });
7570
+ mkdirSync8(projSettingsDir, { recursive: true });
7409
7571
  writeFileSync8(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7410
7572
  }
7411
7573
  } catch {
@@ -7443,7 +7605,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7443
7605
  `
7444
7606
  );
7445
7607
  }
7446
- } else if (existsSync16(identityPath)) {
7608
+ } else if (existsSync17(identityPath)) {
7447
7609
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
7448
7610
  legacyFallbackWarned = true;
7449
7611
  }
@@ -7465,7 +7627,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7465
7627
  let sessionContextFlag = "";
7466
7628
  try {
7467
7629
  const ctxDir = path18.join(os11.homedir(), ".exe-os", "session-cache");
7468
- mkdirSync7(ctxDir, { recursive: true });
7630
+ mkdirSync8(ctxDir, { recursive: true });
7469
7631
  const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
7470
7632
  const ctxContent = [
7471
7633
  `## Session Context`,
@@ -9128,6 +9290,18 @@ var init_platform_procedures = __esm({
9128
9290
  priority: "p0",
9129
9291
  content: "create_task is dispatch + delivery. Task lifecycle: open \u2192 in_progress (you start) \u2192 done (update_task when finished) \u2192 needs_review (reviewer nudged) \u2192 closed (COO only via close_task). DB is the reliable delivery \u2014 intercom is just a speedup nudge. If you finish a task, self-chain: check for next task immediately (step 7). Never wait for a nudge. Never say 'standing by.'"
9130
9292
  },
9293
+ {
9294
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
9295
+ domain: "workflow",
9296
+ priority: "p0",
9297
+ content: "When you dispatch work, you OWN the review. Check list_tasks(status='needs_review') on EVERY prompt \u2014 don't wait for intercom nudges (they're unreliable). When a task shows needs_review: (1) read the deliverable (git diff in worktree, exe/output/ files, or task result summary), (2) verify it works (tsc, build, run), (3) close_task if good or create a fix task if not. Reviews sitting >30 minutes is a pipeline stall. The whole chain: worker calls update_task(done) \u2192 system flags needs_review \u2192 manager pulls and verifies \u2192 close_task \u2192 COO reviews manager's work \u2192 merge to main. Every level actively pulls \u2014 nobody waits."
9298
+ },
9299
+ {
9300
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
9301
+ domain: "workflow",
9302
+ priority: "p0",
9303
+ content: "When a bug from support(action='list_bugs') is fixed and verified, the reviewer MUST triage it upstream: support(action='triage_bug', id='<bug-id>', notes='<what was fixed>', fixed_version='<version>', linked_commit='<hash>'). This closes the bug in the customer's view \u2014 their COO checks list_my_bugs and sees status change from open \u2192 closed with the fix version. Without triage, customers see 'open' forever even after the fix ships. Same for feature requests: support(action='triage_feature', ..., shipped_version='<version>'). Triage is part of the review gate \u2014 a fix is not done until the upstream report is closed."
9304
+ },
9131
9305
  {
9132
9306
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
9133
9307
  domain: "architecture",
@@ -10952,7 +11126,7 @@ __export(keychain_exports, {
10952
11126
  setMasterKey: () => setMasterKey
10953
11127
  });
10954
11128
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
10955
- import { existsSync as existsSync17, statSync as statSync2 } from "fs";
11129
+ import { existsSync as existsSync18, statSync as statSync3 } from "fs";
10956
11130
  import { execSync as execSync10 } from "child_process";
10957
11131
  import path27 from "path";
10958
11132
  import os13 from "os";
@@ -10987,7 +11161,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
10987
11161
  if (process.platform !== "linux") return false;
10988
11162
  try {
10989
11163
  const uid = typeof os13.userInfo().uid === "number" ? os13.userInfo().uid : -1;
10990
- const st = statSync2(keyPath);
11164
+ const st = statSync3(keyPath);
10991
11165
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
10992
11166
  if (uid === 0) return true;
10993
11167
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -11188,7 +11362,7 @@ async function getMasterKey() {
11188
11362
  }
11189
11363
  }
11190
11364
  const keyPath = getKeyPath();
11191
- if (!existsSync17(keyPath)) {
11365
+ if (!existsSync18(keyPath)) {
11192
11366
  process.stderr.write(
11193
11367
  `[keychain] Key not found at ${keyPath} (HOME=${os13.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
11194
11368
  `
@@ -11296,7 +11470,7 @@ async function getKeyStorageInfo() {
11296
11470
  }
11297
11471
  }
11298
11472
  const keyPath = getKeyPath();
11299
- if (!existsSync17(keyPath)) {
11473
+ if (!existsSync18(keyPath)) {
11300
11474
  return {
11301
11475
  kind: "missing",
11302
11476
  secure: false,
@@ -11392,7 +11566,7 @@ async function deleteMasterKey() {
11392
11566
  }
11393
11567
  }
11394
11568
  const keyPath = getKeyPath();
11395
- if (existsSync17(keyPath)) {
11569
+ if (existsSync18(keyPath)) {
11396
11570
  await unlink(keyPath);
11397
11571
  }
11398
11572
  }
@@ -12038,18 +12212,54 @@ __export(shard_manager_exports, {
12038
12212
  shardExists: () => shardExists
12039
12213
  });
12040
12214
  import path28 from "path";
12041
- import { existsSync as existsSync18, mkdirSync as mkdirSync8, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync3 } from "fs";
12215
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, readdirSync as readdirSync4, renameSync as renameSync4, statSync as statSync4 } from "fs";
12042
12216
  import { createClient as createClient2 } from "@libsql/client";
12043
12217
  function initShardManager(encryptionKey) {
12044
12218
  _encryptionKey = encryptionKey;
12045
- if (!existsSync18(SHARDS_DIR)) {
12046
- mkdirSync8(SHARDS_DIR, { recursive: true });
12219
+ _keyValidated = false;
12220
+ _keyValidationPromise = null;
12221
+ if (!existsSync19(SHARDS_DIR)) {
12222
+ mkdirSync9(SHARDS_DIR, { recursive: true });
12223
+ }
12224
+ const existingShards = readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db"));
12225
+ if (existingShards.length === 0) {
12226
+ _keyValidated = true;
12047
12227
  }
12048
12228
  _shardingEnabled = true;
12049
12229
  if (_evictionTimer) clearInterval(_evictionTimer);
12050
12230
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
12051
12231
  _evictionTimer.unref();
12052
12232
  }
12233
+ async function validateEncryptionKey() {
12234
+ if (_keyValidated) return true;
12235
+ if (!_encryptionKey) return false;
12236
+ const existingShards = readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db"));
12237
+ if (existingShards.length === 0) {
12238
+ _keyValidated = true;
12239
+ return true;
12240
+ }
12241
+ for (const shardFile of existingShards.slice(0, 3)) {
12242
+ const dbPath = path28.join(SHARDS_DIR, shardFile);
12243
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
12244
+ try {
12245
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
12246
+ testClient.close();
12247
+ _keyValidated = true;
12248
+ return true;
12249
+ } catch {
12250
+ try {
12251
+ testClient.close();
12252
+ } catch {
12253
+ }
12254
+ }
12255
+ }
12256
+ process.stderr.write(
12257
+ `[shard-manager] WARNING: encryption key cannot read any existing shards (${existingShards.length} found). New shard creation disabled to prevent stranded files. Run /exe-doctor to audit.
12258
+ `
12259
+ );
12260
+ _shardingEnabled = false;
12261
+ return false;
12262
+ }
12053
12263
  function isShardingEnabled() {
12054
12264
  return _shardingEnabled;
12055
12265
  }
@@ -12083,13 +12293,13 @@ function getShardClient(projectName) {
12083
12293
  }
12084
12294
  function shardExists(projectName) {
12085
12295
  const safeName = safeShardName(projectName);
12086
- return existsSync18(path28.join(SHARDS_DIR, `${safeName}.db`));
12296
+ return existsSync19(path28.join(SHARDS_DIR, `${safeName}.db`));
12087
12297
  }
12088
12298
  function safeShardName(projectName) {
12089
12299
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
12090
12300
  }
12091
12301
  function listShards() {
12092
- if (!existsSync18(SHARDS_DIR)) return [];
12302
+ if (!existsSync19(SHARDS_DIR)) return [];
12093
12303
  return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
12094
12304
  }
12095
12305
  async function auditShardHealth(options = {}) {
@@ -12102,7 +12312,7 @@ async function auditShardHealth(options = {}) {
12102
12312
  const shards = [];
12103
12313
  for (const name of names) {
12104
12314
  const dbPath = path28.join(SHARDS_DIR, `${name}.db`);
12105
- const stat = statSync3(dbPath);
12315
+ const stat = statSync4(dbPath);
12106
12316
  const item = {
12107
12317
  name,
12108
12318
  path: dbPath,
@@ -12342,6 +12552,17 @@ async function ensureShardSchema(client) {
12342
12552
  }
12343
12553
  }
12344
12554
  async function getReadyShardClient(projectName) {
12555
+ if (!_keyValidated) {
12556
+ if (!_keyValidationPromise) {
12557
+ _keyValidationPromise = validateEncryptionKey();
12558
+ }
12559
+ const valid = await _keyValidationPromise;
12560
+ if (!valid) {
12561
+ throw new Error(
12562
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
12563
+ );
12564
+ }
12565
+ }
12345
12566
  const safeName = safeShardName(projectName);
12346
12567
  let client = getShardClient(projectName);
12347
12568
  try {
@@ -12354,8 +12575,8 @@ async function getReadyShardClient(projectName) {
12354
12575
  _shards.delete(safeName);
12355
12576
  _shardLastAccess.delete(safeName);
12356
12577
  const dbPath = path28.join(SHARDS_DIR, `${safeName}.db`);
12357
- if (existsSync18(dbPath)) {
12358
- const stat = statSync3(dbPath);
12578
+ if (existsSync19(dbPath)) {
12579
+ const stat = statSync4(dbPath);
12359
12580
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
12360
12581
  const archivedPath = path28.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
12361
12582
  renameSync4(dbPath, archivedPath);
@@ -12420,7 +12641,7 @@ function disposeShards() {
12420
12641
  _shardingEnabled = false;
12421
12642
  _encryptionKey = null;
12422
12643
  }
12423
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
12644
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
12424
12645
  var init_shard_manager = __esm({
12425
12646
  "src/lib/shard-manager.ts"() {
12426
12647
  "use strict";
@@ -12434,6 +12655,8 @@ var init_shard_manager = __esm({
12434
12655
  _evictionTimer = null;
12435
12656
  _encryptionKey = null;
12436
12657
  _shardingEnabled = false;
12658
+ _keyValidated = false;
12659
+ _keyValidationPromise = null;
12437
12660
  }
12438
12661
  });
12439
12662
 
@@ -12881,6 +13104,20 @@ __export(store_exports, {
12881
13104
  vectorToBlob: () => vectorToBlob,
12882
13105
  writeMemory: () => writeMemory
12883
13106
  });
13107
+ function logStoreDebug(context, err) {
13108
+ if (_debugStore) {
13109
+ process.stderr.write(
13110
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
13111
+ `
13112
+ );
13113
+ }
13114
+ }
13115
+ function logStoreWarn(context, err) {
13116
+ process.stderr.write(
13117
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
13118
+ `
13119
+ );
13120
+ }
12884
13121
  function isBusyError2(err) {
12885
13122
  if (err instanceof Error) {
12886
13123
  const msg = err.message.toLowerCase();
@@ -12935,13 +13172,15 @@ async function initStore(options) {
12935
13172
  try {
12936
13173
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
12937
13174
  await initDaemonClient2();
12938
- } catch {
13175
+ } catch (e) {
13176
+ logStoreWarn("catch", e);
12939
13177
  }
12940
13178
  if (!options?.lightweight) {
12941
13179
  try {
12942
13180
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
12943
13181
  initShardManager2(hexKey);
12944
- } catch {
13182
+ } catch (e) {
13183
+ logStoreWarn("catch", e);
12945
13184
  }
12946
13185
  const client = getClient();
12947
13186
  const vResult = await retryOnBusy2(
@@ -12952,7 +13191,8 @@ async function initStore(options) {
12952
13191
  try {
12953
13192
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
12954
13193
  await loadGlobalProcedures2();
12955
- } catch {
13194
+ } catch (e) {
13195
+ logStoreWarn("catch", e);
12956
13196
  }
12957
13197
  }
12958
13198
  }
@@ -13012,7 +13252,8 @@ async function writeMemory(record) {
13012
13252
  memoryType
13013
13253
  });
13014
13254
  if (existing) return;
13015
- } catch {
13255
+ } catch (e) {
13256
+ logStoreWarn("catch", e);
13016
13257
  }
13017
13258
  const dbRow = {
13018
13259
  id: record.id,
@@ -13213,12 +13454,14 @@ async function flushBatch() {
13213
13454
  try {
13214
13455
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
13215
13456
  await insertMemoryCardsForBatch2(batch);
13216
- } catch {
13457
+ } catch (e) {
13458
+ logStoreWarn("catch", e);
13217
13459
  }
13218
13460
  try {
13219
13461
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
13220
13462
  await insertOntologyForBatch2(batch);
13221
- } catch {
13463
+ } catch (e) {
13464
+ logStoreWarn("catch", e);
13222
13465
  }
13223
13466
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
13224
13467
  _pendingRecords.splice(0, batch.length);
@@ -13257,7 +13500,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
13257
13500
  }
13258
13501
  }
13259
13502
  }
13260
- } catch {
13503
+ } catch (e) {
13504
+ logStoreWarn("catch", e);
13261
13505
  }
13262
13506
  return batch.length;
13263
13507
  } finally {
@@ -13299,7 +13543,8 @@ async function searchMemories(queryVector, agentId, options) {
13299
13543
  } else {
13300
13544
  client = getClient();
13301
13545
  }
13302
- } catch {
13546
+ } catch (e) {
13547
+ logStoreDebug("shard routing fallback", e);
13303
13548
  client = getClient();
13304
13549
  }
13305
13550
  const limit = options?.limit ?? 10;
@@ -13415,7 +13660,8 @@ async function attachDocumentMetadata(records) {
13415
13660
  if (!record.document_id) continue;
13416
13661
  record.document_metadata = byId.get(record.document_id) ?? null;
13417
13662
  }
13418
- } catch {
13663
+ } catch (e) {
13664
+ logStoreWarn("catch", e);
13419
13665
  }
13420
13666
  return records;
13421
13667
  }
@@ -13476,11 +13722,12 @@ async function getMemoryCardinality(agentId) {
13476
13722
  args: [agentId]
13477
13723
  });
13478
13724
  return Number(result.rows[0]?.cnt) || 0;
13479
- } catch {
13725
+ } catch (e) {
13726
+ logStoreWarn("getMemoryCardinality", e);
13480
13727
  return 0;
13481
13728
  }
13482
13729
  }
13483
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
13730
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
13484
13731
  var init_store = __esm({
13485
13732
  "src/lib/store.ts"() {
13486
13733
  "use strict";
@@ -13490,6 +13737,7 @@ var init_store = __esm({
13490
13737
  init_config();
13491
13738
  init_state_bus();
13492
13739
  init_memory_write_governor();
13740
+ _debugStore = process.env.EXE_DEBUG === "1";
13493
13741
  INIT_MAX_RETRIES = 3;
13494
13742
  INIT_RETRY_DELAY_MS = 1e3;
13495
13743
  _pendingRecords = [];
@@ -19429,11 +19677,11 @@ function Footer() {
19429
19677
  } catch {
19430
19678
  }
19431
19679
  try {
19432
- const { existsSync: existsSync19 } = await import("fs");
19433
- const { join } = await import("path");
19680
+ const { existsSync: existsSync20 } = await import("fs");
19681
+ const { join: join2 } = await import("path");
19434
19682
  const home = process.env.HOME ?? "";
19435
- const pidPath = join(home, ".exe-os", "exed.pid");
19436
- setDaemon(existsSync19(pidPath) ? "running" : "stopped");
19683
+ const pidPath = join2(home, ".exe-os", "exed.pid");
19684
+ setDaemon(existsSync20(pidPath) ? "running" : "stopped");
19437
19685
  } catch {
19438
19686
  setDaemon("unknown");
19439
19687
  }
@@ -19516,7 +19764,7 @@ function Footer() {
19516
19764
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
19517
19765
  import TextInput from "ink-text-input";
19518
19766
  import path25 from "path";
19519
- import { homedir } from "os";
19767
+ import { homedir as homedir2 } from "os";
19520
19768
 
19521
19769
  // src/tui/components/StatusDot.tsx
19522
19770
  import React16 from "react";
@@ -20303,13 +20551,13 @@ function CommandCenterView({
20303
20551
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
20304
20552
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
20305
20553
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
20306
- const { readFileSync: readFileSync14, existsSync: existsSync19 } = await import("fs");
20307
- const { join } = await import("path");
20308
- const { homedir: homedir3 } = await import("os");
20309
- const configPath = join(homedir3(), ".exe-os", "config.json");
20554
+ const { readFileSync: readFileSync14, existsSync: existsSync20 } = await import("fs");
20555
+ const { join: join2 } = await import("path");
20556
+ const { homedir: homedir4 } = await import("os");
20557
+ const configPath = join2(homedir4(), ".exe-os", "config.json");
20310
20558
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
20311
20559
  let providerConfigs = {};
20312
- if (existsSync19(configPath)) {
20560
+ if (existsSync20(configPath)) {
20313
20561
  try {
20314
20562
  const raw = JSON.parse(readFileSync14(configPath, "utf8"));
20315
20563
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
@@ -20369,10 +20617,10 @@ function CommandCenterView({
20369
20617
  registry.register(BashTool2);
20370
20618
  let agentRole = "CTO";
20371
20619
  try {
20372
- const markerDir = join(homedir3(), ".exe-os", "session-cache");
20620
+ const markerDir = join2(homedir4(), ".exe-os", "session-cache");
20373
20621
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
20374
20622
  for (const f of agentFiles) {
20375
- const data = JSON.parse(readFileSync14(join(markerDir, f), "utf8"));
20623
+ const data = JSON.parse(readFileSync14(join2(markerDir, f), "utf8"));
20376
20624
  if (data.agentRole) {
20377
20625
  agentRole = data.agentRole;
20378
20626
  break;
@@ -20517,7 +20765,7 @@ function CommandCenterView({
20517
20765
  const demoEntries = DEMO_PROJECTS.map((p) => ({
20518
20766
  projectName: p.projectName,
20519
20767
  exeSession: p.exeSession,
20520
- projectDir: path25.join(homedir(), p.projectName),
20768
+ projectDir: path25.join(homedir2(), p.projectName),
20521
20769
  employeeCount: p.employees.length,
20522
20770
  activeCount: p.employees.filter((e) => e.status === "active").length,
20523
20771
  memoryCount: p.employees.length * 4e3,
@@ -20555,8 +20803,8 @@ function CommandCenterView({
20555
20803
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
20556
20804
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
20557
20805
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
20558
- const { existsSync: existsSync19 } = await import("fs");
20559
- const { join } = await import("path");
20806
+ const { existsSync: existsSync20 } = await import("fs");
20807
+ const { join: join2 } = await import("path");
20560
20808
  const client = getClient2();
20561
20809
  if (!client) {
20562
20810
  setDbError(true);
@@ -20626,7 +20874,7 @@ function CommandCenterView({
20626
20874
  }
20627
20875
  const memoryCount = memoryCounts.get(name) ?? 0;
20628
20876
  const openTaskCount = openTaskCounts.get(name) ?? 0;
20629
- const hasGit = projectDir ? existsSync19(join(projectDir, ".git")) : false;
20877
+ const hasGit = projectDir ? existsSync20(join2(projectDir, ".git")) : false;
20630
20878
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
20631
20879
  projectList.push({
20632
20880
  projectName: name,
@@ -20650,8 +20898,8 @@ function CommandCenterView({
20650
20898
  const totalResult = await client.execute("SELECT COUNT(*) as cnt FROM memories");
20651
20899
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
20652
20900
  try {
20653
- const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
20654
- setHealth((h) => ({ ...h, daemon: existsSync19(pidPath) ? "running" : "stopped" }));
20901
+ const pidPath = join2(process.env.HOME ?? "", ".exe-os", "exed.pid");
20902
+ setHealth((h) => ({ ...h, daemon: existsSync20(pidPath) ? "running" : "stopped" }));
20655
20903
  } catch {
20656
20904
  }
20657
20905
  const activityResult = await client.execute(
@@ -20867,7 +21115,7 @@ function ChatMessageRow({ msg }) {
20867
21115
  // src/tui/views/Sessions.tsx
20868
21116
  import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
20869
21117
  import path26 from "path";
20870
- import { homedir as homedir2 } from "os";
21118
+ import { homedir as homedir3 } from "os";
20871
21119
 
20872
21120
  // src/tui/components/TmuxPane.tsx
20873
21121
  import React18, { useState as useState7, useEffect as useEffect9 } from "react";
@@ -21170,7 +21418,7 @@ function SessionsView({
21170
21418
  if (demo) {
21171
21419
  setProjects(DEMO_PROJECTS.map((p) => ({
21172
21420
  ...p,
21173
- projectDir: path26.join(homedir2(), p.projectName),
21421
+ projectDir: path26.join(homedir3(), p.projectName),
21174
21422
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
21175
21423
  })));
21176
21424
  return;
@@ -22051,11 +22299,11 @@ async function loadGatewayConfig() {
22051
22299
  state.running = false;
22052
22300
  }
22053
22301
  try {
22054
- const { existsSync: existsSync19, readFileSync: readFileSync14 } = await import("fs");
22055
- const { join } = await import("path");
22302
+ const { existsSync: existsSync20, readFileSync: readFileSync14 } = await import("fs");
22303
+ const { join: join2 } = await import("path");
22056
22304
  const home = process.env.HOME ?? "";
22057
- const configPath = join(home, ".exe-os", "gateway.json");
22058
- if (existsSync19(configPath)) {
22305
+ const configPath = join2(home, ".exe-os", "gateway.json");
22306
+ if (existsSync20(configPath)) {
22059
22307
  const raw = JSON.parse(readFileSync14(configPath, "utf8"));
22060
22308
  state.port = raw.port ?? 3100;
22061
22309
  state.gatewayUrl = raw.gatewayUrl ?? "";
@@ -22556,11 +22804,11 @@ function TeamView({ onBack, onViewSessions }) {
22556
22804
  setMembers(teamData);
22557
22805
  setDbError(null);
22558
22806
  try {
22559
- const { existsSync: existsSync19, readFileSync: readFileSync14 } = await import("fs");
22560
- const { join } = await import("path");
22807
+ const { existsSync: existsSync20, readFileSync: readFileSync14 } = await import("fs");
22808
+ const { join: join2 } = await import("path");
22561
22809
  const home = process.env.HOME ?? "";
22562
- const gatewayConfig = join(home, ".exe-os", "gateway.json");
22563
- if (existsSync19(gatewayConfig)) {
22810
+ const gatewayConfig = join2(home, ".exe-os", "gateway.json");
22811
+ if (existsSync20(gatewayConfig)) {
22564
22812
  const raw = JSON.parse(readFileSync14(gatewayConfig, "utf8"));
22565
22813
  if (raw.agents && raw.agents.length > 0) {
22566
22814
  setExternals(raw.agents.map((a) => ({
@@ -23209,12 +23457,12 @@ function SettingsView({ onBack }) {
23209
23457
  }
23210
23458
  setProviders(providerList);
23211
23459
  try {
23212
- const { existsSync: existsSync19 } = await import("fs");
23213
- const { join } = await import("path");
23460
+ const { existsSync: existsSync20 } = await import("fs");
23461
+ const { join: join2 } = await import("path");
23214
23462
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
23215
23463
  const cfg = await loadConfig2();
23216
23464
  const home = process.env.HOME ?? "";
23217
- const hasKey = existsSync19(join(home, ".exe-os", "master.key"));
23465
+ const hasKey = existsSync20(join2(home, ".exe-os", "master.key"));
23218
23466
  if (cfg.cloud) {
23219
23467
  setCloud({
23220
23468
  configured: true,
@@ -23224,10 +23472,10 @@ function SettingsView({ onBack }) {
23224
23472
  } else {
23225
23473
  setCloud({ configured: false, endpoint: "", apiKey: "" });
23226
23474
  }
23227
- const pidPath = join(home, ".exe-os", "exed.pid");
23475
+ const pidPath = join2(home, ".exe-os", "exed.pid");
23228
23476
  let daemon = "unknown";
23229
23477
  try {
23230
- daemon = existsSync19(pidPath) ? "running" : "stopped";
23478
+ daemon = existsSync20(pidPath) ? "running" : "stopped";
23231
23479
  } catch {
23232
23480
  }
23233
23481
  let version = "unknown";