cc-proficiency 0.1.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.
Files changed (82) hide show
  1. package/.claude-plugin/plugin.json +11 -0
  2. package/LICENSE +201 -0
  3. package/README.md +345 -0
  4. package/README.zh-CN.md +284 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +543 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/gist/uploader.d.ts +26 -0
  10. package/dist/gist/uploader.d.ts.map +1 -0
  11. package/dist/gist/uploader.js +99 -0
  12. package/dist/gist/uploader.js.map +1 -0
  13. package/dist/hooks/session-end.js +64 -0
  14. package/dist/i18n/locales.d.ts +30 -0
  15. package/dist/i18n/locales.d.ts.map +1 -0
  16. package/dist/i18n/locales.js +64 -0
  17. package/dist/i18n/locales.js.map +1 -0
  18. package/dist/index.d.ts +12 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +38 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/parsers/config-parser.d.ts +25 -0
  23. package/dist/parsers/config-parser.d.ts.map +1 -0
  24. package/dist/parsers/config-parser.js +262 -0
  25. package/dist/parsers/config-parser.js.map +1 -0
  26. package/dist/parsers/history-parser.d.ts +13 -0
  27. package/dist/parsers/history-parser.d.ts.map +1 -0
  28. package/dist/parsers/history-parser.js +50 -0
  29. package/dist/parsers/history-parser.js.map +1 -0
  30. package/dist/parsers/normalizer.d.ts +8 -0
  31. package/dist/parsers/normalizer.d.ts.map +1 -0
  32. package/dist/parsers/normalizer.js +105 -0
  33. package/dist/parsers/normalizer.js.map +1 -0
  34. package/dist/parsers/transcript-parser.d.ts +23 -0
  35. package/dist/parsers/transcript-parser.d.ts.map +1 -0
  36. package/dist/parsers/transcript-parser.js +112 -0
  37. package/dist/parsers/transcript-parser.js.map +1 -0
  38. package/dist/renderer/svg.d.ts +10 -0
  39. package/dist/renderer/svg.d.ts.map +1 -0
  40. package/dist/renderer/svg.js +209 -0
  41. package/dist/renderer/svg.js.map +1 -0
  42. package/dist/scoring/curves.d.ts +34 -0
  43. package/dist/scoring/curves.d.ts.map +1 -0
  44. package/dist/scoring/curves.js +60 -0
  45. package/dist/scoring/curves.js.map +1 -0
  46. package/dist/scoring/engine.d.ts +16 -0
  47. package/dist/scoring/engine.d.ts.map +1 -0
  48. package/dist/scoring/engine.js +137 -0
  49. package/dist/scoring/engine.js.map +1 -0
  50. package/dist/scoring/rule-engine.d.ts +30 -0
  51. package/dist/scoring/rule-engine.d.ts.map +1 -0
  52. package/dist/scoring/rule-engine.js +151 -0
  53. package/dist/scoring/rule-engine.js.map +1 -0
  54. package/dist/scoring/rules.d.ts +32 -0
  55. package/dist/scoring/rules.d.ts.map +1 -0
  56. package/dist/scoring/rules.js +443 -0
  57. package/dist/scoring/rules.js.map +1 -0
  58. package/dist/scoring/signals.d.ts +7 -0
  59. package/dist/scoring/signals.d.ts.map +1 -0
  60. package/dist/scoring/signals.js +245 -0
  61. package/dist/scoring/signals.js.map +1 -0
  62. package/dist/store/local-store.d.ts +12 -0
  63. package/dist/store/local-store.d.ts.map +1 -0
  64. package/dist/store/local-store.js +107 -0
  65. package/dist/store/local-store.js.map +1 -0
  66. package/dist/store/queue.d.ts +24 -0
  67. package/dist/store/queue.d.ts.map +1 -0
  68. package/dist/store/queue.js +105 -0
  69. package/dist/store/queue.js.map +1 -0
  70. package/dist/types.d.ts +264 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +4 -0
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/ci-detect.d.ts +6 -0
  75. package/dist/utils/ci-detect.d.ts.map +1 -0
  76. package/dist/utils/ci-detect.js +19 -0
  77. package/dist/utils/ci-detect.js.map +1 -0
  78. package/hooks/hooks.json +15 -0
  79. package/hooks/session-end.ts +71 -0
  80. package/hooks/tsconfig.json +13 -0
  81. package/package.json +43 -0
  82. package/skills/proficiency/SKILL.md +15 -0
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractSignals = extractSignals;
4
+ const transcript_parser_js_1 = require("../parsers/transcript-parser.js");
5
+ /**
6
+ * Extract all signals from parsed sessions + config.
7
+ */
8
+ function extractSignals(sessions, config) {
9
+ const allEvents = sessions.flatMap((s) => s.events);
10
+ return {
11
+ ccMastery: extractCCMasterySignals(allEvents, config),
12
+ toolMcp: extractToolMcpSignals(allEvents, config),
13
+ agentic: extractAgenticSignals(allEvents, sessions),
14
+ promptCraft: extractPromptCraftSignals(allEvents),
15
+ contextMgmt: extractContextMgmtSignals(sessions, config),
16
+ outcomes: extractOutcomeSignals(allEvents),
17
+ };
18
+ }
19
+ function extractCCMasterySignals(events, config) {
20
+ const toolCalls = events.filter((e) => e.kind === "tool_call");
21
+ // Check which plugins were actually used in transcripts
22
+ const toolNames = new Set(toolCalls.map((tc) => tc.toolName));
23
+ const pluginToolPrefixes = config.pluginNames.map((name) => {
24
+ const parts = name.split("@");
25
+ return parts[0];
26
+ });
27
+ let pluginsUsed = 0;
28
+ for (const prefix of pluginToolPrefixes) {
29
+ if ([...toolNames].some((t) => t.toLowerCase().includes(prefix.toLowerCase()))) {
30
+ pluginsUsed++;
31
+ }
32
+ }
33
+ // Unique skills
34
+ const skillCalls = toolCalls.filter((tc) => tc.toolName === "Skill");
35
+ const uniqueSkills = new Set(skillCalls.map((tc) => String(tc.input?.skill ?? "")));
36
+ // Plan mode
37
+ const userPrompts = events.filter((e) => e.kind === "user_prompt");
38
+ const usedPlanMode = userPrompts.some((p) => p.permissionMode === "plan");
39
+ return {
40
+ hasGlobalClaudeMd: config.hasGlobalClaudeMd,
41
+ globalClaudeMdHasImports: config.globalClaudeMdHasImports,
42
+ projectClaudeMdCount: config.projectClaudeMdCount,
43
+ hasCustomHooks: config.hasCustomHooks,
44
+ hookWithMatcherCount: config.hookWithMatcherCount,
45
+ pluginCount: config.pluginCount,
46
+ pluginsUsedInTranscripts: pluginsUsed,
47
+ uniqueSkillsUsed: uniqueSkills.size,
48
+ usedPlanMode,
49
+ hasRulesFiles: config.hasRulesFiles,
50
+ };
51
+ }
52
+ function extractToolMcpSignals(events, config) {
53
+ const toolCalls = events.filter((e) => e.kind === "tool_call");
54
+ const uniqueTools = new Set(toolCalls.map((tc) => tc.toolName));
55
+ // MCP servers — tools prefixed with mcp__
56
+ const mcpTools = toolCalls.filter((tc) => tc.toolName.startsWith("mcp__"));
57
+ const mcpServers = new Set(mcpTools.map((tc) => {
58
+ // mcp__serverName__toolName → serverName
59
+ const parts = tc.toolName.split("__");
60
+ return parts.length >= 2 ? parts[1] : tc.toolName;
61
+ }));
62
+ // LSP tool calls
63
+ const lspCalls = toolCalls.filter((tc) => tc.toolName === "LSP");
64
+ // Edit success rate: edits NOT followed by another edit within 2 tool calls
65
+ const editCalls = toolCalls.filter((tc) => tc.toolName === "Edit" || tc.toolName === "Write");
66
+ let successfulEdits = 0;
67
+ for (let i = 0; i < editCalls.length; i++) {
68
+ const editIdx = toolCalls.indexOf(editCalls[i]);
69
+ const next1 = toolCalls[editIdx + 1];
70
+ const next2 = toolCalls[editIdx + 2];
71
+ const isCorrectiveReEdit = (next1?.toolName === "Edit" || next1?.toolName === "Write") ||
72
+ (next2?.toolName === "Edit" && next1?.toolName === "Read");
73
+ if (!isCorrectiveReEdit) {
74
+ successfulEdits++;
75
+ }
76
+ }
77
+ return {
78
+ uniqueToolsUsed: uniqueTools.size,
79
+ uniqueMcpServersUsed: mcpServers.size,
80
+ lspToolCallCount: lspCalls.length,
81
+ deliberateWorkflowCount: (0, transcript_parser_js_1.countDeliberateWorkflows)(events),
82
+ editSuccessRate: editCalls.length > 0 ? successfulEdits / editCalls.length : 0.5, // neutral when no data
83
+ totalToolCalls: toolCalls.length,
84
+ };
85
+ }
86
+ function extractAgenticSignals(events, sessions) {
87
+ const toolCalls = events.filter((e) => e.kind === "tool_call");
88
+ // Subagents
89
+ const agentCalls = toolCalls.filter((tc) => tc.toolName === "Agent");
90
+ const subagentTypes = new Set(agentCalls.map((tc) => String(tc.input?.subagent_type ?? "general-purpose")));
91
+ // Worktree
92
+ const usedWorktree = toolCalls.some((tc) => tc.toolName === "EnterWorktree" || tc.toolName === "ExitWorktree");
93
+ // Task management
94
+ const usedTaskMgmt = toolCalls.some((tc) => tc.toolName === "TaskCreate" || tc.toolName === "TaskUpdate");
95
+ // Multi-session projects
96
+ const projectSessions = new Map();
97
+ for (const session of sessions) {
98
+ const existing = projectSessions.get(session.project) ?? new Set();
99
+ existing.add(session.sessionId);
100
+ projectSessions.set(session.project, existing);
101
+ }
102
+ const multiSessionProjects = [...projectSessions.values()].filter((s) => s.size > 1).length;
103
+ return {
104
+ uniqueSubagentTypes: subagentTypes.size,
105
+ totalSubagentCalls: agentCalls.length,
106
+ parallelToolCallCount: (0, transcript_parser_js_1.countParallelToolCalls)(events),
107
+ usedWorktree,
108
+ multiSessionProjectCount: multiSessionProjects,
109
+ usedTaskManagement: usedTaskMgmt,
110
+ };
111
+ }
112
+ function extractPromptCraftSignals(events) {
113
+ const userPrompts = events.filter((e) => e.kind === "user_prompt");
114
+ // Structured prompts (contain markdown indicators)
115
+ const structuredCount = userPrompts.filter((p) => {
116
+ const c = p.content;
117
+ return (c.includes("- ") ||
118
+ c.includes("* ") ||
119
+ c.includes("1. ") ||
120
+ c.includes("## ") ||
121
+ c.includes("```") ||
122
+ c.includes("| "));
123
+ }).length;
124
+ // Iterative refinement: consecutive prompts in same session that refine
125
+ // (not just any consecutive prompt — look for refinement patterns)
126
+ let refinementCount = 0;
127
+ for (let i = 1; i < userPrompts.length; i++) {
128
+ const prev = userPrompts[i - 1];
129
+ const curr = userPrompts[i];
130
+ if (curr.sessionId !== prev.sessionId)
131
+ continue;
132
+ // Refinement indicators: references to prior work, corrections, adjustments
133
+ const c = curr.content.toLowerCase();
134
+ const isRefinement = c.includes("instead") ||
135
+ c.includes("actually") ||
136
+ c.includes("change") ||
137
+ c.includes("also") ||
138
+ c.includes("but ") ||
139
+ c.includes("wait") ||
140
+ c.includes("no,") ||
141
+ c.includes("not that") ||
142
+ c.includes("update") ||
143
+ c.includes("fix") ||
144
+ c.includes("modify");
145
+ if (isRefinement)
146
+ refinementCount++;
147
+ }
148
+ // Unique commands (from prompt content starting with /)
149
+ const commands = new Set();
150
+ for (const p of userPrompts) {
151
+ if (p.content.startsWith("/")) {
152
+ const cmd = p.content.split(" ")[0];
153
+ commands.add(cmd);
154
+ }
155
+ }
156
+ // Context provision: prompts with code blocks, file references, or error traces
157
+ // (not just long prompts — look for actual context signals)
158
+ const contextCount = userPrompts.filter((p) => {
159
+ const c = p.content;
160
+ const hasCodeBlock = c.includes("```");
161
+ const hasFilePath = /[\w/\\]+\.\w{1,4}/.test(c) && (c.includes("/") || c.includes("\\"));
162
+ const hasErrorTrace = c.includes("Error:") || c.includes("error:") || c.includes("at ") && c.includes("(");
163
+ // Require at least one concrete context signal, not just length
164
+ return hasCodeBlock || hasFilePath || hasErrorTrace;
165
+ }).length;
166
+ return {
167
+ structuredPromptRatio: userPrompts.length > 0 ? structuredCount / userPrompts.length : 0,
168
+ iterativeRefinementCount: refinementCount,
169
+ uniqueCommandsUsed: commands.size,
170
+ contextProvisionCount: contextCount,
171
+ totalPrompts: userPrompts.length,
172
+ };
173
+ }
174
+ function extractContextMgmtSignals(sessions, config) {
175
+ const projects = new Set(sessions.map((s) => s.project));
176
+ // Session durations in minutes
177
+ const durations = sessions
178
+ .map((s) => {
179
+ const start = new Date(s.startTime).getTime();
180
+ const end = new Date(s.endTime).getTime();
181
+ if (isNaN(start) || isNaN(end))
182
+ return 0;
183
+ return (end - start) / 60000;
184
+ })
185
+ .filter((d) => d > 0);
186
+ return {
187
+ memoryFileCount: config.memoryFileCount,
188
+ activeMemoryFiles: config.activeMemoryFileCount,
189
+ projectCount: projects.size,
190
+ sessionCount: sessions.length,
191
+ sessionDurations: durations,
192
+ };
193
+ }
194
+ function extractOutcomeSignals(events) {
195
+ const toolCalls = events.filter((e) => e.kind === "tool_call");
196
+ const toolResults = events.filter((e) => e.kind === "tool_result");
197
+ // Edit acceptance rate
198
+ const editCalls = toolCalls.filter((tc) => tc.toolName === "Edit" || tc.toolName === "Write");
199
+ let cleanEdits = 0;
200
+ for (let i = 0; i < editCalls.length; i++) {
201
+ const editIdx = toolCalls.indexOf(editCalls[i]);
202
+ const next = toolCalls[editIdx + 1];
203
+ if (!next || (next.toolName !== "Edit" && next.toolName !== "Write")) {
204
+ cleanEdits++;
205
+ }
206
+ }
207
+ const editAcceptanceRate = editCalls.length > 0 ? cleanEdits / editCalls.length : 0.5; // neutral when no data
208
+ // Error recovery: errors followed by non-error results
209
+ const errors = toolResults.filter((r) => r.kind === "tool_result" && r.isError);
210
+ let recoveries = 0;
211
+ for (const err of errors) {
212
+ const errIdx = events.indexOf(err);
213
+ // Look ahead for successful operations
214
+ for (let j = errIdx + 1; j < Math.min(errIdx + 5, events.length); j++) {
215
+ if (events[j]?.kind === "tool_result" && !events[j].isError) {
216
+ recoveries++;
217
+ break;
218
+ }
219
+ }
220
+ }
221
+ const errorRecoveryRate = errors.length > 0 ? recoveries / errors.length : 0.5; // neutral when no data
222
+ // Permission mode progression
223
+ const userPrompts = events.filter((e) => e.kind === "user_prompt");
224
+ const modes = userPrompts
225
+ .map((p) => p.permissionMode)
226
+ .filter(Boolean);
227
+ let progression = 0;
228
+ if (modes.length > 1) {
229
+ const hasBypass = modes.includes("bypassPermissions");
230
+ const hasDefault = modes.some((m) => m !== "bypassPermissions" && m !== "plan");
231
+ if (hasBypass && hasDefault)
232
+ progression = 0.5; // mixed usage
233
+ if (hasBypass && !hasDefault)
234
+ progression = -0.5; // always bypass
235
+ if (!hasBypass)
236
+ progression = 1; // responsible defaults
237
+ }
238
+ return {
239
+ editAcceptanceRate,
240
+ permissionModeProgression: progression,
241
+ errorRecoveryRate,
242
+ repeatFailureRate: 0, // TODO: implement pattern detection
243
+ };
244
+ }
245
+ //# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../../src/scoring/signals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { LocalStore, SessionSnapshot, CCProficiencyConfig } from "../types.js";
2
+ export declare function loadStore(): LocalStore;
3
+ export declare function saveStore(store: LocalStore): void;
4
+ export declare function isSessionProcessed(store: LocalStore, sessionId: string): boolean;
5
+ export declare function addSnapshot(store: LocalStore, snapshot: SessionSnapshot): void;
6
+ export declare function loadConfig(): CCProficiencyConfig;
7
+ export declare function saveConfig(config: CCProficiencyConfig): void;
8
+ export declare function saveBadge(svg: string): string;
9
+ export declare function getBadgePath(): string;
10
+ export declare function logError(message: string): void;
11
+ export declare function getStoreDir(): string;
12
+ //# sourceMappingURL=local-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-store.d.ts","sourceRoot":"","sources":["../../src/store/local-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAqB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAoBvG,wBAAgB,SAAS,IAAI,UAAU,CAStC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAcjD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAG9E;AAED,wBAAgB,UAAU,IAAI,mBAAmB,CAUhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAG5D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAe9C;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadStore = loadStore;
4
+ exports.saveStore = saveStore;
5
+ exports.isSessionProcessed = isSessionProcessed;
6
+ exports.addSnapshot = addSnapshot;
7
+ exports.loadConfig = loadConfig;
8
+ exports.saveConfig = saveConfig;
9
+ exports.saveBadge = saveBadge;
10
+ exports.getBadgePath = getBadgePath;
11
+ exports.logError = logError;
12
+ exports.getStoreDir = getStoreDir;
13
+ const node_fs_1 = require("node:fs");
14
+ const node_path_1 = require("node:path");
15
+ const node_os_1 = require("node:os");
16
+ const queue_js_1 = require("./queue.js");
17
+ const STORE_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".cc-proficiency");
18
+ const STORE_FILE = (0, node_path_1.join)(STORE_DIR, "store.json");
19
+ const CONFIG_FILE = (0, node_path_1.join)(STORE_DIR, "config.json");
20
+ const BADGE_FILE = (0, node_path_1.join)(STORE_DIR, "cc-proficiency.svg");
21
+ const ERROR_LOG = (0, node_path_1.join)(STORE_DIR, "error.log");
22
+ const MAX_ERROR_LOG_SIZE = 1_000_000; // 1MB
23
+ const RETENTION_DAYS = 90;
24
+ function emptyStore() {
25
+ return {
26
+ processedSessionIds: [],
27
+ snapshots: [],
28
+ lastResult: undefined,
29
+ lastUpdated: undefined,
30
+ };
31
+ }
32
+ function loadStore() {
33
+ (0, queue_js_1.ensureStoreDir)();
34
+ if (!(0, node_fs_1.existsSync)(STORE_FILE))
35
+ return emptyStore();
36
+ try {
37
+ return JSON.parse((0, node_fs_1.readFileSync)(STORE_FILE, "utf-8"));
38
+ }
39
+ catch {
40
+ return emptyStore();
41
+ }
42
+ }
43
+ function saveStore(store) {
44
+ (0, queue_js_1.ensureStoreDir)();
45
+ store.lastUpdated = new Date().toISOString();
46
+ // Prune old snapshots (>90 days)
47
+ const cutoff = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1000;
48
+ store.snapshots = store.snapshots.filter((s) => {
49
+ const ts = new Date(s.timestamp).getTime();
50
+ return !isNaN(ts) && ts > cutoff;
51
+ });
52
+ const tmpFile = (0, node_path_1.join)(STORE_DIR, ".store.json.tmp");
53
+ (0, node_fs_1.writeFileSync)(tmpFile, JSON.stringify(store, null, 2), "utf-8");
54
+ (0, node_fs_1.renameSync)(tmpFile, STORE_FILE);
55
+ }
56
+ function isSessionProcessed(store, sessionId) {
57
+ return store.processedSessionIds.includes(sessionId);
58
+ }
59
+ function addSnapshot(store, snapshot) {
60
+ store.processedSessionIds.push(snapshot.sessionId);
61
+ store.snapshots.push(snapshot);
62
+ }
63
+ function loadConfig() {
64
+ (0, queue_js_1.ensureStoreDir)();
65
+ if (!(0, node_fs_1.existsSync)(CONFIG_FILE)) {
66
+ return { autoUpload: true, public: false };
67
+ }
68
+ try {
69
+ return JSON.parse((0, node_fs_1.readFileSync)(CONFIG_FILE, "utf-8"));
70
+ }
71
+ catch {
72
+ return { autoUpload: true, public: false };
73
+ }
74
+ }
75
+ function saveConfig(config) {
76
+ (0, queue_js_1.ensureStoreDir)();
77
+ (0, node_fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
78
+ }
79
+ function saveBadge(svg) {
80
+ (0, queue_js_1.ensureStoreDir)();
81
+ (0, node_fs_1.writeFileSync)(BADGE_FILE, svg, "utf-8");
82
+ return BADGE_FILE;
83
+ }
84
+ function getBadgePath() {
85
+ return BADGE_FILE;
86
+ }
87
+ function logError(message) {
88
+ (0, queue_js_1.ensureStoreDir)();
89
+ try {
90
+ // Check size and rotate if needed
91
+ if ((0, node_fs_1.existsSync)(ERROR_LOG)) {
92
+ const stat = (0, node_fs_1.statSync)(ERROR_LOG);
93
+ if (stat.size > MAX_ERROR_LOG_SIZE) {
94
+ (0, node_fs_1.writeFileSync)(ERROR_LOG, "", "utf-8"); // truncate
95
+ }
96
+ }
97
+ const timestamp = new Date().toISOString();
98
+ (0, node_fs_1.appendFileSync)(ERROR_LOG, `[${timestamp}] ${message}\n`, "utf-8");
99
+ }
100
+ catch {
101
+ // can't log — silently fail
102
+ }
103
+ }
104
+ function getStoreDir() {
105
+ return STORE_DIR;
106
+ }
107
+ //# sourceMappingURL=local-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-store.js","sourceRoot":"","sources":["../../src/store/local-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { QueueEntry } from "../types.js";
2
+ export declare function ensureStoreDir(): void;
3
+ /**
4
+ * Append a queue entry (called by the hook, must be fast).
5
+ */
6
+ export declare function enqueue(entry: QueueEntry): void;
7
+ /**
8
+ * Read all queue entries.
9
+ */
10
+ export declare function readQueue(): QueueEntry[];
11
+ /**
12
+ * Atomically replace queue with remaining entries.
13
+ * Re-reads queue to merge any entries appended during processing (race-safe).
14
+ */
15
+ export declare function writeQueue(processedIds: Set<string>): void;
16
+ /**
17
+ * Acquire queue lock. Returns true if acquired, false if held by another process.
18
+ */
19
+ export declare function acquireLock(): boolean;
20
+ /**
21
+ * Release queue lock.
22
+ */
23
+ export declare function releaseLock(): void;
24
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/store/queue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,wBAAgB,cAAc,IAAI,IAAI,CAIrC;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAG/C;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,UAAU,EAAE,CAcxC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAS1D;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAyBrC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAMlC"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureStoreDir = ensureStoreDir;
4
+ exports.enqueue = enqueue;
5
+ exports.readQueue = readQueue;
6
+ exports.writeQueue = writeQueue;
7
+ exports.acquireLock = acquireLock;
8
+ exports.releaseLock = releaseLock;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const node_os_1 = require("node:os");
12
+ const STORE_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".cc-proficiency");
13
+ const QUEUE_FILE = (0, node_path_1.join)(STORE_DIR, "queue.jsonl");
14
+ const QUEUE_LOCK = (0, node_path_1.join)(STORE_DIR, "queue.lock");
15
+ const LOCK_STALE_MS = 60_000; // 60 seconds
16
+ function ensureStoreDir() {
17
+ if (!(0, node_fs_1.existsSync)(STORE_DIR)) {
18
+ (0, node_fs_1.mkdirSync)(STORE_DIR, { recursive: true });
19
+ }
20
+ }
21
+ /**
22
+ * Append a queue entry (called by the hook, must be fast).
23
+ */
24
+ function enqueue(entry) {
25
+ ensureStoreDir();
26
+ (0, node_fs_1.appendFileSync)(QUEUE_FILE, JSON.stringify(entry) + "\n", "utf-8");
27
+ }
28
+ /**
29
+ * Read all queue entries.
30
+ */
31
+ function readQueue() {
32
+ if (!(0, node_fs_1.existsSync)(QUEUE_FILE))
33
+ return [];
34
+ const entries = [];
35
+ const content = (0, node_fs_1.readFileSync)(QUEUE_FILE, "utf-8");
36
+ for (const line of content.split("\n")) {
37
+ if (!line.trim())
38
+ continue;
39
+ try {
40
+ entries.push(JSON.parse(line));
41
+ }
42
+ catch {
43
+ // skip malformed
44
+ }
45
+ }
46
+ return entries;
47
+ }
48
+ /**
49
+ * Atomically replace queue with remaining entries.
50
+ * Re-reads queue to merge any entries appended during processing (race-safe).
51
+ */
52
+ function writeQueue(processedIds) {
53
+ ensureStoreDir();
54
+ // Re-read to catch entries appended since we started processing
55
+ const current = readQueue();
56
+ const remaining = current.filter((e) => !processedIds.has(e.sessionId));
57
+ const tmpFile = (0, node_path_1.join)(STORE_DIR, ".queue.jsonl.tmp");
58
+ const content = remaining.map((e) => JSON.stringify(e)).join("\n") + (remaining.length > 0 ? "\n" : "");
59
+ (0, node_fs_1.writeFileSync)(tmpFile, content, "utf-8");
60
+ (0, node_fs_1.renameSync)(tmpFile, QUEUE_FILE);
61
+ }
62
+ /**
63
+ * Acquire queue lock. Returns true if acquired, false if held by another process.
64
+ */
65
+ function acquireLock() {
66
+ ensureStoreDir();
67
+ if ((0, node_fs_1.existsSync)(QUEUE_LOCK)) {
68
+ // Check if stale
69
+ try {
70
+ const lockContent = (0, node_fs_1.readFileSync)(QUEUE_LOCK, "utf-8");
71
+ const lockTime = parseInt(lockContent, 10);
72
+ if (Date.now() - lockTime < LOCK_STALE_MS) {
73
+ return false; // lock is fresh, another process is running
74
+ }
75
+ // Stale lock — break it
76
+ (0, node_fs_1.unlinkSync)(QUEUE_LOCK);
77
+ }
78
+ catch {
79
+ // Can't read lock — try to acquire anyway
80
+ try {
81
+ (0, node_fs_1.unlinkSync)(QUEUE_LOCK);
82
+ }
83
+ catch { /* ignore */ }
84
+ }
85
+ }
86
+ try {
87
+ (0, node_fs_1.writeFileSync)(QUEUE_LOCK, String(Date.now()), { flag: "wx" }); // O_EXCL
88
+ return true;
89
+ }
90
+ catch {
91
+ return false; // another process beat us
92
+ }
93
+ }
94
+ /**
95
+ * Release queue lock.
96
+ */
97
+ function releaseLock() {
98
+ try {
99
+ (0, node_fs_1.unlinkSync)(QUEUE_LOCK);
100
+ }
101
+ catch {
102
+ // already released
103
+ }
104
+ }
105
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/store/queue.ts"],"names":[],"mappings":"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"}