diff --git a/src/commands/context.js b/src/commands/context.js index 951656e..10f85fa 100644 --- a/src/commands/context.js +++ b/src/commands/context.js @@ -1148,6 +1148,15 @@ function countScreenshotCommentEntries(groups = []) { ); } +function formatDynamicRegionEvaluation(dynamicRegions) { + let evaluation = dynamicRegions?.evaluation; + if (!evaluation) return null; + + let policyCount = evaluation.policyRegions?.length || 0; + let regionLabel = policyCount === 1 ? 'region' : 'regions'; + return `${evaluation.status} · ${evaluation.explainedComponentCount}/${evaluation.componentCount} components explained · ${evaluation.residualComponentCount} left · ${policyCount} confirmed ${regionLabel}`; +} + function displayComparisonContext(output, context) { output.header('context', 'comparison'); @@ -1160,6 +1169,9 @@ function displayComparisonContext(output, context) { let confirmedRegionLabels = formatConfirmedRegionLabels( context.history.confirmed_regions ); + let dynamicRegionEvaluation = formatDynamicRegionEvaluation( + context.dynamic_regions + ); output.print( ` ${colors.bold(screenshotName)} ${statusTone(displayState.toUpperCase())}` @@ -1175,8 +1187,13 @@ function displayComparisonContext(output, context) { ); output.labelValue( 'Memory', - `${context.history.similar_by_fingerprint.length} similar · ${context.history.recent_by_name.length} recent · ${context.history.confirmed_regions.length} confirmed regions` + dynamicRegionEvaluation + ? `${context.history.similar_by_fingerprint.length} similar · ${context.history.recent_by_name.length} recent` + : `${context.history.similar_by_fingerprint.length} similar · ${context.history.recent_by_name.length} recent · ${context.history.confirmed_regions.length} confirmed regions` ); + if (dynamicRegionEvaluation) { + output.labelValue('Dynamic content', dynamicRegionEvaluation); + } output.labelValue( 'Review', `${context.review.build_comments.length} build comments · ${countScreenshotCommentEntries(context.review.screenshot_comments)} screenshot comments` diff --git a/tests/commands/context.test.js b/tests/commands/context.test.js index c362dc4..0dccac7 100644 --- a/tests/commands/context.test.js +++ b/tests/commands/context.test.js @@ -1233,6 +1233,70 @@ describe('commands/context', () => { assert.strictEqual(knownRegionsCall.args[1], 'Known header copy band'); }); + it('shows API-backed Dynamic content evaluation in human output', async () => { + let output = createMockOutput(); + + await contextComparisonCommand( + 'comparison-1', + { agent: true }, + {}, + { + loadConfig: async () => ({ + apiKey: 'token', + apiUrl: 'https://api.test', + }), + createApiClient: () => ({}), + getComparisonContext: async () => ({ + scope: { + organization: { slug: 'acme' }, + project: { slug: 'storybook' }, + }, + comparison: { + id: 'comparison-1', + result: 'changed', + screenshot: { name: 'Dashboard' }, + analysis: {}, + }, + dynamic_regions: { + evaluation: { + componentCount: 14, + explainedComponentCount: 11, + policyRegions: [{ id: 'region-1', revision: 3 }], + residualComponentCount: 3, + status: 'uncontained', + }, + }, + history: { + similar_by_fingerprint: [], + recent_by_name: [], + confirmed_regions: [], + }, + review: { + build_comments: [], + screenshot_comments: [], + }, + links: {}, + }), + output, + exit: () => {}, + } + ); + + let memoryCall = output.calls.find( + call => call.method === 'labelValue' && call.args[0] === 'Memory' + ); + let dynamicContentCall = output.calls.find( + call => + call.method === 'labelValue' && call.args[0] === 'Dynamic content' + ); + + assert.strictEqual(memoryCall.args[1], '0 similar · 0 recent'); + assert.strictEqual( + dynamicContentCall.args[1], + 'uncontained · 11/14 components explained · 3 left · 1 confirmed region' + ); + }); + it('returns consistent API-backed comparison evidence for agents', async () => { let output = createMockOutput();