Skip to main content

kaizen/store/sqlite/
sessions.rs

1use super::rows::*;
2use super::*;
3
4impl Store {
5    pub fn upsert_session(&self, s: &SessionRecord) -> Result<()> {
6        self.conn.execute(
7            "INSERT INTO sessions (
8                id, agent, model, workspace, started_at_ms, ended_at_ms, status, trace_path,
9                start_commit, end_commit, branch, dirty_start, dirty_end, repo_binding_source,
10                prompt_fingerprint, parent_session_id, agent_version, os, arch,
11                repo_file_count, repo_total_loc
12             )
13             VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15,
14                ?16, ?17, ?18, ?19, ?20, ?21)
15             ON CONFLICT(id) DO UPDATE SET
16               agent=excluded.agent, model=excluded.model, workspace=excluded.workspace,
17               started_at_ms=excluded.started_at_ms, ended_at_ms=excluded.ended_at_ms,
18               status=excluded.status, trace_path=excluded.trace_path,
19               start_commit=excluded.start_commit, end_commit=excluded.end_commit,
20               branch=excluded.branch, dirty_start=excluded.dirty_start,
21               dirty_end=excluded.dirty_end, repo_binding_source=excluded.repo_binding_source,
22               prompt_fingerprint=excluded.prompt_fingerprint,
23               parent_session_id=excluded.parent_session_id,
24               agent_version=excluded.agent_version, os=excluded.os, arch=excluded.arch,
25               repo_file_count=excluded.repo_file_count, repo_total_loc=excluded.repo_total_loc",
26            params![
27                s.id,
28                s.agent,
29                s.model,
30                s.workspace,
31                s.started_at_ms as i64,
32                s.ended_at_ms.map(|v| v as i64),
33                format!("{:?}", s.status),
34                s.trace_path,
35                s.start_commit,
36                s.end_commit,
37                s.branch,
38                s.dirty_start.map(bool_to_i64),
39                s.dirty_end.map(bool_to_i64),
40                s.repo_binding_source.clone().unwrap_or_default(),
41                s.prompt_fingerprint.as_deref(),
42                s.parent_session_id.as_deref(),
43                s.agent_version.as_deref(),
44                s.os.as_deref(),
45                s.arch.as_deref(),
46                s.repo_file_count.map(|v| v as i64),
47                s.repo_total_loc.map(|v| v as i64),
48            ],
49        )?;
50        self.conn.execute(
51            "INSERT INTO session_repo_binding (
52                session_id, start_commit, end_commit, branch, dirty_start, dirty_end, repo_binding_source
53             ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
54             ON CONFLICT(session_id) DO UPDATE SET
55                start_commit=excluded.start_commit,
56                end_commit=excluded.end_commit,
57                branch=excluded.branch,
58                dirty_start=excluded.dirty_start,
59                dirty_end=excluded.dirty_end,
60                repo_binding_source=excluded.repo_binding_source",
61            params![
62                s.id,
63                s.start_commit,
64                s.end_commit,
65                s.branch,
66                s.dirty_start.map(bool_to_i64),
67                s.dirty_end.map(bool_to_i64),
68                s.repo_binding_source.clone().unwrap_or_default(),
69            ],
70        )?;
71        Ok(())
72    }
73
74    /// Insert a minimal session row if none exists. Used by hook ingestion when
75    /// the first observed event is not `SessionStart` (hooks installed mid-session).
76    pub fn ensure_session_stub(
77        &self,
78        id: &str,
79        agent: &str,
80        workspace: &str,
81        started_at_ms: u64,
82    ) -> Result<()> {
83        self.conn.execute(
84            "INSERT OR IGNORE INTO sessions (
85                id, agent, model, workspace, started_at_ms, ended_at_ms, status, trace_path,
86                start_commit, end_commit, branch, dirty_start, dirty_end, repo_binding_source,
87                prompt_fingerprint, parent_session_id, agent_version, os, arch, repo_file_count, repo_total_loc
88             ) VALUES (?1, ?2, NULL, ?3, ?4, NULL, 'Running', '', NULL, NULL, NULL, NULL, NULL, '',
89                NULL, NULL, NULL, NULL, NULL, NULL, NULL)",
90            params![id, agent, workspace, started_at_ms as i64],
91        )?;
92        Ok(())
93    }
94
95    /// Update only status for existing session.
96    pub fn update_session_status(&self, id: &str, status: SessionStatus) -> Result<()> {
97        self.conn.execute(
98            "UPDATE sessions SET status = ?1 WHERE id = ?2",
99            params![format!("{:?}", status), id],
100        )?;
101        Ok(())
102    }
103}