@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
package/dist/tui/App.js CHANGED
@@ -322,110 +322,6 @@ var init_provider_table = __esm({
322
322
  }
323
323
  });
324
324
 
325
- // src/lib/intercom-queue.ts
326
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
327
- import path2 from "path";
328
- import os2 from "os";
329
- function ensureDir() {
330
- const dir = path2.dirname(QUEUE_PATH);
331
- if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
332
- }
333
- function readQueue() {
334
- try {
335
- if (!existsSync3(QUEUE_PATH)) return [];
336
- return JSON.parse(readFileSync3(QUEUE_PATH, "utf8"));
337
- } catch {
338
- return [];
339
- }
340
- }
341
- function writeQueue(queue) {
342
- ensureDir();
343
- const tmp = `${QUEUE_PATH}.tmp`;
344
- writeFileSync2(tmp, JSON.stringify(queue, null, 2));
345
- renameSync(tmp, QUEUE_PATH);
346
- }
347
- function queueIntercom(targetSession, reason) {
348
- const queue = readQueue();
349
- const existing = queue.find((q) => q.targetSession === targetSession);
350
- if (existing) {
351
- existing.attempts++;
352
- existing.queuedAt = (/* @__PURE__ */ new Date()).toISOString();
353
- existing.reason = reason;
354
- } else {
355
- queue.push({
356
- targetSession,
357
- queuedAt: (/* @__PURE__ */ new Date()).toISOString(),
358
- attempts: 0,
359
- reason
360
- });
361
- }
362
- writeQueue(queue);
363
- }
364
- var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
365
- var init_intercom_queue = __esm({
366
- "src/lib/intercom-queue.ts"() {
367
- "use strict";
368
- QUEUE_PATH = path2.join(os2.homedir(), ".exe-os", "intercom-queue.json");
369
- TTL_MS = 60 * 60 * 1e3;
370
- INTERCOM_LOG = path2.join(os2.homedir(), ".exe-os", "intercom.log");
371
- }
372
- });
373
-
374
- // src/lib/db-retry.ts
375
- function isBusyError(err) {
376
- if (err instanceof Error) {
377
- const msg = err.message.toLowerCase();
378
- return msg.includes("sqlite_busy") || msg.includes("database is locked");
379
- }
380
- return false;
381
- }
382
- function delay(ms) {
383
- return new Promise((resolve) => setTimeout(resolve, ms));
384
- }
385
- async function retryOnBusy(fn, label) {
386
- let lastError;
387
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
388
- try {
389
- return await fn();
390
- } catch (err) {
391
- lastError = err;
392
- if (!isBusyError(err) || attempt === MAX_RETRIES) {
393
- throw err;
394
- }
395
- const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
396
- const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
397
- process.stderr.write(
398
- `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
399
- `
400
- );
401
- await delay(backoff + jitter);
402
- }
403
- }
404
- throw lastError;
405
- }
406
- function wrapWithRetry(client) {
407
- return new Proxy(client, {
408
- get(target, prop, receiver) {
409
- if (prop === "execute") {
410
- return (sql) => retryOnBusy(() => target.execute(sql), "execute");
411
- }
412
- if (prop === "batch") {
413
- return (stmts, mode) => retryOnBusy(() => target.batch(stmts, mode), "batch");
414
- }
415
- return Reflect.get(target, prop, receiver);
416
- }
417
- });
418
- }
419
- var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
420
- var init_db_retry = __esm({
421
- "src/lib/db-retry.ts"() {
422
- "use strict";
423
- MAX_RETRIES = 3;
424
- BASE_DELAY_MS = 200;
425
- MAX_JITTER_MS = 300;
426
- }
427
- });
428
-
429
325
  // src/lib/config.ts
430
326
  var config_exports = {};
