@askexenow/exe-os 0.8.65 → 0.8.69

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 (54) hide show
  1. package/dist/bin/cleanup-stale-review-tasks.js +8 -7
  2. package/dist/bin/cli.js +204 -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 +84 -19
  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-status.js +16 -15
  20. package/dist/bin/exe-team.js +4 -3
  21. package/dist/bin/git-sweep.js +31 -30
  22. package/dist/bin/install.js +284 -113
  23. package/dist/bin/scan-tasks.js +33 -32
  24. package/dist/bin/setup.js +114 -30
  25. package/dist/gateway/index.js +32 -31
  26. package/dist/hooks/bug-report-worker.js +58 -26
  27. package/dist/hooks/commit-complete.js +31 -30
  28. package/dist/hooks/ingest-worker.js +58 -57
  29. package/dist/hooks/post-compact.js +10 -9
  30. package/dist/hooks/pre-compact.js +31 -30
  31. package/dist/hooks/pre-tool-use.js +46 -14
  32. package/dist/hooks/prompt-ingest-worker.js +15 -14
  33. package/dist/hooks/prompt-submit.js +15 -14
  34. package/dist/hooks/response-ingest-worker.js +8 -7
  35. package/dist/hooks/session-end.js +14 -13
  36. package/dist/hooks/session-start.js +10 -9
  37. package/dist/hooks/stop.js +10 -9
  38. package/dist/hooks/subagent-stop.js +10 -9
  39. package/dist/hooks/summary-worker.js +41 -36
  40. package/dist/index.js +43 -42
  41. package/dist/lib/cloud-sync.js +16 -11
  42. package/dist/lib/employees.js +33 -1
  43. package/dist/lib/exe-daemon.js +56 -55
  44. package/dist/lib/messaging.js +9 -8
  45. package/dist/lib/tasks.js +27 -26
  46. package/dist/lib/tmux-routing.js +29 -28
  47. package/dist/mcp/server.js +94 -62
  48. package/dist/mcp/tools/create-task.js +60 -28
  49. package/dist/mcp/tools/list-tasks.js +10 -9
  50. package/dist/mcp/tools/send-message.js +11 -10
  51. package/dist/mcp/tools/update-task.js +21 -20
  52. package/dist/runtime/index.js +31 -30
  53. package/dist/tui/App.js +67 -35
  54. package/package.json +1 -1
