From b4c870e0b3716f68211db326a8c4040578ad71cd Mon Sep 17 00:00:00 2001 From: Luca Martial Date: Thu, 14 May 2026 16:02:23 -0700 Subject: [PATCH] fix(cli): refresh ready command hints --- docs-site/content/docs/cli-reference/index.mdx | 4 +--- packages/cli/src/doctor.test.ts | 13 +++++++++++++ packages/cli/src/doctor.ts | 3 ++- packages/cli/src/status-project.ts | 9 ++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs-site/content/docs/cli-reference/index.mdx b/docs-site/content/docs/cli-reference/index.mdx index 4eb11648..c4ef07db 100644 --- a/docs-site/content/docs/cli-reference/index.mdx +++ b/docs-site/content/docs/cli-reference/index.mdx @@ -37,9 +37,7 @@ ktx ``` The public context-build entrypoint is `ktx ingest [connectionId]` or -`ktx ingest --all`. Legacy command shapes such as `ktx scan`, `ktx ingest run`, -`ktx ingest status`, `ktx ingest replay`, `ktx ingest watch`, and -`ktx setup status` are not part of the current public CLI. +`ktx ingest --all`. ## Global Options diff --git a/packages/cli/src/doctor.test.ts b/packages/cli/src/doctor.test.ts index fddb4c68..daeb5b96 100644 --- a/packages/cli/src/doctor.test.ts +++ b/packages/cli/src/doctor.test.ts @@ -64,6 +64,11 @@ describe('formatDoctorReport', () => { expect(output).toContain('Node 22+ · pnpm 10.20+'); expect(output).not.toContain('v22.16.0'); expect(output).toContain('Everything ready.'); + expect(output).toContain('ktx status --json'); + expect(output).toContain('ktx sl list'); + expect(output).toContain('ktx wiki list'); + expect(output).not.toContain('ktx scan'); + expect(output).not.toContain('ktx sl ask'); }); it('shows the underlying detail for a single-check group on the group line', () => { @@ -462,6 +467,7 @@ describe('runKtxDoctor', () => { it('includes Postgres query-history readiness in project doctor output', async () => { process.env.ANTHROPIC_API_KEY = 'test-key'; // pragma: allowlist secret process.env.OPENAI_API_KEY = 'test-key'; // pragma: allowlist secret + process.env.WAREHOUSE_DATABASE_URL = 'postgresql://reader@example.test/warehouse'; await writeFile( join(tempDir, 'ktx.yaml'), [ @@ -516,8 +522,14 @@ describe('runKtxDoctor', () => { expect(out).toContain('pg_stat_statements ready (PostgreSQL 16.4)'); expect(out).toContain('info: 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 list'); + expect(out).toContain('ktx wiki list'); + expect(out).not.toContain('ktx scan'); + expect(out).not.toContain('ktx sl ask'); delete process.env.ANTHROPIC_API_KEY; delete process.env.OPENAI_API_KEY; + delete process.env.WAREHOUSE_DATABASE_URL; }); it('returns blocked verdict when LLM is not configured', async () => { @@ -543,6 +555,7 @@ describe('runKtxDoctor', () => { ).resolves.toBe(1); expect(testIo.stdout()).toContain('no LLM configured'); + expect(testIo.stdout()).not.toContain('ktx ask'); expect(testIo.stdout()).toContain('ktx setup'); }); diff --git a/packages/cli/src/doctor.ts b/packages/cli/src/doctor.ts index b1845ae3..efb87e2b 100644 --- a/packages/cli/src/doctor.ts +++ b/packages/cli/src/doctor.ts @@ -5,6 +5,7 @@ import { join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { promisify } from 'node:util'; import type { KtxConfigIssue } from '@ktx/context/project'; +import { KTX_NEXT_STEP_DIRECT_COMMANDS } from './next-steps.js'; import type { BuildProjectStatusOptions } from './status-project.js'; const execFileAsync = promisify(execFile); @@ -287,7 +288,7 @@ interface RenderOptions { command?: 'setup' | 'project'; } -const NEXT_STEPS_PROJECT = ['ktx scan', 'ktx wiki', 'ktx sl ask "…"']; +const NEXT_STEPS_PROJECT = KTX_NEXT_STEP_DIRECT_COMMANDS.map((step) => step.command); export function formatDoctorReport(report: DoctorReport, options: Partial = {}): string { const opts: RenderOptions = { diff --git a/packages/cli/src/status-project.ts b/packages/cli/src/status-project.ts index 6e953dc8..2aab1e5c 100644 --- a/packages/cli/src/status-project.ts +++ b/packages/cli/src/status-project.ts @@ -9,6 +9,7 @@ import type { } from '@ktx/context/project'; import type { PostgresPgssProbeResult } from '@ktx/context/ingest'; import type { DoctorCheck } from './doctor.js'; +import { KTX_NEXT_STEP_DIRECT_COMMANDS } from './next-steps.js'; type ProjectStatusLevel = 'ok' | 'warn' | 'fail'; type ProjectVerdict = 'ready' | 'partial' | 'blocked'; @@ -69,6 +70,8 @@ interface WarningItem { fix?: string; } +const PROJECT_READY_COMMANDS = KTX_NEXT_STEP_DIRECT_COMMANDS.map((step) => step.command); + function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } @@ -132,7 +135,7 @@ function buildLlmStatus(config: KtxProjectLlmConfig, env: NodeJS.ProcessEnv): Ll backend, model, status: 'fail', - detail: 'no LLM configured — ktx ask will not work', + detail: 'no LLM configured; research agent will not run', fix: 'Run: ktx setup (choose an LLM provider)', }; } @@ -571,7 +574,7 @@ function buildVerdict( if (llm.status === 'fail') { return { verdict: 'blocked', - reason: 'LLM not configured — `ktx ask` will not work.', + reason: 'LLM not configured; research agent will not run.', nextActions: ['ktx setup'], }; } @@ -605,7 +608,7 @@ function buildVerdict( return { verdict: 'ready', reason: 'Ready.', - nextActions: ['ktx scan', 'ktx wiki', 'ktx sl ask "…"'], + nextActions: [...PROJECT_READY_COMMANDS], }; }