@askexenow/exe-os 0.8.85 → 0.8.86

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 (57) hide show
  1. package/dist/bin/cleanup-stale-review-tasks.js +57 -19
  2. package/dist/bin/cli.js +507 -337
  3. package/dist/bin/exe-agent-config.js +242 -0
  4. package/dist/bin/exe-agent.js +3 -3
  5. package/dist/bin/exe-boot.js +344 -346
  6. package/dist/bin/exe-dispatch.js +375 -250
  7. package/dist/bin/exe-forget.js +5 -1
  8. package/dist/bin/exe-gateway.js +260 -135
  9. package/dist/bin/exe-healthcheck.js +133 -1
  10. package/dist/bin/exe-heartbeat.js +72 -31
  11. package/dist/bin/exe-link.js +25 -2
  12. package/dist/bin/exe-new-employee.js +22 -0
  13. package/dist/bin/exe-pending-messages.js +55 -17
  14. package/dist/bin/exe-pending-reviews.js +57 -19
  15. package/dist/bin/exe-search.js +6 -2
  16. package/dist/bin/exe-session-cleanup.js +260 -135
  17. package/dist/bin/exe-start-codex.js +2598 -0
  18. package/dist/bin/exe-start.sh +15 -3
  19. package/dist/bin/exe-status.js +57 -19
  20. package/dist/bin/git-sweep.js +391 -266
  21. package/dist/bin/install.js +22 -0
  22. package/dist/bin/scan-tasks.js +394 -269
  23. package/dist/bin/setup.js +47 -2
  24. package/dist/gateway/index.js +257 -132
  25. package/dist/hooks/bug-report-worker.js +242 -117
  26. package/dist/hooks/commit-complete.js +389 -264
  27. package/dist/hooks/error-recall.js +6 -2
  28. package/dist/hooks/ingest-worker.js +314 -193
  29. package/dist/hooks/post-compact.js +84 -46
  30. package/dist/hooks/pre-compact.js +272 -147
  31. package/dist/hooks/pre-tool-use.js +104 -66
  32. package/dist/hooks/prompt-submit.js +126 -66
  33. package/dist/hooks/session-end.js +277 -152
  34. package/dist/hooks/session-start.js +70 -28
  35. package/dist/hooks/stop.js +90 -52
  36. package/dist/hooks/subagent-stop.js +84 -46
  37. package/dist/hooks/summary-worker.js +175 -114
  38. package/dist/index.js +296 -171
  39. package/dist/lib/agent-config.js +167 -0
  40. package/dist/lib/cloud-sync.js +25 -2
  41. package/dist/lib/exe-daemon.js +338 -213
  42. package/dist/lib/hybrid-search.js +7 -2
  43. package/dist/lib/messaging.js +95 -39
  44. package/dist/lib/runtime-table.js +16 -0
  45. package/dist/lib/session-wrappers.js +22 -0
  46. package/dist/lib/tasks.js +242 -117
  47. package/dist/lib/tmux-routing.js +314 -189
  48. package/dist/mcp/server.js +573 -274
  49. package/dist/mcp/tools/create-task.js +260 -135
  50. package/dist/mcp/tools/list-tasks.js +68 -30
  51. package/dist/mcp/tools/send-message.js +100 -44
  52. package/dist/mcp/tools/update-task.js +123 -67
  53. package/dist/runtime/index.js +276 -151
  54. package/dist/tui/App.js +479 -354
  55. package/package.json +1 -1
  56. package/src/commands/exe/agent-config.md +27 -0
  57. package/src/commands/exe/cc-doctor.md +10 -0
@@ -2802,17 +2802,53 @@ var init_provider_table = __esm({
2802
2802
  }
2803
2803
  });
2804
2804
 
2805
- // src/lib/intercom-queue.ts
2806
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
2805
+ // src/lib/runtime-table.ts
2806
+ var RUNTIME_TABLE;
2807
+ var init_runtime_table = __esm({
2808
+ "src/lib/runtime-table.ts"() {
2809
+ "use strict";
2810
+ RUNTIME_TABLE = {
2811
+ codex: {
2812
+ binary: "codex",
2813
+ launchMode: "exec",
2814
+ autoApproveFlag: "--full-auto",
2815
+ inlineFlag: "--no-alt-screen",
2816
+ apiKeyEnv: "OPENAI_API_KEY",
2817
+ defaultModel: "gpt-5.4"
2818
+ }
2819
+ };
2820
+ }
2821
+ });
2822
+
2823
+ // src/lib/agent-config.ts
2824
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
2807
2825
  import path8 from "path";
