@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
@@ -2083,9 +2083,79 @@ __export(database_exports, {
2083
2083
  isInitialized: () => isInitialized,
2084
2084
  setExternalClient: () => setExternalClient
2085
2085
  });
2086
- import { chmodSync as chmodSync2 } from "fs";
2086
+ import { chmodSync as chmodSync2, existsSync as existsSync7, statSync as statSync2, copyFileSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync2 } from "fs";
2087
2087
  import { createClient } from "@libsql/client";
2088
+ import { homedir } from "os";
2089
+ import { join } from "path";
2090
+ function logCatchDebug(context, err) {
2091
+ if (_debugDb) {
2092
+ process.stderr.write(
2093
+ `[database] ${context}: ${err instanceof Error ? err.message : String(err)}
2094
+ `
2095
+ );
2096
+ }
2097
+ }
2098
+ function acquireDbLock() {
2099
+ mkdirSync2(join(homedir(), ".exe-os"), { recursive: true });
2100
+ try {
2101
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
2102
+ } catch (err) {
2103
+ if (err && typeof err === "object" && "code" in err && err.code === "EEXIST") {
2104
+ try {
2105
+ const lockStat = statSync2(DB_LOCK_PATH);
2106
+ if (Date.now() - lockStat.mtimeMs > 6e4) {
2107
+ unlinkSync3(DB_LOCK_PATH);
2108
+ _lockFd = openSync2(DB_LOCK_PATH, "wx");
2109
+ return;
2110
+ }
2111
+ } catch (e) {
2112
+ logCatchDebug("stale lock check", e);
2113
+ }
2114
+ process.stderr.write(
2115
+ "[database] WARN: Another process holds db.lock \u2014 waiting briefly then proceeding.\n"
2116
+ );
2117
+ return;
2118
+ }
2119
+ throw err;
2120
+ }
2121
+ }
2122
+ function releaseDbLock() {
2123
+ if (_lockFd !== null) {
2124
+ try {
2125
+ closeSync2(_lockFd);
2126
+ } catch (e) {
2127
+ logCatchDebug("lock close", e);
2128
+ }
2129
+ _lockFd = null;
2130
+ }
2131
+ try {
2132
+ unlinkSync3(DB_LOCK_PATH);
2133
+ } catch (e) {
2134
+ logCatchDebug("lock unlink", e);
2135
+ }
2136
+ }
2088
2137
  async function initDatabase(config) {
2138
+ acquireDbLock();
2139
+ if (existsSync7(config.dbPath)) {
2140
+ const dbStat = statSync2(config.dbPath);
2141
+ if (dbStat.size === 0) {
2142
+ const walPath = config.dbPath + "-wal";
2143
+ if (existsSync7(walPath) && statSync2(walPath).size > 0) {
2144
+ const backupPath = config.dbPath + ".zeroed-" + Date.now();
2145
+ copyFileSync(config.dbPath, backupPath);
2146
+ unlinkSync3(config.dbPath);
2147
+ process.stderr.write(
2148
+ `[database] CRITICAL: DB was 0 bytes. Moved to ${backupPath}, attempting WAL recovery.
2149
+ `
2150
+ );
2151
+ } else {
2152
+ process.stderr.write(
2153
+ `[database] CRITICAL: DB is 0 bytes and no WAL available for recovery. Data may be lost. Check backups at ${config.dbPath}.bak
2154
+ `
2155
+ );
2156
+ }
2157
+ }
2158
+ }
2089
2159
  if (_walCheckpointTimer) {
2090
2160
  clearInterval(_walCheckpointTimer);
2091
2161
  _walCheckpointTimer = null;
@@ -2112,10 +2182,8 @@ async function initDatabase(config) {
2112
2182
  _client = createClient(opts);
2113
2183
  _resilientClient = wrapWithRetry(_client);
2114
2184
  _adapterClient = _resilientClient;
2115
- _client.execute("PRAGMA busy_timeout = 30000").catch(() => {
2116
- });
2117
- _client.execute("PRAGMA journal_mode = WAL").catch(() => {
2118
- });
2185
+ await _client.execute("PRAGMA busy_timeout = 30000");
2186
+ await _client.execute("PRAGMA journal_mode = WAL");
2119
2187
  if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
2120
2188
  _walCheckpointTimer = setInterval(() => {
2121
2189
  _client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
@@ -2130,11 +2198,16 @@ async function initDatabase(config) {
2130
2198
  for (const suffix of ["-wal", "-shm"]) {
2131
2199
  try {
2132
2200
  chmodSync2(config.dbPath + suffix, 384);
2133
- } catch {
2201
+ } catch (chmodErr) {
2202
+ process.stderr.write(`[database] chmod ${suffix} failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
2203
+ `);
2134
2204
  }
2135
2205
  }
2136
- } catch {
2206
+ } catch (chmodErr) {
2207
+ process.stderr.write(`[database] chmod db failed: ${chmodErr instanceof Error ? chmodErr.message : String(chmodErr)}
2208
+ `);
2137
2209
  }
2210
+ releaseDbLock();
2138
2211
  }
2139
2212
  function isInitialized() {
2140
2213
  return _adapterClient !== null || _client !== null;
@@ -2189,7 +2262,8 @@ async function ensureSchema() {
2189
2262
  await client.execute("PRAGMA wal_autocheckpoint = 1000");
2190
2263
  try {
2191
2264
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
2192
- } catch {
2265
+ } catch (e) {
2266
+ logCatchDebug("migration", e);
2193
2267
  }
2194
2268
  await client.executeMultiple(`
2195
2269
  CREATE TABLE IF NOT EXISTS memories (
@@ -2254,6 +2328,23 @@ async function ensureSchema() {
2254
2328
  INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
2255
2329
  END;
2256
2330
  `);
2331
+ try {
2332
+ await client.execute("SELECT COUNT(*) FROM memories_fts LIMIT 1");
2333
+ } catch (ftsErr) {
2334
+ process.stderr.write(
2335
+ `[database] WARN: memories_fts corrupted (${ftsErr instanceof Error ? ftsErr.message : String(ftsErr)}) \u2014 rebuilding FTS index.
2336
+ `
2337
+ );
2338
+ try {
2339
+ await client.execute("INSERT INTO memories_fts(memories_fts) VALUES('rebuild')");
2340
+ process.stderr.write("[database] FTS index rebuilt successfully.\n");
2341
+ } catch (rebuildErr) {
2342
+ process.stderr.write(
2343
+ `[database] ERROR: FTS rebuild failed: ${rebuildErr instanceof Error ? rebuildErr.message : String(rebuildErr)}
2344
+ `
2345
+ );
2346
+ }
2347
+ }
2257
2348
  await client.executeMultiple(`
2258
2349
  CREATE TABLE IF NOT EXISTS sync_meta (
2259
2350
  key TEXT PRIMARY KEY,
@@ -2312,35 +2403,40 @@ async function ensureSchema() {
2312
2403
  });
2313
2404
  }
2314
2405
  }
2315
- } catch {
2406
+ } catch (seedErr) {
2407
+ logCatchDebug("behavior seed", seedErr);
2316
2408
  }
2317
2409
  try {
2318
2410
  await client.execute({
2319
2411
  sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
2320
2412
  args: []
2321
2413
  });
2322
- } catch {
2414
+ } catch (e) {
2415
+ logCatchDebug("migration", e);
2323
2416
  }
2324
2417
  try {
2325
2418
  await client.execute({
2326
2419
  sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
2327
2420
  args: []
2328
2421
  });
2329
- } catch {
2422
+ } catch (e) {
2423
+ logCatchDebug("migration", e);
2330
2424
  }
2331
2425
  try {
2332
2426
  await client.execute({
2333
2427
  sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
2334
2428
  args: []
2335
2429
  });
2336
- } catch {
2430
+ } catch (e) {
2431
+ logCatchDebug("migration", e);
2337
2432
  }
2338
2433
  try {
2339
2434
  await client.execute({
2340
2435
  sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
2341
2436
  args: []
2342
2437
  });
2343
- } catch {
2438
+ } catch (e) {
2439
+ logCatchDebug("migration", e);
2344
2440
  }
2345
2441
  try {
2346
2442
  await client.execute({
@@ -2349,98 +2445,112 @@ async function ensureSchema() {
2349
2445
  WHERE parent_task_id IS NOT NULL`,
2350
2446
  args: []
2351
2447
  });
2352
- } catch {
2448
+ } catch (e) {
2449
+ logCatchDebug("migration", e);
2353
2450
  }
2354
2451
  try {
2355
2452
  await client.execute({
2356
2453
  sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
2357
2454
  args: []
2358
2455
  });
2359
- } catch {
2456
+ } catch (e) {
2457
+ logCatchDebug("migration", e);
2360
2458
  }
2361
2459
  try {
2362
2460
  await client.execute({
2363
2461
  sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
2364
2462
  args: []
2365
2463
  });
2366
- } catch {
2464
+ } catch (e) {
2465
+ logCatchDebug("migration", e);
2367
2466
  }
2368
2467
  try {
2369
2468
  await client.execute({
2370
2469
  sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
2371
2470
  args: []
2372
2471
  });
2373
- } catch {
2472
+ } catch (e) {
2473
+ logCatchDebug("migration", e);
2374
2474
  }
2375
2475
  try {
2376
2476
  await client.execute({
2377
2477
  sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
2378
2478
  args: []
2379
2479
  });
2380
- } catch {
2480
+ } catch (e) {
2481
+ logCatchDebug("migration", e);
2381
2482
  }
2382
2483
  try {
2383
2484
  await client.execute({
2384
2485
  sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
2385
2486
  args: []
2386
2487
  });
2387
- } catch {
2488
+ } catch (e) {
2489
+ logCatchDebug("migration", e);
2388
2490
  }
2389
2491
  try {
2390
2492
  await client.execute({
2391
2493
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
2392
2494
  args: []
2393
2495
  });
2394
- } catch {
2496
+ } catch (e) {
2497
+ logCatchDebug("migration", e);
2395
2498
  }
2396
2499
  try {
2397
2500
  await client.execute({
2398
2501
  sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
2399
2502
  args: []
2400
2503
  });
2401
- } catch {
2504
+ } catch (e) {
2505
+ logCatchDebug("migration", e);
2402
2506
  }
2403
2507
  try {
2404
2508
  await client.execute({
2405
2509
  sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
2406
2510
  args: []
2407
2511
  });
2408
- } catch {
2512
+ } catch (e) {
2513
+ logCatchDebug("migration", e);
2409
2514
  }
2410
2515
  try {
2411
2516
  await client.execute({
2412
2517
  sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
2413
2518
  args: []
2414
2519
  });
2415
- } catch {
2520
+ } catch (e) {
2521
+ logCatchDebug("migration", e);
2416
2522
  }
2417
2523
  try {
2418
2524
  await client.execute({
2419
2525
  sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
2420
2526
  args: []
2421
2527
  });
2422
- } catch {
2528
+ } catch (e) {
2529
+ logCatchDebug("migration", e);
2423
2530
  }
2424
2531
  try {
2425
2532
  await client.execute({
2426
2533
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2427
2534
  args: []
2428
2535
  });
2429
- } catch {
2536
+ } catch (e) {
2537
+ logCatchDebug("migration", e);
2430
2538
  }
2431
2539
  try {
2432
2540
  await client.execute({
2433
2541
  sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
2434
2542
  args: []
2435
2543
  });
2436
- } catch {
2544
+ } catch (e) {
2545
+ logCatchDebug("migration", e);
2437
2546
  }
2438
2547
  try {
2439
2548
  await client.execute({
2440
2549
  sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
2441
2550
  args: []
2442
2551
  });
2443
- } catch {
2552
+ } catch (e) {
2553
+ logCatchDebug("migration", e);
2444
2554
  }
2445
2555
  await client.executeMultiple(`
2446
2556
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2545,14 +2655,16 @@ async function ensureSchema() {
2545
2655
  sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2546
2656
  args: []
2547
2657
  });
2548
- } catch {
2658
+ } catch (e) {
2659
+ logCatchDebug("migration", e);
2549
2660
  }
2550
2661
  try {
2551
2662
  await client.execute({
2552
2663
  sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2553
2664
  args: []
2554
2665
  });
2555
- } catch {
2666
+ } catch (e) {
2667
+ logCatchDebug("migration", e);
2556
2668
  }
2557
2669
  await client.executeMultiple(`
2558
2670
  CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
@@ -2578,7 +2690,8 @@ async function ensureSchema() {
2578
2690
  sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
2579
2691
  args: []
2580
2692
  });
2581
- } catch {
2693
+ } catch (e) {
2694
+ logCatchDebug("migration", e);
2582
2695
  }
2583
2696
  await client.executeMultiple(`
2584
2697
  CREATE TABLE IF NOT EXISTS trajectories (
@@ -2602,7 +2715,8 @@ async function ensureSchema() {
2602
2715
  `);
2603
2716
  try {
2604
2717
  await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
2605
- } catch {
2718
+ } catch (e) {
2719
+ logCatchDebug("migration", e);
2606
2720
  }
2607
2721
  await client.executeMultiple(`
2608
2722
  CREATE TABLE IF NOT EXISTS consolidations (
@@ -2639,63 +2753,72 @@ async function ensureSchema() {
2639
2753
  sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
2640
2754
  args: []
2641
2755
  });
2642
- } catch {
2756
+ } catch (e) {
2757
+ logCatchDebug("migration", e);
2643
2758
  }
2644
2759
  try {
2645
2760
  await client.execute({
2646
2761
  sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
2647
2762
  args: []
2648
2763
  });
2649
- } catch {
2764
+ } catch (e) {
2765
+ logCatchDebug("migration", e);
2650
2766
  }
2651
2767
  try {
2652
2768
  await client.execute({
2653
2769
  sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
2654
2770
  args: []
2655
2771
  });
2656
- } catch {
2772
+ } catch (e) {
2773
+ logCatchDebug("migration", e);
2657
2774
  }
2658
2775
  try {
2659
2776
  await client.execute({
2660
2777
  sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
2661
2778
  args: []
2662
2779
  });
2663
- } catch {
2780
+ } catch (e) {
2781
+ logCatchDebug("migration", e);
2664
2782
  }
2665
2783
  try {
2666
2784
  await client.execute({
2667
2785
  sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
2668
2786
  args: []
2669
2787
  });
2670
- } catch {
2788
+ } catch (e) {
2789
+ logCatchDebug("migration", e);
2671
2790
  }
2672
2791
  try {
2673
2792
  await client.execute({
2674
2793
  sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
2675
2794
  args: []
2676
2795
  });
2677
- } catch {
2796
+ } catch (e) {
2797
+ logCatchDebug("migration", e);
2678
2798
  }
2679
2799
  try {
2680
2800
  await client.execute({
2681
2801
  sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
2682
2802
  args: []
2683
2803
  });
2684
- } catch {
2804
+ } catch (e) {
2805
+ logCatchDebug("migration", e);
2685
2806
  }
2686
2807
  try {
2687
2808
  await client.execute({
2688
2809
  sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
2689
2810
  args: []
2690
2811
  });
2691
- } catch {
2812
+ } catch (e) {
2813
+ logCatchDebug("migration", e);
2692
2814
  }
2693
2815
  try {
2694
2816
  await client.execute({
2695
2817
  sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
2696
2818
  args: []
2697
2819
  });
2698
- } catch {
2820
+ } catch (e) {
2821
+ logCatchDebug("migration", e);
2699
2822
  }
2700
2823
  for (const col of [
2701
2824
  "ALTER TABLE memories ADD COLUMN content_hash TEXT",
@@ -2703,14 +2826,16 @@ async function ensureSchema() {
2703
2826
  ]) {
2704
2827
  try {
2705
2828
  await client.execute(col);
2706
- } catch {
2829
+ } catch (e) {
2830
+ logCatchDebug("migration", e);
2707
2831
  }
2708
2832
  }
2709
2833
  try {
2710
2834
  await client.execute(
2711
2835
  `CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
2712
2836
  );
2713
- } catch {
2837
+ } catch (e) {
2838
+ logCatchDebug("migration", e);
2714
2839
  }
2715
2840
  try {
2716
2841
  await client.execute(
@@ -2718,7 +2843,8 @@ async function ensureSchema() {
2718
2843
  ON memories(content_hash, agent_id, project_name, memory_type)
2719
2844
  WHERE content_hash IS NOT NULL`
2720
2845
  );
2721
- } catch {
2846
+ } catch (e) {
2847
+ logCatchDebug("migration", e);
2722
2848
  }
2723
2849
  await client.executeMultiple(`
2724
2850
  CREATE TABLE IF NOT EXISTS entities (
@@ -2794,7 +2920,8 @@ async function ensureSchema() {
2794
2920
  `);
2795
2921
  try {
2796
2922
  await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
2797
- } catch {
2923
+ } catch (e) {
2924
+ logCatchDebug("migration", e);
2798
2925
  }
2799
2926
  await client.executeMultiple(`
2800
2927
  CREATE TABLE IF NOT EXISTS entity_aliases (
@@ -2809,14 +2936,16 @@ async function ensureSchema() {
2809
2936
  ]) {
2810
2937
  try {
2811
2938
  await client.execute(col);
2812
- } catch {
2939
+ } catch (e) {
2940
+ logCatchDebug("migration", e);
2813
2941
  }
2814
2942
  }
2815
2943
  try {
2816
2944
  await client.execute(
2817
2945
  `CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
2818
2946
  );
2819
- } catch {
2947
+ } catch (e) {
2948
+ logCatchDebug("migration", e);
2820
2949
  }
2821
2950
  await client.executeMultiple(`
2822
2951
  CREATE TABLE IF NOT EXISTS identity (
@@ -2915,7 +3044,8 @@ async function ensureSchema() {
2915
3044
  sql: `ALTER TABLE memories ADD COLUMN ${column}`,
2916
3045
  args: []
2917
3046
  });
2918
- } catch {
3047
+ } catch (e) {
3048
+ logCatchDebug("migration", e);
2919
3049
  }
2920
3050
  }
2921
3051
  for (const col of [
@@ -2924,7 +3054,8 @@ async function ensureSchema() {
2924
3054
  ]) {
2925
3055
  try {
2926
3056
  await client.execute(col);
2927
- } catch {
3057
+ } catch (e) {
3058
+ logCatchDebug("migration", e);
2928
3059
  }
2929
3060
  }
2930
3061
  await client.executeMultiple(`
@@ -3109,56 +3240,64 @@ async function ensureSchema() {
3109
3240
  args: []
3110
3241
  });
3111
3242
  }
3112
- } catch {
3243
+ } catch (e) {
3244
+ logCatchDebug("session_agent_map backfill", e);
3113
3245
  }
3114
3246
  try {
3115
3247
  await client.execute({
3116
3248
  sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
3117
3249
  args: []
3118
3250
  });
3119
- } catch {
3251
+ } catch (e) {
3252
+ logCatchDebug("migration", e);
3120
3253
  }
3121
3254
  try {
3122
3255
  await client.execute({
3123
3256
  sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
3124
3257
  args: []
3125
3258
  });
3126
- } catch {
3259
+ } catch (e) {
3260
+ logCatchDebug("migration", e);
3127
3261
  }
3128
3262
  try {
3129
3263
  await client.execute({
3130
3264
  sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
3131
3265
  args: []
3132
3266
  });
3133
- } catch {
3267
+ } catch (e) {
3268
+ logCatchDebug("migration", e);
3134
3269
  }
3135
3270
  try {
3136
3271
  await client.execute({
3137
3272
  sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
3138
3273
  args: []
3139
3274
  });
3140
- } catch {
3275
+ } catch (e) {
3276
+ logCatchDebug("migration", e);
3141
3277
  }
3142
3278
  try {
3143
3279
  await client.execute({
3144
3280
  sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
3145
3281
  args: []
3146
3282
  });
3147
- } catch {
3283
+ } catch (e) {
3284
+ logCatchDebug("migration", e);
3148
3285
  }
3149
3286
  try {
3150
3287
  await client.execute({
3151
3288
  sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
3152
3289
  args: []
3153
3290
  });
3154
- } catch {
3291
+ } catch (e) {
3292
+ logCatchDebug("migration", e);
3155
3293
  }
3156
3294
  try {
3157
3295
  await client.execute({
3158
3296
  sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
3159
3297
  args: []
3160
3298
  });
3161
- } catch {
3299
+ } catch (e) {
3300
+ logCatchDebug("migration", e);
3162
3301
  }
3163
3302
  await client.executeMultiple(`
3164
3303
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
@@ -3357,13 +3496,15 @@ async function ensureSchema() {
3357
3496
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
3358
3497
  args: []
3359
3498
  });
3360
- } catch {
3499
+ } catch (e) {
3500
+ logCatchDebug("migration", e);
3361
3501
  }
3362
3502
  try {
3363
3503
  await client.execute(
3364
3504
  `CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
3365
3505
  );
3366
- } catch {
3506
+ } catch (e) {
3507
+ logCatchDebug("migration", e);
3367
3508
  }
3368
3509
  try {
3369
3510
  await client.execute({
@@ -3374,20 +3515,23 @@ async function ensureSchema() {
3374
3515
  sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
3375
3516
  args: []
3376
3517
  });
3377
- } catch {
3518
+ } catch (e) {
3519
+ logCatchDebug("migration", e);
3378
3520
  }
3379
3521
  try {
3380
3522
  await client.execute({
3381
3523
  sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
3382
3524
  args: []
3383
3525
  });
3384
- } catch {
3526
+ } catch (e) {
3527
+ logCatchDebug("migration", e);
3385
3528
  }
3386
3529
  try {
3387
3530
  await client.execute(
3388
3531
  `CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
3389
3532
  );
3390
- } catch {
3533
+ } catch (e) {
3534
+ logCatchDebug("migration", e);
3391
3535
  }
3392
3536
  for (const col of [
3393
3537
  "ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
@@ -3395,7 +3539,8 @@ async function ensureSchema() {
3395
3539
  ]) {
3396
3540
  try {
3397
3541
  await client.execute(col);
3398
- } catch {
3542
+ } catch (e) {
3543
+ logCatchDebug("migration", e);
3399
3544
  }
3400
3545
  }
3401
3546
  try {
@@ -3403,13 +3548,15 @@ async function ensureSchema() {
3403
3548
  sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
3404
3549
  args: []
3405
3550
  });
3406
- } catch {
3551
+ } catch (e) {
3552
+ logCatchDebug("migration", e);
3407
3553
  }
3408
3554
  try {
3409
3555
  await client.execute(
3410
3556
  `CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
3411
3557
  );
3412
- } catch {
3558
+ } catch (e) {
3559
+ logCatchDebug("migration", e);
3413
3560
  }
3414
3561
  for (const col of [
3415
3562
  "ALTER TABLE memories ADD COLUMN valid_from TEXT",
@@ -3417,7 +3564,8 @@ async function ensureSchema() {
3417
3564
  ]) {
3418
3565
  try {
3419
3566
  await client.execute(col);
3420
- } catch {
3567
+ } catch (e) {
3568
+ logCatchDebug("migration", e);
3421
3569
  }
3422
3570
  }
3423
3571
  try {
@@ -3425,27 +3573,31 @@ async function ensureSchema() {
3425
3573
  sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3426
3574
  args: []
3427
3575
  });
3428
- } catch {
3576
+ } catch (e) {
3577
+ logCatchDebug("migration", e);
3429
3578
  }
3430
3579
  try {
3431
3580
  await client.execute({
3432
3581
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
3433
3582
  args: []
3434
3583
  });
3435
- } catch {
3584
+ } catch (e) {
3585
+ logCatchDebug("migration", e);
3436
3586
  }
3437
3587
  try {
3438
3588
  await client.execute(
3439
3589
  `CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
3440
3590
  );
3441
- } catch {
3591
+ } catch (e) {
3592
+ logCatchDebug("migration", e);
3442
3593
  }
3443
3594
  try {
3444
3595
  await client.execute({
3445
3596
  sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
3446
3597
  args: []
3447
3598
  });
3448
- } catch {
3599
+ } catch (e) {
3600
+ logCatchDebug("migration", e);
3449
3601
  }
3450
3602
  for (const col of [
3451
3603
  "ALTER TABLE memories ADD COLUMN intent TEXT",
@@ -3466,7 +3618,8 @@ async function ensureSchema() {
3466
3618
  ]) {
3467
3619
  try {
3468
3620
  await client.execute(col);
3469
- } catch {
3621
+ } catch (e) {
3622
+ logCatchDebug("migration", e);
3470
3623
  }
3471
3624
  }
3472
3625
  try {
@@ -3474,14 +3627,16 @@ async function ensureSchema() {
3474
3627
  sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3475
3628
  args: []
3476
3629
  });
3477
- } catch {
3630
+ } catch (e) {
3631
+ logCatchDebug("migration", e);
3478
3632
  }
3479
3633
  try {
3480
3634
  await client.execute({
3481
3635
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
3482
3636
  args: []
3483
3637
  });
3484
- } catch {
3638
+ } catch (e) {
3639
+ logCatchDebug("migration", e);
3485
3640
  }
3486
3641
  }
3487
3642
  async function disposeDatabase() {
@@ -3492,7 +3647,8 @@ async function disposeDatabase() {
3492
3647
  if (_client) {
3493
3648
  try {
3494
3649
  await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
3495
- } catch {
3650
+ } catch (e) {
3651
+ logCatchDebug("WAL checkpoint", e);
3496
3652
  }
3497
3653
  }
3498
3654
  if (_daemonClient) {
@@ -3508,8 +3664,9 @@ async function disposeDatabase() {
3508
3664
  _client = null;
3509
3665
  _resilientClient = null;
3510
3666
  }
3667
+ releaseDbLock();
3511
3668
  }
3512
- var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3669
+ var _debugDb, _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, _lockFd, DB_LOCK_PATH, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
3513
3670
  var init_database = __esm({
3514
3671
  "src/lib/database.ts"() {
3515
3672
  "use strict";
@@ -3517,11 +3674,14 @@ var init_database = __esm({
3517
3674
  init_employees();
3518
3675
  init_database_adapter();
3519
3676
  init_memory();
3677
+ _debugDb = process.env.EXE_DEBUG === "1";
3520
3678
  _client = null;
3521
3679
  _resilientClient = null;
3522
3680
  _walCheckpointTimer = null;
3523
3681
  _daemonClient = null;
3524
3682
  _adapterClient = null;
3683
+ _lockFd = null;
3684
+ DB_LOCK_PATH = join(homedir(), ".exe-os", "db.lock");
3525
3685
  initTurso = initDatabase;
3526
3686
  SOFT_DELETE_RETENTION_DAYS = 7;
3527
3687
  disposeTurso = disposeDatabase;
@@ -3530,7 +3690,7 @@ var init_database = __esm({
3530
3690
 
3531
3691
  // src/lib/keychain.ts
3532
3692
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3533
- import { existsSync as existsSync7, statSync as statSync2 } from "fs";
3693
+ import { existsSync as existsSync8, statSync as statSync3 } from "fs";
3534
3694
  import { execSync as execSync3 } from "child_process";
3535
3695
  import path7 from "path";
3536
3696
  import os5 from "os";
@@ -3565,7 +3725,7 @@ function isRootOnlyTrustedServerKeyFile(keyPath) {
3565
3725
  if (process.platform !== "linux") return false;
3566
3726
  try {
3567
3727
  const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
3568
- const st = statSync2(keyPath);
3728
+ const st = statSync3(keyPath);
3569
3729
  if (!st.isFile() || (st.mode & 63) !== 0) return false;
3570
3730
  if (uid === 0) return true;
3571
3731
  const exeOsDir = process.env.EXE_OS_DIR;
@@ -3766,7 +3926,7 @@ async function getMasterKey() {
3766
3926
  }
3767
3927
  }
3768
3928
  const keyPath = getKeyPath();
3769
- if (!existsSync7(keyPath)) {
3929
+ if (!existsSync8(keyPath)) {
3770
3930
  process.stderr.write(
3771
3931
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3772
3932
  `
@@ -4101,18 +4261,54 @@ __export(shard_manager_exports, {
4101
4261
  shardExists: () => shardExists
4102
4262
  });
4103
4263
  import path8 from "path";
4104
- import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync3 } from "fs";
4264
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
4105
4265
  import { createClient as createClient2 } from "@libsql/client";
4106
4266
  function initShardManager(encryptionKey) {
4107
4267
  _encryptionKey = encryptionKey;
4108
- if (!existsSync8(SHARDS_DIR)) {
4109
- mkdirSync2(SHARDS_DIR, { recursive: true });
4268
+ _keyValidated = false;
4269
+ _keyValidationPromise = null;
4270
+ if (!existsSync9(SHARDS_DIR)) {
4271
+ mkdirSync3(SHARDS_DIR, { recursive: true });
4272
+ }
4273
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
4274
+ if (existingShards.length === 0) {
4275
+ _keyValidated = true;
4110
4276
  }
4111
4277
  _shardingEnabled = true;
4112
4278
  if (_evictionTimer) clearInterval(_evictionTimer);
4113
4279
  _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
4114
4280
  _evictionTimer.unref();
4115
4281
  }
4282
+ async function validateEncryptionKey() {
4283
+ if (_keyValidated) return true;
4284
+ if (!_encryptionKey) return false;
4285
+ const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
4286
+ if (existingShards.length === 0) {
4287
+ _keyValidated = true;
4288
+ return true;
4289
+ }
4290
+ for (const shardFile of existingShards.slice(0, 3)) {
4291
+ const dbPath = path8.join(SHARDS_DIR, shardFile);
4292
+ const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
4293
+ try {
4294
+ await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
4295
+ testClient.close();
4296
+ _keyValidated = true;
4297
+ return true;
4298
+ } catch {
4299
+ try {
4300
+ testClient.close();
4301
+ } catch {
4302
+ }
4303
+ }
4304
+ }
4305
+ process.stderr.write(
4306
+ `[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.
4307
+ `
4308
+ );
4309
+ _shardingEnabled = false;
4310
+ return false;
4311
+ }
4116
4312
  function isShardingEnabled() {
4117
4313
  return _shardingEnabled;
4118
4314
  }
@@ -4146,13 +4342,13 @@ function getShardClient(projectName) {
4146
4342
  }
4147
4343
  function shardExists(projectName) {
4148
4344
  const safeName = safeShardName(projectName);
4149
- return existsSync8(path8.join(SHARDS_DIR, `${safeName}.db`));
4345
+ return existsSync9(path8.join(SHARDS_DIR, `${safeName}.db`));
4150
4346
  }
4151
4347
  function safeShardName(projectName) {
4152
4348
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
4153
4349
  }
4154
4350
  function listShards() {
4155
- if (!existsSync8(SHARDS_DIR)) return [];
4351
+ if (!existsSync9(SHARDS_DIR)) return [];
4156
4352
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
4157
4353
  }
4158
4354
  async function auditShardHealth(options = {}) {
@@ -4165,7 +4361,7 @@ async function auditShardHealth(options = {}) {
4165
4361
  const shards = [];
4166
4362
  for (const name of names) {
4167
4363
  const dbPath = path8.join(SHARDS_DIR, `${name}.db`);
4168
- const stat = statSync3(dbPath);
4364
+ const stat = statSync4(dbPath);
4169
4365
  const item = {
4170
4366
  name,
4171
4367
  path: dbPath,
@@ -4405,6 +4601,17 @@ async function ensureShardSchema(client) {
4405
4601
  }
4406
4602
  }
4407
4603
  async function getReadyShardClient(projectName) {
4604
+ if (!_keyValidated) {
4605
+ if (!_keyValidationPromise) {
4606
+ _keyValidationPromise = validateEncryptionKey();
4607
+ }
4608
+ const valid = await _keyValidationPromise;
4609
+ if (!valid) {
4610
+ throw new Error(
4611
+ `Shard creation blocked: encryption key mismatch with existing shards. Run /exe-doctor to audit.`
4612
+ );
4613
+ }
4614
+ }
4408
4615
  const safeName = safeShardName(projectName);
4409
4616
  let client = getShardClient(projectName);
4410
4617
  try {
@@ -4417,8 +4624,8 @@ async function getReadyShardClient(projectName) {
4417
4624
  _shards.delete(safeName);
4418
4625
  _shardLastAccess.delete(safeName);
4419
4626
  const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
4420
- if (existsSync8(dbPath)) {
4421
- const stat = statSync3(dbPath);
4627
+ if (existsSync9(dbPath)) {
4628
+ const stat = statSync4(dbPath);
4422
4629
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4423
4630
  const archivedPath = path8.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
4424
4631
  renameSync3(dbPath, archivedPath);
@@ -4483,7 +4690,7 @@ function disposeShards() {
4483
4690
  _shardingEnabled = false;
4484
4691
  _encryptionKey = null;
4485
4692
  }
4486
- var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
4693
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled, _keyValidated, _keyValidationPromise;
4487
4694
  var init_shard_manager = __esm({
4488
4695
  "src/lib/shard-manager.ts"() {
4489
4696
  "use strict";
@@ -4497,6 +4704,8 @@ var init_shard_manager = __esm({
4497
4704
  _evictionTimer = null;
4498
4705
  _encryptionKey = null;
4499
4706
  _shardingEnabled = false;
4707
+ _keyValidated = false;
4708
+ _keyValidationPromise = null;
4500
4709
  }
4501
4710
  });
4502
4711
 
@@ -4692,6 +4901,18 @@ var init_platform_procedures = __esm({
4692
4901
  priority: "p0",
4693
4902
  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.'"
4694
4903
  },
4904
+ {
4905
+ title: "Review chain \u2014 managers must actively pull completed work, never wait for nudges",
4906
+ domain: "workflow",
4907
+ priority: "p0",
4908
+ 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."
4909
+ },
4910
+ {
4911
+ title: "Bug fix lifecycle \u2014 triage upstream after every verified fix so customers see the status",
4912
+ domain: "workflow",
4913
+ priority: "p0",
4914
+ 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."
4915
+ },
4695
4916
  {
4696
4917
  title: "Intercom is a speedup, not delivery \u2014 DB is the source of truth",
4697
4918
  domain: "architecture",
@@ -5289,6 +5510,20 @@ __export(store_exports, {
5289
5510
  vectorToBlob: () => vectorToBlob,
5290
5511
  writeMemory: () => writeMemory
5291
5512
  });
5513
+ function logStoreDebug(context, err) {
5514
+ if (_debugStore) {
5515
+ process.stderr.write(
5516
+ `[store] ${context}: ${err instanceof Error ? err.message : String(err)}
5517
+ `
5518
+ );
5519
+ }
5520
+ }
5521
+ function logStoreWarn(context, err) {
5522
+ process.stderr.write(
5523
+ `[store] WARN ${context}: ${err instanceof Error ? err.message : String(err)}
5524
+ `
5525
+ );
5526
+ }
5292
5527
  function isBusyError2(err) {
5293
5528
  if (err instanceof Error) {
5294
5529
  const msg = err.message.toLowerCase();
@@ -5343,13 +5578,15 @@ async function initStore(options) {
5343
5578
  try {
5344
5579
  const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5345
5580
  await initDaemonClient2();
5346
- } catch {
5581
+ } catch (e) {
5582
+ logStoreWarn("catch", e);
5347
5583
  }
5348
5584
  if (!options?.lightweight) {
5349
5585
  try {
5350
5586
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
5351
5587
  initShardManager2(hexKey);
5352
- } catch {
5588
+ } catch (e) {
5589
+ logStoreWarn("catch", e);
5353
5590
  }
5354
5591
  const client = getClient();
5355
5592
  const vResult = await retryOnBusy2(
@@ -5360,7 +5597,8 @@ async function initStore(options) {
5360
5597
  try {
5361
5598
  const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
5362
5599
  await loadGlobalProcedures2();
5363
- } catch {
5600
+ } catch (e) {
5601
+ logStoreWarn("catch", e);
5364
5602
  }
5365
5603
  }
5366
5604
  }
@@ -5420,7 +5658,8 @@ async function writeMemory(record) {
5420
5658
  memoryType
5421
5659
  });
5422
5660
  if (existing) return;
5423
- } catch {
5661
+ } catch (e) {
5662
+ logStoreWarn("catch", e);
5424
5663
  }
5425
5664
  const dbRow = {
5426
5665
  id: record.id,
@@ -5621,12 +5860,14 @@ async function flushBatch() {
5621
5860
  try {
5622
5861
  const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5623
5862
  await insertMemoryCardsForBatch2(batch);
5624
- } catch {
5863
+ } catch (e) {
5864
+ logStoreWarn("catch", e);
5625
5865
  }
5626
5866
  try {
5627
5867
  const { insertOntologyForBatch: insertOntologyForBatch2 } = await Promise.resolve().then(() => (init_agentic_ontology(), agentic_ontology_exports));
5628
5868
  await insertOntologyForBatch2(batch);
5629
- } catch {
5869
+ } catch (e) {
5870
+ logStoreWarn("catch", e);
5630
5871
  }
5631
5872
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
5632
5873
  _pendingRecords.splice(0, batch.length);
@@ -5665,7 +5906,8 @@ ${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
5665
5906
  }
5666
5907
  }
5667
5908
  }
5668
- } catch {
5909
+ } catch (e) {
5910
+ logStoreWarn("catch", e);
5669
5911
  }
5670
5912
  return batch.length;
5671
5913
  } finally {
@@ -5707,7 +5949,8 @@ async function searchMemories(queryVector, agentId, options) {
5707
5949
  } else {
5708
5950
  client = getClient();
5709
5951
  }
5710
- } catch {
5952
+ } catch (e) {
5953
+ logStoreDebug("shard routing fallback", e);
5711
5954
  client = getClient();
5712
5955
  }
5713
5956
  const limit = options?.limit ?? 10;
@@ -5823,7 +6066,8 @@ async function attachDocumentMetadata(records) {
5823
6066
  if (!record.document_id) continue;
5824
6067
  record.document_metadata = byId.get(record.document_id) ?? null;
5825
6068
  }
5826
- } catch {
6069
+ } catch (e) {
6070
+ logStoreWarn("catch", e);
5827
6071
  }
5828
6072
  return records;
5829
6073
  }
@@ -5884,11 +6128,12 @@ async function getMemoryCardinality(agentId) {
5884
6128
  args: [agentId]
5885
6129
  });
5886
6130
  return Number(result.rows[0]?.cnt) || 0;
5887
- } catch {
6131
+ } catch (e) {
6132
+ logStoreWarn("getMemoryCardinality", e);
5888
6133
  return 0;
5889
6134
  }
5890
6135
  }
5891
- var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
6136
+ var _debugStore, INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
5892
6137
  var init_store = __esm({
5893
6138
  "src/lib/store.ts"() {
5894
6139
  "use strict";
@@ -5898,6 +6143,7 @@ var init_store = __esm({
5898
6143
  init_config();
5899
6144
  init_state_bus();
5900
6145
  init_memory_write_governor();
6146
+ _debugStore = process.env.EXE_DEBUG === "1";
5901
6147
  INIT_MAX_RETRIES = 3;
5902
6148
  INIT_RETRY_DELAY_MS = 1e3;
5903
6149
  _pendingRecords = [];
@@ -5910,13 +6156,13 @@ var init_store = __esm({
5910
6156
  });
5911
6157
 
5912
6158
  // src/lib/session-registry.ts
5913
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync9 } from "fs";
6159
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync10 } from "fs";
5914
6160
  import path9 from "path";
5915
6161
  import os6 from "os";
5916
6162
  function registerSession(entry) {
5917
6163
  const dir = path9.dirname(REGISTRY_PATH);
5918
- if (!existsSync9(dir)) {
5919
- mkdirSync3(dir, { recursive: true });
6164
+ if (!existsSync10(dir)) {
6165
+ mkdirSync4(dir, { recursive: true });
5920
6166
  }
5921
6167
  const sessions = listSessions();
5922
6168
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -6210,16 +6456,16 @@ __export(intercom_queue_exports, {
6210
6456
  queueIntercom: () => queueIntercom,
6211
6457
  readQueue: () => readQueue
6212
6458
  });
6213
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync4, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
6459
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync4, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
6214
6460
  import path10 from "path";
6215
6461
  import os7 from "os";
6216
6462
  function ensureDir() {
6217
6463
  const dir = path10.dirname(QUEUE_PATH);
6218
- if (!existsSync10(dir)) mkdirSync4(dir, { recursive: true });
6464
+ if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
6219
6465
  }
6220
6466
  function readQueue() {
6221
6467
  try {
6222
- if (!existsSync10(QUEUE_PATH)) return [];
6468
+ if (!existsSync11(QUEUE_PATH)) return [];
6223
6469
  return JSON.parse(readFileSync7(QUEUE_PATH, "utf8"));
6224
6470
  } catch {
6225
6471
  return [];
@@ -6328,7 +6574,7 @@ var init_intercom_queue = __esm({
6328
6574
  });
6329
6575
 
6330
6576
  // src/lib/license.ts
6331
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
6577
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync6 } from "fs";
6332
6578
  import { randomUUID as randomUUID3 } from "crypto";
6333
6579
  import { createRequire as createRequire2 } from "module";
6334
6580
  import { pathToFileURL as pathToFileURL2 } from "url";
@@ -6355,11 +6601,11 @@ var init_license = __esm({
6355
6601
  });
6356
6602
 
6357
6603
  // src/lib/plan-limits.ts
6358
- import { readFileSync as readFileSync9, existsSync as existsSync12 } from "fs";
6604
+ import { readFileSync as readFileSync9, existsSync as existsSync13 } from "fs";
6359
6605
  import path12 from "path";
6360
6606
  function getLicenseSync() {
6361
6607
  try {
6362
- if (!existsSync12(CACHE_PATH2)) return freeLicense();
6608
+ if (!existsSync13(CACHE_PATH2)) return freeLicense();
6363
6609
  const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
6364
6610
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
6365
6611
  const parts = raw.token.split(".");
@@ -6398,7 +6644,7 @@ function assertEmployeeLimitSync(rosterPath) {
6398
6644
  const filePath = rosterPath ?? EMPLOYEES_PATH;
6399
6645
  let count = 0;
6400
6646
  try {
6401
- if (existsSync12(filePath)) {
6647
+ if (existsSync13(filePath)) {
6402
6648
  const raw = readFileSync9(filePath, "utf8");
6403
6649
  const employees = JSON.parse(raw);
6404
6650
  count = Array.isArray(employees) ? employees.length : 0;
@@ -6436,9 +6682,9 @@ var init_plan_limits = __esm({
6436
6682
  import os9 from "os";
6437
6683
  import path13 from "path";
6438
6684
  import {
6439
- existsSync as existsSync13,
6685
+ existsSync as existsSync14,
6440
6686
  lstatSync,
6441
- mkdirSync as mkdirSync6,
6687
+ mkdirSync as mkdirSync7,
6442
6688
  readlinkSync as readlinkSync2,
6443
6689
  symlinkSync as symlinkSync2
6444
6690
  } from "fs";
@@ -6454,8 +6700,8 @@ function claudeAgentLinkPath(homeDir, agentId) {
6454
6700
  function ensureAgentSymlink(agentId, homeDir = os9.homedir()) {
6455
6701
  const target = identitySourcePath(homeDir, agentId);
6456
6702
  const link = claudeAgentLinkPath(homeDir, agentId);
6457
- mkdirSync6(claudeAgentsDir(homeDir), { recursive: true });
6458
- if (existsSync13(link)) {
6703
+ mkdirSync7(claudeAgentsDir(homeDir), { recursive: true });
6704
+ if (existsSync14(link)) {
6459
6705
  let stat;
6460
6706
  try {
6461
6707
  stat = lstatSync(link);
@@ -6829,7 +7075,7 @@ __export(tasks_review_exports, {
6829
7075
  listPendingReviews: () => listPendingReviews
6830
7076
  });
6831
7077
  import path14 from "path";
6832
- import { existsSync as existsSync14, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
7078
+ import { existsSync as existsSync15, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
6833
7079
  function formatAge(isoTimestamp) {
6834
7080
  if (!isoTimestamp) return "";
6835
7081
  const ms = Date.now() - new Date(isoTimestamp).getTime();
@@ -7099,10 +7345,10 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
7099
7345
  }
7100
7346
  try {
7101
7347
  const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
7102
- if (existsSync14(cacheDir)) {
7348
+ if (existsSync15(cacheDir)) {
7103
7349
  for (const f of readdirSync2(cacheDir)) {
7104
7350
  if (f.startsWith("review-notified-")) {
7105
- unlinkSync3(path14.join(cacheDir, f));
7351
+ unlinkSync4(path14.join(cacheDir, f));
7106
7352
  }
7107
7353
  }
7108
7354
  }
@@ -7149,11 +7395,11 @@ __export(tmux_routing_exports, {
7149
7395
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
7150
7396
  });
7151
7397
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
7152
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync15, appendFileSync, readdirSync as readdirSync3 } from "fs";
7398
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync3 } from "fs";
7153
7399
  import path15 from "path";
7154
7400
  import os10 from "os";
7155
7401
  import { fileURLToPath as fileURLToPath2 } from "url";
7156
- import { unlinkSync as unlinkSync4 } from "fs";
7402
+ import { unlinkSync as unlinkSync5 } from "fs";
7157
7403
  function spawnLockPath(sessionName) {
7158
7404
  return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
7159
7405
  }
@@ -7166,11 +7412,11 @@ function isProcessAlive(pid) {
7166
7412
  }
7167
7413
  }
7168
7414
  function acquireSpawnLock2(sessionName) {
7169
- if (!existsSync15(SPAWN_LOCK_DIR)) {
7170
- mkdirSync7(SPAWN_LOCK_DIR, { recursive: true });
7415
+ if (!existsSync16(SPAWN_LOCK_DIR)) {
7416
+ mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
7171
7417
  }
7172
7418
  const lockFile = spawnLockPath(sessionName);
7173
- if (existsSync15(lockFile)) {
7419
+ if (existsSync16(lockFile)) {
7174
7420
  try {
7175
7421
  const lock = JSON.parse(readFileSync10(lockFile, "utf8"));
7176
7422
  const age = Date.now() - lock.timestamp;
@@ -7185,7 +7431,7 @@ function acquireSpawnLock2(sessionName) {
7185
7431
  }
7186
7432
  function releaseSpawnLock2(sessionName) {
7187
7433
  try {
7188
- unlinkSync4(spawnLockPath(sessionName));
7434
+ unlinkSync5(spawnLockPath(sessionName));
7189
7435
  } catch {
7190
7436
  }
7191
7437
  }
@@ -7198,7 +7444,7 @@ function resolveBehaviorsExporterScript() {
7198
7444
  "bin",
7199
7445
  "exe-export-behaviors.js"
7200
7446
  );
7201
- return existsSync15(scriptPath) ? scriptPath : null;
7447
+ return existsSync16(scriptPath) ? scriptPath : null;
7202
7448
  } catch {
7203
7449
  return null;
7204
7450
  }
@@ -7264,8 +7510,8 @@ function extractRootExe(name) {
7264
7510
  return parts.length > 0 ? parts[parts.length - 1] : null;
7265
7511
  }
7266
7512
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
7267
- if (!existsSync15(SESSION_CACHE)) {
7268
- mkdirSync7(SESSION_CACHE, { recursive: true });
7513
+ if (!existsSync16(SESSION_CACHE)) {
7514
+ mkdirSync8(SESSION_CACHE, { recursive: true });
7269
7515
  }
7270
7516
  const rootExe = extractRootExe(parentExe) ?? parentExe;
7271
7517
  const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
@@ -7295,11 +7541,13 @@ function getDispatchedBy(sessionKey) {
7295
7541
  }
7296
7542
  }
7297
7543
  function resolveExeSession() {
7298
- if (process.env.EXE_SESSION_NAME) {
7299
- return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
7300
- }
7301
7544
  const mySession = getMySession();
7302
- if (!mySession) return null;
7545
+ if (!mySession) {
7546
+ if (process.env.EXE_SESSION_NAME) {
7547
+ return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
7548
+ }
7549
+ return null;
7550
+ }
7303
7551
  const fromSessionName = extractRootExe(mySession);
7304
7552
  let candidate = null;
7305
7553
  try {
@@ -7394,7 +7642,7 @@ async function verifyPaneAtCapacity(sessionName) {
7394
7642
  }
7395
7643
  function readDebounceState() {
7396
7644
  try {
7397
- if (!existsSync15(DEBOUNCE_FILE)) return {};
7645
+ if (!existsSync16(DEBOUNCE_FILE)) return {};
7398
7646
  const raw = JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
7399
7647
  const state = {};
7400
7648
  for (const [key, val] of Object.entries(raw)) {
@@ -7411,7 +7659,7 @@ function readDebounceState() {
7411
7659
  }
7412
7660
  function writeDebounceState(state) {
7413
7661
  try {
7414
- if (!existsSync15(SESSION_CACHE)) mkdirSync7(SESSION_CACHE, { recursive: true });
7662
+ if (!existsSync16(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
7415
7663
  writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
7416
7664
  } catch {
7417
7665
  }
@@ -7512,7 +7760,7 @@ function sendIntercom(targetSession) {
7512
7760
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7513
7761
  const agent = baseAgentName(rawAgent);
7514
7762
  const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
7515
- if (existsSync15(markerPath)) {
7763
+ if (existsSync16(markerPath)) {
7516
7764
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker + not idle \u2014 will auto-chain)`);
7517
7765
  return "debounced";
7518
7766
  }
@@ -7523,7 +7771,7 @@ function sendIntercom(targetSession) {
7523
7771
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
7524
7772
  const agent = baseAgentName(rawAgent);
7525
7773
  const taskDir = path15.join(process.cwd(), "exe", agent);
7526
- if (existsSync15(taskDir)) {
7774
+ if (existsSync16(taskDir)) {
7527
7775
  const files = readdirSync3(taskDir).filter(
7528
7776
  (f) => f.endsWith(".md") && f !== "DONE.txt"
7529
7777
  );
@@ -7684,15 +7932,15 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7684
7932
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
7685
7933
  const logDir = path15.join(os10.homedir(), ".exe-os", "session-logs");
7686
7934
  const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
7687
- if (!existsSync15(logDir)) {
7688
- mkdirSync7(logDir, { recursive: true });
7935
+ if (!existsSync16(logDir)) {
7936
+ mkdirSync8(logDir, { recursive: true });
7689
7937
  }
7690
7938
  transport.kill(sessionName);
7691
7939
  let cleanupSuffix = "";
7692
7940
  try {
7693
7941
  const thisFile = fileURLToPath2(import.meta.url);
7694
7942
  const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
7695
- if (existsSync15(cleanupScript)) {
7943
+ if (existsSync16(cleanupScript)) {
7696
7944
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
7697
7945
  }
7698
7946
  } catch {
@@ -7747,7 +7995,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7747
7995
  if (changed) {
7748
7996
  perms.allow = allow;
7749
7997
  settings.permissions = perms;
7750
- mkdirSync7(projSettingsDir, { recursive: true });
7998
+ mkdirSync8(projSettingsDir, { recursive: true });
7751
7999
  writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7752
8000
  }
7753
8001
  } catch {
@@ -7785,7 +8033,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7785
8033
  `
7786
8034
  );
7787
8035
  }
7788
- } else if (existsSync15(identityPath)) {
8036
+ } else if (existsSync16(identityPath)) {
7789
8037
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
7790
8038
  legacyFallbackWarned = true;
7791
8039
  }
@@ -7807,7 +8055,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7807
8055
  let sessionContextFlag = "";
7808
8056
  try {
7809
8057
  const ctxDir = path15.join(os10.homedir(), ".exe-os", "session-cache");
7810
- mkdirSync7(ctxDir, { recursive: true });
8058
+ mkdirSync8(ctxDir, { recursive: true });
7811
8059
  const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
7812
8060
  const ctxContent = [
7813
8061
  `## Session Context`,
@@ -8028,8 +8276,8 @@ import os11 from "os";
8028
8276
  import {
8029
8277
  readFileSync as readFileSync11,
8030
8278
  readdirSync as readdirSync4,
8031
- unlinkSync as unlinkSync5,
8032
- existsSync as existsSync16,
8279
+ unlinkSync as unlinkSync6,
8280
+ existsSync as existsSync17,
8033
8281
  rmdirSync
8034
8282
  } from "fs";
8035
8283
  async function writeNotification(notification) {
@@ -8188,7 +8436,7 @@ import path18 from "path";
8188
8436
  import os12 from "os";
8189
8437
  import { execSync as execSync8 } from "child_process";
8190
8438
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
8191
- import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
8439
+ import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
8192
8440
  async function writeCheckpoint(input) {
8193
8441
  const client = getClient();
8194
8442
  const row = await resolveTask(client, input.taskId);
@@ -8429,7 +8677,7 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
8429
8677
  const EXE_OS_DIR = path18.join(os12.homedir(), ".exe-os");
8430
8678
  const mdPath = path18.join(EXE_OS_DIR, taskFile);
8431
8679
  const mdDir = path18.dirname(mdPath);
8432
- if (!existsSync17(mdDir)) await mkdir4(mdDir, { recursive: true });
8680
+ if (!existsSync18(mdDir)) await mkdir4(mdDir, { recursive: true });
8433
8681
  const reviewer = input.reviewer ?? input.assignedBy;
8434
8682
  const mdContent = `# ${input.title}
8435
8683
 
@@ -8735,7 +8983,7 @@ async function deleteTaskCore(taskId, _baseDir) {
8735
8983
  async function ensureArchitectureDoc(baseDir, projectName) {
8736
8984
  const archPath = path18.join(baseDir, "exe", "ARCHITECTURE.md");
8737
8985
  try {
8738
- if (existsSync17(archPath)) return;
8986
+ if (existsSync18(archPath)) return;
8739
8987
  const template = [
8740
8988
  `# ${projectName} \u2014 System Architecture`,
8741
8989
  "",
@@ -8770,7 +9018,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
8770
9018
  async function ensureGitignoreExe(baseDir) {
8771
9019
  const gitignorePath = path18.join(baseDir, ".gitignore");
8772
9020
  try {
8773
- if (existsSync17(gitignorePath)) {
9021
+ if (existsSync18(gitignorePath)) {
8774
9022
  const content = readFileSync12(gitignorePath, "utf-8");
8775
9023
  if (/^\/?exe\/?$/m.test(content)) return;
8776
9024
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
@@ -9003,10 +9251,10 @@ async function disposeEmbedder() {
9003
9251
  async function embedDirect(text) {
9004
9252
  const llamaCpp = await import("node-llama-cpp");
9005
9253
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
9006
- const { existsSync: existsSync18 } = await import("fs");
9254
+ const { existsSync: existsSync19 } = await import("fs");
9007
9255
  const path21 = await import("path");
9008
9256
  const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
9009
- if (!existsSync18(modelPath)) {
9257
+ if (!existsSync19(modelPath)) {
9010
9258
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
9011
9259
  }
9012
9260
  const llama = await llamaCpp.getLlama();
@@ -9373,7 +9621,7 @@ __export(tasks_exports, {
9373
9621
  writeCheckpoint: () => writeCheckpoint
9374
9622
  });
9375
9623
  import path20 from "path";
9376
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, unlinkSync as unlinkSync6 } from "fs";
9624
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7 } from "fs";
9377
9625
  async function createTask(input) {
9378
9626
  const result = await createTaskCore(input);
9379
9627
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -9395,11 +9643,11 @@ async function updateTask(input) {
9395
9643
  const cacheDir = path20.join(EXE_AI_DIR, "session-cache");
9396
9644
  const cachePath = path20.join(cacheDir, `current-task-${agent}.json`);
9397
9645
  if (input.status === "in_progress") {
9398
- mkdirSync8(cacheDir, { recursive: true });
9646
+ mkdirSync9(cacheDir, { recursive: true });
9399
9647
  writeFileSync8(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
9400
9648
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
9401
9649
  try {
9402
- unlinkSync6(cachePath);
9650
+ unlinkSync7(cachePath);
9403
9651
  } catch {
9404
9652
  }
9405
9653
  }