@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,50 @@
1
+ export interface PostHogConfig {
2
+ apiKey: string;
3
+ host: string;
4
+ batchSize: number;
5
+ flushInterval: number;
6
+ }
7
+ export interface CaptureConfig {
8
+ prompts: boolean;
9
+ responses: boolean;
10
+ fileContent: boolean;
11
+ filePaths: boolean;
12
+ agentThinking: boolean;
13
+ }
14
+ export interface PrivacyConfig {
15
+ hashUserIds: boolean;
16
+ redactSecrets: boolean;
17
+ allowedRepos: string[];
18
+ }
19
+ export interface StorageConfig {
20
+ fallbackToLocal: boolean;
21
+ localDbPath: string;
22
+ retryFailedEvents: boolean;
23
+ maxRetries: number;
24
+ }
25
+ export interface SystemConfig {
26
+ logLevel: string;
27
+ logPath: string;
28
+ }
29
+ export interface ConfigData {
30
+ posthog: PostHogConfig;
31
+ capture: CaptureConfig;
32
+ privacy: PrivacyConfig;
33
+ storage: StorageConfig;
34
+ system: SystemConfig;
35
+ }
36
+ export declare class Config {
37
+ posthog: PostHogConfig;
38
+ capture: CaptureConfig;
39
+ privacy: PrivacyConfig;
40
+ storage: StorageConfig;
41
+ system: SystemConfig;
42
+ constructor(data?: Partial<ConfigData>);
43
+ static getDataDir(): string;
44
+ static getConfigPath(): string;
45
+ static load(): Config;
46
+ save(): void;
47
+ toJSON(): ConfigData;
48
+ isConfigured(): boolean;
49
+ }
50
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,qBAAa,MAAM;IACV,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;gBAEhB,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC;IAoCtC,MAAM,CAAC,UAAU,IAAI,MAAM;IAK3B,MAAM,CAAC,aAAa,IAAI,MAAM;IAI9B,MAAM,CAAC,IAAI,IAAI,MAAM;IAmBrB,IAAI,IAAI,IAAI;IAYZ,MAAM,IAAI,UAAU;IAUpB,YAAY,IAAI,OAAO;CAGxB"}
package/dist/config.js ADDED
@@ -0,0 +1,119 @@
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.Config = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ class Config {
41
+ constructor(data) {
42
+ // Defaults
43
+ this.posthog = {
44
+ apiKey: data?.posthog?.apiKey || '',
45
+ host: data?.posthog?.host || 'https://eu.i.posthog.com',
46
+ batchSize: data?.posthog?.batchSize || 100,
47
+ flushInterval: data?.posthog?.flushInterval || 5000,
48
+ };
49
+ this.capture = {
50
+ prompts: data?.capture?.prompts ?? true,
51
+ responses: data?.capture?.responses ?? false,
52
+ fileContent: data?.capture?.fileContent ?? false,
53
+ filePaths: data?.capture?.filePaths ?? true,
54
+ agentThinking: data?.capture?.agentThinking ?? true,
55
+ };
56
+ this.privacy = {
57
+ hashUserIds: data?.privacy?.hashUserIds ?? true,
58
+ redactSecrets: data?.privacy?.redactSecrets ?? true,
59
+ allowedRepos: data?.privacy?.allowedRepos || [],
60
+ };
61
+ this.storage = {
62
+ fallbackToLocal: data?.storage?.fallbackToLocal ?? true,
63
+ localDbPath: data?.storage?.localDbPath || path.join(Config.getDataDir(), 'events.json'),
64
+ retryFailedEvents: data?.storage?.retryFailedEvents ?? true,
65
+ maxRetries: data?.storage?.maxRetries || 3,
66
+ };
67
+ this.system = {
68
+ logLevel: data?.system?.logLevel || 'info',
69
+ logPath: data?.system?.logPath || path.join(Config.getDataDir(), 'logs'),
70
+ };
71
+ }
72
+ static getDataDir() {
73
+ const homeDir = os.homedir();
74
+ return path.join(homeDir, '.coding-analytics');
75
+ }
76
+ static getConfigPath() {
77
+ return path.join(Config.getDataDir(), 'config.json');
78
+ }
79
+ static load() {
80
+ const configPath = Config.getConfigPath();
81
+ if (!fs.existsSync(configPath)) {
82
+ // Create default config
83
+ const config = new Config();
84
+ config.save();
85
+ return config;
86
+ }
87
+ try {
88
+ const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
89
+ return new Config(data);
90
+ }
91
+ catch (error) {
92
+ console.warn('Failed to load config, using defaults:', error);
93
+ return new Config();
94
+ }
95
+ }
96
+ save() {
97
+ const configPath = Config.getConfigPath();
98
+ const dataDir = Config.getDataDir();
99
+ // Ensure directory exists
100
+ if (!fs.existsSync(dataDir)) {
101
+ fs.mkdirSync(dataDir, { recursive: true });
102
+ }
103
+ fs.writeFileSync(configPath, JSON.stringify(this.toJSON(), null, 2));
104
+ }
105
+ toJSON() {
106
+ return {
107
+ posthog: this.posthog,
108
+ capture: this.capture,
109
+ privacy: this.privacy,
110
+ storage: this.storage,
111
+ system: this.system,
112
+ };
113
+ }
114
+ isConfigured() {
115
+ return !!this.posthog.apiKey;
116
+ }
117
+ }
118
+ exports.Config = Config;
119
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Config } from './config';
2
+ import { HookEvent } from './hooks-listener';
3
+ export interface EnrichedEvent {
4
+ event: string;
5
+ distinct_id: string;
6
+ properties: Record<string, any>;
7
+ timestamp: string;
8
+ }
9
+ export declare class Enricher {
10
+ private config;
11
+ private cachedUserId;
12
+ private cachedMachineId;
13
+ private gitContextCache;
14
+ constructor(config: Config);
15
+ enrich(hookEvent: HookEvent): Promise<EnrichedEvent>;
16
+ private getGitContext;
17
+ private fetchGitContext;
18
+ private extractRepoName;
19
+ private getSystemContext;
20
+ private getCursorVersion;
21
+ private getUserId;
22
+ private getClaudeAccountUuid;
23
+ private getCursorEmail;
24
+ private getCursorDbPath;
25
+ private getMachineId;
26
+ private hash;
27
+ }
28
+ //# sourceMappingURL=enricher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enricher.d.ts","sourceRoot":"","sources":["../enricher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQ7C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,eAAe,CAAuB;IAE9C,OAAO,CAAC,eAAe,CAA0C;gBAErD,MAAM,EAAE,MAAM;IAIpB,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;YA+B5C,aAAa;YASb,eAAe;IA2D7B,OAAO,CAAC,eAAe;YAQT,gBAAgB;YAUhB,gBAAgB;YAqBhB,SAAS;IA+BvB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,eAAe;YA0BT,YAAY;IAc1B,OAAO,CAAC,IAAI;CAGb"}
@@ -0,0 +1,258 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Enricher = void 0;
40
+ const simple_git_1 = __importDefault(require("simple-git"));
41
+ const os = __importStar(require("os"));
42
+ const crypto = __importStar(require("crypto"));
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const child_process_1 = require("child_process");
46
+ class Enricher {
47
+ constructor(config) {
48
+ this.cachedUserId = null;
49
+ this.cachedMachineId = null;
50
+ // Keyed by workspace path — avoids re-running 5 git subprocesses per event in a flush batch
51
+ this.gitContextCache = new Map();
52
+ this.config = config;
53
+ }
54
+ async enrich(hookEvent) {
55
+ const properties = {
56
+ ...hookEvent.data,
57
+ };
58
+ // Add git context — Claude hooks don't supply workspace_path so fall back to cwd
59
+ const workspacePath = hookEvent.data.workspace_path ||
60
+ (hookEvent.provider === 'claude' ? process.cwd() : undefined);
61
+ if (workspacePath) {
62
+ const gitContext = await this.getGitContext(workspacePath);
63
+ Object.assign(properties, gitContext);
64
+ }
65
+ // Add system context
66
+ const systemContext = await this.getSystemContext();
67
+ Object.assign(properties, systemContext);
68
+ // Get user ID
69
+ const userId = await this.getUserId();
70
+ return {
71
+ event: hookEvent.type,
72
+ distinct_id: userId,
73
+ properties: {
74
+ ...properties,
75
+ provider: hookEvent.provider ?? 'cursor',
76
+ },
77
+ timestamp: hookEvent.timestamp,
78
+ };
79
+ }
80
+ async getGitContext(workspacePath) {
81
+ if (this.gitContextCache.has(workspacePath)) {
82
+ return this.gitContextCache.get(workspacePath);
83
+ }
84
+ const context = await this.fetchGitContext(workspacePath);
85
+ this.gitContextCache.set(workspacePath, context);
86
+ return context;
87
+ }
88
+ async fetchGitContext(workspacePath) {
89
+ try {
90
+ const git = (0, simple_git_1.default)(workspacePath);
91
+ // Check if it's a git repo
92
+ const isRepo = await git.checkIsRepo();
93
+ if (!isRepo) {
94
+ return { git_enabled: false };
95
+ }
96
+ // Get current branch
97
+ const branch = await git.branchLocal();
98
+ // Get remote URL
99
+ const remotes = await git.getRemotes(true);
100
+ const origin = remotes.find(r => r.name === 'origin');
101
+ // Get last commit
102
+ const log = await git.log({ n: 1 });
103
+ const lastCommit = log.latest;
104
+ // Check if working directory is dirty
105
+ const status = await git.status();
106
+ // Extract repo name from remote
107
+ const repository = origin?.refs?.fetch
108
+ ? this.extractRepoName(origin.refs.fetch)
109
+ : 'unknown';
110
+ // Privacy: Check if repo is allowed
111
+ if (this.config.privacy.allowedRepos.length > 0) {
112
+ const allowed = this.config.privacy.allowedRepos.some(pattern => {
113
+ const regex = new RegExp(pattern.replace('*', '.*'));
114
+ return regex.test(repository);
115
+ });
116
+ if (!allowed) {
117
+ return {
118
+ git_enabled: true,
119
+ repository: '[filtered]',
120
+ branch: '[filtered]',
121
+ };
122
+ }
123
+ }
124
+ return {
125
+ git_enabled: true,
126
+ repository,
127
+ branch: branch.current,
128
+ last_commit: lastCommit?.hash?.substring(0, 7) || null,
129
+ is_dirty: !status.isClean(),
130
+ modified_files: status.modified.length,
131
+ staged_files: status.staged.length,
132
+ };
133
+ }
134
+ catch (error) {
135
+ return { git_enabled: false, git_error: error.message };
136
+ }
137
+ }
138
+ extractRepoName(remoteUrl) {
139
+ // Extract from URLs like:
140
+ // git@github.com:org/repo.git
141
+ // https://github.com/org/repo.git
142
+ const match = remoteUrl.match(/([^/:]+\/[^/.]+)(\.git)?$/);
143
+ return match ? match[1] : remoteUrl;
144
+ }
145
+ async getSystemContext() {
146
+ return {
147
+ os: os.platform(),
148
+ os_version: os.release(),
149
+ cursor_version: await this.getCursorVersion(),
150
+ node_version: process.version,
151
+ machine_id: await this.getMachineId(),
152
+ };
153
+ }
154
+ async getCursorVersion() {
155
+ try {
156
+ // Try to read Cursor version from common locations
157
+ const cursorPaths = [
158
+ path.join(os.homedir(), '.cursor', 'version'),
159
+ path.join(os.homedir(), 'AppData', 'Local', 'Programs', 'Cursor', 'version'), // Windows
160
+ '/Applications/Cursor.app/Contents/Resources/app/version', // Mac
161
+ ];
162
+ for (const versionPath of cursorPaths) {
163
+ if (fs.existsSync(versionPath)) {
164
+ return fs.readFileSync(versionPath, 'utf-8').trim();
165
+ }
166
+ }
167
+ return 'unknown';
168
+ }
169
+ catch {
170
+ return 'unknown';
171
+ }
172
+ }
173
+ async getUserId() {
174
+ if (this.cachedUserId) {
175
+ return this.cachedUserId;
176
+ }
177
+ // 1. Claude account UUID — stable, already opaque, no hashing needed
178
+ const claudeUuid = this.getClaudeAccountUuid();
179
+ if (claudeUuid) {
180
+ this.cachedUserId = claudeUuid;
181
+ return this.cachedUserId;
182
+ }
183
+ // 2. Cursor cached email from state.vscdb
184
+ const cursorEmail = this.getCursorEmail();
185
+ if (cursorEmail) {
186
+ this.cachedUserId = this.config.privacy.hashUserIds ? this.hash(cursorEmail) : cursorEmail;
187
+ return this.cachedUserId;
188
+ }
189
+ // 3. Git global email
190
+ try {
191
+ const git = (0, simple_git_1.default)();
192
+ const email = (await git.raw(['config', '--global', 'user.email'])).trim();
193
+ this.cachedUserId = this.config.privacy.hashUserIds ? this.hash(email) : email;
194
+ return this.cachedUserId;
195
+ }
196
+ catch {
197
+ // 4. Last resort: machine ID
198
+ return await this.getMachineId();
199
+ }
200
+ }
201
+ getClaudeAccountUuid() {
202
+ try {
203
+ const claudeJsonPath = path.join(os.homedir(), '.claude.json');
204
+ if (!fs.existsSync(claudeJsonPath))
205
+ return null;
206
+ const data = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf-8'));
207
+ return data?.oauthAccount?.accountUuid ?? null;
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ }
213
+ getCursorEmail() {
214
+ try {
215
+ const dbPath = this.getCursorDbPath();
216
+ if (!dbPath || !fs.existsSync(dbPath))
217
+ return null;
218
+ // sqlite3 CLI ships with macOS and is standard on Linux — no npm dependency needed
219
+ const result = (0, child_process_1.execSync)(`sqlite3 "${dbPath}" "SELECT value FROM ItemTable WHERE key='cursorAuth/cachedEmail';"`, { timeout: 3000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
220
+ return result || null;
221
+ }
222
+ catch {
223
+ return null;
224
+ }
225
+ }
226
+ getCursorDbPath() {
227
+ const home = os.homedir();
228
+ const candidates = [];
229
+ switch (os.platform()) {
230
+ case 'darwin':
231
+ candidates.push(path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'state.vscdb'), path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
232
+ break;
233
+ case 'linux':
234
+ candidates.push(path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
235
+ break;
236
+ case 'win32':
237
+ candidates.push(path.join(process.env.APPDATA ?? '', 'Cursor', 'User', 'globalStorage', 'state.vscdb'));
238
+ break;
239
+ }
240
+ return candidates.find(p => fs.existsSync(p)) ?? null;
241
+ }
242
+ async getMachineId() {
243
+ if (this.cachedMachineId) {
244
+ return this.cachedMachineId;
245
+ }
246
+ // Use machine-specific identifier
247
+ const hostname = os.hostname();
248
+ const username = os.userInfo().username;
249
+ const machineKey = `${hostname}-${username}`;
250
+ this.cachedMachineId = this.hash(machineKey);
251
+ return this.cachedMachineId;
252
+ }
253
+ hash(input) {
254
+ return crypto.createHash('sha256').update(input).digest('hex').substring(0, 16);
255
+ }
256
+ }
257
+ exports.Enricher = Enricher;
258
+ //# sourceMappingURL=enricher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enricher.js","sourceRoot":"","sources":["../enricher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface FlushResult {
2
+ processed: number;
3
+ failed: number;
4
+ }
5
+ export declare class Flusher {
6
+ private config;
7
+ constructor();
8
+ flush(): Promise<FlushResult>;
9
+ }
10
+ //# sourceMappingURL=flusher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusher.d.ts","sourceRoot":"","sources":["../flusher.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAS;;IAMjB,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;CAoDpC"}
@@ -0,0 +1,89 @@
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.Flusher = void 0;
37
+ const config_1 = require("./config");
38
+ const enricher_1 = require("./enricher");
39
+ const batcher_1 = require("./batcher");
40
+ const queue_1 = require("./queue");
41
+ const logger_1 = require("./logger");
42
+ class Flusher {
43
+ constructor() {
44
+ this.config = config_1.Config.load();
45
+ }
46
+ async flush() {
47
+ const queue = new queue_1.Queue();
48
+ const events = queue.drain();
49
+ if (events.length === 0) {
50
+ return { processed: 0, failed: 0 };
51
+ }
52
+ logger_1.logger.info('Flusher: processing queued events', { count: events.length });
53
+ // One Enricher for the whole batch:
54
+ // - userId, machineId cached after first resolution
55
+ // - git context cached per workspace path (see Enricher)
56
+ const enricher = new enricher_1.Enricher(this.config);
57
+ const batcher = new batcher_1.EventBatcher(this.config);
58
+ const failedLines = [];
59
+ let processed = 0;
60
+ let failed = 0;
61
+ for (const { hookEvent, queuedAt } of events) {
62
+ try {
63
+ // Preserve the original queued timestamp rather than the flush time
64
+ hookEvent.timestamp = hookEvent.timestamp || queuedAt;
65
+ const enriched = await enricher.enrich(hookEvent);
66
+ await batcher.add(enriched);
67
+ processed++;
68
+ }
69
+ catch (error) {
70
+ logger_1.logger.error('Flusher: failed to process event', { error, hookType: hookEvent.type });
71
+ // Re-queue so it retries next flush cycle
72
+ failedLines.push(JSON.stringify({ hookEvent, queuedAt }));
73
+ failed++;
74
+ }
75
+ }
76
+ // Flush to PostHog (falls back to local-storage on network failure)
77
+ await batcher.shutdown();
78
+ // Re-append failed events so they are retried next cycle
79
+ if (failedLines.length > 0) {
80
+ const { appendFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
81
+ const { join } = await Promise.resolve().then(() => __importStar(require('path')));
82
+ appendFileSync(join(config_1.Config.getDataDir(), 'queue.jsonl'), failedLines.join('\n') + '\n', 'utf-8');
83
+ }
84
+ logger_1.logger.info('Flusher: complete', { processed, failed });
85
+ return { processed, failed };
86
+ }
87
+ }
88
+ exports.Flusher = Flusher;
89
+ //# sourceMappingURL=flusher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flusher.js","sourceRoot":"","sources":["../flusher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAkC;AAClC,yCAAsC;AACtC,uCAAyC;AACzC,mCAAgC;AAChC,qCAAkC;AAOlC,MAAa,OAAO;IAGlB;QACE,IAAI,CAAC,MAAM,GAAG,eAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,KAAK,GAAG,IAAI,aAAK,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAE7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACrC,CAAC;QAED,eAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAE3E,oCAAoC;QACpC,oDAAoD;QACpD,yDAAyD;QACzD,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,sBAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,WAAW,GAAa,EAAE,CAAC;QAEjC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,MAAM,GAAG,CAAC,CAAC;QAEf,KAAK,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,MAAM,EAAE,CAAC;YAC7C,IAAI,CAAC;gBACH,oEAAoE;gBACpE,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,IAAI,QAAQ,CAAC;gBACtD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAClD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAC5B,SAAS,EAAE,CAAC;YACd,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,eAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtF,0CAA0C;gBAC1C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC1D,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEzB,yDAAyD;QACzD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,EAAE,cAAc,EAAE,GAAG,wDAAa,IAAI,GAAC,CAAC;YAC9C,MAAM,EAAE,IAAI,EAAE,GAAG,wDAAa,MAAM,GAAC,CAAC;YACtC,cAAc,CACZ,IAAI,CAAC,eAAM,CAAC,UAAU,EAAE,EAAE,aAAa,CAAC,EACxC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAC7B,OAAO,CACR,CAAC;QACJ,CAAC;QAED,eAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QACxD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC/B,CAAC;CACF;AA3DD,0BA2DC"}
@@ -0,0 +1,35 @@
1
+ interface AuthIds {
2
+ claude: string | null;
3
+ cursor: string | null;
4
+ }
5
+ interface HealthStatus {
6
+ status: 'healthy' | 'degraded' | 'unhealthy';
7
+ checks: {
8
+ posthog: boolean;
9
+ localStorage: boolean;
10
+ cursorHooks: boolean;
11
+ claudeHooks: boolean;
12
+ cron: boolean;
13
+ queueSize: number;
14
+ lastEvent: string | null;
15
+ authIds: AuthIds;
16
+ };
17
+ }
18
+ export declare class HealthMonitor {
19
+ private config;
20
+ constructor();
21
+ check(): Promise<HealthStatus>;
22
+ testPostHog(): Promise<boolean>;
23
+ private checkLocalStorage;
24
+ private checkCursorHooksInstalled;
25
+ private checkClaudeHooksInstalled;
26
+ private getLastEventTime;
27
+ private resolveAuthIds;
28
+ private readClaudeId;
29
+ private readCursorId;
30
+ private getCursorDbPath;
31
+ private maskUuid;
32
+ private maskEmail;
33
+ }
34
+ export {};
35
+ //# sourceMappingURL=health-monitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-monitor.d.ts","sourceRoot":"","sources":["../health-monitor.ts"],"names":[],"mappings":"AAUA,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,UAAU,YAAY;IACpB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAC7C,MAAM,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,EAAE,OAAO,CAAC;QACtB,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,IAAI,EAAE,OAAO,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;;IAMjB,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;IAuB9B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;YAavB,iBAAiB;IAU/B,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,yBAAyB;YAWnB,gBAAgB;IAY9B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,eAAe;IAwBvB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,SAAS;CAOlB"}