diff --git a/packages/cli/src/context-build-view.test.ts b/packages/cli/src/context-build-view.test.ts index 877c90b6..c232d432 100644 --- a/packages/cli/src/context-build-view.test.ts +++ b/packages/cli/src/context-build-view.test.ts @@ -189,6 +189,52 @@ describe('renderContextBuildView', () => { expect(output).toContain('Project: /tmp/project'); }); + it('renders public warnings in the foreground view', () => { + const state = initViewState([ + { + connectionId: 'docs', + driver: 'notion', + operation: 'source-ingest', + adapter: 'notion', + debugCommand: 'ktx ingest docs --debug', + steps: ['source-ingest', 'memory-update'], + }, + ]); + + const rendered = renderContextBuildView(state, { + styled: false, + warnings: ['--deep affects database ingest only; ignoring it for docs.'], + }); + + expect(rendered).toContain('Warnings:'); + expect(rendered).toContain('--deep affects database ingest only; ignoring it for docs.'); + }); + + it('renders public notices in the foreground view before warnings', () => { + const state = initViewState([ + { + connectionId: 'warehouse', + driver: 'postgres', + operation: 'database-ingest', + debugCommand: 'ktx ingest warehouse --debug', + steps: ['database-schema', 'query-history'], + databaseDepth: 'deep', + detectRelationships: true, + queryHistory: { enabled: true, dialect: 'postgres' }, + }, + ]); + + const rendered = renderContextBuildView(state, { + styled: false, + notices: ['Schema ingest runs before query history for warehouse.'], + warnings: ['--query-history requires deep ingest; running warehouse with --deep.'], + }); + + expect(rendered.indexOf('Notices:')).toBeLessThan(rendered.indexOf('Warnings:')); + expect(rendered).toContain('Schema ingest runs before query history for warehouse.'); + expect(rendered).toContain('--query-history requires deep ingest; running warehouse with --deep.'); + }); + it('renders dynamic separator matching header width', () => { const state = initViewState([ { connectionId: 'warehouse', driver: 'postgres', operation: 'database-ingest', debugCommand: '', steps: ['database-schema'] }, diff --git a/packages/cli/src/context-build-view.ts b/packages/cli/src/context-build-view.ts index b7705477..23365a28 100644 --- a/packages/cli/src/context-build-view.ts +++ b/packages/cli/src/context-build-view.ts @@ -198,6 +198,12 @@ function renderTargetGroup( return ['', ` ${label}:`, ...targets.map((t) => renderTargetLine(t, frame, styled, width))]; } +function renderMessageGroup(label: string, messages: string[], styled: boolean): string[] { + if (messages.length === 0) return []; + const renderedMessages = messages.map((message) => ` - ${message}`); + return ['', ` ${label}:`, ...renderedMessages.map((line) => (styled ? dim(line) : line))]; +} + function retryCommand(input: { projectDir?: string; entrypoint?: 'setup' | 'ingest'; @@ -214,7 +220,14 @@ function retryCommand(input: { export function renderContextBuildView( state: ContextBuildViewState, - options: { styled?: boolean; showHint?: boolean; hintText?: string; projectDir?: string } = {}, + options: { + styled?: boolean; + showHint?: boolean; + hintText?: string; + projectDir?: string; + notices?: string[]; + warnings?: string[]; + } = {}, ): string { const styled = options.styled ?? true; const width = columnWidth(state); @@ -242,6 +255,8 @@ export function renderContextBuildView( ...(options.projectDir ? [` Project: ${options.projectDir}`] : []), ...renderTargetGroup('Databases', state.primarySources, state.frame, styled, width), ...renderTargetGroup('Context sources', state.contextSources, state.frame, styled, width), + ...renderMessageGroup('Notices', options.notices ?? [], styled), + ...renderMessageGroup('Warnings', options.warnings ?? [], styled), '', ]; @@ -629,7 +644,12 @@ export async function runContextBuild( state.startedAt = nowFn(); const repainter = isTTY ? createRepainter(io) : null; - const viewOpts = { styled: true, projectDir: args.projectDir }; + const viewOpts = { + styled: true, + projectDir: args.projectDir, + notices: plan.notices ?? [], + warnings: plan.warnings, + }; const paint = (hint: boolean) => repainter?.paint(renderContextBuildView(state, { ...viewOpts, showHint: hint })); paint(true);