@askexenow/exe-os 0.9.8 → 0.9.9

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 (101) hide show
  1. package/dist/bin/backfill-conversations.js +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -26,6 +26,44 @@ var __copyProps = (to, from, except, desc) => {
26
26
  };
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
+ // src/lib/secure-files.ts
30
+ import { chmodSync, existsSync, mkdirSync } from "fs";
31
+ import { chmod, mkdir } from "fs/promises";
32
+ async function ensurePrivateDir(dirPath) {
33
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
34
+ try {
35
+ await chmod(dirPath, PRIVATE_DIR_MODE);
36
+ } catch {
37
+ }
38
+ }
39
+ function ensurePrivateDirSync(dirPath) {
40
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
41
+ try {
42
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
43
+ } catch {
44
+ }
45
+ }
46
+ async function enforcePrivateFile(filePath) {
47
+ try {
48
+ await chmod(filePath, PRIVATE_FILE_MODE);
49
+ } catch {
50
+ }
51
+ }
52
+ function enforcePrivateFileSync(filePath) {
53
+ try {
54
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
55
+ } catch {
56
+ }
57
+ }
58
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
59
+ var init_secure_files = __esm({
60
+ "src/lib/secure-files.ts"() {
61
+ "use strict";
62
+ PRIVATE_DIR_MODE = 448;
63
+ PRIVATE_FILE_MODE = 384;
64
+ }
65
+ });
66
+
29
67
  // src/lib/config.ts
30
68
  var config_exports = {};
