Add support for index view in context hook and refactor summary retrieval method
This commit is contained in:
@@ -8,9 +8,12 @@ import { contextHook } from '../../hooks/context.js';
|
|||||||
import { stdin } from 'process';
|
import { stdin } from 'process';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Check for --index flag
|
||||||
|
const useIndexView = process.argv.includes('--index');
|
||||||
|
|
||||||
if (stdin.isTTY) {
|
if (stdin.isTTY) {
|
||||||
// Running manually from terminal - print formatted output with colors
|
// Running manually from terminal - print formatted output with colors
|
||||||
const contextOutput = contextHook(undefined, true);
|
const contextOutput = contextHook(undefined, true, useIndexView);
|
||||||
console.log(contextOutput);
|
console.log(contextOutput);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
@@ -19,7 +22,7 @@ try {
|
|||||||
stdin.on('data', (chunk) => input += chunk);
|
stdin.on('data', (chunk) => input += chunk);
|
||||||
stdin.on('end', () => {
|
stdin.on('end', () => {
|
||||||
const parsed = input.trim() ? JSON.parse(input) : undefined;
|
const parsed = input.trim() ? JSON.parse(input) : undefined;
|
||||||
const contextOutput = contextHook(parsed, false);
|
const contextOutput = contextHook(parsed, false, useIndexView);
|
||||||
const result = {
|
const result = {
|
||||||
hookSpecificOutput: {
|
hookSpecificOutput: {
|
||||||
hookEventName: "SessionStart",
|
hookEventName: "SessionStart",
|
||||||
|
|||||||
+202
-157
@@ -30,7 +30,7 @@ const colors = {
|
|||||||
*
|
*
|
||||||
* Output: Returns formatted context string to be wrapped in hookSpecificOutput
|
* Output: Returns formatted context string to be wrapped in hookSpecificOutput
|
||||||
*/
|
*/
|
||||||
export function contextHook(input?: SessionStartInput, useColors: boolean = false): string {
|
export function contextHook(input?: SessionStartInput, useColors: boolean = false, useIndexView: boolean = false): string {
|
||||||
// v4.0.0: Ensure worker is running before loading context
|
// v4.0.0: Ensure worker is running before loading context
|
||||||
ensureWorkerRunning();
|
ensureWorkerRunning();
|
||||||
const cwd = input?.cwd ?? process.cwd();
|
const cwd = input?.cwd ?? process.cwd();
|
||||||
@@ -39,215 +39,260 @@ export function contextHook(input?: SessionStartInput, useColors: boolean = fals
|
|||||||
const db = new SessionStore();
|
const db = new SessionStore();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const sessions = db.getRecentSessionsWithStatus(project, 3);
|
const summaries = db.getRecentSummariesWithSessionInfo(project, 3);
|
||||||
|
|
||||||
if (sessions.length === 0) {
|
if (summaries.length === 0) {
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
return `\n${colors.bright}${colors.cyan}📝 Recent Session Context${colors.reset}\n\n${colors.dim}No previous sessions found for this project yet.${colors.reset}\n`;
|
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 '# Recent Session Context\n\nNo previous sessions found for this project yet.';
|
return `# [${project}] recent context\n\nNo previous summaries found for this project yet.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const output: string[] = [];
|
const output: string[] = [];
|
||||||
|
|
||||||
if (useColors) {
|
// Index view: Show previous as index, latest in full at bottom (chat-style)
|
||||||
output.push('');
|
if (useIndexView) {
|
||||||
output.push(`${colors.bright}${colors.cyan}📝 Recent Session Context${colors.reset}`);
|
|
||||||
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
|
|
||||||
output.push(`${colors.dim}Showing last ${sessions.length} session(s) for ${colors.reset}${colors.bright}${project}${colors.reset}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (useColors) {
|
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(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
|
||||||
output.push('');
|
output.push('');
|
||||||
} else {
|
} else {
|
||||||
output.push('---');
|
output.push(`# [${project}] recent context`);
|
||||||
output.push('');
|
output.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if session has a summary
|
// Show index of previous summaries (oldest to newest)
|
||||||
if (session.has_summary) {
|
if (summaries.length > 1) {
|
||||||
const summary = db.getSummaryForSession(session.sdk_session_id);
|
|
||||||
|
|
||||||
if (summary) {
|
|
||||||
const promptLabel = summary.prompt_number ? ` (Prompt #${summary.prompt_number})` : '';
|
|
||||||
|
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}${colors.green}✓ Summary${promptLabel}${colors.reset}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Summary${promptLabel}**`);
|
|
||||||
output.push('');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summary.request) {
|
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${summary.request}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Request:** ${summary.request}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summary.learned) {
|
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}${colors.blue}Learned:${colors.reset} ${summary.learned}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Learned:** ${summary.learned}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summary.completed) {
|
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}${colors.green}Completed:${colors.reset} ${summary.completed}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Completed:** ${summary.completed}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get files from observations (not from summary which is never populated)
|
|
||||||
const sessionFiles = db.getFilesForSession(session.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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (session.status === 'active') {
|
|
||||||
// Active session without summary - show observation titles
|
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
output.push(`${colors.bright}${colors.yellow}⏳ In Progress${colors.reset}`);
|
output.push(`${colors.bright}${colors.dim}Previous Requests:${colors.reset}`);
|
||||||
output.push('');
|
output.push('');
|
||||||
} else {
|
} else {
|
||||||
output.push(`**In Progress**`);
|
output.push('**Previous Requests:**');
|
||||||
output.push('');
|
output.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.user_prompt) {
|
// 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) {
|
if (useColors) {
|
||||||
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${session.user_prompt}`);
|
output.push(`${colors.dim}• ${dateTimeStr}:${colors.reset} ${prev.request || '(no request)'}`);
|
||||||
output.push('');
|
|
||||||
} else {
|
} else {
|
||||||
output.push(`**Request:** ${session.user_prompt}`);
|
output.push(`- ${dateTimeStr}: ${prev.request || '(no request)'}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const observations = db.getObservationsForSession(session.sdk_session_id);
|
if (useColors) {
|
||||||
|
output.push('');
|
||||||
if (observations.length > 0) {
|
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
|
||||||
output.push('');
|
output.push('');
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}Observations (${observations.length}):${colors.reset}`);
|
|
||||||
for (const obs of observations) {
|
|
||||||
output.push(` ${colors.dim}•${colors.reset} ${obs.title}`);
|
|
||||||
}
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Observations (${observations.length}):**`);
|
|
||||||
for (const obs of observations) {
|
|
||||||
output.push(`- ${obs.title}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
output.push('');
|
output.push('');
|
||||||
if (useColors) {
|
output.push('---');
|
||||||
output.push(`${colors.dim}No observations yet${colors.reset}`);
|
output.push('');
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push('*No observations yet*');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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('');
|
||||||
const activeDateTime = new Date(session.started_at).toLocaleString();
|
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('');
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (useColors) {
|
||||||
output.push(`${colors.dim}Status: Active - summary pending${colors.reset}`);
|
output.push('');
|
||||||
output.push(`${colors.dim}Date: ${activeDateTime}${colors.reset}`);
|
output.push(`${colors.dim}${'─'.repeat(23)} New Session ${'─'.repeat(24)}${colors.reset}`);
|
||||||
|
output.push('');
|
||||||
} else {
|
} else {
|
||||||
output.push(`**Status:** Active - summary pending`);
|
output.push('');
|
||||||
output.push(`**Date:** ${activeDateTime}`);
|
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 {
|
} else {
|
||||||
// Failed or completed session without summary
|
// First summary - just add a blank line after header
|
||||||
const displayStatus = session.status === 'failed' ? 'stopped' : session.status;
|
|
||||||
const statusIcon = session.status === 'failed' ? '⚠️' : '○';
|
|
||||||
|
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
const statusColor = session.status === 'failed' ? colors.yellow : colors.gray;
|
|
||||||
output.push(`${colors.bright}${statusColor}${statusIcon} ${displayStatus.charAt(0).toUpperCase() + displayStatus.slice(1)}${colors.reset}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**${displayStatus.charAt(0).toUpperCase() + displayStatus.slice(1)}**`);
|
|
||||||
output.push('');
|
output.push('');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (session.user_prompt) {
|
isFirstSummary = false;
|
||||||
if (useColors) {
|
|
||||||
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${session.user_prompt}`);
|
|
||||||
output.push('');
|
|
||||||
} else {
|
|
||||||
output.push(`**Request:** ${session.user_prompt}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output.push('');
|
if (summary.request) {
|
||||||
const failedDateTime = new Date(session.started_at).toLocaleString();
|
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
output.push(`${colors.dim}Status: ${displayStatus} - no summary available${colors.reset}`);
|
output.push(`${colors.bright}${colors.yellow}Request:${colors.reset} ${summary.request}`);
|
||||||
output.push(`${colors.dim}Date: ${failedDateTime}${colors.reset}`);
|
output.push('');
|
||||||
} else {
|
} else {
|
||||||
output.push(`**Status:** ${displayStatus} - no summary available`);
|
output.push(`**Request:** ${summary.request}`);
|
||||||
output.push(`**Date:** ${failedDateTime}`);
|
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) {
|
if (!useColors) {
|
||||||
output.push('');
|
output.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previousSessionId = summary.sdk_session_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
output.push('');
|
output.push('');
|
||||||
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
|
output.push(`${colors.gray}${'─'.repeat(60)}${colors.reset}`);
|
||||||
output.push('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join('\n');
|
return output.join('\n');
|
||||||
|
|||||||
@@ -433,6 +433,31 @@ export class SessionStore {
|
|||||||
return stmt.all(project, limit) as any[];
|
return stmt.all(project, limit) as any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get recent summaries with session info for context display
|
||||||
|
*/
|
||||||
|
getRecentSummariesWithSessionInfo(project: string, limit: number = 3): Array<{
|
||||||
|
sdk_session_id: string;
|
||||||
|
request: string | null;
|
||||||
|
learned: string | null;
|
||||||
|
completed: string | null;
|
||||||
|
next_steps: string | null;
|
||||||
|
prompt_number: number | null;
|
||||||
|
created_at: string;
|
||||||
|
}> {
|
||||||
|
const stmt = this.db.prepare(`
|
||||||
|
SELECT
|
||||||
|
sdk_session_id, request, learned, completed, next_steps,
|
||||||
|
prompt_number, created_at
|
||||||
|
FROM session_summaries
|
||||||
|
WHERE project = ?
|
||||||
|
ORDER BY created_at_epoch DESC
|
||||||
|
LIMIT ?
|
||||||
|
`);
|
||||||
|
|
||||||
|
return stmt.all(project, limit) as any[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get recent observations for a project
|
* Get recent observations for a project
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user