@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,13 +1,41 @@
1
- // src/lib/employees.ts
2
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
3
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
4
- import { execSync } from "child_process";
5
- import path2 from "path";
6
- import os2 from "os";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/lib/secure-files.ts
12
+ import { chmodSync, existsSync, mkdirSync } from "fs";
13
+ import { chmod, mkdir } from "fs/promises";
14
+ function ensurePrivateDirSync(dirPath) {
15
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
16
+ try {
17
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
18
+ } catch {
19
+ }
20
+ }
21
+ function enforcePrivateFileSync(filePath) {
22
+ try {
23
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
24
+ } catch {
25
+ }
26
+ }
27
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
28
+ var init_secure_files = __esm({
29
+ "src/lib/secure-files.ts"() {
30
+ "use strict";
31
+ PRIVATE_DIR_MODE = 448;
32
+ PRIVATE_FILE_MODE = 384;
33
+ }
34
+ });
7
35
 
8
36
  // src/lib/config.ts
9
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
10
- import { readFileSync, existsSync, renameSync } from "fs";
37
+ import { readFile, writeFile } from "fs/promises";
38
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
11
39
  import path from "path";
12
40
  import os from "os";
13
41
  function resolveDataDir() {
@@ -15,7 +43,7 @@ function resolveDataDir() {
15
43
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
16
44
  const newDir = path.join(os.homedir(), ".exe-os");
17
45
  const legacyDir = path.join(os.homedir(), ".exe-mem");
18
- if (!existsSync(newDir) && existsSync(legacyDir)) {
46
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
19
47
  try {
20
48
  renameSync(legacyDir, newDir);
21
49
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -26,72 +54,199 @@ function resolveDataDir() {
26
54
  }
27
55
  return newDir;
28
56
  }
29
- var EXE_AI_DIR = resolveDataDir();
30
- var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
31
- var MODELS_DIR = path.join(EXE_AI_DIR, "models");
32
- var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
33
- var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
34
- var CURRENT_CONFIG_VERSION = 1;
35
- var DEFAULT_CONFIG = {
36
- config_version: CURRENT_CONFIG_VERSION,
37
- dbPath: DB_PATH,
38
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
39
- embeddingDim: 1024,
40
- batchSize: 20,
41
- flushIntervalMs: 1e4,
42
- autoIngestion: true,
43
- autoRetrieval: true,
44
- searchMode: "hybrid",
45
- hookSearchMode: "hybrid",
46
- fileGrepEnabled: true,
47
- splashEffect: true,
48
- consolidationEnabled: true,
49
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
50
- consolidationModel: "claude-haiku-4-5-20251001",
51
- consolidationMaxCallsPerRun: 20,
52
- selfQueryRouter: true,
53
- selfQueryModel: "claude-haiku-4-5-20251001",
54
- rerankerEnabled: true,
55
- scalingRoadmap: {
56
- rerankerAutoTrigger: {
57
- enabled: true,
58
- broadQueryMinCardinality: 5e4,
59
- fetchTopK: 150,
60
- returnTopK: 5
61
- }
62
- },
63
- graphRagEnabled: true,
64
- wikiEnabled: false,
65
- wikiUrl: "",
66
- wikiApiKey: "",
67
- wikiSyncIntervalMs: 30 * 60 * 1e3,
68
- wikiWorkspaceMapping: {},
69
- wikiAutoUpdate: true,
70
- wikiAutoUpdateThreshold: 0.5,
71
- wikiAutoUpdateCreateNew: true,
72
- skillLearning: true,
73
- skillThreshold: 3,
74
- skillModel: "claude-haiku-4-5-20251001",
75
- exeHeartbeat: {
76
- enabled: true,
77
- intervalSeconds: 60,
78
- staleInProgressThresholdHours: 2
79
- },
80
- sessionLifecycle: {
81
- idleKillEnabled: true,
82
- idleKillTicksRequired: 3,
83
- idleKillIntercomAckWindowMs: 1e4,
84
- maxAutoInstances: 10
85
- },
86
- autoUpdate: {
87
- checkOnBoot: true,
88
- autoInstall: false,
89
- checkIntervalMs: 24 * 60 * 60 * 1e3
57
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
58
+ var init_config = __esm({
59
+ "src/lib/config.ts"() {
60
+ "use strict";
61
+ init_secure_files();
62
+ EXE_AI_DIR = resolveDataDir();
63
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
64
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
65
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
66
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
67
+ CURRENT_CONFIG_VERSION = 1;
68
+ DEFAULT_CONFIG = {
69
+ config_version: CURRENT_CONFIG_VERSION,
70
+ dbPath: DB_PATH,
71
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
72
+ embeddingDim: 1024,
73
+ batchSize: 20,
74
+ flushIntervalMs: 1e4,
75
+ autoIngestion: true,
76
+ autoRetrieval: true,
77
+ searchMode: "hybrid",
78
+ hookSearchMode: "hybrid",
79
+ fileGrepEnabled: true,
80
+ splashEffect: true,
81
+ consolidationEnabled: true,
82
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
83
+ consolidationModel: "claude-haiku-4-5-20251001",
84
+ consolidationMaxCallsPerRun: 20,
85
+ selfQueryRouter: true,
86
+ selfQueryModel: "claude-haiku-4-5-20251001",
87
+ rerankerEnabled: true,
88
+ scalingRoadmap: {
89
+ rerankerAutoTrigger: {
90
+ enabled: true,
91
+ broadQueryMinCardinality: 5e4,
92
+ fetchTopK: 150,
93
+ returnTopK: 5
94
+ }
95
+ },
96
+ graphRagEnabled: true,
97
+ wikiEnabled: false,
98
+ wikiUrl: "",
99
+ wikiApiKey: "",
100
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
101
+ wikiWorkspaceMapping: {},
102
+ wikiAutoUpdate: true,
103
+ wikiAutoUpdateThreshold: 0.5,
104
+ wikiAutoUpdateCreateNew: true,
105
+ skillLearning: true,
106
+ skillThreshold: 3,
107
+ skillModel: "claude-haiku-4-5-20251001",
108
+ exeHeartbeat: {
109
+ enabled: true,
110
+ intervalSeconds: 60,
111
+ staleInProgressThresholdHours: 2
112
+ },
113
+ sessionLifecycle: {
114
+ idleKillEnabled: true,
115
+ idleKillTicksRequired: 3,
116
+ idleKillIntercomAckWindowMs: 1e4,
117
+ maxAutoInstances: 10
118
+ },
119
+ autoUpdate: {
120
+ checkOnBoot: true,
121
+ autoInstall: false,
122
+ checkIntervalMs: 24 * 60 * 60 * 1e3
123
+ }
124
+ };
90
125
  }
91
- };
126
+ });
127
+
128
+ // src/lib/runtime-table.ts
129
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
130
+ var init_runtime_table = __esm({
131
+ "src/lib/runtime-table.ts"() {
132
+ "use strict";
133
+ RUNTIME_TABLE = {
134
+ codex: {
135
+ binary: "codex",
136
+ launchMode: "interactive",
137
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
138
+ inlineFlag: "--no-alt-screen",
139
+ apiKeyEnv: "OPENAI_API_KEY",
140
+ defaultModel: "gpt-5.4"
141
+ },
142
+ opencode: {
143
+ binary: "opencode",
144
+ launchMode: "exec",
145
+ autoApproveFlag: "--dangerously-skip-permissions",
146
+ inlineFlag: "",
147
+ apiKeyEnv: "ANTHROPIC_API_KEY",
148
+ defaultModel: "anthropic/claude-sonnet-4-6"
149
+ }
150
+ };
151
+ DEFAULT_RUNTIME = "claude";
152
+ }
153
+ });
154
+
155
+ // src/lib/agent-config.ts
156
+ var agent_config_exports = {};
157
+ __export(agent_config_exports, {
158
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
159
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
160
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
161
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
162
+ clearAgentRuntime: () => clearAgentRuntime,
163
+ getAgentRuntime: () => getAgentRuntime,
164
+ loadAgentConfig: () => loadAgentConfig,
165
+ saveAgentConfig: () => saveAgentConfig,
166
+ setAgentRuntime: () => setAgentRuntime
167
+ });
168
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
169
+ import path2 from "path";
170
+ function loadAgentConfig() {
171
+ if (!existsSync3(AGENT_CONFIG_PATH)) return {};
172
+ try {
173
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
174
+ } catch {
175
+ return {};
176
+ }
177
+ }
178
+ function saveAgentConfig(config) {
179
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
180
+ ensurePrivateDirSync(dir);
181
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
182
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
183
+ }
184
+ function getAgentRuntime(agentId) {
185
+ const config = loadAgentConfig();
186
+ const entry = config[agentId];
187
+ if (entry) return entry;
188
+ const orgDefault = config["default"];
189
+ if (orgDefault) return orgDefault;
190
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
191
+ }
192
+ function setAgentRuntime(agentId, runtime, model) {
193
+ const knownModels = KNOWN_RUNTIMES[runtime];
194
+ if (!knownModels) {
195
+ return {
196
+ ok: false,
197
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
198
+ };
199
+ }
200
+ if (!knownModels.includes(model)) {
201
+ return {
202
+ ok: false,
203
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
204
+ };
205
+ }
206
+ const config = loadAgentConfig();
207
+ config[agentId] = { runtime, model };
208
+ saveAgentConfig(config);
209
+ return { ok: true };
210
+ }
211
+ function clearAgentRuntime(agentId) {
212
+ const config = loadAgentConfig();
213
+ delete config[agentId];
214
+ saveAgentConfig(config);
215
+ }
216
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
217
+ var init_agent_config = __esm({
218
+ "src/lib/agent-config.ts"() {
219
+ "use strict";
220
+ init_config();
221
+ init_runtime_table();
222
+ init_secure_files();
223
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
224
+ KNOWN_RUNTIMES = {
225
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
226
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
227
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
228
+ };
229
+ RUNTIME_LABELS = {
230
+ claude: "Claude Code (Anthropic)",
231
+ codex: "Codex (OpenAI)",
232
+ opencode: "OpenCode (open source)"
233
+ };
234
+ DEFAULT_MODELS = {
235
+ claude: "claude-opus-4",
236
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
237
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
238
+ };
239
+ }
240
+ });
92
241
 
93
242
  // src/lib/employees.ts
94
- var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
243
+ init_config();
244
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
245
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
246
+ import { execSync } from "child_process";
247
+ import path3 from "path";
248
+ import os2 from "os";
249
+ var EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
95
250
  var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
96
251
  var COORDINATOR_ROLE = "COO";
97
252
  function normalizeRole(role) {
@@ -129,7 +284,7 @@ function validateEmployeeName(name) {
129
284
  return { valid: true };
130
285
  }
131
286
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
132
- if (!existsSync2(employeesPath)) {
287
+ if (!existsSync4(employeesPath)) {
133
288
  return [];
134
289
  }
135
290
  const raw = await readFile2(employeesPath, "utf-8");
@@ -140,13 +295,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
140
295
  }
141
296
  }
142
297
  async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
143
- await mkdir2(path2.dirname(employeesPath), { recursive: true });
298
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
144
299
  await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
145
300
  }
146
301
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
147
- if (!existsSync2(employeesPath)) return [];
302
+ if (!existsSync4(employeesPath)) return [];
148
303
  try {
149
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
304
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
150
305
  } catch {
151
306
  return [];
152
307
  }
@@ -189,6 +344,54 @@ function addEmployee(employees, employee) {
189
344
  }
190
345
  return [...employees, normalized];
191
346
  }
347
+ var IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
348
+ var TEAM_SECTION_RE = /^## Team\b.*$/m;
349
+ function appendToCoordinatorTeam(employee) {
350
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
351
+ if (!coordinator) return;
352
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
353
+ if (!existsSync4(idPath)) return;
354
+ const content = readFileSync3(idPath, "utf-8");
355
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
356
+ const teamMatch = content.match(TEAM_SECTION_RE);
357
+ if (!teamMatch || teamMatch.index === void 0) return;
358
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
359
+ const nextHeading = afterTeam.match(/\n## /);
360
+ const entry = `
361
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
362
+ `;
363
+ let updated;
364
+ if (nextHeading && nextHeading.index !== void 0) {
365
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
366
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
367
+ } else {
368
+ updated = content.trimEnd() + "\n" + entry;
369
+ }
370
+ writeFileSync2(idPath, updated, "utf-8");
371
+ }
372
+ function capitalize(s) {
373
+ return s.charAt(0).toUpperCase() + s.slice(1);
374
+ }
375
+ async function hireEmployee(employee) {
376
+ const employees = await loadEmployees();
377
+ const updated = addEmployee(employees, employee);
378
+ await saveEmployees(updated);
379
+ try {
380
+ appendToCoordinatorTeam(employee);
381
+ } catch {
382
+ }
383
+ try {
384
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
385
+ const config = loadAgentConfig2();
386
+ const name = employee.name.toLowerCase();
387
+ if (!config[name] && config["default"]) {
388
+ config[name] = { ...config["default"] };
389
+ saveAgentConfig2(config);
390
+ }
391
+ } catch {
392
+ }
393
+ return updated;
394
+ }
192
395
  async function normalizeRosterCase(rosterPath) {
193
396
  const employees = await loadEmployees(rosterPath);
194
397
  let changed = false;
@@ -198,14 +401,14 @@ async function normalizeRosterCase(rosterPath) {
198
401
  emp.name = emp.name.toLowerCase();
199
402
  changed = true;
200
403
  try {
201
- const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
202
- const oldPath = path2.join(identityDir, `${oldName}.md`);
203
- const newPath = path2.join(identityDir, `${emp.name}.md`);
204
- if (existsSync2(oldPath) && !existsSync2(newPath)) {
404
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
405
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
406
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
407
+ if (existsSync4(oldPath) && !existsSync4(newPath)) {
205
408
  renameSync2(oldPath, newPath);
206
- } else if (existsSync2(oldPath) && oldPath !== newPath) {
207
- const content = readFileSync2(oldPath, "utf-8");
208
- writeFileSync(newPath, content, "utf-8");
409
+ } else if (existsSync4(oldPath) && oldPath !== newPath) {
410
+ const content = readFileSync3(oldPath, "utf-8");
411
+ writeFileSync2(newPath, content, "utf-8");
209
412
  if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
210
413
  unlinkSync(oldPath);
211
414
  }
@@ -235,7 +438,7 @@ function registerBinSymlinks(name) {
235
438
  errors.push("Could not find 'exe-os' in PATH");
236
439
  return { created, skipped, errors };
237
440
  }
238
- const binDir = path2.dirname(exeBinPath);
441
+ const binDir = path3.dirname(exeBinPath);
239
442
  let target;
240
443
  try {
241
444
  target = readlinkSync(exeBinPath);
@@ -245,8 +448,8 @@ function registerBinSymlinks(name) {
245
448
  }
246
449
  for (const suffix of ["", "-opencode"]) {
247
450
  const linkName = `${name}${suffix}`;
248
- const linkPath = path2.join(binDir, linkName);
249
- if (existsSync2(linkPath)) {
451
+ const linkPath = path3.join(binDir, linkName);
452
+ if (existsSync4(linkPath)) {
250
453
  skipped.push(linkName);
251
454
  continue;
252
455
  }
@@ -272,6 +475,7 @@ export {
272
475
  getEmployeeByRole,
273
476
  getEmployeeNamesByRole,
274
477
  hasRole,
478
+ hireEmployee,
275
479
  isCoordinatorName,
276
480
  isCoordinatorRole,
277
481
  isMultiInstance,