@@ -1614,9 +1614,10 @@ ${p.content}`).join("\n\n");
1614
1614
 
1615
1615
  // src/lib/employees.ts
1616
1616
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1617
- import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
1617
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
1618
1618
  import { execSync } from "child_process";
1619
1619
  import path4 from "path";
1620
+ import os3 from "os";
1620
1621
  var EMPLOYEES_PATH;
1621
1622
  var init_employees = __esm({
1622
1623
  "src/lib/employees.ts"() {
@@ -1629,11 +1630,11 @@ var init_employees = __esm({
1629
1630
  // src/lib/notifications.ts
1630
1631
  import crypto from "crypto";
1631
1632
  import path5 from "path";
1632
- import os3 from "os";
1633
+ import os4 from "os";
1633
1634
  import {
1634
1635
  readFileSync as readFileSync3,
1635
1636
  readdirSync as readdirSync2,
1636
- unlinkSync,
1637
+ unlinkSync as unlinkSync2,
1637
1638
  existsSync as existsSync5,
1638
1639
  rmdirSync
1639
1640
  } from "fs";
@@ -1646,12 +1647,12 @@ var init_notifications = __esm({
1646
1647
 
1647
1648
  // src/lib/session-registry.ts
1648
1649
  import path6 from "path";
1649
- import os4 from "os";
1650
+ import os5 from "os";
1650
1651
  var REGISTRY_PATH;
1651
1652
  var init_session_registry = __esm({
1652
1653
  "src/lib/session-registry.ts"() {
1653
1654
  "use strict";
1654
- REGISTRY_PATH = path6.join(os4.homedir(), ".exe-os", "session-registry.json");
1655
+ REGISTRY_PATH = path6.join(os5.homedir(), ".exe-os", "session-registry.json");
1655
1656
  }
1656
1657
  });
1657
1658
 
@@ -1827,21 +1828,21 @@ var init_provider_table = __esm({
1827
1828
  });
1828
1829
 
1829
1830
  // src/lib/intercom-queue.ts
1830
- import { readFileSync as readFileSync4, writeFileSync, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1831
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
1831
1832
  import path7 from "path";
1832
- import os5 from "os";
1833
+ import os6 from "os";
1833
1834
  var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
1834
1835
  var init_intercom_queue = __esm({
1835
1836
  "src/lib/intercom-queue.ts"() {
1836
1837
  "use strict";
1837
- QUEUE_PATH = path7.join(os5.homedir(), ".exe-os", "intercom-queue.json");
1838
+ QUEUE_PATH = path7.join(os6.homedir(), ".exe-os", "intercom-queue.json");
1838
1839
  TTL_MS = 60 * 60 * 1e3;
1839
- INTERCOM_LOG = path7.join(os5.homedir(), ".exe-os", "intercom.log");
1840
+ INTERCOM_LOG = path7.join(os6.homedir(), ".exe-os", "intercom.log");
1840
1841
  }
1841
1842
  });
1842
1843
 
1843
1844
  // src/lib/license.ts
1844
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
1845
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
1845
1846
  import { randomUUID as randomUUID2 } from "crypto";
1846
1847
  import path8 from "path";
1847
1848
  import { jwtVerify, importSPKI } from "jose";
@@ -1872,9 +1873,9 @@ var init_plan_limits = __esm({
1872
1873
  });
1873
1874
 
1874
1875
  // src/lib/tmux-routing.ts
1875
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync9, appendFileSync } from "fs";
1876
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync9, appendFileSync } from "fs";
1876
1877
  import path10 from "path";
1877
- import os6 from "os";
1878
+ import os7 from "os";
1878
1879
  import { fileURLToPath as fileURLToPath2 } from "url";
1879
1880
  function getMySession() {
1880
1881
  return getTransport().getMySession();
@@ -1916,9 +1917,9 @@ var init_tmux_routing = __esm({
1916
1917
  init_provider_table();
1917
1918
  init_intercom_queue();
1918
1919
  init_plan_limits();
1919
- SPAWN_LOCK_DIR = path10.join(os6.homedir(), ".exe-os", "spawn-locks");
1920
- SESSION_CACHE = path10.join(os6.homedir(), ".exe-os", "session-cache");
1921
- INTERCOM_LOG2 = path10.join(os6.homedir(), ".exe-os", "intercom.log");
1920
+ SPAWN_LOCK_DIR = path10.join(os7.homedir(), ".exe-os", "spawn-locks");
1921
+ SESSION_CACHE = path10.join(os7.homedir(), ".exe-os", "session-cache");
1922
+ INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
1922
1923
  DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
1923
1924
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1924
1925
  }
@@ -1926,7 +1927,7 @@ var init_tmux_routing = __esm({
1926
1927
 
1927
1928
  // src/lib/tasks-review.ts
1928
1929
  import path11 from "path";
1929
- import { existsSync as existsSync10, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
1930
+ import { existsSync as existsSync10, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
1930
1931
  async function listPendingReviews(limit, sessionScope) {
1931
1932
  const client = getClient();
1932
1933
  if (sessionScope) {
@@ -1986,8 +1987,8 @@ var init_task_scope = __esm({
1986
1987
 
1987
1988
  // src/bin/exe-heartbeat.ts
1988
1989
  import { createHash } from "crypto";
1989
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
1990
- import os7 from "os";
1990
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
1991
+ import os8 from "os";
1991
1992
  import path12 from "path";
1992
1993
 
1993
1994
  // src/lib/store.ts
@@ -2148,7 +2149,7 @@ var MESSAGE_PREVIEW_CHARS = 80;
2148
2149
  var MARKER_FILENAME = "exe-heartbeat-marker.json";
2149
2150
  var SESSION_CACHE_SUBDIR = "session-cache";
2150
2151
  function resolveExeOsDir() {
2151
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path12.join(os7.homedir(), ".exe-os");
2152
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path12.join(os8.homedir(), ".exe-os");
2152
2153
  }
2153
2154
  function getMarkerDir() {
2154
2155
  return path12.join(resolveExeOsDir(), SESSION_CACHE_SUBDIR);
@@ -2172,7 +2173,7 @@ function readMarker() {
2172
2173
  function writeMarker(marker) {
2173
2174
  try {
2174
2175
  mkdirSync5(getMarkerDir(), { recursive: true });
2175
- writeFileSync4(getMarkerPath(), JSON.stringify(marker));
2176
+ writeFileSync5(getMarkerPath(), JSON.stringify(marker));
2176
2177
  } catch {
2177
2178
  }
2178
2179
  }
@@ -2170,14 +2170,16 @@ __export(employees_exports, {
2170
2170
  isMultiInstance: () => isMultiInstance,
2171
2171
  loadEmployees: () => loadEmployees,
2172
2172
  loadEmployeesSync: () => loadEmployeesSync,
2173
+ normalizeRosterCase: () => normalizeRosterCase,
2173
2174
  registerBinSymlinks: () => registerBinSymlinks,
2174
2175
  saveEmployees: () => saveEmployees,
2175
2176
  validateEmployeeName: () => validateEmployeeName
2176
2177
  });
2177
2178
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
2178
- import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
2179
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
2179
2180
  import { execSync as execSync2 } from "child_process";
2180
2181
  import path5 from "path";
2182
+ import os4 from "os";
2181
2183
  function validateEmployeeName(name) {
2182
2184
  if (!name) {
2183
2185
  return { valid: false, error: "Name is required" };
@@ -2245,6 +2247,36 @@ function addEmployee(employees, employee) {
2245
2247
  }
2246
2248
  return [...employees, normalized];
2247
2249
  }
2250
+ async function normalizeRosterCase(rosterPath) {
2251
+ const employees = await loadEmployees(rosterPath);
2252
+ let changed = false;
2253
+ for (const emp of employees) {
2254
+ if (emp.name !== emp.name.toLowerCase()) {
2255
+ const oldName = emp.name;
2256
+ emp.name = emp.name.toLowerCase();
2257
+ changed = true;
2258
+ try {
2259
+ const identityDir = path5.join(os4.homedir(), ".exe-os", "identity");
2260
+ const oldPath = path5.join(identityDir, `${oldName}.md`);
2261
+ const newPath = path5.join(identityDir, `${emp.name}.md`);
2262
+ if (existsSync5(oldPath) && !existsSync5(newPath)) {
2263
+ renameSync2(oldPath, newPath);
2264
+ } else if (existsSync5(oldPath) && oldPath !== newPath) {
2265
+ const content = readFileSync2(oldPath, "utf-8");
2266
+ writeFileSync2(newPath, content, "utf-8");
2267
+ if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
2268
+ unlinkSync2(oldPath);
2269
+ }
2270
+ }
2271
+ } catch {
2272
+ }
2273
+ }
2274
+ }
2275
+ if (changed) {
2276
+ await saveEmployees(employees, rosterPath);
2277
+ }
2278
+ return changed;
2279
+ }
2248
2280
  function findExeBin() {
2249
2281
  try {
2250
2282
  return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
@@ -2347,7 +2379,7 @@ __export(active_agent_exports, {
2347
2379
  getAllActiveAgents: () => getAllActiveAgents,
2348
2380
  writeActiveAgent: () => writeActiveAgent
2349
2381
  });
2350
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync3 } from "fs";
2382
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
2351
2383
  import { execSync as execSync4 } from "child_process";
2352
2384
  import path6 from "path";
2353
2385
  function getMarkerPath() {
@@ -2356,7 +2388,7 @@ function getMarkerPath() {
2356
2388
  function writeActiveAgent(agentId, agentRole) {
2357
2389
  try {
2358
2390
  mkdirSync3(CACHE_DIR, { recursive: true });
2359
- writeFileSync2(
2391
+ writeFileSync3(
2360
2392
  getMarkerPath(),
2361
2393
  JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
2362
2394
  );
@@ -2365,7 +2397,7 @@ function writeActiveAgent(agentId, agentRole) {
2365
2397
  }
2366
2398
  function clearActiveAgent() {
2367
2399
  try {
2368
- unlinkSync2(getMarkerPath());
2400
+ unlinkSync3(getMarkerPath());
2369
2401
  } catch {
2370
2402
  }
2371
2403
  }
@@ -2379,7 +2411,7 @@ function getActiveAgent() {
2379
2411
  const age = Date.now() - new Date(data.startedAt).getTime();
2380
2412
  if (age > STALE_MS) {
2381
2413
  try {
2382
- unlinkSync2(markerPath);
2414
+ unlinkSync3(markerPath);
2383
2415
  } catch {
2384
2416
  }
2385
2417
  } else {
@@ -2432,7 +2464,7 @@ function getAllActiveAgents() {
2432
2464
  const age = Date.now() - new Date(data.startedAt).getTime();
2433
2465
  if (age > STALE_MS) {
2434
2466
  try {
2435
- unlinkSync2(path6.join(CACHE_DIR, file));
2467
+ unlinkSync3(path6.join(CACHE_DIR, file));
2436
2468
  } catch {
2437
2469
  }
2438
2470
  continue;
@@ -2455,11 +2487,11 @@ function getAllActiveAgents() {
2455
2487
  function cleanupSessionMarkers() {
2456
2488
  const key = getSessionKey();
2457
2489
  try {
2458
- unlinkSync2(path6.join(CACHE_DIR, `active-agent-${key}.json`));
2490
+ unlinkSync3(path6.join(CACHE_DIR, `active-agent-${key}.json`));
2459
2491
  } catch {
2460
2492
  }
2461
2493
  try {
2462
- unlinkSync2(path6.join(CACHE_DIR, "active-agent-undefined.json"));
2494
+ unlinkSync3(path6.join(CACHE_DIR, "active-agent-undefined.json"));
2463
2495
  } catch {
2464
2496
  }
2465
2497
  }
@@ -2475,9 +2507,9 @@ var init_active_agent = __esm({
2475
2507
  });
2476
2508
 
2477
2509
  // src/bin/exe-launch-agent.ts
2478
- import os4 from "os";
2510
+ import os5 from "os";
2479
2511
  import path7 from "path";
2480
- import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, readdirSync as readdirSync4 } from "fs";
2512
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync4 } from "fs";
2481
2513
  import { spawnSync } from "child_process";
2482
2514
 
2483
2515
  // src/lib/store.ts
@@ -2972,7 +3004,7 @@ function parseBasename(basename) {
2972
3004
  function resolveAgent(argv) {
2973
3005
  const invokedAs = path7.basename(argv[1] ?? "");
2974
3006
  if (invokedAs && invokedAs !== "exe-launch-agent" && !invokedAs.endsWith(".js")) {
2975
- const { agent: agent2, provider } = parseBasename(invokedAs);
3007
+ const { agent: agent2, provider } = parseBasename(invokedAs.toLowerCase());
2976
3008
  return { agent: agent2, provider, passthrough: argv.slice(2) };
2977
3009
  }
2978
3010
  const rest = argv.slice(2);
@@ -2982,7 +3014,7 @@ function resolveAgent(argv) {
2982
3014
  "exe-launch-agent: missing --agent <name>. Invoke via the per-agent symlink (exe/yoshi/tom/mari/sasha) or pass --agent explicitly."
2983
3015
  );
2984
3016
  }
2985
- const agent = rest[agentIdx + 1];
3017
+ const agent = rest[agentIdx + 1].toLowerCase();
2986
3018
  const passthrough = [...rest.slice(0, agentIdx), ...rest.slice(agentIdx + 2)];
2987
3019
  return { agent, provider: DEFAULT_PROVIDER, passthrough };
2988
3020
  }
@@ -2997,10 +3029,19 @@ async function isKnownAgent(agent) {
2997
3029
  }
2998
3030
  }
2999
3031
  function identityPathFor(agent) {
3000
- return path7.join(os4.homedir(), ".exe-os", "identity", `${agent}.md`);
3032
+ const dir = path7.join(os5.homedir(), ".exe-os", "identity");
3033
+ const exactPath = path7.join(dir, `${agent}.md`);
3034
+ if (existsSync6(exactPath)) return exactPath;
3035
+ try {
3036
+ const files = readdirSync4(dir);
3037
+ const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3038
+ if (match) return path7.join(dir, match);
3039
+ } catch {
3040
+ }
3041
+ return exactPath;
3001
3042
  }
3002
3043
  function leanMcpConfigFor(agent) {
3003
- const p = path7.join(os4.homedir(), ".exe-os", "mcp-configs", `${agent}-lean.json`);
3044
+ const p = path7.join(os5.homedir(), ".exe-os", "mcp-configs", `${agent}-lean.json`);
3004
3045
  return existsSync6(p) ? p : null;
3005
3046
  }
3006
3047
  var _ccHelpOutput = null;
@@ -3024,8 +3065,32 @@ function _resetCcHelpCache() {
3024
3065
  function buildLaunchPlan(agent, behaviorsPath, passthrough, _hasAgentFlag, _provider) {
3025
3066
  const args = ["--dangerously-skip-permissions"];
3026
3067
  const idPath = identityPathFor(agent);
3027
- const ccAgentPath = path7.join(os4.homedir(), ".claude", "agents", `${agent}.md`);
3028
- const effectiveIdPath = existsSync6(idPath) ? idPath : existsSync6(ccAgentPath) ? ccAgentPath : null;
3068
+ const ccAgentPath = path7.join(os5.homedir(), ".claude", "agents", `${agent}.md`);
3069
+ let effectiveCcPath = null;
3070
+ if (existsSync6(ccAgentPath)) {
3071
+ effectiveCcPath = ccAgentPath;
3072
+ } else {
3073
+ try {
3074
+ const ccAgentDir = path7.join(os5.homedir(), ".claude", "agents");
3075
+ const ccFiles = readdirSync4(ccAgentDir);
3076
+ const ccMatch = ccFiles.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
3077
+ if (ccMatch) effectiveCcPath = path7.join(ccAgentDir, ccMatch);
3078
+ } catch {
3079
+ }
3080
+ }
3081
+ const effectiveIdPath = existsSync6(idPath) ? idPath : effectiveCcPath;
3082
+ if (!effectiveIdPath) {
3083
+ process.stderr.write(
3084
+ `
3085
+ \u26A0\uFE0F No identity file found for agent "${agent}".
3086
+ Checked: ${idPath}
3087
+ Checked: ${ccAgentPath}
3088
+ Claude will boot without agent identity.
3089
+ Fix: run exe-os setup (option 2) to sync from cloud, or copy the identity file manually.
3090
+
3091
+ `
3092
+ );
3093
+ }
3029
3094
  if (effectiveIdPath) {
3030
3095
  if (ccSupportsFlag("--system-prompt")) {
3031
3096
  try {
@@ -3156,7 +3221,7 @@ async function main() {
3156
3221
  _resetCcAgentSupportCache();
3157
3222
  const hasAgentFlag = claudeSupportsAgentFlag();
3158
3223
  if (hasAgentFlag) {
3159
- const ccAgentDir = path7.join(os4.homedir(), ".claude", "agents");
3224
+ const ccAgentDir = path7.join(os5.homedir(), ".claude", "agents");
3160
3225
  const ccAgentFile = path7.join(ccAgentDir, `${agent}.md`);
3161
3226
  if (!existsSync6(ccAgentFile)) {
3162
3227
  const exeIdentity = identityPathFor(agent);
@@ -3177,7 +3242,7 @@ async function main() {
3177
3242
  mkdirSync4(ccAgentDir, { recursive: true });
3178
3243
  let content = readFileSync4(sourceFile, "utf-8");
3179
3244
  content = content.replace(/\$\{agent_id\}/g, agent);
3180
- writeFileSync3(ccAgentFile, content, "utf-8");
3245
+ writeFileSync4(ccAgentFile, content, "utf-8");
3181
3246
  process.stderr.write(
3182
3247
  `[exe-launch-agent] auto-provisioned ${ccAgentFile} from ${sourceFile}
