chekk 0.3.0 → 0.4.1

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;
@@ -78,15 +80,37 @@ function displayLabeledSnippet(label, prompt, maxLen = 120) {
78
80
  console.log(` ${dim('\u21B3')} ${dim(label + ':')} ${dim.italic('\u201C' + s + '\u201D')}`);
79
81
  }
80
82
 
83
+ // Cross-dimension filters: reject prompts that clearly belong to another dimension
84
+ const architecturalRe = /\b(architect|design|refactor|redesign|restructure|system design|data model|schema|api design|infrastructure|migration|strategy)\b/i;
85
+ const debugRe = /\b(error|bug|broken|crash|fail|exception|traceback|stack trace|doesn'?t work|not working|TypeError|SyntaxError|ImportError|ReferenceError|500|502|503|404|CORS)\b/i;
86
+ const planningRe = /\b(plan|breakdown|break down|think through|help me think|pros and cons|how should|code review|audit)\b/i;
87
+
88
+ // For each dimension, prompts matching these patterns are *excluded* as evidence
89
+ const dimensionExclusions = {
90
+ 'specific_report': [architecturalRe, planningRe],
91
+ 'quick_fix': [architecturalRe, planningRe],
92
+ 'architectural': [debugRe],
93
+ 'planning': [debugRe],
94
+ 'exploratory': [debugRe],
95
+ 'decomposition': [],
96
+ 'followup': [],
97
+ 'context_setting': [],
98
+ 'refinement': [],
99
+ };
100
+
81
101
  function pickExample(examples, type) {
82
102
  if (!examples || !examples.length) return null;
83
- const match = examples.find(e => e.type === type);
84
- return match ? match.prompt : null;
103
+ const exclusions = dimensionExclusions[type] || [];
104
+ // Prefer a match that doesn't trigger exclusion patterns
105
+ const candidates = examples.filter(e => e.type === type);
106
+ if (candidates.length === 0) return null;
107
+ const clean = candidates.find(e => !exclusions.some(re => re.test(e.prompt)));
108
+ return (clean || candidates[0]).prompt;
85
109
  }
86
110
 
87
111
  // ── Box drawing ──
88
112
 
89
- function box(lines, width = 43) {
113
+ function box(lines, width = 47) {
90
114
  const out = [];
91
115
  out.push(dim(' \u250C' + '\u2500'.repeat(width) + '\u2510'));
92
116
  for (const line of lines) {
@@ -98,33 +122,44 @@ function box(lines, width = 43) {
98
122
  return out;
99
123
  }
100
124
 
101
- function doubleRule(width = 47) {
125
+ function doubleRule(width = 53) {
102
126
  return dim(' ' + '\u2550'.repeat(width));
103
127
  }
104
128
 
129
+ function wrapText(text, maxWidth = 49) {
130
+ const words = text.split(' ');
131
+ const lines = [];
132
+ let current = '';
133
+ for (const word of words) {
134
+ if (current.length + word.length + 1 > maxWidth) {
135
+ lines.push(current);
136
+ current = word;
137
+ } else {
138
+ current = current ? current + ' ' + word : word;
139
+ }
140
+ }
141
+ if (current) lines.push(current);
142
+ return lines;
143
+ }
144
+
105
145
  // ══════════════════════════════════════════════
106
- // HEADER
146
+ // HEADER — Scanning + progress
107
147
  // ══════════════════════════════════════════════
108
148
 
109
149
  export function displayHeader() {
110
150
  console.log();
111
151
  const lines = [
112
152
  '',
113
- ` ${bold.white('chekk')}${dim(' v0.3.0')}`,
114
- ` ${dim('the engineering capability score')}`,
153
+ ` ${bold.white('chekk')}${dim(' v0.4.1')}`,
154
+ ` ${dim('engineering capability profile')}`,
115
155
  '',
116
156
  ];
117
157
  for (const l of box(lines, 45)) console.log(l);
118
158
  console.log();
119
159
  }
120
160
 
121
- // ══════════════════════════════════════════════
122
- // SCAN RESULTS
123
- // ══════════════════════════════════════════════
124
-
125
161
  export function displayScan(tools) {
126
162
  console.log(dim(' Scanning local AI tools...\n'));
127
-
128
163
  for (const tool of tools) {
129
164
  const sessions = numberFormat(tool.sessions);
130
165
  const projects = tool.projects.length;
@@ -136,10 +171,6 @@ export function displayScan(tools) {
136
171
  console.log();
137
172
  }
138
173
 
139
- // ══════════════════════════════════════════════
140
- // ANALYSIS PROGRESS BAR
141
- // ══════════════════════════════════════════════
142
-
143
174
  export function displayAnalysisStart(dateRange) {
144
175
  console.log(` ${dim('Analyzing')} ${white(dateRange)}${dim('...\n')}`);
145
176
  }
@@ -148,7 +179,6 @@ export async function displayProgressBar(durationMs = 2000) {
148
179
  const width = 40;
149
180
  const steps = 40;
150
181
  const stepTime = durationMs / steps;
151
-
152
182
  for (let i = 0; i <= steps; i++) {
153
183
  const filled = i;
154
184
  const empty = width - filled;
@@ -159,108 +189,199 @@ export async function displayProgressBar(durationMs = 2000) {
159
189
  }
160
190
  console.log();
161
191
  console.log();
162
- console.log(` ${green('\u2713')} ${dim('Score generated.')}`);
192
+ console.log(` ${green('\u2713')} ${dim('Profile generated.')}`);
163
193
  console.log();
164
194
  }
165
195
 
166
196
  // ══════════════════════════════════════════════
167
- // MAIN SCORE DISPLAY
197
+ // PROFILE HEADER — Official document feel
168
198
  // ══════════════════════════════════════════════
169
199
 
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);
200
+ function displayProfileHeader(result, extra = {}) {
201
+ const { sessionStats } = extra;
202
+ const now = new Date();
203
+ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
204
+ const dateStr = `${months[now.getMonth()]} ${now.getDate()}, ${now.getFullYear()}`;
175
205
 
176
- // Big score block
177
206
  console.log(doubleRule());
178
207
  console.log();
179
- console.log(dim(' YOUR CHEKK SCORE'));
208
+ console.log(` ${bold.white('ENGINEERING CAPABILITY PROFILE')}`);
209
+ console.log();
210
+ if (sessionStats) {
211
+ console.log(` ${dim(`Generated ${dateStr} | chekk v0.4.1`)}`);
212
+ console.log(` ${dim(`Analysis: ${sessionStats.totalSessions} sessions \u00B7 ${sessionStats.tools.length} tool${sessionStats.tools.length > 1 ? 's' : ''} \u00B7 ${numberFormat(sessionStats.totalExchanges)} exchanges`)}`);
213
+ if (sessionStats.dateRangeShort) {
214
+ console.log(` ${dim(`Period: ${sessionStats.dateRangeShort}`)}`);
215
+ }
216
+ }
217
+ console.log();
218
+ console.log(doubleRule());
219
+ }
220
+
221
+ // ══════════════════════════════════════════════
222
+ // SUMMARY BLOCK
223
+ // ══════════════════════════════════════════════
224
+
225
+ function displaySummary(result, extra = {}) {
226
+ const { overall, scores, archetype, tier, tierBadge, tierPercentile } = result;
227
+ const { scoreDelta, perToolScores, insights, sessionStats } = extra;
228
+ const tc = tierColor(tier);
229
+
230
+ // Find strongest and weakest
231
+ const dims = [
232
+ { label: 'Thinking', score: scores.decomposition },
233
+ { label: 'Debugging', score: scores.debugCycles },
234
+ { label: 'AI Leverage', score: scores.aiLeverage },
235
+ { label: 'Workflow', score: scores.sessionStructure },
236
+ ];
237
+ dims.sort((a, b) => b.score - a.score);
238
+ const strongest = dims[0];
239
+ const weakest = dims[dims.length - 1];
240
+
180
241
  console.log();
242
+ console.log(dim(' SUMMARY'));
181
243
 
182
- // Score + delta
244
+ const badge = tierBadge || '';
245
+ const toolsList = sessionStats ? sessionStats.tools.join(' \u00B7 ') : '';
246
+ const sessionCount = sessionStats ? `${sessionStats.totalSessions} across ${sessionStats.projectCount} projects` : '';
247
+ const period = sessionStats?.dateRangeShort || '';
248
+
249
+ // Delta string
183
250
  let deltaStr = '';
184
251
  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')}`;
252
+ if (scoreDelta > 0) deltaStr = ` ${green('\u2191 +' + scoreDelta)}`;
253
+ else if (scoreDelta < 0) deltaStr = ` ${orange('\u2193 ' + scoreDelta)}`;
188
254
  }
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}`);
255
+
256
+ const summaryLines = [
257
+ '',
258
+ ` ${dim('Score')} ${scoreColor(overall).bold(String(overall))}${deltaStr}`,
259
+ ` ${dim('Tier')} ${tc(tier)} ${badge} ${dim('\u2014')} ${dim(tierPercentile)}`,
260
+ ` ${dim('Archetype')} ${bold.white(archetype.name)}`,
261
+ ];
262
+ if (toolsList) summaryLines.push(` ${dim('Tools')} ${dim(toolsList)}`);
263
+ if (sessionCount) summaryLines.push(` ${dim('Sessions')} ${dim(sessionCount)}`);
264
+ if (period) summaryLines.push(` ${dim('Period')} ${dim(period)}`);
265
+ summaryLines.push(` ${dim('Strongest')} ${dim(strongest.label + ' (' + dimTierLabel(strongest.score) + ')')}`);
266
+ summaryLines.push(` ${dim('Growth Area')} ${dim(weakest.label + ' (' + dimTierLabel(weakest.score) + ')')}`);
267
+ summaryLines.push('');
268
+
269
+ for (const l of box(summaryLines, 53)) console.log(l);
194
270
  console.log();
195
- console.log(` ${dim('Archetype:')} ${bold.white(archetype.name)}`);
271
+ }
272
+
273
+ // ══════════════════════════════════════════════
274
+ // ARCHETYPE DEFINITION
275
+ // ══════════════════════════════════════════════
196
276
 
197
- if (prose && prose.tagline) {
198
- console.log(` ${dim('"' + prose.tagline + '"')}`);
277
+ function displayArchetype(result) {
278
+ const { archetype } = result;
279
+ console.log(` ${bold.white(archetype.name)}`);
280
+ console.log();
281
+ if (archetype.description) {
282
+ const lines = wrapText(archetype.description, 51);
283
+ for (const line of lines) {
284
+ console.log(` ${dim(line)}`);
285
+ }
286
+ }
287
+ if (archetype.distribution) {
288
+ console.log();
289
+ console.log(` ${dim('Distribution: ' + archetype.distribution + ' of scored engineers')}`);
199
290
  }
200
291
  console.log();
292
+ }
201
293
 
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());
294
+ // ══════════════════════════════════════════════
295
+ // DIMENSIONS with ranges and qualitative labels
296
+ // ══════════════════════════════════════════════
297
+
298
+ function displayDimensions(result) {
299
+ const { scores } = result;
300
+ console.log(dim(' DIMENSIONS'));
206
301
  console.log();
207
302
 
208
- // Dimensions box with qualitative labels
209
- console.log(dim(' DIMENSIONS\n'));
303
+ // Score weight transparency
304
+ console.log(` ${dim('Weights: Thinking 25% | Debugging 25% | AI Leverage 30% | Workflow 20%')}`);
305
+ console.log();
210
306
 
211
- function dimLine(label, score) {
307
+ function dimLine(label, key, score) {
212
308
  const labelStr = bold(label);
213
309
  const labelVisible = label.length;
214
310
  const labelPad = ' '.repeat(Math.max(0, 15 - labelVisible));
215
- const scoreStr = String(score);
216
- const scorePad = score < 10 ? ' ' : score < 100 ? ' ' : '';
217
311
  const tierLabel = dimTierLabel(score);
218
- const tierStr = dimTierColor(score)(tierLabel);
219
- return ` ${labelStr}${labelPad}${progressBar(score)} ${scorePad}${bold(scoreStr)} ${dim('\u2500\u2500')} ${tierStr} `;
312
+ const tierStr = dimTierColor(score)(pad(tierLabel, 11));
313
+ const range = DIM_RANGES[key];
314
+ const rangeStr = dim(`range: ${range.min}-${range.max} | you: ${score}`);
315
+ return [
316
+ ` ${labelStr}${labelPad}${progressBar(score)} ${tierStr}`,
317
+ ` ${' '.repeat(15)}${rangeStr}`,
318
+ ];
220
319
  }
221
320
 
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
- }
321
+ const allLines = [''];
322
+ allLines.push(...dimLine('Thinking', 'decomposition', scores.decomposition));
323
+ allLines.push('');
324
+ allLines.push(...dimLine('Debugging', 'debugCycles', scores.debugCycles));
325
+ allLines.push('');
326
+ allLines.push(...dimLine('AI Leverage', 'aiLeverage', scores.aiLeverage));
327
+ allLines.push('');
328
+ allLines.push(...dimLine('Workflow', 'sessionStructure', scores.sessionStructure));
329
+ allLines.push('');
330
+
331
+ for (const l of box(allLines, 53)) console.log(l);
332
+ console.log();
333
+ }
334
+
335
+ // ══════════════════════════════════════════════
336
+ // CROSS-PLATFORM
337
+ // ══════════════════════════════════════════════
338
+
339
+ function displayCrossPlatform(perToolScores) {
340
+ if (!perToolScores || Object.keys(perToolScores).length <= 1) return;
341
+
342
+ console.log(dim(' CROSS-PLATFORM\n'));
343
+ const sorted = Object.entries(perToolScores).sort((a, b) => {
344
+ if (a[1].score === null) return 1;
345
+ if (b[1].score === null) return -1;
346
+ return b[1].score - a[1].score;
347
+ });
348
+ const maxSessions = Math.max(...sorted.map(([, v]) => v.sessions));
349
+
350
+ for (const [tool, data] of sorted) {
351
+ if (data.score !== null) {
352
+ const isPrimary = data.sessions === maxSessions;
353
+ const label = isPrimary ? 'primary tool' : data.sessions < 5 ? 'limited usage' : 'active';
354
+ console.log(` ${pad(bold(tool), 18)} ${bold(String(data.score))} ${progressBar(data.score)} ${dim(label)}`);
355
+ } else {
356
+ console.log(` ${pad(bold(tool), 18)} ${dim('--')} ${dim('\u2591'.repeat(18))} ${dim('limited data')}`);
257
357
  }
358
+ }
359
+ console.log();
360
+ }
361
+
362
+ // ══════════════════════════════════════════════
363
+ // PROJECT ANALYSIS
364
+ // ══════════════════════════════════════════════
365
+
366
+ function displayProjects(insights) {
367
+ const projects = insights?.projectComplexity;
368
+ if (!projects || projects.length === 0) return;
369
+
370
+ console.log(dim(' PROJECT ANALYSIS\n'));
371
+ for (const p of projects) {
372
+ const compColor = p.complexity === 'HIGH' ? green : p.complexity === 'MEDIUM' ? yellow : dim;
373
+ const signals = p.signals.length > 0 ? p.signals.join(' \u00B7 ') : '';
374
+ console.log(` ${pad(bold(p.name), 32)} Complexity: ${compColor(p.complexity)}`);
375
+ if (signals) {
376
+ console.log(` ${dim(signals)}`);
377
+ }
378
+ console.log(` ${dim(`${p.sessions} sessions \u00B7 ${numberFormat(p.exchanges)} exchanges \u00B7 ${p.daysActive} days active`)}`);
258
379
  console.log();
259
380
  }
260
381
  }
261
382
 
262
383
  // ══════════════════════════════════════════════
263
- // DIMENSION NARRATIVES (data-driven, punchy)
384
+ // DIMENSION NARRATIVES — Clinical, benchmarked
264
385
  // ══════════════════════════════════════════════
265
386
 
266
387
  export function displayNarratives(metrics, prose) {
@@ -275,10 +396,10 @@ export function displayNarratives(metrics, prose) {
275
396
 
276
397
  if (prose && prose.sections) {
277
398
  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') },
399
+ 'thinking': { label: 'Evidence', prompt: pickExample(metrics.decomposition.examples, 'decomposition') },
400
+ 'debugging': { label: 'Evidence', prompt: pickExample(metrics.debugCycles.examples, 'specific_report') || pickExample(metrics.debugCycles.examples, 'quick_fix') },
401
+ 'ai leverage': { label: 'Evidence', prompt: pickExample(metrics.aiLeverage.examples, 'architectural') || pickExample(metrics.aiLeverage.examples, 'planning') },
402
+ 'workflow': { label: 'Evidence', prompt: pickExample(metrics.sessionStructure.examples, 'context_setting') || pickExample(metrics.sessionStructure.examples, 'refinement') },
282
403
  };
283
404
 
284
405
  for (const section of prose.sections) {
@@ -293,21 +414,17 @@ export function displayNarratives(metrics, prose) {
293
414
  console.log();
294
415
  }
295
416
  } else {
296
- displayDataNarrativesWithTracker(metrics, shownSnippets);
417
+ displayDataNarratives(metrics, shownSnippets);
297
418
  }
298
419
  }
299
420
 
300
- function displayDataNarrativesWithTracker(metrics, shownSnippets) {
421
+ function displayDataNarratives(metrics, shownSnippets) {
301
422
  const d = metrics.decomposition.details;
302
423
  const db = metrics.debugCycles.details;
303
424
  const ai = metrics.aiLeverage.details;
304
425
  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
426
 
310
- function showLabeledSnippet(label, prompt) {
427
+ function showSnippet(label, prompt) {
311
428
  if (!prompt) return;
312
429
  const s = cleanPrompt(prompt, 120);
313
430
  if (shownSnippets.has(s)) return;
@@ -315,128 +432,180 @@ function displayDataNarrativesWithTracker(metrics, shownSnippets) {
315
432
  displayLabeledSnippet(label, prompt);
316
433
  }
317
434
 
318
- // Thinking
435
+ // Thinking — clinical
319
436
  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'));
437
+ console.log(` ${dim(`Avg session depth: ${d.avgExchangesPerSession} exchanges (benchmark: ${BENCHMARKS.avgExchangesPerSession})`)}`);
438
+ console.log(` ${dim(`Avg prompt length: ${numberFormat(d.avgPromptLength)} chars (benchmark: ${BENCHMARKS.avgPromptLength})`)}`);
439
+ console.log(` ${dim(`Multi-step ratio: ${d.multiStepSessions}/${d.totalSessions} sessions (${Math.round(d.multiStepSessions / Math.max(1, d.totalSessions) * 100)}%)`)}`);
440
+ showSnippet('Evidence', pickExample(metrics.decomposition.examples, 'decomposition'));
325
441
  console.log();
326
442
 
327
- // Debugging
443
+ // Debugging — clinical
328
444
  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'));
445
+ console.log(` ${dim(`Avg resolution: ${db.avgTurnsToResolve} turns (benchmark: ${BENCHMARKS.avgTurnsToResolve})`)}`);
446
+ console.log(` ${dim(`Specific reports: ${db.specificReportRatio}% (benchmark: ${BENCHMARKS.specificReportRatio}%)`)}`);
447
+ console.log(` ${dim(`Extended loops: ${db.longLoops} | Quick fixes: ${db.quickFixes}/${db.totalDebugSequences}`)}`);
448
+ showSnippet('Evidence', pickExample(metrics.debugCycles.examples, 'specific_report') || pickExample(metrics.debugCycles.examples, 'quick_fix'));
334
449
  console.log();
335
450
 
336
- // AI Leverage
451
+ // AI Leverage — clinical
337
452
  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'));
453
+ console.log(` ${dim(`High-level ratio: ${ai.highLevelRatio}% (benchmark: ${BENCHMARKS.highLevelRatio}%)`)}`);
454
+ console.log(` ${dim(`Breakdown: ${ai.architecturalPrompts} architectural \u00B7 ${ai.planningPrompts} planning \u00B7 ${ai.exploratoryPrompts} exploratory`)}`);
455
+ console.log(` ${dim(`Boilerplate: ${ai.boilerplatePrompts} (${Math.round(ai.boilerplatePrompts / Math.max(1, ai.totalPrompts) * 100)}%) \u00B7 Testing: ${ai.testingPrompts}`)}`);
456
+ showSnippet('Evidence', pickExample(metrics.aiLeverage.examples, 'architectural') || pickExample(metrics.aiLeverage.examples, 'planning'));
343
457
  console.log();
344
458
 
345
- // Workflow
459
+ // Workflow — clinical
346
460
  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'));
461
+ console.log(` ${dim(`Context-setting: ${ss.contextSetRatio}% (benchmark: ${BENCHMARKS.contextSetRatio}%)`)}`);
462
+ console.log(` ${dim(`Review at end: ${ss.reviewEndRatio}% (benchmark: ${BENCHMARKS.reviewEndRatio}%)`)}`);
463
+ console.log(` ${dim(`Refinement rate: ${ss.refinementRatio}% (benchmark: ${BENCHMARKS.refinementRatio}%)`)}`);
464
+ showSnippet('Evidence', pickExample(metrics.sessionStructure.examples, 'context_setting') || pickExample(metrics.sessionStructure.examples, 'refinement'));
351
465
  console.log();
352
466
  }
353
467
 
354
-
355
468
  // ══════════════════════════════════════════════
356
- // COACHING RECOMMENDATION
469
+ // SIGNATURES — What makes you distinctive
357
470
  // ══════════════════════════════════════════════
358
471
 
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)}`);
472
+ function displaySignatures(insights) {
473
+ const sigs = insights?.signatures;
474
+ if (!sigs || sigs.length === 0) return;
475
+
476
+ console.log(dim(' YOUR SIGNATURES\n'));
477
+ for (const sig of sigs) {
478
+ console.log(` ${cyan('\u2726')} ${bold(sig.name)}`);
479
+ const lines = wrapText(sig.detail, 49);
480
+ for (const line of lines) {
481
+ console.log(` ${dim(line)}`);
482
+ }
483
+ console.log();
386
484
  }
387
- console.log();
388
485
  }
389
486
 
390
-
391
487
  // ══════════════════════════════════════════════
392
- // EASTER EGGS
488
+ // WATCH POINTS — Areas to improve
393
489
  // ══════════════════════════════════════════════
394
490
 
395
- export function displayEasterEggs(result, metrics) {
396
- const { overall } = result;
397
- const db = metrics.debugCycles.details;
398
-
399
- const eggs = [];
491
+ function displayWatchPoints(insights) {
492
+ const wps = insights?.watchPoints;
493
+ if (!wps || wps.length === 0) return;
400
494
 
401
- if (overall >= 90) {
402
- eggs.push('Top-tier. Companies should be applying to you.');
495
+ console.log(dim(' WATCH POINTS\n'));
496
+ for (const wp of wps) {
497
+ console.log(` ${orange('\u26A0')} ${bold(wp.name)}`);
498
+ const lines = wrapText(wp.detail, 49);
499
+ for (const line of lines) {
500
+ console.log(` ${dim(line)}`);
501
+ }
502
+ console.log();
403
503
  }
504
+ }
505
+
506
+ // ══════════════════════════════════════════════
507
+ // TRAJECTORY — Weekly evolution
508
+ // ══════════════════════════════════════════════
404
509
 
405
- if (db.longLoops === 0 && db.totalDebugSequences > 10) {
406
- eggs.push('Zero debug spirals. Either you\'re exceptional or your AI is.');
510
+ function displayTrajectory(insights) {
511
+ const traj = insights?.trajectory;
512
+ if (!traj) return;
513
+
514
+ console.log(dim(' YOUR TRAJECTORY\n'));
515
+ for (let i = 0; i < traj.weeks.length; i++) {
516
+ const w = traj.weeks[i];
517
+ const prev = i > 0 ? traj.weeks[i - 1] : null;
518
+ const arrow = prev ? (w.score > prev.score ? green(' \u2191') : w.score < prev.score ? orange(' \u2193') : dim(' \u2192')) : '';
519
+ const tierLabel = dimTierLabel(w.score);
520
+ console.log(` ${dim(pad(w.label, 16))} Score: ${scoreColor(w.score).bold(String(w.score))} ${dimTierColor(w.score)(tierLabel)}${arrow}`);
407
521
  }
522
+ console.log();
523
+ const velColor = traj.velocityLabel === 'FAST' ? green : traj.velocityLabel === 'STEADY' ? cyan : traj.velocityLabel === 'STABLE' ? yellow : orange;
524
+ console.log(` ${dim('Learning velocity:')} ${velColor(traj.velocityLabel)} ${dim('\u2014 ' + traj.velocityDetail)}`);
525
+ console.log();
526
+ }
408
527
 
409
- if (db.vagueReports === 0 && db.totalDebugSequences > 20) {
410
- eggs.push('Never once said "it\'s broken, fix it." Respect.');
528
+ // ══════════════════════════════════════════════
529
+ // ASSESSMENT Narrative paragraph
530
+ // ══════════════════════════════════════════════
531
+
532
+ function displayAssessment(insights) {
533
+ const assessment = insights?.assessment;
534
+ if (!assessment) return;
535
+
536
+ console.log(dim(' ASSESSMENT\n'));
537
+ const lines = wrapText(assessment, 51);
538
+ for (const line of lines) {
539
+ console.log(` ${dim(line)}`);
411
540
  }
541
+ console.log();
542
+ }
412
543
 
413
- if (eggs.length > 0) {
414
- for (const egg of eggs) {
415
- console.log(` ${dim('\u2727')} ${dim.italic(egg)}`);
416
- }
544
+ // ══════════════════════════════════════════════
545
+ // CONFIDENCE INDICATOR
546
+ // ══════════════════════════════════════════════
547
+
548
+ function displayConfidence(insights, sessionStats) {
549
+ const conf = insights?.confidence;
550
+ if (!conf) return;
551
+
552
+ const barWidth = 18;
553
+ const filled = Math.round((conf.score / 100) * barWidth);
554
+ const empty = barWidth - filled;
555
+ const confColor = conf.level === 'HIGH' ? green : conf.level === 'MODERATE' ? yellow : orange;
556
+ const bar = confColor('\u2588'.repeat(filled)) + dim('\u2591'.repeat(empty));
557
+
558
+ console.log(` ${dim('Profile confidence:')} ${bar} ${confColor(conf.level)}`);
559
+ if (sessionStats) {
560
+ console.log(` ${dim(`Based on ${sessionStats.totalSessions} sessions across ${sessionStats.tools.length} tool${sessionStats.tools.length > 1 ? 's' : ''}.`)}`);
561
+ }
562
+ console.log();
563
+ if (conf.level !== 'HIGH') {
564
+ console.log(` ${dim('Confidence increases with more sessions and tool')}`);
565
+ console.log(` ${dim('diversity. Run again in 30 days for updated assessment.')}`);
417
566
  console.log();
418
567
  }
419
568
  }
420
569
 
421
570
  // ══════════════════════════════════════════════
422
- // VIRAL ENDING
571
+ // METHODOLOGY FOOTER
423
572
  // ══════════════════════════════════════════════
424
573
 
425
- export function displayEnding(result) {
574
+ function displayMethodology() {
575
+ console.log(doubleRule());
576
+ console.log();
577
+ console.log(` ${dim('METHODOLOGY')}`);
578
+ console.log(` ${dim('Scores derived from structural analysis of prompt')}`);
579
+ console.log(` ${dim('patterns, debug sequences, and session architecture')}`);
580
+ console.log(` ${dim('across detected AI coding tools. Tier placement based')}`);
581
+ console.log(` ${dim('on distribution of scored engineers. No prompt content')}`);
582
+ console.log(` ${dim('is stored or transmitted. Learn more: chekk.dev/methodology')}`);
583
+ console.log();
584
+ }
585
+
586
+ // ══════════════════════════════════════════════
587
+ // NEXT STEPS — Credential issuance
588
+ // ══════════════════════════════════════════════
589
+
590
+ function displayNextSteps(result) {
426
591
  const { overall, archetype, tier, tierBadge } = result;
427
592
  const tc = tierColor(tier);
428
593
 
429
594
  console.log(doubleRule());
430
595
  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')}`);
596
+ console.log(` ${bold.white('NEXT STEPS')}`);
597
+ console.log();
598
+ console.log(` ${dim('\u2192 Claim your verified profile')}`);
599
+ console.log(` ${dim('Link your GitHub and LinkedIn to create your')}`);
600
+ console.log(` ${dim('portable engineering credential.')}`);
601
+ console.log(` ${cyan.underline('chekk.dev/claim')}`);
602
+ console.log();
603
+ console.log(` ${dim('\u2192 View industry benchmarks')}`);
604
+ console.log(` ${dim('See how you compare across scored engineers.')}`);
605
+ console.log(` ${cyan.underline('chekk.dev/benchmarks')}`);
438
606
  console.log();
439
- console.log(` ${dim('\u2192 Leaderboard:')} ${cyan.underline('chekk.dev/leaderboard')}`);
607
+ console.log(` ${dim('\u2192 Export this report')}`);
608
+ console.log(` ${dim('npx chekk --json')}`);
440
609
  console.log();
441
610
 
442
611
  // Copy-paste share line
@@ -446,12 +615,12 @@ export function displayEnding(result) {
446
615
  console.log(` ${dim('\u2191 Copy this to share')}`);
447
616
  console.log();
448
617
  console.log(doubleRule());
449
- console.log(` ${dim('chekk.dev \u2014 the engineering capability score')}`);
618
+ console.log(` ${dim('chekk.dev \u2014 engineering capability profiles')}`);
450
619
  console.log();
451
620
  }
452
621
 
453
622
  // ══════════════════════════════════════════════
454
- // VERBOSE: DETAILED BREAKDOWN (with interpretation)
623
+ // VERBOSE: DETAILED BREAKDOWN
455
624
  // ══════════════════════════════════════════════
456
625
 
457
626
  export function displayVerbose(metrics, sessions) {
@@ -475,72 +644,77 @@ export function displayVerbose(metrics, sessions) {
475
644
  }
476
645
  console.log();
477
646
 
478
- // Decomposition details with interpretation
647
+ // Decomposition
479
648
  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')}`);
649
+ console.log(bold(' DECOMPOSITION'));
650
+ console.log(` ${dim(pad('Avg session depth', 30))} ${dim(String(d.avgExchangesPerSession))} ${dim(`(benchmark: ${BENCHMARKS.avgExchangesPerSession})`)}`);
651
+ console.log(` ${dim(pad('Avg prompt length', 30))} ${dim(d.avgPromptLength + ' chars')} ${dim(`(benchmark: ${BENCHMARKS.avgPromptLength})`)}`);
652
+ 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')}`);
653
+ console.log(` ${dim(pad('Single-shot sessions', 30))} ${dim(String(d.singleShotSessions))}`);
654
+ 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
655
  console.log();
489
656
 
490
- // Debug cycle details
657
+ // Debug
491
658
  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`)}`);
659
+ console.log(bold(' DEBUG CYCLES'));
660
+ console.log(` ${dim(pad('Total sequences', 30))} ${dim(String(db.totalDebugSequences))}`);
661
+ console.log(` ${dim(pad('Avg turns to resolve', 30))} ${dim(String(db.avgTurnsToResolve))} ${dim(`(benchmark: ${BENCHMARKS.avgTurnsToResolve})`)}`);
662
+ console.log(` ${dim(pad('Quick fixes (\u22642 turns)', 30))} ${dim(String(db.quickFixes))}`);
663
+ console.log(` ${dim(pad('Extended loops (>5 turns)', 30))} ${dim(String(db.longLoops))} ${dim(db.longLoops === 0 ? '\u2014 zero spirals' : '')}`);
664
+ console.log(` ${dim(pad('Specific report ratio', 30))} ${dim(db.specificReportRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.specificReportRatio}%)`)}`);
665
+ console.log(` ${dim(pad('Vague reports', 30))} ${dim(String(db.vagueReports))} ${dim(db.vagueReports === 0 ? '\u2014 never vague' : '')}`);
499
666
  console.log();
500
667
 
501
- // AI Leverage details
668
+ // AI Leverage
502
669
  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
670
+ console.log(bold(' AI LEVERAGE'));
671
+ console.log(` ${dim(pad('Total prompts', 30))} ${dim(numberFormat(ai.totalPrompts))}`);
672
+ console.log(` ${dim(pad('Architectural', 30))} ${dim(String(ai.architecturalPrompts))} ${dim(`(${Math.round(ai.architecturalPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
673
+ console.log(` ${dim(pad('Planning', 30))} ${dim(String(ai.planningPrompts))} ${dim(`(${Math.round(ai.planningPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
674
+ console.log(` ${dim(pad('Exploratory', 30))} ${dim(String(ai.exploratoryPrompts))} ${dim(`(${Math.round(ai.exploratoryPrompts / Math.max(1, ai.totalPrompts) * 100)}%)`)}`);
675
+ 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' : '')}`);
676
+ console.log(` ${dim(pad('Testing', 30))} ${dim(String(ai.testingPrompts))}`);
677
+ console.log(` ${dim(pad('High-level ratio', 30))} ${dim(ai.highLevelRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.highLevelRatio}%)`)}`);
678
+ console.log();
679
+
680
+ // Session structure
516
681
  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')}`);
682
+ console.log(bold(' SESSION STRUCTURE'));
683
+ console.log(` ${dim(pad('Context-setting', 30))} ${dim(ss.contextSetRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.contextSetRatio}%)`)}`);
684
+ console.log(` ${dim(pad('Plan before code', 30))} ${dim(ss.planBeforeCodeRatio + '%')}`);
685
+ console.log(` ${dim(pad('Review at end', 30))} ${dim(ss.reviewEndRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.reviewEndRatio}%)`)}`);
686
+ console.log(` ${dim(pad('Refinement rate', 30))} ${dim(ss.refinementRatio + '%')} ${dim(`(benchmark: ${BENCHMARKS.refinementRatio}%)`)}`);
687
+ console.log(` ${dim(pad('Avg first prompt', 30))} ${dim(ss.avgFirstPromptLength + ' chars')}`);
523
688
  if (ss.durationDistribution) {
524
689
  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))}`);
690
+ console.log(` ${dim(pad('Focused sessions (10-45m)', 30))} ${dim(String(dur.focused))}`);
691
+ console.log(` ${dim(pad('Short (<5m)', 30))} ${dim(String(dur.short))}`);
692
+ console.log(` ${dim(pad('Medium (5-60m)', 30))} ${dim(String(dur.medium))}`);
693
+ console.log(` ${dim(pad('Long (>60m)', 30))} ${dim(String(dur.long))}`);
529
694
  }
530
695
  console.log();
531
696
  }
532
697
 
533
698
  // ══════════════════════════════════════════════
534
- // OFFLINE DISPLAY (no API)
699
+ // OFFLINE DISPLAY
535
700
  // ══════════════════════════════════════════════
536
701
 
537
702
  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);
703
+ displayProfileHeader(result, extra);
704
+ displaySummary(result, extra);
705
+ displayArchetype(result);
706
+ displayDimensions(result);
707
+ displayCrossPlatform(extra.perToolScores);
708
+ displayDataNarratives(metrics, new Set());
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
+ console.log(dim(' Run without --offline for AI-generated narrative insights\n'));
717
+ displayNextSteps(result);
544
718
  }
545
719
 
546
720
  // ══════════════════════════════════════════════
@@ -548,11 +722,20 @@ export function displayOffline(result, metrics, extra = {}) {
548
722
  // ══════════════════════════════════════════════
549
723
 
550
724
  export function displayFull(result, metrics, prose, extra = {}) {
551
- displayScore(result, prose, extra);
725
+ displayProfileHeader(result, extra);
726
+ displaySummary(result, extra);
727
+ displayArchetype(result);
728
+ displayDimensions(result);
729
+ displayCrossPlatform(extra.perToolScores);
552
730
  displayNarratives(metrics, prose);
553
- displayCoaching(result, metrics);
554
- displayEasterEggs(result, metrics);
555
- displayEnding(result);
731
+ displayProjects(extra.insights);
732
+ displaySignatures(extra.insights);
733
+ displayWatchPoints(extra.insights);
734
+ displayTrajectory(extra.insights);
735
+ displayAssessment(extra.insights);
736
+ displayConfidence(extra.insights, extra.sessionStats);
737
+ displayMethodology();
738
+ displayNextSteps(result);
556
739
  }
557
740
 
558
741
  // ── Utility ──