@askexenow/exe-os 0.9.112 → 0.9.113

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 (95) hide show
  1. package/README.md +9 -7
  2. package/dist/bin/agentic-ontology-backfill.js +54 -11
  3. package/dist/bin/agentic-reflection-backfill.js +29 -1
  4. package/dist/bin/agentic-semantic-label.js +29 -1
  5. package/dist/bin/backfill-conversations.js +53 -10
  6. package/dist/bin/backfill-responses.js +54 -11
  7. package/dist/bin/backfill-vectors.js +29 -1
  8. package/dist/bin/bulk-sync-postgres.js +55 -12
  9. package/dist/bin/cleanup-stale-review-tasks.js +75 -15
  10. package/dist/bin/cli.js +293 -76
  11. package/dist/bin/exe-agent-config.js +7 -1
  12. package/dist/bin/exe-agent.js +28 -2
  13. package/dist/bin/exe-assign.js +54 -11
  14. package/dist/bin/exe-boot.js +481 -147
  15. package/dist/bin/exe-call.js +45 -4
  16. package/dist/bin/exe-cloud.js +93 -15
  17. package/dist/bin/exe-dispatch.js +369 -24
  18. package/dist/bin/exe-doctor.js +53 -10
  19. package/dist/bin/exe-export-behaviors.js +54 -11
  20. package/dist/bin/exe-forget.js +54 -11
  21. package/dist/bin/exe-gateway.js +128 -23
  22. package/dist/bin/exe-heartbeat.js +75 -15
  23. package/dist/bin/exe-kill.js +54 -11
  24. package/dist/bin/exe-launch-agent.js +70 -12
  25. package/dist/bin/exe-new-employee.js +175 -7
  26. package/dist/bin/exe-pending-messages.js +75 -15
  27. package/dist/bin/exe-pending-notifications.js +75 -15
  28. package/dist/bin/exe-pending-reviews.js +75 -15
  29. package/dist/bin/exe-rename.js +54 -11
  30. package/dist/bin/exe-review.js +54 -11
  31. package/dist/bin/exe-search.js +54 -11
  32. package/dist/bin/exe-session-cleanup.js +491 -146
  33. package/dist/bin/exe-settings.js +10 -4
  34. package/dist/bin/exe-start-codex.js +524 -245
  35. package/dist/bin/exe-start-opencode.js +534 -165
  36. package/dist/bin/exe-status.js +75 -15
  37. package/dist/bin/exe-support.js +1 -1
  38. package/dist/bin/exe-team.js +54 -11
  39. package/dist/bin/git-sweep.js +369 -24
  40. package/dist/bin/graph-backfill.js +54 -11
  41. package/dist/bin/graph-export.js +54 -11
  42. package/dist/bin/install.js +62 -4
  43. package/dist/bin/intercom-check.js +491 -146
  44. package/dist/bin/pre-publish.js +13 -1
  45. package/dist/bin/scan-tasks.js +369 -24
  46. package/dist/bin/setup.js +91 -13
  47. package/dist/bin/shard-migrate.js +54 -11
  48. package/dist/bin/stack-update.js +1 -1
  49. package/dist/bin/update.js +3 -3
  50. package/dist/gateway/index.js +128 -23
  51. package/dist/hooks/bug-report-worker.js +128 -23
  52. package/dist/hooks/codex-stop-task-finalizer.js +512 -140
  53. package/dist/hooks/commit-complete.js +369 -24
  54. package/dist/hooks/error-recall.js +54 -11
  55. package/dist/hooks/ingest.js +4575 -252
  56. package/dist/hooks/instructions-loaded.js +54 -11
  57. package/dist/hooks/notification.js +54 -11
  58. package/dist/hooks/post-compact.js +75 -15
  59. package/dist/hooks/post-tool-combined.js +75 -15
  60. package/dist/hooks/pre-compact.js +449 -104
  61. package/dist/hooks/pre-tool-use.js +90 -15
  62. package/dist/hooks/prompt-submit.js +129 -24
  63. package/dist/hooks/session-end.js +451 -109
  64. package/dist/hooks/session-start.js +104 -16
  65. package/dist/hooks/stop.js +74 -14
  66. package/dist/hooks/subagent-stop.js +75 -15
  67. package/dist/hooks/summary-worker.js +73 -7
  68. package/dist/index.js +128 -23
  69. package/dist/lib/agent-config.js +16 -1
  70. package/dist/lib/cloud-sync.js +38 -1
  71. package/dist/lib/consolidation.js +16 -1
  72. package/dist/lib/database.js +16 -0
  73. package/dist/lib/db.js +16 -0
  74. package/dist/lib/device-registry.js +16 -0
  75. package/dist/lib/employee-templates.js +29 -3
  76. package/dist/lib/employees.js +16 -1
  77. package/dist/lib/exe-daemon.js +268 -42
  78. package/dist/lib/hybrid-search.js +54 -11
  79. package/dist/lib/license.js +3 -3
  80. package/dist/lib/messaging.js +21 -4
  81. package/dist/lib/schedules.js +29 -1
  82. package/dist/lib/skill-learning.js +458 -70
  83. package/dist/lib/status-brief.js +14 -1
  84. package/dist/lib/store.js +54 -11
  85. package/dist/lib/tasks.js +393 -91
  86. package/dist/lib/tmux-routing.js +316 -14
  87. package/dist/mcp/server.js +169 -30
  88. package/dist/mcp/tools/create-task.js +75 -13
  89. package/dist/mcp/tools/deactivate-behavior.js +33 -24
  90. package/dist/mcp/tools/list-tasks.js +21 -4
  91. package/dist/mcp/tools/send-message.js +21 -4
  92. package/dist/mcp/tools/update-task.js +390 -91
  93. package/dist/runtime/index.js +446 -101
  94. package/dist/tui/App.js +208 -54
  95. package/package.json +1 -1
