@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
package/dist/bin/exe-search.js
CHANGED
|
@@ -371,6 +371,12 @@ function getClient() {
|
|
|
371
371
|
if (!_resilientClient) {
|
|
372
372
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
373
373
|
}
|
|
374
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
375
|
+
return _resilientClient;
|
|
376
|
+
}
|
|
377
|
+
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
378
|
+
return _daemonClient;
|
|
379
|
+
}
|
|
374
380
|
return _resilientClient;
|
|
375
381
|
}
|
|
376
382
|
function getRawClient() {
|
|
@@ -859,6 +865,12 @@ async function ensureSchema() {
|
|
|
859
865
|
} catch {
|
|
860
866
|
}
|
|
861
867
|
}
|
|
868
|
+
try {
|
|
869
|
+
await client.execute(
|
|
870
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash, agent_id)`
|
|
871
|
+
);
|
|
872
|
+
} catch {
|
|
873
|
+
}
|
|
862
874
|
await client.executeMultiple(`
|
|
863
875
|
CREATE TABLE IF NOT EXISTS entities (
|
|
864
876
|
id TEXT PRIMARY KEY,
|
|
@@ -911,7 +923,30 @@ async function ensureSchema() {
|
|
|
911
923
|
entity_id TEXT NOT NULL,
|
|
912
924
|
PRIMARY KEY (hyperedge_id, entity_id)
|
|
913
925
|
);
|
|
926
|
+
|
|
927
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
928
|
+
name,
|
|
929
|
+
content=entities,
|
|
930
|
+
content_rowid=rowid
|
|
931
|
+
);
|
|
932
|
+
|
|
933
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ai AFTER INSERT ON entities BEGIN
|
|
934
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
935
|
+
END;
|
|
936
|
+
|
|
937
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_ad AFTER DELETE ON entities BEGIN
|
|
938
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
939
|
+
END;
|
|
940
|
+
|
|
941
|
+
CREATE TRIGGER IF NOT EXISTS entities_fts_au AFTER UPDATE ON entities BEGIN
|
|
942
|
+
INSERT INTO entities_fts(entities_fts, rowid, name) VALUES('delete', old.rowid, old.name);
|
|
943
|
+
INSERT INTO entities_fts(rowid, name) VALUES (new.rowid, new.name);
|
|
944
|
+
END;
|
|
914
945
|
`);
|
|
946
|
+
try {
|
|
947
|
+
await client.execute("INSERT INTO entities_fts(entities_fts) VALUES('rebuild')");
|
|
948
|
+
} catch {
|
|
949
|
+
}
|
|
915
950
|
await client.executeMultiple(`
|
|
916
951
|
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
917
952
|
alias TEXT NOT NULL PRIMARY KEY,
|
|
@@ -1092,6 +1127,33 @@ async function ensureSchema() {
|
|
|
1092
1127
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
1093
1128
|
ON conversations(channel_id);
|
|
1094
1129
|
`);
|
|
1130
|
+
await client.executeMultiple(`
|
|
1131
|
+
CREATE TABLE IF NOT EXISTS session_agent_map (
|
|
1132
|
+
session_uuid TEXT PRIMARY KEY,
|
|
1133
|
+
agent_id TEXT NOT NULL,
|
|
1134
|
+
session_name TEXT,
|
|
1135
|
+
task_id TEXT,
|
|
1136
|
+
project_name TEXT,
|
|
1137
|
+
started_at TEXT NOT NULL
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
1141
|
+
ON session_agent_map(agent_id);
|
|
1142
|
+
`);
|
|
1143
|
+
try {
|
|
1144
|
+
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
1145
|
+
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
1146
|
+
await client.execute({
|
|
1147
|
+
sql: `INSERT OR IGNORE INTO session_agent_map (session_uuid, agent_id, session_name, started_at)
|
|
1148
|
+
SELECT session_id, agent_id, '', MIN(timestamp)
|
|
1149
|
+
FROM memories
|
|
1150
|
+
WHERE session_id IS NOT NULL AND session_id != '' AND agent_id IS NOT NULL AND agent_id != ''
|
|
1151
|
+
GROUP BY session_id, agent_id`,
|
|
1152
|
+
args: []
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
} catch {
|
|
1156
|
+
}
|
|
1095
1157
|
try {
|
|
1096
1158
|
await client.execute({
|
|
1097
1159
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -1225,15 +1287,41 @@ async function ensureSchema() {
|
|
|
1225
1287
|
});
|
|
1226
1288
|
} catch {
|
|
1227
1289
|
}
|
|
1290
|
+
for (const col of [
|
|
1291
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
1292
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
1293
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
1294
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
1295
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
1296
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
1297
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
1298
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
1299
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
1300
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
1301
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
1302
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
1303
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
1304
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
1305
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1306
|
+
]) {
|
|
1307
|
+
try {
|
|
1308
|
+
await client.execute(col);
|
|
1309
|
+
} catch {
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1228
1312
|
}
|
|
1229
1313
|
async function disposeDatabase() {
|
|
1314
|
+
if (_daemonClient) {
|
|
1315
|
+
_daemonClient.close();
|
|
1316
|
+
_daemonClient = null;
|
|
1317
|
+
}
|
|
1230
1318
|
if (_client) {
|
|
1231
1319
|
_client.close();
|
|
1232
1320
|
_client = null;
|
|
1233
1321
|
_resilientClient = null;
|
|
1234
1322
|
}
|
|
1235
1323
|
}
|
|
1236
|
-
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1324
|
+
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1237
1325
|
var init_database = __esm({
|
|
1238
1326
|
"src/lib/database.ts"() {
|
|
1239
1327
|
"use strict";
|
|
@@ -1241,6 +1329,7 @@ var init_database = __esm({
|
|
|
1241
1329
|
init_employees();
|
|
1242
1330
|
_client = null;
|
|
1243
1331
|
_resilientClient = null;
|
|
1332
|
+
_daemonClient = null;
|
|
1244
1333
|
initTurso = initDatabase;
|
|
1245
1334
|
disposeTurso = disposeDatabase;
|
|
1246
1335
|
}
|
|
@@ -1277,12 +1366,20 @@ async function getMasterKey() {
|
|
|
1277
1366
|
}
|
|
1278
1367
|
const keyPath = getKeyPath();
|
|
1279
1368
|
if (!existsSync3(keyPath)) {
|
|
1369
|
+
process.stderr.write(
|
|
1370
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
1371
|
+
`
|
|
1372
|
+
);
|
|
1280
1373
|
return null;
|
|
1281
1374
|
}
|
|
1282
1375
|
try {
|
|
1283
1376
|
const content = await readFile3(keyPath, "utf-8");
|
|
1284
1377
|
return Buffer.from(content.trim(), "base64");
|
|
1285
|
-
} catch {
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
process.stderr.write(
|
|
1380
|
+
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
1381
|
+
`
|
|
1382
|
+
);
|
|
1286
1383
|
return null;
|
|
1287
1384
|
}
|
|
1288
1385
|
}
|
|
@@ -1793,6 +1890,7 @@ __export(store_exports, {
|
|
|
1793
1890
|
vectorToBlob: () => vectorToBlob,
|
|
1794
1891
|
writeMemory: () => writeMemory
|
|
1795
1892
|
});
|
|
1893
|
+
import { createHash } from "crypto";
|
|
1796
1894
|
function isBusyError2(err) {
|
|
1797
1895
|
if (err instanceof Error) {
|
|
1798
1896
|
const msg = err.message.toLowerCase();
|
|
@@ -1866,12 +1964,52 @@ function classifyTier(record) {
|
|
|
1866
1964
|
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1867
1965
|
return 3;
|
|
1868
1966
|
}
|
|
1967
|
+
function inferFilePaths(record) {
|
|
1968
|
+
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
1969
|
+
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
1970
|
+
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
1971
|
+
return match ? JSON.stringify([match[1]]) : null;
|
|
1972
|
+
}
|
|
1973
|
+
function inferCommitHash(record) {
|
|
1974
|
+
if (record.tool_name !== "Bash") return null;
|
|
1975
|
+
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
1976
|
+
return match ? match[1] : null;
|
|
1977
|
+
}
|
|
1978
|
+
function inferLanguageType(record) {
|
|
1979
|
+
const text = record.raw_text;
|
|
1980
|
+
if (!text || text.length < 10) return null;
|
|
1981
|
+
const trimmed = text.trimStart();
|
|
1982
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
1983
|
+
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
1984
|
+
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
1985
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
1986
|
+
return "mixed";
|
|
1987
|
+
}
|
|
1988
|
+
function inferDomain(record) {
|
|
1989
|
+
const proj = (record.project_name ?? "").toLowerCase();
|
|
1990
|
+
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
1991
|
+
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
1992
|
+
return null;
|
|
1993
|
+
}
|
|
1869
1994
|
async function writeMemory(record) {
|
|
1870
1995
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1871
1996
|
throw new Error(
|
|
1872
1997
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
1873
1998
|
);
|
|
1874
1999
|
}
|
|
2000
|
+
const contentHash = createHash("md5").update(record.raw_text).digest("hex");
|
|
2001
|
+
if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
try {
|
|
2005
|
+
const client = getClient();
|
|
2006
|
+
const existing = await client.execute({
|
|
2007
|
+
sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
|
|
2008
|
+
args: [contentHash, record.agent_id]
|
|
2009
|
+
});
|
|
2010
|
+
if (existing.rows.length > 0) return;
|
|
2011
|
+
} catch {
|
|
2012
|
+
}
|
|
1875
2013
|
const dbRow = {
|
|
1876
2014
|
id: record.id,
|
|
1877
2015
|
agent_id: record.agent_id,
|
|
@@ -1901,7 +2039,23 @@ async function writeMemory(record) {
|
|
|
1901
2039
|
supersedes_id: record.supersedes_id ?? null,
|
|
1902
2040
|
draft: record.draft ? 1 : 0,
|
|
1903
2041
|
memory_type: record.memory_type ?? "raw",
|
|
1904
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
2042
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
2043
|
+
content_hash: contentHash,
|
|
2044
|
+
intent: record.intent ?? null,
|
|
2045
|
+
outcome: record.outcome ?? null,
|
|
2046
|
+
domain: record.domain ?? inferDomain(record),
|
|
2047
|
+
referenced_entities: record.referenced_entities ?? null,
|
|
2048
|
+
retrieval_count: record.retrieval_count ?? 0,
|
|
2049
|
+
chain_position: record.chain_position ?? null,
|
|
2050
|
+
review_status: record.review_status ?? null,
|
|
2051
|
+
context_window_pct: record.context_window_pct ?? null,
|
|
2052
|
+
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
2053
|
+
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
2054
|
+
duration_ms: record.duration_ms ?? null,
|
|
2055
|
+
token_cost: record.token_cost ?? null,
|
|
2056
|
+
audience: record.audience ?? null,
|
|
2057
|
+
language_type: record.language_type ?? inferLanguageType(record),
|
|
2058
|
+
parent_memory_id: record.parent_memory_id ?? null
|
|
1905
2059
|
};
|
|
1906
2060
|
_pendingRecords.push(dbRow);
|
|
1907
2061
|
orgBus.emit({
|
|
@@ -1959,80 +2113,85 @@ async function flushBatch() {
|
|
|
1959
2113
|
const draft = row.draft ? 1 : 0;
|
|
1960
2114
|
const memoryType = row.memory_type ?? "raw";
|
|
1961
2115
|
const trajectory = row.trajectory ?? null;
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
2116
|
+
const contentHash = row.content_hash ?? null;
|
|
2117
|
+
const intent = row.intent ?? null;
|
|
2118
|
+
const outcome = row.outcome ?? null;
|
|
2119
|
+
const domain = row.domain ?? null;
|
|
2120
|
+
const referencedEntities = row.referenced_entities ?? null;
|
|
2121
|
+
const retrievalCount = row.retrieval_count ?? 0;
|
|
2122
|
+
const chainPosition = row.chain_position ?? null;
|
|
2123
|
+
const reviewStatus = row.review_status ?? null;
|
|
2124
|
+
const contextWindowPct = row.context_window_pct ?? null;
|
|
2125
|
+
const filePaths = row.file_paths ?? null;
|
|
2126
|
+
const commitHash = row.commit_hash ?? null;
|
|
2127
|
+
const durationMs = row.duration_ms ?? null;
|
|
2128
|
+
const tokenCost = row.token_cost ?? null;
|
|
2129
|
+
const audience = row.audience ?? null;
|
|
2130
|
+
const languageType = row.language_type ?? null;
|
|
2131
|
+
const parentMemoryId = row.parent_memory_id ?? null;
|
|
2132
|
+
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
1972
2133
|
tool_name, project_name,
|
|
1973
2134
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1974
2135
|
confidence, last_accessed,
|
|
1975
2136
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1976
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
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
|
-
trajectory
|
|
2035
|
-
]
|
|
2137
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
2138
|
+
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
2139
|
+
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
2140
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
2141
|
+
const metaArgs = [
|
|
2142
|
+
intent,
|
|
2143
|
+
outcome,
|
|
2144
|
+
domain,
|
|
2145
|
+
referencedEntities,
|
|
2146
|
+
retrievalCount,
|
|
2147
|
+
chainPosition,
|
|
2148
|
+
reviewStatus,
|
|
2149
|
+
contextWindowPct,
|
|
2150
|
+
filePaths,
|
|
2151
|
+
commitHash,
|
|
2152
|
+
durationMs,
|
|
2153
|
+
tokenCost,
|
|
2154
|
+
audience,
|
|
2155
|
+
languageType,
|
|
2156
|
+
parentMemoryId
|
|
2157
|
+
];
|
|
2158
|
+
const baseArgs = [
|
|
2159
|
+
row.id,
|
|
2160
|
+
row.agent_id,
|
|
2161
|
+
row.agent_role,
|
|
2162
|
+
row.session_id,
|
|
2163
|
+
row.timestamp,
|
|
2164
|
+
row.tool_name,
|
|
2165
|
+
row.project_name,
|
|
2166
|
+
row.has_error,
|
|
2167
|
+
row.raw_text
|
|
2168
|
+
];
|
|
2169
|
+
const sharedArgs = [
|
|
2170
|
+
row.version,
|
|
2171
|
+
taskId,
|
|
2172
|
+
importance,
|
|
2173
|
+
status,
|
|
2174
|
+
confidence,
|
|
2175
|
+
lastAccessed,
|
|
2176
|
+
workspaceId,
|
|
2177
|
+
documentId,
|
|
2178
|
+
userId,
|
|
2179
|
+
charOffset,
|
|
2180
|
+
pageNumber,
|
|
2181
|
+
sourcePath,
|
|
2182
|
+
sourceType,
|
|
2183
|
+
tier,
|
|
2184
|
+
supersedesId,
|
|
2185
|
+
draft,
|
|
2186
|
+
memoryType,
|
|
2187
|
+
trajectory,
|
|
2188
|
+
contentHash
|
|
2189
|
+
];
|
|
2190
|
+
return {
|
|
2191
|
+
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
2192
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
2193
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2194
|
+
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
2036
2195
|
};
|
|
2037
2196
|
};
|
|
2038
2197
|
const globalClient = getClient();
|
|
@@ -2371,12 +2530,141 @@ var init_self_query_router = __esm({
|
|
|
2371
2530
|
}
|
|
2372
2531
|
});
|
|
2373
2532
|
|
|
2533
|
+
// src/lib/reranker.ts
|
|
2534
|
+
var reranker_exports = {};
|
|
2535
|
+
__export(reranker_exports, {
|
|
2536
|
+
disposeReranker: () => disposeReranker,
|
|
2537
|
+
getRerankerModelPath: () => getRerankerModelPath,
|
|
2538
|
+
isRerankerAvailable: () => isRerankerAvailable,
|
|
2539
|
+
rerank: () => rerank,
|
|
2540
|
+
rerankWithContext: () => rerankWithContext,
|
|
2541
|
+
rerankWithScores: () => rerankWithScores
|
|
2542
|
+
});
|
|
2543
|
+
import path5 from "path";
|
|
2544
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2545
|
+
function resetIdleTimer() {
|
|
2546
|
+
if (_idleTimer) clearTimeout(_idleTimer);
|
|
2547
|
+
_idleTimer = setTimeout(() => {
|
|
2548
|
+
void disposeReranker();
|
|
2549
|
+
}, IDLE_TIMEOUT_MS);
|
|
2550
|
+
if (_idleTimer && typeof _idleTimer === "object" && "unref" in _idleTimer) {
|
|
2551
|
+
_idleTimer.unref();
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
function isRerankerAvailable() {
|
|
2555
|
+
return existsSync5(path5.join(MODELS_DIR, RERANKER_MODEL_FILE));
|
|
2556
|
+
}
|
|
2557
|
+
function getRerankerModelPath() {
|
|
2558
|
+
return path5.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
2559
|
+
}
|
|
2560
|
+
async function ensureLoaded() {
|
|
2561
|
+
if (_rerankerContext) {
|
|
2562
|
+
resetIdleTimer();
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
const modelPath = path5.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
2566
|
+
if (!existsSync5(modelPath)) {
|
|
2567
|
+
throw new Error(
|
|
2568
|
+
`Reranker model not found at ${modelPath}. Run /exe-setup to download it.`
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
process.stderr.write("[reranker] Loading Jina Reranker v3...\n");
|
|
2572
|
+
const { getLlama } = await import("node-llama-cpp");
|
|
2573
|
+
const llama = await getLlama();
|
|
2574
|
+
_rerankerModel = await llama.loadModel({ modelPath });
|
|
2575
|
+
_rerankerContext = await _rerankerModel.createEmbeddingContext();
|
|
2576
|
+
process.stderr.write("[reranker] Jina Reranker v3 loaded.\n");
|
|
2577
|
+
resetIdleTimer();
|
|
2578
|
+
}
|
|
2579
|
+
async function disposeReranker() {
|
|
2580
|
+
if (_idleTimer) {
|
|
2581
|
+
clearTimeout(_idleTimer);
|
|
2582
|
+
_idleTimer = null;
|
|
2583
|
+
}
|
|
2584
|
+
if (_rerankerContext) {
|
|
2585
|
+
try {
|
|
2586
|
+
await _rerankerContext.dispose();
|
|
2587
|
+
} catch {
|
|
2588
|
+
}
|
|
2589
|
+
_rerankerContext = null;
|
|
2590
|
+
}
|
|
2591
|
+
if (_rerankerModel) {
|
|
2592
|
+
try {
|
|
2593
|
+
await _rerankerModel.dispose();
|
|
2594
|
+
} catch {
|
|
2595
|
+
}
|
|
2596
|
+
_rerankerModel = null;
|
|
2597
|
+
}
|
|
2598
|
+
process.stderr.write("[reranker] Unloaded (idle timeout).\n");
|
|
2599
|
+
}
|
|
2600
|
+
async function rerankWithScores(query, texts, topK) {
|
|
2601
|
+
if (texts.length === 0) return [];
|
|
2602
|
+
await ensureLoaded();
|
|
2603
|
+
const ctx = _rerankerContext;
|
|
2604
|
+
const scored = [];
|
|
2605
|
+
for (let i = 0; i < texts.length; i++) {
|
|
2606
|
+
const text = texts[i] ?? "";
|
|
2607
|
+
try {
|
|
2608
|
+
const input = `query: ${query} document: ${text.slice(0, 512)}`;
|
|
2609
|
+
const embedding = await ctx.getEmbeddingFor(input);
|
|
2610
|
+
const score = embedding.vector[0] ?? 0;
|
|
2611
|
+
scored.push({ text, score, index: i });
|
|
2612
|
+
} catch {
|
|
2613
|
+
scored.push({ text, score: -1, index: i });
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
scored.sort((a, b) => b.score - a.score);
|
|
2617
|
+
return typeof topK === "number" ? scored.slice(0, topK) : scored;
|
|
2618
|
+
}
|
|
2619
|
+
async function rerank(query, candidates, topK = 5) {
|
|
2620
|
+
if (candidates.length === 0) return [];
|
|
2621
|
+
if (candidates.length <= topK) return candidates;
|
|
2622
|
+
const scored = await rerankWithScores(
|
|
2623
|
+
query,
|
|
2624
|
+
candidates.map((c) => c.raw_text),
|
|
2625
|
+
topK
|
|
2626
|
+
);
|
|
2627
|
+
return scored.map((s) => candidates[s.index]);
|
|
2628
|
+
}
|
|
2629
|
+
async function rerankWithContext(query, candidates, topK) {
|
|
2630
|
+
if (candidates.length === 0) return [];
|
|
2631
|
+
await ensureLoaded();
|
|
2632
|
+
const ctx = _rerankerContext;
|
|
2633
|
+
const scored = [];
|
|
2634
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
2635
|
+
const candidate = candidates[i];
|
|
2636
|
+
try {
|
|
2637
|
+
const docText = candidate.context ? `[${candidate.context}] ${candidate.text.slice(0, 460)}` : candidate.text.slice(0, 512);
|
|
2638
|
+
const input = `query: ${query} document: ${docText}`;
|
|
2639
|
+
const embedding = await ctx.getEmbeddingFor(input);
|
|
2640
|
+
const score = embedding.vector[0] ?? 0;
|
|
2641
|
+
scored.push({ text: candidate.text, score, index: i });
|
|
2642
|
+
} catch {
|
|
2643
|
+
scored.push({ text: candidate.text, score: -1, index: i });
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
scored.sort((a, b) => b.score - a.score);
|
|
2647
|
+
return typeof topK === "number" ? scored.slice(0, topK) : scored;
|
|
2648
|
+
}
|
|
2649
|
+
var RERANKER_MODEL_FILE, IDLE_TIMEOUT_MS, _rerankerContext, _rerankerModel, _idleTimer;
|
|
2650
|
+
var init_reranker = __esm({
|
|
2651
|
+
"src/lib/reranker.ts"() {
|
|
2652
|
+
"use strict";
|
|
2653
|
+
init_config();
|
|
2654
|
+
RERANKER_MODEL_FILE = "jina-reranker-v3-q4_k_m.gguf";
|
|
2655
|
+
IDLE_TIMEOUT_MS = 6e4;
|
|
2656
|
+
_rerankerContext = null;
|
|
2657
|
+
_rerankerModel = null;
|
|
2658
|
+
_idleTimer = null;
|
|
2659
|
+
}
|
|
2660
|
+
});
|
|
2661
|
+
|
|
2374
2662
|
// src/lib/exe-daemon-client.ts
|
|
2375
2663
|
import net from "net";
|
|
2376
2664
|
import { spawn } from "child_process";
|
|
2377
2665
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2378
|
-
import { existsSync as
|
|
2379
|
-
import
|
|
2666
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
2667
|
+
import path6 from "path";
|
|
2380
2668
|
import { fileURLToPath } from "url";
|
|
2381
2669
|
function handleData(chunk) {
|
|
2382
2670
|
_buffer += chunk.toString();
|
|
@@ -2391,10 +2679,12 @@ function handleData(chunk) {
|
|
|
2391
2679
|
if (!line) continue;
|
|
2392
2680
|
try {
|
|
2393
2681
|
const response = JSON.parse(line);
|
|
2394
|
-
const
|
|
2682
|
+
const id = response.id;
|
|
2683
|
+
if (!id) continue;
|
|
2684
|
+
const entry = _pending.get(id);
|
|
2395
2685
|
if (entry) {
|
|
2396
2686
|
clearTimeout(entry.timer);
|
|
2397
|
-
_pending.delete(
|
|
2687
|
+
_pending.delete(id);
|
|
2398
2688
|
entry.resolve(response);
|
|
2399
2689
|
}
|
|
2400
2690
|
} catch {
|
|
@@ -2402,7 +2692,7 @@ function handleData(chunk) {
|
|
|
2402
2692
|
}
|
|
2403
2693
|
}
|
|
2404
2694
|
function cleanupStaleFiles() {
|
|
2405
|
-
if (
|
|
2695
|
+
if (existsSync6(PID_PATH)) {
|
|
2406
2696
|
try {
|
|
2407
2697
|
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
2408
2698
|
if (pid > 0) {
|
|
@@ -2425,11 +2715,11 @@ function cleanupStaleFiles() {
|
|
|
2425
2715
|
}
|
|
2426
2716
|
}
|
|
2427
2717
|
function findPackageRoot() {
|
|
2428
|
-
let dir =
|
|
2429
|
-
const { root } =
|
|
2718
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
2719
|
+
const { root } = path6.parse(dir);
|
|
2430
2720
|
while (dir !== root) {
|
|
2431
|
-
if (
|
|
2432
|
-
dir =
|
|
2721
|
+
if (existsSync6(path6.join(dir, "package.json"))) return dir;
|
|
2722
|
+
dir = path6.dirname(dir);
|
|
2433
2723
|
}
|
|
2434
2724
|
return null;
|
|
2435
2725
|
}
|
|
@@ -2439,8 +2729,8 @@ function spawnDaemon() {
|
|
|
2439
2729
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
2440
2730
|
return;
|
|
2441
2731
|
}
|
|
2442
|
-
const daemonPath =
|
|
2443
|
-
if (!
|
|
2732
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
2733
|
+
if (!existsSync6(daemonPath)) {
|
|
2444
2734
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
2445
2735
|
`);
|
|
2446
2736
|
return;
|
|
@@ -2448,7 +2738,7 @@ function spawnDaemon() {
|
|
|
2448
2738
|
const resolvedPath = daemonPath;
|
|
2449
2739
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
2450
2740
|
`);
|
|
2451
|
-
const logPath =
|
|
2741
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
2452
2742
|
let stderrFd = "ignore";
|
|
2453
2743
|
try {
|
|
2454
2744
|
stderrFd = openSync(logPath, "a");
|
|
@@ -2565,6 +2855,9 @@ async function connectEmbedDaemon() {
|
|
|
2565
2855
|
return false;
|
|
2566
2856
|
}
|
|
2567
2857
|
function sendRequest(texts, priority) {
|
|
2858
|
+
return sendDaemonRequest({ texts, priority });
|
|
2859
|
+
}
|
|
2860
|
+
function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
2568
2861
|
return new Promise((resolve) => {
|
|
2569
2862
|
if (!_socket || !_connected) {
|
|
2570
2863
|
resolve({ error: "Not connected" });
|
|
@@ -2574,10 +2867,10 @@ function sendRequest(texts, priority) {
|
|
|
2574
2867
|
const timer = setTimeout(() => {
|
|
2575
2868
|
_pending.delete(id);
|
|
2576
2869
|
resolve({ error: "Request timeout" });
|
|
2577
|
-
},
|
|
2870
|
+
}, timeoutMs);
|
|
2578
2871
|
_pending.set(id, { resolve, timer });
|
|
2579
2872
|
try {
|
|
2580
|
-
_socket.write(JSON.stringify({ id,
|
|
2873
|
+
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
2581
2874
|
} catch {
|
|
2582
2875
|
clearTimeout(timer);
|
|
2583
2876
|
_pending.delete(id);
|
|
@@ -2587,34 +2880,15 @@ function sendRequest(texts, priority) {
|
|
|
2587
2880
|
}
|
|
2588
2881
|
async function pingDaemon() {
|
|
2589
2882
|
if (!_socket || !_connected) return null;
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
}, 5e3);
|
|
2596
|
-
_pending.set(id, {
|
|
2597
|
-
resolve: (data) => {
|
|
2598
|
-
if (data.health) {
|
|
2599
|
-
resolve(data.health);
|
|
2600
|
-
} else {
|
|
2601
|
-
resolve(null);
|
|
2602
|
-
}
|
|
2603
|
-
},
|
|
2604
|
-
timer
|
|
2605
|
-
});
|
|
2606
|
-
try {
|
|
2607
|
-
_socket.write(JSON.stringify({ id, type: "health" }) + "\n");
|
|
2608
|
-
} catch {
|
|
2609
|
-
clearTimeout(timer);
|
|
2610
|
-
_pending.delete(id);
|
|
2611
|
-
resolve(null);
|
|
2612
|
-
}
|
|
2613
|
-
});
|
|
2883
|
+
const response = await sendDaemonRequest({ type: "health" }, 5e3);
|
|
2884
|
+
if (response.health) {
|
|
2885
|
+
return response.health;
|
|
2886
|
+
}
|
|
2887
|
+
return null;
|
|
2614
2888
|
}
|
|
2615
2889
|
function killAndRespawnDaemon() {
|
|
2616
2890
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
2617
|
-
if (
|
|
2891
|
+
if (existsSync6(PID_PATH)) {
|
|
2618
2892
|
try {
|
|
2619
2893
|
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
2620
2894
|
if (pid > 0) {
|
|
@@ -2700,9 +2974,9 @@ var init_exe_daemon_client = __esm({
|
|
|
2700
2974
|
"src/lib/exe-daemon-client.ts"() {
|
|
2701
2975
|
"use strict";
|
|
2702
2976
|
init_config();
|
|
2703
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
2704
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
2705
|
-
SPAWN_LOCK_PATH =
|
|
2977
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
2978
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
2979
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
2706
2980
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
2707
2981
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
2708
2982
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -2791,7 +3065,7 @@ __export(project_name_exports, {
|
|
|
2791
3065
|
getProjectName: () => getProjectName
|
|
2792
3066
|
});
|
|
2793
3067
|
import { execSync as execSync2 } from "child_process";
|
|
2794
|
-
import
|
|
3068
|
+
import path7 from "path";
|
|
2795
3069
|
function getProjectName(cwd) {
|
|
2796
3070
|
const dir = cwd ?? process.cwd();
|
|
2797
3071
|
if (_cached && _cachedCwd === dir) return _cached;
|
|
@@ -2804,7 +3078,7 @@ function getProjectName(cwd) {
|
|
|
2804
3078
|
timeout: 2e3,
|
|
2805
3079
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2806
3080
|
}).trim();
|
|
2807
|
-
repoRoot =
|
|
3081
|
+
repoRoot = path7.dirname(gitCommonDir);
|
|
2808
3082
|
} catch {
|
|
2809
3083
|
repoRoot = execSync2("git rev-parse --show-toplevel", {
|
|
2810
3084
|
cwd: dir,
|
|
@@ -2813,11 +3087,11 @@ function getProjectName(cwd) {
|
|
|
2813
3087
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2814
3088
|
}).trim();
|
|
2815
3089
|
}
|
|
2816
|
-
_cached =
|
|
3090
|
+
_cached = path7.basename(repoRoot);
|
|
2817
3091
|
_cachedCwd = dir;
|
|
2818
3092
|
return _cached;
|
|
2819
3093
|
} catch {
|
|
2820
|
-
_cached =
|
|
3094
|
+
_cached = path7.basename(dir);
|
|
2821
3095
|
_cachedCwd = dir;
|
|
2822
3096
|
return _cached;
|
|
2823
3097
|
}
|
|
@@ -2841,8 +3115,8 @@ __export(file_grep_exports, {
|
|
|
2841
3115
|
grepProjectFiles: () => grepProjectFiles
|
|
2842
3116
|
});
|
|
2843
3117
|
import { execSync as execSync3 } from "child_process";
|
|
2844
|
-
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, existsSync as
|
|
2845
|
-
import
|
|
3118
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync7 } from "fs";
|
|
3119
|
+
import path8 from "path";
|
|
2846
3120
|
import crypto from "crypto";
|
|
2847
3121
|
function hasRipgrep() {
|
|
2848
3122
|
if (_hasRg === null) {
|
|
@@ -2882,7 +3156,7 @@ async function grepProjectFiles(query, projectRoot, options) {
|
|
|
2882
3156
|
session_id: "file-grep",
|
|
2883
3157
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2884
3158
|
tool_name: "file_grep",
|
|
2885
|
-
project_name:
|
|
3159
|
+
project_name: path8.basename(projectRoot),
|
|
2886
3160
|
has_error: false,
|
|
2887
3161
|
raw_text: `${prefix} ${buildSnippet(hit, projectRoot)}`,
|
|
2888
3162
|
vector: null,
|
|
@@ -2956,7 +3230,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
2956
3230
|
const files = collectFiles(projectRoot, patterns ?? DEFAULT_PATTERNS);
|
|
2957
3231
|
const hits = [];
|
|
2958
3232
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
2959
|
-
const absPath =
|
|
3233
|
+
const absPath = path8.join(projectRoot, filePath);
|
|
2960
3234
|
try {
|
|
2961
3235
|
const stat = statSync2(absPath);
|
|
2962
3236
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
@@ -2983,15 +3257,15 @@ function collectFiles(root, patterns) {
|
|
|
2983
3257
|
const files = [];
|
|
2984
3258
|
function walk(dir, relative) {
|
|
2985
3259
|
if (files.length >= MAX_FILES) return;
|
|
2986
|
-
const basename =
|
|
3260
|
+
const basename = path8.basename(dir);
|
|
2987
3261
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
2988
3262
|
try {
|
|
2989
3263
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
2990
3264
|
for (const entry of entries) {
|
|
2991
3265
|
if (files.length >= MAX_FILES) return;
|
|
2992
|
-
const rel =
|
|
3266
|
+
const rel = path8.join(relative, entry.name);
|
|
2993
3267
|
if (entry.isDirectory()) {
|
|
2994
|
-
walk(
|
|
3268
|
+
walk(path8.join(dir, entry.name), rel);
|
|
2995
3269
|
} else if (entry.isFile()) {
|
|
2996
3270
|
for (const pat of patterns) {
|
|
2997
3271
|
if (matchGlob(rel, pat)) {
|
|
@@ -3023,7 +3297,7 @@ function matchGlob(filePath, pattern) {
|
|
|
3023
3297
|
if (slashIdx !== -1) {
|
|
3024
3298
|
const dir = pattern.slice(0, slashIdx);
|
|
3025
3299
|
const ext2 = pattern.slice(slashIdx + 1).replace("*", "");
|
|
3026
|
-
const fileDir =
|
|
3300
|
+
const fileDir = path8.dirname(filePath);
|
|
3027
3301
|
return fileDir === dir && filePath.endsWith(ext2);
|
|
3028
3302
|
}
|
|
3029
3303
|
const ext = pattern.replace("*", "");
|
|
@@ -3031,8 +3305,8 @@ function matchGlob(filePath, pattern) {
|
|
|
3031
3305
|
}
|
|
3032
3306
|
function buildSnippet(hit, projectRoot) {
|
|
3033
3307
|
try {
|
|
3034
|
-
const absPath =
|
|
3035
|
-
if (!
|
|
3308
|
+
const absPath = path8.join(projectRoot, hit.filePath);
|
|
3309
|
+
if (!existsSync7(absPath)) return hit.matchLine;
|
|
3036
3310
|
const lines = readFileSync4(absPath, "utf8").split("\n");
|
|
3037
3311
|
const start = Math.max(0, hit.lineNumber - 3);
|
|
3038
3312
|
const end = Math.min(lines.length, hit.lineNumber + 2);
|
|
@@ -3058,111 +3332,574 @@ var init_file_grep = __esm({
|
|
|
3058
3332
|
}
|
|
3059
3333
|
});
|
|
3060
3334
|
|
|
3061
|
-
// src/lib/
|
|
3062
|
-
var
|
|
3063
|
-
__export(
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3335
|
+
// src/lib/graph-query.ts
|
|
3336
|
+
var graph_query_exports = {};
|
|
3337
|
+
__export(graph_query_exports, {
|
|
3338
|
+
getConversationPartners: () => getConversationPartners,
|
|
3339
|
+
getEntityByName: () => getEntityByName,
|
|
3340
|
+
getEntityNeighbors: () => getEntityNeighbors,
|
|
3341
|
+
getEntityTimeline: () => getEntityTimeline,
|
|
3342
|
+
getGraphStats: () => getGraphStats,
|
|
3343
|
+
getHotEntities: () => getHotEntities,
|
|
3344
|
+
getRelationshipFrequency: () => getRelationshipFrequency,
|
|
3345
|
+
getRelationships: () => getRelationships,
|
|
3346
|
+
searchEntities: () => searchEntities,
|
|
3347
|
+
traverseChain: () => traverseChain
|
|
3069
3348
|
});
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3349
|
+
async function getEntityByName(client, name, type) {
|
|
3350
|
+
const sql = type ? `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) AND type = ? LIMIT 1` : `SELECT * FROM entities WHERE LOWER(name) = LOWER(?) LIMIT 1`;
|
|
3351
|
+
const args = type ? [name, type] : [name];
|
|
3352
|
+
const result = await client.execute({ sql, args });
|
|
3353
|
+
if (result.rows.length === 0) return null;
|
|
3354
|
+
const row = result.rows[0];
|
|
3355
|
+
return {
|
|
3356
|
+
id: String(row.id),
|
|
3357
|
+
name: String(row.name),
|
|
3358
|
+
type: String(row.type),
|
|
3359
|
+
firstSeen: String(row.first_seen),
|
|
3360
|
+
lastSeen: String(row.last_seen),
|
|
3361
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
async function searchEntities(client, query, limit = 10) {
|
|
3365
|
+
const result = await client.execute({
|
|
3366
|
+
sql: `SELECT * FROM entities WHERE LOWER(name) LIKE ? ORDER BY last_seen DESC LIMIT ?`,
|
|
3367
|
+
args: [`%${query.toLowerCase()}%`, limit]
|
|
3368
|
+
});
|
|
3369
|
+
return result.rows.map((row) => ({
|
|
3370
|
+
id: String(row.id),
|
|
3371
|
+
name: String(row.name),
|
|
3372
|
+
type: String(row.type),
|
|
3373
|
+
firstSeen: String(row.first_seen),
|
|
3374
|
+
lastSeen: String(row.last_seen),
|
|
3375
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3376
|
+
}));
|
|
3377
|
+
}
|
|
3378
|
+
async function getRelationships(client, entityId, options) {
|
|
3379
|
+
const direction = options?.direction ?? "both";
|
|
3380
|
+
let sql;
|
|
3381
|
+
const args = [];
|
|
3382
|
+
if (direction === "outgoing") {
|
|
3383
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3384
|
+
FROM relationships r
|
|
3385
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3386
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3387
|
+
WHERE r.source_entity_id = ?`;
|
|
3388
|
+
args.push(entityId);
|
|
3389
|
+
} else if (direction === "incoming") {
|
|
3390
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3391
|
+
FROM relationships r
|
|
3392
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3393
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3394
|
+
WHERE r.target_entity_id = ?`;
|
|
3395
|
+
args.push(entityId);
|
|
3396
|
+
} else {
|
|
3397
|
+
sql = `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3398
|
+
FROM relationships r
|
|
3399
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3400
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3401
|
+
WHERE r.source_entity_id = ? OR r.target_entity_id = ?`;
|
|
3402
|
+
args.push(entityId, entityId);
|
|
3403
|
+
}
|
|
3404
|
+
if (options?.type) {
|
|
3405
|
+
sql += ` AND r.type = ?`;
|
|
3406
|
+
args.push(options.type);
|
|
3407
|
+
}
|
|
3408
|
+
sql += ` ORDER BY r.weight DESC, r.timestamp DESC`;
|
|
3409
|
+
const result = await client.execute({ sql, args });
|
|
3410
|
+
return result.rows.map((row) => ({
|
|
3411
|
+
id: String(row.id),
|
|
3412
|
+
sourceEntityId: String(row.source_entity_id),
|
|
3413
|
+
targetEntityId: String(row.target_entity_id),
|
|
3414
|
+
type: String(row.type),
|
|
3415
|
+
weight: Number(row.weight),
|
|
3416
|
+
timestamp: String(row.timestamp),
|
|
3417
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
3418
|
+
confidence: Number(row.confidence ?? 1),
|
|
3419
|
+
confidenceLabel: String(row.confidence_label ?? "extracted"),
|
|
3420
|
+
sourceName: String(row.source_name),
|
|
3421
|
+
targetName: String(row.target_name)
|
|
3422
|
+
}));
|
|
3423
|
+
}
|
|
3424
|
+
async function traverseChain(client, startEntityId, relationshipType, maxDepth = 3) {
|
|
3425
|
+
const result = await client.execute({
|
|
3426
|
+
sql: `WITH RECURSIVE chain(entity_id, depth, rel_type) AS (
|
|
3427
|
+
SELECT ?, 0, ''
|
|
3428
|
+
UNION ALL
|
|
3429
|
+
SELECT r.target_entity_id, c.depth + 1, r.type
|
|
3430
|
+
FROM chain c
|
|
3431
|
+
JOIN relationships r ON r.source_entity_id = c.entity_id
|
|
3432
|
+
WHERE r.type = ? AND c.depth < ?
|
|
3433
|
+
)
|
|
3434
|
+
SELECT DISTINCT e.*, chain.depth, chain.rel_type
|
|
3435
|
+
FROM chain
|
|
3436
|
+
JOIN entities e ON e.id = chain.entity_id
|
|
3437
|
+
ORDER BY chain.depth ASC`,
|
|
3438
|
+
args: [startEntityId, relationshipType, maxDepth]
|
|
3439
|
+
});
|
|
3440
|
+
return result.rows.map((row) => ({
|
|
3441
|
+
entity: {
|
|
3442
|
+
id: String(row.id),
|
|
3443
|
+
name: String(row.name),
|
|
3444
|
+
type: String(row.type),
|
|
3445
|
+
firstSeen: String(row.first_seen),
|
|
3446
|
+
lastSeen: String(row.last_seen),
|
|
3447
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3448
|
+
},
|
|
3449
|
+
depth: Number(row.depth),
|
|
3450
|
+
relationship: String(row.rel_type)
|
|
3451
|
+
}));
|
|
3452
|
+
}
|
|
3453
|
+
async function getEntityNeighbors(client, entityId, maxHops = 2) {
|
|
3454
|
+
const result = await client.execute({
|
|
3455
|
+
sql: `WITH RECURSIVE neighborhood(entity_id, depth, rel_type, rel_confidence) AS (
|
|
3456
|
+
SELECT ?, 0, '', 1.0
|
|
3457
|
+
UNION ALL
|
|
3458
|
+
SELECT CASE
|
|
3459
|
+
WHEN r.source_entity_id = n.entity_id THEN r.target_entity_id
|
|
3460
|
+
ELSE r.source_entity_id
|
|
3461
|
+
END, n.depth + 1, r.type, COALESCE(r.confidence, 1.0)
|
|
3462
|
+
FROM neighborhood n
|
|
3463
|
+
JOIN relationships r ON r.source_entity_id = n.entity_id
|
|
3464
|
+
OR r.target_entity_id = n.entity_id
|
|
3465
|
+
WHERE n.depth < ?
|
|
3466
|
+
)
|
|
3467
|
+
SELECT DISTINCT e.*, MIN(neighborhood.depth) as depth,
|
|
3468
|
+
neighborhood.rel_type, neighborhood.rel_confidence
|
|
3469
|
+
FROM neighborhood
|
|
3470
|
+
JOIN entities e ON e.id = neighborhood.entity_id
|
|
3471
|
+
GROUP BY e.id
|
|
3472
|
+
ORDER BY depth ASC, e.last_seen DESC
|
|
3473
|
+
LIMIT 50`,
|
|
3474
|
+
args: [entityId, maxHops]
|
|
3475
|
+
});
|
|
3476
|
+
return result.rows.map((row) => ({
|
|
3477
|
+
entity: {
|
|
3478
|
+
id: String(row.id),
|
|
3479
|
+
name: String(row.name),
|
|
3480
|
+
type: String(row.type),
|
|
3481
|
+
firstSeen: String(row.first_seen),
|
|
3482
|
+
lastSeen: String(row.last_seen),
|
|
3483
|
+
properties: JSON.parse(String(row.properties ?? "{}"))
|
|
3484
|
+
},
|
|
3485
|
+
depth: Number(row.depth),
|
|
3486
|
+
relType: String(row.rel_type ?? ""),
|
|
3487
|
+
relConfidence: Number(row.rel_confidence ?? 1)
|
|
3488
|
+
}));
|
|
3489
|
+
}
|
|
3490
|
+
async function getGraphStats(client) {
|
|
3491
|
+
const entityCount = await client.execute("SELECT COUNT(*) as cnt FROM entities");
|
|
3492
|
+
const relCount = await client.execute("SELECT COUNT(*) as cnt FROM relationships");
|
|
3493
|
+
const typeResult = await client.execute(
|
|
3494
|
+
"SELECT type, COUNT(*) as cnt FROM entities GROUP BY type ORDER BY cnt DESC"
|
|
3495
|
+
);
|
|
3496
|
+
const types = {};
|
|
3497
|
+
for (const row of typeResult.rows) {
|
|
3498
|
+
types[String(row.type)] = Number(row.cnt);
|
|
3079
3499
|
}
|
|
3500
|
+
return {
|
|
3501
|
+
entities: Number(entityCount.rows[0]?.cnt ?? 0),
|
|
3502
|
+
relationships: Number(relCount.rows[0]?.cnt ?? 0),
|
|
3503
|
+
types
|
|
3504
|
+
};
|
|
3080
3505
|
}
|
|
3081
|
-
function
|
|
3082
|
-
|
|
3506
|
+
async function getEntityTimeline(client, entityId, since) {
|
|
3507
|
+
const args = [entityId, entityId];
|
|
3508
|
+
let sinceClause = "";
|
|
3509
|
+
if (since) {
|
|
3510
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
3511
|
+
args.push(since.toISOString());
|
|
3512
|
+
}
|
|
3513
|
+
const result = await client.execute({
|
|
3514
|
+
sql: `SELECT r.*, s.name as source_name, t.name as target_name
|
|
3515
|
+
FROM relationships r
|
|
3516
|
+
JOIN entities s ON r.source_entity_id = s.id
|
|
3517
|
+
JOIN entities t ON r.target_entity_id = t.id
|
|
3518
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
3519
|
+
ORDER BY r.timestamp DESC`,
|
|
3520
|
+
args
|
|
3521
|
+
});
|
|
3522
|
+
return result.rows.map((row) => ({
|
|
3523
|
+
relationship: {
|
|
3524
|
+
id: String(row.id),
|
|
3525
|
+
sourceEntityId: String(row.source_entity_id),
|
|
3526
|
+
targetEntityId: String(row.target_entity_id),
|
|
3527
|
+
type: String(row.type),
|
|
3528
|
+
weight: Number(row.weight),
|
|
3529
|
+
timestamp: String(row.timestamp),
|
|
3530
|
+
properties: JSON.parse(String(row.properties ?? "{}")),
|
|
3531
|
+
sourceName: String(row.source_name),
|
|
3532
|
+
targetName: String(row.target_name)
|
|
3533
|
+
},
|
|
3534
|
+
timestamp: String(row.timestamp)
|
|
3535
|
+
}));
|
|
3083
3536
|
}
|
|
3084
|
-
function
|
|
3085
|
-
|
|
3537
|
+
async function getRelationshipFrequency(client, entityId, options) {
|
|
3538
|
+
const granularity = options?.granularity ?? "day";
|
|
3539
|
+
const args = [entityId, entityId];
|
|
3540
|
+
let typeClause = "";
|
|
3541
|
+
if (options?.type) {
|
|
3542
|
+
typeClause = " AND r.type = ?";
|
|
3543
|
+
args.push(options.type);
|
|
3544
|
+
}
|
|
3545
|
+
let bucketExpr;
|
|
3546
|
+
switch (granularity) {
|
|
3547
|
+
case "week":
|
|
3548
|
+
bucketExpr = `strftime('%Y', r.timestamp) || '-W' || strftime('%W', r.timestamp)`;
|
|
3549
|
+
break;
|
|
3550
|
+
case "month":
|
|
3551
|
+
bucketExpr = `strftime('%Y-%m', r.timestamp)`;
|
|
3552
|
+
break;
|
|
3553
|
+
default:
|
|
3554
|
+
bucketExpr = `strftime('%Y-%m-%d', r.timestamp)`;
|
|
3555
|
+
}
|
|
3556
|
+
const result = await client.execute({
|
|
3557
|
+
sql: `SELECT ${bucketExpr} as bucket, COUNT(*) as cnt, r.type as rel_type
|
|
3558
|
+
FROM relationships r
|
|
3559
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${typeClause}
|
|
3560
|
+
GROUP BY bucket${options?.type ? "" : ", r.type"}
|
|
3561
|
+
ORDER BY bucket DESC`,
|
|
3562
|
+
args
|
|
3563
|
+
});
|
|
3564
|
+
return result.rows.map((row) => ({
|
|
3565
|
+
bucket: String(row.bucket),
|
|
3566
|
+
count: Number(row.cnt),
|
|
3567
|
+
relationshipType: options?.type ? options.type : String(row.rel_type)
|
|
3568
|
+
}));
|
|
3086
3569
|
}
|
|
3087
|
-
async function
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3570
|
+
async function getConversationPartners(client, contactEntityId, since) {
|
|
3571
|
+
const args = [contactEntityId, contactEntityId];
|
|
3572
|
+
let sinceClause = "";
|
|
3573
|
+
if (since) {
|
|
3574
|
+
sinceClause = " AND r.timestamp >= ?";
|
|
3575
|
+
args.push(since.toISOString());
|
|
3091
3576
|
}
|
|
3092
|
-
const
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3577
|
+
const result = await client.execute({
|
|
3578
|
+
sql: `SELECT
|
|
3579
|
+
CASE
|
|
3580
|
+
WHEN r.source_entity_id = ? THEN r.target_entity_id
|
|
3581
|
+
ELSE r.source_entity_id
|
|
3582
|
+
END as partner_id,
|
|
3583
|
+
COUNT(*) as interaction_count,
|
|
3584
|
+
MAX(r.timestamp) as last_interaction
|
|
3585
|
+
FROM relationships r
|
|
3586
|
+
WHERE (r.source_entity_id = ? OR r.target_entity_id = ?)${sinceClause}
|
|
3587
|
+
GROUP BY partner_id
|
|
3588
|
+
ORDER BY interaction_count DESC`,
|
|
3589
|
+
args: [contactEntityId, ...args]
|
|
3590
|
+
});
|
|
3591
|
+
const partners = [];
|
|
3592
|
+
for (const row of result.rows) {
|
|
3593
|
+
const partnerId = String(row.partner_id);
|
|
3594
|
+
const entityResult = await client.execute({
|
|
3595
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
3596
|
+
args: [partnerId]
|
|
3597
|
+
});
|
|
3598
|
+
if (entityResult.rows.length === 0) continue;
|
|
3599
|
+
const e = entityResult.rows[0];
|
|
3600
|
+
partners.push({
|
|
3601
|
+
agentEntity: {
|
|
3602
|
+
id: String(e.id),
|
|
3603
|
+
name: String(e.name),
|
|
3604
|
+
type: String(e.type),
|
|
3605
|
+
firstSeen: String(e.first_seen),
|
|
3606
|
+
lastSeen: String(e.last_seen),
|
|
3607
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
3608
|
+
},
|
|
3609
|
+
interactionCount: Number(row.interaction_count),
|
|
3610
|
+
lastInteraction: String(row.last_interaction)
|
|
3611
|
+
});
|
|
3097
3612
|
}
|
|
3098
|
-
|
|
3099
|
-
const { getLlama } = await import("node-llama-cpp");
|
|
3100
|
-
const llama = await getLlama();
|
|
3101
|
-
_rerankerModel = await llama.loadModel({ modelPath });
|
|
3102
|
-
_rerankerContext = await _rerankerModel.createEmbeddingContext();
|
|
3103
|
-
process.stderr.write("[reranker] Jina Reranker v3 loaded.\n");
|
|
3104
|
-
resetIdleTimer();
|
|
3613
|
+
return partners;
|
|
3105
3614
|
}
|
|
3106
|
-
async function
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3615
|
+
async function getHotEntities(client, since, limit = 10) {
|
|
3616
|
+
const sinceISO = since.toISOString();
|
|
3617
|
+
const result = await client.execute({
|
|
3618
|
+
sql: `SELECT entity_id, COUNT(*) as rel_count
|
|
3619
|
+
FROM (
|
|
3620
|
+
SELECT source_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
3621
|
+
UNION ALL
|
|
3622
|
+
SELECT target_entity_id as entity_id FROM relationships WHERE timestamp >= ?
|
|
3623
|
+
)
|
|
3624
|
+
GROUP BY entity_id
|
|
3625
|
+
ORDER BY rel_count DESC
|
|
3626
|
+
LIMIT ?`,
|
|
3627
|
+
args: [sinceISO, sinceISO, limit]
|
|
3628
|
+
});
|
|
3629
|
+
const hotEntities = [];
|
|
3630
|
+
for (const row of result.rows) {
|
|
3631
|
+
const eid = String(row.entity_id);
|
|
3632
|
+
const entityResult = await client.execute({
|
|
3633
|
+
sql: "SELECT * FROM entities WHERE id = ?",
|
|
3634
|
+
args: [eid]
|
|
3635
|
+
});
|
|
3636
|
+
if (entityResult.rows.length === 0) continue;
|
|
3637
|
+
const e = entityResult.rows[0];
|
|
3638
|
+
hotEntities.push({
|
|
3639
|
+
entity: {
|
|
3640
|
+
id: String(e.id),
|
|
3641
|
+
name: String(e.name),
|
|
3642
|
+
type: String(e.type),
|
|
3643
|
+
firstSeen: String(e.first_seen),
|
|
3644
|
+
lastSeen: String(e.last_seen),
|
|
3645
|
+
properties: JSON.parse(String(e.properties ?? "{}"))
|
|
3646
|
+
},
|
|
3647
|
+
newRelationships: Number(row.rel_count)
|
|
3648
|
+
});
|
|
3110
3649
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3650
|
+
return hotEntities;
|
|
3651
|
+
}
|
|
3652
|
+
var init_graph_query = __esm({
|
|
3653
|
+
"src/lib/graph-query.ts"() {
|
|
3654
|
+
"use strict";
|
|
3655
|
+
}
|
|
3656
|
+
});
|
|
3657
|
+
|
|
3658
|
+
// src/lib/entity-boost.ts
|
|
3659
|
+
var entity_boost_exports = {};
|
|
3660
|
+
__export(entity_boost_exports, {
|
|
3661
|
+
applyEntityBoost: () => applyEntityBoost
|
|
3662
|
+
});
|
|
3663
|
+
function getRelTypeWeights() {
|
|
3664
|
+
const override = process.env.RELATIONSHIP_TYPE_WEIGHTS;
|
|
3665
|
+
if (!override) return DEFAULT_RELATIONSHIP_WEIGHTS;
|
|
3666
|
+
try {
|
|
3667
|
+
return { ...DEFAULT_RELATIONSHIP_WEIGHTS, ...JSON.parse(override) };
|
|
3668
|
+
} catch {
|
|
3669
|
+
return DEFAULT_RELATIONSHIP_WEIGHTS;
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
async function matchEntities(query, client) {
|
|
3673
|
+
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);
|
|
3674
|
+
if (words.length === 0) return [];
|
|
3675
|
+
try {
|
|
3676
|
+
const matchExpr = words.map((w) => `${w}*`).join(" OR ");
|
|
3677
|
+
const result = await client.execute({
|
|
3678
|
+
sql: `SELECT e.id, e.name FROM entities e
|
|
3679
|
+
JOIN entities_fts fts ON e.rowid = fts.rowid
|
|
3680
|
+
WHERE entities_fts MATCH ?
|
|
3681
|
+
ORDER BY rank
|
|
3682
|
+
LIMIT ?`,
|
|
3683
|
+
args: [matchExpr, MAX_ENTITY_MATCHES]
|
|
3684
|
+
});
|
|
3685
|
+
if (result.rows.length > 0) {
|
|
3686
|
+
return result.rows.map((row) => ({
|
|
3687
|
+
entityId: String(row.id),
|
|
3688
|
+
name: String(row.name)
|
|
3689
|
+
}));
|
|
3115
3690
|
}
|
|
3116
|
-
|
|
3691
|
+
} catch {
|
|
3117
3692
|
}
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3693
|
+
const conditions = words.map(() => `LOWER(name) LIKE ?`);
|
|
3694
|
+
const args = words.map((w) => `%${w}%`);
|
|
3695
|
+
try {
|
|
3696
|
+
const result = await client.execute({
|
|
3697
|
+
sql: `SELECT id, name FROM entities
|
|
3698
|
+
WHERE ${conditions.join(" OR ")}
|
|
3699
|
+
LIMIT ?`,
|
|
3700
|
+
args: [...args, MAX_ENTITY_MATCHES]
|
|
3701
|
+
});
|
|
3702
|
+
return result.rows.map((row) => ({
|
|
3703
|
+
entityId: String(row.id),
|
|
3704
|
+
name: String(row.name)
|
|
3705
|
+
}));
|
|
3706
|
+
} catch {
|
|
3707
|
+
return [];
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
async function getLinkedMemories(entityIds, client) {
|
|
3711
|
+
const linked = /* @__PURE__ */ new Map();
|
|
3712
|
+
if (entityIds.length === 0) return linked;
|
|
3713
|
+
const placeholders = entityIds.map(() => "?").join(",");
|
|
3714
|
+
try {
|
|
3715
|
+
const result = await client.execute({
|
|
3716
|
+
sql: `SELECT entity_id, memory_id FROM entity_memories
|
|
3717
|
+
WHERE entity_id IN (${placeholders})`,
|
|
3718
|
+
args: entityIds
|
|
3719
|
+
});
|
|
3720
|
+
for (const row of result.rows) {
|
|
3721
|
+
const entityId = String(row.entity_id);
|
|
3722
|
+
const memoryId = String(row.memory_id);
|
|
3723
|
+
const entry = linked.get(entityId) ?? {
|
|
3724
|
+
entityId,
|
|
3725
|
+
memoryIds: /* @__PURE__ */ new Set(),
|
|
3726
|
+
count: 0
|
|
3727
|
+
};
|
|
3728
|
+
entry.memoryIds.add(memoryId);
|
|
3729
|
+
entry.count = entry.memoryIds.size;
|
|
3730
|
+
linked.set(entityId, entry);
|
|
3122
3731
|
}
|
|
3123
|
-
|
|
3732
|
+
} catch {
|
|
3124
3733
|
}
|
|
3125
|
-
|
|
3734
|
+
return linked;
|
|
3126
3735
|
}
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
const
|
|
3132
|
-
|
|
3133
|
-
|
|
3736
|
+
function spreadAttenuation(numLinked) {
|
|
3737
|
+
return 1 / (1 + 1e-3 * (numLinked - 1) ** 2);
|
|
3738
|
+
}
|
|
3739
|
+
async function traverseAndScore(entities, client, boostMap, resultIds, graphContextMap) {
|
|
3740
|
+
const topEntities = entities.slice(0, TOP_ENTITIES_TO_TRAVERSE);
|
|
3741
|
+
if (topEntities.length === 0) return;
|
|
3742
|
+
const { getEntityNeighbors: getEntityNeighbors2 } = await Promise.resolve().then(() => (init_graph_query(), graph_query_exports));
|
|
3743
|
+
const relWeights = getRelTypeWeights();
|
|
3744
|
+
const neighborEntityIds = [];
|
|
3745
|
+
const neighborMeta = /* @__PURE__ */ new Map();
|
|
3746
|
+
for (const entity of topEntities) {
|
|
3134
3747
|
try {
|
|
3135
|
-
const
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3748
|
+
const neighbors = await getEntityNeighbors2(
|
|
3749
|
+
client,
|
|
3750
|
+
entity.entityId,
|
|
3751
|
+
GRAPH_TRAVERSAL_MAX_HOPS
|
|
3752
|
+
);
|
|
3753
|
+
for (const n of neighbors) {
|
|
3754
|
+
if (n.depth === 0) continue;
|
|
3755
|
+
if (neighborMeta.has(n.entity.id)) continue;
|
|
3756
|
+
neighborEntityIds.push(n.entity.id);
|
|
3757
|
+
neighborMeta.set(n.entity.id, {
|
|
3758
|
+
depth: n.depth,
|
|
3759
|
+
relType: n.relType,
|
|
3760
|
+
relConfidence: n.relConfidence,
|
|
3761
|
+
sourceName: entity.name
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3139
3764
|
} catch {
|
|
3140
|
-
scored.push({ text, score: -1, index: i });
|
|
3141
3765
|
}
|
|
3142
3766
|
}
|
|
3143
|
-
|
|
3144
|
-
|
|
3767
|
+
if (neighborEntityIds.length === 0) return;
|
|
3768
|
+
const neighborLinked = await getLinkedMemories(neighborEntityIds, client);
|
|
3769
|
+
for (const [entityId, entry] of neighborLinked) {
|
|
3770
|
+
const meta = neighborMeta.get(entityId);
|
|
3771
|
+
if (!meta) continue;
|
|
3772
|
+
const relWeight = relWeights[meta.relType] ?? DEFAULT_REL_WEIGHT;
|
|
3773
|
+
const depthDecay = 1 / (1 + meta.depth);
|
|
3774
|
+
const neighborBoost = ENTITY_BOOST_WEIGHT * meta.relConfidence * depthDecay * relWeight;
|
|
3775
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3776
|
+
const finalBoost = neighborBoost * attenuation;
|
|
3777
|
+
for (const memoryId of entry.memoryIds) {
|
|
3778
|
+
if (resultIds.has(memoryId)) {
|
|
3779
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + finalBoost);
|
|
3780
|
+
const contextPath = `${meta.sourceName} ${meta.relType} ${entityId}`;
|
|
3781
|
+
if (!graphContextMap.has(memoryId)) {
|
|
3782
|
+
graphContextMap.set(memoryId, contextPath);
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3145
3787
|
}
|
|
3146
|
-
async function
|
|
3147
|
-
if (
|
|
3148
|
-
|
|
3149
|
-
const
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3788
|
+
async function applyHyperedgeBoost(entities, client, boostMap, resultIds) {
|
|
3789
|
+
if (entities.length < 2) return;
|
|
3790
|
+
const entityIds = entities.map((e) => e.entityId);
|
|
3791
|
+
const placeholders = entityIds.map(() => "?").join(",");
|
|
3792
|
+
try {
|
|
3793
|
+
const result = await client.execute({
|
|
3794
|
+
sql: `SELECT hyperedge_id, entity_id FROM hyperedge_nodes
|
|
3795
|
+
WHERE entity_id IN (${placeholders})`,
|
|
3796
|
+
args: entityIds
|
|
3797
|
+
});
|
|
3798
|
+
const hyperedgeEntities = /* @__PURE__ */ new Map();
|
|
3799
|
+
for (const row of result.rows) {
|
|
3800
|
+
const hid = String(row.hyperedge_id);
|
|
3801
|
+
const eid = String(row.entity_id);
|
|
3802
|
+
const set = hyperedgeEntities.get(hid) ?? /* @__PURE__ */ new Set();
|
|
3803
|
+
set.add(eid);
|
|
3804
|
+
hyperedgeEntities.set(hid, set);
|
|
3805
|
+
}
|
|
3806
|
+
const sharedHyperedgeIds = [];
|
|
3807
|
+
for (const [hid, eids] of hyperedgeEntities) {
|
|
3808
|
+
if (eids.size >= 2) {
|
|
3809
|
+
sharedHyperedgeIds.push(hid);
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
if (sharedHyperedgeIds.length === 0) return;
|
|
3813
|
+
const hPlaceholders = sharedHyperedgeIds.map(() => "?").join(",");
|
|
3814
|
+
const allNodesResult = await client.execute({
|
|
3815
|
+
sql: `SELECT DISTINCT entity_id FROM hyperedge_nodes
|
|
3816
|
+
WHERE hyperedge_id IN (${hPlaceholders})`,
|
|
3817
|
+
args: sharedHyperedgeIds
|
|
3818
|
+
});
|
|
3819
|
+
const allEntityIds = allNodesResult.rows.map((r) => String(r.entity_id));
|
|
3820
|
+
if (allEntityIds.length === 0) return;
|
|
3821
|
+
const linked = await getLinkedMemories(allEntityIds, client);
|
|
3822
|
+
for (const [, entry] of linked) {
|
|
3823
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3824
|
+
const boost = ENTITY_BOOST_WEIGHT * attenuation;
|
|
3825
|
+
for (const memoryId of entry.memoryIds) {
|
|
3826
|
+
if (resultIds.has(memoryId)) {
|
|
3827
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + boost);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3831
|
+
} catch {
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
async function applyEntityBoost(results, query, client) {
|
|
3835
|
+
const emptyResult = { results, graphContext: /* @__PURE__ */ new Map() };
|
|
3836
|
+
if (ENTITY_BOOST_WEIGHT === 0 || results.length === 0) {
|
|
3837
|
+
return emptyResult;
|
|
3838
|
+
}
|
|
3839
|
+
console.time("entity-boost");
|
|
3840
|
+
const entities = await matchEntities(query, client);
|
|
3841
|
+
if (entities.length === 0) {
|
|
3842
|
+
console.timeEnd("entity-boost");
|
|
3843
|
+
return emptyResult;
|
|
3844
|
+
}
|
|
3845
|
+
const boostMap = /* @__PURE__ */ new Map();
|
|
3846
|
+
const resultIds = new Set(results.map((r) => r.id));
|
|
3847
|
+
const graphContextMap = /* @__PURE__ */ new Map();
|
|
3848
|
+
const directLinked = await getLinkedMemories(
|
|
3849
|
+
entities.map((e) => e.entityId),
|
|
3850
|
+
client
|
|
3153
3851
|
);
|
|
3154
|
-
|
|
3852
|
+
for (const [, entry] of directLinked) {
|
|
3853
|
+
const attenuation = spreadAttenuation(entry.count);
|
|
3854
|
+
const boost = ENTITY_BOOST_WEIGHT * attenuation;
|
|
3855
|
+
for (const memoryId of entry.memoryIds) {
|
|
3856
|
+
if (resultIds.has(memoryId)) {
|
|
3857
|
+
boostMap.set(memoryId, (boostMap.get(memoryId) ?? 0) + boost);
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
await traverseAndScore(entities, client, boostMap, resultIds, graphContextMap);
|
|
3862
|
+
await applyHyperedgeBoost(entities, client, boostMap, resultIds);
|
|
3863
|
+
if (boostMap.size === 0) {
|
|
3864
|
+
console.timeEnd("entity-boost");
|
|
3865
|
+
return emptyResult;
|
|
3866
|
+
}
|
|
3867
|
+
const scored = results.map((r, i) => ({
|
|
3868
|
+
record: r,
|
|
3869
|
+
baseScore: 1 / (1 + i * 0.1),
|
|
3870
|
+
entityBoost: boostMap.get(r.id) ?? 0
|
|
3871
|
+
}));
|
|
3872
|
+
scored.sort(
|
|
3873
|
+
(a, b) => b.baseScore + b.entityBoost - (a.baseScore + a.entityBoost)
|
|
3874
|
+
);
|
|
3875
|
+
console.timeEnd("entity-boost");
|
|
3876
|
+
return {
|
|
3877
|
+
results: scored.map((s) => s.record),
|
|
3878
|
+
graphContext: graphContextMap
|
|
3879
|
+
};
|
|
3155
3880
|
}
|
|
3156
|
-
var
|
|
3157
|
-
var
|
|
3158
|
-
"src/lib/
|
|
3881
|
+
var ENTITY_BOOST_WEIGHT, MIN_WORD_LENGTH, MAX_ENTITY_MATCHES, GRAPH_TRAVERSAL_MAX_HOPS, TOP_ENTITIES_TO_TRAVERSE, DEFAULT_RELATIONSHIP_WEIGHTS, DEFAULT_REL_WEIGHT;
|
|
3882
|
+
var init_entity_boost = __esm({
|
|
3883
|
+
"src/lib/entity-boost.ts"() {
|
|
3159
3884
|
"use strict";
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3885
|
+
ENTITY_BOOST_WEIGHT = parseFloat(
|
|
3886
|
+
process.env.ENTITY_BOOST_WEIGHT ?? "0.5"
|
|
3887
|
+
);
|
|
3888
|
+
MIN_WORD_LENGTH = 3;
|
|
3889
|
+
MAX_ENTITY_MATCHES = 20;
|
|
3890
|
+
GRAPH_TRAVERSAL_MAX_HOPS = Math.min(
|
|
3891
|
+
parseInt(process.env.GRAPH_TRAVERSAL_MAX_HOPS ?? "2", 10),
|
|
3892
|
+
3
|
|
3893
|
+
);
|
|
3894
|
+
TOP_ENTITIES_TO_TRAVERSE = 5;
|
|
3895
|
+
DEFAULT_RELATIONSHIP_WEIGHTS = {
|
|
3896
|
+
decided: 1,
|
|
3897
|
+
depends_on: 0.8,
|
|
3898
|
+
part_of: 0.7,
|
|
3899
|
+
related_to: 0.5,
|
|
3900
|
+
mentioned_in: 0.3
|
|
3901
|
+
};
|
|
3902
|
+
DEFAULT_REL_WEIGHT = 0.4;
|
|
3166
3903
|
}
|
|
3167
3904
|
});
|
|
3168
3905
|
|
|
@@ -3213,8 +3950,14 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3213
3950
|
`
|
|
3214
3951
|
);
|
|
3215
3952
|
}
|
|
3953
|
+
let rerankerAvailable = false;
|
|
3954
|
+
try {
|
|
3955
|
+
const { isRerankerAvailable: isRerankerAvailable2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
3956
|
+
rerankerAvailable = isRerankerAvailable2();
|
|
3957
|
+
} catch {
|
|
3958
|
+
}
|
|
3216
3959
|
const broadFetchTopK = config.scalingRoadmap?.rerankerAutoTrigger?.fetchTopK ?? 150;
|
|
3217
|
-
const fetchLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : Math.max(limit * 3, 30);
|
|
3960
|
+
const fetchLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : rerankerAvailable ? Math.max(limit * 4, 60) : Math.max(limit * 3, 30);
|
|
3218
3961
|
const fetchOptions = { ...effectiveOptions, limit: fetchLimit, includeSource: false };
|
|
3219
3962
|
let queryVector = null;
|
|
3220
3963
|
try {
|
|
@@ -3224,7 +3967,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3224
3967
|
process.stderr.write("[hybrid-search] Embed daemon unavailable \u2014 FTS-only mode\n");
|
|
3225
3968
|
}
|
|
3226
3969
|
let grepPromise = Promise.resolve([]);
|
|
3227
|
-
if (config.fileGrepEnabled
|
|
3970
|
+
if (config.fileGrepEnabled === true) {
|
|
3228
3971
|
try {
|
|
3229
3972
|
const { getProjectName: getProjectName2 } = await Promise.resolve().then(() => (init_project_name(), project_name_exports));
|
|
3230
3973
|
const projectRoot = process.cwd();
|
|
@@ -3260,7 +4003,17 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3260
4003
|
if (lists.length === 0) return [];
|
|
3261
4004
|
if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
|
|
3262
4005
|
const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, 150) : limit;
|
|
3263
|
-
|
|
4006
|
+
let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
|
|
4007
|
+
let graphContextMap = /* @__PURE__ */ new Map();
|
|
4008
|
+
if (merged.length > 0) {
|
|
4009
|
+
try {
|
|
4010
|
+
const { applyEntityBoost: applyEntityBoost2 } = await Promise.resolve().then(() => (init_entity_boost(), entity_boost_exports));
|
|
4011
|
+
const boosted = await applyEntityBoost2(merged, effectiveQuery, getClient());
|
|
4012
|
+
merged = boosted.results;
|
|
4013
|
+
graphContextMap = boosted.graphContext;
|
|
4014
|
+
} catch {
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
3264
4017
|
const auto = config.scalingRoadmap?.rerankerAutoTrigger ?? {
|
|
3265
4018
|
enabled: config.rerankerEnabled ?? true,
|
|
3266
4019
|
broadQueryMinCardinality: 5e4,
|
|
@@ -3268,20 +4021,29 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3268
4021
|
returnTopK: 5
|
|
3269
4022
|
};
|
|
3270
4023
|
let rerankedAndBlended = null;
|
|
3271
|
-
if (effectiveIsBroad && auto.enabled) {
|
|
4024
|
+
if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
|
|
3272
4025
|
const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
|
|
3273
4026
|
if (cardinality2 > auto.broadQueryMinCardinality) {
|
|
3274
4027
|
try {
|
|
3275
|
-
|
|
3276
|
-
if (
|
|
3277
|
-
const
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
4028
|
+
let rerankedRecords;
|
|
4029
|
+
if (graphContextMap.size > 0) {
|
|
4030
|
+
const { rerankWithContext: rerankWithContext2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
4031
|
+
const candidates = merged.map((m) => ({
|
|
4032
|
+
text: m.raw_text,
|
|
4033
|
+
context: graphContextMap.get(m.id)
|
|
4034
|
+
}));
|
|
4035
|
+
const scored = await rerankWithContext2(effectiveQuery, candidates, auto.returnTopK);
|
|
4036
|
+
rerankedRecords = scored.map((s) => merged[s.index]);
|
|
4037
|
+
} else {
|
|
4038
|
+
const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
4039
|
+
rerankedRecords = await rerank2(effectiveQuery, merged, auto.returnTopK);
|
|
4040
|
+
}
|
|
4041
|
+
if (rerankedRecords.length > 0) {
|
|
4042
|
+
rerankedAndBlended = rrfMergeMulti(
|
|
4043
|
+
[rerankedRecords],
|
|
4044
|
+
auto.returnTopK,
|
|
4045
|
+
RRF_K
|
|
4046
|
+
);
|
|
3285
4047
|
}
|
|
3286
4048
|
} catch {
|
|
3287
4049
|
}
|
|
@@ -3301,7 +4063,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
3301
4063
|
try {
|
|
3302
4064
|
const client = getClient();
|
|
3303
4065
|
void client.execute({
|
|
3304
|
-
sql: `UPDATE memories SET last_accessed =
|
|
4066
|
+
sql: `UPDATE memories SET last_accessed = ?, retrieval_count = COALESCE(retrieval_count, 0) + 1 WHERE id IN (${placeholders})`,
|
|
3305
4067
|
args: [now, ...ids]
|
|
3306
4068
|
}).catch(() => {
|
|
3307
4069
|
});
|
|
@@ -3471,7 +4233,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
3471
4233
|
source_type: row.source_type ?? null
|
|
3472
4234
|
}));
|
|
3473
4235
|
}
|
|
3474
|
-
async function recentRecords(agentId, options, limit) {
|
|
4236
|
+
async function recentRecords(agentId, options, limit, textFilter) {
|
|
3475
4237
|
const client = getClient();
|
|
3476
4238
|
const statusFilter = options?.includeArchived ? "" : `
|
|
3477
4239
|
AND COALESCE(status, 'active') = 'active'`;
|
|
@@ -3511,6 +4273,10 @@ async function recentRecords(agentId, options, limit) {
|
|
|
3511
4273
|
sql += ` AND memory_type = ?`;
|
|
3512
4274
|
args.push(options.memoryType);
|
|
3513
4275
|
}
|
|
4276
|
+
if (textFilter) {
|
|
4277
|
+
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
4278
|
+
args.push(textFilter);
|
|
4279
|
+
}
|
|
3514
4280
|
sql += ` ORDER BY timestamp DESC LIMIT ?`;
|
|
3515
4281
|
args.push(limit);
|
|
3516
4282
|
const result = await client.execute({ sql, args });
|
|
@@ -3630,6 +4396,7 @@ import { realpathSync } from "fs";
|
|
|
3630
4396
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3631
4397
|
function isMainModule(importMetaUrl) {
|
|
3632
4398
|
if (process.argv[1] == null) return false;
|
|
4399
|
+
if (process.argv[1].includes("mcp/server")) return false;
|
|
3633
4400
|
try {
|
|
3634
4401
|
const scriptPath = realpathSync(process.argv[1]);
|
|
3635
4402
|
const modulePath = realpathSync(fileURLToPath2(importMetaUrl));
|