@askexenow/exe-os 0.8.64 → 0.8.68

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 (55) hide show
  1. package/dist/bin/cleanup-stale-review-tasks.js +8 -7
  2. package/dist/bin/cli.js +215 -120
  3. package/dist/bin/exe-assign.js +11 -10
  4. package/dist/bin/exe-boot.js +83 -78
  5. package/dist/bin/exe-call.js +33 -1
  6. package/dist/bin/exe-cloud.js +3 -2
  7. package/dist/bin/exe-dispatch.js +31 -30
  8. package/dist/bin/exe-gateway.js +33 -32
  9. package/dist/bin/exe-heartbeat.js +21 -20
  10. package/dist/bin/exe-launch-agent.js +48 -16
  11. package/dist/bin/exe-link.js +16 -11
  12. package/dist/bin/exe-new-employee.js +20 -19
  13. package/dist/bin/exe-pending-messages.js +7 -6
  14. package/dist/bin/exe-pending-reviews.js +16 -15
  15. package/dist/bin/exe-rename.js +12 -11
  16. package/dist/bin/exe-review.js +4 -3
  17. package/dist/bin/exe-session-cleanup.js +20 -19
  18. package/dist/bin/exe-settings.js +3 -2
  19. package/dist/bin/exe-start.sh +2 -2
  20. package/dist/bin/exe-status.js +16 -15
  21. package/dist/bin/exe-team.js +4 -3
  22. package/dist/bin/git-sweep.js +31 -30
  23. package/dist/bin/install.js +284 -113
  24. package/dist/bin/scan-tasks.js +33 -32
  25. package/dist/bin/setup.js +114 -30
  26. package/dist/gateway/index.js +32 -31
  27. package/dist/hooks/bug-report-worker.js +58 -26
  28. package/dist/hooks/commit-complete.js +31 -30
  29. package/dist/hooks/ingest-worker.js +58 -57
  30. package/dist/hooks/post-compact.js +10 -9
  31. package/dist/hooks/pre-compact.js +31 -30
  32. package/dist/hooks/pre-tool-use.js +46 -14
  33. package/dist/hooks/prompt-ingest-worker.js +15 -14
  34. package/dist/hooks/prompt-submit.js +15 -14
  35. package/dist/hooks/response-ingest-worker.js +8 -7
  36. package/dist/hooks/session-end.js +14 -13
  37. package/dist/hooks/session-start.js +10 -9
  38. package/dist/hooks/stop.js +10 -9
  39. package/dist/hooks/subagent-stop.js +10 -9
  40. package/dist/hooks/summary-worker.js +41 -36
  41. package/dist/index.js +43 -42
  42. package/dist/lib/cloud-sync.js +16 -11
  43. package/dist/lib/employees.js +33 -1
  44. package/dist/lib/exe-daemon.js +56 -55
  45. package/dist/lib/messaging.js +9 -8
  46. package/dist/lib/tasks.js +27 -26
  47. package/dist/lib/tmux-routing.js +29 -28
  48. package/dist/mcp/server.js +94 -62
  49. package/dist/mcp/tools/create-task.js +60 -28
  50. package/dist/mcp/tools/list-tasks.js +10 -9
  51. package/dist/mcp/tools/send-message.js +11 -10
  52. package/dist/mcp/tools/update-task.js +21 -20
  53. package/dist/runtime/index.js +31 -30
  54. package/dist/tui/App.js +67 -35
  55. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -286,14 +286,16 @@ __export(employees_exports, {
286
286
  isMultiInstance: () => isMultiInstance,
287
287
  loadEmployees: () => loadEmployees,
288
288
  loadEmployeesSync: () => loadEmployeesSync,
289
+ normalizeRosterCase: () => normalizeRosterCase,
289
290
  registerBinSymlinks: () => registerBinSymlinks,
290
291
  saveEmployees: () => saveEmployees,
291
292
  validateEmployeeName: () => validateEmployeeName
292
293
  });
293
294
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
294
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
295
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
295
296
  import { execSync } from "child_process";
296
297
  import path2 from "path";
