@askexenow/exe-os 0.8.80 → 0.8.82

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 (110) hide show
  1. package/dist/bin/backfill-conversations.js +359 -267
  2. package/dist/bin/backfill-responses.js +357 -265
  3. package/dist/bin/backfill-vectors.js +339 -264
  4. package/dist/bin/cleanup-stale-review-tasks.js +315 -256
  5. package/dist/bin/cli.js +494 -240
  6. package/dist/bin/exe-agent.js +141 -46
  7. package/dist/bin/exe-assign.js +151 -63
  8. package/dist/bin/exe-boot.js +294 -115
  9. package/dist/bin/exe-call.js +76 -51
  10. package/dist/bin/exe-cloud.js +58 -45
  11. package/dist/bin/exe-dispatch.js +434 -277
  12. package/dist/bin/exe-doctor.js +317 -246
  13. package/dist/bin/exe-export-behaviors.js +328 -248
  14. package/dist/bin/exe-forget.js +314 -231
  15. package/dist/bin/exe-gateway.js +2676 -1402
  16. package/dist/bin/exe-heartbeat.js +329 -264
  17. package/dist/bin/exe-kill.js +324 -244
  18. package/dist/bin/exe-launch-agent.js +574 -463
  19. package/dist/bin/exe-link.js +1055 -95
  20. package/dist/bin/exe-new-employee.js +49 -54
  21. package/dist/bin/exe-pending-messages.js +310 -253
  22. package/dist/bin/exe-pending-notifications.js +299 -228
  23. package/dist/bin/exe-pending-reviews.js +314 -245
  24. package/dist/bin/exe-rename.js +259 -195
  25. package/dist/bin/exe-review.js +140 -64
  26. package/dist/bin/exe-search.js +543 -356
  27. package/dist/bin/exe-session-cleanup.js +463 -382
  28. package/dist/bin/exe-settings.js +129 -99
  29. package/dist/bin/exe-start.sh +6 -6
  30. package/dist/bin/exe-status.js +95 -36
  31. package/dist/bin/exe-team.js +116 -51
  32. package/dist/bin/git-sweep.js +482 -307
  33. package/dist/bin/graph-backfill.js +357 -245
  34. package/dist/bin/graph-export.js +324 -244
  35. package/dist/bin/install.js +33 -10
  36. package/dist/bin/scan-tasks.js +481 -307
  37. package/dist/bin/setup.js +1147 -140
  38. package/dist/bin/shard-migrate.js +321 -241
  39. package/dist/bin/update.js +1 -7
  40. package/dist/bin/wiki-sync.js +318 -238
  41. package/dist/gateway/index.js +2656 -1383
  42. package/dist/hooks/bug-report-worker.js +641 -472
  43. package/dist/hooks/commit-complete.js +482 -307
  44. package/dist/hooks/error-recall.js +363 -135
  45. package/dist/hooks/exe-heartbeat-hook.js +97 -27
  46. package/dist/hooks/ingest-worker.js +584 -397
  47. package/dist/hooks/ingest.js +123 -58
  48. package/dist/hooks/instructions-loaded.js +212 -82
  49. package/dist/hooks/notification.js +200 -70
  50. package/dist/hooks/post-compact.js +199 -81
  51. package/dist/hooks/pre-compact.js +352 -140
  52. package/dist/hooks/pre-tool-use.js +416 -278
  53. package/dist/hooks/prompt-ingest-worker.js +376 -299
  54. package/dist/hooks/prompt-submit.js +414 -188
  55. package/dist/hooks/response-ingest-worker.js +408 -338
  56. package/dist/hooks/session-end.js +209 -83
  57. package/dist/hooks/session-start.js +382 -158
  58. package/dist/hooks/stop.js +209 -83
  59. package/dist/hooks/subagent-stop.js +209 -85
  60. package/dist/hooks/summary-worker.js +606 -510
  61. package/dist/index.js +2133 -855
  62. package/dist/lib/cloud-sync.js +1175 -184
  63. package/dist/lib/config.js +1 -9
  64. package/dist/lib/consolidation.js +71 -34
  65. package/dist/lib/database.js +166 -14
  66. package/dist/lib/device-registry.js +189 -117
  67. package/dist/lib/embedder.js +6 -10
  68. package/dist/lib/employee-templates.js +134 -39
  69. package/dist/lib/employees.js +30 -7
  70. package/dist/lib/exe-daemon-client.js +5 -7
  71. package/dist/lib/exe-daemon.js +514 -152
  72. package/dist/lib/hybrid-search.js +543 -356
  73. package/dist/lib/identity-templates.js +15 -15
  74. package/dist/lib/identity.js +19 -15
  75. package/dist/lib/license.js +1 -7
  76. package/dist/lib/messaging.js +157 -135
  77. package/dist/lib/reminders.js +97 -0
  78. package/dist/lib/schedules.js +302 -231
  79. package/dist/lib/skill-learning.js +33 -27
  80. package/dist/lib/status-brief.js +11 -14
  81. package/dist/lib/store.js +326 -237
  82. package/dist/lib/task-router.js +105 -1
  83. package/dist/lib/tasks.js +233 -116
  84. package/dist/lib/tmux-routing.js +173 -56
  85. package/dist/lib/ws-client.js +13 -3
  86. package/dist/mcp/server.js +2009 -1015
  87. package/dist/mcp/tools/complete-reminder.js +97 -0
  88. package/dist/mcp/tools/create-reminder.js +97 -0
  89. package/dist/mcp/tools/create-task.js +426 -262
  90. package/dist/mcp/tools/deactivate-behavior.js +119 -44
  91. package/dist/mcp/tools/list-reminders.js +97 -0
  92. package/dist/mcp/tools/list-tasks.js +56 -57
  93. package/dist/mcp/tools/send-message.js +206 -143
  94. package/dist/mcp/tools/update-task.js +259 -85
  95. package/dist/runtime/index.js +495 -316
  96. package/dist/tui/App.js +1128 -919
  97. package/package.json +2 -10
  98. package/src/commands/exe/afk.md +8 -8
  99. package/src/commands/exe/assign.md +1 -1
  100. package/src/commands/exe/build-adv.md +1 -1
  101. package/src/commands/exe/call.md +10 -10
  102. package/src/commands/exe/employee-heartbeat.md +9 -6
  103. package/src/commands/exe/heartbeat.md +5 -5
  104. package/src/commands/exe/intercom.md +26 -15
  105. package/src/commands/exe/launch.md +2 -2
  106. package/src/commands/exe/new-employee.md +1 -1
  107. package/src/commands/exe/review.md +2 -2
  108. package/src/commands/exe/schedule.md +1 -1
  109. package/src/commands/exe/sessions.md +2 -2
  110. package/src/commands/exe.md +22 -20
