@askexenow/exe-os 0.9.7 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/bin/backfill-conversations.js +953 -105
  2. package/dist/bin/backfill-responses.js +952 -104
  3. package/dist/bin/backfill-vectors.js +956 -108
  4. package/dist/bin/cleanup-stale-review-tasks.js +802 -58
  5. package/dist/bin/cli.js +2292 -1070
  6. package/dist/bin/exe-agent-config.js +157 -101
  7. package/dist/bin/exe-agent.js +55 -29
  8. package/dist/bin/exe-assign.js +940 -92
  9. package/dist/bin/exe-boot.js +1424 -442
  10. package/dist/bin/exe-call.js +240 -141
  11. package/dist/bin/exe-cloud.js +198 -70
  12. package/dist/bin/exe-dispatch.js +951 -192
  13. package/dist/bin/exe-doctor.js +791 -51
  14. package/dist/bin/exe-export-behaviors.js +790 -42
  15. package/dist/bin/exe-forget.js +771 -31
  16. package/dist/bin/exe-gateway.js +1592 -521
  17. package/dist/bin/exe-heartbeat.js +850 -109
  18. package/dist/bin/exe-kill.js +783 -35
  19. package/dist/bin/exe-launch-agent.js +1030 -107
  20. package/dist/bin/exe-link.js +916 -110
  21. package/dist/bin/exe-new-employee.js +526 -217
  22. package/dist/bin/exe-pending-messages.js +1046 -62
  23. package/dist/bin/exe-pending-notifications.js +1318 -111
  24. package/dist/bin/exe-pending-reviews.js +1040 -72
  25. package/dist/bin/exe-rename.js +772 -59
  26. package/dist/bin/exe-review.js +772 -32
  27. package/dist/bin/exe-search.js +982 -128
  28. package/dist/bin/exe-session-cleanup.js +1180 -306
  29. package/dist/bin/exe-settings.js +185 -105
  30. package/dist/bin/exe-start-codex.js +886 -132
  31. package/dist/bin/exe-start-opencode.js +873 -119
  32. package/dist/bin/exe-status.js +803 -59
  33. package/dist/bin/exe-team.js +772 -32
  34. package/dist/bin/git-sweep.js +1046 -223
  35. package/dist/bin/graph-backfill.js +779 -31
  36. package/dist/bin/graph-export.js +785 -37
  37. package/dist/bin/install.js +632 -200
  38. package/dist/bin/scan-tasks.js +1055 -232
  39. package/dist/bin/setup.js +1419 -320
  40. package/dist/bin/shard-migrate.js +783 -35
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +782 -34
  43. package/dist/gateway/index.js +1444 -449
  44. package/dist/hooks/bug-report-worker.js +1141 -269
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +1044 -221
  47. package/dist/hooks/error-recall.js +989 -135
  48. package/dist/hooks/exe-heartbeat-hook.js +99 -75
  49. package/dist/hooks/ingest-worker.js +4176 -3226
  50. package/dist/hooks/ingest.js +920 -168
  51. package/dist/hooks/instructions-loaded.js +874 -70
  52. package/dist/hooks/notification.js +860 -56
  53. package/dist/hooks/post-compact.js +881 -73
  54. package/dist/hooks/pre-compact.js +1050 -227
  55. package/dist/hooks/pre-tool-use.js +1084 -159
  56. package/dist/hooks/prompt-ingest-worker.js +1089 -164
  57. package/dist/hooks/prompt-submit.js +1469 -515
  58. package/dist/hooks/response-ingest-worker.js +1104 -179
  59. package/dist/hooks/session-end.js +1085 -251
  60. package/dist/hooks/session-start.js +1241 -231
  61. package/dist/hooks/stop.js +935 -109
  62. package/dist/hooks/subagent-stop.js +881 -73
  63. package/dist/hooks/summary-worker.js +1323 -307
  64. package/dist/index.js +1449 -452
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +909 -115
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +42 -9
  69. package/dist/lib/database.js +739 -33
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +2359 -0
  72. package/dist/lib/device-registry.js +760 -47
  73. package/dist/lib/embedder.js +201 -73
  74. package/dist/lib/employee-templates.js +30 -4
  75. package/dist/lib/employees.js +290 -86
  76. package/dist/lib/exe-daemon-client.js +187 -83
  77. package/dist/lib/exe-daemon.js +1696 -616
  78. package/dist/lib/hybrid-search.js +982 -128
  79. package/dist/lib/identity.js +43 -13
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +167 -80
  82. package/dist/lib/reminders.js +35 -5
  83. package/dist/lib/schedules.js +772 -32
  84. package/dist/lib/skill-learning.js +54 -7
  85. package/dist/lib/store.js +779 -31
  86. package/dist/lib/task-router.js +94 -73
  87. package/dist/lib/tasks.js +298 -225
  88. package/dist/lib/tmux-routing.js +246 -172
  89. package/dist/lib/token-spend.js +52 -14
  90. package/dist/mcp/server.js +2893 -850
  91. package/dist/mcp/tools/complete-reminder.js +35 -5
  92. package/dist/mcp/tools/create-reminder.js +35 -5
  93. package/dist/mcp/tools/create-task.js +507 -323
  94. package/dist/mcp/tools/deactivate-behavior.js +40 -10
  95. package/dist/mcp/tools/list-reminders.js +35 -5
  96. package/dist/mcp/tools/list-tasks.js +277 -104
  97. package/dist/mcp/tools/send-message.js +129 -56
  98. package/dist/mcp/tools/update-task.js +1864 -188
  99. package/dist/runtime/index.js +1083 -259
  100. package/dist/tui/App.js +1501 -434
  101. package/package.json +3 -2
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
+ }) : x)(function(x) {
7
+ if (typeof require !== "undefined") return require.apply(this, arguments);
8
+ throw Error('Dynamic require of "' + x + '" is not supported');
9
+ });
4
10
  var __esm = (fn, res) => function __init() {
5
11
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
12
  };
@@ -9,9 +15,34 @@ var __export = (target, all) => {
9
15
  __defProp(target, name, { get: all[name], enumerable: true });
10
16
  };
11
17
 
18
+ // src/lib/secure-files.ts
19
+ import { chmodSync, existsSync, mkdirSync } from "fs";
20
+ import { chmod, mkdir } from "fs/promises";
21
+ function ensurePrivateDirSync(dirPath) {
22
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
23
+ try {
24
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
25
+ } catch {
26
+ }
27
+ }
28
+ function enforcePrivateFileSync(filePath) {
29
+ try {
30
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
31
+ } catch {
32
+ }
33
+ }
34
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
35
+ var init_secure_files = __esm({
36
+ "src/lib/secure-files.ts"() {
37
+ "use strict";
38
+ PRIVATE_DIR_MODE = 448;
39
+ PRIVATE_FILE_MODE = 384;
40
+ }
41
+ });
42
+
12
43
  // src/lib/config.ts
13
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
14
- import { readFileSync, existsSync, renameSync } from "fs";
44
+ import { readFile, writeFile } from "fs/promises";
45
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
15
46
  import path from "path";
16
47
  import os from "os";
