@tokentop/agent-cursor 1.0.0 → 1.2.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.
- package/README.md +92 -0
- package/dist/auth.d.ts +11 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/cache.d.ts +17 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/csv.d.ts +49 -0
- package/dist/csv.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +915 -13
- package/dist/parser.d.ts +33 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/storage.d.ts +15 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/watcher.d.ts +17 -0
- package/dist/watcher.d.ts.map +1 -0
- package/package.json +3 -4
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# @tokentop/agent-cursor
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@tokentop/agent-cursor)
|
|
4
|
+
[](https://github.com/tokentopapp/agent-cursor/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
[tokentop](https://github.com/tokentopapp/tokentop) agent plugin for **Cursor**. Parses Cursor's local SQLite session data and enriches it with server-side token counts for accurate usage tracking.
|
|
8
|
+
|
|
9
|
+
## Capabilities
|
|
10
|
+
|
|
11
|
+
| Capability | Status |
|
|
12
|
+
|-----------|--------|
|
|
13
|
+
| Session parsing | Yes |
|
|
14
|
+
| Real-time tracking | Yes |
|
|
15
|
+
| Server enrichment | Yes |
|
|
16
|
+
| Multi-provider | No |
|
|
17
|
+
|
|
18
|
+
## How It Works
|
|
19
|
+
|
|
20
|
+
Cursor stores session data as "composers" in a SQLite KV table (`state.vscdb`). Each conversation turn is a "bubble" with token counts, model info, and timestamps.
|
|
21
|
+
|
|
22
|
+
**Hybrid token strategy:**
|
|
23
|
+
|
|
24
|
+
1. **Immediate** — Sessions appear within seconds using local token estimates (`text.length / 4`)
|
|
25
|
+
2. **Enriched** — Accurate token counts (including cache read/write breakdown) are backfilled from Cursor's CSV server export
|
|
26
|
+
|
|
27
|
+
Enriched data persists across app restarts via plugin storage.
|
|
28
|
+
|
|
29
|
+
**Real-time activity detection:**
|
|
30
|
+
|
|
31
|
+
The activity watcher uses a rowid-based cursor on the SQLite DB with a read-write connection (to avoid WAL snapshot isolation). New bubbles are detected via 1s polling + `fs.watch`, with a 500ms fast-poll for pending bubbles during streaming.
|
|
32
|
+
|
|
33
|
+
## Settings
|
|
34
|
+
|
|
35
|
+
| Setting | Type | Default | Description |
|
|
36
|
+
|---------|------|---------|-------------|
|
|
37
|
+
| Server enrichment | boolean | `true` | Fetch accurate token counts from Cursor's server |
|
|
38
|
+
| Server refresh interval | number | `5` | How often to refresh server data (minutes, 1–60) |
|
|
39
|
+
| Estimate tokens | boolean | `true` | Show estimated tokens while server data loads |
|
|
40
|
+
|
|
41
|
+
## Permissions
|
|
42
|
+
|
|
43
|
+
| Type | Access | Details |
|
|
44
|
+
|------|--------|---------|
|
|
45
|
+
| Filesystem | Read | `~/.cursor`, `~/Library/Application Support/Cursor`, `~/.config/Cursor` |
|
|
46
|
+
| Network | HTTPS | `cursor.com` (CSV usage export) |
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
This plugin is **bundled with tokentop** — no separate install needed. If you need it standalone:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bun add @tokentop/agent-cursor
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Requirements
|
|
57
|
+
|
|
58
|
+
- [Cursor](https://cursor.com) installed
|
|
59
|
+
- [Bun](https://bun.sh/) >= 1.0.0
|
|
60
|
+
- `@tokentop/plugin-sdk` ^1.0.0 (peer dependency)
|
|
61
|
+
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bun install
|
|
66
|
+
bun run build
|
|
67
|
+
bun test
|
|
68
|
+
bun run typecheck
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Project Structure
|
|
72
|
+
|
|
73
|
+
| File | Responsibility |
|
|
74
|
+
|------|----------------|
|
|
75
|
+
| `src/index.ts` | Plugin entry — `createAgentPlugin()` wiring, config schema, exports |
|
|
76
|
+
| `src/parser.ts` | Session parsing — SQLite reads, workspace mapping, token estimation |
|
|
77
|
+
| `src/watcher.ts` | Activity detection — rowid cursor, WAL watching, pending bubbles |
|
|
78
|
+
| `src/csv.ts` | Server enrichment — CSV fetch, parse, match, cache, persistent storage |
|
|
79
|
+
| `src/auth.ts` | Auth — JWT decode, session cookie for CSV endpoint |
|
|
80
|
+
| `src/storage.ts` | Persistence — PluginStorage bridge for enrichment cache |
|
|
81
|
+
| `src/cache.ts` | Caching — TTL session cache, LRU aggregate cache, metadata index |
|
|
82
|
+
| `src/paths.ts` | Paths — cross-platform Cursor config/data directories |
|
|
83
|
+
| `src/types.ts` | Types — Cursor-specific interfaces |
|
|
84
|
+
| `src/utils.ts` | SQLite helpers — DB open, KV reads, provider mapping |
|
|
85
|
+
|
|
86
|
+
## Contributing
|
|
87
|
+
|
|
88
|
+
See the [Contributing Guide](https://github.com/tokentopapp/.github/blob/main/CONTRIBUTING.md). Issues for this plugin should be [filed on the main tokentop repo](https://github.com/tokentopapp/tokentop/issues/new?template=bug_report.yml&labels=bug,agent-cursor).
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the Cursor access token from local SQLite and constructs the
|
|
3
|
+
* WorkosCursorSessionToken cookie needed for Cursor's dashboard API.
|
|
4
|
+
*
|
|
5
|
+
* Cookie format: `WorkosCursorSessionToken={userId}%3A%3A{accessToken}`
|
|
6
|
+
* where userId is the JWT `sub` claim (e.g. "google-oauth2|user_01K...").
|
|
7
|
+
*
|
|
8
|
+
* Returns null if credentials are unavailable or malformed.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildSessionCookie(): string | null;
|
|
11
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAqCA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAgBlD"}
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SessionUsageData } from '@tokentop/plugin-sdk';
|
|
2
|
+
import type { SessionAggregateCacheEntry } from './types.ts';
|
|
3
|
+
export declare const sessionCache: {
|
|
4
|
+
lastCheck: number;
|
|
5
|
+
lastResult: SessionUsageData[];
|
|
6
|
+
lastLimit: number;
|
|
7
|
+
lastSince: number | undefined;
|
|
8
|
+
};
|
|
9
|
+
export declare const CACHE_TTL_MS = 2000;
|
|
10
|
+
export declare const SESSION_AGGREGATE_CACHE_MAX = 10000;
|
|
11
|
+
export declare const sessionAggregateCache: Map<string, SessionAggregateCacheEntry>;
|
|
12
|
+
export declare function evictSessionAggregateCache(): void;
|
|
13
|
+
export declare const composerMetadataIndex: Map<string, {
|
|
14
|
+
lastUpdatedAt: number;
|
|
15
|
+
composerId: string;
|
|
16
|
+
}>;
|
|
17
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAE7D,eAAO,MAAM,YAAY,EAAE;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAM/B,CAAC;AAEF,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,eAAO,MAAM,qBAAqB,yCAAgD,CAAC;AAEnF,wBAAgB,0BAA0B,IAAI,IAAI,CAUjD;AAED,eAAO,MAAM,qBAAqB;mBACjB,MAAM;gBACT,MAAM;EAChB,CAAC"}
|
package/dist/csv.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AgentFetchContext, SessionUsageData } from '@tokentop/plugin-sdk';
|
|
2
|
+
import type { CursorCsvUsageRow } from './types.ts';
|
|
3
|
+
/** Default TTL for cached CSV data. Overridden by `csvRefreshMinutes` config. */
|
|
4
|
+
export declare const CSV_CACHE_TTL_MS: number;
|
|
5
|
+
/**
|
|
6
|
+
* Parse Cursor's CSV usage export into structured rows.
|
|
7
|
+
*
|
|
8
|
+
* CSV columns (in order):
|
|
9
|
+
* Date, Kind, Model, Max Mode, Input (w/ Cache Write),
|
|
10
|
+
* Input (w/o Cache Write), Cache Read, Output Tokens, Total Tokens, Cost
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseUsageCsv(csvText: string): CursorCsvUsageRow[];
|
|
13
|
+
/**
|
|
14
|
+
* Get cached CSV data, awaiting the fetch when the cache is stale or empty.
|
|
15
|
+
*
|
|
16
|
+
* Reads `csvEnrichment` and `csvRefreshMinutes` from `ctx.config`.
|
|
17
|
+
* When the cache is missing or expired, awaits the server fetch (~1-3s)
|
|
18
|
+
* so enriched data lands on the same parseSessions cycle. Fresh cache
|
|
19
|
+
* returns immediately with no network call.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCsvRows(ctx: AgentFetchContext): Promise<CursorCsvUsageRow[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Invalidate the CSV cache so the next `getCsvRows` call triggers a
|
|
24
|
+
* fresh background fetch. Does NOT clear the per-session enrichment
|
|
25
|
+
* cache — previously-enriched sessions keep their accurate data.
|
|
26
|
+
*/
|
|
27
|
+
export declare function invalidateCsvCache(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Enrich locally-parsed session rows with actual token data from the CSV export.
|
|
30
|
+
*
|
|
31
|
+
* The CSV contains per-session aggregates, not per-bubble data. This function:
|
|
32
|
+
* 1. Groups local rows by sessionId
|
|
33
|
+
* 2. Matches each session to a CSV row by timestamp proximity (±60s)
|
|
34
|
+
* using sessionUpdatedAt — model matching is skipped because Cursor
|
|
35
|
+
* reports "auto" in the CSV rather than the resolved model name
|
|
36
|
+
* 3. Distributes the CSV totals across the session's bubbles
|
|
37
|
+
* proportionally based on each bubble's estimated output tokens
|
|
38
|
+
* 4. Caches enriched results per-session so they survive CSV cache
|
|
39
|
+
* expiry and DB activity without regressing to estimates
|
|
40
|
+
* 5. Persists the enrichment cache to PluginStorage so data survives restarts
|
|
41
|
+
*
|
|
42
|
+
* When called with no CSV rows (cache miss / TTL expired / first call),
|
|
43
|
+
* returns previously-enriched data from the per-session cache for known
|
|
44
|
+
* sessions. New/unenriched sessions keep their local estimates.
|
|
45
|
+
*/
|
|
46
|
+
export declare function enrichWithCsvData(localRows: SessionUsageData[], csvRows: CursorCsvUsageRow[]): Promise<SessionUsageData[]>;
|
|
47
|
+
/** Reset CSV cache and enrichment cache — for testing. */
|
|
48
|
+
export declare function resetCsvCache(): void;
|
|
49
|
+
//# sourceMappingURL=csv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../src/csv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIpD,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,QAAgB,CAAC;AAwB9C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAmClE;AA6BD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoCrF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAqBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,EAAE,iBAAiB,EAAE,GAC3B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAqG7B;AA+BD,0DAA0D;AAC1D,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { CACHE_TTL_MS, SESSION_AGGREGATE_CACHE_MAX, composerMetadataIndex, sessionAggregateCache, sessionCache } from './cache.ts';
|
|
2
|
+
import { CURSOR_GLOBAL_STORAGE_PATH, CURSOR_HOME, CURSOR_STATE_DB_PATH, CURSOR_WORKSPACE_STORAGE_PATH } from './paths.ts';
|
|
3
|
+
import { RECONCILIATION_INTERVAL_MS } from './watcher.ts';
|
|
4
|
+
import { CSV_CACHE_TTL_MS, resetCsvCache } from './csv.ts';
|
|
1
5
|
declare const cursorAgentPlugin: import("@tokentop/plugin-sdk").AgentPlugin;
|
|
6
|
+
export { CACHE_TTL_MS, CSV_CACHE_TTL_MS, CURSOR_GLOBAL_STORAGE_PATH, CURSOR_HOME, CURSOR_STATE_DB_PATH, CURSOR_WORKSPACE_STORAGE_PATH, RECONCILIATION_INTERVAL_MS, SESSION_AGGREGATE_CACHE_MAX, composerMetadataIndex, resetCsvCache, sessionAggregateCache, sessionCache, };
|
|
2
7
|
export default cursorAgentPlugin;
|
|
3
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnI,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAC1H,OAAO,EAAE,0BAA0B,EAAyC,MAAM,cAAc,CAAC;AACjG,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG3D,QAAA,MAAM,iBAAiB,4CAkFrB,CAAC;AAEH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,0BAA0B,EAC1B,WAAW,EACX,oBAAoB,EACpB,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,YAAY,GACb,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|