@askexenow/exe-os 0.8.83 → 0.8.85

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 (95) hide show
  1. package/dist/bin/backfill-conversations.js +746 -595
  2. package/dist/bin/backfill-responses.js +745 -594
  3. package/dist/bin/backfill-vectors.js +312 -226
  4. package/dist/bin/cleanup-stale-review-tasks.js +97 -2
  5. package/dist/bin/cli.js +14350 -12518
  6. package/dist/bin/exe-agent.js +97 -88
  7. package/dist/bin/exe-assign.js +1003 -854
  8. package/dist/bin/exe-boot.js +1257 -320
  9. package/dist/bin/exe-call.js +10 -0
  10. package/dist/bin/exe-cloud.js +29 -6
  11. package/dist/bin/exe-dispatch.js +210 -34
  12. package/dist/bin/exe-doctor.js +403 -6
  13. package/dist/bin/exe-export-behaviors.js +175 -72
  14. package/dist/bin/exe-forget.js +97 -2
  15. package/dist/bin/exe-gateway.js +550 -171
  16. package/dist/bin/exe-healthcheck.js +1 -0
  17. package/dist/bin/exe-heartbeat.js +100 -5
  18. package/dist/bin/exe-kill.js +175 -72
  19. package/dist/bin/exe-launch-agent.js +189 -76
  20. package/dist/bin/exe-link.js +902 -80
  21. package/dist/bin/exe-new-employee.js +38 -8
  22. package/dist/bin/exe-pending-messages.js +96 -2
  23. package/dist/bin/exe-pending-notifications.js +97 -2
  24. package/dist/bin/exe-pending-reviews.js +98 -3
  25. package/dist/bin/exe-rename.js +564 -23
  26. package/dist/bin/exe-review.js +231 -73
  27. package/dist/bin/exe-search.js +989 -226
  28. package/dist/bin/exe-session-cleanup.js +4806 -1665
  29. package/dist/bin/exe-settings.js +20 -5
  30. package/dist/bin/exe-status.js +97 -2
  31. package/dist/bin/exe-team.js +97 -2
  32. package/dist/bin/git-sweep.js +899 -207
  33. package/dist/bin/graph-backfill.js +175 -72
  34. package/dist/bin/graph-export.js +175 -72
  35. package/dist/bin/install.js +38 -7
  36. package/dist/bin/list-providers.js +1 -0
  37. package/dist/bin/scan-tasks.js +904 -211
  38. package/dist/bin/setup.js +867 -268
  39. package/dist/bin/shard-migrate.js +175 -72
  40. package/dist/bin/update.js +1 -0
  41. package/dist/bin/wiki-sync.js +175 -72
  42. package/dist/gateway/index.js +548 -166
  43. package/dist/hooks/bug-report-worker.js +208 -23
  44. package/dist/hooks/commit-complete.js +897 -205
  45. package/dist/hooks/error-recall.js +988 -226
  46. package/dist/hooks/ingest-worker.js +1638 -1194
  47. package/dist/hooks/ingest.js +3 -0
  48. package/dist/hooks/instructions-loaded.js +707 -97
  49. package/dist/hooks/notification.js +699 -89
  50. package/dist/hooks/post-compact.js +714 -104
  51. package/dist/hooks/pre-compact.js +897 -205
  52. package/dist/hooks/pre-tool-use.js +742 -123
  53. package/dist/hooks/prompt-ingest-worker.js +242 -101
  54. package/dist/hooks/prompt-submit.js +995 -233
  55. package/dist/hooks/response-ingest-worker.js +242 -101
  56. package/dist/hooks/session-end.js +3941 -400
  57. package/dist/hooks/session-start.js +1001 -226
  58. package/dist/hooks/stop.js +725 -115
  59. package/dist/hooks/subagent-stop.js +714 -104
  60. package/dist/hooks/summary-worker.js +1964 -1330
  61. package/dist/index.js +1651 -1053
  62. package/dist/lib/cloud-sync.js +907 -86
  63. package/dist/lib/consolidation.js +2 -1
  64. package/dist/lib/database.js +642 -87
  65. package/dist/lib/db-daemon-client.js +503 -0
  66. package/dist/lib/device-registry.js +547 -7
  67. package/dist/lib/embedder.js +14 -28
  68. package/dist/lib/employee-templates.js +84 -74
  69. package/dist/lib/employees.js +9 -0
  70. package/dist/lib/exe-daemon-client.js +16 -29
  71. package/dist/lib/exe-daemon.js +1955 -922
  72. package/dist/lib/hybrid-search.js +988 -226
  73. package/dist/lib/identity.js +87 -67
  74. package/dist/lib/keychain.js +9 -1
  75. package/dist/lib/messaging.js +8 -1
  76. package/dist/lib/reminders.js +91 -74
  77. package/dist/lib/schedules.js +96 -2
  78. package/dist/lib/skill-learning.js +103 -85
  79. package/dist/lib/store.js +234 -73
  80. package/dist/lib/tasks.js +111 -22
  81. package/dist/lib/tmux-routing.js +120 -31
  82. package/dist/lib/token-spend.js +273 -0
  83. package/dist/lib/ws-client.js +11 -0
  84. package/dist/mcp/server.js +5222 -475
  85. package/dist/mcp/tools/complete-reminder.js +94 -77
  86. package/dist/mcp/tools/create-reminder.js +94 -77
  87. package/dist/mcp/tools/create-task.js +120 -22
  88. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  89. package/dist/mcp/tools/list-reminders.js +94 -77
  90. package/dist/mcp/tools/list-tasks.js +31 -1
  91. package/dist/mcp/tools/send-message.js +8 -1
  92. package/dist/mcp/tools/update-task.js +39 -10
  93. package/dist/runtime/index.js +911 -219
  94. package/dist/tui/App.js +997 -295
  95. package/package.json +6 -1
