(
projectId: string,
options: { chat?: boolean | undefined } = {},
)
| 190 | } |
| 191 | |
| 192 | export function listProjectThreads( |
| 193 | projectId: string, |
| 194 | options: { chat?: boolean | undefined } = {}, |
| 195 | ): Thread[] { |
| 196 | const db = getThreadStateDatabase() |
| 197 | const rows = db |
| 198 | .prepare( |
| 199 | ` |
| 200 | SELECT |
| 201 | threads.id AS id, |
| 202 | threads.title AS title, |
| 203 | threads.session_path AS sessionPath, |
| 204 | COALESCE(inbox_items.last_assistant_preview, threads.last_assistant_preview) AS summary, |
| 205 | threads.running AS running, |
| 206 | COALESCE(inbox_items.unread, 0) AS unread, |
| 207 | threads.pinned AS pinned, |
| 208 | threads.last_modified_ms AS lastModifiedMs |
| 209 | FROM threads |
| 210 | LEFT JOIN inbox_items ON inbox_items.session_path = threads.session_path |
| 211 | WHERE threads.cwd = ? AND threads.archived = 0 |
| 212 | ORDER BY threads.pinned DESC, threads.last_modified_ms DESC, threads.title COLLATE NOCASE ASC |
| 213 | `, |
| 214 | ) |
| 215 | .all(projectId) as ThreadRow[] |
| 216 | |
| 217 | return rows |
| 218 | .filter((row) => matchesThreadScope(row.sessionPath, options)) |
| 219 | .map((row) => |
| 220 | mapThreadRow({ |
| 221 | ...row, |
| 222 | running: getEffectiveThreadRunningState(row.running, getLiveThread(row.sessionPath)) |
| 223 | ? 1 |
| 224 | : 0, |
| 225 | }), |
| 226 | ) |
| 227 | } |
| 228 | |
| 229 | export function listInboxThreads(): InboxThread[] { |
| 230 | const db = getThreadStateDatabase() |
no test coverage detected