@@ -398,11 +398,168 @@ var init_session_key = __esm({
398
398
  }
399
399
  });
400
400
 
401
+ // src/lib/runtime-table.ts
402
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
403
+ var init_runtime_table = __esm({
404
+ "src/lib/runtime-table.ts"() {
405
+ "use strict";
406
+ RUNTIME_TABLE = {
407
+ codex: {
408
+ binary: "codex",
409
+ launchMode: "interactive",
410
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
411
+ inlineFlag: "--no-alt-screen",
412
+ apiKeyEnv: "OPENAI_API_KEY",
413
+ defaultModel: "gpt-5.5"
414
+ },
415
+ opencode: {
416
+ binary: "opencode",
417
+ launchMode: "exec",
418
+ autoApproveFlag: "--dangerously-skip-permissions",
419
+ inlineFlag: "",
420
+ apiKeyEnv: "ANTHROPIC_API_KEY",
421
+ defaultModel: "anthropic/claude-sonnet-4-6"
422
+ }
423
+ };
424
+ DEFAULT_RUNTIME = "claude";
425
+ }
426
+ });
427
+
428
+ // src/lib/agent-config.ts
429
+ var agent_config_exports = {};
430
+ __export(agent_config_exports, {
431
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
432
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
433
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
434
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
435
+ clearAgentRuntime: () => clearAgentRuntime,
436
+ getAgentRuntime: () => getAgentRuntime,
437
+ loadAgentConfig: () => loadAgentConfig,
438
+ saveAgentConfig: () => saveAgentConfig,
439
+ setAgentMcps: () => setAgentMcps,
440
+ setAgentRuntime: () => setAgentRuntime
441
+ });
442
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
443
+ import path2 from "path";
444
+ function loadAgentConfig() {
445
+ if (!existsSync3(AGENT_CONFIG_PATH)) return {};
446
+ try {
447
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
448
+ } catch {
449
+ return {};
450
+ }
451
+ }
452
+ function saveAgentConfig(config) {
453
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
454
+ ensurePrivateDirSync(dir);
455
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
456
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
457
+ }
458
+ function getAgentRuntime(agentId) {
459
+ const config = loadAgentConfig();
460
+ const entry = config[agentId];
461
+ if (entry) return entry;
462
+ const orgDefault = config["default"];
463
+ if (orgDefault) return orgDefault;
464
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
465
+ }
466
+ function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
467
+ const knownModels = KNOWN_RUNTIMES[runtime];
468
+ if (!knownModels) {
469
+ return {
470
+ ok: false,
471
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
472
+ };
473
+ }
474
+ if (!knownModels.includes(model)) {
475
+ return {
476
+ ok: false,
477
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
478
+ };
479
+ }
480
+ const config = loadAgentConfig();
481
+ const existing = config[agentId];
482
+ const entry = { runtime, model };
483
+ if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
484
+ if (mcps !== void 0) {
485
+ entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
486
+ } else if (existing?.mcps) {
487
+ entry.mcps = existing.mcps;
488
+ }
489
+ config[agentId] = entry;
490
+ saveAgentConfig(config);
491
+ return { ok: true };
492
+ }
493
+ function setAgentMcps(agentId, mcps) {
494
+ const config = loadAgentConfig();
495
+ const existing = config[agentId] ?? getAgentRuntime(agentId);
496
+ existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
497
+ config[agentId] = existing;
498
+ saveAgentConfig(config);
499
+ return { ok: true };
500
+ }
501
+ function clearAgentRuntime(agentId) {
502
+ const config = loadAgentConfig();
503
+ delete config[agentId];
504
+ saveAgentConfig(config);
505
+ }
506
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
507
+ var init_agent_config = __esm({
508
+ "src/lib/agent-config.ts"() {
509
+ "use strict";
510
+ init_config();
511
+ init_runtime_table();
512
+ init_secure_files();
513
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
514
+ KNOWN_RUNTIMES = {
515
+ claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
516
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
517
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
518
+ };
519
+ RUNTIME_LABELS = {
520
+ claude: "Claude Code (Anthropic)",
521
+ codex: "Codex (OpenAI)",
522
+ opencode: "OpenCode (open source)"
523
+ };
524
+ DEFAULT_MODELS = {
525
+ claude: "claude-opus-4.6",
526
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
527
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
528
+ };
529
+ }
530
+ });
531
+
401
532
  // src/lib/employees.ts
