Repository navigation
[G1] Cursor: event-level parity (messages, tool calls, file edits, model, usage, real timestamps) #166
Copy link
Copy link
Closed
Description
Part of #160 (group 1 — independent).
Problem
Cursor is advertised as a supported harness (README, SOURCE_CHOICES), but hydration stores prompts only:
ingest_cursor(crates/ai-hist/src/hydrate.rs:1546-1582) reads every line and callsai_hist_core::parse_cursor_text(crates/ai-hist-core/src/lib.rs:1175), which requiresrole == "user", readsmessage.content, strips the<user_query>wrapper, and returns text.- Result:
historyrows + asessionsrow. Zerosession_events,tool_calls,file_edits,models,token_json. - Every prompt gets the file mtime as its timestamp (
hydrate.rs; discoverydiscover.rs:1095-1100also setsfirst_activity_ms: None). - Relationship capability is
"never"(crates/ai-hist-core/src/relationships.rs:164). - Despite all of that,
HydrateSessionResult.capabilityreports"full"(see the capability-honesty issue).
Discovery already locates the files correctly: ~/.cursor/projects/<encoded-path>/agent-transcripts/<id>/<id>.jsonl (discover.rs:1033-1063), cwd from decode_cursor_project (lib.rs:3956).
Scope
- Characterize the format first. Capture real Cursor transcripts (several Cursor versions) into
tests/fixtures/cursor/(see the fixture-corpus issue): assistant records, tool calls (Cursor's tool names:read_file,edit_file,run_terminal_cmd,codebase_search,grep, etc.), tool results, thinking, and whatever usage/model metadata Cursor writes. Document the findings indocs/session-catalog.md"How each adapter works → cursor" before writing the parser, including an explicit list of fields Cursor does not write (so the capability matrix can say "unavailable" truthfully rather than "not implemented"). - Implement
ingest_cursor_transcriptincrates/ai-hist/src/lib.rsmirroring the Claude parser's shape:session_eventsfortext/thinking/tool_use/tool_result,tool_callswithtool_use_id/name/target/args_json/is_error,file_editsfor edit tools (withstructured_patch_jsonwhen Cursor records a diff,lines_added/removedvia the existingcount_patch_text),modelandtoken_jsonwhen present, real per-record timestamps when present (fall back to mtime only for records that carry no time, and record that fact in a diagnostic). - Discovery: populate
first_activity_ms,models,last_assistant_textfrom the head/tail scan when the format allows (discover.rsCursorProvider). - Relationships: if Cursor records subagent/background-agent spawns, wire them through
record_relationshipand updaterelationship_capabilities; otherwise document "never" with the evidence. - Update the un-ignored corpus tests,
docs/session-catalog.mdmatrix, andREADME.md("Provider-aware evidence" paragraph) to state exactly what Cursor exposes.
Acceptance
- Snapshot for the Cursor fixture contains
session_eventsof all four kinds, ≥1tool_callsrow, ≥1file_editsrow, and non-nullts_msthat differ across records. ai-hist sessions tools cursor <id>andai-hist sessions edits cursor <id>return rows.getSessionEventsPage({source:'cursor'})events carrytokenUsage/modelwhen the fixture has them; when Cursor genuinely lacks usage, the capability matrix says so andhydrateSessionreportspartial(after the honesty issue lands) rather thanfull.- No prompt timestamp is the file mtime unless the record has no timestamp field, and that case emits a
CURSOR_TIMESTAMP_FROM_MTIMEdiagnostic.
Out of scope
Cost (burn); cloud/remote Cursor sessions.
Reactions are currently unavailable
Activity
Merge branch 'main' into claude/g1-166-cursor-parity