engrm 0.4.25 → 0.4.26
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/README.md +6 -4
- package/dist/hooks/pre-compact.js +47 -11
- package/dist/hooks/session-start.js +858 -96
- package/dist/hooks/stop.js +1 -1
- package/dist/server.js +193 -33
- package/package.json +1 -1
package/dist/hooks/stop.js
CHANGED
|
@@ -3009,7 +3009,7 @@ function buildBeacon(db, config, sessionId, metrics) {
|
|
|
3009
3009
|
sentinel_used: valueSignals.security_findings_count > 0,
|
|
3010
3010
|
risk_score: riskScore,
|
|
3011
3011
|
stacks_detected: stacks,
|
|
3012
|
-
client_version: "0.4.
|
|
3012
|
+
client_version: "0.4.26",
|
|
3013
3013
|
context_observations_injected: metrics?.contextObsInjected ?? 0,
|
|
3014
3014
|
context_total_available: metrics?.contextTotalAvailable ?? 0,
|
|
3015
3015
|
recall_attempts: metrics?.recallAttempts ?? 0,
|
package/dist/server.js
CHANGED
|
@@ -16458,8 +16458,12 @@ function getRecentRequests(db, input) {
|
|
|
16458
16458
|
function getRecentChat(db, input) {
|
|
16459
16459
|
const limit = Math.max(1, Math.min(input.limit ?? 20, 100));
|
|
16460
16460
|
if (input.session_id) {
|
|
16461
|
+
const messages2 = db.getSessionChatMessages(input.session_id, limit).slice(-limit).reverse();
|
|
16461
16462
|
return {
|
|
16462
|
-
messages:
|
|
16463
|
+
messages: messages2,
|
|
16464
|
+
session_count: countDistinctSessions(messages2),
|
|
16465
|
+
source_summary: summarizeChatSources(messages2),
|
|
16466
|
+
transcript_backed: messages2.some((message) => message.source_kind === "transcript")
|
|
16463
16467
|
};
|
|
16464
16468
|
}
|
|
16465
16469
|
const projectScoped = input.project_scoped !== false;
|
|
@@ -16474,11 +16478,24 @@ function getRecentChat(db, input) {
|
|
|
16474
16478
|
projectName = project.name;
|
|
16475
16479
|
}
|
|
16476
16480
|
}
|
|
16481
|
+
const messages = db.getRecentChatMessages(projectId, limit, input.user_id);
|
|
16477
16482
|
return {
|
|
16478
|
-
messages
|
|
16479
|
-
project: projectName
|
|
16483
|
+
messages,
|
|
16484
|
+
project: projectName,
|
|
16485
|
+
session_count: countDistinctSessions(messages),
|
|
16486
|
+
source_summary: summarizeChatSources(messages),
|
|
16487
|
+
transcript_backed: messages.some((message) => message.source_kind === "transcript")
|
|
16480
16488
|
};
|
|
16481
16489
|
}
|
|
16490
|
+
function summarizeChatSources(messages) {
|
|
16491
|
+
return messages.reduce((summary, message) => {
|
|
16492
|
+
summary[message.source_kind] += 1;
|
|
16493
|
+
return summary;
|
|
16494
|
+
}, { transcript: 0, hook: 0 });
|
|
16495
|
+
}
|
|
16496
|
+
function countDistinctSessions(messages) {
|
|
16497
|
+
return new Set(messages.map((message) => message.session_id)).size;
|
|
16498
|
+
}
|
|
16482
16499
|
|
|
16483
16500
|
// src/tools/search-chat.ts
|
|
16484
16501
|
function searchChat(db, input) {
|
|
@@ -16495,11 +16512,24 @@ function searchChat(db, input) {
|
|
|
16495
16512
|
projectName = project.name;
|
|
16496
16513
|
}
|
|
16497
16514
|
}
|
|
16515
|
+
const messages = db.searchChatMessages(input.query, projectId, limit, input.user_id);
|
|
16498
16516
|
return {
|
|
16499
|
-
messages
|
|
16500
|
-
project: projectName
|
|
16517
|
+
messages,
|
|
16518
|
+
project: projectName,
|
|
16519
|
+
session_count: countDistinctSessions2(messages),
|
|
16520
|
+
source_summary: summarizeChatSources2(messages),
|
|
16521
|
+
transcript_backed: messages.some((message) => message.source_kind === "transcript")
|
|
16501
16522
|
};
|
|
16502
16523
|
}
|
|
16524
|
+
function summarizeChatSources2(messages) {
|
|
16525
|
+
return messages.reduce((summary, message) => {
|
|
16526
|
+
summary[message.source_kind] += 1;
|
|
16527
|
+
return summary;
|
|
16528
|
+
}, { transcript: 0, hook: 0 });
|
|
16529
|
+
}
|
|
16530
|
+
function countDistinctSessions2(messages) {
|
|
16531
|
+
return new Set(messages.map((message) => message.session_id)).size;
|
|
16532
|
+
}
|
|
16503
16533
|
|
|
16504
16534
|
// src/tools/session-story.ts
|
|
16505
16535
|
function getSessionStory(db, input) {
|
|
@@ -17230,6 +17260,7 @@ function findStaleDecisionsGlobal(db, options) {
|
|
|
17230
17260
|
}
|
|
17231
17261
|
|
|
17232
17262
|
// src/context/inject.ts
|
|
17263
|
+
var FRESH_CONTINUITY_WINDOW_DAYS = 3;
|
|
17233
17264
|
function tokenizeProjectHint(text) {
|
|
17234
17265
|
return Array.from(new Set((text.toLowerCase().match(/[a-z0-9_+-]{4,}/g) ?? []).filter(Boolean)));
|
|
17235
17266
|
}
|
|
@@ -17369,20 +17400,21 @@ function buildSessionContext(db, cwd, options = {}) {
|
|
|
17369
17400
|
const canonicalId = project?.canonical_id ?? detected.canonical_id;
|
|
17370
17401
|
if (maxCount !== undefined) {
|
|
17371
17402
|
const remaining = Math.max(0, maxCount - pinned.length - dedupedRecent.length);
|
|
17372
|
-
|
|
17373
|
-
const recentPrompts2 =
|
|
17374
|
-
const recentToolEvents2 =
|
|
17403
|
+
let all = [...pinned, ...dedupedRecent, ...sorted.slice(0, remaining)];
|
|
17404
|
+
const recentPrompts2 = isNewProject ? [] : db.getRecentUserPrompts(projectId, 6, opts.userId);
|
|
17405
|
+
const recentToolEvents2 = isNewProject ? [] : db.getRecentToolEvents(projectId, 6, opts.userId);
|
|
17375
17406
|
const recentSessions2 = isNewProject ? [] : db.getRecentSessions(projectId, 5, opts.userId);
|
|
17376
17407
|
const projectTypeCounts2 = isNewProject ? undefined : getProjectTypeCounts(db, projectId, opts.userId);
|
|
17377
17408
|
const recentOutcomes2 = isNewProject ? undefined : getRecentOutcomes(db, projectId, opts.userId, recentSessions2);
|
|
17378
|
-
const recentHandoffs2 = getRecentHandoffs(db, {
|
|
17409
|
+
const recentHandoffs2 = isNewProject ? [] : getRecentHandoffs(db, {
|
|
17379
17410
|
cwd,
|
|
17380
|
-
project_scoped:
|
|
17411
|
+
project_scoped: true,
|
|
17381
17412
|
user_id: opts.userId,
|
|
17382
17413
|
current_device_id: opts.currentDeviceId,
|
|
17383
17414
|
limit: 3
|
|
17384
17415
|
}).handoffs;
|
|
17385
17416
|
const recentChatMessages2 = !isNewProject && project ? db.getRecentChatMessages(project.id, 4, opts.userId) : [];
|
|
17417
|
+
all = filterAutoLoadedObservationsForContinuity(all, pinned, isNewProject, recentPrompts2, recentToolEvents2, recentSessions2, recentHandoffs2, recentChatMessages2, summariesFromRecentSessions(db, projectId, recentSessions2));
|
|
17386
17418
|
return {
|
|
17387
17419
|
project_name: projectName,
|
|
17388
17420
|
canonical_id: canonicalId,
|
|
@@ -17418,19 +17450,20 @@ function buildSessionContext(db, cwd, options = {}) {
|
|
|
17418
17450
|
selected.push(obs);
|
|
17419
17451
|
}
|
|
17420
17452
|
const summaries = isNewProject ? [] : db.getRecentSummaries(projectId, 5);
|
|
17421
|
-
const recentPrompts =
|
|
17422
|
-
const recentToolEvents =
|
|
17453
|
+
const recentPrompts = isNewProject ? [] : db.getRecentUserPrompts(projectId, 6, opts.userId);
|
|
17454
|
+
const recentToolEvents = isNewProject ? [] : db.getRecentToolEvents(projectId, 6, opts.userId);
|
|
17423
17455
|
const recentSessions = isNewProject ? [] : db.getRecentSessions(projectId, 5, opts.userId);
|
|
17424
17456
|
const projectTypeCounts = isNewProject ? undefined : getProjectTypeCounts(db, projectId, opts.userId);
|
|
17425
17457
|
const recentOutcomes = isNewProject ? undefined : getRecentOutcomes(db, projectId, opts.userId, recentSessions);
|
|
17426
|
-
const recentHandoffs = getRecentHandoffs(db, {
|
|
17458
|
+
const recentHandoffs = isNewProject ? [] : getRecentHandoffs(db, {
|
|
17427
17459
|
cwd,
|
|
17428
|
-
project_scoped:
|
|
17460
|
+
project_scoped: true,
|
|
17429
17461
|
user_id: opts.userId,
|
|
17430
17462
|
current_device_id: opts.currentDeviceId,
|
|
17431
17463
|
limit: 3
|
|
17432
17464
|
}).handoffs;
|
|
17433
17465
|
const recentChatMessages = !isNewProject ? db.getRecentChatMessages(projectId, 4, opts.userId) : [];
|
|
17466
|
+
const filteredSelected = filterAutoLoadedObservationsForContinuity(selected, pinned, isNewProject, recentPrompts, recentToolEvents, recentSessions, recentHandoffs, recentChatMessages, summaries);
|
|
17434
17467
|
let securityFindings = [];
|
|
17435
17468
|
if (!isNewProject) {
|
|
17436
17469
|
try {
|
|
@@ -17478,8 +17511,8 @@ function buildSessionContext(db, cwd, options = {}) {
|
|
|
17478
17511
|
return {
|
|
17479
17512
|
project_name: projectName,
|
|
17480
17513
|
canonical_id: canonicalId,
|
|
17481
|
-
observations:
|
|
17482
|
-
session_count:
|
|
17514
|
+
observations: filteredSelected.map(toContextObservation),
|
|
17515
|
+
session_count: filteredSelected.length,
|
|
17483
17516
|
total_active: totalActive,
|
|
17484
17517
|
summaries: summaries.length > 0 ? summaries : undefined,
|
|
17485
17518
|
securityFindings: securityFindings.length > 0 ? securityFindings : undefined,
|
|
@@ -17494,6 +17527,39 @@ function buildSessionContext(db, cwd, options = {}) {
|
|
|
17494
17527
|
recentChatMessages: recentChatMessages.length > 0 ? recentChatMessages : undefined
|
|
17495
17528
|
};
|
|
17496
17529
|
}
|
|
17530
|
+
function filterAutoLoadedObservationsForContinuity(observations, pinned, isNewProject, recentPrompts, recentToolEvents, recentSessions, recentHandoffs, recentChatMessages, summaries) {
|
|
17531
|
+
if (isNewProject)
|
|
17532
|
+
return observations;
|
|
17533
|
+
if (hasFreshProjectContinuity(recentPrompts, recentToolEvents, recentSessions, recentHandoffs, recentChatMessages, summaries)) {
|
|
17534
|
+
return observations;
|
|
17535
|
+
}
|
|
17536
|
+
const pinnedIds = new Set(pinned.map((obs) => obs.id));
|
|
17537
|
+
return observations.filter((obs) => {
|
|
17538
|
+
if (pinnedIds.has(obs.id))
|
|
17539
|
+
return true;
|
|
17540
|
+
return observationAgeDays(obs.created_at_epoch) <= FRESH_CONTINUITY_WINDOW_DAYS;
|
|
17541
|
+
});
|
|
17542
|
+
}
|
|
17543
|
+
function hasFreshProjectContinuity(recentPrompts, recentToolEvents, recentSessions, recentHandoffs, recentChatMessages, summaries) {
|
|
17544
|
+
const freshEnough = (epoch) => typeof epoch === "number" && observationAgeDays(epoch) <= FRESH_CONTINUITY_WINDOW_DAYS;
|
|
17545
|
+
return recentPrompts.some((item) => freshEnough(item.created_at_epoch)) || recentToolEvents.some((item) => freshEnough(item.created_at_epoch)) || recentSessions.some((item) => freshEnough(item.completed_at_epoch ?? item.started_at_epoch)) || recentHandoffs.some((item) => freshEnough(item.created_at_epoch)) || recentChatMessages.some((item) => freshEnough(item.created_at_epoch)) || summaries.some((item) => freshEnough(item.created_at_epoch));
|
|
17546
|
+
}
|
|
17547
|
+
function summariesFromRecentSessions(db, projectId, recentSessions) {
|
|
17548
|
+
const seen = new Set;
|
|
17549
|
+
const rows = [];
|
|
17550
|
+
for (const session of recentSessions) {
|
|
17551
|
+
if (seen.has(session.session_id))
|
|
17552
|
+
continue;
|
|
17553
|
+
seen.add(session.session_id);
|
|
17554
|
+
const summary = db.getSessionSummary(session.session_id);
|
|
17555
|
+
if (summary && summary.project_id === projectId)
|
|
17556
|
+
rows.push(summary);
|
|
17557
|
+
}
|
|
17558
|
+
return rows;
|
|
17559
|
+
}
|
|
17560
|
+
function observationAgeDays(createdAtEpoch) {
|
|
17561
|
+
return Math.max(0, (Math.floor(Date.now() / 1000) - createdAtEpoch) / 86400);
|
|
17562
|
+
}
|
|
17497
17563
|
function estimateObservationTokens(obs, index) {
|
|
17498
17564
|
const DETAILED_THRESHOLD = 5;
|
|
17499
17565
|
const titleCost = estimateTokens(`- **[${obs.type}]** ${obs.title} (2026-01-01, q=0.5)`);
|
|
@@ -17948,9 +18014,12 @@ function getProjectMemoryIndex(db, input) {
|
|
|
17948
18014
|
`)
|
|
17949
18015
|
].filter(Boolean).join(`
|
|
17950
18016
|
`));
|
|
18017
|
+
const continuityState = classifyContinuityState(recentRequestsCount, recentToolsCount, recentHandoffsCount.length, recentChatCount, recentSessions, recentOutcomes.length);
|
|
17951
18018
|
return {
|
|
17952
18019
|
project: project.name,
|
|
17953
18020
|
canonical_id: project.canonical_id,
|
|
18021
|
+
continuity_state: continuityState,
|
|
18022
|
+
continuity_summary: describeContinuityState(continuityState),
|
|
17954
18023
|
observation_counts: counts,
|
|
17955
18024
|
recent_sessions: recentSessions,
|
|
17956
18025
|
recent_outcomes: recentOutcomes,
|
|
@@ -17972,6 +18041,26 @@ function getProjectMemoryIndex(db, input) {
|
|
|
17972
18041
|
suggested_tools: suggestedTools
|
|
17973
18042
|
};
|
|
17974
18043
|
}
|
|
18044
|
+
function classifyContinuityState(recentRequestsCount, recentToolsCount, recentHandoffsCount, recentChatCount, recentSessions, recentOutcomesCount) {
|
|
18045
|
+
const hasRaw = recentRequestsCount > 0 || recentToolsCount > 0;
|
|
18046
|
+
const hasResume = recentHandoffsCount > 0 || recentChatCount > 0;
|
|
18047
|
+
const hasSessionThread = recentSessions.length > 0 || recentOutcomesCount > 0;
|
|
18048
|
+
if (hasRaw && (hasResume || hasSessionThread))
|
|
18049
|
+
return "fresh";
|
|
18050
|
+
if (hasRaw || hasResume || hasSessionThread)
|
|
18051
|
+
return "thin";
|
|
18052
|
+
return "cold";
|
|
18053
|
+
}
|
|
18054
|
+
function describeContinuityState(state) {
|
|
18055
|
+
switch (state) {
|
|
18056
|
+
case "fresh":
|
|
18057
|
+
return "Fresh repo-local continuity is available.";
|
|
18058
|
+
case "thin":
|
|
18059
|
+
return "Only partial continuity is available; recent prompts/chat are safer than older memory.";
|
|
18060
|
+
default:
|
|
18061
|
+
return "No fresh repo-local continuity yet; older memory should be treated cautiously.";
|
|
18062
|
+
}
|
|
18063
|
+
}
|
|
17975
18064
|
function extractPaths(value) {
|
|
17976
18065
|
if (!value)
|
|
17977
18066
|
return [];
|
|
@@ -18078,9 +18167,12 @@ function getMemoryConsole(db, input) {
|
|
|
18078
18167
|
cwd,
|
|
18079
18168
|
user_id: input.user_id
|
|
18080
18169
|
}) : null;
|
|
18170
|
+
const continuityState = projectIndex?.continuity_state ?? classifyContinuityState(requests.length, tools.length, recentHandoffs.length, recentChat.length, sessions, (projectIndex?.recent_outcomes ?? []).length);
|
|
18081
18171
|
return {
|
|
18082
18172
|
project: project?.name,
|
|
18083
18173
|
capture_mode: requests.length > 0 || tools.length > 0 ? "rich" : "observations-only",
|
|
18174
|
+
continuity_state: continuityState,
|
|
18175
|
+
continuity_summary: projectIndex?.continuity_summary ?? describeContinuityState(continuityState),
|
|
18084
18176
|
sessions,
|
|
18085
18177
|
requests,
|
|
18086
18178
|
tools,
|
|
@@ -18622,16 +18714,65 @@ function getCaptureQuality(db, input = {}) {
|
|
|
18622
18714
|
summary_only: allSessions.filter((s) => s.capture_state === "summary-only").length,
|
|
18623
18715
|
legacy: allSessions.filter((s) => s.capture_state === "legacy").length
|
|
18624
18716
|
};
|
|
18625
|
-
const
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
|
|
18634
|
-
|
|
18717
|
+
const chatCoverageRow = db.db.query(`SELECT
|
|
18718
|
+
COUNT(DISTINCT CASE WHEN source_kind = 'transcript' THEN session_id END) as transcript_backed_sessions,
|
|
18719
|
+
COUNT(DISTINCT CASE
|
|
18720
|
+
WHEN source_kind = 'hook'
|
|
18721
|
+
AND NOT EXISTS (
|
|
18722
|
+
SELECT 1 FROM chat_messages t2
|
|
18723
|
+
WHERE t2.session_id = chat_messages.session_id
|
|
18724
|
+
AND t2.source_kind = 'transcript'
|
|
18725
|
+
)
|
|
18726
|
+
THEN session_id
|
|
18727
|
+
END) as hook_only_sessions,
|
|
18728
|
+
COUNT(*) as chat_messages
|
|
18729
|
+
FROM chat_messages
|
|
18730
|
+
WHERE 1 = 1
|
|
18731
|
+
${input.user_id ? " AND user_id = ?" : ""}`).get(...input.user_id ? [input.user_id] : []) ?? {
|
|
18732
|
+
transcript_backed_sessions: 0,
|
|
18733
|
+
hook_only_sessions: 0,
|
|
18734
|
+
chat_messages: 0
|
|
18735
|
+
};
|
|
18736
|
+
const chatCoverageByProject = new Map;
|
|
18737
|
+
const chatRows = db.db.query(`SELECT p.canonical_id, cm.source_kind, COUNT(*) as count
|
|
18738
|
+
FROM chat_messages cm
|
|
18739
|
+
JOIN projects p ON p.id = cm.project_id
|
|
18740
|
+
WHERE cm.project_id IS NOT NULL
|
|
18741
|
+
${input.user_id ? " AND cm.user_id = ?" : ""}
|
|
18742
|
+
GROUP BY p.canonical_id, cm.source_kind`).all(...input.user_id ? [input.user_id] : []);
|
|
18743
|
+
for (const row of chatRows) {
|
|
18744
|
+
const current = chatCoverageByProject.get(row.canonical_id) ?? {
|
|
18745
|
+
chat_message_count: 0,
|
|
18746
|
+
transcript_count: 0,
|
|
18747
|
+
hook_only_count: 0
|
|
18748
|
+
};
|
|
18749
|
+
current.chat_message_count += row.count;
|
|
18750
|
+
if (row.source_kind === "transcript") {
|
|
18751
|
+
current.transcript_count += row.count;
|
|
18752
|
+
} else {
|
|
18753
|
+
current.hook_only_count += row.count;
|
|
18754
|
+
}
|
|
18755
|
+
chatCoverageByProject.set(row.canonical_id, current);
|
|
18756
|
+
}
|
|
18757
|
+
const topProjects = workspace.projects.slice(0, limit).map((project) => {
|
|
18758
|
+
const chat = chatCoverageByProject.get(project.canonical_id) ?? {
|
|
18759
|
+
chat_message_count: 0,
|
|
18760
|
+
transcript_count: 0,
|
|
18761
|
+
hook_only_count: 0
|
|
18762
|
+
};
|
|
18763
|
+
return {
|
|
18764
|
+
name: project.name,
|
|
18765
|
+
canonical_id: project.canonical_id,
|
|
18766
|
+
observation_count: project.observation_count,
|
|
18767
|
+
session_count: project.session_count,
|
|
18768
|
+
prompt_count: project.prompt_count,
|
|
18769
|
+
tool_event_count: project.tool_event_count,
|
|
18770
|
+
assistant_checkpoint_count: project.assistant_checkpoint_count,
|
|
18771
|
+
chat_message_count: chat.chat_message_count,
|
|
18772
|
+
chat_coverage_state: chat.transcript_count > 0 ? "transcript-backed" : chat.hook_only_count > 0 ? "hook-only" : "none",
|
|
18773
|
+
raw_capture_state: project.prompt_count > 0 && project.tool_event_count > 0 ? "rich" : project.prompt_count > 0 || project.tool_event_count > 0 ? "partial" : "summary-only"
|
|
18774
|
+
};
|
|
18775
|
+
});
|
|
18635
18776
|
const checkpointTypeRows = db.db.query(`SELECT type, COUNT(*) as count
|
|
18636
18777
|
FROM observations
|
|
18637
18778
|
WHERE source_tool = 'assistant-stop'
|
|
@@ -18666,9 +18807,14 @@ function getCaptureQuality(db, input = {}) {
|
|
|
18666
18807
|
sessions: workspace.totals.sessions,
|
|
18667
18808
|
prompts: workspace.totals.prompts,
|
|
18668
18809
|
tool_events: workspace.totals.tool_events,
|
|
18669
|
-
assistant_checkpoints: workspace.totals.assistant_checkpoints
|
|
18810
|
+
assistant_checkpoints: workspace.totals.assistant_checkpoints,
|
|
18811
|
+
chat_messages: chatCoverageRow.chat_messages
|
|
18670
18812
|
},
|
|
18671
18813
|
session_states: sessionStates,
|
|
18814
|
+
chat_coverage: {
|
|
18815
|
+
transcript_backed_sessions: chatCoverageRow.transcript_backed_sessions,
|
|
18816
|
+
hook_only_sessions: chatCoverageRow.hook_only_sessions
|
|
18817
|
+
},
|
|
18672
18818
|
projects_with_raw_capture: workspace.projects_with_raw_capture,
|
|
18673
18819
|
provenance_summary: workspace.provenance_summary,
|
|
18674
18820
|
provenance_type_mix: provenanceTypeMix,
|
|
@@ -18869,9 +19015,12 @@ function getSessionContext(db, input) {
|
|
|
18869
19015
|
}).messages.length;
|
|
18870
19016
|
const captureState = recentRequests > 0 && recentTools > 0 ? "rich" : recentRequests > 0 || recentTools > 0 ? "partial" : "summary-only";
|
|
18871
19017
|
const hotFiles = buildHotFiles(context);
|
|
19018
|
+
const continuityState = classifyContinuityState(recentRequests, recentTools, recentHandoffs, recentChatMessages, context.recentSessions ?? [], (context.recentOutcomes ?? []).length);
|
|
18872
19019
|
return {
|
|
18873
19020
|
project_name: context.project_name,
|
|
18874
19021
|
canonical_id: context.canonical_id,
|
|
19022
|
+
continuity_state: continuityState,
|
|
19023
|
+
continuity_summary: describeContinuityState(continuityState),
|
|
18875
19024
|
session_count: context.session_count,
|
|
18876
19025
|
total_active: context.total_active,
|
|
18877
19026
|
recent_requests: recentRequests,
|
|
@@ -21003,7 +21152,7 @@ process.on("SIGTERM", () => {
|
|
|
21003
21152
|
});
|
|
21004
21153
|
var server = new McpServer({
|
|
21005
21154
|
name: "engrm",
|
|
21006
|
-
version: "0.4.
|
|
21155
|
+
version: "0.4.26"
|
|
21007
21156
|
});
|
|
21008
21157
|
server.tool("save_observation", "Save an observation to memory", {
|
|
21009
21158
|
type: exports_external.enum([
|
|
@@ -21715,7 +21864,8 @@ server.tool("memory_console", "Show a high-signal local overview of what Engrm c
|
|
|
21715
21864
|
content: [
|
|
21716
21865
|
{
|
|
21717
21866
|
type: "text",
|
|
21718
|
-
text: `${projectLine}` + `${captureLine}` +
|
|
21867
|
+
text: `${projectLine}` + `${captureLine}` + `Continuity: ${result.continuity_state} — ${result.continuity_summary}
|
|
21868
|
+
` + `${typeof result.assistant_checkpoint_count === "number" ? `Assistant checkpoints: ${result.assistant_checkpoint_count}
|
|
21719
21869
|
` : ""}` + `Handoffs: ${result.saved_handoffs} saved, ${result.rolling_handoff_drafts} rolling drafts
|
|
21720
21870
|
` + `${typeof result.estimated_read_tokens === "number" ? `Estimated read cost: ~${result.estimated_read_tokens}t
|
|
21721
21871
|
` : ""}` + `Suggested tools: ${result.suggested_tools.join(", ") || "(none)"}
|
|
@@ -21798,16 +21948,18 @@ server.tool("capture_quality", "Show how healthy Engrm capture is across the wor
|
|
|
21798
21948
|
`) : "- (none)";
|
|
21799
21949
|
const checkpointTypeLines = result.assistant_checkpoint_types.length > 0 ? result.assistant_checkpoint_types.map((item) => `- ${item.type}: ${item.count}`).join(`
|
|
21800
21950
|
`) : "- (none)";
|
|
21801
|
-
const projectLines = result.top_projects.length > 0 ? result.top_projects.map((project) => `- ${project.name} [${project.raw_capture_state}] obs=${project.observation_count} sessions=${project.session_count} prompts=${project.prompt_count} tools=${project.tool_event_count} checkpoints=${project.assistant_checkpoint_count}`).join(`
|
|
21951
|
+
const projectLines = result.top_projects.length > 0 ? result.top_projects.map((project) => `- ${project.name} [${project.raw_capture_state}] obs=${project.observation_count} sessions=${project.session_count} prompts=${project.prompt_count} tools=${project.tool_event_count} checkpoints=${project.assistant_checkpoint_count} chat=${project.chat_message_count} (${project.chat_coverage_state})`).join(`
|
|
21802
21952
|
`) : "- (none)";
|
|
21803
21953
|
return {
|
|
21804
21954
|
content: [
|
|
21805
21955
|
{
|
|
21806
21956
|
type: "text",
|
|
21807
|
-
text: `Workspace totals: projects=${result.totals.projects}, observations=${result.totals.observations}, sessions=${result.totals.sessions}, prompts=${result.totals.prompts}, tools=${result.totals.tool_events}, checkpoints=${result.totals.assistant_checkpoints}
|
|
21957
|
+
text: `Workspace totals: projects=${result.totals.projects}, observations=${result.totals.observations}, sessions=${result.totals.sessions}, prompts=${result.totals.prompts}, tools=${result.totals.tool_events}, checkpoints=${result.totals.assistant_checkpoints}, chat=${result.totals.chat_messages}
|
|
21808
21958
|
|
|
21809
21959
|
` + `Session capture states: rich=${result.session_states.rich}, partial=${result.session_states.partial}, summary-only=${result.session_states.summary_only}, legacy=${result.session_states.legacy}
|
|
21810
21960
|
|
|
21961
|
+
` + `Chat recall coverage: transcript-backed sessions=${result.chat_coverage.transcript_backed_sessions}, hook-only sessions=${result.chat_coverage.hook_only_sessions}
|
|
21962
|
+
|
|
21811
21963
|
` + `Projects with raw capture: ${result.projects_with_raw_capture}
|
|
21812
21964
|
|
|
21813
21965
|
` + `Assistant checkpoints by type:
|
|
@@ -21910,6 +22062,7 @@ server.tool("session_context", "Preview the exact project memory context Engrm w
|
|
|
21910
22062
|
type: "text",
|
|
21911
22063
|
text: `Project: ${result.project_name}
|
|
21912
22064
|
` + `Canonical ID: ${result.canonical_id}
|
|
22065
|
+
` + `Continuity: ${result.continuity_state} — ${result.continuity_summary}
|
|
21913
22066
|
` + `Loaded observations: ${result.session_count}
|
|
21914
22067
|
` + `Searchable total: ${result.total_active}
|
|
21915
22068
|
` + `Recent requests: ${result.recent_requests}
|
|
@@ -21990,6 +22143,7 @@ server.tool("project_memory_index", "Show a typed local memory index for the cur
|
|
|
21990
22143
|
type: "text",
|
|
21991
22144
|
text: `Project: ${result.project}
|
|
21992
22145
|
` + `Canonical ID: ${result.canonical_id}
|
|
22146
|
+
` + `Continuity: ${result.continuity_state} — ${result.continuity_summary}
|
|
21993
22147
|
` + `Recent requests captured: ${result.recent_requests_count}
|
|
21994
22148
|
` + `Recent tools captured: ${result.recent_tools_count}
|
|
21995
22149
|
|
|
@@ -22258,6 +22412,9 @@ server.tool("recent_chat", "Inspect recently captured chat messages in the separ
|
|
|
22258
22412
|
const result = getRecentChat(db, params);
|
|
22259
22413
|
const projectLine = result.project ? `Project: ${result.project}
|
|
22260
22414
|
` : "";
|
|
22415
|
+
const coverageLine = `Coverage: ${result.messages.length} messages across ${result.session_count} session${result.session_count === 1 ? "" : "s"} ` + `· transcript ${result.source_summary.transcript} · hook ${result.source_summary.hook}
|
|
22416
|
+
` + `${result.transcript_backed ? "" : `Hint: run refresh_chat_recall if this looks under-captured.
|
|
22417
|
+
`}`;
|
|
22261
22418
|
const rows = result.messages.length > 0 ? result.messages.map((msg) => {
|
|
22262
22419
|
const stamp = new Date(msg.created_at_epoch * 1000).toISOString().split("T")[0];
|
|
22263
22420
|
return `- ${stamp} [${msg.role}] [${msg.source_kind}] ${msg.content.replace(/\s+/g, " ").trim().slice(0, 200)}`;
|
|
@@ -22267,7 +22424,7 @@ server.tool("recent_chat", "Inspect recently captured chat messages in the separ
|
|
|
22267
22424
|
content: [
|
|
22268
22425
|
{
|
|
22269
22426
|
type: "text",
|
|
22270
|
-
text: `${projectLine}Recent chat:
|
|
22427
|
+
text: `${projectLine}${coverageLine}Recent chat:
|
|
22271
22428
|
${rows}`
|
|
22272
22429
|
}
|
|
22273
22430
|
]
|
|
@@ -22283,6 +22440,9 @@ server.tool("search_chat", "Search the separate chat lane without mixing it into
|
|
|
22283
22440
|
const result = searchChat(db, params);
|
|
22284
22441
|
const projectLine = result.project ? `Project: ${result.project}
|
|
22285
22442
|
` : "";
|
|
22443
|
+
const coverageLine = `Coverage: ${result.messages.length} matches across ${result.session_count} session${result.session_count === 1 ? "" : "s"} ` + `· transcript ${result.source_summary.transcript} · hook ${result.source_summary.hook}
|
|
22444
|
+
` + `${result.transcript_backed ? "" : `Hint: run refresh_chat_recall if this looks under-captured.
|
|
22445
|
+
`}`;
|
|
22286
22446
|
const rows = result.messages.length > 0 ? result.messages.map((msg) => {
|
|
22287
22447
|
const stamp = new Date(msg.created_at_epoch * 1000).toISOString().split("T")[0];
|
|
22288
22448
|
return `- ${stamp} [${msg.role}] [${msg.source_kind}] ${msg.content.replace(/\s+/g, " ").trim().slice(0, 200)}`;
|
|
@@ -22292,7 +22452,7 @@ server.tool("search_chat", "Search the separate chat lane without mixing it into
|
|
|
22292
22452
|
content: [
|
|
22293
22453
|
{
|
|
22294
22454
|
type: "text",
|
|
22295
|
-
text: `${projectLine}Chat search for "${params.query}":
|
|
22455
|
+
text: `${projectLine}${coverageLine}Chat search for "${params.query}":
|
|
22296
22456
|
${rows}`
|
|
22297
22457
|
}
|
|
22298
22458
|
]
|