Repository navigation
Conversation
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #27.
Do not merge before operator review. It depends on an API whose real responses I could not call (no key), and on a key type an individual account may not be able to get.
What it does
cursor(src/providers/cursor.mjs) next to Claude and Codex; sessions show a provider badge in the list.src/cursor-api.mjs: token store, HTTP client, event cache. Sync runs on save, hourly and on demand, in the server (not in discovery), so providers stay synchronous and offline.API used
Cursor Admin API,
POST https://api.cursor.com/teams/filtered-usage-events(per-request events: model,conversationId,tokenUsagewith input/output/cacheWrite/cacheRead tokens andtotalCents). Auth: HTTP Basic, key as username, empty password.Individual accounts: per the docs, Admin API keys are created by team administrators (API Keys page in the dashboard) and the API is listed for Enterprise teams. I found no documented personal usage endpoint. The other key types (Analytics, Cloud Agents user key, Origin personal key) are not usage-event APIs. So a Pro/individual account probably cannot use this. If the operator has no team plan, the panel will report 401/403 and nothing else works. This is the main open point; an undocumented dashboard-cookie endpoint exists but I did not use it (unofficial, session cookie as secret).
Session mapping
Cursor has no session id. Decision for the operator: sessions group by
conversationIdwhen present; otherwise per user, a gap of more than 30 minutes starts a new session. Each event is one request = one turn with one call. No prompts are available (humanMsgs0, no first prompt); title is "Cursor conversation " or "Cursor · email". An admin key returns the whole team's events, so a team shows every member's sessions.Cost
Not priced through the Claude/Codex tables (Cursor model names differ and Cursor already reports money). Cost is
tokenUsage.totalCentswith confidencereported. Request-based events (isTokenBasedCallfalse) have no tokens or amount, so such sessions arepartial. Per-token-class cost parts are zero (Cursor does not give them), so the in/out/cache$sub-figures show $0 for Cursor rows while the total is right. Once #28 lands, tokens could be re-priced through its entry point; not done here to avoid its files.Token handling
~/.config/agent-atlas/cursor-token(dir 0700, file 0600;AGENT_ATLAS_CONFIG_DIRoverrides). Removing the key also deletes the cached events.https://api.cursor.com(no env override,redirect: "error"). Error messages carry the HTTP status only, never the response body.application/jsonand a same-originOrigin, so another web page cannot drive a local server.Tests
test/cursor.test.mjs(8 tests, mocked HTTP, fixturetest/fixtures/cursor-usage-events.jsonmodelled on the documented response shape): token storage/permissions/redaction, Basic auth and host, error mapping, pagination and merge, grouping, tree tokens/cost, and the server flow.typecheckandbuildpass.npm test: the same 4 failures as main (browser test and 3querySessionsdate tests) remain; I left them alone.Unverified
Field names and shapes come from the docs, not from a real response. Event time range limits for this endpoint are unstated (I request 30 days). A real key may reveal differences.
Review fixes (second push)
/api/*route only accepts Host127.0.0.1:<port>,localhost:<port>,[::1]:<port>(plusserve({ allowedHosts })). Changes (PUT/POST/DELETE) also need a matching Origin,application/json, and a per-launch CSRF token (injected into the served page as a meta tag, sent asx-atlas-csrf).wx, 0600) temp file, so a planted symlink is never followed; config dir must be owned by the user and is tightened to 0700.chargedCents, falling back tototalCents; each tree recordscostBasis(chargedCents,totalCentsormixed). This supersedes the Cost section above: request-based events get their charged cost instead of making the session partial. Included usage may show $0 charged.test/cursor.test.mjs(rebound Host on reads and writes, missing Origin/CSRF, symlink, in-flight sync, charged vs total, truncation). Same 4 pre-existing failures on main elsewhere.Last round