@askexenow/exe-os 0.9.8 → 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 +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
@@ -1,11 +1,47 @@
1
+ var __defProp = Object.defineProperty;
1
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
2
9
  var __esm = (fn, res) => function __init() {
3
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
11
  };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+
17
+ // src/lib/secure-files.ts
18
+ import { chmodSync, existsSync, mkdirSync } from "fs";
19
+ import { chmod, mkdir } from "fs/promises";
20
+ function ensurePrivateDirSync(dirPath) {
21
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
22
+ try {
23
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
24
+ } catch {
25
+ }
26
+ }
27
+ function enforcePrivateFileSync(filePath) {
28
+ try {
29
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
30
+ } catch {
31
+ }
32
+ }
33
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
34
+ var init_secure_files = __esm({
35
+ "src/lib/secure-files.ts"() {
36
+ "use strict";
37
+ PRIVATE_DIR_MODE = 448;
38
+ PRIVATE_FILE_MODE = 384;
39
+ }
40
+ });
5
41
 
6
42
  // src/lib/config.ts
7
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
8
- import { readFileSync, existsSync, renameSync } from "fs";
43
+ import { readFile, writeFile } from "fs/promises";
44
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
9
45
  import path from "path";
10
46
  import os from "os";
11
47
  function resolveDataDir() {
@@ -13,7 +49,7 @@ function resolveDataDir() {
13
49
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
14
50
  const newDir = path.join(os.homedir(), ".exe-os");
15
51
  const legacyDir = path.join(os.homedir(), ".exe-mem");
16
- if (!existsSync(newDir) && existsSync(legacyDir)) {
52
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
17
53
  try {
18
54
  renameSync(legacyDir, newDir);
19
55
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -77,7 +113,7 @@ function normalizeAutoUpdate(raw) {
77
113
  function loadConfigSync() {
78
114
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
79
115
  const configPath = path.join(dir, "config.json");
80
- if (!existsSync(configPath)) {
116
+ if (!existsSync2(configPath)) {
81
117
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
82
118
  }
83
119
  try {
@@ -97,6 +133,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
97
133
  var init_config = __esm({
98
134
  "src/lib/config.ts"() {
99
135
  "use strict";
136
+ init_secure_files();
100
137
  EXE_AI_DIR = resolveDataDir();
101
138
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
102
139
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -173,19 +210,703 @@ var init_config = __esm({
173
210
  }
174
211
  });
175
212
 
213
+ // src/lib/runtime-table.ts
214
+ var RUNTIME_TABLE, DEFAULT_RUNTIME;
215
+ var init_runtime_table = __esm({
216
+ "src/lib/runtime-table.ts"() {
217
+ "use strict";
218
+ RUNTIME_TABLE = {
219
+ codex: {
220
+ binary: "codex",
221
+ launchMode: "interactive",
222
+ autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
223
+ inlineFlag: "--no-alt-screen",
224
+ apiKeyEnv: "OPENAI_API_KEY",
225
+ defaultModel: "gpt-5.4"
226
+ },
227
+ opencode: {
228
+ binary: "opencode",
229
+ launchMode: "exec",
230
+ autoApproveFlag: "--dangerously-skip-permissions",
231
+ inlineFlag: "",
232
+ apiKeyEnv: "ANTHROPIC_API_KEY",
233
+ defaultModel: "anthropic/claude-sonnet-4-6"
234
+ }
235
+ };
236
+ DEFAULT_RUNTIME = "claude";
237
+ }
238
+ });
239
+
240
+ // src/lib/agent-config.ts
241
+ var agent_config_exports = {};
242
+ __export(agent_config_exports, {
243
+ AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
244
+ DEFAULT_MODELS: () => DEFAULT_MODELS,
245
+ KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
246
+ RUNTIME_LABELS: () => RUNTIME_LABELS,
247
+ clearAgentRuntime: () => clearAgentRuntime,
248
+ getAgentRuntime: () => getAgentRuntime,
249
+ loadAgentConfig: () => loadAgentConfig,
250
+ saveAgentConfig: () => saveAgentConfig,
251
+ setAgentRuntime: () => setAgentRuntime
252
+ });
253
+ import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
254
+ import path2 from "path";
255
+ function loadAgentConfig() {
256
+ if (!existsSync3(AGENT_CONFIG_PATH)) return {};
257
+ try {
258
+ return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
259
+ } catch {
260
+ return {};
261
+ }
262
+ }
263
+ function saveAgentConfig(config) {
264
+ const dir = path2.dirname(AGENT_CONFIG_PATH);
265
+ ensurePrivateDirSync(dir);
266
+ writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
267
+ enforcePrivateFileSync(AGENT_CONFIG_PATH);
268
+ }
269
+ function getAgentRuntime(agentId) {
270
+ const config = loadAgentConfig();
271
+ const entry = config[agentId];
272
+ if (entry) return entry;
273
+ const orgDefault = config["default"];
274
+ if (orgDefault) return orgDefault;
275
+ return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
276
+ }
277
+ function setAgentRuntime(agentId, runtime, model) {
278
+ const knownModels = KNOWN_RUNTIMES[runtime];
279
+ if (!knownModels) {
280
+ return {
281
+ ok: false,
282
+ error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
283
+ };
284
+ }
285
+ if (!knownModels.includes(model)) {
286
+ return {
287
+ ok: false,
288
+ error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
289
+ };
290
+ }
291
+ const config = loadAgentConfig();
292
+ config[agentId] = { runtime, model };
293
+ saveAgentConfig(config);
294
+ return { ok: true };
295
+ }
296
+ function clearAgentRuntime(agentId) {
297
+ const config = loadAgentConfig();
298
+ delete config[agentId];
299
+ saveAgentConfig(config);
300
+ }
301
+ var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
302
+ var init_agent_config = __esm({
303
+ "src/lib/agent-config.ts"() {
304
+ "use strict";
305
+ init_config();
306
+ init_runtime_table();
307
+ init_secure_files();
308
+ AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
309
+ KNOWN_RUNTIMES = {
310
+ claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
311
+ codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
312
+ opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
313
+ };
314
+ RUNTIME_LABELS = {
315
+ claude: "Claude Code (Anthropic)",
316
+ codex: "Codex (OpenAI)",
317
+ opencode: "OpenCode (open source)"
318
+ };
319
+ DEFAULT_MODELS = {
320
+ claude: "claude-opus-4",
321
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
322
+ opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
323
+ };
324
+ }
325
+ });
326
+
327
+ // src/lib/employees.ts
328
+ var employees_exports = {};
329
+ __export(employees_exports, {
330
+ COORDINATOR_ROLE: () => COORDINATOR_ROLE,
331
+ DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
332
+ EMPLOYEES_PATH: () => EMPLOYEES_PATH,
333
+ addEmployee: () => addEmployee,
334
+ baseAgentName: () => baseAgentName,
335
+ canCoordinate: () => canCoordinate,
336
+ getCoordinatorEmployee: () => getCoordinatorEmployee,
337
+ getCoordinatorName: () => getCoordinatorName,
338
+ getEmployee: () => getEmployee,
339
+ getEmployeeByRole: () => getEmployeeByRole,
340
+ getEmployeeNamesByRole: () => getEmployeeNamesByRole,
341
+ hasRole: () => hasRole,
342
+ hireEmployee: () => hireEmployee,
343
+ isCoordinatorName: () => isCoordinatorName,
344
+ isCoordinatorRole: () => isCoordinatorRole,
345
+ isMultiInstance: () => isMultiInstance,
346
+ loadEmployees: () => loadEmployees,
347
+ loadEmployeesSync: () => loadEmployeesSync,
348
+ normalizeRole: () => normalizeRole,
349
+ normalizeRosterCase: () => normalizeRosterCase,
350
+ registerBinSymlinks: () => registerBinSymlinks,
351
+ saveEmployees: () => saveEmployees,
352
+ validateEmployeeName: () => validateEmployeeName
353
+ });
354
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
355
+ import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
356
+ import { execSync as execSync2 } from "child_process";
357
+ import path3 from "path";
358
+ import os2 from "os";
359
+ function normalizeRole(role) {
360
+ return (role ?? "").trim().toLowerCase();
361
+ }
362
+ function isCoordinatorRole(role) {
363
+ return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
364
+ }
365
+ function getCoordinatorEmployee(employees) {
366
+ return employees.find((e) => isCoordinatorRole(e.role));
367
+ }
368
+ function getCoordinatorName(employees = loadEmployeesSync()) {
369
+ return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
370
+ }
371
+ function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
372
+ if (!agentName) return false;
373
+ return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
374
+ }
375
+ function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
376
+ return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
377
+ }
378
+ function validateEmployeeName(name) {
379
+ if (!name) {
380
+ return { valid: false, error: "Name is required" };
381
+ }
382
+ if (name.length > 32) {
383
+ return { valid: false, error: "Name must be 32 characters or fewer" };
384
+ }
385
+ if (!/^[a-z][a-z0-9]*$/.test(name)) {
386
+ return {
387
+ valid: false,
388
+ error: "Name must start with a letter and contain only lowercase alphanumeric characters"
389
+ };
390
+ }
391
+ return { valid: true };
392
+ }
393
+ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
394
+ if (!existsSync4(employeesPath)) {
395
+ return [];
396
+ }
397
+ const raw = await readFile2(employeesPath, "utf-8");
398
+ try {
399
+ return JSON.parse(raw);
400
+ } catch {
401
+ return [];
402
+ }
403
+ }
404
+ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
405
+ await mkdir2(path3.dirname(employeesPath), { recursive: true });
406
+ await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
407
+ }
408
+ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
409
+ if (!existsSync4(employeesPath)) return [];
410
+ try {
411
+ return JSON.parse(readFileSync3(employeesPath, "utf-8"));
412
+ } catch {
413
+ return [];
414
+ }
415
+ }
416
+ function getEmployee(employees, name) {
417
+ return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
418
+ }
419
+ function getEmployeeByRole(employees, role) {
420
+ const lower = role.toLowerCase();
421
+ return employees.find((e) => e.role.toLowerCase() === lower);
422
+ }
423
+ function getEmployeeNamesByRole(employees, role) {
424
+ const lower = role.toLowerCase();
425
+ return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
426
+ }
427
+ function hasRole(agentName, role) {
428
+ const employees = loadEmployeesSync();
429
+ const emp = getEmployee(employees, agentName);
430
+ return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
431
+ }
432
+ function baseAgentName(name, employees) {
433
+ const match = name.match(/^([a-zA-Z]+)\d+$/);
434
+ if (!match) return name;
435
+ const base = match[1];
436
+ const roster = employees ?? loadEmployeesSync();
437
+ if (getEmployee(roster, base)) return base;
438
+ return name;
439
+ }
440
+ function isMultiInstance(agentName, employees) {
441
+ const roster = employees ?? loadEmployeesSync();
442
+ const emp = getEmployee(roster, agentName);
443
+ if (!emp) return false;
444
+ return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
445
+ }
446
+ function addEmployee(employees, employee) {
447
+ const normalized = { ...employee, name: employee.name.toLowerCase() };
448
+ if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
449
+ throw new Error(`Employee '${normalized.name}' already exists`);
450
+ }
451
+ return [...employees, normalized];
452
+ }
453
+ function appendToCoordinatorTeam(employee) {
454
+ const coordinator = getCoordinatorEmployee(loadEmployeesSync());
455
+ if (!coordinator) return;
456
+ const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
457
+ if (!existsSync4(idPath)) return;
458
+ const content = readFileSync3(idPath, "utf-8");
459
+ if (content.includes(`**${capitalize(employee.name)}`)) return;
460
+ const teamMatch = content.match(TEAM_SECTION_RE);
461
+ if (!teamMatch || teamMatch.index === void 0) return;
462
+ const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
463
+ const nextHeading = afterTeam.match(/\n## /);
464
+ const entry = `
465
+ **${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
466
+ `;
467
+ let updated;
468
+ if (nextHeading && nextHeading.index !== void 0) {
469
+ const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
470
+ updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
471
+ } else {
472
+ updated = content.trimEnd() + "\n" + entry;
473
+ }
474
+ writeFileSync2(idPath, updated, "utf-8");
475
+ }
476
+ function capitalize(s) {
477
+ return s.charAt(0).toUpperCase() + s.slice(1);
478
+ }
479
+ async function hireEmployee(employee) {
480
+ const employees = await loadEmployees();
481
+ const updated = addEmployee(employees, employee);
482
+ await saveEmployees(updated);
483
+ try {
484
+ appendToCoordinatorTeam(employee);
485
+ } catch {
486
+ }
487
+ try {
488
+ const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
489
+ const config = loadAgentConfig2();
490
+ const name = employee.name.toLowerCase();
491
+ if (!config[name] && config["default"]) {
492
+ config[name] = { ...config["default"] };
493
+ saveAgentConfig2(config);
494
+ }
495
+ } catch {
496
+ }
497
+ return updated;
498
+ }
499
+ async function normalizeRosterCase(rosterPath) {
500
+ const employees = await loadEmployees(rosterPath);
501
+ let changed = false;
502
+ for (const emp of employees) {
503
+ if (emp.name !== emp.name.toLowerCase()) {
504
+ const oldName = emp.name;
505
+ emp.name = emp.name.toLowerCase();
506
+ changed = true;
507
+ try {
508
+ const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
509
+ const oldPath = path3.join(identityDir, `${oldName}.md`);
510
+ const newPath = path3.join(identityDir, `${emp.name}.md`);
511
+ if (existsSync4(oldPath) && !existsSync4(newPath)) {
512
+ renameSync2(oldPath, newPath);
513
+ } else if (existsSync4(oldPath) && oldPath !== newPath) {
514
+ const content = readFileSync3(oldPath, "utf-8");
515
+ writeFileSync2(newPath, content, "utf-8");
516
+ if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
517
+ unlinkSync(oldPath);
518
+ }
519
+ }
520
+ } catch {
521
+ }
522
+ }
523
+ }
524
+ if (changed) {
525
+ await saveEmployees(employees, rosterPath);
526
+ }
527
+ return changed;
528
+ }
529
+ function findExeBin() {
530
+ try {
531
+ return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
532
+ } catch {
533
+ return null;
534
+ }
535
+ }
536
+ function registerBinSymlinks(name) {
537
+ const created = [];
538
+ const skipped = [];
539
+ const errors = [];
540
+ const exeBinPath = findExeBin();
541
+ if (!exeBinPath) {
542
+ errors.push("Could not find 'exe-os' in PATH");
543
+ return { created, skipped, errors };
544
+ }
545
+ const binDir = path3.dirname(exeBinPath);
546
+ let target;
547
+ try {
548
+ target = readlinkSync(exeBinPath);
549
+ } catch {
550
+ errors.push("Could not read 'exe' symlink");
551
+ return { created, skipped, errors };
552
+ }
553
+ for (const suffix of ["", "-opencode"]) {
554
+ const linkName = `${name}${suffix}`;
555
+ const linkPath = path3.join(binDir, linkName);
556
+ if (existsSync4(linkPath)) {
557
+ skipped.push(linkName);
558
+ continue;
559
+ }
560
+ try {
561
+ symlinkSync(target, linkPath);
562
+ created.push(linkName);
563
+ } catch (err) {
564
+ errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
565
+ }
566
+ }
567
+ return { created, skipped, errors };
568
+ }
569
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
570
+ var init_employees = __esm({
571
+ "src/lib/employees.ts"() {
572
+ "use strict";
573
+ init_config();
574
+ EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
575
+ DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
576
+ COORDINATOR_ROLE = "COO";
577
+ MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
578
+ IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
579
+ TEAM_SECTION_RE = /^## Team\b.*$/m;
580
+ }
581
+ });
582
+
583
+ // src/lib/mcp-prefix.ts
584
+ function isExeMcpTool(toolName) {
585
+ if (!toolName) return false;
586
+ return MCP_TOOL_PREFIXES.some((p) => toolName.startsWith(p));
587
+ }
588
+ function stripExeMcpPrefix(toolName) {
589
+ for (const p of MCP_TOOL_PREFIXES) {
590
+ if (toolName.startsWith(p)) return toolName.slice(p.length);
591
+ }
592
+ return toolName;
593
+ }
594
+ var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
595
+ var init_mcp_prefix = __esm({
596
+ "src/lib/mcp-prefix.ts"() {
597
+ "use strict";
598
+ MCP_PRIMARY_KEY = "exe-os";
599
+ MCP_LEGACY_KEY = "exe-mem";
600
+ MCP_TOOL_PREFIXES = [
601
+ `mcp__${MCP_PRIMARY_KEY}__`,
602
+ `mcp__${MCP_LEGACY_KEY}__`
603
+ ];
604
+ }
605
+ });
606
+
607
+ // src/lib/content-extractor.ts
608
+ var content_extractor_exports = {};
609
+ __export(content_extractor_exports, {
610
+ extractSemanticText: () => extractSemanticText
611
+ });
612
+ function extractSemanticText(toolName, toolInput, toolResponse) {
613
+ switch (toolName) {
614
+ case "Write":
615
+ return extractWrite(toolInput);
616
+ case "Edit":
617
+ return extractEdit(toolInput);
618
+ case "Read":
619
+ return extractRead(toolInput, toolResponse);
620
+ case "Bash":
621
+ return extractBash(toolInput, toolResponse);
622
+ case "Grep":
623
+ return extractGrep(toolInput, toolResponse);
624
+ case "Glob":
625
+ return extractGlob(toolInput, toolResponse);
626
+ default:
627
+ if (isExeMcpTool(toolName)) {
628
+ return extractExeMemMcp(toolName, toolInput, toolResponse);
629
+ }
630
+ if (toolName.startsWith("mcp__")) {
631
+ return extractGenericMcp(toolName, toolInput, toolResponse);
632
+ }
633
+ return extractDefault(toolName, toolInput, toolResponse);
634
+ }
635
+ }
636
+ function findContainingChunk(filePath, snippet) {
637
+ try {
638
+ const ext = filePath.split(".").pop()?.toLowerCase();
639
+ if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
640
+ const { readFileSync: readFileSync7 } = __require("fs");
641
+ const source = readFileSync7(filePath, "utf8");
642
+ const lines = source.split("\n");
643
+ const lowerSnippet = snippet.toLowerCase().slice(0, 80);
644
+ let matchLine = -1;
645
+ for (let i = 0; i < lines.length; i++) {
646
+ if (lines[i].toLowerCase().includes(lowerSnippet)) {
647
+ matchLine = i;
648
+ break;
649
+ }
650
+ }
651
+ if (matchLine === -1) return "";
652
+ for (let i = matchLine; i >= 0; i--) {
653
+ const line = lines[i];
654
+ const fnMatch = line.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
655
+ if (fnMatch) return `Function ${fnMatch[1]} in ${filePath}:${i + 1}`;
656
+ const classMatch = line.match(/(?:export\s+)?class\s+(\w+)/);
657
+ if (classMatch) return `Class ${classMatch[1]} in ${filePath}:${i + 1}`;
658
+ const arrowMatch = line.match(/(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?\(/);
659
+ if (arrowMatch) return `Function ${arrowMatch[1]} in ${filePath}:${i + 1}`;
660
+ }
661
+ } catch {
662
+ }
663
+ return "";
664
+ }
665
+ function extractWrite(input2) {
666
+ const filePath = String(input2.file_path ?? "");
667
+ const content = String(input2.content ?? "");
668
+ const chunkContext = findContainingChunk(filePath, content.slice(0, 200));
669
+ const prefix = chunkContext ? `Wrote ${filePath} (${chunkContext})` : `Wrote ${filePath}`;
670
+ return `${prefix}
671
+ ${content.slice(0, MAX_CONTENT)}`;
672
+ }
673
+ function extractEdit(input2) {
674
+ const filePath = String(input2.file_path ?? "");
675
+ const oldStr = String(input2.old_string ?? "");
676
+ const newStr = String(input2.new_string ?? "");
677
+ const chunkContext = findContainingChunk(filePath, oldStr.slice(0, 200));
678
+ const prefix = chunkContext ? `Edited ${filePath} (${chunkContext})` : `Edited ${filePath}`;
679
+ return `${prefix}
680
+ Removed: ${oldStr.slice(0, MAX_CONTENT / 2)}
681
+ Added: ${newStr.slice(0, MAX_CONTENT / 2)}`;
682
+ }
683
+ function extractRead(input2, response) {
684
+ const filePath = String(input2.file_path ?? "");
685
+ const file = response.file;
686
+ const content = file ? String(file.content ?? "") : "";
687
+ if (!content) {
688
+ const text = String(response.text ?? response.content ?? "");
689
+ return `Read ${filePath}
690
+ ${text.slice(0, MAX_CONTENT)}`;
691
+ }
692
+ return `Read ${filePath}
693
+ ${content.slice(0, MAX_CONTENT)}`;
694
+ }
695
+ function extractBash(input2, response) {
696
+ const command = String(input2.command ?? "");
697
+ const description = input2.description ? String(input2.description) : "";
698
+ const stdout = String(response.stdout ?? response.text ?? "");
699
+ const stderr = String(response.stderr ?? "");
700
+ const parts = [description ? `${description}: ${command}` : `Ran: ${command}`];
701
+ if (stdout) parts.push(`Output: ${stdout.slice(0, MAX_OUTPUT)}`);
702
+ if (stderr && !stdout) parts.push(`Error: ${stderr.slice(0, MAX_OUTPUT)}`);
703
+ return parts.join("\n");
704
+ }
705
+ function extractGrep(input2, response) {
706
+ const pattern = String(input2.pattern ?? "");
707
+ const path9 = input2.path ? String(input2.path) : "";
708
+ const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
709
+ return `Searched for "${pattern}"${path9 ? ` in ${path9}` : ""}
710
+ ${output.slice(0, MAX_OUTPUT)}`;
711
+ }
712
+ function extractGlob(input2, response) {
713
+ const pattern = String(input2.pattern ?? "");
714
+ const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
715
+ return `Found files matching "${pattern}"
716
+ ${output.slice(0, MAX_OUTPUT)}`;
717
+ }
718
+ function extractExeMemMcp(toolName, input2, response) {
719
+ const shortName = stripExeMcpPrefix(toolName);
720
+ switch (shortName) {
721
+ case "store_memory": {
722
+ const text = String(input2.text ?? input2.query ?? "");
723
+ return `Stored memory: ${text.slice(0, MAX_CONTENT)}`;
724
+ }
725
+ case "recall_my_memory":
726
+ case "ask_team_memory": {
727
+ const query = String(input2.query ?? "");
728
+ const member = input2.team_member ? ` (from ${input2.team_member})` : "";
729
+ const resultText = extractResponseText(response);
730
+ return `Memory search${member}: "${query}"
731
+ ${resultText.slice(0, MAX_OUTPUT)}`;
732
+ }
733
+ case "create_task": {
734
+ const title = String(input2.title ?? "");
735
+ const assignedTo = String(input2.assigned_to ?? "");
736
+ const priority = String(input2.priority ?? "p1");
737
+ const context = String(input2.context ?? "");
738
+ return `Task created: "${title}" assigned to ${assignedTo} [${priority}]
739
+ ${context.slice(0, MAX_CONTENT)}`;
740
+ }
741
+ case "update_task": {
742
+ const taskId = String(input2.task_id ?? "");
743
+ const status = String(input2.status ?? "");
744
+ const result = input2.result ? String(input2.result) : "";
745
+ return `Task updated: ${taskId} \u2192 ${status}${result ? `
746
+ Result: ${result.slice(0, MAX_CONTENT)}` : ""}`;
747
+ }
748
+ case "list_tasks": {
749
+ const resultText = extractResponseText(response);
750
+ return `Listed tasks
751
+ ${resultText.slice(0, MAX_OUTPUT)}`;
752
+ }
753
+ default: {
754
+ return extractGenericMcp(toolName, input2, response);
755
+ }
756
+ }
757
+ }
758
+ function extractGenericMcp(toolName, input2, response) {
759
+ const shortName = toolName.replace(/^mcp__[^_]+__/, "");
760
+ const inputParts = Object.entries(input2).filter(([, v]) => v != null && String(v).length > 0).map(([k, v]) => `${k}: ${String(v).slice(0, 200)}`).join(", ");
761
+ const resultText = extractResponseText(response);
762
+ return `${shortName}(${inputParts})
763
+ ${resultText.slice(0, MAX_OUTPUT)}`;
764
+ }
765
+ function extractDefault(toolName, input2, response) {
766
+ const inputStr = JSON.stringify(input2);
767
+ const resultText = extractResponseText(response);
768
+ return `Tool: ${toolName}
769
+ ${inputStr.slice(0, MAX_CONTENT / 2)}
770
+ ${resultText.slice(0, MAX_OUTPUT)}`;
771
+ }
772
+ function extractResponseText(response) {
773
+ if (typeof response.text === "string") return response.text;
774
+ if (typeof response.content === "string") return response.content;
775
+ if (Array.isArray(response.content)) {
776
+ return response.content.map((block) => {
777
+ if (typeof block === "object" && block !== null && "text" in block) {
778
+ return String(block.text);
779
+ }
780
+ return "";
781
+ }).filter(Boolean).join("\n");
782
+ }
783
+ if (Array.isArray(response)) {
784
+ return response.map((item) => {
785
+ if (typeof item === "object" && item !== null && "text" in item) {
786
+ return String(item.text);
787
+ }
788
+ return "";
789
+ }).filter(Boolean).join("\n");
790
+ }
791
+ return JSON.stringify(response).slice(0, MAX_OUTPUT);
792
+ }
793
+ var MAX_CONTENT, MAX_OUTPUT;
794
+ var init_content_extractor = __esm({
795
+ "src/lib/content-extractor.ts"() {
796
+ "use strict";
797
+ init_mcp_prefix();
798
+ MAX_CONTENT = 2e3;
799
+ MAX_OUTPUT = 1e3;
800
+ }
801
+ });
802
+
803
+ // src/lib/project-name.ts
804
+ var project_name_exports = {};
805
+ __export(project_name_exports, {
806
+ _resetCache: () => _resetCache,
807
+ getProjectName: () => getProjectName
808
+ });
809
+ import { execSync as execSync4 } from "child_process";
810
+ import path6 from "path";
811
+ function getProjectName(cwd) {
812
+ const dir = cwd ?? process.cwd();
813
+ if (_cached2 && _cachedCwd === dir) return _cached2;
814
+ try {
815
+ let repoRoot;
816
+ try {
817
+ const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
818
+ cwd: dir,
819
+ encoding: "utf8",
820
+ timeout: 2e3,
821
+ stdio: ["pipe", "pipe", "pipe"]
822
+ }).trim();
823
+ repoRoot = path6.dirname(gitCommonDir);
824
+ } catch {
825
+ repoRoot = execSync4("git rev-parse --show-toplevel", {
826
+ cwd: dir,
827
+ encoding: "utf8",
828
+ timeout: 2e3,
829
+ stdio: ["pipe", "pipe", "pipe"]
830
+ }).trim();
831
+ }
832
+ _cached2 = path6.basename(repoRoot);
833
+ _cachedCwd = dir;
834
+ return _cached2;
835
+ } catch {
836
+ _cached2 = path6.basename(dir);
837
+ _cachedCwd = dir;
838
+ return _cached2;
839
+ }
840
+ }
841
+ function _resetCache() {
842
+ _cached2 = null;
843
+ _cachedCwd = null;
844
+ }
845
+ var _cached2, _cachedCwd;
846
+ var init_project_name = __esm({
847
+ "src/lib/project-name.ts"() {
848
+ "use strict";
849
+ _cached2 = null;
850
+ _cachedCwd = null;
851
+ }
852
+ });
853
+
854
+ // src/lib/daemon-auth.ts
855
+ var daemon_auth_exports = {};
856
+ __export(daemon_auth_exports, {
857
+ DAEMON_TOKEN_PATH: () => DAEMON_TOKEN_PATH,
858
+ ensureDaemonToken: () => ensureDaemonToken,
859
+ readDaemonToken: () => readDaemonToken
860
+ });
861
+ import crypto2 from "crypto";
862
+ import path7 from "path";
863
+ import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
864
+ function normalizeToken(token) {
865
+ if (!token) return null;
866
+ const trimmed = token.trim();
867
+ return trimmed.length > 0 ? trimmed : null;
868
+ }
869
+ function readDaemonToken() {
870
+ try {
871
+ if (!existsSync6(DAEMON_TOKEN_PATH)) return null;
872
+ return normalizeToken(readFileSync5(DAEMON_TOKEN_PATH, "utf8"));
873
+ } catch {
874
+ return null;
875
+ }
876
+ }
877
+ function ensureDaemonToken(seed) {
878
+ const existing = readDaemonToken();
879
+ if (existing) return existing;
880
+ const token = normalizeToken(seed) ?? crypto2.randomBytes(32).toString("hex");
881
+ ensurePrivateDirSync(EXE_AI_DIR);
882
+ writeFileSync5(DAEMON_TOKEN_PATH, `${token}
883
+ `, "utf8");
884
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
885
+ return token;
886
+ }
887
+ var DAEMON_TOKEN_PATH;
888
+ var init_daemon_auth = __esm({
889
+ "src/lib/daemon-auth.ts"() {
890
+ "use strict";
891
+ init_config();
892
+ init_secure_files();
893
+ DAEMON_TOKEN_PATH = path7.join(EXE_AI_DIR, "exed.token");
894
+ }
895
+ });
896
+
176
897
  // src/adapters/claude/hooks/ingest.ts
177
898
  init_config();
178
899
  init_config();
179
900
  import { spawn } from "child_process";
180
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync4, openSync, closeSync } from "fs";
181
- import path5 from "path";
901
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync7, openSync, closeSync } from "fs";
902
+ import path8 from "path";
182
903
  import { fileURLToPath } from "url";
183
904
 
184
905
  // src/lib/active-agent.ts
185
906
  init_config();
186
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync, unlinkSync as unlinkSync2, readdirSync } from "fs";
907
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
187
908
  import { execSync as execSync3 } from "child_process";
188
- import path3 from "path";
909
+ import path4 from "path";
189
910
 
190
911
  // src/lib/session-key.ts
191
912
  import { execSync } from "child_process";
@@ -249,43 +970,9 @@ function getSessionKey() {
249
970
  return _cached;
250
971
  }
251
972
 
252
- // src/lib/employees.ts
253
- init_config();
254
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
255
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
256
- import { execSync as execSync2 } from "child_process";
257
- import path2 from "path";
258
- import os2 from "os";
259
- var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
260
- var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
261
- var COORDINATOR_ROLE = "COO";
262
- function normalizeRole(role) {
263
- return (role ?? "").trim().toLowerCase();
264
- }
265
- function isCoordinatorRole(role) {
266
- return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
267
- }
268
- function getCoordinatorEmployee(employees) {
269
- return employees.find((e) => isCoordinatorRole(e.role));
270
- }
271
- function getCoordinatorName(employees = loadEmployeesSync()) {
272
- return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
273
- }
274
- function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
275
- if (!existsSync2(employeesPath)) return [];
276
- try {
277
- return JSON.parse(readFileSync2(employeesPath, "utf-8"));
278
- } catch {
279
- return [];
280
- }
281
- }
282
- function getEmployee(employees, name) {
283
- return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
284
- }
285
- var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
286
-
287
973
  // src/lib/active-agent.ts