533
+ var employees_exports = {};
534
+ __export(employees_exports, {
535
+ COORDINATOR_ROLE: () => COORDINATOR_ROLE,
536
+ DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
537
+ EMPLOYEES_PATH: () => EMPLOYEES_PATH,
538
+ addEmployee: () => addEmployee,
539
+ baseAgentName: () => baseAgentName,
540
+ canCoordinate: () => canCoordinate,
541
+ getCoordinatorEmployee: () => getCoordinatorEmployee,
542
+ getCoordinatorName: () => getCoordinatorName,
543
+ getEmployee: () => getEmployee,
544
+ getEmployeeByRole: () => getEmployeeByRole,
545
+ getEmployeeNamesByRole: () => getEmployeeNamesByRole,
546
+ hasRole: () => hasRole,
547
+ hireEmployee: () => hireEmployee,
548
+ isCoordinatorName: () => isCoordinatorName,
549
+ isCoordinatorRole: () => isCoordinatorRole,
550
+ isMultiInstance: () => isMultiInstance,
551
+ loadEmployees: () => loadEmployees,
552
+ loadEmployeesSync: () => loadEmployeesSync,
553
+ normalizeRole: () => normalizeRole,
554
+ normalizeRosterCase: () => normalizeRosterCase,
555
+ registerBinSymlinks: () => registerBinSymlinks,
556
+ saveEmployees: () => saveEmployees,
557
+ validateEmployeeName: () => validateEmployeeName
558
+ });
402
559
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
403
- import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
560
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
404
561
  import { execSync as execSync2 } from "child_process";
405
- import path2 from "path";
562
+ import path3 from "path";
406
563
  import os2 from "os";
407
564
  function normalizeRole(role) {
408
565
  return (role ?? "").trim().toLowerCase();
@@ -423,8 +580,23 @@ function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
423
580
  function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
424
581
  return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
425
582
  }
583
+ function validateEmployeeName(name) {
584
+ if (!name) {
585
+ return { valid: false, error: "Name is required" };
586
+ }
587
+ if (name.length > 32) {
588
+ return { valid: false, error: "Name must be 32 characters or fewer" };
589
+ }
590
+ if (!/^[a-z][a-z0-9]*$/.test(name)) {
591
+ return {
592
+ valid: false,
593
+ error: "Name must start with a letter and contain only lowercase alphanumeric characters"
594
+ };
595
+ }
596
+ return { valid: true };
597
+ }
426
598
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
427
- if (!existsSync3(employeesPath)) {
599
+ if (!existsSync4(employeesPath)) {
428
600
  return [];
429
601
  }
430
602
  const raw = await readFile2(employeesPath, "utf-8");
@@ -434,10 +606,14 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
434
606
  return [];
435
607
  }
436
608
  }
609
+ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
610
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
611
+ await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
612
+ }
437
613
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
438
- if (!existsSync3(employeesPath)) return [];
614
+ if (!existsSync4(employeesPath)) return [];
439
615
  try {
440
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
616
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
441
617
  } catch {
442
618
  return [];
443
619
  }
@@ -445,6 +621,19 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
445
621
  function getEmployee(employees, name) {
446
622
  return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
447
623
  }
