Refactor contextHook to simplify recent summaries retrieval and output formatting

- Updated contextHook to query session_summaries directly instead of using sdk_sessions table.
- Removed unnecessary complexity in output formatting, focusing on recent summaries for the project.
- Enhanced file reading and modification tracking by parsing observations directly.
- Made the database connection public in SessionStore for easier access.
This commit is contained in:
Alex Newman
2025-10-21 22:36:41 -04:00
parent 3ca5e33b4a
commit 1c25c3a7e7
5 changed files with 111 additions and 284 deletions
+63 -240
View File
@@ -26,12 +26,9 @@ const colors = {
/**
* Context Hook - SessionStart
* Shows user what happened in recent sessions
*
* Output: Returns formatted context string to be wrapped in hookSpecificOutput
* Shows recent summaries for the project
*/
export function contextHook(input?: SessionStartInput, useColors: boolean = false, useIndexView: boolean = false): string {
// v4.0.0: Ensure worker is running before loading context
ensureWorkerRunning();
const cwd = input?.cwd ?? process.cwd();
const project = cwd ? path.basename(cwd) : 'unknown-project';
@@ -39,260 +36,86 @@ export function contextHook(input?: SessionStartInput, useColors: boolean = fals
const db = new SessionStore();
try {
const summaries = db.getRecentSummariesWithSessionInfo(project, 3);
// Query session_summaries directly - no need for sdk_sessions table
const summaries = db.db.prepare(`
SELECT sdk_session_id, request, learned, completed, next_steps, created_at
FROM session_summaries
WHERE project = ?
ORDER BY created_at_epoch DESC
LIMIT 3
`).all(project) as Array<{
sdk_session_id: string;
request: string | null;
learned: string | null;
completed: string | null;
next_steps: string | null;
created_at: string;
}>;
if (summaries.length === 0) {
if (useColors) {
return `\n${colors.bright}${colors.cyan}📝 [${project}] recent context${colors.reset}\n${colors.gray}${'─'.repeat(60)}${colors.reset}\n\n${colors.dim}No previous summaries found for this project yet.${colors.reset}\n`;
}
return `# [${project}] recent context\n\nNo previous summaries found for this project yet.`;
}
const output: string[] = [];
// Index view: Show previous as index, latest in full at bottom (chat-style)
if (useIndexView) {
if (useColors) {
output.push('');
output.push(`${colors.bright}${colors.cyan}📝 [${project}] recent context${colors.reset}`);
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
output.push('');
} else {
output.push(`# [${project}] recent context`);
output.push('');
}
// Show index of previous summaries (oldest to newest)
if (summaries.length > 1) {
if (useColors) {
output.push(`${colors.bright}${colors.dim}Previous Requests:${colors.reset}`);
output.push('');
} else {
output.push('**Previous Requests:**');
output.push('');
}
// Iterate backwards through array (skip first which is most recent)
for (let i = summaries.length - 1; i >= 1; i--) {
const prev = summaries[i];
const prevDate = new Date(prev.created_at);
const dateTimeStr = prevDate.toLocaleString();
if (useColors) {
output.push(`${colors.dim}${dateTimeStr}:${colors.reset} ${prev.request || '(no request)'}`);
} else {
output.push(`- ${dateTimeStr}: ${prev.request || '(no request)'}`);
}
}
if (useColors) {
output.push('');
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
output.push('');
} else {
output.push('');
output.push('---');
output.push('');
}
}
// Show most recent summary in full at the bottom
const latest = summaries[0];
if (latest.request) {
if (useColors) {
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${latest.request}`);
output.push('');
} else {
output.push(`**Request:** ${latest.request}`);
output.push('');
}
}
if (latest.learned) {
if (useColors) {
output.push(`${colors.bright}${colors.blue}Learned:${colors.reset} ${latest.learned}`);
output.push('');
} else {
output.push(`**Learned:** ${latest.learned}`);
output.push('');
}
}
if (latest.completed) {
if (useColors) {
output.push(`${colors.bright}${colors.green}Completed:${colors.reset} ${latest.completed}`);
output.push('');
} else {
output.push(`**Completed:** ${latest.completed}`);
output.push('');
}
}
if (latest.next_steps) {
if (useColors) {
output.push(`${colors.bright}${colors.magenta}Next Steps:${colors.reset} ${latest.next_steps}`);
output.push('');
} else {
output.push(`**Next Steps:** ${latest.next_steps}`);
output.push('');
}
}
// Get files for latest summary
const latestFiles = db.getFilesForSession(latest.sdk_session_id);
if (latestFiles.filesRead.length > 0) {
if (useColors) {
output.push(`${colors.dim}Files Read: ${latestFiles.filesRead.join(', ')}${colors.reset}`);
} else {
output.push(`**Files Read:** ${latestFiles.filesRead.join(', ')}`);
}
}
if (latestFiles.filesModified.length > 0) {
if (useColors) {
output.push(`${colors.dim}Files Modified: ${latestFiles.filesModified.join(', ')}${colors.reset}`);
} else {
output.push(`**Files Modified:** ${latestFiles.filesModified.join(', ')}`);
}
}
const latestDate = new Date(latest.created_at).toLocaleString();
if (useColors) {
output.push(`${colors.dim}Date: ${latestDate}${colors.reset}`);
} else {
output.push(`**Date:** ${latestDate}`);
}
if (useColors) {
output.push('');
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
}
return output.join('\n');
}
if (useColors) {
output.push('');
output.push(`${colors.bright}${colors.cyan}📝 [${project}] recent context${colors.reset}`);
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
} else {
output.push(`# [${project}] recent context`);
output.push('');
}
output.push(`# [${project}] recent context`);
output.push('');
let previousSessionId: string | null = null;
let isFirstSummary = true;
for (const summary of summaries) {
// Add session break indicator if this is a different session
const isNewSession = previousSessionId !== null && summary.sdk_session_id !== previousSessionId;
if (isNewSession) {
if (useColors) {
output.push('');
output.push(`${colors.dim}${'─'.repeat(23)} New Session ${'─'.repeat(24)}${colors.reset}`);
output.push('');
} else {
output.push('');
output.push('--- New Session ---');
output.push('');
}
} else if (!isFirstSummary) {
// Only show regular separator if not first summary and not showing "New Session"
if (useColors) {
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
output.push('');
} else {
output.push('---');
output.push('');
}
} else {
// First summary - just add a blank line after header
if (useColors) {
output.push('');
}
}
isFirstSummary = false;
if (summary.request) {
if (useColors) {
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${summary.request}`);
output.push('');
} else {
output.push(`**Request:** ${summary.request}`);
output.push('');
}
}
if (summary.learned) {
if (useColors) {
output.push(`${colors.bright}${colors.blue}Learned:${colors.reset} ${summary.learned}`);
output.push('');
} else {
output.push(`**Learned:** ${summary.learned}`);
output.push('');
}
}
if (summary.completed) {
if (useColors) {
output.push(`${colors.bright}${colors.green}Completed:${colors.reset} ${summary.completed}`);
output.push('');
} else {
output.push(`**Completed:** ${summary.completed}`);
output.push('');
}
}
if (summary.next_steps) {
if (useColors) {
output.push(`${colors.bright}${colors.magenta}Next Steps:${colors.reset} ${summary.next_steps}`);
output.push('');
} else {
output.push(`**Next Steps:** ${summary.next_steps}`);
output.push('');
}
}
// Get files from observations (not from summary which is never populated)
const sessionFiles = db.getFilesForSession(summary.sdk_session_id);
if (sessionFiles.filesRead.length > 0) {
if (useColors) {
output.push(`${colors.dim}Files Read: ${sessionFiles.filesRead.join(', ')}${colors.reset}`);
} else {
output.push(`**Files Read:** ${sessionFiles.filesRead.join(', ')}`);
}
}
if (sessionFiles.filesModified.length > 0) {
if (useColors) {
output.push(`${colors.dim}Files Modified: ${sessionFiles.filesModified.join(', ')}${colors.reset}`);
} else {
output.push(`**Files Modified:** ${sessionFiles.filesModified.join(', ')}`);
}
}
const dateTime = new Date(summary.created_at).toLocaleString();
if (useColors) {
output.push(`${colors.dim}Date: ${dateTime}${colors.reset}`);
} else {
output.push(`**Date:** ${dateTime}`);
}
if (!useColors) {
output.push('');
output.push('--- New Session ---');
output.push('');
}
previousSessionId = summary.sdk_session_id;
}
if (summary.request) output.push(`**Request:** ${summary.request}`);
if (summary.learned) output.push(`**Learned:** ${summary.learned}`);
if (summary.completed) output.push(`**Completed:** ${summary.completed}`);
if (summary.next_steps) output.push(`**Next Steps:** ${summary.next_steps}`);
if (useColors) {
// Get files from observations by sdk_session_id
const observations = db.db.prepare(`
SELECT files_read, files_modified
FROM observations
WHERE sdk_session_id = ?
`).all(summary.sdk_session_id) as Array<{
files_read: string | null;
files_modified: string | null;
}>;
const filesReadSet = new Set<string>();
const filesModifiedSet = new Set<string>();
for (const obs of observations) {
if (obs.files_read) {
try {
const files = JSON.parse(obs.files_read);
if (Array.isArray(files)) files.forEach(f => filesReadSet.add(f));
} catch {}
}
if (obs.files_modified) {
try {
const files = JSON.parse(obs.files_modified);
if (Array.isArray(files)) files.forEach(f => filesModifiedSet.add(f));
} catch {}
}
}
if (filesReadSet.size > 0) {
output.push(`**Files Read:** ${Array.from(filesReadSet).join(', ')}`);
}
if (filesModifiedSet.size > 0) {
output.push(`**Files Modified:** ${Array.from(filesModifiedSet).join(', ')}`);
}
const dateTime = new Date(summary.created_at).toLocaleString();
output.push(`**Date:** ${dateTime}`);
output.push('');
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
previousSessionId = summary.sdk_session_id;
}
return output.join('\n');