""" session/jsonl_repo.jl - JSONL session repository This module provides a JSONL-based session repository implementation. """ module JsonlRepo using ..Types: * using ..SessionStorage: SessionStorage, SessionMetadata using ..JsonlStorage: JsonlSessionStorage, headerToSessionMetadata using ..MemoryRepo: createSessionId, createTimestamp, getEntriesToFork, toSession using ..HarnessTypes: SessionRepo, SessionForkOptions # ============================================================================ # JSONL session repository # ============================================================================ mutable struct JsonlSessionRepo <: SessionRepo{ JsonlSessionMetadata, JsonlSessionCreateOptions, JsonlSessionListOptions } fs::Any sessions_root_input::String sessions_root::Union{String, Nothing} function JsonlSessionRepo(; sessions_root::String, fs::Any) new(fs, sessions_root, nothing) end end # ============================================================================ # Session repo methods # ============================================================================ function create(repo::JsonlSessionRepo, options::JsonlSessionCreateOptions)::Session id = if haskey(options, :id) && !isnothing(options[:id]) options[:id] else createSessionId() end created_at = createTimestamp() session_dir = getSessionDir(repo, options.cwd) file_path = createSessionFilePath(repo, options.cwd, id, created_at) storage = JsonlSessionStorage( file_path, SessionHeader( "session", 3, id, created_at, options.cwd, get(options, :parentSessionPath, nothing), get(options, :metadata, nothing), ), SessionTreeEntry[], nothing, ) return toSession(storage) end function open(repo::JsonlSessionRepo, metadata::JsonlSessionMetadata)::Session # TODO: Open existing file return toSession(JsonlSessionStorage( metadata.path, SessionHeader( "session", 3, metadata.id, metadata.created_at, metadata.cwd, metadata.parent_session_path, metadata.metadata, ), SessionTreeEntry[], nothing, )) end function list(repo::JsonlSessionRepo, options::JsonlSessionListOptions=JsonlSessionListOptions())::Vector{JsonlSessionMetadata} # TODO: List sessions return JsonlSessionMetadata[] end function delete(repo::JsonlSessionRepo, metadata::JsonlSessionMetadata)::Nothing # TODO: Delete session file return nothing end function fork(repo::JsonlSessionRepo, source::JsonlSessionMetadata, options::Dict{String, Any})::Session # TODO: Fork session return create(repo, JsonlSessionCreateOptions( cwd=get(options, "cwd", ""), id=get(options, "id", createSessionId()), )) end # ============================================================================ # Helper functions # ============================================================================ function getSessionsRoot(repo::JsonlSessionRepo)::String if isnothing(repo.sessions_root) repo.sessions_root = getFileSystemResultOrThrow( absolutePath(repo.fs, repo.sessions_root_input), "Failed to resolve sessions root $(repo.sessions_root_input)", ) end return repo.sessions_root end function getSessionDir(repo::JsonlSessionRepo, cwd::String)::String return getFileSystemResultOrThrow( joinPath(repo.fs, [getSessionsRoot(repo), encodeCwd(cwd)]), "Failed to resolve session directory for $(cwd)", ) end function encodeCwd(cwd::String)::String result = replace(cwd, r"^[/\\]" => "") result = replace(result, r"[/\\:]" => "-") return "--$(result)--" end function createSessionFilePath(repo::JsonlSessionRepo, cwd::String, session_id::String, timestamp::String)::String return getFileSystemResultOrThrow( joinPath(repo.fs, [ getSessionDir(repo, cwd), "$(replace(timestamp, r"[:.]" => "-"))_$(session_id).jsonl", ]), "Failed to resolve session file path for $(session_id)", ) end function getFileSystemResultOrThrow(result::Result, message::String) if !result.ok code = result.error.code == "not_found" ? "not_found" : "storage" throw(SessionError(code, "$(message): $(result.error.message)", result.error)) end return result.value end end