@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,19 @@
1
+ import { Config } from './config';
2
+ import { EnrichedEvent } from './enricher';
3
+ export declare class LocalStorage {
4
+ private filePath;
5
+ private config;
6
+ constructor(config?: Config);
7
+ private read;
8
+ private write;
9
+ store(events: EnrichedEvent[]): Promise<void>;
10
+ retryFailed(): Promise<{
11
+ success: number;
12
+ failed: number;
13
+ }>;
14
+ getRecent(count?: number): Promise<EnrichedEvent[]>;
15
+ getCount(): Promise<number>;
16
+ cleanup(olderThanDays?: number): Promise<number>;
17
+ close(): void;
18
+ }
19
+ //# sourceMappingURL=local-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-storage.d.ts","sourceRoot":"","sources":["../local-storage.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiB3C,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAiB3B,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,KAAK;IAIP,KAAK,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7C,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAoD3D,SAAS,CAAC,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAQvD,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B,OAAO,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAU1D,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,152 @@
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.LocalStorage = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const config_1 = require("./config");
40
+ const posthog_node_1 = require("posthog-node");
41
+ const logger_1 = require("./logger");
42
+ class LocalStorage {
43
+ constructor(config) {
44
+ this.config = config ?? config_1.Config.load();
45
+ // Derive file path: replace .db extension with .json if needed
46
+ const configuredPath = this.config.storage.localDbPath;
47
+ this.filePath = configuredPath.endsWith('.db')
48
+ ? configuredPath.slice(0, -3) + '.json'
49
+ : configuredPath.endsWith('.json')
50
+ ? configuredPath
51
+ : configuredPath + '.json';
52
+ const dir = path.dirname(this.filePath);
53
+ if (!fs.existsSync(dir)) {
54
+ fs.mkdirSync(dir, { recursive: true });
55
+ }
56
+ }
57
+ read() {
58
+ if (!fs.existsSync(this.filePath)) {
59
+ return { events: [], next_id: 1 };
60
+ }
61
+ try {
62
+ return JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));
63
+ }
64
+ catch {
65
+ return { events: [], next_id: 1 };
66
+ }
67
+ }
68
+ write(data) {
69
+ fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
70
+ }
71
+ async store(events) {
72
+ const data = this.read();
73
+ const now = Math.floor(Date.now() / 1000);
74
+ for (const event of events) {
75
+ data.events.push({
76
+ id: data.next_id++,
77
+ data: JSON.stringify(event),
78
+ timestamp: new Date(event.timestamp).getTime(),
79
+ retry_count: 0,
80
+ created_at: now,
81
+ });
82
+ }
83
+ this.write(data);
84
+ logger_1.logger.debug('Events stored locally', { count: events.length });
85
+ }
86
+ async retryFailed() {
87
+ if (!this.config.storage.retryFailedEvents) {
88
+ return { success: 0, failed: 0 };
89
+ }
90
+ const data = this.read();
91
+ const pending = data.events
92
+ .filter(e => e.retry_count < this.config.storage.maxRetries)
93
+ .slice(0, 100);
94
+ if (pending.length === 0) {
95
+ return { success: 0, failed: 0 };
96
+ }
97
+ const posthog = new posthog_node_1.PostHog(this.config.posthog.apiKey, {
98
+ host: this.config.posthog.host,
99
+ });
100
+ let success = 0;
101
+ let failed = 0;
102
+ for (const row of pending) {
103
+ try {
104
+ const event = JSON.parse(row.data);
105
+ posthog.capture({
106
+ distinctId: event.distinct_id,
107
+ event: event.event,
108
+ properties: event.properties,
109
+ timestamp: new Date(event.timestamp),
110
+ });
111
+ await posthog.flush();
112
+ data.events = data.events.filter(e => e.id !== row.id);
113
+ success++;
114
+ }
115
+ catch (error) {
116
+ logger_1.logger.error('Failed to retry event', { error, eventId: row.id });
117
+ const stored = data.events.find(e => e.id === row.id);
118
+ if (stored)
119
+ stored.retry_count++;
120
+ failed++;
121
+ }
122
+ }
123
+ this.write(data);
124
+ await posthog.shutdown();
125
+ return { success, failed };
126
+ }
127
+ async getRecent(count = 10) {
128
+ const data = this.read();
129
+ return data.events
130
+ .slice(-count)
131
+ .reverse()
132
+ .map(e => JSON.parse(e.data));
133
+ }
134
+ async getCount() {
135
+ return this.read().events.length;
136
+ }
137
+ async cleanup(olderThanDays = 30) {
138
+ const data = this.read();
139
+ const cutoff = Math.floor((Date.now() - olderThanDays * 24 * 60 * 60 * 1000) / 1000);
140
+ const before = data.events.length;
141
+ data.events = data.events.filter(e => e.created_at >= cutoff);
142
+ const removed = before - data.events.length;
143
+ if (removed > 0)
144
+ this.write(data);
145
+ return removed;
146
+ }
147
+ close() {
148
+ // No-op for file-based storage
149
+ }
150
+ }
151
+ exports.LocalStorage = LocalStorage;
152
+ //# sourceMappingURL=local-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-storage.js","sourceRoot":"","sources":["../local-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import winston from 'winston';
2
+ export declare const logger: winston.Logger;
3
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAW9B,eAAO,MAAM,MAAM,gBAajB,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,59 @@
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.logger = void 0;
40
+ const winston_1 = __importDefault(require("winston"));
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const os = __importStar(require("os"));
44
+ const logsDir = path.join(os.homedir(), '.coding-analytics', 'logs');
45
+ if (!fs.existsSync(logsDir)) {
46
+ fs.mkdirSync(logsDir, { recursive: true });
47
+ }
48
+ exports.logger = winston_1.default.createLogger({
49
+ level: process.env.LOG_LEVEL || 'info',
50
+ format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.json()),
51
+ transports: [
52
+ new winston_1.default.transports.File({
53
+ filename: path.join(logsDir, 'coding-analytics.log'),
54
+ maxsize: 10 * 1024 * 1024, // 10 MB
55
+ maxFiles: 3,
56
+ }),
57
+ ],
58
+ });
59
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../logger.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sDAA8B;AAC9B,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AAEzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAErE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAEY,QAAA,MAAM,GAAG,iBAAO,CAAC,YAAY,CAAC;IACzC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IACtC,MAAM,EAAE,iBAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,iBAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAC1B,iBAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACtB;IACD,UAAU,EAAE;QACV,IAAI,iBAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC;YACpD,OAAO,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;YACnC,QAAQ,EAAE,CAAC;SACZ,CAAC;KACH;CACF,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { HookEvent } from './hooks-listener';
2
+ export interface QueuedEvent {
3
+ hookEvent: HookEvent;
4
+ queuedAt: string;
5
+ }
6
+ export declare class Queue {
7
+ private filePath;
8
+ constructor();
9
+ /**
10
+ * Appends a single event to the queue file.
11
+ * appendFileSync writes are atomic for small payloads, safe for concurrent hook calls.
12
+ */
13
+ append(hookEvent: HookEvent): void;
14
+ /**
15
+ * Atomically moves the queue file aside for processing.
16
+ * New hook calls will write to a fresh queue.jsonl while this batch is processed.
17
+ * Returns all valid queued events and deletes the processing file.
18
+ */
19
+ drain(): QueuedEvent[];
20
+ pendingCount(): number;
21
+ }
22
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../queue.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAS;;IAUzB;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAKlC;;;;OAIG;IACH,KAAK,IAAI,WAAW,EAAE;IA2BtB,YAAY,IAAI,MAAM;CASvB"}
package/dist/queue.js ADDED
@@ -0,0 +1,102 @@
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.Queue = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const config_1 = require("./config");
40
+ class Queue {
41
+ constructor() {
42
+ const dataDir = config_1.Config.getDataDir();
43
+ if (!fs.existsSync(dataDir)) {
44
+ fs.mkdirSync(dataDir, { recursive: true });
45
+ }
46
+ this.filePath = path.join(dataDir, 'queue.jsonl');
47
+ }
48
+ /**
49
+ * Appends a single event to the queue file.
50
+ * appendFileSync writes are atomic for small payloads, safe for concurrent hook calls.
51
+ */
52
+ append(hookEvent) {
53
+ const entry = { hookEvent, queuedAt: new Date().toISOString() };
54
+ fs.appendFileSync(this.filePath, JSON.stringify(entry) + '\n', 'utf-8');
55
+ }
56
+ /**
57
+ * Atomically moves the queue file aside for processing.
58
+ * New hook calls will write to a fresh queue.jsonl while this batch is processed.
59
+ * Returns all valid queued events and deletes the processing file.
60
+ */
61
+ drain() {
62
+ if (!fs.existsSync(this.filePath))
63
+ return [];
64
+ if (fs.statSync(this.filePath).size === 0) {
65
+ fs.unlinkSync(this.filePath);
66
+ return [];
67
+ }
68
+ const processingPath = this.filePath + '.processing';
69
+ try {
70
+ fs.renameSync(this.filePath, processingPath);
71
+ }
72
+ catch {
73
+ return [];
74
+ }
75
+ const events = fs.readFileSync(processingPath, 'utf-8')
76
+ .split('\n')
77
+ .filter(l => l.trim())
78
+ .flatMap(line => {
79
+ try {
80
+ return [JSON.parse(line)];
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ });
86
+ fs.unlinkSync(processingPath);
87
+ return events;
88
+ }
89
+ pendingCount() {
90
+ try {
91
+ if (!fs.existsSync(this.filePath))
92
+ return 0;
93
+ const content = fs.readFileSync(this.filePath, 'utf-8');
94
+ return content.split('\n').filter(l => l.trim()).length;
95
+ }
96
+ catch {
97
+ return 0;
98
+ }
99
+ }
100
+ }
101
+ exports.Queue = Queue;
102
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../queue.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAC7B,qCAAkC;AAQlC,MAAa,KAAK;IAGhB;QACE,MAAM,OAAO,GAAG,eAAM,CAAC,UAAU,EAAE,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAoB;QACzB,MAAM,KAAK,GAAgB,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7E,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7C,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC1C,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC;QAErD,IAAI,CAAC;YACH,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC;aACpD,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACrB,OAAO,CAAC,IAAI,CAAC,EAAE;YACd,IAAI,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC,CAAC;YAAC,CAAC;YACjD,MAAM,CAAC;gBAAC,OAAO,EAAE,CAAC;YAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QAEL,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,YAAY;QACV,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACxD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;CACF;AA7DD,sBA6DC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@tekdi/coding-analytics",
3
+ "version": "1.0.0",
4
+ "description": "Monitor Cursor AI usage and send analytics to PostHog",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "coding-analytics": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist/",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "ts-node cli.ts",
16
+ "test": "jest",
17
+ "lint": "eslint **/*.ts",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "cursor",
22
+ "monitoring",
23
+ "analytics",
24
+ "posthog"
25
+ ],
26
+ "author": "Tekdi Technologies",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "commander": "^11.1.0",
30
+ "dotenv": "^16.3.1",
31
+ "posthog-node": "^4.0.0",
32
+ "simple-git": "^3.21.0",
33
+ "systeminformation": "^5.21.20",
34
+ "winston": "^3.11.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/jest": "^29.5.11",
38
+ "@types/node": "^20.10.6",
39
+ "@typescript-eslint/eslint-plugin": "^6.16.0",
40
+ "@typescript-eslint/parser": "^6.16.0",
41
+ "eslint": "^8.56.0",
42
+ "jest": "^29.7.0",
43
+ "ts-node": "^10.9.2",
44
+ "typescript": "^5.3.3"
45
+ },
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ }
49
+ }