diff options
| author | Adam Malczewski <[email protected]> | 2026-05-21 19:52:35 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-21 19:52:35 +0900 |
| commit | 4ba2673557c7cfd0bc31b03e2c35ab5e1efe60e7 (patch) | |
| tree | dddae8fc37a12157f4c8e840475e9e5d6203464a /packages/core/src/db/tabs.ts | |
| parent | 55633c90c0d96e62153a4b6655f3f833a3b46ad4 (diff) | |
| download | dispatch-4ba2673557c7cfd0bc31b03e2c35ab5e1efe60e7.tar.gz dispatch-4ba2673557c7cfd0bc31b03e2c35ab5e1efe60e7.zip | |
feat: tab system with per-tab agents, DB persistence, and DaisyUI tabs-lift UI
- Add tabs, messages, and settings tables to SQLite database
- Backend: refactor AgentManager to manage per-tab Agent instances via Map<tabId, TabAgent>
- Backend: WebSocket events tagged with tabId for multiplexing
- Backend: tab CRUD routes (create, list, update, archive, messages)
- Backend: persist user and assistant messages to DB during chat
- Frontend: new tabStore replaces single chatStore with multi-tab reactive state
- Frontend: TabBar component using DaisyUI tabs-lift style with status dots
- Frontend: Settings sidebar panel for title generation model selection
- Frontend: wire ChatPanel, ChatInput, Header to use tabStore
- Fix HMR listener accumulation via wsClient.clearCallbacks()
- Delete old single-chat chatStore (chat.svelte.ts)
Diffstat (limited to 'packages/core/src/db/tabs.ts')
| -rw-r--r-- | packages/core/src/db/tabs.ts | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/packages/core/src/db/tabs.ts b/packages/core/src/db/tabs.ts new file mode 100644 index 0000000..0f4511f --- /dev/null +++ b/packages/core/src/db/tabs.ts @@ -0,0 +1,73 @@ +import { getDatabase } from "./index.js"; + +export interface TabRow { + id: string; + title: string; + keyId: string | null; + modelId: string | null; + status: string; + isOpen: boolean; + position: number; + createdAt: number; + updatedAt: number; +} + +function rowToTab(row: Record<string, unknown>): TabRow { + return { + id: row.id as string, + title: row.title as string, + keyId: row.key_id as string | null, + modelId: row.model_id as string | null, + status: row.status as string, + isOpen: (row.is_open as number) === 1, + position: row.position as number, + createdAt: row.created_at as number, + updatedAt: row.updated_at as number, + }; +} + +export function createTab(id: string, title: string): TabRow { + const db = getDatabase(); + const now = Date.now(); + const maxPos = db.query("SELECT COALESCE(MAX(position), -1) as max_pos FROM tabs WHERE is_open = 1").get() as { max_pos: number }; + const position = (maxPos?.max_pos ?? -1) + 1; + db.query( + `INSERT INTO tabs (id, title, key_id, model_id, status, is_open, position, created_at, updated_at) + VALUES ($id, $title, NULL, NULL, 'idle', 1, $position, $now, $now)`, + ).run({ $id: id, $title: title, $position: position, $now: now }); + return { id, title, keyId: null, modelId: null, status: "idle", isOpen: true, position, createdAt: now, updatedAt: now }; +} + +export function getTab(id: string): TabRow | null { + const db = getDatabase(); + const row = db.query("SELECT * FROM tabs WHERE id = $id").get({ $id: id }) as Record<string, unknown> | null; + return row ? rowToTab(row) : null; +} + +export function listOpenTabs(): TabRow[] { + const db = getDatabase(); + const rows = db.query("SELECT * FROM tabs WHERE is_open = 1 ORDER BY position ASC").all() as Array<Record<string, unknown>>; + return rows.map(rowToTab); +} + +export function updateTabTitle(id: string, title: string): void { + const db = getDatabase(); + db.query("UPDATE tabs SET title = $title, updated_at = $now WHERE id = $id").run({ $id: id, $title: title, $now: Date.now() }); +} + +export function updateTabModel(id: string, keyId: string | null, modelId: string | null): void { + const db = getDatabase(); + db.query("UPDATE tabs SET key_id = $keyId, model_id = $modelId, updated_at = $now WHERE id = $id").run({ + $id: id, $keyId: keyId, $modelId: modelId, $now: Date.now(), + }); +} + +export function updateTabStatus(id: string, status: string): void { + const db = getDatabase(); + db.query("UPDATE tabs SET status = $status, updated_at = $now WHERE id = $id").run({ $id: id, $status: status, $now: Date.now() }); +} + +export function archiveTab(id: string): void { + const db = getDatabase(); + db.query("UPDATE tabs SET is_open = 0, updated_at = $now WHERE id = $id").run({ $id: id, $now: Date.now() }); +} |