298
+ import os2 from "os";
297
299
  function validateEmployeeName(name) {
298
300
  if (!name) {
299
301
  return { valid: false, error: "Name is required" };
@@ -361,6 +363,36 @@ function addEmployee(employees, employee) {
361
363
  }
362
364
  return [...employees, normalized];
363
365
  }
366
+ async function normalizeRosterCase(rosterPath) {
367
+ const employees = await loadEmployees(rosterPath);
368
+ let changed = false;
369
+ for (const emp of employees) {
370
+ if (emp.name !== emp.name.toLowerCase()) {
371
+ const oldName = emp.name;
372
+ emp.name = emp.name.toLowerCase();
373
+ changed = true;
374
+ try {
375
+ const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
376
+ const oldPath = path2.join(identityDir, `${oldName}.md`);
377
+ const newPath = path2.join(identityDir, `${emp.name}.md`);
378
+ if (existsSync2(oldPath) && !existsSync2(newPath)) {
379
+ renameSync2(oldPath, newPath);
380
+ } else if (existsSync2(oldPath) && oldPath !== newPath) {
381
+ const content = readFileSync2(oldPath, "utf-8");
382
+ writeFileSync(newPath, content, "utf-8");
383
+ if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
384
+ unlinkSync(oldPath);
385
+ }
386
+ }
387
+ } catch {
388
+ }
389
+ }
390
+ }
391
+ if (changed) {
392
+ await saveEmployees(employees, rosterPath);
393
+ }
394
+ return changed;
395
+ }
364
396
  function findExeBin() {
365
397
  try {
366
398
  return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
@@ -412,7 +444,7 @@ var init_employees = __esm({
412
444
  });
413
445
 
414
446
  // src/lib/agent-symlinks.ts
415
- import os2 from "os";
447
+ import os3 from "os";
416
448
  import path3 from "path";
417
449
  import {
418
450
  existsSync as existsSync3,
@@ -430,7 +462,7 @@ function identitySourcePath(homeDir, agentId) {
430
462
  function claudeAgentLinkPath(homeDir, agentId) {
431
463
  return path3.join(claudeAgentsDir(homeDir), `${agentId}.md`);
432
464
  }
433
- function ensureAgentSymlink(agentId, homeDir = os2.homedir()) {
465
+ function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
434
466
  const target = identitySourcePath(homeDir, agentId);
435
467
  const link = claudeAgentLinkPath(homeDir, agentId);
436
468
  mkdirSync(claudeAgentsDir(homeDir), { recursive: true });
@@ -468,7 +500,7 @@ function ensureAgentSymlink(agentId, homeDir = os2.homedir()) {
468
500
  }
469
501
  return { agentId, action: "created", target, link };
470
502
  }
471
- async function ensureAllAgentSymlinks(homeDir = os2.homedir()) {
503
+ async function ensureAllAgentSymlinks(homeDir = os3.homedir()) {
472
504
  const employees = await loadEmployees();
473
505
  return employees.map((emp) => ensureAgentSymlink(emp.name, homeDir));
474
506
  }
@@ -513,9 +545,9 @@ __export(installer_exports, {
513
545
  setupTmux: () => setupTmux
514
546
  });
515
547
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
516
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, copyFileSync, mkdirSync as mkdirSync2 } from "fs";
548
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, copyFileSync, mkdirSync as mkdirSync2 } from "fs";
517
549
  import path4 from "path";
518
- import os3 from "os";
550
+ import os4 from "os";
519
551
  import { execSync as execSync2 } from "child_process";
520
552
  import { fileURLToPath } from "url";
521
553
  function resolvePackageRoot() {
@@ -535,7 +567,7 @@ function resolvePackageRoot() {
535
567
  }
536
568
  return path4.resolve(path4.dirname(thisFile), "..", "..", "..");
537
569
  }
538
- async function copySlashCommands(packageRoot, homeDir = os3.homedir()) {
570
+ async function copySlashCommands(packageRoot, homeDir = os4.homedir()) {
539
571
  let copied = 0;
540
572
  let skipped = 0;
541
573
  const skillsBase = path4.join(homeDir, ".claude", "skills");
@@ -588,7 +620,7 @@ name: ${skillName}
588
620
  await writeFile3(destPath, content);
589
621
  return true;
590
622
  }
591
- async function registerMcpServer(packageRoot, homeDir = os3.homedir()) {
623
+ async function registerMcpServer(packageRoot, homeDir = os4.homedir()) {
592
624
  const claudeJsonPath = path4.join(homeDir, ".claude.json");
593
625
  let claudeJson = {};
594
626
  if (existsSync4(claudeJsonPath)) {
@@ -620,7 +652,7 @@ async function registerMcpServer(packageRoot, homeDir = os3.homedir()) {
620
652
  await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
621
653
  return true;
622
654
  }
623
- async function mergeHooks(packageRoot, homeDir = os3.homedir()) {
655
+ async function mergeHooks(packageRoot, homeDir = os4.homedir()) {
624
656
  const settingsPath = path4.join(homeDir, ".claude", "settings.json");
625
657
  let settings = {};
626
658
  if (existsSync4(settingsPath)) {
@@ -935,7 +967,7 @@ async function runInstaller(homeDir) {
935
967
  `Hooks: ${hookResult.added} added, ${hookResult.skipped} unchanged
936
968
  `
937
969
  );
938
- const resolvedHome = homeDir ?? os3.homedir();
970
+ const resolvedHome = homeDir ?? os4.homedir();
939
971
  const exeWorkspace = path4.join(resolvedHome, "exe");
940
972
  if (!existsSync4(exeWorkspace)) {
941
973
  try {
@@ -964,7 +996,7 @@ exe-os installed successfully.
964
996
  `);
965
997
  }
966
998
  function setupTmux(home) {
967
- const homeDir = home ?? os3.homedir();
999
+ const homeDir = home ?? os4.homedir();
968
1000
  const exeDir = path4.join(homeDir, ".exe-os");
969
1001
  const exeTmuxConf = path4.join(exeDir, "tmux.conf");
970
1002
  const userTmuxConf = path4.join(homeDir, ".tmux.conf");
@@ -987,11 +1019,11 @@ function setupTmux(home) {
987
1019
  process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
988
1020
  `);
989
1021
  }
990
- writeFileSync(userTmuxConf, `${sourceLine}
1022
+ writeFileSync2(userTmuxConf, `${sourceLine}
991
1023
  ${existing}`);
992
1024
  }
993
1025
  } else {
994
- writeFileSync(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1026
+ writeFileSync2(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
995
1027
  ${sourceLine}
996
1028
  `);
997
1029
  }
@@ -1985,9 +2017,9 @@ __export(keychain_exports, {
1985
2017
  import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
1986
2018
  import { existsSync as existsSync5 } from "fs";
1987
2019
  import path5 from "path";
1988
- import os4 from "os";
2020
+ import os5 from "os";
1989
2021
  function getKeyDir() {
1990
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os4.homedir(), ".exe-os");
2022
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os5.homedir(), ".exe-os");
1991
2023
  }
1992
2024
  function getKeyPath() {
1993
2025
  return path5.join(getKeyDir(), "master.key");
@@ -3057,7 +3089,7 @@ var init_store = __esm({
3057
3089
  import net from "net";
3058
3090
  import { spawn } from "child_process";
3059
3091
  import { randomUUID as randomUUID2 } from "crypto";
3060
- import { existsSync as existsSync7, unlinkSync, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
3092
+ import { existsSync as existsSync7, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
3061
3093
  import path7 from "path";
3062
3094
  import { fileURLToPath as fileURLToPath2 } from "url";
3063
3095
  function handleData(chunk) {
@@ -3097,11 +3129,11 @@ function cleanupStaleFiles() {
3097
3129
  } catch {
3098
3130
  }
3099
3131
  try {
3100
- unlinkSync(PID_PATH);
3132
+ unlinkSync2(PID_PATH);
3101
3133
  } catch {
3102
3134
  }
3103
3135
  try {
3104
- unlinkSync(SOCKET_PATH);
3136
+ unlinkSync2(SOCKET_PATH);
3105
3137
  } catch {
3106
3138
  }
3107
3139
  }
@@ -3163,7 +3195,7 @@ function acquireSpawnLock() {
3163
3195
  const stat2 = statSync(SPAWN_LOCK_PATH);
3164
3196
  if (Date.now() - stat2.mtimeMs > SPAWN_LOCK_STALE_MS) {
3165
3197
  try {
3166
- unlinkSync(SPAWN_LOCK_PATH);
3198
+ unlinkSync2(SPAWN_LOCK_PATH);
3167
3199
  } catch {
3168
3200
  }
3169
3201
  try {
@@ -3180,7 +3212,7 @@ function acquireSpawnLock() {
3180
3212
  }
3181
3213
  function releaseSpawnLock() {
3182
3214
  try {
3183
- unlinkSync(SPAWN_LOCK_PATH);
3215
+ unlinkSync2(SPAWN_LOCK_PATH);
3184
3216
  } catch {
3185
3217
  }
3186
3218
  }
@@ -3311,11 +3343,11 @@ function killAndRespawnDaemon() {
3311
3343
  _connected = false;
3312
3344
  _buffer = "";
3313
3345
  try {
3314
- unlinkSync(PID_PATH);
3346
+ unlinkSync2(PID_PATH);
3315
3347
  } catch {
3316
3348
  }
3317
3349
  try {
3318
- unlinkSync(SOCKET_PATH);
3350
+ unlinkSync2(SOCKET_PATH);
3319
3351
  } catch {
3320
3352
  }
3321
3353
  spawnDaemon();
@@ -4417,7 +4449,7 @@ __export(exe_rename_exports, {
4417
4449
  main: () => main,
4418
4450
  renameEmployee: () => renameEmployee
4419
4451
  });
4420
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, existsSync as existsSync8 } from "fs";
4452
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync3, existsSync as existsSync8 } from "fs";
4421
4453
  import { execSync as execSync3 } from "child_process";
4422
4454
  import path9 from "path";
4423
4455
  import { homedir as homedir2 } from "os";
@@ -4450,7 +4482,7 @@ async function renameEmployee(oldName, newName, opts = {}) {
4450
4482
  undo: () => {
4451
4483
  employee.name = originalName;
4452
4484
  employee.systemPrompt = originalPrompt;
4453
- writeFileSync2(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
4485
+ writeFileSync3(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
4454
4486
  }
4455
4487
  });
4456
4488
  const oldIdentityPath = path9.join(identityDir, `${oldName}.md`);
@@ -4461,14 +4493,14 @@ async function renameEmployee(oldName, newName, opts = {}) {
4461
4493
  /^(agent_id:\s*)\S+/m,
4462
4494
  `$1${newName}`
4463
4495
  );
4464
- renameSync2(oldIdentityPath, newIdentityPath);
4465
- writeFileSync2(newIdentityPath, updatedContent, "utf-8");
4496
+ renameSync3(oldIdentityPath, newIdentityPath);
4497
+ writeFileSync3(newIdentityPath, updatedContent, "utf-8");
4466
4498
  rollbackStack.push({
4467
4499
  description: "restore identity file",
4468
4500
  undo: () => {
4469
4501
  if (existsSync8(newIdentityPath)) {
4470
- writeFileSync2(newIdentityPath, content, "utf-8");
4471
- renameSync2(newIdentityPath, oldIdentityPath);
4502
+ writeFileSync3(newIdentityPath, content, "utf-8");
4503
+ renameSync3(newIdentityPath, oldIdentityPath);
4472
4504
  }
4473
4505
  }
4474
4506
  });
@@ -4477,13 +4509,13 @@ async function renameEmployee(oldName, newName, opts = {}) {
4477
4509
  const newAgentPath = path9.join(agentsDir, `${newName}.md`);
4478
4510
  if (existsSync8(oldAgentPath)) {
4479
4511
  const agentContent = readFileSync5(oldAgentPath, "utf-8");
4480
- renameSync2(oldAgentPath, newAgentPath);
4512
+ renameSync3(oldAgentPath, newAgentPath);
4481
4513
  rollbackStack.push({
4482
4514
  description: "restore agent file",
4483
4515
  undo: () => {
4484
4516
  if (existsSync8(newAgentPath)) {
4485
- renameSync2(newAgentPath, oldAgentPath);
4486
- writeFileSync2(oldAgentPath, agentContent, "utf-8");
4517
+ renameSync3(newAgentPath, oldAgentPath);
4518
+ writeFileSync3(oldAgentPath, agentContent, "utf-8");
4487
4519
  }
4488
4520
  }
4489
4521
  });
@@ -4566,7 +4598,7 @@ function removeOldSymlinks(name) {
4566
4598
  const linkPath = path9.join(binDir, `${name}${suffix}`);
4567
4599
  if (existsSync8(linkPath)) {
4568
4600
  try {
4569
- unlinkSync2(linkPath);
4601
+ unlinkSync3(linkPath);
4570
4602
  } catch {
4571
4603
  }
4572
4604
  }
@@ -4609,7 +4641,7 @@ var init_exe_rename = __esm({
4609
4641
  });
4610
4642
 
4611
4643
  // src/lib/model-downloader.ts
4612
- import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync9, unlinkSync as unlinkSync3, renameSync as renameSync3 } from "fs";
4644
+ import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync9, unlinkSync as unlinkSync4, renameSync as renameSync4 } from "fs";
4613
4645
  import { mkdir as mkdir5 } from "fs/promises";
4614
4646
  import { createHash } from "crypto";
4615
4647
  import path10 from "path";
@@ -4630,7 +4662,7 @@ async function downloadModel(opts) {
4630
4662
  let downloaded = 0;
4631
4663
  for (let attempt = 1; attempt <= MAX_RETRIES2; attempt++) {
4632
4664
  try {
4633
- if (existsSync9(tmpPath)) unlinkSync3(tmpPath);
4665
+ if (existsSync9(tmpPath)) unlinkSync4(tmpPath);
4634
4666
  const response = await fetchFn(GGUF_URL, {
4635
4667
  redirect: "follow",
4636
4668
  signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
@@ -4662,12 +4694,12 @@ async function downloadModel(opts) {
4662
4694
  }
4663
4695
  const actualHash = hash.digest("hex");
4664
4696
  if (actualHash !== EXPECTED_SHA256) {
4665
- unlinkSync3(tmpPath);
4697
+ unlinkSync4(tmpPath);
4666
4698
  throw new Error(
4667
4699
  `SHA256 mismatch: expected ${EXPECTED_SHA256}, got ${actualHash}`
4668
4700
  );
4669
4701
  }
4670
- renameSync3(tmpPath, destPath);
4702
+ renameSync4(tmpPath, destPath);
4671
4703
  return destPath;
4672
4704
  } catch (err) {
4673
4705
  lastErr = err instanceof Error ? err : new Error(String(err));
@@ -4675,7 +4707,7 @@ async function downloadModel(opts) {
4675
4707
  process.stderr.write(`
4676
4708
  Download attempt ${attempt} failed, retrying...
4677
4709
  `);
4678
- if (existsSync9(tmpPath)) unlinkSync3(tmpPath);
4710
+ if (existsSync9(tmpPath)) unlinkSync4(tmpPath);
4679
4711
  }
4680
4712
  }
4681
4713
  }
@@ -4786,7 +4818,7 @@ __export(license_exports, {
4786
4818
  stopLicenseRevalidation: () => stopLicenseRevalidation,
4787
4819
  validateLicense: () => validateLicense
4788
4820
  });
4789
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
4821
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
4790
4822
  import { randomUUID as randomUUID3 } from "crypto";
4791
4823
  import path11 from "path";
4792
4824
  import { jwtVerify, importSPKI } from "jose";
@@ -4816,7 +4848,7 @@ function loadDeviceId() {
4816
4848
  }
4817
4849
  const id = randomUUID3();
4818
4850
  mkdirSync4(EXE_AI_DIR, { recursive: true });
4819
- writeFileSync3(DEVICE_ID_PATH, id, "utf8");
4851
+ writeFileSync4(DEVICE_ID_PATH, id, "utf8");
4820
4852
  return id;
4821
4853
  }
4822
4854
  function loadLicense() {
@@ -4829,7 +4861,7 @@ function loadLicense() {
4829
4861
  }
4830
4862
  function saveLicense(apiKey) {
4831
4863
  mkdirSync4(EXE_AI_DIR, { recursive: true });
4832
- writeFileSync3(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4864
+ writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
4833
4865
  }
4834
4866
  async function verifyLicenseJwt(token) {
4835
4867
  try {
@@ -4900,7 +4932,7 @@ function getRawCachedPlan() {
4900
4932
  }
4901
4933
  function cacheResponse(token) {
4902
4934
  try {
4903
- writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
4935
+ writeFileSync4(CACHE_PATH, JSON.stringify({ token }), "utf8");
4904
4936
  } catch {
4905
4937
  }
4906
4938
  }
@@ -5263,7 +5295,7 @@ __export(cloud_sync_exports, {
5263
5295
  mergeRosterFromRemote: () => mergeRosterFromRemote,
5264
5296
  recordRosterDeletion: () => recordRosterDeletion
5265
5297
  });
5266
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync11, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
5298
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync11, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
5267
5299
  import crypto3 from "crypto";
5268
5300
  import path12 from "path";
5269
5301
  import { homedir as homedir3 } from "os";
@@ -5282,7 +5314,7 @@ async function withRosterLock(fn) {
5282
5314
  try {
5283
5315
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5284
5316
  closeSync2(fd);
5285
- writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5317
+ writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
5286
5318
  } catch (err) {
5287
5319
  if (err.code === "EEXIST") {
5288
5320
  try {
@@ -5290,10 +5322,10 @@ async function withRosterLock(fn) {
5290
5322
  if (Date.now() - ts < LOCK_STALE_MS) {
5291
5323
  throw new Error("Roster merge already in progress \u2014 another sync is running");
5292
5324
  }
5293
- unlinkSync4(ROSTER_LOCK_PATH);
5325
+ unlinkSync5(ROSTER_LOCK_PATH);
5294
5326
  const fd = openSync2(ROSTER_LOCK_PATH, "wx");
5295
5327
  closeSync2(fd);
5296
- writeFileSync4(ROSTER_LOCK_PATH, String(Date.now()));
5328
+ writeFileSync5(ROSTER_LOCK_PATH, String(Date.now()));
5297
5329
  } catch (retryErr) {
5298
5330
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
5299
5331
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -5306,7 +5338,7 @@ async function withRosterLock(fn) {
5306
5338
  return await fn();
5307
5339
  } finally {
5308
5340
  try {
5309
- unlinkSync4(ROSTER_LOCK_PATH);
5341
+ unlinkSync5(ROSTER_LOCK_PATH);
5310
5342
  } catch {
5311
5343
  }
5312
5344
  }
@@ -5606,13 +5638,13 @@ function recordRosterDeletion(name) {
5606
5638
  } catch {
5607
5639
  }
5608
5640
  if (!deletions.includes(name)) deletions.push(name);
5609
- writeFileSync4(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5641
+ writeFileSync5(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
5610
5642
  }
5611
5643
  function consumeRosterDeletions() {
5612
5644
  try {
5613
5645
  if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
5614
5646
  const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
5615
- writeFileSync4(ROSTER_DELETIONS_PATH, "[]");
5647
+ writeFileSync5(ROSTER_DELETIONS_PATH, "[]");
5616
5648
  return deletions;
5617
5649
  } catch {
5618
5650
  return [];
@@ -5728,7 +5760,7 @@ function mergeConfig(remoteConfig, configPath) {
5728
5760
  const merged = { ...remoteConfig, ...local };
5729
5761
  const dir = path12.dirname(cfgPath);
5730
5762
  if (!existsSync11(dir)) mkdirSync5(dir, { recursive: true });
5731
- writeFileSync4(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5763
+ writeFileSync5(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
5732
5764
  }
5733
5765
  async function mergeRosterFromRemote(remote, paths) {
5734
5766
  return withRosterLock(async () => {
@@ -5748,7 +5780,11 @@ async function mergeRosterFromRemote(remote, paths) {
5748
5780
  } catch {
5749
5781
  }
5750
5782
  }
5751
- const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
5783
+ const lookupKey = `${remoteEmp.name}.md`;
5784
+ const matchedKey = Object.keys(remote.identities).find(
5785
+ (k) => k.toLowerCase() === lookupKey.toLowerCase()
5786
+ ) ?? lookupKey;
5787
+ const remoteIdentity = remote.identities[matchedKey];
5752
5788
  if (remoteIdentity) {
5753
5789
  if (!existsSync11(identityDir)) mkdirSync5(identityDir, { recursive: true });
5754
5790
  const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
@@ -5758,7 +5794,7 @@ async function mergeRosterFromRemote(remote, paths) {
5758
5794
  } catch {
5759
5795
  }
5760
5796
  if (localIdentity !== remoteIdentity) {
5761
- writeFileSync4(idPath, remoteIdentity, "utf-8");
5797
+ writeFileSync5(idPath, remoteIdentity, "utf-8");
5762
5798
  identitiesUpdated++;
5763
5799
  }
5764
5800
  }
@@ -6230,7 +6266,7 @@ __export(identity_exports, {
6230
6266
  listIdentities: () => listIdentities,
6231
6267
  updateIdentity: () => updateIdentity
6232
6268
  });
6233
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
6269
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
6234
6270
  import { readdirSync as readdirSync3 } from "fs";
6235
6271
  import path13 from "path";
6236
6272
  import { createHash as createHash2 } from "crypto";
@@ -6296,7 +6332,7 @@ async function updateIdentity(agentId, content, updatedBy) {
6296
6332
  ensureDir();
6297
6333
  const filePath = identityPath(agentId);
6298
6334
  const hash = contentHash(content);
6299
- writeFileSync5(filePath, content, "utf-8");
6335
+ writeFileSync6(filePath, content, "utf-8");
6300
6336
  try {
6301
6337
  const client = getClient();
6302
6338
  await client.execute({
@@ -6894,11 +6930,11 @@ __export(session_wrappers_exports, {
6894
6930
  import {
6895
6931
  existsSync as existsSync13,
6896
6932
  readFileSync as readFileSync9,
6897
- writeFileSync as writeFileSync6,
6933
+ writeFileSync as writeFileSync7,
6898
6934
  mkdirSync as mkdirSync7,
6899
6935
  chmodSync,
6900
6936
  readdirSync as readdirSync4,
6901
- unlinkSync as unlinkSync5
6937
+ unlinkSync as unlinkSync6
6902
6938
  } from "fs";
6903
6939
  import path14 from "path";
6904
6940
  import { homedir as homedir4 } from "os";
@@ -6914,7 +6950,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
6914
6950
  ];
6915
6951
  for (const src of candidates) {
6916
6952
  if (existsSync13(src)) {
6917
- writeFileSync6(exeStartDst, readFileSync9(src));
6953
+ writeFileSync7(exeStartDst, readFileSync9(src));
6918
6954
  chmodSync(exeStartDst, 493);
6919
6955
  break;
6920
6956
  }
@@ -6935,7 +6971,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
6935
6971
  try {
6936
6972
  const content = readFileSync9(fPath, "utf8");
6937
6973
  if (content.includes("exe-start")) {
6938
- unlinkSync5(fPath);
6974
+ unlinkSync6(fPath);
6939
6975
  }
6940
6976
  } catch {
6941
6977
  }
@@ -6949,7 +6985,7 @@ exec "${exeStartDst}" "$0" "$@"
6949
6985
  for (const emp of employees) {
6950
6986
  for (let n = 1; n <= MAX_N; n++) {
6951
6987
  const wrapperPath = path14.join(binDir, `${emp.name}${n}`);
6952
- writeFileSync6(wrapperPath, wrapperContent);
6988
+ writeFileSync7(wrapperPath, wrapperContent);
6953
6989
  chmodSync(wrapperPath, 493);
6954
6990
  created++;
6955
6991
  }
@@ -6985,7 +7021,7 @@ export PATH="${binDir}:$PATH"
6985
7021
  if (content.includes(".exe-os/bin")) {
6986
7022
  return false;
6987
7023
  }
6988
- writeFileSync6(profilePath, content + exportLine);
7024
+ writeFileSync7(profilePath, content + exportLine);
6989
7025
  return true;
6990
7026
  } catch {
6991
7027
  continue;
@@ -7008,8 +7044,8 @@ __export(setup_wizard_exports, {
7008
7044
  validateModel: () => validateModel
7009
7045
  });
7010
7046
  import crypto4 from "crypto";
7011
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync7, unlinkSync as unlinkSync6 } from "fs";
7012
- import os5 from "os";
7047
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync8, unlinkSync as unlinkSync7 } from "fs";
7048
+ import os6 from "os";
7013
7049
  import path15 from "path";
7014
7050
  import { createInterface as createInterface2 } from "readline";
7015
7051
  function findPackageRoot2() {
@@ -7037,11 +7073,11 @@ function loadSetupState() {
7037
7073
  }
7038
7074
  function saveSetupState(state) {
7039
7075
  mkdirSync8(path15.dirname(SETUP_STATE_PATH), { recursive: true });
7040
- writeFileSync7(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7076
+ writeFileSync8(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
7041
7077
  }
7042
7078
  function clearSetupState() {
7043
7079
  try {
7044
- unlinkSync6(SETUP_STATE_PATH);
7080
+ unlinkSync7(SETUP_STATE_PATH);
7045
7081
  } catch {
7046
7082
  }
7047
7083
  }
@@ -7247,7 +7283,7 @@ async function runSetupWizard(opts = {}) {
7247
7283
  await saveConfig(config);
7248
7284
  log("");
7249
7285
  try {
7250
- const claudeJsonPath = path15.join(os5.homedir(), ".claude.json");
7286
+ const claudeJsonPath = path15.join(os6.homedir(), ".claude.json");
7251
7287
  let claudeJson = {};
7252
7288
  try {
7253
7289
  claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
@@ -7255,11 +7291,11 @@ async function runSetupWizard(opts = {}) {
7255
7291
  }
7256
7292
  if (!claudeJson.projects) claudeJson.projects = {};
7257
7293
  const projects = claudeJson.projects;
7258
- for (const dir of [process.cwd(), os5.homedir()]) {
7294
+ for (const dir of [process.cwd(), os6.homedir()]) {
7259
7295
  if (!projects[dir]) projects[dir] = {};
7260
7296
  projects[dir].hasTrustDialogAccepted = true;
7261
7297
  }
7262
- writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7298
+ writeFileSync8(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7263
7299
  } catch {
7264
7300
  }
7265
7301
  state.completedSteps.push(5);
@@ -7295,6 +7331,54 @@ async function runSetupWizard(opts = {}) {
7295
7331
  log(`Team: ${teamList}`);
7296
7332
  createdEmployees.push(...roster.map((e) => ({ name: e.name, role: e.role })));
7297
7333
  }
7334
+ let missingIdentities = [];
7335
+ for (const emp of roster) {
7336
+ const idPath = identityPath2(emp.name);
7337
+ if (!existsSync14(idPath)) {
7338
+ missingIdentities.push(emp.name);
7339
+ }
7340
+ }
7341
+ if (missingIdentities.length > 0) {
7342
+ log("");
7343
+ log(`\u26A0 Identity files missing for: ${missingIdentities.join(", ")}`);
7344
+ log(" Your main device needs to push them to cloud first.");
7345
+ log("");
7346
+ log(" On your MAIN device, run: exe-os cloud sync");
7347
+ log(" Then come back here and press Enter to retry the pull.");
7348
+ log("");
7349
+ await ask(rl, "Press Enter after syncing from your main device... ");
7350
+ try {
7351
+ const { initSyncCrypto: retryInitCrypto } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
7352
+ const { cloudPullRoster: retryPull } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
7353
+ const retryKey = await getMasterKey();
7354
+ if (retryKey) {
7355
+ retryInitCrypto(retryKey);
7356
+ const retryConfig = await loadConfig();
7357
+ if (retryConfig.cloud?.apiKey && retryConfig.cloud?.endpoint) {
7358
+ const retryResult = await retryPull({
7359
+ apiKey: retryConfig.cloud.apiKey,
7360
+ endpoint: retryConfig.cloud.endpoint
7361
+ });
7362
+ if (retryResult.identitiesUpdated && retryResult.identitiesUpdated > 0) {
7363
+ log(`Pulled ${retryResult.identitiesUpdated} identity file(s) from cloud.`);
7364
+ }
7365
+ }
7366
+ }
7367
+ missingIdentities = [];
7368
+ for (const emp of roster) {
7369
+ if (!existsSync14(identityPath2(emp.name))) {
7370
+ missingIdentities.push(emp.name);
7371
+ }
7372
+ }
7373
+ if (missingIdentities.length > 0) {
7374
+ log(`\u26A0 Still missing: ${missingIdentities.join(", ")}. Identities will sync on next daemon cycle.`);
7375
+ } else {
7376
+ log("All identity files synced successfully.");
7377
+ }
7378
+ } catch {
7379
+ log("Retry pull failed \u2014 identities will sync when the daemon starts.");
7380
+ }
7381
+ }
7298
7382
  for (const emp of roster) {
7299
7383
  registerBinSymlinks2(emp.name);
7300
7384
  }
@@ -7340,7 +7424,7 @@ async function runSetupWizard(opts = {}) {
7340
7424
  const cooIdPath = identityPath2(cooName);
7341
7425
  mkdirSync8(path15.dirname(cooIdPath), { recursive: true });
7342
7426
  const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
7343
- writeFileSync7(cooIdPath, replaced, "utf-8");
7427
+ writeFileSync8(cooIdPath, replaced, "utf-8");
7344
7428
  }
7345
7429
  registerBinSymlinks2(cooName);
7346
7430
  createdEmployees.push({ name: cooName, role: "COO" });
@@ -7441,7 +7525,7 @@ async function runSetupWizard(opts = {}) {
7441
7525
  const ctoIdPath = identityPath2(ctoName);
7442
7526
  mkdirSync8(path15.dirname(ctoIdPath), { recursive: true });
7443
7527
  const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
7444
- writeFileSync7(ctoIdPath, replaced, "utf-8");
7528
+ writeFileSync8(ctoIdPath, replaced, "utf-8");
7445
7529
  }
7446
7530
  registerBinSymlinks2(ctoName);
7447
7531
  createdEmployees.push({ name: ctoName, role: "CTO" });
@@ -7469,7 +7553,7 @@ async function runSetupWizard(opts = {}) {
7469
7553
  const cmoIdPath = identityPath2(cmoName);
7470
7554
  mkdirSync8(path15.dirname(cmoIdPath), { recursive: true });
7471
7555
  const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
7472
- writeFileSync7(cmoIdPath, replaced, "utf-8");
7556
+ writeFileSync8(cmoIdPath, replaced, "utf-8");
7473
7557
  }
7474
7558
  registerBinSymlinks2(cmoName);
7475
7559
  createdEmployees.push({ name: cmoName, role: "CMO" });
@@ -7541,7 +7625,7 @@ var init_setup_wizard = __esm({
7541
7625
  init_config();
7542
7626
  init_keychain();
7543
7627
  init_model_downloader();
7544
- SETUP_STATE_PATH = path15.join(os5.homedir(), ".exe-os", "setup-state.json");
7628
+ SETUP_STATE_PATH = path15.join(os6.homedir(), ".exe-os", "setup-state.json");
7545
7629
  }
7546
7630
  });
7547
7631
 
@@ -14104,10 +14188,10 @@ __export(session_registry_exports, {
14104
14188
  pruneStaleSessions: () => pruneStaleSessions,
14105
14189
  registerSession: () => registerSession
14106
14190
  });
14107
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, existsSync as existsSync16 } from "fs";
14191
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, existsSync as existsSync16 } from "fs";
14108
14192
  import { execSync as execSync6 } from "child_process";
14109
14193
  import path17 from "path";
14110
- import os6 from "os";
14194
+ import os7 from "os";
14111
14195
  function registerSession(entry) {
14112
14196
  const dir = path17.dirname(REGISTRY_PATH);
14113
14197
  if (!existsSync16(dir)) {
@@ -14120,7 +14204,7 @@ function registerSession(entry) {
14120
14204
  } else {
14121
14205
  sessions.push(entry);
14122
14206
  }
14123
- writeFileSync8(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
14207
+ writeFileSync9(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
14124
14208
  }
14125
14209
  function listSessions() {
14126
14210
  try {
@@ -14145,7 +14229,7 @@ function pruneStaleSessions() {
14145
14229
  const alive = sessions.filter((s) => liveSet.has(s.windowName));
14146
14230
  const pruned = sessions.length - alive.length;
14147
14231
  if (pruned > 0) {
14148
- writeFileSync8(REGISTRY_PATH, JSON.stringify(alive, null, 2));
14232
+ writeFileSync9(REGISTRY_PATH, JSON.stringify(alive, null, 2));
14149
14233
  }
14150
14234
  return pruned;
14151
14235
  }
@@ -14153,7 +14237,7 @@ var REGISTRY_PATH;
14153
14237
  var init_session_registry = __esm({
14154
14238
  "src/lib/session-registry.ts"() {
14155
14239
  "use strict";
14156
- REGISTRY_PATH = path17.join(os6.homedir(), ".exe-os", "session-registry.json");
14240
+ REGISTRY_PATH = path17.join(os7.homedir(), ".exe-os", "session-registry.json");
14157
14241
  }
14158
14242
  });
14159
14243
 
@@ -14358,9 +14442,9 @@ var init_provider_table = __esm({
14358
14442
  });
14359
14443
 
14360
14444
  // src/lib/intercom-queue.ts
14361
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, renameSync as renameSync4, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
14445
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, renameSync as renameSync5, existsSync as existsSync17, mkdirSync as mkdirSync10 } from "fs";
14362
14446
  import path18 from "path";
14363
- import os7 from "os";
14447
+ import os8 from "os";
14364
14448
  function ensureDir2() {
14365
14449
  const dir = path18.dirname(QUEUE_PATH);
14366
14450
  if (!existsSync17(dir)) mkdirSync10(dir, { recursive: true });
@@ -14376,8 +14460,8 @@ function readQueue() {
14376
14460
  function writeQueue(queue) {
14377
14461
  ensureDir2();
14378
14462
  const tmp = `${QUEUE_PATH}.tmp`;
14379
- writeFileSync9(tmp, JSON.stringify(queue, null, 2));
14380
- renameSync4(tmp, QUEUE_PATH);
14463
+ writeFileSync10(tmp, JSON.stringify(queue, null, 2));
14464
+ renameSync5(tmp, QUEUE_PATH);
14381
14465
  }
14382
14466
  function queueIntercom(targetSession, reason) {
14383
14467
  const queue = readQueue();
@@ -14400,9 +14484,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
14400
14484
  var init_intercom_queue = __esm({
14401
14485
  "src/lib/intercom-queue.ts"() {
14402
14486
  "use strict";
14403
- QUEUE_PATH = path18.join(os7.homedir(), ".exe-os", "intercom-queue.json");
14487
+ QUEUE_PATH = path18.join(os8.homedir(), ".exe-os", "intercom-queue.json");
14404
14488
  TTL_MS = 60 * 60 * 1e3;
14405
- INTERCOM_LOG = path18.join(os7.homedir(), ".exe-os", "intercom.log");
14489
+ INTERCOM_LOG = path18.join(os8.homedir(), ".exe-os", "intercom.log");
14406
14490
  }
14407
14491
  });
14408
14492
 
@@ -14487,11 +14571,11 @@ var init_plan_limits = __esm({
14487
14571
  // src/lib/notifications.ts
14488
14572
  import crypto5 from "crypto";
14489
14573
  import path20 from "path";
14490
- import os8 from "os";
14574
+ import os9 from "os";
14491
14575
  import {
14492
14576
  readFileSync as readFileSync16,
14493
14577
  readdirSync as readdirSync5,
14494
- unlinkSync as unlinkSync7,
14578
+ unlinkSync as unlinkSync8,
14495
14579
  existsSync as existsSync19,
14496
14580
  rmdirSync
14497
14581
  } from "fs";
@@ -15003,7 +15087,7 @@ var init_tasks_crud = __esm({
15003
15087
 
15004
15088
  // src/lib/tasks-review.ts
15005
15089
  import path22 from "path";
15006
- import { existsSync as existsSync21, readdirSync as readdirSync6, unlinkSync as unlinkSync8 } from "fs";
15090
+ import { existsSync as existsSync21, readdirSync as readdirSync6, unlinkSync as unlinkSync9 } from "fs";
15007
15091
  async function countPendingReviews(sessionScope) {
15008
15092
  const client = getClient();
15009
15093
  if (sessionScope) {
@@ -15188,7 +15272,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
15188
15272
  if (existsSync21(cacheDir)) {
15189
15273
  for (const f of readdirSync6(cacheDir)) {
15190
15274
  if (f.startsWith("review-notified-")) {
15191
- unlinkSync8(path22.join(cacheDir, f));
15275
+ unlinkSync9(path22.join(cacheDir, f));
15192
15276
  }
15193
15277
  }
15194
15278
  }
@@ -15794,7 +15878,7 @@ __export(tasks_exports, {
15794
15878
  writeCheckpoint: () => writeCheckpoint
15795
15879
  });
15796
15880
  import path25 from "path";
15797
- import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, unlinkSync as unlinkSync9 } from "fs";
15881
+ import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync11, unlinkSync as unlinkSync10 } from "fs";
15798
15882
  async function createTask(input) {
15799
15883
  const result = await createTaskCore(input);
15800
15884
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -15817,10 +15901,10 @@ async function updateTask(input) {
15817
15901
  const cachePath = path25.join(cacheDir, `current-task-${agent}.json`);
15818
15902
  if (input.status === "in_progress") {
15819
15903
  mkdirSync11(cacheDir, { recursive: true });
15820
- writeFileSync10(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
15904
+ writeFileSync11(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
15821
15905
  } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
15822
15906
  try {
15823
- unlinkSync9(cachePath);
15907
+ unlinkSync10(cachePath);
15824
15908
  } catch {
15825
15909
  }
15826
15910
  }
@@ -16262,11 +16346,11 @@ __export(tmux_routing_exports, {
16262
16346
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
16263
16347
  });
16264
16348
  import { execFileSync as execFileSync3, execSync as execSync11 } from "child_process";
16265
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, existsSync as existsSync22, appendFileSync as appendFileSync2 } from "fs";
16349
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync12, existsSync as existsSync22, appendFileSync as appendFileSync2 } from "fs";
16266
16350
  import path26 from "path";
16267
- import os9 from "os";
16351
+ import os10 from "os";
16268
16352
  import { fileURLToPath as fileURLToPath4 } from "url";
16269
- import { unlinkSync as unlinkSync10 } from "fs";
16353
+ import { unlinkSync as unlinkSync11 } from "fs";
16270
16354
  function spawnLockPath(sessionName) {
16271
16355
  return path26.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
16272
16356
  }
@@ -16293,12 +16377,12 @@ function acquireSpawnLock2(sessionName) {
16293
16377
  } catch {
16294
16378
  }
16295
16379
  }
16296
- writeFileSync11(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
16380
+ writeFileSync12(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
16297
16381
  return true;
16298
16382
  }
16299
16383
  function releaseSpawnLock2(sessionName) {
16300
16384
  try {
16301
- unlinkSync10(spawnLockPath(sessionName));
16385
+ unlinkSync11(spawnLockPath(sessionName));
16302
16386
  } catch {
16303
16387
  }
16304
16388
  }
@@ -16380,7 +16464,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
16380
16464
  }
16381
16465
  const rootExe = extractRootExe(parentExe) ?? parentExe;
16382
16466
  const filePath = path26.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
16383
- writeFileSync11(filePath, JSON.stringify({
16467
+ writeFileSync12(filePath, JSON.stringify({
16384
16468
  parentExe: rootExe,
16385
16469
  dispatchedBy: dispatchedBy || rootExe,
16386
16470
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -16467,7 +16551,7 @@ function readDebounceState() {
16467
16551
  function writeDebounceState(state) {
16468
16552
  try {
16469
16553
  if (!existsSync22(SESSION_CACHE)) mkdirSync12(SESSION_CACHE, { recursive: true });
16470
- writeFileSync11(DEBOUNCE_FILE, JSON.stringify(state));
16554
+ writeFileSync12(DEBOUNCE_FILE, JSON.stringify(state));
16471
16555
  } catch {
16472
16556
  }
16473
16557
  }
@@ -16656,7 +16740,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16656
16740
  const transport = getTransport();
16657
16741
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
16658
16742
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
16659
- const logDir = path26.join(os9.homedir(), ".exe-os", "session-logs");
16743
+ const logDir = path26.join(os10.homedir(), ".exe-os", "session-logs");
16660
16744
  const logFile = path26.join(logDir, `${instanceLabel}-${Date.now()}.log`);
16661
16745
  if (!existsSync22(logDir)) {
16662
16746
  mkdirSync12(logDir, { recursive: true });
@@ -16672,7 +16756,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16672
16756
  } catch {
16673
16757
  }
16674
16758
  try {
16675
- const claudeJsonPath = path26.join(os9.homedir(), ".claude.json");
16759
+ const claudeJsonPath = path26.join(os10.homedir(), ".claude.json");
16676
16760
  let claudeJson = {};
16677
16761
  try {
16678
16762
  claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
@@ -16683,11 +16767,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16683
16767
  const trustDir = opts?.cwd ?? projectDir;
16684
16768
  if (!projects[trustDir]) projects[trustDir] = {};
16685
16769
  projects[trustDir].hasTrustDialogAccepted = true;
16686
- writeFileSync11(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
16770
+ writeFileSync12(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
16687
16771
  } catch {
16688
16772
  }
16689
16773
  try {
16690
- const settingsDir = path26.join(os9.homedir(), ".claude", "projects");
16774
+ const settingsDir = path26.join(os10.homedir(), ".claude", "projects");
16691
16775
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
16692
16776
  const projSettingsDir = path26.join(settingsDir, normalizedKey);
16693
16777
  const settingsPath = path26.join(projSettingsDir, "settings.json");
@@ -16722,7 +16806,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16722
16806
  perms.allow = allow;
16723
16807
  settings.permissions = perms;
16724
16808
  mkdirSync12(projSettingsDir, { recursive: true });
16725
- writeFileSync11(settingsPath, JSON.stringify(settings, null, 2) + "\n");
16809
+ writeFileSync12(settingsPath, JSON.stringify(settings, null, 2) + "\n");
16726
16810
  }
16727
16811
  } catch {
16728
16812
  }
@@ -16735,7 +16819,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16735
16819
  let legacyFallbackWarned = false;
16736
16820
  if (!useExeAgent && !useBinSymlink) {
16737
16821
  const identityPath2 = path26.join(
16738
- os9.homedir(),
16822
+ os10.homedir(),
16739
16823
  ".exe-os",
16740
16824
  "identity",
16741
16825
  `${employeeName}.md`
@@ -16765,7 +16849,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16765
16849
  }
16766
16850
  let sessionContextFlag = "";
16767
16851
  try {
16768
- const ctxDir = path26.join(os9.homedir(), ".exe-os", "session-cache");
16852
+ const ctxDir = path26.join(os10.homedir(), ".exe-os", "session-cache");
16769
16853
  mkdirSync12(ctxDir, { recursive: true });
16770
16854
  const ctxFile = path26.join(ctxDir, `session-context-${sessionName}.md`);
16771
16855
  const ctxContent = [
@@ -16774,7 +16858,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16774
16858
  `Your parent exe session is ${exeSession}.`,
16775
16859
  `Your employees (if any) use the -${exeSession} suffix (e.g., tom-${exeSession}).`
16776
16860
  ].join("\n");
16777
- writeFileSync11(ctxFile, ctxContent);
16861
+ writeFileSync12(ctxFile, ctxContent);
16778
16862
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
16779
16863
  } catch {
16780
16864
  }
@@ -16813,7 +16897,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16813
16897
  try {
16814
16898
  const mySession = getMySession();
16815
16899
  const dispatchInfo = path26.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
16816
- writeFileSync11(dispatchInfo, JSON.stringify({
16900
+ writeFileSync12(dispatchInfo, JSON.stringify({
16817
16901
  dispatchedBy: mySession,
16818
16902
  rootExe: exeSession,
16819
16903
  provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
@@ -16876,13 +16960,13 @@ var init_tmux_routing = __esm({
16876
16960
  init_provider_table();
16877
16961
  init_intercom_queue();
16878
16962
  init_plan_limits();
16879
- SPAWN_LOCK_DIR = path26.join(os9.homedir(), ".exe-os", "spawn-locks");
16880
- SESSION_CACHE = path26.join(os9.homedir(), ".exe-os", "session-cache");
16963
+ SPAWN_LOCK_DIR = path26.join(os10.homedir(), ".exe-os", "spawn-locks");
16964
+ SESSION_CACHE = path26.join(os10.homedir(), ".exe-os", "session-cache");
16881
16965
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
16882
16966
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
16883
16967
  VERIFY_PANE_LINES = 200;
16884
16968
  INTERCOM_DEBOUNCE_MS = 3e4;
16885
- INTERCOM_LOG2 = path26.join(os9.homedir(), ".exe-os", "intercom.log");
16969
+ INTERCOM_LOG2 = path26.join(os10.homedir(), ".exe-os", "intercom.log");
16886
16970
  DEBOUNCE_FILE = path26.join(SESSION_CACHE, "intercom-debounce.json");
16887
16971
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
16888
16972
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -19340,7 +19424,7 @@ var init_hooks = __esm({
19340
19424
 
19341
19425
  // src/runtime/safety-checks.ts
19342
19426
  import path27 from "path";
19343
- import os10 from "os";
19427
+ import os11 from "os";
19344
19428
  function checkPathSafety(filePath) {
19345
19429
  const resolved = path27.resolve(filePath);
19346
19430
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
@@ -19367,7 +19451,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
19367
19451
  var init_safety_checks = __esm({
19368
19452
  "src/runtime/safety-checks.ts"() {
19369
19453
  "use strict";
19370
- HOME = os10.homedir();
19454
+ HOME = os11.homedir();
19371
19455
  BYPASS_IMMUNE_PATTERNS = [
19372
19456
  {
19373
19457
  pattern: /\/\.git\/hooks\//,
@@ -24532,9 +24616,9 @@ Unhandled rejection: ${reason}
24532
24616
  });
24533
24617
 
24534
24618
  // src/bin/cli.ts
24535
- import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync12, readdirSync as readdirSync7, rmSync } from "fs";
24619
+ import { existsSync as existsSync23, readFileSync as readFileSync19, writeFileSync as writeFileSync13, readdirSync as readdirSync7, rmSync } from "fs";
24536
24620
  import path35 from "path";
24537
- import os11 from "os";
24621
+ import os12 from "os";
24538
24622
  var args = process.argv.slice(2);
24539
24623
  if (args.includes("--global")) {
24540
24624
  process.stderr.write(
@@ -24597,7 +24681,7 @@ if (args.includes("--global")) {
24597
24681
  });
24598
24682
  await init_App2().then(() => App_exports);
24599
24683
  } else {
24600
- const claudeDir = path35.join(os11.homedir(), ".claude");
24684
+ const claudeDir = path35.join(os12.homedir(), ".claude");
24601
24685
  const settingsPath = path35.join(claudeDir, "settings.json");
24602
24686
  const hasClaudeCode = existsSync23(settingsPath) && (() => {
24603
24687
  try {
@@ -24608,13 +24692,24 @@ if (args.includes("--global")) {
24608
24692
  }
24609
24693
  })();
24610
24694
  if (hasClaudeCode) {
24695
+ let cooName = "exe";
24696
+ try {
24697
+ const rosterPath = path35.join(os12.homedir(), ".exe-os", "exe-employees.json");
24698
+ if (existsSync23(rosterPath)) {
24699
+ const roster = JSON.parse(readFileSync19(rosterPath, "utf8"));
24700
+ const coo = roster.find((e) => e.role === "COO");
24701
+ if (coo) cooName = coo.name;
24702
+ }
24703
+ } catch {
24704
+ }
24611
24705
  console.log(`
24612
24706
  \x1B[1mexe-os\x1B[0m \u2014 AI Employee Operating System
24613
24707
 
24614
24708
  \x1B[33mMode 1 detected:\x1B[0m Claude Code integration is installed.
24615
- Open Claude Code and run \x1B[1m/exe\x1B[0m to boot your COO.
24709
+ cd into a project folder and run \x1B[1m${cooName}1\x1B[0m to boot your COO.
24616
24710
 
24617
24711
  \x1B[2mCommands:\x1B[0m
24712
+ ${cooName}1 Launch COO in project folder
24618
24713
  exe-os update Check for and install updates
24619
24714
  exe-os setup Re-run setup wizard
24620
24715
  exe-os claude check Verify Claude Code integration
@@ -24640,9 +24735,9 @@ async function runClaudeInstall() {
24640
24735
  }
24641
24736
  }
24642
24737
  async function runClaudeCheck() {
24643
- const claudeDir = path35.join(os11.homedir(), ".claude");
24738
+ const claudeDir = path35.join(os12.homedir(), ".claude");
24644
24739
  const settingsPath = path35.join(claudeDir, "settings.json");
24645
- const claudeJsonPath = path35.join(os11.homedir(), ".claude.json");
24740
+ const claudeJsonPath = path35.join(os12.homedir(), ".claude.json");
24646
24741
  let ok = true;
24647
24742
  if (existsSync23(settingsPath)) {
24648
24743
  let settings;
@@ -24712,7 +24807,7 @@ async function runClaudeCheck() {
24712
24807
  async function runClaudeUninstall(flags = []) {
24713
24808
  const dryRun = flags.includes("--dry-run");
24714
24809
  const purge = flags.includes("--purge");
24715
- const homeDir = os11.homedir();
24810
+ const homeDir = os12.homedir();
24716
24811
  const claudeDir = path35.join(homeDir, ".claude");
24717
24812
  const settingsPath = path35.join(claudeDir, "settings.json");
24718
24813
  const claudeJsonPath = path35.join(homeDir, ".claude.json");
@@ -24760,7 +24855,7 @@ async function runClaudeUninstall(flags = []) {
24760
24855
  permCount = before - settings.permissions.allow.length;
24761
24856
  }
24762
24857
  if (!dryRun) {
24763
- writeFileSync12(settingsPath, JSON.stringify(settings, null, 2) + "\n");
24858
+ writeFileSync13(settingsPath, JSON.stringify(settings, null, 2) + "\n");
24764
24859
  }
24765
24860
  log("\u2713 Removed exe-os hooks from settings.json");
24766
24861
  if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
@@ -24789,7 +24884,7 @@ async function runClaudeUninstall(flags = []) {
24789
24884
  }
24790
24885
  if (removedMcp) {
24791
24886
  if (!dryRun) {
24792
- writeFileSync12(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
24887
+ writeFileSync13(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
24793
24888
  }
24794
24889
  log("\u2713 Removed exe-os MCP server from claude.json");
24795
24890
  removed++;
@@ -24825,7 +24920,7 @@ async function runClaudeUninstall(flags = []) {
24825
24920
  const endIdx = content.indexOf(endMarker);
24826
24921
  if (startIdx !== -1 && endIdx !== -1) {
24827
24922
  const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
24828
- if (!dryRun) writeFileSync12(claudeMdPath, cleaned);
24923
+ if (!dryRun) writeFileSync13(claudeMdPath, cleaned);
24829
24924
  log("\u2713 Removed orchestration block from CLAUDE.md");
24830
24925
  removed++;
24831
24926
  }
@@ -24877,7 +24972,7 @@ async function runClaudeUninstall(flags = []) {
24877
24972
  if (pSettings.permissions.allow.length < before) changed = true;
24878
24973
  }
24879
24974
  if (changed && !dryRun) {
24880
- writeFileSync12(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
24975
+ writeFileSync13(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
24881
24976
  }
24882
24977
  if (changed) projectCount++;
24883
24978
  } catch {