@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
@@ -3,9 +3,47 @@ var __esm = (fn, res) => function __init() {
3
3
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
4
  };
5
5
 
6
+ // src/lib/secure-files.ts
7
+ import { chmodSync, existsSync, mkdirSync } from "fs";
8
+ import { chmod, mkdir } from "fs/promises";
9
+ async function ensurePrivateDir(dirPath) {
10
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
11
+ try {
12
+ await chmod(dirPath, PRIVATE_DIR_MODE);
13
+ } catch {
14
+ }
15
+ }
16
+ function ensurePrivateDirSync(dirPath) {
17
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
18
+ try {
19
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
20
+ } catch {
21
+ }
22
+ }
23
+ async function enforcePrivateFile(filePath) {
24
+ try {
25
+ await chmod(filePath, PRIVATE_FILE_MODE);
26
+ } catch {
27
+ }
28
+ }
29
+ function enforcePrivateFileSync(filePath) {
30
+ try {
31
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
32
+ } catch {
33
+ }
34
+ }
35
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
36
+ var init_secure_files = __esm({
37
+ "src/lib/secure-files.ts"() {
38
+ "use strict";
39
+ PRIVATE_DIR_MODE = 448;
40
+ PRIVATE_FILE_MODE = 384;
41
+ }
42
+ });
43
+
6
44
  // src/lib/config.ts
7
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
8
- import { readFileSync, existsSync, renameSync } from "fs";
45
+ import { readFile, writeFile } from "fs/promises";
46
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
9
47
  import path from "path";
10
48
  import os from "os";