431
327
  __export(config_exports, {
@@ -443,17 +339,17 @@ __export(config_exports, {
443
339
  saveConfig: () => saveConfig
444
340
  });
445
341
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
446
- import { readFileSync as readFileSync4, existsSync as existsSync4, renameSync as renameSync2 } from "fs";
447
- import path3 from "path";
448
- import os3 from "os";
342
+ import { readFileSync as readFileSync3, existsSync as existsSync3, renameSync } from "fs";
343
+ import path2 from "path";
344
+ import os2 from "os";
449
345
  function resolveDataDir() {
450
346
  if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
451
347
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
452
- const newDir = path3.join(os3.homedir(), ".exe-os");
453
- const legacyDir = path3.join(os3.homedir(), ".exe-mem");
454
- if (!existsSync4(newDir) && existsSync4(legacyDir)) {
348
+ const newDir = path2.join(os2.homedir(), ".exe-os");
349
+ const legacyDir = path2.join(os2.homedir(), ".exe-mem");
350
+ if (!existsSync3(newDir) && existsSync3(legacyDir)) {
455
351
  try {
456
- renameSync2(legacyDir, newDir);
352
+ renameSync(legacyDir, newDir);
457
353
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
458
354
  `);
459
355
  } catch {
@@ -515,9 +411,9 @@ function normalizeAutoUpdate(raw) {
515
411
  async function loadConfig() {
516
412
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
517
413
  await mkdir(dir, { recursive: true });
518
- const configPath = path3.join(dir, "config.json");
519
- if (!existsSync4(configPath)) {
520
- return { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db") };
414
+ const configPath = path2.join(dir, "config.json");
415
+ if (!existsSync3(configPath)) {
416
+ return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
521
417
  }
522
418
  const raw = await readFile(configPath, "utf-8");
523
419
  try {
@@ -535,38 +431,38 @@ async function loadConfig() {
535
431
  normalizeScalingRoadmap(migratedCfg);
536
432
  normalizeSessionLifecycle(migratedCfg);
537
433
  normalizeAutoUpdate(migratedCfg);
538
- const config = { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db"), ...migratedCfg };
434
+ const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
539
435
  if (config.dbPath.startsWith("~")) {
540
- config.dbPath = config.dbPath.replace(/^~/, os3.homedir());
436
+ config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
541
437
  }
542
438
  return config;
543
439
  } catch {
544
- return { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db") };
440
+ return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
545
441
  }
546
442
  }
547
443
  function loadConfigSync() {
548
444
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
549
- const configPath = path3.join(dir, "config.json");
550
- if (!existsSync4(configPath)) {
551
- return { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db") };
445
+ const configPath = path2.join(dir, "config.json");
446
+ if (!existsSync3(configPath)) {
447
+ return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
552
448
  }
553
449
  try {
554
- const raw = readFileSync4(configPath, "utf-8");
450
+ const raw = readFileSync3(configPath, "utf-8");
555
451
  let parsed = JSON.parse(raw);
556
452
  parsed = migrateLegacyConfig(parsed);
557
453
  const { config: migratedCfg } = migrateConfig(parsed);
558
454
  normalizeScalingRoadmap(migratedCfg);
559
455
  normalizeSessionLifecycle(migratedCfg);
560
456
  normalizeAutoUpdate(migratedCfg);
561
- return { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db"), ...migratedCfg };
457
+ return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
562
458
  } catch {
563
- return { ...DEFAULT_CONFIG, dbPath: path3.join(dir, "memories.db") };
459
+ return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
564
460
  }
565
461
  }
566
462
  async function saveConfig(config) {
567
463
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
568
464
  await mkdir(dir, { recursive: true });
569
- const configPath = path3.join(dir, "config.json");
465
+ const configPath = path2.join(dir, "config.json");
570
466
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
571
467
  if (config.cloud?.apiKey) {
572
468
  await chmod(configPath, 384);
@@ -591,10 +487,10 @@ var init_config = __esm({
591
487
  "src/lib/config.ts"() {
592
488
  "use strict";
593
489
  EXE_AI_DIR = resolveDataDir();
594
- DB_PATH = path3.join(EXE_AI_DIR, "memories.db");
595
- MODELS_DIR = path3.join(EXE_AI_DIR, "models");
596
- CONFIG_PATH = path3.join(EXE_AI_DIR, "config.json");
597
- LEGACY_LANCE_PATH = path3.join(EXE_AI_DIR, "local.lance");
490
+ DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
491
+ MODELS_DIR = path2.join(EXE_AI_DIR, "models");
492
+ CONFIG_PATH = path2.join(EXE_AI_DIR, "config.json");
493
+ LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
598
494
  CURRENT_CONFIG_VERSION = 1;
599
495
  DEFAULT_CONFIG = {
600
496
  config_version: CURRENT_CONFIG_VERSION,
@@ -666,6 +562,161 @@ var init_config = __esm({
666
562
  }
667
563
  });
668
564
 
565
+ // src/lib/runtime-table.ts
566
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
567
+ var init_runtime_table = __esm({
568
+ "src/lib/runtime-table.ts"() {
569
+ "use strict";
570
+ RUNTIME_TABLE = {
571
+ codex: {
572
+ binary: "codex",
573
+ launchMode: "exec",
574
+ autoApproveFlag: "--full-auto",
575
+ inlineFlag: "--no-alt-screen",
576
+ apiKeyEnv: "OPENAI_API_KEY",
577
+ defaultModel: "gpt-5.4"
578
+ }
579
+ };
580
+ DEFAULT_RUNTIME = "claude";
581
+ }
582
+ });
583
+
584
+ // src/lib/agent-config.ts
585
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
586
+ import path3 from "path";
587
+ function loadAgentConfig() {
588
+ if (!existsSync4(AGENT_CONFIG_PATH)) return {};
589
+ try {
590
+ return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf-8"));
591
+ } catch {
592
+ return {};
593
+ }
594
+ }
595
+ function getAgentRuntime(agentId) {
596
+ const config = loadAgentConfig();
597
+ const entry = config[agentId];
598
+ if (entry) return entry;
599
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
600
+ }
601
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
602
+ var init_agent_config = __esm({
603
+ "src/lib/agent-config.ts"() {
604
+ "use strict";
605
+ init_config();
606
+ init_runtime_table();
607
+ AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
608
+ DEFAULT_MODELS = {
609
+ claude: "claude-opus-4",
610
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
611
+ opencode: "minimax-m2.7"
612
+ };
613
+ }
614
+ });
615
+
616
+ // src/lib/intercom-queue.ts
617
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
618
+ import path4 from "path";
619
+ import os3 from "os";
620
+ function ensureDir() {
621
+ const dir = path4.dirname(QUEUE_PATH);
622
+ if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
623
+ }
624
+ function readQueue() {
625
+ try {
626
+ if (!existsSync5(QUEUE_PATH)) return [];
627
+ return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
628
+ } catch {
629
+ return [];
630
+ }
631
+ }
632
+ function writeQueue(queue) {
633
+ ensureDir();
634
+ const tmp = `${QUEUE_PATH}.tmp`;
635
+ writeFileSync3(tmp, JSON.stringify(queue, null, 2));
636
+ renameSync2(tmp, QUEUE_PATH);
637
+ }
638
+ function queueIntercom(targetSession, reason) {
639
+ const queue = readQueue();
640
+ const existing = queue.find((q) => q.targetSession === targetSession);
641
+ if (existing) {
642
+ existing.attempts++;
643
+ existing.queuedAt = (/* @__PURE__ */ new Date()).toISOString();
644
+ existing.reason = reason;
645
+ } else {
646
+ queue.push({
647
+ targetSession,
648
+ queuedAt: (/* @__PURE__ */ new Date()).toISOString(),
649
+ attempts: 0,
650
+ reason
651
+ });
652
+ }
653
+ writeQueue(queue);
654
+ }
655
+ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
656
+ var init_intercom_queue = __esm({
657
+ "src/lib/intercom-queue.ts"() {
658
+ "use strict";
659
+ QUEUE_PATH = path4.join(os3.homedir(), ".exe-os", "intercom-queue.json");
660
+ TTL_MS = 60 * 60 * 1e3;
661
+ INTERCOM_LOG = path4.join(os3.homedir(), ".exe-os", "intercom.log");
662
+ }
663
+ });
664
+
665
+ // src/lib/db-retry.ts
666
+ function isBusyError(err) {
667
+ if (err instanceof Error) {
668
+ const msg = err.message.toLowerCase();
669
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
670
+ }
671
+ return false;
672
+ }
673
+ function delay(ms) {
674
+ return new Promise((resolve) => setTimeout(resolve, ms));
675
+ }
676
+ async function retryOnBusy(fn, label) {
677
+ let lastError;
678
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
679
+ try {
680
+ return await fn();
681
+ } catch (err) {
682
+ lastError = err;
683
+ if (!isBusyError(err) || attempt === MAX_RETRIES) {
684
+ throw err;
685
+ }
686
+ const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
687
+ const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
688
+ process.stderr.write(
689
+ `[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
690
+ `
691
+ );
692
+ await delay(backoff + jitter);
693
+ }
694
+ }
695
+ throw lastError;
696
+ }
697
+ function wrapWithRetry(client) {
698
+ return new Proxy(client, {
699
+ get(target, prop, receiver) {
700
+ if (prop === "execute") {
701
+ return (sql) => retryOnBusy(() => target.execute(sql), "execute");
702
+ }
703
+ if (prop === "batch") {
704
+ return (stmts, mode) => retryOnBusy(() => target.batch(stmts, mode), "batch");
705
+ }
706
+ return Reflect.get(target, prop, receiver);
707
+ }
708
+ });
709
+ }
710
+ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
711
+ var init_db_retry = __esm({
712
+ "src/lib/db-retry.ts"() {
713
+ "use strict";
714
+ MAX_RETRIES = 3;
715
+ BASE_DELAY_MS = 200;
716
+ MAX_JITTER_MS = 300;
717
+ }
718
+ });
719
+
669
720
  // src/lib/employees.ts
670
721
  var employees_exports = {};
671
722
  __export(employees_exports, {
@@ -693,9 +744,9 @@ __export(employees_exports, {
693
744
  validateEmployeeName: () => validateEmployeeName
694
745
  });
695
746
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
696
- import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
747
+ import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
697
748
  import { execSync as execSync4 } from "child_process";
698
- import path4 from "path";
749
+ import path5 from "path";
699
750
  import os4 from "os";
700
751
  function normalizeRole(role) {
701
752
  return (role ?? "").trim().toLowerCase();
@@ -732,7 +783,7 @@ function validateEmployeeName(name) {
732
783
  return { valid: true };
733
784
  }
734
785
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
735
- if (!existsSync5(employeesPath)) {
786
+ if (!existsSync6(employeesPath)) {
736
787
  return [];
737
788
  }
738
789
  const raw = await readFile2(employeesPath, "utf-8");
@@ -743,13 +794,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
743
794
  }
744
795
  }
745
796
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
746
- await mkdir2(path4.dirname(employeesPath), { recursive: true });
797
+ await mkdir2(path5.dirname(employeesPath), { recursive: true });
747
798
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
748
799
  }
749
800
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
750
- if (!existsSync5(employeesPath)) return [];
801
+ if (!existsSync6(employeesPath)) return [];
751
802
  try {
752
- return JSON.parse(readFileSync5(employeesPath, "utf-8"));
803
+ return JSON.parse(readFileSync6(employeesPath, "utf-8"));
753
804
  } catch {
754
805
  return [];
755
806
  }
@@ -800,14 +851,14 @@ async function normalizeRosterCase(rosterPath) {
800
851
  emp.name = emp.name.toLowerCase();
801
852
  changed = true;
802
853
  try {
803
- const identityDir = path4.join(os4.homedir(), ".exe-os", "identity");
804
- const oldPath = path4.join(identityDir, `${oldName}.md`);
805
- const newPath = path4.join(identityDir, `${emp.name}.md`);
806
- if (existsSync5(oldPath) && !existsSync5(newPath)) {
854
+ const identityDir = path5.join(os4.homedir(), ".exe-os", "identity");
855
+ const oldPath = path5.join(identityDir, `${oldName}.md`);
856
+ const newPath = path5.join(identityDir, `${emp.name}.md`);
857
+ if (existsSync6(oldPath) && !existsSync6(newPath)) {
807
858
  renameSync3(oldPath, newPath);
808
- } else if (existsSync5(oldPath) && oldPath !== newPath) {
809
- const content = readFileSync5(oldPath, "utf-8");
810
- writeFileSync3(newPath, content, "utf-8");
859
+ } else if (existsSync6(oldPath) && oldPath !== newPath) {
860
+ const content = readFileSync6(oldPath, "utf-8");
861
+ writeFileSync4(newPath, content, "utf-8");
811
862
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
812
863
  unlinkSync(oldPath);
813
864
  }
@@ -837,7 +888,7 @@ function registerBinSymlinks(name) {
837
888
  errors.push("Could not find 'exe-os' in PATH");
838
889
  return { created, skipped, errors };
839
890
  }
840
- const binDir = path4.dirname(exeBinPath);
891
+ const binDir = path5.dirname(exeBinPath);
841
892
  let target;
842
893
  try {
843
894
  target = readlinkSync(exeBinPath);
@@ -847,8 +898,8 @@ function registerBinSymlinks(name) {
847
898
  }
848
899
  for (const suffix of ["", "-opencode"]) {
849
900
  const linkName = `${name}${suffix}`;
850
- const linkPath = path4.join(binDir, linkName);
851
- if (existsSync5(linkPath)) {
901
+ const linkPath = path5.join(binDir, linkName);
902
+ if (existsSync6(linkPath)) {
852
903
  skipped.push(linkName);
853
904
  continue;
854
905
  }
@@ -866,7 +917,7 @@ var init_employees = __esm({
866
917
  "src/lib/employees.ts"() {
867
918
  "use strict";
868
919
  init_config();
869
- EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
920
+ EMPLOYEES_PATH = path5.join(EXE_AI_DIR, "exe-employees.json");
870
921
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
871
922
  COORDINATOR_ROLE = "COO";
872
923
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
@@ -877,8 +928,8 @@ var init_employees = __esm({
877
928
  import net from "net";
878
929
  import { spawn } from "child_process";
879
930
  import { randomUUID } from "crypto";
880
- import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
881
- import path5 from "path";
931
+ import { existsSync as existsSync7, unlinkSync as unlinkSync2, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
932
+ import path6 from "path";
882
933
  import { fileURLToPath } from "url";
883
934
  function handleData(chunk) {
884
935
  _buffer += chunk.toString();
@@ -906,9 +957,9 @@ function handleData(chunk) {
906
957
  }
907
958
  }
908
959
  function cleanupStaleFiles() {
909
- if (existsSync6(PID_PATH)) {
960
+ if (existsSync7(PID_PATH)) {
910
961
  try {
911
- const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
962
+ const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
912
963
  if (pid > 0) {
913
964
  try {
914
965
  process.kill(pid, 0);
@@ -929,11 +980,11 @@ function cleanupStaleFiles() {
929
980
  }
930
981
  }
931
982
  function findPackageRoot() {
932
- let dir = path5.dirname(fileURLToPath(import.meta.url));
933
- const { root } = path5.parse(dir);
983
+ let dir = path6.dirname(fileURLToPath(import.meta.url));
984
+ const { root } = path6.parse(dir);
934
985
  while (dir !== root) {
935
- if (existsSync6(path5.join(dir, "package.json"))) return dir;
936
- dir = path5.dirname(dir);
986
+ if (existsSync7(path6.join(dir, "package.json"))) return dir;
987
+ dir = path6.dirname(dir);
937
988
  }
938
989
  return null;
939
990
  }
@@ -943,8 +994,8 @@ function spawnDaemon() {
943
994
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
944
995
  return;
945
996
  }
946
- const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
947
- if (!existsSync6(daemonPath)) {
997
+ const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
998
+ if (!existsSync7(daemonPath)) {
948
999
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
949
1000
  `);
950
1001
  return;
@@ -952,7 +1003,7 @@ function spawnDaemon() {
952
1003
  const resolvedPath = daemonPath;
953
1004
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
954
1005
  `);
955
- const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
1006
+ const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
956
1007
  let stderrFd = "ignore";
957
1008
  try {
958
1009
  stderrFd = openSync(logPath, "a");
@@ -1097,9 +1148,9 @@ var init_exe_daemon_client = __esm({
1097
1148
  "src/lib/exe-daemon-client.ts"() {
1098
1149
  "use strict";
1099
1150
  init_config();
1100
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
1101
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
1102
- SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
1151
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
1152
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
1153
+ SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
1103
1154
  SPAWN_LOCK_STALE_MS = 3e4;
1104
1155
  CONNECT_TIMEOUT_MS = 15e3;
1105
1156
  REQUEST_TIMEOUT_MS = 3e4;
@@ -2340,9 +2391,9 @@ __export(license_exports, {
2340
2391
  stopLicenseRevalidation: () => stopLicenseRevalidation,
2341
2392
  validateLicense: () => validateLicense
2342
2393
  });
2343
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
2394
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
2344
2395
  import { randomUUID as randomUUID2 } from "crypto";
2345
- import path6 from "path";
2396
+ import path7 from "path";
2346
2397
  import { jwtVerify, importSPKI } from "jose";
2347
2398
  async function fetchRetry(url, init) {
2348
2399
  try {
@@ -2353,37 +2404,37 @@ async function fetchRetry(url, init) {
2353
2404
  }
2354
2405
  }
2355
2406
  function loadDeviceId() {
2356
- const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
2407
+ const deviceJsonPath = path7.join(EXE_AI_DIR, "device.json");
2357
2408
  try {
2358
- if (existsSync7(deviceJsonPath)) {
2359
- const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
2409
+ if (existsSync8(deviceJsonPath)) {
2410
+ const data = JSON.parse(readFileSync8(deviceJsonPath, "utf8"));
2360
2411
  if (data.deviceId) return data.deviceId;
2361
2412
  }
2362
2413
  } catch {
2363
2414
  }
2364
2415
  try {
2365
- if (existsSync7(DEVICE_ID_PATH)) {
2366
- const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
2416
+ if (existsSync8(DEVICE_ID_PATH)) {
2417
+ const id2 = readFileSync8(DEVICE_ID_PATH, "utf8").trim();
2367
2418
  if (id2) return id2;
2368
2419
  }
2369
2420
  } catch {
2370
2421
  }
2371
2422
  const id = randomUUID2();
2372
- mkdirSync3(EXE_AI_DIR, { recursive: true });
2373
- writeFileSync4(DEVICE_ID_PATH, id, "utf8");
2423
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
2424
+ writeFileSync5(DEVICE_ID_PATH, id, "utf8");
2374
2425
  return id;
2375
2426
  }
2376
2427
  function loadLicense() {
2377
2428
  try {
2378
- if (!existsSync7(LICENSE_PATH)) return null;
2379
- return readFileSync7(LICENSE_PATH, "utf8").trim();
2429
+ if (!existsSync8(LICENSE_PATH)) return null;
2430
+ return readFileSync8(LICENSE_PATH, "utf8").trim();
2380
2431
  } catch {
2381
2432
  return null;
2382
2433
  }
2383
2434
  }
2384
2435
  function saveLicense(apiKey) {
2385
- mkdirSync3(EXE_AI_DIR, { recursive: true });
2386
- writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2436
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
2437
+ writeFileSync5(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2387
2438
  }
2388
2439
  async function verifyLicenseJwt(token) {
2389
2440
  try {
@@ -2409,8 +2460,8 @@ async function verifyLicenseJwt(token) {
2409
2460
  }
2410
2461
  async function getCachedLicense() {
2411
2462
  try {
2412
- if (!existsSync7(CACHE_PATH)) return null;
2413
- const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
2463
+ if (!existsSync8(CACHE_PATH)) return null;
2464
+ const raw = JSON.parse(readFileSync8(CACHE_PATH, "utf8"));
2414
2465
  if (!raw.token || typeof raw.token !== "string") return null;
2415
2466
  return await verifyLicenseJwt(raw.token);
2416
2467
  } catch {
@@ -2419,8 +2470,8 @@ async function getCachedLicense() {
2419
2470
  }
2420
2471
  function readCachedToken() {
2421
2472
  try {
2422
- if (!existsSync7(CACHE_PATH)) return null;
2423
- const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
2473
+ if (!existsSync8(CACHE_PATH)) return null;
2474
+ const raw = JSON.parse(readFileSync8(CACHE_PATH, "utf8"));
2424
2475
  return typeof raw.token === "string" ? raw.token : null;
2425
2476
  } catch {
2426
2477
  return null;
@@ -2454,7 +2505,7 @@ function getRawCachedPlan() {
2454
2505
  }
2455
2506
  function cacheResponse(token) {
2456
2507
  try {
2457
- writeFileSync4(CACHE_PATH, JSON.stringify({ token }), "utf8");
2508
+ writeFileSync5(CACHE_PATH, JSON.stringify({ token }), "utf8");
2458
2509
  } catch {
2459
2510
  }
2460
2511
  }
@@ -2518,9 +2569,9 @@ async function checkLicense() {
2518
2569
  let key = loadLicense();
2519
2570
  if (!key) {
2520
2571
  try {
2521
- const configPath = path6.join(EXE_AI_DIR, "config.json");
2522
- if (existsSync7(configPath)) {
2523
- const raw = JSON.parse(readFileSync7(configPath, "utf8"));
2572
+ const configPath = path7.join(EXE_AI_DIR, "config.json");
2573
+ if (existsSync8(configPath)) {
2574
+ const raw = JSON.parse(readFileSync8(configPath, "utf8"));
2524
2575
  const cloud = raw.cloud;
2525
2576
  if (cloud?.apiKey) {
2526
2577
  key = cloud.apiKey;
@@ -2679,9 +2730,9 @@ var init_license = __esm({
2679
2730
  "src/lib/license.ts"() {
2680
2731
  "use strict";
2681
2732
  init_config();
2682
- LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
2683
- CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
2684
- DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
2733
+ LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
2734
+ CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
2735
+ DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
2685
2736
  API_BASE = "https://askexe.com/cloud";
2686
2737
  RETRY_DELAY_MS = 500;
2687
2738
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -2711,12 +2762,12 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
2711
2762
  });
2712
2763
 
2713
2764
  // src/lib/plan-limits.ts
2714
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
2715
- import path7 from "path";
2765
+ import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
2766
+ import path8 from "path";
2716
2767
  function getLicenseSync() {
2717
2768
  try {
2718
- if (!existsSync8(CACHE_PATH2)) return freeLicense();
2719
- const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
2769
+ if (!existsSync9(CACHE_PATH2)) return freeLicense();
2770
+ const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
2720
2771
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
2721
2772
  const parts = raw.token.split(".");
2722
2773
  if (parts.length !== 3) return freeLicense();
@@ -2754,8 +2805,8 @@ function assertEmployeeLimitSync(rosterPath) {
2754
2805
  const filePath = rosterPath ?? EMPLOYEES_PATH;
2755
2806
  let count = 0;
2756
2807
  try {
2757
- if (existsSync8(filePath)) {
2758
- const raw = readFileSync8(filePath, "utf8");
2808
+ if (existsSync9(filePath)) {
2809
+ const raw = readFileSync9(filePath, "utf8");
2759
2810
  const employees = JSON.parse(raw);
2760
2811
  count = Array.isArray(employees) ? employees.length : 0;
2761
2812
  }
@@ -2784,19 +2835,19 @@ var init_plan_limits = __esm({
2784
2835
  this.name = "PlanLimitError";
2785
2836
  }
2786
2837
  };
2787
- CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
2838
+ CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
2788
2839
  }
2789
2840
  });
2790
2841
 
2791
2842
  // src/lib/notifications.ts
2792
2843
  import crypto from "crypto";
2793
- import path8 from "path";
2844
+ import path9 from "path";
2794
2845
  import os5 from "os";
2795
2846
  import {
2796
- readFileSync as readFileSync9,
2847
+ readFileSync as readFileSync10,
2797
2848
  readdirSync,
2798
2849
  unlinkSync as unlinkSync3,
2799
- existsSync as existsSync9,
2850
+ existsSync as existsSync10,
2800
2851
  rmdirSync
2801
2852
  } from "fs";
2802
2853
  async function writeNotification(notification) {
@@ -2947,11 +2998,11 @@ __export(tasks_crud_exports, {
2947
2998
  writeCheckpoint: () => writeCheckpoint
2948
2999
  });
2949
3000
  import crypto3 from "crypto";
2950
- import path9 from "path";
3001
+ import path10 from "path";
2951
3002
  import os6 from "os";
2952
3003
  import { execSync as execSync5 } from "child_process";
2953
3004
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2954
- import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
3005
+ import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
2955
3006
  async function writeCheckpoint(input) {
2956
3007
  const client = getClient();
2957
3008
  const row = await resolveTask(client, input.taskId);
@@ -3126,8 +3177,8 @@ ${laneWarning}` : laneWarning;
3126
3177
  }
3127
3178
  if (input.baseDir) {
3128
3179
  try {
3129
- await mkdir3(path9.join(input.baseDir, "exe", "output"), { recursive: true });
3130
- await mkdir3(path9.join(input.baseDir, "exe", "research"), { recursive: true });
3180
+ await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
3181
+ await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
3131
3182
  await ensureArchitectureDoc(input.baseDir, input.projectName);
3132
3183
  await ensureGitignoreExe(input.baseDir);
3133
3184
  } catch {
@@ -3163,10 +3214,10 @@ ${laneWarning}` : laneWarning;
3163
3214
  });
3164
3215
  if (input.baseDir) {
3165
3216
  try {
3166
- const EXE_OS_DIR = path9.join(os6.homedir(), ".exe-os");
3167
- const mdPath = path9.join(EXE_OS_DIR, taskFile);
3168
- const mdDir = path9.dirname(mdPath);
3169
- if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
3217
+ const EXE_OS_DIR = path10.join(os6.homedir(), ".exe-os");
3218
+ const mdPath = path10.join(EXE_OS_DIR, taskFile);
3219
+ const mdDir = path10.dirname(mdPath);
3220
+ if (!existsSync11(mdDir)) await mkdir3(mdDir, { recursive: true });
3170
3221
  const reviewer = input.reviewer ?? input.assignedBy;
3171
3222
  const mdContent = `# ${input.title}
3172
3223
 
@@ -3191,7 +3242,11 @@ If you skip this, your reviewer will not know you're done and your work won't be
3191
3242
  Do NOT let a failed commit or any error prevent you from calling update_task(done).
3192
3243
  `;
3193
3244
  await writeFile3(mdPath, mdContent, "utf-8");
3194
- } catch {
3245
+ } catch (err) {
3246
+ process.stderr.write(
3247
+ `[create-task] WARNING: .md file write failed for ${taskFile}: ${err instanceof Error ? err.message : String(err)}
3248
+ `
3249
+ );
3195
3250
  }
3196
3251
  }
3197
3252
  return {
@@ -3451,9 +3506,9 @@ async function deleteTaskCore(taskId, _baseDir) {
3451
3506
  return { taskFile, assignedTo, assignedBy, taskSlug };
3452
3507
  }
3453
3508
  async function ensureArchitectureDoc(baseDir, projectName) {
3454
- const archPath = path9.join(baseDir, "exe", "ARCHITECTURE.md");
3509
+ const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
3455
3510
  try {
3456
- if (existsSync10(archPath)) return;
3511
+ if (existsSync11(archPath)) return;
3457
3512
  const template = [
3458
3513
  `# ${projectName} \u2014 System Architecture`,
3459
3514
  "",
@@ -3486,10 +3541,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
3486
3541
  }
3487
3542
  }
3488
3543
  async function ensureGitignoreExe(baseDir) {
3489
- const gitignorePath = path9.join(baseDir, ".gitignore");
3544
+ const gitignorePath = path10.join(baseDir, ".gitignore");
3490
3545
  try {
3491
- if (existsSync10(gitignorePath)) {
3492
- const content = readFileSync10(gitignorePath, "utf-8");
3546
+ if (existsSync11(gitignorePath)) {
3547
+ const content = readFileSync11(gitignorePath, "utf-8");
3493
3548
  if (/^\/?exe\/?$/m.test(content)) return;
3494
3549
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
3495
3550
  } else {
@@ -3520,8 +3575,8 @@ var init_tasks_crud = __esm({
3520
3575
  });
3521
3576
 
3522
3577
  // src/lib/tasks-review.ts
3523
- import path10 from "path";
3524
- import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
3578
+ import path11 from "path";
3579
+ import { existsSync as existsSync12, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
3525
3580
  async function countPendingReviews(sessionScope) {
3526
3581
  const client = getClient();
3527
3582
  if (sessionScope) {
@@ -3702,11 +3757,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
3702
3757
  );
3703
3758
  }
3704
3759
  try {
3705
- const cacheDir = path10.join(EXE_AI_DIR, "session-cache");
3706
- if (existsSync11(cacheDir)) {
3760
+ const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
3761
+ if (existsSync12(cacheDir)) {
3707
3762
  for (const f of readdirSync2(cacheDir)) {
3708
3763
  if (f.startsWith("review-notified-")) {
3709
- unlinkSync4(path10.join(cacheDir, f));
3764
+ unlinkSync4(path11.join(cacheDir, f));
3710
3765
  }
3711
3766
  }
3712
3767
  }
@@ -3727,7 +3782,7 @@ var init_tasks_review = __esm({
3727
3782
  });
3728
3783
 
3729
3784
  // src/lib/tasks-chain.ts
3730
- import path11 from "path";
3785
+ import path12 from "path";
3731
3786
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
3732
3787
  async function cascadeUnblock(taskId, baseDir, now) {
3733
3788
  const client = getClient();
@@ -3744,7 +3799,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
3744
3799
  });
3745
3800
  for (const ur of unblockedRows.rows) {
3746
3801
  try {
3747
- const ubFile = path11.join(baseDir, String(ur.task_file));
3802
+ const ubFile = path12.join(baseDir, String(ur.task_file));
3748
3803
  let ubContent = await readFile3(ubFile, "utf-8");
3749
3804
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
3750
3805
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -3813,7 +3868,7 @@ var init_tasks_chain = __esm({
3813
3868
 
3814
3869
  // src/lib/project-name.ts
3815
3870
  import { execSync as execSync6 } from "child_process";
3816
- import path12 from "path";
3871
+ import path13 from "path";
3817
3872
  function getProjectName(cwd2) {
3818
3873
  const dir = cwd2 ?? process.cwd();
3819
3874
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -3826,7 +3881,7 @@ function getProjectName(cwd2) {
3826
3881
  timeout: 2e3,
3827
3882
  stdio: ["pipe", "pipe", "pipe"]
3828
3883
  }).trim();
3829
- repoRoot = path12.dirname(gitCommonDir);
3884
+ repoRoot = path13.dirname(gitCommonDir);
3830
3885
  } catch {
3831
3886
  repoRoot = execSync6("git rev-parse --show-toplevel", {
3832
3887
  cwd: dir,
@@ -3835,11 +3890,11 @@ function getProjectName(cwd2) {
3835
3890
  stdio: ["pipe", "pipe", "pipe"]
3836
3891
  }).trim();
3837
3892
  }
3838
- _cached2 = path12.basename(repoRoot);
3893
+ _cached2 = path13.basename(repoRoot);
3839
3894
  _cachedCwd = dir;
3840
3895
  return _cached2;
3841
3896
  } catch {
3842
- _cached2 = path12.basename(dir);
3897
+ _cached2 = path13.basename(dir);
3843
3898
  _cachedCwd = dir;
3844
3899
  return _cached2;
3845
3900
  }
@@ -4312,8 +4367,8 @@ __export(tasks_exports, {
4312
4367
  updateTaskStatus: () => updateTaskStatus,
4313
4368
  writeCheckpoint: () => writeCheckpoint
4314
4369
  });
4315
- import path13 from "path";
4316
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync5 } from "fs";
4370
+ import path14 from "path";
4371
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
4317
4372
  async function createTask(input) {
4318
4373
  const result = await createTaskCore(input);
4319
4374
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -4332,11 +4387,11 @@ async function updateTask(input) {
4332
4387
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
4333
4388
  try {
4334
4389
  const agent = String(row.assigned_to);
4335
- const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
4336
- const cachePath = path13.join(cacheDir, `current-task-${agent}.json`);
4390
+ const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
4391
+ const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
4337
4392
  if (input.status === "in_progress") {
4338
- mkdirSync4(cacheDir, { recursive: true });
4339
- writeFileSync5(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
4393
+ mkdirSync5(cacheDir, { recursive: true });
4394
+ writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
4340
4395
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
4341
4396
  try {
4342
4397
  unlinkSync5(cachePath);
@@ -4803,13 +4858,13 @@ __export(tmux_routing_exports, {
4803
4858
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
4804
4859
  });
4805
4860
  import { execFileSync as execFileSync3, execSync as execSync7 } from "child_process";
4806
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync12, appendFileSync } from "fs";
4807
- import path14 from "path";
4861
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync13, appendFileSync } from "fs";
4862
+ import path15 from "path";
4808
4863
  import os7 from "os";
4809
4864
  import { fileURLToPath as fileURLToPath2 } from "url";
4810
4865
  import { unlinkSync as unlinkSync6 } from "fs";
4811
4866
  function spawnLockPath(sessionName) {
4812
- return path14.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
4867
+ return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
4813
4868
  }
4814
4869
  function isProcessAlive(pid) {
4815
4870
  try {
@@ -4820,13 +4875,13 @@ function isProcessAlive(pid) {
4820
4875
  }
4821
4876
  }
4822
4877
  function acquireSpawnLock2(sessionName) {
4823
- if (!existsSync12(SPAWN_LOCK_DIR)) {
4824
- mkdirSync5(SPAWN_LOCK_DIR, { recursive: true });
4878
+ if (!existsSync13(SPAWN_LOCK_DIR)) {
4879
+ mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
4825
4880
  }
4826
4881
  const lockFile = spawnLockPath(sessionName);
4827
- if (existsSync12(lockFile)) {
4882
+ if (existsSync13(lockFile)) {
4828
4883
  try {
4829
- const lock = JSON.parse(readFileSync11(lockFile, "utf8"));
4884
+ const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
4830
4885
  const age = Date.now() - lock.timestamp;
4831
4886
  if (isProcessAlive(lock.pid) && age < 6e4) {
4832
4887
  return false;
@@ -4834,7 +4889,7 @@ function acquireSpawnLock2(sessionName) {
4834
4889
  } catch {
4835
4890
  }
4836
4891
  }
4837
- writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
4892
+ writeFileSync7(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
4838
4893
  return true;
4839
4894
  }
4840
4895
  function releaseSpawnLock2(sessionName) {
@@ -4846,13 +4901,13 @@ function releaseSpawnLock2(sessionName) {
4846
4901
  function resolveBehaviorsExporterScript() {
4847
4902
  try {
4848
4903
  const thisFile = fileURLToPath2(import.meta.url);
4849
- const scriptPath = path14.join(
4850
- path14.dirname(thisFile),
4904
+ const scriptPath = path15.join(
4905
+ path15.dirname(thisFile),
4851
4906
  "..",
4852
4907
  "bin",
4853
4908
  "exe-export-behaviors.js"
4854
4909
  );
4855
- return existsSync12(scriptPath) ? scriptPath : null;
4910
+ return existsSync13(scriptPath) ? scriptPath : null;
4856
4911
  } catch {
4857
4912
  return null;
4858
4913
  }
@@ -4918,12 +4973,12 @@ function extractRootExe(name) {
4918
4973
  return parts.length > 0 ? parts[parts.length - 1] : null;
4919
4974
  }
4920
4975
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4921
- if (!existsSync12(SESSION_CACHE)) {
4922
- mkdirSync5(SESSION_CACHE, { recursive: true });
4976
+ if (!existsSync13(SESSION_CACHE)) {
4977
+ mkdirSync6(SESSION_CACHE, { recursive: true });
4923
4978
  }
4924
4979
  const rootExe = extractRootExe(parentExe) ?? parentExe;
4925
- const filePath = path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
4926
- writeFileSync6(filePath, JSON.stringify({
4980
+ const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
4981
+ writeFileSync7(filePath, JSON.stringify({
4927
4982
  parentExe: rootExe,
4928
4983
  dispatchedBy: dispatchedBy || rootExe,
4929
4984
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -4931,7 +4986,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
4931
4986
  }
4932
4987
  function getParentExe(sessionKey) {
4933
4988
  try {
4934
- const data = JSON.parse(readFileSync11(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4989
+ const data = JSON.parse(readFileSync12(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
4935
4990
  return data.parentExe || null;
4936
4991
  } catch {
4937
4992
  return null;
@@ -4939,8 +4994,8 @@ function getParentExe(sessionKey) {
4939
4994
  }
4940
4995
  function getDispatchedBy(sessionKey) {
4941
4996
  try {
4942
- const data = JSON.parse(readFileSync11(
4943
- path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
4997
+ const data = JSON.parse(readFileSync12(
4998
+ path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
4944
4999
  "utf8"
4945
5000
  ));
4946
5001
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -5001,32 +5056,50 @@ async function verifyPaneAtCapacity(sessionName) {
5001
5056
  }
5002
5057
  function readDebounceState() {
5003
5058
  try {
5004
- if (!existsSync12(DEBOUNCE_FILE)) return {};
5005
- return JSON.parse(readFileSync11(DEBOUNCE_FILE, "utf8"));
5059
+ if (!existsSync13(DEBOUNCE_FILE)) return {};
5060
+ const raw = JSON.parse(readFileSync12(DEBOUNCE_FILE, "utf8"));
5061
+ const state = {};
5062
+ for (const [key, val] of Object.entries(raw)) {
5063
+ if (typeof val === "number") {
5064
+ state[key] = { lastSent: val, pending: 0 };
5065
+ } else if (val && typeof val === "object" && "lastSent" in val) {
5066
+ state[key] = val;
5067
+ }
5068
+ }
5069
+ return state;
5006
5070
  } catch {
5007
5071
  return {};
5008
5072
  }
5009
5073
  }
5010
5074
  function writeDebounceState(state) {
5011
5075
  try {
5012
- if (!existsSync12(SESSION_CACHE)) mkdirSync5(SESSION_CACHE, { recursive: true });
5013
- writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
5076
+ if (!existsSync13(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
5077
+ writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
5014
5078
  } catch {
5015
5079
  }
5016
5080
  }
5017
5081
  function isDebounced(targetSession) {
5018
5082
  const state = readDebounceState();
5019
- const lastSent = state[targetSession] ?? 0;
5020
- return Date.now() - lastSent < INTERCOM_DEBOUNCE_MS;
5083
+ const entry = state[targetSession];
5084
+ const lastSent = entry?.lastSent ?? 0;
5085
+ if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
5086
+ if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
5087
+ state[targetSession].pending++;
5088
+ writeDebounceState(state);
5089
+ return true;
5090
+ }
5091
+ return false;
5021
5092
  }
5022
5093
  function recordDebounce(targetSession) {
5023
5094
  const state = readDebounceState();
5024
- state[targetSession] = Date.now();
5095
+ const batched = state[targetSession]?.pending ?? 0;
5096
+ state[targetSession] = { lastSent: Date.now(), pending: 0 };
5025
5097
  const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
5026
5098
  for (const key of Object.keys(state)) {
5027
- if ((state[key] ?? 0) < cutoff) delete state[key];
5099
+ if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
5028
5100
  }
5029
5101
  writeDebounceState(state);
5102
+ return batched;
5030
5103
  }
5031
5104
  function logIntercom(msg) {
5032
5105
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
@@ -5071,7 +5144,7 @@ function sendIntercom(targetSession) {
5071
5144
  return "skipped_exe";
5072
5145
  }
5073
5146
  if (isDebounced(targetSession)) {
5074
- logIntercom(`DEBOUNCE \u2192 ${targetSession} (cross-process file debounce)`);
5147
+ logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
5075
5148
  return "debounced";
5076
5149
  }
5077
5150
  try {
@@ -5083,14 +5156,14 @@ function sendIntercom(targetSession) {
5083
5156
  const sessionState = getSessionState(targetSession);
5084
5157
  if (sessionState === "no_claude") {
5085
5158
  queueIntercom(targetSession, "claude not running in session");
5086
- recordDebounce(targetSession);
5087
- logIntercom(`QUEUED \u2192 ${targetSession} (no claude process \u2014 raw shell detected)`);
5159
+ const batched2 = recordDebounce(targetSession);
5160
+ logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
5088
5161
  return "queued";
5089
5162
  }
5090
5163
  if (sessionState === "thinking" || sessionState === "tool") {
5091
5164
  queueIntercom(targetSession, "session busy at send time");
5092
- recordDebounce(targetSession);
5093
- logIntercom(`QUEUED \u2192 ${targetSession} (session busy, will retry from queue)`);
5165
+ const batched2 = recordDebounce(targetSession);
5166
+ logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
5094
5167
  return "queued";
5095
5168
  }
5096
5169
  if (transport.isPaneInCopyMode(targetSession)) {
@@ -5098,8 +5171,8 @@ function sendIntercom(targetSession) {
5098
5171
  transport.sendKeys(targetSession, "q");
5099
5172
  }
5100
5173
  transport.sendKeys(targetSession, "/exe-intercom");
5101
- recordDebounce(targetSession);
5102
- logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
5174
+ const batched = recordDebounce(targetSession);
5175
+ logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
5103
5176
  return "delivered";
5104
5177
  } catch {
5105
5178
  logIntercom(`FAIL \u2192 ${targetSession}`);
@@ -5201,26 +5274,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5201
5274
  const transport = getTransport();
5202
5275
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
5203
5276
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
5204
- const logDir = path14.join(os7.homedir(), ".exe-os", "session-logs");
5205
- const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5206
- if (!existsSync12(logDir)) {
5207
- mkdirSync5(logDir, { recursive: true });
5277
+ const logDir = path15.join(os7.homedir(), ".exe-os", "session-logs");
5278
+ const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5279
+ if (!existsSync13(logDir)) {
5280
+ mkdirSync6(logDir, { recursive: true });
5208
5281
  }
5209
5282
  transport.kill(sessionName);
5210
5283
  let cleanupSuffix = "";
5211
5284
  try {
5212
5285
  const thisFile = fileURLToPath2(import.meta.url);
5213
- const cleanupScript = path14.join(path14.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5214
- if (existsSync12(cleanupScript)) {
5286
+ const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
5287
+ if (existsSync13(cleanupScript)) {
5215
5288
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
5216
5289
  }
5217
5290
  } catch {
5218
5291
  }
5219
5292
  try {
5220
- const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
5293
+ const claudeJsonPath = path15.join(os7.homedir(), ".claude.json");
5221
5294
  let claudeJson = {};
5222
5295
  try {
5223
- claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
5296
+ claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
5224
5297
  } catch {
5225
5298
  }
5226
5299
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -5228,17 +5301,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5228
5301
  const trustDir = opts?.cwd ?? projectDir;
5229
5302
  if (!projects[trustDir]) projects[trustDir] = {};
5230
5303
  projects[trustDir].hasTrustDialogAccepted = true;
5231
- writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
5304
+ writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
5232
5305
  } catch {
5233
5306
  }
5234
5307
  try {
5235
- const settingsDir = path14.join(os7.homedir(), ".claude", "projects");
5308
+ const settingsDir = path15.join(os7.homedir(), ".claude", "projects");
5236
5309
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
5237
- const projSettingsDir = path14.join(settingsDir, normalizedKey);
5238
- const settingsPath = path14.join(projSettingsDir, "settings.json");
5310
+ const projSettingsDir = path15.join(settingsDir, normalizedKey);
5311
+ const settingsPath = path15.join(projSettingsDir, "settings.json");
5239
5312
  let settings = {};
5240
5313
  try {
5241
- settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
5314
+ settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
5242
5315
  } catch {
5243
5316
  }
5244
5317
  const perms = settings.permissions ?? {};
@@ -5266,20 +5339,23 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5266
5339
  if (changed) {
5267
5340
  perms.allow = allow;
5268
5341
  settings.permissions = perms;
5269
- mkdirSync5(projSettingsDir, { recursive: true });
5270
- writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5342
+ mkdirSync6(projSettingsDir, { recursive: true });
5343
+ writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n");
5271
5344
  }
5272
5345
  } catch {
5273
5346
  }
5274
5347
  const spawnCwd = opts?.cwd ?? projectDir;
5275
5348
  const useExeAgent = !!(opts?.model && opts?.provider);
5276
- const ccProvider = useExeAgent ? DEFAULT_PROVIDER : detectActiveProvider();
5349
+ const agentRtConfig = getAgentRuntime(employeeName);
5350
+ const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
5351
+ const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
5352
+ const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
5277
5353
  const useBinSymlink = ccProvider !== DEFAULT_PROVIDER;
5278
5354
  let identityFlag = "";
5279
5355
  let behaviorsFlag = "";
5280
5356
  let legacyFallbackWarned = false;
5281
5357
  if (!useExeAgent && !useBinSymlink) {
5282
- const identityPath = path14.join(
5358
+ const identityPath = path15.join(
5283
5359
  os7.homedir(),
5284
5360
  ".exe-os",
5285
5361
  "identity",
@@ -5289,13 +5365,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5289
5365
  const hasAgentFlag = claudeSupportsAgentFlag();
5290
5366
  if (hasAgentFlag) {
5291
5367
  identityFlag = ` --agent ${employeeName}`;
5292
- } else if (existsSync12(identityPath)) {
5368
+ } else if (existsSync13(identityPath)) {
5293
5369
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
5294
5370
  legacyFallbackWarned = true;
5295
5371
  }
5296
5372
  const behaviorsFile = exportBehaviorsSync(
5297
5373
  employeeName,
5298
- path14.basename(spawnCwd),
5374
+ path15.basename(spawnCwd),
5299
5375
  sessionName
5300
5376
  );
5301
5377
  if (behaviorsFile) {
@@ -5310,16 +5386,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5310
5386
  }
5311
5387
  let sessionContextFlag = "";
5312
5388
  try {
5313
- const ctxDir = path14.join(os7.homedir(), ".exe-os", "session-cache");
5314
- mkdirSync5(ctxDir, { recursive: true });
5315
- const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
5389
+ const ctxDir = path15.join(os7.homedir(), ".exe-os", "session-cache");
5390
+ mkdirSync6(ctxDir, { recursive: true });
5391
+ const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
5316
5392
  const ctxContent = [
5317
5393
  `## Session Context`,
5318
5394
  `You are running in tmux session: ${sessionName}.`,
5319
5395
  `Your parent coordinator session is ${exeSession}.`,
5320
5396
  `Your employees (if any) use the -${exeSession} suffix.`
5321
5397
  ].join("\n");
5322
- writeFileSync6(ctxFile, ctxContent);
5398
+ writeFileSync7(ctxFile, ctxContent);
5323
5399
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
5324
5400
  } catch {
5325
5401
  }
@@ -5333,9 +5409,48 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5333
5409
  }
5334
5410
  }
5335
5411
  }
5412
+ if (useCodex) {
5413
+ const codexCfg = RUNTIME_TABLE.codex;
5414
+ if (codexCfg?.apiKeyEnv) {
5415
+ const keyVal = process.env[codexCfg.apiKeyEnv];
5416
+ if (keyVal) {
5417
+ envPrefix = `${envPrefix} ${codexCfg.apiKeyEnv}=${keyVal}`;
5418
+ }
5419
+ }
5420
+ envPrefix = `${envPrefix} EXE_AGENT_MODEL=${agentRtConfig.model}`;
5421
+ }
5422
+ if (useOpencode) {
5423
+ const ocCfg = PROVIDER_TABLE.opencode;
5424
+ if (ocCfg?.apiKeyEnv) {
5425
+ const keyVal = process.env[ocCfg.apiKeyEnv];
5426
+ if (keyVal) {
5427
+ envPrefix = `${envPrefix} ${ocCfg.apiKeyEnv}=${keyVal}`;
5428
+ }
5429
+ }
5430
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
5431
+ }
5432
+ if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
5433
+ const defaultClaudeModel = DEFAULT_MODELS.claude;
5434
+ if (agentRtConfig.runtime === "claude" && agentRtConfig.model !== defaultClaudeModel) {
5435
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
5436
+ }
5437
+ }
5336
5438
  let spawnCommand;
5337
5439
  if (useExeAgent) {
5338
5440
  spawnCommand = `${envPrefix} exe-agent --employee ${employeeName} --model ${opts.model} --provider ${opts.provider}${cleanupSuffix}`;
5441
+ } else if (useCodex) {
5442
+ process.stderr.write(
5443
+ `[tmux-routing] agent-config: ${employeeName} \u2192 codex (${agentRtConfig.model})
5444
+ `
5445
+ );
5446
+ spawnCommand = `${envPrefix} exe-start-codex --agent ${employeeName}${cleanupSuffix}`;
5447
+ } else if (useOpencode) {
5448
+ const binName = `${employeeName}-opencode`;
5449
+ process.stderr.write(
5450
+ `[tmux-routing] agent-config: ${employeeName} \u2192 opencode (${agentRtConfig.model})
5451
+ `
5452
+ );
5453
+ spawnCommand = `${envPrefix} ${binName}${cleanupSuffix}`;
5339
5454
  } else if (useBinSymlink) {
5340
5455
  const binName = `${employeeName}-${ccProvider}`;
5341
5456
  process.stderr.write(
@@ -5357,11 +5472,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5357
5472
  transport.pipeLog(sessionName, logFile);
5358
5473
  try {
5359
5474
  const mySession = getMySession();
5360
- const dispatchInfo = path14.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5361
- writeFileSync6(dispatchInfo, JSON.stringify({
5475
+ const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
5476
+ writeFileSync7(dispatchInfo, JSON.stringify({
5362
5477
  dispatchedBy: mySession,
5363
5478
  rootExe: exeSession,
5364
- provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
5479
+ provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
5480
+ runtime: useCodex ? "codex" : useOpencode ? "opencode" : useExeAgent ? "exe-agent" : "claude",
5481
+ model: useCodex ? agentRtConfig.model : useOpencode ? agentRtConfig.model : void 0,
5365
5482
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
5366
5483
  }));
5367
5484
  } catch {
@@ -5379,6 +5496,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5379
5496
  booted = true;
5380
5497
  break;
5381
5498
  }
5499
+ } else if (useCodex) {
5500
+ if (pane.includes("codex") || pane.includes("Codex") || pane.includes("exe-start-codex")) {
5501
+ booted = true;
5502
+ break;
5503
+ }
5382
5504
  } else {
5383
5505
  if (pane.includes("Claude Code") || pane.includes("\u276F")) {
5384
5506
  booted = true;
@@ -5390,9 +5512,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5390
5512
  }
5391
5513
  if (!booted) {
5392
5514
  releaseSpawnLock2(sessionName);
5393
- return { sessionName, error: `${useExeAgent ? "exe-agent" : "claude"} did not boot within 15s` };
5515
+ const runtimeLabel = useExeAgent ? "exe-agent" : useCodex ? "codex" : "claude";
5516
+ return { sessionName, error: `${runtimeLabel} did not boot within 15s` };
5394
5517
  }
5395
- if (!useExeAgent) {
5518
+ if (!useExeAgent && !useCodex) {
5396
5519
  try {
5397
5520
  transport.sendKeys(sessionName, `/exe-call ${employeeName}`);
5398
5521
  } catch {
@@ -5419,17 +5542,19 @@ var init_tmux_routing = __esm({
5419
5542
  init_cc_agent_support();
5420
5543
  init_mcp_prefix();
5421
5544
  init_provider_table();
5545
+ init_agent_config();
5546
+ init_runtime_table();
5422
5547
  init_intercom_queue();
5423
5548
  init_plan_limits();
5424
5549
  init_employees();
5425
- SPAWN_LOCK_DIR = path14.join(os7.homedir(), ".exe-os", "spawn-locks");
5426
- SESSION_CACHE = path14.join(os7.homedir(), ".exe-os", "session-cache");
5550
+ SPAWN_LOCK_DIR = path15.join(os7.homedir(), ".exe-os", "spawn-locks");
5551
+ SESSION_CACHE = path15.join(os7.homedir(), ".exe-os", "session-cache");
5427
5552
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5428
5553
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5429
5554
  VERIFY_PANE_LINES = 200;
5430
5555
  INTERCOM_DEBOUNCE_MS = 3e4;
5431
- INTERCOM_LOG2 = path14.join(os7.homedir(), ".exe-os", "intercom.log");
5432
- DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
5556
+ INTERCOM_LOG2 = path15.join(os7.homedir(), ".exe-os", "intercom.log");
5557
+ DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
5433
5558
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5434
5559
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
5435
5560
  }
@@ -7298,10 +7423,10 @@ var init_hooks = __esm({
7298
7423
  });
7299
7424
 
7300
7425
  // src/runtime/safety-checks.ts
7301
- import path15 from "path";
7426
+ import path16 from "path";
7302
7427
  import os8 from "os";
7303
7428
  function checkPathSafety(filePath) {
7304
- const resolved = path15.resolve(filePath);
7429
+ const resolved = path16.resolve(filePath);
7305
7430
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
7306
7431
  const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
7307
7432
  if (matches) {
@@ -7311,7 +7436,7 @@ function checkPathSafety(filePath) {
7311
7436
  return { safe: true, bypassImmune: true };
7312
7437
  }
7313
7438
  function checkReadPathSafety(filePath) {
7314
- const resolved = path15.resolve(filePath);
7439
+ const resolved = path16.resolve(filePath);
7315
7440
  const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
7316
7441
  (p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
7317
7442
  );
@@ -7337,11 +7462,11 @@ var init_safety_checks = __esm({
7337
7462
  reason: "Git config can set hooks and command execution"
7338
7463
  },
7339
7464
  {
7340
- pattern: (p) => p.startsWith(path15.join(HOME, ".claude")),
7465
+ pattern: (p) => p.startsWith(path16.join(HOME, ".claude")),
7341
7466
  reason: "Claude configuration files are protected"
7342
7467
  },
7343
7468
  {
7344
- pattern: (p) => p.startsWith(path15.join(HOME, ".exe-os")),
7469
+ pattern: (p) => p.startsWith(path16.join(HOME, ".exe-os")),
7345
7470
  reason: "exe-os configuration files are protected"
7346
7471
  },
7347
7472
  {
@@ -7358,7 +7483,7 @@ var init_safety_checks = __esm({
7358
7483
  },
7359
7484
  {
7360
7485
  pattern: (p) => {
7361
- const name = path15.basename(p);
7486
+ const name = path16.basename(p);
7362
7487
  return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
7363
7488
  },
7364
7489
  reason: "Shell configuration files can execute arbitrary code on login"
@@ -7385,7 +7510,7 @@ __export(file_read_exports, {
7385
7510
  FileReadTool: () => FileReadTool
7386
7511
  });
7387
7512
  import fs3 from "fs/promises";
7388
- import path16 from "path";
7513
+ import path17 from "path";
7389
7514
  import { z } from "zod";
7390
7515
  function isBinary(buf) {
7391
7516
  for (let i = 0; i < buf.length; i++) {
@@ -7421,7 +7546,7 @@ var init_file_read = __esm({
7421
7546
  return { behavior: "allow" };
7422
7547
  },
7423
7548
  async call(input, context) {
7424
- const filePath = path16.isAbsolute(input.file_path) ? input.file_path : path16.resolve(context.cwd, input.file_path);
7549
+ const filePath = path17.isAbsolute(input.file_path) ? input.file_path : path17.resolve(context.cwd, input.file_path);
7425
7550
  let stat;
7426
7551
  try {
7427
7552
  stat = await fs3.stat(filePath);
@@ -7461,7 +7586,7 @@ __export(glob_exports, {
7461
7586
  GlobTool: () => GlobTool
7462
7587
  });
7463
7588
  import fs4 from "fs/promises";
7464
- import path17 from "path";
7589
+ import path18 from "path";
7465
7590
  import { z as z2 } from "zod";
7466
7591
  async function walkDir(dir, maxDepth = 10) {
7467
7592
  const results = [];
@@ -7477,7 +7602,7 @@ async function walkDir(dir, maxDepth = 10) {
7477
7602
  if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
7478
7603
  continue;
7479
7604
  }
7480
- const fullPath = path17.join(current, entry.name);
7605
+ const fullPath = path18.join(current, entry.name);
7481
7606
  if (entry.isDirectory()) {
7482
7607
  await walk(fullPath, depth + 1);
7483
7608
  } else {
@@ -7511,11 +7636,11 @@ var init_glob = __esm({
7511
7636
  inputSchema: inputSchema2,
7512
7637
  isReadOnly: true,
7513
7638
  async call(input, context) {
7514
- const baseDir = input.path ? path17.isAbsolute(input.path) ? input.path : path17.resolve(context.cwd, input.path) : context.cwd;
7639
+ const baseDir = input.path ? path18.isAbsolute(input.path) ? input.path : path18.resolve(context.cwd, input.path) : context.cwd;
7515
7640
  try {
7516
7641
  const entries = await walkDir(baseDir);
7517
7642
  const matched = entries.filter(
7518
- (e) => simpleGlobMatch(path17.relative(baseDir, e.path), input.pattern)
7643
+ (e) => simpleGlobMatch(path18.relative(baseDir, e.path), input.pattern)
7519
7644
  );
7520
7645
  matched.sort((a, b) => b.mtime - a.mtime);
7521
7646
  if (matched.length === 0) {
@@ -7541,7 +7666,7 @@ __export(grep_exports, {
7541
7666
  });
7542
7667
  import { spawn as spawn2 } from "child_process";
7543
7668
  import fs5 from "fs/promises";
7544
- import path18 from "path";
7669
+ import path19 from "path";
7545
7670
  import { z as z3 } from "zod";
7546
7671
  function runRipgrep(input, searchPath, context) {
7547
7672
  return new Promise((resolve, reject) => {
@@ -7595,7 +7720,7 @@ async function nodeGrep(input, searchPath) {
7595
7720
  }
7596
7721
  for (const entry of entries) {
7597
7722
  if (entry.name === "node_modules" || entry.name === ".git") continue;
7598
- const fullPath = path18.join(dir, entry.name);
7723
+ const fullPath = path19.join(dir, entry.name);
7599
7724
  if (entry.isDirectory()) {
7600
7725
  await walk(fullPath);
7601
7726
  } else {
@@ -7641,7 +7766,7 @@ var init_grep = __esm({
7641
7766
  inputSchema: inputSchema3,
7642
7767
  isReadOnly: true,
7643
7768
  async call(input, context) {
7644
- const searchPath = input.path ? path18.isAbsolute(input.path) ? input.path : path18.resolve(context.cwd, input.path) : context.cwd;
7769
+ const searchPath = input.path ? path19.isAbsolute(input.path) ? input.path : path19.resolve(context.cwd, input.path) : context.cwd;
7645
7770
  try {
7646
7771
  const result = await runRipgrep(input, searchPath, context);
7647
7772
  return result;
@@ -7666,7 +7791,7 @@ __export(file_write_exports, {
7666
7791
  FileWriteTool: () => FileWriteTool
7667
7792
  });
7668
7793
  import fs6 from "fs/promises";
7669
- import path19 from "path";
7794
+ import path20 from "path";
7670
7795
  import { z as z4 } from "zod";
7671
7796
  var inputSchema4, FileWriteTool;
7672
7797
  var init_file_write = __esm({
@@ -7694,8 +7819,8 @@ var init_file_write = __esm({
7694
7819
  return { behavior: "allow" };
7695
7820
  },
7696
7821
  async call(input, context) {
7697
- const filePath = path19.isAbsolute(input.file_path) ? input.file_path : path19.resolve(context.cwd, input.file_path);
7698
- const dir = path19.dirname(filePath);
7822
+ const filePath = path20.isAbsolute(input.file_path) ? input.file_path : path20.resolve(context.cwd, input.file_path);
7823
+ const dir = path20.dirname(filePath);
7699
7824
  await fs6.mkdir(dir, { recursive: true });
7700
7825
  await fs6.writeFile(filePath, input.content, "utf-8");
7701
7826
  return {
@@ -7713,7 +7838,7 @@ __export(file_edit_exports, {
7713
7838
  FileEditTool: () => FileEditTool
7714
7839
  });
7715
7840
  import fs7 from "fs/promises";
7716
- import path20 from "path";
7841
+ import path21 from "path";
7717
7842
  import { z as z5 } from "zod";
7718
7843
  function countOccurrences(haystack, needle) {
7719
7844
  let count = 0;
@@ -7754,7 +7879,7 @@ var init_file_edit = __esm({
7754
7879
  return { behavior: "allow" };
7755
7880
  },
7756
7881
  async call(input, context) {
7757
- const filePath = path20.isAbsolute(input.file_path) ? input.file_path : path20.resolve(context.cwd, input.file_path);
7882
+ const filePath = path21.isAbsolute(input.file_path) ? input.file_path : path21.resolve(context.cwd, input.file_path);
7758
7883
  let content;
7759
7884
  try {
7760
7885
  content = await fs7.readFile(filePath, "utf-8");
@@ -8419,14 +8544,14 @@ __export(keychain_exports, {
8419
8544
  setMasterKey: () => setMasterKey
8420
8545
  });
8421
8546
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
8422
- import { existsSync as existsSync13 } from "fs";
8423
- import path23 from "path";
8547
+ import { existsSync as existsSync14 } from "fs";
8548
+ import path24 from "path";
8424
8549
  import os9 from "os";
8425
8550
  function getKeyDir() {
8426
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os9.homedir(), ".exe-os");
8551
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path24.join(os9.homedir(), ".exe-os");
8427
8552
  }
8428
8553
  function getKeyPath() {
8429
- return path23.join(getKeyDir(), "master.key");
8554
+ return path24.join(getKeyDir(), "master.key");
8430
8555
  }
8431
8556
  async function tryKeytar() {
8432
8557
  try {
@@ -8447,7 +8572,7 @@ async function getMasterKey() {
8447
8572
  }
8448
8573
  }
8449
8574
  const keyPath = getKeyPath();
8450
- if (!existsSync13(keyPath)) {
8575
+ if (!existsSync14(keyPath)) {
8451
8576
  process.stderr.write(
8452
8577
  `[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
8453
8578
  `
@@ -8490,7 +8615,7 @@ async function deleteMasterKey() {
8490
8615
  }
8491
8616
  }
8492
8617
  const keyPath = getKeyPath();
8493
- if (existsSync13(keyPath)) {
8618
+ if (existsSync14(keyPath)) {
8494
8619
  await unlink(keyPath);
8495
8620
  }
8496
8621
  }
@@ -8790,8 +8915,8 @@ __export(wiki_client_exports, {
8790
8915
  listDocuments: () => listDocuments,
8791
8916
  listWorkspaces: () => listWorkspaces
8792
8917
  });
8793
- async function wikiFetch(config, path25, method = "GET", body) {
8794
- const url = `${config.baseUrl}/api/v1${path25}`;
8918
+ async function wikiFetch(config, path26, method = "GET", body) {
8919
+ const url = `${config.baseUrl}/api/v1${path26}`;
8795
8920
  const headers = {
8796
8921
  Authorization: `Bearer ${config.apiKey}`,
8797
8922
  "Content-Type": "application/json"
@@ -8824,7 +8949,7 @@ async function wikiFetch(config, path25, method = "GET", body) {
8824
8949
  }
8825
8950
  }
8826
8951
  if (!response.ok) {
8827
- throw new Error(`Wiki API ${method} ${path25}: ${response.status} ${response.statusText}`);
8952
+ throw new Error(`Wiki API ${method} ${path26}: ${response.status} ${response.statusText}`);
8828
8953
  }
8829
8954
  return response.json();
8830
8955
  } finally {
@@ -8945,13 +9070,13 @@ __export(shard_manager_exports, {
8945
9070
  listShards: () => listShards,
8946
9071
  shardExists: () => shardExists
8947
9072
  });
8948
- import path24 from "path";
8949
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
9073
+ import path25 from "path";
9074
+ import { existsSync as existsSync15, mkdirSync as mkdirSync7, readdirSync as readdirSync3 } from "fs";
8950
9075
  import { createClient as createClient2 } from "@libsql/client";
8951
9076
  function initShardManager(encryptionKey) {
8952
9077
  _encryptionKey = encryptionKey;
8953
- if (!existsSync14(SHARDS_DIR)) {
8954
- mkdirSync6(SHARDS_DIR, { recursive: true });
9078
+ if (!existsSync15(SHARDS_DIR)) {
9079
+ mkdirSync7(SHARDS_DIR, { recursive: true });
8955
9080
  }
8956
9081
  _shardingEnabled = true;
8957
9082
  }
@@ -8971,7 +9096,7 @@ function getShardClient(projectName) {
8971
9096
  }
8972
9097
  const cached = _shards.get(safeName);
8973
9098
  if (cached) return cached;
8974
- const dbPath = path24.join(SHARDS_DIR, `${safeName}.db`);
9099
+ const dbPath = path25.join(SHARDS_DIR, `${safeName}.db`);
8975
9100
  const client = createClient2({
8976
9101
  url: `file:${dbPath}`,
8977
9102
  encryptionKey: _encryptionKey
@@ -8981,10 +9106,10 @@ function getShardClient(projectName) {
8981
9106
  }
8982
9107
  function shardExists(projectName) {
8983
9108
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
8984
- return existsSync14(path24.join(SHARDS_DIR, `${safeName}.db`));
9109
+ return existsSync15(path25.join(SHARDS_DIR, `${safeName}.db`));
8985
9110
  }
8986
9111
  function listShards() {
8987
- if (!existsSync14(SHARDS_DIR)) return [];
9112
+ if (!existsSync15(SHARDS_DIR)) return [];
8988
9113
  return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
8989
9114
  }
8990
9115
  async function ensureShardSchema(client) {
@@ -9170,7 +9295,7 @@ var init_shard_manager = __esm({
9170
9295
  "src/lib/shard-manager.ts"() {
9171
9296
  "use strict";
9172
9297
  init_config();
9173
- SHARDS_DIR = path24.join(EXE_AI_DIR, "shards");
9298
+ SHARDS_DIR = path25.join(EXE_AI_DIR, "shards");
9174
9299
  _shards = /* @__PURE__ */ new Map();
9175
9300
  _encryptionKey = null;
9176
9301
  _shardingEnabled = false;
@@ -13740,8 +13865,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
13740
13865
  }
13741
13866
 
13742
13867
  // src/tui/ink/components/ErrorOverview.js
13743
- var cleanupPath = (path25) => {
13744
- return path25?.replace(`file://${cwd()}/`, "");
13868
+ var cleanupPath = (path26) => {
13869
+ return path26?.replace(`file://${cwd()}/`, "");
13745
13870
  };
13746
13871
  var stackUtils = new StackUtils({
13747
13872
  cwd: cwd(),
@@ -15673,11 +15798,11 @@ function Footer() {
15673
15798
  } catch {
15674
15799
  }
15675
15800
  try {
15676
- const { existsSync: existsSync15 } = await import("fs");
15801
+ const { existsSync: existsSync16 } = await import("fs");
15677
15802
  const { join } = await import("path");
15678
15803
  const home = process.env.HOME ?? "";
15679
15804
  const pidPath = join(home, ".exe-os", "exed.pid");
15680
- setDaemon(existsSync15(pidPath) ? "running" : "stopped");
15805
+ setDaemon(existsSync16(pidPath) ? "running" : "stopped");
15681
15806
  } catch {
15682
15807
  setDaemon("unknown");
15683
15808
  }
@@ -15759,7 +15884,7 @@ function Footer() {
15759
15884
  // src/tui/views/CommandCenter.tsx
15760
15885
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
15761
15886
  import TextInput from "ink-text-input";
15762
- import path21 from "path";
15887
+ import path22 from "path";
15763
15888
  import { homedir } from "os";
15764
15889
 
15765
15890
  // src/tui/components/StatusDot.tsx
@@ -16546,15 +16671,15 @@ function CommandCenterView({
16546
16671
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
16547
16672
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
16548
16673
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
16549
- const { readFileSync: readFileSync12, existsSync: existsSync15 } = await import("fs");
16674
+ const { readFileSync: readFileSync13, existsSync: existsSync16 } = await import("fs");
16550
16675
  const { join } = await import("path");
16551
16676
  const { homedir: homedir3 } = await import("os");
16552
16677
  const configPath = join(homedir3(), ".exe-os", "config.json");
16553
16678
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
16554
16679
  let providerConfigs = {};
16555
- if (existsSync15(configPath)) {
16680
+ if (existsSync16(configPath)) {
16556
16681
  try {
16557
- const raw = JSON.parse(readFileSync12(configPath, "utf8"));
16682
+ const raw = JSON.parse(readFileSync13(configPath, "utf8"));
16558
16683
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
16559
16684
  if (raw.providers && typeof raw.providers === "object") {
16560
16685
  providerConfigs = raw.providers;
@@ -16615,7 +16740,7 @@ function CommandCenterView({
16615
16740
  const markerDir = join(homedir3(), ".exe-os", "session-cache");
16616
16741
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
16617
16742
  for (const f of agentFiles) {
16618
- const data = JSON.parse(readFileSync12(join(markerDir, f), "utf8"));
16743
+ const data = JSON.parse(readFileSync13(join(markerDir, f), "utf8"));
16619
16744
  if (data.agentRole) {
16620
16745
  agentRole = data.agentRole;
16621
16746
  break;
@@ -16760,7 +16885,7 @@ function CommandCenterView({
16760
16885
  const demoEntries = DEMO_PROJECTS.map((p) => ({
16761
16886
  projectName: p.projectName,
16762
16887
  exeSession: p.exeSession,
16763
- projectDir: path21.join(homedir(), p.projectName),
16888
+ projectDir: path22.join(homedir(), p.projectName),
16764
16889
  employeeCount: p.employees.length,
16765
16890
  activeCount: p.employees.filter((e) => e.status === "active").length,
16766
16891
  memoryCount: p.employees.length * 4e3,
@@ -16798,7 +16923,7 @@ function CommandCenterView({
16798
16923
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
16799
16924
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
16800
16925
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
16801
- const { existsSync: existsSync15 } = await import("fs");
16926
+ const { existsSync: existsSync16 } = await import("fs");
16802
16927
  const { join } = await import("path");
16803
16928
  const client = getClient2();
16804
16929
  if (!client) {
@@ -16869,7 +16994,7 @@ function CommandCenterView({
16869
16994
  }
16870
16995
  const memoryCount = memoryCounts.get(name) ?? 0;
16871
16996
  const openTaskCount = openTaskCounts.get(name) ?? 0;
16872
- const hasGit = projectDir ? existsSync15(join(projectDir, ".git")) : false;
16997
+ const hasGit = projectDir ? existsSync16(join(projectDir, ".git")) : false;
16873
16998
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
16874
16999
  projectList.push({
16875
17000
  projectName: name,
@@ -16894,7 +17019,7 @@ function CommandCenterView({
16894
17019
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
16895
17020
  try {
16896
17021
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
16897
- setHealth((h) => ({ ...h, daemon: existsSync15(pidPath) ? "running" : "stopped" }));
17022
+ setHealth((h) => ({ ...h, daemon: existsSync16(pidPath) ? "running" : "stopped" }));
16898
17023
  } catch {
16899
17024
  }
16900
17025
  const activityResult = await client.execute(
@@ -17109,7 +17234,7 @@ function ChatMessageRow({ msg }) {
17109
17234
 
17110
17235
  // src/tui/views/Sessions.tsx
17111
17236
  import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
17112
- import path22 from "path";
17237
+ import path23 from "path";
17113
17238
  import { homedir as homedir2 } from "os";
17114
17239
 
17115
17240
  // src/tui/components/TmuxPane.tsx
@@ -17412,7 +17537,7 @@ function SessionsView({
17412
17537
  if (demo) {
17413
17538
  setProjects(DEMO_PROJECTS.map((p) => ({
17414
17539
  ...p,
17415
- projectDir: path22.join(homedir2(), p.projectName),
17540
+ projectDir: path23.join(homedir2(), p.projectName),
17416
17541
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
17417
17542
  })));
17418
17543
  return;
@@ -18309,12 +18434,12 @@ async function loadGatewayConfig() {
18309
18434
  state.running = false;
18310
18435
  }
18311
18436
  try {
18312
- const { existsSync: existsSync15, readFileSync: readFileSync12 } = await import("fs");
18437
+ const { existsSync: existsSync16, readFileSync: readFileSync13 } = await import("fs");
18313
18438
  const { join } = await import("path");
18314
18439
  const home = process.env.HOME ?? "";
18315
18440
  const configPath = join(home, ".exe-os", "gateway.json");
18316
- if (existsSync15(configPath)) {
18317
- const raw = JSON.parse(readFileSync12(configPath, "utf8"));
18441
+ if (existsSync16(configPath)) {
18442
+ const raw = JSON.parse(readFileSync13(configPath, "utf8"));
18318
18443
  state.port = raw.port ?? 3100;
18319
18444
  state.gatewayUrl = raw.gatewayUrl ?? "";
18320
18445
  if (raw.adapters) {
@@ -18840,12 +18965,12 @@ function TeamView({ onBack, onViewSessions }) {
18840
18965
  setMembers(teamData);
18841
18966
  setDbError(null);
18842
18967
  try {
18843
- const { existsSync: existsSync15, readFileSync: readFileSync12 } = await import("fs");
18968
+ const { existsSync: existsSync16, readFileSync: readFileSync13 } = await import("fs");
18844
18969
  const { join } = await import("path");
18845
18970
  const home = process.env.HOME ?? "";
18846
18971
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
18847
- if (existsSync15(gatewayConfig)) {
18848
- const raw = JSON.parse(readFileSync12(gatewayConfig, "utf8"));
18972
+ if (existsSync16(gatewayConfig)) {
18973
+ const raw = JSON.parse(readFileSync13(gatewayConfig, "utf8"));
18849
18974
  if (raw.agents && raw.agents.length > 0) {
18850
18975
  setExternals(raw.agents.map((a) => ({
18851
18976
  name: a.name,
@@ -19509,12 +19634,12 @@ function SettingsView({ onBack }) {
19509
19634
  }
19510
19635
  setProviders(providerList);
19511
19636
  try {
19512
- const { existsSync: existsSync15 } = await import("fs");
19637
+ const { existsSync: existsSync16 } = await import("fs");
19513
19638
  const { join } = await import("path");
19514
19639
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
19515
19640
  const cfg = await loadConfig2();
19516
19641
  const home = process.env.HOME ?? "";
19517
- const hasKey = existsSync15(join(home, ".exe-os", "master.key"));
19642
+ const hasKey = existsSync16(join(home, ".exe-os", "master.key"));
19518
19643
  if (cfg.cloud) {
19519
19644
  setCloud({
19520
19645
  configured: true,
@@ -19527,22 +19652,22 @@ function SettingsView({ onBack }) {
19527
19652
  const pidPath = join(home, ".exe-os", "exed.pid");
19528
19653
  let daemon = "unknown";
19529
19654
  try {
19530
- daemon = existsSync15(pidPath) ? "running" : "stopped";
19655
+ daemon = existsSync16(pidPath) ? "running" : "stopped";
19531
19656
  } catch {
19532
19657
  }
19533
19658
  let version = "unknown";
19534
19659
  try {
19535
- const { readFileSync: readFileSync12 } = await import("fs");
19660
+ const { readFileSync: readFileSync13 } = await import("fs");
19536
19661
  const { createRequire } = await import("module");
19537
19662
  const require2 = createRequire(import.meta.url);
19538
19663
  const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
19539
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
19664
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
19540
19665
  version = pkg.version;
19541
19666
  } catch {
19542
19667
  try {
19543
- const { readFileSync: readFileSync12 } = await import("fs");
19668
+ const { readFileSync: readFileSync13 } = await import("fs");
19544
19669
  const { join: joinPath } = await import("path");
19545
- const pkg = JSON.parse(readFileSync12(joinPath(process.cwd(), "package.json"), "utf8"));
19670
+ const pkg = JSON.parse(readFileSync13(joinPath(process.cwd(), "package.json"), "utf8"));
19546
19671
  version = pkg.version;
19547
19672
  } catch {
19548
19673
  }