31
69
  __export(config_exports, {
@@ -42,8 +80,8 @@ __export(config_exports, {
42
80
  migrateConfig: () => migrateConfig,
43
81
  saveConfig: () => saveConfig
44
82
  });
45
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
46
- import { readFileSync, existsSync, renameSync } from "fs";
83
+ import { readFile, writeFile } from "fs/promises";
84
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
47
85
  import path from "path";
48
86
  import os from "os";
49
87
  function resolveDataDir() {
@@ -51,7 +89,7 @@ function resolveDataDir() {
51
89
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
52
90
  const newDir = path.join(os.homedir(), ".exe-os");
53
91
  const legacyDir = path.join(os.homedir(), ".exe-mem");
54
- if (!existsSync(newDir) && existsSync(legacyDir)) {
92
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
55
93
  try {
56
94
  renameSync(legacyDir, newDir);
57
95
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -114,9 +152,9 @@ function normalizeAutoUpdate(raw) {
114
152
  }
115
153
  async function loadConfig() {
116
154
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
117
- await mkdir(dir, { recursive: true });
155
+ await ensurePrivateDir(dir);
118
156
  const configPath = path.join(dir, "config.json");
119
- if (!existsSync(configPath)) {
157
+ if (!existsSync2(configPath)) {
120
158
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
121
159
  }
122
160
  const raw = await readFile(configPath, "utf-8");
@@ -129,6 +167,7 @@ async function loadConfig() {
129
167
  `);
130
168
  try {
131
169
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
170
+ await enforcePrivateFile(configPath);
132
171
  } catch {
133
172
  }
134
173
  }
@@ -147,7 +186,7 @@ async function loadConfig() {
147
186
  function loadConfigSync() {
148
187
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
149
188
  const configPath = path.join(dir, "config.json");
150
- if (!existsSync(configPath)) {
189
+ if (!existsSync2(configPath)) {
151
190
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
152
191
  }
153
192
  try {
@@ -165,12 +204,10 @@ function loadConfigSync() {
165
204
  }
166
205
  async function saveConfig(config) {
167
206
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
168
- await mkdir(dir, { recursive: true });
207
+ await ensurePrivateDir(dir);
169
208
  const configPath = path.join(dir, "config.json");
170
209
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
171
- if (config.cloud?.apiKey) {
172
- await chmod(configPath, 384);
173
- }
210
+ await enforcePrivateFile(configPath);
174
211
  }
175
212
  async function loadConfigFrom(configPath) {
176
213
  const raw = await readFile(configPath, "utf-8");
@@ -190,6 +227,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
190
227
  var init_config = __esm({
191
228
  "src/lib/config.ts"() {
192
229
  "use strict";
230
+ init_secure_files();
193
231
  EXE_AI_DIR = resolveDataDir();
194
232
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
195
233
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -306,10 +344,10 @@ __export(agent_config_exports, {
306
344
  saveAgentConfig: () => saveAgentConfig,
307
345
  setAgentRuntime: () => setAgentRuntime
308
346
  });
309
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
347
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
310
348
  import path2 from "path";
311
349
  function loadAgentConfig() {
312
- if (!existsSync2(AGENT_CONFIG_PATH)) return {};
350
+ if (!existsSync3(AGENT_CONFIG_PATH)) return {};
313
351
  try {
314
352
  return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
315
353
  } catch {
@@ -318,8 +356,9 @@ function loadAgentConfig() {
318
356
  }
319
357
  function saveAgentConfig(config) {
320
358
  const dir = path2.dirname(AGENT_CONFIG_PATH);
321
- if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
359
+ ensurePrivateDirSync(dir);
322
360
  writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
361
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
323
362
  }
324
363
  function getAgentRuntime(agentId) {
325
364
  const config = loadAgentConfig();
@@ -359,6 +398,7 @@ var init_agent_config = __esm({
359
398
  "use strict";
360
399
  init_config();
361
400
  init_runtime_table();
401
+ init_secure_files();
362
402
  AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
363
403
  KNOWN_RUNTIMES = {
364
404
  claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
@@ -406,7 +446,7 @@ __export(employees_exports, {
406
446
  validateEmployeeName: () => validateEmployeeName
407
447
  });
408
448
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
409
- import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
449
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
410
450
  import { execSync } from "child_process";
411
451
  import path3 from "path";
412
452
  import os2 from "os";
@@ -445,7 +485,7 @@ function validateEmployeeName(name) {
445
485
  return { valid: true };
446
486
  }
447
487
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
448
- if (!existsSync3(employeesPath)) {
488
+ if (!existsSync4(employeesPath)) {
449
489
  return [];
450
490
  }
451
491
  const raw = await readFile2(employeesPath, "utf-8");
@@ -460,7 +500,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
460
500
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
461
501
  }
462
502
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
463
- if (!existsSync3(employeesPath)) return [];
503
+ if (!existsSync4(employeesPath)) return [];
464
504
  try {
465
505
  return JSON.parse(readFileSync3(employeesPath, "utf-8"));
466
506
  } catch {
@@ -508,7 +548,7 @@ function appendToCoordinatorTeam(employee) {
508
548
  const coordinator = getCoordinatorEmployee(loadEmployeesSync());
509
549
  if (!coordinator) return;
510
550
  const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
511
- if (!existsSync3(idPath)) return;
551
+ if (!existsSync4(idPath)) return;
512
552
  const content = readFileSync3(idPath, "utf-8");
513
553
  if (content.includes(`**${capitalize(employee.name)}`)) return;
514
554
  const teamMatch = content.match(TEAM_SECTION_RE);
@@ -562,9 +602,9 @@ async function normalizeRosterCase(rosterPath) {
562
602
  const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
563
603
  const oldPath = path3.join(identityDir, `${oldName}.md`);
564
604
  const newPath = path3.join(identityDir, `${emp.name}.md`);
565
- if (existsSync3(oldPath) && !existsSync3(newPath)) {
605
+ if (existsSync4(oldPath) && !existsSync4(newPath)) {
566
606
  renameSync2(oldPath, newPath);
567
- } else if (existsSync3(oldPath) && oldPath !== newPath) {
607
+ } else if (existsSync4(oldPath) && oldPath !== newPath) {
568
608
  const content = readFileSync3(oldPath, "utf-8");
569
609
  writeFileSync2(newPath, content, "utf-8");
570
610
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
@@ -607,7 +647,7 @@ function registerBinSymlinks(name) {
607
647
  for (const suffix of ["", "-opencode"]) {
608
648
  const linkName = `${name}${suffix}`;
609
649
  const linkPath = path3.join(binDir, linkName);
610
- if (existsSync3(linkPath)) {
650
+ if (existsSync4(linkPath)) {
611
651
  skipped.push(linkName);
612
652
  continue;
613
653
  }
@@ -638,7 +678,7 @@ var init_employees = __esm({
638
678
  import os3 from "os";
639
679
  import path4 from "path";
640
680
  import {
641
- existsSync as existsSync4,
681
+ existsSync as existsSync5,
642
682
  lstatSync,
643
683
  mkdirSync as mkdirSync2,
644
684
  readlinkSync as readlinkSync2,
@@ -657,7 +697,7 @@ function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
657
697
  const target = identitySourcePath(homeDir, agentId);
658
698
  const link = claudeAgentLinkPath(homeDir, agentId);
659
699
  mkdirSync2(claudeAgentsDir(homeDir), { recursive: true });
660
- if (existsSync4(link)) {
700
+ if (existsSync5(link)) {
661
701
  let stat2;
662
702
  try {
663
703
  stat2 = lstatSync(link);
@@ -731,12 +771,12 @@ __export(preferences_exports, {
731
771
  loadPreferences: () => loadPreferences,
732
772
  savePreferences: () => savePreferences
733
773
  });
734
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
774
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
735
775
  import path5 from "path";
736
776
  import os4 from "os";
737
777
  function loadPreferences(homeDir = os4.homedir()) {
738
778
  const configPath = path5.join(homeDir, ".exe-os", "config.json");
739
- if (!existsSync5(configPath)) return {};
779
+ if (!existsSync6(configPath)) return {};
740
780
  try {
741
781
  const config = JSON.parse(readFileSync4(configPath, "utf-8"));
742
782
  return config.preferences ?? {};
@@ -747,9 +787,9 @@ function loadPreferences(homeDir = os4.homedir()) {
747
787
  function savePreferences(prefs, homeDir = os4.homedir()) {
748
788
  const configDir = path5.join(homeDir, ".exe-os");
749
789
  const configPath = path5.join(configDir, "config.json");
750
- mkdirSync3(configDir, { recursive: true });
790
+ ensurePrivateDirSync(configDir);
751
791
  let config = {};
752
- if (existsSync5(configPath)) {
792
+ if (existsSync6(configPath)) {
753
793
  try {
754
794
  config = JSON.parse(readFileSync4(configPath, "utf-8"));
755
795
  } catch {
@@ -758,10 +798,12 @@ function savePreferences(prefs, homeDir = os4.homedir()) {
758
798
  }
759
799
  config.preferences = prefs;
760
800
  writeFileSync3(configPath, JSON.stringify(config, null, 2) + "\n");
801
+ enforcePrivateFileSync(configPath);
761
802
  }
762
803
  var init_preferences = __esm({
763
804
  "src/lib/preferences.ts"() {
764
805
  "use strict";
806
+ init_secure_files();
765
807
  }
766
808
  });
767
809
 
@@ -779,7 +821,7 @@ __export(installer_exports, {
779
821
  setupTmux: () => setupTmux
780
822
  });
781
823
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
782
- import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync4 } from "fs";
824
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
783
825
  import path6 from "path";
784
826
  import os5 from "os";
785
827
  import { execSync as execSync2 } from "child_process";
@@ -790,7 +832,7 @@ function resolvePackageRoot() {
790
832
  const root = path6.parse(dir).root;
791
833
  while (dir !== root) {
792
834
  const pkgPath = path6.join(dir, "package.json");
793
- if (existsSync6(pkgPath)) {
835
+ if (existsSync7(pkgPath)) {
794
836
  try {
795
837
  const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
796
838
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
@@ -806,7 +848,7 @@ async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
806
848
  let skipped = 0;
807
849
  const skillsBase = path6.join(homeDir, ".claude", "skills");
808
850
  const exeDir = path6.join(packageRoot, "src", "commands", "exe");
809
- if (existsSync6(exeDir)) {
851
+ if (existsSync7(exeDir)) {
810
852
  const entries = await readdir(exeDir);
811
853
  const mdFiles = entries.filter((f) => f.endsWith(".md"));
812
854
  for (const file of mdFiles) {
@@ -821,7 +863,7 @@ async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
821
863
  }
822
864
  }
823
865
  const topLevelSrc = path6.join(packageRoot, "src", "commands", "exe.md");
824
- if (existsSync6(topLevelSrc)) {
866
+ if (existsSync7(topLevelSrc)) {
825
867
  const destDir = path6.join(skillsBase, "exe");
826
868
  await mkdir3(destDir, { recursive: true });
827
869
  const destPath = path6.join(destDir, "SKILL.md");
@@ -847,7 +889,7 @@ name: ${skillName}
847
889
  `);
848
890
  }
849
891
  }
850
- if (existsSync6(destPath)) {
892
+ if (existsSync7(destPath)) {
851
893
  const existing = await readFile3(destPath, "utf-8");
852
894
  if (existing === content) return false;
853
895
  }
@@ -857,7 +899,7 @@ name: ${skillName}
857
899
  async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
858
900
  const claudeJsonPath = path6.join(homeDir, ".claude.json");
859
901
  let claudeJson = {};
860
- if (existsSync6(claudeJsonPath)) {
902
+ if (existsSync7(claudeJsonPath)) {
861
903
  try {
862
904
  claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
863
905
  } catch {
@@ -874,21 +916,21 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
874
916
  env: {}
875
917
  };
876
918
  const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
877
- const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
878
919
  const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
879
- const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
880
- if (memMatches && osMatches) {
920
+ if (claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
921
+ delete claudeJson.mcpServers[MCP_PRIMARY_KEY];
922
+ }
923
+ if (memMatches && !claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
881
924
  await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
882
925
  return false;
883
926
  }
884
927
  claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
885
- claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
886
928
  await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
887
929
  await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
888
930
  return true;
889
931
  }
890
932
  async function cleanSettingsJsonMcp(settingsPath) {
891
- if (!existsSync6(settingsPath)) return;
933
+ if (!existsSync7(settingsPath)) return;
892
934
  try {
893
935
  const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
894
936
  const servers = settings.mcpServers;
@@ -915,7 +957,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
915
957
  const logSuffix = ` 2>> "${hookLogPath}"`;
916
958
  await mkdir3(logsDir, { recursive: true });
917
959
  let settings = {};
918
- if (existsSync6(settingsPath)) {
960
+ if (existsSync7(settingsPath)) {
919
961
  try {
920
962
  settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
921
963
  } catch {
@@ -1183,7 +1225,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
1183
1225
  }
1184
1226
  async function cleanOldShellFunctions(homeDir = os5.homedir()) {
1185
1227
  const rosterPath = path6.join(homeDir, ".exe-os", "exe-employees.json");
1186
- if (!existsSync6(rosterPath)) return 0;
1228
+ if (!existsSync7(rosterPath)) return 0;
1187
1229
  let employees;
1188
1230
  try {
1189
1231
  employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
@@ -1204,7 +1246,7 @@ async function cleanOldShellFunctions(homeDir = os5.homedir()) {
1204
1246
  const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
1205
1247
  let totalRemoved = 0;
1206
1248
  for (const rcPath of rcFiles) {
1207
- if (!existsSync6(rcPath)) continue;
1249
+ if (!existsSync7(rcPath)) continue;
1208
1250
  let content;
1209
1251
  try {
1210
1252
  content = await readFile3(rcPath, "utf-8");
@@ -1337,13 +1379,13 @@ async function installStatusLine(packageRoot, homeDir = os5.homedir()) {
1337
1379
  const claudeDir = path6.join(homeDir, ".claude");
1338
1380
  await mkdir3(claudeDir, { recursive: true });
1339
1381
  const assetPath = path6.join(packageRoot, "dist", "assets", "statusline-command.sh");
1340
- if (!existsSync6(assetPath)) return "asset-missing";
1382
+ if (!existsSync7(assetPath)) return "asset-missing";
1341
1383
  const destScript = path6.join(claudeDir, "statusline-command.sh");
1342
1384
  const assetContent = await readFile3(assetPath, "utf-8");
1343
1385
  await writeFile3(destScript, assetContent, { mode: 493 });
1344
1386
  const settingsPath = path6.join(claudeDir, "settings.json");
1345
1387
  let settings = {};
1346
- if (existsSync6(settingsPath)) {
1388
+ if (existsSync7(settingsPath)) {
1347
1389
  try {
1348
1390
  settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
1349
1391
  } catch {
@@ -1382,7 +1424,7 @@ async function runInstaller(homeDir) {
1382
1424
  );
1383
1425
  const resolvedHome = homeDir ?? os5.homedir();
1384
1426
  const exeWorkspace = path6.join(resolvedHome, "exe");
1385
- if (!existsSync6(exeWorkspace)) {
1427
+ if (!existsSync7(exeWorkspace)) {
1386
1428
  try {
1387
1429
  await mkdir3(path6.join(exeWorkspace, "content"), { recursive: true });
1388
1430
  await mkdir3(path6.join(exeWorkspace, "operations"), { recursive: true });
@@ -1429,17 +1471,17 @@ function setupTmux(home) {
1429
1471
  const sourceLine = "source-file ~/.exe-os/tmux.conf";
1430
1472
  const pkgRoot = resolvePackageRoot();
1431
1473
  const assetPath = path6.join(pkgRoot, "dist", "assets", "tmux.conf");
1432
- if (!existsSync6(assetPath)) {
1474
+ if (!existsSync7(assetPath)) {
1433
1475
  process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
1434
1476
  `);
1435
1477
  return;
1436
1478
  }
1437
- mkdirSync4(exeDir, { recursive: true });
1479
+ mkdirSync3(exeDir, { recursive: true });
1438
1480
  copyFileSync(assetPath, exeTmuxConf);
1439
- if (existsSync6(userTmuxConf)) {
1481
+ if (existsSync7(userTmuxConf)) {
1440
1482
  const existing = readFileSync5(userTmuxConf, "utf8");
1441
1483
  if (!existing.includes(sourceLine)) {
1442
- if (!existsSync6(backupPath)) {
1484
+ if (!existsSync7(backupPath)) {
1443
1485
  copyFileSync(userTmuxConf, backupPath);
1444
1486
  process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
1445
1487
  `);
@@ -1462,7 +1504,7 @@ function setupGhostty(home) {
1462
1504
  const homeDir = home ?? os5.homedir();
1463
1505
  const xdgConfig = path6.join(homeDir, ".config", "ghostty");
1464
1506
  const macConfig = path6.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
1465
- const ghosttyInstalled = existsSync6(xdgConfig) || existsSync6(macConfig) || (() => {
1507
+ const ghosttyInstalled = existsSync7(xdgConfig) || existsSync7(macConfig) || (() => {
1466
1508
  try {
1467
1509
  execSync2("which ghostty 2>/dev/null");
1468
1510
  return true;
@@ -1475,28 +1517,28 @@ function setupGhostty(home) {
1475
1517
  }
1476
1518
  const pkgRoot = resolvePackageRoot();
1477
1519
  const assetPath = path6.join(pkgRoot, "dist", "assets", "ghostty.conf");
1478
- if (!existsSync6(assetPath)) {
1520
+ if (!existsSync7(assetPath)) {
1479
1521
  process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
1480
1522
  return;
1481
1523
  }
1482
1524
  const configDir = xdgConfig;
1483
1525
  const configPath = path6.join(configDir, "config");
1484
1526
  const backupPath = path6.join(configDir, "config.backup");
1485
- mkdirSync4(configDir, { recursive: true });
1527
+ mkdirSync3(configDir, { recursive: true });
1486
1528
  const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
1487
1529
  const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
1488
1530
  const assetContent = readFileSync5(assetPath, "utf8").trim();
1489
1531
  const markedSection = `${START_MARKER}
1490
1532
  ${assetContent}
1491
1533
  ${END_MARKER}`;
1492
- if (existsSync6(configPath)) {
1534
+ if (existsSync7(configPath)) {
1493
1535
  const existing = readFileSync5(configPath, "utf8");
1494
1536
  if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
1495
1537
  const before = existing.slice(0, existing.indexOf(START_MARKER));
1496
1538
  const after = existing.slice(existing.indexOf(END_MARKER) + END_MARKER.length);
1497
1539
  writeFileSync4(configPath, `${before}${markedSection}${after}`);
1498
1540
  } else if (existing.includes("Exe OS")) {
1499
- if (!existsSync6(backupPath)) {
1541
+ if (!existsSync7(backupPath)) {
1500
1542
  copyFileSync(configPath, backupPath);
1501
1543
  process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
1502
1544
  `);
@@ -1504,7 +1546,7 @@ ${END_MARKER}`;
1504
1546
  writeFileSync4(configPath, `${markedSection}
1505
1547
  `);
1506
1548
  } else {
1507
- if (!existsSync6(backupPath)) {
1549
+ if (!existsSync7(backupPath)) {
1508
1550
  copyFileSync(configPath, backupPath);
1509
1551
  process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
1510
1552
  `);
@@ -1564,7 +1606,7 @@ __export(keychain_exports, {
1564
1606
  setMasterKey: () => setMasterKey
1565
1607
  });
1566
1608
  import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
1567
- import { existsSync as existsSync7 } from "fs";
1609
+ import { existsSync as existsSync8 } from "fs";
1568
1610
  import path7 from "path";
1569
1611
  import os6 from "os";
1570
1612
  function getKeyDir() {
@@ -1592,7 +1634,7 @@ async function getMasterKey() {
1592
1634
  }
1593
1635
  }
1594
1636
  const keyPath = getKeyPath();
1595
- if (!existsSync7(keyPath)) {
1637
+ if (!existsSync8(keyPath)) {
1596
1638
  process.stderr.write(
1597
1639
  `[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
1598
1640
  `
@@ -1635,7 +1677,7 @@ async function deleteMasterKey() {
1635
1677
  }
1636
1678
  }
1637
1679
  const keyPath = getKeyPath();
1638
- if (existsSync7(keyPath)) {
1680
+ if (existsSync8(keyPath)) {
1639
1681
  await unlink(keyPath);
1640
1682
  }
1641
1683
  }
@@ -2363,13 +2405,50 @@ var init_database_adapter = __esm({
2363
2405
  }
2364
2406
  });
2365
2407
 
2408
+ // src/lib/daemon-auth.ts
2409
+ import crypto2 from "crypto";
2410
+ import path9 from "path";
2411
+ import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
2412
+ function normalizeToken(token) {
2413
+ if (!token) return null;
2414
+ const trimmed = token.trim();
2415
+ return trimmed.length > 0 ? trimmed : null;
2416
+ }
2417
+ function readDaemonToken() {
2418
+ try {
2419
+ if (!existsSync9(DAEMON_TOKEN_PATH)) return null;
2420
+ return normalizeToken(readFileSync6(DAEMON_TOKEN_PATH, "utf8"));
2421
+ } catch {
2422
+ return null;
2423
+ }
2424
+ }
2425
+ function ensureDaemonToken(seed) {
2426
+ const existing = readDaemonToken();
2427
+ if (existing) return existing;
2428
+ const token = normalizeToken(seed) ?? crypto2.randomBytes(32).toString("hex");
2429
+ ensurePrivateDirSync(EXE_AI_DIR);
2430
+ writeFileSync5(DAEMON_TOKEN_PATH, `${token}
2431
+ `, "utf8");
2432
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
2433
+ return token;
2434
+ }
2435
+ var DAEMON_TOKEN_PATH;
2436
+ var init_daemon_auth = __esm({
2437
+ "src/lib/daemon-auth.ts"() {
2438
+ "use strict";
2439
+ init_config();
2440
+ init_secure_files();
2441
+ DAEMON_TOKEN_PATH = path9.join(EXE_AI_DIR, "exed.token");
2442
+ }
2443
+ });
2444
+
2366
2445
  // src/lib/exe-daemon-client.ts
2367
2446
  import net from "net";
2368
2447
  import os8 from "os";
2369
2448
  import { spawn } from "child_process";
2370
2449
  import { randomUUID } from "crypto";
2371
- import { existsSync as existsSync8, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
2372
- import path9 from "path";
2450
+ import { existsSync as existsSync10, unlinkSync as unlinkSync2, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
2451
+ import path10 from "path";
2373
2452
  import { fileURLToPath as fileURLToPath3 } from "url";
2374
2453
  function handleData(chunk) {
2375
2454
  _buffer += chunk.toString();
@@ -2397,9 +2476,9 @@ function handleData(chunk) {
2397
2476
  }
2398
2477
  }
2399
2478
  function cleanupStaleFiles() {
2400
- if (existsSync8(PID_PATH)) {
2479
+ if (existsSync10(PID_PATH)) {
2401
2480
  try {
2402
- const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
2481
+ const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
2403
2482
  if (pid > 0) {
2404
2483
  try {
2405
2484
  process.kill(pid, 0);
@@ -2420,11 +2499,11 @@ function cleanupStaleFiles() {
2420
2499
  }
2421
2500
  }
2422
2501
  function findPackageRoot() {
2423
- let dir = path9.dirname(fileURLToPath3(import.meta.url));
2424
- const { root } = path9.parse(dir);
2502
+ let dir = path10.dirname(fileURLToPath3(import.meta.url));
2503
+ const { root } = path10.parse(dir);
2425
2504
  while (dir !== root) {
2426
- if (existsSync8(path9.join(dir, "package.json"))) return dir;
2427
- dir = path9.dirname(dir);
2505
+ if (existsSync10(path10.join(dir, "package.json"))) return dir;
2506
+ dir = path10.dirname(dir);
2428
2507
  }
2429
2508
  return null;
2430
2509
  }
@@ -2450,16 +2529,17 @@ function spawnDaemon() {
2450
2529
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
2451
2530
  return;
2452
2531
  }
2453
- const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
2454
- if (!existsSync8(daemonPath)) {
2532
+ const daemonPath = path10.join(pkgRoot, "dist", "lib", "exe-daemon.js");
2533
+ if (!existsSync10(daemonPath)) {
2455
2534
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
2456
2535
  `);
2457
2536
  return;
2458
2537
  }
2459
2538
  const resolvedPath = daemonPath;
2539
+ const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
2460
2540
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
2461
2541
  `);
2462
- const logPath = path9.join(path9.dirname(SOCKET_PATH), "exed.log");
2542
+ const logPath = path10.join(path10.dirname(SOCKET_PATH), "exed.log");
2463
2543
  let stderrFd = "ignore";
2464
2544
  try {
2465
2545
  stderrFd = openSync(logPath, "a");
@@ -2477,7 +2557,8 @@ function spawnDaemon() {
2477
2557
  TMUX_PANE: void 0,
2478
2558
  // Prevents resolveExeSession() from scoping to one session
2479
2559
  EXE_DAEMON_SOCK: SOCKET_PATH,
2480
- EXE_DAEMON_PID: PID_PATH
2560
+ EXE_DAEMON_PID: PID_PATH,
2561
+ [DAEMON_TOKEN_ENV]: daemonToken
2481
2562
  }
2482
2563
  });
2483
2564
  child.unref();
@@ -2587,13 +2668,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
2587
2668
  return;
2588
2669
  }
2589
2670
  const id = randomUUID();
2671
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
2590
2672
  const timer = setTimeout(() => {
2591
2673
  _pending.delete(id);
2592
2674
  resolve({ error: "Request timeout" });
2593
2675
  }, timeoutMs);
2594
2676
  _pending.set(id, { resolve, timer });
2595
2677
  try {
2596
- _socket.write(JSON.stringify({ id, ...payload }) + "\n");
2678
+ _socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
2597
2679
  } catch {
2598
2680
  clearTimeout(timer);
2599
2681
  _pending.delete(id);
@@ -2622,9 +2704,9 @@ function killAndRespawnDaemon() {
2622
2704
  }
2623
2705
  try {
2624
2706
  process.stderr.write("[exed-client] Killing daemon for restart...\n");
2625
- if (existsSync8(PID_PATH)) {
2707
+ if (existsSync10(PID_PATH)) {
2626
2708
  try {
2627
- const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
2709
+ const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
2628
2710
  if (pid > 0) {
2629
2711
  try {
2630
2712
  process.kill(pid, "SIGKILL");
@@ -2744,17 +2826,19 @@ function disconnectClient() {
2744
2826
  function isClientConnected() {
2745
2827
  return _connected;
2746
2828
  }
2747
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
2829
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
2748
2830
  var init_exe_daemon_client = __esm({
2749
2831
  "src/lib/exe-daemon-client.ts"() {
2750
2832
  "use strict";
2751
2833
  init_config();
2752
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path9.join(EXE_AI_DIR, "exed.sock");
2753
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path9.join(EXE_AI_DIR, "exed.pid");
2754
- SPAWN_LOCK_PATH = path9.join(EXE_AI_DIR, "exed-spawn.lock");
2834
+ init_daemon_auth();
2835
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path10.join(EXE_AI_DIR, "exed.sock");
2836
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path10.join(EXE_AI_DIR, "exed.pid");
2837
+ SPAWN_LOCK_PATH = path10.join(EXE_AI_DIR, "exed-spawn.lock");
2755
2838
  SPAWN_LOCK_STALE_MS = 3e4;
2756
2839
  CONNECT_TIMEOUT_MS = 15e3;
2757
2840
  REQUEST_TIMEOUT_MS = 3e4;
2841
+ DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
2758
2842
  _socket = null;
2759
2843
  _connected = false;
2760
2844
  _buffer = "";
@@ -3339,6 +3423,7 @@ async function ensureSchema() {
3339
3423
  project TEXT NOT NULL,
3340
3424
  summary TEXT NOT NULL,
3341
3425
  task_file TEXT,
3426
+ session_scope TEXT,
3342
3427
  read INTEGER NOT NULL DEFAULT 0,
3343
3428
  created_at TEXT NOT NULL
3344
3429
  );
@@ -3347,7 +3432,7 @@ async function ensureSchema() {
3347
3432
  ON notifications(read);
3348
3433
 
3349
3434
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
3350
- ON notifications(agent_id);
3435
+ ON notifications(agent_id, session_scope);
3351
3436
 
3352
3437
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
3353
3438
  ON notifications(task_file);
@@ -3385,6 +3470,7 @@ async function ensureSchema() {
3385
3470
  target_agent TEXT NOT NULL,
3386
3471
  target_project TEXT,
3387
3472
  target_device TEXT NOT NULL DEFAULT 'local',
3473
+ session_scope TEXT,
3388
3474
  content TEXT NOT NULL,
3389
3475
  priority TEXT DEFAULT 'normal',
3390
3476
  status TEXT DEFAULT 'pending',
@@ -3398,10 +3484,31 @@ async function ensureSchema() {
3398
3484
  );
3399
3485
 
3400
3486
  CREATE INDEX IF NOT EXISTS idx_messages_target
3401
- ON messages(target_agent, status);
3487
+ ON messages(target_agent, session_scope, status);
3402
3488
 
3403
3489
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
3404
- ON messages(target_agent, from_agent, server_seq);
3490
+ ON messages(target_agent, session_scope, from_agent, server_seq);
3491
+ `);
3492
+ try {
3493
+ await client.execute({
3494
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
3495
+ args: []
3496
+ });
3497
+ } catch {
3498
+ }
3499
+ try {
3500
+ await client.execute({
3501
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
3502
+ args: []
3503
+ });
3504
+ } catch {
3505
+ }
3506
+ await client.executeMultiple(`
3507
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
3508
+ ON notifications(agent_id, session_scope, read, created_at);
3509
+
3510
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
3511
+ ON messages(target_agent, session_scope, status, created_at);
3405
3512
  `);
3406
3513
  try {
3407
3514
  await client.execute({
@@ -3985,6 +4092,13 @@ async function ensureSchema() {
3985
4092
  } catch {
3986
4093
  }
3987
4094
  }
4095
+ try {
4096
+ await client.execute({
4097
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
4098
+ args: []
4099
+ });
4100
+ } catch {
4101
+ }
3988
4102
  }
3989
4103
  async function disposeDatabase() {
3990
4104
  if (_walCheckpointTimer) {
@@ -4030,13 +4144,13 @@ __export(crypto_exports, {
4030
4144
  initSyncCrypto: () => initSyncCrypto,
4031
4145
  isSyncCryptoInitialized: () => isSyncCryptoInitialized
4032
4146
  });
4033
- import crypto2 from "crypto";
4147
+ import crypto3 from "crypto";
4034
4148
  function initSyncCrypto(masterKey) {
4035
4149
  if (masterKey.length !== 32) {
4036
4150
  throw new Error(`Master key must be 32 bytes, got ${masterKey.length}`);
4037
4151
  }
4038
4152
  _syncKey = Buffer.from(
4039
- crypto2.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
4153
+ crypto3.hkdfSync("sha256", masterKey, "", SYNC_HKDF_INFO, 32)
4040
4154
  );
4041
4155
  }
4042
4156
  function isSyncCryptoInitialized() {
@@ -4050,8 +4164,8 @@ function requireSyncKey() {
4050
4164
  }
4051
4165
  function encryptSyncBlob(data) {
4052
4166
  const key = requireSyncKey();
4053
- const iv = crypto2.randomBytes(IV_LENGTH);
4054
- const cipher = crypto2.createCipheriv(ALGORITHM, key, iv);
4167
+ const iv = crypto3.randomBytes(IV_LENGTH);
4168
+ const cipher = crypto3.createCipheriv(ALGORITHM, key, iv);
4055
4169
  const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
4056
4170
  const tag = cipher.getAuthTag();
4057
4171
  return Buffer.concat([iv, encrypted, tag]).toString("base64");
@@ -4065,7 +4179,7 @@ function decryptSyncBlob(ciphertext) {
4065
4179
  const iv = combined.subarray(0, IV_LENGTH);
4066
4180
  const tag = combined.subarray(combined.length - TAG_LENGTH);
4067
4181
  const encrypted = combined.subarray(IV_LENGTH, combined.length - TAG_LENGTH);
4068
- const decipher = crypto2.createDecipheriv(ALGORITHM, key, iv);
4182
+ const decipher = crypto3.createDecipheriv(ALGORITHM, key, iv);
4069
4183
  decipher.setAuthTag(tag);
4070
4184
  return Buffer.concat([decipher.update(encrypted), decipher.final()]);
4071
4185
  }
@@ -4118,9 +4232,12 @@ __export(license_exports, {
4118
4232
  stopLicenseRevalidation: () => stopLicenseRevalidation,
4119
4233
  validateLicense: () => validateLicense
4120
4234
  });
4121
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
4235
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync4 } from "fs";
4122
4236
  import { randomUUID as randomUUID2 } from "crypto";
4123
- import path10 from "path";
4237
+ import { createRequire as createRequire2 } from "module";
4238
+ import { pathToFileURL as pathToFileURL2 } from "url";
4239
+ import os9 from "os";
4240
+ import path11 from "path";
4124
4241
  import { jwtVerify, importSPKI } from "jose";
4125
4242
  async function fetchRetry(url, init) {
4126
4243
  try {
@@ -4131,37 +4248,37 @@ async function fetchRetry(url, init) {
4131
4248
  }
4132
4249
  }
4133
4250
  function loadDeviceId() {
4134
- const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
4251
+ const deviceJsonPath = path11.join(EXE_AI_DIR, "device.json");
4135
4252
  try {
4136
- if (existsSync9(deviceJsonPath)) {
4137
- const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
4253
+ if (existsSync11(deviceJsonPath)) {
4254
+ const data = JSON.parse(readFileSync8(deviceJsonPath, "utf8"));
4138
4255
  if (data.deviceId) return data.deviceId;
4139
4256
  }
4140
4257
  } catch {
4141
4258
  }
4142
4259
  try {
4143
- if (existsSync9(DEVICE_ID_PATH)) {
4144
- const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
4260
+ if (existsSync11(DEVICE_ID_PATH)) {
4261
+ const id2 = readFileSync8(DEVICE_ID_PATH, "utf8").trim();
4145
4262
  if (id2) return id2;
4146
4263
  }
4147
4264
  } catch {
4148
4265
  }
4149
4266
  const id = randomUUID2();
4150
- mkdirSync5(EXE_AI_DIR, { recursive: true });
4151
- writeFileSync5(DEVICE_ID_PATH, id, "utf8");
4267
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
4268
+ writeFileSync6(DEVICE_ID_PATH, id, "utf8");
4152
4269
  return id;
4153
4270
  }
4154
4271
  function loadLicense() {
4155
4272
  try {
4156
- if (!existsSync9(LICENSE_PATH)) return null;
4157
- return readFileSync7(LICENSE_PATH, "utf8").trim();
4273
+ if (!existsSync11(LICENSE_PATH)) return null;
4274
+ return readFileSync8(LICENSE_PATH, "utf8").trim();
4158
4275
  } catch {
4159
4276
  return null;
4160
4277
  }
4161
4278
  }
4162
4279
  function saveLicense(apiKey) {
4163
- mkdirSync5(EXE_AI_DIR, { recursive: true });
4164
- writeFileSync5(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4280
+ mkdirSync4(EXE_AI_DIR, { recursive: true });
4281
+ writeFileSync6(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4165
4282
  }
4166
4283
  async function verifyLicenseJwt(token) {
4167
4284
  try {
@@ -4187,8 +4304,8 @@ async function verifyLicenseJwt(token) {
4187
4304
  }
4188
4305
  async function getCachedLicense() {
4189
4306
  try {
4190
- if (!existsSync9(CACHE_PATH)) return null;
4191
- const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
4307
+ if (!existsSync11(CACHE_PATH)) return null;
4308
+ const raw = JSON.parse(readFileSync8(CACHE_PATH, "utf8"));
4192
4309
  if (!raw.token || typeof raw.token !== "string") return null;
4193
4310
  return await verifyLicenseJwt(raw.token);
4194
4311
  } catch {
@@ -4197,8 +4314,8 @@ async function getCachedLicense() {
4197
4314
  }
4198
4315
  function readCachedToken() {
4199
4316
  try {
4200
- if (!existsSync9(CACHE_PATH)) return null;
4201
- const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
4317
+ if (!existsSync11(CACHE_PATH)) return null;
4318
+ const raw = JSON.parse(readFileSync8(CACHE_PATH, "utf8"));
4202
4319
  return typeof raw.token === "string" ? raw.token : null;
4203
4320
  } catch {
4204
4321
  return null;
@@ -4232,56 +4349,130 @@ function getRawCachedPlan() {
4232
4349
  }
4233
4350
  function cacheResponse(token) {
4234
4351
  try {
4235
- writeFileSync5(CACHE_PATH, JSON.stringify({ token }), "utf8");
4352
+ writeFileSync6(CACHE_PATH, JSON.stringify({ token }), "utf8");
4236
4353
  } catch {
4237
4354
  }
4238
4355
  }
4239
- async function validateLicense(apiKey, deviceId) {
4240
- const did = deviceId ?? loadDeviceId();
4356
+ function loadPrismaForLicense() {
4357
+ if (_prismaFailed) return null;
4358
+ const dbUrl = process.env.DATABASE_URL;
4359
+ if (!dbUrl) {
4360
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path11.join(os9.homedir(), "exe-db");
4361
+ if (!existsSync11(path11.join(exeDbRoot, "package.json"))) {
4362
+ _prismaFailed = true;
4363
+ return null;
4364
+ }
4365
+ }
4366
+ if (!_prismaPromise) {
4367
+ _prismaPromise = (async () => {
4368
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
4369
+ if (explicitPath) {
4370
+ const mod2 = await import(pathToFileURL2(explicitPath).href);
4371
+ const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
4372
+ if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
4373
+ return new Ctor2();
4374
+ }
4375
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path11.join(os9.homedir(), "exe-db");
4376
+ const req = createRequire2(path11.join(exeDbRoot, "package.json"));
4377
+ const entry = req.resolve("@prisma/client");
4378
+ const mod = await import(pathToFileURL2(entry).href);
4379
+ const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
4380
+ if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
4381
+ return new Ctor();
4382
+ })().catch((err) => {
4383
+ _prismaFailed = true;
4384
+ _prismaPromise = null;
4385
+ throw err;
4386
+ });
4387
+ }
4388
+ return _prismaPromise;
4389
+ }
4390
+ async function validateViaPostgres(apiKey) {
4391
+ const loader = loadPrismaForLicense();
4392
+ if (!loader) return null;
4393
+ try {
4394
+ const prisma = await loader;
4395
+ const rows = await prisma.$queryRawUnsafe(
4396
+ `SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
4397
+ FROM billing.licenses WHERE key = $1 LIMIT 1`,
4398
+ apiKey
4399
+ );
4400
+ if (!rows || rows.length === 0) return null;
4401
+ const row = rows[0];
4402
+ if (row.status !== "active") return null;
4403
+ if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
4404
+ const plan = row.plan;
4405
+ const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
4406
+ return {
4407
+ valid: true,
4408
+ plan,
4409
+ email: row.email,
4410
+ expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
4411
+ deviceLimit: row.device_limit ?? limits.devices,
4412
+ employeeLimit: row.employee_limit ?? limits.employees,
4413
+ memoryLimit: row.memory_limit ?? limits.memories
4414
+ };
4415
+ } catch {
4416
+ return null;
4417
+ }
4418
+ }
4419
+ async function validateViaCFWorker(apiKey, deviceId) {
4241
4420
  try {
4242
4421
  const res = await fetchRetry(`${API_BASE}/auth/activate`, {
4243
4422
  method: "POST",
4244
4423
  headers: { "Content-Type": "application/json" },
4245
- body: JSON.stringify({ apiKey, deviceId: did }),
4424
+ body: JSON.stringify({ apiKey, deviceId }),
4246
4425
  signal: AbortSignal.timeout(1e4)
4247
4426
  });
4248
- if (res.ok) {
4249
- const data = await res.json();
4250
- if (data.error === "device_limit_exceeded") {
4251
- const cached2 = await getCachedLicense();
4252
- if (cached2) return cached2;
4253
- const raw2 = getRawCachedPlan();
4254
- if (raw2) return { ...raw2, valid: false };
4255
- return { ...FREE_LICENSE, valid: false, plan: "free" };
4256
- }
4257
- if (data.token) {
4258
- cacheResponse(data.token);
4259
- const verified = await verifyLicenseJwt(data.token);
4260
- if (verified) return verified;
4261
- }
4262
- const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
4263
- return {
4264
- valid: data.valid,
4265
- plan: data.plan,
4266
- email: data.email,
4267
- expiresAt: data.expiresAt,
4268
- deviceLimit: limits.devices,
4269
- employeeLimit: limits.employees,
4270
- memoryLimit: limits.memories
4271
- };
4427
+ if (!res.ok) return null;
4428
+ const data = await res.json();
4429
+ if (data.error === "device_limit_exceeded") return null;
4430
+ if (!data.valid) return null;
4431
+ if (data.token) {
4432
+ cacheResponse(data.token);
4433
+ const verified = await verifyLicenseJwt(data.token);
4434
+ if (verified) return verified;
4435
+ }
4436
+ const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
4437
+ return {
4438
+ valid: data.valid,
4439
+ plan: data.plan,
4440
+ email: data.email,
4441
+ expiresAt: data.expiresAt,
4442
+ deviceLimit: limits.devices,
4443
+ employeeLimit: limits.employees,
4444
+ memoryLimit: limits.memories
4445
+ };
4446
+ } catch {
4447
+ return null;
4448
+ }
4449
+ }
4450
+ async function validateLicense(apiKey, deviceId) {
4451
+ const did = deviceId ?? loadDeviceId();
4452
+ const pgResult = await validateViaPostgres(apiKey);
4453
+ if (pgResult) {
4454
+ try {
4455
+ writeFileSync6(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
4456
+ } catch {
4457
+ }
4458
+ return pgResult;
4459
+ }
4460
+ const cfResult = await validateViaCFWorker(apiKey, did);
4461
+ if (cfResult) return cfResult;
4462
+ const cached = await getCachedLicense();
4463
+ if (cached) return cached;
4464
+ try {
4465
+ if (existsSync11(CACHE_PATH)) {
4466
+ const raw = JSON.parse(readFileSync8(CACHE_PATH, "utf8"));
4467
+ if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
4468
+ return raw.pgLicense;
4469
+ }
4272
4470
  }
4273
- const cached = await getCachedLicense();
4274
- if (cached) return cached;
4275
- const raw = getRawCachedPlan();
4276
- if (raw) return raw;
4277
- return { ...FREE_LICENSE, valid: false, plan: "free" };
4278
4471
  } catch {
4279
- const cached = await getCachedLicense();
4280
- if (cached) return cached;
4281
- const rawFallback = getRawCachedPlan();
4282
- if (rawFallback) return rawFallback;
4283
- return { ...FREE_LICENSE, valid: false, error: "offline" };
4284
4472
  }
4473
+ const rawFallback = getRawCachedPlan();
4474
+ if (rawFallback) return rawFallback;
4475
+ return { ...FREE_LICENSE, valid: false };
4285
4476
  }
4286
4477
  function getCacheAgeMs() {
4287
4478
  try {
@@ -4296,9 +4487,9 @@ async function checkLicense() {
4296
4487
  let key = loadLicense();
4297
4488
  if (!key) {
4298
4489
  try {
4299
- const configPath = path10.join(EXE_AI_DIR, "config.json");
4300
- if (existsSync9(configPath)) {
4301
- const raw = JSON.parse(readFileSync7(configPath, "utf8"));
4490
+ const configPath = path11.join(EXE_AI_DIR, "config.json");
4491
+ if (existsSync11(configPath)) {
4492
+ const raw = JSON.parse(readFileSync8(configPath, "utf8"));
4302
4493
  const cloud = raw.cloud;
4303
4494
  if (cloud?.apiKey) {
4304
4495
  key = cloud.apiKey;
@@ -4452,14 +4643,14 @@ function stopLicenseRevalidation() {
4452
4643
  _revalTimer = null;
4453
4644
  }
4454
4645
  }
4455
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
4646
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, _prismaPromise, _prismaFailed, CACHE_MAX_AGE_MS, _revalTimer;
4456
4647
  var init_license = __esm({
4457
4648
  "src/lib/license.ts"() {
4458
4649
  "use strict";
4459
4650
  init_config();
4460
- LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
4461
- CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
4462
- DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
4651
+ LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
4652
+ CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
4653
+ DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
4463
4654
  API_BASE = "https://askexe.com/cloud";
4464
4655
  RETRY_DELAY_MS = 500;
4465
4656
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -4483,6 +4674,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
4483
4674
  employeeLimit: 1,
4484
4675
  memoryLimit: 5e3
4485
4676
  };
4677
+ _prismaPromise = null;
4678
+ _prismaFailed = false;
4486
4679
  CACHE_MAX_AGE_MS = 36e5;
4487
4680
  _revalTimer = null;
4488
4681
  }
@@ -4507,8 +4700,8 @@ __export(crdt_sync_exports, {
4507
4700
  rebuildFromDb: () => rebuildFromDb
4508
4701
  });
4509
4702
  import * as Y from "yjs";
4510
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync10, mkdirSync as mkdirSync6, unlinkSync as unlinkSync3 } from "fs";
4511
- import path11 from "path";
4703
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync12, mkdirSync as mkdirSync5, unlinkSync as unlinkSync3 } from "fs";
4704
+ import path12 from "path";
4512
4705
  import { homedir } from "os";
4513
4706
  function getStatePath() {
4514
4707
  return _statePathOverride ?? DEFAULT_STATE_PATH;
@@ -4520,9 +4713,9 @@ function initCrdtDoc() {
4520
4713
  if (doc) return doc;
4521
4714
  doc = new Y.Doc();
4522
4715
  const sp = getStatePath();
4523
- if (existsSync10(sp)) {
4716
+ if (existsSync12(sp)) {
4524
4717
  try {
4525
- const state = readFileSync8(sp);
4718
+ const state = readFileSync9(sp);
4526
4719
  Y.applyUpdate(doc, new Uint8Array(state));
4527
4720
  } catch {
4528
4721
  console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
@@ -4664,10 +4857,10 @@ function persistState() {
4664
4857
  if (!doc) return;
4665
4858
  try {
4666
4859
  const sp = getStatePath();
4667
- const dir = path11.dirname(sp);
4668
- if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
4860
+ const dir = path12.dirname(sp);
4861
+ if (!existsSync12(dir)) mkdirSync5(dir, { recursive: true });
4669
4862
  const state = Y.encodeStateAsUpdate(doc);
4670
- writeFileSync6(sp, Buffer.from(state));
4863
+ writeFileSync7(sp, Buffer.from(state));
4671
4864
  } catch {
4672
4865
  }
4673
4866
  }
@@ -4708,7 +4901,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
4708
4901
  var init_crdt_sync = __esm({
4709
4902
  "src/lib/crdt-sync.ts"() {
4710
4903
  "use strict";
4711
- DEFAULT_STATE_PATH = path11.join(homedir(), ".exe-os", "crdt-state.bin");
4904
+ DEFAULT_STATE_PATH = path12.join(homedir(), ".exe-os", "crdt-state.bin");
4712
4905
  _statePathOverride = null;
4713
4906
  doc = null;
4714
4907
  }
@@ -4740,39 +4933,107 @@ __export(cloud_sync_exports, {
4740
4933
  cloudSync: () => cloudSync,
4741
4934
  mergeConfig: () => mergeConfig,
4742
4935
  mergeRosterFromRemote: () => mergeRosterFromRemote,
4936
+ pushToPostgres: () => pushToPostgres,
4743
4937
  recordRosterDeletion: () => recordRosterDeletion
4744
4938
  });
4745
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync11, readdirSync, mkdirSync as mkdirSync7, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
4746
- import crypto3 from "crypto";
4747
- import path12 from "path";
4939
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync13, readdirSync, mkdirSync as mkdirSync6, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
4940
+ import crypto4 from "crypto";
4941
+ import path13 from "path";
4748
4942
  import { homedir as homedir2 } from "os";
4749
4943
  function sqlSafe(v) {
4750
4944
  return v === void 0 ? null : v;
4751
4945
  }
4752
4946
  function logError(msg) {
4753
4947
  try {
4754
- const logPath = path12.join(homedir2(), ".exe-os", "workers.log");
4948
+ const logPath = path13.join(homedir2(), ".exe-os", "workers.log");
4755
4949
  appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
4756
4950
  `);
4757
4951
  } catch {
4758
4952
  }
4759
4953
  }
4954
+ function loadPgClient() {
4955
+ if (_pgFailed) return null;
4956
+ const postgresUrl = process.env.DATABASE_URL;
4957
+ const configPath = path13.join(EXE_AI_DIR, "config.json");
4958
+ let cloudPostgresUrl;
4959
+ try {
4960
+ if (existsSync13(configPath)) {
4961
+ const cfg = JSON.parse(readFileSync10(configPath, "utf8"));
4962
+ cloudPostgresUrl = cfg.cloud?.postgresUrl;
4963
+ if (cfg.cloud?.syncToPostgres === false) {
4964
+ _pgFailed = true;
4965
+ return null;
4966
+ }
4967
+ }
4968
+ } catch {
4969
+ }
4970
+ const url = postgresUrl || cloudPostgresUrl;
4971
+ if (!url) {
4972
+ _pgFailed = true;
4973
+ return null;
4974
+ }
4975
+ if (!_pgPromise) {
4976
+ _pgPromise = (async () => {
4977
+ const { createRequire: createRequire3 } = await import("module");
4978
+ const { pathToFileURL: pathToFileURL3 } = await import("url");
4979
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path13.join(homedir2(), "exe-db");
4980
+ const req = createRequire3(path13.join(exeDbRoot, "package.json"));
4981
+ const entry = req.resolve("@prisma/client");
4982
+ const mod = await import(pathToFileURL3(entry).href);
4983
+ const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
4984
+ if (!Ctor) throw new Error("No PrismaClient");
4985
+ return new Ctor();
4986
+ })().catch(() => {
4987
+ _pgFailed = true;
4988
+ _pgPromise = null;
4989
+ throw new Error("pg_unavailable");
4990
+ });
4991
+ }
4992
+ return _pgPromise;
4993
+ }
4994
+ async function pushToPostgres(records) {
4995
+ const loader = loadPgClient();
4996
+ if (!loader) return 0;
4997
+ let prisma;
4998
+ try {
4999
+ prisma = await loader;
5000
+ } catch {
5001
+ return 0;
5002
+ }
5003
+ let inserted = 0;
5004
+ for (const rec of records) {
5005
+ try {
5006
+ await prisma.$executeRawUnsafe(
5007
+ `INSERT INTO raw.raw_events (id, source, source_id, event_type, payload, metadata, timestamp)
5008
+ VALUES (gen_random_uuid(), 'cloud_sync', $1, 'memory', $2::jsonb, $3::jsonb, $4)
5009
+ ON CONFLICT (source, source_id, event_type) DO NOTHING`,
5010
+ String(rec.id ?? ""),
5011
+ JSON.stringify(rec),
5012
+ JSON.stringify({ agent_id: rec.agent_id, project_name: rec.project_name, tool_name: rec.tool_name }),
5013
+ rec.timestamp ? new Date(String(rec.timestamp)) : /* @__PURE__ */ new Date()
5014
+ );
5015
+ inserted++;
5016
+ } catch {
5017
+ }
5018
+ }
5019
+ return inserted;
5020
+ }
4760
5021
  async function withRosterLock(fn) {
4761
5022
  try {
4762
5023
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
4763
5024
  closeSync2(fd);
4764
- writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
5025
+ writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
4765
5026
  } catch (err) {
4766
5027
  if (err.code === "EEXIST") {
4767
5028
  try {
4768
- const ts = parseInt(readFileSync9(ROSTER_LOCK_PATH, "utf-8"), 10);
5029
+ const ts = parseInt(readFileSync10(ROSTER_LOCK_PATH, "utf-8"), 10);
4769
5030
  if (Date.now() - ts < LOCK_STALE_MS) {
4770
5031
  throw new Error("Roster merge already in progress \u2014 another sync is running");
4771
5032
  }
4772
5033
  unlinkSync4(ROSTER_LOCK_PATH);
4773
5034
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
4774
5035
  closeSync2(fd);
4775
- writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
5036
+ writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
4776
5037
  } catch (retryErr) {
4777
5038
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
4778
5039
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -5042,6 +5303,10 @@ async function cloudSync(config) {
5042
5303
  const maxVersion = Number(records[records.length - 1].version);
5043
5304
  const pushOk = await cloudPush(records, maxVersion, config);
5044
5305
  if (!pushOk) break;
5306
+ try {
5307
+ await pushToPostgres(records);
5308
+ } catch {
5309
+ }
5045
5310
  await client.execute({
5046
5311
  sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
5047
5312
  args: [String(maxVersion)]
@@ -5146,8 +5411,8 @@ async function cloudSync(config) {
5146
5411
  try {
5147
5412
  const employees = await loadEmployees();
5148
5413
  rosterResult.employees = employees.length;
5149
- const idDir = path12.join(EXE_AI_DIR, "identity");
5150
- if (existsSync11(idDir)) {
5414
+ const idDir = path13.join(EXE_AI_DIR, "identity");
5415
+ if (existsSync13(idDir)) {
5151
5416
  rosterResult.identities = readdirSync(idDir).filter((f) => f.endsWith(".md")).length;
5152
5417
  }
5153
5418
  } catch {
@@ -5168,62 +5433,62 @@ async function cloudSync(config) {
5168
5433
  function recordRosterDeletion(name) {
5169
5434
  let deletions = [];
5170
5435
  try {
5171
- if (existsSync11(ROSTER_DELETIONS_PATH)) {
5172
- deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
5436
+ if (existsSync13(ROSTER_DELETIONS_PATH)) {
5437
+ deletions = JSON.parse(readFileSync10(ROSTER_DELETIONS_PATH, "utf-8"));
5173
5438
  }
5174
5439
  } catch {
5175
5440
  }
5176
5441
  if (!deletions.includes(name)) deletions.push(name);
5177
- writeFileSync7(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5442
+ writeFileSync8(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5178
5443
  }
5179
5444
  function consumeRosterDeletions() {
5180
5445
  try {
5181
- if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
5182
- const deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
5183
- writeFileSync7(ROSTER_DELETIONS_PATH, "[]");
5446
+ if (!existsSync13(ROSTER_DELETIONS_PATH)) return [];
5447
+ const deletions = JSON.parse(readFileSync10(ROSTER_DELETIONS_PATH, "utf-8"));
5448
+ writeFileSync8(ROSTER_DELETIONS_PATH, "[]");
5184
5449
  return deletions;
5185
5450
  } catch {
5186
5451
  return [];
5187
5452
  }
5188
5453
  }
5189
5454
  function buildRosterBlob(paths) {
5190
- const rosterPath = paths?.rosterPath ?? path12.join(EXE_AI_DIR, "exe-employees.json");
5191
- const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5192
- const configPath = paths?.configPath ?? path12.join(EXE_AI_DIR, "config.json");
5455
+ const rosterPath = paths?.rosterPath ?? path13.join(EXE_AI_DIR, "exe-employees.json");
5456
+ const identityDir = paths?.identityDir ?? path13.join(EXE_AI_DIR, "identity");
5457
+ const configPath = paths?.configPath ?? path13.join(EXE_AI_DIR, "config.json");
5193
5458
  let roster = [];
5194
- if (existsSync11(rosterPath)) {
5459
+ if (existsSync13(rosterPath)) {
5195
5460
  try {
5196
- roster = JSON.parse(readFileSync9(rosterPath, "utf-8"));
5461
+ roster = JSON.parse(readFileSync10(rosterPath, "utf-8"));
5197
5462
  } catch {
5198
5463
  }
5199
5464
  }
5200
5465
  const identities = {};
5201
- if (existsSync11(identityDir)) {
5466
+ if (existsSync13(identityDir)) {
5202
5467
  for (const file of readdirSync(identityDir).filter((f) => f.endsWith(".md"))) {
5203
5468
  try {
5204
- identities[file] = readFileSync9(path12.join(identityDir, file), "utf-8");
5469
+ identities[file] = readFileSync10(path13.join(identityDir, file), "utf-8");
5205
5470
  } catch {
5206
5471
  }
5207
5472
  }
5208
5473
  }
5209
5474
  let config;
5210
- if (existsSync11(configPath)) {
5475
+ if (existsSync13(configPath)) {
5211
5476
  try {
5212
- config = JSON.parse(readFileSync9(configPath, "utf-8"));
5477
+ config = JSON.parse(readFileSync10(configPath, "utf-8"));
5213
5478
  } catch {
5214
5479
  }
5215
5480
  }
5216
5481
  let agentConfig;
5217
- const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
5218
- if (existsSync11(agentConfigPath)) {
5482
+ const agentConfigPath = path13.join(EXE_AI_DIR, "agent-config.json");
5483
+ if (existsSync13(agentConfigPath)) {
5219
5484
  try {
5220
- agentConfig = JSON.parse(readFileSync9(agentConfigPath, "utf-8"));
5485
+ agentConfig = JSON.parse(readFileSync10(agentConfigPath, "utf-8"));
5221
5486
  } catch {
5222
5487
  }
5223
5488
  }
5224
5489
  const deletedNames = consumeRosterDeletions();
5225
5490
  const content = JSON.stringify({ roster, identities, config, agentConfig, deletedNames });
5226
- const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
5491
+ const hash = crypto4.createHash("sha256").update(content).digest("hex").slice(0, 16);
5227
5492
  return { roster, identities, config, agentConfig, deletedNames, version: hash };
5228
5493
  }
5229
5494
  async function cloudPushRoster(config) {
@@ -5293,23 +5558,24 @@ async function cloudPullRoster(config) {
5293
5558
  }
5294
5559
  }
5295
5560
  function mergeConfig(remoteConfig, configPath) {
5296
- const cfgPath = configPath ?? path12.join(EXE_AI_DIR, "config.json");
5561
+ const cfgPath = configPath ?? path13.join(EXE_AI_DIR, "config.json");
5297
5562
  let local = {};
5298
- if (existsSync11(cfgPath)) {
5563
+ if (existsSync13(cfgPath)) {
5299
5564
  try {
5300
- local = JSON.parse(readFileSync9(cfgPath, "utf-8"));
5565
+ local = JSON.parse(readFileSync10(cfgPath, "utf-8"));
5301
5566
  } catch {
5302
5567
  }
5303
5568
  }
5304
5569
  const merged = { ...remoteConfig, ...local };
5305
- const dir = path12.dirname(cfgPath);
5306
- if (!existsSync11(dir)) mkdirSync7(dir, { recursive: true });
5307
- writeFileSync7(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5570
+ const dir = path13.dirname(cfgPath);
5571
+ ensurePrivateDirSync(dir);
5572
+ writeFileSync8(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5573
+ enforcePrivateFileSync(cfgPath);
5308
5574
  }
5309
5575
  async function mergeRosterFromRemote(remote, paths) {
5310
5576
  return withRosterLock(async () => {
5311
5577
  const rosterPath = paths?.rosterPath ?? void 0;
5312
- const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
5578
+ const identityDir = paths?.identityDir ?? path13.join(EXE_AI_DIR, "identity");
5313
5579
  const localEmployees = await loadEmployees(rosterPath);
5314
5580
  const localNames = new Set(localEmployees.map((e) => e.name));
5315
5581
  let added = 0;
@@ -5330,15 +5596,15 @@ async function mergeRosterFromRemote(remote, paths) {
5330
5596
  ) ?? lookupKey;
5331
5597
  const remoteIdentity = remote.identities[matchedKey];
5332
5598
  if (remoteIdentity) {
5333
- if (!existsSync11(identityDir)) mkdirSync7(identityDir, { recursive: true });
5334
- const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
5599
+ if (!existsSync13(identityDir)) mkdirSync6(identityDir, { recursive: true });
5600
+ const idPath = path13.join(identityDir, `${remoteEmp.name}.md`);
5335
5601
  let localIdentity = null;
5336
5602
  try {
5337
- localIdentity = existsSync11(idPath) ? readFileSync9(idPath, "utf-8") : null;
5603
+ localIdentity = existsSync13(idPath) ? readFileSync10(idPath, "utf-8") : null;
5338
5604
  } catch {
5339
5605
  }
5340
5606
  if (localIdentity !== remoteIdentity) {
5341
- writeFileSync7(idPath, remoteIdentity, "utf-8");
5607
+ writeFileSync8(idPath, remoteIdentity, "utf-8");
5342
5608
  identitiesUpdated++;
5343
5609
  }
5344
5610
  }
@@ -5364,16 +5630,18 @@ async function mergeRosterFromRemote(remote, paths) {
5364
5630
  }
5365
5631
  if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
5366
5632
  try {
5367
- const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
5633
+ const agentConfigPath = path13.join(EXE_AI_DIR, "agent-config.json");
5368
5634
  let local = {};
5369
- if (existsSync11(agentConfigPath)) {
5635
+ if (existsSync13(agentConfigPath)) {
5370
5636
  try {
5371
- local = JSON.parse(readFileSync9(agentConfigPath, "utf-8"));
5637
+ local = JSON.parse(readFileSync10(agentConfigPath, "utf-8"));
5372
5638
  } catch {
5373
5639
  }
5374
5640
  }
5375
5641
  const merged = { ...remote.agentConfig, ...local };
5376
- writeFileSync7(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
5642
+ ensurePrivateDirSync(path13.dirname(agentConfigPath));
5643
+ writeFileSync8(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
5644
+ enforcePrivateFileSync(agentConfigPath);
5377
5645
  } catch {
5378
5646
  }
5379
5647
  }
@@ -5797,7 +6065,7 @@ async function cloudPullDocuments(config) {
5797
6065
  }
5798
6066
  return { pulled };
5799
6067
  }
5800
- var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
6068
+ var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, _pgPromise, _pgFailed, ROSTER_DELETIONS_PATH;
5801
6069
  var init_cloud_sync = __esm({
5802
6070
  "src/lib/cloud-sync.ts"() {
5803
6071
  "use strict";
@@ -5808,12 +6076,15 @@ var init_cloud_sync = __esm({
5808
6076
  init_config();
5809
6077
  init_crdt_sync();
5810
6078
  init_employees();
6079
+ init_secure_files();
5811
6080
  LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
5812
6081
  FETCH_TIMEOUT_MS = 3e4;
5813
6082
  PUSH_BATCH_SIZE = 5e3;
5814
- ROSTER_LOCK_PATH = path12.join(EXE_AI_DIR, "roster-merge.lock");
6083
+ ROSTER_LOCK_PATH = path13.join(EXE_AI_DIR, "roster-merge.lock");
5815
6084
  LOCK_STALE_MS = 3e4;
5816
- ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
6085
+ _pgPromise = null;
6086
+ _pgFailed = false;
6087
+ ROSTER_DELETIONS_PATH = path13.join(EXE_AI_DIR, "roster-deletions.json");
5817
6088
  }
5818
6089
  });
5819
6090
 
@@ -6111,6 +6382,7 @@ var shard_manager_exports = {};
6111
6382
  __export(shard_manager_exports, {
6112
6383
  disposeShards: () => disposeShards,
6113
6384
  ensureShardSchema: () => ensureShardSchema,
6385
+ getOpenShardCount: () => getOpenShardCount,
6114
6386
  getReadyShardClient: () => getReadyShardClient,
6115
6387
  getShardClient: () => getShardClient,
6116
6388
  getShardsDir: () => getShardsDir,
@@ -6119,15 +6391,18 @@ __export(shard_manager_exports, {
6119
6391
  listShards: () => listShards,
6120
6392
  shardExists: () => shardExists
6121
6393
  });
6122
- import path13 from "path";
6123
- import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync2 } from "fs";
6394
+ import path14 from "path";
6395
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync2 } from "fs";
6124
6396
  import { createClient as createClient2 } from "@libsql/client";
6125
6397
  function initShardManager(encryptionKey) {
6126
6398
  _encryptionKey = encryptionKey;
6127
- if (!existsSync12(SHARDS_DIR)) {
6128
- mkdirSync8(SHARDS_DIR, { recursive: true });
6399
+ if (!existsSync14(SHARDS_DIR)) {
6400
+ mkdirSync7(SHARDS_DIR, { recursive: true });
6129
6401
  }
6130
6402
  _shardingEnabled = true;
6403
+ if (_evictionTimer) clearInterval(_evictionTimer);
6404
+ _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
6405
+ _evictionTimer.unref();
6131
6406
  }
6132
6407
  function isShardingEnabled() {
6133
6408
  return _shardingEnabled;
@@ -6144,21 +6419,28 @@ function getShardClient(projectName) {
6144
6419
  throw new Error(`Invalid project name for shard: "${projectName}"`);
6145
6420
  }
6146
6421
  const cached = _shards.get(safeName);
6147
- if (cached) return cached;
6148
- const dbPath = path13.join(SHARDS_DIR, `${safeName}.db`);
6422
+ if (cached) {
6423
+ _shardLastAccess.set(safeName, Date.now());
6424
+ return cached;
6425
+ }
6426
+ while (_shards.size >= MAX_OPEN_SHARDS) {
6427
+ evictLRU();
6428
+ }
6429
+ const dbPath = path14.join(SHARDS_DIR, `${safeName}.db`);
6149
6430
  const client = createClient2({
6150
6431
  url: `file:${dbPath}`,
6151
6432
  encryptionKey: _encryptionKey
6152
6433
  });
6153
6434
  _shards.set(safeName, client);
6435
+ _shardLastAccess.set(safeName, Date.now());
6154
6436
  return client;
6155
6437
  }
6156
6438
  function shardExists(projectName) {
6157
6439
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
6158
- return existsSync12(path13.join(SHARDS_DIR, `${safeName}.db`));
6440
+ return existsSync14(path14.join(SHARDS_DIR, `${safeName}.db`));
6159
6441
  }
6160
6442
  function listShards() {
6161
- if (!existsSync12(SHARDS_DIR)) return [];
6443
+ if (!existsSync14(SHARDS_DIR)) return [];
6162
6444
  return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
6163
6445
  }
6164
6446
  async function ensureShardSchema(client) {
@@ -6210,6 +6492,8 @@ async function ensureShardSchema(client) {
6210
6492
  for (const col of [
6211
6493
  "ALTER TABLE memories ADD COLUMN task_id TEXT",
6212
6494
  "ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
6495
+ "ALTER TABLE memories ADD COLUMN author_device_id TEXT",
6496
+ "ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
6213
6497
  "ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
6214
6498
  "ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
6215
6499
  "ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
@@ -6347,21 +6631,69 @@ async function getReadyShardClient(projectName) {
6347
6631
  await ensureShardSchema(client);
6348
6632
  return client;
6349
6633
  }
6634
+ function evictLRU() {
6635
+ let oldest = null;
6636
+ let oldestTime = Infinity;
6637
+ for (const [name, time] of _shardLastAccess) {
6638
+ if (time < oldestTime) {
6639
+ oldestTime = time;
6640
+ oldest = name;
6641
+ }
6642
+ }
6643
+ if (oldest) {
6644
+ const client = _shards.get(oldest);
6645
+ if (client) {
6646
+ client.close();
6647
+ }
6648
+ _shards.delete(oldest);
6649
+ _shardLastAccess.delete(oldest);
6650
+ }
6651
+ }
6652
+ function evictIdleShards() {
6653
+ const now = Date.now();
6654
+ const toEvict = [];
6655
+ for (const [name, lastAccess] of _shardLastAccess) {
6656
+ if (now - lastAccess > SHARD_IDLE_MS) {
6657
+ toEvict.push(name);
6658
+ }
6659
+ }
6660
+ for (const name of toEvict) {
6661
+ const client = _shards.get(name);
6662
+ if (client) {
6663
+ client.close();
6664
+ }
6665
+ _shards.delete(name);
6666
+ _shardLastAccess.delete(name);
6667
+ }
6668
+ }
6669
+ function getOpenShardCount() {
6670
+ return _shards.size;
6671
+ }
6350
6672
  function disposeShards() {
6673
+ if (_evictionTimer) {
6674
+ clearInterval(_evictionTimer);
6675
+ _evictionTimer = null;
6676
+ }
6351
6677
  for (const [, client] of _shards) {
6352
6678
  client.close();
6353
6679
  }
6354
6680
  _shards.clear();
6681
+ _shardLastAccess.clear();
6355
6682
  _shardingEnabled = false;
6356
6683
  _encryptionKey = null;
6357
6684
  }
6358
- var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
6685
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
6359
6686
  var init_shard_manager = __esm({
6360
6687
  "src/lib/shard-manager.ts"() {
6361
6688
  "use strict";
6362
6689
  init_config();
6363
- SHARDS_DIR = path13.join(EXE_AI_DIR, "shards");
6690
+ SHARDS_DIR = path14.join(EXE_AI_DIR, "shards");
6691
+ SHARD_IDLE_MS = 5 * 60 * 1e3;
6692
+ MAX_OPEN_SHARDS = 10;
6693
+ EVICTION_INTERVAL_MS = 60 * 1e3;
6364
6694
  _shards = /* @__PURE__ */ new Map();
6695
+ _shardLastAccess = /* @__PURE__ */ new Map();
6696
+ _evictionTimer = null;
6365
6697
  _encryptionKey = null;
6366
6698
  _shardingEnabled = false;
6367
6699
  }
@@ -7129,15 +7461,15 @@ var backfill_conversations_exports = {};
7129
7461
  __export(backfill_conversations_exports, {
7130
7462
  backfillConversations: () => backfillConversations
7131
7463
  });
7132
- import crypto4 from "crypto";
7464
+ import crypto5 from "crypto";
7133
7465
  import { createReadStream } from "fs";
7134
7466
  import { readdir as readdir2, stat } from "fs/promises";
7135
- import path14 from "path";
7467
+ import path15 from "path";
7136
7468
  import { createInterface as createInterface2 } from "readline";
7137
7469
  import { homedir as homedir3 } from "os";
7138
7470
  import { parseArgs } from "util";
7139
7471
  async function findJsonlFiles(sinceDate, projectFilter) {
7140
- const projectsDir = path14.join(homedir3(), ".claude", "projects");
7472
+ const projectsDir = path15.join(homedir3(), ".claude", "projects");
7141
7473
  const files = [];
7142
7474
  async function walk(dir, depth = 0) {
7143
7475
  if (depth > MAX_WALK_DEPTH) return;
@@ -7148,7 +7480,7 @@ async function findJsonlFiles(sinceDate, projectFilter) {
7148
7480
  return;
7149
7481
  }
7150
7482
  for (const entry of entries) {
7151
- const full = path14.join(dir, entry.name);
7483
+ const full = path15.join(dir, entry.name);
7152
7484
  if (entry.isDirectory()) {
7153
7485
  if (entry.name === "subagents" || entry.name === "tool-results") continue;
7154
7486
  await walk(full, depth + 1);
@@ -7173,7 +7505,7 @@ async function findJsonlFiles(sinceDate, projectFilter) {
7173
7505
  if (!entry.isDirectory()) continue;
7174
7506
  const decoded = decodeProjectDir(entry.name);
7175
7507
  if (decoded.toLowerCase().includes(projectFilter.toLowerCase())) {
7176
- await walk(path14.join(projectsDir, entry.name));
7508
+ await walk(path15.join(projectsDir, entry.name));
7177
7509
  }
7178
7510
  }
7179
7511
  } else {
@@ -7190,14 +7522,14 @@ function decodeProjectDir(dirName) {
7190
7522
  return dirName;
7191
7523
  }
7192
7524
  function projectNameFromPath(filePath) {
7193
- const projectsDir = path14.join(homedir3(), ".claude", "projects");
7194
- const relative = path14.relative(projectsDir, filePath);
7195
- const projectDir = relative.split(path14.sep)[0] ?? "unknown";
7525
+ const projectsDir = path15.join(homedir3(), ".claude", "projects");
7526
+ const relative = path15.relative(projectsDir, filePath);
7527
+ const projectDir = relative.split(path15.sep)[0] ?? "unknown";
7196
7528
  return decodeProjectDir(projectDir);
7197
7529
  }
7198
7530
  async function parseConversation(filePath) {
7199
7531
  const conv = {
7200
- sessionId: path14.basename(filePath, ".jsonl"),
7532
+ sessionId: path15.basename(filePath, ".jsonl"),
7201
7533
  projectName: projectNameFromPath(filePath),
7202
7534
  cwd: void 0,
7203
7535
  startTime: void 0,
@@ -7261,7 +7593,7 @@ async function parseConversation(filePath) {
7261
7593
  }
7262
7594
  }
7263
7595
  if (conv.cwd) {
7264
- conv.projectName = path14.basename(conv.cwd);
7596
+ conv.projectName = path15.basename(conv.cwd);
7265
7597
  const worktreeMatch = conv.cwd.match(/\.worktrees\/([^/]+)/);
7266
7598
  if (worktreeMatch?.[1]) {
7267
7599
  conv.agentId = worktreeMatch[1];
@@ -7434,7 +7766,7 @@ async function backfillConversations(options) {
7434
7766
  }
7435
7767
  }
7436
7768
  await writeMemory({
7437
- id: crypto4.randomUUID(),
7769
+ id: crypto5.randomUUID(),
7438
7770
  agent_id: conv.agentId,
7439
7771
  agent_role: isCoordinatorName(conv.agentId) ? "COO" : "specialist",
7440
7772
  session_id: conv.sessionId,
@@ -7913,9 +8245,9 @@ Unclassified: ${unclassified}
7913
8245
  }
7914
8246
  async function exportBatches(options) {
7915
8247
  const fs8 = await import("fs");
7916
- const path45 = await import("path");
8248
+ const path46 = await import("path");
7917
8249
  const client = getClient();
7918
- const outDir = path45.join(process.cwd(), "exe/output/classifications/input");
8250
+ const outDir = path46.join(process.cwd(), "exe/output/classifications/input");
7919
8251
  fs8.mkdirSync(outDir, { recursive: true });
7920
8252
  const countResult = await client.execute({
7921
8253
  sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
@@ -7939,7 +8271,7 @@ async function exportBatches(options) {
7939
8271
  const text = String(row.text || "").replace(/\n/g, " ");
7940
8272
  return JSON.stringify({ id: row.id, text });
7941
8273
  });
7942
- const batchFile = path45.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
8274
+ const batchFile = path46.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
7943
8275
  fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
7944
8276
  exported += batch.rows.length;
7945
8277
  offset += options.batchSize;
@@ -7955,7 +8287,7 @@ async function exportBatches(options) {
7955
8287
  }
7956
8288
  async function importClassifications(importDir) {
7957
8289
  const fs8 = await import("fs");
7958
- const path45 = await import("path");
8290
+ const path46 = await import("path");
7959
8291
  const client = getClient();
7960
8292
  const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
7961
8293
  process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
@@ -7963,7 +8295,7 @@ async function importClassifications(importDir) {
7963
8295
  let imported = 0;
7964
8296
  let invalid = 0;
7965
8297
  for (const file of files) {
7966
- const lines = fs8.readFileSync(path45.join(importDir, file), "utf-8").split("\n").filter(Boolean);
8298
+ const lines = fs8.readFileSync(path46.join(importDir, file), "utf-8").split("\n").filter(Boolean);
7967
8299
  for (const line of lines) {
7968
8300
  try {
7969
8301
  const rec = JSON.parse(line);
@@ -8104,17 +8436,17 @@ __export(identity_exports, {
8104
8436
  listIdentities: () => listIdentities,
8105
8437
  updateIdentity: () => updateIdentity
8106
8438
  });
8107
- import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
8439
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
8108
8440
  import { readdirSync as readdirSync3 } from "fs";
8109
- import path15 from "path";
8441
+ import path16 from "path";
8110
8442
  import { createHash as createHash2 } from "crypto";
8111
8443
  function ensureDir() {
8112
- if (!existsSync13(IDENTITY_DIR2)) {
8113
- mkdirSync9(IDENTITY_DIR2, { recursive: true });
8444
+ if (!existsSync15(IDENTITY_DIR2)) {
8445
+ mkdirSync8(IDENTITY_DIR2, { recursive: true });
8114
8446
  }
8115
8447
  }
8116
8448
  function identityPath(agentId) {
8117
- return path15.join(IDENTITY_DIR2, `${agentId}.md`);
8449
+ return path16.join(IDENTITY_DIR2, `${agentId}.md`);
8118
8450
  }
8119
8451
  function parseFrontmatter(raw) {
8120
8452
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
@@ -8155,8 +8487,8 @@ function contentHash(content) {
8155
8487
  }
8156
8488
  function getIdentity(agentId) {
8157
8489
  const filePath = identityPath(agentId);
8158
- if (!existsSync13(filePath)) return null;
8159
- const raw = readFileSync10(filePath, "utf-8");
8490
+ if (!existsSync15(filePath)) return null;
8491
+ const raw = readFileSync11(filePath, "utf-8");
8160
8492
  const { frontmatter, body } = parseFrontmatter(raw);
8161
8493
  return {
8162
8494
  agentId,
@@ -8170,7 +8502,7 @@ async function updateIdentity(agentId, content, updatedBy) {
8170
8502
  ensureDir();
8171
8503
  const filePath = identityPath(agentId);
8172
8504
  const hash = contentHash(content);
8173
- writeFileSync8(filePath, content, "utf-8");
8505
+ writeFileSync9(filePath, content, "utf-8");
8174
8506
  try {
8175
8507
  const client = getClient();
8176
8508
  await client.execute({
@@ -8226,15 +8558,15 @@ var init_identity = __esm({
8226
8558
  "use strict";
8227
8559
  init_config();
8228
8560
  init_database();
8229
- IDENTITY_DIR2 = path15.join(EXE_AI_DIR, "identity");
8561
+ IDENTITY_DIR2 = path16.join(EXE_AI_DIR, "identity");
8230
8562
  }
8231
8563
  });
8232
8564
 
8233
8565
  // src/lib/orchestration-package.ts
8234
8566
  import { randomUUID as randomUUID4 } from "crypto";
8235
- import { copyFileSync as copyFileSync2, existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
8236
- import os9 from "os";
8237
- import path16 from "path";
8567
+ import { copyFileSync as copyFileSync2, existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync10 } from "fs";
8568
+ import os10 from "os";
8569
+ import path17 from "path";
8238
8570
  function ensureObject(value, label) {
8239
8571
  if (value == null || Array.isArray(value) || typeof value !== "object") {
8240
8572
  throw new Error(`${label} must be an object`);
@@ -8293,15 +8625,15 @@ function validateProcedureEntry(value, index) {
8293
8625
  };
8294
8626
  }
8295
8627
  function getRosterPath() {
8296
- return path16.join(os9.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
8628
+ return path17.join(os10.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
8297
8629
  }
8298
8630
  function getBackupPath() {
8299
- return path16.join(os9.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
8631
+ return path17.join(os10.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
8300
8632
  }
8301
8633
  function readRosterFile() {
8302
8634
  const rosterPath = getRosterPath();
8303
- if (!existsSync14(rosterPath)) return [];
8304
- const raw = readFileSync11(rosterPath, "utf-8");
8635
+ if (!existsSync16(rosterPath)) return [];
8636
+ const raw = readFileSync12(rosterPath, "utf-8");
8305
8637
  const parsed = JSON.parse(raw);
8306
8638
  if (!Array.isArray(parsed)) {
8307
8639
  throw new Error("Roster file must contain a JSON array");
@@ -8313,8 +8645,8 @@ function writeRosterFile(roster) {
8313
8645
  throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
8314
8646
  }
8315
8647
  const rosterPath = getRosterPath();
8316
- mkdirSync10(path16.dirname(rosterPath), { recursive: true });
8317
- if (existsSync14(rosterPath)) {
8648
+ mkdirSync9(path17.dirname(rosterPath), { recursive: true });
8649
+ if (existsSync16(rosterPath)) {
8318
8650
  const currentRoster = readRosterFile();
8319
8651
  if (roster.length < currentRoster.length) {
8320
8652
  throw new Error(
@@ -8323,7 +8655,7 @@ function writeRosterFile(roster) {
8323
8655
  }
8324
8656
  copyFileSync2(rosterPath, getBackupPath());
8325
8657
  }
8326
- writeFileSync9(rosterPath, `${JSON.stringify(roster, null, 2)}
8658
+ writeFileSync10(rosterPath, `${JSON.stringify(roster, null, 2)}
8327
8659
  `, "utf-8");
8328
8660
  }
8329
8661
  function buildImportedRosterEntries(roster, timestamp) {
@@ -8590,8 +8922,8 @@ var exe_export_exports = {};
8590
8922
  __export(exe_export_exports, {
8591
8923
  runExeExport: () => runExeExport
8592
8924
  });
8593
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
8594
- import path17 from "path";
8925
+ import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
8926
+ import path18 from "path";
8595
8927
  function printUsage() {
8596
8928
  process.stdout.write("Usage: exe-os export --output <path>\n");
8597
8929
  }
@@ -8612,8 +8944,8 @@ async function runExeExport(argv = process.argv.slice(2)) {
8612
8944
  await initStore();
8613
8945
  try {
8614
8946
  const pkg = await exportOrchestration("cli");
8615
- mkdirSync11(path17.dirname(outputPath), { recursive: true });
8616
- writeFileSync10(outputPath, `${JSON.stringify(pkg, null, 2)}
8947
+ mkdirSync10(path18.dirname(outputPath), { recursive: true });
8948
+ writeFileSync11(outputPath, `${JSON.stringify(pkg, null, 2)}
8617
8949
  `, "utf-8");
8618
8950
  process.stdout.write(
8619
8951
  `Exported ${pkg.roster.length} roster entries, ${Object.keys(pkg.identities).length} identities, ${pkg.behaviors.length} behaviors, ${pkg.procedures.length} procedures to ${outputPath}
@@ -8649,7 +8981,7 @@ var exe_import_exports = {};
8649
8981
  __export(exe_import_exports, {
8650
8982
  runExeImport: () => runExeImport
8651
8983
  });
8652
- import { readFileSync as readFileSync12 } from "fs";
8984
+ import { readFileSync as readFileSync13 } from "fs";
8653
8985
  function printUsage2() {
8654
8986
  process.stdout.write("Usage: exe-os import --from <path> [--merge]\n");
8655
8987
  }
@@ -8672,7 +9004,7 @@ async function runExeImport(argv = process.argv.slice(2)) {
8672
9004
  if (parsed == null) return;
8673
9005
  await initStore();
8674
9006
  try {
8675
- const raw = readFileSync12(parsed.packagePath, "utf-8");
9007
+ const raw = readFileSync13(parsed.packagePath, "utf-8");
8676
9008
  const pkg = validatePackage(JSON.parse(raw));
8677
9009
  const result = await importOrchestration(pkg, parsed.strategy);
8678
9010
  process.stdout.write(
@@ -8712,14 +9044,14 @@ __export(session_registry_exports, {
8712
9044
  pruneStaleSessions: () => pruneStaleSessions,
8713
9045
  registerSession: () => registerSession
8714
9046
  });
8715
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, existsSync as existsSync15 } from "fs";
9047
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11, existsSync as existsSync17 } from "fs";
8716
9048
  import { execSync as execSync3 } from "child_process";
8717
- import path18 from "path";
8718
- import os10 from "os";
9049
+ import path19 from "path";
9050
+ import os11 from "os";
8719
9051
  function registerSession(entry) {
8720
- const dir = path18.dirname(REGISTRY_PATH);
8721
- if (!existsSync15(dir)) {
8722
- mkdirSync12(dir, { recursive: true });
9052
+ const dir = path19.dirname(REGISTRY_PATH);
9053
+ if (!existsSync17(dir)) {
9054
+ mkdirSync11(dir, { recursive: true });
8723
9055
  }
8724
9056
  const sessions = listSessions();
8725
9057
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -8728,11 +9060,11 @@ function registerSession(entry) {
8728
9060
  } else {
8729
9061
  sessions.push(entry);
8730
9062
  }
8731
- writeFileSync11(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
9063
+ writeFileSync12(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
8732
9064
  }
8733
9065
  function listSessions() {
8734
9066
  try {
8735
- const raw = readFileSync13(REGISTRY_PATH, "utf8");
9067
+ const raw = readFileSync14(REGISTRY_PATH, "utf8");
8736
9068
  return JSON.parse(raw);
8737
9069
  } catch {
8738
9070
  return [];
@@ -8753,7 +9085,7 @@ function pruneStaleSessions() {
8753
9085
  const alive = sessions.filter((s) => liveSet.has(s.windowName));
8754
9086
  const pruned = sessions.length - alive.length;
8755
9087
  if (pruned > 0) {
8756
- writeFileSync11(REGISTRY_PATH, JSON.stringify(alive, null, 2));
9088
+ writeFileSync12(REGISTRY_PATH, JSON.stringify(alive, null, 2));
8757
9089
  }
8758
9090
  return pruned;
8759
9091
  }
@@ -8761,7 +9093,7 @@ var REGISTRY_PATH;
8761
9093
  var init_session_registry = __esm({
8762
9094
  "src/lib/session-registry.ts"() {
8763
9095
  "use strict";
8764
- REGISTRY_PATH = path18.join(os10.homedir(), ".exe-os", "session-registry.json");
9096
+ REGISTRY_PATH = path19.join(os11.homedir(), ".exe-os", "session-registry.json");
8765
9097
  }
8766
9098
  });
8767
9099
 
@@ -9007,17 +9339,17 @@ __export(intercom_queue_exports, {
9007
9339
  queueIntercom: () => queueIntercom,
9008
9340
  readQueue: () => readQueue
9009
9341
  });
9010
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, renameSync as renameSync3, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
9011
- import path19 from "path";
9012
- import os11 from "os";
9342
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, renameSync as renameSync3, existsSync as existsSync18, mkdirSync as mkdirSync12 } from "fs";
9343
+ import path20 from "path";
9344
+ import os12 from "os";
9013
9345
  function ensureDir2() {
9014
- const dir = path19.dirname(QUEUE_PATH);
9015
- if (!existsSync16(dir)) mkdirSync13(dir, { recursive: true });
9346
+ const dir = path20.dirname(QUEUE_PATH);
9347
+ if (!existsSync18(dir)) mkdirSync12(dir, { recursive: true });
9016
9348
  }
9017
9349
  function readQueue() {
9018
9350
  try {
9019
- if (!existsSync16(QUEUE_PATH)) return [];
9020
- return JSON.parse(readFileSync14(QUEUE_PATH, "utf8"));
9351
+ if (!existsSync18(QUEUE_PATH)) return [];
9352
+ return JSON.parse(readFileSync15(QUEUE_PATH, "utf8"));
9021
9353
  } catch {
9022
9354
  return [];
9023
9355
  }
@@ -9025,7 +9357,7 @@ function readQueue() {
9025
9357
  function writeQueue(queue) {
9026
9358
  ensureDir2();
9027
9359
  const tmp = `${QUEUE_PATH}.tmp`;
9028
- writeFileSync12(tmp, JSON.stringify(queue, null, 2));
9360
+ writeFileSync13(tmp, JSON.stringify(queue, null, 2));
9029
9361
  renameSync3(tmp, QUEUE_PATH);
9030
9362
  }
9031
9363
  function queueIntercom(targetSession, reason) {
@@ -9117,20 +9449,20 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
9117
9449
  var init_intercom_queue = __esm({
9118
9450
  "src/lib/intercom-queue.ts"() {
9119
9451
  "use strict";
9120
- QUEUE_PATH = path19.join(os11.homedir(), ".exe-os", "intercom-queue.json");
9452
+ QUEUE_PATH = path20.join(os12.homedir(), ".exe-os", "intercom-queue.json");
9121
9453
  MAX_RETRIES2 = 5;
9122
9454
  TTL_MS = 60 * 60 * 1e3;
9123
- INTERCOM_LOG = path19.join(os11.homedir(), ".exe-os", "intercom.log");
9455
+ INTERCOM_LOG = path20.join(os12.homedir(), ".exe-os", "intercom.log");
9124
9456
  }
9125
9457
  });
9126
9458
 
9127
9459
  // src/lib/plan-limits.ts
9128
- import { readFileSync as readFileSync15, existsSync as existsSync17 } from "fs";
9129
- import path20 from "path";
9460
+ import { readFileSync as readFileSync16, existsSync as existsSync19 } from "fs";
9461
+ import path21 from "path";
9130
9462
  function getLicenseSync() {
9131
9463
  try {
9132
- if (!existsSync17(CACHE_PATH2)) return freeLicense();
9133
- const raw = JSON.parse(readFileSync15(CACHE_PATH2, "utf8"));
9464
+ if (!existsSync19(CACHE_PATH2)) return freeLicense();
9465
+ const raw = JSON.parse(readFileSync16(CACHE_PATH2, "utf8"));
9134
9466
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
9135
9467
  const parts = raw.token.split(".");
9136
9468
  if (parts.length !== 3) return freeLicense();
@@ -9168,8 +9500,8 @@ function assertEmployeeLimitSync(rosterPath) {
9168
9500
  const filePath = rosterPath ?? EMPLOYEES_PATH;
9169
9501
  let count = 0;
9170
9502
  try {
9171
- if (existsSync17(filePath)) {
9172
- const raw = readFileSync15(filePath, "utf8");
9503
+ if (existsSync19(filePath)) {
9504
+ const raw = readFileSync16(filePath, "utf8");
9173
9505
  const employees = JSON.parse(raw);
9174
9506
  count = Array.isArray(employees) ? employees.length : 0;
9175
9507
  }
@@ -9198,29 +9530,69 @@ var init_plan_limits = __esm({
9198
9530
  this.name = "PlanLimitError";
9199
9531
  }
9200
9532
  };
9201
- CACHE_PATH2 = path20.join(EXE_AI_DIR, "license-cache.json");
9533
+ CACHE_PATH2 = path21.join(EXE_AI_DIR, "license-cache.json");
9534
+ }
9535
+ });
9536
+
9537
+ // src/lib/task-scope.ts
9538
+ var task_scope_exports = {};
9539
+ __export(task_scope_exports, {
9540
+ getCurrentSessionScope: () => getCurrentSessionScope,
9541
+ sessionScopeFilter: () => sessionScopeFilter,
9542
+ strictSessionScopeFilter: () => strictSessionScopeFilter
9543
+ });
9544
+ function getCurrentSessionScope() {
9545
+ try {
9546
+ return resolveExeSession();
9547
+ } catch {
9548
+ return null;
9549
+ }
9550
+ }
9551
+ function sessionScopeFilter(sessionScope, tableAlias) {
9552
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
9553
+ if (!scope) return { sql: "", args: [] };
9554
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
9555
+ return {
9556
+ sql: ` AND (${col} IS NULL OR ${col} = ?)`,
9557
+ args: [scope]
9558
+ };
9559
+ }
9560
+ function strictSessionScopeFilter(sessionScope, tableAlias) {
9561
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
9562
+ if (!scope) return { sql: "", args: [] };
9563
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
9564
+ return {
9565
+ sql: ` AND ${col} = ?`,
9566
+ args: [scope]
9567
+ };
9568
+ }
9569
+ var init_task_scope = __esm({
9570
+ "src/lib/task-scope.ts"() {
9571
+ "use strict";
9572
+ init_tmux_routing();
9202
9573
  }
9203
9574
  });
9204
9575
 
9205
9576
  // src/lib/notifications.ts
9206
- import crypto5 from "crypto";
9207
- import path21 from "path";
9208
- import os12 from "os";
9577
+ import crypto6 from "crypto";
9578
+ import path22 from "path";
9579
+ import os13 from "os";
9209
9580
  import {
9210
- readFileSync as readFileSync16,
9581
+ readFileSync as readFileSync17,
9211
9582
  readdirSync as readdirSync4,
9212
9583
  unlinkSync as unlinkSync5,
9213
- existsSync as existsSync18,
9584
+ existsSync as existsSync20,
9214
9585
  rmdirSync
9215
9586
  } from "fs";
9216
9587
  async function writeNotification(notification) {
9217
9588
  try {
9218
9589
  const client = getClient();
9219
- const id = crypto5.randomUUID();
9590
+ const id = crypto6.randomUUID();
9220
9591
  const now = (/* @__PURE__ */ new Date()).toISOString();
9592
+ const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
9221
9593
  await client.execute({
9222
- sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
9223
- VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
9594
+ sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
9595
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`,
9224
9596
  args: [
9225
9597
  id,
9226
9598
  notification.agentId,
@@ -9229,6 +9601,7 @@ async function writeNotification(notification) {
9229
9601
  notification.project,
9230
9602
  notification.summary,
9231
9603
  notification.taskFile ?? null,
9604
+ sessionScope,
9232
9605
  now
9233
9606
  ]
9234
9607
  });
@@ -9237,12 +9610,14 @@ async function writeNotification(notification) {
9237
9610
  `);
9238
9611
  }
9239
9612
  }
9240
- async function markAsReadByTaskFile(taskFile) {
9613
+ async function markAsReadByTaskFile(taskFile, sessionScope) {
9241
9614
  try {
9242
9615
  const client = getClient();
9616
+ const scope = strictSessionScopeFilter(sessionScope);
9243
9617
  await client.execute({
9244
- sql: "UPDATE notifications SET read = 1 WHERE task_file = ? AND read = 0",
9245
- args: [taskFile]
9618
+ sql: `UPDATE notifications SET read = 1
9619
+ WHERE task_file = ? AND read = 0${scope.sql}`,
9620
+ args: [taskFile, ...scope.args]
9246
9621
  });
9247
9622
  } catch {
9248
9623
  }
@@ -9251,11 +9626,12 @@ var init_notifications = __esm({
9251
9626
  "src/lib/notifications.ts"() {
9252
9627
  "use strict";
9253
9628
  init_database();
9629
+ init_task_scope();
9254
9630
  }
9255
9631
  });
9256
9632
 
9257
9633
  // src/lib/session-kill-telemetry.ts
9258
- import crypto6 from "crypto";
9634
+ import crypto7 from "crypto";
9259
9635
  async function recordSessionKill(input) {
9260
9636
  try {
9261
9637
  const client = getClient();
@@ -9265,7 +9641,7 @@ async function recordSessionKill(input) {
9265
9641
  ticks_idle, estimated_tokens_saved)
9266
9642
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
9267
9643
  args: [
9268
- crypto6.randomUUID(),
9644
+ crypto7.randomUUID(),
9269
9645
  input.sessionName,
9270
9646
  input.agentId,
9271
9647
  (/* @__PURE__ */ new Date()).toISOString(),
@@ -9288,35 +9664,6 @@ var init_session_kill_telemetry = __esm({
9288
9664
  }
9289
9665
  });
9290
9666
 
9291
- // src/lib/task-scope.ts
9292
- var task_scope_exports = {};
9293
- __export(task_scope_exports, {
9294
- getCurrentSessionScope: () => getCurrentSessionScope,
9295
- sessionScopeFilter: () => sessionScopeFilter
9296
- });
9297
- function getCurrentSessionScope() {
9298
- try {
9299
- return resolveExeSession();
9300
- } catch {
9301
- return null;
9302
- }
9303
- }
9304
- function sessionScopeFilter(sessionScope, tableAlias) {
9305
- const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
9306
- if (!scope) return { sql: "", args: [] };
9307
- const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
9308
- return {
9309
- sql: ` AND (${col} IS NULL OR ${col} = ?)`,
9310
- args: [scope]
9311
- };
9312
- }
9313
- var init_task_scope = __esm({
9314
- "src/lib/task-scope.ts"() {
9315
- "use strict";
9316
- init_tmux_routing();
9317
- }
9318
- });
9319
-
9320
9667
  // src/lib/tasks-crud.ts
9321
9668
  var tasks_crud_exports = {};
9322
9669
  __export(tasks_crud_exports, {
@@ -9334,12 +9681,12 @@ __export(tasks_crud_exports, {
9334
9681
  updateTaskStatus: () => updateTaskStatus,
9335
9682
  writeCheckpoint: () => writeCheckpoint
9336
9683
  });
9337
- import crypto7 from "crypto";
9338
- import path22 from "path";
9339
- import os13 from "os";
9684
+ import crypto8 from "crypto";
9685
+ import path23 from "path";
9686
+ import os14 from "os";
9340
9687
  import { execSync as execSync6 } from "child_process";
9341
9688
  import { mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
9342
- import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
9689
+ import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
9343
9690
  async function writeCheckpoint(input) {
9344
9691
  const client = getClient();
9345
9692
  const row = await resolveTask(client, input.taskId);
@@ -9455,7 +9802,7 @@ async function resolveTask(client, identifier, scopeSession) {
9455
9802
  }
9456
9803
  async function createTaskCore(input) {
9457
9804
  const client = getClient();
9458
- const id = crypto7.randomUUID();
9805
+ const id = crypto8.randomUUID();
9459
9806
  const now = (/* @__PURE__ */ new Date()).toISOString();
9460
9807
  const slug = slugify(input.title);
9461
9808
  let earlySessionScope = null;
@@ -9514,8 +9861,8 @@ ${laneWarning}` : laneWarning;
9514
9861
  }
9515
9862
  if (input.baseDir) {
9516
9863
  try {
9517
- await mkdir5(path22.join(input.baseDir, "exe", "output"), { recursive: true });
9518
- await mkdir5(path22.join(input.baseDir, "exe", "research"), { recursive: true });
9864
+ await mkdir5(path23.join(input.baseDir, "exe", "output"), { recursive: true });
9865
+ await mkdir5(path23.join(input.baseDir, "exe", "research"), { recursive: true });
9519
9866
  await ensureArchitectureDoc(input.baseDir, input.projectName);
9520
9867
  await ensureGitignoreExe(input.baseDir);
9521
9868
  } catch {
@@ -9551,13 +9898,19 @@ ${laneWarning}` : laneWarning;
9551
9898
  });
9552
9899
  if (input.baseDir) {
9553
9900
  try {
9554
- const EXE_OS_DIR = path22.join(os13.homedir(), ".exe-os");
9555
- const mdPath = path22.join(EXE_OS_DIR, taskFile);
9556
- const mdDir = path22.dirname(mdPath);
9557
- if (!existsSync19(mdDir)) await mkdir5(mdDir, { recursive: true });
9901
+ const EXE_OS_DIR = path23.join(os14.homedir(), ".exe-os");
9902
+ const mdPath = path23.join(EXE_OS_DIR, taskFile);
9903
+ const mdDir = path23.dirname(mdPath);
9904
+ if (!existsSync21(mdDir)) await mkdir5(mdDir, { recursive: true });
9558
9905
  const reviewer = input.reviewer ?? input.assignedBy;
9559
9906
  const mdContent = `# ${input.title}
9560
9907
 
9908
+ ## MANDATORY: When done
9909
+
9910
+ You MUST call update_task with status "done" and a result summary when finished.
9911
+ If you skip this, your reviewer will not know you're done and your work won't be reviewed.
9912
+ Do NOT let a failed commit or any error prevent you from calling update_task(done).
9913
+
9561
9914
  **ID:** ${id}
9562
9915
  **Status:** ${initialStatus}
9563
9916
  **Priority:** ${input.priority}
@@ -9571,12 +9924,6 @@ ${laneWarning}` : laneWarning;
9571
9924
  ## Context
9572
9925
 
9573
9926
  ${input.context}
9574
-
9575
- ## MANDATORY: When done
9576
-
9577
- You MUST call update_task with status "done" and a result summary when finished.
9578
- If you skip this, your reviewer will not know you're done and your work won't be reviewed.
9579
- Do NOT let a failed commit or any error prevent you from calling update_task(done).
9580
9927
  `;
9581
9928
  await writeFile5(mdPath, mdContent, "utf-8");
9582
9929
  } catch (err) {
@@ -9825,7 +10172,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
9825
10172
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
9826
10173
  } catch {
9827
10174
  }
9828
- if (input.status === "done" || input.status === "cancelled") {
10175
+ if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
9829
10176
  try {
9830
10177
  const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
9831
10178
  clearQueueForAgent2(String(row.assigned_to));
@@ -9854,9 +10201,9 @@ async function deleteTaskCore(taskId, _baseDir) {
9854
10201
  return { taskFile, assignedTo, assignedBy, taskSlug };
9855
10202
  }
9856
10203
  async function ensureArchitectureDoc(baseDir, projectName) {
9857
- const archPath = path22.join(baseDir, "exe", "ARCHITECTURE.md");
10204
+ const archPath = path23.join(baseDir, "exe", "ARCHITECTURE.md");
9858
10205
  try {
9859
- if (existsSync19(archPath)) return;
10206
+ if (existsSync21(archPath)) return;
9860
10207
  const template = [
9861
10208
  `# ${projectName} \u2014 System Architecture`,
9862
10209
  "",
@@ -9889,10 +10236,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
9889
10236
  }
9890
10237
  }
9891
10238
  async function ensureGitignoreExe(baseDir) {
9892
- const gitignorePath = path22.join(baseDir, ".gitignore");
10239
+ const gitignorePath = path23.join(baseDir, ".gitignore");
9893
10240
  try {
9894
- if (existsSync19(gitignorePath)) {
9895
- const content = readFileSync17(gitignorePath, "utf-8");
10241
+ if (existsSync21(gitignorePath)) {
10242
+ const content = readFileSync18(gitignorePath, "utf-8");
9896
10243
  if (/^\/?exe\/?$/m.test(content)) return;
9897
10244
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
9898
10245
  } else {
@@ -9923,58 +10270,42 @@ var init_tasks_crud = __esm({
9923
10270
  });
9924
10271
 
9925
10272
  // src/lib/tasks-review.ts
9926
- import path23 from "path";
9927
- import { existsSync as existsSync20, readdirSync as readdirSync5, unlinkSync as unlinkSync6 } from "fs";
10273
+ import path24 from "path";
10274
+ import { existsSync as existsSync22, readdirSync as readdirSync5, unlinkSync as unlinkSync6 } from "fs";
9928
10275
  async function countPendingReviews(sessionScope) {
9929
10276
  const client = getClient();
9930
- if (sessionScope) {
9931
- const result2 = await client.execute({
9932
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
9933
- args: [sessionScope]
9934
- });
9935
- return Number(result2.rows[0]?.cnt) || 0;
9936
- }
10277
+ const scope = strictSessionScopeFilter(
10278
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
10279
+ );
9937
10280
  const result = await client.execute({
9938
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review'",
9939
- args: []
10281
+ sql: `SELECT COUNT(*) as cnt FROM tasks
10282
+ WHERE status = 'needs_review'${scope.sql}`,
10283
+ args: [...scope.args]
9940
10284
  });
9941
10285
  return Number(result.rows[0]?.cnt) || 0;
9942
10286
  }
9943
10287
  async function countNewPendingReviewsSince(sinceIso, sessionScope) {
9944
10288
  const client = getClient();
9945
- if (sessionScope) {
9946
- const result2 = await client.execute({
9947
- sql: `SELECT COUNT(*) as cnt FROM tasks
9948
- WHERE status = 'needs_review' AND updated_at > ?
9949
- AND session_scope = ?`,
9950
- args: [sinceIso, sessionScope]
9951
- });
9952
- return Number(result2.rows[0]?.cnt) || 0;
9953
- }
10289
+ const scope = strictSessionScopeFilter(
10290
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
10291
+ );
9954
10292
  const result = await client.execute({
9955
10293
  sql: `SELECT COUNT(*) as cnt FROM tasks
9956
- WHERE status = 'needs_review' AND updated_at > ?`,
9957
- args: [sinceIso]
10294
+ WHERE status = 'needs_review' AND updated_at > ?${scope.sql}`,
10295
+ args: [sinceIso, ...scope.args]
9958
10296
  });
9959
10297
  return Number(result.rows[0]?.cnt) || 0;
9960
10298
  }
9961
10299
  async function listPendingReviews(limit, sessionScope) {
9962
10300
  const client = getClient();
9963
- if (sessionScope) {
9964
- const result2 = await client.execute({
9965
- sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
9966
- WHERE status = 'needs_review'
9967
- AND session_scope = ?
9968
- ORDER BY updated_at ASC LIMIT ?`,
9969
- args: [sessionScope, limit]
9970
- });
9971
- return result2.rows;
9972
- }
10301
+ const scope = strictSessionScopeFilter(
10302
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
10303
+ );
9973
10304
  const result = await client.execute({
9974
10305
  sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
9975
- WHERE status = 'needs_review'
10306
+ WHERE status = 'needs_review'${scope.sql}
9976
10307
  ORDER BY updated_at ASC LIMIT ?`,
9977
- args: [limit]
10308
+ args: [...scope.args, limit]
9978
10309
  });
9979
10310
  return result.rows;
9980
10311
  }
@@ -9986,7 +10317,7 @@ async function cleanupOrphanedReviews() {
9986
10317
  WHERE status IN ('open', 'needs_review', 'in_progress')
9987
10318
  AND assigned_by = 'system'
9988
10319
  AND title LIKE 'Review:%'
9989
- AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
10320
+ AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled', 'closed'))`,
9990
10321
  args: [now]
9991
10322
  });
9992
10323
  const r1b = await client.execute({
@@ -10105,11 +10436,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
10105
10436
  );
10106
10437
  }
10107
10438
  try {
10108
- const cacheDir = path23.join(EXE_AI_DIR, "session-cache");
10109
- if (existsSync20(cacheDir)) {
10439
+ const cacheDir = path24.join(EXE_AI_DIR, "session-cache");
10440
+ if (existsSync22(cacheDir)) {
10110
10441
  for (const f of readdirSync5(cacheDir)) {
10111
10442
  if (f.startsWith("review-notified-")) {
10112
- unlinkSync6(path23.join(cacheDir, f));
10443
+ unlinkSync6(path24.join(cacheDir, f));
10113
10444
  }
10114
10445
  }
10115
10446
  }
@@ -10126,11 +10457,12 @@ var init_tasks_review = __esm({
10126
10457
  init_tmux_routing();
10127
10458
  init_session_key();
10128
10459
  init_state_bus();
10460
+ init_task_scope();
10129
10461
  }
10130
10462
  });
10131
10463
 
10132
10464
  // src/lib/tasks-chain.ts
10133
- import path24 from "path";
10465
+ import path25 from "path";
10134
10466
  import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
10135
10467
  async function cascadeUnblock(taskId, baseDir, now) {
10136
10468
  const client = getClient();
@@ -10147,7 +10479,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
10147
10479
  });
10148
10480
  for (const ur of unblockedRows.rows) {
10149
10481
  try {
10150
- const ubFile = path24.join(baseDir, String(ur.task_file));
10482
+ const ubFile = path25.join(baseDir, String(ur.task_file));
10151
10483
  let ubContent = await readFile5(ubFile, "utf-8");
10152
10484
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
10153
10485
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -10182,7 +10514,7 @@ async function checkSubtaskCompletion(parentTaskId, projectName) {
10182
10514
  const scScope = sessionScopeFilter();
10183
10515
  const remaining = await client.execute({
10184
10516
  sql: `SELECT COUNT(*) as cnt FROM tasks
10185
- WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled')${scScope.sql}`,
10517
+ WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled', 'closed')${scScope.sql}`,
10186
10518
  args: [parentTaskId, ...scScope.args]
10187
10519
  });
10188
10520
  const cnt = Number(remaining.rows[0]?.cnt ?? 1);
@@ -10216,7 +10548,7 @@ var init_tasks_chain = __esm({
10216
10548
 
10217
10549
  // src/lib/project-name.ts
10218
10550
  import { execSync as execSync7 } from "child_process";
10219
- import path25 from "path";
10551
+ import path26 from "path";
10220
10552
  function getProjectName(cwd2) {
10221
10553
  const dir = cwd2 ?? process.cwd();
10222
10554
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -10229,7 +10561,7 @@ function getProjectName(cwd2) {
10229
10561
  timeout: 2e3,
10230
10562
  stdio: ["pipe", "pipe", "pipe"]
10231
10563
  }).trim();
10232
- repoRoot = path25.dirname(gitCommonDir);
10564
+ repoRoot = path26.dirname(gitCommonDir);
10233
10565
  } catch {
10234
10566
  repoRoot = execSync7("git rev-parse --show-toplevel", {
10235
10567
  cwd: dir,
@@ -10238,11 +10570,11 @@ function getProjectName(cwd2) {
10238
10570
  stdio: ["pipe", "pipe", "pipe"]
10239
10571
  }).trim();
10240
10572
  }
10241
- _cached2 = path25.basename(repoRoot);
10573
+ _cached2 = path26.basename(repoRoot);
10242
10574
  _cachedCwd = dir;
10243
10575
  return _cached2;
10244
10576
  } catch {
10245
- _cached2 = path25.basename(dir);
10577
+ _cached2 = path26.basename(dir);
10246
10578
  _cachedCwd = dir;
10247
10579
  return _cached2;
10248
10580
  }
@@ -10385,10 +10717,10 @@ var init_tasks_notify = __esm({
10385
10717
  });
10386
10718
 
10387
10719
  // src/lib/behaviors.ts
10388
- import crypto8 from "crypto";
10720
+ import crypto9 from "crypto";
10389
10721
  async function storeBehavior(opts) {
10390
10722
  const client = getClient();
10391
- const id = crypto8.randomUUID();
10723
+ const id = crypto9.randomUUID();
10392
10724
  const now = (/* @__PURE__ */ new Date()).toISOString();
10393
10725
  await client.execute({
10394
10726
  sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
@@ -10417,7 +10749,7 @@ __export(skill_learning_exports, {
10417
10749
  storeTrajectory: () => storeTrajectory,
10418
10750
  sweepTrajectories: () => sweepTrajectories
10419
10751
  });
10420
- import crypto9 from "crypto";
10752
+ import crypto10 from "crypto";
10421
10753
  async function extractTrajectory(taskId, agentId) {
10422
10754
  const client = getClient();
10423
10755
  const result = await client.execute({
@@ -10446,11 +10778,11 @@ async function extractTrajectory(taskId, agentId) {
10446
10778
  return signature;
10447
10779
  }
10448
10780
  function hashSignature(signature) {
10449
- return crypto9.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
10781
+ return crypto10.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
10450
10782
  }
10451
10783
  async function storeTrajectory(opts) {
10452
10784
  const client = getClient();
10453
- const id = crypto9.randomUUID();
10785
+ const id = crypto10.randomUUID();
10454
10786
  const now = (/* @__PURE__ */ new Date()).toISOString();
10455
10787
  const signatureHash = hashSignature(opts.signature);
10456
10788
  await client.execute({
@@ -10715,8 +11047,8 @@ __export(tasks_exports, {
10715
11047
  updateTaskStatus: () => updateTaskStatus,
10716
11048
  writeCheckpoint: () => writeCheckpoint
10717
11049
  });
10718
- import path26 from "path";
10719
- import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, unlinkSync as unlinkSync7 } from "fs";
11050
+ import path27 from "path";
11051
+ import { writeFileSync as writeFileSync14, mkdirSync as mkdirSync13, unlinkSync as unlinkSync7 } from "fs";
10720
11052
  async function createTask(input) {
10721
11053
  const result = await createTaskCore(input);
10722
11054
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -10735,12 +11067,12 @@ async function updateTask(input) {
10735
11067
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
10736
11068
  try {
10737
11069
  const agent = String(row.assigned_to);
10738
- const cacheDir = path26.join(EXE_AI_DIR, "session-cache");
10739
- const cachePath = path26.join(cacheDir, `current-task-${agent}.json`);
11070
+ const cacheDir = path27.join(EXE_AI_DIR, "session-cache");
11071
+ const cachePath = path27.join(cacheDir, `current-task-${agent}.json`);
10740
11072
  if (input.status === "in_progress") {
10741
- mkdirSync14(cacheDir, { recursive: true });
10742
- writeFileSync13(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
10743
- } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
11073
+ mkdirSync13(cacheDir, { recursive: true });
11074
+ writeFileSync14(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
11075
+ } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
10744
11076
  try {
10745
11077
  unlinkSync7(cachePath);
10746
11078
  } catch {
@@ -10748,10 +11080,10 @@ async function updateTask(input) {
10748
11080
  }
10749
11081
  } catch {
10750
11082
  }
10751
- if (input.status === "done") {
11083
+ if (input.status === "done" || input.status === "closed") {
10752
11084
  await cleanupReviewFile(row, taskFile, input.baseDir);
10753
11085
  }
10754
- if (input.status === "done" || input.status === "cancelled") {
11086
+ if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
10755
11087
  try {
10756
11088
  const client = getClient();
10757
11089
  const taskTitle = String(row.title);
@@ -10767,7 +11099,7 @@ async function updateTask(input) {
10767
11099
  if (!isCoordinatorName(assignedAgent)) {
10768
11100
  try {
10769
11101
  const draftClient = getClient();
10770
- if (input.status === "done") {
11102
+ if (input.status === "done" || input.status === "closed") {
10771
11103
  await draftClient.execute({
10772
11104
  sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
10773
11105
  args: [assignedAgent]
@@ -10784,7 +11116,7 @@ async function updateTask(input) {
10784
11116
  try {
10785
11117
  const client = getClient();
10786
11118
  const cascaded = await client.execute({
10787
- sql: `UPDATE tasks SET status = 'done', updated_at = ?
11119
+ sql: `UPDATE tasks SET status = 'closed', updated_at = ?
10788
11120
  WHERE parent_task_id = ? AND status = 'needs_review'`,
10789
11121
  args: [now, taskId]
10790
11122
  });
@@ -10797,14 +11129,14 @@ async function updateTask(input) {
10797
11129
  } catch {
10798
11130
  }
10799
11131
  }
10800
- const isTerminal = input.status === "done" || input.status === "needs_review";
11132
+ const isTerminal = input.status === "done" || input.status === "needs_review" || input.status === "closed";
10801
11133
  if (isTerminal) {
10802
11134
  const isCoordinator = isCoordinatorName(String(row.assigned_to));
10803
11135
  if (!isCoordinator) {
10804
11136
  notifyTaskDone();
10805
11137
  }
10806
11138
  await markTaskNotificationsRead(taskFile);
10807
- if (input.status === "done") {
11139
+ if (input.status === "done" || input.status === "closed") {
10808
11140
  try {
10809
11141
  await cascadeUnblock(taskId, input.baseDir, now);
10810
11142
  } catch {
@@ -10824,7 +11156,7 @@ async function updateTask(input) {
10824
11156
  }
10825
11157
  }
10826
11158
  }
10827
- if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
11159
+ if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
10828
11160
  Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
10829
11161
  ({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
10830
11162
  taskId,
@@ -11196,6 +11528,7 @@ __export(tmux_routing_exports, {
11196
11528
  isEmployeeAlive: () => isEmployeeAlive,
11197
11529
  isExeSession: () => isExeSession,
11198
11530
  isSessionBusy: () => isSessionBusy,
11531
+ notifyCoordinatorTaskCompletion: () => notifyCoordinatorTaskCompletion,
11199
11532
  notifyParentExe: () => notifyParentExe,
11200
11533
  parseParentExe: () => parseParentExe,
11201
11534
  registerParentExe: () => registerParentExe,
@@ -11206,13 +11539,13 @@ __export(tmux_routing_exports, {
11206
11539
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
11207
11540
  });
11208
11541
  import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
11209
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, existsSync as existsSync21, appendFileSync as appendFileSync2, readdirSync as readdirSync6 } from "fs";
11210
- import path27 from "path";
11211
- import os14 from "os";
11542
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14, existsSync as existsSync23, appendFileSync as appendFileSync2, readdirSync as readdirSync6 } from "fs";
11543
+ import path28 from "path";
11544
+ import os15 from "os";
11212
11545
  import { fileURLToPath as fileURLToPath4 } from "url";
11213
11546
  import { unlinkSync as unlinkSync8 } from "fs";
11214
11547
  function spawnLockPath(sessionName) {
11215
- return path27.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
11548
+ return path28.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
11216
11549
  }
11217
11550
  function isProcessAlive(pid) {
11218
11551
  try {
@@ -11223,13 +11556,13 @@ function isProcessAlive(pid) {
11223
11556
  }
11224
11557
  }
11225
11558
  function acquireSpawnLock2(sessionName) {
11226
- if (!existsSync21(SPAWN_LOCK_DIR)) {
11227
- mkdirSync15(SPAWN_LOCK_DIR, { recursive: true });
11559
+ if (!existsSync23(SPAWN_LOCK_DIR)) {
11560
+ mkdirSync14(SPAWN_LOCK_DIR, { recursive: true });
11228
11561
  }
11229
11562
  const lockFile = spawnLockPath(sessionName);
11230
- if (existsSync21(lockFile)) {
11563
+ if (existsSync23(lockFile)) {
11231
11564
  try {
11232
- const lock = JSON.parse(readFileSync18(lockFile, "utf8"));
11565
+ const lock = JSON.parse(readFileSync19(lockFile, "utf8"));
11233
11566
  const age = Date.now() - lock.timestamp;
11234
11567
  if (isProcessAlive(lock.pid) && age < 6e4) {
11235
11568
  return false;
@@ -11237,7 +11570,7 @@ function acquireSpawnLock2(sessionName) {
11237
11570
  } catch {
11238
11571
  }
11239
11572
  }
11240
- writeFileSync14(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
11573
+ writeFileSync15(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
11241
11574
  return true;
11242
11575
  }
11243
11576
  function releaseSpawnLock2(sessionName) {
@@ -11249,13 +11582,13 @@ function releaseSpawnLock2(sessionName) {
11249
11582
  function resolveBehaviorsExporterScript() {
11250
11583
  try {
11251
11584
  const thisFile = fileURLToPath4(import.meta.url);
11252
- const scriptPath = path27.join(
11253
- path27.dirname(thisFile),
11585
+ const scriptPath = path28.join(
11586
+ path28.dirname(thisFile),
11254
11587
  "..",
11255
11588
  "bin",
11256
11589
  "exe-export-behaviors.js"
11257
11590
  );
11258
- return existsSync21(scriptPath) ? scriptPath : null;
11591
+ return existsSync23(scriptPath) ? scriptPath : null;
11259
11592
  } catch {
11260
11593
  return null;
11261
11594
  }
@@ -11321,12 +11654,12 @@ function extractRootExe(name) {
11321
11654
  return parts.length > 0 ? parts[parts.length - 1] : null;
11322
11655
  }
11323
11656
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
11324
- if (!existsSync21(SESSION_CACHE)) {
11325
- mkdirSync15(SESSION_CACHE, { recursive: true });
11657
+ if (!existsSync23(SESSION_CACHE)) {
11658
+ mkdirSync14(SESSION_CACHE, { recursive: true });
11326
11659
  }
11327
11660
  const rootExe = extractRootExe(parentExe) ?? parentExe;
11328
- const filePath = path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
11329
- writeFileSync14(filePath, JSON.stringify({
11661
+ const filePath = path28.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
11662
+ writeFileSync15(filePath, JSON.stringify({
11330
11663
  parentExe: rootExe,
11331
11664
  dispatchedBy: dispatchedBy || rootExe,
11332
11665
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -11334,7 +11667,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
11334
11667
  }
11335
11668
  function getParentExe(sessionKey) {
11336
11669
  try {
11337
- const data = JSON.parse(readFileSync18(path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
11670
+ const data = JSON.parse(readFileSync19(path28.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
11338
11671
  return data.parentExe || null;
11339
11672
  } catch {
11340
11673
  return null;
@@ -11342,8 +11675,8 @@ function getParentExe(sessionKey) {
11342
11675
  }
11343
11676
  function getDispatchedBy(sessionKey) {
11344
11677
  try {
11345
- const data = JSON.parse(readFileSync18(
11346
- path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
11678
+ const data = JSON.parse(readFileSync19(
11679
+ path28.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
11347
11680
  "utf8"
11348
11681
  ));
11349
11682
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -11413,8 +11746,8 @@ async function verifyPaneAtCapacity(sessionName) {
11413
11746
  }
11414
11747
  function readDebounceState() {
11415
11748
  try {
11416
- if (!existsSync21(DEBOUNCE_FILE)) return {};
11417
- const raw = JSON.parse(readFileSync18(DEBOUNCE_FILE, "utf8"));
11749
+ if (!existsSync23(DEBOUNCE_FILE)) return {};
11750
+ const raw = JSON.parse(readFileSync19(DEBOUNCE_FILE, "utf8"));
11418
11751
  const state = {};
11419
11752
  for (const [key, val] of Object.entries(raw)) {
11420
11753
  if (typeof val === "number") {
@@ -11430,8 +11763,8 @@ function readDebounceState() {
11430
11763
  }
11431
11764
  function writeDebounceState(state) {
11432
11765
  try {
11433
- if (!existsSync21(SESSION_CACHE)) mkdirSync15(SESSION_CACHE, { recursive: true });
11434
- writeFileSync14(DEBOUNCE_FILE, JSON.stringify(state));
11766
+ if (!existsSync23(SESSION_CACHE)) mkdirSync14(SESSION_CACHE, { recursive: true });
11767
+ writeFileSync15(DEBOUNCE_FILE, JSON.stringify(state));
11435
11768
  } catch {
11436
11769
  }
11437
11770
  }
@@ -11529,8 +11862,8 @@ function sendIntercom(targetSession) {
11529
11862
  try {
11530
11863
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
11531
11864
  const agent = baseAgentName(rawAgent);
11532
- const markerPath = path27.join(SESSION_CACHE, `current-task-${agent}.json`);
11533
- if (existsSync21(markerPath)) {
11865
+ const markerPath = path28.join(SESSION_CACHE, `current-task-${agent}.json`);
11866
+ if (existsSync23(markerPath)) {
11534
11867
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
11535
11868
  return "debounced";
11536
11869
  }
@@ -11539,8 +11872,8 @@ function sendIntercom(targetSession) {
11539
11872
  try {
11540
11873
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
11541
11874
  const agent = baseAgentName(rawAgent);
11542
- const taskDir = path27.join(process.cwd(), "exe", agent);
11543
- if (existsSync21(taskDir)) {
11875
+ const taskDir = path28.join(process.cwd(), "exe", agent);
11876
+ if (existsSync23(taskDir)) {
11544
11877
  const files = readdirSync6(taskDir).filter(
11545
11878
  (f) => f.endsWith(".md") && f !== "DONE.txt"
11546
11879
  );
@@ -11600,6 +11933,21 @@ function notifyParentExe(sessionKey) {
11600
11933
  }
11601
11934
  return true;
11602
11935
  }
11936
+ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitle) {
11937
+ const transport = getTransport();
11938
+ try {
11939
+ const sessions = transport.listSessions();
11940
+ if (!sessions.includes(coordinatorSession)) return false;
11941
+ execSync8(
11942
+ `tmux send-keys -t ${JSON.stringify(coordinatorSession)} '/exe-intercom' Enter`,
11943
+ { timeout: 3e3 }
11944
+ );
11945
+ logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}")`);
11946
+ return true;
11947
+ } catch {
11948
+ return false;
11949
+ }
11950
+ }
11603
11951
  function ensureEmployee(employeeName, exeSession, projectDir, opts) {
11604
11952
  if (isCoordinatorName(employeeName)) {
11605
11953
  return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
@@ -11673,26 +12021,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11673
12021
  const transport = getTransport();
11674
12022
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
11675
12023
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
11676
- const logDir = path27.join(os14.homedir(), ".exe-os", "session-logs");
11677
- const logFile = path27.join(logDir, `${instanceLabel}-${Date.now()}.log`);
11678
- if (!existsSync21(logDir)) {
11679
- mkdirSync15(logDir, { recursive: true });
12024
+ const logDir = path28.join(os15.homedir(), ".exe-os", "session-logs");
12025
+ const logFile = path28.join(logDir, `${instanceLabel}-${Date.now()}.log`);
12026
+ if (!existsSync23(logDir)) {
12027
+ mkdirSync14(logDir, { recursive: true });
11680
12028
  }
11681
12029
  transport.kill(sessionName);
11682
12030
  let cleanupSuffix = "";
11683
12031
  try {
11684
12032
  const thisFile = fileURLToPath4(import.meta.url);
11685
- const cleanupScript = path27.join(path27.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
11686
- if (existsSync21(cleanupScript)) {
12033
+ const cleanupScript = path28.join(path28.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
12034
+ if (existsSync23(cleanupScript)) {
11687
12035
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
11688
12036
  }
11689
12037
  } catch {
11690
12038
  }
11691
12039
  try {
11692
- const claudeJsonPath = path27.join(os14.homedir(), ".claude.json");
12040
+ const claudeJsonPath = path28.join(os15.homedir(), ".claude.json");
11693
12041
  let claudeJson = {};
11694
12042
  try {
11695
- claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
12043
+ claudeJson = JSON.parse(readFileSync19(claudeJsonPath, "utf8"));
11696
12044
  } catch {
11697
12045
  }
11698
12046
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -11700,17 +12048,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11700
12048
  const trustDir = opts?.cwd ?? projectDir;
11701
12049
  if (!projects[trustDir]) projects[trustDir] = {};
11702
12050
  projects[trustDir].hasTrustDialogAccepted = true;
11703
- writeFileSync14(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
12051
+ writeFileSync15(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
11704
12052
  } catch {
11705
12053
  }
11706
12054
  try {
11707
- const settingsDir = path27.join(os14.homedir(), ".claude", "projects");
12055
+ const settingsDir = path28.join(os15.homedir(), ".claude", "projects");
11708
12056
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
11709
- const projSettingsDir = path27.join(settingsDir, normalizedKey);
11710
- const settingsPath = path27.join(projSettingsDir, "settings.json");
12057
+ const projSettingsDir = path28.join(settingsDir, normalizedKey);
12058
+ const settingsPath = path28.join(projSettingsDir, "settings.json");
11711
12059
  let settings = {};
11712
12060
  try {
11713
- settings = JSON.parse(readFileSync18(settingsPath, "utf8"));
12061
+ settings = JSON.parse(readFileSync19(settingsPath, "utf8"));
11714
12062
  } catch {
11715
12063
  }
11716
12064
  const perms = settings.permissions ?? {};
@@ -11738,8 +12086,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11738
12086
  if (changed) {
11739
12087
  perms.allow = allow;
11740
12088
  settings.permissions = perms;
11741
- mkdirSync15(projSettingsDir, { recursive: true });
11742
- writeFileSync14(settingsPath, JSON.stringify(settings, null, 2) + "\n");
12089
+ mkdirSync14(projSettingsDir, { recursive: true });
12090
+ writeFileSync15(settingsPath, JSON.stringify(settings, null, 2) + "\n");
11743
12091
  }
11744
12092
  } catch {
11745
12093
  }
@@ -11754,8 +12102,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11754
12102
  let behaviorsFlag = "";
11755
12103
  let legacyFallbackWarned = false;
11756
12104
  if (!useExeAgent && !useBinSymlink) {
11757
- const identityPath2 = path27.join(
11758
- os14.homedir(),
12105
+ const identityPath2 = path28.join(
12106
+ os15.homedir(),
11759
12107
  ".exe-os",
11760
12108
  "identity",
11761
12109
  `${employeeName}.md`
@@ -11764,13 +12112,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11764
12112
  const hasAgentFlag = claudeSupportsAgentFlag();
11765
12113
  if (hasAgentFlag) {
11766
12114
  identityFlag = ` --agent ${employeeName}`;
11767
- } else if (existsSync21(identityPath2)) {
12115
+ } else if (existsSync23(identityPath2)) {
11768
12116
  identityFlag = ` --append-system-prompt-file ${identityPath2}`;
11769
12117
  legacyFallbackWarned = true;
11770
12118
  }
11771
12119
  const behaviorsFile = exportBehaviorsSync(
11772
12120
  employeeName,
11773
- path27.basename(spawnCwd),
12121
+ path28.basename(spawnCwd),
11774
12122
  sessionName
11775
12123
  );
11776
12124
  if (behaviorsFile) {
@@ -11785,16 +12133,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11785
12133
  }
11786
12134
  let sessionContextFlag = "";
11787
12135
  try {
11788
- const ctxDir = path27.join(os14.homedir(), ".exe-os", "session-cache");
11789
- mkdirSync15(ctxDir, { recursive: true });
11790
- const ctxFile = path27.join(ctxDir, `session-context-${sessionName}.md`);
12136
+ const ctxDir = path28.join(os15.homedir(), ".exe-os", "session-cache");
12137
+ mkdirSync14(ctxDir, { recursive: true });
12138
+ const ctxFile = path28.join(ctxDir, `session-context-${sessionName}.md`);
11791
12139
  const ctxContent = [
11792
12140
  `## Session Context`,
11793
12141
  `You are running in tmux session: ${sessionName}.`,
11794
12142
  `Your parent coordinator session is ${exeSession}.`,
11795
12143
  `Your employees (if any) use the -${exeSession} suffix.`
11796
12144
  ].join("\n");
11797
- writeFileSync14(ctxFile, ctxContent);
12145
+ writeFileSync15(ctxFile, ctxContent);
11798
12146
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
11799
12147
  } catch {
11800
12148
  }
@@ -11871,8 +12219,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11871
12219
  transport.pipeLog(sessionName, logFile);
11872
12220
  try {
11873
12221
  const mySession = getMySession();
11874
- const dispatchInfo = path27.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
11875
- writeFileSync14(dispatchInfo, JSON.stringify({
12222
+ const dispatchInfo = path28.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
12223
+ writeFileSync15(dispatchInfo, JSON.stringify({
11876
12224
  dispatchedBy: mySession,
11877
12225
  rootExe: exeSession,
11878
12226
  provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
@@ -11946,15 +12294,15 @@ var init_tmux_routing = __esm({
11946
12294
  init_intercom_queue();
11947
12295
  init_plan_limits();
11948
12296
  init_employees();
11949
- SPAWN_LOCK_DIR = path27.join(os14.homedir(), ".exe-os", "spawn-locks");
11950
- SESSION_CACHE = path27.join(os14.homedir(), ".exe-os", "session-cache");
12297
+ SPAWN_LOCK_DIR = path28.join(os15.homedir(), ".exe-os", "spawn-locks");
12298
+ SESSION_CACHE = path28.join(os15.homedir(), ".exe-os", "session-cache");
11951
12299
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
11952
12300
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
11953
12301
  VERIFY_PANE_LINES = 200;
11954
12302
  INTERCOM_DEBOUNCE_MS = 3e4;
11955
12303
  CODEX_DEBOUNCE_MS = 12e4;
11956
- INTERCOM_LOG2 = path27.join(os14.homedir(), ".exe-os", "intercom.log");
11957
- DEBOUNCE_FILE = path27.join(SESSION_CACHE, "intercom-debounce.json");
12304
+ INTERCOM_LOG2 = path28.join(os15.homedir(), ".exe-os", "intercom.log");
12305
+ DEBOUNCE_FILE = path28.join(SESSION_CACHE, "intercom-debounce.json");
11958
12306
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
11959
12307
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
11960
12308
  }
@@ -11977,10 +12325,10 @@ __export(messaging_exports, {
11977
12325
  sendMessage: () => sendMessage,
11978
12326
  setWsClientSend: () => setWsClientSend
11979
12327
  });
11980
- import crypto10 from "crypto";
12328
+ import crypto11 from "crypto";
11981
12329
  function generateUlid() {
11982
12330
  const timestamp = Date.now().toString(36).padStart(10, "0");
11983
- const random = crypto10.randomBytes(10).toString("hex").slice(0, 16);
12331
+ const random = crypto11.randomBytes(10).toString("hex").slice(0, 16);
11984
12332
  return (timestamp + random).toUpperCase();
11985
12333
  }
11986
12334
  function rowToMessage(row) {
@@ -11991,6 +12339,7 @@ function rowToMessage(row) {
11991
12339
  targetAgent: row.target_agent,
11992
12340
  targetProject: row.target_project ?? null,
11993
12341
  targetDevice: row.target_device,
12342
+ sessionScope: row.session_scope ?? null,
11994
12343
  content: row.content,
11995
12344
  priority: row.priority ?? "normal",
11996
12345
  status: row.status ?? "pending",
@@ -12008,15 +12357,17 @@ async function sendMessage(input) {
12008
12357
  const id = generateUlid();
12009
12358
  const now = (/* @__PURE__ */ new Date()).toISOString();
12010
12359
  const targetDevice = input.targetDevice ?? "local";
12360
+ const sessionScope = input.sessionScope === void 0 ? resolveExeSession() : input.sessionScope;
12011
12361
  await client.execute({
12012
- sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, content, priority, status, created_at)
12013
- VALUES (?, ?, 'local', ?, ?, ?, ?, ?, 'pending', ?)`,
12362
+ sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, session_scope, content, priority, status, created_at)
12363
+ VALUES (?, ?, 'local', ?, ?, ?, ?, ?, ?, 'pending', ?)`,
12014
12364
  args: [
12015
12365
  id,
12016
12366
  input.fromAgent,
12017
12367
  input.targetAgent,
12018
12368
  input.targetProject ?? null,
12019
12369
  targetDevice,
12370
+ sessionScope,
12020
12371
  input.content,
12021
12372
  input.priority ?? "normal",
12022
12373
  now
@@ -12030,9 +12381,10 @@ async function sendMessage(input) {
12030
12381
  }
12031
12382
  } catch {
12032
12383
  }
12384
+ const sentScope = strictSessionScopeFilter(sessionScope);
12033
12385
  const result = await client.execute({
12034
- sql: "SELECT * FROM messages WHERE id = ?",
12035
- args: [id]
12386
+ sql: `SELECT * FROM messages WHERE id = ?${sentScope.sql}`,
12387
+ args: [id, ...sentScope.args]
12036
12388
  });
12037
12389
  return rowToMessage(result.rows[0]);
12038
12390
  }
@@ -12056,6 +12408,7 @@ async function deliverCrossMachineMessage(messageId, targetDevice) {
12056
12408
  fromAgent: msg.fromAgent,
12057
12409
  targetAgent: msg.targetAgent,
12058
12410
  targetProject: msg.targetProject,
12411
+ sessionScope: msg.sessionScope,
12059
12412
  content: msg.content,
12060
12413
  priority: msg.priority,
12061
12414
  createdAt: msg.createdAt
@@ -12099,7 +12452,7 @@ async function deliverLocalMessage(messageId) {
12099
12452
  } catch {
12100
12453
  const newRetryCount = msg.retryCount + 1;
12101
12454
  if (newRetryCount >= MAX_RETRIES3) {
12102
- await markFailed(messageId, "session unavailable after 10 retries");
12455
+ await markFailed(messageId, "session unavailable after 10 retries", msg.sessionScope);
12103
12456
  } else {
12104
12457
  await client.execute({
12105
12458
  sql: "UPDATE messages SET retry_count = ? WHERE id = ?",
@@ -12109,85 +12462,101 @@ async function deliverLocalMessage(messageId) {
12109
12462
  return false;
12110
12463
  }
12111
12464
  }
12112
- async function getPendingMessages(targetAgent) {
12465
+ async function getPendingMessages(targetAgent, sessionScope) {
12113
12466
  const client = getClient();
12467
+ const scope = strictSessionScopeFilter(sessionScope);
12114
12468
  const result = await client.execute({
12115
12469
  sql: `SELECT * FROM messages
12116
- WHERE target_agent = ? AND status IN ('pending', 'delivered')
12470
+ WHERE target_agent = ? AND status IN ('pending', 'delivered')${scope.sql}
12117
12471
  ORDER BY id`,
12118
- args: [targetAgent]
12472
+ args: [targetAgent, ...scope.args]
12119
12473
  });
12120
12474
  return result.rows.map((row) => rowToMessage(row));
12121
12475
  }
12122
- async function markRead(messageId) {
12476
+ async function markRead(messageId, sessionScope) {
12123
12477
  const client = getClient();
12478
+ const scope = strictSessionScopeFilter(sessionScope);
12124
12479
  await client.execute({
12125
- sql: "UPDATE messages SET status = 'read' WHERE id = ? AND status IN ('pending', 'delivered')",
12126
- args: [messageId]
12480
+ sql: `UPDATE messages SET status = 'read'
12481
+ WHERE id = ? AND status IN ('pending', 'delivered')${scope.sql}`,
12482
+ args: [messageId, ...scope.args]
12127
12483
  });
12128
12484
  }
12129
- async function markAcknowledged(messageId) {
12485
+ async function markAcknowledged(messageId, sessionScope) {
12130
12486
  const client = getClient();
12487
+ const scope = strictSessionScopeFilter(sessionScope);
12131
12488
  await client.execute({
12132
- sql: "UPDATE messages SET status = 'acknowledged', processed_at = ? WHERE id = ? AND status = 'read'",
12133
- args: [(/* @__PURE__ */ new Date()).toISOString(), messageId]
12489
+ sql: `UPDATE messages SET status = 'acknowledged', processed_at = ?
12490
+ WHERE id = ? AND status = 'read'${scope.sql}`,
12491
+ args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
12134
12492
  });
12135
12493
  }
12136
- async function markProcessed(messageId) {
12494
+ async function markProcessed(messageId, sessionScope) {
12137
12495
  const client = getClient();
12496
+ const scope = strictSessionScopeFilter(sessionScope);
12138
12497
  await client.execute({
12139
- sql: "UPDATE messages SET status = 'processed', processed_at = ? WHERE id = ?",
12140
- args: [(/* @__PURE__ */ new Date()).toISOString(), messageId]
12498
+ sql: `UPDATE messages SET status = 'processed', processed_at = ?
12499
+ WHERE id = ?${scope.sql}`,
12500
+ args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
12141
12501
  });
12142
12502
  }
12143
- async function getMessageStatus(messageId) {
12503
+ async function getMessageStatus(messageId, sessionScope) {
12144
12504
  const client = getClient();
12505
+ const scope = strictSessionScopeFilter(sessionScope);
12145
12506
  const result = await client.execute({
12146
- sql: "SELECT status FROM messages WHERE id = ?",
12147
- args: [messageId]
12507
+ sql: `SELECT status FROM messages WHERE id = ?${scope.sql}`,
12508
+ args: [messageId, ...scope.args]
12148
12509
  });
12149
12510
  return result.rows[0]?.status ?? null;
12150
12511
  }
12151
- async function getUnacknowledgedMessages(targetAgent) {
12512
+ async function getUnacknowledgedMessages(targetAgent, sessionScope) {
12152
12513
  const client = getClient();
12514
+ const scope = strictSessionScopeFilter(sessionScope);
12153
12515
  const result = await client.execute({
12154
12516
  sql: `SELECT * FROM messages
12155
- WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')
12517
+ WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')${scope.sql}
12156
12518
  ORDER BY id`,
12157
- args: [targetAgent]
12519
+ args: [targetAgent, ...scope.args]
12158
12520
  });
12159
12521
  return result.rows.map((row) => rowToMessage(row));
12160
12522
  }
12161
- async function getReadMessages(targetAgent) {
12523
+ async function getReadMessages(targetAgent, sessionScope) {
12162
12524
  const client = getClient();
12525
+ const scope = strictSessionScopeFilter(sessionScope);
12163
12526
  const result = await client.execute({
12164
- sql: "SELECT * FROM messages WHERE target_agent = ? AND status = 'read' ORDER BY id",
12165
- args: [targetAgent]
12527
+ sql: `SELECT * FROM messages
12528
+ WHERE target_agent = ? AND status = 'read'${scope.sql}
12529
+ ORDER BY id`,
12530
+ args: [targetAgent, ...scope.args]
12166
12531
  });
12167
12532
  return result.rows.map((row) => rowToMessage(row));
12168
12533
  }
12169
- async function markFailed(messageId, reason) {
12534
+ async function markFailed(messageId, reason, sessionScope) {
12170
12535
  const client = getClient();
12536
+ const scope = strictSessionScopeFilter(sessionScope);
12171
12537
  await client.execute({
12172
- sql: "UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ? WHERE id = ?",
12173
- args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId]
12538
+ sql: `UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ?
12539
+ WHERE id = ?${scope.sql}`,
12540
+ args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId, ...scope.args]
12174
12541
  });
12175
12542
  }
12176
- async function getFailedMessages() {
12543
+ async function getFailedMessages(sessionScope) {
12177
12544
  const client = getClient();
12545
+ const scope = strictSessionScopeFilter(sessionScope);
12178
12546
  const result = await client.execute({
12179
- sql: "SELECT * FROM messages WHERE status = 'failed' ORDER BY created_at DESC",
12180
- args: []
12547
+ sql: `SELECT * FROM messages WHERE status = 'failed'${scope.sql} ORDER BY created_at DESC`,
12548
+ args: [...scope.args]
12181
12549
  });
12182
12550
  return result.rows.map((row) => rowToMessage(row));
12183
12551
  }
12184
- async function retryPendingMessages() {
12552
+ async function retryPendingMessages(sessionScope) {
12185
12553
  const client = getClient();
12554
+ const scope = strictSessionScopeFilter(sessionScope);
12186
12555
  const result = await client.execute({
12187
12556
  sql: `SELECT * FROM messages
12188
- WHERE status = 'pending' AND retry_count < ?
12557
+ WHERE status = 'pending' AND retry_count < ?${scope.sql}
12189
12558
  ORDER BY id`,
12190
- args: [MAX_RETRIES3]
12559
+ args: [MAX_RETRIES3, ...scope.args]
12191
12560
  });
12192
12561
  let delivered = 0;
12193
12562
  for (const row of result.rows) {
@@ -12206,6 +12575,7 @@ var init_messaging = __esm({
12206
12575
  "use strict";
12207
12576
  init_database();
12208
12577
  init_tmux_routing();
12578
+ init_task_scope();
12209
12579
  MAX_RETRIES3 = 10;
12210
12580
  _wsClientSend = null;
12211
12581
  }
@@ -12221,9 +12591,9 @@ __export(active_agent_exports, {
12221
12591
  resolveActiveAgentFromTmuxSession: () => resolveActiveAgentFromTmuxSession,
12222
12592
  writeActiveAgent: () => writeActiveAgent
12223
12593
  });
12224
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16, unlinkSync as unlinkSync9, readdirSync as readdirSync7 } from "fs";
12594
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15, unlinkSync as unlinkSync9, readdirSync as readdirSync7 } from "fs";
12225
12595
  import { execSync as execSync9 } from "child_process";
12226
- import path28 from "path";
12596
+ import path29 from "path";
12227
12597
  function isNameWithOptionalInstance(candidate, baseName) {
12228
12598
  if (candidate === baseName) return true;
12229
12599
  if (!candidate.startsWith(baseName)) return false;
@@ -12267,12 +12637,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
12267
12637
  return null;
12268
12638
  }
12269
12639
  function getMarkerPath() {
12270
- return path28.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
12640
+ return path29.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
12271
12641
  }
12272
12642
  function writeActiveAgent(agentId, agentRole) {
12273
12643
  try {
12274
- mkdirSync16(CACHE_DIR, { recursive: true });
12275
- writeFileSync15(
12644
+ mkdirSync15(CACHE_DIR, { recursive: true });
12645
+ writeFileSync16(
12276
12646
  getMarkerPath(),
12277
12647
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
12278
12648
  );
@@ -12288,7 +12658,7 @@ function clearActiveAgent() {
12288
12658
  function getActiveAgent() {
12289
12659
  try {
12290
12660
  const markerPath = getMarkerPath();
12291
- const raw = readFileSync19(markerPath, "utf8");
12661
+ const raw = readFileSync20(markerPath, "utf8");
12292
12662
  const data = JSON.parse(raw);
12293
12663
  if (data.agentId) {
12294
12664
  if (data.startedAt) {
@@ -12336,14 +12706,14 @@ function getAllActiveAgents() {
12336
12706
  const key = file.slice("active-agent-".length, -".json".length);
12337
12707
  if (key === "undefined") continue;
12338
12708
  try {
12339
- const raw = readFileSync19(path28.join(CACHE_DIR, file), "utf8");
12709
+ const raw = readFileSync20(path29.join(CACHE_DIR, file), "utf8");
12340
12710
  const data = JSON.parse(raw);
12341
12711
  if (!data.agentId) continue;
12342
12712
  if (data.startedAt) {
12343
12713
  const age = Date.now() - new Date(data.startedAt).getTime();
12344
12714
  if (age > STALE_MS) {
12345
12715
  try {
12346
- unlinkSync9(path28.join(CACHE_DIR, file));
12716
+ unlinkSync9(path29.join(CACHE_DIR, file));
12347
12717
  } catch {
12348
12718
  }
12349
12719
  continue;
@@ -12366,11 +12736,11 @@ function getAllActiveAgents() {
12366
12736
  function cleanupSessionMarkers() {
12367
12737
  const key = getSessionKey();
12368
12738
  try {
12369
- unlinkSync9(path28.join(CACHE_DIR, `active-agent-${key}.json`));
12739
+ unlinkSync9(path29.join(CACHE_DIR, `active-agent-${key}.json`));
12370
12740
  } catch {
12371
12741
  }
12372
12742
  try {
12373
- unlinkSync9(path28.join(CACHE_DIR, "active-agent-undefined.json"));
12743
+ unlinkSync9(path29.join(CACHE_DIR, "active-agent-undefined.json"));
12374
12744
  } catch {
12375
12745
  }
12376
12746
  }
@@ -12381,7 +12751,7 @@ var init_active_agent = __esm({
12381
12751
  init_config();
12382
12752
  init_session_key();
12383
12753
  init_employees();
12384
- CACHE_DIR = path28.join(EXE_AI_DIR, "session-cache");
12754
+ CACHE_DIR = path29.join(EXE_AI_DIR, "session-cache");
12385
12755
  STALE_MS = 24 * 60 * 60 * 1e3;
12386
12756
  }
12387
12757
  });
@@ -13009,14 +13379,14 @@ __export(exe_rename_exports, {
13009
13379
  main: () => main2,
13010
13380
  renameEmployee: () => renameEmployee
13011
13381
  });
13012
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, renameSync as renameSync4, unlinkSync as unlinkSync10, existsSync as existsSync22 } from "fs";
13382
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync17, renameSync as renameSync4, unlinkSync as unlinkSync10, existsSync as existsSync24 } from "fs";
13013
13383
  import { execSync as execSync10 } from "child_process";
13014
- import path29 from "path";
13384
+ import path30 from "path";
13015
13385
  import { homedir as homedir4 } from "os";
13016
13386
  async function renameEmployee(oldName, newName, opts = {}) {
13017
- const rosterPath = opts.rosterPath ?? path29.join(homedir4(), ".exe-os", "exe-employees.json");
13018
- const identityDir = opts.identityDir ?? path29.join(homedir4(), ".exe-os", "identity");
13019
- const agentsDir = opts.agentsDir ?? path29.join(homedir4(), ".claude", "agents");
13387
+ const rosterPath = opts.rosterPath ?? path30.join(homedir4(), ".exe-os", "exe-employees.json");
13388
+ const identityDir = opts.identityDir ?? path30.join(homedir4(), ".exe-os", "identity");
13389
+ const agentsDir = opts.agentsDir ?? path30.join(homedir4(), ".claude", "agents");
13020
13390
  const validation = validateEmployeeName(newName);
13021
13391
  if (!validation.valid) {
13022
13392
  return { success: false, error: validation.error };
@@ -13045,40 +13415,40 @@ async function renameEmployee(oldName, newName, opts = {}) {
13045
13415
  undo: () => {
13046
13416
  employee.name = originalName;
13047
13417
  employee.systemPrompt = originalPrompt;
13048
- writeFileSync16(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
13418
+ writeFileSync17(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
13049
13419
  }
13050
13420
  });
13051
- const oldIdentityPath = path29.join(identityDir, `${rosterOldName}.md`);
13052
- const newIdentityPath = path29.join(identityDir, `${newName}.md`);
13053
- if (existsSync22(oldIdentityPath)) {
13054
- const content = readFileSync20(oldIdentityPath, "utf-8");
13421
+ const oldIdentityPath = path30.join(identityDir, `${rosterOldName}.md`);
13422
+ const newIdentityPath = path30.join(identityDir, `${newName}.md`);
13423
+ if (existsSync24(oldIdentityPath)) {
13424
+ const content = readFileSync21(oldIdentityPath, "utf-8");
13055
13425
  const updatedContent = content.replace(
13056
13426
  /^(agent_id:\s*)\S+/m,
13057
13427
  `$1${newName}`
13058
13428
  );
13059
13429
  renameSync4(oldIdentityPath, newIdentityPath);
13060
- writeFileSync16(newIdentityPath, updatedContent, "utf-8");
13430
+ writeFileSync17(newIdentityPath, updatedContent, "utf-8");
13061
13431
  rollbackStack.push({
13062
13432
  description: "restore identity file",
13063
13433
  undo: () => {
13064
- if (existsSync22(newIdentityPath)) {
13065
- writeFileSync16(newIdentityPath, content, "utf-8");
13434
+ if (existsSync24(newIdentityPath)) {
13435
+ writeFileSync17(newIdentityPath, content, "utf-8");
13066
13436
  renameSync4(newIdentityPath, oldIdentityPath);
13067
13437
  }
13068
13438
  }
13069
13439
  });
13070
13440
  }
13071
- const oldAgentPath = path29.join(agentsDir, `${rosterOldName}.md`);
13072
- const newAgentPath = path29.join(agentsDir, `${newName}.md`);
13073
- if (existsSync22(oldAgentPath)) {
13074
- const agentContent = readFileSync20(oldAgentPath, "utf-8");
13441
+ const oldAgentPath = path30.join(agentsDir, `${rosterOldName}.md`);
13442
+ const newAgentPath = path30.join(agentsDir, `${newName}.md`);
13443
+ if (existsSync24(oldAgentPath)) {
13444
+ const agentContent = readFileSync21(oldAgentPath, "utf-8");
13075
13445
  renameSync4(oldAgentPath, newAgentPath);
13076
13446
  rollbackStack.push({
13077
13447
  description: "restore agent file",
13078
13448
  undo: () => {
13079
- if (existsSync22(newAgentPath)) {
13449
+ if (existsSync24(newAgentPath)) {
13080
13450
  renameSync4(newAgentPath, oldAgentPath);
13081
- writeFileSync16(oldAgentPath, agentContent, "utf-8");
13451
+ writeFileSync17(oldAgentPath, agentContent, "utf-8");
13082
13452
  }
13083
13453
  }
13084
13454
  });
@@ -13156,10 +13526,10 @@ function removeOldSymlinks(name) {
13156
13526
  try {
13157
13527
  const exeBinPath = findExeBin2();
13158
13528
  if (!exeBinPath) return;
13159
- const binDir = path29.dirname(exeBinPath);
13529
+ const binDir = path30.dirname(exeBinPath);
13160
13530
  for (const suffix of ["", "-opencode"]) {
13161
- const linkPath = path29.join(binDir, `${name}${suffix}`);
13162
- if (existsSync22(linkPath)) {
13531
+ const linkPath = path30.join(binDir, `${name}${suffix}`);
13532
+ if (existsSync24(linkPath)) {
13163
13533
  try {
13164
13534
  unlinkSync10(linkPath);
13165
13535
  } catch {
@@ -13204,16 +13574,16 @@ var init_exe_rename = __esm({
13204
13574
  });
13205
13575
 
13206
13576
  // src/lib/model-downloader.ts
13207
- import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync23, unlinkSync as unlinkSync11, renameSync as renameSync5 } from "fs";
13577
+ import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync25, unlinkSync as unlinkSync11, renameSync as renameSync5 } from "fs";
13208
13578
  import { mkdir as mkdir6 } from "fs/promises";
13209
13579
  import { createHash as createHash3 } from "crypto";
13210
- import path30 from "path";
13580
+ import path31 from "path";
13211
13581
  async function downloadModel(opts) {
13212
13582
  const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
13213
- const destPath = path30.join(destDir, LOCAL_FILENAME);
13583
+ const destPath = path31.join(destDir, LOCAL_FILENAME);
13214
13584
  const tmpPath = destPath + ".tmp";
13215
13585
  await mkdir6(destDir, { recursive: true });
13216
- if (existsSync23(destPath)) {
13586
+ if (existsSync25(destPath)) {
13217
13587
  const hash = await fileHash(destPath);
13218
13588
  if (hash === EXPECTED_SHA256) {
13219
13589
  return destPath;
@@ -13225,7 +13595,7 @@ async function downloadModel(opts) {
13225
13595
  let downloaded = 0;
13226
13596
  for (let attempt = 1; attempt <= MAX_RETRIES4; attempt++) {
13227
13597
  try {
13228
- if (existsSync23(tmpPath)) unlinkSync11(tmpPath);
13598
+ if (existsSync25(tmpPath)) unlinkSync11(tmpPath);
13229
13599
  const response = await fetchFn(GGUF_URL, {
13230
13600
  redirect: "follow",
13231
13601
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
@@ -13270,7 +13640,7 @@ async function downloadModel(opts) {
13270
13640
  process.stderr.write(`
13271
13641
  Download attempt ${attempt} failed, retrying...
13272
13642
  `);
13273
- if (existsSync23(tmpPath)) unlinkSync11(tmpPath);
13643
+ if (existsSync25(tmpPath)) unlinkSync11(tmpPath);
13274
13644
  }
13275
13645
  }
13276
13646
  }
@@ -13333,10 +13703,10 @@ async function disposeEmbedder() {
13333
13703
  async function embedDirect(text) {
13334
13704
  const llamaCpp = await import("node-llama-cpp");
13335
13705
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
13336
- const { existsSync: existsSync30 } = await import("fs");
13337
- const path45 = await import("path");
13338
- const modelPath = path45.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
13339
- if (!existsSync30(modelPath)) {
13706
+ const { existsSync: existsSync32 } = await import("fs");
13707
+ const path46 = await import("path");
13708
+ const modelPath = path46.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
13709
+ if (!existsSync32(modelPath)) {
13340
13710
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
13341
13711
  }
13342
13712
  const llama = await llamaCpp.getLlama();
@@ -13911,36 +14281,36 @@ __export(session_wrappers_exports, {
13911
14281
  generateSessionWrappers: () => generateSessionWrappers
13912
14282
  });
13913
14283
  import {
13914
- existsSync as existsSync24,
13915
- readFileSync as readFileSync21,
13916
- writeFileSync as writeFileSync17,
13917
- mkdirSync as mkdirSync17,
13918
- chmodSync,
14284
+ existsSync as existsSync26,
14285
+ readFileSync as readFileSync22,
14286
+ writeFileSync as writeFileSync18,
14287
+ mkdirSync as mkdirSync16,
14288
+ chmodSync as chmodSync2,
13919
14289
  readdirSync as readdirSync8,
13920
14290
  unlinkSync as unlinkSync12
13921
14291
  } from "fs";
13922
- import path31 from "path";
14292
+ import path32 from "path";
13923
14293
  import { homedir as homedir5 } from "os";
13924
14294
  function generateSessionWrappers(packageRoot, homeDir) {
13925
14295
  const home = homeDir ?? homedir5();
13926
- const binDir = path31.join(home, ".exe-os", "bin");
13927
- const rosterPath = path31.join(home, ".exe-os", "exe-employees.json");
13928
- mkdirSync17(binDir, { recursive: true });
13929
- const exeStartDst = path31.join(binDir, "exe-start");
14296
+ const binDir = path32.join(home, ".exe-os", "bin");
14297
+ const rosterPath = path32.join(home, ".exe-os", "exe-employees.json");
14298
+ mkdirSync16(binDir, { recursive: true });
14299
+ const exeStartDst = path32.join(binDir, "exe-start");
13930
14300
  const candidates = [
13931
- path31.join(packageRoot, "dist", "bin", "exe-start.sh"),
13932
- path31.join(packageRoot, "src", "bin", "exe-start.sh")
14301
+ path32.join(packageRoot, "dist", "bin", "exe-start.sh"),
14302
+ path32.join(packageRoot, "src", "bin", "exe-start.sh")
13933
14303
  ];
13934
14304
  for (const src of candidates) {
13935
- if (existsSync24(src)) {
13936
- writeFileSync17(exeStartDst, readFileSync21(src));
13937
- chmodSync(exeStartDst, 493);
14305
+ if (existsSync26(src)) {
14306
+ writeFileSync18(exeStartDst, readFileSync22(src));
14307
+ chmodSync2(exeStartDst, 493);
13938
14308
  break;
13939
14309
  }
13940
14310
  }
13941
14311
  let employees = [];
13942
14312
  try {
13943
- employees = JSON.parse(readFileSync21(rosterPath, "utf8"));
14313
+ employees = JSON.parse(readFileSync22(rosterPath, "utf8"));
13944
14314
  } catch {
13945
14315
  return { created: 0, pathConfigured: false };
13946
14316
  }
@@ -13950,9 +14320,9 @@ function generateSessionWrappers(packageRoot, homeDir) {
13950
14320
  try {
13951
14321
  for (const f of readdirSync8(binDir)) {
13952
14322
  if (f === "exe-start") continue;
13953
- const fPath = path31.join(binDir, f);
14323
+ const fPath = path32.join(binDir, f);
13954
14324
  try {
13955
- const content = readFileSync21(fPath, "utf8");
14325
+ const content = readFileSync22(fPath, "utf8");
13956
14326
  if (content.includes("exe-start")) {
13957
14327
  unlinkSync12(fPath);
13958
14328
  }
@@ -13967,31 +14337,31 @@ exec "${exeStartDst}" "$0" "$@"
13967
14337
  `;
13968
14338
  for (const emp of employees) {
13969
14339
  for (let n = 1; n <= MAX_N; n++) {
13970
- const wrapperPath = path31.join(binDir, `${emp.name}${n}`);
13971
- writeFileSync17(wrapperPath, wrapperContent);
13972
- chmodSync(wrapperPath, 493);
14340
+ const wrapperPath = path32.join(binDir, `${emp.name}${n}`);
14341
+ writeFileSync18(wrapperPath, wrapperContent);
14342
+ chmodSync2(wrapperPath, 493);
13973
14343
  created++;
13974
14344
  }
13975
14345
  }
13976
14346
  const codexLauncherCandidates = [
13977
- path31.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
13978
- path31.join(packageRoot, "src", "bin", "exe-start-codex.ts")
14347
+ path32.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
14348
+ path32.join(packageRoot, "src", "bin", "exe-start-codex.ts")
13979
14349
  ];
13980
14350
  let codexLauncher = null;
13981
14351
  for (const c of codexLauncherCandidates) {
13982
- if (existsSync24(c)) {
14352
+ if (existsSync26(c)) {
13983
14353
  codexLauncher = c;
13984
14354
  break;
13985
14355
  }
13986
14356
  }
13987
14357
  if (codexLauncher) {
13988
14358
  for (const emp of employees) {
13989
- const wrapperPath = path31.join(binDir, `${emp.name}-codex`);
14359
+ const wrapperPath = path32.join(binDir, `${emp.name}-codex`);
13990
14360
  const content = `#!/bin/bash
13991
14361
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
13992
14362
  `;
13993
- writeFileSync17(wrapperPath, content);
13994
- chmodSync(wrapperPath, 493);
14363
+ writeFileSync18(wrapperPath, content);
14364
+ chmodSync2(wrapperPath, 493);
13995
14365
  created++;
13996
14366
  }
13997
14367
  }
@@ -14009,24 +14379,24 @@ export PATH="${binDir}:$PATH"
14009
14379
  const shell = process.env.SHELL ?? "/bin/bash";
14010
14380
  const profilePaths = [];
14011
14381
  if (shell.includes("zsh")) {
14012
- profilePaths.push(path31.join(home, ".zshrc"));
14382
+ profilePaths.push(path32.join(home, ".zshrc"));
14013
14383
  } else if (shell.includes("bash")) {
14014
- profilePaths.push(path31.join(home, ".bashrc"));
14015
- profilePaths.push(path31.join(home, ".bash_profile"));
14384
+ profilePaths.push(path32.join(home, ".bashrc"));
14385
+ profilePaths.push(path32.join(home, ".bash_profile"));
14016
14386
  } else {
14017
- profilePaths.push(path31.join(home, ".profile"));
14387
+ profilePaths.push(path32.join(home, ".profile"));
14018
14388
  }
14019
14389
  for (const profilePath of profilePaths) {
14020
14390
  try {
14021
14391
  let content = "";
14022
14392
  try {
14023
- content = readFileSync21(profilePath, "utf8");
14393
+ content = readFileSync22(profilePath, "utf8");
14024
14394
  } catch {
14025
14395
  }
14026
14396
  if (content.includes(".exe-os/bin")) {
14027
14397
  return false;
14028
14398
  }
14029
- writeFileSync17(profilePath, content + exportLine);
14399
+ writeFileSync18(profilePath, content + exportLine);
14030
14400
  return true;
14031
14401
  } catch {
14032
14402
  continue;
@@ -14048,37 +14418,37 @@ __export(setup_wizard_exports, {
14048
14418
  runSetupWizard: () => runSetupWizard,
14049
14419
  validateModel: () => validateModel
14050
14420
  });
14051
- import crypto11 from "crypto";
14052
- import { existsSync as existsSync25, mkdirSync as mkdirSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync18, unlinkSync as unlinkSync13 } from "fs";
14053
- import os15 from "os";
14054
- import path32 from "path";
14421
+ import crypto12 from "crypto";
14422
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync23, writeFileSync as writeFileSync19, unlinkSync as unlinkSync13 } from "fs";
14423
+ import os16 from "os";
14424
+ import path33 from "path";
14055
14425
  import { createInterface as createInterface3 } from "readline";
14056
14426
  function findPackageRoot2() {
14057
- let dir = path32.dirname(new URL(import.meta.url).pathname);
14058
- const root = path32.parse(dir).root;
14427
+ let dir = path33.dirname(new URL(import.meta.url).pathname);
14428
+ const root = path33.parse(dir).root;
14059
14429
  while (dir !== root) {
14060
- const pkgPath = path32.join(dir, "package.json");
14061
- if (existsSync25(pkgPath)) {
14430
+ const pkgPath = path33.join(dir, "package.json");
14431
+ if (existsSync27(pkgPath)) {
14062
14432
  try {
14063
- const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
14433
+ const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
14064
14434
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
14065
14435
  } catch {
14066
14436
  }
14067
14437
  }
14068
- dir = path32.dirname(dir);
14438
+ dir = path33.dirname(dir);
14069
14439
  }
14070
14440
  return null;
14071
14441
  }
14072
14442
  function loadSetupState() {
14073
14443
  try {
14074
- return JSON.parse(readFileSync22(SETUP_STATE_PATH, "utf8"));
14444
+ return JSON.parse(readFileSync23(SETUP_STATE_PATH, "utf8"));
14075
14445
  } catch {
14076
14446
  return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
14077
14447
  }
14078
14448
  }
14079
14449
  function saveSetupState(state) {
14080
- mkdirSync18(path32.dirname(SETUP_STATE_PATH), { recursive: true });
14081
- writeFileSync18(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
14450
+ mkdirSync17(path33.dirname(SETUP_STATE_PATH), { recursive: true });
14451
+ writeFileSync19(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
14082
14452
  }
14083
14453
  function clearSetupState() {
14084
14454
  try {
@@ -14097,10 +14467,10 @@ function ask2(rl, prompt) {
14097
14467
  });
14098
14468
  }
14099
14469
  function getAvailableMemoryGB() {
14100
- return os15.freemem() / (1024 * 1024 * 1024);
14470
+ return os16.freemem() / (1024 * 1024 * 1024);
14101
14471
  }
14102
14472
  function getTotalMemoryGB() {
14103
- return os15.totalmem() / (1024 * 1024 * 1024);
14473
+ return os16.totalmem() / (1024 * 1024 * 1024);
14104
14474
  }
14105
14475
  function isLowMemory() {
14106
14476
  return getAvailableMemoryGB() < 2;
@@ -14111,8 +14481,8 @@ async function validateModel(log) {
14111
14481
  if (totalGB <= 8 || isLowMemory()) {
14112
14482
  log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
14113
14483
  log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
14114
- const modelPath = path32.join(MODELS_DIR, LOCAL_FILENAME);
14115
- if (existsSync25(modelPath)) {
14484
+ const modelPath = path33.join(MODELS_DIR, LOCAL_FILENAME);
14485
+ if (existsSync27(modelPath)) {
14116
14486
  const { statSync: statSync2 } = await import("fs");
14117
14487
  const size = statSync2(modelPath).size;
14118
14488
  if (size > 300 * 1e6) {
@@ -14203,7 +14573,7 @@ async function runSetupWizard(opts = {}) {
14203
14573
  if (state.completedSteps.length > 0) {
14204
14574
  log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
14205
14575
  }
14206
- if (existsSync25(LEGACY_LANCE_PATH)) {
14576
+ if (existsSync27(LEGACY_LANCE_PATH)) {
14207
14577
  log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
14208
14578
  log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
14209
14579
  log(" The old directory will not be modified or deleted.");
@@ -14215,7 +14585,7 @@ async function runSetupWizard(opts = {}) {
14215
14585
  log("Encryption key already exists \u2014 skipping generation.");
14216
14586
  } else {
14217
14587
  log("Generating 256-bit encryption key...");
14218
- const key = crypto11.randomBytes(32);
14588
+ const key = crypto12.randomBytes(32);
14219
14589
  await setMasterKey(key);
14220
14590
  log("Encryption key generated and stored securely.");
14221
14591
  }
@@ -14367,19 +14737,19 @@ async function runSetupWizard(opts = {}) {
14367
14737
  await saveConfig(config);
14368
14738
  log("");
14369
14739
  try {
14370
- const claudeJsonPath = path32.join(os15.homedir(), ".claude.json");
14740
+ const claudeJsonPath = path33.join(os16.homedir(), ".claude.json");
14371
14741
  let claudeJson = {};
14372
14742
  try {
14373
- claudeJson = JSON.parse(readFileSync22(claudeJsonPath, "utf8"));
14743
+ claudeJson = JSON.parse(readFileSync23(claudeJsonPath, "utf8"));
14374
14744
  } catch {
14375
14745
  }
14376
14746
  if (!claudeJson.projects) claudeJson.projects = {};
14377
14747
  const projects = claudeJson.projects;
14378
- for (const dir of [process.cwd(), os15.homedir()]) {
14748
+ for (const dir of [process.cwd(), os16.homedir()]) {
14379
14749
  if (!projects[dir]) projects[dir] = {};
14380
14750
  projects[dir].hasTrustDialogAccepted = true;
14381
14751
  }
14382
- writeFileSync18(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
14752
+ writeFileSync19(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
14383
14753
  } catch {
14384
14754
  }
14385
14755
  state.completedSteps.push(5);
@@ -14393,7 +14763,7 @@ async function runSetupWizard(opts = {}) {
14393
14763
  const prefs = { ...existingPrefs };
14394
14764
  log("=== Config Defaults ===");
14395
14765
  log("");
14396
- const ghosttyDetected = existsSync25(path32.join(os15.homedir(), ".config", "ghostty")) || existsSync25(path32.join(os15.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
14766
+ const ghosttyDetected = existsSync27(path33.join(os16.homedir(), ".config", "ghostty")) || existsSync27(path33.join(os16.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
14397
14767
  if (ghosttyDetected) {
14398
14768
  const ghosttyAnswer = await ask2(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
14399
14769
  prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
@@ -14440,7 +14810,7 @@ async function runSetupWizard(opts = {}) {
14440
14810
  let missingIdentities = [];
14441
14811
  for (const emp of roster) {
14442
14812
  const idPath = identityPath2(emp.name);
14443
- if (!existsSync25(idPath)) {
14813
+ if (!existsSync27(idPath)) {
14444
14814
  missingIdentities.push(emp.name);
14445
14815
  }
14446
14816
  }
@@ -14472,7 +14842,7 @@ async function runSetupWizard(opts = {}) {
14472
14842
  }
14473
14843
  missingIdentities = [];
14474
14844
  for (const emp of roster) {
14475
- if (!existsSync25(identityPath2(emp.name))) {
14845
+ if (!existsSync27(identityPath2(emp.name))) {
14476
14846
  missingIdentities.push(emp.name);
14477
14847
  }
14478
14848
  }
@@ -14537,9 +14907,9 @@ async function runSetupWizard(opts = {}) {
14537
14907
  const cooIdentityContent = getIdentityTemplate("coo");
14538
14908
  if (cooIdentityContent) {
14539
14909
  const cooIdPath = identityPath2(cooName);
14540
- mkdirSync18(path32.dirname(cooIdPath), { recursive: true });
14910
+ mkdirSync17(path33.dirname(cooIdPath), { recursive: true });
14541
14911
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
14542
- writeFileSync18(cooIdPath, replaced, "utf-8");
14912
+ writeFileSync19(cooIdPath, replaced, "utf-8");
14543
14913
  }
14544
14914
  registerBinSymlinks2(cooName);
14545
14915
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -14633,9 +15003,9 @@ async function runSetupWizard(opts = {}) {
14633
15003
  const ctoIdentityContent = getIdentityTemplate("cto");
14634
15004
  if (ctoIdentityContent) {
14635
15005
  const ctoIdPath = identityPath2(ctoName);
14636
- mkdirSync18(path32.dirname(ctoIdPath), { recursive: true });
15006
+ mkdirSync17(path33.dirname(ctoIdPath), { recursive: true });
14637
15007
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
14638
- writeFileSync18(ctoIdPath, replaced, "utf-8");
15008
+ writeFileSync19(ctoIdPath, replaced, "utf-8");
14639
15009
  }
14640
15010
  registerBinSymlinks2(ctoName);
14641
15011
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -14656,9 +15026,9 @@ async function runSetupWizard(opts = {}) {
14656
15026
  const cmoIdentityContent = getIdentityTemplate("cmo");
14657
15027
  if (cmoIdentityContent) {
14658
15028
  const cmoIdPath = identityPath2(cmoName);
14659
- mkdirSync18(path32.dirname(cmoIdPath), { recursive: true });
15029
+ mkdirSync17(path33.dirname(cmoIdPath), { recursive: true });
14660
15030
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
14661
- writeFileSync18(cmoIdPath, replaced, "utf-8");
15031
+ writeFileSync19(cmoIdPath, replaced, "utf-8");
14662
15032
  }
14663
15033
  registerBinSymlinks2(cmoName);
14664
15034
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -14680,7 +15050,7 @@ async function runSetupWizard(opts = {}) {
14680
15050
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
14681
15051
  }
14682
15052
  if (wrapResult.pathConfigured) {
14683
- const binDir = path32.join(os15.homedir(), ".exe-os", "bin");
15053
+ const binDir = path33.join(os16.homedir(), ".exe-os", "bin");
14684
15054
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
14685
15055
  pathJustConfigured = true;
14686
15056
  }
@@ -14723,7 +15093,7 @@ async function runSetupWizard(opts = {}) {
14723
15093
  const pkgRoot2 = findPackageRoot2();
14724
15094
  if (pkgRoot2) {
14725
15095
  try {
14726
- version = JSON.parse(readFileSync22(path32.join(pkgRoot2, "package.json"), "utf-8")).version;
15096
+ version = JSON.parse(readFileSync23(path33.join(pkgRoot2, "package.json"), "utf-8")).version;
14727
15097
  } catch {
14728
15098
  }
14729
15099
  }
@@ -14757,17 +15127,17 @@ var init_setup_wizard = __esm({
14757
15127
  init_config();
14758
15128
  init_keychain();
14759
15129
  init_model_downloader();
14760
- SETUP_STATE_PATH = path32.join(os15.homedir(), ".exe-os", "setup-state.json");
15130
+ SETUP_STATE_PATH = path33.join(os16.homedir(), ".exe-os", "setup-state.json");
14761
15131
  }
14762
15132
  });
14763
15133
 
14764
15134
  // src/lib/update-check.ts
14765
15135
  import { execSync as execSync11 } from "child_process";
14766
- import { readFileSync as readFileSync23 } from "fs";
14767
- import path33 from "path";
15136
+ import { readFileSync as readFileSync24 } from "fs";
15137
+ import path34 from "path";
14768
15138
  function getLocalVersion(packageRoot) {
14769
- const pkgPath = path33.join(packageRoot, "package.json");
14770
- const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
15139
+ const pkgPath = path34.join(packageRoot, "package.json");
15140
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
14771
15141
  return pkg.version;
14772
15142
  }
14773
15143
  function getRemoteVersion() {
@@ -19291,8 +19661,8 @@ var init_ErrorOverview = __esm({
19291
19661
  "use strict";
19292
19662
  init_Box();
19293
19663
  init_Text();
19294
- cleanupPath = (path45) => {
19295
- return path45?.replace(`file://${cwd()}/`, "");
19664
+ cleanupPath = (path46) => {
19665
+ return path46?.replace(`file://${cwd()}/`, "");
19296
19666
  };
19297
19667
  stackUtils = new StackUtils({
19298
19668
  cwd: cwd(),
@@ -21700,11 +22070,11 @@ function Footer() {
21700
22070
  } catch {
21701
22071
  }
21702
22072
  try {
21703
- const { existsSync: existsSync30 } = await import("fs");
22073
+ const { existsSync: existsSync32 } = await import("fs");
21704
22074
  const { join } = await import("path");
21705
22075
  const home = process.env.HOME ?? "";
21706
22076
  const pidPath = join(home, ".exe-os", "exed.pid");
21707
- setDaemon(existsSync30(pidPath) ? "running" : "stopped");
22077
+ setDaemon(existsSync32(pidPath) ? "running" : "stopped");
21708
22078
  } catch {
21709
22079
  setDaemon("unknown");
21710
22080
  }
@@ -23746,10 +24116,10 @@ var init_hooks = __esm({
23746
24116
  });
23747
24117
 
23748
24118
  // src/runtime/safety-checks.ts
23749
- import path34 from "path";
23750
- import os16 from "os";
24119
+ import path35 from "path";
24120
+ import os17 from "os";
23751
24121
  function checkPathSafety(filePath) {
23752
- const resolved = path34.resolve(filePath);
24122
+ const resolved = path35.resolve(filePath);
23753
24123
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
23754
24124
  const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
23755
24125
  if (matches) {
@@ -23759,7 +24129,7 @@ function checkPathSafety(filePath) {
23759
24129
  return { safe: true, bypassImmune: true };
23760
24130
  }
23761
24131
  function checkReadPathSafety(filePath) {
23762
- const resolved = path34.resolve(filePath);
24132
+ const resolved = path35.resolve(filePath);
23763
24133
  const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
23764
24134
  (p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
23765
24135
  );
@@ -23774,7 +24144,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
23774
24144
  var init_safety_checks = __esm({
23775
24145
  "src/runtime/safety-checks.ts"() {
23776
24146
  "use strict";
23777
- HOME = os16.homedir();
24147
+ HOME = os17.homedir();
23778
24148
  BYPASS_IMMUNE_PATTERNS = [
23779
24149
  {
23780
24150
  pattern: /\/\.git\/hooks\//,
@@ -23785,11 +24155,11 @@ var init_safety_checks = __esm({
23785
24155
  reason: "Git config can set hooks and command execution"
23786
24156
  },
23787
24157
  {
23788
- pattern: (p) => p.startsWith(path34.join(HOME, ".claude")),
24158
+ pattern: (p) => p.startsWith(path35.join(HOME, ".claude")),
23789
24159
  reason: "Claude configuration files are protected"
23790
24160
  },
23791
24161
  {
23792
- pattern: (p) => p.startsWith(path34.join(HOME, ".exe-os")),
24162
+ pattern: (p) => p.startsWith(path35.join(HOME, ".exe-os")),
23793
24163
  reason: "exe-os configuration files are protected"
23794
24164
  },
23795
24165
  {
@@ -23806,7 +24176,7 @@ var init_safety_checks = __esm({
23806
24176
  },
23807
24177
  {
23808
24178
  pattern: (p) => {
23809
- const name = path34.basename(p);
24179
+ const name = path35.basename(p);
23810
24180
  return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
23811
24181
  },
23812
24182
  reason: "Shell configuration files can execute arbitrary code on login"
@@ -23833,7 +24203,7 @@ __export(file_read_exports, {
23833
24203
  FileReadTool: () => FileReadTool
23834
24204
  });
23835
24205
  import fs3 from "fs/promises";
23836
- import path35 from "path";
24206
+ import path36 from "path";
23837
24207
  import { z } from "zod";
23838
24208
  function isBinary(buf) {
23839
24209
  for (let i = 0; i < buf.length; i++) {
@@ -23869,7 +24239,7 @@ var init_file_read = __esm({
23869
24239
  return { behavior: "allow" };
23870
24240
  },
23871
24241
  async call(input, context) {
23872
- const filePath = path35.isAbsolute(input.file_path) ? input.file_path : path35.resolve(context.cwd, input.file_path);
24242
+ const filePath = path36.isAbsolute(input.file_path) ? input.file_path : path36.resolve(context.cwd, input.file_path);
23873
24243
  let stat2;
23874
24244
  try {
23875
24245
  stat2 = await fs3.stat(filePath);
@@ -23909,7 +24279,7 @@ __export(glob_exports, {
23909
24279
  GlobTool: () => GlobTool
23910
24280
  });
23911
24281
  import fs4 from "fs/promises";
23912
- import path36 from "path";
24282
+ import path37 from "path";
23913
24283
  import { z as z2 } from "zod";
23914
24284
  async function walkDir(dir, maxDepth = 10) {
23915
24285
  const results = [];
@@ -23925,7 +24295,7 @@ async function walkDir(dir, maxDepth = 10) {
23925
24295
  if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
23926
24296
  continue;
23927
24297
  }
23928
- const fullPath = path36.join(current, entry.name);
24298
+ const fullPath = path37.join(current, entry.name);
23929
24299
  if (entry.isDirectory()) {
23930
24300
  await walk(fullPath, depth + 1);
23931
24301
  } else {
@@ -23959,11 +24329,11 @@ var init_glob = __esm({
23959
24329
  inputSchema: inputSchema2,
23960
24330
  isReadOnly: true,
23961
24331
  async call(input, context) {
23962
- const baseDir = input.path ? path36.isAbsolute(input.path) ? input.path : path36.resolve(context.cwd, input.path) : context.cwd;
24332
+ const baseDir = input.path ? path37.isAbsolute(input.path) ? input.path : path37.resolve(context.cwd, input.path) : context.cwd;
23963
24333
  try {
23964
24334
  const entries = await walkDir(baseDir);
23965
24335
  const matched = entries.filter(
23966
- (e) => simpleGlobMatch(path36.relative(baseDir, e.path), input.pattern)
24336
+ (e) => simpleGlobMatch(path37.relative(baseDir, e.path), input.pattern)
23967
24337
  );
23968
24338
  matched.sort((a, b) => b.mtime - a.mtime);
23969
24339
  if (matched.length === 0) {
@@ -23989,7 +24359,7 @@ __export(grep_exports, {
23989
24359
  });
23990
24360
  import { spawn as spawn2 } from "child_process";
23991
24361
  import fs5 from "fs/promises";
23992
- import path37 from "path";
24362
+ import path38 from "path";
23993
24363
  import { z as z3 } from "zod";
23994
24364
  function runRipgrep(input, searchPath, context) {
23995
24365
  return new Promise((resolve, reject) => {
@@ -24043,7 +24413,7 @@ async function nodeGrep(input, searchPath) {
24043
24413
  }
24044
24414
  for (const entry of entries) {
24045
24415
  if (entry.name === "node_modules" || entry.name === ".git") continue;
24046
- const fullPath = path37.join(dir, entry.name);
24416
+ const fullPath = path38.join(dir, entry.name);
24047
24417
  if (entry.isDirectory()) {
24048
24418
  await walk(fullPath);
24049
24419
  } else {
@@ -24089,7 +24459,7 @@ var init_grep = __esm({
24089
24459
  inputSchema: inputSchema3,
24090
24460
  isReadOnly: true,
24091
24461
  async call(input, context) {
24092
- const searchPath = input.path ? path37.isAbsolute(input.path) ? input.path : path37.resolve(context.cwd, input.path) : context.cwd;
24462
+ const searchPath = input.path ? path38.isAbsolute(input.path) ? input.path : path38.resolve(context.cwd, input.path) : context.cwd;
24093
24463
  try {
24094
24464
  const result = await runRipgrep(input, searchPath, context);
24095
24465
  return result;
@@ -24114,7 +24484,7 @@ __export(file_write_exports, {
24114
24484
  FileWriteTool: () => FileWriteTool
24115
24485
  });
24116
24486
  import fs6 from "fs/promises";
24117
- import path38 from "path";
24487
+ import path39 from "path";
24118
24488
  import { z as z4 } from "zod";
24119
24489
  var inputSchema4, FileWriteTool;
24120
24490
  var init_file_write = __esm({
@@ -24142,8 +24512,8 @@ var init_file_write = __esm({
24142
24512
  return { behavior: "allow" };
24143
24513
  },
24144
24514
  async call(input, context) {
24145
- const filePath = path38.isAbsolute(input.file_path) ? input.file_path : path38.resolve(context.cwd, input.file_path);
24146
- const dir = path38.dirname(filePath);
24515
+ const filePath = path39.isAbsolute(input.file_path) ? input.file_path : path39.resolve(context.cwd, input.file_path);
24516
+ const dir = path39.dirname(filePath);
24147
24517
  await fs6.mkdir(dir, { recursive: true });
24148
24518
  await fs6.writeFile(filePath, input.content, "utf-8");
24149
24519
  return {
@@ -24161,7 +24531,7 @@ __export(file_edit_exports, {
24161
24531
  FileEditTool: () => FileEditTool
24162
24532
  });
24163
24533
  import fs7 from "fs/promises";
24164
- import path39 from "path";
24534
+ import path40 from "path";
24165
24535
  import { z as z5 } from "zod";
24166
24536
  function countOccurrences(haystack, needle) {
24167
24537
  let count = 0;
@@ -24202,7 +24572,7 @@ var init_file_edit = __esm({
24202
24572
  return { behavior: "allow" };
24203
24573
  },
24204
24574
  async call(input, context) {
24205
- const filePath = path39.isAbsolute(input.file_path) ? input.file_path : path39.resolve(context.cwd, input.file_path);
24575
+ const filePath = path40.isAbsolute(input.file_path) ? input.file_path : path40.resolve(context.cwd, input.file_path);
24206
24576
  let content;
24207
24577
  try {
24208
24578
  content = await fs7.readFile(filePath, "utf-8");
@@ -24444,7 +24814,7 @@ var init_bash = __esm({
24444
24814
  // src/tui/views/CommandCenter.tsx
24445
24815
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
24446
24816
  import TextInput from "ink-text-input";
24447
- import path40 from "path";
24817
+ import path41 from "path";
24448
24818
  import { homedir as homedir6 } from "os";
24449
24819
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
24450
24820
  function CommandCenterView({
@@ -24479,15 +24849,15 @@ function CommandCenterView({
24479
24849
  const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
24480
24850
  const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
24481
24851
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
24482
- const { readFileSync: readFileSync27, existsSync: existsSync30 } = await import("fs");
24852
+ const { readFileSync: readFileSync28, existsSync: existsSync32 } = await import("fs");
24483
24853
  const { join } = await import("path");
24484
24854
  const { homedir: homedir8 } = await import("os");
24485
24855
  const configPath = join(homedir8(), ".exe-os", "config.json");
24486
24856
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
24487
24857
  let providerConfigs = {};
24488
- if (existsSync30(configPath)) {
24858
+ if (existsSync32(configPath)) {
24489
24859
  try {
24490
- const raw = JSON.parse(readFileSync27(configPath, "utf8"));
24860
+ const raw = JSON.parse(readFileSync28(configPath, "utf8"));
24491
24861
  if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
24492
24862
  if (raw.providers && typeof raw.providers === "object") {
24493
24863
  providerConfigs = raw.providers;
@@ -24548,7 +24918,7 @@ function CommandCenterView({
24548
24918
  const markerDir = join(homedir8(), ".exe-os", "session-cache");
24549
24919
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
24550
24920
  for (const f of agentFiles) {
24551
- const data = JSON.parse(readFileSync27(join(markerDir, f), "utf8"));
24921
+ const data = JSON.parse(readFileSync28(join(markerDir, f), "utf8"));
24552
24922
  if (data.agentRole) {
24553
24923
  agentRole = data.agentRole;
24554
24924
  break;
@@ -24693,7 +25063,7 @@ function CommandCenterView({
24693
25063
  const demoEntries = DEMO_PROJECTS.map((p) => ({
24694
25064
  projectName: p.projectName,
24695
25065
  exeSession: p.exeSession,
24696
- projectDir: path40.join(homedir6(), p.projectName),
25066
+ projectDir: path41.join(homedir6(), p.projectName),
24697
25067
  employeeCount: p.employees.length,
24698
25068
  activeCount: p.employees.filter((e) => e.status === "active").length,
24699
25069
  memoryCount: p.employees.length * 4e3,
@@ -24731,7 +25101,7 @@ function CommandCenterView({
24731
25101
  const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
24732
25102
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
24733
25103
  const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
24734
- const { existsSync: existsSync30 } = await import("fs");
25104
+ const { existsSync: existsSync32 } = await import("fs");
24735
25105
  const { join } = await import("path");
24736
25106
  const client = getClient2();
24737
25107
  if (!client) {
@@ -24802,7 +25172,7 @@ function CommandCenterView({
24802
25172
  }
24803
25173
  const memoryCount = memoryCounts.get(name) ?? 0;
24804
25174
  const openTaskCount = openTaskCounts.get(name) ?? 0;
24805
- const hasGit = projectDir ? existsSync30(join(projectDir, ".git")) : false;
25175
+ const hasGit = projectDir ? existsSync32(join(projectDir, ".git")) : false;
24806
25176
  const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
24807
25177
  projectList.push({
24808
25178
  projectName: name,
@@ -24827,7 +25197,7 @@ function CommandCenterView({
24827
25197
  setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
24828
25198
  try {
24829
25199
  const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
24830
- setHealth((h) => ({ ...h, daemon: existsSync30(pidPath) ? "running" : "stopped" }));
25200
+ setHealth((h) => ({ ...h, daemon: existsSync32(pidPath) ? "running" : "stopped" }));
24831
25201
  } catch {
24832
25202
  }
24833
25203
  const activityResult = await client.execute(
@@ -25697,7 +26067,7 @@ var init_useOrchestrator = __esm({
25697
26067
 
25698
26068
  // src/tui/views/Sessions.tsx
25699
26069
  import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
25700
- import path41 from "path";
26070
+ import path42 from "path";
25701
26071
  import { homedir as homedir7 } from "os";
25702
26072
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
25703
26073
  function isCoordinatorEntry(entry) {
@@ -25735,7 +26105,7 @@ function SessionsView({
25735
26105
  if (demo) {
25736
26106
  setProjects(DEMO_PROJECTS.map((p) => ({
25737
26107
  ...p,
25738
- projectDir: path41.join(homedir7(), p.projectName),
26108
+ projectDir: path42.join(homedir7(), p.projectName),
25739
26109
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
25740
26110
  })));
25741
26111
  return;
@@ -26145,6 +26515,133 @@ var init_Sessions = __esm({
26145
26515
  }
26146
26516
  });
26147
26517
 
26518
+ // src/lib/tui-data.ts
26519
+ var tui_data_exports = {};
26520
+ __export(tui_data_exports, {
26521
+ loadMemoryDashboard: () => loadMemoryDashboard,
26522
+ loadTaskList: () => loadTaskList,
26523
+ loadTeamMetrics: () => loadTeamMetrics,
26524
+ searchWikiMemoryRows: () => searchWikiMemoryRows
26525
+ });
26526
+ async function loadMemoryDashboard(limit) {
26527
+ const client = getClient();
26528
+ const [countResult, recentResult, agentResult] = await Promise.all([
26529
+ client.execute("SELECT COUNT(*) as cnt FROM memories"),
26530
+ client.execute({
26531
+ sql: "SELECT agent_id, tool_name, project_name, raw_text, timestamp FROM memories ORDER BY timestamp DESC LIMIT ?",
26532
+ args: [limit]
26533
+ }),
26534
+ client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id ORDER BY cnt DESC")
26535
+ ]);
26536
+ return {
26537
+ total: Number(countResult.rows[0]?.cnt ?? 0),
26538
+ recent: recentResult.rows.map((row) => ({
26539
+ agentId: String(row.agent_id ?? "unknown"),
26540
+ toolName: String(row.tool_name ?? ""),
26541
+ projectName: String(row.project_name ?? ""),
26542
+ rawText: String(row.raw_text ?? ""),
26543
+ timestamp: String(row.timestamp ?? "")
26544
+ })),
26545
+ byAgent: agentResult.rows.map((row) => ({
26546
+ agentId: String(row.agent_id ?? "unknown"),
26547
+ count: Number(row.cnt ?? 0)
26548
+ }))
26549
+ };
26550
+ }
26551
+ async function loadTeamMetrics(employeeNames) {
26552
+ const client = getClient();
26553
+ const memoryCounts = /* @__PURE__ */ new Map();
26554
+ const projectsByEmployee = /* @__PURE__ */ new Map();
26555
+ const currentTaskByEmployee = /* @__PURE__ */ new Map();
26556
+ const scope = sessionScopeFilter();
26557
+ const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
26558
+ for (const row of memResult.rows) {
26559
+ memoryCounts.set(String(row.agent_id), Number(row.cnt));
26560
+ }
26561
+ for (const employeeName of employeeNames) {
26562
+ const [projectResult, taskResult] = await Promise.all([
26563
+ client.execute({
26564
+ sql: `SELECT DISTINCT project_name,
26565
+ MAX(CASE WHEN status = 'in_progress' THEN 1 WHEN status = 'open' THEN 2 ELSE 3 END) as urgency
26566
+ FROM tasks
26567
+ WHERE assigned_to = ? AND status IN ('open','in_progress','done')${scope.sql}
26568
+ GROUP BY project_name
26569
+ ORDER BY urgency ASC
26570
+ LIMIT 5`,
26571
+ args: [employeeName, ...scope.args]
26572
+ }),
26573
+ client.execute({
26574
+ sql: `SELECT title FROM tasks
26575
+ WHERE assigned_to = ? AND status = 'in_progress'${scope.sql}
26576
+ ORDER BY updated_at DESC
26577
+ LIMIT 1`,
26578
+ args: [employeeName, ...scope.args]
26579
+ })
26580
+ ]);
26581
+ const projects = projectResult.rows.map((row) => {
26582
+ const urgency = Number(row.urgency);
26583
+ return {
26584
+ name: String(row.project_name),
26585
+ status: urgency === 1 ? "active" : urgency === 2 ? "has_tasks" : "idle"
26586
+ };
26587
+ });
26588
+ if (projects.length > 0) projectsByEmployee.set(employeeName, projects);
26589
+ if (taskResult.rows.length > 0) {
26590
+ currentTaskByEmployee.set(employeeName, String(taskResult.rows[0].title));
26591
+ }
26592
+ }
26593
+ return { memoryCounts, projectsByEmployee, currentTaskByEmployee };
26594
+ }
26595
+ async function loadTaskList() {
26596
+ const client = getClient();
26597
+ const scope = sessionScopeFilter();
26598
+ const result = await client.execute({
26599
+ sql: `SELECT id, title, priority, assigned_to, assigned_by, status, project_name, created_at, result
26600
+ FROM tasks
26601
+ WHERE 1=1${scope.sql}
26602
+ ORDER BY
26603
+ CASE status WHEN 'in_progress' THEN 0 WHEN 'open' THEN 1 WHEN 'blocked' THEN 2 WHEN 'needs_review' THEN 3 WHEN 'done' THEN 4 ELSE 5 END,
26604
+ CASE priority WHEN 'p0' THEN 0 WHEN 'p1' THEN 1 WHEN 'p2' THEN 2 ELSE 3 END,
26605
+ created_at DESC`,
26606
+ args: [...scope.args]
26607
+ });
26608
+ return result.rows.map((row) => ({
26609
+ id: String(row.id ?? ""),
26610
+ title: String(row.title ?? ""),
26611
+ priority: String(row.priority ?? "p2").toUpperCase(),
26612
+ assignedTo: String(row.assigned_to ?? ""),
26613
+ assignedBy: String(row.assigned_by ?? ""),
26614
+ status: String(row.status ?? "open"),
26615
+ projectName: String(row.project_name ?? ""),
26616
+ createdAt: String(row.created_at ?? ""),
26617
+ result: String(row.result ?? "")
26618
+ }));
26619
+ }
26620
+ async function searchWikiMemoryRows(query) {
26621
+ const client = getClient();
26622
+ const result = await client.execute({
26623
+ sql: `SELECT id, agent_id, raw_text, timestamp, project_name
26624
+ FROM memories
26625
+ WHERE raw_text LIKE ? AND COALESCE(status, 'active') = 'active'
26626
+ ORDER BY timestamp DESC LIMIT 20`,
26627
+ args: [`%${query}%`]
26628
+ });
26629
+ return result.rows.map((row) => ({
26630
+ id: String(row.id),
26631
+ agentId: String(row.agent_id),
26632
+ rawText: String(row.raw_text),
26633
+ timestamp: String(row.timestamp),
26634
+ projectName: String(row.project_name ?? "")
26635
+ }));
26636
+ }
26637
+ var init_tui_data = __esm({
26638
+ "src/lib/tui-data.ts"() {
26639
+ "use strict";
26640
+ init_database();
26641
+ init_task_scope();
26642
+ }
26643
+ });
26644
+
26148
26645
  // src/tui/views/Tasks.tsx
26149
26646
  import React20, { useState as useState10, useEffect as useEffect12, useMemo as useMemo5 } from "react";
26150
26647
  import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
@@ -26264,37 +26761,22 @@ function TasksView({ onBack }) {
26264
26761
  const { withTrace: withTrace2 } = await Promise.resolve().then(() => (init_telemetry(), telemetry_exports));
26265
26762
  return withTrace2("tui.tasks.loadTasks", async () => {
26266
26763
  try {
26267
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
26268
- const client = getClient2();
26269
- if (client) {
26270
- const tScope = sessionScopeFilter();
26271
- const result = await client.execute({
26272
- sql: `SELECT id, title, priority, assigned_to, assigned_by, status, project_name, created_at, result
26273
- FROM tasks
26274
- WHERE 1=1${tScope.sql}
26275
- ORDER BY
26276
- CASE status WHEN 'in_progress' THEN 0 WHEN 'open' THEN 1 WHEN 'blocked' THEN 2 WHEN 'needs_review' THEN 3 WHEN 'done' THEN 4 ELSE 5 END,
26277
- CASE priority WHEN 'p0' THEN 0 WHEN 'p1' THEN 1 WHEN 'p2' THEN 2 ELSE 3 END,
26278
- created_at DESC`,
26279
- args: [...tScope.args]
26280
- });
26281
- setAllTasks(
26282
- result.rows.map((r) => ({
26283
- id: String(r.id ?? ""),
26284
- priority: String(r.priority ?? "p2").toUpperCase(),
26285
- title: String(r.title ?? ""),
26286
- assignee: String(r.assigned_to ?? ""),
26287
- assignedBy: String(r.assigned_by ?? ""),
26288
- status: String(r.status ?? "open"),
26289
- project: String(r.project_name ?? ""),
26290
- createdAt: String(r.created_at ?? ""),
26291
- result: String(r.result ?? "")
26292
- }))
26293
- );
26294
- setDbError(null);
26295
- } else {
26296
- setDbError("Database client not initialized. Run exe-os setup.");
26297
- }
26764
+ const { loadTaskList: loadTaskList2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
26765
+ const tasks = await loadTaskList2();
26766
+ setAllTasks(
26767
+ tasks.map((task) => ({
26768
+ id: task.id,
26769
+ priority: task.priority,
26770
+ title: task.title,
26771
+ assignee: task.assignedTo,
26772
+ assignedBy: task.assignedBy,
26773
+ status: task.status,
26774
+ project: task.projectName,
26775
+ createdAt: task.createdAt,
26776
+ result: task.result
26777
+ }))
26778
+ );
26779
+ setDbError(null);
26298
26780
  } catch (err) {
26299
26781
  setDbError(err instanceof Error ? err.message : "Unknown error");
26300
26782
  } finally {
@@ -26423,7 +26905,6 @@ var init_Tasks = __esm({
26423
26905
  await init_ink2();
26424
26906
  init_DemoContext();
26425
26907
  init_demo_data();
26426
- init_task_scope();
26427
26908
  STATUS_FILTERS = ["all", "open", "in_progress", "done", "blocked", "needs_review"];
26428
26909
  PRIORITY_COLORS = {
26429
26910
  P0: "red",
@@ -26839,12 +27320,12 @@ async function loadGatewayConfig() {
26839
27320
  state.running = false;
26840
27321
  }
26841
27322
  try {
26842
- const { existsSync: existsSync30, readFileSync: readFileSync27 } = await import("fs");
27323
+ const { existsSync: existsSync32, readFileSync: readFileSync28 } = await import("fs");
26843
27324
  const { join } = await import("path");
26844
27325
  const home = process.env.HOME ?? "";
26845
27326
  const configPath = join(home, ".exe-os", "gateway.json");
26846
- if (existsSync30(configPath)) {
26847
- const raw = JSON.parse(readFileSync27(configPath, "utf8"));
27327
+ if (existsSync32(configPath)) {
27328
+ const raw = JSON.parse(readFileSync28(configPath, "utf8"));
26848
27329
  state.port = raw.port ?? 3100;
26849
27330
  state.gatewayUrl = raw.gatewayUrl ?? "";
26850
27331
  if (raw.adapters) {
@@ -27414,41 +27895,16 @@ function TeamView({ onBack, onViewSessions }) {
27414
27895
  let projectsByEmployee = /* @__PURE__ */ new Map();
27415
27896
  let currentTaskByEmployee = /* @__PURE__ */ new Map();
27416
27897
  try {
27417
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
27418
- const client = getClient2();
27419
- if (client) {
27420
- const memResult = await client.execute("SELECT agent_id, COUNT(*) as cnt FROM memories GROUP BY agent_id");
27421
- for (const row of memResult.rows) {
27422
- memoryCounts.set(String(row.agent_id), Number(row.cnt));
27423
- }
27424
- const tmScope = sessionScopeFilter();
27425
- for (const emp of roster) {
27426
- const projResult = await client.execute({
27427
- sql: `SELECT DISTINCT project_name,
27428
- MAX(CASE WHEN status = 'in_progress' THEN 1 WHEN status = 'open' THEN 2 ELSE 3 END) as urgency
27429
- FROM tasks WHERE assigned_to = ? AND status IN ('open','in_progress','done')${tmScope.sql}
27430
- GROUP BY project_name ORDER BY urgency ASC LIMIT 5`,
27431
- args: [emp.name, ...tmScope.args]
27432
- });
27433
- const projects = projResult.rows.filter((r) => !DEPRECATED_PROJECTS.has(String(r.project_name))).map((r) => {
27434
- const urgency = Number(r.urgency);
27435
- let pStatus = "idle";
27436
- if (urgency === 1) pStatus = "active";
27437
- else if (urgency === 2) pStatus = "has_tasks";
27438
- return { name: String(r.project_name), status: pStatus };
27439
- });
27440
- if (projects.length > 0) projectsByEmployee.set(emp.name, projects);
27441
- }
27442
- for (const emp of roster) {
27443
- const taskResult = await client.execute({
27444
- sql: `SELECT title FROM tasks WHERE assigned_to = ? AND status = 'in_progress'${tmScope.sql} ORDER BY updated_at DESC LIMIT 1`,
27445
- args: [emp.name, ...tmScope.args]
27446
- });
27447
- if (taskResult.rows.length > 0) {
27448
- currentTaskByEmployee.set(emp.name, String(taskResult.rows[0].title));
27449
- }
27450
- }
27451
- }
27898
+ const { loadTeamMetrics: loadTeamMetrics2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
27899
+ const teamMetrics = await loadTeamMetrics2(roster.map((emp) => emp.name));
27900
+ memoryCounts = teamMetrics.memoryCounts;
27901
+ projectsByEmployee = new Map(
27902
+ Array.from(teamMetrics.projectsByEmployee.entries()).map(([name, projects]) => [
27903
+ name,
27904
+ projects.filter((project) => !DEPRECATED_PROJECTS.has(project.name))
27905
+ ])
27906
+ );
27907
+ currentTaskByEmployee = teamMetrics.currentTaskByEmployee;
27452
27908
  } catch {
27453
27909
  }
27454
27910
  const teamData = roster.map((emp) => {
@@ -27467,12 +27923,12 @@ function TeamView({ onBack, onViewSessions }) {
27467
27923
  setMembers(teamData);
27468
27924
  setDbError(null);
27469
27925
  try {
27470
- const { existsSync: existsSync30, readFileSync: readFileSync27 } = await import("fs");
27926
+ const { existsSync: existsSync32, readFileSync: readFileSync28 } = await import("fs");
27471
27927
  const { join } = await import("path");
27472
27928
  const home = process.env.HOME ?? "";
27473
27929
  const gatewayConfig = join(home, ".exe-os", "gateway.json");
27474
- if (existsSync30(gatewayConfig)) {
27475
- const raw = JSON.parse(readFileSync27(gatewayConfig, "utf8"));
27930
+ if (existsSync32(gatewayConfig)) {
27931
+ const raw = JSON.parse(readFileSync28(gatewayConfig, "utf8"));
27476
27932
  if (raw.agents && raw.agents.length > 0) {
27477
27933
  setExternals(raw.agents.map((a) => ({
27478
27934
  name: a.name,
@@ -27639,7 +28095,6 @@ var init_Team = __esm({
27639
28095
  init_demo_data();
27640
28096
  init_useOrchestrator();
27641
28097
  init_agent_status();
27642
- init_task_scope();
27643
28098
  DEPRECATED_PROJECTS = /* @__PURE__ */ new Set(["exe-ai-employees"]);
27644
28099
  }
27645
28100
  });
@@ -27653,8 +28108,8 @@ __export(wiki_client_exports, {
27653
28108
  listDocuments: () => listDocuments,
27654
28109
  listWorkspaces: () => listWorkspaces
27655
28110
  });
27656
- async function wikiFetch(config, path45, method = "GET", body) {
27657
- const url = `${config.baseUrl}/api/v1${path45}`;
28111
+ async function wikiFetch(config, path46, method = "GET", body) {
28112
+ const url = `${config.baseUrl}/api/v1${path46}`;
27658
28113
  const headers = {
27659
28114
  Authorization: `Bearer ${config.apiKey}`,
27660
28115
  "Content-Type": "application/json"
@@ -27687,7 +28142,7 @@ async function wikiFetch(config, path45, method = "GET", body) {
27687
28142
  }
27688
28143
  }
27689
28144
  if (!response.ok) {
27690
- throw new Error(`Wiki API ${method} ${path45}: ${response.status} ${response.statusText}`);
28145
+ throw new Error(`Wiki API ${method} ${path46}: ${response.status} ${response.statusText}`);
27691
28146
  }
27692
28147
  return response.json();
27693
28148
  } finally {
@@ -27933,24 +28388,8 @@ function WikiView({ onBack }) {
27933
28388
  }
27934
28389
  setSearchLoading(true);
27935
28390
  try {
27936
- const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
27937
- const client = getClient2();
27938
- const result = await client.execute({
27939
- sql: `SELECT id, agent_id, raw_text, timestamp, project_name
27940
- FROM memories
27941
- WHERE raw_text LIKE ? AND COALESCE(status, 'active') = 'active'
27942
- ORDER BY timestamp DESC LIMIT 20`,
27943
- args: [`%${query}%`]
27944
- });
27945
- setSearchResults(
27946
- result.rows.map((r) => ({
27947
- id: String(r.id),
27948
- agentId: String(r.agent_id),
27949
- rawText: String(r.raw_text),
27950
- timestamp: String(r.timestamp),
27951
- projectName: String(r.project_name ?? "")
27952
- }))
27953
- );
28391
+ const { searchWikiMemoryRows: searchWikiMemoryRows2 } = await Promise.resolve().then(() => (init_tui_data(), tui_data_exports));
28392
+ setSearchResults(await searchWikiMemoryRows2(query));
27954
28393
  } catch {
27955
28394
  setSearchResults([]);
27956
28395
  } finally {
@@ -28297,12 +28736,12 @@ function SettingsView({ onBack }) {
28297
28736
  }
28298
28737
  setProviders(providerList);
28299
28738
  try {
28300
- const { existsSync: existsSync30 } = await import("fs");
28739
+ const { existsSync: existsSync32 } = await import("fs");
28301
28740
  const { join } = await import("path");
28302
28741
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
28303
28742
  const cfg = await loadConfig2();
28304
28743
  const home = process.env.HOME ?? "";
28305
- const hasKey = existsSync30(join(home, ".exe-os", "master.key"));
28744
+ const hasKey = existsSync32(join(home, ".exe-os", "master.key"));
28306
28745
  if (cfg.cloud) {
28307
28746
  setCloud({
28308
28747
  configured: true,
@@ -28315,22 +28754,22 @@ function SettingsView({ onBack }) {
28315
28754
  const pidPath = join(home, ".exe-os", "exed.pid");
28316
28755
  let daemon = "unknown";
28317
28756
  try {
28318
- daemon = existsSync30(pidPath) ? "running" : "stopped";
28757
+ daemon = existsSync32(pidPath) ? "running" : "stopped";
28319
28758
  } catch {
28320
28759
  }
28321
28760
  let version = "unknown";
28322
28761
  try {
28323
- const { readFileSync: readFileSync27 } = await import("fs");
28324
- const { createRequire: createRequire2 } = await import("module");
28325
- const require2 = createRequire2(import.meta.url);
28762
+ const { readFileSync: readFileSync28 } = await import("fs");
28763
+ const { createRequire: createRequire3 } = await import("module");
28764
+ const require2 = createRequire3(import.meta.url);
28326
28765
  const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
28327
- const pkg = JSON.parse(readFileSync27(pkgPath, "utf8"));
28766
+ const pkg = JSON.parse(readFileSync28(pkgPath, "utf8"));
28328
28767
  version = pkg.version;
28329
28768
  } catch {
28330
28769
  try {
28331
- const { readFileSync: readFileSync27 } = await import("fs");
28770
+ const { readFileSync: readFileSync28 } = await import("fs");
28332
28771
  const { join: joinPath } = await import("path");
28333
- const pkg = JSON.parse(readFileSync27(joinPath(process.cwd(), "package.json"), "utf8"));
28772
+ const pkg = JSON.parse(readFileSync28(joinPath(process.cwd(), "package.json"), "utf8"));
28334
28773
  version = pkg.version;
28335
28774
  } catch {
28336
28775
  }
@@ -29131,15 +29570,15 @@ __export(installer_exports2, {
29131
29570
  verifyOpenCodeHooks: () => verifyOpenCodeHooks
29132
29571
  });
29133
29572
  import { readFile as readFile6, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
29134
- import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
29135
- import path42 from "path";
29136
- import os17 from "os";
29137
- async function registerOpenCodeMcp(packageRoot, homeDir = os17.homedir()) {
29138
- const configDir = path42.join(homeDir, ".config", "opencode");
29139
- const configPath = path42.join(configDir, "opencode.json");
29573
+ import { existsSync as existsSync29, readFileSync as readFileSync26 } from "fs";
29574
+ import path43 from "path";
29575
+ import os18 from "os";
29576
+ async function registerOpenCodeMcp(packageRoot, homeDir = os18.homedir()) {
29577
+ const configDir = path43.join(homeDir, ".config", "opencode");
29578
+ const configPath = path43.join(configDir, "opencode.json");
29140
29579
  await mkdir7(configDir, { recursive: true });
29141
29580
  let config = {};
29142
- if (existsSync27(configPath)) {
29581
+ if (existsSync29(configPath)) {
29143
29582
  try {
29144
29583
  config = JSON.parse(await readFile6(configPath, "utf-8"));
29145
29584
  } catch {
@@ -29151,7 +29590,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os17.homedir()) {
29151
29590
  }
29152
29591
  const newEntry = {
29153
29592
  type: "local",
29154
- command: ["node", path42.join(packageRoot, "dist", "mcp", "server.js")],
29593
+ command: ["node", path43.join(packageRoot, "dist", "mcp", "server.js")],
29155
29594
  enabled: true
29156
29595
  };
29157
29596
  const current = config.mcp["exe-os"];
@@ -29165,15 +29604,15 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os17.homedir()) {
29165
29604
  await writeFile7(configPath, JSON.stringify(config, null, 2) + "\n");
29166
29605
  return true;
29167
29606
  }
29168
- async function installOpenCodePlugin(packageRoot, homeDir = os17.homedir()) {
29169
- const pluginDir = path42.join(homeDir, ".config", "opencode", "plugins");
29170
- const pluginPath = path42.join(pluginDir, "exe-os.mjs");
29607
+ async function installOpenCodePlugin(packageRoot, homeDir = os18.homedir()) {
29608
+ const pluginDir = path43.join(homeDir, ".config", "opencode", "plugins");
29609
+ const pluginPath = path43.join(pluginDir, "exe-os.mjs");
29171
29610
  await mkdir7(pluginDir, { recursive: true });
29172
29611
  const pluginContent = PLUGIN_TEMPLATE.replace(
29173
29612
  /__PACKAGE_ROOT__/g,
29174
29613
  packageRoot.replace(/\\/g, "\\\\")
29175
29614
  );
29176
- if (existsSync27(pluginPath)) {
29615
+ if (existsSync29(pluginPath)) {
29177
29616
  const existing = await readFile6(pluginPath, "utf-8");
29178
29617
  if (existing === pluginContent) {
29179
29618
  return false;
@@ -29182,17 +29621,17 @@ async function installOpenCodePlugin(packageRoot, homeDir = os17.homedir()) {
29182
29621
  await writeFile7(pluginPath, pluginContent);
29183
29622
  return true;
29184
29623
  }
29185
- function verifyOpenCodeHooks(homeDir = os17.homedir()) {
29186
- const configPath = path42.join(homeDir, ".config", "opencode", "opencode.json");
29187
- const pluginPath = path42.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
29188
- if (!existsSync27(configPath)) return false;
29624
+ function verifyOpenCodeHooks(homeDir = os18.homedir()) {
29625
+ const configPath = path43.join(homeDir, ".config", "opencode", "opencode.json");
29626
+ const pluginPath = path43.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
29627
+ if (!existsSync29(configPath)) return false;
29189
29628
  try {
29190
- const config = JSON.parse(readFileSync25(configPath, "utf-8"));
29629
+ const config = JSON.parse(readFileSync26(configPath, "utf-8"));
29191
29630
  if (!config.mcp?.["exe-os"]?.enabled) return false;
29192
29631
  } catch {
29193
29632
  return false;
29194
29633
  }
29195
- if (!existsSync27(pluginPath)) return false;
29634
+ if (!existsSync29(pluginPath)) return false;
29196
29635
  return true;
29197
29636
  }
29198
29637
  async function runOpenCodeInstaller(homeDir) {
@@ -29225,19 +29664,19 @@ __export(installer_exports3, {
29225
29664
  verifyCodexHooks: () => verifyCodexHooks
29226
29665
  });
29227
29666
  import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
29228
- import { existsSync as existsSync28 } from "fs";
29229
- import path43 from "path";
29230
- import os18 from "os";
29231
- async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29232
- const codexDir = path43.join(homeDir, ".codex");
29233
- const hooksPath = path43.join(codexDir, "hooks.json");
29234
- const logsDir = path43.join(homeDir, ".exe-os", "logs");
29235
- const hookLogPath = path43.join(logsDir, "hooks.log");
29667
+ import { existsSync as existsSync30 } from "fs";
29668
+ import path44 from "path";
29669
+ import os19 from "os";
29670
+ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
29671
+ const codexDir = path44.join(homeDir, ".codex");
29672
+ const hooksPath = path44.join(codexDir, "hooks.json");
29673
+ const logsDir = path44.join(homeDir, ".exe-os", "logs");
29674
+ const hookLogPath = path44.join(logsDir, "hooks.log");
29236
29675
  const logSuffix = ` 2>> "${hookLogPath}"`;
29237
29676
  await mkdir8(codexDir, { recursive: true });
29238
29677
  await mkdir8(logsDir, { recursive: true });
29239
29678
  let hooksJson = {};
29240
- if (existsSync28(hooksPath)) {
29679
+ if (existsSync30(hooksPath)) {
29241
29680
  try {
29242
29681
  hooksJson = JSON.parse(await readFile7(hooksPath, "utf-8"));
29243
29682
  } catch {
@@ -29254,7 +29693,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29254
29693
  hooks: [
29255
29694
  {
29256
29695
  type: "command",
29257
- command: `node "${path43.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
29696
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
29258
29697
  timeout: 30,
29259
29698
  statusMessage: "exe-os: loading memory brief"
29260
29699
  }
@@ -29269,11 +29708,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29269
29708
  hooks: [
29270
29709
  {
29271
29710
  type: "command",
29272
- command: `node "${path43.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
29711
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
29273
29712
  },
29274
29713
  {
29275
29714
  type: "command",
29276
- command: `node "${path43.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
29715
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
29277
29716
  }
29278
29717
  ]
29279
29718
  },
@@ -29285,11 +29724,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29285
29724
  hooks: [
29286
29725
  {
29287
29726
  type: "command",
29288
- command: `node "${path43.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
29727
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
29289
29728
  },
29290
29729
  {
29291
29730
  type: "command",
29292
- command: `node "${path43.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
29731
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
29293
29732
  timeout: 5
29294
29733
  }
29295
29734
  ]
@@ -29302,7 +29741,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29302
29741
  hooks: [
29303
29742
  {
29304
29743
  type: "command",
29305
- command: `node "${path43.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
29744
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
29306
29745
  }
29307
29746
  ]
29308
29747
  },
@@ -29315,7 +29754,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29315
29754
  hooks: [
29316
29755
  {
29317
29756
  type: "command",
29318
- command: `node "${path43.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
29757
+ command: `node "${path44.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
29319
29758
  }
29320
29759
  ]
29321
29760
  },
@@ -29346,9 +29785,9 @@ async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
29346
29785
  await writeFile8(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
29347
29786
  return { added, skipped };
29348
29787
  }
29349
- function verifyCodexHooks(homeDir = os18.homedir()) {
29350
- const hooksPath = path43.join(homeDir, ".codex", "hooks.json");
29351
- if (!existsSync28(hooksPath)) return false;
29788
+ function verifyCodexHooks(homeDir = os19.homedir()) {
29789
+ const hooksPath = path44.join(homeDir, ".codex", "hooks.json");
29790
+ if (!existsSync30(hooksPath)) return false;
29352
29791
  try {
29353
29792
  const hooksJson = JSON.parse(
29354
29793
  __require("fs").readFileSync(hooksPath, "utf-8")
@@ -29368,14 +29807,14 @@ function verifyCodexHooks(homeDir = os18.homedir()) {
29368
29807
  return false;
29369
29808
  }
29370
29809
  }
29371
- async function installCodexStatusLine(homeDir = os18.homedir()) {
29810
+ async function installCodexStatusLine(homeDir = os19.homedir()) {
29372
29811
  const prefs = loadPreferences(homeDir);
29373
29812
  if (prefs.codexStatusLine === false) return "opted-out";
29374
- const codexDir = path43.join(homeDir, ".codex");
29375
- const configPath = path43.join(codexDir, "config.toml");
29813
+ const codexDir = path44.join(homeDir, ".codex");
29814
+ const configPath = path44.join(codexDir, "config.toml");
29376
29815
  await mkdir8(codexDir, { recursive: true });
29377
29816
  let content = "";
29378
- if (existsSync28(configPath)) {
29817
+ if (existsSync30(configPath)) {
29379
29818
  content = await readFile7(configPath, "utf-8");
29380
29819
  if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
29381
29820
  return "already-configured";
@@ -29423,14 +29862,14 @@ var init_installer3 = __esm({
29423
29862
  });
29424
29863
 
29425
29864
  // src/bin/cli.ts
29426
- import { existsSync as existsSync29, readFileSync as readFileSync26, writeFileSync as writeFileSync19, readdirSync as readdirSync9, rmSync } from "fs";
29427
- import path44 from "path";
29428
- import os19 from "os";
29865
+ import { existsSync as existsSync31, readFileSync as readFileSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync9, rmSync } from "fs";
29866
+ import path45 from "path";
29867
+ import os20 from "os";
29429
29868
  var args = process.argv.slice(2);
29430
29869
  if (args.includes("--version") || args.includes("-v")) {
29431
29870
  try {
29432
- const pkgPath = path44.join(path44.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
29433
- const pkg = JSON.parse(readFileSync26(pkgPath, "utf8"));
29871
+ const pkgPath = path45.join(path45.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
29872
+ const pkg = JSON.parse(readFileSync27(pkgPath, "utf8"));
29434
29873
  console.log(pkg.version);
29435
29874
  } catch {
29436
29875
  console.log("unknown");
@@ -29594,11 +30033,11 @@ ID: ${result.id}`);
29594
30033
  });
29595
30034
  await init_App2().then(() => App_exports);
29596
30035
  } else {
29597
- const claudeDir = path44.join(os19.homedir(), ".claude");
29598
- const settingsPath = path44.join(claudeDir, "settings.json");
29599
- const hasClaudeCode = existsSync29(settingsPath) && (() => {
30036
+ const claudeDir = path45.join(os20.homedir(), ".claude");
30037
+ const settingsPath = path45.join(claudeDir, "settings.json");
30038
+ const hasClaudeCode = existsSync31(settingsPath) && (() => {
29600
30039
  try {
29601
- const raw = readFileSync26(settingsPath, "utf8");
30040
+ const raw = readFileSync27(settingsPath, "utf8");
29602
30041
  return raw.includes("exe-os") || raw.includes("exe-mem");
29603
30042
  } catch {
29604
30043
  return false;
@@ -29608,9 +30047,9 @@ ID: ${result.id}`);
29608
30047
  const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
29609
30048
  let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
29610
30049
  try {
29611
- const rosterPath = path44.join(os19.homedir(), ".exe-os", "exe-employees.json");
29612
- if (existsSync29(rosterPath)) {
29613
- const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
30050
+ const rosterPath = path45.join(os20.homedir(), ".exe-os", "exe-employees.json");
30051
+ if (existsSync31(rosterPath)) {
30052
+ const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
29614
30053
  const coo = roster.find((e) => e.role === "COO");
29615
30054
  if (coo) cooName = coo.name;
29616
30055
  }
@@ -29674,14 +30113,14 @@ async function runCodexInstall() {
29674
30113
  }
29675
30114
  }
29676
30115
  async function runClaudeCheck() {
29677
- const claudeDir = path44.join(os19.homedir(), ".claude");
29678
- const settingsPath = path44.join(claudeDir, "settings.json");
29679
- const claudeJsonPath = path44.join(os19.homedir(), ".claude.json");
30116
+ const claudeDir = path45.join(os20.homedir(), ".claude");
30117
+ const settingsPath = path45.join(claudeDir, "settings.json");
30118
+ const claudeJsonPath = path45.join(os20.homedir(), ".claude.json");
29680
30119
  let ok = true;
29681
- if (existsSync29(settingsPath)) {
30120
+ if (existsSync31(settingsPath)) {
29682
30121
  let settings;
29683
30122
  try {
29684
- settings = JSON.parse(readFileSync26(settingsPath, "utf8"));
30123
+ settings = JSON.parse(readFileSync27(settingsPath, "utf8"));
29685
30124
  } catch {
29686
30125
  console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
29687
30126
  ok = false;
@@ -29707,10 +30146,10 @@ async function runClaudeCheck() {
29707
30146
  console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
29708
30147
  ok = false;
29709
30148
  }
29710
- if (existsSync29(claudeJsonPath)) {
30149
+ if (existsSync31(claudeJsonPath)) {
29711
30150
  let claudeJson;
29712
30151
  try {
29713
- claudeJson = JSON.parse(readFileSync26(claudeJsonPath, "utf8"));
30152
+ claudeJson = JSON.parse(readFileSync27(claudeJsonPath, "utf8"));
29714
30153
  } catch {
29715
30154
  console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
29716
30155
  ok = false;
@@ -29729,8 +30168,8 @@ async function runClaudeCheck() {
29729
30168
  console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
29730
30169
  ok = false;
29731
30170
  }
29732
- const skillsDir = path44.join(claudeDir, "skills");
29733
- if (existsSync29(skillsDir)) {
30171
+ const skillsDir = path45.join(claudeDir, "skills");
30172
+ if (existsSync31(skillsDir)) {
29734
30173
  console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
29735
30174
  } else {
29736
30175
  console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
@@ -29746,17 +30185,17 @@ async function runClaudeCheck() {
29746
30185
  async function runClaudeUninstall(flags = []) {
29747
30186
  const dryRun = flags.includes("--dry-run");
29748
30187
  const purge = flags.includes("--purge");
29749
- const homeDir = os19.homedir();
29750
- const claudeDir = path44.join(homeDir, ".claude");
29751
- const settingsPath = path44.join(claudeDir, "settings.json");
29752
- const claudeJsonPath = path44.join(homeDir, ".claude.json");
29753
- const exeOsDir = path44.join(homeDir, ".exe-os");
30188
+ const homeDir = os20.homedir();
30189
+ const claudeDir = path45.join(homeDir, ".claude");
30190
+ const settingsPath = path45.join(claudeDir, "settings.json");
30191
+ const claudeJsonPath = path45.join(homeDir, ".claude.json");
30192
+ const exeOsDir = path45.join(homeDir, ".exe-os");
29754
30193
  let removed = 0;
29755
30194
  const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
29756
30195
  let settings = {};
29757
- if (existsSync29(settingsPath)) {
30196
+ if (existsSync31(settingsPath)) {
29758
30197
  try {
29759
- settings = JSON.parse(readFileSync26(settingsPath, "utf8"));
30198
+ settings = JSON.parse(readFileSync27(settingsPath, "utf8"));
29760
30199
  } catch {
29761
30200
  console.error("Your ~/.claude/settings.json appears malformed.");
29762
30201
  if (purge) {
@@ -29794,15 +30233,15 @@ async function runClaudeUninstall(flags = []) {
29794
30233
  permCount = before - settings.permissions.allow.length;
29795
30234
  }
29796
30235
  if (!dryRun) {
29797
- writeFileSync19(settingsPath, JSON.stringify(settings, null, 2) + "\n");
30236
+ writeFileSync20(settingsPath, JSON.stringify(settings, null, 2) + "\n");
29798
30237
  }
29799
30238
  log("\u2713 Removed exe-os hooks from settings.json");
29800
30239
  if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
29801
30240
  removed++;
29802
30241
  }
29803
30242
  }
29804
- if (existsSync29(claudeJsonPath)) {
29805
- const raw = readFileSync26(claudeJsonPath, "utf8");
30243
+ if (existsSync31(claudeJsonPath)) {
30244
+ const raw = readFileSync27(claudeJsonPath, "utf8");
29806
30245
  if (raw.length > 1e6) {
29807
30246
  console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
29808
30247
  } else {
@@ -29823,7 +30262,7 @@ async function runClaudeUninstall(flags = []) {
29823
30262
  }
29824
30263
  if (removedMcp) {
29825
30264
  if (!dryRun) {
29826
- writeFileSync19(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
30265
+ writeFileSync20(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
29827
30266
  }
29828
30267
  log("\u2713 Removed exe-os MCP server from claude.json");
29829
30268
  removed++;
@@ -29831,14 +30270,14 @@ async function runClaudeUninstall(flags = []) {
29831
30270
  }
29832
30271
  }
29833
30272
  }
29834
- const skillsDir = path44.join(claudeDir, "skills");
29835
- if (existsSync29(skillsDir)) {
30273
+ const skillsDir = path45.join(claudeDir, "skills");
30274
+ if (existsSync31(skillsDir)) {
29836
30275
  let skillCount = 0;
29837
30276
  try {
29838
30277
  const entries = readdirSync9(skillsDir);
29839
30278
  for (const entry of entries) {
29840
30279
  if (entry.startsWith("exe")) {
29841
- const fullPath = path44.join(skillsDir, entry);
30280
+ const fullPath = path45.join(skillsDir, entry);
29842
30281
  if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
29843
30282
  skillCount++;
29844
30283
  }
@@ -29850,30 +30289,30 @@ async function runClaudeUninstall(flags = []) {
29850
30289
  removed++;
29851
30290
  }
29852
30291
  }
29853
- const claudeMdPath = path44.join(claudeDir, "CLAUDE.md");
29854
- if (existsSync29(claudeMdPath)) {
29855
- const content = readFileSync26(claudeMdPath, "utf8");
30292
+ const claudeMdPath = path45.join(claudeDir, "CLAUDE.md");
30293
+ if (existsSync31(claudeMdPath)) {
30294
+ const content = readFileSync27(claudeMdPath, "utf8");
29856
30295
  const startMarker = "<!-- exe-os:orchestration-start -->";
29857
30296
  const endMarker = "<!-- exe-os:orchestration-end -->";
29858
30297
  const startIdx = content.indexOf(startMarker);
29859
30298
  const endIdx = content.indexOf(endMarker);
29860
30299
  if (startIdx !== -1 && endIdx !== -1) {
29861
30300
  const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
29862
- if (!dryRun) writeFileSync19(claudeMdPath, cleaned);
30301
+ if (!dryRun) writeFileSync20(claudeMdPath, cleaned);
29863
30302
  log("\u2713 Removed orchestration block from CLAUDE.md");
29864
30303
  removed++;
29865
30304
  }
29866
30305
  }
29867
- const agentsDir = path44.join(claudeDir, "agents");
29868
- if (existsSync29(agentsDir)) {
30306
+ const agentsDir = path45.join(claudeDir, "agents");
30307
+ if (existsSync31(agentsDir)) {
29869
30308
  let agentCount = 0;
29870
30309
  try {
29871
30310
  const entries = readdirSync9(agentsDir).filter((f) => f.endsWith(".md"));
29872
30311
  let knownNames = /* @__PURE__ */ new Set();
29873
- const rosterPath = path44.join(exeOsDir, "exe-employees.json");
29874
- if (existsSync29(rosterPath)) {
30312
+ const rosterPath = path45.join(exeOsDir, "exe-employees.json");
30313
+ if (existsSync31(rosterPath)) {
29875
30314
  try {
29876
- const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
30315
+ const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
29877
30316
  knownNames = new Set(roster.map((e) => e.name));
29878
30317
  } catch {
29879
30318
  }
@@ -29881,7 +30320,7 @@ async function runClaudeUninstall(flags = []) {
29881
30320
  for (const entry of entries) {
29882
30321
  const name = entry.replace(/\.md$/, "");
29883
30322
  if (knownNames.has(name)) {
29884
- if (!dryRun) rmSync(path44.join(agentsDir, entry), { force: true });
30323
+ if (!dryRun) rmSync(path45.join(agentsDir, entry), { force: true });
29885
30324
  agentCount++;
29886
30325
  }
29887
30326
  }
@@ -29892,16 +30331,16 @@ async function runClaudeUninstall(flags = []) {
29892
30331
  removed++;
29893
30332
  }
29894
30333
  }
29895
- const projectsDir = path44.join(claudeDir, "projects");
29896
- if (existsSync29(projectsDir)) {
30334
+ const projectsDir = path45.join(claudeDir, "projects");
30335
+ if (existsSync31(projectsDir)) {
29897
30336
  let projectCount = 0;
29898
30337
  try {
29899
30338
  const projects = readdirSync9(projectsDir);
29900
30339
  for (const proj of projects) {
29901
- const projSettings = path44.join(projectsDir, proj, "settings.json");
29902
- if (!existsSync29(projSettings)) continue;
30340
+ const projSettings = path45.join(projectsDir, proj, "settings.json");
30341
+ if (!existsSync31(projSettings)) continue;
29903
30342
  try {
29904
- const pSettings = JSON.parse(readFileSync26(projSettings, "utf8"));
30343
+ const pSettings = JSON.parse(readFileSync27(projSettings, "utf8"));
29905
30344
  let changed = false;
29906
30345
  if (Array.isArray(pSettings.permissions?.allow)) {
29907
30346
  const before = pSettings.permissions.allow.length;
@@ -29911,7 +30350,7 @@ async function runClaudeUninstall(flags = []) {
29911
30350
  if (pSettings.permissions.allow.length < before) changed = true;
29912
30351
  }
29913
30352
  if (changed && !dryRun) {
29914
- writeFileSync19(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
30353
+ writeFileSync20(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
29915
30354
  }
29916
30355
  if (changed) projectCount++;
29917
30356
  } catch {
@@ -29935,18 +30374,18 @@ async function runClaudeUninstall(flags = []) {
29935
30374
  };
29936
30375
  const exeBinPath = findExeBin3();
29937
30376
  if (!exeBinPath) throw new Error("exe-os not found in PATH");
29938
- const binDir = path44.dirname(exeBinPath);
30377
+ const binDir = path45.dirname(exeBinPath);
29939
30378
  let symlinkCount = 0;
29940
- const rosterPath = path44.join(exeOsDir, "exe-employees.json");
29941
- if (existsSync29(rosterPath)) {
29942
- const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
30379
+ const rosterPath = path45.join(exeOsDir, "exe-employees.json");
30380
+ if (existsSync31(rosterPath)) {
30381
+ const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
29943
30382
  const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
29944
30383
  const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME2;
29945
30384
  for (const emp of roster) {
29946
30385
  if (emp.name === coordinatorName) continue;
29947
30386
  for (const suffix of ["", "-opencode"]) {
29948
- const linkPath = path44.join(binDir, `${emp.name}${suffix}`);
29949
- if (existsSync29(linkPath)) {
30387
+ const linkPath = path45.join(binDir, `${emp.name}${suffix}`);
30388
+ if (existsSync31(linkPath)) {
29950
30389
  if (!dryRun) rmSync(linkPath, { force: true });
29951
30390
  symlinkCount++;
29952
30391
  }
@@ -29959,7 +30398,7 @@ async function runClaudeUninstall(flags = []) {
29959
30398
  }
29960
30399
  } catch {
29961
30400
  }
29962
- if (purge && existsSync29(exeOsDir)) {
30401
+ if (purge && existsSync31(exeOsDir)) {
29963
30402
  if (!dryRun) {
29964
30403
  process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
29965
30404
  process.stdout.write(" Removing ~/.exe-os...\n");
@@ -29984,7 +30423,7 @@ async function checkForUpdateOnBoot() {
29984
30423
  const config = await loadConfig2();
29985
30424
  if (!config.autoUpdate.checkOnBoot) return;
29986
30425
  const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
29987
- const packageRoot = path44.resolve(
30426
+ const packageRoot = path45.resolve(
29988
30427
  new URL("../..", import.meta.url).pathname
29989
30428
  );
29990
30429
  const result = checkForUpdate2(packageRoot);
@@ -30044,7 +30483,7 @@ async function runActivate(key) {
30044
30483
  const idTemplate = getIdentityTemplate(identityKey);
30045
30484
  if (idTemplate) {
30046
30485
  const idPath = identityPath2(name);
30047
- const dir = path44.dirname(idPath);
30486
+ const dir = path45.dirname(idPath);
30048
30487
  if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
30049
30488
  fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
30050
30489
  }