refactor: improve type safety by removing 'as any' casts
Created database.ts with proper database result types and replaced 38+ 'as any' casts throughout the codebase with proper type annotations. Changes: - Created src/types/database.ts with TableColumnInfo, IndexInfo, and database record types - Fixed all type casts in SessionStore.ts (migrations, query results) - Fixed type casts in SessionSearch.ts, SettingsManager.ts, SettingsRoutes.ts - Improved MCP server JSON schema typing All builds pass and worker service runs successfully. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -383,7 +383,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
tools: tools.map(tool => ({
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
inputSchema: zodToJsonSchema(tool.inputSchema) as any
|
||||
inputSchema: zodToJsonSchema(tool.inputSchema) as Record<string, unknown>
|
||||
}))
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { TableNameRow } from '../../types/database.js';
|
||||
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
|
||||
import {
|
||||
ObservationSearchResult,
|
||||
@@ -48,8 +49,8 @@ export class SessionSearch {
|
||||
private ensureFTSTables(): void {
|
||||
try {
|
||||
// Check if FTS tables already exist
|
||||
const tables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts'").all() as any[];
|
||||
const hasFTS = tables.some((t: any) => t.name === 'observations_fts' || t.name === 'session_summaries_fts');
|
||||
const tables = this.db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts'").all() as TableNameRow[];
|
||||
const hasFTS = tables.some(t => t.name === 'observations_fts' || t.name === 'session_summaries_fts');
|
||||
|
||||
if (hasFTS) {
|
||||
// Already migrated
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
|
||||
import { logger } from '../../utils/logger.js';
|
||||
import {
|
||||
TableColumnInfo,
|
||||
IndexInfo,
|
||||
TableNameRow,
|
||||
SchemaVersion,
|
||||
SdkSessionRecord,
|
||||
ObservationRecord,
|
||||
SessionSummaryRecord,
|
||||
UserPromptRecord,
|
||||
LatestPromptResult
|
||||
} from '../../types/database.js';
|
||||
|
||||
/**
|
||||
* Session data store for SDK sessions, observations, and summaries
|
||||
@@ -47,7 +58,7 @@ export class SessionStore {
|
||||
`);
|
||||
|
||||
// Get applied migrations
|
||||
const appliedVersions = this.db.prepare('SELECT version FROM schema_versions ORDER BY version').all() as Array<{version: number}>;
|
||||
const appliedVersions = this.db.prepare('SELECT version FROM schema_versions ORDER BY version').all() as SchemaVersion[];
|
||||
const maxApplied = appliedVersions.length > 0 ? Math.max(...appliedVersions.map(v => v.version)) : 0;
|
||||
|
||||
// Only run migration004 if no migrations have been applied
|
||||
@@ -131,12 +142,12 @@ export class SessionStore {
|
||||
private ensureWorkerPortColumn(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(5) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(5) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if column exists
|
||||
const tableInfo = this.db.pragma('table_info(sdk_sessions)');
|
||||
const hasWorkerPort = (tableInfo as any[]).some((col: any) => col.name === 'worker_port');
|
||||
const tableInfo = this.db.pragma('table_info(sdk_sessions)') as TableColumnInfo[];
|
||||
const hasWorkerPort = tableInfo.some(col => col.name === 'worker_port');
|
||||
|
||||
if (!hasWorkerPort) {
|
||||
this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN worker_port INTEGER');
|
||||
@@ -156,12 +167,12 @@ export class SessionStore {
|
||||
private ensurePromptTrackingColumns(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(6) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(6) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check sdk_sessions for prompt_counter
|
||||
const sessionsInfo = this.db.pragma('table_info(sdk_sessions)');
|
||||
const hasPromptCounter = (sessionsInfo as any[]).some((col: any) => col.name === 'prompt_counter');
|
||||
const sessionsInfo = this.db.pragma('table_info(sdk_sessions)') as TableColumnInfo[];
|
||||
const hasPromptCounter = sessionsInfo.some(col => col.name === 'prompt_counter');
|
||||
|
||||
if (!hasPromptCounter) {
|
||||
this.db.exec('ALTER TABLE sdk_sessions ADD COLUMN prompt_counter INTEGER DEFAULT 0');
|
||||
@@ -169,8 +180,8 @@ export class SessionStore {
|
||||
}
|
||||
|
||||
// Check observations for prompt_number
|
||||
const observationsInfo = this.db.pragma('table_info(observations)');
|
||||
const obsHasPromptNumber = (observationsInfo as any[]).some((col: any) => col.name === 'prompt_number');
|
||||
const observationsInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
|
||||
const obsHasPromptNumber = observationsInfo.some(col => col.name === 'prompt_number');
|
||||
|
||||
if (!obsHasPromptNumber) {
|
||||
this.db.exec('ALTER TABLE observations ADD COLUMN prompt_number INTEGER');
|
||||
@@ -178,8 +189,8 @@ export class SessionStore {
|
||||
}
|
||||
|
||||
// Check session_summaries for prompt_number
|
||||
const summariesInfo = this.db.pragma('table_info(session_summaries)');
|
||||
const sumHasPromptNumber = (summariesInfo as any[]).some((col: any) => col.name === 'prompt_number');
|
||||
const summariesInfo = this.db.pragma('table_info(session_summaries)') as TableColumnInfo[];
|
||||
const sumHasPromptNumber = summariesInfo.some(col => col.name === 'prompt_number');
|
||||
|
||||
if (!sumHasPromptNumber) {
|
||||
this.db.exec('ALTER TABLE session_summaries ADD COLUMN prompt_number INTEGER');
|
||||
@@ -199,12 +210,12 @@ export class SessionStore {
|
||||
private removeSessionSummariesUniqueConstraint(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(7) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(7) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if UNIQUE constraint exists
|
||||
const summariesIndexes = this.db.pragma('index_list(session_summaries)');
|
||||
const hasUniqueConstraint = (summariesIndexes as any[]).some((idx: any) => idx.unique === 1);
|
||||
const summariesIndexes = this.db.pragma('index_list(session_summaries)') as IndexInfo[];
|
||||
const hasUniqueConstraint = summariesIndexes.some(idx => idx.unique === 1);
|
||||
|
||||
if (!hasUniqueConstraint) {
|
||||
// Already migrated (no constraint exists)
|
||||
@@ -284,12 +295,12 @@ export class SessionStore {
|
||||
private addObservationHierarchicalFields(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(8) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(8) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if new fields already exist
|
||||
const tableInfo = this.db.pragma('table_info(observations)');
|
||||
const hasTitle = (tableInfo as any[]).some((col: any) => col.name === 'title');
|
||||
const tableInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
|
||||
const hasTitle = tableInfo.some(col => col.name === 'title');
|
||||
|
||||
if (hasTitle) {
|
||||
// Already migrated
|
||||
@@ -326,12 +337,12 @@ export class SessionStore {
|
||||
private makeObservationsTextNullable(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(9) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(9) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if text column is already nullable
|
||||
const tableInfo = this.db.pragma('table_info(observations)');
|
||||
const textColumn = (tableInfo as any[]).find((col: any) => col.name === 'text');
|
||||
const tableInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
|
||||
const textColumn = tableInfo.find(col => col.name === 'text');
|
||||
|
||||
if (!textColumn || textColumn.notnull === 0) {
|
||||
// Already migrated or text column doesn't exist
|
||||
@@ -413,12 +424,12 @@ export class SessionStore {
|
||||
private createUserPromptsTable(): void {
|
||||
try {
|
||||
// Check if migration already applied
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(10) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(10) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if table already exists
|
||||
const tableInfo = this.db.pragma('table_info(user_prompts)');
|
||||
if ((tableInfo as any[]).length > 0) {
|
||||
const tableInfo = this.db.pragma('table_info(user_prompts)') as TableColumnInfo[];
|
||||
if (tableInfo.length > 0) {
|
||||
// Already migrated
|
||||
this.db.prepare('INSERT OR IGNORE INTO schema_versions (version, applied_at) VALUES (?, ?)').run(10, new Date().toISOString());
|
||||
return;
|
||||
@@ -502,12 +513,12 @@ export class SessionStore {
|
||||
private ensureDiscoveryTokensColumn(): void {
|
||||
try {
|
||||
// Check if migration already applied to avoid unnecessary re-runs
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(11) as {version: number} | undefined;
|
||||
const applied = this.db.prepare('SELECT version FROM schema_versions WHERE version = ?').get(11) as SchemaVersion | undefined;
|
||||
if (applied) return;
|
||||
|
||||
// Check if discovery_tokens column exists in observations table
|
||||
const observationsInfo = this.db.pragma('table_info(observations)');
|
||||
const obsHasDiscoveryTokens = (observationsInfo as any[]).some((col: any) => col.name === 'discovery_tokens');
|
||||
const observationsInfo = this.db.pragma('table_info(observations)') as TableColumnInfo[];
|
||||
const obsHasDiscoveryTokens = observationsInfo.some(col => col.name === 'discovery_tokens');
|
||||
|
||||
if (!obsHasDiscoveryTokens) {
|
||||
this.db.exec('ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
|
||||
@@ -515,8 +526,8 @@ export class SessionStore {
|
||||
}
|
||||
|
||||
// Check if discovery_tokens column exists in session_summaries table
|
||||
const summariesInfo = this.db.pragma('table_info(session_summaries)');
|
||||
const sumHasDiscoveryTokens = (summariesInfo as any[]).some((col: any) => col.name === 'discovery_tokens');
|
||||
const summariesInfo = this.db.pragma('table_info(session_summaries)') as TableColumnInfo[];
|
||||
const sumHasDiscoveryTokens = summariesInfo.some(col => col.name === 'discovery_tokens');
|
||||
|
||||
if (!sumHasDiscoveryTokens) {
|
||||
this.db.exec('ALTER TABLE session_summaries ADD COLUMN discovery_tokens INTEGER DEFAULT 0');
|
||||
@@ -556,7 +567,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(project, limit) as any[];
|
||||
return stmt.all(project, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -581,7 +592,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(project, limit) as any[];
|
||||
return stmt.all(project, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,7 +612,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(project, limit) as any[];
|
||||
return stmt.all(project, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -625,7 +636,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(limit) as any[];
|
||||
return stmt.all(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +666,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(limit) as any[];
|
||||
return stmt.all(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -685,7 +696,7 @@ export class SessionStore {
|
||||
LIMIT ?
|
||||
`);
|
||||
|
||||
return stmt.all(limit) as any[];
|
||||
return stmt.all(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,7 +739,7 @@ export class SessionStore {
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
return stmt.get(claudeSessionId) as any;
|
||||
return stmt.get(claudeSessionId) as LatestPromptResult | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -760,7 +771,7 @@ export class SessionStore {
|
||||
ORDER BY started_at_epoch ASC
|
||||
`);
|
||||
|
||||
return stmt.all(project, limit) as any[];
|
||||
return stmt.all(project, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,20 +790,20 @@ export class SessionStore {
|
||||
ORDER BY created_at_epoch ASC
|
||||
`);
|
||||
|
||||
return stmt.all(sdkSessionId) as any[];
|
||||
return stmt.all(sdkSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single observation by ID
|
||||
*/
|
||||
getObservationById(id: number): any | null {
|
||||
getObservationById(id: number): ObservationRecord | null {
|
||||
const stmt = this.db.prepare(`
|
||||
SELECT *
|
||||
FROM observations
|
||||
WHERE id = ?
|
||||
`);
|
||||
|
||||
return stmt.get(id) as any || null;
|
||||
return stmt.get(id) as ObservationRecord | undefined || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -801,7 +812,7 @@ export class SessionStore {
|
||||
getObservationsByIds(
|
||||
ids: number[],
|
||||
options: { orderBy?: 'date_desc' | 'date_asc'; limit?: number } = {}
|
||||
): any[] {
|
||||
): ObservationRecord[] {
|
||||
if (ids.length === 0) return [];
|
||||
|
||||
const { orderBy = 'date_desc', limit } = options;
|
||||
@@ -819,7 +830,7 @@ export class SessionStore {
|
||||
${limitClause}
|
||||
`);
|
||||
|
||||
return stmt.all(...ids) as any[];
|
||||
return stmt.all(...ids) as ObservationRecord[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -847,7 +858,7 @@ export class SessionStore {
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
return stmt.get(sdkSessionId) as any || null;
|
||||
return stmt.get(sdkSessionId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -920,7 +931,7 @@ export class SessionStore {
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
return stmt.get(id) as any || null;
|
||||
return stmt.get(id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -939,7 +950,7 @@ export class SessionStore {
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
return stmt.get(claudeSessionId) as any || null;
|
||||
return stmt.get(claudeSessionId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,7 +964,7 @@ export class SessionStore {
|
||||
LIMIT 1
|
||||
`);
|
||||
|
||||
return stmt.get(claudeSessionId) as any || null;
|
||||
return stmt.get(claudeSessionId) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1343,7 +1354,7 @@ export class SessionStore {
|
||||
getSessionSummariesByIds(
|
||||
ids: number[],
|
||||
options: { orderBy?: 'date_desc' | 'date_asc'; limit?: number } = {}
|
||||
): any[] {
|
||||
): SessionSummaryRecord[] {
|
||||
if (ids.length === 0) return [];
|
||||
|
||||
const { orderBy = 'date_desc', limit } = options;
|
||||
@@ -1358,7 +1369,7 @@ export class SessionStore {
|
||||
${limitClause}
|
||||
`);
|
||||
|
||||
return stmt.all(...ids) as any[];
|
||||
return stmt.all(...ids) as SessionSummaryRecord[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1368,7 +1379,7 @@ export class SessionStore {
|
||||
getUserPromptsByIds(
|
||||
ids: number[],
|
||||
options: { orderBy?: 'date_desc' | 'date_asc'; limit?: number } = {}
|
||||
): any[] {
|
||||
): UserPromptRecord[] {
|
||||
if (ids.length === 0) return [];
|
||||
|
||||
const { orderBy = 'date_desc', limit } = options;
|
||||
@@ -1388,7 +1399,7 @@ export class SessionStore {
|
||||
${limitClause}
|
||||
`);
|
||||
|
||||
return stmt.all(...ids) as any[];
|
||||
return stmt.all(...ids) as UserPromptRecord[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1451,8 +1462,8 @@ export class SessionStore {
|
||||
`;
|
||||
|
||||
try {
|
||||
const beforeRecords = this.db.prepare(beforeQuery).all(anchorObservationId, ...projectParams, depthBefore + 1) as any[];
|
||||
const afterRecords = this.db.prepare(afterQuery).all(anchorObservationId, ...projectParams, depthAfter + 1) as any[];
|
||||
const beforeRecords = this.db.prepare(beforeQuery).all(anchorObservationId, ...projectParams, depthBefore + 1) as Array<{id: number; created_at_epoch: number}>;
|
||||
const afterRecords = this.db.prepare(afterQuery).all(anchorObservationId, ...projectParams, depthAfter + 1) as Array<{id: number; created_at_epoch: number}>;
|
||||
|
||||
// Get the earliest and latest timestamps from boundary observations
|
||||
if (beforeRecords.length === 0 && afterRecords.length === 0) {
|
||||
@@ -1484,8 +1495,8 @@ export class SessionStore {
|
||||
`;
|
||||
|
||||
try {
|
||||
const beforeRecords = this.db.prepare(beforeQuery).all(anchorEpoch, ...projectParams, depthBefore) as any[];
|
||||
const afterRecords = this.db.prepare(afterQuery).all(anchorEpoch, ...projectParams, depthAfter + 1) as any[];
|
||||
const beforeRecords = this.db.prepare(beforeQuery).all(anchorEpoch, ...projectParams, depthBefore) as Array<{created_at_epoch: number}>;
|
||||
const afterRecords = this.db.prepare(afterQuery).all(anchorEpoch, ...projectParams, depthAfter + 1) as Array<{created_at_epoch: number}>;
|
||||
|
||||
if (beforeRecords.length === 0 && afterRecords.length === 0) {
|
||||
return { observations: [], sessions: [], prompts: [] };
|
||||
@@ -1523,9 +1534,9 @@ export class SessionStore {
|
||||
`;
|
||||
|
||||
try {
|
||||
const observations = this.db.prepare(obsQuery).all(startEpoch, endEpoch, ...projectParams) as any[];
|
||||
const sessions = this.db.prepare(sessQuery).all(startEpoch, endEpoch, ...projectParams) as any[];
|
||||
const prompts = this.db.prepare(promptQuery).all(startEpoch, endEpoch, ...projectParams) as any[];
|
||||
const observations = this.db.prepare(obsQuery).all(startEpoch, endEpoch, ...projectParams) as ObservationRecord[];
|
||||
const sessions = this.db.prepare(sessQuery).all(startEpoch, endEpoch, ...projectParams) as SessionSummaryRecord[];
|
||||
const prompts = this.db.prepare(promptQuery).all(startEpoch, endEpoch, ...projectParams) as UserPromptRecord[];
|
||||
|
||||
return {
|
||||
observations,
|
||||
|
||||
@@ -37,7 +37,7 @@ export class SettingsManager {
|
||||
for (const row of rows) {
|
||||
const key = row.key as keyof ViewerSettings;
|
||||
if (key in settings) {
|
||||
(settings as any)[key] = JSON.parse(row.value);
|
||||
settings[key] = JSON.parse(row.value) as ViewerSettings[typeof key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import {
|
||||
OBSERVATION_TYPES,
|
||||
OBSERVATION_CONCEPTS,
|
||||
DEFAULT_OBSERVATION_TYPES_STRING,
|
||||
DEFAULT_OBSERVATION_CONCEPTS_STRING
|
||||
DEFAULT_OBSERVATION_CONCEPTS_STRING,
|
||||
ObservationType,
|
||||
ObservationConcept
|
||||
} from '../../../../constants/observation-metadata.js';
|
||||
|
||||
export class SettingsRoutes {
|
||||
@@ -348,7 +350,7 @@ export class SettingsRoutes {
|
||||
if (settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES) {
|
||||
const types = settings.CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES.split(',').map((t: string) => t.trim());
|
||||
for (const type of types) {
|
||||
if (type && !OBSERVATION_TYPES.includes(type as any)) {
|
||||
if (type && !OBSERVATION_TYPES.includes(type as ObservationType)) {
|
||||
return { valid: false, error: `Invalid observation type: ${type}. Valid types: ${OBSERVATION_TYPES.join(', ')}` };
|
||||
}
|
||||
}
|
||||
@@ -358,7 +360,7 @@ export class SettingsRoutes {
|
||||
if (settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS) {
|
||||
const concepts = settings.CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS.split(',').map((c: string) => c.trim());
|
||||
for (const concept of concepts) {
|
||||
if (concept && !OBSERVATION_CONCEPTS.includes(concept as any)) {
|
||||
if (concept && !OBSERVATION_CONCEPTS.includes(concept as ObservationConcept)) {
|
||||
return { valid: false, error: `Invalid observation concept: ${concept}. Valid concepts: ${OBSERVATION_CONCEPTS.join(', ')}` };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* TypeScript types for database query results
|
||||
* Provides type safety for better-sqlite3 query results
|
||||
*/
|
||||
|
||||
/**
|
||||
* Schema information from sqlite3 PRAGMA table_info
|
||||
*/
|
||||
export interface TableColumnInfo {
|
||||
cid: number;
|
||||
name: string;
|
||||
type: string;
|
||||
notnull: number;
|
||||
dflt_value: string | null;
|
||||
pk: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Index information from sqlite3 PRAGMA index_list
|
||||
*/
|
||||
export interface IndexInfo {
|
||||
seq: number;
|
||||
name: string;
|
||||
unique: number;
|
||||
origin: string;
|
||||
partial: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Table name from sqlite_master
|
||||
*/
|
||||
export interface TableNameRow {
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schema version record
|
||||
*/
|
||||
export interface SchemaVersion {
|
||||
version: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* SDK Session database record
|
||||
*/
|
||||
export interface SdkSessionRecord {
|
||||
id: number;
|
||||
claude_session_id: string;
|
||||
sdk_session_id: string | null;
|
||||
project: string;
|
||||
user_prompt: string | null;
|
||||
started_at: string;
|
||||
started_at_epoch: number;
|
||||
completed_at: string | null;
|
||||
completed_at_epoch: number | null;
|
||||
status: 'active' | 'completed' | 'failed';
|
||||
worker_port?: number;
|
||||
prompt_counter?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Observation database record
|
||||
*/
|
||||
export interface ObservationRecord {
|
||||
id: number;
|
||||
sdk_session_id: string;
|
||||
project: string;
|
||||
text: string | null;
|
||||
type: 'decision' | 'bugfix' | 'feature' | 'refactor' | 'discovery' | 'change';
|
||||
created_at: string;
|
||||
created_at_epoch: number;
|
||||
title?: string;
|
||||
concept?: string;
|
||||
source_files?: string;
|
||||
prompt_number?: number;
|
||||
discovery_tokens?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Session Summary database record
|
||||
*/
|
||||
export interface SessionSummaryRecord {
|
||||
id: number;
|
||||
sdk_session_id: string;
|
||||
project: string;
|
||||
request: string | null;
|
||||
investigated: string | null;
|
||||
learned: string | null;
|
||||
completed: string | null;
|
||||
next_steps: string | null;
|
||||
created_at: string;
|
||||
created_at_epoch: number;
|
||||
prompt_number?: number;
|
||||
discovery_tokens?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* User Prompt database record
|
||||
*/
|
||||
export interface UserPromptRecord {
|
||||
id: number;
|
||||
claude_session_id: string;
|
||||
prompt_number: number;
|
||||
prompt_text: string;
|
||||
created_at: string;
|
||||
created_at_epoch: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Latest user prompt with session join
|
||||
*/
|
||||
export interface LatestPromptResult {
|
||||
id: number;
|
||||
claude_session_id: string;
|
||||
sdk_session_id: string;
|
||||
project: string;
|
||||
prompt_number: number;
|
||||
prompt_text: string;
|
||||
created_at_epoch: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Observation with context (for time-based queries)
|
||||
*/
|
||||
export interface ObservationWithContext {
|
||||
id: number;
|
||||
sdk_session_id: string;
|
||||
project: string;
|
||||
text: string | null;
|
||||
type: string;
|
||||
created_at: string;
|
||||
created_at_epoch: number;
|
||||
title?: string;
|
||||
concept?: string;
|
||||
source_files?: string;
|
||||
prompt_number?: number;
|
||||
discovery_tokens?: number;
|
||||
}
|
||||
Reference in New Issue
Block a user