chekk 0.5.4 → 1.0.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/index.js DELETED
@@ -1,281 +0,0 @@
1
- import chalk from 'chalk';
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
- import { join } from 'path';
4
- import { homedir } from 'os';
5
- import { detectTools } from './detect.js';
6
- import { parseAllProjects } from './parsers/claude-code.js';
7
- import { parseAllWorkspaces } from './parsers/cursor.js';
8
- import { parseAllSessions as parseCodexSessions } from './parsers/codex.js';
9
- import { computeDecomposition } from './metrics/decomposition.js';
10
- import { computeDebugCycles } from './metrics/debug-cycles.js';
11
- import { computeAILeverage } from './metrics/ai-leverage.js';
12
- import { computeSessionStructure } from './metrics/session-structure.js';
13
- import { computeOverallScore } from './scorer.js';
14
- import { computeTokenEfficiency } from './metrics/token-efficiency.js';
15
- import {
16
- computeSignatures,
17
- computeWatchPoints,
18
- computeTrajectory,
19
- computeProjectComplexity,
20
- generateAssessment,
21
- computeConfidence,
22
- } from './insights.js';
23
- import {
24
- displayHeader,
25
- displayScan,
26
- displayAnalysisStart,
27
- displayProgressBar,
28
- displayFull,
29
- displayOffline,
30
- displayVerbose,
31
- } from './display.js';
32
- import { generateProse, askVerbose, askClaim, uploadAndClaim } from './upload.js';
33
-
34
- // ── Score history ──
35
- const HISTORY_DIR = join(homedir(), '.chekk');
36
- const HISTORY_FILE = join(HISTORY_DIR, 'history.json');
37
-
38
- function loadHistory() {
39
- try {
40
- if (existsSync(HISTORY_FILE)) {
41
- return JSON.parse(readFileSync(HISTORY_FILE, 'utf-8'));
42
- }
43
- } catch {}
44
- return { scans: [] };
45
- }
46
-
47
- function saveHistory(history) {
48
- try {
49
- if (!existsSync(HISTORY_DIR)) mkdirSync(HISTORY_DIR, { recursive: true });
50
- writeFileSync(HISTORY_FILE, JSON.stringify(history, null, 2));
51
- } catch {}
52
- }
53
-
54
- function computePerToolScores(allSessions) {
55
- const toolSessions = {};
56
- for (const s of allSessions) {
57
- const t = s.sourceTool || 'Unknown';
58
- if (!toolSessions[t]) toolSessions[t] = [];
59
- toolSessions[t].push(s);
60
- }
61
-
62
- const perTool = {};
63
- for (const [tool, sessions] of Object.entries(toolSessions)) {
64
- if (sessions.length < 2) {
65
- perTool[tool] = { sessions: sessions.length, score: null, label: 'limited data' };
66
- continue;
67
- }
68
- const m = {
69
- decomposition: computeDecomposition(sessions),
70
- debugCycles: computeDebugCycles(sessions),
71
- aiLeverage: computeAILeverage(sessions),
72
- sessionStructure: computeSessionStructure(sessions),
73
- };
74
- const r = computeOverallScore(m);
75
- perTool[tool] = { sessions: sessions.length, score: r.overall, label: null };
76
- }
77
- return perTool;
78
- }
79
-
80
- export async function run(options = {}) {
81
- // ── Header ──
82
- displayHeader();
83
-
84
- // ── Step 1: Detect tools ──
85
- const tools = detectTools();
86
-
87
- if (tools.length === 0) {
88
- console.log(chalk.dim(' No AI coding tools detected.'));
89
- console.log(chalk.dim(' Chekk supports Claude Code, Cursor, and Codex.\n'));
90
- process.exit(1);
91
- }
92
-
93
- displayScan(tools);
94
-
95
- // ── Step 2: Parse sessions (tag each with sourceTool) ──
96
- let allSessions = [];
97
- for (const tool of tools) {
98
- let parsed = [];
99
- if (tool.tool === 'Claude Code') {
100
- parsed = parseAllProjects(tool.basePath);
101
- } else if (tool.tool === 'Cursor') {
102
- parsed = parseAllWorkspaces(tool.basePath);
103
- } else if (tool.tool === 'Codex') {
104
- parsed = parseCodexSessions(tool.basePath);
105
- }
106
- for (const s of parsed) {
107
- s.sourceTool = tool.tool;
108
- }
109
- allSessions.push(...parsed);
110
- }
111
-
112
- if (allSessions.length === 0) {
113
- console.log(chalk.dim(' No sessions found to analyze.\n'));
114
- process.exit(1);
115
- }
116
-
117
- // Stats
118
- const totalExchanges = allSessions.reduce((sum, s) => sum + s.exchangeCount, 0);
119
- const projects = [...new Set(allSessions.map(s => s.project))];
120
- const allTimestamps = allSessions
121
- .map(s => s.startTime)
122
- .filter(Boolean)
123
- .map(t => new Date(t))
124
- .sort((a, b) => a - b);
125
-
126
- const dateRangeShort = allTimestamps.length >= 2
127
- ? formatDateRange(allTimestamps[0], allTimestamps[allTimestamps.length - 1])
128
- : 'recent history';
129
-
130
- const dateRangeFull = allTimestamps.length >= 2
131
- ? `${allTimestamps[0].toLocaleDateString()} to ${allTimestamps[allTimestamps.length - 1].toLocaleDateString()}`
132
- : 'unknown';
133
-
134
- displayAnalysisStart(dateRangeShort);
135
-
136
- // ── Step 3: Compute metrics ──
137
- const metrics = {
138
- decomposition: computeDecomposition(allSessions),
139
- debugCycles: computeDebugCycles(allSessions),
140
- aiLeverage: computeAILeverage(allSessions),
141
- sessionStructure: computeSessionStructure(allSessions),
142
- };
143
-
144
- const result = computeOverallScore(metrics);
145
-
146
- // ── Step 3a: Compute token efficiency analytics ──
147
- const tokenEfficiency = computeTokenEfficiency(allSessions);
148
-
149
- // ── Cross-platform scores ──
150
- const perToolScores = tools.length > 1 ? computePerToolScores(allSessions) : null;
151
-
152
- // ── Score delta (compare to last scan) ──
153
- const history = loadHistory();
154
- const lastScan = history.scans.length > 0 ? history.scans[history.scans.length - 1] : null;
155
- const scoreDelta = lastScan ? result.overall - lastScan.overall : null;
156
-
157
- // Save current scan
158
- history.scans.push({
159
- overall: result.overall,
160
- tier: result.tier,
161
- archetype: result.archetype.name,
162
- scores: result.scores,
163
- date: new Date().toISOString(),
164
- });
165
- // Keep last 20 scans
166
- if (history.scans.length > 20) history.scans = history.scans.slice(-20);
167
- saveHistory(history);
168
-
169
- const sessionStats = {
170
- totalSessions: allSessions.length,
171
- totalExchanges,
172
- projectCount: projects.length,
173
- dateRange: dateRangeFull,
174
- dateRangeShort,
175
- tools: tools.map(t => t.tool),
176
- };
177
-
178
- // ── Step 3b: Compute insights ──
179
- const signatures = computeSignatures(allSessions, metrics, tokenEfficiency);
180
- const watchPoints = computeWatchPoints(allSessions, metrics, tokenEfficiency);
181
- const trajectory = computeTrajectory(allSessions);
182
- const projectComplexity = computeProjectComplexity(allSessions);
183
- const assessment = generateAssessment(result, metrics, signatures, watchPoints);
184
- const confidence = computeConfidence(sessionStats);
185
-
186
- const insights = { signatures, watchPoints, trajectory, projectComplexity, assessment, confidence };
187
-
188
- // ── JSON output ──
189
- if (options.json) {
190
- console.log(JSON.stringify({ metrics, result, sessionStats, perToolScores, scoreDelta, insights, tokenEfficiency }, null, 2));
191
- return;
192
- }
193
-
194
- // ── Step 4: Progress bar + API call in parallel ──
195
- let prose = null;
196
- if (!options.offline) {
197
- const [, proseResult] = await Promise.all([
198
- displayProgressBar(1500),
199
- generateProse(metrics, result, sessionStats, tokenEfficiency).catch(() => null),
200
- ]);
201
- prose = proseResult;
202
- } else {
203
- await displayProgressBar(1500);
204
- }
205
-
206
- // ── Step 5: Display results ──
207
- // Track line count so we can scroll back to top when done
208
- let lineCount = 0;
209
- const origWrite = process.stdout.write.bind(process.stdout);
210
- process.stdout.write = function(chunk, ...args) {
211
- if (typeof chunk === 'string') {
212
- lineCount += (chunk.match(/\n/g) || []).length;
213
- }
214
- return origWrite(chunk, ...args);
215
- };
216
-
217
- const extra = { scoreDelta, perToolScores, insights, sessionStats, tokenEfficiency };
218
- if (options.offline) {
219
- displayOffline(result, metrics, extra);
220
- } else {
221
- displayFull(result, metrics, prose, extra);
222
- }
223
-
224
- // ── Step 6: Verbose prompt (interactive) ──
225
- if (options.verbose) {
226
- displayVerbose(metrics, allSessions, tokenEfficiency);
227
- } else {
228
- try {
229
- const wantsVerbose = await askVerbose();
230
- if (wantsVerbose) {
231
- console.log();
232
- displayVerbose(metrics, allSessions, tokenEfficiency);
233
- } else {
234
- console.log();
235
- }
236
- } catch {
237
- console.log();
238
- }
239
- }
240
-
241
- // ── Step 7: Claim prompt ──
242
- if (options.upload !== false) {
243
- try {
244
- const wantsClaim = await askClaim();
245
- if (wantsClaim) {
246
- try {
247
- const claimResult = await uploadAndClaim(metrics, result, sessionStats);
248
- console.log();
249
- console.log(` ${chalk.green('\u2713')} ${chalk.dim('Profile created:')} ${chalk.cyan.underline(claimResult.claimUrl || 'https://chekk.dev/claim')}`);
250
- console.log();
251
- } catch (err) {
252
- console.log();
253
- console.log(chalk.dim(` Could not create profile \u2014 try again later`));
254
- console.log();
255
- }
256
- } else {
257
- console.log();
258
- console.log(chalk.dim(' Run `npx chekk` again anytime.\n'));
259
- }
260
- } catch {
261
- console.log();
262
- }
263
- }
264
-
265
- // ── Scroll to top of output ──
266
- // Restore original write and scroll terminal back so profile starts at top
267
- process.stdout.write = origWrite;
268
- if (lineCount > 0 && process.stdout.isTTY) {
269
- process.stdout.write(`\x1b[${lineCount}A`);
270
- }
271
- }
272
-
273
- function formatDateRange(start, end) {
274
- const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
275
- const s = `${months[start.getMonth()]} ${start.getDate()}`;
276
- const e = `${months[end.getMonth()]} ${end.getDate()}, ${end.getFullYear()}`;
277
- if (start.getFullYear() === end.getFullYear()) {
278
- return `${s} \u2013 ${e}`;
279
- }
280
- return `${s}, ${start.getFullYear()} \u2013 ${e}`;
281
- }