2826
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
2827
+ var init_agent_config = __esm({
2828
+ "src/lib/agent-config.ts"() {
2829
+ "use strict";
2830
+ init_config();
2831
+ init_runtime_table();
2832
+ AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
2833
+ DEFAULT_MODELS = {
2834
+ claude: "claude-opus-4",
2835
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
2836
+ opencode: "minimax-m2.7"
2837
+ };
2838
+ }
2839
+ });
2840
+
2841
+ // src/lib/intercom-queue.ts
2842
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
2843
+ import path9 from "path";
2808
2844
  import os6 from "os";
2809
2845
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
2810
2846
  var init_intercom_queue = __esm({
2811
2847
  "src/lib/intercom-queue.ts"() {
2812
2848
  "use strict";
2813
- QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
2849
+ QUEUE_PATH = path9.join(os6.homedir(), ".exe-os", "intercom-queue.json");
2814
2850
  TTL_MS = 60 * 60 * 1e3;
2815
- INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
2851
+ INTERCOM_LOG = path9.join(os6.homedir(), ".exe-os", "intercom.log");
2816
2852
  }
2817
2853
  });
2818
2854
 
@@ -2833,9 +2869,9 @@ __export(license_exports, {
2833
2869
  stopLicenseRevalidation: () => stopLicenseRevalidation,
2834
2870
  validateLicense: () => validateLicense
2835
2871
  });
2836
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
2872
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
2837
2873
  import { randomUUID as randomUUID3 } from "crypto";
2838
- import path9 from "path";
2874
+ import path10 from "path";
2839
2875
  import { jwtVerify, importSPKI } from "jose";