@@ -273,6 +273,7 @@ __export(employees_exports, {
273
273
  DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
274
274
  EMPLOYEES_PATH: () => EMPLOYEES_PATH,
275
275
  addEmployee: () => addEmployee,
276
+ baseAgentName: () => baseAgentName,
276
277
  canCoordinate: () => canCoordinate,
277
278
  getCoordinatorEmployee: () => getCoordinatorEmployee,
278
279
  getCoordinatorName: () => getCoordinatorName,
@@ -369,6 +370,14 @@ function hasRole(agentName, role) {
369
370
  const emp = getEmployee(employees, agentName);
370
371
  return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
371
372
  }
373
+ function baseAgentName(name, employees) {
374
+ const match = name.match(/^([a-zA-Z]+)\d+$/);
375
+ if (!match) return name;
376
+ const base = match[1];
377
+ const roster = employees ?? loadEmployeesSync();
378
+ if (getEmployee(roster, base)) return base;
379
+ return name;
380
+ }
372
381
  function isMultiInstance(agentName, employees) {
373
382
  const roster = employees ?? loadEmployeesSync();
374
383
  const emp = getEmployee(roster, agentName);
@@ -470,15 +479,22 @@ function getClient() {
470
479
  if (!_resilientClient) {
471
480
  throw new Error("Database client not initialized. Call initDatabase() first.");
472
481
  }
482
+ if (process.env.EXE_IS_DAEMON === "1") {
483
+ return _resilientClient;
484
+ }
485
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
486
+ return _daemonClient;
487
+ }
473
488
  return _resilientClient;
474
489
  }
475
- var _resilientClient;
490
+ var _resilientClient, _daemonClient;
476
491
  var init_database = __esm({
477
492
  "src/lib/database.ts"() {
478
493
  "use strict";
479
494
  init_db_retry();
480
495
  init_employees();
481
496
  _resilientClient = null;
497
+ _daemonClient = null;
482
498
  }
483
499
  });
484
500
 
@@ -1658,7 +1674,7 @@ function notifyParentExe(sessionKey) {
1658
1674
  return true;
1659
1675
  }
1660
1676
  function ensureEmployee(employeeName, exeSession, projectDir, opts) {
1661
- if (employeeName === "exe" || isCoordinatorName(employeeName)) {
1677
+ if (isCoordinatorName(employeeName)) {
1662
1678
  return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
1663
1679
  }
1664
1680
  try {
@@ -1991,6 +2007,7 @@ var init_task_scope = __esm({
1991
2007
  // src/lib/tasks-crud.ts
1992
2008
  import crypto3 from "crypto";
1993
2009
  import path9 from "path";
2010
+ import os7 from "os";
1994
2011
  import { execSync as execSync5 } from "child_process";
1995
2012
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
1996
2013
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
@@ -2034,6 +2051,35 @@ function extractParentFromContext(contextBody) {
2034
2051
  function slugify(title) {
2035
2052
  return title.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
2036
2053
  }
2054
+ function buildKeywordIndex() {
2055
+ const idx = /* @__PURE__ */ new Map();
2056
+ for (const [role, keywords] of Object.entries(LANE_KEYWORDS)) {
2057
+ for (const kw of keywords) {
2058
+ const existing = idx.get(kw) ?? [];
2059
+ existing.push(role);
2060
+ idx.set(kw, existing);
2061
+ }
2062
+ }
2063
+ return idx;
2064
+ }
2065
+ function checkLaneAffinity(title, context, assigneeName) {
2066
+ const employees = loadEmployeesSync();
2067
+ const employee = employees.find((e) => e.name === assigneeName);
2068
+ if (!employee) return void 0;
2069
+ const assigneeRole = employee.role;
2070
+ const text = `${title} ${context}`.toLowerCase();
2071
+ const matchedRoles = /* @__PURE__ */ new Set();
2072
+ for (const [keyword, roles] of KEYWORD_INDEX) {
2073
+ if (text.includes(keyword)) {
2074
+ for (const role of roles) matchedRoles.add(role);
2075
+ }
2076
+ }
2077
+ if (matchedRoles.size === 0) return void 0;
2078
+ if (matchedRoles.has(assigneeRole)) return void 0;
2079
+ if (assigneeRole === "COO") return void 0;
2080
+ const expectedRoles = Array.from(matchedRoles).join(" or ");
2081
+ return `\u26A0\uFE0F Lane mismatch: task content suggests ${expectedRoles}, but assigned to ${assigneeName} (${assigneeRole}).`;
2082
+ }
2037
2083
  async function resolveTask(client, identifier, scopeSession) {
2038
2084
  const scope = sessionScopeFilter(scopeSession);
2039
2085
  let result = await client.execute({
@@ -2083,7 +2129,14 @@ async function createTaskCore(input) {
2083
2129
  const id = crypto3.randomUUID();
2084
2130
  const now = (/* @__PURE__ */ new Date()).toISOString();
2085
2131
  const slug = slugify(input.title);
2086
- const taskFile = input.taskFile ?? `exe/${input.assignedTo}/${slug}.md`;
2132
+ let earlySessionScope = null;
2133
+ try {
2134
+ const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
2135
+ earlySessionScope = resolveExeSession2();
2136
+ } catch {
2137
+ }
2138
+ const scope = earlySessionScope ?? "default";
2139
+ const taskFile = input.taskFile ?? `tasks/${scope}/${input.assignedTo}/${slug}.md`;
2087
2140
  let blockedById = null;
2088
2141
  const initialStatus = input.blockedBy ? "blocked" : "open";
2089
2142
  if (input.blockedBy) {
@@ -2123,6 +2176,13 @@ async function createTaskCore(input) {
2123
2176
  if (dupCheck.rows.length > 0) {
2124
2177
  warning = `similar active task already exists (${String(dupCheck.rows[0].id)}). Created new task anyway.`;
2125
2178
  }
2179
+ if (!process.env.DISABLE_LANE_AFFINITY) {
2180
+ const laneWarning = checkLaneAffinity(input.title, input.context, input.assignedTo);
2181
+ if (laneWarning) {
2182
+ warning = warning ? `${warning}
2183
+ ${laneWarning}` : laneWarning;
2184
+ }
2185
+ }
2126
2186
  if (input.baseDir) {
2127
2187
  try {
2128
2188
  await mkdir3(path9.join(input.baseDir, "exe", "output"), { recursive: true });
@@ -2133,12 +2193,7 @@ async function createTaskCore(input) {
2133
2193
  }
2134
2194
  }
2135
2195
  const complexity = input.complexity ?? "standard";
2136
- let sessionScope = null;
2137
- try {
2138
- const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
2139
- sessionScope = resolveExeSession2();
2140
- } catch {
2141
- }
2196
+ const sessionScope = earlySessionScope;
2142
2197
  await client.execute({
2143
2198
  sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
2144
2199
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -2165,6 +2220,39 @@ async function createTaskCore(input) {
2165
2220
  now
2166
2221
  ]
2167
2222
  });
2223
+ if (input.baseDir) {
2224
+ try {
2225
+ const EXE_OS_DIR = path9.join(os7.homedir(), ".exe-os");
2226
+ const mdPath = path9.join(EXE_OS_DIR, taskFile);
2227
+ const mdDir = path9.dirname(mdPath);
2228
+ if (!existsSync9(mdDir)) await mkdir3(mdDir, { recursive: true });
2229
+ const reviewer = input.reviewer ?? input.assignedBy;
2230
+ const mdContent = `# ${input.title}
2231
+
2232
+ **ID:** ${id}
2233
+ **Status:** ${initialStatus}
2234
+ **Priority:** ${input.priority}
2235
+ **Assigned by:** ${input.assignedBy}
2236
+ **Assigned to:** ${input.assignedTo}
2237
+ **Project:** ${input.projectName}
2238
+ **Created:** ${now.split("T")[0]}${parentTaskId ? `
2239
+ **Parent task:** ${parentTaskId}` : ""}
2240
+ **Reviewer:** ${reviewer}
2241
+
2242
+ ## Context
2243
+
2244
+ ${input.context}
2245
+
2246
+ ## MANDATORY: When done
2247
+
2248
+ You MUST call update_task with status "done" and a result summary when finished.
2249
+ If you skip this, your reviewer will not know you're done and your work won't be reviewed.
2250
+ Do NOT let a failed commit or any error prevent you from calling update_task(done).
2251
+ `;
2252
+ await writeFile3(mdPath, mdContent, "utf-8");
2253
+ } catch {
2254
+ }
2255
+ }
2168
2256
  return {
2169
2257
  id,
2170
2258
  title: input.title,
@@ -2357,7 +2445,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
2357
2445
  return { row, taskFile, now, taskId };
2358
2446
  }
2359
2447
  }
2360
- if (curStatus === "in_progress" && input.callerAgentId && (input.callerAgentId === assignedBy || input.callerAgentId === "exe")) {
2448
+ if (curStatus === "in_progress" && input.callerAgentId && (input.callerAgentId === assignedBy || isCoordinatorName(input.callerAgentId))) {
2361
2449
  process.stderr.write(
2362
2450
  `[tasks] Assigner override: ${input.callerAgentId} reclaiming ${taskId}
2363
2451
  `
@@ -2469,12 +2557,22 @@ async function ensureGitignoreExe(baseDir) {
2469
2557
  } catch {
2470
2558
  }
2471
2559
  }
2472
- var DELEGATION_KEYWORDS, TASK_ALREADY_CLAIMED_PREFIX;
2560
+ var LANE_KEYWORDS, KEYWORD_INDEX, DELEGATION_KEYWORDS, TASK_ALREADY_CLAIMED_PREFIX;
2473
2561
  var init_tasks_crud = __esm({
2474
2562
  "src/lib/tasks-crud.ts"() {
2475
2563
  "use strict";
2476
2564
  init_database();
2477
2565
  init_task_scope();
2566
+ init_employees();
2567
+ LANE_KEYWORDS = {
2568
+ CMO: ["sales", "script", "pitch", "offer", "copy", "objection", "brand", "content", "seo", "marketing", "newsletter", "carousel", "social", "campaign"],
2569
+ CTO: ["spec", "architecture", "migration", "schema", "database", "design doc", "adr", "security audit", "tech stack"],
2570
+ "Principal Engineer": ["implement", "build", "fix", "commit", "refactor", "bug", "feature", "wire", "integration"],
2571
+ "Staff Code Reviewer": ["critique", "verdict", "review", "audit", "code quality"],
2572
+ "Content Production Specialist": ["render", "video", "image", "b-roll", "remotion", "animation", "thumbnail"],
2573
+ "AI Product Lead": ["competitive", "analysis", "benchmark", "compare", "scout", "evaluate", "poc"]
2574
+ };
2575
+ KEYWORD_INDEX = buildKeywordIndex();
2478
2576
  DELEGATION_KEYWORDS = /parallel|delegate|wave|worktree|multi-instance/i;
2479
2577
  TASK_ALREADY_CLAIMED_PREFIX = "TASK_ALREADY_CLAIMED";
2480
2578
  }
@@ -2504,7 +2602,7 @@ async function countNewPendingReviewsSince(sinceIso, sessionScope) {
2504
2602
  const result2 = await client.execute({
2505
2603
  sql: `SELECT COUNT(*) as cnt FROM tasks
2506
2604
  WHERE status = 'needs_review' AND updated_at > ?
2507
- AND (session_scope = ? OR session_scope IS NULL)`,
2605
+ AND session_scope = ?`,
2508
2606
  args: [sinceIso, sessionScope]
2509
2607
  });
2510
2608
  return Number(result2.rows[0]?.cnt) || 0;
@@ -2522,7 +2620,7 @@ async function listPendingReviews(limit, sessionScope) {
2522
2620
  const result2 = await client.execute({
2523
2621
  sql: `SELECT title, assigned_to, project_name FROM tasks
2524
2622
  WHERE status = 'needs_review'
2525
- AND (session_scope = ? OR session_scope IS NULL)
2623
+ AND session_scope = ?
2526
2624
  ORDER BY priority ASC, created_at DESC LIMIT ?`,
2527
2625
  args: [sessionScope, limit]
2528
2626
  });
@@ -2643,14 +2741,14 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
2643
2741
  if (parts.length >= 3 && parts[0] === "review") {
2644
2742
  const agent = parts[1];
2645
2743
  const slug = parts.slice(2).join("-");
2646
- const originalTaskFile = `exe/${agent}/${slug}.md`;
2744
+ const legacyTaskFile = `exe/${agent}/${slug}.md`;
2647
2745
  const result = await client.execute({
2648
- sql: "UPDATE tasks SET status = 'done', updated_at = ? WHERE task_file = ? AND status = 'needs_review'",
2649
- args: [now, originalTaskFile]
2746
+ sql: "UPDATE tasks SET status = 'done', updated_at = ? WHERE (task_file = ? OR task_file LIKE ?) AND status = 'needs_review'",
2747
+ args: [now, legacyTaskFile, `tasks/%/${agent}/${slug}.md`]
2650
2748
  });
2651
2749
  if (result.rowsAffected > 0) {
2652
2750
  process.stderr.write(
2653
- `[review-cleanup] Cascaded original task to done (legacy path): ${originalTaskFile}
2751
+ `[review-cleanup] Cascaded original task to done: ${agent}/${slug}.md
2654
2752
  `
2655
2753
  );
2656
2754
  }
@@ -2832,7 +2930,7 @@ function findSessionForProject(projectName) {
2832
2930
  const sessions = listSessions();
2833
2931
  for (const s of sessions) {
2834
2932
  const proj = s.projectDir.split("/").filter(Boolean).pop();
2835
- if (proj === projectName && (s.agentId === "exe" || isCoordinatorName(s.agentId))) return s;
2933
+ if (proj === projectName && isCoordinatorName(s.agentId)) return s;
2836
2934
  }
2837
2935
  return null;
2838
2936
  }
@@ -2878,7 +2976,7 @@ var init_session_scope = __esm({
2878
2976
 
2879
2977
  // src/lib/tasks-notify.ts
2880
2978
  async function dispatchTaskToEmployee(input) {
2881
- if (input.assignedTo === "exe" || isCoordinatorName(input.assignedTo)) return { dispatched: "skipped" };
2979
+ if (isCoordinatorName(input.assignedTo)) return { dispatched: "skipped" };
2882
2980
  let crossProject = false;
2883
2981
  if (input.projectName) {
2884
2982
  try {
@@ -3357,7 +3455,7 @@ async function updateTask(input) {
3357
3455
  }
3358
3456
  const isTerminal = input.status === "done" || input.status === "needs_review";
3359
3457
  if (isTerminal) {
3360
- const isCoordinator = String(row.assigned_to) === "exe" || isCoordinatorName(String(row.assigned_to));
3458
+ const isCoordinator = isCoordinatorName(String(row.assigned_to));
3361
3459
  if (!isCoordinator) {
3362
3460
  notifyTaskDone();
3363
3461
  }
@@ -3382,7 +3480,7 @@ async function updateTask(input) {
3382
3480
  }
3383
3481
  }
3384
3482
  }
3385
- if (input.status === "done" && String(row.assigned_to) !== "exe" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
3483
+ if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
3386
3484
  Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
3387
3485
  ({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
3388
3486
  taskId,
@@ -3398,7 +3496,7 @@ async function updateTask(input) {
3398
3496
  });
3399
3497
  }
3400
3498
  let nextTask;
3401
- if (isTerminal && String(row.assigned_to) !== "exe" && !isCoordinatorName(String(row.assigned_to))) {
3499
+ if (isTerminal && !isCoordinatorName(String(row.assigned_to))) {
3402
3500
  try {
3403
3501
  nextTask = await findNextTask(String(row.assigned_to));
3404
3502
  } catch {
@@ -1,18 +1,7 @@
1
- // src/mcp/tools/deactivate-behavior.ts
2
- import { z } from "zod";
3
-
4
- // src/lib/behaviors.ts
5
- import crypto from "crypto";
6
-
7
- // src/lib/database.ts
8
- import { createClient } from "@libsql/client";
9
-
10
- // src/lib/employees.ts
11
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
12
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
13
- import { execSync } from "child_process";
14
- import path2 from "path";
15
- import os2 from "os";
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
16
5
 
17
6
  // src/lib/config.ts
18
7
  import { readFile, writeFile, mkdir, chmod } from "fs/promises";
@@ -35,71 +24,92 @@ function resolveDataDir() {
35
24
  }
36
25
  return newDir;
37
26
  }
38
- var EXE_AI_DIR = resolveDataDir();
39
- var DB_PATH = path.join(EXE_AI_DIR, "memories.db");
40
- var MODELS_DIR = path.join(EXE_AI_DIR, "models");
41
- var CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
42
- var LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
43
- var CURRENT_CONFIG_VERSION = 1;
44
- var DEFAULT_CONFIG = {
45
- config_version: CURRENT_CONFIG_VERSION,
46
- dbPath: DB_PATH,
47
- modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
48
- embeddingDim: 1024,
49
- batchSize: 20,
50
- flushIntervalMs: 1e4,
51
- autoIngestion: true,
52
- autoRetrieval: true,
53
- searchMode: "hybrid",
54
- hookSearchMode: "hybrid",
55
- fileGrepEnabled: true,
56
- splashEffect: true,
57
- consolidationEnabled: true,
58
- consolidationIntervalMs: 6 * 60 * 60 * 1e3,
59
- consolidationModel: "claude-haiku-4-5-20251001",
60
- consolidationMaxCallsPerRun: 20,
61
- selfQueryRouter: true,
62
- selfQueryModel: "claude-haiku-4-5-20251001",
63
- rerankerEnabled: true,
64
- scalingRoadmap: {
65
- rerankerAutoTrigger: {
66
- enabled: true,
67
- broadQueryMinCardinality: 5e4,
68
- fetchTopK: 150,
69
- returnTopK: 5
70
- }
71
- },
72
- graphRagEnabled: true,
73
- wikiEnabled: false,
74
- wikiUrl: "",
75
- wikiApiKey: "",
76
- wikiSyncIntervalMs: 30 * 60 * 1e3,
77
- wikiWorkspaceMapping: {},
78
- wikiAutoUpdate: true,
79
- wikiAutoUpdateThreshold: 0.5,
80
- wikiAutoUpdateCreateNew: true,
81
- skillLearning: true,
82
- skillThreshold: 3,
83
- skillModel: "claude-haiku-4-5-20251001",
84
- exeHeartbeat: {
85
- enabled: true,
86
- intervalSeconds: 60,
87
- staleInProgressThresholdHours: 2
88
- },
89
- sessionLifecycle: {
90
- idleKillEnabled: true,
91
- idleKillTicksRequired: 3,
92
- idleKillIntercomAckWindowMs: 1e4,
93
- maxAutoInstances: 10
94
- },
95
- autoUpdate: {
96
- checkOnBoot: true,
97
- autoInstall: false,
98
- checkIntervalMs: 24 * 60 * 60 * 1e3
27
+ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG;
28
+ var init_config = __esm({
29
+ "src/lib/config.ts"() {
30
+ "use strict";
31
+ EXE_AI_DIR = resolveDataDir();
32
+ DB_PATH = path.join(EXE_AI_DIR, "memories.db");
33
+ MODELS_DIR = path.join(EXE_AI_DIR, "models");
34
+ CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
35
+ LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
36
+ CURRENT_CONFIG_VERSION = 1;
37
+ DEFAULT_CONFIG = {
38
+ config_version: CURRENT_CONFIG_VERSION,
39
+ dbPath: DB_PATH,
40
+ modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
41
+ embeddingDim: 1024,
42
+ batchSize: 20,
43
+ flushIntervalMs: 1e4,
44
+ autoIngestion: true,
45
+ autoRetrieval: true,
46
+ searchMode: "hybrid",
47
+ hookSearchMode: "hybrid",
48
+ fileGrepEnabled: true,
49
+ splashEffect: true,
50
+ consolidationEnabled: true,
51
+ consolidationIntervalMs: 6 * 60 * 60 * 1e3,
52
+ consolidationModel: "claude-haiku-4-5-20251001",
53
+ consolidationMaxCallsPerRun: 20,
54
+ selfQueryRouter: true,
55
+ selfQueryModel: "claude-haiku-4-5-20251001",
56
+ rerankerEnabled: true,
57
+ scalingRoadmap: {
58
+ rerankerAutoTrigger: {
59
+ enabled: true,
60
+ broadQueryMinCardinality: 5e4,
61
+ fetchTopK: 150,
62
+ returnTopK: 5
63
+ }
64
+ },
65
+ graphRagEnabled: true,
66
+ wikiEnabled: false,
67
+ wikiUrl: "",
68
+ wikiApiKey: "",
69
+ wikiSyncIntervalMs: 30 * 60 * 1e3,
70
+ wikiWorkspaceMapping: {},
71
+ wikiAutoUpdate: true,
72
+ wikiAutoUpdateThreshold: 0.5,
73
+ wikiAutoUpdateCreateNew: true,
74
+ skillLearning: true,
75
+ skillThreshold: 3,
76
+ skillModel: "claude-haiku-4-5-20251001",
77
+ exeHeartbeat: {
78
+ enabled: true,
79
+ intervalSeconds: 60,
80
+ staleInProgressThresholdHours: 2
81
+ },
82
+ sessionLifecycle: {
83
+ idleKillEnabled: true,
84
+ idleKillTicksRequired: 3,
85
+ idleKillIntercomAckWindowMs: 1e4,
86
+ maxAutoInstances: 10
87
+ },
88
+ autoUpdate: {
89
+ checkOnBoot: true,
90
+ autoInstall: false,
91
+ checkIntervalMs: 24 * 60 * 60 * 1e3
92
+ }
93
+ };
99
94
  }
100
- };
95
+ });
96
+
97
+ // src/mcp/tools/deactivate-behavior.ts
98
+ import { z } from "zod";
99
+
100
+ // src/lib/behaviors.ts
101
+ import crypto from "crypto";
102
+
103
+ // src/lib/database.ts
104
+ import { createClient } from "@libsql/client";
101
105
 
102
106
  // src/lib/employees.ts
107
+ init_config();
108
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
109
+ import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
110
+ import { execSync } from "child_process";
111
+ import path2 from "path";
112
+ import os2 from "os";
103
113
  var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
104
114
  var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
105
115
  var COORDINATOR_ROLE = "COO";
@@ -136,10 +146,17 @@ function getEmployee(employees, name) {
136
146
 
137
147
  // src/lib/database.ts
138
148
  var _resilientClient = null;
149
+ var _daemonClient = null;
139
150
  function getClient() {
140
151
  if (!_resilientClient) {
141
152
  throw new Error("Database client not initialized. Call initDatabase() first.");
142
153
  }
154
+ if (process.env.EXE_IS_DAEMON === "1") {
155
+ return _resilientClient;
156
+ }
157
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
158
+ return _daemonClient;
159
+ }
143
160
  return _resilientClient;
144
161
  }
145
162
 
@@ -154,6 +171,7 @@ async function deactivateBehavior(id) {
154
171
  }
155
172
 
156
173
  // src/adapters/claude/active-agent.ts
174
+ init_config();
157
175
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync, unlinkSync as unlinkSync2, readdirSync } from "fs";
158
176
  import { execSync as execSync3 } from "child_process";
159
177
  import path3 from "path";