624
+ function getEmployeeByRole(employees, role) {
625
+ const lower = role.toLowerCase();
626
+ return employees.find((e) => e.role.toLowerCase() === lower);
627
+ }
628
+ function getEmployeeNamesByRole(employees, role) {
629
+ const lower = role.toLowerCase();
630
+ return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
631
+ }
632
+ function hasRole(agentName, role) {
633
+ const employees = loadEmployeesSync();
634
+ const emp = getEmployee(employees, agentName);
635
+ return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
636
+ }
448
637
  function baseAgentName(name, employees) {
449
638
  const match = name.match(/^([a-zA-Z]+)\d+$/);
450
639
  if (!match) return name;
@@ -459,26 +648,151 @@ function isMultiInstance(agentName, employees) {
459
648
  if (!emp) return false;
460
649
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
461
650
  }
462
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
651
+ function addEmployee(employees, employee) {
652
+ const { systemPrompt: _legacyPrompt, ...rest } = employee;
653
+ const normalized = { ...rest, name: employee.name.toLowerCase() };
654
+ if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
655
+ throw new Error(`Employee '${normalized.name}' already exists`);
656
+ }
657
+ return [...employees, normalized];
658
+ }
659
+ function appendToCoordinatorTeam(employee) {
660
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
661
+ if (!coordinator) return;
662
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
663
+ if (!existsSync4(idPath)) return;
664
+ const content = readFileSync3(idPath, "utf-8");
665
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
666
+ const teamMatch = content.match(TEAM_SECTION_RE);
667
+ if (!teamMatch || teamMatch.index === void 0) return;
668
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
669
+ const nextHeading = afterTeam.match(/\n## /);
670
+ const entry = `
671
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
672
+ `;
673
+ let updated;
674
+ if (nextHeading && nextHeading.index !== void 0) {
675
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
676
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
677
+ } else {
678
+ updated = content.trimEnd() + "\n" + entry;
679
+ }
680
+ writeFileSync2(idPath, updated, "utf-8");
681
+ }
682
+ function capitalize(s) {
683
+ return s.charAt(0).toUpperCase() + s.slice(1);
684
+ }
685
+ async function hireEmployee(employee) {
686
+ const employees = await loadEmployees();
687
+ const updated = addEmployee(employees, employee);
688
+ await saveEmployees(updated);
689
+ try {
690
+ appendToCoordinatorTeam(employee);
691
+ } catch {
692
+ }
693
+ try {
694
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
695
+ const config = loadAgentConfig2();
696
+ const name = employee.name.toLowerCase();
697
+ if (!config[name] && config["default"]) {
698
+ config[name] = { ...config["default"] };
699
+ saveAgentConfig2(config);
700
+ }
701
+ } catch {
702
+ }
703
+ return updated;
704
+ }
705
+ async function normalizeRosterCase(rosterPath) {
706
+ const employees = await loadEmployees(rosterPath);
707
+ let changed = false;
708
+ for (const emp of employees) {
709
+ if (emp.name !== emp.name.toLowerCase()) {
710
+ const oldName = emp.name;
711
+ emp.name = emp.name.toLowerCase();
712
+ changed = true;
713
+ try {
714
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
715
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
716
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
717
+ if (existsSync4(oldPath) && !existsSync4(newPath)) {
718
+ renameSync2(oldPath, newPath);
719
+ } else if (existsSync4(oldPath) && oldPath !== newPath) {
720
+ const content = readFileSync3(oldPath, "utf-8");
721
+ writeFileSync2(newPath, content, "utf-8");
722
+ if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
723
+ unlinkSync(oldPath);
724
+ }
725
+ }
726
+ } catch {
727
+ }
728
+ }
729
+ }
730
+ if (changed) {
731
+ await saveEmployees(employees, rosterPath);
732
+ }
733
+ return changed;
734
+ }
735
+ function findExeBin() {
736
+ try {
737
+ return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
738
+ } catch {
739
+ return null;
740
+ }
741
+ }
742
+ function registerBinSymlinks(name) {
743
+ const created = [];
744
+ const skipped = [];
745
+ const errors = [];
746
+ const exeBinPath = findExeBin();
747
+ if (!exeBinPath) {
748
+ errors.push("Could not find 'exe-os' in PATH");
749
+ return { created, skipped, errors };
750
+ }
751
+ const binDir = path3.dirname(exeBinPath);
752
+ let target;
753
+ try {
754
+ target = readlinkSync(exeBinPath);
755
+ } catch {
756
+ errors.push("Could not read 'exe' symlink");
757
+ return { created, skipped, errors };
758
+ }
759
+ for (const suffix of ["", "-opencode"]) {
760
+ const linkName = `${name}${suffix}`;
761
+ const linkPath = path3.join(binDir, linkName);
762
+ if (existsSync4(linkPath)) {
763
+ skipped.push(linkName);
764
+ continue;
765
+ }
766
+ try {
767
+ symlinkSync(target, linkPath);
768
+ created.push(linkName);
769
+ } catch (err) {
770
+ errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
771
+ }
772
+ }
773
+ return { created, skipped, errors };
774
+ }
775
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
463
776
  var init_employees = __esm({
464
777
  "src/lib/employees.ts"() {
465
778
  "use strict";
466
779
  init_config();
467
- EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
780
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
468
781
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
469
782
  COORDINATOR_ROLE = "COO";
470
783
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
471
- IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
784
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
785
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
472
786
  }
473
787
  });
474
788
 
475
789
  // src/lib/session-registry.ts
476
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
477
- import path5 from "path";
790
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
791
+ import path6 from "path";
478
792
  import os4 from "os";
