Class: Agent::Sessions::Adapters::Cursor

Inherits:
Base
  • Object
show all
Defined in:
lib/agent/sessions/adapters/cursor.rb

Constant Summary

Constants inherited from Base

Base::FIDELITIES

Constants included from Enumeration

Enumeration::MAX_LINE_BYTES

Instance Method Summary collapse

Methods inherited from Base

#base_dir, fidelity_value, homedir_config, #initialize, #locate, reader_class, #retention, #retention_source, store_configs, #verify

Methods included from Enumeration

#bytes_for, #encode_project, #project_dir_name, #project_paths, #sessions, #sessions_for_project

Constructor Details

This class inherits a constructor from Agent::Sessions::Adapters::Base

Instance Method Details

#project_path_for(path) ⇒ Object

cwd's presence in meta.json is not enough on its own (rule 1): the key can hold a Hash, an Integer, anything JSON allows, and project_paths' .uniq.sort raises on a non-String member. is_a?(String) is the guard, not merely a style preference.



90
91
92
93
# File 'lib/agent/sessions/adapters/cursor.rb', line 90

def project_path_for(path)
  cwd = meta_for(path)["cwd"]
  cwd if cwd.is_a?(String)
end

#session_id_from(path) ⇒ Object

chats///store.db — two nested ids (design doc 16 Q5), so the session id keeps both. The blob store is never opened here; the sibling meta.json is the metadata source (8.3), with stat as fallback.

Pure string manipulation on path — File.basename/File.dirname never raise for any String input, so this hook cannot violate rule 3 (build_session lets a raising hook propagate) regardless of shape. A path shallower than two segments is not reachable through this store's OWN enumeration: the glob above is "//store.db", and Dir.glob's "*" never crosses a "/", so every path this adapter actually enumerates is exactly two directories deep, by construction, not by convention (see test_session_id_from_does_not_raise_for_a_shallow_path, which calls this hook directly to pin the behaviour for a caller that bypasses the glob).



72
73
74
75
76
# File 'lib/agent/sessions/adapters/cursor.rb', line 72

def session_id_from(path)
  uuid = File.basename(File.dirname(path))
  chat = File.basename(File.dirname(File.dirname(path)))
  "#{chat}/#{uuid}"
end

#started_at_for(path, stat) ⇒ Object



78
79
80
# File 'lib/agent/sessions/adapters/cursor.rb', line 78

def started_at_for(path, stat)
  meta_time(path, "createdAtMs") || super
end

#updated_at_for(path, stat) ⇒ Object



82
83
84
# File 'lib/agent/sessions/adapters/cursor.rb', line 82

def updated_at_for(path, stat)
  meta_time(path, "updatedAtMs") || super
end

#warningsObject

meta.json's field names (createdAtMs, updatedAtMs, cwd) are read from design doc 8.3, itself written from a machine that had them to check against — this machine has no ~/.cursor/chats (Cursor CLI is a separate product from the Cursor editor and is simply not installed here). Gated, the same shape as pi's identical warning about its own unverified header key and cursor_ide's about its real session location below: a "here is what breaks, please act on it" report reaches only someone whose declared store actually exists.

Why THIS unverified assumption specifically needs a warning, where some others might get away without one: the failure is silent and looks correct. If createdAtMs/updatedAtMs are the wrong keys, meta_time returns nil and started_at_for/updated_at_for fall back to stat.birthtime/mtime — real file timestamps, not an obviously broken value. If cwd is the wrong key, project_path_for returns nil exactly the way it correctly does for a chat that genuinely has no recorded cwd. Nothing in the output distinguishes "Cursor recorded no project" from "the gem read the wrong key" — projects, du --by project, and sessions_for_project all silently under-report Cursor, with no error and no implausible-looking number anywhere to notice.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/agent/sessions/adapters/cursor.rb', line 46

def warnings
  list = super
  if primary_layer.exists?
    list << "Cursor's meta.json field names (createdAtMs, updatedAtMs, cwd) are unverified " \
            "against a real chat — this machine has none to check them against. If `projects` " \
            "or `du --by project` report nothing for Cursor despite it having chats, or every " \
            "session's started_at matches its file's own mtime exactly, those keys may be " \
            "wrong; please open an issue with the first bytes of one real meta.json"
  end
  list
end