@askexenow/exe-os 0.8.85 → 0.8.87

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 +510 -340
  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 +50 -5
  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
@@ -3287,18 +3287,69 @@ var init_provider_table = __esm({
3287
3287
  }
3288
3288
  });
3289
3289
 
3290
- // src/lib/intercom-queue.ts
3291
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
3290
+ // src/lib/runtime-table.ts
3291
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
3292
+ var init_runtime_table = __esm({
3293
+ "src/lib/runtime-table.ts"() {
3294
+ "use strict";
3295
+ RUNTIME_TABLE = {
3296
+ codex: {
3297
+ binary: "codex",
3298
+ launchMode: "exec",
3299
+ autoApproveFlag: "--full-auto",
3300
+ inlineFlag: "--no-alt-screen",
3301
+ apiKeyEnv: "OPENAI_API_KEY",
3302
+ defaultModel: "gpt-5.4"
3303
+ }
3304
+ };
3305
+ DEFAULT_RUNTIME = "claude";
3306
+ }
3307
+ });
3308
+
3309
+ // src/lib/agent-config.ts
3310
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
3292
3311
  import path7 from "path";
3312
+ function loadAgentConfig() {
3313
+ if (!existsSync7(AGENT_CONFIG_PATH)) return {};
3314
+ try {
3315
+ return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
3316
+ } catch {
3317
+ return {};
3318
+ }
3319
+ }
3320
+ function getAgentRuntime(agentId) {
3321
+ const config = loadAgentConfig();
3322
+ const entry = config[agentId];
3323
+ if (entry) return entry;
3324
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
3325
+ }
3326
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
3327
+ var init_agent_config = __esm({
3328
+ "src/lib/agent-config.ts"() {
3329
+ "use strict";
3330
+ init_config();
3331
+ init_runtime_table();
3332
+ AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
3333
+ DEFAULT_MODELS = {
3334
+ claude: "claude-opus-4",
3335
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
3336
+ opencode: "minimax-m2.7"
3337
+ };
3338
+ }
3339
+ });
3340
+
3341
+ // src/lib/intercom-queue.ts
3342
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
3343
+ import path8 from "path";
3293
3344
  import os5 from "os";
3294
3345
  function ensureDir() {
3295
- const dir = path7.dirname(QUEUE_PATH);
3296
- if (!existsSync7(dir)) mkdirSync3(dir, { recursive: true });
3346
+ const dir = path8.dirname(QUEUE_PATH);
3347
+ if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
3297
3348
  }