288
- var CACHE_DIR = path3.join(EXE_AI_DIR, "session-cache");
974
+ init_employees();
975
+ var CACHE_DIR = path4.join(EXE_AI_DIR, "session-cache");
289
976
  var STALE_MS = 24 * 60 * 60 * 1e3;
290
977
  function isNameWithOptionalInstance(candidate, baseName) {
291
978
  if (candidate === baseName) return true;
@@ -330,12 +1017,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
330
1017
  return null;
331
1018
  }
332
1019
  function getMarkerPath() {
333
- return path3.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
1020
+ return path4.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
334
1021
  }
335
1022
  function getActiveAgent() {
336
1023
  try {
337
1024
  const markerPath = getMarkerPath();
338
- const raw = readFileSync3(markerPath, "utf8");
1025
+ const raw = readFileSync4(markerPath, "utf8");
339
1026
  const data = JSON.parse(raw);
340
1027
  if (data.agentId) {
341
1028
  if (data.startedAt) {
@@ -376,21 +1063,8 @@ function getActiveAgent() {
376
1063
  }
377
1064
 
378
1065
  // src/lib/error-detector.ts
1066
+ init_mcp_prefix();
379
1067
  import crypto from "crypto";
380
-
381
- // 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
- function isExeMcpTool(toolName) {
389
- if (!toolName) return false;
390
- return MCP_TOOL_PREFIXES.some((p) => toolName.startsWith(p));
391
- }
392
-
393
- // src/lib/error-detector.ts
394
1068
  var ERROR_PATTERNS = [
395
1069
  /\bError\b/i,
396
1070
  /\bERR!\b/,
@@ -527,16 +1201,16 @@ function errorFingerprint(toolName, errorText) {
527
1201
 
528
1202
  // src/lib/worker-gate.ts
529
1203
  init_config();
530
- import { readdirSync as readdirSync2, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
531
- import path4 from "path";
532
- var WORKER_PID_DIR = path4.join(EXE_AI_DIR, "worker-pids");
1204
+ import { readdirSync as readdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
1205
+ import path5 from "path";
1206
+ var WORKER_PID_DIR = path5.join(EXE_AI_DIR, "worker-pids");
533
1207
  var MAX_CONCURRENT_WORKERS = 3;
534
1208
  function tryAcquireWorkerSlot() {
535
1209
  try {
536
- mkdirSync2(WORKER_PID_DIR, { recursive: true });
1210
+ mkdirSync3(WORKER_PID_DIR, { recursive: true });
537
1211
  const reservationId = `res-${process.pid}-${Date.now()}`;
538
- const reservationPath = path4.join(WORKER_PID_DIR, `${reservationId}.pid`);
539
- writeFileSync3(reservationPath, String(process.pid));
1212
+ const reservationPath = path5.join(WORKER_PID_DIR, `${reservationId}.pid`);
1213
+ writeFileSync4(reservationPath, String(process.pid));
540
1214
  const files = readdirSync2(WORKER_PID_DIR);
541
1215
  let alive = 0;
542
1216
  for (const f of files) {
@@ -553,7 +1227,7 @@ function tryAcquireWorkerSlot() {
553
1227
  alive++;
554
1228
  } catch {
555
1229
  try {
556
- unlinkSync3(path4.join(WORKER_PID_DIR, f));
1230
+ unlinkSync3(path5.join(WORKER_PID_DIR, f));
557
1231
  } catch {
558
1232
  }
559
1233
  }
@@ -576,14 +1250,15 @@ function tryAcquireWorkerSlot() {
576
1250
  }
577
1251
  function registerWorkerPid(pid) {
578
1252
  try {
579
- mkdirSync2(WORKER_PID_DIR, { recursive: true });
580
- writeFileSync3(path4.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
1253
+ mkdirSync3(WORKER_PID_DIR, { recursive: true });
1254
+ writeFileSync4(path5.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
581
1255
  } catch {
582
1256
  }
583
1257
  }
584
- var BACKFILL_LOCK = path4.join(WORKER_PID_DIR, "backfill.lock");
1258
+ var BACKFILL_LOCK = path5.join(WORKER_PID_DIR, "backfill.lock");
585
1259
 
586
1260
  // src/adapters/claude/hooks/ingest.ts
1261
+ init_employees();
587
1262
  if (!process.env.AGENT_ID) {
588
1263
  process.env.AGENT_ID = "default";
589
1264
  process.env.AGENT_ROLE = "employee";
@@ -594,7 +1269,7 @@ if (!loadConfigSync().autoIngestion) {
594
1269
  if (!process.env.EXE_OS_DIR) {
595
1270
  process.env.EXE_OS_DIR = EXE_AI_DIR;
596
1271
  }
597
- var WORKER_LOG_PATH = path5.join(EXE_AI_DIR, "workers.log");
1272
+ var WORKER_LOG_PATH = path8.join(EXE_AI_DIR, "workers.log");
598
1273
  function openWorkerLog() {
599
1274
  try {
600
1275
  return openSync(WORKER_LOG_PATH, "a");
@@ -606,13 +1281,13 @@ var ALLOWED_TOOL_RE = /^(Bash|Edit|Write|Read|Glob|Grep|Agent|apply_patch|mcp__.
606
1281
  var WRITE_TOOL_RE = /^(Bash|Edit|Write|apply_patch)$/;
607
1282
  var SUMMARY_INTERVAL = 25;
608
1283
  var MIN_WRITES_FOR_SUMMARY = 3;
609
- var COUNTER_DIR = path5.join(EXE_AI_DIR, "session-cache");
1284
+ var COUNTER_DIR = path8.join(EXE_AI_DIR, "session-cache");
610
1285
  function getCounterPath(sessionId) {
611
- return path5.join(COUNTER_DIR, `counter-${sessionId}.json`);
1286
+ return path8.join(COUNTER_DIR, `counter-${sessionId}.json`);
612
1287
  }
613
1288
  function loadCounter(sessionId) {
614
1289
  try {
615
- const raw = readFileSync4(getCounterPath(sessionId), "utf8");
1290
+ const raw = readFileSync6(getCounterPath(sessionId), "utf8");
616
1291
  return JSON.parse(raw);
617
1292
  } catch {
618
1293
  return { total: 0, writes: 0, pipelineWrites: 0, lastSummaryAt: 0, pipelineDetected: false };
@@ -620,8 +1295,8 @@ function loadCounter(sessionId) {
620
1295
  }
621
1296
  function saveCounter(sessionId, counter) {
622
1297
  try {
623
- mkdirSync3(COUNTER_DIR, { recursive: true });
624
- writeFileSync4(getCounterPath(sessionId), JSON.stringify(counter));
1298
+ mkdirSync4(COUNTER_DIR, { recursive: true });
1299
+ writeFileSync6(getCounterPath(sessionId), JSON.stringify(counter));
625
1300
  } catch {
626
1301
  }
627
1302
  }
@@ -633,15 +1308,15 @@ process.stdin.on("data", (chunk) => {
633
1308
  input += chunk;
634
1309
  }
635
1310
  });
636
- process.stdin.on("end", () => {
1311
+ process.stdin.on("end", async () => {
637
1312
  try {
638
1313
  if (process.env.EXE_DEBUG_HOOKS) {
639
1314
  try {
640
- const debugPath = path5.join(EXE_AI_DIR, "logs", "hook-stdin-ingest.log");
641
- mkdirSync3(path5.dirname(debugPath), { recursive: true });
1315
+ const debugPath = path8.join(EXE_AI_DIR, "logs", "hook-stdin-ingest.log");
1316
+ mkdirSync4(path8.dirname(debugPath), { recursive: true });
642
1317
  const ts = (/* @__PURE__ */ new Date()).toISOString();
643
1318
  const snippet = input.length > 2e3 ? input.slice(0, 2e3) + "...[truncated]" : input;
644
- writeFileSync4(debugPath, `[${ts}] ${snippet}
1319
+ writeFileSync6(debugPath, `[${ts}] ${snippet}
645
1320
  `, { flag: "a" });
646
1321
  } catch {
647
1322
  }
@@ -708,14 +1383,14 @@ Your output files must start with: exe/output/${agent.agentId}-`
708
1383
  const classification = classifyError(errorText);
709
1384
  if (classification === "system" && data.session_id) {
710
1385
  const fp = errorFingerprint(data.tool_name, errorText);
711
- const fpFilePath = path5.join(COUNTER_DIR, `bug-fingerprints-${data.session_id}.json`);
1386
+ const fpFilePath = path8.join(COUNTER_DIR, `bug-fingerprints-${data.session_id}.json`);
712
1387
  let fpData = {
713
1388
  seen: {},
714
1389
  taskCount: 0,
715
1390
  lastTaskAt: ""
716
1391
  };
717
1392
  try {
718
- fpData = JSON.parse(readFileSync4(fpFilePath, "utf8"));
1393
+ fpData = JSON.parse(readFileSync6(fpFilePath, "utf8"));
719
1394
  } catch {
720
1395
  }
721
1396
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -733,13 +1408,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
733
1408
  fpData.seen[fp] = { count: 1, firstAt: now, lastAt: now };
734
1409
  fpData.taskCount++;
735
1410
  fpData.lastTaskAt = now;
736
- const bugWorkerPath = path5.resolve(
737
- path5.dirname(fileURLToPath(import.meta.url)),
1411
+ const bugWorkerPath = path8.resolve(
1412
+ path8.dirname(fileURLToPath(import.meta.url)),
738
1413
  "bug-report-worker.js"
739
1414
  );
740
- if (existsSync4(bugWorkerPath) && tryAcquireWorkerSlot()) {
1415
+ if (existsSync7(bugWorkerPath) && tryAcquireWorkerSlot()) {
741
1416
  const stderrFd2 = openWorkerLog();
742
- const projectName = process.cwd().split(path5.sep).pop() ?? "unknown";
1417
+ const projectName = process.cwd().split(path8.sep).pop() ?? "unknown";
743
1418
  const bugToolInput = data.tool_input ?? {};
744
1419
  const bugWorker = spawn(process.execPath, [bugWorkerPath], {
745
1420
  detached: true,
@@ -767,8 +1442,8 @@ Your output files must start with: exe/output/${agent.agentId}-`
767
1442
  }
768
1443
  }
769
1444
  try {
770
- mkdirSync3(COUNTER_DIR, { recursive: true });
771
- writeFileSync4(fpFilePath, JSON.stringify(fpData));
1445
+ mkdirSync4(COUNTER_DIR, { recursive: true });
1446
+ writeFileSync6(fpFilePath, JSON.stringify(fpData));
772
1447
  } catch {
773
1448
  }
774
1449
  }
@@ -785,11 +1460,11 @@ Your output files must start with: exe/output/${agent.agentId}-`
785
1460
  }
786
1461
  const callsSinceLastSummary = counter.total - counter.lastSummaryAt;
787
1462
  if (callsSinceLastSummary >= SUMMARY_INTERVAL && counter.writes >= MIN_WRITES_FOR_SUMMARY) {
788
- const summaryWorkerPath = path5.resolve(
789
- path5.dirname(fileURLToPath(import.meta.url)),
1463
+ const summaryWorkerPath = path8.resolve(
1464
+ path8.dirname(fileURLToPath(import.meta.url)),
790
1465
  "summary-worker.js"
791
1466
  );
792
- if (existsSync4(summaryWorkerPath) && tryAcquireWorkerSlot()) {
1467
+ if (existsSync7(summaryWorkerPath) && tryAcquireWorkerSlot()) {
793
1468
  const stderrFd2 = openWorkerLog();
794
1469
  const summaryWorker = spawn(process.execPath, [summaryWorkerPath], {
795
1470
  detached: true,
@@ -835,13 +1510,13 @@ WARNING: You are writing code without running the build pipeline. If this task a
835
1510
  const bashOutput = typeof data.tool_response === "string" ? data.tool_response : JSON.stringify(data.tool_response ?? "");
836
1511
  const commitMatch = bashOutput.match(/\[(\S+)\s+([a-f0-9]{7,40})\]\s+(.+)/);
837
1512
  if (commitMatch) {
838
- const commitWorkerPath = path5.resolve(
839
- path5.dirname(fileURLToPath(import.meta.url)),
1513
+ const commitWorkerPath = path8.resolve(
1514
+ path8.dirname(fileURLToPath(import.meta.url)),
840
1515
  "commit-complete.js"
841
1516
  );
842
- if (existsSync4(commitWorkerPath) && tryAcquireWorkerSlot()) {
1517
+ if (existsSync7(commitWorkerPath) && tryAcquireWorkerSlot()) {
843
1518
  const stderrFd2 = openWorkerLog();
844
- const projectName = process.cwd().split(path5.sep).pop() ?? "unknown";
1519
+ const projectName = process.cwd().split(path8.sep).pop() ?? "unknown";
845
1520
  const commitWorker = spawn(process.execPath, [commitWorkerPath], {
846
1521
  detached: true,
847
1522
  stdio: ["ignore", "ignore", stderrFd2],
@@ -865,8 +1540,68 @@ WARNING: You are writing code without running the build pipeline. If this task a
865
1540
  if (!ALLOWED_TOOL_RE.test(data.tool_name)) {
866
1541
  process.exit(0);
867
1542
  }
868
- const workerPath = path5.resolve(
869
- path5.dirname(fileURLToPath(import.meta.url)),
1543
+ let sentViaDaemon = false;
1544
+ try {
1545
+ const socketPath = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
1546
+ if (existsSync7(socketPath)) {
1547
+ const { extractSemanticText: extractSemanticText2 } = await Promise.resolve().then(() => (init_content_extractor(), content_extractor_exports));
1548
+ const { getProjectName: getProjectName2 } = await Promise.resolve().then(() => (init_project_name(), project_name_exports));
1549
+ const { canCoordinate: canCoordinate2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
1550
+ const { readDaemonToken: readDaemonToken2 } = await Promise.resolve().then(() => (init_daemon_auth(), daemon_auth_exports));
1551
+ const rawText = extractSemanticText2(data.tool_name, data.tool_input ?? {}, data.tool_response ?? {});
1552
+ if (rawText.length >= 50) {
1553
+ let taskId = null;
1554
+ try {
1555
+ const cachePath = path8.join(EXE_AI_DIR, "session-cache", `current-task-${agent.agentId}.json`);
1556
+ if (existsSync7(cachePath)) {
1557
+ const cached = JSON.parse(readFileSync6(cachePath, "utf8"));
1558
+ taskId = cached.taskId ?? null;
1559
+ }
1560
+ } catch {
1561
+ }
1562
+ const detectData2 = { tool_name: data.tool_name, tool_response: data.tool_response };
1563
+ const hasError = detectError(detectData2);
1564
+ const isDraft = taskId !== null && !canCoordinate2(agent.agentId, agent.agentRole);
1565
+ const toolInputStr = JSON.stringify(data.tool_input ?? "").slice(0, 200);
1566
+ const toolOutputStr = JSON.stringify(data.tool_response ?? "").slice(0, 200);
1567
+ const token = process.env.EXE_DAEMON_TOKEN ?? readDaemonToken2();
1568
+ const projectName = getProjectName2(data.cwd ?? process.cwd());
1569
+ const payload = JSON.stringify({
1570
+ id: `ingest-${Date.now()}`,
1571
+ token,
1572
+ type: "ingest",
1573
+ rawText,
1574
+ agentId: agent.agentId,
1575
+ agentRole: agent.agentRole,
1576
+ sessionId: data.session_id ?? "",
1577
+ toolName: data.tool_name,
1578
+ projectName,
1579
+ hasError,
1580
+ taskId,
1581
+ confidence: agent.agentId === "default" ? 0.9 : 0.7,
1582
+ draft: isDraft,
1583
+ trajectory: { input: toolInputStr, tool: data.tool_name, output: toolOutputStr, result_type: hasError ? "error" : "success" }
1584
+ }) + "\n";
1585
+ const net = await import("net");
1586
+ const sock = net.connect(socketPath);
1587
+ sock.on("error", () => {
1588
+ });
1589
+ sock.write(payload, () => {
1590
+ sock.destroy();
1591
+ });
1592
+ sentViaDaemon = true;
1593
+ } else {
1594
+ sentViaDaemon = true;
1595
+ }
1596
+ }
1597
+ } catch {
1598
+ }
1599
+ if (sentViaDaemon) {
1600
+ setTimeout(() => process.exit(0), 10);
1601
+ return;
1602
+ }
1603
+ const workerPath = path8.resolve(
1604
+ path8.dirname(fileURLToPath(import.meta.url)),
870
1605
  "ingest-worker.js"
871
1606
  );
872
1607
  if (!tryAcquireWorkerSlot()) {