@askexenow/exe-os 0.8.83 → 0.8.86
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 +154 -21
- package/dist/bin/cli.js +14678 -12676
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +100 -91
- package/dist/bin/exe-assign.js +1003 -854
- package/dist/bin/exe-boot.js +1420 -485
- package/dist/bin/exe-call.js +10 -0
- package/dist/bin/exe-cloud.js +29 -6
- package/dist/bin/exe-dispatch.js +572 -271
- package/dist/bin/exe-doctor.js +403 -6
- package/dist/bin/exe-export-behaviors.js +175 -72
- package/dist/bin/exe-forget.js +102 -3
- package/dist/bin/exe-gateway.js +796 -292
- package/dist/bin/exe-healthcheck.js +134 -1
- package/dist/bin/exe-heartbeat.js +172 -36
- package/dist/bin/exe-kill.js +175 -72
- package/dist/bin/exe-launch-agent.js +189 -76
- package/dist/bin/exe-link.js +927 -82
- package/dist/bin/exe-new-employee.js +60 -8
- package/dist/bin/exe-pending-messages.js +151 -19
- package/dist/bin/exe-pending-notifications.js +97 -2
- package/dist/bin/exe-pending-reviews.js +155 -22
- package/dist/bin/exe-rename.js +564 -23
- package/dist/bin/exe-review.js +231 -73
- package/dist/bin/exe-search.js +995 -228
- package/dist/bin/exe-session-cleanup.js +4930 -1664
- package/dist/bin/exe-settings.js +20 -5
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +154 -21
- package/dist/bin/exe-team.js +97 -2
- package/dist/bin/git-sweep.js +1180 -363
- package/dist/bin/graph-backfill.js +175 -72
- package/dist/bin/graph-export.js +175 -72
- package/dist/bin/install.js +60 -7
- package/dist/bin/list-providers.js +1 -0
- package/dist/bin/scan-tasks.js +1185 -367
- package/dist/bin/setup.js +914 -270
- 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 +792 -285
- package/dist/hooks/bug-report-worker.js +445 -135
- package/dist/hooks/commit-complete.js +1178 -361
- package/dist/hooks/error-recall.js +994 -228
- package/dist/hooks/ingest-worker.js +1799 -1234
- 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 +757 -109
- package/dist/hooks/pre-compact.js +1061 -244
- package/dist/hooks/pre-tool-use.js +787 -130
- package/dist/hooks/prompt-ingest-worker.js +242 -101
- package/dist/hooks/prompt-submit.js +1121 -299
- package/dist/hooks/response-ingest-worker.js +242 -101
- package/dist/hooks/session-end.js +4063 -397
- package/dist/hooks/session-start.js +1071 -254
- package/dist/hooks/stop.js +768 -120
- package/dist/hooks/subagent-stop.js +757 -109
- package/dist/hooks/summary-worker.js +1706 -1011
- package/dist/index.js +1821 -1098
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +932 -88
- 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 +2733 -1575
- package/dist/lib/hybrid-search.js +995 -228
- package/dist/lib/identity.js +87 -67
- package/dist/lib/keychain.js +9 -1
- package/dist/lib/messaging.js +103 -40
- package/dist/lib/reminders.js +91 -74
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/schedules.js +96 -2
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/skill-learning.js +103 -85
- package/dist/lib/store.js +234 -73
- package/dist/lib/tasks.js +348 -134
- package/dist/lib/tmux-routing.js +422 -208
- package/dist/lib/token-spend.js +273 -0
- package/dist/lib/ws-client.js +11 -0
- package/dist/mcp/server.js +5742 -696
- 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 +375 -152
- 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 +99 -31
- package/dist/mcp/tools/send-message.js +108 -45
- package/dist/mcp/tools/update-task.js +162 -77
- package/dist/runtime/index.js +1075 -258
- package/dist/tui/App.js +1333 -506
- package/package.json +6 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -391,6 +391,12 @@ function getClient() {
|
|
|
391
391
|
if (!_resilientClient) {
|
|
392
392
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
393
393
|
}
|
|
394
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
395
|
+
return _resilientClient;
|
|
396
|
+
}
|
|
397
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
398
|
+
return _daemonClient;
|
|
399
|
+
}
|
|
394
400
|
return _resilientClient;
|
|
395
401
|
}
|
|
396
402
|
function getRawClient() {
|
|
@@ -879,6 +885,12 @@ async function ensureSchema() {
|
|
|
879
885
|
} catch {
|
|
880
886
|
}
|
|
881
887
|
}
|
|
888
|
+
try {
|
|
889
|
+
await client.execute(
|
|
890
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
891
|
+
);
|
|
892
|
+
} catch {
|
|
893
|
+
}
|
|
882
894
|
await client.executeMultiple(`
|
|
883
895
|
CREATE TABLE IF NOT EXISTS entities (
|
|
884
896
|
id TEXT PRIMARY KEY,
|
|
@@ -931,7 +943,30 @@ async function ensureSchema() {
|
|
|
931
943
|
entity_id TEXT NOT NULL,
|
|
932
944
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
933
945
|
);
|
|
946
|
+
|
|
947
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
948
|
+
name,
|
|
949
|
+
content=entities,
|
|
950
|
+
content_rowid=rowid
|
|
951
|
+
);
|
|
952
|
+
|
|
953
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
954
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
955
|
+
END;
|
|
956
|
+
|
|
957
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
958
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
959
|
+
END;
|
|
960
|
+
|
|
961
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
962
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
963
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
964
|
+
END;
|
|
934
965
|
`);
|
|
966
|
+
try {
|
|
967
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
968
|
+
} catch {
|
|
969
|
+
}
|
|
935
970
|
await client.executeMultiple(`
|
|
936
971
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
937
972
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1112,6 +1147,33 @@ async function ensureSchema() {
|
|
|
1112
1147
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1113
1148
|
ON conversations(channel_id);
|
|
1114
1149
|
`);
|
|
1150
|
+
await client.executeMultiple(`
|
|
1151
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1152
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1153
|
+
agent_id TEXT NOT NULL,
|
|
1154
|
+
session_name TEXT,
|
|
1155
|
+
task_id TEXT,
|
|
1156
|
+
project_name TEXT,
|
|
1157
|
+
started_at TEXT NOT NULL
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1160
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1161
|
+
ON session_agent_map(agent_id);
|
|
1162
|
+
`);
|
|
1163
|
+
try {
|
|
1164
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1165
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1166
|
+
await client.execute({
|
|
1167
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1168
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1169
|
+
FROM memories
|
|
1170
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1171
|
+
GROUP BY session_id, agent_id`,
|
|
1172
|
+
args: []
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
} catch {
|
|
1176
|
+
}
|
|
1115
1177
|
try {
|
|
1116
1178
|
await client.execute({
|
|
1117
1179
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1245,15 +1307,41 @@ async function ensureSchema() {
|
|
|
1245
1307
|
});
|
|
1246
1308
|
} catch {
|
|
1247
1309
|
}
|
|
1310
|
+
for (const col of [
|
|
1311
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1312
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1313
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1314
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1315
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1316
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1317
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1318
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1319
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1320
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1321
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1322
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1323
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1324
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1325
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1326
|
+
]) {
|
|
1327
|
+
try {
|
|
1328
|
+
await client.execute(col);
|
|
1329
|
+
} catch {
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1248
1332
|
}
|
|
1249
1333
|
async function disposeDatabase() {
|
|
1334
|
+
if (_daemonClient) {
|
|
1335
|
+
_daemonClient.close();
|
|
1336
|
+
_daemonClient = null;
|
|
1337
|
+
}
|
|
1250
1338
|
if (_client) {
|
|
1251
1339
|
_client.close();
|
|
1252
1340
|
_client = null;
|
|
1253
1341
|
_resilientClient = null;
|
|
1254
1342
|
}
|
|
1255
1343
|
}
|
|
1256
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1344
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1257
1345
|
var init_database = __esm({
|
|
1258
1346
|
"src/lib/database.ts"() {
|
|
1259
1347
|
"use strict";
|
|
@@ -1261,6 +1349,7 @@ var init_database = __esm({
|
|
|
1261
1349
|
init_employees();
|
|
1262
1350
|
_client = null;
|
|
1263
1351
|
_resilientClient = null;
|
|
1352
|
+
_daemonClient = null;
|
|
1264
1353
|
initTurso = initDatabase;
|
|
1265
1354
|
disposeTurso = disposeDatabase;
|
|
1266
1355
|
}
|
|
@@ -1297,12 +1386,20 @@ async function getMasterKey() {
|
|
|
1297
1386
|
}
|
|
1298
1387
|
const keyPath = getKeyPath();
|
|
1299
1388
|
if (!existsSync3(keyPath)) {
|
|
1389
|
+
process.stderr.write(
|
|
1390
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
1391
|
+
`
|
|
1392
|
+
);
|
|
1300
1393
|
return null;
|
|
1301
1394
|
}
|
|
1302
1395
|
try {
|
|
1303
1396
|
const content = await readFile3(keyPath, "utf-8");
|
|
1304
1397
|
return Buffer.from(content.trim(), "base64");
|
|
1305
|
-
} catch {
|
|
1398
|
+
} catch (err) {
|
|
1399
|
+
process.stderr.write(
|
|
1400
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
1401
|
+
`
|
|
1402
|
+
);
|
|
1306
1403
|
return null;
|
|
1307
1404
|
}
|
|
1308
1405
|
}
|
|
@@ -1813,6 +1910,7 @@ __export(store_exports, {
|
|
|
1813
1910
|
vectorToBlob: () => vectorToBlob,
|
|
1814
1911
|
writeMemory: () => writeMemory
|
|
1815
1912
|
});
|
|
1913
|
+
import { createHash } from "crypto";
|
|
1816
1914
|
function isBusyError2(err) {
|
|
1817
1915
|
if (err instanceof Error) {
|
|
1818
1916
|
const msg = err.message.toLowerCase();
|
|
@@ -1886,12 +1984,52 @@ function classifyTier(record) {
|
|
|
1886
1984
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1887
1985
|
return 3;
|
|
1888
1986
|
}
|
|
1987
|
+
function inferFilePaths(record) {
|
|
1988
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
1989
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
1990
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
1991
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
1992
|
+
}
|
|
1993
|
+
function inferCommitHash(record) {
|
|
1994
|
+
if (record.tool_name !== "Bash") return null;
|
|
1995
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
1996
|
+
return match ? match[1] : null;
|
|
1997
|
+
}
|
|
1998
|
+
function inferLanguageType(record) {
|
|
1999
|
+
const text = record.raw_text;
|
|
2000
|
+
if (!text || text.length < 10) return null;
|
|
2001
|
+
const trimmed = text.trimStart();
|
|
2002
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
2003
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
2004
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
2005
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
2006
|
+
return "mixed";
|
|
2007
|
+
}
|
|
2008
|
+
function inferDomain(record) {
|
|
2009
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
2010
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
2011
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
2012
|
+
return null;
|
|
2013
|
+
}
|
|
1889
2014
|
async function writeMemory(record) {
|
|
1890
2015
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1891
2016
|
throw new Error(
|
|
1892
2017
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
1893
2018
|
);
|
|
1894
2019
|
}
|
|
2020
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
2021
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
try {
|
|
2025
|
+
const client = getClient();
|
|
2026
|
+
const existing = await client.execute({
|
|
2027
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
2028
|
+
args: [contentHash, record.agent_id]
|
|
2029
|
+
});
|
|
2030
|
+
if (existing.rows.length > 0) return;
|
|
2031
|
+
} catch {
|
|
2032
|
+
}
|
|
1895
2033
|
const dbRow = {
|
|
1896
2034
|
id: record.id,
|
|
1897
2035
|
agent_id: record.agent_id,
|
|
@@ -1921,7 +2059,23 @@ async function writeMemory(record) {
|
|
|
1921
2059
|
supersedes_id: record.supersedes_id ?? null,
|
|
1922
2060
|
draft: record.draft ? 1 : 0,
|
|
1923
2061
|
memory_type: record.memory_type ?? "raw",
|
|
1924
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
2062
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
2063
|
+
content_hash: contentHash,
|
|
2064
|
+
intent: record.intent ?? null,
|
|
2065
|
+
outcome: record.outcome ?? null,
|
|
2066
|
+
domain: record.domain ?? inferDomain(record),
|
|
2067
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
2068
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
2069
|
+
chain_position: record.chain_position ?? null,
|
|
2070
|
+
review_status: record.review_status ?? null,
|
|
2071
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
2072
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
2073
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
2074
|
+
duration_ms: record.duration_ms ?? null,
|
|
2075
|
+
token_cost: record.token_cost ?? null,
|
|
2076
|
+
audience: record.audience ?? null,
|
|
2077
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
2078
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
1925
2079
|
};
|
|
1926
2080
|
_pendingRecords.push(dbRow);
|
|
1927
2081
|
orgBus.emit({
|
|
@@ -1979,80 +2133,85 @@ async function flushBatch() {
|
|
|
1979
2133
|
const draft = row.draft ? 1 : 0;
|
|
1980
2134
|
const memoryType = row.memory_type ?? "raw";
|
|
1981
2135
|
const trajectory = row.trajectory ?? null;
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2136
|
+
const contentHash = row.content_hash ?? null;
|
|
2137
|
+
const intent = row.intent ?? null;
|
|
2138
|
+
const outcome = row.outcome ?? null;
|
|
2139
|
+
const domain = row.domain ?? null;
|
|
2140
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
2141
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
2142
|
+
const chainPosition = row.chain_position ?? null;
|
|
2143
|
+
const reviewStatus = row.review_status ?? null;
|
|
2144
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
2145
|
+
const filePaths = row.file_paths ?? null;
|
|
2146
|
+
const commitHash = row.commit_hash ?? null;
|
|
2147
|
+
const durationMs = row.duration_ms ?? null;
|
|
2148
|
+
const tokenCost = row.token_cost ?? null;
|
|
2149
|
+
const audience = row.audience ?? null;
|
|
2150
|
+
const languageType = row.language_type ?? null;
|
|
2151
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
2152
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
1992
2153
|
tool_name, project_name,
|
|
1993
2154
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1994
2155
|
confidence, last_accessed,
|
|
1995
2156
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1996
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
trajectory
|
|
2055
|
-
]
|
|
2157
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
2158
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
2159
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
2160
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
2161
|
+
const metaArgs = [
|
|
2162
|
+
intent,
|
|
2163
|
+
outcome,
|
|
2164
|
+
domain,
|
|
2165
|
+
referencedEntities,
|
|
2166
|
+
retrievalCount,
|
|
2167
|
+
chainPosition,
|
|
2168
|
+
reviewStatus,
|
|
2169
|
+
contextWindowPct,
|
|
2170
|
+
filePaths,
|
|
2171
|
+
commitHash,
|
|
2172
|
+
durationMs,
|
|
2173
|
+
tokenCost,
|
|
2174
|
+
audience,
|
|
2175
|
+
languageType,
|
|
2176
|
+
parentMemoryId
|
|
2177
|
+
];
|
|
2178
|
+
const baseArgs = [
|
|
2179
|
+
row.id,
|
|
2180
|
+
row.agent_id,
|
|
2181
|
+
row.agent_role,
|
|
2182
|
+
row.session_id,
|
|
2183
|
+
row.timestamp,
|
|
2184
|
+
row.tool_name,
|
|
2185
|
+
row.project_name,
|
|
2186
|
+
row.has_error,
|
|
2187
|
+
row.raw_text
|
|
2188
|
+
];
|
|
2189
|
+
const sharedArgs = [
|
|
2190
|
+
row.version,
|
|
2191
|
+
taskId,
|
|
2192
|
+
importance,
|
|
2193
|
+
status,
|
|
2194
|
+
confidence,
|
|
2195
|
+
lastAccessed,
|
|
2196
|
+
workspaceId,
|
|
2197
|
+
documentId,
|
|
2198
|
+
userId,
|
|
2199
|
+
charOffset,
|
|
2200
|
+
pageNumber,
|
|
2201
|
+
sourcePath,
|
|
2202
|
+
sourceType,
|
|
2203
|
+
tier,
|
|
2204
|
+
supersedesId,
|
|
2205
|
+
draft,
|
|
2206
|
+
memoryType,
|
|
2207
|
+
trajectory,
|
|
2208
|
+
contentHash
|
|
2209
|
+
];
|
|
2210
|
+
return {
|
|
2211
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
2212
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
2213
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2214
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
2056
2215
|
};
|
|
2057
2216
|
};
|
|
2058
2217
|
const globalClient = getClient();
|
|
@@ -2391,12 +2550,141 @@ var init_self_query_router = __esm({
|
|
|
2391
2550
|
}
|
|
2392
2551
|
});
|
|
2393
2552
|
|
|
2553
|
+
// src/lib/reranker.ts
|
|
2554
|
+
var reranker_exports = {};
|
|
2555
|
+
__export(reranker_exports, {
|
|
2556
|
+
disposeReranker: () => disposeReranker,
|
|
2557
|
+
getRerankerModelPath: () => getRerankerModelPath,
|
|
2558
|
+
isRerankerAvailable: () => isRerankerAvailable,
|
|
2559
|
+
rerank: () => rerank,
|
|
2560
|
+
rerankWithContext: () => rerankWithContext,
|
|
2561
|
+
rerankWithScores: () => rerankWithScores
|
|
2562
|
+
});
|
|
2563
|
+
import path5 from "path";
|
|
2564
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2565
|
+
function resetIdleTimer() {
|
|
2566
|
+
if (_idleTimer) clearTimeout(_idleTimer);
|
|
2567
|
+
_idleTimer = setTimeout(() => {
|
|
2568
|
+
void disposeReranker();
|
|
2569
|
+
}, IDLE_TIMEOUT_MS);
|
|
2570
|
+
if (_idleTimer && typeof _idleTimer === "object" && "unref" in _idleTimer) {
|
|
2571
|
+
_idleTimer.unref();
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
function isRerankerAvailable() {
|
|
2575
|
+
return existsSync5(path5.join(MODELS_DIR, RERANKER_MODEL_FILE));
|
|
2576
|
+
}
|
|
2577
|
+
function getRerankerModelPath() {
|
|
2578
|
+
return path5.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
2579
|
+
}
|
|
2580
|
+
async function ensureLoaded() {
|
|
2581
|
+
if (_rerankerContext) {
|
|
2582
|
+
resetIdleTimer();
|
|
2583
|
+
return;
|
|
2584
|
+
}
|
|
2585
|
+
const modelPath = path5.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
2586
|
+
if (!existsSync5(modelPath)) {
|
|
2587
|
+
throw new Error(
|
|
2588
|
+
`Reranker model not found at ${modelPath}. Run /exe-setup to download it.`
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2591
|
+
process.stderr.write("[reranker] Loading Jina Reranker v3...\n");
|
|
2592
|
+
const { getLlama } = await import("node-llama-cpp");
|
|
2593
|
+
const llama = await getLlama();
|
|
2594
|
+
_rerankerModel = await llama.loadModel({ modelPath });
|
|
2595
|
+
_rerankerContext = await _rerankerModel.createEmbeddingContext();
|
|
2596
|
+
process.stderr.write("[reranker] Jina Reranker v3 loaded.\n");
|
|
2597
|
+
resetIdleTimer();
|
|
2598
|
+
}
|
|
2599
|
+
async function disposeReranker() {
|
|
2600
|
+
if (_idleTimer) {
|
|
2601
|
+
clearTimeout(_idleTimer);
|
|
2602
|
+
_idleTimer = null;
|
|
2603
|
+
}
|
|
2604
|
+
if (_rerankerContext) {
|
|
2605
|
+
try {
|
|
2606
|
+
await _rerankerContext.dispose();
|
|
2607
|
+
} catch {
|
|
2608
|
+
}
|
|
2609
|
+
_rerankerContext = null;
|
|
2610
|
+
}
|
|
2611
|
+
if (_rerankerModel) {
|
|
2612
|
+
try {
|
|
2613
|
+
await _rerankerModel.dispose();
|
|
2614
|
+
} catch {
|
|
2615
|
+
}
|
|
2616
|
+
_rerankerModel = null;
|
|
2617
|
+
}
|
|
2618
|
+
process.stderr.write("[reranker] Unloaded (idle timeout).\n");
|
|
2619
|
+
}
|
|
2620
|
+
async function rerankWithScores(query, texts, topK) {
|
|
2621
|
+
if (texts.length === 0) return [];
|
|
2622
|
+
await ensureLoaded();
|
|
2623
|
+
const ctx = _rerankerContext;
|
|
2624
|
+
const scored = [];
|
|
2625
|
+
for (let i = 0; i < texts.length; i++) {
|
|
2626
|
+
const text = texts[i] ?? "";
|
|
2627
|
+
try {
|
|
2628
|
+
const input2 = `query: ${query} document: ${text.slice(0, 512)}`;
|
|
2629
|
+
const embedding = await ctx.getEmbeddingFor(input2);
|
|
2630
|
+
const score = embedding.vector[0] ?? 0;
|
|
2631
|
+
scored.push({ text, score, index: i });
|
|
2632
|
+
} catch {
|
|
2633
|
+
scored.push({ text, score: -1, index: i });
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
scored.sort((a, b) => b.score - a.score);
|
|
2637
|
+
return typeof topK === "number" ? scored.slice(0, topK) : scored;
|
|
2638
|
+
}
|
|
2639
|
+
async function rerank(query, candidates, topK = 5) {
|
|
2640
|
+
if (candidates.length === 0) return [];
|
|
2641
|
+
if (candidates.length <= topK) return candidates;
|
|
2642
|
+
const scored = await rerankWithScores(
|
|
2643
|
+
query,
|
|
2644
|
+
candidates.map((c) => c.raw_text),
|
|
2645
|
+
topK
|
|
2646
|
+
);
|
|
2647
|
+
return scored.map((s) => candidates[s.index]);
|
|
2648
|
+
}
|
|
2649
|
+
async function rerankWithContext(query, candidates, topK) {
|
|
2650
|
+
if (candidates.length === 0) return [];
|
|
2651
|
+
await ensureLoaded();
|
|
2652
|
+
const ctx = _rerankerContext;
|
|
2653
|
+
const scored = [];
|
|
2654
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
2655
|
+
const candidate = candidates[i];
|
|
2656
|
+
try {
|
|
2657
|
+
const docText = candidate.context ? `[${candidate.context}] ${candidate.text.slice(0, 460)}` : candidate.text.slice(0, 512);
|
|
2658
|
+
const input2 = `query: ${query} document: ${docText}`;
|
|
2659
|
+
const embedding = await ctx.getEmbeddingFor(input2);
|
|
2660
|
+
const score = embedding.vector[0] ?? 0;
|
|
2661
|
+
scored.push({ text: candidate.text, score, index: i });
|
|
2662
|
+
} catch {
|
|
2663
|
+
scored.push({ text: candidate.text, score: -1, index: i });
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
scored.sort((a, b) => b.score - a.score);
|
|
2667
|
+
return typeof topK === "number" ? scored.slice(0, topK) : scored;
|
|
2668
|
+
}
|
|
2669
|
+
var RERANKER_MODEL_FILE, IDLE_TIMEOUT_MS, _rerankerContext, _rerankerModel, _idleTimer;
|
|
2670
|
+
var init_reranker = __esm({
|
|
2671
|
+
"src/lib/reranker.ts"() {
|
|
2672
|
+
"use strict";
|
|
2673
|
+
init_config();
|
|
2674
|
+
RERANKER_MODEL_FILE = "jina-reranker-v3-q4_k_m.gguf";
|
|
2675
|
+
IDLE_TIMEOUT_MS = 6e4;
|
|
2676
|
+
_rerankerContext = null;
|
|
2677
|
+
_rerankerModel = null;
|
|
2678
|
+
_idleTimer = null;
|
|
2679
|
+
}
|
|
2680
|
+
});
|
|
2681
|
+
|
|
2394
2682
|
// src/lib/exe-daemon-client.ts
|
|
2395
2683
|
import net from "net";
|
|
2396
2684
|
import { spawn } from "child_process";
|
|
2397
2685
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2398
|
-
import { existsSync as
|
|
2399
|
-
import
|
|
2686
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
2687
|
+
import path6 from "path";
|
|
2400
2688
|
import { fileURLToPath } from "url";
|
|
2401
2689
|
function handleData(chunk) {
|
|
2402
2690
|
_buffer += chunk.toString();
|
|
@@ -2411,10 +2699,12 @@ function handleData(chunk) {
|
|
|
2411
2699
|
if (!line) continue;
|
|
2412
2700
|
try {
|
|
2413
2701
|
const response = JSON.parse(line);
|
|
2414
|
-
const
|
|
2702
|
+
const id = response.id;
|
|
2703
|
+
if (!id) continue;
|
|
2704
|
+
const entry = _pending.get(id);
|
|
2415
2705
|
if (entry) {
|
|
2416
2706
|
clearTimeout(entry.timer);
|
|
2417
|
-
_pending.delete(
|
|
2707
|
+
_pending.delete(id);
|
|
2418
2708
|
entry.resolve(response);
|
|
2419
2709
|
}
|
|
2420
2710
|
} catch {
|
|
@@ -2422,7 +2712,7 @@ function handleData(chunk) {
|
|
|
2422
2712
|
}
|
|
2423
2713
|
}
|
|
2424
2714
|
function cleanupStaleFiles() {
|
|
2425
|
-
if (
|
|
2715
|
+
if (existsSync6(PID_PATH)) {
|
|
2426
2716
|
try {
|
|
2427
2717
|
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
2428
2718
|
if (pid > 0) {
|
|
@@ -2445,11 +2735,11 @@ function cleanupStaleFiles() {
|
|
|
2445
2735
|
}
|
|
2446
2736
|
}
|
|
2447
2737
|
function findPackageRoot() {
|
|
2448
|
-
let dir =
|
|
2449
|
-
const { root } =
|
|
2738
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
2739
|
+
const { root } = path6.parse(dir);
|
|
2450
2740
|
while (dir !== root) {
|
|
2451
|
-
if (
|
|
2452
|
-
dir =
|
|
2741
|
+
if (existsSync6(path6.join(dir, "package.json"))) return dir;
|
|
2742
|
+
dir = path6.dirname(dir);
|
|
2453
2743
|
}
|
|
2454
2744
|
return null;
|
|
2455
2745
|
}
|
|
@@ -2459,8 +2749,8 @@ function spawnDaemon() {
|
|
|
2459
2749
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
2460
2750
|
return;
|
|
2461
2751
|
}
|
|
2462
|
-
const daemonPath =
|
|
2463
|
-
if (!
|
|
2752
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
2753
|
+
if (!existsSync6(daemonPath)) {
|
|
2464
2754
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
2465
2755
|
`);
|
|
2466
2756
|
return;
|
|
@@ -2468,7 +2758,7 @@ function spawnDaemon() {
|
|
|
2468
2758
|
const resolvedPath = daemonPath;
|
|
2469
2759
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
2470
2760
|
`);
|
|
2471
|
-
const logPath =
|
|
2761
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
2472
2762
|
let stderrFd = "ignore";
|
|
2473
2763
|
try {
|
|
2474
2764
|
stderrFd = openSync(logPath, "a");
|
|
@@ -2585,6 +2875,9 @@ async function connectEmbedDaemon() {
|
|
|
2585
2875
|
return false;
|
|
2586
2876
|
}
|
|
2587
2877
|
function sendRequest(texts, priority) {
|
|
2878
|
+
return sendDaemonRequest({ texts, priority });
|
|
2879
|
+
}
|
|
2880
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
2588
2881
|
return new Promise((resolve) => {
|
|
2589
2882
|
if (!_socket || !_connected) {
|
|
2590
2883
|
resolve({ error: "Not connected" });
|
|
@@ -2594,10 +2887,10 @@ function sendRequest(texts, priority) {
|
|
|
2594
2887
|
const timer = setTimeout(() => {
|
|
2595
2888
|
_pending.delete(id);
|
|
2596
2889
|
resolve({ error: "Request timeout" });
|
|
2597
|
-
},
|
|
2890
|
+
}, timeoutMs);
|
|
2598
2891
|
_pending.set(id, { resolve, timer });
|
|
2599
2892
|
try {
|
|
2600
|
-
_socket.write(JSON.stringify({ id,
|
|
2893
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
2601
2894
|
} catch {
|
|
2602
2895
|
clearTimeout(timer);
|
|
2603
2896
|
_pending.delete(id);
|
|
@@ -2607,34 +2900,15 @@ function sendRequest(texts, priority) {
|
|
|
2607
2900
|
}
|
|
2608
2901
|
async function pingDaemon() {
|
|
2609
2902
|
if (!_socket || !_connected) return null;
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
}, 5e3);
|
|
2616
|
-
_pending.set(id, {
|
|
2617
|
-
resolve: (data) => {
|
|
2618
|
-
if (data.health) {
|
|
2619
|
-
resolve(data.health);
|
|
2620
|
-
} else {
|
|
2621
|
-
resolve(null);
|
|
2622
|
-
}
|
|
2623
|
-
},
|
|
2624
|
-
timer
|
|
2625
|
-
});
|
|
2626
|
-
try {
|
|
2627
|
-
_socket.write(JSON.stringify({ id, type: "health" }) + "\n");
|
|
2628
|
-
} catch {
|
|
2629
|
-
clearTimeout(timer);
|
|
2630
|
-
_pending.delete(id);
|
|
2631
|
-
resolve(null);
|
|
2632
|
-
}
|
|
2633
|
-
});
|
|
2903
|
+
const response = await sendDaemonRequest({ type: "health" }, 5e3);
|
|
2904
|
+
if (response.health) {
|
|
2905
|
+
return response.health;
|
|
2906
|
+
}
|
|
2907
|
+
return null;
|
|
2634
2908
|
}
|
|
2635
2909
|
function killAndRespawnDaemon() {
|
|
2636
2910
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
2637
|
-
if (
|
|
2911
|
+
if (existsSync6(PID_PATH)) {
|
|
2638
2912
|
try {
|
|
2639
2913
|
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
2640
2914
|
if (pid > 0) {
|
|
@@ -2720,9 +2994,9 @@ var init_exe_daemon_client = __esm({
|
|
|
2720
2994
|
"src/lib/exe-daemon-client.ts"() {
|
|
2721
2995
|
"use strict";
|
|
2722
2996
|
init_config();
|
|
2723
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
2724
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
2725
|
-
SPAWN_LOCK_PATH =
|
|
2997
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
2998
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
2999
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
2726
3000
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
2727
3001
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
2728
3002
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -2773,10 +3047,10 @@ async function disposeEmbedder() {
|
|
|
2773
3047
|
async function embedDirect(text) {
|
|
2774
3048
|
const llamaCpp = await import("node-llama-cpp");
|
|
2775
3049
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2776
|
-
const { existsSync:
|
|
2777
|
-
const
|
|
2778
|
-
const modelPath =
|
|
2779
|
-
if (!
|
|
3050
|
+
const { existsSync: existsSync13 } = await import("fs");
|
|
3051
|
+
const path17 = await import("path");
|
|
3052
|
+
const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
3053
|
+
if (!existsSync13(modelPath)) {
|
|
2780
3054
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2781
3055
|
}
|
|
2782
3056
|
const llama = await llamaCpp.getLlama();
|
|
@@ -2811,7 +3085,7 @@ __export(project_name_exports, {
|
|
|
2811
3085
|
getProjectName: () => getProjectName
|
|
2812
3086
|
});
|
|
2813
3087
|
import { execSync as execSync2 } from "child_process";
|
|
2814
|
-
import
|
|
3088
|
+
import path7 from "path";
|
|
2815
3089
|
function getProjectName(cwd) {
|
|
2816
3090
|
const dir = cwd ?? process.cwd();
|
|
2817
3091
|
if (_cached && _cachedCwd === dir) return _cached;
|
|
@@ -2824,7 +3098,7 @@ function getProjectName(cwd) {
|
|
|
2824
3098
|
timeout: 2e3,
|
|
2825
3099
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2826
3100
|
}).trim();
|
|
2827
|
-
repoRoot =
|
|
3101
|
+
repoRoot = path7.dirname(gitCommonDir);
|
|
2828
3102
|
} catch {
|
|
2829
3103
|
repoRoot = execSync2("git rev-parse --show-toplevel", {
|
|
2830
3104
|
cwd: dir,
|
|
@@ -2833,11 +3107,11 @@ function getProjectName(cwd) {
|
|
|
2833
3107
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2834
3108
|
}).trim();
|
|
2835
3109
|
}
|
|
2836
|
-
_cached =
|
|
3110
|
+
_cached = path7.basename(repoRoot);
|
|
2837
3111
|
_cachedCwd = dir;
|
|
2838
3112
|
return _cached;
|
|
2839
3113
|
} catch {
|
|
2840
|
-
_cached =
|
|
3114
|
+
_cached = path7.basename(dir);
|
|
2841
3115
|
_cachedCwd = dir;
|
|
2842
3116
|
return _cached;
|
|
2843
3117
|
}
|
|
@@ -2861,8 +3135,8 @@ __export(file_grep_exports, {
|
|
|
2861
3135
|
grepProjectFiles: () => grepProjectFiles
|
|
2862
3136
|
});
|
|
2863
3137
|
import { execSync as execSync3 } from "child_process";
|
|
2864
|
-
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, existsSync as
|
|
2865
|
-
import
|
|
3138
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync7 } from "fs";
|
|
3139
|
+
import path8 from "path";
|
|
2866
3140
|
import crypto from "crypto";
|
|
2867
3141
|
function hasRipgrep() {
|
|
2868
3142
|
if (_hasRg === null) {
|
|
@@ -2902,7 +3176,7 @@ async function grepProjectFiles(query, projectRoot, options) {
|
|
|
2902
3176
|
session_id: "file-grep",
|
|
2903
3177
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2904
3178
|
tool_name: "file_grep",
|
|
2905
|
-
project_name:
|
|
3179
|
+
project_name: path8.basename(projectRoot),
|
|
2906
3180
|
has_error: false,
|
|
2907
3181
|
raw_text: `${prefix} ${buildSnippet(hit, projectRoot)}`,
|
|
2908
3182
|
vector: null,
|
|
@@ -2976,7 +3250,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
2976
3250
|
const files = collectFiles(projectRoot, patterns ?? DEFAULT_PATTERNS);
|
|
2977
3251
|
const hits = [];
|
|
2978
3252
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
2979
|
-
const absPath =
|
|
3253
|
+
const absPath = path8.join(projectRoot, filePath);
|
|
2980
3254
|
try {
|
|
2981
3255
|
const stat = statSync2(absPath);
|
|
2982
3256
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
@@ -3003,15 +3277,15 @@ function collectFiles(root, patterns) {
|
|
|
3003
3277
|
const files = [];
|
|
3004
3278
|
function walk(dir, relative) {
|
|
3005
3279
|
if (files.length >= MAX_FILES) return;
|
|
3006
|
-
const basename =
|
|
3280
|
+
const basename = path8.basename(dir);
|
|
3007
3281
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
3008
3282
|
try {
|
|
3009
3283
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
3010
3284
|
for (const entry of entries) {
|
|
3011
3285
|
if (files.length >= MAX_FILES) return;
|
|
3012
|
-
const rel =
|
|
3286
|
+
const rel = path8.join(relative, entry.name);
|
|
3013
3287
|
if (entry.isDirectory()) {
|
|
3014
|
-
walk(
|
|
3288
|
+
walk(path8.join(dir, entry.name), rel);
|
|
3015
3289
|
} else if (entry.isFile()) {
|
|
3016
3290
|
for (const pat of patterns) {
|
|
3017
3291
|
if (matchGlob(rel, pat)) {
|
|
@@ -3043,7 +3317,7 @@ function matchGlob(filePath, pattern) {
|
|
|
3043
3317
|
if (slashIdx !== -1) {
|
|
3044
3318
|
const dir = pattern.slice(0, slashIdx);
|
|
3045
3319
|
const ext2 = pattern.slice(slashIdx + 1).replace("*", "");
|
|
3046
|
-
const fileDir =
|
|
3320
|
+
const fileDir = path8.dirname(filePath);
|
|
3047
3321
|
return fileDir === dir && filePath.endsWith(ext2);
|
|
3048
3322
|
}
|
|
3049
3323
|
const ext = pattern.replace("*", "");
|
|
@@ -3051,8 +3325,8 @@ function matchGlob(filePath, pattern) {
|
|
|
3051
3325
|
}
|
|
3052
3326
|
function buildSnippet(hit, projectRoot) {
|
|
3053
3327
|
try {
|
|
3054
|
-
const absPath =
|
|
3055
|
-
if (!
|
|
3328
|
+
const absPath = path8.join(projectRoot, hit.filePath);
|
|
3329
|
+
if (!existsSync7(absPath)) return hit.matchLine;
|
|
3056
3330
|
const lines = readFileSync4(absPath, "utf8").split("\n");
|
|
3057
3331
|
const start = Math.max(0, hit.lineNumber - 3);
|
|
3058
3332
|
const end = Math.min(lines.length, hit.lineNumber + 2);
|
|
@@ -3078,111 +3352,574 @@ var init_file_grep = __esm({
|
|
|
3078
3352
|
}
|
|
3079
3353
|
});
|
|
3080
3354
|
|
|
3081
|
-
// src/lib/
|
|
3082
|
-
var
|
|
3083
|
-
__export(
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3355
|
+
// src/lib/graph-query.ts
|
|
3356
|
+
var graph_query_exports = {};
|
|
3357
|
+
__export(graph_query_exports, {
|
|
3358
|
+
getConversationPartners: () => getConversationPartners,
|
|
3359
|
+
getEntityByName: () => getEntityByName,
|
|
3360
|
+
getEntityNeighbors: () => getEntityNeighbors,
|
|
3361
|
+
getEntityTimeline: () => getEntityTimeline,
|
|
3362
|
+
getGraphStats: () => getGraphStats,
|
|
3363
|
+
getHotEntities: () => getHotEntities,
|
|
3364
|
+
getRelationshipFrequency: () => getRelationshipFrequency,
|
|
3365
|
+
getRelationships: () => getRelationships,
|
|
3366
|
+
searchEntities: () => searchEntities,
|
|
3367
|
+
traverseChain: () => traverseChain
|
|
3089
3368
|
});
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3369
|
+
async function getEntityByName(client, name, type) {
|
|
3370
|
+
const sql = type ? `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) AND type = ? LIMIT 1` : `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) LIMIT 1`;
|
|
3371
|
+
const args = type ? [name, type] : [name];
|
|
3372
|
+
const result = await client.execute({ sql, args });
|
|
3373
|
+
if (result.rows.length === 0) return null;
|
|
3374
|
+
const row = result.rows[0];
|
|
3375
|
+
return {
|
|
3376
|
+
id: String(row.id),
|
|
3377
|
+
name: String(row.name),
|
|
3378
|
+
type: String(row.type),
|
|
3379
|
+
firstSeen: String(row.first_seen),
|
|
3380
|
+
lastSeen: String(row.last_seen),
|
|
3381
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
async function searchEntities(client, query, limit = 10) {
|
|
3385
|
+
const result = await client.execute({
|
|
3386
|
+
sql: `SELECT * FROM entities WHERE LOWER(name) LIKE ? ORDER BY last_seen DESC LIMIT ?`,
|
|
3387
|
+
args: [`%${query.toLowerCase()}%`, limit]
|
|
3388
|
+
});
|
|
3389
|
+
return result.rows.map((row) => ({
|
|
3390
|
+
id: String(row.id),
|
|
3391
|
+
name: String(row.name),
|
|
3392
|
+
type: String(row.type),
|
|
3393
|
+
firstSeen: String(row.first_seen),
|
|
3394
|
+
lastSeen: String(row.last_seen),
|
|
3395
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3396
|
+
}));
|
|
3397
|
+
}
|
|
3398
|
+
async function getRelationships(client, entityId, options) {
|
|
3399
|
+
const direction = options?.direction ?? "both";
|
|
3400
|
+
let sql;
|
|
3401
|
+
const args = [];
|
|
3402
|
+
if (direction === "outgoing") {
|
|
3403
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3404
|
+
FROM relationships r
|
|
3405
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3406
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3407
|
+
WHERE r.source_entity_id = ?`;
|
|
3408
|
+
args.push(entityId);
|
|
3409
|
+
} else if (direction === "incoming") {
|
|
3410
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3411
|
+
FROM relationships r
|
|
3412
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3413
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3414
|
+
WHERE r.target_entity_id = ?`;
|
|
3415
|
+
args.push(entityId);
|
|
3416
|
+
} else {
|
|
3417
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3418
|
+
FROM relationships r
|
|
3419
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3420
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3421
|
+
WHERE r.source_entity_id = ? OR r.target_entity_id = ?`;
|
|
3422
|
+
args.push(entityId, entityId);
|
|
3423
|
+
}
|
|
3424
|
+
if (options?.type) {
|
|
3425
|
+
sql += ` AND r.type = ?`;
|
|
3426
|
+
args.push(options.type);
|
|
3427
|
+
}
|
|
3428
|
+
sql += ` ORDER BY r.weight DESC, r.timestamp DESC`;
|
|
3429
|
+
const result = await client.execute({ sql, args });
|
|
3430
|
+
return result.rows.map((row) => ({
|
|
3431
|
+
id: String(row.id),
|
|
3432
|
+
sourceEntityId: String(row.source_entity_id),
|
|
3433
|
+
targetEntityId: String(row.target_entity_id),
|
|
3434
|
+
type: String(row.type),
|
|
3435
|
+
weight: Number(row.weight),
|
|
3436
|
+
timestamp: String(row.timestamp),
|
|
3437
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
3438
|
+
confidence: Number(row.confidence ?? 1),
|
|
3439
|
+
confidenceLabel: String(row.confidence_label ?? "extracted"),
|
|
3440
|
+
sourceName: String(row.source_name),
|
|
3441
|
+
targetName: String(row.target_name)
|
|
3442
|
+
}));
|
|
3443
|
+
}
|
|
3444
|
+
async function traverseChain(client, startEntityId, relationshipType, maxDepth = 3) {
|
|
3445
|
+
const result = await client.execute({
|
|
3446
|
+
sql: `WITH RECURSIVE chain(entity_id, depth, rel_type) AS (
|
|
3447
|
+
SELECT ?, 0, ''
|
|
3448
|
+
UNION ALL
|
|
3449
|
+
SELECT r.target_entity_id, c.depth + 1, r.type
|
|
3450
|
+
FROM chain c
|
|
3451
|
+
JOIN relationships r ON r.source_entity_id = c.entity_id
|
|
3452
|
+
WHERE r.type = ? AND c.depth < ?
|
|
3453
|
+
)
|
|
3454
|
+
SELECT DISTINCT e.*, chain.depth, chain.rel_type
|
|
3455
|
+
FROM chain
|
|
3456
|
+
JOIN entities e ON e.id = chain.entity_id
|
|
3457
|
+
ORDER BY chain.depth ASC`,
|
|
3458
|
+
args: [startEntityId, relationshipType, maxDepth]
|
|
3459
|
+
});
|
|
3460
|
+
return result.rows.map((row) => ({
|
|
3461
|
+
entity: {
|
|
3462
|
+
id: String(row.id),
|
|
3463
|
+
name: String(row.name),
|
|
3464
|
+
type: String(row.type),
|
|
3465
|
+
firstSeen: String(row.first_seen),
|
|
3466
|
+
lastSeen: String(row.last_seen),
|
|
3467
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3468
|
+
},
|
|
3469
|
+
depth: Number(row.depth),
|
|
3470
|
+
relationship: String(row.rel_type)
|
|
3471
|
+
}));
|
|
3472
|
+
}
|
|
3473
|
+
async function getEntityNeighbors(client, entityId, maxHops = 2) {
|
|
3474
|
+
const result = await client.execute({
|
|
3475
|
+
sql: `WITH RECURSIVE neighborhood(entity_id, depth, rel_type, rel_confidence) AS (
|
|
3476
|
+
SELECT ?, 0, '', 1.0
|
|
3477
|
+
UNION ALL
|
|
3478
|
+
SELECT CASE
|
|
3479
|
+
WHEN r.source_entity_id = n.entity_id THEN r.target_entity_id
|
|
3480
|
+
ELSE r.source_entity_id
|
|
3481
|
+
END, n.depth + 1, r.type, COALESCE(r.confidence, 1.0)
|
|
3482
|
+
FROM neighborhood n
|
|
3483
|
+
JOIN relationships r ON r.source_entity_id = n.entity_id
|
|
3484
|
+
OR r.target_entity_id = n.entity_id
|
|
3485
|
+
WHERE n.depth < ?
|
|
3486
|
+
)
|
|
3487
|
+
SELECT DISTINCT e.*, MIN(neighborhood.depth) as depth,
|
|
3488
|
+
neighborhood.rel_type, neighborhood.rel_confidence
|
|
3489
|
+
FROM neighborhood
|
|
3490
|
+
JOIN entities e ON e.id = neighborhood.entity_id
|
|
3491
|
+
GROUP BY e.id
|
|
3492
|
+
ORDER BY depth ASC, e.last_seen DESC
|
|
3493
|
+
LIMIT 50`,
|
|
3494
|
+
args: [entityId, maxHops]
|
|
3495
|
+
});
|
|
3496
|
+
return result.rows.map((row) => ({
|
|
3497
|
+
entity: {
|
|
3498
|
+
id: String(row.id),
|
|
3499
|
+
name: String(row.name),
|
|
3500
|
+
type: String(row.type),
|
|
3501
|
+
firstSeen: String(row.first_seen),
|
|
3502
|
+
lastSeen: String(row.last_seen),
|
|
3503
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3504
|
+
},
|
|
3505
|
+
depth: Number(row.depth),
|
|
3506
|
+
relType: String(row.rel_type ?? ""),
|
|
3507
|
+
relConfidence: Number(row.rel_confidence ?? 1)
|
|
3508
|
+
}));
|
|
3509
|
+
}
|
|
3510
|
+
async function getGraphStats(client) {
|
|
3511
|
+
const entityCount = await client.execute("SELECT COUNT(*) as cnt FROM entities");
|
|
3512
|
+
const relCount = await client.execute("SELECT COUNT(*) as cnt FROM relationships");
|
|
3513
|
+
const typeResult = await client.execute(
|
|
3514
|
+
"SELECT type, COUNT(*) as cnt FROM entities GROUP BY type ORDER BY cnt DESC"
|
|
3515
|
+
);
|
|
3516
|
+
const types = {};
|
|
3517
|
+
for (const row of typeResult.rows) {
|
|
3518
|
+
types[String(row.type)] = Number(row.cnt);
|
|
3099
3519
|
}
|
|
3520
|
+
return {
|
|
3521
|
+
entities: Number(entityCount.rows[0]?.cnt ?? 0),
|
|
3522
|
+
relationships: Number(relCount.rows[0]?.cnt ?? 0),
|
|
3523
|
+
types
|
|
3524
|
+
};
|
|
3100
3525
|
}
|
|
3101
|
-
function
|
|
3102
|
-
|
|
3526
|
+
async function getEntityTimeline(client, entityId, since) {
|
|
3527
|
+
const args = [entityId, entityId];
|
|
3528
|
+
let sinceClause = "";
|
|
3529
|
+
if (since) {
|
|
3530
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
3531
|
+
args.push(since.toISOString());
|
|
3532
|
+
}
|
|
3533
|
+
const result = await client.execute({
|
|
3534
|
+
sql: `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3535
|
+
FROM relationships r
|
|
3536
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3537
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3538
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
3539
|
+
ORDER BY r.timestamp DESC`,
|
|
3540
|
+
args
|
|
3541
|
+
});
|
|
3542
|
+
return result.rows.map((row) => ({
|
|
3543
|
+
relationship: {
|
|
3544
|
+
id: String(row.id),
|
|
3545
|
+
sourceEntityId: String(row.source_entity_id),
|
|
3546
|
+
targetEntityId: String(row.target_entity_id),
|
|
3547
|
+
type: String(row.type),
|
|
3548
|
+
weight: Number(row.weight),
|
|
3549
|
+
timestamp: String(row.timestamp),
|
|
3550
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
3551
|
+
sourceName: String(row.source_name),
|
|
3552
|
+
targetName: String(row.target_name)
|
|
3553
|
+
},
|
|
3554
|
+
timestamp: String(row.timestamp)
|
|
3555
|
+
}));
|
|
3103
3556
|
}
|
|
3104
|
-
function
|
|
3105
|
-
|
|
3557
|
+
async function getRelationshipFrequency(client, entityId, options) {
|
|
3558
|
+
const granularity = options?.granularity ?? "day";
|
|
3559
|
+
const args = [entityId, entityId];
|
|
3560
|
+
let typeClause = "";
|
|
3561
|
+
if (options?.type) {
|
|
3562
|
+
typeClause = " AND r.type = ?";
|
|
3563
|
+
args.push(options.type);
|
|
3564
|
+
}
|
|
3565
|
+
let bucketExpr;
|
|
3566
|
+
switch (granularity) {
|
|
3567
|
+
case "week":
|
|
3568
|
+
bucketExpr = `strftime('%Y', r.timestamp) || '-W' || strftime('%W', r.timestamp)`;
|
|
3569
|
+
break;
|
|
3570
|
+
case "month":
|
|
3571
|
+
bucketExpr = `strftime('%Y-%m', r.timestamp)`;
|
|
3572
|
+
break;
|
|
3573
|
+
default:
|
|
3574
|
+
bucketExpr = `strftime('%Y-%m-%d', r.timestamp)`;
|
|
3575
|
+
}
|
|
3576
|
+
const result = await client.execute({
|
|
3577
|
+
sql: `SELECT ${bucketExpr} as bucket, COUNT(*) as cnt, r.type as rel_type
|
|
3578
|
+
FROM relationships r
|
|
3579
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${typeClause}
|
|
3580
|
+
GROUP BY bucket${options?.type ? "" : ", r.type"}
|
|
3581
|
+
ORDER BY bucket DESC`,
|
|
3582
|
+
args
|
|
3583
|
+
});
|
|
3584
|
+
return result.rows.map((row) => ({
|
|
3585
|
+
bucket: String(row.bucket),
|
|
3586
|
+
count: Number(row.cnt),
|
|
3587
|
+
relationshipType: options?.type ? options.type : String(row.rel_type)
|
|
3588
|
+
}));
|
|
3106
3589
|
}
|
|
3107
|
-
async function
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3590
|
+
async function getConversationPartners(client, contactEntityId, since) {
|
|
3591
|
+
const args = [contactEntityId, contactEntityId];
|
|
3592
|
+
let sinceClause = "";
|
|
3593
|
+
if (since) {
|
|
3594
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
3595
|
+
args.push(since.toISOString());
|
|
3111
3596
|
}
|
|
3112
|
-
const
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3597
|
+
const result = await client.execute({
|
|
3598
|
+
sql: `SELECT
|
|
3599
|
+
CASE
|
|
3600
|
+
WHEN r.source_entity_id = ? THEN r.target_entity_id
|
|
3601
|
+
ELSE r.source_entity_id
|
|
3602
|
+
END as partner_id,
|
|
3603
|
+
COUNT(*) as interaction_count,
|
|
3604
|
+
MAX(r.timestamp) as last_interaction
|
|
3605
|
+
FROM relationships r
|
|
3606
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
3607
|
+
GROUP BY partner_id
|
|
3608
|
+
ORDER BY interaction_count DESC`,
|
|
3609
|
+
args: [contactEntityId, ...args]
|
|
3610
|
+
});
|
|
3611
|
+
const partners = [];
|
|
3612
|
+
for (const row of result.rows) {
|
|
3613
|
+
const partnerId = String(row.partner_id);
|
|
3614
|
+
const entityResult = await client.execute({
|
|
3615
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
3616
|
+
args: [partnerId]
|
|
3617
|
+
});
|
|
3618
|
+
if (entityResult.rows.length === 0) continue;
|
|
3619
|
+
const e = entityResult.rows[0];
|
|
3620
|
+
partners.push({
|
|
3621
|
+
agentEntity: {
|
|
3622
|
+
id: String(e.id),
|
|
3623
|
+
name: String(e.name),
|
|
3624
|
+
type: String(e.type),
|
|
3625
|
+
firstSeen: String(e.first_seen),
|
|
3626
|
+
lastSeen: String(e.last_seen),
|
|
3627
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
3628
|
+
},
|
|
3629
|
+
interactionCount: Number(row.interaction_count),
|
|
3630
|
+
lastInteraction: String(row.last_interaction)
|
|
3631
|
+
});
|
|
3117
3632
|
}
|
|
3118
|
-
|
|
3119
|
-
const { getLlama } = await import("node-llama-cpp");
|
|
3120
|
-
const llama = await getLlama();
|
|
3121
|
-
_rerankerModel = await llama.loadModel({ modelPath });
|
|
3122
|
-
_rerankerContext = await _rerankerModel.createEmbeddingContext();
|
|
3123
|
-
process.stderr.write("[reranker] Jina Reranker v3 loaded.\n");
|
|
3124
|
-
resetIdleTimer();
|
|
3633
|
+
return partners;
|
|
3125
3634
|
}
|
|
3126
|
-
async function
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3635
|
+
async function getHotEntities(client, since, limit = 10) {
|
|
3636
|
+
const sinceISO = since.toISOString();
|
|
3637
|
+
const result = await client.execute({
|
|
3638
|
+
sql: `SELECT entity_id, COUNT(*) as rel_count
|
|
3639
|
+
FROM (
|
|
3640
|
+
SELECT source_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
3641
|
+
UNION ALL
|
|
3642
|
+
SELECT target_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
3643
|
+
)
|
|
3644
|
+
GROUP BY entity_id
|
|
3645
|
+
ORDER BY rel_count DESC
|
|
3646
|
+
LIMIT ?`,
|
|
3647
|
+
args: [sinceISO, sinceISO, limit]
|
|
3648
|
+
});
|
|
3649
|
+
const hotEntities = [];
|
|
3650
|
+
for (const row of result.rows) {
|
|
3651
|
+
const eid = String(row.entity_id);
|
|
3652
|
+
const entityResult = await client.execute({
|
|
3653
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
3654
|
+
args: [eid]
|
|
3655
|
+
});
|
|
3656
|
+
if (entityResult.rows.length === 0) continue;
|
|
3657
|
+
const e = entityResult.rows[0];
|
|
3658
|
+
hotEntities.push({
|
|
3659
|
+
entity: {
|
|
3660
|
+
id: String(e.id),
|
|
3661
|
+
name: String(e.name),
|
|
3662
|
+
type: String(e.type),
|
|
3663
|
+
firstSeen: String(e.first_seen),
|
|
3664
|
+
lastSeen: String(e.last_seen),
|
|
3665
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
3666
|
+
},
|
|
3667
|
+
newRelationships: Number(row.rel_count)
|
|
3668
|
+
});
|
|
3130
3669
|
}
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3670
|
+
return hotEntities;
|
|
3671
|
+
}
|
|
3672
|
+
var init_graph_query = __esm({
|
|
3673
|
+
"src/lib/graph-query.ts"() {
|
|
3674
|
+
"use strict";
|
|
3675
|
+
}
|
|
3676
|
+
});
|
|
3677
|
+
|
|
3678
|
+
// src/lib/entity-boost.ts
|
|
3679
|
+
var entity_boost_exports = {};
|
|
3680
|
+
__export(entity_boost_exports, {
|
|
3681
|
+
applyEntityBoost: () => applyEntityBoost
|
|
3682
|
+
});
|
|
3683
|
+
function getRelTypeWeights() {
|
|
3684
|
+
const override = process.env.RELATIONSHIP_TYPE_WEIGHTS;
|
|
3685
|
+
if (!override) return DEFAULT_RELATIONSHIP_WEIGHTS;
|
|
3686
|
+
try {
|
|
3687
|
+
return { ...DEFAULT_RELATIONSHIP_WEIGHTS, ...JSON.parse(override) };
|
|
3688
|
+
} catch {
|
|
3689
|
+
return DEFAULT_RELATIONSHIP_WEIGHTS;
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
async function matchEntities(query, client) {
|
|
3693
|
+
const words = query.toLowerCase().split(/\s+/).filter((w) => w.length >= MIN_WORD_LENGTH).map((w) => w.replace(/[^a-z0-9_-]/g, "")).filter((w) => w.length >= MIN_WORD_LENGTH);
|
|
3694
|
+
if (words.length === 0) return [];
|
|
3695
|
+
try {
|
|
3696
|
+
const matchExpr = words.map((w) => `${w}*`).join(" OR ");
|
|
3697
|
+
const result = await client.execute({
|
|
3698
|
+
sql: `SELECT e.id, e.name FROM entities e
|
|
3699
|
+
JOIN entities_fts fts ON e.rowid = fts.rowid
|
|
3700
|
+
WHERE entities_fts MATCH ?
|
|
3701
|
+
ORDER BY rank
|
|
3702
|
+
LIMIT ?`,
|
|
3703
|
+
args: [matchExpr, MAX_ENTITY_MATCHES]
|
|
3704
|
+
});
|
|
3705
|
+
if (result.rows.length > 0) {
|
|
3706
|
+
return result.rows.map((row) => ({
|
|
3707
|
+
entityId: String(row.id),
|
|
3708
|
+
name: String(row.name)
|
|
3709
|
+
}));
|
|
3135
3710
|
}
|
|
3136
|
-
|
|
3711
|
+
} catch {
|
|
3137
3712
|
}
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3713
|
+
const conditions = words.map(() => `LOWER(name) LIKE ?`);
|
|
3714
|
+
const args = words.map((w) => `%${w}%`);
|
|
3715
|
+
try {
|
|
3716
|
+
const result = await client.execute({
|
|
3717
|
+
sql: `SELECT id, name FROM entities
|
|
3718
|
+
WHERE ${conditions.join(" OR ")}
|
|
3719
|
+
LIMIT ?`,
|
|
3720
|
+
args: [...args, MAX_ENTITY_MATCHES]
|
|
3721
|
+
});
|
|
3722
|
+
return result.rows.map((row) => ({
|
|
3723
|
+
entityId: String(row.id),
|
|
3724
|
+
name: String(row.name)
|
|
3725
|
+
}));
|
|
3726
|
+
} catch {
|
|
3727
|
+
return [];
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
async function getLinkedMemories(entityIds, client) {
|
|
3731
|
+
const linked = /* @__PURE__ */ new Map();
|
|
3732
|
+
if (entityIds.length === 0) return linked;
|
|
3733
|
+
const placeholders = entityIds.map(() => "?").join(",");
|
|
3734
|
+
try {
|
|
3735
|
+
const result = await client.execute({
|
|
3736
|
+
sql: `SELECT entity_id, memory_id FROM entity_memories
|
|
3737
|
+
WHERE entity_id IN (${placeholders})`,
|
|
3738
|
+
args: entityIds
|
|
3739
|
+
});
|
|
3740
|
+
for (const row of result.rows) {
|
|
3741
|
+
const entityId = String(row.entity_id);
|
|
3742
|
+
const memoryId = String(row.memory_id);
|
|
3743
|
+
const entry = linked.get(entityId) ?? {
|
|
3744
|
+
entityId,
|
|
3745
|
+
memoryIds: /* @__PURE__ */ new Set(),
|
|
3746
|
+
count: 0
|
|
3747
|
+
};
|
|
3748
|
+
entry.memoryIds.add(memoryId);
|
|
3749
|
+
entry.count = entry.memoryIds.size;
|
|
3750
|
+
linked.set(entityId, entry);
|
|
3142
3751
|
}
|
|
3143
|
-
|
|
3752
|
+
} catch {
|
|
3144
3753
|
}
|
|
3145
|
-
|
|
3754
|
+
return linked;
|
|
3146
3755
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
const
|
|
3152
|
-
|
|
3153
|
-
|
|
3756
|
+
function spreadAttenuation(numLinked) {
|
|
3757
|
+
return 1 / (1 + 1e-3 * (numLinked - 1) ** 2);
|
|
3758
|
+
}
|
|
3759
|
+
async function traverseAndScore(entities, client, boostMap, resultIds, graphContextMap) {
|
|
3760
|
+
const topEntities = entities.slice(0, TOP_ENTITIES_TO_TRAVERSE);
|
|
3761
|
+
if (topEntities.length === 0) return;
|
|
3762
|
+
const { getEntityNeighbors: getEntityNeighbors2 } = await Promise.resolve().then(() => (init_graph_query(), graph_query_exports));
|
|
3763
|
+
const relWeights = getRelTypeWeights();
|
|
3764
|
+
const neighborEntityIds = [];
|
|
3765
|
+
const neighborMeta = /* @__PURE__ */ new Map();
|
|
3766
|
+
for (const entity of topEntities) {
|
|
3154
3767
|
try {
|
|
3155
|
-
const
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3768
|
+
const neighbors = await getEntityNeighbors2(
|
|
3769
|
+
client,
|
|
3770
|
+
entity.entityId,
|
|
3771
|
+
GRAPH_TRAVERSAL_MAX_HOPS
|
|
3772
|
+
);
|
|
3773
|
+
for (const n of neighbors) {
|
|
3774
|
+
if (n.depth === 0) continue;
|
|
3775
|
+
if (neighborMeta.has(n.entity.id)) continue;
|
|
3776
|
+
neighborEntityIds.push(n.entity.id);
|
|
3777
|
+
neighborMeta.set(n.entity.id, {
|
|
3778
|
+
depth: n.depth,
|
|
3779
|
+
relType: n.relType,
|
|
3780
|
+
relConfidence: n.relConfidence,
|
|
3781
|
+
sourceName: entity.name
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3159
3784
|
} catch {
|
|
3160
|
-
scored.push({ text, score: -1, index: i });
|
|
3161
3785
|
}
|
|
3162
3786
|
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3787
|
+
if (neighborEntityIds.length === 0) return;
|
|
3788
|
+
const neighborLinked = await getLinkedMemories(neighborEntityIds, client);
|
|
3789
|
+
for (const [entityId, entry] of neighborLinked) {
|
|
3790
|
+
const meta = neighborMeta.get(entityId);
|
|
3791
|
+
if (!meta) continue;
|
|
3792
|
+
const relWeight = relWeights[meta.relType] ?? DEFAULT_REL_WEIGHT;
|
|
3793
|
+
const depthDecay = 1 / (1 + meta.depth);
|
|
3794
|
+
const neighborBoost = ENTITY_BOOST_WEIGHT * meta.relConfidence * depthDecay * relWeight;
|
|
3795
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3796
|
+
const finalBoost = neighborBoost * attenuation;
|
|
3797
|
+
for (const memoryId of entry.memoryIds) {
|
|
3798
|
+
if (resultIds.has(memoryId)) {
|
|
3799
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + finalBoost);
|
|
3800
|
+
const contextPath = `${meta.sourceName} ${meta.relType} ${entityId}`;
|
|
3801
|
+
if (!graphContextMap.has(memoryId)) {
|
|
3802
|
+
graphContextMap.set(memoryId, contextPath);
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3165
3807
|
}
|
|
3166
|
-
async function
|
|
3167
|
-
if (
|
|
3168
|
-
|
|
3169
|
-
const
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3808
|
+
async function applyHyperedgeBoost(entities, client, boostMap, resultIds) {
|
|
3809
|
+
if (entities.length < 2) return;
|
|
3810
|
+
const entityIds = entities.map((e) => e.entityId);
|
|
3811
|
+
const placeholders = entityIds.map(() => "?").join(",");
|
|
3812
|
+
try {
|
|
3813
|
+
const result = await client.execute({
|
|
3814
|
+
sql: `SELECT hyperedge_id, entity_id FROM hyperedge_nodes
|
|
3815
|
+
WHERE entity_id IN (${placeholders})`,
|
|
3816
|
+
args: entityIds
|
|
3817
|
+
});
|
|
3818
|
+
const hyperedgeEntities = /* @__PURE__ */ new Map();
|
|
3819
|
+
for (const row of result.rows) {
|
|
3820
|
+
const hid = String(row.hyperedge_id);
|
|
3821
|
+
const eid = String(row.entity_id);
|
|
3822
|
+
const set = hyperedgeEntities.get(hid) ?? /* @__PURE__ */ new Set();
|
|
3823
|
+
set.add(eid);
|
|
3824
|
+
hyperedgeEntities.set(hid, set);
|
|
3825
|
+
}
|
|
3826
|
+
const sharedHyperedgeIds = [];
|
|
3827
|
+
for (const [hid, eids] of hyperedgeEntities) {
|
|
3828
|
+
if (eids.size >= 2) {
|
|
3829
|
+
sharedHyperedgeIds.push(hid);
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
if (sharedHyperedgeIds.length === 0) return;
|
|
3833
|
+
const hPlaceholders = sharedHyperedgeIds.map(() => "?").join(",");
|
|
3834
|
+
const allNodesResult = await client.execute({
|
|
3835
|
+
sql: `SELECT DISTINCT entity_id FROM hyperedge_nodes
|
|
3836
|
+
WHERE hyperedge_id IN (${hPlaceholders})`,
|
|
3837
|
+
args: sharedHyperedgeIds
|
|
3838
|
+
});
|
|
3839
|
+
const allEntityIds = allNodesResult.rows.map((r) => String(r.entity_id));
|
|
3840
|
+
if (allEntityIds.length === 0) return;
|
|
3841
|
+
const linked = await getLinkedMemories(allEntityIds, client);
|
|
3842
|
+
for (const [, entry] of linked) {
|
|
3843
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3844
|
+
const boost = ENTITY_BOOST_WEIGHT * attenuation;
|
|
3845
|
+
for (const memoryId of entry.memoryIds) {
|
|
3846
|
+
if (resultIds.has(memoryId)) {
|
|
3847
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + boost);
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
} catch {
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
async function applyEntityBoost(results, query, client) {
|
|
3855
|
+
const emptyResult = { results, graphContext: /* @__PURE__ */ new Map() };
|
|
3856
|
+
if (ENTITY_BOOST_WEIGHT === 0 || results.length === 0) {
|
|
3857
|
+
return emptyResult;
|
|
3858
|
+
}
|
|
3859
|
+
console.time("entity-boost");
|
|
3860
|
+
const entities = await matchEntities(query, client);
|
|
3861
|
+
if (entities.length === 0) {
|
|
3862
|
+
console.timeEnd("entity-boost");
|
|
3863
|
+
return emptyResult;
|
|
3864
|
+
}
|
|
3865
|
+
const boostMap = /* @__PURE__ */ new Map();
|
|
3866
|
+
const resultIds = new Set(results.map((r) => r.id));
|
|
3867
|
+
const graphContextMap = /* @__PURE__ */ new Map();
|
|
3868
|
+
const directLinked = await getLinkedMemories(
|
|
3869
|
+
entities.map((e) => e.entityId),
|
|
3870
|
+
client
|
|
3173
3871
|
);
|
|
3174
|
-
|
|
3872
|
+
for (const [, entry] of directLinked) {
|
|
3873
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3874
|
+
const boost = ENTITY_BOOST_WEIGHT * attenuation;
|
|
3875
|
+
for (const memoryId of entry.memoryIds) {
|
|
3876
|
+
if (resultIds.has(memoryId)) {
|
|
3877
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + boost);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3881
|
+
await traverseAndScore(entities, client, boostMap, resultIds, graphContextMap);
|
|
3882
|
+
await applyHyperedgeBoost(entities, client, boostMap, resultIds);
|
|
3883
|
+
if (boostMap.size === 0) {
|
|
3884
|
+
console.timeEnd("entity-boost");
|
|
3885
|
+
return emptyResult;
|
|
3886
|
+
}
|
|
3887
|
+
const scored = results.map((r, i) => ({
|
|
3888
|
+
record: r,
|
|
3889
|
+
baseScore: 1 / (1 + i * 0.1),
|
|
3890
|
+
entityBoost: boostMap.get(r.id) ?? 0
|
|
3891
|
+
}));
|
|
3892
|
+
scored.sort(
|
|
3893
|
+
(a, b) => b.baseScore + b.entityBoost - (a.baseScore + a.entityBoost)
|
|
3894
|
+
);
|
|
3895
|
+
console.timeEnd("entity-boost");
|
|
3896
|
+
return {
|
|
3897
|
+
results: scored.map((s) => s.record),
|
|
3898
|
+
graphContext: graphContextMap
|
|
3899
|
+
};
|
|
3175
3900
|
}
|
|
3176
|
-
var
|
|
3177
|
-
var
|
|
3178
|
-
"src/lib/
|
|
3901
|
+
var ENTITY_BOOST_WEIGHT, MIN_WORD_LENGTH, MAX_ENTITY_MATCHES, GRAPH_TRAVERSAL_MAX_HOPS, TOP_ENTITIES_TO_TRAVERSE, DEFAULT_RELATIONSHIP_WEIGHTS, DEFAULT_REL_WEIGHT;
|
|
3902
|
+
var init_entity_boost = __esm({
|
|
3903
|
+
"src/lib/entity-boost.ts"() {
|
|
3179
3904
|
"use strict";
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3905
|
+
ENTITY_BOOST_WEIGHT = parseFloat(
|
|
3906
|
+
process.env.ENTITY_BOOST_WEIGHT ?? "0.5"
|
|
3907
|
+
);
|
|
3908
|
+
MIN_WORD_LENGTH = 3;
|
|
3909
|
+
MAX_ENTITY_MATCHES = 20;
|
|
3910
|
+
GRAPH_TRAVERSAL_MAX_HOPS = Math.min(
|
|
3911
|
+
parseInt(process.env.GRAPH_TRAVERSAL_MAX_HOPS ?? "2", 10),
|
|
3912
|
+
3
|
|
3913
|
+
);
|
|
3914
|
+
TOP_ENTITIES_TO_TRAVERSE = 5;
|
|
3915
|
+
DEFAULT_RELATIONSHIP_WEIGHTS = {
|
|
3916
|
+
decided: 1,
|
|
3917
|
+
depends_on: 0.8,
|
|
3918
|
+
part_of: 0.7,
|
|
3919
|
+
related_to: 0.5,
|
|
3920
|
+
mentioned_in: 0.3
|
|
3921
|
+
};
|
|
3922
|
+
DEFAULT_REL_WEIGHT = 0.4;
|
|
3186
3923
|
}
|
|
3187
3924
|
});
|
|
3188
3925
|
|
|
@@ -3368,39 +4105,75 @@ var init_provider_table = __esm({
|
|
|
3368
4105
|
}
|
|
3369
4106
|
});
|
|
3370
4107
|
|
|
3371
|
-
// src/lib/
|
|
3372
|
-
|
|
4108
|
+
// src/lib/runtime-table.ts
|
|
4109
|
+
var RUNTIME_TABLE;
|
|
4110
|
+
var init_runtime_table = __esm({
|
|
4111
|
+
"src/lib/runtime-table.ts"() {
|
|
4112
|
+
"use strict";
|
|
4113
|
+
RUNTIME_TABLE = {
|
|
4114
|
+
codex: {
|
|
4115
|
+
binary: "codex",
|
|
4116
|
+
launchMode: "exec",
|
|
4117
|
+
autoApproveFlag: "--full-auto",
|
|
4118
|
+
inlineFlag: "--no-alt-screen",
|
|
4119
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
4120
|
+
defaultModel: "gpt-5.4"
|
|
4121
|
+
}
|
|
4122
|
+
};
|
|
4123
|
+
}
|
|
4124
|
+
});
|
|
4125
|
+
|
|
4126
|
+
// src/lib/agent-config.ts
|
|
4127
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
|
|
3373
4128
|
import path11 from "path";
|
|
4129
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
4130
|
+
var init_agent_config = __esm({
|
|
4131
|
+
"src/lib/agent-config.ts"() {
|
|
4132
|
+
"use strict";
|
|
4133
|
+
init_config();
|
|
4134
|
+
init_runtime_table();
|
|
4135
|
+
AGENT_CONFIG_PATH = path11.join(EXE_AI_DIR, "agent-config.json");
|
|
4136
|
+
DEFAULT_MODELS = {
|
|
4137
|
+
claude: "claude-opus-4",
|
|
4138
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
4139
|
+
opencode: "minimax-m2.7"
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4142
|
+
});
|
|
4143
|
+
|
|
4144
|
+
// src/lib/intercom-queue.ts
|
|
4145
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
4146
|
+
import path12 from "path";
|
|
3374
4147
|
import os5 from "os";
|
|
3375
4148
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
3376
4149
|
var init_intercom_queue = __esm({
|
|
3377
4150
|
"src/lib/intercom-queue.ts"() {
|
|
3378
4151
|
"use strict";
|
|
3379
|
-
QUEUE_PATH =
|
|
4152
|
+
QUEUE_PATH = path12.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
3380
4153
|
TTL_MS = 60 * 60 * 1e3;
|
|
3381
|
-
INTERCOM_LOG =
|
|
4154
|
+
INTERCOM_LOG = path12.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
3382
4155
|
}
|
|
3383
4156
|
});
|
|
3384
4157
|
|
|
3385
4158
|
// src/lib/license.ts
|
|
3386
|
-
import { readFileSync as
|
|
4159
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
|
|
3387
4160
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3388
|
-
import
|
|
4161
|
+
import path13 from "path";
|
|
3389
4162
|
import { jwtVerify, importSPKI } from "jose";
|
|
3390
4163
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
3391
4164
|
var init_license = __esm({
|
|
3392
4165
|
"src/lib/license.ts"() {
|
|
3393
4166
|
"use strict";
|
|
3394
4167
|
init_config();
|
|
3395
|
-
LICENSE_PATH =
|
|
3396
|
-
CACHE_PATH =
|
|
3397
|
-
DEVICE_ID_PATH =
|
|
4168
|
+
LICENSE_PATH = path13.join(EXE_AI_DIR, "license.key");
|
|
4169
|
+
CACHE_PATH = path13.join(EXE_AI_DIR, "license-cache.json");
|
|
4170
|
+
DEVICE_ID_PATH = path13.join(EXE_AI_DIR, "device-id");
|
|
3398
4171
|
}
|
|
3399
4172
|
});
|
|
3400
4173
|
|
|
3401
4174
|
// src/lib/plan-limits.ts
|
|
3402
|
-
import { readFileSync as
|
|
3403
|
-
import
|
|
4175
|
+
import { readFileSync as readFileSync9, existsSync as existsSync11 } from "fs";
|
|
4176
|
+
import path14 from "path";
|
|
3404
4177
|
var CACHE_PATH2;
|
|
3405
4178
|
var init_plan_limits = __esm({
|
|
3406
4179
|
"src/lib/plan-limits.ts"() {
|
|
@@ -3409,13 +4182,13 @@ var init_plan_limits = __esm({
|
|
|
3409
4182
|
init_employees();
|
|
3410
4183
|
init_license();
|
|
3411
4184
|
init_config();
|
|
3412
|
-
CACHE_PATH2 =
|
|
4185
|
+
CACHE_PATH2 = path14.join(EXE_AI_DIR, "license-cache.json");
|
|
3413
4186
|
}
|
|
3414
4187
|
});
|
|
3415
4188
|
|
|
3416
4189
|
// src/lib/tmux-routing.ts
|
|
3417
|
-
import { readFileSync as
|
|
3418
|
-
import
|
|
4190
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
4191
|
+
import path15 from "path";
|
|
3419
4192
|
import os6 from "os";
|
|
3420
4193
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3421
4194
|
function getMySession() {
|
|
@@ -3429,7 +4202,7 @@ function extractRootExe(name) {
|
|
|
3429
4202
|
}
|
|
3430
4203
|
function getParentExe(sessionKey) {
|
|
3431
4204
|
try {
|
|
3432
|
-
const data = JSON.parse(
|
|
4205
|
+
const data = JSON.parse(readFileSync10(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
3433
4206
|
return data.parentExe || null;
|
|
3434
4207
|
} catch {
|
|
3435
4208
|
return null;
|
|
@@ -3458,13 +4231,15 @@ var init_tmux_routing = __esm({
|
|
|
3458
4231
|
init_cc_agent_support();
|
|
3459
4232
|
init_mcp_prefix();
|
|
3460
4233
|
init_provider_table();
|
|
4234
|
+
init_agent_config();
|
|
4235
|
+
init_runtime_table();
|
|
3461
4236
|
init_intercom_queue();
|
|
3462
4237
|
init_plan_limits();
|
|
3463
4238
|
init_employees();
|
|
3464
|
-
SPAWN_LOCK_DIR =
|
|
3465
|
-
SESSION_CACHE =
|
|
3466
|
-
INTERCOM_LOG2 =
|
|
3467
|
-
DEBOUNCE_FILE =
|
|
4239
|
+
SPAWN_LOCK_DIR = path15.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
4240
|
+
SESSION_CACHE = path15.join(os6.homedir(), ".exe-os", "session-cache");
|
|
4241
|
+
INTERCOM_LOG2 = path15.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
4242
|
+
DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3468
4243
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3469
4244
|
}
|
|
3470
4245
|
});
|
|
@@ -3498,7 +4273,7 @@ init_config();
|
|
|
3498
4273
|
init_config();
|
|
3499
4274
|
init_store();
|
|
3500
4275
|
init_database();
|
|
3501
|
-
import
|
|
4276
|
+
import path16 from "path";
|
|
3502
4277
|
import { unlinkSync as unlinkSync4 } from "fs";
|
|
3503
4278
|
|
|
3504
4279
|
// src/lib/hybrid-search.ts
|
|
@@ -3545,8 +4320,14 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3545
4320
|
`
|
|
3546
4321
|
);
|
|
3547
4322
|
}
|
|
4323
|
+
let rerankerAvailable = false;
|
|
4324
|
+
try {
|
|
4325
|
+
const { isRerankerAvailable: isRerankerAvailable2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
4326
|
+
rerankerAvailable = isRerankerAvailable2();
|
|
4327
|
+
} catch {
|
|
4328
|
+
}
|
|
3548
4329
|
const broadFetchTopK = config.scalingRoadmap?.rerankerAutoTrigger?.fetchTopK ?? 150;
|
|
3549
|
-
const fetchLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : Math.max(limit * 3, 30);
|
|
4330
|
+
const fetchLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : rerankerAvailable ? Math.max(limit * 4, 60) : Math.max(limit * 3, 30);
|
|
3550
4331
|
const fetchOptions = { ...effectiveOptions, limit: fetchLimit, includeSource: false };
|
|
3551
4332
|
let queryVector = null;
|
|
3552
4333
|
try {
|
|
@@ -3556,7 +4337,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3556
4337
|
process.stderr.write("[hybrid-search] Embed daemon unavailable \u2014 FTS-only mode\n");
|
|
3557
4338
|
}
|
|
3558
4339
|
let grepPromise = Promise.resolve([]);
|
|
3559
|
-
if (config.fileGrepEnabled
|
|
4340
|
+
if (config.fileGrepEnabled === true) {
|
|
3560
4341
|
try {
|
|
3561
4342
|
const { getProjectName: getProjectName2 } = await Promise.resolve().then(() => (init_project_name(), project_name_exports));
|
|
3562
4343
|
const projectRoot = process.cwd();
|
|
@@ -3592,7 +4373,17 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3592
4373
|
if (lists.length === 0) return [];
|
|
3593
4374
|
if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
|
|
3594
4375
|
const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, 150) : limit;
|
|
3595
|
-
|
|
4376
|
+
let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
|
|
4377
|
+
let graphContextMap = /* @__PURE__ */ new Map();
|
|
4378
|
+
if (merged.length > 0) {
|
|
4379
|
+
try {
|
|
4380
|
+
const { applyEntityBoost: applyEntityBoost2 } = await Promise.resolve().then(() => (init_entity_boost(), entity_boost_exports));
|
|
4381
|
+
const boosted = await applyEntityBoost2(merged, effectiveQuery, getClient());
|
|
4382
|
+
merged = boosted.results;
|
|
4383
|
+
graphContextMap = boosted.graphContext;
|
|
4384
|
+
} catch {
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
3596
4387
|
const auto = config.scalingRoadmap?.rerankerAutoTrigger ?? {
|
|
3597
4388
|
enabled: config.rerankerEnabled ?? true,
|
|
3598
4389
|
broadQueryMinCardinality: 5e4,
|
|
@@ -3600,20 +4391,29 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3600
4391
|
returnTopK: 5
|
|
3601
4392
|
};
|
|
3602
4393
|
let rerankedAndBlended = null;
|
|
3603
|
-
if (effectiveIsBroad && auto.enabled) {
|
|
4394
|
+
if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
|
|
3604
4395
|
const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
|
|
3605
4396
|
if (cardinality2 > auto.broadQueryMinCardinality) {
|
|
3606
4397
|
try {
|
|
3607
|
-
|
|
3608
|
-
if (
|
|
3609
|
-
const
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
4398
|
+
let rerankedRecords;
|
|
4399
|
+
if (graphContextMap.size > 0) {
|
|
4400
|
+
const { rerankWithContext: rerankWithContext2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
4401
|
+
const candidates = merged.map((m) => ({
|
|
4402
|
+
text: m.raw_text,
|
|
4403
|
+
context: graphContextMap.get(m.id)
|
|
4404
|
+
}));
|
|
4405
|
+
const scored = await rerankWithContext2(effectiveQuery, candidates, auto.returnTopK);
|
|
4406
|
+
rerankedRecords = scored.map((s) => merged[s.index]);
|
|
4407
|
+
} else {
|
|
4408
|
+
const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
4409
|
+
rerankedRecords = await rerank2(effectiveQuery, merged, auto.returnTopK);
|
|
4410
|
+
}
|
|
4411
|
+
if (rerankedRecords.length > 0) {
|
|
4412
|
+
rerankedAndBlended = rrfMergeMulti(
|
|
4413
|
+
[rerankedRecords],
|
|
4414
|
+
auto.returnTopK,
|
|
4415
|
+
RRF_K
|
|
4416
|
+
);
|
|
3617
4417
|
}
|
|
3618
4418
|
} catch {
|
|
3619
4419
|
}
|
|
@@ -3633,7 +4433,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3633
4433
|
try {
|
|
3634
4434
|
const client = getClient();
|
|
3635
4435
|
void client.execute({
|
|
3636
|
-
sql: `UPDATE memories SET last_accessed =
|
|
4436
|
+
sql: `UPDATE memories SET last_accessed = ?, retrieval_count = COALESCE(retrieval_count, 0) + 1 WHERE id IN (${placeholders})`,
|
|
3637
4437
|
args: [now, ...ids]
|
|
3638
4438
|
}).catch(() => {
|
|
3639
4439
|
});
|
|
@@ -3803,7 +4603,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
3803
4603
|
source_type: row.source_type ?? null
|
|
3804
4604
|
}));
|
|
3805
4605
|
}
|
|
3806
|
-
async function recentRecords(agentId, options, limit) {
|
|
4606
|
+
async function recentRecords(agentId, options, limit, textFilter) {
|
|
3807
4607
|
const client = getClient();
|
|
3808
4608
|
const statusFilter = options?.includeArchived ? "" : `
|
|
3809
4609
|
AND COALESCE(status, 'active') = 'active'`;
|
|
@@ -3843,6 +4643,10 @@ async function recentRecords(agentId, options, limit) {
|
|
|
3843
4643
|
sql += ` AND memory_type = ?`;
|
|
3844
4644
|
args.push(options.memoryType);
|
|
3845
4645
|
}
|
|
4646
|
+
if (textFilter) {
|
|
4647
|
+
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
4648
|
+
args.push(textFilter);
|
|
4649
|
+
}
|
|
3846
4650
|
sql += ` ORDER BY timestamp DESC LIMIT ?`;
|
|
3847
4651
|
args.push(limit);
|
|
3848
4652
|
const result = await client.execute({ sql, args });
|
|
@@ -4083,8 +4887,8 @@ process.stdin.on("end", async () => {
|
|
|
4083
4887
|
const source = data.source ?? "startup";
|
|
4084
4888
|
if (source === "startup") {
|
|
4085
4889
|
try {
|
|
4086
|
-
const undefinedPath =
|
|
4087
|
-
process.env.EXE_OS_DIR ??
|
|
4890
|
+
const undefinedPath = path16.join(
|
|
4891
|
+
process.env.EXE_OS_DIR ?? path16.join(process.env.HOME ?? "", ".exe-os"),
|
|
4088
4892
|
"session-cache",
|
|
4089
4893
|
"active-agent-undefined.json"
|
|
4090
4894
|
);
|
|
@@ -4097,6 +4901,19 @@ process.stdin.on("end", async () => {
|
|
|
4097
4901
|
const search = config.hookSearchMode === "hybrid" ? hybridSearch : lightweightSearch;
|
|
4098
4902
|
const agent = getActiveAgent();
|
|
4099
4903
|
const agentId = agent.agentId;
|
|
4904
|
+
try {
|
|
4905
|
+
const sessionId = data.session_id;
|
|
4906
|
+
if (sessionId && agentId !== "default") {
|
|
4907
|
+
const client = getClient();
|
|
4908
|
+
const sessionName = process.env.EXE_SESSION_NAME ?? "";
|
|
4909
|
+
await client.execute({
|
|
4910
|
+
sql: `INSERT OR REPLACE INTO session_agent_map (session_uuid, agent_id, session_name, project_name, started_at)
|
|
4911
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
4912
|
+
args: [sessionId, agentId, sessionName, projectName, (/* @__PURE__ */ new Date()).toISOString()]
|
|
4913
|
+
});
|
|
4914
|
+
}
|
|
4915
|
+
} catch {
|
|
4916
|
+
}
|
|
4100
4917
|
let query;
|
|
4101
4918
|
let header;
|
|
4102
4919
|
if (source === "resume") {
|