Luigit
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 Pi's agent directory.
local directory = function()
  local explicit = vim.env.PI_CODING_AGENT_SESSION_DIR
  if explicit and explicit ~= '' then return vim.fs.normalize( explicit ) end
  local agent = vim.env.PI_CODING_AGENT_DIR
  if not agent or agent == '' then agent = ( vim.env.HOME or vim.uv.os_homedir() ) .. '/.pi/agent' end
  return vim.fs.normalize( agent .. '/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 = function( path )
  if type( path ) ~= 'string' or path == '' then return nil end
  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
end

local valid_file = function( path, id )
  local record = header( path )
  return record ~= nil and record.id == id
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 }`. Every header determines its cwd;
--- default bucket storage and explicit flat directories are both supported.
--- @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 = {}
  local add = function( file )
    local record = header( file )
    local recorded = record and record.cwd
    if type( recorded ) ~= 'string' then return end
    recorded = vim.fs.normalize( recorded )
    local same = recorded == target
    if vim.fn.has 'win32' == 1 then same = recorded:lower() == target:lower() end
    local parsed = parse_name( vim.fs.basename( file ) )
    if same and parsed then
      table.insert( matches, { id = parsed.id, timestamp = parsed.timestamp, file = file, } )
    end
  end
  while true do
    local name, kind = vim.uv.fs_scandir_next( scan )
    if not name then break end
    if kind == 'file' and name:match '%.jsonl$' then
      add( root .. '/' .. name )
    elseif kind == 'directory' then
      local bucket = root .. '/' .. name
      for _, file in ipairs( bucket_files( bucket ) ) do add( bucket .. '/' .. file ) end
    end
  end

  table.sort( matches, function( a, b ) return a.timestamp > b.timestamp end )
  return matches
end

return {
  valid_file = valid_file,
  directory = directory,
  parse_name = parse_name,
  sessions = sessions,
}