3183
3248
  `
@@ -3192,7 +3257,7 @@ async function main() {
3192
3257
  const empRole = (() => {
3193
3258
  try {
3194
3259
  const emps = __require("fs").readFileSync(
3195
- path7.join(os4.homedir(), ".exe-os", "exe-employees.json"),
3260
+ path7.join(os5.homedir(), ".exe-os", "exe-employees.json"),
3196
3261
  "utf-8"
3197
3262
  );
3198
3263
  const found = JSON.parse(emps).find(
@@ -399,9 +399,10 @@ var init_license = __esm({
399
399
 
400
400
  // src/lib/employees.ts
401
401
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
402
- import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
402
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
403
403
  import { execSync } from "child_process";
404
404
  import path4 from "path";
405
+ import os3 from "os";
405
406
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
406
407
  if (!existsSync4(employeesPath)) {
407
408
  return [];
@@ -494,7 +495,7 @@ __export(cloud_sync_exports, {
494
495
  mergeRosterFromRemote: () => mergeRosterFromRemote,
495
496
  recordRosterDeletion: () => recordRosterDeletion
496
497
  });
497
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync, openSync, closeSync } from "fs";
498
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync as unlinkSync2, openSync, closeSync } from "fs";
498
499
  import crypto2 from "crypto";
499
500
  import path5 from "path";
500
501
  import { homedir } from "os";
@@ -513,7 +514,7 @@ async function withRosterLock(fn) {
513
514
  try {
514
515
  const fd = openSync(ROSTER_LOCK_PATH, "wx");
515
516
  closeSync(fd);
516
- writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
517
+ writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
517
518
  } catch (err) {
518
519
  if (err.code === "EEXIST") {
519
520
  try {
@@ -521,10 +522,10 @@ async function withRosterLock(fn) {
521
522
  if (Date.now() - ts < LOCK_STALE_MS) {
522
523
  throw new Error("Roster merge already in progress \u2014 another sync is running");
523
524
  }
524
- unlinkSync(ROSTER_LOCK_PATH);
525
+ unlinkSync2(ROSTER_LOCK_PATH);
525
526
  const fd = openSync(ROSTER_LOCK_PATH, "wx");
526
527
  closeSync(fd);
527
- writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
528
+ writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
528
529
  } catch (retryErr) {
529
530
  if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
530
531
  throw new Error("Roster merge already in progress \u2014 another sync is running");
@@ -537,7 +538,7 @@ async function withRosterLock(fn) {
537
538
  return await fn();
538
539
  } finally {
539
540
  try {
540
- unlinkSync(ROSTER_LOCK_PATH);
541
+ unlinkSync2(ROSTER_LOCK_PATH);
541
542
  } catch {
542
543
  }
543
544
  }
@@ -837,13 +838,13 @@ function recordRosterDeletion(name) {
837
838
  } catch {
838
839
  }
839
840
  if (!deletions.includes(name)) deletions.push(name);
840
- writeFileSync2(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
841
+ writeFileSync3(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
841
842
  }
842
843
  function consumeRosterDeletions() {
843
844
  try {
844
845
  if (!existsSync5(ROSTER_DELETIONS_PATH)) return [];
845
846
  const deletions = JSON.parse(readFileSync4(ROSTER_DELETIONS_PATH, "utf-8"));
846
- writeFileSync2(ROSTER_DELETIONS_PATH, "[]");
847
+ writeFileSync3(ROSTER_DELETIONS_PATH, "[]");
847
848
  return deletions;
848
849
  } catch {
849
850
  return [];
@@ -959,7 +960,7 @@ function mergeConfig(remoteConfig, configPath) {
959
960
  const merged = { ...remoteConfig, ...local };
960
961
  const dir = path5.dirname(cfgPath);
961
962
  if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
962
- writeFileSync2(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
963
+ writeFileSync3(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
963
964
  }
964
965
  async function mergeRosterFromRemote(remote, paths) {
965
966
  return withRosterLock(async () => {
@@ -979,7 +980,11 @@ async function mergeRosterFromRemote(remote, paths) {
979
980
  } catch {
980
981
  }
981
982
  }
982
- const remoteIdentity = remote.identities[`${remoteEmp.name}.md`];
983
+ const lookupKey = `${remoteEmp.name}.md`;
984
+ const matchedKey = Object.keys(remote.identities).find(
985
+ (k) => k.toLowerCase() === lookupKey.toLowerCase()
986
+ ) ?? lookupKey;
987
+ const remoteIdentity = remote.identities[matchedKey];
983
988
  if (remoteIdentity) {
984
989
  if (!existsSync5(identityDir)) mkdirSync2(identityDir, { recursive: true });
985
990
  const idPath = path5.join(identityDir, `${remoteEmp.name}.md`);
@@ -989,7 +994,7 @@ async function mergeRosterFromRemote(remote, paths) {
989
994
  } catch {
990
995
  }
991
996
  if (localIdentity !== remoteIdentity) {
992
- writeFileSync2(idPath, remoteIdentity, "utf-8");
997
+ writeFileSync3(idPath, remoteIdentity, "utf-8");
993
998
  identitiesUpdated++;
994
999
  }
995
1000
  }
@@ -114,9 +114,10 @@ var init_config = __esm({
114
114
 
115
115
  // src/lib/employees.ts
116
116
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
117
- import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
117
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
118
118
  import { execSync } from "child_process";
119
119
  import path3 from "path";
120
+ import os2 from "os";
120
121
  function validateEmployeeName(name) {
121
122
  if (!name) {
122
123
  return { valid: false, error: "Name is required" };
@@ -766,7 +767,7 @@ __export(identity_exports, {
766
767
  listIdentities: () => listIdentities,
767
768
  updateIdentity: () => updateIdentity
768
769
  });
769
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
770
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
770
771
  import { readdirSync as readdirSync2 } from "fs";
771
772
  import path6 from "path";
772
773
  import { createHash } from "crypto";
@@ -832,7 +833,7 @@ async function updateIdentity(agentId, content, updatedBy) {
832
833
  ensureDir();
833
834
  const filePath = identityPath(agentId);
834
835
  const hash = contentHash(content);
835
- writeFileSync3(filePath, content, "utf-8");
836
+ writeFileSync4(filePath, content, "utf-8");
836
837
  try {
837
838
  const client = getClient();
838
839
  await client.execute({
@@ -893,7 +894,7 @@ var init_identity = __esm({
893
894
  });
894
895
 
895
896
  // src/lib/agent-symlinks.ts
896
- import os2 from "os";
897
+ import os3 from "os";
897
898
  import path7 from "path";
898
899
  import {
899
900
  existsSync as existsSync7,
@@ -911,7 +912,7 @@ function identitySourcePath(homeDir, agentId) {
911
912
  function claudeAgentLinkPath(homeDir, agentId) {
912
913
  return path7.join(claudeAgentsDir(homeDir), `${agentId}.md`);
913
914
  }
914
- function ensureAgentSymlink(agentId, homeDir = os2.homedir()) {
915
+ function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
915
916
  const target = identitySourcePath(homeDir, agentId);
916
917
  const link = claudeAgentLinkPath(homeDir, agentId);
917
918
  mkdirSync4(claudeAgentsDir(homeDir), { recursive: true });
@@ -949,7 +950,7 @@ function ensureAgentSymlink(agentId, homeDir = os2.homedir()) {
949
950
  }
950
951
  return { agentId, action: "created", target, link };
951
952
  }
952
- async function ensureAllAgentSymlinks(homeDir = os2.homedir()) {
953
+ async function ensureAllAgentSymlinks(homeDir = os3.homedir()) {
953
954
  const employees = await loadEmployees();
954
955
  return employees.map((emp) => ensureAgentSymlink(emp.name, homeDir));
955
956
  }
@@ -994,9 +995,9 @@ __export(installer_exports, {
994
995
  setupTmux: () => setupTmux
995
996
  });
996
997
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
997
- import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync5 } from "fs";
998
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync5, copyFileSync, mkdirSync as mkdirSync5 } from "fs";
998
999
  import path8 from "path";
999
- import os3 from "os";
1000
+ import os4 from "os";
1000
1001
  import { execSync as execSync2 } from "child_process";
1001
1002
  import { fileURLToPath as fileURLToPath2 } from "url";
1002
1003
  function resolvePackageRoot() {
@@ -1016,7 +1017,7 @@ function resolvePackageRoot() {
1016
1017
  }
1017
1018
  return path8.resolve(path8.dirname(thisFile), "..", "..", "..");
1018
1019
  }
1019
- async function copySlashCommands(packageRoot, homeDir = os3.homedir()) {
1020
+ async function copySlashCommands(packageRoot, homeDir = os4.homedir()) {
1020
1021
  let copied = 0;
1021
1022
  let skipped = 0;
1022
1023
  const skillsBase = path8.join(homeDir, ".claude", "skills");
@@ -1069,7 +1070,7 @@ name: ${skillName}
1069
1070
  await writeFile3(destPath, content);
1070
1071
  return true;
1071
1072
  }
1072
- async function registerMcpServer(packageRoot, homeDir = os3.homedir()) {
1073
+ async function registerMcpServer(packageRoot, homeDir = os4.homedir()) {
1073
1074
  const claudeJsonPath = path8.join(homeDir, ".claude.json");
1074
1075
  let claudeJson = {};
1075
1076
  if (existsSync8(claudeJsonPath)) {
@@ -1101,7 +1102,7 @@ async function registerMcpServer(packageRoot, homeDir = os3.homedir()) {
1101
1102
  await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
1102
1103
  return true;
1103
1104
  }
1104
- async function mergeHooks(packageRoot, homeDir = os3.homedir()) {
1105
+ async function mergeHooks(packageRoot, homeDir = os4.homedir()) {
1105
1106
  const settingsPath = path8.join(homeDir, ".claude", "settings.json");
1106
1107
  let settings = {};
1107
1108
  if (existsSync8(settingsPath)) {
@@ -1416,7 +1417,7 @@ async function runInstaller(homeDir) {
1416
1417
  `Hooks: ${hookResult.added} added, ${hookResult.skipped} unchanged
