@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.
- package/dist/bin/backfill-conversations.js +746 -595
- package/dist/bin/backfill-responses.js +745 -594
- package/dist/bin/backfill-vectors.js +312 -226
- package/dist/bin/cleanup-stale-review-tasks.js +97 -2
- package/dist/bin/cli.js +14350 -12518
- package/dist/bin/exe-agent.js +97 -88
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1257 -320
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +210 -34
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +97 -2
- package/dist/bin/exe-gateway.js +550 -171
- package/dist/bin/exe-healthcheck.js +1 -0
- package/dist/bin/exe-heartbeat.js +100 -5
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +902 -80
- package/dist/bin/exe-new-employee.js +38 -8
- package/dist/bin/exe-pending-messages.js +96 -2
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +98 -3
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +989 -226
- package/dist/bin/exe-session-cleanup.js +4806 -1665
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-status.js +97 -2
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +899 -207
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +38 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +904 -211
- package/dist/bin/setup.js +867 -268
- package/dist/bin/shard-migrate.js +175 -72
- package/dist/bin/update.js +1 -0
- package/dist/bin/wiki-sync.js +175 -72
- package/dist/gateway/index.js +548 -166
- package/dist/hooks/bug-report-worker.js +208 -23
- package/dist/hooks/commit-complete.js +897 -205
- package/dist/hooks/error-recall.js +988 -226
- package/dist/hooks/ingest-worker.js +1638 -1194
- package/dist/hooks/ingest.js +3 -0
- package/dist/hooks/instructions-loaded.js +707 -97
- package/dist/hooks/notification.js +699 -89
- package/dist/hooks/post-compact.js +714 -104
- package/dist/hooks/pre-compact.js +897 -205
- package/dist/hooks/pre-tool-use.js +742 -123
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +995 -233
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +3941 -400
- package/dist/hooks/session-start.js +1001 -226
- package/dist/hooks/stop.js +725 -115
- package/dist/hooks/subagent-stop.js +714 -104
- package/dist/hooks/summary-worker.js +1964 -1330
- package/dist/index.js +1651 -1053
- package/dist/lib/cloud-sync.js +907 -86
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/database.js +642 -87
- package/dist/lib/db-daemon-client.js +503 -0
- package/dist/lib/device-registry.js +547 -7
- package/dist/lib/embedder.js +14 -28
- package/dist/lib/employee-templates.js +84 -74
- package/dist/lib/employees.js +9 -0
- package/dist/lib/exe-daemon-client.js +16 -29
- package/dist/lib/exe-daemon.js +1955 -922
- package/dist/lib/hybrid-search.js +988 -226
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +8 -1
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +111 -22
- package/dist/lib/tmux-routing.js +120 -31
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5222 -475
- package/dist/mcp/tools/complete-reminder.js +94 -77
- package/dist/mcp/tools/create-reminder.js +94 -77
- package/dist/mcp/tools/create-task.js +120 -22
- package/dist/mcp/tools/deactivate-behavior.js +95 -77
- package/dist/mcp/tools/list-reminders.js +94 -77
- package/dist/mcp/tools/list-tasks.js +31 -1
- package/dist/mcp/tools/send-message.js +8 -1
- package/dist/mcp/tools/update-task.js +39 -10
- package/dist/runtime/index.js +911 -219
- package/dist/tui/App.js +997 -295
- 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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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 &&
|
|
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 (
|
|
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 =
|
|
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" &&
|
|
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 &&
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
39
|
-
var
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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";
|