3298
3349
  function readQueue() {
3299
3350
  try {
3300
- if (!existsSync7(QUEUE_PATH)) return [];
3301
- return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
3351
+ if (!existsSync8(QUEUE_PATH)) return [];
3352
+ return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
3302
3353
  } catch {
3303
3354
  return [];
3304
3355
  }
@@ -3306,7 +3357,7 @@ function readQueue() {
3306
3357
  function writeQueue(queue) {
3307
3358
  ensureDir();
3308
3359
  const tmp = `${QUEUE_PATH}.tmp`;
3309
- writeFileSync3(tmp, JSON.stringify(queue, null, 2));
3360
+ writeFileSync4(tmp, JSON.stringify(queue, null, 2));
3310
3361
  renameSync3(tmp, QUEUE_PATH);
3311
3362
  }
3312
3363
  function queueIntercom(targetSession, reason) {
@@ -3330,25 +3381,25 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
3330
3381
  var init_intercom_queue = __esm({
3331
3382
  "src/lib/intercom-queue.ts"() {
3332
3383
  "use strict";
3333
- QUEUE_PATH = path7.join(os5.homedir(), ".exe-os", "intercom-queue.json");
3384
+ QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
3334
3385
  TTL_MS = 60 * 60 * 1e3;
3335
- INTERCOM_LOG = path7.join(os5.homedir(), ".exe-os", "intercom.log");
3386
+ INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
3336
3387
  }
3337
3388
  });
3338
3389
 
3339
3390
  // src/lib/license.ts
3340
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
3391
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
3341
3392
  import { randomUUID as randomUUID3 } from "crypto";
3342
- import path8 from "path";
3393
+ import path9 from "path";
3343
3394
  import { jwtVerify, importSPKI } from "jose";
3344
3395
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
3345
3396
  var init_license = __esm({
3346
3397
  "src/lib/license.ts"() {
3347
3398
  "use strict";
3348
3399
  init_config();
3349
- LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
3350
- CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
3351
- DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
3400
+ LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3401
+ CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3402
+ DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
3352
3403
  PLAN_LIMITS = {
3353
3404
  free: { devices: 1, employees: 1, memories: 5e3 },
3354
3405
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -3360,12 +3411,12 @@ var init_license = __esm({
3360
3411
  });
3361
3412
 
3362
3413
  // src/lib/plan-limits.ts
3363
- import { readFileSync as readFileSync7, existsSync as existsSync9 } from "fs";
3364
- import path9 from "path";
3414
+ import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
3415
+ import path10 from "path";
3365
3416
  function getLicenseSync() {
3366
3417
  try {
3367
- if (!existsSync9(CACHE_PATH2)) return freeLicense();
3368
- const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
3418
+ if (!existsSync10(CACHE_PATH2)) return freeLicense();
3419
+ const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
3369
3420
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
3370
3421
  const parts = raw.token.split(".");
3371
3422
  if (parts.length !== 3) return freeLicense();
@@ -3403,8 +3454,8 @@ function assertEmployeeLimitSync(rosterPath) {
3403
3454
  const filePath = rosterPath ?? EMPLOYEES_PATH;
3404
3455
  let count = 0;
3405
3456
  try {
3406
- if (existsSync9(filePath)) {
3407
- const raw = readFileSync7(filePath, "utf8");
3457
+ if (existsSync10(filePath)) {
3458
+ const raw = readFileSync8(filePath, "utf8");
3408
3459
  const employees = JSON.parse(raw);
3409
3460
  count = Array.isArray(employees) ? employees.length : 0;
3410
3461
  }
@@ -3433,19 +3484,19 @@ var init_plan_limits = __esm({
3433
3484
  this.name = "PlanLimitError";
3434
3485
  }
3435
3486
  };
3436
- CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
3487
+ CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
3437
3488
  }
3438
3489
  });
3439
3490
 
3440
3491
  // src/lib/notifications.ts
3441
3492
  import crypto from "crypto";
3442
- import path10 from "path";
3493
+ import path11 from "path";
3443
3494
  import os6 from "os";
3444
3495
  import {
3445
- readFileSync as readFileSync8,
3496
+ readFileSync as readFileSync9,
3446
3497
  readdirSync as readdirSync2,
3447
3498
  unlinkSync as unlinkSync3,
3448
- existsSync as existsSync10,
3499
+ existsSync as existsSync11,
3449
3500
  rmdirSync
3450
3501
  } from "fs";
3451
3502
  async function writeNotification(notification) {
@@ -3541,11 +3592,11 @@ __export(tasks_crud_exports, {
3541
3592
  writeCheckpoint: () => writeCheckpoint
3542
3593
  });
3543
3594
  import crypto3 from "crypto";
3544
- import path11 from "path";
3595
+ import path12 from "path";
3545
3596
  import os7 from "os";
3546
3597
  import { execSync as execSync4 } from "child_process";
3547
3598
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
3548
- import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
3599
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
3549
3600
  async function writeCheckpoint(input) {
3550
3601
  const client = getClient();
3551
3602
  const row = await resolveTask(client, input.taskId);
@@ -3720,8 +3771,8 @@ ${laneWarning}` : laneWarning;
3720
3771
  }
3721
3772
  if (input.baseDir) {
3722
3773
  try {
3723
- await mkdir4(path11.join(input.baseDir, "exe", "output"), { recursive: true });
3724
- await mkdir4(path11.join(input.baseDir, "exe", "research"), { recursive: true });
3774
+ await mkdir4(path12.join(input.baseDir, "exe", "output"), { recursive: true });
3775
+ await mkdir4(path12.join(input.baseDir, "exe", "research"), { recursive: true });
3725
3776
  await ensureArchitectureDoc(input.baseDir, input.projectName);
3726
3777
  await ensureGitignoreExe(input.baseDir);
3727
3778
  } catch {
@@ -3757,10 +3808,10 @@ ${laneWarning}` : laneWarning;
3757
3808
  });
3758
3809
  if (input.baseDir) {
3759
3810
  try {
3760
- const EXE_OS_DIR = path11.join(os7.homedir(), ".exe-os");
3761
- const mdPath = path11.join(EXE_OS_DIR, taskFile);
3762
- const mdDir = path11.dirname(mdPath);
3763
- if (!existsSync11(mdDir)) await mkdir4(mdDir, { recursive: true });
3811
+ const EXE_OS_DIR = path12.join(os7.homedir(), ".exe-os");
3812
+ const mdPath = path12.join(EXE_OS_DIR, taskFile);
3813
+ const mdDir = path12.dirname(mdPath);
3814
+ if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
3764
3815
  const reviewer = input.reviewer ?? input.assignedBy;
3765
3816
  const mdContent = `# ${input.title}
3766
3817
 
@@ -3785,7 +3836,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
3785
3836
  Do NOT let a failed commit or any error prevent you from calling update_task(done).
3786
3837
  `;
3787
3838
  await writeFile4(mdPath, mdContent, "utf-8");
3788
- } catch {
3839
+ } catch (err) {
3840
+ process.stderr.write(
3841
+ `[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
3842
+ `
3843
+ );
3789
3844
  }
3790
3845
  }
3791
3846
  return {
@@ -4045,9 +4100,9 @@ async function deleteTaskCore(taskId, _baseDir) {
4045
4100
  return { taskFile, assignedTo, assignedBy, taskSlug };
4046
4101
  }
4047
4102
  async function ensureArchitectureDoc(baseDir, projectName) {
4048
- const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
4103
+ const archPath = path12.join(baseDir, "exe", "ARCHITECTURE.md");
4049
4104
  try {
4050
- if (existsSync11(archPath)) return;
4105
+ if (existsSync12(archPath)) return;
4051
4106
  const template = [
4052
4107
  `# ${projectName} \u2014 System Architecture`,
4053
4108
  "",
@@ -4080,10 +4135,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
4080
4135
  }
4081
4136
  }
4082
4137
  async function ensureGitignoreExe(baseDir) {
4083
- const gitignorePath = path11.join(baseDir, ".gitignore");
4138
+ const gitignorePath = path12.join(baseDir, ".gitignore");
4084
4139
  try {
4085
- if (existsSync11(gitignorePath)) {
4086
- const content = readFileSync9(gitignorePath, "utf-8");
4140
+ if (existsSync12(gitignorePath)) {
4141
+ const content = readFileSync10(gitignorePath, "utf-8");
4087
4142
  if (/^\/?exe\/?$/m.test(content)) return;
4088
4143
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
4089
4144
  } else {
@@ -4124,8 +4179,8 @@ __export(tasks_review_exports, {
4124
4179
  getReviewChecklist: () => getReviewChecklist,
4125
4180
  listPendingReviews: () => listPendingReviews
4126
4181
  });
4127
- import path12 from "path";
4128
- import { existsSync as existsSync12, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
4182
+ import path13 from "path";
4183
+ import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
4129
4184
  async function countPendingReviews(sessionScope) {
4130
4185
  const client = getClient();
4131
4186
  if (sessionScope) {
@@ -4395,11 +4450,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
4395
4450
  );
4396
4451
  }
4397
4452
  try {
4398
- const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
4399
- if (existsSync12(cacheDir)) {
4453
+ const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
4454
+ if (existsSync13(cacheDir)) {
4400
4455
  for (const f of readdirSync3(cacheDir)) {
4401
4456
  if (f.startsWith("review-notified-")) {
4402
- unlinkSync4(path12.join(cacheDir, f));
4457
+ unlinkSync4(path13.join(cacheDir, f));
4403
4458
  }
4404
4459
  }
4405
4460
  }
@@ -4420,7 +4475,7 @@ var init_tasks_review = __esm({
4420
4475
  });
4421
4476
 
4422
4477
  // src/lib/tasks-chain.ts
4423
- import path13 from "path";
4478
+ import path14 from "path";
4424
4479
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
4425
4480
  async function cascadeUnblock(taskId, baseDir, now) {
4426
4481
  const client = getClient();
@@ -4437,7 +4492,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
4437
4492
  });
4438
4493
  for (const ur of unblockedRows.rows) {
4439
4494
  try {
4440
- const ubFile = path13.join(baseDir, String(ur.task_file));
4495
+ const ubFile = path14.join(baseDir, String(ur.task_file));
4441
4496
  let ubContent = await readFile4(ubFile, "utf-8");
4442
4497
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
4443
4498
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -4506,7 +4561,7 @@ var init_tasks_chain = __esm({
4506
4561
 
4507
4562
  // src/lib/project-name.ts
4508
4563
  import { execSync as execSync5 } from "child_process";
4509
- import path14 from "path";
4564
+ import path15 from "path";
4510
4565
  function getProjectName(cwd) {
4511
4566
  const dir = cwd ?? process.cwd();
4512
4567
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -4519,7 +4574,7 @@ function getProjectName(cwd) {
4519
4574
  timeout: 2e3,
4520
4575
  stdio: ["pipe", "pipe", "pipe"]
4521
4576
  }).trim();
4522
- repoRoot = path14.dirname(gitCommonDir);
4577
+ repoRoot = path15.dirname(gitCommonDir);
4523
4578
  } catch {
4524
4579
  repoRoot = execSync5("git rev-parse --show-toplevel", {
4525
4580
  cwd: dir,
@@ -4528,11 +4583,11 @@ function getProjectName(cwd) {
4528
4583
  stdio: ["pipe", "pipe", "pipe"]
4529
4584
  }).trim();
4530
4585
  }
4531
- _cached2 = path14.basename(repoRoot);
4586
+ _cached2 = path15.basename(repoRoot);
4532
4587
  _cachedCwd = dir;
4533
4588
  return _cached2;
4534
4589
  } catch {
4535
- _cached2 = path14.basename(dir);
4590
+ _cached2 = path15.basename(dir);
4536
4591
  _cachedCwd = dir;
4537
4592
  return _cached2;
4538
4593
  }
@@ -5005,8 +5060,8 @@ __export(tasks_exports, {
5005
5060
  updateTaskStatus: () => updateTaskStatus,
5006
5061
  writeCheckpoint: () => writeCheckpoint
5007
5062
  });
5008
- import path15 from "path";
5009
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
5063
+ import path16 from "path";
5064
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
5010
5065
  async function createTask(input) {
5011
5066
  const result = await createTaskCore(input);
5012
5067
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -5025,11 +5080,11 @@ async function updateTask(input) {
5025
5080
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
5026
5081
  try {
5027
5082
  const agent = String(row.assigned_to);
5028
- const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
5029
- const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
5083
+ const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
5084
+ const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
5030
5085
  if (input.status === "in_progress") {
5031
- mkdirSync5(cacheDir, { recursive: true });
5032
- writeFileSync5(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
5086
+ mkdirSync6(cacheDir, { recursive: true });
5087
+ writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
5033
5088
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
5034
5089
  try {
5035
5090
  unlinkSync5(cachePath);
@@ -5496,13 +5551,13 @@ __export(tmux_routing_exports, {
5496
5551
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
5497
5552
  });
5498
5553
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
5499
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync13, appendFileSync } from "fs";
5500
- import path16 from "path";
5554
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync } from "fs";
5555
+ import path17 from "path";
5501
5556
  import os8 from "os";
5502
5557
  import { fileURLToPath as fileURLToPath2 } from "url";
5503
5558
  import { unlinkSync as unlinkSync6 } from "fs";
5504
5559
  function spawnLockPath(sessionName) {
5505
- return path16.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
5560
+ return path17.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
5506
5561
  }
5507
5562
  function isProcessAlive(pid) {
5508
5563
  try {
@@ -5513,13 +5568,13 @@ function isProcessAlive(pid) {
5513
5568
  }
5514
5569
  }
5515
5570
  function acquireSpawnLock2(sessionName) {
5516
- if (!existsSync13(SPAWN_LOCK_DIR)) {
5517
- mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
5571
+ if (!existsSync14(SPAWN_LOCK_DIR)) {
5572
+ mkdirSync7(SPAWN_LOCK_DIR, { recursive: true });
5518
5573
  }
5519
5574
  const lockFile = spawnLockPath(sessionName);
5520
- if (existsSync13(lockFile)) {
5575
+ if (existsSync14(lockFile)) {
5521
5576
  try {
5522
- const lock = JSON.parse(readFileSync10(lockFile, "utf8"));
5577
+ const lock = JSON.parse(readFileSync11(lockFile, "utf8"));
5523
5578
  const age = Date.now() - lock.timestamp;
5524
5579
  if (isProcessAlive(lock.pid) && age < 6e4) {
5525
5580
  return false;
@@ -5527,7 +5582,7 @@ function acquireSpawnLock2(sessionName) {
5527
5582
  } catch {
5528
5583
  }
5529
5584
  }
5530
- writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
5585
+ writeFileSync7(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
5531
5586
  return true;
5532
5587
  }
5533
5588
  function releaseSpawnLock2(sessionName) {
@@ -5539,13 +5594,13 @@ function releaseSpawnLock2(sessionName) {
5539
5594
  function resolveBehaviorsExporterScript() {
5540
5595
  try {
5541
5596
  const thisFile = fileURLToPath2(import.meta.url);
5542
- const scriptPath = path16.join(
5543
- path16.dirname(thisFile),
5597
+ const scriptPath = path17.join(
5598
+ path17.dirname(thisFile),
5544
5599
  "..",
5545
5600
  "bin",
5546
5601
  "exe-export-behaviors.js"
5547
5602
  );
5548
- return existsSync13(scriptPath) ? scriptPath : null;
5603
+ return existsSync14(scriptPath) ? scriptPath : null;
5549
5604
  } catch {
5550
5605
  return null;
5551
5606
  }
@@ -5611,12 +5666,12 @@ function extractRootExe(name) {
5611
5666
  return parts.length > 0 ? parts[parts.length - 1] : null;
5612
5667
  }
5613
5668
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
5614
- if (!existsSync13(SESSION_CACHE)) {
5615
- mkdirSync6(SESSION_CACHE, { recursive: true });
5669
+ if (!existsSync14(SESSION_CACHE)) {
5670
+ mkdirSync7(SESSION_CACHE, { recursive: true });
5616
5671
  }
5617
5672
  const rootExe = extractRootExe(parentExe) ?? parentExe;
5618
- const filePath = path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
5619
- writeFileSync6(filePath, JSON.stringify({
5673
+ const filePath = path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
5674
+ writeFileSync7(filePath, JSON.stringify({
5620
5675
  parentExe: rootExe,
5621
5676
  dispatchedBy: dispatchedBy || rootExe,
5622
5677
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -5624,7 +5679,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
5624
5679
  }
5625
5680
  function getParentExe(sessionKey) {
5626
5681
  try {
5627
- const data = JSON.parse(readFileSync10(path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
5682
+ const data = JSON.parse(readFileSync11(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
5628
5683
  return data.parentExe || null;
5629
5684
  } catch {
5630
5685
  return null;
@@ -5632,8 +5687,8 @@ function getParentExe(sessionKey) {
5632
5687
  }
5633
5688
  function getDispatchedBy(sessionKey) {
5634
5689
  try {
5635
- const data = JSON.parse(readFileSync10(
5636
- path16.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
5690
+ const data = JSON.parse(readFileSync11(
5691
+ path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
5637
5692
  "utf8"
5638
5693
  ));
5639
5694
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -5694,32 +5749,50 @@ async function verifyPaneAtCapacity(sessionName) {
5694
5749
  }
5695
5750
  function readDebounceState() {
5696
5751
  try {
5697
- if (!existsSync13(DEBOUNCE_FILE)) return {};
5698
- return JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
5752
+ if (!existsSync14(DEBOUNCE_FILE)) return {};
5753
+ const raw = JSON.parse(readFileSync11(DEBOUNCE_FILE, "utf8"));
5754
+ const state = {};
5755
+ for (const [key, val] of Object.entries(raw)) {
5756
+ if (typeof val === "number") {
5757
+ state[key] = { lastSent: val, pending: 0 };
5758
+ } else if (val && typeof val === "object" && "lastSent" in val) {
5759
+ state[key] = val;
5760
+ }
5761
+ }
5762
+ return state;
5699
5763
  } catch {
5700
5764
  return {};
5701
5765
  }
5702
5766
  }
5703
5767
  function writeDebounceState(state) {
5704
5768
  try {
5705
- if (!existsSync13(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
5706
- writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
5769
+ if (!existsSync14(SESSION_CACHE)) mkdirSync7(SESSION_CACHE, { recursive: true });
5770
+ writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
5707
5771
  } catch {
5708
5772
  }
5709
5773
  }
5710
5774
  function isDebounced(targetSession) {
5711
5775
  const state = readDebounceState();
5712
- const lastSent = state[targetSession] ?? 0;
5713
- return Date.now() - lastSent < INTERCOM_DEBOUNCE_MS;
5776
+ const entry = state[targetSession];
5777
+ const lastSent = entry?.lastSent ?? 0;
5778
+ if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
5779
+ if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
5780
+ state[targetSession].pending++;
5781
+ writeDebounceState(state);
5782
+ return true;
5783
+ }
5784
+ return false;
5714
5785
  }
5715
5786
  function recordDebounce(targetSession) {
5716
5787
  const state = readDebounceState();
5717
- state[targetSession] = Date.now();
5788
+ const batched = state[targetSession]?.pending ?? 0;
5789
+ state[targetSession] = { lastSent: Date.now(), pending: 0 };
5718
5790
  const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
5719
5791
  for (const key of Object.keys(state)) {
5720
- if ((state[key] ?? 0) < cutoff) delete state[key];
5792
+ if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
5721
5793
  }
5722
5794
  writeDebounceState(state);
5795
+ return batched;
5723
5796
  }
5724
5797
  function logIntercom(msg) {
5725
5798
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
@@ -5764,7 +5837,7 @@ function sendIntercom(targetSession) {
5764
5837
  return "skipped_exe";
5765
5838
  }
5766
5839
  if (isDebounced(targetSession)) {
5767
- logIntercom(`DEBOUNCE \u2192 ${targetSession} (cross-process file debounce)`);
5840
+ logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
5768
5841
  return "debounced";
5769
5842
  }
5770
5843
  try {
@@ -5776,14 +5849,14 @@ function sendIntercom(targetSession) {
5776
5849
  const sessionState = getSessionState(targetSession);
5777
5850
  if (sessionState === "no_claude") {
5778
5851
  queueIntercom(targetSession, "claude not running in session");
5779
- recordDebounce(targetSession);
5780
- logIntercom(`QUEUED \u2192 ${targetSession} (no claude process \u2014 raw shell detected)`);
5852
+ const batched2 = recordDebounce(targetSession);
5853
+ logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
5781
5854
  return "queued";
5782
5855
  }
5783
5856
  if (sessionState === "thinking" || sessionState === "tool") {
5784
5857
  queueIntercom(targetSession, "session busy at send time");
5785
- recordDebounce(targetSession);
5786
- logIntercom(`QUEUED \u2192 ${targetSession} (session busy, will retry from queue)`);
5858
+ const batched2 = recordDebounce(targetSession);
5859
+ logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
5787
5860
  return "queued";
5788
5861
  }
5789
5862
  if (transport.isPaneInCopyMode(targetSession)) {
@@ -5791,8 +5864,8 @@ function sendIntercom(targetSession) {
5791
5864
  transport.sendKeys(targetSession, "q");
5792
5865
  }
5793
5866
  transport.sendKeys(targetSession, "/exe-intercom");
5794
- recordDebounce(targetSession);
5795
- logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
5867
+ const batched = recordDebounce(targetSession);
5868
+ logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
5796
5869
  return "delivered";
5797
5870
  } catch {
5798
5871
  logIntercom(`FAIL \u2192 ${targetSession}`);
@@ -5894,26 +5967,26 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
5894
5967
  const transport = getTransport();
5895
5968
  const sessionName = employeeSessionName(employeeName, exeSession2, opts?.instance);
5896
5969
  const instanceLabel2 = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
5897
- const logDir = path16.join(os8.homedir(), ".exe-os", "session-logs");
5898
- const logFile = path16.join(logDir, `${instanceLabel2}-${Date.now()}.log`);
5899
- if (!existsSync13(logDir)) {
5900
- mkdirSync6(logDir, { recursive: true });
5970
+ const logDir = path17.join(os8.homedir(), ".exe-os", "session-logs");
5971
+ const logFile = path17.join(logDir, `${instanceLabel2}-${Date.now()}.log`);
5972
+ if (!existsSync14(logDir)) {
5973
+ mkdirSync7(logDir, { recursive: true });
5901
5974
  }
5902
5975
  transport.kill(sessionName);
5903
5976
  let cleanupSuffix = "";
5904
5977
  try {
5905
5978
  const thisFile = fileURLToPath2(import.meta.url);
5906
- const cleanupScript = path16.join(path16.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5907
- if (existsSync13(cleanupScript)) {
5979
+ const cleanupScript = path17.join(path17.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5980
+ if (existsSync14(cleanupScript)) {
5908
5981
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession2}"`;
5909
5982
  }
5910
5983
  } catch {
5911
5984
  }
5912
5985
  try {
5913
- const claudeJsonPath = path16.join(os8.homedir(), ".claude.json");
5986
+ const claudeJsonPath = path17.join(os8.homedir(), ".claude.json");
5914
5987
  let claudeJson = {};
5915
5988
  try {
5916
- claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
5989
+ claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
5917
5990
  } catch {
5918
5991
  }
5919
5992
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -5921,17 +5994,17 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
5921
5994
  const trustDir = opts?.cwd ?? projectDir;
5922
5995
  if (!projects[trustDir]) projects[trustDir] = {};
5923
5996
  projects[trustDir].hasTrustDialogAccepted = true;
5924
- writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
5997
+ writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
5925
5998
  } catch {
5926
5999
  }
5927
6000
  try {
5928
- const settingsDir = path16.join(os8.homedir(), ".claude", "projects");
6001
+ const settingsDir = path17.join(os8.homedir(), ".claude", "projects");
5929
6002
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
5930
- const projSettingsDir = path16.join(settingsDir, normalizedKey);
5931
- const settingsPath = path16.join(projSettingsDir, "settings.json");
6003
+ const projSettingsDir = path17.join(settingsDir, normalizedKey);
6004
+ const settingsPath = path17.join(projSettingsDir, "settings.json");
5932
6005
  let settings = {};
5933
6006
  try {
5934
- settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
6007
+ settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
5935
6008
  } catch {
5936
6009
  }
5937
6010
  const perms = settings.permissions ?? {};
@@ -5959,20 +6032,23 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
5959
6032
  if (changed) {
5960
6033
  perms.allow = allow;
5961
6034
  settings.permissions = perms;
5962
- mkdirSync6(projSettingsDir, { recursive: true });
5963
- writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
6035
+ mkdirSync7(projSettingsDir, { recursive: true });
6036
+ writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5964
6037
  }
5965
6038
  } catch {
5966
6039
  }
5967
6040
  const spawnCwd = opts?.cwd ?? projectDir;
5968
6041
  const useExeAgent = !!(opts?.model && opts?.provider);
5969
- const ccProvider = useExeAgent ? DEFAULT_PROVIDER : detectActiveProvider();
6042
+ const agentRtConfig = getAgentRuntime(employeeName);
6043
+ const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
6044
+ const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
6045
+ const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
5970
6046
  const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
5971
6047
  let identityFlag = "";
5972
6048
  let behaviorsFlag = "";
5973
6049
  let legacyFallbackWarned = false;
5974
6050
  if (!useExeAgent && !useBinSymlink) {
5975
- const identityPath = path16.join(
6051
+ const identityPath = path17.join(
5976
6052
  os8.homedir(),
5977
6053
  ".exe-os",
5978
6054
  "identity",
@@ -5982,13 +6058,13 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
5982
6058
  const hasAgentFlag = claudeSupportsAgentFlag();
5983
6059
  if (hasAgentFlag) {
5984
6060
  identityFlag = ` --agent ${employeeName}`;
5985
- } else if (existsSync13(identityPath)) {
6061
+ } else if (existsSync14(identityPath)) {
5986
6062
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
5987
6063
  legacyFallbackWarned = true;
5988
6064
  }
5989
6065
  const behaviorsFile = exportBehaviorsSync(
5990
6066
  employeeName,
5991
- path16.basename(spawnCwd),
6067
+ path17.basename(spawnCwd),
5992
6068
  sessionName
5993
6069
  );
5994
6070
  if (behaviorsFile) {
@@ -6003,16 +6079,16 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6003
6079
  }
6004
6080
  let sessionContextFlag = "";
6005
6081
  try {
6006
- const ctxDir = path16.join(os8.homedir(), ".exe-os", "session-cache");
6007
- mkdirSync6(ctxDir, { recursive: true });
6008
- const ctxFile = path16.join(ctxDir, `session-context-${sessionName}.md`);
6082
+ const ctxDir = path17.join(os8.homedir(), ".exe-os", "session-cache");
6083
+ mkdirSync7(ctxDir, { recursive: true });
6084
+ const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
6009
6085
  const ctxContent = [
6010
6086
  `## Session Context`,
6011
6087
  `You are running in tmux session: ${sessionName}.`,
6012
6088
  `Your parent coordinator session is ${exeSession2}.`,
6013
6089
  `Your employees (if any) use the -${exeSession2} suffix.`
6014
6090
  ].join("\n");
6015
- writeFileSync6(ctxFile, ctxContent);
6091
+ writeFileSync7(ctxFile, ctxContent);
6016
6092
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
6017
6093
  } catch {
6018
6094
  }
@@ -6026,9 +6102,48 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6026
6102
  }
6027
6103
  }
6028
6104
  }
6105
+ if (useCodex) {
6106
+ const codexCfg = RUNTIME_TABLE.codex;
6107
+ if (codexCfg?.apiKeyEnv) {
6108
+ const keyVal = process.env[codexCfg.apiKeyEnv];
6109
+ if (keyVal) {
6110
+ envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
6111
+ }
6112
+ }
6113
+ envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
6114
+ }
6115
+ if (useOpencode) {
6116
+ const ocCfg = PROVIDER_TABLE.opencode;
6117
+ if (ocCfg?.apiKeyEnv) {
6118
+ const keyVal = process.env[ocCfg.apiKeyEnv];
6119
+ if (keyVal) {
6120
+ envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
6121
+ }
6122
+ }
6123
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
6124
+ }
6125
+ if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
6126
+ const defaultClaudeModel = DEFAULT_MODELS.claude;
6127
+ if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
6128
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
6129
+ }
6130
+ }
6029
6131
  let spawnCommand;
6030
6132
  if (useExeAgent) {
6031
6133
  spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
6134
+ } else if (useCodex) {
6135
+ process.stderr.write(
6136
+ `[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
6137
+ `
6138
+ );
6139
+ spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
6140
+ } else if (useOpencode) {
6141
+ const binName = `${employeeName}-opencode`;
6142
+ process.stderr.write(
6143
+ `[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
6144
+ `
6145
+ );
6146
+ spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
6032
6147
  } else if (useBinSymlink) {
6033
6148
  const binName = `${employeeName}-${ccProvider}`;
6034
6149
  process.stderr.write(
@@ -6050,11 +6165,13 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6050
6165
  transport.pipeLog(sessionName, logFile);
6051
6166
  try {
6052
6167
  const mySession = getMySession();
6053
- const dispatchInfo = path16.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
6054
- writeFileSync6(dispatchInfo, JSON.stringify({
6168
+ const dispatchInfo = path17.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
6169
+ writeFileSync7(dispatchInfo, JSON.stringify({
6055
6170
  dispatchedBy: mySession,
6056
6171
  rootExe: exeSession2,
6057
- provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
6172
+ provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
6173
+ runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
6174
+ model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
6058
6175
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
6059
6176
  }));
6060
6177
  } catch {
@@ -6072,6 +6189,11 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6072
6189
  booted = true;
6073
6190
  break;
6074
6191
  }
6192
+ } else if (useCodex) {
6193
+ if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
6194
+ booted = true;
6195
+ break;
6196
+ }
6075
6197
  } else {
6076
6198
  if (pane.includes("Claude Code") || pane.includes("\u276F")) {
6077
6199
  booted = true;
@@ -6083,9 +6205,10 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6083
6205
  }
6084
6206
  if (!booted) {
6085
6207
  releaseSpawnLock2(sessionName);
6086
- return { sessionName, error: `${useExeAgent ? "exe-agent" : "claude"} did not boot within 15s` };
6208
+ const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
6209
+ return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
6087
6210
  }
6088
- if (!useExeAgent) {
6211
+ if (!useExeAgent && !useCodex) {
6089
6212
  try {
6090
6213
  transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
6091
6214
  } catch {
@@ -6112,17 +6235,19 @@ var init_tmux_routing = __esm({
6112
6235
  init_cc_agent_support();
6113
6236
  init_mcp_prefix();
6114
6237
  init_provider_table();
6238
+ init_agent_config();
6239
+ init_runtime_table();
6115
6240
  init_intercom_queue();
6116
6241
  init_plan_limits();
6117
6242
  init_employees();
6118
- SPAWN_LOCK_DIR = path16.join(os8.homedir(), ".exe-os", "spawn-locks");
6119
- SESSION_CACHE = path16.join(os8.homedir(), ".exe-os", "session-cache");
6243
+ SPAWN_LOCK_DIR = path17.join(os8.homedir(), ".exe-os", "spawn-locks");
6244
+ SESSION_CACHE = path17.join(os8.homedir(), ".exe-os", "session-cache");
6120
6245
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
6121
6246
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
6122
6247
  VERIFY_PANE_LINES = 200;
6123
6248
  INTERCOM_DEBOUNCE_MS = 3e4;
6124
- INTERCOM_LOG2 = path16.join(os8.homedir(), ".exe-os", "intercom.log");
6125
- DEBOUNCE_FILE = path16.join(SESSION_CACHE, "intercom-debounce.json");
6249
+ INTERCOM_LOG2 = path17.join(os8.homedir(), ".exe-os", "intercom.log");
6250
+ DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
6126
6251
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
6127
6252
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
6128
6253
  }
@@ -6189,10 +6314,10 @@ async function disposeEmbedder() {
6189
6314
  async function embedDirect(text) {
6190
6315
  const llamaCpp = await import("node-llama-cpp");
6191
6316
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
6192
- const { existsSync: existsSync15 } = await import("fs");
6193
- const path18 = await import("path");
6194
- const modelPath = path18.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
6195
- if (!existsSync15(modelPath)) {
6317
+ const { existsSync: existsSync16 } = await import("fs");
6318
+ const path19 = await import("path");
6319
+ const modelPath = path19.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
6320
+ if (!existsSync16(modelPath)) {
6196
6321
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
6197
6322
  }
6198
6323
  const llama = await llamaCpp.getLlama();
@@ -6450,8 +6575,8 @@ __export(worktree_exports, {
6450
6575
  worktreePath: () => worktreePath
6451
6576
  });
6452
6577
  import { execSync as execSync8 } from "child_process";
6453
- import { existsSync as existsSync14, readFileSync as readFileSync11, appendFileSync as appendFileSync2, mkdirSync as mkdirSync7, realpathSync } from "fs";
6454
- import path17 from "path";
6578
+ import { existsSync as existsSync15, readFileSync as readFileSync12, appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, realpathSync } from "fs";
6579
+ import path18 from "path";
6455
6580
  function getGitRoot(dir) {
6456
6581
  try {
6457
6582
  const root = execSync8("git rev-parse --show-toplevel", {
@@ -6471,14 +6596,14 @@ function getMainRepoRoot(dir) {
6471
6596
  "git rev-parse --path-format=absolute --git-common-dir",
6472
6597
  { cwd: dir, encoding: "utf-8", timeout: GIT_TIMEOUT_MS, stdio: ["pipe", "pipe", "pipe"] }
6473
6598
  ).trim();
6474
- return realpath(path17.dirname(commonDir));
6599
+ return realpath(path18.dirname(commonDir));
6475
6600
  } catch {
6476
6601
  return null;
6477
6602
  }
6478
6603
  }
6479
6604
  function worktreePath(repoRoot, employeeName, instance) {
6480
6605
  const label = instanceLabel(employeeName, instance);
6481
- return path17.join(repoRoot, ".worktrees", label);
6606
+ return path18.join(repoRoot, ".worktrees", label);
6482
6607
  }
6483
6608
  function worktreeBranch(employeeName, instance) {
6484
6609
  return `${instanceLabel(employeeName, instance)}-work`;
@@ -6491,11 +6616,11 @@ function ensureWorktree(projectDir, employeeName, instance) {
6491
6616
  if (!repoRoot) return null;
6492
6617
  const wtPath = worktreePath(repoRoot, employeeName, instance);
6493
6618
  const branch = worktreeBranch(employeeName, instance);
6494
- if (existsSync14(path17.join(wtPath, ".git"))) {
6619
+ if (existsSync15(path18.join(wtPath, ".git"))) {
6495
6620
  return wtPath;
6496
6621
  }
6497
- const worktreesDir = path17.join(repoRoot, ".worktrees");
6498
- mkdirSync7(worktreesDir, { recursive: true });
6622
+ const worktreesDir = path18.join(repoRoot, ".worktrees");
6623
+ mkdirSync8(worktreesDir, { recursive: true });
6499
6624
  ensureGitignoreEntry(repoRoot, "/.worktrees/");
6500
6625
  try {
6501
6626
  execSync8("git worktree prune", {
@@ -6550,7 +6675,7 @@ function cleanupWorktree(projectDir, employeeName, instance) {
6550
6675
  if (!repoRoot) return { cleaned: false, reason: "not a git repo" };
6551
6676
  const wtPath = worktreePath(repoRoot, employeeName, instance);
6552
6677
  const branch = worktreeBranch(employeeName, instance);
6553
- if (!existsSync14(wtPath)) {
6678
+ if (!existsSync15(wtPath)) {
6554
6679
  return { cleaned: false, reason: "worktree does not exist" };
6555
6680
  }
6556
6681
  if (isWorktreeDirty(wtPath)) {
@@ -6628,9 +6753,9 @@ function realpath(p) {
6628
6753
  }
6629
6754
  function ensureGitignoreEntry(repoRoot, entry) {
6630
6755
  try {
6631
- const gitignorePath = path17.join(repoRoot, ".gitignore");
6632
- if (existsSync14(gitignorePath)) {
6633
- const content = readFileSync11(gitignorePath, "utf-8");
6756
+ const gitignorePath = path18.join(repoRoot, ".gitignore");
6757
+ if (existsSync15(gitignorePath)) {
6758
+ const content = readFileSync12(gitignorePath, "utf-8");
6634
6759
  if (content.includes(entry)) return;
6635
6760
  appendFileSync2(gitignorePath, `
6636
6761
  # Agent worktrees (exe-os)