chekk 0.2.0 → 0.2.2
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/bin/chekk.js +1 -1
- package/package.json +1 -1
- package/src/display.js +29 -12
- package/src/index.js +31 -14
- package/src/scorer.js +138 -48
- package/src/upload.js +17 -0
package/bin/chekk.js
CHANGED
|
@@ -8,7 +8,7 @@ const program = new Command();
|
|
|
8
8
|
program
|
|
9
9
|
.name('chekk')
|
|
10
10
|
.description('The engineering capability score. See how you prompt.')
|
|
11
|
-
.version('0.2.
|
|
11
|
+
.version('0.2.2')
|
|
12
12
|
.option('--offline', 'Skip AI prose generation, show data-driven output')
|
|
13
13
|
.option('--verbose', 'Show detailed per-project and per-metric breakdowns')
|
|
14
14
|
.option('--json', 'Output raw metrics as JSON')
|
package/package.json
CHANGED
package/src/display.js
CHANGED
|
@@ -12,7 +12,8 @@ const white = chalk.white;
|
|
|
12
12
|
|
|
13
13
|
function tierColor(tier) {
|
|
14
14
|
if (tier === 'LEGENDARY') return gold;
|
|
15
|
-
if (tier === 'RARE') return purple;
|
|
15
|
+
if (tier === 'ULTRA RARE') return purple;
|
|
16
|
+
if (tier === 'RARE') return cyan;
|
|
16
17
|
if (tier === 'UNCOMMON') return blue;
|
|
17
18
|
return dim;
|
|
18
19
|
}
|
|
@@ -67,11 +68,11 @@ export function displayHeader() {
|
|
|
67
68
|
console.log();
|
|
68
69
|
const lines = [
|
|
69
70
|
'',
|
|
70
|
-
` ${bold.white('chekk')}${dim(' v0.2.
|
|
71
|
+
` ${bold.white('chekk')}${dim(' v0.2.2')}`,
|
|
71
72
|
` ${dim('the engineering capability score')}`,
|
|
72
73
|
'',
|
|
73
74
|
];
|
|
74
|
-
for (const l of box(lines)) console.log(l);
|
|
75
|
+
for (const l of box(lines, 45)) console.log(l);
|
|
75
76
|
console.log();
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -130,7 +131,7 @@ export async function displayProgressBar(durationMs = 2000) {
|
|
|
130
131
|
// ══════════════════════════════════════════════
|
|
131
132
|
|
|
132
133
|
export function displayScore(result, prose) {
|
|
133
|
-
const { overall, scores, archetype, tier } = result;
|
|
134
|
+
const { overall, scores, archetype, tier, tierBadge, tierPercentile } = result;
|
|
134
135
|
const tc = tierColor(tier);
|
|
135
136
|
const sc = scoreColor(overall);
|
|
136
137
|
|
|
@@ -140,7 +141,9 @@ export function displayScore(result, prose) {
|
|
|
140
141
|
console.log(dim(' YOUR CHEKK SCORE'));
|
|
141
142
|
console.log();
|
|
142
143
|
console.log(` ${sc.bold(String(overall))}`);
|
|
143
|
-
|
|
144
|
+
const badgeStr = tierBadge ? ` ${tierBadge}` : '';
|
|
145
|
+
const pctStr = tierPercentile ? ` ${dim(tierPercentile)}` : '';
|
|
146
|
+
console.log(` ${tc('\u2500\u2500 ' + tier + ' \u2500\u2500')}${badgeStr}${pctStr}`);
|
|
144
147
|
console.log();
|
|
145
148
|
console.log(` ${dim('Archetype:')} ${bold.white(archetype.name)}`);
|
|
146
149
|
|
|
@@ -153,15 +156,28 @@ export function displayScore(result, prose) {
|
|
|
153
156
|
|
|
154
157
|
// Dimensions box
|
|
155
158
|
console.log(dim(' DIMENSIONS\n'));
|
|
159
|
+
|
|
160
|
+
// Build dimension lines with fixed-width layout
|
|
161
|
+
// Format: " Label ██████████████░░░░ XX "
|
|
162
|
+
// Visible: 2 + 15 + 18 + 2 + 3 + 1 = ~41 chars
|
|
163
|
+
function dimLine(label, score) {
|
|
164
|
+
const labelStr = bold(label);
|
|
165
|
+
const labelVisible = label.length;
|
|
166
|
+
const labelPad = ' '.repeat(Math.max(0, 15 - labelVisible));
|
|
167
|
+
const scoreStr = String(score);
|
|
168
|
+
const scorePad = score < 10 ? ' ' : score < 100 ? ' ' : '';
|
|
169
|
+
return ` ${labelStr}${labelPad}${progressBar(score)} ${scorePad}${bold(scoreStr)} `;
|
|
170
|
+
}
|
|
171
|
+
|
|
156
172
|
const dimLines = [
|
|
157
173
|
'',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
174
|
+
dimLine('Thinking', scores.decomposition),
|
|
175
|
+
dimLine('Debugging', scores.debugCycles),
|
|
176
|
+
dimLine('AI Leverage', scores.aiLeverage),
|
|
177
|
+
dimLine('Workflow', scores.sessionStructure),
|
|
162
178
|
'',
|
|
163
179
|
];
|
|
164
|
-
for (const l of box(dimLines)) console.log(l);
|
|
180
|
+
for (const l of box(dimLines, 45)) console.log(l);
|
|
165
181
|
console.log();
|
|
166
182
|
}
|
|
167
183
|
|
|
@@ -259,7 +275,7 @@ export function displayEasterEggs(result, metrics) {
|
|
|
259
275
|
// ══════════════════════════════════════════════
|
|
260
276
|
|
|
261
277
|
export function displayEnding(result) {
|
|
262
|
-
const { overall, archetype, tier } = result;
|
|
278
|
+
const { overall, archetype, tier, tierBadge } = result;
|
|
263
279
|
const tc = tierColor(tier);
|
|
264
280
|
|
|
265
281
|
console.log(doubleRule());
|
|
@@ -269,7 +285,8 @@ export function displayEnding(result) {
|
|
|
269
285
|
console.log();
|
|
270
286
|
|
|
271
287
|
// Copy-paste share line
|
|
272
|
-
const
|
|
288
|
+
const badge = tierBadge ? ` ${tierBadge}` : '';
|
|
289
|
+
const shareLine = `${overall} \u2014 ${tier}${badge} \u2014 ${archetype.name}`;
|
|
273
290
|
console.log(` ${dim('"')}${tc(shareLine)}${dim('"')}`);
|
|
274
291
|
console.log(` ${dim('\u2191 Copy this to share')}`);
|
|
275
292
|
console.log();
|
package/src/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
displayOffline,
|
|
16
16
|
displayVerbose,
|
|
17
17
|
} from './display.js';
|
|
18
|
-
import { generateProse, askClaim, uploadAndClaim } from './upload.js';
|
|
18
|
+
import { generateProse, askVerbose, askClaim, uploadAndClaim } from './upload.js';
|
|
19
19
|
|
|
20
20
|
export async function run(options = {}) {
|
|
21
21
|
// ── Header ──
|
|
@@ -93,35 +93,52 @@ export async function run(options = {}) {
|
|
|
93
93
|
tools: supported.map(t => t.tool),
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
-
// Progress bar animation
|
|
97
|
-
await displayProgressBar(1500);
|
|
98
|
-
|
|
99
96
|
// ── JSON output ──
|
|
100
97
|
if (options.json) {
|
|
101
98
|
console.log(JSON.stringify({ metrics, result, sessionStats }, null, 2));
|
|
102
99
|
return;
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
// ── Step 4:
|
|
102
|
+
// ── Step 4: Progress bar + API call in parallel ──
|
|
103
|
+
// Run prose generation alongside the progress bar so score appears
|
|
104
|
+
// immediately when the bar hits 100% — no lag.
|
|
105
|
+
let prose = null;
|
|
106
|
+
if (!options.offline) {
|
|
107
|
+
const [, proseResult] = await Promise.all([
|
|
108
|
+
displayProgressBar(1500),
|
|
109
|
+
generateProse(metrics, result, sessionStats).catch(() => null),
|
|
110
|
+
]);
|
|
111
|
+
prose = proseResult;
|
|
112
|
+
} else {
|
|
113
|
+
await displayProgressBar(1500);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── Step 5: Display results ──
|
|
106
117
|
if (options.offline) {
|
|
107
118
|
displayOffline(result, metrics);
|
|
108
119
|
} else {
|
|
109
|
-
// Generate prose from API
|
|
110
|
-
let prose = null;
|
|
111
|
-
try {
|
|
112
|
-
prose = await generateProse(metrics, result, sessionStats);
|
|
113
|
-
} catch {
|
|
114
|
-
// Silently fall back to data-driven display
|
|
115
|
-
}
|
|
116
120
|
displayFull(result, metrics, prose);
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
// ── Verbose
|
|
123
|
+
// ── Step 6: Verbose prompt (interactive) ──
|
|
124
|
+
// If --verbose flag was passed, show immediately. Otherwise prompt.
|
|
120
125
|
if (options.verbose) {
|
|
121
126
|
displayVerbose(metrics, allSessions);
|
|
127
|
+
} else {
|
|
128
|
+
try {
|
|
129
|
+
const wantsVerbose = await askVerbose();
|
|
130
|
+
if (wantsVerbose) {
|
|
131
|
+
console.log();
|
|
132
|
+
displayVerbose(metrics, allSessions);
|
|
133
|
+
} else {
|
|
134
|
+
console.log();
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
console.log();
|
|
138
|
+
}
|
|
122
139
|
}
|
|
123
140
|
|
|
124
|
-
// ── Step
|
|
141
|
+
// ── Step 7: Claim prompt ──
|
|
125
142
|
if (options.upload !== false) {
|
|
126
143
|
try {
|
|
127
144
|
const wantsClaim = await askClaim();
|
package/src/scorer.js
CHANGED
|
@@ -1,79 +1,162 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Combine individual metric scores into composite scores and assign archetype.
|
|
3
|
+
*
|
|
4
|
+
* Archetypes and tiers are consistent with the GitHub analysis system.
|
|
5
|
+
* 15 archetypes across 5 tiers, mapped from repo-based signals to
|
|
6
|
+
* prompt-behavior signals measured by the CLI.
|
|
3
7
|
*/
|
|
4
8
|
|
|
9
|
+
// ── Tier thresholds (match GitHub analysis) ──
|
|
10
|
+
|
|
11
|
+
const TIERS = [
|
|
12
|
+
{ name: 'LEGENDARY', min: 85, badge: '🌟🌟🌟', percentile: 'Top 1%' },
|
|
13
|
+
{ name: 'ULTRA RARE', min: 73, badge: '🌟🌟', percentile: 'Top 5%' },
|
|
14
|
+
{ name: 'RARE', min: 60, badge: '⭐', percentile: 'Top 15%' },
|
|
15
|
+
{ name: 'UNCOMMON', min: 47, badge: '◆', percentile: 'Top 30%' },
|
|
16
|
+
{ name: 'COMMON', min: 0, badge: '●', percentile: 'Top 50%' },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// ── Archetype definitions ──
|
|
20
|
+
// Each archetype has a match function based on the 4 CLI dimension scores:
|
|
21
|
+
// decomposition (thinking), debugCycles (debugging),
|
|
22
|
+
// aiLeverage (AI leverage), sessionStructure (workflow)
|
|
23
|
+
//
|
|
24
|
+
// Tier-restricted: archetypes only match within their allowed tier range.
|
|
25
|
+
|
|
5
26
|
const ARCHETYPES = [
|
|
27
|
+
// ── LEGENDARY (85+) ──
|
|
6
28
|
{
|
|
7
|
-
id: '
|
|
8
|
-
name: 'THE
|
|
9
|
-
|
|
10
|
-
match: (s) =>
|
|
29
|
+
id: 'THE_10X_ENGINEER',
|
|
30
|
+
name: 'THE 10X ENGINEER',
|
|
31
|
+
tierRange: ['LEGENDARY'],
|
|
32
|
+
match: (s) => true, // If you hit LEGENDARY, you're a 10x
|
|
11
33
|
priority: 1,
|
|
12
34
|
},
|
|
35
|
+
|
|
36
|
+
// ── ULTRA RARE (73-84) ──
|
|
13
37
|
{
|
|
14
|
-
id: '
|
|
15
|
-
name: 'THE
|
|
16
|
-
|
|
17
|
-
|
|
38
|
+
id: 'THE_ARCHITECT',
|
|
39
|
+
name: 'THE ARCHITECT',
|
|
40
|
+
tierRange: ['ULTRA RARE'],
|
|
41
|
+
// High decomposition + structured workflow + strong leverage
|
|
42
|
+
match: (s) => s.decomposition >= 70 && s.sessionStructure >= 65,
|
|
18
43
|
priority: 2,
|
|
19
44
|
},
|
|
45
|
+
{
|
|
46
|
+
id: 'THE_PROFESSOR',
|
|
47
|
+
name: 'THE PROFESSOR',
|
|
48
|
+
tierRange: ['ULTRA RARE'],
|
|
49
|
+
// Exceptional at explaining: high decomposition, detailed prompts, strong context-setting
|
|
50
|
+
match: (s) => s.decomposition >= 65 && s.sessionStructure >= 70,
|
|
51
|
+
priority: 3,
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// ── RARE (60-72) ──
|
|
55
|
+
{
|
|
56
|
+
id: 'THE_SPECIALIST',
|
|
57
|
+
name: 'THE SPECIALIST',
|
|
58
|
+
tierRange: ['RARE'],
|
|
59
|
+
// Deep focused work: high debug efficiency + high leverage in specific domain
|
|
60
|
+
match: (s) => s.debugCycles >= 70 && s.aiLeverage >= 65,
|
|
61
|
+
priority: 4,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'THE_SYSTEMS_THINKER',
|
|
65
|
+
name: 'THE SYSTEMS THINKER',
|
|
66
|
+
tierRange: ['RARE'],
|
|
67
|
+
// Strong decomposition + structured approach to complex problems
|
|
68
|
+
match: (s) => s.decomposition >= 65 && s.sessionStructure >= 60,
|
|
69
|
+
priority: 5,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'THE_MAINTAINER',
|
|
73
|
+
name: 'THE MAINTAINER',
|
|
74
|
+
tierRange: ['RARE'],
|
|
75
|
+
// Reliable workflow + solid debugging: keeps things running
|
|
76
|
+
match: (s) => s.sessionStructure >= 60 && s.debugCycles >= 60,
|
|
77
|
+
priority: 6,
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
// ── UNCOMMON (47-59) ──
|
|
81
|
+
{
|
|
82
|
+
id: 'THE_CRAFTSPERSON',
|
|
83
|
+
name: 'THE CRAFTSPERSON',
|
|
84
|
+
tierRange: ['UNCOMMON'],
|
|
85
|
+
// Quality obsession: high debug precision + structured sessions
|
|
86
|
+
match: (s) => s.debugCycles >= 60 && s.sessionStructure >= 55,
|
|
87
|
+
priority: 7,
|
|
88
|
+
},
|
|
20
89
|
{
|
|
21
90
|
id: 'THE_BUILDER',
|
|
22
91
|
name: 'THE BUILDER',
|
|
23
|
-
|
|
92
|
+
tierRange: ['UNCOMMON'],
|
|
93
|
+
// Well-rounded: decent across all dimensions
|
|
24
94
|
match: (s) => {
|
|
25
|
-
const
|
|
26
|
-
return
|
|
95
|
+
const min = Math.min(s.decomposition, s.debugCycles, s.aiLeverage, s.sessionStructure);
|
|
96
|
+
return min >= 45;
|
|
27
97
|
},
|
|
28
|
-
priority:
|
|
98
|
+
priority: 8,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'THE_CONTRIBUTOR',
|
|
102
|
+
name: 'THE CONTRIBUTOR',
|
|
103
|
+
tierRange: ['UNCOMMON'],
|
|
104
|
+
// Strong AI leverage + decent decomposition: collaborates well with AI
|
|
105
|
+
match: (s) => s.aiLeverage >= 55 && s.decomposition >= 50,
|
|
106
|
+
priority: 9,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'THE_HIDDEN_GEM',
|
|
110
|
+
name: 'THE HIDDEN GEM',
|
|
111
|
+
tierRange: ['UNCOMMON'],
|
|
112
|
+
// Strong skills but unstructured: high debug or leverage but low structure
|
|
113
|
+
match: (s) => (s.debugCycles >= 55 || s.aiLeverage >= 55) && s.sessionStructure < 50,
|
|
114
|
+
priority: 10,
|
|
29
115
|
},
|
|
30
116
|
{
|
|
31
117
|
id: 'THE_EXPLORER',
|
|
32
118
|
name: 'THE EXPLORER',
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
119
|
+
tierRange: ['UNCOMMON'],
|
|
120
|
+
// High leverage + curiosity-driven: research-heavy prompting
|
|
121
|
+
match: (s) => s.aiLeverage >= 50,
|
|
122
|
+
priority: 11,
|
|
36
123
|
},
|
|
124
|
+
|
|
125
|
+
// ── COMMON (0-46) ──
|
|
37
126
|
{
|
|
38
|
-
id: '
|
|
39
|
-
name: 'THE
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
127
|
+
id: 'THE_TINKERER',
|
|
128
|
+
name: 'THE TINKERER',
|
|
129
|
+
tierRange: ['COMMON'],
|
|
130
|
+
// Practical problem-solving: decent debug + some leverage
|
|
131
|
+
match: (s) => s.debugCycles >= 40 && s.aiLeverage >= 35,
|
|
132
|
+
priority: 12,
|
|
43
133
|
},
|
|
44
134
|
{
|
|
45
|
-
id: '
|
|
46
|
-
name: 'THE
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
priority: 6,
|
|
135
|
+
id: 'THE_GRINDER',
|
|
136
|
+
name: 'THE GRINDER',
|
|
137
|
+
tierRange: ['COMMON'],
|
|
138
|
+
// High volume, iterative: lots of exchanges, keeps going
|
|
139
|
+
match: (s) => s.decomposition >= 35,
|
|
140
|
+
priority: 13,
|
|
53
141
|
},
|
|
54
142
|
{
|
|
55
|
-
id: '
|
|
56
|
-
name: 'THE
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
143
|
+
id: 'THE_HOBBYIST',
|
|
144
|
+
name: 'THE HOBBYIST',
|
|
145
|
+
tierRange: ['COMMON'],
|
|
146
|
+
// Active but early: some leverage or debugging skill
|
|
147
|
+
match: (s) => s.aiLeverage >= 30 || s.debugCycles >= 30,
|
|
148
|
+
priority: 14,
|
|
60
149
|
},
|
|
61
150
|
{
|
|
62
|
-
id: '
|
|
63
|
-
name: 'THE
|
|
64
|
-
|
|
151
|
+
id: 'THE_APPRENTICE',
|
|
152
|
+
name: 'THE APPRENTICE',
|
|
153
|
+
tierRange: ['COMMON'],
|
|
154
|
+
// Default fallback for COMMON tier
|
|
65
155
|
match: () => true,
|
|
66
156
|
priority: 99,
|
|
67
157
|
},
|
|
68
158
|
];
|
|
69
159
|
|
|
70
|
-
const TIERS = [
|
|
71
|
-
{ name: 'LEGENDARY', min: 90 },
|
|
72
|
-
{ name: 'RARE', min: 75 },
|
|
73
|
-
{ name: 'UNCOMMON', min: 55 },
|
|
74
|
-
{ name: 'COMMON', min: 0 },
|
|
75
|
-
];
|
|
76
|
-
|
|
77
160
|
export function computeOverallScore(metrics) {
|
|
78
161
|
const scores = {
|
|
79
162
|
decomposition: metrics.decomposition.score,
|
|
@@ -90,13 +173,18 @@ export function computeOverallScore(metrics) {
|
|
|
90
173
|
scores.sessionStructure * 0.2
|
|
91
174
|
);
|
|
92
175
|
|
|
93
|
-
// Assign
|
|
94
|
-
const sortedArchetypes = [...ARCHETYPES].sort((a, b) => a.priority - b.priority);
|
|
95
|
-
const archetype = sortedArchetypes.find(a => a.match(scores)) || ARCHETYPES[ARCHETYPES.length - 1];
|
|
96
|
-
|
|
97
|
-
// Assign tier
|
|
176
|
+
// Assign tier first
|
|
98
177
|
const tier = TIERS.find(t => overall >= t.min) || TIERS[TIERS.length - 1];
|
|
99
178
|
|
|
179
|
+
// Assign archetype within tier
|
|
180
|
+
const tierArchetypes = ARCHETYPES
|
|
181
|
+
.filter(a => a.tierRange.includes(tier.name))
|
|
182
|
+
.sort((a, b) => a.priority - b.priority);
|
|
183
|
+
|
|
184
|
+
const archetype = tierArchetypes.find(a => a.match(scores))
|
|
185
|
+
|| tierArchetypes[tierArchetypes.length - 1]
|
|
186
|
+
|| { id: 'THE_APPRENTICE', name: 'THE APPRENTICE' };
|
|
187
|
+
|
|
100
188
|
return {
|
|
101
189
|
overall,
|
|
102
190
|
scores,
|
|
@@ -105,5 +193,7 @@ export function computeOverallScore(metrics) {
|
|
|
105
193
|
name: archetype.name,
|
|
106
194
|
},
|
|
107
195
|
tier: tier.name,
|
|
196
|
+
tierBadge: tier.badge,
|
|
197
|
+
tierPercentile: tier.percentile,
|
|
108
198
|
};
|
|
109
199
|
}
|
package/src/upload.js
CHANGED
|
@@ -47,6 +47,23 @@ export async function generateProse(metrics, result, sessionStats) {
|
|
|
47
47
|
return response.json();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Ask user if they want to see detailed breakdown.
|
|
52
|
+
*/
|
|
53
|
+
export function askVerbose() {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const rl = createInterface({
|
|
56
|
+
input: process.stdin,
|
|
57
|
+
output: process.stdout,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
rl.question(' See detailed breakdown? (y/n) ', (answer) => {
|
|
61
|
+
rl.close();
|
|
62
|
+
resolve(answer.toLowerCase().startsWith('y'));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
/**
|
|
51
68
|
* Ask user if they want to claim their profile.
|
|
52
69
|
*/
|