repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi/store.lua
Raw--- Reads Pi's on-disk session store to enumerate prior sessions for a cwd.
--- Pi offers no session-listing RPC, so a cwd picker reads the filesystem.
--- Sessions are bucketed per project; the bucket directory name encodes the
--- cwd but is lossy, so the authoritative cwd is each session file's header.
--- The directory Pi stores sessions in.
--- `PI_CODING_AGENT_SESSION_DIR` wins; otherwise XDG state, resolved at
--- runtime and never hardcoded.
local directory = function()
local explicit = vim.env.PI_CODING_AGENT_SESSION_DIR
if explicit and explicit ~= '' then return vim.fs.normalize( explicit ) end
local state = vim.env.XDG_STATE_HOME
if not state or state == '' then state = vim.fs.normalize( vim.env.HOME .. '/.local/state' ) end
return vim.fs.normalize( state .. '/pi/sessions' )
end
--- Pulls the id and timestamp out of a `<ISO>_<uuid>.jsonl` session filename.
local parse_name = function( name )
local timestamp, id = name:match '^(.+)_([^_]+)%.jsonl$'
if not id then return nil end
return { id = id, timestamp = timestamp, }
end
--- The `cwd` a session file was recorded for, from its header line.
local header_cwd = function( path )
local handle = io.open( path, 'r' )
if not handle then return nil end
local first = handle:read( 'l' )
handle:close()
if not first then return nil end
local ok, record = pcall( vim.json.decode, first )
if not ok or type( record ) ~= 'table' or record.type ~= 'session' then return nil end
return record.cwd
end
--- The session files directly inside one bucket directory.
local bucket_files = function( bucket )
local found = {}
local handle = vim.uv.fs_scandir( bucket )
if not handle then return found end
while true do
local name, kind = vim.uv.fs_scandir_next( handle )
if not name then break end
if kind == 'file' and name:match '%.jsonl$' then table.insert( found, name ) end
end
return found
end
--- Prior sessions recorded for a working directory, most recent first.
--- Each entry is `{ id, timestamp, file }`. Reads one header per bucket to
--- find the one that belongs to the cwd, then trusts filenames for ordering.
--- @param cwd string working directory to match
--- @param dir string? session directory override, for tests
local sessions = function( cwd, dir )
if type( cwd ) ~= 'string' or cwd == '' then return {} end
local root = dir and vim.fs.normalize( dir ) or directory()
local target = vim.fs.normalize( cwd )
local scan = vim.uv.fs_scandir( root )
if not scan then return {} end
local matches = {}
while true do
local name, kind = vim.uv.fs_scandir_next( scan )
if not name then break end
if kind == 'directory' then
local bucket = root .. '/' .. name
local files = bucket_files( bucket )
if #files > 0 and header_cwd( bucket .. '/' .. files[1] ) == target then
for _, file in ipairs( files ) do
local parsed = parse_name( file )
if parsed then
table.insert( matches, { id = parsed.id, timestamp = parsed.timestamp, file = bucket .. '/' .. file, } )
end
end
end
end
end
table.sort( matches, function( a, b ) return a.timestamp > b.timestamp end )
return matches
end
return {
directory = directory,
parse_name = parse_name,
sessions = sessions,
}