cc-proficiency 0.2.3 → 0.2.5

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.
Files changed (146) hide show
  1. package/README.md +23 -0
  2. package/dist/cli/commands/achievements.d.ts +2 -0
  3. package/dist/cli/commands/achievements.d.ts.map +1 -0
  4. package/dist/cli/commands/achievements.js +52 -0
  5. package/dist/cli/commands/achievements.js.map +1 -0
  6. package/dist/cli/commands/analyze.d.ts +2 -0
  7. package/dist/cli/commands/analyze.d.ts.map +1 -0
  8. package/dist/cli/commands/analyze.js +32 -0
  9. package/dist/cli/commands/analyze.js.map +1 -0
  10. package/dist/cli/commands/badge.d.ts +2 -0
  11. package/dist/cli/commands/badge.d.ts.map +1 -0
  12. package/dist/cli/commands/badge.js +25 -0
  13. package/dist/cli/commands/badge.js.map +1 -0
  14. package/dist/cli/commands/config.d.ts +2 -0
  15. package/dist/cli/commands/config.d.ts.map +1 -0
  16. package/dist/cli/commands/config.js +43 -0
  17. package/dist/cli/commands/config.js.map +1 -0
  18. package/dist/cli/commands/explain.d.ts +2 -0
  19. package/dist/cli/commands/explain.d.ts.map +1 -0
  20. package/dist/cli/commands/explain.js +44 -0
  21. package/dist/cli/commands/explain.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +2 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +69 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/commands/leaderboard.d.ts +2 -0
  27. package/dist/cli/commands/leaderboard.d.ts.map +1 -0
  28. package/dist/cli/commands/leaderboard.js +58 -0
  29. package/dist/cli/commands/leaderboard.js.map +1 -0
  30. package/dist/cli/commands/process.d.ts +2 -0
  31. package/dist/cli/commands/process.d.ts.map +1 -0
  32. package/dist/cli/commands/process.js +84 -0
  33. package/dist/cli/commands/process.js.map +1 -0
  34. package/dist/cli/commands/push.d.ts +2 -0
  35. package/dist/cli/commands/push.d.ts.map +1 -0
  36. package/dist/cli/commands/push.js +8 -0
  37. package/dist/cli/commands/push.js.map +1 -0
  38. package/dist/cli/commands/share.d.ts +2 -0
  39. package/dist/cli/commands/share.d.ts.map +1 -0
  40. package/dist/cli/commands/share.js +129 -0
  41. package/dist/cli/commands/share.js.map +1 -0
  42. package/dist/cli/commands/status.d.ts +2 -0
  43. package/dist/cli/commands/status.d.ts.map +1 -0
  44. package/dist/cli/commands/status.js +54 -0
  45. package/dist/cli/commands/status.js.map +1 -0
  46. package/dist/cli/commands/uninstall.d.ts +2 -0
  47. package/dist/cli/commands/uninstall.d.ts.map +1 -0
  48. package/dist/cli/commands/uninstall.js +27 -0
  49. package/dist/cli/commands/uninstall.js.map +1 -0
  50. package/dist/cli/index.d.ts +3 -0
  51. package/dist/cli/index.d.ts.map +1 -0
  52. package/dist/cli/index.js +108 -0
  53. package/dist/cli/index.js.map +1 -0
  54. package/dist/cli/services/hooks.d.ts +3 -0
  55. package/dist/cli/services/hooks.d.ts.map +1 -0
  56. package/dist/cli/services/hooks.js +68 -0
  57. package/dist/cli/services/hooks.js.map +1 -0
  58. package/dist/cli/services/leaderboard.d.ts +11 -0
  59. package/dist/cli/services/leaderboard.d.ts.map +1 -0
  60. package/dist/cli/services/leaderboard.js +120 -0
  61. package/dist/cli/services/leaderboard.js.map +1 -0
  62. package/dist/cli/services/publishing.d.ts +18 -0
  63. package/dist/cli/services/publishing.d.ts.map +1 -0
  64. package/dist/cli/services/publishing.js +112 -0
  65. package/dist/cli/services/publishing.js.map +1 -0
  66. package/dist/cli/services/sessions.d.ts +11 -0
  67. package/dist/cli/services/sessions.d.ts.map +1 -0
  68. package/dist/cli/services/sessions.js +80 -0
  69. package/dist/cli/services/sessions.js.map +1 -0
  70. package/dist/cli/utils/formatting.d.ts +5 -0
  71. package/dist/cli/utils/formatting.d.ts.map +1 -0
  72. package/dist/cli/utils/formatting.js +66 -0
  73. package/dist/cli/utils/formatting.js.map +1 -0
  74. package/dist/cli/utils/locale.d.ts +3 -0
  75. package/dist/cli/utils/locale.d.ts.map +1 -0
  76. package/dist/cli/utils/locale.js +14 -0
  77. package/dist/cli/utils/locale.js.map +1 -0
  78. package/dist/cli/utils/update-check.d.ts +7 -0
  79. package/dist/cli/utils/update-check.d.ts.map +1 -0
  80. package/dist/cli/utils/update-check.js +122 -0
  81. package/dist/cli/utils/update-check.js.map +1 -0
  82. package/dist/gist/registry.d.ts +26 -0
  83. package/dist/gist/registry.d.ts.map +1 -0
  84. package/dist/gist/registry.js +101 -0
  85. package/dist/gist/registry.js.map +1 -0
  86. package/dist/gist/uploader.d.ts +9 -1
  87. package/dist/gist/uploader.d.ts.map +1 -1
  88. package/dist/gist/uploader.js +47 -1
  89. package/dist/gist/uploader.js.map +1 -1
  90. package/dist/hooks/session-end.js +3 -2
  91. package/dist/i18n/locales.d.ts.map +1 -1
  92. package/dist/i18n/locales.js +2 -1
  93. package/dist/i18n/locales.js.map +1 -1
  94. package/dist/index.d.ts +1 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +3 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/parsers/config-detectors.d.ts +29 -0
  99. package/dist/parsers/config-detectors.d.ts.map +1 -0
  100. package/dist/parsers/config-detectors.js +367 -0
  101. package/dist/parsers/config-detectors.js.map +1 -0
  102. package/dist/parsers/config-parser.d.ts +7 -2
  103. package/dist/parsers/config-parser.d.ts.map +1 -1
  104. package/dist/parsers/config-parser.js +36 -228
  105. package/dist/parsers/config-parser.js.map +1 -1
  106. package/dist/renderer/svg.d.ts.map +1 -1
  107. package/dist/renderer/svg.js +3 -1
  108. package/dist/renderer/svg.js.map +1 -1
  109. package/dist/scoring/engine.d.ts +1 -1
  110. package/dist/scoring/engine.d.ts.map +1 -1
  111. package/dist/scoring/engine.js +30 -8
  112. package/dist/scoring/engine.js.map +1 -1
  113. package/dist/scoring/feature-scores.d.ts +27 -0
  114. package/dist/scoring/feature-scores.d.ts.map +1 -0
  115. package/dist/scoring/feature-scores.js +63 -0
  116. package/dist/scoring/feature-scores.js.map +1 -0
  117. package/dist/scoring/rule-engine.d.ts.map +1 -1
  118. package/dist/scoring/rule-engine.js.map +1 -1
  119. package/dist/scoring/rules.d.ts.map +1 -1
  120. package/dist/scoring/rules.js +12 -0
  121. package/dist/scoring/rules.js.map +1 -1
  122. package/dist/scoring/signals.js +4 -2
  123. package/dist/scoring/signals.js.map +1 -1
  124. package/dist/store/achievements.d.ts.map +1 -1
  125. package/dist/store/achievements.js +8 -0
  126. package/dist/store/achievements.js.map +1 -1
  127. package/dist/store/local-store.d.ts +3 -1
  128. package/dist/store/local-store.d.ts.map +1 -1
  129. package/dist/store/local-store.js +21 -3
  130. package/dist/store/local-store.js.map +1 -1
  131. package/dist/store/public-profile.d.ts +12 -0
  132. package/dist/store/public-profile.d.ts.map +1 -0
  133. package/dist/store/public-profile.js +50 -0
  134. package/dist/store/public-profile.js.map +1 -0
  135. package/dist/store/queue.js +1 -1
  136. package/dist/store/queue.js.map +1 -1
  137. package/dist/store/remote-store.d.ts.map +1 -1
  138. package/dist/types.d.ts +54 -0
  139. package/dist/types.d.ts.map +1 -1
  140. package/hooks/session-end.ts +4 -3
  141. package/package.json +8 -3
  142. package/dist/cli.d.ts +0 -3
  143. package/dist/cli.d.ts.map +0 -1
  144. package/dist/cli.js +0 -722
  145. package/dist/cli.js.map +0 -1
  146. package/skills/proficiency/SKILL.md +0 -15
