costhawk 1.5.11 → 1.5.13
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.
- package/dist/build-info.d.ts +1 -1
- package/dist/build-info.js +1 -1
- package/dist/cursor-parser.d.ts +194 -0
- package/dist/cursor-parser.d.ts.map +1 -0
- package/dist/cursor-parser.js +888 -0
- package/dist/cursor-parser.js.map +1 -0
- package/dist/index.js +202 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/build-info.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const BUILD_COMMIT_SHA = "
|
|
1
|
+
export declare const BUILD_COMMIT_SHA = "1ed40d7";
|
|
2
2
|
//# sourceMappingURL=build-info.d.ts.map
|
package/dist/build-info.js
CHANGED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor Local SQLite Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Cursor IDE chat history from the local SQLite database to extract
|
|
5
|
+
* token usage and timestamps. Read-only. Does not push to any backend.
|
|
6
|
+
*
|
|
7
|
+
* Storage:
|
|
8
|
+
* macOS: ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb
|
|
9
|
+
* Linux: ~/.config/Cursor/User/globalStorage/state.vscdb
|
|
10
|
+
* Windows: %APPDATA%/Cursor/User/globalStorage/state.vscdb
|
|
11
|
+
*
|
|
12
|
+
* Schema:
|
|
13
|
+
* Table cursorDiskKV (key TEXT, value BLOB)
|
|
14
|
+
* Conversations: composerData:<composerId>
|
|
15
|
+
* Messages: bubbleId:<composerId>:<bubbleId>
|
|
16
|
+
*
|
|
17
|
+
* Token data lives at $.tokenCount.inputTokens and $.tokenCount.outputTokens
|
|
18
|
+
* on bubble rows. Model name at $.modelInfo.modelName. Server-side dedup id
|
|
19
|
+
* at $.serverBubbleId.
|
|
20
|
+
*
|
|
21
|
+
* Timestamps (verified in Task #30 against a real state.vscdb):
|
|
22
|
+
* - $.createdAt on bubbles is an ISO 8601 string (~56% coverage, all-or-
|
|
23
|
+
* nothing per composer — likely added in a newer Cursor version).
|
|
24
|
+
* - $.createdAt on composerData rows is a Unix milliseconds number (100%
|
|
25
|
+
* coverage). Same field name, different type — parser handles both.
|
|
26
|
+
* - $.lastUpdatedAt on composerData rows is Unix ms (~13% coverage).
|
|
27
|
+
* - $.timingInfo.client* on bubbles is performance.now()-style relative
|
|
28
|
+
* (seconds since Cursor process start), NOT absolute — never use it as
|
|
29
|
+
* a wall-clock timestamp.
|
|
30
|
+
*
|
|
31
|
+
* Fallback ladder for per-session timestamps: prefer min/max of bubble
|
|
32
|
+
* createdAt when present, otherwise use composerData.createdAt with optional
|
|
33
|
+
* composerData.lastUpdatedAt as end time. Every session gets non-null
|
|
34
|
+
* timestamps; the `timestampSource` / `timestampQuality` fields surface
|
|
35
|
+
* whether the values are precise or approximate.
|
|
36
|
+
*
|
|
37
|
+
* Workspace metadata fields (workspaceHash/workspaceName) remain unverified
|
|
38
|
+
* and return null. composerData.name is a candidate for workspaceName but
|
|
39
|
+
* has not been confirmed yet.
|
|
40
|
+
*/
|
|
41
|
+
import type { TokenUsage } from "./transcript-parser.js";
|
|
42
|
+
/**
|
|
43
|
+
* Single Cursor session in parser output.
|
|
44
|
+
*
|
|
45
|
+
* Shape is intentionally distinct from Claude/Codex SessionUsage because
|
|
46
|
+
* Cursor's timestamp coverage is partial — provenance fields surface
|
|
47
|
+
* whether startTime/endTime/dailyUsage came from per-bubble timestamps
|
|
48
|
+
* (precise) or a composer-level fallback (approximate).
|
|
49
|
+
*
|
|
50
|
+
* workspaceHash / workspaceName remain null — composerData.name is a
|
|
51
|
+
* candidate for workspaceName but was not verified in Task #30 and is
|
|
52
|
+
* deferred to a later release.
|
|
53
|
+
*/
|
|
54
|
+
export interface CursorSessionUsage {
|
|
55
|
+
sessionId: string;
|
|
56
|
+
workspaceHash: string | null;
|
|
57
|
+
workspaceName: string | null;
|
|
58
|
+
model: string;
|
|
59
|
+
tokens: TokenUsage;
|
|
60
|
+
messageCount: number;
|
|
61
|
+
filePath: string;
|
|
62
|
+
startTime: string | null;
|
|
63
|
+
endTime: string | null;
|
|
64
|
+
timestampSource: "bubble" | "composer" | "mixed" | "none";
|
|
65
|
+
timestampQuality: "precise" | "approximate" | "none";
|
|
66
|
+
dailyUsage: Record<string, TokenUsage>;
|
|
67
|
+
dailyUsageSource: "bubble" | "composer" | "none";
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Backward-compat alias. PR1 shipped `CursorSessionUsageDryRun` in the
|
|
71
|
+
* published `.d.ts`; removing it in a patch release would be a breaking
|
|
72
|
+
* change for anyone who imported the type. The alias will be kept for at
|
|
73
|
+
* least one release after the rename.
|
|
74
|
+
*/
|
|
75
|
+
export type CursorSessionUsageDryRun = CursorSessionUsage;
|
|
76
|
+
/**
|
|
77
|
+
* Transparency payload for the `what_we_read` MCP mode. Describes where
|
|
78
|
+
* the parser is reading from and what it sees at the table/prefix level,
|
|
79
|
+
* without leaking conversation content. UUIDs in sample keys are
|
|
80
|
+
* truncated to 8 characters — enough to distinguish keys at a glance,
|
|
81
|
+
* not enough to be a stable correlation handle.
|
|
82
|
+
*/
|
|
83
|
+
export interface CursorMeta {
|
|
84
|
+
filePath: string;
|
|
85
|
+
dbFileSize: number;
|
|
86
|
+
tables: string[];
|
|
87
|
+
keyPrefixes: Record<string, number>;
|
|
88
|
+
sampleBubbleKeys: string[];
|
|
89
|
+
sampleComposerKeys: string[];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Output of the `self_test` MCP mode. Runs the full parser pipeline and
|
|
93
|
+
* reports health + coverage + invariant checks. overallStatus semantics:
|
|
94
|
+
* PASS — parser ran, invariants held, coverage looks healthy
|
|
95
|
+
* DEGRADED — parser ran but some bubbles lack timestamps / invariants
|
|
96
|
+
* tripped warnings / coverage is partial. Not an error.
|
|
97
|
+
* FAIL — parser could not run (missing DB, missing sqlite3, query
|
|
98
|
+
* failure, or corrupt top-level output). Surfaces as
|
|
99
|
+
* MCP isError:true at the tool boundary.
|
|
100
|
+
*/
|
|
101
|
+
export interface CursorSelfTestResult {
|
|
102
|
+
filePath: string;
|
|
103
|
+
dbExists: boolean;
|
|
104
|
+
sqlite3Path: string;
|
|
105
|
+
canQuery: boolean;
|
|
106
|
+
tokenBubbleCount: number;
|
|
107
|
+
composerCount: number;
|
|
108
|
+
sessionsWithTokens: number;
|
|
109
|
+
timestampCoverage: {
|
|
110
|
+
bubblesWithCreatedAt: number;
|
|
111
|
+
totalBubbles: number;
|
|
112
|
+
composersWithCreatedAt: number;
|
|
113
|
+
totalComposers: number;
|
|
114
|
+
};
|
|
115
|
+
invariantChecks: Array<{
|
|
116
|
+
name: string;
|
|
117
|
+
passed: boolean;
|
|
118
|
+
details?: string;
|
|
119
|
+
}>;
|
|
120
|
+
warnings: string[];
|
|
121
|
+
errors: string[];
|
|
122
|
+
overallStatus: "PASS" | "DEGRADED" | "FAIL";
|
|
123
|
+
}
|
|
124
|
+
export interface CursorParserError {
|
|
125
|
+
code: "CURSOR_DB_NOT_FOUND" | "CURSOR_SQLITE3_NOT_FOUND" | "CURSOR_SQLITE_QUERY_FAILED";
|
|
126
|
+
message: string;
|
|
127
|
+
}
|
|
128
|
+
export interface CursorParserResult {
|
|
129
|
+
sessions: CursorSessionUsage[];
|
|
130
|
+
filePath: string;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get the default Cursor SQLite path for the current platform, honoring
|
|
134
|
+
* the COSTHAWK_CURSOR_DB_PATH environment override.
|
|
135
|
+
*/
|
|
136
|
+
export declare function getCursorDbPath(): string;
|
|
137
|
+
/**
|
|
138
|
+
* Check whether the Cursor SQLite database exists at the resolved path.
|
|
139
|
+
*/
|
|
140
|
+
export declare function cursorDbExists(): boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Type guard — narrows an unknown error to a CursorParserError.
|
|
143
|
+
*/
|
|
144
|
+
declare function isCursorParserError(value: unknown): value is CursorParserError;
|
|
145
|
+
/**
|
|
146
|
+
* Parse Cursor usage from local SQLite. Read-only — does NOT push anything
|
|
147
|
+
* to the costcanary backend.
|
|
148
|
+
*
|
|
149
|
+
* Returns aggregated session data per composer with per-session token totals,
|
|
150
|
+
* message counts, start/end timestamps, and daily usage buckets. Throws
|
|
151
|
+
* CursorParserError on unrecoverable failures (missing DB, missing sqlite3
|
|
152
|
+
* binary, malformed SQLite output).
|
|
153
|
+
*
|
|
154
|
+
* Dedup strategy: per composer, keep one entry per (serverBubbleId ?? bubbleId).
|
|
155
|
+
* On collision, keep the candidate with the larger token total.
|
|
156
|
+
*
|
|
157
|
+
* Mixed-model handling: if a composer contains multiple non-empty model names,
|
|
158
|
+
* the returned `model` field is "mixed". If no model info is present on any
|
|
159
|
+
* bubble, the field is "unknown".
|
|
160
|
+
*
|
|
161
|
+
* Sort order: total tokens descending.
|
|
162
|
+
*/
|
|
163
|
+
export declare function parseCursorUsage(): CursorParserResult;
|
|
164
|
+
/**
|
|
165
|
+
* Backward-compat alias. PR1 consumers called this function name; keep it
|
|
166
|
+
* working for one release after the rename.
|
|
167
|
+
*/
|
|
168
|
+
export declare const parseCursorUsageDryRun: typeof parseCursorUsage;
|
|
169
|
+
/**
|
|
170
|
+
* Return transparency metadata about the Cursor SQLite: file size, table
|
|
171
|
+
* list, key-prefix histogram, and a small sample of bubble and composer
|
|
172
|
+
* keys with their UUIDs truncated. Powers the `what_we_read` MCP mode so
|
|
173
|
+
* users can see exactly what data CostHawk is reading.
|
|
174
|
+
*
|
|
175
|
+
* Throws CursorParserError on missing DB, missing sqlite3, or query failure.
|
|
176
|
+
*/
|
|
177
|
+
export declare function getCursorMeta(): CursorMeta;
|
|
178
|
+
/**
|
|
179
|
+
* Run a full parser health check against the live DB. Reports coverage
|
|
180
|
+
* numbers, validates invariants, and classifies the result as PASS,
|
|
181
|
+
* DEGRADED, or FAIL.
|
|
182
|
+
*
|
|
183
|
+
* - FAIL is reserved for unrecoverable failures (DB missing, sqlite3
|
|
184
|
+
* missing, query error). The MCP tool surfaces FAIL as isError:true.
|
|
185
|
+
* - DEGRADED means the parser ran but flagged warnings — e.g., invariant
|
|
186
|
+
* tolerance exceeded, partial timestamp coverage, unexpected row shapes.
|
|
187
|
+
* - PASS means the parser ran cleanly with full coverage and no warnings.
|
|
188
|
+
*
|
|
189
|
+
* Never throws — catches errors and reports them as FAIL so callers can
|
|
190
|
+
* present the full structured payload to users.
|
|
191
|
+
*/
|
|
192
|
+
export declare function runCursorSelfTest(): CursorSelfTestResult;
|
|
193
|
+
export { isCursorParserError };
|
|
194
|
+
//# sourceMappingURL=cursor-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-parser.d.ts","sourceRoot":"","sources":["../src/cursor-parser.ts"],"names":[],"mappings":"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"}
|