@@ -26,6 +26,137 @@ var init_db_retry = __esm({
26
26
  }
27
27
  });
28
28
 
29
+ // src/lib/config.ts
30
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
31
+ import { readFileSync, existsSync, renameSync } from "fs";
32
+ import path from "path";
33
+ import os from "os";
34
+ function resolveDataDir() {
35
+ if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
36
+ if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
37
+ const newDir = path.join(os.homedir(), ".exe-os");
38
+ const legacyDir = path.join(os.homedir(), ".exe-mem");
39
+ if (!existsSync(newDir) && existsSync(legacyDir)) {
40
+ try {
41
+ renameSync(legacyDir, newDir);
42
+ process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
43
+ `);
44
+ } catch {
45
+ return legacyDir;
46
+ }
47
+ }
48
+ return newDir;
49
+ }
50
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
51
+ var init_config = __esm({
52
+ "src/lib/config.ts"() {
53
+ "use strict";
54
+ EXE_AI_DIR = resolveDataDir();
55
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
56
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
57
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
58
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
59
+ CURRENT_CONFIG_VERSION = 1;
60
+ DEFAULT_CONFIG = {
61
+ config_version: CURRENT_CONFIG_VERSION,
62
+ dbPath: DB_PATH,
63
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
64
+ embeddingDim: 1024,
65
+ batchSize: 20,
66
+ flushIntervalMs: 1e4,
67
+ autoIngestion: true,
68
+ autoRetrieval: true,
69
+ searchMode: "hybrid",
70
+ hookSearchMode: "hybrid",
71
+ fileGrepEnabled: true,
72
+ splashEffect: true,
73
+ consolidationEnabled: true,
74
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
75
+ consolidationModel: "claude-haiku-4-5-20251001",
76
+ consolidationMaxCallsPerRun: 20,
77
+ selfQueryRouter: true,
78
+ selfQueryModel: "claude-haiku-4-5-20251001",
79
+ rerankerEnabled: true,
80
+ scalingRoadmap: {
81
+ rerankerAutoTrigger: {
82
+ enabled: true,
83
+ broadQueryMinCardinality: 5e4,
84
+ fetchTopK: 150,
85
+ returnTopK: 5
86
+ }
87
+ },
88
+ graphRagEnabled: true,
89
+ wikiEnabled: false,
90
+ wikiUrl: "",
91
+ wikiApiKey: "",
92
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
93
+ wikiWorkspaceMapping: {},
94
+ wikiAutoUpdate: true,
95
+ wikiAutoUpdateThreshold: 0.5,
96
+ wikiAutoUpdateCreateNew: true,
97
+ skillLearning: true,
98
+ skillThreshold: 3,
99
+ skillModel: "claude-haiku-4-5-20251001",
100
+ exeHeartbeat: {
101
+ enabled: true,
102
+ intervalSeconds: 60,
103
+ staleInProgressThresholdHours: 2
104
+ },
105
+ sessionLifecycle: {
106
+ idleKillEnabled: true,
107
+ idleKillTicksRequired: 3,
108
+ idleKillIntercomAckWindowMs: 1e4,
109
+ maxAutoInstances: 10
110
+ },
111
+ autoUpdate: {
112
+ checkOnBoot: true,
113
+ autoInstall: false,
114
+ checkIntervalMs: 24 * 60 * 60 * 1e3
115
+ }
116
+ };
117
+ }
118
+ });
119
+
120
+ // src/lib/employees.ts
121
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
122
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
123
+ import { execSync } from "child_process";
124
+ import path2 from "path";
125
+ import os2 from "os";
126
+ function normalizeRole(role) {
127
+ return (role ?? "").trim().toLowerCase();
128
+ }
129
+ function isCoordinatorRole(role) {
130
+ return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
131
+ }
132
+ function getCoordinatorEmployee(employees) {
133
+ return employees.find((e) => isCoordinatorRole(e.role));
134
+ }
135
+ function getCoordinatorName(employees = loadEmployeesSync()) {
136
+ return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
137
+ }
138
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
139
+ if (!existsSync2(employeesPath)) return [];
140
+ try {
141
+ return JSON.parse(readFileSync2(employeesPath, "utf-8"));
142
+ } catch {
143
+ return [];
144
+ }
145
+ }
146
+ function getEmployee(employees, name) {
147
+ return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
148
+ }
149
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
150
+ var init_employees = __esm({
151
+ "src/lib/employees.ts"() {
152
+ "use strict";
153
+ init_config();
154
+ EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
155
+ DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
156
+ COORDINATOR_ROLE = "COO";
157
+ }
158
+ });
159
+
29
160
  // src/lib/database.ts
30
161
  import { createClient } from "@libsql/client";
31
162
  function getClient() {
@@ -39,29 +170,30 @@ var init_database = __esm({
39
170
  "src/lib/database.ts"() {
40
171
  "use strict";
41
172
  init_db_retry();
173
+ init_employees();
42
174
  _resilientClient = null;
43
175
  }
44
176
  });
45
177
 
46
178
  // src/lib/session-registry.ts
47
- import path from "path";
48
- import os from "os";
179
+ import path3 from "path";
180
+ import os3 from "os";
49
181
  var REGISTRY_PATH;
50
182
  var init_session_registry = __esm({
51
183
  "src/lib/session-registry.ts"() {
52
184
  "use strict";
53
- REGISTRY_PATH = path.join(os.homedir(), ".exe-os", "session-registry.json");
185
+ REGISTRY_PATH = path3.join(os3.homedir(), ".exe-os", "session-registry.json");
54
186
  }
55
187
  });
56
188
 
57
189
  // src/lib/session-key.ts
58
- import { execSync } from "child_process";
190
+ import { execSync as execSync2 } from "child_process";
59
191
  function getSessionKey() {
60
192
  if (_cached) return _cached;
61
193
  let pid = process.ppid;
62
194
  for (let i = 0; i < 10; i++) {
63
195
  try {
64
- const info = execSync(`ps -p ${pid} -o ppid=,comm=`, {
196
+ const info = execSync2(`ps -p ${pid} -o ppid=,comm=`, {
65
197
  encoding: "utf8",
66
198
  timeout: 2e3
67
199
  }).trim();
@@ -197,7 +329,7 @@ var init_transport = __esm({
197
329
  });
198
330
 
199
331
  // src/lib/cc-agent-support.ts
200
- import { execSync as execSync2 } from "child_process";
332
+ import { execSync as execSync3 } from "child_process";
201
333
  var init_cc_agent_support = __esm({
202
334
  "src/lib/cc-agent-support.ts"() {
203
335
  "use strict";
@@ -226,17 +358,17 @@ var init_provider_table = __esm({
226
358
  });
227
359
 
228
360
  // src/lib/intercom-queue.ts
229
- import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "fs";
230
- import path2 from "path";
231
- import os2 from "os";
361
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync3, mkdirSync } from "fs";
362
+ import path4 from "path";
363
+ import os4 from "os";
232
364
  function ensureDir() {
233
- const dir = path2.dirname(QUEUE_PATH);
234
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
365
+ const dir = path4.dirname(QUEUE_PATH);
366
+ if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
235
367
  }
236
368
  function readQueue() {
237
369
  try {
238
- if (!existsSync(QUEUE_PATH)) return [];
239
- return JSON.parse(readFileSync(QUEUE_PATH, "utf8"));
370
+ if (!existsSync3(QUEUE_PATH)) return [];
371
+ return JSON.parse(readFileSync3(QUEUE_PATH, "utf8"));
240
372
  } catch {
241
373
  return [];
242
374
  }
@@ -244,8 +376,8 @@ function readQueue() {
244
376
  function writeQueue(queue) {
245
377
  ensureDir();
246
378
  const tmp = `${QUEUE_PATH}.tmp`;
247
- writeFileSync(tmp, JSON.stringify(queue, null, 2));
248
- renameSync(tmp, QUEUE_PATH);
379
+ writeFileSync2(tmp, JSON.stringify(queue, null, 2));
380
+ renameSync3(tmp, QUEUE_PATH);
249
381
  }
250
382
  function queueIntercom(targetSession, reason) {
251
383
  const queue = readQueue();
@@ -268,121 +400,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
268
400
  var init_intercom_queue = __esm({
269
401
  "src/lib/intercom-queue.ts"() {
270
402
  "use strict";
271
- QUEUE_PATH = path2.join(os2.homedir(), ".exe-os", "intercom-queue.json");
403
+ QUEUE_PATH = path4.join(os4.homedir(), ".exe-os", "intercom-queue.json");
272
404
  TTL_MS = 60 * 60 * 1e3;
273
- INTERCOM_LOG = path2.join(os2.homedir(), ".exe-os", "intercom.log");
274
- }
275
- });
276
-
277
- // src/lib/config.ts
278
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
279
- import { readFileSync as readFileSync2, existsSync as existsSync2, renameSync as renameSync2 } from "fs";
280
- import path3 from "path";
281
- import os3 from "os";
282
- function resolveDataDir() {
283
- if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
284
- if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
285
- const newDir = path3.join(os3.homedir(), ".exe-os");
286
- const legacyDir = path3.join(os3.homedir(), ".exe-mem");
287
- if (!existsSync2(newDir) && existsSync2(legacyDir)) {
288
- try {
289
- renameSync2(legacyDir, newDir);
290
- process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
291
- `);
292
- } catch {
293
- return legacyDir;
294
- }
295
- }
296
- return newDir;
297
- }
298
- var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
299
- var init_config = __esm({
300
- "src/lib/config.ts"() {
301
- "use strict";
302
- EXE_AI_DIR = resolveDataDir();
303
- DB_PATH = path3.join(EXE_AI_DIR, "memories.db");
304
- MODELS_DIR = path3.join(EXE_AI_DIR, "models");
305
- CONFIG_PATH = path3.join(EXE_AI_DIR, "config.json");
306
- LEGACY_LANCE_PATH = path3.join(EXE_AI_DIR, "local.lance");
307
- CURRENT_CONFIG_VERSION = 1;
308
- DEFAULT_CONFIG = {
309
- config_version: CURRENT_CONFIG_VERSION,
310
- dbPath: DB_PATH,
311
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
312
- embeddingDim: 1024,
313
- batchSize: 20,
314
- flushIntervalMs: 1e4,
315
- autoIngestion: true,
316
- autoRetrieval: true,
317
- searchMode: "hybrid",
318
- hookSearchMode: "hybrid",
319
- fileGrepEnabled: true,
320
- splashEffect: true,
321
- consolidationEnabled: true,
322
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
323
- consolidationModel: "claude-haiku-4-5-20251001",
324
- consolidationMaxCallsPerRun: 20,
325
- selfQueryRouter: true,
326
- selfQueryModel: "claude-haiku-4-5-20251001",
327
- rerankerEnabled: true,
328
- scalingRoadmap: {
329
- rerankerAutoTrigger: {
330
- enabled: true,
331
- broadQueryMinCardinality: 5e4,
332
- fetchTopK: 150,
333
- returnTopK: 5
334
- }
335
- },
336
- graphRagEnabled: true,
337
- wikiEnabled: false,
338
- wikiUrl: "",
339
- wikiApiKey: "",
340
- wikiSyncIntervalMs: 30 * 60 * 1e3,
341
- wikiWorkspaceMapping: {
342
- exe: "Executive",
343
- yoshi: "Engineering",
344
- mari: "Marketing",
345
- tom: "Engineering",
346
- sasha: "Production"
347
- },
348
- wikiAutoUpdate: true,
349
- wikiAutoUpdateThreshold: 0.5,
350
- wikiAutoUpdateCreateNew: true,
351
- skillLearning: true,
352
- skillThreshold: 3,
353
- skillModel: "claude-haiku-4-5-20251001",
354
- exeHeartbeat: {
355
- enabled: true,
356
- intervalSeconds: 60,
357
- staleInProgressThresholdHours: 2
358
- },
359
- sessionLifecycle: {
360
- idleKillEnabled: true,
361
- idleKillTicksRequired: 3,
362
- idleKillIntercomAckWindowMs: 1e4,
363
- maxAutoInstances: 10
364
- },
365
- autoUpdate: {
366
- checkOnBoot: true,
367
- autoInstall: false,
368
- checkIntervalMs: 24 * 60 * 60 * 1e3
369
- }
370
- };
371
- }
372
- });
373
-
374
- // src/lib/employees.ts
375
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
376
- import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
377
- import { execSync as execSync3 } from "child_process";
378
- import path4 from "path";
379
- import os4 from "os";
380
- var EMPLOYEES_PATH;
381
- var init_employees = __esm({
382
- "src/lib/employees.ts"() {
383
- "use strict";
384
- init_config();
385
- EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
405
+ INTERCOM_LOG = path4.join(os4.homedir(), ".exe-os", "intercom.log");
386
406
  }
387
407
  });