package/dist/cli.js DELETED
@@ -1,722 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
- const node_os_1 = require("node:os");
7
- const transcript_parser_js_1 = require("./parsers/transcript-parser.js");
8
- const config_parser_js_1 = require("./parsers/config-parser.js");
9
- const engine_js_1 = require("./scoring/engine.js");
10
- const svg_js_1 = require("./renderer/svg.js");
11
- const locales_js_1 = require("./i18n/locales.js");
12
- const local_store_js_1 = require("./store/local-store.js");
13
- const queue_js_1 = require("./store/queue.js");
14
- const uploader_js_1 = require("./gist/uploader.js");
15
- const remote_store_js_1 = require("./store/remote-store.js");
16
- const achievements_js_1 = require("./store/achievements.js");
17
- const CLAUDE_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".claude");
18
- function getConfigLocale() {
19
- const config = (0, local_store_js_1.loadConfig)();
20
- if (config.locale === "zh-CN")
21
- return "zh-CN";
22
- if (config.locale === "en")
23
- return "en";
24
- return (0, locales_js_1.detectLocale)();
25
- }
26
- async function main() {
27
- const args = process.argv.slice(2);
28
- const command = args[0];
29
- switch (command) {
30
- case "init":
31
- return await cmdInit();
32
- case "analyze":
33
- return cmdAnalyze(args);
34
- case "process":
35
- return cmdProcess();
36
- case "badge":
37
- return cmdBadge(args);
38
- case "push":
39
- return cmdPush();
40
- case "explain":
41
- return cmdExplain();
42
- case "achievements":
43
- return cmdAchievements();
44
- case "status":
45
- return cmdStatus();
46
- case "config":
47
- return cmdConfig(args.slice(1));
48
- case "uninstall":
49
- return cmdUninstall();
50
- case "version":
51
- console.log(`cc-proficiency v${getVersion()} (scoring ${engine_js_1.SCORING_VERSION})`);
52
- return;
53
- default:
54
- printUsage();
55
- return;
56
- }
57
- }
58
- function getVersion() {
59
- try {
60
- const pkg = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, "..", "package.json"), "utf-8"));
61
- return pkg.version ?? "0.1.0";
62
- }
63
- catch {
64
- return "0.1.0";
65
- }
66
- }
67
- function printUsage() {
68
- console.log(`
69
- cc-proficiency — Claude Code Proficiency Badge Generator
70
-
71
- Commands:
72
- init Set up configuration and hooks
73
- analyze [--full] Analyze sessions and compute scores
74
- process Process queued sessions from hook
75
- badge [--output <f>] Generate SVG badge
76
- push Upload badge to GitHub Gist
77
- explain Show score drivers and improvement tips
78
- status Show hook activity, queue, and config
79
- config [key] [value] View or set configuration
80
- uninstall Remove hooks and clean up
81
- version Show version info
82
-
83
- Examples:
84
- cc-proficiency init
85
- cc-proficiency analyze --full
86
- cc-proficiency badge --output badge.svg
87
- cc-proficiency explain
88
- `);
89
- }
90
- // ── Init ──
91
- async function cmdInit() {
92
- console.log("Initializing cc-proficiency...\n");
93
- (0, queue_js_1.ensureStoreDir)();
94
- const config = (0, local_store_js_1.loadConfig)();
95
- // Detect GitHub user
96
- if ((0, uploader_js_1.isGhAuthenticated)()) {
97
- const username = (0, uploader_js_1.getGhUsername)();
98
- if (username) {
99
- config.username = username;
100
- console.log(` GitHub user: @${username}`);
101
- }
102
- }
103
- else {
104
- console.log(" ⚠ GitHub CLI not authenticated.");
105
- console.log(" Badge will be saved locally to: " + (0, local_store_js_1.getBadgePath)());
106
- console.log(" To enable auto-upload: gh auth login && cc-proficiency init\n");
107
- }
108
- // Inject hook into settings.json
109
- injectHook();
110
- console.log(" ✓ Hook injected into ~/.claude/settings.json");
111
- // Run analysis first (so we have a real badge before creating Gist)
112
- console.log("\n Running initial analysis...");
113
- (0, local_store_js_1.saveConfig)(config);
114
- await cmdAnalyze(["--full"]);
115
- // Generate the real badge SVG
116
- const store = (0, local_store_js_1.loadStore)();
117
- let badgeSvg = '<svg xmlns="http://www.w3.org/2000/svg"><text>No data</text></svg>';
118
- if (store.lastResult) {
119
- badgeSvg = (0, svg_js_1.renderBadge)(store.lastResult, getConfigLocale());
120
- (0, local_store_js_1.saveBadge)(badgeSvg);
121
- }
122
- // Create Gist with the REAL badge (not a placeholder)
123
- if (config.username && (0, uploader_js_1.isGhAuthenticated)() && !config.gistId) {
124
- console.log(" Creating private Gist with badge...");
125
- const result = (0, uploader_js_1.createGist)(badgeSvg, config.public);
126
- if (result.success && result.url) {
127
- config.gistId = result.url;
128
- const rawUrl = (0, uploader_js_1.getGistRawUrl)(config.username, result.url);
129
- console.log(` ✓ Gist created`);
130
- console.log(`\n Add to your README:`);
131
- console.log(` ![CC Proficiency](${rawUrl})`);
132
- }
133
- else {
134
- console.log(` ⚠ Could not create Gist: ${result.error}`);
135
- }
136
- }
137
- else if (config.gistId && (0, uploader_js_1.isGhAuthenticated)()) {
138
- // Existing Gist — push the updated badge
139
- const gistResult = (0, uploader_js_1.updateGist)(config.gistId, badgeSvg);
140
- if (gistResult.success) {
141
- const rawUrl = (0, uploader_js_1.getGistRawUrl)(config.username ?? "", config.gistId);
142
- console.log(` ✓ Badge pushed to Gist: ${rawUrl}`);
143
- }
144
- }
145
- (0, local_store_js_1.saveConfig)(config);
146
- console.log("\n ✓ Configuration saved to " + (0, local_store_js_1.getStoreDir)());
147
- console.log(" Badge saved locally to: " + (0, local_store_js_1.getBadgePath)());
148
- }
149
- function injectHook() {
150
- const settingsPath = (0, node_path_1.join)(CLAUDE_DIR, "settings.json");
151
- let settings = {};
152
- if ((0, node_fs_1.existsSync)(settingsPath)) {
153
- try {
154
- settings = JSON.parse((0, node_fs_1.readFileSync)(settingsPath, "utf-8"));
155
- }
156
- catch {
157
- console.log(" ⚠ Could not parse settings.json, creating new hooks section");
158
- }
159
- }
160
- // Check for existing cc-proficiency hook (idempotent)
161
- const hooks = (settings.hooks ?? {});
162
- const stopHooks = (hooks.Stop ?? []);
163
- const alreadyInstalled = stopHooks.some((group) => group.hooks?.some((h) => h.command?.includes("cc-proficiency")));
164
- if (alreadyInstalled) {
165
- console.log(" Hook already installed (skipping)");
166
- return;
167
- }
168
- // Ensure ~/.claude/ exists before writing settings.json
169
- if (!(0, node_fs_1.existsSync)(CLAUDE_DIR)) {
170
- (0, node_fs_1.mkdirSync)(CLAUDE_DIR, { recursive: true });
171
- }
172
- // Find the installed path of this package
173
- // When compiled: dist/cli.js → dist/hooks/session-end.js
174
- const hookScript = (0, node_path_1.join)(__dirname, "hooks", "session-end.js");
175
- const hookCommand = `node "${hookScript}"`;
176
- stopHooks.push({
177
- hooks: [
178
- {
179
- type: "command",
180
- command: hookCommand,
181
- timeout: 5,
182
- },
183
- ],
184
- });
185
- hooks.Stop = stopHooks;
186
- settings.hooks = hooks;
187
- (0, node_fs_1.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
188
- }
189
- // ── Analyze ──
190
- async function cmdAnalyze(args) {
191
- const full = args.includes("--full");
192
- console.log(full ? "Running full analysis..." : "Running incremental analysis...\n");
193
- const { sessions, config } = await gatherData(full);
194
- if (sessions.length === 0) {
195
- console.log("No sessions found. Use Claude Code first, then run analyze again.");
196
- return;
197
- }
198
- const setupChecklist = (0, config_parser_js_1.buildSetupChecklist)(config);
199
- const userConfig = (0, local_store_js_1.loadConfig)();
200
- const result = (0, engine_js_1.computeProficiency)(sessions, config, userConfig.username ?? "unknown", setupChecklist);
201
- // Update store with processed session IDs
202
- const store = (0, local_store_js_1.loadStore)();
203
- store.lastResult = result;
204
- for (const s of sessions) {
205
- if (!store.processedSessionIds.includes(s.sessionId)) {
206
- store.processedSessionIds.push(s.sessionId);
207
- }
208
- }
209
- (0, local_store_js_1.saveStore)(store);
210
- // Display
211
- printResult(result);
212
- }
213
- async function gatherData(full) {
214
- const config = (0, config_parser_js_1.parseClaudeConfig)();
215
- const sessions = [];
216
- const store = full ? { processedSessionIds: [] } : (0, local_store_js_1.loadStore)();
217
- const projectsDir = (0, node_path_1.join)(CLAUDE_DIR, "projects");
218
- if (!(0, node_fs_1.existsSync)(projectsDir))
219
- return { sessions, config };
220
- const projects = (0, node_fs_1.readdirSync)(projectsDir);
221
- for (const proj of projects) {
222
- const projDir = (0, node_path_1.join)(projectsDir, proj);
223
- try {
224
- const files = (0, node_fs_1.readdirSync)(projDir).filter((f) => f.endsWith(".jsonl"));
225
- for (const file of files) {
226
- const sessionId = file.replace(".jsonl", "");
227
- if (!full && (0, local_store_js_1.isSessionProcessed)(store, sessionId)) {
228
- continue;
229
- }
230
- try {
231
- const session = await (0, transcript_parser_js_1.parseTranscript)((0, node_path_1.join)(projDir, file));
232
- if (session.events.length > 0) {
233
- sessions.push(session);
234
- }
235
- }
236
- catch {
237
- // skip unreadable files
238
- }
239
- }
240
- }
241
- catch {
242
- // skip unreadable project dirs
243
- }
244
- }
245
- return { sessions, config };
246
- }
247
- function printResult(result) {
248
- console.log(` Claude Code Proficiency — @${result.username}`);
249
- console.log(" " + "─".repeat(40));
250
- if (result.phase === "calibrating") {
251
- const needed = Math.max(0, 3 - result.sessionCount);
252
- console.log(` ⏳ Calibrating... (${result.sessionCount} sessions, need ${needed} more)`);
253
- console.log("");
254
- printSetupChecklist(result.setupChecklist);
255
- return;
256
- }
257
- for (const d of result.domains) {
258
- const bar = progressBar(d.score, 20);
259
- const conf = d.confidence === "high" ? "●" : d.confidence === "medium" ? "◐" : "○";
260
- console.log(` ${d.label.padEnd(14)} ${bar} ${String(d.score).padStart(3)} ${conf}`);
261
- }
262
- console.log(" " + "─".repeat(40));
263
- // Feature inventory
264
- const f = result.features;
265
- if (f.hooks.length > 0) {
266
- const shown = f.hooks.slice(0, 3).map((h) => `${h.name} (${h.count}x)`).join(", ");
267
- const more = f.hooks.length > 3 ? ` +${f.hooks.length - 3}` : "";
268
- console.log(` Hooks ${shown}${more}`);
269
- }
270
- if (f.skills.length > 0) {
271
- const shown = f.skills.slice(0, 3).map((s) => `${s.name} (${s.count}x)`).join(", ");
272
- const more = f.skills.length > 3 ? ` +${f.skills.length - 3}` : "";
273
- console.log(` Skills ${shown}${more}`);
274
- }
275
- if (f.mcpServers.length > 0) {
276
- console.log(` MCP ${f.mcpServers.join(", ")}`);
277
- }
278
- const toolSummary = f.topTools.slice(0, 4).map((t) => `${t.name} ${t.count}`).join(" · ");
279
- console.log(` Tools ${toolSummary} (+${f.uniqueToolCount - Math.min(4, f.topTools.length)} more)`);
280
- console.log(" " + "─".repeat(40));
281
- const hrs = result.features.totalHours >= 1000 ? (result.features.totalHours / 1000).toFixed(1) + "kh" : result.features.totalHours + "h";
282
- console.log(` ${hrs} · ${result.sessionCount} sessions · ${result.projectCount} projects`);
283
- if (result.phase === "early") {
284
- console.log(` (early results — stabilizes at 10 sessions)`);
285
- }
286
- }
287
- function progressBar(score, width) {
288
- const filled = Math.round((score / 100) * width);
289
- const empty = width - filled;
290
- return "█".repeat(filled) + "░".repeat(empty);
291
- }
292
- function printSetupChecklist(cl) {
293
- const items = [
294
- ["CLAUDE.md", cl.hasClaudeMd],
295
- ["Hooks", cl.hasHooks],
296
- ["Plugins", cl.hasPlugins],
297
- ["MCP Servers", cl.hasMcpServers],
298
- ["Memory", cl.hasMemory],
299
- ["Rules", cl.hasRules],
300
- ];
301
- console.log(" Setup:");
302
- for (const [label, ok] of items) {
303
- console.log(` ${ok ? "✓" : "✗"} ${label}`);
304
- }
305
- }
306
- // ── Process ──
307
- async function cmdProcess() {
308
- if (!(0, queue_js_1.acquireLock)()) {
309
- console.log("Another process is running. Skipping.");
310
- return;
311
- }
312
- try {
313
- const queue = (0, queue_js_1.readQueue)();
314
- if (queue.length === 0) {
315
- console.log("Queue empty. Nothing to process.");
316
- return;
317
- }
318
- const store = (0, local_store_js_1.loadStore)();
319
- const newSessions = [];
320
- const processed = [];
321
- for (const entry of queue) {
322
- if ((0, local_store_js_1.isSessionProcessed)(store, entry.sessionId)) {
323
- processed.push(entry.sessionId);
324
- continue;
325
- }
326
- if (!(0, node_fs_1.existsSync)(entry.transcriptPath)) {
327
- (0, local_store_js_1.logError)(`Transcript not found: ${entry.transcriptPath}`);
328
- processed.push(entry.sessionId);
329
- continue;
330
- }
331
- try {
332
- const session = await (0, transcript_parser_js_1.parseTranscript)(entry.transcriptPath);
333
- if (session.events.length > 0) {
334
- newSessions.push(session);
335
- store.processedSessionIds.push(entry.sessionId);
336
- }
337
- processed.push(entry.sessionId);
338
- }
339
- catch (err) {
340
- (0, local_store_js_1.logError)(`Failed to parse ${entry.sessionId}: ${err}`);
341
- processed.push(entry.sessionId);
342
- }
343
- }
344
- // Recompute overall scores from all snapshots
345
- if (newSessions.length > 0) {
346
- const config = (0, config_parser_js_1.parseClaudeConfig)();
347
- const allSessions = await gatherAllProcessedSessions(store);
348
- const sessionsToScore = allSessions.length > 0 ? allSessions : newSessions;
349
- const setupChecklist = (0, config_parser_js_1.buildSetupChecklist)(config);
350
- const userConfig = (0, local_store_js_1.loadConfig)();
351
- const result = (0, engine_js_1.computeProficiency)(sessionsToScore, config, userConfig.username ?? "unknown", setupChecklist);
352
- store.lastResult = result;
353
- // Generate and save badge
354
- const svg = (0, svg_js_1.renderBadge)(result, getConfigLocale());
355
- const badgePath = (0, local_store_js_1.saveBadge)(svg);
356
- // Push to gist if configured and autoUpload enabled
357
- if (userConfig.autoUpload && userConfig.gistId && (0, uploader_js_1.isGhAuthenticated)()) {
358
- const gistResult = (0, uploader_js_1.updateGist)(userConfig.gistId, svg);
359
- if (!gistResult.success) {
360
- (0, local_store_js_1.logError)(`Gist push failed: ${gistResult.error}`);
361
- }
362
- }
363
- console.log(`Processed ${newSessions.length} session(s). Badge saved to ${badgePath}`);
364
- }
365
- // Remove processed entries from queue (re-reads to avoid race with hook appends)
366
- (0, queue_js_1.writeQueue)(new Set(processed));
367
- (0, local_store_js_1.saveStore)(store);
368
- }
369
- finally {
370
- (0, queue_js_1.releaseLock)();
371
- }
372
- }
373
- async function gatherAllProcessedSessions(store) {
374
- // Re-parse transcripts for all stored session IDs that still have files
375
- const sessions = [];
376
- const projectsDir = (0, node_path_1.join)(CLAUDE_DIR, "projects");
377
- if (!(0, node_fs_1.existsSync)(projectsDir))
378
- return sessions;
379
- const projects = (0, node_fs_1.readdirSync)(projectsDir);
380
- for (const proj of projects) {
381
- const projDir = (0, node_path_1.join)(projectsDir, proj);
382
- try {
383
- const files = (0, node_fs_1.readdirSync)(projDir).filter((f) => f.endsWith(".jsonl"));
384
- for (const file of files) {
385
- const sessionId = file.replace(".jsonl", "");
386
- if (store.processedSessionIds.includes(sessionId)) {
387
- try {
388
- const session = await (0, transcript_parser_js_1.parseTranscript)((0, node_path_1.join)(projDir, file));
389
- if (session.events.length > 0)
390
- sessions.push(session);
391
- }
392
- catch { /* skip */ }
393
- }
394
- }
395
- }
396
- catch { /* skip */ }
397
- }
398
- return sessions;
399
- }
400
- // ── Badge ──
401
- async function cmdBadge(args) {
402
- const store = (0, local_store_js_1.loadStore)();
403
- if (!store.lastResult) {
404
- console.log("No analysis data. Run 'cc-proficiency analyze' first.");
405
- return;
406
- }
407
- const svg = (0, svg_js_1.renderBadge)(store.lastResult, getConfigLocale());
408
- const outputIdx = args.indexOf("--output");
409
- if (outputIdx !== -1 && args[outputIdx + 1]) {
410
- (0, node_fs_1.writeFileSync)(args[outputIdx + 1], svg, "utf-8");
411
- console.log(`Badge written to ${args[outputIdx + 1]}`);
412
- }
413
- else {
414
- const path = (0, local_store_js_1.saveBadge)(svg);
415
- console.log(`Badge saved to ${path}`);
416
- }
417
- }
418
- // ── Push ──
419
- function cmdPush() {
420
- const config = (0, local_store_js_1.loadConfig)();
421
- const store = (0, local_store_js_1.loadStore)();
422
- if (!store.lastResult) {
423
- console.log("No analysis data. Run 'cc-proficiency analyze' first.");
424
- return;
425
- }
426
- const svg = (0, svg_js_1.renderBadge)(store.lastResult, getConfigLocale());
427
- (0, local_store_js_1.saveBadge)(svg);
428
- if (!(0, uploader_js_1.isGhAuthenticated)() || !config.gistId) {
429
- if (!(0, uploader_js_1.isGhAuthenticated)()) {
430
- console.log("⚠ GitHub CLI not authenticated.");
431
- console.log("To enable: gh auth login && cc-proficiency init");
432
- }
433
- if (!config.gistId) {
434
- console.log("No Gist configured. Run 'cc-proficiency init' first.");
435
- }
436
- console.log("Badge saved locally to: " + (0, local_store_js_1.getBadgePath)());
437
- return;
438
- }
439
- // Pull remote, merge, push
440
- const remoteJson = (0, uploader_js_1.readGistFile)(config.gistId, "cc-proficiency.json");
441
- let remote = remoteJson ? (0, remote_store_js_1.parseRemoteStore)(remoteJson) : null;
442
- if (!remote)
443
- remote = (0, remote_store_js_1.emptyRemoteStore)(config.username ?? "unknown");
444
- // Build local session list for merge
445
- const avgHours = store.lastResult.features.totalHours / Math.max(store.processedSessionIds.length, 1);
446
- const localSessions = store.processedSessionIds.map((id) => {
447
- const snap = store.snapshots.find((s) => s.sessionId === id);
448
- return {
449
- id,
450
- date: snap ? (0, remote_store_js_1.getUTCDate)(snap.timestamp) : new Date().toISOString().slice(0, 10),
451
- hours: avgHours,
452
- };
453
- });
454
- const merged = (0, remote_store_js_1.mergeIntoRemote)(remote, localSessions, store.lastResult);
455
- // Get totals from merged store
456
- const totals = (0, remote_store_js_1.getTotalStats)(merged);
457
- const ctx = {
458
- totalSessions: totals.sessions,
459
- totalHours: totals.hours,
460
- totalProjects: totals.projects,
461
- domains: merged.domains,
462
- streak: merged.streak,
463
- features: store.lastResult.features,
464
- activeDates: merged.streak.activeDates,
465
- };
466
- const newAchievements = (0, achievements_js_1.checkAchievements)(ctx, merged.achievements.map((a) => a.id));
467
- for (const id of newAchievements) {
468
- merged.achievements.push({ id, unlockedAt: new Date().toISOString() });
469
- const def = (0, achievements_js_1.getAchievementDef)(id);
470
- if (def)
471
- console.log(` 🏆 Achievement unlocked: ${def.icon} ${def.name}`);
472
- }
473
- // Build weekly trend for current week
474
- const thisWeek = (0, remote_store_js_1.getWeekMonday)(new Date().toISOString());
475
- const localTrend = {
476
- week: thisWeek,
477
- domains: Object.fromEntries(store.lastResult.domains.map((d) => [d.id, d.score])),
478
- hours: store.lastResult.features.totalHours,
479
- sessions: store.lastResult.sessionCount,
480
- };
481
- merged.weeklyTrends = (0, remote_store_js_1.mergeWeeklyTrends)(merged.weeklyTrends, [localTrend]);
482
- // Update result with gamification data and re-render badge
483
- store.lastResult.streak = merged.streak.current;
484
- store.lastResult.achievementCount = merged.achievements.length;
485
- const finalSvg = (0, svg_js_1.renderBadge)(store.lastResult, getConfigLocale());
486
- (0, local_store_js_1.saveBadge)(finalSvg);
487
- // Push SVG + JSON atomically
488
- const pushResult = (0, uploader_js_1.pushGistFiles)(config.gistId, {
489
- "cc-proficiency.svg": finalSvg,
490
- "cc-proficiency.json": JSON.stringify(merged, null, 2),
491
- });
492
- if (pushResult.success) {
493
- const rawUrl = (0, uploader_js_1.getGistRawUrl)(config.username ?? "", config.gistId);
494
- console.log("✓ Badge + data pushed to Gist");
495
- console.log(` ${rawUrl}`);
496
- console.log(` ${totals.sessions} sessions · ${totals.hours.toFixed(1)}h · ${merged.achievements.length} achievements · 🔥 ${merged.streak.current}d streak`);
497
- }
498
- else {
499
- console.log(`✗ Push failed: ${pushResult.error}`);
500
- }
501
- }
502
- // ── Achievements ──
503
- function cmdAchievements() {
504
- const store = (0, local_store_js_1.loadStore)();
505
- const config = (0, local_store_js_1.loadConfig)();
506
- if (!store.lastResult) {
507
- console.log("No analysis data. Run 'cc-proficiency analyze' first.");
508
- return;
509
- }
510
- // Try to load remote achievements
511
- let unlockedIds = [];
512
- if (config.gistId && (0, uploader_js_1.isGhAuthenticated)()) {
513
- const remoteJson = (0, uploader_js_1.readGistFile)(config.gistId, "cc-proficiency.json");
514
- const remote = remoteJson ? (0, remote_store_js_1.parseRemoteStore)(remoteJson) : null;
515
- if (remote) {
516
- unlockedIds = remote.achievements.map((a) => a.id);
517
- }
518
- }
519
- // Build context from local data
520
- const result = store.lastResult;
521
- const ctx = {
522
- totalSessions: result.sessionCount,
523
- totalHours: result.features.totalHours,
524
- totalProjects: result.projectCount,
525
- domains: result.domains,
526
- streak: { current: 0, longest: 0 },
527
- features: result.features,
528
- activeDates: [],
529
- };
530
- // Also check locally
531
- const newLocal = (0, achievements_js_1.checkAchievements)(ctx, unlockedIds);
532
- const allUnlocked = new Set([...unlockedIds, ...newLocal]);
533
- console.log(`\n Achievements (${allUnlocked.size}/${achievements_js_1.ACHIEVEMENTS.length})\n`);
534
- for (const achievement of achievements_js_1.ACHIEVEMENTS) {
535
- const unlocked = allUnlocked.has(achievement.id);
536
- const { current, target } = achievement.progress(ctx);
537
- const pct = Math.min(100, Math.round((current / target) * 100));
538
- const bar = progressBar(pct, 12);
539
- if (unlocked) {
540
- console.log(` ${achievement.icon} ${achievement.name.padEnd(18)} ${bar} Done!`);
541
- }
542
- else {
543
- console.log(` \u2591 ${achievement.name.padEnd(18)} ${bar} ${current}/${target}`);
544
- }
545
- }
546
- console.log("");
547
- }
548
- // ── Status ──
549
- function cmdStatus() {
550
- const hookLogPath = (0, node_path_1.join)((0, local_store_js_1.getStoreDir)(), "hook.log");
551
- const queuePath = (0, node_path_1.join)((0, local_store_js_1.getStoreDir)(), "queue.jsonl");
552
- const store = (0, local_store_js_1.loadStore)();
553
- const config = (0, local_store_js_1.loadConfig)();
554
- console.log("\n cc-proficiency status\n");
555
- // Config
556
- console.log(` Username: ${config.username ?? "(not set)"}`);
557
- console.log(` Gist ID: ${config.gistId ?? "(not set)"}`);
558
- console.log(` Auto-upload: ${config.autoUpload}`);
559
- console.log(` Locale: ${config.locale ?? "en"}`);
560
- // Store
561
- console.log(`\n Sessions processed: ${store.processedSessionIds.length}`);
562
- console.log(` Last updated: ${store.lastUpdated ?? "never"}`);
563
- // Queue
564
- const queue = (0, queue_js_1.readQueue)();
565
- console.log(` Queue pending: ${queue.length}`);
566
- // Hook log
567
- if ((0, node_fs_1.existsSync)(hookLogPath)) {
568
- const log = (0, node_fs_1.readFileSync)(hookLogPath, "utf-8").trim().split("\n");
569
- const recent = log.slice(-10);
570
- console.log(`\n Hook log (last ${recent.length} entries):`);
571
- for (const line of recent) {
572
- console.log(` ${line}`);
573
- }
574
- // Last hook fire
575
- const lastQueued = log.filter((l) => l.includes("QUEUED")).pop();
576
- if (lastQueued) {
577
- const match = lastQueued.match(/\[(.*?)\]/);
578
- console.log(`\n Last hook fired: ${match ? match[1] : "unknown"}`);
579
- }
580
- }
581
- else {
582
- console.log("\n Hook log: no entries yet (hook hasn't fired)");
583
- }
584
- // Lock status
585
- const lockPath = (0, node_path_1.join)((0, local_store_js_1.getStoreDir)(), "queue.lock");
586
- if ((0, node_fs_1.existsSync)(lockPath)) {
587
- try {
588
- const lockTime = parseInt((0, node_fs_1.readFileSync)(lockPath, "utf-8"), 10);
589
- const age = Math.round((Date.now() - lockTime) / 1000);
590
- console.log(` Queue lock: held (${age}s ago)${age > 60 ? " ← STALE" : ""}`);
591
- }
592
- catch {
593
- console.log(" Queue lock: present (unknown age)");
594
- }
595
- }
596
- else {
597
- console.log(" Queue lock: none");
598
- }
599
- console.log("");
600
- }
601
- // ── Explain ──
602
- function cmdExplain() {
603
- const store = (0, local_store_js_1.loadStore)();
604
- if (!store.lastResult) {
605
- console.log("No analysis data. Run 'cc-proficiency analyze' first.");
606
- return;
607
- }
608
- const result = store.lastResult;
609
- const sorted = [...result.domains].sort((a, b) => b.score - a.score);
610
- const weakest = [...result.domains].sort((a, b) => a.score - b.score);
611
- console.log(`\n Claude Code Proficiency — @${result.username}\n`);
612
- console.log(" Strengths:");
613
- for (const d of sorted) {
614
- console.log(` ${d.label.padEnd(14)} ${d.score}/100`);
615
- }
616
- const tips = {
617
- "cc-mastery": "Enhance CLAUDE.md with imports, add hooks with matchers, create rules files, use plan mode",
618
- "tool-mcp": "Chain tools deliberately (Grep→Read→Edit), set up MCP servers, use LSP integration",
619
- "agentic": "Use subagents with different types (Explore, Plan), try parallel agents and worktrees",
620
- "prompt-craft": "Structure prompts with markdown lists, provide code blocks and file references",
621
- "context-mgmt": "Use cross-session memory files, work across multiple projects, update CLAUDE.md",
622
- };
623
- console.log("\n Areas to Improve:");
624
- for (let i = 0; i < Math.min(2, weakest.length); i++) {
625
- const d = weakest[i];
626
- console.log(` ${d.label} (${d.score}/100)`);
627
- console.log(` → ${tips[d.id] ?? "Practice using this feature area"}`);
628
- }
629
- // Feature inventory detail
630
- const f = result.features;
631
- console.log("\n Feature Usage:");
632
- if (f.hooks.length > 0)
633
- console.log(` Hooks: ${f.hooks.map((h) => `${h.name} (${h.count}x)`).join(", ")}`);
634
- if (f.skills.length > 0)
635
- console.log(` Skills: ${f.skills.map((s) => `${s.name} (${s.count}x)`).join(", ")}`);
636
- if (f.mcpServers.length > 0)
637
- console.log(` MCP: ${f.mcpServers.join(", ")}`);
638
- console.log(` Tools: ${f.topTools.map((t) => `${t.name} (${t.count})`).join(", ")} +${f.uniqueToolCount - f.topTools.length} more`);
639
- console.log(` Flags: ${f.usedPlanMode ? "✓ Plan" : "✗ Plan"} ${f.hasMemory ? "✓ Memory" : "✗ Memory"} ${f.hasRules ? "✓ Rules" : "✗ Rules"}`);
640
- console.log(`\n ${result.sessionCount} sessions · ${result.projectCount} projects\n`);
641
- }
642
- // ── Config ──
643
- function cmdConfig(args) {
644
- const config = (0, local_store_js_1.loadConfig)();
645
- if (args.length === 0) {
646
- console.log(JSON.stringify(config, null, 2));
647
- return;
648
- }
649
- if (args.length === 1) {
650
- const key = args[0];
651
- if (key in config) {
652
- console.log(`${key}: ${JSON.stringify(config[key])}`);
653
- }
654
- else {
655
- console.log(`Unknown key: ${key}`);
656
- }
657
- return;
658
- }
659
- const [key, value] = args;
660
- if (key === "username")
661
- config.username = value;
662
- else if (key === "gistId")
663
- config.gistId = value;
664
- else if (key === "autoUpload")
665
- config.autoUpload = value === "true";
666
- else if (key === "public")
667
- config.public = value === "true";
668
- else if (key === "locale")
669
- config.locale = value;
670
- else {
671
- console.log(`Unknown key: ${key}`);
672
- return;
673
- }
674
- (0, local_store_js_1.saveConfig)(config);
675
- console.log(`Set ${key} = ${value}`);
676
- }
677
- // ── Uninstall ──
678
- function cmdUninstall() {
679
- console.log("Uninstalling cc-proficiency...\n");
680
- // Remove hook from settings.json
681
- const settingsPath = (0, node_path_1.join)(CLAUDE_DIR, "settings.json");
682
- if ((0, node_fs_1.existsSync)(settingsPath)) {
683
- try {
684
- const settings = JSON.parse((0, node_fs_1.readFileSync)(settingsPath, "utf-8"));
685
- if (settings.hooks?.Stop) {
686
- settings.hooks.Stop = settings.hooks.Stop.filter((group) => !group.hooks?.some((h) => h.command?.includes("cc-proficiency")));
687
- if (settings.hooks.Stop.length === 0) {
688
- delete settings.hooks.Stop;
689
- }
690
- if (Object.keys(settings.hooks).length === 0) {
691
- delete settings.hooks;
692
- }
693
- (0, node_fs_1.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2), "utf-8");
694
- console.log(" ✓ Hook removed from settings.json");
695
- }
696
- }
697
- catch {
698
- console.log(" ⚠ Could not update settings.json");
699
- }
700
- }
701
- // Remove local data
702
- const storeDir = (0, local_store_js_1.getStoreDir)();
703
- if ((0, node_fs_1.existsSync)(storeDir)) {
704
- try {
705
- const files = (0, node_fs_1.readdirSync)(storeDir);
706
- for (const f of files) {
707
- (0, node_fs_1.unlinkSync)((0, node_path_1.join)(storeDir, f));
708
- }
709
- (0, node_fs_1.rmdirSync)(storeDir);
710
- console.log(" ✓ Local data removed");
711
- }
712
- catch {
713
- console.log(" ⚠ Could not fully remove " + storeDir);
714
- }
715
- }
716
- console.log("\n cc-proficiency uninstalled. Run 'npm uninstall -g cc-proficiency' to remove the package.");
717
- }
718
- main().catch((err) => {
719
- console.error("Error:", err);
720
- process.exit(1);
721
- });
722
- //# sourceMappingURL=cli.js.map