1417
1418
  `
1418
1419
  );
1419
- const resolvedHome = homeDir ?? os3.homedir();
1420
+ const resolvedHome = homeDir ?? os4.homedir();
1420
1421
  const exeWorkspace = path8.join(resolvedHome, "exe");
1421
1422
  if (!existsSync8(exeWorkspace)) {
1422
1423
  try {
@@ -1445,7 +1446,7 @@ exe-os installed successfully.
1445
1446
  `);
1446
1447
  }
1447
1448
  function setupTmux(home) {
1448
- const homeDir = home ?? os3.homedir();
1449
+ const homeDir = home ?? os4.homedir();
1449
1450
  const exeDir = path8.join(homeDir, ".exe-os");
1450
1451
  const exeTmuxConf = path8.join(exeDir, "tmux.conf");
1451
1452
  const userTmuxConf = path8.join(homeDir, ".tmux.conf");
@@ -1468,11 +1469,11 @@ function setupTmux(home) {
1468
1469
  process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
1469
1470
  `);
1470
1471
  }
1471
- writeFileSync4(userTmuxConf, `${sourceLine}
1472
+ writeFileSync5(userTmuxConf, `${sourceLine}
1472
1473
  ${existing}`);
1473
1474
  }
1474
1475
  } else {
1475
- writeFileSync4(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1476
+ writeFileSync5(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1476
1477
  ${sourceLine}
1477
1478
  `);
1478
1479
  }
@@ -2086,7 +2087,7 @@ import path5 from "path";
2086
2087
 
2087
2088
  // src/lib/license.ts
2088
2089
  init_config();
2089
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
2090
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
2090
2091
  import { randomUUID as randomUUID2 } from "crypto";
2091
2092
  import path4 from "path";
2092
2093
  import { jwtVerify, importSPKI } from "jose";
@@ -2142,7 +2143,7 @@ function loadDeviceId() {
2142
2143
  }
2143
2144
  const id = randomUUID2();
2144
2145
  mkdirSync2(EXE_AI_DIR, { recursive: true });
2145
- writeFileSync2(DEVICE_ID_PATH, id, "utf8");
2146
+ writeFileSync3(DEVICE_ID_PATH, id, "utf8");
2146
2147
  return id;
2147
2148
  }
2148
2149
  function loadLicense() {
@@ -2155,7 +2156,7 @@ function loadLicense() {
2155
2156
  }
2156
2157
  function saveLicense(apiKey) {
2157
2158
  mkdirSync2(EXE_AI_DIR, { recursive: true });
2158
- writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2159
+ writeFileSync3(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2159
2160
  }
2160
2161
  async function verifyLicenseJwt(token) {
2161
2162
  try {
@@ -2226,7 +2227,7 @@ function getRawCachedPlan() {
2226
2227
  }
2227
2228
  function cacheResponse(token) {
2228
2229
  try {
2229
- writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
2230
+ writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
2230
2231
  } catch {
2231
2232
  }
2232
2233
  }
@@ -1652,9 +1652,10 @@ var init_intercom_queue = __esm({
1652
1652
 
1653
1653
  // src/lib/employees.ts
1654
1654
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1655
- import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
1655
+ import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
1656
1656
  import { execSync as execSync3 } from "child_process";
1657
1657
  import path6 from "path";
1658
+ import os5 from "os";
1658
1659
  var EMPLOYEES_PATH;
1659
1660
  var init_employees = __esm({
1660
1661
  "src/lib/employees.ts"() {
@@ -1665,7 +1666,7 @@ var init_employees = __esm({
1665
1666
  });
1666
1667
 
1667
1668
  // src/lib/license.ts
1668
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1669
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1669
1670
  import { randomUUID as randomUUID2 } from "crypto";
1670
1671
  import path7 from "path";
1671
1672
  import { jwtVerify, importSPKI } from "jose";
@@ -1697,7 +1698,7 @@ var init_plan_limits = __esm({
1697
1698
 
1698
1699
  // src/lib/tmux-routing.ts
1699
1700
  import path9 from "path";
1700
- import os5 from "os";
1701
+ import os6 from "os";
1701
1702
  import { fileURLToPath } from "url";
1702
1703
  var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
1703
1704
  var init_tmux_routing = __esm({
@@ -1711,9 +1712,9 @@ var init_tmux_routing = __esm({
1711
1712
  init_provider_table();
1712
1713
  init_intercom_queue();
1713
1714
  init_plan_limits();
1714
- SPAWN_LOCK_DIR = path9.join(os5.homedir(), ".exe-os", "spawn-locks");
1715
- SESSION_CACHE = path9.join(os5.homedir(), ".exe-os", "session-cache");
1716
- INTERCOM_LOG2 = path9.join(os5.homedir(), ".exe-os", "intercom.log");
1715
+ SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
1716
+ SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
1717
+ INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
1717
1718
  DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
1718
1719
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
1719
1720
  }