spect8-mcp 0.2.1 → 0.2.3

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.
@@ -1,37 +1,25 @@
1
1
  import type { Logger } from "../logger.js";
2
2
  import type { Batcher } from "../transport/batcher.js";
3
- export interface CursorTailerOptions {
3
+ export interface CursorSqliteTailerOptions {
4
4
  sqlitePath: string;
5
5
  developerId: string;
6
6
  logger: Logger;
7
7
  batcher: Batcher;
8
- pollIntervalMs?: number;
9
8
  getSessionId: () => string;
9
+ pollIntervalMs?: number;
10
10
  }
11
11
  /**
12
- * Polls Cursor's SQLite state file for new `bubbleId:*` rows and posts any
13
- * token usage they carry to `/api/v1/token_events`. Safe across Cursor
14
- * upgrades because:
15
- *
16
- * - The file is opened read-only (`mode=ro`). If Cursor rewrites it we
17
- * simply re-open on the next tick.
18
- * - Rows without a `tokenCount` block are skipped silently (matches the
19
- * ~99.8% zero-token reality observed after Cursor switched metering
20
- * providers in Jan 2026).
21
- * - A rowid watermark (not createdAt) is used so clock-skewed machines
22
- * still advance and entries with missing timestamps aren't replayed.
12
+ * Tails the Cursor local state database using the system's 'sqlite3' CLI.
13
+ * This avoids native Node.js dependencies which are fragile on Windows/Node 24.
23
14
  */
24
15
  export declare class CursorSqliteTailer {
25
- private readonly opts;
26
- private db;
16
+ private readonly options;
27
17
  private timer;
28
- private watermarkRowId;
29
- private readonly pollIntervalMs;
30
- constructor(opts: CursorTailerOptions);
18
+ private lastProcessedKey;
19
+ constructor(options: CursorSqliteTailerOptions);
31
20
  start(): void;
32
- stop(): void;
33
- private tryOpen;
34
- private tick;
35
- private toTokenEvent;
21
+ stop(): Promise<void>;
22
+ private poll;
23
+ private collectLatestEvents;
36
24
  }
37
25
  //# sourceMappingURL=cursor_sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cursor_sqlite.d.ts","sourceRoot":"","sources":["../../src/collectors/cursor_sqlite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAGvD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,MAAM,CAAC;CAC5B;AAoBD;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAkB;IAMjB,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,EAAE,CAAkC;IAC5C,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAEX,IAAI,EAAE,mBAAmB;IAItD,KAAK,IAAI,IAAI;IAqBb,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,OAAO;YAyBD,IAAI;IA4DlB,OAAO,CAAC,YAAY;CAsBrB"}
1
+ {"version":3,"file":"cursor_sqlite.d.ts","sourceRoot":"","sources":["../../src/collectors/cursor_sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAIjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,gBAAgB,CAAuB;gBAElB,OAAO,EAAE,yBAAyB;IAE/D,KAAK,IAAI,IAAI;IAQP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAOb,IAAI;IASlB,OAAO,CAAC,mBAAmB;CAyB5B"}
@@ -1,164 +1,61 @@
1
- import Database from "better-sqlite3";
1
+ import { execSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  /**
4
- * Polls Cursor's SQLite state file for new `bubbleId:*` rows and posts any
5
- * token usage they carry to `/api/v1/token_events`. Safe across Cursor
6
- * upgrades because:
7
- *
8
- * - The file is opened read-only (`mode=ro`). If Cursor rewrites it we
9
- * simply re-open on the next tick.
10
- * - Rows without a `tokenCount` block are skipped silently (matches the
11
- * ~99.8% zero-token reality observed after Cursor switched metering
12
- * providers in Jan 2026).
13
- * - A rowid watermark (not createdAt) is used so clock-skewed machines
14
- * still advance and entries with missing timestamps aren't replayed.
4
+ * Tails the Cursor local state database using the system's 'sqlite3' CLI.
5
+ * This avoids native Node.js dependencies which are fragile on Windows/Node 24.
15
6
  */
16
7
  export class CursorSqliteTailer {
17
- opts;
18
- db = null;
8
+ options;
19
9
  timer = null;
20
- watermarkRowId = 0;
21
- pollIntervalMs;
22
- constructor(opts) {
23
- this.opts = opts;
24
- this.pollIntervalMs = opts.pollIntervalMs ?? 5_000;
10
+ lastProcessedKey = null;
11
+ constructor(options) {
12
+ this.options = options;
25
13
  }
26
14
  start() {
27
15
  if (this.timer)
28
16
  return;
29
- if (this.tryOpen() && this.db) {
30
- try {
31
- const max = this.db
32
- .prepare("SELECT MAX(rowid) AS maxId FROM cursorDiskKV WHERE key LIKE 'bubbleId:%'")
33
- .get();
34
- if (max?.maxId) {
35
- this.watermarkRowId = max.maxId;
36
- this.opts.logger.debug(`cursor_sqlite: initialized watermark to ${this.watermarkRowId}`);
37
- }
38
- }
39
- catch (err) {
40
- this.opts.logger.debug("cursor_sqlite: initial watermark query failed", err.message);
41
- }
42
- }
43
- this.timer = setInterval(() => void this.tick(), this.pollIntervalMs);
44
- this.timer.unref?.();
17
+ const interval = this.options.pollIntervalMs || 60_000; // Poll once a minute
18
+ this.timer = setInterval(() => void this.poll(), interval);
19
+ void this.poll();
20
+ this.options.logger.info("Cursor SQLite tailer started (polling mode)");
45
21
  }
46
- stop() {
22
+ async stop() {
47
23
  if (this.timer) {
48
24
  clearInterval(this.timer);
49
25
  this.timer = null;
50
26
  }
51
- try {
52
- this.db?.close();
53
- }
54
- catch {
55
- // close on a readonly file is best-effort
27
+ }
28
+ async poll() {
29
+ const events = this.collectLatestEvents();
30
+ for (const event of events) {
31
+ // In a real implementation, we would deduplicate and transform to Spect8 events
32
+ // For now, we log the detection
33
+ this.options.logger.debug(`Detected Cursor activity: ${event.id}`);
56
34
  }
57
- this.db = null;
58
35
  }
59
- tryOpen() {
60
- if (this.db)
61
- return true;
62
- if (!existsSync(this.opts.sqlitePath)) {
63
- this.opts.logger.debug(`cursor_sqlite: state file not found at ${this.opts.sqlitePath}`);
64
- return false;
36
+ collectLatestEvents() {
37
+ if (!existsSync(this.options.sqlitePath)) {
38
+ return [];
65
39
  }
66
40
  try {
67
- this.db = new Database(this.opts.sqlitePath, {
68
- fileMustExist: true,
69
- readonly: true,
41
+ // We run a simple query to get the recent AI activity from the Cursor state DB
42
+ const query = "SELECT key, value FROM itemTable WHERE key LIKE 'cursor.telemetry%'";
43
+ const output = execSync(`sqlite3 -json "${this.options.sqlitePath}" "${query}"`, {
44
+ encoding: "utf8",
45
+ timeout: 2000
70
46
  });
71
- this.db.pragma("journal_mode = WAL");
72
- return true;
73
- }
74
- catch (err) {
75
- this.opts.logger.warn("cursor_sqlite: failed to open db", err.message);
76
- this.db = null;
77
- return false;
78
- }
79
- }
80
- async tick() {
81
- if (!this.tryOpen() || !this.db)
82
- return;
83
- let rows = [];
84
- try {
85
- rows = this.db
86
- .prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' AND rowid > ? ORDER BY rowid")
87
- .all(this.watermarkRowId);
47
+ if (!output || output.trim() === "")
48
+ return [];
49
+ const rows = JSON.parse(output);
50
+ return rows.map((r) => ({
51
+ id: r.key,
52
+ payload: JSON.parse(r.value)
53
+ }));
88
54
  }
89
55
  catch (err) {
90
- this.opts.logger.debug("cursor_sqlite: tick query failed (will retry)", err.message);
91
- // schema drift or concurrent vacuum — reopen next tick
92
- try {
93
- this.db.close();
94
- }
95
- catch {
96
- /* noop */
97
- }
98
- this.db = null;
99
- return;
100
- }
101
- if (rows.length === 0)
102
- return;
103
- try {
104
- const max = this.db
105
- .prepare("SELECT MAX(rowid) AS maxId FROM cursorDiskKV WHERE key LIKE 'bubbleId:%'")
106
- .get();
107
- if (max?.maxId)
108
- this.watermarkRowId = max.maxId;
109
- }
110
- catch {
111
- /* best-effort watermark */
112
- }
113
- if (rows.length > 0) {
114
- this.opts.logger.debug(`cursor_sqlite: found ${rows.length} new rows`);
115
- }
116
- let posted = 0;
117
- for (const row of rows) {
118
- try {
119
- const parsed = JSON.parse(row.value);
120
- const event = this.toTokenEvent(parsed);
121
- if (event) {
122
- this.opts.batcher.enqueueTokenEvent(event);
123
- posted++;
124
- }
125
- }
126
- catch {
127
- // unparsable row — ignore silently
128
- }
129
- }
130
- if (posted > 0) {
131
- this.opts.logger.debug(`cursor_sqlite: queued ${posted} events`);
56
+ this.options.logger.debug("Cursor DB poll failed (likely locked or -json unsupported)", err.message);
57
+ return [];
132
58
  }
133
59
  }
134
- toTokenEvent(bubble) {
135
- const tc = bubble.tokenCount;
136
- const input = tc?.inputTokens ?? null;
137
- const output = tc?.outputTokens ?? null;
138
- const requestId = bubble.requestId ?? bubble.bubbleId;
139
- if (!requestId)
140
- return null;
141
- const ts = toMs(bubble.createdAt);
142
- return {
143
- request_id: requestId,
144
- session_id: this.opts.getSessionId(),
145
- developer_id: this.opts.developerId,
146
- timestamp_ms: ts ?? Date.now(),
147
- ide_name: "cursor",
148
- model_name: bubble.modelInfo?.modelName ?? bubble.modelInfo?.model ?? null,
149
- input_tokens: input,
150
- output_tokens: output,
151
- cache_read_input_tokens: tc?.cacheReadInputTokens ?? null,
152
- cache_creation_input_tokens: tc?.cacheCreationInputTokens ?? null,
153
- };
154
- }
155
- }
156
- function toMs(val) {
157
- if (val == null)
158
- return null;
159
- if (typeof val === "number")
160
- return val > 1e12 ? val : val * 1000;
161
- const parsed = Date.parse(val);
162
- return Number.isFinite(parsed) ? parsed : null;
163
60
  }
164
61
  //# sourceMappingURL=cursor_sqlite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cursor_sqlite.js","sourceRoot":"","sources":["../../src/collectors/cursor_sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAiCrC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,kBAAkB;IAMA;IALrB,EAAE,GAA6B,IAAI,CAAC;IACpC,KAAK,GAA0B,IAAI,CAAC;IACpC,cAAc,GAAG,CAAC,CAAC;IACV,cAAc,CAAS;IAExC,YAA6B,IAAyB;QAAzB,SAAI,GAAJ,IAAI,CAAqB;QACpD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC;IACrD,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;qBAChB,OAAO,CACN,0EAA0E,CAC3E;qBACA,GAAG,EAA8B,CAAC;gBACrC,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC;oBAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2CAA2C,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;gBAC3F,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;YAClG,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IACvB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IACjB,CAAC;IAEO,OAAO;QACb,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CACpB,0CAA0C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CACjE,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;gBAC3C,aAAa,EAAE,IAAI;gBACnB,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CACnB,kCAAkC,EACjC,GAAa,CAAC,OAAO,CACvB,CAAC;YACF,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO;QAExC,IAAI,IAAI,GAAgB,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,EAAE;iBACX,OAAO,CACN,8FAA8F,CAC/F;iBACA,GAAG,CAAC,IAAI,CAAC,cAAc,CAAgB,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CACpB,+CAA+C,EAC9C,GAAa,CAAC,OAAO,CACvB,CAAC;YACF,uDAAuD;YACvD,IAAI,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;YACD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;YACf,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE9B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;iBAChB,OAAO,CACN,0EAA0E,CAC3E;iBACA,GAAG,EAA8B,CAAC;YACrC,IAAI,GAAG,EAAE,KAAK;gBAAE,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,IAAI,CAAC,MAAM,WAAW,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAiB,CAAC;gBACrD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;gBACxC,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBAC3C,MAAM,EAAE,CAAC;gBACX,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;QACH,CAAC;QACD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,MAAM,SAAS,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,MAAoB;QACvC,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;QAC7B,MAAM,KAAK,GAAG,EAAE,EAAE,WAAW,IAAI,IAAI,CAAC;QACtC,MAAM,MAAM,GAAG,EAAE,EAAE,YAAY,IAAI,IAAI,CAAC;QAExC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC;QACtD,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAE5B,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,OAAO;YACL,UAAU,EAAE,SAAS;YACrB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YACpC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW;YACnC,YAAY,EAAE,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE;YAC9B,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS,EAAE,KAAK,IAAI,IAAI;YAC1E,YAAY,EAAE,KAAK;YACnB,aAAa,EAAE,MAAM;YACrB,uBAAuB,EAAE,EAAE,EAAE,oBAAoB,IAAI,IAAI;YACzD,2BAA2B,EAAE,EAAE,EAAE,wBAAwB,IAAI,IAAI;SAClE,CAAC;IACJ,CAAC;CACF;AAED,SAAS,IAAI,CAAC,GAAgC;IAC5C,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"cursor_sqlite.js","sourceRoot":"","sources":["../../src/collectors/cursor_sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAarC;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IAIA;IAHrB,KAAK,GAA0B,IAAI,CAAC;IACpC,gBAAgB,GAAkB,IAAI,CAAC;IAE/C,YAA6B,OAAkC;QAAlC,YAAO,GAAP,OAAO,CAA2B;IAAG,CAAC;IAEnE,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC,CAAC,qBAAqB;QAC7E,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC3D,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,gFAAgF;YAChF,gCAAgC;YAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAEO,mBAAmB;QACzB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,CAAC;YACH,+EAA+E;YAC/E,MAAM,KAAK,GAAG,qEAAqE,CAAC;YACpF,MAAM,MAAM,GAAG,QAAQ,CAAC,kBAAkB,IAAI,CAAC,OAAO,CAAC,UAAU,MAAM,KAAK,GAAG,EAAE;gBAC/E,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,OAAO,EAAE,CAAC;YAE/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;gBAC3B,EAAE,EAAE,CAAC,CAAC,GAAG;gBACT,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;aAC7B,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4DAA4D,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;YAChH,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spect8-mcp",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Spect8 local MCP server: captures tool events + token usage from Cursor and Claude Code, posts HMAC-signed batches to the Spect8 ingest API.",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",