479
793
  function registerSession(entry) {
480
- const dir = path5.dirname(REGISTRY_PATH);
481
- if (!existsSync5(dir)) {
794
+ const dir = path6.dirname(REGISTRY_PATH);
795
+ if (!existsSync6(dir)) {
482
796
  mkdirSync4(dir, { recursive: true });
483
797
  }
484
798
  const sessions = listSessions();
@@ -488,11 +802,11 @@ function registerSession(entry) {
488
802
  } else {
489
803
  sessions.push(entry);
490
804
  }
491
- writeFileSync4(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
805
+ writeFileSync5(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
492
806
  }
493
807
  function listSessions() {
494
808
  try {
495
- const raw = readFileSync5(REGISTRY_PATH, "utf8");
809
+ const raw = readFileSync6(REGISTRY_PATH, "utf8");
496
810
  return JSON.parse(raw);
497
811
  } catch {
498
812
  return [];
@@ -502,7 +816,7 @@ var REGISTRY_PATH;
502
816
  var init_session_registry = __esm({
503
817
  "src/lib/session-registry.ts"() {
504
818
  "use strict";
505
- REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
819
+ REGISTRY_PATH = path6.join(os4.homedir(), ".exe-os", "session-registry.json");
506
820
  }
507
821
  });
508
822
 
@@ -696,68 +1010,6 @@ var init_provider_table = __esm({
696
1010
  }
697
1011
  });
698
1012
 
699
- // src/lib/runtime-table.ts
700
- var RUNTIME_TABLE, DEFAULT_RUNTIME;
701
- var init_runtime_table = __esm({
702
- "src/lib/runtime-table.ts"() {
703
- "use strict";
704
- RUNTIME_TABLE = {
705
- codex: {
706
- binary: "codex",
707
- launchMode: "interactive",
708
- autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
709
- inlineFlag: "--no-alt-screen",
710
- apiKeyEnv: "OPENAI_API_KEY",
711
- defaultModel: "gpt-5.5"
712
- },
713
- opencode: {
714
- binary: "opencode",
715
- launchMode: "exec",
716
- autoApproveFlag: "--dangerously-skip-permissions",
717
- inlineFlag: "",
718
- apiKeyEnv: "ANTHROPIC_API_KEY",
719
- defaultModel: "anthropic/claude-sonnet-4-6"
720
- }
721
- };
722
- DEFAULT_RUNTIME = "claude";
723
- }
724
- });
725
-
726
- // src/lib/agent-config.ts
727
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6 } from "fs";
728
- import path6 from "path";
729
- function loadAgentConfig() {
730
- if (!existsSync6(AGENT_CONFIG_PATH)) return {};
731
- try {
732
- return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
733
- } catch {
734
- return {};
735
- }
736
- }
737
- function getAgentRuntime(agentId) {
738
- const config = loadAgentConfig();
739
- const entry = config[agentId];
740
- if (entry) return entry;
741
- const orgDefault = config["default"];
742
- if (orgDefault) return orgDefault;
743
- return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
744
- }
745
- var AGENT_CONFIG_PATH, DEFAULT_MODELS;
746
- var init_agent_config = __esm({
747
- "src/lib/agent-config.ts"() {
748
- "use strict";
749
- init_config();
750
- init_runtime_table();
751
- init_secure_files();
752
- AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
753
- DEFAULT_MODELS = {
754
- claude: "claude-opus-4.6",
755
- codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
756
- opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
757
- };
758
- }
759
- });
760
-
761
1013
  // src/lib/intercom-queue.ts
762
1014
  var intercom_queue_exports = {};
763
1015
  __export(intercom_queue_exports, {
@@ -3840,6 +4092,22 @@ async function ensureSchema() {
3840
4092
  } catch (e) {
3841
4093
  logCatchDebug("migration", e);
3842
4094
  }
4095
+ try {
4096
+ await client.execute({
4097
+ sql: `ALTER TABLE memories ADD COLUMN visibility TEXT DEFAULT 'private'`,
4098
+ args: []
4099
+ });
4100
+ } catch (e) {
4101
+ logCatchDebug("migration", e);
4102
+ }
4103
+ try {
4104
+ await client.execute({
4105
+ sql: `ALTER TABLE memories ADD COLUMN strength REAL DEFAULT 1.0`,
4106
+ args: []
4107
+ });
4108
+ } catch (e) {
4109
+ logCatchDebug("migration", e);
4110
+ }
3843
4111
  }
3844
4112
  async function disposeDatabase() {
3845
4113
  if (_walCheckpointTimer) {
@@ -4258,7 +4526,7 @@ async function assertVpsLicense(opts) {
4258
4526
  }
4259
4527
  if (!transientFailure) {
4260
4528
  throw new Error(
4261
- "License validation failed: unknown backend state. Restore network connectivity to https://askexe.com/cloud and retry."
4529
+ "License validation failed: unknown backend state. Restore network connectivity to https://cloud.askexe.com and retry."
4262
4530
  );
4263
4531
  }
4264
4532
  const fresh = await getCachedLicense();
@@ -4295,7 +4563,7 @@ async function assertVpsLicense(opts) {
4295
4563
  } catch {
4296
4564
  }
4297
4565
  throw new Error(
4298
- `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
4566
+ `License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://cloud.askexe.com and retry. This VPS image refuses to boot after the offline grace window.`
4299
4567
  );
4300
4568
  }
4301
4569
  function startLicenseRevalidation(intervalMs = 36e5) {
@@ -4327,7 +4595,7 @@ var init_license = __esm({
4327
4595
  LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
4328
4596
  CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
4329
4597
  DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
4330
- API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
4598
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://cloud.askexe.com";
4331
4599
  RETRY_DELAY_MS = 500;
4332
4600
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
4333
4601
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
@@ -5038,6 +5306,19 @@ async function resolveTask(client, identifier, scopeSession) {
5038
5306
  args: [identifier, ...scope.args]
5039
5307
  });
5040
5308
  if (result.rows.length === 1) return result.rows[0];
5309
+ if (/^[a-f0-9]{7,12}$/i.test(identifier)) {
5310
+ result = await client.execute({
5311
+ sql: `SELECT * FROM tasks WHERE id LIKE ?`,
5312
+ args: [`${identifier}%`]
5313
+ });
5314
+ if (result.rows.length === 1) return result.rows[0];
5315
+ if (result.rows.length > 1) {
5316
+ const matches = result.rows.map((r) => `${String(r.id)} "${String(r.title)}" (${String(r.status)})`).join(", ");
5317
+ throw new Error(
5318
+ `Multiple tasks match short-ID "${identifier}": ${matches}. Use a longer prefix to disambiguate.`
5319
+ );
5320
+ }
5321
+ }
5041
5322
  result = await client.execute({
5042
5323
  sql: `SELECT * FROM tasks WHERE task_file LIKE ?${scope.sql}`,
5043
5324
  args: [`%${identifier}%`, ...scope.args]
@@ -5892,12 +6173,13 @@ async function cascadeUnblock(taskId, baseDir, now) {
5892
6173
  WHERE blocked_by = ? AND status = 'blocked'`,
5893
6174
  args: [now, taskId]
5894
6175
  });
5895
- if (baseDir && unblocked.rowsAffected > 0) {
5896
- const ubScope = sessionScopeFilter();
5897
- const unblockedRows = await client.execute({
5898
- sql: `SELECT task_file FROM tasks WHERE blocked_by IS NULL AND updated_at = ?${ubScope.sql}`,
5899
- args: [now, ...ubScope.args]
5900
- });
6176
+ if (unblocked.rowsAffected === 0) return;
6177
+ const ubScope = sessionScopeFilter();
6178
+ const unblockedRows = await client.execute({
6179
+ sql: `SELECT id, title, assigned_to, priority, task_file FROM tasks WHERE blocked_by IS NULL AND updated_at = ?${ubScope.sql}`,
6180
+ args: [now, ...ubScope.args]
6181
+ });
6182
+ if (baseDir) {
5901
6183
  for (const ur of unblockedRows.rows) {
5902
6184
  try {
5903
6185
  const ubFile = path18.join(baseDir, String(ur.task_file));
@@ -5909,6 +6191,19 @@ async function cascadeUnblock(taskId, baseDir, now) {
5909
6191
  }
5910
6192
  }
5911
6193
  }
6194
+ if (unblockedRows.rows.length > 0 && !process.env.VITEST) {
6195
+ try {
6196
+ const { queueIntercom: queueIntercom2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
6197
+ const dispatched = /* @__PURE__ */ new Set();
6198
+ for (const ur of unblockedRows.rows) {
6199
+ const assignee = String(ur.assigned_to);
6200
+ if (dispatched.has(assignee)) continue;
6201
+ dispatched.add(assignee);
6202
+ queueIntercom2(`${assignee}`, `unblocked: "${String(ur.title)}" is now ready`);
6203
+ }
6204
+ } catch {
6205
+ }
6206
+ }
5912
6207
  }
5913
6208
  async function findNextTask(assignedTo) {
5914
6209
  const client = getClient();
@@ -6118,6 +6413,15 @@ var init_embedder = __esm({
6118
6413
  // src/lib/behaviors.ts
6119
6414
  import crypto5 from "crypto";
6120
6415
  async function storeBehavior(opts) {
6416
+ try {
6417
+ const { loadEmployeesSync: loadEmployeesSync2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
6418
+ const roster = loadEmployeesSync2();
6419
+ if (roster.length > 0 && !roster.some((e) => e.name === opts.agentId)) {
6420
+ throw new Error(`Agent "${opts.agentId}" not found in roster. Cannot store behavior for unregistered agent.`);
6421
+ }
6422
+ } catch (e) {
6423
+ if (e instanceof Error && e.message.includes("not found in roster")) throw e;
6424
+ }
6121
6425
  const client = getClient();
6122
6426
  const id = crypto5.randomUUID();
6123
6427
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -6571,6 +6875,12 @@ async function updateTask(input2) {
6571
6875
  }
6572
6876
  }
6573
6877
  }
6878
+ if (input2.status === "cancelled") {
6879
+ try {
6880
+ await cascadeUnblock(taskId, input2.baseDir, now);
6881
+ } catch {
6882
+ }
6883
+ }
6574
6884
  if ((input2.status === "done" || input2.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
6575
6885
  Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
6576
6886
  ({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
@@ -7102,11 +7412,12 @@ function getDispatchedBy(sessionKey) {
7102
7412
  }
7103
7413
  }
7104
7414
  function resolveExeSession() {
7415
+ if (process.env.EXE_SESSION_NAME) {
7416
+ const fromEnv = extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
7417
+ if (fromEnv) return fromEnv;
7418
+ }
7105
7419
  const mySession = getMySession();
7106
7420
  if (!mySession) {
7107
- if (process.env.EXE_SESSION_NAME) {
7108
- return extractRootExe(process.env.EXE_SESSION_NAME) ?? process.env.EXE_SESSION_NAME;
7109
- }
7110
7421
  return null;
7111
7422
  }
7112
7423
  const fromSessionName = extractRootExe(mySession);
@@ -7121,6 +7432,10 @@ function resolveExeSession() {
7121
7432
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
7122
7433
  `
7123
7434
  );
7435
+ try {
7436
+ registerParentExe(key, fromSessionName);
7437
+ } catch {
7438
+ }
7124
7439
  candidate = fromSessionName;
7125
7440
  } else {
7126
7441
  candidate = fromCache;
@@ -8848,11 +9163,17 @@ var init_platform_procedures = __esm({
8848
9163
  content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
8849
9164
  },
8850
9165
  {
8851
- title: "Customer orchestration maturity \u2014 recommend, never trap",
9166
+ title: "Orchestration phase guidance \u2014 recommend, never trap",
8852
9167
  domain: "workflow",
8853
9168
  priority: "p1",
8854
9169
  content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
8855
9170
  },
9171
+ {
9172
+ title: "Routing slot vs display title \u2014 internal 'coo' is plumbing, not your name",
9173
+ domain: "identity",
9174
+ priority: "p0",
9175
+ content: "These procedures reference 'COO' as a shorthand for the coordinator role. This is an INTERNAL routing slot used by exe-os code (chain-of-command checks, dispatch logic, session detection). It is NOT your display title. Your actual title comes from your identity file's `title:` field \u2014 that is what you use externally: introductions, sign-offs, team comms, and any user-facing text. If your identity says `title: AI Chief of Staff`, you are the AI Chief of Staff. The routing slot stays `role: coo` for code compatibility \u2014 never rename it, but also never introduce yourself as 'COO' unless your identity file explicitly says so. The founder chose your title; respect it."
9176
+ },
8856
9177
  {
8857
9178
  title: "Single dispatch path \u2014 create_task only",
8858
9179
  domain: "workflow",
@@ -8886,6 +9207,12 @@ var init_platform_procedures = __esm({
8886
9207
  priority: "p0",
8887
9208
  content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
8888
9209
  },
9210
+ {
9211
+ title: "Destructive operations \u2014 mandatory reviewer gate",
9212
+ domain: "security",
9213
+ priority: "p0",
9214
+ content: "Before ANY destructive operation (delete, remove, overwrite, drop, reset, force-push, truncate), you MUST: (1) Have your full task spec accessible \u2014 if you cannot read it, STOP and report to your reviewer. Never improvise destructive actions. (2) Confirm with your reviewer (assigned_by or COO) before executing. (3) If the task spec explicitly authorizes the operation, proceed \u2014 but log it. Violation = immediate task failure. This applies to ALL agents regardless of role."
9215
+ },
8889
9216
  {
8890
9217
  title: "Customer patch triage \u2014 upstream bug vs customization",
8891
9218
  domain: "support",
@@ -9171,10 +9498,24 @@ function stableId(memoryId, type, content) {
9171
9498
  return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
9172
9499
  }
9173
9500
  function cleanText(text) {
9174
- return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
9501
+ let cleaned = text.replace(
9502
+ /```(\w*)\n(.*?)(?:\n[\s\S]*?)```/g,
9503
+ (_m, lang, firstLine) => `[code${lang ? `:${lang}` : ""}] ${firstLine.trim()}`
9504
+ );
9505
+ cleaned = cleaned.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
9506
+ return cleaned;
9175
9507
  }
9176
- function splitSentences(text) {
9177
- return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
9508
+ function splitSegments(text) {
9509
+ const cleaned = cleanText(text);
9510
+ const segments = cleaned.split(/(?<=[.!?:;])\s+|\n{2,}|(?<=\))\s+(?=[A-Z])|\s*[|│]\s*/).map((s) => s.trim()).filter((s) => s.length >= MIN_SEGMENT_CHARS && s.length <= MAX_SEGMENT_CHARS);
9511
+ if (segments.length === 0 && cleaned.length >= MIN_SEGMENT_CHARS) {
9512
+ const lines = cleaned.split(/\n+/).map((l) => l.trim()).filter((l) => l.length >= MIN_SEGMENT_CHARS && l.length <= MAX_SEGMENT_CHARS);
9513
+ if (lines.length > 0) return lines;
9514
+ if (cleaned.length >= MIN_SEGMENT_CHARS) {
9515
+ return [cleaned.slice(0, MAX_SEGMENT_CHARS)];
9516
+ }
9517
+ }
9518
+ return segments;
9178
9519
  }
9179
9520
  function inferCardType(sentence, toolName) {
9180
9521
  const lower = sentence.toLowerCase();
@@ -9206,12 +9547,12 @@ function predicateFor(type) {
9206
9547
  }
9207
9548
  }
9208
9549
  function extractMemoryCards(row) {
9209
- const sentences = splitSentences(row.raw_text);
9550
+ const segments = splitSegments(row.raw_text);
9210
9551
  const cards = [];
9211
- for (const sentence of sentences) {
9552
+ for (const sentence of segments) {
9212
9553
  const type = inferCardType(sentence, row.tool_name);
9213
9554
  const subject = extractSubject(sentence, row.agent_id);
9214
- const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
9555
+ const content = sentence.length > MAX_SEGMENT_CHARS ? `${sentence.slice(0, MAX_SEGMENT_CHARS - 1)}\u2026` : sentence;
9215
9556
  cards.push({
9216
9557
  id: stableId(row.id, type, content),
9217
9558
  memory_id: row.id,
@@ -9307,13 +9648,14 @@ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
9307
9648
  last_accessed: String(row.timestamp)
9308
9649
  }));
9309
9650
  }
9310
- var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
9651
+ var MAX_CARDS_PER_MEMORY, MAX_SEGMENT_CHARS, MIN_SEGMENT_CHARS;
9311
9652
  var init_memory_cards = __esm({
9312
9653
  "src/lib/memory-cards.ts"() {
9313
9654
  "use strict";
9314
9655
  init_database();
9315
- MAX_CARDS_PER_MEMORY = 6;
9316
- MAX_SENTENCE_CHARS = 360;
9656
+ MAX_CARDS_PER_MEMORY = 8;
9657
+ MAX_SEGMENT_CHARS = 500;
9658
+ MIN_SEGMENT_CHARS = 20;
9317
9659
  }
9318
9660
  });
9319
9661
 
@@ -10650,9 +10992,9 @@ var init_git_task_sweep = __esm({
10650
10992
  // src/lib/active-agent.ts
10651
10993
  init_config();
10652
10994
  init_session_key();
10653
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
10995
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
10654
10996
  import { execSync as execSync3 } from "child_process";
10655
- import path3 from "path";
10997
+ import path4 from "path";
10656
10998
 
10657
10999
  // src/mcp/agent-context.ts
10658
11000
  import { AsyncLocalStorage } from "async_hooks";
@@ -10663,7 +11005,7 @@ function getAgentContext() {
10663
11005
 
10664
11006
  // src/lib/active-agent.ts
10665
11007
  init_employees();
10666
- var CACHE_DIR = path3.join(EXE_AI_DIR, "session-cache");
11008
+ var CACHE_DIR = path4.join(EXE_AI_DIR, "session-cache");
10667
11009
  var STALE_MS = 24 * 60 * 60 * 1e3;
10668
11010
  function isNameWithOptionalInstance(candidate, baseName) {
10669
11011
  if (candidate === baseName) return true;
@@ -10708,7 +11050,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
10708
11050
  return null;
10709
11051
  }
10710
11052
  function getMarkerPath() {
10711
- return path3.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
11053
+ return path4.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
10712
11054
  }
10713
11055
  function clearActiveAgent() {
10714
11056
  try {
@@ -10721,7 +11063,7 @@ function getActiveAgent() {
10721
11063
  if (httpCtx) return httpCtx;
10722
11064
  try {
10723
11065
  const markerPath = getMarkerPath();
10724
- const raw = readFileSync3(markerPath, "utf8");
11066
+ const raw = readFileSync4(markerPath, "utf8");
10725
11067
  const data = JSON.parse(raw);
10726
11068
  if (data.agentId) {
10727
11069
  if (data.startedAt) {
@@ -10766,15 +11108,15 @@ init_session_key();
10766
11108
 
10767
11109
  // src/lib/cache-warmth.ts
10768
11110
  import os3 from "os";
10769
- import path4 from "path";
10770
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
11111
+ import path5 from "path";
11112
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
10771
11113
  var CACHE_TTL_MS = 5 * 60 * 1e3;
10772
- var CACHE_DIR2 = path4.join(
10773
- process.env.EXE_OS_DIR ?? path4.join(os3.homedir(), ".exe-os"),
11114
+ var CACHE_DIR2 = path5.join(
11115
+ process.env.EXE_OS_DIR ?? path5.join(os3.homedir(), ".exe-os"),
10774
11116
  "session-cache"
10775
11117
  );
10776
11118
  function getStatePath(sessionKey) {
10777
- return path4.join(CACHE_DIR2, `cache-warmth-${sessionKey}.json`);
11119
+ return path5.join(CACHE_DIR2, `cache-warmth-${sessionKey}.json`);
10778
11120
  }
10779
11121
  function clearCacheState(sessionKey) {
10780
11122
  try {