388
408
 
@@ -439,7 +459,7 @@ function employeeSessionName(employee, exeSession, instance) {
439
459
  exeSession = root;
440
460
  } else {
441
461
  throw new Error(
442
- `Invalid exeSession "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name (e.g., "exe1", "work", "yoda1")`
462
+ `Invalid coordinator session "${exeSession}" \u2014 contains a dash but no recognizable root session. Pass a root session name.`
443
463
  );
444
464
  }
445
465
  }
@@ -453,8 +473,10 @@ function employeeSessionName(employee, exeSession, instance) {
453
473
  return name;
454
474
  }
455
475
  function extractRootExe(name) {
456
- const match = name.match(/(exe\d+)$/);
457
- return match?.[1] ?? null;
476
+ if (!name) return null;
477
+ if (!name.includes("-")) return name;
478
+ const parts = name.split("-").filter(Boolean);
479
+ return parts.length > 0 ? parts[parts.length - 1] : null;
458
480
  }
459
481
  function getParentExe(sessionKey) {
460
482
  try {
@@ -537,12 +559,14 @@ function getSessionState(sessionName) {
537
559
  }
538
560
  }
539
561
  function isExeSession(sessionName) {
540
- return /^exe\d*$/.test(sessionName);
562
+ const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
563
+ const coordinatorName = getCoordinatorName();
564
+ return matchesBaseWithInstance(coordinatorName) || matchesBaseWithInstance("exe");
541
565
  }
542
566
  function sendIntercom(targetSession) {
543
567
  const transport = getTransport();
544
568
  if (isExeSession(targetSession)) {
545
- logIntercom(`SKIP_EXE \u2192 ${targetSession} (exe sessions use prompt-submit hook)`);
569
+ logIntercom(`SKIP_COORDINATOR \u2192 ${targetSession} (coordinator sessions use prompt-submit hook)`);
546
570
  return "skipped_exe";
547
571
  }
548
572
  if (isDebounced(targetSession)) {
@@ -593,6 +617,7 @@ var init_tmux_routing = __esm({
593
617
  init_provider_table();
594
618
  init_intercom_queue();
595
619
  init_plan_limits();
620
+ init_employees();
596
621
  SPAWN_LOCK_DIR = path7.join(os5.homedir(), ".exe-os", "spawn-locks");
597
622
  SESSION_CACHE = path7.join(os5.homedir(), ".exe-os", "session-cache");
598
623
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
@@ -716,7 +741,7 @@ async function deliverLocalMessage(messageId) {
716
741
  try {
717
742
  const exeSession = resolveExeSession();
718
743
  if (!exeSession) {
719
- throw new Error("No exe session found");
744
+ throw new Error("No coordinator session found");
720
745
  }
721
746
  const sessionName = employeeSessionName(targetAgent, exeSession);
722
747
  if (!isEmployeeAlive(sessionName)) {
@@ -759,8 +784,51 @@ import path8 from "path";
759
784
  init_session_key();
760
785
 
761
786
  // src/adapters/claude/active-agent.ts
787
+ init_employees();
762
788
  var CACHE_DIR = path8.join(EXE_AI_DIR, "session-cache");
763
789
  var STALE_MS = 24 * 60 * 60 * 1e3;
790
+ function isNameWithOptionalInstance(candidate, baseName) {
791
+ if (candidate === baseName) return true;
792
+ if (!candidate.startsWith(baseName)) return false;
793
+ return /^\d+$/.test(candidate.slice(baseName.length));
794
+ }
795
+ function resolveEmployeeFromSessionPrefix(prefix, employees) {
796
+ const sorted = [...employees].sort((a, b) => b.name.length - a.name.length);
797
+ for (const employee of sorted) {
798
+ if (isNameWithOptionalInstance(prefix, employee.name)) {
799
+ return { agentId: employee.name, agentRole: employee.role };
800
+ }
801
+ }
802
+ return null;
803
+ }
804
+ function resolveActiveAgentFromTmuxSession(sessionName) {
805
+ const employees = loadEmployeesSync();
806
+ const coordinator = getCoordinatorEmployee(employees);
807
+ const coordinatorName = coordinator?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
808
+ if (isNameWithOptionalInstance(sessionName, coordinatorName)) {
809
+ return {
810
+ agentId: coordinatorName,
811
+ agentRole: coordinator?.role ?? "COO"
812
+ };
813
+ }
814
+ if (isNameWithOptionalInstance(sessionName, DEFAULT_COORDINATOR_TEMPLATE_NAME)) {
815
+ return {
816
+ agentId: coordinator?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME,
817
+ agentRole: coordinator?.role ?? "COO"
818
+ };
819
+ }
820
+ if (sessionName.includes("-")) {
821
+ const prefix = sessionName.split("-")[0] ?? "";
822
+ const employee = resolveEmployeeFromSessionPrefix(prefix, employees);
823
+ if (employee) return employee;
824
+ const legacy = prefix.match(/^([a-zA-Z]+)\d*$/);
825
+ if (legacy?.[1] && legacy[1] !== DEFAULT_COORDINATOR_TEMPLATE_NAME) {
826
+ const emp = getEmployee(employees, legacy[1]);
827
+ return { agentId: emp?.name ?? legacy[1], agentRole: emp?.role ?? "employee" };
828
+ }
829
+ }
830
+ return null;
831
+ }
764
832
  function getMarkerPath() {
765
833
  return path8.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
766
834
  }
@@ -797,13 +865,8 @@ function getActiveAgent() {
797
865
  "tmux display-message -p '#{session_name}' 2>/dev/null",
798
866
  { encoding: "utf8", timeout: 2e3 }
799
867
  ).trim();
800
- const empMatch = sessionName.match(/^([a-zA-Z]+)\d*-exe\d+$/);
801
- if (empMatch && empMatch[1] !== "exe") {
802
- return { agentId: empMatch[1], agentRole: "employee" };
803
- }
804
- if (/^exe\d+$/.test(sessionName)) {
805
- return { agentId: "exe", agentRole: "COO" };
806
- }
868
+ const resolved = resolveActiveAgentFromTmuxSession(sessionName);
869
+ if (resolved) return resolved;
807
870
  } catch {
808
871
  }
809
872
  return {
@@ -820,7 +883,7 @@ function registerSendMessage(server) {
820
883
  title: "Send Message",
821
884
  description: "Send a structured message to another agent. Messages are queued and delivered via intercom. NOTE: messages are fire-and-forget \u2014 do NOT use for actionable work dispatch. Use create_task instead to assign work to employees.",
822
885
  inputSchema: {
823
- target_agent: z.string().describe("Recipient agent name (e.g., 'yoshi', 'tom', 'exe')"),
886
+ target_agent: z.string().describe("Recipient agent name"),
824
887
  content: z.string().describe("Message content"),
825
888
  target_project: z.string().optional().describe("Project context (optional)"),
826
889
  priority: z.enum(["normal", "urgent"]).default("normal").describe("Message priority (default: normal)"),