diff --git a/packages/cli/src/context/ingest/historic-sql-probes.test.ts b/packages/cli/src/context/ingest/historic-sql-probes.test.ts index e96b261f..275a84c7 100644 --- a/packages/cli/src/context/ingest/historic-sql-probes.test.ts +++ b/packages/cli/src/context/ingest/historic-sql-probes.test.ts @@ -95,7 +95,7 @@ describe('historic-SQL probe registry', () => { projectDir: '/work/project', connectionId: 'warehouse', connection: { - driver: 'postgres', + driver: 'postgres' as const, url: 'env:DATABASE_URL', context: { queryHistory: { enabled: true } }, }, diff --git a/packages/cli/src/doctor.test.ts b/packages/cli/src/doctor.test.ts index b483ea20..e494fbac 100644 --- a/packages/cli/src/doctor.test.ts +++ b/packages/cli/src/doctor.test.ts @@ -30,6 +30,30 @@ function makeIo() { }; } +function fakeDoctorHistoricSqlRunner() { + return { + dialect: 'postgres' as const, + catalogName: 'pg_stat_statements', + async run() { + return { warnings: [], info: [] }; + }, + formatSuccessDetail(result: unknown) { + const typed = result as { pgServerVersion?: string; warnings: string[]; info?: string[] }; + const info = typed.info && typed.info.length > 0 ? `; ${typed.info.join('; ')}` : ''; + return { + detail: `pg_stat_statements ready (${typed.pgServerVersion ?? 'PostgreSQL 16.4'})${info}`, + warnings: typed.warnings, + }; + }, + fixAdvice(error: unknown) { + return { + failHeadline: error instanceof Error ? error.message : String(error), + remediation: 'Fix query-history grants.', + }; + }, + }; +} + describe('formatDoctorReport', () => { it('shows the failing check and its fix in plain output', () => { const checks: DoctorCheck[] = [ @@ -539,14 +563,19 @@ describe('runKtxDoctor', () => { { command: 'project', projectDir: tempDir, outputMode: 'plain', inputMode: 'disabled' }, testIo.io, { - postgresQueryHistoryProbe: async () => { + queryHistoryReadinessProbe: async () => { probeCalls += 1; return { - pgServerVersion: 'PostgreSQL 16.4', - warnings: [], - info: [ - 'pg_stat_statements.max is 1000; set it to at least 5000 to reduce query-template eviction churn', - ], + ok: true, + dialect: 'postgres', + runner: fakeDoctorHistoricSqlRunner(), + result: { + pgServerVersion: 'PostgreSQL 16.4', + warnings: [], + info: [ + 'pg_stat_statements.max is 1000; set it to at least 5000 to reduce query-template eviction churn', + ], + }, }; }, }, @@ -558,7 +587,7 @@ describe('runKtxDoctor', () => { expect(out).toContain('Query history'); expect(out).toContain('warehouse'); expect(out).toContain('pg_stat_statements ready (PostgreSQL 16.4)'); - expect(out).toContain('info: pg_stat_statements.max is 1000'); + expect(out).toContain('pg_stat_statements.max is 1000'); expect(out).not.toContain('Update the Postgres parameter group or config'); expect(out).toContain('ktx status --json'); expect(out).toContain('ktx sl'); @@ -639,10 +668,15 @@ describe('runKtxDoctor', () => { { command: 'project', projectDir: tempDir, outputMode: 'plain', inputMode: 'disabled' }, testIo.io, { - postgresQueryHistoryProbe: async () => ({ - pgServerVersion: 'PostgreSQL 16.4', - warnings: [], - info: [], + queryHistoryReadinessProbe: async () => ({ + ok: true, + dialect: 'postgres', + runner: fakeDoctorHistoricSqlRunner(), + result: { + pgServerVersion: 'PostgreSQL 16.4', + warnings: [], + info: [], + }, }), }, ), @@ -850,9 +884,14 @@ describe('runKtxDoctor', () => { { command: 'validate', projectDir: tempDir, outputMode: 'plain', inputMode: 'disabled' }, testIo.io, { - postgresQueryHistoryProbe: async () => { + queryHistoryReadinessProbe: async () => { probeCalls += 1; - return { pgServerVersion: 'PostgreSQL 16.4', warnings: [], info: [] }; + return { + ok: true, + dialect: 'postgres', + runner: fakeDoctorHistoricSqlRunner(), + result: { pgServerVersion: 'PostgreSQL 16.4', warnings: [], info: [] }, + }; }, }, ), diff --git a/packages/cli/src/ingest.test.ts b/packages/cli/src/ingest.test.ts index 33eecfba..a8621062 100644 --- a/packages/cli/src/ingest.test.ts +++ b/packages/cli/src/ingest.test.ts @@ -284,7 +284,30 @@ describe('runKtxIngest', () => { return 0; }, scanConnection: async () => 0, - historicSqlProbe: async () => ({ ok: true, lines: ['PASS Historic SQL probe skipped in test'] }), + historicSqlReadinessProbe: async () => ({ + ok: true, + dialect: 'postgres', + runner: { + dialect: 'postgres', + catalogName: 'pg_stat_statements', + async run() { + return { warnings: [], info: [] }; + }, + formatSuccessDetail() { + return { + detail: 'pg_stat_statements ready (PostgreSQL 16.4)', + warnings: [], + }; + }, + fixAdvice() { + return { + failHeadline: 'pg_stat_statements unavailable', + remediation: 'Fix query-history grants.', + }; + }, + }, + result: { pgServerVersion: 'PostgreSQL 16.4', warnings: [], info: [] }, + }), }, context: async () => ({ status: 'skipped', projectDir }), runtime: async () => runtimeReady(projectDir), diff --git a/packages/cli/src/status-project.ts b/packages/cli/src/status-project.ts index 11648e10..6e239c63 100644 --- a/packages/cli/src/status-project.ts +++ b/packages/cli/src/status-project.ts @@ -1,7 +1,7 @@ import { stat as statAsync, readdir as readdirAsync } from 'node:fs/promises'; import { basename, join } from 'node:path'; import { runClaudeCodeAuthProbe } from './context/llm/claude-code-runtime.js'; -import type { KtxConfigIssue, KtxProjectConfig, KtxProjectEmbeddingConfig, KtxProjectLlmConfig } from './context/project/config.js'; +import type { KtxConfigIssue, KtxProjectConfig, KtxProjectConnectionConfig, KtxProjectEmbeddingConfig, KtxProjectLlmConfig } from './context/project/config.js'; import type { KtxLocalProject } from './context/project/project.js'; import { ktxLocalStateDbPath } from './context/project/local-state-db.js'; import {