chekk 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/display.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import chalk from 'chalk';
2
+ import { BENCHMARKS, DIM_RANGES } from './insights.js';
2
3
 
3
4
  // ── Color palette ──
4
5
  const gold = chalk.hex('#FFD700');
@@ -7,6 +8,8 @@ const blue = chalk.hex('#3B82F6');
7
8
  const green = chalk.hex('#22C55E');
8
9
  const cyan = chalk.hex('#06B6D4');
9
10
  const orange = chalk.hex('#F97316');
11
+ const red = chalk.hex('#EF4444');
12
+ const yellow = chalk.hex('#EAB308');
10
13
  const dim = chalk.dim;
11
14
  const bold = chalk.bold;
12
15
  const white = chalk.white;
@@ -22,9 +25,9 @@ function tierColor(tier) {
22
25
  function scoreColor(score) {
23
26
  if (score >= 85) return green;
24
27
  if (score >= 70) return cyan;
25
- if (score >= 55) return chalk.hex('#EAB308');
28
+ if (score >= 55) return yellow;
26
29
  if (score >= 40) return orange;
27
- return chalk.hex('#EF4444');
30
+ return red;
28
31
  }
29
32
 
30
33
  function progressBar(score, width = 18) {
@@ -45,23 +48,22 @@ function pad(str, len) {
45
48
 
46
49
  // ── Qualitative tier labels for dimensions ──
47
50
  function dimTierLabel(score) {
48
- if (score >= 80) return 'exceptional';
49
- if (score >= 65) return 'strong';
50
- if (score >= 50) return 'solid';
51
- if (score >= 35) return 'developing';
52
- return 'needs work';
51
+ if (score >= 80) return 'EXCEPTIONAL';
52
+ if (score >= 65) return 'STRONG';
53
+ if (score >= 50) return 'SOLID';
54
+ if (score >= 35) return 'DEVELOPING';
55
+ return 'NEEDS WORK';
53
56
  }
54
57
 
55
58
  function dimTierColor(score) {
56
59
  if (score >= 80) return green;
57
60
  if (score >= 65) return cyan;
58
- if (score >= 50) return chalk.hex('#EAB308');
61
+ if (score >= 50) return yellow;
59
62
  if (score >= 35) return orange;
60
- return chalk.hex('#EF4444');
63
+ return red;
61
64
  }
62
65
 
63
66
  // ── Snippet helpers ──
64
- // Longer snippets with context labels instead of truncated decorations
65
67
 
66
68
  function cleanPrompt(prompt, maxLen = 120) {
67
69
  if (!prompt) return null;
@@ -86,7 +88,7 @@ function pickExample(examples, type) {
86
88
 
87
89
  // ── Box drawing ──
88
90
 
89
- function box(lines, width = 43) {
91
+ function box(lines, width = 47) {
90
92
  const out = [];
91
93
  out.push(dim(' \u250C' + '\u2500'.repeat(width) + '\u2510'));
92
94
  for (const line of lines) {
@@ -98,33 +100,44 @@ function box(lines, width = 43) {
98
100
  return out;
99
101
  }
100
102
 
101
- function doubleRule(width = 47) {
103
+ function doubleRule(width = 53) {
102
104
  return dim(' ' + '\u2550'.repeat(width));
103
105
  }
104
106
 
107
+ function wrapText(text, maxWidth = 49) {
108
+ const words = text.split(' ');
109
+ const lines = [];
110
+ let current = '';
111
+ for (const word of words) {
112
+ if (current.length + word.length + 1 > maxWidth) {
113
+ lines.push(current);
114
+ current = word;
115
+ } else {
116
+ current = current ? current + ' ' + word : word;
117
+ }
118
+ }
119
+ if (current) lines.push(current);
120
+ return lines;
121
+ }
122
+
105
123
  // ══════════════════════════════════════════════
106
- // HEADER
124
+ // HEADER — Scanning + progress
107
125
  // ══════════════════════════════════════════════
108
126
 
109
127
  export function displayHeader() {
110
128
  console.log();
111
129
  const lines = [
112
130
  '',
113
- ` ${bold.white('chekk')}${dim(' v0.3.0')}`,
114
- ` ${dim('the engineering capability score')}`,
131
+ ` ${bold.white('chekk')}${dim(' v0.4.0')}`,
132
+ ` ${dim('engineering capability profile')}`,
115
133
  '',
116
134
  ];
117
135
  for (const l of box(lines, 45)) console.log(l);
118
136
  console.log();
119
137
  }
120
138
 
121
- // ══════════════════════════════════════════════
122
- // SCAN RESULTS
123
- // ══════════════════════════════════════════════
124
-
125
139
  export function displayScan(tools) {
126
140
  console.log(dim(' Scanning local AI tools...\n'));
127
-
128
141
  for (const tool of tools) {
129
142
  const sessions = numberFormat(tool.sessions);
130
143
  const projects = tool.projects.length;
@@ -136,10 +149,6 @@ export function displayScan(tools) {
136
149
  console.log();
137
150
  }
138
151
 
139
- // ══════════════════════════════════════════════
140
- // ANALYSIS PROGRESS BAR
141
- // ══════════════════════════════════════════════
142
-
143
152
  export function displayAnalysisStart(dateRange) {
144
153
  console.log(` ${dim('Analyzing')} ${white(dateRange)}${dim('...\n')}`);
145
154
  }
@@ -148,7 +157,6 @@ export async function displayProgressBar(durationMs = 2000) {
148
157
  const width = 40;
149
158
  const steps = 40;
150
159
  const stepTime = durationMs / steps;
151
-
152
160
  for (let i = 0; i <= steps; i++) {
153
161
  const filled = i;
154
162
  const empty = width - filled;
@@ -159,108 +167,199 @@ export async function displayProgressBar(durationMs = 2000) {
159
167
  }
160
168
  console.log();
161
169
  console.log();
162
- console.log(` ${green('\u2713')} ${dim('Score generated.')}`);
170
+ console.log(` ${green('\u2713')} ${dim('Profile generated.')}`);
163
171
  console.log();
164
172
  }
165
173
 
166
174
  // ══════════════════════════════════════════════
167
- // MAIN SCORE DISPLAY
175
+ // PROFILE HEADER — Official document feel
168
176
  // ══════════════════════════════════════════════
169
177
 
170
- export function displayScore(result, prose, extra = {}) {
171
- const { overall, scores, archetype, tier, tierBadge, tierPercentile } = result;
172
- const { scoreDelta, perToolScores } = extra;
173
- const tc = tierColor(tier);
174
- const sc = scoreColor(overall);
178
+ function displayProfileHeader(result, extra = {}) {
179
+ const { sessionStats } = extra;
180
+ const now = new Date();
181
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
182
+ const dateStr = `${months[now.getMonth()]} ${now.getDate()}, ${now.getFullYear()}`;
175
183
 
176
- // Big score block
177
184
  console.log(doubleRule());
178
185
  console.log();
179
- console.log(dim(' YOUR CHEKK SCORE'));
186
+ console.log(` ${bold.white('ENGINEERING CAPABILITY PROFILE')}`);
180
187
  console.log();
188
+ if (sessionStats) {
189
+ console.log(` ${dim(`Generated ${dateStr} | chekk v0.4.0`)}`);
190
+ console.log(` ${dim(`Analysis: ${sessionStats.totalSessions} sessions \u00B7 ${sessionStats.tools.length} tool${sessionStats.tools.length > 1 ? 's' : ''} \u00B7 ${numberFormat(sessionStats.totalExchanges)} exchanges`)}`);
191
+ if (sessionStats.dateRangeShort) {
192
+ console.log(` ${dim(`Period: ${sessionStats.dateRangeShort}`)}`);
193
+ }
194
+ }
195
+ console.log();
196
+ console.log(doubleRule());
197
+ }
198
+
199
+ // ══════════════════════════════════════════════
200
+ // SUMMARY BLOCK
201
+ // ══════════════════════════════════════════════
202
+
203
+ function displaySummary(result, extra = {}) {
204
+ const { overall, scores, archetype, tier, tierBadge, tierPercentile } = result;
205
+ const { scoreDelta, perToolScores, insights, sessionStats } = extra;
206
+ const tc = tierColor(tier);
207
+
208
+ // Find strongest and weakest
209
+ const dims = [
210
+ { label: 'Thinking', score: scores.decomposition },
211
+ { label: 'Debugging', score: scores.debugCycles },
212
+ { label: 'AI Leverage', score: scores.aiLeverage },
213
+ { label: 'Workflow', score: scores.sessionStructure },
214
+ ];
215
+ dims.sort((a, b) => b.score - a.score);
216
+ const strongest = dims[0];
217
+ const weakest = dims[dims.length - 1];
218
+
219
+ console.log();
220
+ console.log(dim(' SUMMARY'));
221
+
222
+ const badge = tierBadge || '';
223
+ const toolsList = sessionStats ? sessionStats.tools.join(' \u00B7 ') : '';
224
+ const sessionCount = sessionStats ? `${sessionStats.totalSessions} across ${sessionStats.projectCount} projects` : '';
225
+ const period = sessionStats?.dateRangeShort || '';
181
226
 
182
- // Score + delta
227
+ // Delta string
183
228
  let deltaStr = '';
184
229
  if (scoreDelta !== null && scoreDelta !== undefined) {
185
- if (scoreDelta > 0) deltaStr = ` ${green('\u2191 +' + scoreDelta + ' since last scan')}`;
186
- else if (scoreDelta < 0) deltaStr = ` ${orange('\u2193 ' + scoreDelta + ' since last scan')}`;
187
- else deltaStr = ` ${dim('\u2192 same as last scan')}`;
230
+ if (scoreDelta > 0) deltaStr = ` ${green('\u2191 +' + scoreDelta)}`;
231
+ else if (scoreDelta < 0) deltaStr = ` ${orange('\u2193 ' + scoreDelta)}`;
188
232
  }
189
- console.log(` ${sc.bold(String(overall))}`);
190
- const badgeStr = tierBadge ? ` ${tierBadge}` : '';
191
- const pctStr = tierPercentile ? ` ${dim(tierPercentile)}` : '';
192
- console.log(` ${tc('\u2500\u2500 ' + tier + ' \u2500\u2500')}${badgeStr}${pctStr}`);
193
- if (deltaStr) console.log(` ${deltaStr}`);
233
+
234
+ const summaryLines = [
235
+ '',
236
+ ` ${dim('Score')} ${scoreColor(overall).bold(String(overall))}${deltaStr}`,
237
+ ` ${dim('Tier')} ${tc(tier)} ${badge} ${dim('\u2014')} ${dim(tierPercentile)}`,
238
+ ` ${dim('Archetype')} ${bold.white(archetype.name)}`,
239
+ ];
240
+ if (toolsList) summaryLines.push(` ${dim('Tools')} ${dim(toolsList)}`);
241
+ if (sessionCount) summaryLines.push(` ${dim('Sessions')} ${dim(sessionCount)}`);
242
+ if (period) summaryLines.push(` ${dim('Period')} ${dim(period)}`);
243
+ summaryLines.push(` ${dim('Strongest')} ${dim(strongest.label + ' (' + dimTierLabel(strongest.score) + ')')}`);
244
+ summaryLines.push(` ${dim('Growth Area')} ${dim(weakest.label + ' (' + dimTierLabel(weakest.score) + ')')}`);
245
+ summaryLines.push('');
246
+
247
+ for (const l of box(summaryLines, 53)) console.log(l);
194
248
  console.log();
195
- console.log(` ${dim('Archetype:')} ${bold.white(archetype.name)}`);
249
+ }
196
250
 
197
- if (prose && prose.tagline) {
198
- console.log(` ${dim('"' + prose.tagline + '"')}`);
251
+ // ══════════════════════════════════════════════
252
+ // ARCHETYPE DEFINITION
253
+ // ══════════════════════════════════════════════
254
+
255
+ function displayArchetype(result) {
256
+ const { archetype } = result;
257
+ console.log(` ${bold.white(archetype.name)}`);
258
+ console.log();
259
+ if (archetype.description) {
260
+ const lines = wrapText(archetype.description, 51);
261
+ for (const line of lines) {
262
+ console.log(` ${dim(line)}`);
263
+ }
264
+ }
265
+ if (archetype.distribution) {
266
+ console.log();
267
+ console.log(` ${dim('Distribution: ' + archetype.distribution + ' of scored engineers')}`);
199
268
  }
200
269
  console.log();
270
+ }
201
271
 
202
- // ── Score weights (transparency) ──
203
- console.log(` ${dim('Score = Thinking (25%) + Debugging (25%) + AI Leverage (30%) + Workflow (20%)')}`);
204
- console.log();
205
- console.log(doubleRule());
272
+ // ══════════════════════════════════════════════
273
+ // DIMENSIONS with ranges and qualitative labels
274
+ // ══════════════════════════════════════════════
275
+
276
+ function displayDimensions(result) {
277
+ const { scores } = result;
278
+ console.log(dim(' DIMENSIONS'));
206
279
  console.log();
207
280
 
208
- // Dimensions box with qualitative labels
209
- console.log(dim(' DIMENSIONS\n'));
281
+ // Score weight transparency
282
+ console.log(` ${dim('Weights: Thinking 25% | Debugging 25% | AI Leverage 30% | Workflow 20%')}`);
283
+ console.log();
210
284
 
211
- function dimLine(label, score) {
285
+ function dimLine(label, key, score) {
212
286
  const labelStr = bold(label);
213
287
  const labelVisible = label.length;
214
288
  const labelPad = ' '.repeat(Math.max(0, 15 - labelVisible));
215
- const scoreStr = String(score);
216
- const scorePad = score < 10 ? ' ' : score < 100 ? ' ' : '';
217
289
  const tierLabel = dimTierLabel(score);
218
- const tierStr = dimTierColor(score)(tierLabel);
219
- return ` ${labelStr}${labelPad}${progressBar(score)} ${scorePad}${bold(scoreStr)} ${dim('\u2500\u2500')} ${tierStr} `;
290
+ const tierStr = dimTierColor(score)(pad(tierLabel, 11));
291
+ const range = DIM_RANGES[key];
292
+ const rangeStr = dim(`range: ${range.min}-${range.max} | you: ${score}`);
293
+ return [
294
+ ` ${labelStr}${labelPad}${progressBar(score)} ${tierStr}`,
295
+ ` ${' '.repeat(15)}${rangeStr}`,
296
+ ];
220
297
  }
221
298
 
222
- const dimLines = [
223
- '',
224
- dimLine('Thinking', scores.decomposition),
225
- dimLine('Debugging', scores.debugCycles),
226
- dimLine('AI Leverage', scores.aiLeverage),
227
- dimLine('Workflow', scores.sessionStructure),
228
- '',
229
- ];
230
- for (const l of box(dimLines, 53)) console.log(l);
231
- console.log();
232
-
233
- // ── Cross-platform breakdown ──
234
- if (perToolScores && Object.keys(perToolScores).length > 1) {
235
- console.log(dim(' CROSS-PLATFORM\n'));
236
- // Sort by score descending, null scores last
237
- const sorted = Object.entries(perToolScores).sort((a, b) => {
238
- if (a[1].score === null) return 1;
239
- if (b[1].score === null) return -1;
240
- return b[1].score - a[1].score;
241
- });
242
- // Find primary (most sessions)
243
- const maxSessions = Math.max(...sorted.map(([, v]) => v.sessions));
244
-
245
- for (const [tool, data] of sorted) {
246
- if (data.score !== null) {
247
- const isPrimary = data.sessions === maxSessions;
248
- const label = isPrimary ? 'primary tool' : data.sessions < 5 ? 'limited usage' : (data.label || 'active');
249
- const barWidth = 18;
250
- const filled = Math.round((data.score / 100) * barWidth);
251
- const empty = barWidth - filled;
252
- const bar = scoreColor(data.score)('\u2588'.repeat(filled)) + dim('\u2591'.repeat(empty));
253
- console.log(` ${pad(bold(tool), 18)} ${bold(String(data.score))} ${bar} ${dim(label)}`);
254
- } else {
255
- console.log(` ${pad(bold(tool), 18)} ${dim('--')} ${dim('\u2591'.repeat(18))} ${dim('limited data')}`);
256
- }
299
+ const allLines = [''];
300
+ allLines.push(...dimLine('Thinking', 'decomposition', scores.decomposition));
301
+ allLines.push('');
302
+ allLines.push(...dimLine('Debugging', 'debugCycles', scores.debugCycles));
303
+ allLines.push('');
304
+ allLines.push(...dimLine('AI Leverage', 'aiLeverage', scores.aiLeverage));
305
+ allLines.push('');
306
+ allLines.push(...dimLine('Workflow', 'sessionStructure', scores.sessionStructure));
307
+ allLines.push('');
308
+
309
+ for (const l of box(allLines, 53)) console.log(l);
310
+ console.log();
311
+ }
312
+
313
+ // ══════════════════════════════════════════════
314
+ // CROSS-PLATFORM
315
+ // ══════════════════════════════════════════════
316
+
317
+ function displayCrossPlatform(perToolScores) {
318
+ if (!perToolScores || Object.keys(perToolScores).length <= 1) return;
319
+
320
+ console.log(dim(' CROSS-PLATFORM\n'));
321
+ const sorted = Object.entries(perToolScores).sort((a, b) => {
322
+ if (a[1].score === null) return 1;
323
+ if (b[1].score === null) return -1;
324
+ return b[1].score - a[1].score;
325
+ });
326
+ const maxSessions = Math.max(...sorted.map(([, v]) => v.sessions));
327
+
328
+ for (const [tool, data] of sorted) {
329
+ if (data.score !== null) {
330
+ const isPrimary = data.sessions === maxSessions;
331
+ const label = isPrimary ? 'primary tool' : data.sessions < 5 ? 'limited usage' : 'active';
332
+ console.log(` ${pad(bold(tool), 18)} ${bold(String(data.score))} ${progressBar(data.score)} ${dim(label)}`);
333
+ } else {
334
+ console.log(` ${pad(bold(tool), 18)} ${dim('--')} ${dim('\u2591'.repeat(18))} ${dim('limited data')}`);
257
335
  }
336
+ }
337
+ console.log();
338
+ }
339
+
340
+ // ══════════════════════════════════════════════
341
+ // PROJECT ANALYSIS
342
+ // ══════════════════════════════════════════════
343
+
344
+ function displayProjects(insights) {
345
+ const projects = insights?.projectComplexity;
346
+ if (!projects || projects.length === 0) return;
347
+
348
+ console.log(dim(' PROJECT ANALYSIS\n'));
349
+ for (const p of projects) {
350
+ const compColor = p.complexity === 'HIGH' ? green : p.complexity === 'MEDIUM' ? yellow : dim;
351
+ const signals = p.signals.length > 0 ? p.signals.join(' \u00B7 ') : '';
352
+ console.log(` ${pad(bold(p.name), 32)} Complexity: ${compColor(p.complexity)}`);
353
+ if (signals) {
354
+ console.log(` ${dim(signals)}`);
355
+ }
356
+ console.log(` ${dim(`${p.sessions} sessions \u00B7 ${numberFormat(p.exchanges)} exchanges \u00B7 ${p.daysActive} days active`)}`);
258
357
  console.log();
259
358
  }
260
359
  }
261
360
 
262
361
  // ══════════════════════════════════════════════
263
- // DIMENSION NARRATIVES (data-driven, punchy)
362
+ // DIMENSION NARRATIVES — Clinical, benchmarked
264
363
  // ══════════════════════════════════════════════
265
364
 
266
365
  export function displayNarratives(metrics, prose) {
@@ -275,10 +374,10 @@ export function displayNarratives(metrics, prose) {
275
374
 
276
375
  if (prose && prose.sections) {
277
376
  const sectionSnippetMap = {
278
- 'thinking': { label: 'Best decomposition prompt', prompt: pickExample(metrics.decomposition.examples, 'decomposition') },
279
- 'debugging': { label: 'Best debug prompt', prompt: pickExample(metrics.debugCycles.examples, 'specific_report') || pickExample(metrics.debugCycles.examples, 'quick_fix') },
280
- 'ai leverage': { label: 'Best leverage prompt', prompt: pickExample(metrics.aiLeverage.examples, 'architectural') || pickExample(metrics.aiLeverage.examples, 'planning') },
281
- 'workflow': { label: 'Best workflow prompt', prompt: pickExample(metrics.sessionStructure.examples, 'context_setting') || pickExample(metrics.sessionStructure.examples, 'refinement') },
377
+ 'thinking': { label: 'Evidence', prompt: pickExample(metrics.decomposition.examples, 'decomposition') },
378
+ 'debugging': { label: 'Evidence', prompt: pickExample(metrics.debugCycles.examples, 'specific_report') || pickExample(metrics.debugCycles.examples, 'quick_fix') },
379
+ 'ai leverage': { label: 'Evidence', prompt: pickExample(metrics.aiLeverage.examples, 'architectural') || pickExample(metrics.aiLeverage.examples, 'planning') },
380
+ 'workflow': { label: 'Evidence', prompt: pickExample(metrics.sessionStructure.examples, 'context_setting') || pickExample(metrics.sessionStructure.examples, 'refinement') },
282
381
  };
283
382
 
284
383
  for (const section of prose.sections) {
@@ -293,21 +392,17 @@ export function displayNarratives(metrics, prose) {
293
392
  console.log();
294
393
  }
295
394
  } else {
296
- displayDataNarrativesWithTracker(metrics, shownSnippets);
395
+ displayDataNarratives(metrics, shownSnippets);
297
396
  }
298
397
  }
299
398
 
300
- function displayDataNarrativesWithTracker(metrics, shownSnippets) {
399
+ function displayDataNarratives(metrics, shownSnippets) {
301
400
  const d = metrics.decomposition.details;
302
401
  const db = metrics.debugCycles.details;
303
402
  const ai = metrics.aiLeverage.details;
304
403
  const ss = metrics.sessionStructure.details;
305
- const dEx = metrics.decomposition.examples || [];
306
- const dbEx = metrics.debugCycles.examples || [];
307
- const aiEx = metrics.aiLeverage.examples || [];
308
- const ssEx = metrics.sessionStructure.examples || [];
309
404
 
310
- function showLabeledSnippet(label, prompt) {
405
+ function showSnippet(label, prompt) {
311
406
  if (!prompt) return;
312
407
  const s = cleanPrompt(prompt, 120);
313
408
  if (shownSnippets.has(s)) return;
@@ -315,128 +410,180 @@ function displayDataNarrativesWithTracker(metrics, shownSnippets) {
315
410
  displayLabeledSnippet(label, prompt);
316
411
  }
317
412
 
318
- // Thinking
413
+ // Thinking — clinical
319
414
  console.log(` ${bold('\uD83E\uDDE0 THINKING')}`);
320
- const exchPerSession = d.avgExchangesPerSession;
321
- console.log(` ${dim(exchPerSession > 20 ? `${exchPerSession} avg exchanges/session \u2014 marathon builder` : exchPerSession > 8 ? `${exchPerSession} avg exchanges/session \u2014 iterative` : `${exchPerSession} avg exchanges/session \u2014 concise`)}`);
322
- console.log(` ${dim(d.avgPromptLength > 500 ? `${numberFormat(d.avgPromptLength)} char avg prompt \u2014 thinks out loud` : `${d.avgPromptLength} char avg prompt \u2014 concise communicator`)}`);
323
- console.log(` ${dim(d.multiStepSessions > d.singleShotSessions * 2 ? 'Multi-step decomposition over single-shot' : 'Mix of multi-step and single-shot sessions')}`);
324
- showLabeledSnippet('Best decomposition prompt', pickExample(dEx, 'decomposition'));
415
+ console.log(` ${dim(`Avg session depth: ${d.avgExchangesPerSession} exchanges (benchmark: ${BENCHMARKS.avgExchangesPerSession})`)}`);
416
+ console.log(` ${dim(`Avg prompt length: ${numberFormat(d.avgPromptLength)} chars (benchmark: ${BENCHMARKS.avgPromptLength})`)}`);
417
+ console.log(` ${dim(`Multi-step ratio: ${d.multiStepSessions}/${d.totalSessions} sessions (${Math.round(d.multiStepSessions / Math.max(1, d.totalSessions) * 100)}%)`)}`);
418
+ showSnippet('Evidence', pickExample(metrics.decomposition.examples, 'decomposition'));
325
419
  console.log();
326
420
 
327
- // Debugging
421
+ // Debugging — clinical
328
422
  console.log(` ${bold('\u26A1 DEBUGGING')}`);
329
- const turns = db.avgTurnsToResolve;
330
- console.log(` ${dim(turns <= 2 ? `${turns} turns to resolve \u2014 surgical` : turns <= 4 ? `${turns} turns to resolve \u2014 efficient` : `${turns} turns to resolve \u2014 iterative`)}`);
331
- console.log(` ${dim(`${db.specificReportRatio}% specific error reports \u2014 ${db.specificReportRatio >= 80 ? 'precise' : db.specificReportRatio >= 50 ? 'decent' : 'vague'}`)}`);
332
- console.log(` ${dim(db.longLoops === 0 ? 'Zero long loops \u2014 efficient debugger' : `${db.longLoops} extended debug loops`)}`);
333
- showLabeledSnippet('Best debug prompt', pickExample(dbEx, 'specific_report') || pickExample(dbEx, 'quick_fix'));
423
+ console.log(` ${dim(`Avg resolution: ${db.avgTurnsToResolve} turns (benchmark: ${BENCHMARKS.avgTurnsToResolve})`)}`);
424
+ console.log(` ${dim(`Specific reports: ${db.specificReportRatio}% (benchmark: ${BENCHMARKS.specificReportRatio}%)`)}`);
425
+ console.log(` ${dim(`Extended loops: ${db.longLoops} | Quick fixes: ${db.quickFixes}/${db.totalDebugSequences}`)}`);
426
+ showSnippet('Evidence', pickExample(metrics.debugCycles.examples, 'specific_report') || pickExample(metrics.debugCycles.examples, 'quick_fix'));
334
427
  console.log();
335
428
 
336
- // AI Leverage
429
+ // AI Leverage — clinical
337
430
  console.log(` ${bold('\uD83D\uDD27 AI LEVERAGE')}`);
338
- console.log(` ${dim(`${ai.highLevelRatio}% architecture prompts \u2014 ${ai.highLevelRatio > 25 ? 'high-level partner usage' : 'room to leverage AI more strategically'}`)}`);
339
- const codingRatio = ai.toolDiversity.coding > ai.toolDiversity.research ? 'Coding-heavy' : 'Research-heavy';
340
- console.log(` ${dim(`${codingRatio} over ${ai.toolDiversity.coding > ai.toolDiversity.research ? 'research' : 'coding'}-heavy`)}`);
341
- console.log(` ${dim(`${ai.architecturalPrompts} architectural, ${ai.planningPrompts} planning, ${ai.exploratoryPrompts} exploratory`)}`);
342
- showLabeledSnippet('Best leverage prompt', pickExample(aiEx, 'architectural') || pickExample(aiEx, 'planning'));
431
+ console.log(` ${dim(`High-level ratio: ${ai.highLevelRatio}% (benchmark: ${BENCHMARKS.highLevelRatio}%)`)}`);
432
+ console.log(` ${dim(`Breakdown: ${ai.architecturalPrompts} architectural \u00B7 ${ai.planningPrompts} planning \u00B7 ${ai.exploratoryPrompts} exploratory`)}`);
433
+ console.log(` ${dim(`Boilerplate: ${ai.boilerplatePrompts} (${Math.round(ai.boilerplatePrompts / Math.max(1, ai.totalPrompts) * 100)}%) \u00B7 Testing: ${ai.testingPrompts}`)}`);
434
+ showSnippet('Evidence', pickExample(metrics.aiLeverage.examples, 'architectural') || pickExample(metrics.aiLeverage.examples, 'planning'));
343
435
  console.log();
344
436
 
345
- // Workflow
437
+ // Workflow — clinical
346
438
  console.log(` ${bold('\uD83D\uDCD0 WORKFLOW')}`);
347
- console.log(` ${dim(`${ss.contextSetRatio}% context-setting rate \u2014 ${ss.contextSetRatio > 50 ? 'deliberate' : ss.contextSetRatio > 25 ? 'moderate' : 'low'}`)}`);
348
- console.log(` ${dim(`${ss.reviewEndRatio}% sessions end with review`)}`);
349
- console.log(` ${dim(`${ss.refinementRatio}% refinement rate \u2014 ${ss.refinementRatio > 20 ? 'critical eye' : 'accepts readily'}`)}`);
350
- showLabeledSnippet('Best workflow prompt', pickExample(ssEx, 'context_setting') || pickExample(ssEx, 'refinement'));
439
+ console.log(` ${dim(`Context-setting: ${ss.contextSetRatio}% (benchmark: ${BENCHMARKS.contextSetRatio}%)`)}`);
440
+ console.log(` ${dim(`Review at end: ${ss.reviewEndRatio}% (benchmark: ${BENCHMARKS.reviewEndRatio}%)`)}`);
441
+ console.log(` ${dim(`Refinement rate: ${ss.refinementRatio}% (benchmark: ${BENCHMARKS.refinementRatio}%)`)}`);
442
+ showSnippet('Evidence', pickExample(metrics.sessionStructure.examples, 'context_setting') || pickExample(metrics.sessionStructure.examples, 'refinement'));
351
443
  console.log();
352
444
  }
353
445
 
354
-
355
446
  // ══════════════════════════════════════════════
356
- // COACHING RECOMMENDATION
447
+ // SIGNATURES — What makes you distinctive
357
448
  // ══════════════════════════════════════════════
358
449
 
359
- function displayCoaching(result, metrics) {
360
- const { scores } = result;
361
- // Find the weakest dimension
362
- const dims = [
363
- { key: 'decomposition', label: 'Thinking', score: scores.decomposition },
364
- { key: 'debugCycles', label: 'Debugging', score: scores.debugCycles },
365
- { key: 'aiLeverage', label: 'AI Leverage', score: scores.aiLeverage },
366
- { key: 'sessionStructure', label: 'Workflow', score: scores.sessionStructure },
367
- ];
368
- dims.sort((a, b) => a.score - b.score);
369
- const weakest = dims[0];
370
-
371
- // Only show coaching if the weakest is actually dragging things down
372
- if (weakest.score >= 70) return;
373
-
374
- const tips = {
375
- decomposition: 'Break complex tasks into subtasks before prompting.\nEngineers who decompose problems score 15+ points higher.',
376
- debugCycles: 'Include specific error messages and stack traces in debug prompts.\nPrecise reports resolve 2x faster than "it\'s broken, fix it."',
377
- aiLeverage: 'Use AI for architecture and planning, not just code generation.\nAsk "what\'s the best approach" before "write the code."',
378
- sessionStructure: 'Set context at the start of each session and review at the end.\nEngineers who do this score 12 points higher on average.',
379
- };
380
-
381
- console.log(` ${bold('\uD83D\uDCA1 TO LEVEL UP')}`);
382
- console.log(` ${dim(`Your ${weakest.label} score (${weakest.score}) is your biggest opportunity.`)}`);
383
- const tipLines = tips[weakest.key].split('\n');
384
- for (const line of tipLines) {
385
- console.log(` ${dim(line)}`);
450
+ function displaySignatures(insights) {
451
+ const sigs = insights?.signatures;
452
+ if (!sigs || sigs.length === 0) return;
453
+
454
+ console.log(dim(' YOUR SIGNATURES\n'));
455
+ for (const sig of sigs) {
456
+ console.log(` ${cyan('\u2726')} ${bold(sig.name)}`);
457
+ const lines = wrapText(sig.detail, 49);
458
+ for (const line of lines) {
459
+ console.log(` ${dim(line)}`);
460
+ }
461
+ console.log();
386
462
  }
387
- console.log();
388
463
  }
389
464
 
390
-
391
465
  // ══════════════════════════════════════════════
392
- // EASTER EGGS
466
+ // WATCH POINTS — Areas to improve
393
467
  // ══════════════════════════════════════════════
394
468
 
395
- export function displayEasterEggs(result, metrics) {
396
- const { overall } = result;
397
- const db = metrics.debugCycles.details;
398
-
399
- const eggs = [];
469
+ function displayWatchPoints(insights) {
470
+ const wps = insights?.watchPoints;
471
+ if (!wps || wps.length === 0) return;
400
472
 
401
- if (overall >= 90) {
402
- eggs.push('Top-tier. Companies should be applying to you.');
473
+ console.log(dim(' WATCH POINTS\n'));
474
+ for (const wp of wps) {
475
+ console.log(` ${orange('\u26A0')} ${bold(wp.name)}`);
476
+ const lines = wrapText(wp.detail, 49);
477
+ for (const line of lines) {
478
+ console.log(` ${dim(line)}`);
479
+ }
480
+ console.log();
403
481
  }
482
+ }
483
+
484
+ // ══════════════════════════════════════════════
485
+ // TRAJECTORY — Weekly evolution
486
+ // ══════════════════════════════════════════════
404
487
 
405
- if (db.longLoops === 0 && db.totalDebugSequences > 10) {
406
- eggs.push('Zero debug spirals. Either you\'re exceptional or your AI is.');
488
+ function displayTrajectory(insights) {
489
+ const traj = insights?.trajectory;
490
+ if (!traj) return;
491
+
492
+ console.log(dim(' YOUR TRAJECTORY\n'));
493
+ for (let i = 0; i < traj.weeks.length; i++) {
494
+ const w = traj.weeks[i];
495
+ const prev = i > 0 ? traj.weeks[i - 1] : null;
496
+ const arrow = prev ? (w.score > prev.score ? green(' \u2191') : w.score < prev.score ? orange(' \u2193') : dim(' \u2192')) : '';
497
+ const tierLabel = dimTierLabel(w.score);
498
+ console.log(` ${dim(pad(w.label, 16))} Score: ${scoreColor(w.score).bold(String(w.score))} ${dimTierColor(w.score)(tierLabel)}${arrow}`);
407
499
  }
500
+ console.log();
501
+ const velColor = traj.velocityLabel === 'FAST' ? green : traj.velocityLabel === 'STEADY' ? cyan : traj.velocityLabel === 'STABLE' ? yellow : orange;
502
+ console.log(` ${dim('Learning velocity:')} ${velColor(traj.velocityLabel)} ${dim('\u2014 ' + traj.velocityDetail)}`);
503
+ console.log();
504
+ }
408
505
 
409
- if (db.vagueReports === 0 && db.totalDebugSequences > 20) {
410
- eggs.push('Never once said "it\'s broken, fix it." Respect.');
506
+ // ══════════════════════════════════════════════
507
+ // ASSESSMENT Narrative paragraph
508
+ // ══════════════════════════════════════════════
509
+
510
+ function displayAssessment(insights) {
511
+ const assessment = insights?.assessment;
512
+ if (!assessment) return;
513
+
514
+ console.log(dim(' ASSESSMENT\n'));
515
+ const lines = wrapText(assessment, 51);
516
+ for (const line of lines) {
517
+ console.log(` ${dim(line)}`);
411
518
  }
519
+ console.log();
520
+ }
412
521
 
413
- if (eggs.length > 0) {
414
- for (const egg of eggs) {
415
- console.log(` ${dim('\u2727')} ${dim.italic(egg)}`);
416
- }
522
+ // ══════════════════════════════════════════════
523
+ // CONFIDENCE INDICATOR
524
+ // ══════════════════════════════════════════════
525
+
526
+ function displayConfidence(insights, sessionStats) {
527
+ const conf = insights?.confidence;
528
+ if (!conf) return;
529
+
530
+ const barWidth = 18;
531
+ const filled = Math.round((conf.score / 100) * barWidth);
532
+ const empty = barWidth - filled;
533
+ const confColor = conf.level === 'HIGH' ? green : conf.level === 'MODERATE' ? yellow : orange;
534
+ const bar = confColor('\u2588'.repeat(filled)) + dim('\u2591'.repeat(empty));
535
+
536
+ console.log(` ${dim('Profile confidence:')} ${bar} ${confColor(conf.level)}`);
537
+ if (sessionStats) {
538
+ console.log(` ${dim(`Based on ${sessionStats.totalSessions} sessions across ${sessionStats.tools.length} tool${sessionStats.tools.length > 1 ? 's' : ''}.`)}`);
539
+ }
540
+ console.log();
541
+ if (conf.level !== 'HIGH') {
542
+ console.log(` ${dim('Confidence increases with more sessions and tool')}`);
543
+ console.log(` ${dim('diversity. Run again in 30 days for updated assessment.')}`);
417
544
  console.log();
418
545
  }
419
546
  }
420
547
 
421
548
  // ══════════════════════════════════════════════
422
- // VIRAL ENDING
549
+ // METHODOLOGY FOOTER
423
550
  // ══════════════════════════════════════════════
424
551
 
425
- export function displayEnding(result) {
552
+ function displayMethodology() {
553
+ console.log(doubleRule());
554
+ console.log();
555
+ console.log(` ${dim('METHODOLOGY')}`);
556
+ console.log(` ${dim('Scores derived from structural analysis of prompt')}`);
557
+ console.log(` ${dim('patterns, debug sequences, and session architecture')}`);
558
+ console.log(` ${dim('across detected AI coding tools. Tier placement based')}`);
559
+ console.log(` ${dim('on distribution of scored engineers. No prompt content')}`);
560
+ console.log(` ${dim('is stored or transmitted. Learn more: chekk.dev/methodology')}`);
561
+ console.log();
562
+ }
563
+
564
+ // ══════════════════════════════════════════════
565
+ // NEXT STEPS — Credential issuance
566
+ // ══════════════════════════════════════════════
567
+
568
+ function displayNextSteps(result) {
426
569
  const { overall, archetype, tier, tierBadge } = result;
427
570
  const tc = tierColor(tier);
428
571
 
429
572
  console.log(doubleRule());
430
573
  console.log();
431
-
432
- // Value-driven claim CTA
433
- console.log(` ${dim('\u2192 Claim your profile to:')}`);
434
- console.log(` ${dim(' \u00B7 See how you compare across 10K+ engineers')}`);
435
- console.log(` ${dim(' \u00B7 Get matched with roles at top startups')}`);
436
- console.log(` ${dim(' \u00B7 Track your score over time')}`);
437
- console.log(` ${cyan.underline(' chekk.dev/claim')}`);
574
+ console.log(` ${bold.white('NEXT STEPS')}`);
575
+ console.log();
576
+ console.log(` ${dim('\u2192 Claim your verified profile')}`);
577
+ console.log(` ${dim('Link your GitHub and LinkedIn to create your')}`);
578
+ console.log(` ${dim('portable engineering credential.')}`);
579
+ console.log(` ${cyan.underline('chekk.dev/claim')}`);
580
+ console.log();
581
+ console.log(` ${dim('\u2192 View industry benchmarks')}`);
582
+ console.log(` ${dim('See how you compare across scored engineers.')}`);
583
+ console.log(` ${cyan.underline('chekk.dev/benchmarks')}`);
438
584
  console.log();
439
- console.log(` ${dim('\u2192 Leaderboard:')} ${cyan.underline('chekk.dev/leaderboard')}`);
585
+ console.log(` ${dim('\u2192 Export this report')}`);
586
+ console.log(` ${dim('npx chekk --json')}`);
440
587
  console.log();
441
588
 
442
589
  // Copy-paste share line
@@ -446,12 +593,12 @@ export function displayEnding(result) {
446
593
  console.log(` ${dim('\u2191 Copy this to share')}`);
447
594
  console.log();
448
595
  console.log(doubleRule());
449
- console.log(` ${dim('chekk.dev \u2014 the engineering capability score')}`);
596
+ console.log(` ${dim('chekk.dev \u2014 engineering capability profiles')}`);
450
597
  console.log();
451
598
  }
452
599
 
453
600
  // ══════════════════════════════════════════════
454
- // VERBOSE: DETAILED BREAKDOWN (with interpretation)
601
+ // VERBOSE: DETAILED BREAKDOWN
455
602
  // ══════════════════════════════════════════════
456
603
 
457
604
  export function displayVerbose(metrics, sessions) {
@@ -475,72 +622,77 @@ export function displayVerbose(metrics, sessions) {
475
622
  }
476
623
  console.log();
477
624
 
478
- // Decomposition details with interpretation
625
+ // Decomposition
479
626
  const d = metrics.decomposition.details;
480
- console.log(bold(' DECOMPOSITION DETAILS'));
481
- console.log(` ${dim(pad('totalSessions', 30))} ${dim(String(d.totalSessions))}`);
482
- console.log(` ${dim(pad('multiStepSessions', 30))} ${dim(String(d.multiStepSessions))} ${dim(d.multiStepSessions > d.totalSessions * 0.5 ? '\u2014 strong iterative work' : '\u2014 room for more iteration')}`);
483
- console.log(` ${dim(pad('singleShotSessions', 30))} ${dim(String(d.singleShotSessions))} ${dim(d.singleShotSessions < d.totalSessions * 0.3 ? '\u2014 good, not over-relying on one-shots' : '\u2014 consider breaking tasks down more')}`);
484
- console.log(` ${dim(pad('avgExchangesPerSession', 30))} ${dim(String(d.avgExchangesPerSession))} ${dim(d.avgExchangesPerSession > 12 ? '\u2014 deep sessions' : d.avgExchangesPerSession > 5 ? '\u2014 moderate depth' : '\u2014 shallow sessions')}`);
485
- console.log(` ${dim(pad('avgPromptLength', 30))} ${dim(String(d.avgPromptLength) + ' chars')} ${dim(d.avgPromptLength > 300 ? '\u2014 detailed communicator' : d.avgPromptLength > 100 ? '\u2014 moderate detail' : '\u2014 terse')}`);
486
- console.log(` ${dim(pad('longPromptRatio', 30))} ${dim(d.longPromptRatio + '%')}`);
487
- console.log(` ${dim(pad('contextualFollowupRatio', 30))} ${dim(d.contextualFollowupRatio + '%')} ${dim(d.contextualFollowupRatio > 20 ? '\u2014 builds on previous context well' : '\u2014 could reference prior context more')}`);
627
+ console.log(bold(' DECOMPOSITION'));
628
+ console.log(` ${dim(pad('Avg session depth', 30))} ${dim(String(d.avgExchangesPerSession))} ${dim(`(benchmark: ${BENCHMARKS.avgExchangesPerSession})`)}`);
629
+ console.log(` ${dim(pad('Avg prompt length', 30))} ${dim(d.avgPromptLength + ' chars')} ${dim(`(benchmark: ${BENCHMARKS.avgPromptLength})`)}`);
630
+ console.log(` ${dim(pad('Multi-step sessions', 30))} ${dim(String(d.multiStepSessions) + '/' + d.totalSessions)} ${dim(d.multiStepSessions > d.totalSessions * 0.5 ? '\u2014 strong' : '\u2014 room to grow')}`);
631
+ console.log(` ${dim(pad('Single-shot sessions', 30))} ${dim(String(d.singleShotSessions))}`);
632
+ console.log(` ${dim(pad('Contextual followups', 30))} ${dim(d.contextualFollowupRatio + '%')} ${dim(d.contextualFollowupRatio > 20 ? '\u2014 builds on context well' : '\u2014 could reference prior work more')}`);
488
633
  console.log();
489
634
 
490
- // Debug cycle details
635
+ // Debug
491
636
  const db = metrics.debugCycles.details;
492
- console.log(bold(' DEBUG CYCLE DETAILS'));
493
- console.log(` ${dim(pad('totalDebugSequences', 30))} ${dim(String(db.totalDebugSequences))}`);
494
- console.log(` ${dim(pad('avgTurnsToResolve', 30))} ${dim(String(db.avgTurnsToResolve))} ${dim(db.avgTurnsToResolve <= 2 ? '\u2014 surgical precision' : db.avgTurnsToResolve <= 4 ? '\u2014 efficient' : '\u2014 could be tighter')}`);
495
- console.log(` ${dim(pad('quickFixes', 30))} ${dim(String(db.quickFixes))} ${dim(db.quickFixes > db.totalDebugSequences * 0.5 ? '\u2014 most issues resolved fast' : '')}`);
496
- console.log(` ${dim(pad('longLoops', 30))} ${dim(String(db.longLoops))} ${dim(db.longLoops === 0 ? '\u2014 zero spirals' : '\u2014 some extended debugging')}`);
497
- console.log(` ${dim(pad('specificReportRatio', 30))} ${dim(db.specificReportRatio + '%')} ${dim(db.specificReportRatio >= 80 ? '\u2014 precise error reporting' : '\u2014 include more stack traces/line numbers')}`);
498
- console.log(` ${dim(pad('vagueReports', 30))} ${dim(String(db.vagueReports))} ${dim(db.vagueReports === 0 ? '\u2014 never vague' : `\u2014 ${db.vagueReports} vague reports`)}`);
637
+ console.log(bold(' DEBUG CYCLES'));
638
+ console.log(` ${dim(pad('Total sequences', 30))} ${dim(String(db.totalDebugSequences))}`);
639
+ console.log(` ${dim(pad('Avg turns to resolve', 30))} ${dim(String(db.avgTurnsToResolve))} ${dim(`(benchmark: ${BENCHMARKS.avgTurnsToResolve})`)}`);
640
+ console.log(` ${dim(pad('Quick fixes (\u22642 turns)', 30))} ${dim(String(db.quickFixes))}`);
641
+ console.log(` ${dim(pad('Extended loops (>5 turns)', 30))} ${dim(String(db.longLoops))} ${dim(db.longLoops === 0 ? '\u2014 zero spirals' : '')}`);
642
+ console.log(` ${dim(pad('Specific report ratio', 30))} ${dim(db.specificReportRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.specificReportRatio}%)`)}`);
643
+ console.log(` ${dim(pad('Vague reports', 30))} ${dim(String(db.vagueReports))} ${dim(db.vagueReports === 0 ? '\u2014 never vague' : '')}`);
499
644
  console.log();
500
645
 
501
- // AI Leverage details
646
+ // AI Leverage
502
647
  const ai = metrics.aiLeverage.details;
503
- console.log(bold(' AI LEVERAGE DETAILS'));
504
- console.log(` ${dim(pad('totalPrompts', 30))} ${dim(numberFormat(ai.totalPrompts))}`);
505
- console.log(` ${dim(pad('architecturalPrompts', 30))} ${dim(String(ai.architecturalPrompts))} ${dim(`(${Math.round(ai.architecturalPrompts / ai.totalPrompts * 100)}%)`)} ${dim(ai.architecturalPrompts > ai.totalPrompts * 0.1 ? '\u2014 strategic usage' : '\u2014 could use AI for more design work')}`);
506
- console.log(` ${dim(pad('planningPrompts', 30))} ${dim(String(ai.planningPrompts))} ${dim(`(${Math.round(ai.planningPrompts / ai.totalPrompts * 100)}%)`)}`);
507
- console.log(` ${dim(pad('exploratoryPrompts', 30))} ${dim(String(ai.exploratoryPrompts))} ${dim(`(${Math.round(ai.exploratoryPrompts / ai.totalPrompts * 100)}%)`)}`);
508
- console.log(` ${dim(pad('boilerplatePrompts', 30))} ${dim(String(ai.boilerplatePrompts))} ${dim(`(${Math.round(ai.boilerplatePrompts / ai.totalPrompts * 100)}%)`)} ${dim(ai.boilerplatePrompts < ai.totalPrompts * 0.05 ? '\u2014 very low, minimal repetitive work' : '\u2014 some boilerplate delegation')}`);
509
- console.log(` ${dim(pad('testingPrompts', 30))} ${dim(String(ai.testingPrompts))} ${dim(`(${Math.round(ai.testingPrompts / ai.totalPrompts * 100)}%)`)}`);
510
- console.log(` ${dim(pad('highLevelRatio', 30))} ${dim(ai.highLevelRatio + '%')} ${dim(ai.highLevelRatio > 30 ? '\u2014 strong strategic AI usage' : '\u2014 room to leverage AI for higher-level work')}`);
511
- console.log(` ${dim(pad('toolDiversity.research', 30))} ${dim(String(ai.toolDiversity.research))}`);
512
- console.log(` ${dim(pad('toolDiversity.coding', 30))} ${dim(String(ai.toolDiversity.coding))}`);
513
- console.log();
514
-
515
- // Session structure details
648
+ console.log(bold(' AI LEVERAGE'));
649
+ console.log(` ${dim(pad('Total prompts', 30))} ${dim(numberFormat(ai.totalPrompts))}`);
650
+ console.log(` ${dim(pad('Architectural', 30))} ${dim(String(ai.architecturalPrompts))} ${dim(`(${Math.round(ai.architecturalPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
651
+ console.log(` ${dim(pad('Planning', 30))} ${dim(String(ai.planningPrompts))} ${dim(`(${Math.round(ai.planningPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
652
+ console.log(` ${dim(pad('Exploratory', 30))} ${dim(String(ai.exploratoryPrompts))} ${dim(`(${Math.round(ai.exploratoryPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
653
+ console.log(` ${dim(pad('Boilerplate', 30))} ${dim(String(ai.boilerplatePrompts))} ${dim(`(${Math.round(ai.boilerplatePrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)} ${dim(ai.boilerplatePrompts < ai.totalPrompts * 0.05 ? '\u2014 minimal' : '')}`);
654
+ console.log(` ${dim(pad('Testing', 30))} ${dim(String(ai.testingPrompts))}`);
655
+ console.log(` ${dim(pad('High-level ratio', 30))} ${dim(ai.highLevelRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.highLevelRatio}%)`)}`);
656
+ console.log();
657
+
658
+ // Session structure
516
659
  const ss = metrics.sessionStructure.details;
517
- console.log(bold(' SESSION STRUCTURE DETAILS'));
518
- console.log(` ${dim(pad('contextSetRatio', 30))} ${dim(ss.contextSetRatio + '%')} ${dim(ss.contextSetRatio > 50 ? '\u2014 deliberate context-setting' : '\u2014 try explaining goals upfront')}`);
519
- console.log(` ${dim(pad('planBeforeCodeRatio', 30))} ${dim(ss.planBeforeCodeRatio + '%')} ${dim(ss.planBeforeCodeRatio > 20 ? '\u2014 plans before coding' : '\u2014 consider planning before diving in')}`);
520
- console.log(` ${dim(pad('reviewEndRatio', 30))} ${dim(ss.reviewEndRatio + '%')} ${dim(ss.reviewEndRatio > 30 ? '\u2014 reviews work before shipping' : '\u2014 add review steps before finishing')}`);
521
- console.log(` ${dim(pad('refinementRatio', 30))} ${dim(ss.refinementRatio + '%')} ${dim(ss.refinementRatio > 20 ? '\u2014 critically evaluates output' : '\u2014 push back on AI output more')}`);
522
- console.log(` ${dim(pad('avgFirstPromptLength', 30))} ${dim(ss.avgFirstPromptLength + ' chars')} ${dim(ss.avgFirstPromptLength > 200 ? '\u2014 thorough session openers' : '\u2014 try longer context-setting openers')}`);
660
+ console.log(bold(' SESSION STRUCTURE'));
661
+ console.log(` ${dim(pad('Context-setting', 30))} ${dim(ss.contextSetRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.contextSetRatio}%)`)}`);
662
+ console.log(` ${dim(pad('Plan before code', 30))} ${dim(ss.planBeforeCodeRatio + '%')}`);
663
+ console.log(` ${dim(pad('Review at end', 30))} ${dim(ss.reviewEndRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.reviewEndRatio}%)`)}`);
664
+ console.log(` ${dim(pad('Refinement rate', 30))} ${dim(ss.refinementRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.refinementRatio}%)`)}`);
665
+ console.log(` ${dim(pad('Avg first prompt', 30))} ${dim(ss.avgFirstPromptLength + ' chars')}`);
523
666
  if (ss.durationDistribution) {
524
667
  const dur = ss.durationDistribution;
525
- console.log(` ${dim(pad('duration.focused (10-45m)', 30))} ${dim(String(dur.focused))} ${dim('\u2014 sweet spot sessions')}`);
526
- console.log(` ${dim(pad('duration.short (<5m)', 30))} ${dim(String(dur.short))}`);
527
- console.log(` ${dim(pad('duration.medium (5-60m)', 30))} ${dim(String(dur.medium))}`);
528
- console.log(` ${dim(pad('duration.long (>60m)', 30))} ${dim(String(dur.long))}`);
668
+ console.log(` ${dim(pad('Focused sessions (10-45m)', 30))} ${dim(String(dur.focused))}`);
669
+ console.log(` ${dim(pad('Short (<5m)', 30))} ${dim(String(dur.short))}`);
670
+ console.log(` ${dim(pad('Medium (5-60m)', 30))} ${dim(String(dur.medium))}`);
671
+ console.log(` ${dim(pad('Long (>60m)', 30))} ${dim(String(dur.long))}`);
529
672
  }
530
673
  console.log();
531
674
  }
532
675
 
533
676
  // ══════════════════════════════════════════════
534
- // OFFLINE DISPLAY (no API)
677
+ // OFFLINE DISPLAY
535
678
  // ══════════════════════════════════════════════
536
679
 
537
680
  export function displayOffline(result, metrics, extra = {}) {
538
- displayScore(result, null, extra);
539
- displayDataNarrativesWithTracker(metrics, new Set());
540
- displayCoaching(result, metrics);
541
- displayEasterEggs(result, metrics);
542
- console.log(dim(' Run without --offline for personalized AI-generated insights\n'));
543
- displayEnding(result);
681
+ displayProfileHeader(result, extra);
682
+ displaySummary(result, extra);
683
+ displayArchetype(result);
684
+ displayDimensions(result);
685
+ displayCrossPlatform(extra.perToolScores);
686
+ displayDataNarratives(metrics, new Set());
687
+ displayProjects(extra.insights);
688
+ displaySignatures(extra.insights);
689
+ displayWatchPoints(extra.insights);
690
+ displayTrajectory(extra.insights);
691
+ displayAssessment(extra.insights);
692
+ displayConfidence(extra.insights, extra.sessionStats);
693
+ displayMethodology();
694
+ console.log(dim(' Run without --offline for AI-generated narrative insights\n'));
695
+ displayNextSteps(result);
544
696
  }
545
697
 
546
698
  // ══════════════════════════════════════════════
@@ -548,11 +700,20 @@ export function displayOffline(result, metrics, extra = {}) {
548
700
  // ══════════════════════════════════════════════
549
701
 
550
702
  export function displayFull(result, metrics, prose, extra = {}) {
551
- displayScore(result, prose, extra);
703
+ displayProfileHeader(result, extra);
704
+ displaySummary(result, extra);
705
+ displayArchetype(result);
706
+ displayDimensions(result);
707
+ displayCrossPlatform(extra.perToolScores);
552
708
  displayNarratives(metrics, prose);
553
- displayCoaching(result, metrics);
554
- displayEasterEggs(result, metrics);
555
- displayEnding(result);
709
+ displayProjects(extra.insights);
710
+ displaySignatures(extra.insights);
711
+ displayWatchPoints(extra.insights);
712
+ displayTrajectory(extra.insights);
713
+ displayAssessment(extra.insights);
714
+ displayConfidence(extra.insights, extra.sessionStats);
715
+ displayMethodology();
716
+ displayNextSteps(result);
556
717
  }
557
718
 
558
719
  // ── Utility ──