17
48
  function resolveDataDir() {
@@ -19,7 +50,7 @@ function resolveDataDir() {
19
50
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
20
51
  const newDir = path.join(os.homedir(), ".exe-os");
21
52
  const legacyDir = path.join(os.homedir(), ".exe-mem");
22
- if (!existsSync(newDir) && existsSync(legacyDir)) {
53
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
23
54
  try {
24
55
  renameSync(legacyDir, newDir);
25
56
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -34,6 +65,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
34
65
  var init_config = __esm({
35
66
  "src/lib/config.ts"() {
36
67
  "use strict";
68
+ init_secure_files();
37
69
  EXE_AI_DIR = resolveDataDir();
38
70
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
39
71
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -100,6 +132,120 @@ var init_config = __esm({
100
132
  }
101
133
  });
102
134
 
135
+ // src/lib/runtime-table.ts
136
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
137
+ var init_runtime_table = __esm({
138
+ "src/lib/runtime-table.ts"() {
139
+ "use strict";
140
+ RUNTIME_TABLE = {
141
+ codex: {
142
+ binary: "codex",
143
+ launchMode: "interactive",
144
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
145
+ inlineFlag: "--no-alt-screen",
146
+ apiKeyEnv: "OPENAI_API_KEY",
147
+ defaultModel: "gpt-5.4"
148
+ },
149
+ opencode: {
150
+ binary: "opencode",
151
+ launchMode: "exec",
152
+ autoApproveFlag: "--dangerously-skip-permissions",
153
+ inlineFlag: "",
154
+ apiKeyEnv: "ANTHROPIC_API_KEY",
155
+ defaultModel: "anthropic/claude-sonnet-4-6"
156
+ }
157
+ };
158
+ DEFAULT_RUNTIME = "claude";
159
+ }
160
+ });
161
+
162
+ // src/lib/agent-config.ts
163
+ var agent_config_exports = {};
164
+ __export(agent_config_exports, {
165
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
166
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
167
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
168
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
169
+ clearAgentRuntime: () => clearAgentRuntime,
170
+ getAgentRuntime: () => getAgentRuntime,
171
+ loadAgentConfig: () => loadAgentConfig,
172
+ saveAgentConfig: () => saveAgentConfig,
173
+ setAgentRuntime: () => setAgentRuntime
174
+ });
175
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
176
+ import path2 from "path";
177
+ function loadAgentConfig() {
178
+ if (!existsSync3(AGENT_CONFIG_PATH)) return {};
179
+ try {
180
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
181
+ } catch {
182
+ return {};
183
+ }
184
+ }
185
+ function saveAgentConfig(config) {
186
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
187
+ ensurePrivateDirSync(dir);
188
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
189
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
190
+ }
191
+ function getAgentRuntime(agentId) {
192
+ const config = loadAgentConfig();
193
+ const entry = config[agentId];
194
+ if (entry) return entry;
195
+ const orgDefault = config["default"];
196
+ if (orgDefault) return orgDefault;
197
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
198
+ }
199
+ function setAgentRuntime(agentId, runtime, model) {
200
+ const knownModels = KNOWN_RUNTIMES[runtime];
201
+ if (!knownModels) {
202
+ return {
203
+ ok: false,
204
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
205
+ };
206
+ }
207
+ if (!knownModels.includes(model)) {
208
+ return {
209
+ ok: false,
210
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
211
+ };
212
+ }
213
+ const config = loadAgentConfig();
214
+ config[agentId] = { runtime, model };
215
+ saveAgentConfig(config);
216
+ return { ok: true };
217
+ }
218
+ function clearAgentRuntime(agentId) {
219
+ const config = loadAgentConfig();
220
+ delete config[agentId];
221
+ saveAgentConfig(config);
222
+ }
223
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
224
+ var init_agent_config = __esm({
225
+ "src/lib/agent-config.ts"() {
226
+ "use strict";
227
+ init_config();
228
+ init_runtime_table();
229
+ init_secure_files();
230
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
231
+ KNOWN_RUNTIMES = {
232
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
233
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
234
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
235
+ };
236
+ RUNTIME_LABELS = {
237
+ claude: "Claude Code (Anthropic)",
238
+ codex: "Codex (OpenAI)",
239
+ opencode: "OpenCode (open source)"
240
+ };
241
+ DEFAULT_MODELS = {
242
+ claude: "claude-opus-4",
243
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
244
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
245
+ };
246
+ }
247
+ });
248
+
103
249
  // src/lib/employees.ts
104
250
  var employees_exports = {};
105
251
  __export(employees_exports, {
@@ -115,6 +261,7 @@ __export(employees_exports, {
115
261
  getEmployeeByRole: () => getEmployeeByRole,
116
262
  getEmployeeNamesByRole: () => getEmployeeNamesByRole,
117
263
  hasRole: () => hasRole,
264
+ hireEmployee: () => hireEmployee,
118
265
  isCoordinatorName: () => isCoordinatorName,
119
266
  isCoordinatorRole: () => isCoordinatorRole,
120
267
  isMultiInstance: () => isMultiInstance,
@@ -127,9 +274,9 @@ __export(employees_exports, {
127
274
  validateEmployeeName: () => validateEmployeeName
128
275
  });
129
276
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
130
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
277
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
131
278
  import { execSync } from "child_process";
132
- import path2 from "path";
279
+ import path3 from "path";
133
280
  import os2 from "os";
134
281
  function normalizeRole(role) {
135
282
  return (role ?? "").trim().toLowerCase();
@@ -166,7 +313,7 @@ function validateEmployeeName(name) {
166
313
  return { valid: true };
167
314
  }
168
315
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
169
- if (!existsSync2(employeesPath)) {
316
+ if (!existsSync4(employeesPath)) {
170
317
  return [];
171
318
  }
172
319
  const raw = await readFile2(employeesPath, "utf-8");
@@ -177,13 +324,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
177
324
  }
178
325
  }
179
326
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
180
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
327
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
181
328
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
182
329
  }
183
330
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
184
- if (!existsSync2(employeesPath)) return [];
331
+ if (!existsSync4(employeesPath)) return [];
185
332
  try {
186
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
333
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
187
334
  } catch {
188
335
  return [];
189
336
  }
@@ -225,6 +372,52 @@ function addEmployee(employees, employee) {
225
372
  }
226
373
  return [...employees, normalized];
227
374
  }
375
+ function appendToCoordinatorTeam(employee) {
376
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
377
+ if (!coordinator) return;
378
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
379
+ if (!existsSync4(idPath)) return;
380
+ const content = readFileSync3(idPath, "utf-8");
381
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
382
+ const teamMatch = content.match(TEAM_SECTION_RE);
383
+ if (!teamMatch || teamMatch.index === void 0) return;
384
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
385
+ const nextHeading = afterTeam.match(/\n## /);
386
+ const entry = `
387
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
388
+ `;
389
+ let updated;
390
+ if (nextHeading && nextHeading.index !== void 0) {
391
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
392
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
393
+ } else {
394
+ updated = content.trimEnd() + "\n" + entry;
395
+ }
396
+ writeFileSync2(idPath, updated, "utf-8");
397
+ }
398
+ function capitalize(s) {
399
+ return s.charAt(0).toUpperCase() + s.slice(1);
400
+ }
401
+ async function hireEmployee(employee) {
402
+ const employees = await loadEmployees();
403
+ const updated = addEmployee(employees, employee);
404
+ await saveEmployees(updated);
405
+ try {
406
+ appendToCoordinatorTeam(employee);
407
+ } catch {
408
+ }
409
+ try {
410
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
411
+ const config = loadAgentConfig2();
412
+ const name = employee.name.toLowerCase();
413
+ if (!config[name] && config["default"]) {
414
+ config[name] = { ...config["default"] };
415
+ saveAgentConfig2(config);
416
+ }
417
+ } catch {
418
+ }
419
+ return updated;
420
+ }
228
421
  async function normalizeRosterCase(rosterPath) {
229
422
  const employees = await loadEmployees(rosterPath);
230
423
  let changed = false;
@@ -234,14 +427,14 @@ async function normalizeRosterCase(rosterPath) {
234
427
  emp.name = emp.name.toLowerCase();
235
428
  changed = true;
236
429
  try {
237
- const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
238
- const oldPath = path2.join(identityDir, `${oldName}.md`);
239
- const newPath = path2.join(identityDir, `${emp.name}.md`);
240
- if (existsSync2(oldPath) && !existsSync2(newPath)) {
430
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
431
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
432
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
433
+ if (existsSync4(oldPath) && !existsSync4(newPath)) {
241
434
  renameSync2(oldPath, newPath);
242
- } else if (existsSync2(oldPath) && oldPath !== newPath) {
243
- const content = readFileSync2(oldPath, "utf-8");
244
- writeFileSync(newPath, content, "utf-8");
435
+ } else if (existsSync4(oldPath) && oldPath !== newPath) {
436
+ const content = readFileSync3(oldPath, "utf-8");
437
+ writeFileSync2(newPath, content, "utf-8");
245
438
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
246
439
  unlinkSync(oldPath);
247
440
  }
@@ -271,7 +464,7 @@ function registerBinSymlinks(name) {
271
464
  errors.push("Could not find 'exe-os' in PATH");
272
465
  return { created, skipped, errors };
273
466
  }
274
- const binDir = path2.dirname(exeBinPath);
467
+ const binDir = path3.dirname(exeBinPath);
275
468
  let target;
276
469
  try {
277
470
  target = readlinkSync(exeBinPath);
@@ -281,8 +474,8 @@ function registerBinSymlinks(name) {
281
474
  }
282
475
  for (const suffix of ["", "-opencode"]) {
283
476
  const linkName = `${name}${suffix}`;
284
- const linkPath = path2.join(binDir, linkName);
285
- if (existsSync2(linkPath)) {
477
+ const linkPath = path3.join(binDir, linkName);
478
+ if (existsSync4(linkPath)) {
286
479
  skipped.push(linkName);
287
480
  continue;
288
481
  }
@@ -295,51 +488,44 @@ function registerBinSymlinks(name) {
295
488
  }
296
489
  return { created, skipped, errors };
297
490
  }
298
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
491
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
299
492
  var init_employees = __esm({
300
493
  "src/lib/employees.ts"() {
301
494
  "use strict";
302
495
  init_config();
303
- EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
496
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
304
497
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
305
498
  COORDINATOR_ROLE = "COO";
306
499
  MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
500
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
501
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
307
502
  }
308
503
  });
309
504
 
310
- // src/adapters/claude/installer.ts
311
- import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
312
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
313
- import path5 from "path";
314
- import os5 from "os";
315
- import { execSync as execSync2 } from "child_process";
316
- import { fileURLToPath } from "url";
317
-
318
505
  // src/lib/agent-symlinks.ts
319
- init_employees();
320
506
  import os3 from "os";
321
- import path3 from "path";
507
+ import path4 from "path";
322
508
  import {
323
- existsSync as existsSync3,
509
+ existsSync as existsSync5,
324
510
  lstatSync,
325
- mkdirSync,
511
+ mkdirSync as mkdirSync2,
326
512
  readlinkSync as readlinkSync2,
327
513
  symlinkSync as symlinkSync2
328
514
  } from "fs";
329
515
  function claudeAgentsDir(homeDir) {
330
- return path3.join(homeDir, ".claude", "agents");
516
+ return path4.join(homeDir, ".claude", "agents");
331
517
  }
332
518
  function identitySourcePath(homeDir, agentId) {
333
- return path3.join(homeDir, ".exe-os", "identity", `${agentId}.md`);
519
+ return path4.join(homeDir, ".exe-os", "identity", `${agentId}.md`);
334
520
  }
335
521
  function claudeAgentLinkPath(homeDir, agentId) {
336
- return path3.join(claudeAgentsDir(homeDir), `${agentId}.md`);
522
+ return path4.join(claudeAgentsDir(homeDir), `${agentId}.md`);
337
523
  }
338
524
  function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
339
525
  const target = identitySourcePath(homeDir, agentId);
340
526
  const link = claudeAgentLinkPath(homeDir, agentId);
341
- mkdirSync(claudeAgentsDir(homeDir), { recursive: true });
342
- if (existsSync3(link)) {
527
+ mkdirSync2(claudeAgentsDir(homeDir), { recursive: true });
528
+ if (existsSync5(link)) {
343
529
  let stat;
344
530
  try {
345
531
  stat = lstatSync(link);
@@ -377,14 +563,14 @@ async function ensureAllAgentSymlinks(homeDir = os3.homedir()) {
377
563
  const employees = await loadEmployees();
378
564
  return employees.map((emp) => ensureAgentSymlink(emp.name, homeDir));
379
565
  }
566
+ var init_agent_symlinks = __esm({
567
+ "src/lib/agent-symlinks.ts"() {
568
+ "use strict";
569
+ init_employees();
570
+ }
571
+ });
380
572
 
381
573
  // src/lib/mcp-prefix.ts
382
- var MCP_PRIMARY_KEY = "exe-os";
383
- var MCP_LEGACY_KEY = "exe-mem";
384
- var MCP_TOOL_PREFIXES = [
385
- `mcp__${MCP_PRIMARY_KEY}__`,
386
- `mcp__${MCP_LEGACY_KEY}__`
387
- ];
388
574
  function expandDualPrefixTools(shortNames) {
389
575
  const out = [];
390
576
  for (const name of shortNames) {
@@ -394,64 +580,88 @@ function expandDualPrefixTools(shortNames) {
394
580
  }
395
581
  return out;
396
582
  }
583
+ var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
584
+ var init_mcp_prefix = __esm({
585
+ "src/lib/mcp-prefix.ts"() {
586
+ "use strict";
587
+ MCP_PRIMARY_KEY = "exe-os";
588
+ MCP_LEGACY_KEY = "exe-mem";
589
+ MCP_TOOL_PREFIXES = [
590
+ `mcp__${MCP_PRIMARY_KEY}__`,
591
+ `mcp__${MCP_LEGACY_KEY}__`
592
+ ];
593
+ }
594
+ });
397
595
 
398
596
  // src/lib/preferences.ts
399
- import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
400
- import path4 from "path";
597
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
598
+ import path5 from "path";
401
599
  import os4 from "os";
402
600
  function loadPreferences(homeDir = os4.homedir()) {
403
- const configPath = path4.join(homeDir, ".exe-os", "config.json");
404
- if (!existsSync4(configPath)) return {};
601
+ const configPath = path5.join(homeDir, ".exe-os", "config.json");
602
+ if (!existsSync6(configPath)) return {};
405
603
  try {
406
- const config = JSON.parse(readFileSync3(configPath, "utf-8"));
604
+ const config = JSON.parse(readFileSync4(configPath, "utf-8"));
407
605
  return config.preferences ?? {};
408
606
  } catch {
409
607
  return {};
410
608
  }
411
609
  }
610
+ var init_preferences = __esm({
611
+ "src/lib/preferences.ts"() {
612
+ "use strict";
613
+ init_secure_files();
614
+ }
615
+ });
412
616
 
413
617
  // src/adapters/claude/installer.ts
618
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
619
+ import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
620
+ import path6 from "path";
621
+ import os5 from "os";
622
+ import { execSync as execSync2 } from "child_process";
623
+ import { fileURLToPath } from "url";
414
624
  function resolvePackageRoot() {
415
625
  const thisFile = fileURLToPath(import.meta.url);
416
- let dir = path5.dirname(thisFile);
417
- const root = path5.parse(dir).root;
626
+ let dir = path6.dirname(thisFile);
627
+ const root = path6.parse(dir).root;
418
628
  while (dir !== root) {
419
- const pkgPath = path5.join(dir, "package.json");
420
- if (existsSync5(pkgPath)) {
629
+ const pkgPath = path6.join(dir, "package.json");
630
+ if (existsSync7(pkgPath)) {
421
631
  try {
422
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
632
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
423
633
  if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
424
634
  } catch {
425
635
  }
426
636
  }
427
- dir = path5.dirname(dir);
637
+ dir = path6.dirname(dir);
428
638
  }
429
- return path5.resolve(path5.dirname(thisFile), "..", "..", "..");
639
+ return path6.resolve(path6.dirname(thisFile), "..", "..", "..");
430
640
  }
431
641
  async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
432
642
  let copied = 0;
433
643
  let skipped = 0;
434
- const skillsBase = path5.join(homeDir, ".claude", "skills");
435
- const exeDir = path5.join(packageRoot, "src", "commands", "exe");
436
- if (existsSync5(exeDir)) {
644
+ const skillsBase = path6.join(homeDir, ".claude", "skills");
645
+ const exeDir = path6.join(packageRoot, "src", "commands", "exe");
646
+ if (existsSync7(exeDir)) {
437
647
  const entries = await readdir(exeDir);
438
648
  const mdFiles = entries.filter((f) => f.endsWith(".md"));
439
649
  for (const file of mdFiles) {
440
650
  const name = file.replace(".md", "");
441
- const destDir = path5.join(skillsBase, `exe-${name}`);
651
+ const destDir = path6.join(skillsBase, `exe-${name}`);
442
652
  await mkdir3(destDir, { recursive: true });
443
- const srcPath = path5.join(exeDir, file);
444
- const destPath = path5.join(destDir, "SKILL.md");
653
+ const srcPath = path6.join(exeDir, file);
654
+ const destPath = path6.join(destDir, "SKILL.md");
445
655
  const result = await copyAsSkill(srcPath, destPath, `exe-${name}`);
446
656
  if (result) copied++;
447
657
  else skipped++;
448
658
  }
449
659
  }
450
- const topLevelSrc = path5.join(packageRoot, "src", "commands", "exe.md");
451
- if (existsSync5(topLevelSrc)) {
452
- const destDir = path5.join(skillsBase, "exe");
660
+ const topLevelSrc = path6.join(packageRoot, "src", "commands", "exe.md");
661
+ if (existsSync7(topLevelSrc)) {
662
+ const destDir = path6.join(skillsBase, "exe");
453
663
  await mkdir3(destDir, { recursive: true });
454
- const destPath = path5.join(destDir, "SKILL.md");
664
+ const destPath = path6.join(destDir, "SKILL.md");
455
665
  const result = await copyAsSkill(topLevelSrc, destPath, "exe");
456
666
  if (result) copied++;
457
667
  else skipped++;
@@ -474,7 +684,7 @@ name: ${skillName}
474
684
  `);
475
685
  }
476
686
  }
477
- if (existsSync5(destPath)) {
687
+ if (existsSync7(destPath)) {
478
688
  const existing = await readFile3(destPath, "utf-8");
479
689
  if (existing === content) return false;
480
690
  }
@@ -482,9 +692,9 @@ name: ${skillName}
482
692
  return true;
483
693
  }
484
694
  async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
485
- const claudeJsonPath = path5.join(homeDir, ".claude.json");
695
+ const claudeJsonPath = path6.join(homeDir, ".claude.json");
486
696
  let claudeJson = {};
487
- if (existsSync5(claudeJsonPath)) {
697
+ if (existsSync7(claudeJsonPath)) {
488
698
  try {
489
699
  claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
490
700
  } catch {
@@ -497,25 +707,25 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
497
707
  const newEntry = {
498
708
  type: "stdio",
499
709
  command: "node",
500
- args: [path5.join(packageRoot, "dist", "mcp", "server.js")],
710
+ args: [path6.join(packageRoot, "dist", "mcp", "server.js")],
501
711
  env: {}
502
712
  };
503
713
  const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
504
- const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
505
714
  const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
506
- const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
507
- if (memMatches && osMatches) {
508
- await cleanSettingsJsonMcp(path5.join(homeDir, ".claude", "settings.json"));
715
+ if (claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
716
+ delete claudeJson.mcpServers[MCP_PRIMARY_KEY];
717
+ }
718
+ if (memMatches && !claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
719
+ await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
509
720
  return false;
510
721
  }
511
722
  claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
512
- claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
513
723
  await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
514
- await cleanSettingsJsonMcp(path5.join(homeDir, ".claude", "settings.json"));
724
+ await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
515
725
  return true;
516
726
  }
517
727
  async function cleanSettingsJsonMcp(settingsPath) {
518
- if (!existsSync5(settingsPath)) return;
728
+ if (!existsSync7(settingsPath)) return;
519
729
  try {
520
730
  const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
521
731
  const servers = settings.mcpServers;
@@ -536,13 +746,13 @@ async function cleanSettingsJsonMcp(settingsPath) {
536
746
  }
537
747
  }
538
748
  async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
539
- const settingsPath = path5.join(homeDir, ".claude", "settings.json");
540
- const logsDir = path5.join(homeDir, ".exe-os", "logs");
541
- const hookLogPath = path5.join(logsDir, "hooks.log");
749
+ const settingsPath = path6.join(homeDir, ".claude", "settings.json");
750
+ const logsDir = path6.join(homeDir, ".exe-os", "logs");
751
+ const hookLogPath = path6.join(logsDir, "hooks.log");
542
752
  const logSuffix = ` 2>> "${hookLogPath}"`;
543
753
  await mkdir3(logsDir, { recursive: true });
544
754
  let settings = {};
545
- if (existsSync5(settingsPath)) {
755
+ if (existsSync7(settingsPath)) {
546
756
  try {
547
757
  settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
548
758
  } catch {
@@ -564,11 +774,11 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
564
774
  hooks: [
565
775
  {
566
776
  type: "command",
567
- command: `node "${path5.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
777
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
568
778
  },
569
779
  {
570
780
  type: "command",
571
- command: `node "${path5.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
781
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
572
782
  }
573
783
  ]
574
784
  },
@@ -580,7 +790,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
580
790
  hooks: [
581
791
  {
582
792
  type: "command",
583
- command: `node "${path5.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
793
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
584
794
  timeout: 1e4
585
795
  }
586
796
  ]
@@ -593,7 +803,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
593
803
  hooks: [
594
804
  {
595
805
  type: "command",
596
- command: `node "${path5.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
806
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
597
807
  }
598
808
  ]
599
809
  },
@@ -605,7 +815,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
605
815
  hooks: [
606
816
  {
607
817
  type: "command",
608
- command: `node "${path5.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
818
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
609
819
  timeout: 5e3
610
820
  }
611
821
  ]
@@ -618,7 +828,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
618
828
  hooks: [
619
829
  {
620
830
  type: "command",
621
- command: `node "${path5.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
831
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
622
832
  }
623
833
  ]
624
834
  },
@@ -631,7 +841,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
631
841
  hooks: [
632
842
  {
633
843
  type: "command",
634
- command: `node "${path5.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
844
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
635
845
  }
636
846
  ]
637
847
  },
@@ -643,7 +853,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
643
853
  hooks: [
644
854
  {
645
855
  type: "command",
646
- command: `node "${path5.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"${logSuffix}`
856
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"${logSuffix}`
647
857
  }
648
858
  ]
649
859
  },
@@ -655,7 +865,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
655
865
  hooks: [
656
866
  {
657
867
  type: "command",
658
- command: `node "${path5.join(packageRoot, "dist", "hooks", "pre-compact.js")}"${logSuffix}`,
868
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "pre-compact.js")}"${logSuffix}`,
659
869
  timeout: 1e4
660
870
  }
661
871
  ]
@@ -668,7 +878,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
668
878
  hooks: [
669
879
  {
670
880
  type: "command",
671
- command: `node "${path5.join(packageRoot, "dist", "hooks", "session-end.js")}"${logSuffix}`
881
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "session-end.js")}"${logSuffix}`
672
882
  }
673
883
  ]
674
884
  },
@@ -680,7 +890,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
680
890
  hooks: [
681
891
  {
682
892
  type: "command",
683
- command: `node "${path5.join(packageRoot, "dist", "hooks", "notification.js")}"${logSuffix}`
893
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "notification.js")}"${logSuffix}`
684
894
  }
685
895
  ]
686
896
  },
@@ -692,7 +902,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
692
902
  hooks: [
693
903
  {
694
904
  type: "command",
695
- command: `node "${path5.join(packageRoot, "dist", "hooks", "post-compact.js")}"${logSuffix}`,
905
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "post-compact.js")}"${logSuffix}`,
696
906
  timeout: 1e4
697
907
  }
698
908
  ]
@@ -705,7 +915,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
705
915
  hooks: [
706
916
  {
707
917
  type: "command",
708
- command: `node "${path5.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"${logSuffix}`
918
+ command: `node "${path6.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"${logSuffix}`
709
919
  }
710
920
  ]
711
921
  },
@@ -804,13 +1014,13 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
804
1014
  allowList.push(tool);
805
1015
  }
806
1016
  }
807
- await mkdir3(path5.dirname(settingsPath), { recursive: true });
1017
+ await mkdir3(path6.dirname(settingsPath), { recursive: true });
808
1018
  await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
809
1019
  return { added, skipped };
810
1020
  }
811
1021
  async function cleanOldShellFunctions(homeDir = os5.homedir()) {
812
- const rosterPath = path5.join(homeDir, ".exe-os", "exe-employees.json");
813
- if (!existsSync5(rosterPath)) return 0;
1022
+ const rosterPath = path6.join(homeDir, ".exe-os", "exe-employees.json");
1023
+ if (!existsSync7(rosterPath)) return 0;
814
1024
  let employees;
815
1025
  try {
816
1026
  employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
@@ -825,13 +1035,13 @@ async function cleanOldShellFunctions(homeDir = os5.homedir()) {
825
1035
  return { name: n, funcDef, forLoop };
826
1036
  });
827
1037
  const rcFiles = [
828
- path5.join(homeDir, ".zshrc"),
829
- path5.join(homeDir, ".bashrc")
1038
+ path6.join(homeDir, ".zshrc"),
1039
+ path6.join(homeDir, ".bashrc")
830
1040
  ];
831
1041
  const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
832
1042
  let totalRemoved = 0;
833
1043
  for (const rcPath of rcFiles) {
834
- if (!existsSync5(rcPath)) continue;
1044
+ if (!existsSync7(rcPath)) continue;
835
1045
  let content;
836
1046
  try {
837
1047
  content = await readFile3(rcPath, "utf-8");
@@ -934,22 +1144,9 @@ async function cleanOldShellFunctions(homeDir = os5.homedir()) {
934
1144
  function escapeRegExp(s) {
935
1145
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
936
1146
  }
937
- var EXE_SECTION_START = "<!-- exe-os:orchestration-start -->";
938
- var EXE_SECTION_END = "<!-- exe-os:orchestration-end -->";
939
- var ORCHESTRATION_RULES = `${EXE_SECTION_START}
940
- ## exe-os Multi-Agent Orchestration (auto-managed \u2014 do not edit)
941
-
942
- These rules are injected by exe-os and override default behavior for multi-agent coordination.
943
-
944
- - **Session routing is deterministic.** When working in a coordinator session, ALL employee sessions use that same coordinator-session suffix. NEVER reference, consider, or dispatch to employee sessions from other project sessions. This is not a choice \u2014 it is a hard constraint.
945
- - **Always use create_task to assign work.** Never use messages, tmux send-keys, or ad-hoc instructions as a substitute for tasks.
946
- - **Never modify another agent's in-progress task.** Create a new task instead. Modifying active tasks causes race conditions.
947
- - **Chain of command:** founder -> COO -> managers -> specialists. The COO does not bypass managers for specialist work.
948
- - **Verify dispatch.** After every create_task, confirm the employee received and started the task via tmux capture-pane.
949
- ${EXE_SECTION_END}`;
950
1147
  async function injectOrchestrationRules(homeDir) {
951
- const claudeDir = path5.join(homeDir, ".claude");
952
- const claudeMdPath = path5.join(claudeDir, "CLAUDE.md");
1148
+ const claudeDir = path6.join(homeDir, ".claude");
1149
+ const claudeMdPath = path6.join(claudeDir, "CLAUDE.md");
953
1150
  await mkdir3(claudeDir, { recursive: true });
954
1151
  let existing = "";
955
1152
  try {
@@ -974,16 +1171,16 @@ async function injectOrchestrationRules(homeDir) {
974
1171
  async function installStatusLine(packageRoot, homeDir = os5.homedir()) {
975
1172
  const prefs = loadPreferences(homeDir);
976
1173
  if (prefs.ccStatusLine === false) return "opted-out";
977
- const claudeDir = path5.join(homeDir, ".claude");
1174
+ const claudeDir = path6.join(homeDir, ".claude");
978
1175
  await mkdir3(claudeDir, { recursive: true });
979
- const assetPath = path5.join(packageRoot, "dist", "assets", "statusline-command.sh");
980
- if (!existsSync5(assetPath)) return "asset-missing";
981
- const destScript = path5.join(claudeDir, "statusline-command.sh");
1176
+ const assetPath = path6.join(packageRoot, "dist", "assets", "statusline-command.sh");
1177
+ if (!existsSync7(assetPath)) return "asset-missing";
1178
+ const destScript = path6.join(claudeDir, "statusline-command.sh");
982
1179
  const assetContent = await readFile3(assetPath, "utf-8");
983
1180
  await writeFile3(destScript, assetContent, { mode: 493 });
984
- const settingsPath = path5.join(claudeDir, "settings.json");
1181
+ const settingsPath = path6.join(claudeDir, "settings.json");
985
1182
  let settings = {};
986
- if (existsSync5(settingsPath)) {
1183
+ if (existsSync7(settingsPath)) {
987
1184
  try {
988
1185
  settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
989
1186
  } catch {
@@ -1021,12 +1218,12 @@ async function runInstaller(homeDir) {
1021
1218
  `
1022
1219
  );
1023
1220
  const resolvedHome = homeDir ?? os5.homedir();
1024
- const exeWorkspace = path5.join(resolvedHome, "exe");
1025
- if (!existsSync5(exeWorkspace)) {
1221
+ const exeWorkspace = path6.join(resolvedHome, "exe");
1222
+ if (!existsSync7(exeWorkspace)) {
1026
1223
  try {
1027
- await mkdir3(path5.join(exeWorkspace, "content"), { recursive: true });
1028
- await mkdir3(path5.join(exeWorkspace, "operations"), { recursive: true });
1029
- await mkdir3(path5.join(exeWorkspace, "output"), { recursive: true });
1224
+ await mkdir3(path6.join(exeWorkspace, "content"), { recursive: true });
1225
+ await mkdir3(path6.join(exeWorkspace, "operations"), { recursive: true });
1226
+ await mkdir3(path6.join(exeWorkspace, "output"), { recursive: true });
1030
1227
  process.stderr.write(
1031
1228
  `Created ~/exe/ \u2014 your automation workspace for non-code projects
1032
1229
  `
@@ -1062,33 +1259,33 @@ exe-os installed successfully.
1062
1259
  }
1063
1260
  function setupTmux(home) {
1064
1261
  const homeDir = home ?? os5.homedir();
1065
- const exeDir = path5.join(homeDir, ".exe-os");
1066
- const exeTmuxConf = path5.join(exeDir, "tmux.conf");
1067
- const userTmuxConf = path5.join(homeDir, ".tmux.conf");
1068
- const backupPath = path5.join(homeDir, ".tmux.conf.backup");
1262
+ const exeDir = path6.join(homeDir, ".exe-os");
1263
+ const exeTmuxConf = path6.join(exeDir, "tmux.conf");
1264
+ const userTmuxConf = path6.join(homeDir, ".tmux.conf");
1265
+ const backupPath = path6.join(homeDir, ".tmux.conf.backup");
1069
1266
  const sourceLine = "source-file ~/.exe-os/tmux.conf";
1070
1267
  const pkgRoot = resolvePackageRoot();
1071
- const assetPath = path5.join(pkgRoot, "dist", "assets", "tmux.conf");
1072
- if (!existsSync5(assetPath)) {
1268
+ const assetPath = path6.join(pkgRoot, "dist", "assets", "tmux.conf");
1269
+ if (!existsSync7(assetPath)) {
1073
1270
  process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
1074
1271
  `);
1075
1272
  return;
1076
1273
  }
1077
1274
  mkdirSync3(exeDir, { recursive: true });
1078
1275
  copyFileSync(assetPath, exeTmuxConf);
1079
- if (existsSync5(userTmuxConf)) {
1080
- const existing = readFileSync4(userTmuxConf, "utf8");
1276
+ if (existsSync7(userTmuxConf)) {
1277
+ const existing = readFileSync5(userTmuxConf, "utf8");
1081
1278
  if (!existing.includes(sourceLine)) {
1082
- if (!existsSync5(backupPath)) {
1279
+ if (!existsSync7(backupPath)) {
1083
1280
  copyFileSync(userTmuxConf, backupPath);
1084
1281
  process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
1085
1282
  `);
1086
1283
  }
1087
- writeFileSync3(userTmuxConf, `${sourceLine}
1284
+ writeFileSync4(userTmuxConf, `${sourceLine}
1088
1285
  ${existing}`);
1089
1286
  }
1090
1287
  } else {
1091
- writeFileSync3(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1288
+ writeFileSync4(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
1092
1289
  ${sourceLine}
1093
1290
  `);
1094
1291
  }
@@ -1100,9 +1297,9 @@ ${sourceLine}
1100
1297
  }
1101
1298
  function setupGhostty(home) {
1102
1299
  const homeDir = home ?? os5.homedir();
1103
- const xdgConfig = path5.join(homeDir, ".config", "ghostty");
1104
- const macConfig = path5.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
1105
- const ghosttyInstalled = existsSync5(xdgConfig) || existsSync5(macConfig) || (() => {
1300
+ const xdgConfig = path6.join(homeDir, ".config", "ghostty");
1301
+ const macConfig = path6.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
1302
+ const ghosttyInstalled = existsSync7(xdgConfig) || existsSync7(macConfig) || (() => {
1106
1303
  try {
1107
1304
  execSync2("which ghostty 2>/dev/null");
1108
1305
  return true;
@@ -1114,47 +1311,47 @@ function setupGhostty(home) {
1114
1311
  return;
1115
1312
  }
1116
1313
  const pkgRoot = resolvePackageRoot();
1117
- const assetPath = path5.join(pkgRoot, "dist", "assets", "ghostty.conf");
1118
- if (!existsSync5(assetPath)) {
1314
+ const assetPath = path6.join(pkgRoot, "dist", "assets", "ghostty.conf");
1315
+ if (!existsSync7(assetPath)) {
1119
1316
  process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
1120
1317
  return;
1121
1318
  }
1122
1319
  const configDir = xdgConfig;
1123
- const configPath = path5.join(configDir, "config");
1124
- const backupPath = path5.join(configDir, "config.backup");
1320
+ const configPath = path6.join(configDir, "config");
1321
+ const backupPath = path6.join(configDir, "config.backup");
1125
1322
  mkdirSync3(configDir, { recursive: true });
1126
1323
  const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
1127
1324
  const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
1128
- const assetContent = readFileSync4(assetPath, "utf8").trim();
1325
+ const assetContent = readFileSync5(assetPath, "utf8").trim();
1129
1326
  const markedSection = `${START_MARKER}
1130
1327
  ${assetContent}
1131
1328
  ${END_MARKER}`;
1132
- if (existsSync5(configPath)) {
1133
- const existing = readFileSync4(configPath, "utf8");
1329
+ if (existsSync7(configPath)) {
1330
+ const existing = readFileSync5(configPath, "utf8");
1134
1331
  if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
1135
1332
  const before = existing.slice(0, existing.indexOf(START_MARKER));
1136
1333
  const after = existing.slice(existing.indexOf(END_MARKER) + END_MARKER.length);
1137
- writeFileSync3(configPath, `${before}${markedSection}${after}`);
1334
+ writeFileSync4(configPath, `${before}${markedSection}${after}`);
1138
1335
  } else if (existing.includes("Exe OS")) {
1139
- if (!existsSync5(backupPath)) {
1336
+ if (!existsSync7(backupPath)) {
1140
1337
  copyFileSync(configPath, backupPath);
1141
1338
  process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
1142
1339
  `);
1143
1340
  }
1144
- writeFileSync3(configPath, `${markedSection}
1341
+ writeFileSync4(configPath, `${markedSection}
1145
1342
  `);
1146
1343
  } else {
1147
- if (!existsSync5(backupPath)) {
1344
+ if (!existsSync7(backupPath)) {
1148
1345
  copyFileSync(configPath, backupPath);
1149
1346
  process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
1150
1347
  `);
1151
1348
  }
1152
- writeFileSync3(configPath, `${markedSection}
1349
+ writeFileSync4(configPath, `${markedSection}
1153
1350
 
1154
1351
  ${existing}`);
1155
1352
  }
1156
1353
  } else {
1157
- writeFileSync3(configPath, `${markedSection}
1354
+ writeFileSync4(configPath, `${markedSection}
1158
1355
  `);
1159
1356
  }
1160
1357
  process.stderr.write("exe-os: Ghostty config installed\n");
@@ -1171,46 +1368,275 @@ function summarizeSymlinkResults(results) {
1171
1368
  }
1172
1369
  return summary;
1173
1370
  }
1371
+ var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
1372
+ var init_installer = __esm({
1373
+ "src/adapters/claude/installer.ts"() {
1374
+ "use strict";
1375
+ init_agent_symlinks();
1376
+ init_mcp_prefix();
1377
+ init_preferences();
1378
+ EXE_SECTION_START = "<!-- exe-os:orchestration-start -->";
1379
+ EXE_SECTION_END = "<!-- exe-os:orchestration-end -->";
1380
+ ORCHESTRATION_RULES = `${EXE_SECTION_START}
1381
+ ## exe-os Multi-Agent Orchestration (auto-managed \u2014 do not edit)
1382
+
1383
+ These rules are injected by exe-os and override default behavior for multi-agent coordination.
1384
+
1385
+ - **Session routing is deterministic.** When working in a coordinator session, ALL employee sessions use that same coordinator-session suffix. NEVER reference, consider, or dispatch to employee sessions from other project sessions. This is not a choice \u2014 it is a hard constraint.
1386
+ - **Always use create_task to assign work.** Never use messages, tmux send-keys, or ad-hoc instructions as a substitute for tasks.
1387
+ - **Never modify another agent's in-progress task.** Create a new task instead. Modifying active tasks causes race conditions.
1388
+ - **Chain of command:** founder -> COO -> managers -> specialists. The COO does not bypass managers for specialist work.
1389
+ - **Verify dispatch.** After every create_task, confirm the employee received and started the task via tmux capture-pane.
1390
+ ${EXE_SECTION_END}`;
1391
+ }
1392
+ });
1393
+
1394
+ // src/adapters/codex/installer.ts
1395
+ var installer_exports = {};
1396
+ __export(installer_exports, {
1397
+ installCodexStatusLine: () => installCodexStatusLine,
1398
+ mergeCodexHooks: () => mergeCodexHooks,
1399
+ runCodexInstaller: () => runCodexInstaller,
1400
+ verifyCodexHooks: () => verifyCodexHooks
1401
+ });
1402
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
1403
+ import { existsSync as existsSync9 } from "fs";
1404
+ import path8 from "path";
1405
+ import os6 from "os";
1406
+ async function mergeCodexHooks(packageRoot, homeDir = os6.homedir()) {
1407
+ const codexDir = path8.join(homeDir, ".codex");
1408
+ const hooksPath = path8.join(codexDir, "hooks.json");
1409
+ const logsDir = path8.join(homeDir, ".exe-os", "logs");
1410
+ const hookLogPath = path8.join(logsDir, "hooks.log");
1411
+ const logSuffix = ` 2>> "${hookLogPath}"`;
1412
+ await mkdir4(codexDir, { recursive: true });
1413
+ await mkdir4(logsDir, { recursive: true });
1414
+ let hooksJson = {};
1415
+ if (existsSync9(hooksPath)) {
1416
+ try {
1417
+ hooksJson = JSON.parse(await readFile4(hooksPath, "utf-8"));
1418
+ } catch {
1419
+ hooksJson = {};
1420
+ }
1421
+ }
1422
+ if (!hooksJson.hooks) {
1423
+ hooksJson.hooks = {};
1424
+ }
1425
+ const hooksToRegister = [
1426
+ {
1427
+ event: "SessionStart",
1428
+ group: {
1429
+ hooks: [
1430
+ {
1431
+ type: "command",
1432
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
1433
+ timeout: 30,
1434
+ statusMessage: "exe-os: loading memory brief"
1435
+ }
1436
+ ]
1437
+ },
1438
+ marker: "dist/hooks/session-start.js"
1439
+ },
1440
+ {
1441
+ event: "PostToolUse",
1442
+ group: {
1443
+ matcher: "Bash|apply_patch|Edit|Write|Read|Glob|Grep|mcp__.*",
1444
+ hooks: [
1445
+ {
1446
+ type: "command",
1447
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
1448
+ },
1449
+ {
1450
+ type: "command",
1451
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
1452
+ }
1453
+ ]
1454
+ },
1455
+ marker: "dist/hooks/ingest.js"
1456
+ },
1457
+ {
1458
+ event: "UserPromptSubmit",
1459
+ group: {
1460
+ hooks: [
1461
+ {
1462
+ type: "command",
1463
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
1464
+ },
1465
+ {
1466
+ type: "command",
1467
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
1468
+ timeout: 5
1469
+ }
1470
+ ]
1471
+ },
1472
+ marker: "dist/hooks/prompt-submit.js"
1473
+ },
1474
+ {
1475
+ event: "Stop",
1476
+ group: {
1477
+ hooks: [
1478
+ {
1479
+ type: "command",
1480
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
1481
+ }
1482
+ ]
1483
+ },
1484
+ marker: "dist/hooks/stop.js"
1485
+ },
1486
+ {
1487
+ event: "PreToolUse",
1488
+ group: {
1489
+ matcher: "Bash|apply_patch",
1490
+ hooks: [
1491
+ {
1492
+ type: "command",
1493
+ command: `node "${path8.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
1494
+ }
1495
+ ]
1496
+ },
1497
+ marker: "dist/hooks/pre-tool-use.js"
1498
+ }
1499
+ ];
1500
+ let added = 0;
1501
+ let skipped = 0;
1502
+ for (const { event, group, marker } of hooksToRegister) {
1503
+ if (!hooksJson.hooks[event]) {
1504
+ hooksJson.hooks[event] = [];
1505
+ }
1506
+ const existing = hooksJson.hooks[event];
1507
+ const correctCommand = group.hooks[0]?.command ?? "";
1508
+ const alreadyCorrect = existing.some(
1509
+ (g) => g.hooks.some((h) => h.command === correctCommand)
1510
+ );
1511
+ if (alreadyCorrect) {
1512
+ skipped++;
1513
+ } else {
1514
+ hooksJson.hooks[event] = existing.filter(
1515
+ (g) => !g.hooks.some((h) => h.command.includes(marker))
1516
+ );
1517
+ hooksJson.hooks[event].push(group);
1518
+ added++;
1519
+ }
1520
+ }
1521
+ await writeFile4(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
1522
+ return { added, skipped };
1523
+ }
1524
+ function verifyCodexHooks(homeDir = os6.homedir()) {
1525
+ const hooksPath = path8.join(homeDir, ".codex", "hooks.json");
1526
+ if (!existsSync9(hooksPath)) return false;
1527
+ try {
1528
+ const hooksJson = JSON.parse(
1529
+ __require("fs").readFileSync(hooksPath, "utf-8")
1530
+ );
1531
+ if (!hooksJson.hooks) return false;
1532
+ const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
1533
+ for (const event of required) {
1534
+ const groups = hooksJson.hooks[event];
1535
+ if (!groups || !groups.some(
1536
+ (g) => g.hooks.some((h) => h.command.includes("dist/hooks/"))
1537
+ )) {
1538
+ return false;
1539
+ }
1540
+ }
1541
+ return true;
1542
+ } catch {
1543
+ return false;
1544
+ }
1545
+ }
1546
+ async function installCodexStatusLine(homeDir = os6.homedir()) {
1547
+ const prefs = loadPreferences(homeDir);
1548
+ if (prefs.codexStatusLine === false) return "opted-out";
1549
+ const codexDir = path8.join(homeDir, ".codex");
1550
+ const configPath = path8.join(codexDir, "config.toml");
1551
+ await mkdir4(codexDir, { recursive: true });
1552
+ let content = "";
1553
+ if (existsSync9(configPath)) {
1554
+ content = await readFile4(configPath, "utf-8");
1555
+ if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
1556
+ return "already-configured";
1557
+ }
1558
+ }
1559
+ const statusLineToml = `[tui]
1560
+ status_line = [${DEFAULT_CODEX_STATUS_LINE.map((s) => `"${s}"`).join(", ")}]`;
1561
+ if (content.includes("[tui]")) {
1562
+ content = content.replace(/\[tui\]/, `${statusLineToml}`);
1563
+ } else {
1564
+ const separator = content.length > 0 && !content.endsWith("\n") ? "\n\n" : content.length > 0 ? "\n" : "";
1565
+ content = content + separator + statusLineToml + "\n";
1566
+ }
1567
+ await writeFile4(configPath, content);
1568
+ return "installed";
1569
+ }
1570
+ async function runCodexInstaller(homeDir) {
1571
+ const packageRoot = resolvePackageRoot();
1572
+ const result = await mergeCodexHooks(packageRoot, homeDir);
1573
+ process.stderr.write(
1574
+ `[exe-os] Codex hooks: ${result.added} added, ${result.skipped} unchanged
1575
+ `
1576
+ );
1577
+ const statusResult = await installCodexStatusLine(homeDir);
1578
+ process.stderr.write(
1579
+ `[exe-os] Codex status line: ${statusResult}
1580
+ `
1581
+ );
1582
+ }
1583
+ var DEFAULT_CODEX_STATUS_LINE;
1584
+ var init_installer2 = __esm({
1585
+ "src/adapters/codex/installer.ts"() {
1586
+ "use strict";
1587
+ init_installer();
1588
+ init_preferences();
1589
+ DEFAULT_CODEX_STATUS_LINE = [
1590
+ "model-with-reasoning",
1591
+ "current-dir",
1592
+ "project-name",
1593
+ "git-branch",
1594
+ "run-state",
1595
+ "context-used"
1596
+ ];
1597
+ }
1598
+ });
1174
1599
 
1175
1600
  // src/bin/install.ts
1176
- import { existsSync as existsSync7, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync2, openSync, closeSync } from "fs";
1601
+ init_installer();
1602
+ import { existsSync as existsSync10, readFileSync as readFileSync7, unlinkSync as unlinkSync3, readdirSync as readdirSync2, openSync, closeSync } from "fs";
1177
1603
  import { spawn, execSync as execSync3 } from "child_process";
1178
- import path7 from "path";
1179
- import os6 from "os";
1604
+ import path9 from "path";
1605
+ import os7 from "os";
1180
1606
 
1181
1607
  // src/lib/session-wrappers.ts
1182
1608
  import {
1183
- existsSync as existsSync6,
1184
- readFileSync as readFileSync5,
1185
- writeFileSync as writeFileSync4,
1609
+ existsSync as existsSync8,
1610
+ readFileSync as readFileSync6,
1611
+ writeFileSync as writeFileSync5,
1186
1612
  mkdirSync as mkdirSync4,
1187
- chmodSync,
1613
+ chmodSync as chmodSync2,
1188
1614
  readdirSync,
1189
1615
  unlinkSync as unlinkSync2
1190
1616
  } from "fs";
1191
- import path6 from "path";
1617
+ import path7 from "path";
1192
1618
  import { homedir } from "os";
1193
1619
  var MAX_N = 9;
1194
1620
  function generateSessionWrappers(packageRoot, homeDir) {
1195
1621
  const home = homeDir ?? homedir();
1196
- const binDir = path6.join(home, ".exe-os", "bin");
1197
- const rosterPath = path6.join(home, ".exe-os", "exe-employees.json");
1622
+ const binDir = path7.join(home, ".exe-os", "bin");
1623
+ const rosterPath = path7.join(home, ".exe-os", "exe-employees.json");
1198
1624
  mkdirSync4(binDir, { recursive: true });
1199
- const exeStartDst = path6.join(binDir, "exe-start");
1625
+ const exeStartDst = path7.join(binDir, "exe-start");
1200
1626
  const candidates = [
1201
- path6.join(packageRoot, "dist", "bin", "exe-start.sh"),
1202
- path6.join(packageRoot, "src", "bin", "exe-start.sh")
1627
+ path7.join(packageRoot, "dist", "bin", "exe-start.sh"),
1628
+ path7.join(packageRoot, "src", "bin", "exe-start.sh")
1203
1629
  ];
1204
1630
  for (const src of candidates) {
1205
- if (existsSync6(src)) {
1206
- writeFileSync4(exeStartDst, readFileSync5(src));
1207
- chmodSync(exeStartDst, 493);
1631
+ if (existsSync8(src)) {
1632
+ writeFileSync5(exeStartDst, readFileSync6(src));
1633
+ chmodSync2(exeStartDst, 493);
1208
1634
  break;
1209
1635
  }
1210
1636
  }
1211
1637
  let employees = [];
1212
1638
  try {
1213
- employees = JSON.parse(readFileSync5(rosterPath, "utf8"));
1639
+ employees = JSON.parse(readFileSync6(rosterPath, "utf8"));
1214
1640
  } catch {
1215
1641
  return { created: 0, pathConfigured: false };
1216
1642
  }
@@ -1220,9 +1646,9 @@ function generateSessionWrappers(packageRoot, homeDir) {
1220
1646
  try {
1221
1647
  for (const f of readdirSync(binDir)) {
1222
1648
  if (f === "exe-start") continue;
1223
- const fPath = path6.join(binDir, f);
1649
+ const fPath = path7.join(binDir, f);
1224
1650
  try {
1225
- const content = readFileSync5(fPath, "utf8");
1651
+ const content = readFileSync6(fPath, "utf8");
1226
1652
  if (content.includes("exe-start")) {
1227
1653
  unlinkSync2(fPath);
1228
1654
  }
@@ -1237,31 +1663,31 @@ exec "${exeStartDst}" "$0" "$@"
1237
1663
  `;
1238
1664
  for (const emp of employees) {
1239
1665
  for (let n = 1; n <= MAX_N; n++) {
1240
- const wrapperPath = path6.join(binDir, `${emp.name}${n}`);
1241
- writeFileSync4(wrapperPath, wrapperContent);
1242
- chmodSync(wrapperPath, 493);
1666
+ const wrapperPath = path7.join(binDir, `${emp.name}${n}`);
1667
+ writeFileSync5(wrapperPath, wrapperContent);
1668
+ chmodSync2(wrapperPath, 493);
1243
1669
  created++;
1244
1670
  }
1245
1671
  }
1246
1672
  const codexLauncherCandidates = [
1247
- path6.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
1248
- path6.join(packageRoot, "src", "bin", "exe-start-codex.ts")
1673
+ path7.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
1674
+ path7.join(packageRoot, "src", "bin", "exe-start-codex.ts")
1249
1675
  ];
1250
1676
  let codexLauncher = null;
1251
1677
  for (const c of codexLauncherCandidates) {
1252
- if (existsSync6(c)) {
1678
+ if (existsSync8(c)) {
1253
1679
  codexLauncher = c;
1254
1680
  break;
1255
1681
  }
1256
1682
  }
1257
1683
  if (codexLauncher) {
1258
1684
  for (const emp of employees) {
1259
- const wrapperPath = path6.join(binDir, `${emp.name}-codex`);
1685
+ const wrapperPath = path7.join(binDir, `${emp.name}-codex`);
1260
1686
  const content = `#!/bin/bash
1261
1687
  exec node "${codexLauncher}" --agent ${emp.name} "$@"
1262
1688
  `;
1263
- writeFileSync4(wrapperPath, content);
1264
- chmodSync(wrapperPath, 493);
1689
+ writeFileSync5(wrapperPath, content);
1690
+ chmodSync2(wrapperPath, 493);
1265
1691
  created++;
1266
1692
  }
1267
1693
  }
@@ -1279,24 +1705,24 @@ export PATH="${binDir}:$PATH"
1279
1705
  const shell = process.env.SHELL ?? "/bin/bash";
1280
1706
  const profilePaths = [];
1281
1707
  if (shell.includes("zsh")) {
1282
- profilePaths.push(path6.join(home, ".zshrc"));
1708
+ profilePaths.push(path7.join(home, ".zshrc"));
1283
1709
  } else if (shell.includes("bash")) {
1284
- profilePaths.push(path6.join(home, ".bashrc"));
1285
- profilePaths.push(path6.join(home, ".bash_profile"));
1710
+ profilePaths.push(path7.join(home, ".bashrc"));
1711
+ profilePaths.push(path7.join(home, ".bash_profile"));
1286
1712
  } else {
1287
- profilePaths.push(path6.join(home, ".profile"));
1713
+ profilePaths.push(path7.join(home, ".profile"));
1288
1714
  }
1289
1715
  for (const profilePath of profilePaths) {
1290
1716
  try {
1291
1717
  let content = "";
1292
1718
  try {
1293
- content = readFileSync5(profilePath, "utf8");
1719
+ content = readFileSync6(profilePath, "utf8");
1294
1720
  } catch {
1295
1721
  }
1296
1722
  if (content.includes(".exe-os/bin")) {
1297
1723
  return false;
1298
1724
  }
1299
- writeFileSync4(profilePath, content + exportLine);
1725
+ writeFileSync5(profilePath, content + exportLine);
1300
1726
  return true;
1301
1727
  } catch {
1302
1728
  continue;
@@ -1306,14 +1732,14 @@ export PATH="${binDir}:$PATH"
1306
1732
  }
1307
1733
 
1308
1734
  // src/bin/install.ts
1309
- var homedir2 = os6.homedir;
1310
- var EXE_DIR = path7.join(homedir2(), ".exe-os");
1735
+ var homedir2 = os7.homedir;
1736
+ var EXE_DIR = path9.join(homedir2(), ".exe-os");
1311
1737
  function restartDaemon() {
1312
- const pidPath = path7.join(EXE_DIR, "exed.pid");
1313
- const sockPath = path7.join(EXE_DIR, "exed.sock");
1738
+ const pidPath = path9.join(EXE_DIR, "exed.pid");
1739
+ const sockPath = path9.join(EXE_DIR, "exed.sock");
1314
1740
  try {
1315
- if (existsSync7(pidPath)) {
1316
- const pid = parseInt(readFileSync6(pidPath, "utf8").trim(), 10);
1741
+ if (existsSync10(pidPath)) {
1742
+ const pid = parseInt(readFileSync7(pidPath, "utf8").trim(), 10);
1317
1743
  if (!isNaN(pid) && pid > 0) {
1318
1744
  try {
1319
1745
  process.kill(pid, "SIGKILL");
@@ -1354,11 +1780,11 @@ function restartDaemon() {
1354
1780
  } catch {
1355
1781
  }
1356
1782
  try {
1357
- const wpDir = path7.join(EXE_DIR, "worker-pids");
1358
- if (existsSync7(wpDir)) {
1783
+ const wpDir = path9.join(EXE_DIR, "worker-pids");
1784
+ if (existsSync10(wpDir)) {
1359
1785
  for (const f of readdirSync2(wpDir)) {
1360
1786
  try {
1361
- unlinkSync3(path7.join(wpDir, f));
1787
+ unlinkSync3(path9.join(wpDir, f));
1362
1788
  } catch {
1363
1789
  }
1364
1790
  }
@@ -1375,7 +1801,7 @@ function restartDaemon() {
1375
1801
  }
1376
1802
  } catch {
1377
1803
  }
1378
- const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
1804
+ const totalGB = os7.totalmem() / (1024 * 1024 * 1024);
1379
1805
  if (totalGB <= 8) {
1380
1806
  process.stderr.write(
1381
1807
  `exe-os: ${totalGB.toFixed(0)}GB system \u2014 skipping daemon spawn (keyword search mode)
@@ -1385,13 +1811,13 @@ function restartDaemon() {
1385
1811
  }
1386
1812
  try {
1387
1813
  const pkgRoot = resolvePackageRoot();
1388
- const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1389
- if (!existsSync7(daemonPath)) {
1814
+ const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1815
+ if (!existsSync10(daemonPath)) {
1390
1816
  process.stderr.write(`exe-os: daemon not found at ${daemonPath} \u2014 skipping respawn
1391
1817
  `);
1392
1818
  return;
1393
1819
  }
1394
- const logPath = path7.join(EXE_DIR, "exed.log");
1820
+ const logPath = path9.join(EXE_DIR, "exed.log");
1395
1821
  let stderrFd = "ignore";
1396
1822
  try {
1397
1823
  stderrFd = openSync(logPath, "a");
@@ -1461,6 +1887,12 @@ if (args.includes("--commands-only")) {
1461
1887
  } catch (err) {
1462
1888
  process.stderr.write(`exe-os: session wrapper generation failed: ${err instanceof Error ? err.message : String(err)}
1463
1889
  `);
1890
+ }
1891
+ try {
1892
+ execSync3("which codex", { encoding: "utf8", timeout: 5e3 });
1893
+ const { runCodexInstaller: runCodexInstaller2 } = await Promise.resolve().then(() => (init_installer2(), installer_exports));
1894
+ await runCodexInstaller2();
1895
+ } catch {
1464
1896
  }
1465
1897
  restartDaemon();
1466
1898
  } catch (err) {