11
49
  function resolveDataDir() {
@@ -13,7 +51,7 @@ function resolveDataDir() {
13
51
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
14
52
  const newDir = path.join(os.homedir(), ".exe-os");
15
53
  const legacyDir = path.join(os.homedir(), ".exe-mem");
16
- if (!existsSync(newDir) && existsSync(legacyDir)) {
54
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
17
55
  try {
18
56
  renameSync(legacyDir, newDir);
19
57
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -76,9 +114,9 @@ function normalizeAutoUpdate(raw) {
76
114
  }
77
115
  async function loadConfig() {
78
116
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
79
- await mkdir(dir, { recursive: true });
117
+ await ensurePrivateDir(dir);
80
118
  const configPath = path.join(dir, "config.json");
81
- if (!existsSync(configPath)) {
119
+ if (!existsSync2(configPath)) {
82
120
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
83
121
  }
84
122
  const raw = await readFile(configPath, "utf-8");
@@ -91,6 +129,7 @@ async function loadConfig() {
91
129
  `);
92
130
  try {
93
131
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
132
+ await enforcePrivateFile(configPath);
94
133
  } catch {
95
134
  }
96
135
  }
@@ -108,17 +147,16 @@ async function loadConfig() {
108
147
  }
109
148
  async function saveConfig(config) {
110
149
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
111
- await mkdir(dir, { recursive: true });
150
+ await ensurePrivateDir(dir);
112
151
  const configPath = path.join(dir, "config.json");
113
152
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
114
- if (config.cloud?.apiKey) {
115
- await chmod(configPath, 384);
116
- }
153
+ await enforcePrivateFile(configPath);
117
154
  }
118
155
  var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
119
156
  var init_config = __esm({
120
157
  "src/lib/config.ts"() {
121
158
  "use strict";
159
+ init_secure_files();
122
160
  EXE_AI_DIR = resolveDataDir();
123
161
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
124
162
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -204,24 +242,46 @@ var init_db_retry = __esm({
204
242
 
205
243
  // src/lib/employees.ts
206
244
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
207
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
245
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
208
246
  import { execSync } from "child_process";
209
247
  import path2 from "path";
210
248
  import os2 from "os";
211
249
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
212
- if (!existsSync2(employeesPath)) return [];
250
+ if (!existsSync3(employeesPath)) return [];
213
251
  try {
214
252
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
215
253
  } catch {
216
254
  return [];
217
255
  }
218
256
  }
219
- var EMPLOYEES_PATH;
257
+ var EMPLOYEES_PATH, IDENTITY_DIR;
220
258
  var init_employees = __esm({
221
259
  "src/lib/employees.ts"() {
222
260
  "use strict";
223
261
  init_config();
224
262
  EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
263
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
264
+ }
265
+ });
266
+
267
+ // src/lib/database-adapter.ts
268
+ import os3 from "os";
269
+ import path3 from "path";
270
+ import { createRequire } from "module";
271
+ import { pathToFileURL } from "url";
272
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
273
+ var init_database_adapter = __esm({
274
+ "src/lib/database-adapter.ts"() {
275
+ "use strict";
276
+ BOOLEAN_COLUMNS_BY_TABLE = {
277
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
278
+ behaviors: /* @__PURE__ */ new Set(["active"]),
279
+ notifications: /* @__PURE__ */ new Set(["read"]),
280
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
281
+ };
282
+ BOOLEAN_COLUMN_NAMES = new Set(
283
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
284
+ );
225
285
  }
226
286
  });
227
287
 
@@ -232,19 +292,114 @@ var init_database = __esm({
232
292
  "use strict";
233
293
  init_db_retry();
234
294
  init_employees();
295
+ init_database_adapter();
235
296
  }
236
297
  });
237
298
 
238
299
  // src/lib/crdt-sync.ts
239
300
  import * as Y from "yjs";
240
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
241
- import path4 from "path";
301
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
302
+ import path5 from "path";
242
303
  import { homedir } from "os";
243
304
  var DEFAULT_STATE_PATH;
244
305
  var init_crdt_sync = __esm({
245
306
  "src/lib/crdt-sync.ts"() {
246
307
  "use strict";
247
- DEFAULT_STATE_PATH = path4.join(homedir(), ".exe-os", "crdt-state.bin");
308
+ DEFAULT_STATE_PATH = path5.join(homedir(), ".exe-os", "crdt-state.bin");
309
+ }
310
+ });
311
+
312
+ // src/lib/runtime-table.ts
313
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
314
+ var init_runtime_table = __esm({
315
+ "src/lib/runtime-table.ts"() {
316
+ "use strict";
317
+ RUNTIME_TABLE = {
318
+ codex: {
319
+ binary: "codex",
320
+ launchMode: "interactive",
321
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
322
+ inlineFlag: "--no-alt-screen",
323
+ apiKeyEnv: "OPENAI_API_KEY",
324
+ defaultModel: "gpt-5.4"
325
+ },
326
+ opencode: {
327
+ binary: "opencode",
328
+ launchMode: "exec",
329
+ autoApproveFlag: "--dangerously-skip-permissions",
330
+ inlineFlag: "",
331
+ apiKeyEnv: "ANTHROPIC_API_KEY",
332
+ defaultModel: "anthropic/claude-sonnet-4-6"
333
+ }
334
+ };
335
+ DEFAULT_RUNTIME = "claude";
336
+ }
337
+ });
338
+
339
+ // src/lib/agent-config.ts
340
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
341
+ import path7 from "path";
342
+ function loadAgentConfig() {
343
+ if (!existsSync7(AGENT_CONFIG_PATH)) return {};
344
+ try {
345
+ return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
346
+ } catch {
347
+ return {};
348
+ }
349
+ }
350
+ function saveAgentConfig(config) {
351
+ const dir = path7.dirname(AGENT_CONFIG_PATH);
352
+ ensurePrivateDirSync(dir);
353
+ writeFileSync5(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
354
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
355
+ }
356
+ function setAgentRuntime(agentId, runtime, model) {
357
+ const knownModels = KNOWN_RUNTIMES[runtime];
358
+ if (!knownModels) {
359
+ return {
360
+ ok: false,
361
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
362
+ };
363
+ }
364
+ if (!knownModels.includes(model)) {
365
+ return {
366
+ ok: false,
367
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
368
+ };
369
+ }
370
+ const config = loadAgentConfig();
371
+ config[agentId] = { runtime, model };
372
+ saveAgentConfig(config);
373
+ return { ok: true };
374
+ }
375
+ function clearAgentRuntime(agentId) {
376
+ const config = loadAgentConfig();
377
+ delete config[agentId];
378
+ saveAgentConfig(config);
379
+ }
380
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
381
+ var init_agent_config = __esm({
382
+ "src/lib/agent-config.ts"() {
383
+ "use strict";
384
+ init_config();
385
+ init_runtime_table();
386
+ init_secure_files();
387
+ AGENT_CONFIG_PATH = path7.join(EXE_AI_DIR, "agent-config.json");
388
+ KNOWN_RUNTIMES = {
389
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
390
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
391
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
392
+ };
393
+ RUNTIME_LABELS = {
394
+ claude: "Claude Code (Anthropic)",
395
+ codex: "Codex (OpenAI)",
396
+ opencode: "OpenCode (open source)"
397
+ };
398
+ DEFAULT_MODELS = {
399
+ claude: "claude-opus-4",
400
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
401
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
402
+ };
248
403
  }
249
404
  });
250
405
 
@@ -269,9 +424,9 @@ function isMainModule(importMetaUrl) {
269
424
 
270
425
  // src/lib/cloud-sync.ts
271
426
  init_database();
272
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
427
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync4, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
273
428
  import crypto2 from "crypto";
274
- import path5 from "path";
429
+ import path6 from "path";
275
430
  import { homedir as homedir2 } from "os";
276
431
 
277
432
  // src/lib/crypto.ts
@@ -282,20 +437,24 @@ import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
282
437
 
283
438
  // src/lib/license.ts
284
439
  init_config();
285
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
440
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
286
441
  import { randomUUID } from "crypto";
287
- import path3 from "path";
442
+ import { createRequire as createRequire2 } from "module";
443
+ import { pathToFileURL as pathToFileURL2 } from "url";
444
+ import os4 from "os";
445
+ import path4 from "path";
288
446
  import { jwtVerify, importSPKI } from "jose";
289
- var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
290
- var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
291
- var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
447
+ var LICENSE_PATH = path4.join(EXE_AI_DIR, "license.key");
448
+ var CACHE_PATH = path4.join(EXE_AI_DIR, "license-cache.json");
449
+ var DEVICE_ID_PATH = path4.join(EXE_AI_DIR, "device-id");
292
450
 
293
451
  // src/lib/cloud-sync.ts
294
452
  init_config();
295
453
  init_crdt_sync();
296
454
  init_employees();
455
+ init_secure_files();
297
456
  var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
298
- var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
457
+ var ROSTER_LOCK_PATH = path6.join(EXE_AI_DIR, "roster-merge.lock");
299
458
  function assertSecureEndpoint(endpoint) {
300
459
  if (endpoint.startsWith("https://")) return;
301
460
  if (endpoint.startsWith("http://")) {
@@ -310,90 +469,11 @@ function assertSecureEndpoint(endpoint) {
310
469
  );
311
470
  }
312
471
  }
313
- var ROSTER_DELETIONS_PATH = path5.join(EXE_AI_DIR, "roster-deletions.json");
314
-
315
- // src/lib/agent-config.ts
316
- init_config();
317
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
318
- import path6 from "path";
319
-
320
- // src/lib/runtime-table.ts
321
- var RUNTIME_TABLE = {
322
- codex: {
323
- binary: "codex",
324
- launchMode: "interactive",
325
- autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
326
- inlineFlag: "--no-alt-screen",
327
- apiKeyEnv: "OPENAI_API_KEY",
328
- defaultModel: "gpt-5.4"
329
- },
330
- opencode: {
331
- binary: "opencode",
332
- launchMode: "exec",
333
- autoApproveFlag: "--dangerously-skip-permissions",
334
- inlineFlag: "",
335
- apiKeyEnv: "ANTHROPIC_API_KEY",
336
- defaultModel: "anthropic/claude-sonnet-4-6"
337
- }
338
- };
339
- var DEFAULT_RUNTIME = "claude";
340
-
341
- // src/lib/agent-config.ts
342
- var AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
343
- var KNOWN_RUNTIMES = {
344
- claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
345
- codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
346
- opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
347
- };
348
- var RUNTIME_LABELS = {
349
- claude: "Claude Code (Anthropic)",
350
- codex: "Codex (OpenAI)",
351
- opencode: "OpenCode (open source)"
352
- };
353
- var DEFAULT_MODELS = {
354
- claude: "claude-opus-4",
355
- codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
356
- opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
357
- };
358
- function loadAgentConfig() {
359
- if (!existsSync6(AGENT_CONFIG_PATH)) return {};
360
- try {
361
- return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
362
- } catch {
363
- return {};
364
- }
365
- }
366
- function saveAgentConfig(config) {
367
- const dir = path6.dirname(AGENT_CONFIG_PATH);
368
- if (!existsSync6(dir)) mkdirSync4(dir, { recursive: true });
369
- writeFileSync5(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
370
- }
371
- function setAgentRuntime(agentId, runtime, model) {
372
- const knownModels = KNOWN_RUNTIMES[runtime];
373
- if (!knownModels) {
374
- return {
375
- ok: false,
376
- error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
377
- };
378
- }
379
- if (!knownModels.includes(model)) {
380
- return {
381
- ok: false,
382
- error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
383
- };
384
- }
385
- const config = loadAgentConfig();
386
- config[agentId] = { runtime, model };
387
- saveAgentConfig(config);
388
- return { ok: true };
389
- }
390
- function clearAgentRuntime(agentId) {
391
- const config = loadAgentConfig();
392
- delete config[agentId];
393
- saveAgentConfig(config);
394
- }
472
+ var ROSTER_DELETIONS_PATH = path6.join(EXE_AI_DIR, "roster-deletions.json");
395
473
 
396
474
  // src/bin/exe-settings.ts
475
+ init_agent_config();
476
+ init_runtime_table();
397
477
  init_employees();
398
478
  function label(value) {
399
479
  return value ? "ON" : "OFF";