@tekdi/coding-analytics 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.
Files changed (49) hide show
  1. package/dist/batcher.d.ts +15 -0
  2. package/dist/batcher.d.ts.map +1 -0
  3. package/dist/batcher.js +90 -0
  4. package/dist/batcher.js.map +1 -0
  5. package/dist/claude-hooks-receiver.d.ts +16 -0
  6. package/dist/claude-hooks-receiver.d.ts.map +1 -0
  7. package/dist/claude-hooks-receiver.js +145 -0
  8. package/dist/claude-hooks-receiver.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +314 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/config.d.ts +50 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +119 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/enricher.d.ts +28 -0
  18. package/dist/enricher.d.ts.map +1 -0
  19. package/dist/enricher.js +258 -0
  20. package/dist/enricher.js.map +1 -0
  21. package/dist/flusher.d.ts +10 -0
  22. package/dist/flusher.d.ts.map +1 -0
  23. package/dist/flusher.js +89 -0
  24. package/dist/flusher.js.map +1 -0
  25. package/dist/health-monitor.d.ts +35 -0
  26. package/dist/health-monitor.d.ts.map +1 -0
  27. package/dist/health-monitor.js +187 -0
  28. package/dist/health-monitor.js.map +1 -0
  29. package/dist/hooks-listener.d.ts +23 -0
  30. package/dist/hooks-listener.d.ts.map +1 -0
  31. package/dist/hooks-listener.js +168 -0
  32. package/dist/hooks-listener.js.map +1 -0
  33. package/dist/install-service.d.ts +15 -0
  34. package/dist/install-service.d.ts.map +1 -0
  35. package/dist/install-service.js +218 -0
  36. package/dist/install-service.js.map +1 -0
  37. package/dist/local-storage.d.ts +19 -0
  38. package/dist/local-storage.d.ts.map +1 -0
  39. package/dist/local-storage.js +152 -0
  40. package/dist/local-storage.js.map +1 -0
  41. package/dist/logger.d.ts +3 -0
  42. package/dist/logger.d.ts.map +1 -0
  43. package/dist/logger.js +59 -0
  44. package/dist/logger.js.map +1 -0
  45. package/dist/queue.d.ts +22 -0
  46. package/dist/queue.d.ts.map +1 -0
  47. package/dist/queue.js +102 -0
  48. package/dist/queue.js.map +1 -0
  49. package/package.json +49 -0
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HealthMonitor = void 0;
37
+ const config_1 = require("./config");
38
+ const local_storage_1 = require("./local-storage");
39
+ const install_service_1 = require("./install-service");
40
+ const queue_1 = require("./queue");
41
+ const posthog_node_1 = require("posthog-node");
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const os = __importStar(require("os"));
45
+ const child_process_1 = require("child_process");
46
+ class HealthMonitor {
47
+ constructor() {
48
+ this.config = config_1.Config.load();
49
+ }
50
+ async check() {
51
+ const [posthog, localStorage, lastEvent] = await Promise.all([
52
+ this.testPostHog(),
53
+ this.checkLocalStorage(),
54
+ this.getLastEventTime(),
55
+ ]);
56
+ const cursorHooks = this.checkCursorHooksInstalled();
57
+ const claudeHooks = this.checkClaudeHooksInstalled();
58
+ const cron = install_service_1.InstallService.isCronInstalled();
59
+ const queueSize = new queue_1.Queue().pendingCount();
60
+ const authIds = this.resolveAuthIds();
61
+ const hooksInstalled = cursorHooks || claudeHooks;
62
+ const allHealthy = posthog && localStorage && hooksInstalled && cron;
63
+ const anyHealthy = posthog || localStorage;
64
+ return {
65
+ status: allHealthy ? 'healthy' : anyHealthy ? 'degraded' : 'unhealthy',
66
+ checks: { posthog, localStorage, cursorHooks, claudeHooks, cron, queueSize, lastEvent, authIds },
67
+ };
68
+ }
69
+ async testPostHog() {
70
+ if (!this.config.posthog.apiKey)
71
+ return false;
72
+ try {
73
+ const client = new posthog_node_1.PostHog(this.config.posthog.apiKey, { host: this.config.posthog.host });
74
+ client.capture({ distinctId: 'health-check', event: 'coding_analytics_health_check' });
75
+ await client.flush();
76
+ await client.shutdown();
77
+ return true;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ async checkLocalStorage() {
84
+ try {
85
+ const storage = new local_storage_1.LocalStorage(this.config);
86
+ await storage.getCount();
87
+ return true;
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ checkCursorHooksInstalled() {
94
+ const hooksPath = path.join(os.homedir(), '.cursor', 'hooks.json');
95
+ if (!fs.existsSync(hooksPath))
96
+ return false;
97
+ try {
98
+ const hooks = JSON.parse(fs.readFileSync(hooksPath, 'utf-8'));
99
+ return !!(hooks.hooks?.onChatStart || hooks.hooks?.onChatMessage);
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ checkClaudeHooksInstalled() {
106
+ const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
107
+ if (!fs.existsSync(settingsPath))
108
+ return false;
109
+ try {
110
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
111
+ return !!(settings.hooks?.UserPromptSubmit || settings.hooks?.PostToolUse);
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ }
117
+ async getLastEventTime() {
118
+ try {
119
+ const storage = new local_storage_1.LocalStorage(this.config);
120
+ const events = await storage.getRecent(1);
121
+ return events.length > 0 ? events[0].timestamp : null;
122
+ }
123
+ catch {
124
+ return null;
125
+ }
126
+ }
127
+ // ── Auth ID resolution ───────────────────────────────────────────────────────
128
+ resolveAuthIds() {
129
+ return {
130
+ claude: this.readClaudeId(),
131
+ cursor: this.readCursorId(),
132
+ };
133
+ }
134
+ readClaudeId() {
135
+ try {
136
+ const data = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.claude.json'), 'utf-8'));
137
+ const uuid = data?.oauthAccount?.accountUuid;
138
+ return uuid ? this.maskUuid(uuid) : null;
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ readCursorId() {
145
+ try {
146
+ const dbPath = this.getCursorDbPath();
147
+ if (!dbPath)
148
+ return null;
149
+ const email = (0, child_process_1.execSync)(`sqlite3 "${dbPath}" "SELECT value FROM ItemTable WHERE key='cursorAuth/cachedEmail';"`, { timeout: 3000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
150
+ return email ? this.maskEmail(email) : null;
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ getCursorDbPath() {
157
+ const home = os.homedir();
158
+ const candidates = [];
159
+ switch (os.platform()) {
160
+ case 'darwin':
161
+ candidates.push(path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'state.vscdb'), path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
162
+ break;
163
+ case 'linux':
164
+ candidates.push(path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
165
+ break;
166
+ case 'win32':
167
+ candidates.push(path.join(process.env.APPDATA ?? '', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
168
+ break;
169
+ }
170
+ return candidates.find(p => fs.existsSync(p)) ?? null;
171
+ }
172
+ // ── Masking helpers ──────────────────────────────────────────────────────────
173
+ maskUuid(uuid) {
174
+ // 44c72054-2bc0-4325-ae54-a9743dc0d9bb → 44c72054-****-****-****-a9743dc0d9bb
175
+ return uuid.replace(/^([0-9a-f]{8})-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-([0-9a-f]{12})$/i, '$1-****-****-****-$2');
176
+ }
177
+ maskEmail(email) {
178
+ // ashwin@tekditechnologies.com → a*****@tekditechnologies.com
179
+ const [local, domain] = email.split('@');
180
+ if (!domain)
181
+ return '***';
182
+ const visible = local[0] ?? '*';
183
+ return `${visible}${'*'.repeat(Math.min(local.length - 1, 5))}@${domain}`;
184
+ }
185
+ }
186
+ exports.HealthMonitor = HealthMonitor;
187
+ //# sourceMappingURL=health-monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-monitor.js","sourceRoot":"","sources":["../health-monitor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAkC;AAClC,mDAA+C;AAC/C,uDAAmD;AACnD,mCAAgC;AAChC,+CAAuC;AACvC,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,iDAAyC;AAqBzC,MAAa,aAAa;IAGxB;QACE,IAAI,CAAC,MAAM,GAAG,eAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC3D,IAAI,CAAC,WAAW,EAAE;YAClB,IAAI,CAAC,iBAAiB,EAAE;YACxB,IAAI,CAAC,gBAAgB,EAAE;SACxB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,gCAAc,CAAC,eAAe,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,IAAI,aAAK,EAAE,CAAC,YAAY,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtC,MAAM,cAAc,GAAG,WAAW,IAAI,WAAW,CAAC;QAClD,MAAM,UAAU,GAAG,OAAO,IAAI,YAAY,IAAI,cAAc,IAAI,IAAI,CAAC;QACrE,MAAM,UAAU,GAAG,OAAO,IAAI,YAAY,CAAC;QAE3C,OAAO;YACL,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW;YACtE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE;SACjG,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,sBAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3F,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC;YACvF,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB;QAC7B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,4BAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,yBAAyB;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,IAAI,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,yBAAyB;QAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QACzE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;YACpE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,IAAI,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC7E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,gBAAgB;QAC5B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,4BAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1C,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,gFAAgF;IAExE,cAAc;QACpB,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE;YAC3B,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE;SAC5B,CAAC;IACJ,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YAC3F,MAAM,IAAI,GAAuB,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC;YACjE,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,KAAK,GAAG,IAAA,wBAAQ,EACpB,YAAY,MAAM,qEAAqE,EACvF,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CACvD,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,eAAe;QACrB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YACtB,KAAK,QAAQ;gBACX,UAAU,CAAC,IAAI,CACb,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,EACnG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,CAC7E,CAAC;gBACF,MAAM;YACR,KAAK,OAAO;gBACV,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC;gBAC9F,MAAM;YACR,KAAK,OAAO;gBACV,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC;gBACxG,MAAM;QACV,CAAC;QAED,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACxD,CAAC;IAED,gFAAgF;IAExE,QAAQ,CAAC,IAAY;QAC3B,8EAA8E;QAC9E,OAAO,IAAI,CAAC,OAAO,CACjB,qEAAqE,EACrE,sBAAsB,CACvB,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,KAAa;QAC7B,8DAA8D;QAC9D,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAChC,OAAO,GAAG,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;IAC5E,CAAC;CACF;AA7JD,sCA6JC"}
@@ -0,0 +1,23 @@
1
+ export interface HookEvent {
2
+ type: string;
3
+ data: any;
4
+ timestamp: string;
5
+ provider?: 'cursor' | 'claude';
6
+ }
7
+ export declare class HooksListener {
8
+ private enricher;
9
+ private batcher;
10
+ private config;
11
+ constructor();
12
+ private getEnricher;
13
+ private getBatcher;
14
+ shutdown(): Promise<void>;
15
+ /** Fast path: map → filter → queue. Exits in <5ms. No network, no git. */
16
+ queueEvent(eventType: string, eventData: any): Promise<void>;
17
+ handleEvent(eventType: string, eventData: any): Promise<void>;
18
+ private mapEvent;
19
+ private applyPrivacyFilters;
20
+ private redactSecrets;
21
+ private estimateTokens;
22
+ }
23
+ //# sourceMappingURL=hooks-listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-listener.d.ts","sourceRoot":"","sources":["../hooks-listener.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAChC;AAED,qBAAa,aAAa;IAExB,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAS;;IAMvB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,UAAU;IAKZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,0EAA0E;IACpE,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnE,OAAO,CAAC,QAAQ;IAgFhB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,cAAc;CAIvB"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HooksListener = void 0;
4
+ const enricher_1 = require("./enricher");
5
+ const batcher_1 = require("./batcher");
6
+ const config_1 = require("./config");
7
+ const logger_1 = require("./logger");
8
+ const queue_1 = require("./queue");
9
+ class HooksListener {
10
+ constructor() {
11
+ // Lazy — only created if handleEvent (direct send) is used
12
+ this.enricher = null;
13
+ this.batcher = null;
14
+ this.config = config_1.Config.load();
15
+ }
16
+ getEnricher() {
17
+ if (!this.enricher)
18
+ this.enricher = new enricher_1.Enricher(this.config);
19
+ return this.enricher;
20
+ }
21
+ getBatcher() {
22
+ if (!this.batcher)
23
+ this.batcher = new batcher_1.EventBatcher(this.config);
24
+ return this.batcher;
25
+ }
26
+ async shutdown() {
27
+ if (this.batcher)
28
+ await this.batcher.shutdown();
29
+ }
30
+ /** Fast path: map → filter → queue. Exits in <5ms. No network, no git. */
31
+ async queueEvent(eventType, eventData) {
32
+ const event = this.mapEvent(eventType, eventData);
33
+ if (!event) {
34
+ logger_1.logger.warn('Unknown Cursor event type', { eventType });
35
+ return;
36
+ }
37
+ new queue_1.Queue().append(this.applyPrivacyFilters(event));
38
+ logger_1.logger.debug('Cursor event queued', { eventType });
39
+ }
40
+ async handleEvent(eventType, eventData) {
41
+ try {
42
+ logger_1.logger.debug('Received hook event', { eventType, eventData });
43
+ // Map Cursor hook types to our event types
44
+ const event = this.mapEvent(eventType, eventData);
45
+ if (!event) {
46
+ logger_1.logger.warn('Unknown event type', { eventType });
47
+ return;
48
+ }
49
+ // Apply privacy filters before enriching
50
+ const filteredEvent = this.applyPrivacyFilters(event);
51
+ // Enrich with context
52
+ const enrichedEvent = await this.getEnricher().enrich(filteredEvent);
53
+ // Send to batcher
54
+ await this.getBatcher().add(enrichedEvent);
55
+ logger_1.logger.debug('Event processed', { event: enrichedEvent.event });
56
+ }
57
+ catch (error) {
58
+ logger_1.logger.error('Failed to handle event', { error, eventType });
59
+ }
60
+ }
61
+ mapEvent(hookType, data) {
62
+ const timestamp = new Date().toISOString();
63
+ switch (hookType) {
64
+ case 'chat-start':
65
+ case 'onChatStart':
66
+ return {
67
+ type: 'cursor_chat_started',
68
+ data: {
69
+ chat_id: data.chatId || data.id,
70
+ workspace_path: data.workspacePath,
71
+ },
72
+ timestamp,
73
+ };
74
+ case 'chat-message':
75
+ case 'onChatMessage':
76
+ return {
77
+ type: data.role === 'user' ? 'cursor_message_sent' : 'cursor_message_received',
78
+ data: {
79
+ chat_id: data.chatId,
80
+ message_id: data.messageId || data.id,
81
+ content: this.config.capture.prompts || this.config.capture.responses
82
+ ? data.content
83
+ : '[redacted]',
84
+ role: data.role,
85
+ token_count: data.tokenCount || this.estimateTokens(data.content),
86
+ },
87
+ timestamp: data.timestamp || timestamp,
88
+ };
89
+ case 'code-edit':
90
+ case 'onCodeEdit':
91
+ return {
92
+ type: 'cursor_code_edited',
93
+ data: {
94
+ chat_id: data.chatId,
95
+ files: this.config.capture.filePaths ? data.files : data.files?.map((f) => ({
96
+ lines_added: f.linesAdded,
97
+ lines_removed: f.linesRemoved,
98
+ type: f.type,
99
+ })),
100
+ total_lines_added: data.files?.reduce((sum, f) => sum + (f.linesAdded || 0), 0),
101
+ total_lines_removed: data.files?.reduce((sum, f) => sum + (f.linesRemoved || 0), 0),
102
+ },
103
+ timestamp: data.timestamp || timestamp,
104
+ };
105
+ case 'chat-end':
106
+ case 'onChatEnd':
107
+ return {
108
+ type: 'cursor_chat_ended',
109
+ data: {
110
+ chat_id: data.chatId,
111
+ duration: data.duration,
112
+ total_messages: data.totalMessages,
113
+ total_tokens: data.totalTokens,
114
+ },
115
+ timestamp: data.timestamp || timestamp,
116
+ };
117
+ case 'agent-think':
118
+ case 'onAgentThink':
119
+ if (!this.config.capture.agentThinking) {
120
+ return null;
121
+ }
122
+ return {
123
+ type: 'cursor_agent_thinking',
124
+ data: {
125
+ chat_id: data.chatId,
126
+ thinking: data.thinking,
127
+ },
128
+ timestamp: data.timestamp || timestamp,
129
+ };
130
+ default:
131
+ return null;
132
+ }
133
+ }
134
+ applyPrivacyFilters(event) {
135
+ if (!this.config.privacy.redactSecrets) {
136
+ return event;
137
+ }
138
+ // Redact secrets from content
139
+ if (event.data.content) {
140
+ event.data.content = this.redactSecrets(event.data.content);
141
+ }
142
+ if (event.data.thinking) {
143
+ event.data.thinking = this.redactSecrets(event.data.thinking);
144
+ }
145
+ return event;
146
+ }
147
+ redactSecrets(text) {
148
+ // API keys
149
+ text = text.replace(/api[_-]?key[s]?['"]?\s*[:=]\s*['"]?([A-Za-z0-9_-]{20,})/gi, 'api_key=[REDACTED]');
150
+ // Bearer tokens
151
+ text = text.replace(/Bearer\s+([A-Za-z0-9_-]{20,})/gi, 'Bearer [REDACTED]');
152
+ // JWT tokens
153
+ text = text.replace(/eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[JWT_REDACTED]');
154
+ // Passwords
155
+ text = text.replace(/password['"]?\s*[:=]\s*['"]?([^\s'"]+)/gi, 'password=[REDACTED]');
156
+ // Connection strings
157
+ text = text.replace(/(postgres|mysql|mongodb):\/\/[^@]+@/g, '$1://[USER]:[PASSWORD]@');
158
+ // AWS keys
159
+ text = text.replace(/AKIA[0-9A-Z]{16}/g, '[AWS_KEY_REDACTED]');
160
+ return text;
161
+ }
162
+ estimateTokens(text) {
163
+ // Rough estimate: ~4 characters per token
164
+ return Math.ceil(text.length / 4);
165
+ }
166
+ }
167
+ exports.HooksListener = HooksListener;
168
+ //# sourceMappingURL=hooks-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-listener.js","sourceRoot":"","sources":["../hooks-listener.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export declare class InstallService {
2
+ private cursorHooksDir;
3
+ private cursorHooksPath;
4
+ private claudeSettingsPath;
5
+ constructor();
6
+ installHooks(): Promise<void>;
7
+ uninstallHooks(): Promise<void>;
8
+ installClaudeHooks(): Promise<void>;
9
+ uninstallClaudeHooks(): Promise<void>;
10
+ static readonly CRON_MARKER = "# coding-analytics-flush";
11
+ static installCron(): void;
12
+ static uninstallCron(): void;
13
+ static isCronInstalled(): boolean;
14
+ }
15
+ //# sourceMappingURL=install-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-service.d.ts","sourceRoot":"","sources":["../install-service.ts"],"names":[],"mappings":"AAoCA,qBAAa,cAAc;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAAS;;IAU7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB7B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCnC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3C,MAAM,CAAC,QAAQ,CAAC,WAAW,8BAA8B;IAEzD,MAAM,CAAC,WAAW,IAAI,IAAI;IAqB1B,MAAM,CAAC,aAAa,IAAI,IAAI;IAmB5B,MAAM,CAAC,eAAe,IAAI,OAAO;CASlC"}
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.InstallService = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ const child_process_1 = require("child_process");
41
+ const config_1 = require("./config");
42
+ const CURSOR_HOOKS_CONFIG = {
43
+ hooks: {
44
+ onChatStart: {
45
+ command: 'coding-analytics',
46
+ args: ['hook', 'chat-start', '--data', '$EVENT_DATA'],
47
+ },
48
+ onChatMessage: {
49
+ command: 'coding-analytics',
50
+ args: ['hook', 'chat-message', '--data', '$EVENT_DATA'],
51
+ },
52
+ onCodeEdit: {
53
+ command: 'coding-analytics',
54
+ args: ['hook', 'code-edit', '--data', '$EVENT_DATA'],
55
+ },
56
+ onChatEnd: {
57
+ command: 'coding-analytics',
58
+ args: ['hook', 'chat-end', '--data', '$EVENT_DATA'],
59
+ },
60
+ },
61
+ };
62
+ const CLAUDE_HOOK_TYPES = [
63
+ 'SessionStart',
64
+ 'UserPromptSubmit',
65
+ 'PostToolUse',
66
+ 'SubagentStart',
67
+ 'SubagentStop',
68
+ 'Stop',
69
+ ];
70
+ class InstallService {
71
+ constructor() {
72
+ this.cursorHooksDir = path.join(os.homedir(), '.cursor');
73
+ this.cursorHooksPath = path.join(this.cursorHooksDir, 'hooks.json');
74
+ this.claudeSettingsPath = path.join(os.homedir(), '.claude', 'settings.json');
75
+ }
76
+ // ── Cursor ──────────────────────────────────────────────────────────────────
77
+ async installHooks() {
78
+ if (!fs.existsSync(this.cursorHooksDir)) {
79
+ fs.mkdirSync(this.cursorHooksDir, { recursive: true });
80
+ }
81
+ let existing = {};
82
+ if (fs.existsSync(this.cursorHooksPath)) {
83
+ try {
84
+ existing = JSON.parse(fs.readFileSync(this.cursorHooksPath, 'utf-8'));
85
+ }
86
+ catch {
87
+ // ignore malformed existing config
88
+ }
89
+ }
90
+ const merged = { ...existing, ...CURSOR_HOOKS_CONFIG };
91
+ fs.writeFileSync(this.cursorHooksPath, JSON.stringify(merged, null, 2));
92
+ }
93
+ async uninstallHooks() {
94
+ if (!fs.existsSync(this.cursorHooksPath))
95
+ return;
96
+ try {
97
+ const existing = JSON.parse(fs.readFileSync(this.cursorHooksPath, 'utf-8'));
98
+ if (existing.hooks) {
99
+ for (const hook of Object.keys(CURSOR_HOOKS_CONFIG.hooks)) {
100
+ delete existing.hooks[hook];
101
+ }
102
+ }
103
+ fs.writeFileSync(this.cursorHooksPath, JSON.stringify(existing, null, 2));
104
+ }
105
+ catch {
106
+ // leave file untouched if we can't parse it
107
+ }
108
+ }
109
+ // ── Claude Code ─────────────────────────────────────────────────────────────
110
+ async installClaudeHooks() {
111
+ const settingsDir = path.dirname(this.claudeSettingsPath);
112
+ if (!fs.existsSync(settingsDir)) {
113
+ fs.mkdirSync(settingsDir, { recursive: true });
114
+ }
115
+ let settings = {};
116
+ if (fs.existsSync(this.claudeSettingsPath)) {
117
+ try {
118
+ settings = JSON.parse(fs.readFileSync(this.claudeSettingsPath, 'utf-8'));
119
+ }
120
+ catch {
121
+ // ignore malformed existing settings
122
+ }
123
+ }
124
+ if (!settings.hooks)
125
+ settings.hooks = {};
126
+ for (const hookType of CLAUDE_HOOK_TYPES) {
127
+ // Preserve any existing hooks that aren't ours, add ours
128
+ const existing = settings.hooks[hookType] ?? [];
129
+ const withoutOurs = existing.filter((h) => !h.hooks?.some((hh) => hh.command?.startsWith('coding-analytics')));
130
+ settings.hooks[hookType] = [
131
+ ...withoutOurs,
132
+ {
133
+ hooks: [
134
+ {
135
+ type: 'command',
136
+ command: `coding-analytics claude-hook ${hookType}`,
137
+ },
138
+ ],
139
+ },
140
+ ];
141
+ }
142
+ fs.writeFileSync(this.claudeSettingsPath, JSON.stringify(settings, null, 2));
143
+ }
144
+ async uninstallClaudeHooks() {
145
+ if (!fs.existsSync(this.claudeSettingsPath))
146
+ return;
147
+ try {
148
+ const settings = JSON.parse(fs.readFileSync(this.claudeSettingsPath, 'utf-8'));
149
+ if (settings.hooks) {
150
+ for (const hookType of CLAUDE_HOOK_TYPES) {
151
+ if (!settings.hooks[hookType])
152
+ continue;
153
+ settings.hooks[hookType] = settings.hooks[hookType].filter((h) => !h.hooks?.some((hh) => hh.command?.startsWith('coding-analytics')));
154
+ if (settings.hooks[hookType].length === 0) {
155
+ delete settings.hooks[hookType];
156
+ }
157
+ }
158
+ }
159
+ fs.writeFileSync(this.claudeSettingsPath, JSON.stringify(settings, null, 2));
160
+ }
161
+ catch {
162
+ // leave file untouched if we can't parse it
163
+ }
164
+ }
165
+ static installCron() {
166
+ if (os.platform() === 'win32') {
167
+ throw new Error('Cron is not supported on Windows. Set up Task Scheduler manually:\n coding-analytics flush');
168
+ }
169
+ const binPath = (0, child_process_1.execSync)('which coding-analytics').toString().trim();
170
+ const logPath = path.join(config_1.Config.getDataDir(), 'logs', 'flush.log');
171
+ const cronLine = `*/5 * * * * ${binPath} flush >> ${logPath} 2>&1 ${InstallService.CRON_MARKER}`;
172
+ let existing = '';
173
+ try {
174
+ existing = (0, child_process_1.execSync)('crontab -l 2>/dev/null').toString();
175
+ }
176
+ catch { }
177
+ const lines = existing.split('\n').filter(l => !l.includes(InstallService.CRON_MARKER));
178
+ lines.push(cronLine);
179
+ const tmpFile = path.join(os.tmpdir(), 'coding-analytics-crontab');
180
+ fs.writeFileSync(tmpFile, lines.filter(l => l.trim()).join('\n') + '\n');
181
+ (0, child_process_1.execSync)(`crontab ${tmpFile}`);
182
+ fs.unlinkSync(tmpFile);
183
+ }
184
+ static uninstallCron() {
185
+ if (os.platform() === 'win32')
186
+ return;
187
+ try {
188
+ const existing = (0, child_process_1.execSync)('crontab -l 2>/dev/null').toString();
189
+ const lines = existing.split('\n').filter(l => !l.includes(InstallService.CRON_MARKER));
190
+ const cleaned = lines.filter(l => l.trim()).join('\n');
191
+ if (cleaned) {
192
+ const tmpFile = path.join(os.tmpdir(), 'coding-analytics-crontab');
193
+ fs.writeFileSync(tmpFile, cleaned + '\n');
194
+ (0, child_process_1.execSync)(`crontab ${tmpFile}`);
195
+ fs.unlinkSync(tmpFile);
196
+ }
197
+ else {
198
+ (0, child_process_1.execSync)('crontab -r 2>/dev/null || true', { stdio: 'ignore' });
199
+ }
200
+ }
201
+ catch { }
202
+ }
203
+ static isCronInstalled() {
204
+ if (os.platform() === 'win32')
205
+ return false;
206
+ try {
207
+ const crontab = (0, child_process_1.execSync)('crontab -l 2>/dev/null').toString();
208
+ return crontab.includes(InstallService.CRON_MARKER);
209
+ }
210
+ catch {
211
+ return false;
212
+ }
213
+ }
214
+ }
215
+ exports.InstallService = InstallService;
216
+ // ── Cron (macOS / Linux only) ────────────────────────────────────────────────
217
+ InstallService.CRON_MARKER = '# coding-analytics-flush';
218
+ //# sourceMappingURL=install-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-service.js","sourceRoot":"","sources":["../install-service.ts"],"names":[],"mappings":"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"}