7ff611feb5
- Removed try-catch blocks in new-hook, save-hook, and summary-hook for cleaner flow. - Enhanced error handling in save and summary hooks to throw errors instead of logging and returning. - Introduced ensureWorkerRunning utility to manage worker service lifecycle and health checks. - Replaced dynamic port allocation with a fixed port for the worker service. - Simplified path management and removed unused port allocator utility. - Added database schema initialization for fresh installations and improved migration handling.
150 lines
4.7 KiB
TypeScript
150 lines
4.7 KiB
TypeScript
import path from 'path';
|
|
import { SessionStore } from '../services/sqlite/SessionStore.js';
|
|
import { ensureWorkerRunning } from '../shared/worker-utils.js';
|
|
|
|
export interface SessionStartInput {
|
|
session_id?: string;
|
|
transcript_path?: string;
|
|
cwd?: string;
|
|
hook_event_name?: string;
|
|
source?: "startup" | "resume" | "clear" | "compact";
|
|
[key: string]: any;
|
|
}
|
|
|
|
/**
|
|
* Context Hook - SessionStart
|
|
* Shows user what happened in recent sessions
|
|
*
|
|
* Output: Returns formatted context string to be wrapped in hookSpecificOutput
|
|
*/
|
|
export function contextHook(input?: SessionStartInput): 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';
|
|
|
|
const db = new SessionStore();
|
|
|
|
try {
|
|
const sessions = db.getRecentSessionsWithStatus(project, 3);
|
|
|
|
if (sessions.length === 0) {
|
|
return '# Recent Session Context\n\nNo previous sessions found for this project yet.';
|
|
}
|
|
|
|
const output: string[] = [];
|
|
output.push('# Recent Session Context');
|
|
output.push('');
|
|
output.push(`Showing last ${sessions.length} session(s) for **${project}**:`);
|
|
output.push('');
|
|
|
|
for (const session of sessions) {
|
|
if (!session.sdk_session_id) continue;
|
|
|
|
output.push('---');
|
|
output.push('');
|
|
|
|
// Check if session has a summary
|
|
if (session.has_summary) {
|
|
const summary = db.getSummaryForSession(session.sdk_session_id);
|
|
|
|
if (summary) {
|
|
const promptLabel = summary.prompt_number ? ` (Prompt #${summary.prompt_number})` : '';
|
|
output.push(`**Summary${promptLabel}**`);
|
|
output.push('');
|
|
|
|
if (summary.request) {
|
|
output.push(`**Request:** ${summary.request}`);
|
|
}
|
|
|
|
if (summary.completed) {
|
|
output.push(`**Completed:** ${summary.completed}`);
|
|
}
|
|
|
|
if (summary.learned) {
|
|
output.push(`**Learned:** ${summary.learned}`);
|
|
}
|
|
|
|
if (summary.next_steps) {
|
|
output.push(`**Next Steps:** ${summary.next_steps}`);
|
|
}
|
|
|
|
if (summary.files_read) {
|
|
try {
|
|
const files = JSON.parse(summary.files_read);
|
|
if (Array.isArray(files) && files.length > 0) {
|
|
output.push(`**Files Read:** ${files.join(', ')}`);
|
|
}
|
|
} catch {
|
|
if (summary.files_read.trim()) {
|
|
output.push(`**Files Read:** ${summary.files_read}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (summary.files_edited) {
|
|
try {
|
|
const files = JSON.parse(summary.files_edited);
|
|
if (Array.isArray(files) && files.length > 0) {
|
|
output.push(`**Files Edited:** ${files.join(', ')}`);
|
|
}
|
|
} catch {
|
|
if (summary.files_edited.trim()) {
|
|
output.push(`**Files Edited:** ${summary.files_edited}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const dateTime = new Date(summary.created_at).toLocaleString();
|
|
output.push(`**Date:** ${dateTime}`);
|
|
}
|
|
} else if (session.status === 'active') {
|
|
// Active session without summary - show observation titles
|
|
output.push(`**In Progress**`);
|
|
output.push('');
|
|
|
|
if (session.user_prompt) {
|
|
output.push(`**Request:** ${session.user_prompt}`);
|
|
}
|
|
|
|
const observations = db.getObservationsForSession(session.sdk_session_id);
|
|
|
|
if (observations.length > 0) {
|
|
output.push('');
|
|
output.push(`**Observations (${observations.length}):**`);
|
|
for (const obs of observations) {
|
|
output.push(`- ${obs.title}`);
|
|
}
|
|
} else {
|
|
output.push('');
|
|
output.push('*No observations yet*');
|
|
}
|
|
|
|
output.push('');
|
|
output.push(`**Status:** Active - summary pending`);
|
|
const activeDateTime = new Date(session.started_at).toLocaleString();
|
|
output.push(`**Date:** ${activeDateTime}`);
|
|
} else {
|
|
// Failed or completed session without summary
|
|
const displayStatus = session.status === 'failed' ? 'stopped' : session.status;
|
|
output.push(`**${displayStatus.charAt(0).toUpperCase() + displayStatus.slice(1)}**`);
|
|
output.push('');
|
|
|
|
if (session.user_prompt) {
|
|
output.push(`**Request:** ${session.user_prompt}`);
|
|
}
|
|
|
|
output.push('');
|
|
output.push(`**Status:** ${displayStatus} - no summary available`);
|
|
const failedDateTime = new Date(session.started_at).toLocaleString();
|
|
output.push(`**Date:** ${failedDateTime}`);
|
|
}
|
|
|
|
output.push('');
|
|
}
|
|
|
|
return output.join('\n');
|
|
} finally {
|
|
db.close();
|
|
}
|
|
} |