2840
2876
  async function fetchRetry(url, init) {
2841
2877
  try {
@@ -2846,37 +2882,37 @@ async function fetchRetry(url, init) {
2846
2882
  }
2847
2883
  }
2848
2884
  function loadDeviceId() {
2849
- const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
2885
+ const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
2850
2886
  try {
2851
- if (existsSync8(deviceJsonPath)) {
2852
- const data = JSON.parse(readFileSync6(deviceJsonPath, "utf8"));
2887
+ if (existsSync9(deviceJsonPath)) {
2888
+ const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
2853
2889
  if (data.deviceId) return data.deviceId;
2854
2890
  }
2855
2891
  } catch {
2856
2892
  }
2857
2893
  try {
2858
- if (existsSync8(DEVICE_ID_PATH)) {
2859
- const id2 = readFileSync6(DEVICE_ID_PATH, "utf8").trim();
2894
+ if (existsSync9(DEVICE_ID_PATH)) {
2895
+ const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
2860
2896
  if (id2) return id2;
2861
2897
  }
2862
2898
  } catch {
2863
2899
  }
2864
2900
  const id = randomUUID3();
2865
- mkdirSync3(EXE_AI_DIR, { recursive: true });
2866
- writeFileSync3(DEVICE_ID_PATH, id, "utf8");
2901
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
2902
+ writeFileSync4(DEVICE_ID_PATH, id, "utf8");
2867
2903
  return id;
2868
2904
  }
2869
2905
  function loadLicense() {
2870
2906
  try {
2871
- if (!existsSync8(LICENSE_PATH)) return null;
2872
- return readFileSync6(LICENSE_PATH, "utf8").trim();
2907
+ if (!existsSync9(LICENSE_PATH)) return null;
2908
+ return readFileSync7(LICENSE_PATH, "utf8").trim();
2873
2909
  } catch {
2874
2910
  return null;
2875
2911
  }
2876
2912
  }
2877
2913
  function saveLicense(apiKey) {
2878
- mkdirSync3(EXE_AI_DIR, { recursive: true });
2879
- writeFileSync3(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2914
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
2915
+ writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2880
2916
  }
2881
2917
  async function verifyLicenseJwt(token) {
2882
2918
  try {
@@ -2902,8 +2938,8 @@ async function verifyLicenseJwt(token) {
2902
2938
  }
2903
2939
  async function getCachedLicense() {
2904
2940
  try {
2905
- if (!existsSync8(CACHE_PATH)) return null;
2906
- const raw = JSON.parse(readFileSync6(CACHE_PATH, "utf8"));
2941
+ if (!existsSync9(CACHE_PATH)) return null;
2942
+ const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
2907
2943
  if (!raw.token || typeof raw.token !== "string") return null;
2908
2944
  return await verifyLicenseJwt(raw.token);
2909
2945
  } catch {
@@ -2912,8 +2948,8 @@ async function getCachedLicense() {
2912
2948
  }
2913
2949
  function readCachedToken() {
2914
2950
  try {
2915
- if (!existsSync8(CACHE_PATH)) return null;
2916
- const raw = JSON.parse(readFileSync6(CACHE_PATH, "utf8"));
2951
+ if (!existsSync9(CACHE_PATH)) return null;
2952
+ const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
2917
2953
  return typeof raw.token === "string" ? raw.token : null;
2918
2954
  } catch {
2919
2955
  return null;
@@ -2947,7 +2983,7 @@ function getRawCachedPlan() {
2947
2983
  }
2948
2984
  function cacheResponse(token) {
2949
2985
  try {
2950
- writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
2986
+ writeFileSync4(CACHE_PATH, JSON.stringify({ token }), "utf8");
2951
2987
  } catch {
2952
2988
  }
2953
2989
  }
@@ -3011,9 +3047,9 @@ async function checkLicense() {
3011
3047
  let key = loadLicense();
3012
3048
  if (!key) {
3013
3049
  try {
3014
- const configPath = path9.join(EXE_AI_DIR, "config.json");
3015
- if (existsSync8(configPath)) {
3016
- const raw = JSON.parse(readFileSync6(configPath, "utf8"));
3050
+ const configPath = path10.join(EXE_AI_DIR, "config.json");
3051
+ if (existsSync9(configPath)) {
3052
+ const raw = JSON.parse(readFileSync7(configPath, "utf8"));
3017
3053
  const cloud = raw.cloud;
3018
3054
  if (cloud?.apiKey) {
3019
3055
  key = cloud.apiKey;
@@ -3172,9 +3208,9 @@ var init_license = __esm({
3172
3208
  "src/lib/license.ts"() {
3173
3209
  "use strict";
3174
3210
  init_config();
3175
- LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3176
- CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3177
- DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
3211
+ LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
3212
+ CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
3213
+ DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
3178
3214
  API_BASE = "https://askexe.com/cloud";
3179
3215
  RETRY_DELAY_MS = 500;
3180
3216
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -3214,12 +3250,12 @@ __export(plan_limits_exports, {
3214
3250
  countActiveMemories: () => countActiveMemories,
3215
3251
  getLicenseSync: () => getLicenseSync
3216
3252
  });
3217
- import { readFileSync as readFileSync7, existsSync as existsSync9 } from "fs";
3218
- import path10 from "path";
3253
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
3254
+ import path11 from "path";
3219
3255
  function getLicenseSync() {
3220
3256
  try {
3221
- if (!existsSync9(CACHE_PATH2)) return freeLicense();
3222
- const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
3257
+ if (!existsSync10(CACHE_PATH2)) return freeLicense();
3258
+ const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
3223
3259
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
3224
3260
  const parts = raw.token.split(".");
3225
3261
  if (parts.length !== 3) return freeLicense();
@@ -3286,8 +3322,8 @@ function assertEmployeeLimitSync(rosterPath) {
3286
3322
  const filePath = rosterPath ?? EMPLOYEES_PATH;
3287
3323
  let count = 0;
3288
3324
  try {
3289
- if (existsSync9(filePath)) {
3290
- const raw = readFileSync7(filePath, "utf8");
3325
+ if (existsSync10(filePath)) {
3326
+ const raw = readFileSync8(filePath, "utf8");
3291
3327
  const employees = JSON.parse(raw);
3292
3328
  count = Array.isArray(employees) ? employees.length : 0;
3293
3329
  }
@@ -3324,13 +3360,13 @@ var init_plan_limits = __esm({
3324
3360
  this.name = "PlanLimitError";
3325
3361
  }
3326
3362
  };
3327
- CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
3363
+ CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
3328
3364
  }
3329
3365
  });
3330
3366
 
3331
3367
  // src/lib/tmux-routing.ts
3332
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync10, appendFileSync } from "fs";
3333
- import path11 from "path";
3368
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
3369
+ import path12 from "path";
3334
3370
  import os7 from "os";
3335
3371
  import { fileURLToPath as fileURLToPath2 } from "url";
3336
3372
  function getMySession() {
@@ -3344,7 +3380,7 @@ function extractRootExe(name) {
3344
3380
  }
3345
3381
  function getParentExe(sessionKey) {
3346
3382
  try {
3347
- const data = JSON.parse(readFileSync8(path11.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3383
+ const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
3348
3384
  return data.parentExe || null;
3349
3385
  } catch {
3350
3386
  return null;
@@ -3373,13 +3409,15 @@ var init_tmux_routing = __esm({
3373
3409
  init_cc_agent_support();
3374
3410
  init_mcp_prefix();
3375
3411
  init_provider_table();
3412
+ init_agent_config();
3413
+ init_runtime_table();
3376
3414
  init_intercom_queue();
3377
3415
  init_plan_limits();
3378
3416
  init_employees();
3379
- SPAWN_LOCK_DIR = path11.join(os7.homedir(), ".exe-os", "spawn-locks");
3380
- SESSION_CACHE = path11.join(os7.homedir(), ".exe-os", "session-cache");
3381
- INTERCOM_LOG2 = path11.join(os7.homedir(), ".exe-os", "intercom.log");
3382
- DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
3417
+ SPAWN_LOCK_DIR = path12.join(os7.homedir(), ".exe-os", "spawn-locks");
3418
+ SESSION_CACHE = path12.join(os7.homedir(), ".exe-os", "session-cache");
3419
+ INTERCOM_LOG2 = path12.join(os7.homedir(), ".exe-os", "intercom.log");
3420
+ DEBOUNCE_FILE = path12.join(SESSION_CACHE, "intercom-debounce.json");
3383
3421
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
3384
3422
  }
3385
3423
  });
@@ -3445,10 +3483,10 @@ async function disposeEmbedder() {
3445
3483
  async function embedDirect(text) {
3446
3484
  const llamaCpp = await import("node-llama-cpp");
3447
3485
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
3448
- const { existsSync: existsSync15 } = await import("fs");
3449
- const path16 = await import("path");
3450
- const modelPath = path16.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
3451
- if (!existsSync15(modelPath)) {
3486
+ const { existsSync: existsSync16 } = await import("fs");
3487
+ const path17 = await import("path");
3488
+ const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
3489
+ if (!existsSync16(modelPath)) {
3452
3490
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
3453
3491
  }
3454
3492
  const llama = await llamaCpp.getLlama();
@@ -3486,14 +3524,14 @@ __export(worker_gate_exports, {
3486
3524
  tryAcquireBackfillLock: () => tryAcquireBackfillLock,
3487
3525
  tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
3488
3526
  });
3489
- import { readdirSync as readdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, mkdirSync as mkdirSync5, existsSync as existsSync11 } from "fs";
3490
- import path12 from "path";
3527
+ import { readdirSync as readdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6, existsSync as existsSync12 } from "fs";
3528
+ import path13 from "path";
3491
3529
  function tryAcquireWorkerSlot() {
3492
3530
  try {
3493
- mkdirSync5(WORKER_PID_DIR, { recursive: true });
3531
+ mkdirSync6(WORKER_PID_DIR, { recursive: true });
3494
3532
  const reservationId = `res-${process.pid}-${Date.now()}`;
3495
- const reservationPath = path12.join(WORKER_PID_DIR, `${reservationId}.pid`);
3496
- writeFileSync5(reservationPath, String(process.pid));
3533
+ const reservationPath = path13.join(WORKER_PID_DIR, `${reservationId}.pid`);
3534
+ writeFileSync6(reservationPath, String(process.pid));
3497
3535
  const files = readdirSync3(WORKER_PID_DIR);
3498
3536
  let alive = 0;
3499
3537
  for (const f of files) {
@@ -3510,7 +3548,7 @@ function tryAcquireWorkerSlot() {
3510
3548
  alive++;
3511
3549
  } catch {
3512
3550
  try {
3513
- unlinkSync4(path12.join(WORKER_PID_DIR, f));
3551
+ unlinkSync4(path13.join(WORKER_PID_DIR, f));
3514
3552
  } catch {
3515
3553
  }
3516
3554
  }
@@ -3533,21 +3571,21 @@ function tryAcquireWorkerSlot() {
3533
3571
  }
3534
3572
  function registerWorkerPid(pid) {
3535
3573
  try {
3536
- mkdirSync5(WORKER_PID_DIR, { recursive: true });
3537
- writeFileSync5(path12.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
3574
+ mkdirSync6(WORKER_PID_DIR, { recursive: true });
3575
+ writeFileSync6(path13.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
3538
3576
  } catch {
3539
3577
  }
3540
3578
  }
3541
3579
  function cleanupWorkerPid() {
3542
3580
  try {
3543
- unlinkSync4(path12.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
3581
+ unlinkSync4(path13.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
3544
3582
  } catch {
3545
3583
  }
3546
3584
  }
3547
3585
  function tryAcquireBackfillLock() {
3548
3586
  try {
3549
- mkdirSync5(WORKER_PID_DIR, { recursive: true });
3550
- if (existsSync11(BACKFILL_LOCK)) {
3587
+ mkdirSync6(WORKER_PID_DIR, { recursive: true });
3588
+ if (existsSync12(BACKFILL_LOCK)) {
3551
3589
  try {
3552
3590
  const pid = parseInt(
3553
3591
  __require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
@@ -3563,7 +3601,7 @@ function tryAcquireBackfillLock() {
3563
3601
  } catch {
3564
3602
  }
3565
3603
  }
3566
- writeFileSync5(BACKFILL_LOCK, String(process.pid));
3604
+ writeFileSync6(BACKFILL_LOCK, String(process.pid));
3567
3605
  return true;
3568
3606
  } catch {
3569
3607
  return true;
@@ -3580,9 +3618,9 @@ var init_worker_gate = __esm({
3580
3618
  "src/lib/worker-gate.ts"() {
3581
3619
  "use strict";
3582
3620
  init_config();
3583
- WORKER_PID_DIR = path12.join(EXE_AI_DIR, "worker-pids");
3621
+ WORKER_PID_DIR = path13.join(EXE_AI_DIR, "worker-pids");
3584
3622
  MAX_CONCURRENT_WORKERS = 3;
3585
- BACKFILL_LOCK = path12.join(WORKER_PID_DIR, "backfill.lock");
3623
+ BACKFILL_LOCK = path13.join(WORKER_PID_DIR, "backfill.lock");
3586
3624
  }
3587
3625
  });
3588
3626
 
@@ -3684,8 +3722,8 @@ __export(crdt_sync_exports, {
3684
3722
  rebuildFromDb: () => rebuildFromDb
3685
3723
  });
3686
3724
  import * as Y from "yjs";
3687
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
3688
- import path13 from "path";
3725
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync13, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
3726
+ import path14 from "path";
3689
3727
  import { homedir } from "os";
3690
3728
  function getStatePath() {
3691
3729
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -3697,9 +3735,9 @@ function initCrdtDoc() {
3697
3735
  if (doc) return doc;
3698
3736
  doc = new Y.Doc();
3699
3737
  const sp = getStatePath();
3700
- if (existsSync12(sp)) {
3738
+ if (existsSync13(sp)) {
3701
3739
  try {
3702
- const state = readFileSync9(sp);
3740
+ const state = readFileSync10(sp);
3703
3741
  Y.applyUpdate(doc, new Uint8Array(state));
3704
3742
  } catch {
3705
3743
  console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
@@ -3841,10 +3879,10 @@ function persistState() {
3841
3879
  if (!doc) return;
3842
3880
  try {
3843
3881
  const sp = getStatePath();
3844
- const dir = path13.dirname(sp);
3845
- if (!existsSync12(dir)) mkdirSync6(dir, { recursive: true });
3882
+ const dir = path14.dirname(sp);
3883
+ if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
3846
3884
  const state = Y.encodeStateAsUpdate(doc);
3847
- writeFileSync6(sp, Buffer.from(state));
3885
+ writeFileSync7(sp, Buffer.from(state));
3848
3886
  } catch {
3849
3887
  }
3850
3888
  }
@@ -3885,7 +3923,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
3885
3923
  var init_crdt_sync = __esm({
3886
3924
  "src/lib/crdt-sync.ts"() {
3887
3925
  "use strict";
3888
- DEFAULT_STATE_PATH = path13.join(homedir(), ".exe-os", "crdt-state.bin");
3926
+ DEFAULT_STATE_PATH = path14.join(homedir(), ".exe-os", "crdt-state.bin");
3889
3927
  _statePathOverride = null;
3890
3928
  doc = null;
3891
3929
  }
@@ -3919,16 +3957,16 @@ __export(cloud_sync_exports, {
3919
3957
  mergeRosterFromRemote: () => mergeRosterFromRemote,
3920
3958
  recordRosterDeletion: () => recordRosterDeletion
3921
3959
  });
3922
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync13, readdirSync as readdirSync4, mkdirSync as mkdirSync7, appendFileSync as appendFileSync2, unlinkSync as unlinkSync6, openSync as openSync2, closeSync as closeSync2 } from "fs";
3960
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync14, readdirSync as readdirSync4, mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, unlinkSync as unlinkSync6, openSync as openSync2, closeSync as closeSync2 } from "fs";
3923
3961
  import crypto3 from "crypto";
3924
- import path14 from "path";
3962
+ import path15 from "path";
3925
3963
  import { homedir as homedir2 } from "os";
3926
3964
  function sqlSafe(v) {
3927
3965
  return v === void 0 ? null : v;
3928
3966
  }
3929
3967
  function logError(msg) {
3930
3968
  try {
3931
- const logPath = path14.join(homedir2(), ".exe-os", "workers.log");
3969
+ const logPath = path15.join(homedir2(), ".exe-os", "workers.log");
3932
3970
  appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
3933
3971
  `);
3934
3972
  } catch {
@@ -3938,18 +3976,18 @@ async function withRosterLock(fn) {
3938
3976
  try {
3939
3977
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3940
3978
  closeSync2(fd);
3941
- writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
3979
+ writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
3942
3980
  } catch (err) {
3943
3981
  if (err.code === "EEXIST") {
3944
3982
  try {
3945
- const ts = parseInt(readFileSync10(ROSTER_LOCK_PATH, "utf-8"), 10);
3983
+ const ts = parseInt(readFileSync11(ROSTER_LOCK_PATH, "utf-8"), 10);
3946
3984
  if (Date.now() - ts < LOCK_STALE_MS) {
3947
3985
  throw new Error("Roster merge already in progress \u2014 another sync is running");
3948
3986
  }
3949
3987
  unlinkSync6(ROSTER_LOCK_PATH);
3950
3988
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
3951
3989
  closeSync2(fd);
3952
- writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
3990
+ writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
3953
3991
  } catch (retryErr) {
3954
3992
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
3955
3993
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -4323,8 +4361,8 @@ async function cloudSync(config) {
4323
4361
  try {
4324
4362
  const employees = await loadEmployees();
4325
4363
  rosterResult.employees = employees.length;
4326
- const idDir = path14.join(EXE_AI_DIR, "identity");
4327
- if (existsSync13(idDir)) {
4364
+ const idDir = path15.join(EXE_AI_DIR, "identity");
4365
+ if (existsSync14(idDir)) {
4328
4366
  rosterResult.identities = readdirSync4(idDir).filter((f) => f.endsWith(".md")).length;
4329
4367
  }
4330
4368
  } catch {
@@ -4345,55 +4383,63 @@ async function cloudSync(config) {
4345
4383
  function recordRosterDeletion(name) {
4346
4384
  let deletions = [];
4347
4385
  try {
4348
- if (existsSync13(ROSTER_DELETIONS_PATH)) {
4349
- deletions = JSON.parse(readFileSync10(ROSTER_DELETIONS_PATH, "utf-8"));
4386
+ if (existsSync14(ROSTER_DELETIONS_PATH)) {
4387
+ deletions = JSON.parse(readFileSync11(ROSTER_DELETIONS_PATH, "utf-8"));
4350
4388
  }
4351
4389
  } catch {
4352
4390
  }
4353
4391
  if (!deletions.includes(name)) deletions.push(name);
4354
- writeFileSync7(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
4392
+ writeFileSync8(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
4355
4393
  }
4356
4394
  function consumeRosterDeletions() {
4357
4395
  try {
4358
- if (!existsSync13(ROSTER_DELETIONS_PATH)) return [];
4359
- const deletions = JSON.parse(readFileSync10(ROSTER_DELETIONS_PATH, "utf-8"));
4360
- writeFileSync7(ROSTER_DELETIONS_PATH, "[]");
4396
+ if (!existsSync14(ROSTER_DELETIONS_PATH)) return [];
4397
+ const deletions = JSON.parse(readFileSync11(ROSTER_DELETIONS_PATH, "utf-8"));
4398
+ writeFileSync8(ROSTER_DELETIONS_PATH, "[]");
4361
4399
  return deletions;
4362
4400
  } catch {
4363
4401
  return [];
4364
4402
  }
4365
4403
  }
4366
4404
  function buildRosterBlob(paths) {
4367
- const rosterPath = paths?.rosterPath ?? path14.join(EXE_AI_DIR, "exe-employees.json");
4368
- const identityDir = paths?.identityDir ?? path14.join(EXE_AI_DIR, "identity");
4369
- const configPath = paths?.configPath ?? path14.join(EXE_AI_DIR, "config.json");
4405
+ const rosterPath = paths?.rosterPath ?? path15.join(EXE_AI_DIR, "exe-employees.json");
4406
+ const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
4407
+ const configPath = paths?.configPath ?? path15.join(EXE_AI_DIR, "config.json");
4370
4408
  let roster = [];
4371
- if (existsSync13(rosterPath)) {
4409
+ if (existsSync14(rosterPath)) {
4372
4410
  try {
4373
- roster = JSON.parse(readFileSync10(rosterPath, "utf-8"));
4411
+ roster = JSON.parse(readFileSync11(rosterPath, "utf-8"));
4374
4412
  } catch {
4375
4413
  }
4376
4414
  }
4377
4415
  const identities = {};
4378
- if (existsSync13(identityDir)) {
4416
+ if (existsSync14(identityDir)) {
4379
4417
  for (const file of readdirSync4(identityDir).filter((f) => f.endsWith(".md"))) {
4380
4418
  try {
4381
- identities[file] = readFileSync10(path14.join(identityDir, file), "utf-8");
4419
+ identities[file] = readFileSync11(path15.join(identityDir, file), "utf-8");
4382
4420
  } catch {
4383
4421
  }
4384
4422
  }
4385
4423
  }
4386
4424
  let config;
4387
- if (existsSync13(configPath)) {
4425
+ if (existsSync14(configPath)) {
4426
+ try {
4427
+ config = JSON.parse(readFileSync11(configPath, "utf-8"));
4428
+ } catch {
4429
+ }
4430
+ }
4431
+ let agentConfig;
4432
+ const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
4433
+ if (existsSync14(agentConfigPath)) {
4388
4434
  try {
4389
- config = JSON.parse(readFileSync10(configPath, "utf-8"));
4435
+ agentConfig = JSON.parse(readFileSync11(agentConfigPath, "utf-8"));
4390
4436
  } catch {
4391
4437
  }
4392
4438
  }
4393
4439
  const deletedNames = consumeRosterDeletions();
4394
- const content = JSON.stringify({ roster, identities, config, deletedNames });
4440
+ const content = JSON.stringify({ roster, identities, config, agentConfig, deletedNames });
4395
4441
  const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
4396
- return { roster, identities, config, deletedNames, version: hash };
4442
+ return { roster, identities, config, agentConfig, deletedNames, version: hash };
4397
4443
  }
4398
4444
  async function cloudPushRoster(config) {
4399
4445
  assertSecureEndpoint(config.endpoint);
@@ -4462,23 +4508,23 @@ async function cloudPullRoster(config) {
4462
4508
  }
4463
4509
  }
4464
4510
  function mergeConfig(remoteConfig, configPath) {
4465
- const cfgPath = configPath ?? path14.join(EXE_AI_DIR, "config.json");
4511
+ const cfgPath = configPath ?? path15.join(EXE_AI_DIR, "config.json");
4466
4512
  let local = {};
4467
- if (existsSync13(cfgPath)) {
4513
+ if (existsSync14(cfgPath)) {
4468
4514
  try {
4469
- local = JSON.parse(readFileSync10(cfgPath, "utf-8"));
4515
+ local = JSON.parse(readFileSync11(cfgPath, "utf-8"));
4470
4516
  } catch {
4471
4517
  }
4472
4518
  }
4473
4519
  const merged = { ...remoteConfig, ...local };
4474
- const dir = path14.dirname(cfgPath);
4475
- if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
4476
- writeFileSync7(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4520
+ const dir = path15.dirname(cfgPath);
4521
+ if (!existsSync14(dir)) mkdirSync8(dir, { recursive: true });
4522
+ writeFileSync8(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
4477
4523
  }
4478
4524
  async function mergeRosterFromRemote(remote, paths) {
4479
4525
  return withRosterLock(async () => {
4480
4526
  const rosterPath = paths?.rosterPath ?? void 0;
4481
- const identityDir = paths?.identityDir ?? path14.join(EXE_AI_DIR, "identity");
4527
+ const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
4482
4528
  const localEmployees = await loadEmployees(rosterPath);
4483
4529
  const localNames = new Set(localEmployees.map((e) => e.name));
4484
4530
  let added = 0;
@@ -4499,15 +4545,15 @@ async function mergeRosterFromRemote(remote, paths) {
4499
4545
  ) ?? lookupKey;
4500
4546
  const remoteIdentity = remote.identities[matchedKey];
4501
4547
  if (remoteIdentity) {
4502
- if (!existsSync13(identityDir)) mkdirSync7(identityDir, { recursive: true });
4503
- const idPath = path14.join(identityDir, `${remoteEmp.name}.md`);
4548
+ if (!existsSync14(identityDir)) mkdirSync8(identityDir, { recursive: true });
4549
+ const idPath = path15.join(identityDir, `${remoteEmp.name}.md`);
4504
4550
  let localIdentity = null;
4505
4551
  try {
4506
- localIdentity = existsSync13(idPath) ? readFileSync10(idPath, "utf-8") : null;
4552
+ localIdentity = existsSync14(idPath) ? readFileSync11(idPath, "utf-8") : null;
4507
4553
  } catch {
4508
4554
  }
4509
4555
  if (localIdentity !== remoteIdentity) {
4510
- writeFileSync7(idPath, remoteIdentity, "utf-8");
4556
+ writeFileSync8(idPath, remoteIdentity, "utf-8");
4511
4557
  identitiesUpdated++;
4512
4558
  }
4513
4559
  }
@@ -4531,6 +4577,21 @@ async function mergeRosterFromRemote(remote, paths) {
4531
4577
  } catch {
4532
4578
  }
4533
4579
  }
4580
+ if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
4581
+ try {
4582
+ const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
4583
+ let local = {};
4584
+ if (existsSync14(agentConfigPath)) {
4585
+ try {
4586
+ local = JSON.parse(readFileSync11(agentConfigPath, "utf-8"));
4587
+ } catch {
4588
+ }
4589
+ }
4590
+ const merged = { ...remote.agentConfig, ...local };
4591
+ writeFileSync8(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
4592
+ } catch {
4593
+ }
4594
+ }
4534
4595
  return { added, identitiesUpdated };
4535
4596
  });
4536
4597
  }
@@ -4965,9 +5026,9 @@ var init_cloud_sync = __esm({
4965
5026
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
4966
5027
  FETCH_TIMEOUT_MS = 3e4;
4967
5028
  PUSH_BATCH_SIZE = 5e3;
4968
- ROSTER_LOCK_PATH = path14.join(EXE_AI_DIR, "roster-merge.lock");
5029
+ ROSTER_LOCK_PATH = path15.join(EXE_AI_DIR, "roster-merge.lock");
4969
5030
  LOCK_STALE_MS = 3e4;
4970
- ROSTER_DELETIONS_PATH = path14.join(EXE_AI_DIR, "roster-deletions.json");
5031
+ ROSTER_DELETIONS_PATH = path15.join(EXE_AI_DIR, "roster-deletions.json");
4971
5032
  }
4972
5033
  });
4973
5034
 
@@ -5334,8 +5395,8 @@ init_task_scope();
5334
5395
  init_employees();
5335
5396
  import crypto4 from "crypto";
5336
5397
  import { execSync as execSync4 } from "child_process";
5337
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, openSync as openSync3, closeSync as closeSync3 } from "fs";
5338
- import path15 from "path";
5398
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync3, closeSync as closeSync3 } from "fs";
5399
+ import path16 from "path";
5339
5400
  async function main() {
5340
5401
  const agentId = process.env.AGENT_ID ?? "default";
5341
5402
  const agentRole = process.env.AGENT_ROLE ?? "employee";
@@ -5470,8 +5531,8 @@ async function main() {
5470
5531
  }
5471
5532
  try {
5472
5533
  const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5473
- const flagPath = path15.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
5474
- if (existsSync14(flagPath)) {
5534
+ const flagPath = path16.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
5535
+ if (existsSync15(flagPath)) {
5475
5536
  const { tryAcquireWorkerSlot: tryAcquireWorkerSlot2, registerWorkerPid: registerWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
5476
5537
  if (!tryAcquireWorkerSlot2()) {
5477
5538
  process.stderr.write("[summary-worker] Backfill needed but worker gate full \u2014 skipping\n");
@@ -5479,11 +5540,11 @@ async function main() {
5479
5540
  const { spawn: spawn2 } = await import("child_process");
5480
5541
  const { fileURLToPath: fileURLToPath3 } = await import("url");
5481
5542
  const thisFile = fileURLToPath3(import.meta.url);
5482
- const backfillPath = path15.resolve(path15.dirname(thisFile), "backfill-vectors.js");
5483
- if (existsSync14(backfillPath)) {
5543
+ const backfillPath = path16.resolve(path16.dirname(thisFile), "backfill-vectors.js");
5544
+ if (existsSync15(backfillPath)) {
5484
5545
  const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5485
- const bLogPath = path15.join(exeDir2, "workers.log");
5486
- mkdirSync8(path15.dirname(bLogPath), { recursive: true });
5546
+ const bLogPath = path16.join(exeDir2, "workers.log");
5547
+ mkdirSync9(path16.dirname(bLogPath), { recursive: true });
5487
5548
  const bLogFd = openSync3(bLogPath, "a");
5488
5549
  const child = spawn2(process.execPath, [backfillPath], {
5489
5550
  detached: true,