sparkecoder 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import * as drizzle_orm_better_sqlite3 from 'drizzle-orm/better-sqlite3';
2
2
  import Database from 'better-sqlite3';
3
- import { s as schema, M as ModelMessage, a as Message, N as NewSession, S as Session, b as SessionConfig, L as LoadedSkill, c as NewTodoItem, T as TodoItem, d as NewToolExecution, e as ToolExecution, A as ActiveStream, f as NewTerminal, g as Terminal } from '../schema-cUDLVN-b.js';
3
+ import { C as Checkpoint, F as FileBackup, s as schema, M as ModelMessage, a as Message, N as NewSession, S as Session, b as SessionConfig, L as LoadedSkill, c as NewTodoItem, T as TodoItem, d as NewToolExecution, e as ToolExecution, A as ActiveStream, f as NewTerminal, g as Terminal } from '../schema-CkrIadxa.js';
4
4
  import 'drizzle-orm/sqlite-core';
5
5
 
6
6
  declare function initDatabase(dbPath: string): drizzle_orm_better_sqlite3.BetterSQLite3Database<typeof schema> & {
@@ -49,6 +49,11 @@ declare const messageQueries: {
49
49
  getRecentBySession(sessionId: string, limit?: number): Message[];
50
50
  countBySession(sessionId: string): number;
51
51
  deleteBySession(sessionId: string): number;
52
+ /**
53
+ * Delete all messages with sequence >= the given sequence number
54
+ * (Used when reverting to a checkpoint)
55
+ */
56
+ deleteFromSequence(sessionId: string, fromSequence: number): number;
52
57
  };
53
58
  declare const toolExecutionQueries: {
54
59
  create(data: Omit<NewToolExecution, "id" | "startedAt">): ToolExecution;
@@ -59,6 +64,11 @@ declare const toolExecutionQueries: {
59
64
  reject(id: string): ToolExecution | undefined;
60
65
  complete(id: string, output: unknown, error?: string): ToolExecution | undefined;
61
66
  getBySession(sessionId: string): ToolExecution[];
67
+ /**
68
+ * Delete all tool executions after a given timestamp
69
+ * (Used when reverting to a checkpoint)
70
+ */
71
+ deleteAfterTime(sessionId: string, afterTime: Date): number;
62
72
  };
63
73
  declare const todoQueries: {
64
74
  create(data: Omit<NewTodoItem, "id" | "createdAt" | "updatedAt">): TodoItem;
@@ -94,5 +104,46 @@ declare const activeStreamQueries: {
94
104
  markError(streamId: string): ActiveStream | undefined;
95
105
  deleteBySession(sessionId: string): number;
96
106
  };
107
+ declare const checkpointQueries: {
108
+ create(data: {
109
+ sessionId: string;
110
+ messageSequence: number;
111
+ gitHead?: string;
112
+ }): Checkpoint;
113
+ getById(id: string): Checkpoint | undefined;
114
+ getBySession(sessionId: string): Checkpoint[];
115
+ getByMessageSequence(sessionId: string, messageSequence: number): Checkpoint | undefined;
116
+ getLatest(sessionId: string): Checkpoint | undefined;
117
+ /**
118
+ * Delete all checkpoints after a given sequence number
119
+ * (Used when reverting to a checkpoint)
120
+ */
121
+ deleteAfterSequence(sessionId: string, messageSequence: number): number;
122
+ deleteBySession(sessionId: string): number;
123
+ };
124
+ declare const fileBackupQueries: {
125
+ create(data: {
126
+ checkpointId: string;
127
+ sessionId: string;
128
+ filePath: string;
129
+ originalContent: string | null;
130
+ existed: boolean;
131
+ }): FileBackup;
132
+ getByCheckpoint(checkpointId: string): FileBackup[];
133
+ getBySession(sessionId: string): FileBackup[];
134
+ /**
135
+ * Get all file backups from a given checkpoint sequence onwards (inclusive)
136
+ * (Used when reverting - need to restore these files)
137
+ *
138
+ * When reverting to checkpoint X, we need backups from checkpoint X and all later ones
139
+ * because checkpoint X's backups represent the state BEFORE processing message X.
140
+ */
141
+ getFromSequence(sessionId: string, messageSequence: number): FileBackup[];
142
+ /**
143
+ * Check if a file already has a backup in the current checkpoint
144
+ */
145
+ hasBackup(checkpointId: string, filePath: string): boolean;
146
+ deleteBySession(sessionId: string): number;
147
+ };
97
148
 
98
- export { ActiveStream, Message, ModelMessage, Session, SessionConfig, Terminal, TodoItem, ToolExecution, activeStreamQueries, closeDatabase, getDb, initDatabase, messageQueries, sessionQueries, skillQueries, terminalQueries, todoQueries, toolExecutionQueries };
149
+ export { ActiveStream, Checkpoint, FileBackup, Message, ModelMessage, Session, SessionConfig, Terminal, TodoItem, ToolExecution, activeStreamQueries, checkpointQueries, closeDatabase, fileBackupQueries, getDb, initDatabase, messageQueries, sessionQueries, skillQueries, terminalQueries, todoQueries, toolExecutionQueries };
package/dist/db/index.js CHANGED
@@ -14,6 +14,8 @@ import { nanoid } from "nanoid";
14
14
  var schema_exports = {};
15
15
  __export(schema_exports, {
16
16
  activeStreams: () => activeStreams,
17
+ checkpoints: () => checkpoints,
18
+ fileBackups: () => fileBackups,
17
19
  loadedSkills: () => loadedSkills,
18
20
  messages: () => messages,
19
21
  sessions: () => sessions,
@@ -98,6 +100,28 @@ var activeStreams = sqliteTable("active_streams", {
98
100
  createdAt: integer("created_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
99
101
  finishedAt: integer("finished_at", { mode: "timestamp" })
100
102
  });
103
+ var checkpoints = sqliteTable("checkpoints", {
104
+ id: text("id").primaryKey(),
105
+ sessionId: text("session_id").notNull().references(() => sessions.id, { onDelete: "cascade" }),
106
+ // The message sequence number this checkpoint was created BEFORE
107
+ // (i.e., the state before this user message was processed)
108
+ messageSequence: integer("message_sequence").notNull(),
109
+ // Optional git commit hash if in a git repo
110
+ gitHead: text("git_head"),
111
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
112
+ });
113
+ var fileBackups = sqliteTable("file_backups", {
114
+ id: text("id").primaryKey(),
115
+ checkpointId: text("checkpoint_id").notNull().references(() => checkpoints.id, { onDelete: "cascade" }),
116
+ sessionId: text("session_id").notNull().references(() => sessions.id, { onDelete: "cascade" }),
117
+ // Relative path from working directory
118
+ filePath: text("file_path").notNull(),
119
+ // Original content (null means file didn't exist before)
120
+ originalContent: text("original_content"),
121
+ // Whether the file existed before this checkpoint
122
+ existed: integer("existed", { mode: "boolean" }).notNull().default(true),
123
+ createdAt: integer("created_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
124
+ });
101
125
 
102
126
  // src/db/index.ts
103
127
  var db = null;
@@ -182,12 +206,35 @@ function initDatabase(dbPath) {
182
206
  finished_at INTEGER
183
207
  );
184
208
 
209
+ -- Checkpoints table - created before each user message
210
+ CREATE TABLE IF NOT EXISTS checkpoints (
211
+ id TEXT PRIMARY KEY,
212
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
213
+ message_sequence INTEGER NOT NULL,
214
+ git_head TEXT,
215
+ created_at INTEGER NOT NULL
216
+ );
217
+
218
+ -- File backups table - stores original file content
219
+ CREATE TABLE IF NOT EXISTS file_backups (
220
+ id TEXT PRIMARY KEY,
221
+ checkpoint_id TEXT NOT NULL REFERENCES checkpoints(id) ON DELETE CASCADE,
222
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
223
+ file_path TEXT NOT NULL,
224
+ original_content TEXT,
225
+ existed INTEGER NOT NULL DEFAULT 1,
226
+ created_at INTEGER NOT NULL
227
+ );
228
+
185
229
  CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
186
230
  CREATE INDEX IF NOT EXISTS idx_tool_executions_session ON tool_executions(session_id);
187
231
  CREATE INDEX IF NOT EXISTS idx_todo_items_session ON todo_items(session_id);
188
232
  CREATE INDEX IF NOT EXISTS idx_loaded_skills_session ON loaded_skills(session_id);
189
233
  CREATE INDEX IF NOT EXISTS idx_terminals_session ON terminals(session_id);
190
234
  CREATE INDEX IF NOT EXISTS idx_active_streams_session ON active_streams(session_id);
235
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_session ON checkpoints(session_id);
236
+ CREATE INDEX IF NOT EXISTS idx_file_backups_checkpoint ON file_backups(checkpoint_id);
237
+ CREATE INDEX IF NOT EXISTS idx_file_backups_session ON file_backups(session_id);
191
238
  `);
192
239
  return db;
193
240
  }
@@ -304,6 +351,19 @@ var messageQueries = {
304
351
  deleteBySession(sessionId) {
305
352
  const result = getDb().delete(messages).where(eq(messages.sessionId, sessionId)).run();
306
353
  return result.changes;
354
+ },
355
+ /**
356
+ * Delete all messages with sequence >= the given sequence number
357
+ * (Used when reverting to a checkpoint)
358
+ */
359
+ deleteFromSequence(sessionId, fromSequence) {
360
+ const result = getDb().delete(messages).where(
361
+ and(
362
+ eq(messages.sessionId, sessionId),
363
+ sql`sequence >= ${fromSequence}`
364
+ )
365
+ ).run();
366
+ return result.changes;
307
367
  }
308
368
  };
309
369
  var toolExecutionQueries = {
@@ -347,6 +407,19 @@ var toolExecutionQueries = {
347
407
  },
348
408
  getBySession(sessionId) {
349
409
  return getDb().select().from(toolExecutions).where(eq(toolExecutions.sessionId, sessionId)).orderBy(toolExecutions.startedAt).all();
410
+ },
411
+ /**
412
+ * Delete all tool executions after a given timestamp
413
+ * (Used when reverting to a checkpoint)
414
+ */
415
+ deleteAfterTime(sessionId, afterTime) {
416
+ const result = getDb().delete(toolExecutions).where(
417
+ and(
418
+ eq(toolExecutions.sessionId, sessionId),
419
+ sql`started_at > ${afterTime.getTime()}`
420
+ )
421
+ ).run();
422
+ return result.changes;
350
423
  }
351
424
  };
352
425
  var todoQueries = {
@@ -490,9 +563,120 @@ var activeStreamQueries = {
490
563
  return result.changes;
491
564
  }
492
565
  };
566
+ var checkpointQueries = {
567
+ create(data) {
568
+ const id = nanoid();
569
+ const result = getDb().insert(checkpoints).values({
570
+ id,
571
+ sessionId: data.sessionId,
572
+ messageSequence: data.messageSequence,
573
+ gitHead: data.gitHead,
574
+ createdAt: /* @__PURE__ */ new Date()
575
+ }).returning().get();
576
+ return result;
577
+ },
578
+ getById(id) {
579
+ return getDb().select().from(checkpoints).where(eq(checkpoints.id, id)).get();
580
+ },
581
+ getBySession(sessionId) {
582
+ return getDb().select().from(checkpoints).where(eq(checkpoints.sessionId, sessionId)).orderBy(checkpoints.messageSequence).all();
583
+ },
584
+ getByMessageSequence(sessionId, messageSequence) {
585
+ return getDb().select().from(checkpoints).where(
586
+ and(
587
+ eq(checkpoints.sessionId, sessionId),
588
+ eq(checkpoints.messageSequence, messageSequence)
589
+ )
590
+ ).get();
591
+ },
592
+ getLatest(sessionId) {
593
+ return getDb().select().from(checkpoints).where(eq(checkpoints.sessionId, sessionId)).orderBy(desc(checkpoints.messageSequence)).limit(1).get();
594
+ },
595
+ /**
596
+ * Delete all checkpoints after a given sequence number
597
+ * (Used when reverting to a checkpoint)
598
+ */
599
+ deleteAfterSequence(sessionId, messageSequence) {
600
+ const result = getDb().delete(checkpoints).where(
601
+ and(
602
+ eq(checkpoints.sessionId, sessionId),
603
+ sql`message_sequence > ${messageSequence}`
604
+ )
605
+ ).run();
606
+ return result.changes;
607
+ },
608
+ deleteBySession(sessionId) {
609
+ const result = getDb().delete(checkpoints).where(eq(checkpoints.sessionId, sessionId)).run();
610
+ return result.changes;
611
+ }
612
+ };
613
+ var fileBackupQueries = {
614
+ create(data) {
615
+ const id = nanoid();
616
+ const result = getDb().insert(fileBackups).values({
617
+ id,
618
+ checkpointId: data.checkpointId,
619
+ sessionId: data.sessionId,
620
+ filePath: data.filePath,
621
+ originalContent: data.originalContent,
622
+ existed: data.existed,
623
+ createdAt: /* @__PURE__ */ new Date()
624
+ }).returning().get();
625
+ return result;
626
+ },
627
+ getByCheckpoint(checkpointId) {
628
+ return getDb().select().from(fileBackups).where(eq(fileBackups.checkpointId, checkpointId)).all();
629
+ },
630
+ getBySession(sessionId) {
631
+ return getDb().select().from(fileBackups).where(eq(fileBackups.sessionId, sessionId)).orderBy(fileBackups.createdAt).all();
632
+ },
633
+ /**
634
+ * Get all file backups from a given checkpoint sequence onwards (inclusive)
635
+ * (Used when reverting - need to restore these files)
636
+ *
637
+ * When reverting to checkpoint X, we need backups from checkpoint X and all later ones
638
+ * because checkpoint X's backups represent the state BEFORE processing message X.
639
+ */
640
+ getFromSequence(sessionId, messageSequence) {
641
+ const checkpointsFrom = getDb().select().from(checkpoints).where(
642
+ and(
643
+ eq(checkpoints.sessionId, sessionId),
644
+ sql`message_sequence >= ${messageSequence}`
645
+ )
646
+ ).all();
647
+ if (checkpointsFrom.length === 0) {
648
+ return [];
649
+ }
650
+ const checkpointIds = checkpointsFrom.map((c) => c.id);
651
+ const allBackups = [];
652
+ for (const cpId of checkpointIds) {
653
+ const backups = getDb().select().from(fileBackups).where(eq(fileBackups.checkpointId, cpId)).all();
654
+ allBackups.push(...backups);
655
+ }
656
+ return allBackups;
657
+ },
658
+ /**
659
+ * Check if a file already has a backup in the current checkpoint
660
+ */
661
+ hasBackup(checkpointId, filePath) {
662
+ const result = getDb().select().from(fileBackups).where(
663
+ and(
664
+ eq(fileBackups.checkpointId, checkpointId),
665
+ eq(fileBackups.filePath, filePath)
666
+ )
667
+ ).get();
668
+ return !!result;
669
+ },
670
+ deleteBySession(sessionId) {
671
+ const result = getDb().delete(fileBackups).where(eq(fileBackups.sessionId, sessionId)).run();
672
+ return result.changes;
673
+ }
674
+ };
493
675
  export {
494
676
  activeStreamQueries,
677
+ checkpointQueries,
495
678
  closeDatabase,
679
+ fileBackupQueries,
496
680
  getDb,
497
681
  initDatabase,
498
682
  messageQueries,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/index.ts","../../src/db/schema.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { drizzle } from 'drizzle-orm/better-sqlite3';\nimport { eq, desc, and, sql } from 'drizzle-orm';\nimport { nanoid } from 'nanoid';\nimport * as schema from './schema.js';\nimport type {\n Session,\n NewSession,\n Message,\n NewMessage,\n ToolExecution,\n NewToolExecution,\n TodoItem,\n NewTodoItem,\n SessionConfig,\n ModelMessage,\n Terminal,\n NewTerminal,\n ActiveStream,\n NewActiveStream,\n} from './schema.js';\n\nlet db: ReturnType<typeof drizzle<typeof schema>> | null = null;\nlet sqlite: Database.Database | null = null;\n\nexport function initDatabase(dbPath: string) {\n sqlite = new Database(dbPath);\n sqlite.pragma('journal_mode = WAL');\n db = drizzle(sqlite, { schema });\n\n // Create tables if they don't exist (preserves existing data)\n sqlite.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n name TEXT,\n working_directory TEXT NOT NULL,\n model TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n config TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n model_message TEXT NOT NULL,\n sequence INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS tool_executions (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_call_id TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n requires_approval INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n started_at INTEGER NOT NULL,\n completed_at INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS todo_items (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n content TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n \"order\" INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS loaded_skills (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n skill_name TEXT NOT NULL,\n loaded_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS terminals (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n name TEXT,\n command TEXT NOT NULL,\n cwd TEXT NOT NULL,\n pid INTEGER,\n status TEXT NOT NULL DEFAULT 'running',\n exit_code INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n stopped_at INTEGER\n );\n\n -- Table for tracking active streams (for resumable streams)\n CREATE TABLE IF NOT EXISTS active_streams (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n stream_id TEXT NOT NULL UNIQUE,\n status TEXT NOT NULL DEFAULT 'active',\n created_at INTEGER NOT NULL,\n finished_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);\n CREATE INDEX IF NOT EXISTS idx_tool_executions_session ON tool_executions(session_id);\n CREATE INDEX IF NOT EXISTS idx_todo_items_session ON todo_items(session_id);\n CREATE INDEX IF NOT EXISTS idx_loaded_skills_session ON loaded_skills(session_id);\n CREATE INDEX IF NOT EXISTS idx_terminals_session ON terminals(session_id);\n CREATE INDEX IF NOT EXISTS idx_active_streams_session ON active_streams(session_id);\n `);\n\n return db;\n}\n\nexport function getDb() {\n if (!db) {\n throw new Error('Database not initialized. Call initDatabase first.');\n }\n return db;\n}\n\nexport function closeDatabase() {\n if (sqlite) {\n sqlite.close();\n sqlite = null;\n db = null;\n }\n}\n\n// Session queries\nexport const sessionQueries = {\n create(data: Omit<NewSession, 'id' | 'createdAt' | 'updatedAt'>): Session {\n const id = nanoid();\n const now = new Date();\n const result = getDb()\n .insert(schema.sessions)\n .values({\n id,\n ...data,\n createdAt: now,\n updatedAt: now,\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): Session | undefined {\n return getDb().select().from(schema.sessions).where(eq(schema.sessions.id, id)).get();\n },\n\n list(limit = 50, offset = 0): Session[] {\n return getDb()\n .select()\n .from(schema.sessions)\n .orderBy(desc(schema.sessions.createdAt))\n .limit(limit)\n .offset(offset)\n .all();\n },\n\n updateStatus(id: string, status: Session['status']): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ status, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n updateModel(id: string, model: string): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ model, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n update(id: string, updates: { model?: string; name?: string; config?: SessionConfig }): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ ...updates, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb().delete(schema.sessions).where(eq(schema.sessions.id, id)).run();\n return result.changes > 0;\n },\n};\n\n// Message queries - stores AI SDK ModelMessage directly\nexport const messageQueries = {\n /**\n * Get the next sequence number for a session\n */\n getNextSequence(sessionId: string): number {\n const result = getDb()\n .select({ maxSeq: sql<number>`COALESCE(MAX(sequence), -1)` })\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .get();\n return (result?.maxSeq ?? -1) + 1;\n },\n\n /**\n * Create a single message from a ModelMessage\n */\n create(sessionId: string, modelMessage: ModelMessage): Message {\n const id = nanoid();\n const sequence = this.getNextSequence(sessionId);\n const result = getDb()\n .insert(schema.messages)\n .values({\n id,\n sessionId,\n modelMessage,\n sequence,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n /**\n * Add multiple ModelMessages at once (from response.messages)\n * Maintains insertion order via sequence numbers\n */\n addMany(sessionId: string, modelMessages: ModelMessage[]): Message[] {\n const results: Message[] = [];\n let sequence = this.getNextSequence(sessionId);\n for (const msg of modelMessages) {\n const id = nanoid();\n const result = getDb()\n .insert(schema.messages)\n .values({\n id,\n sessionId,\n modelMessage: msg,\n sequence,\n createdAt: new Date(),\n })\n .returning()\n .get();\n results.push(result);\n sequence++;\n }\n return results;\n },\n\n /**\n * Get all messages for a session as ModelMessage[]\n * Ordered by sequence to maintain exact insertion order\n */\n getBySession(sessionId: string): Message[] {\n return getDb()\n .select()\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .orderBy(schema.messages.sequence)\n .all();\n },\n\n /**\n * Get ModelMessages directly (for passing to AI SDK)\n */\n getModelMessages(sessionId: string): ModelMessage[] {\n const messages = this.getBySession(sessionId);\n return messages.map(m => m.modelMessage);\n },\n\n getRecentBySession(sessionId: string, limit = 50): Message[] {\n return getDb()\n .select()\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .orderBy(desc(schema.messages.sequence))\n .limit(limit)\n .all()\n .reverse();\n },\n\n countBySession(sessionId: string): number {\n const result = getDb()\n .select({ count: sql<number>`count(*)` })\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .get();\n return result?.count ?? 0;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Tool execution queries\nexport const toolExecutionQueries = {\n create(data: Omit<NewToolExecution, 'id' | 'startedAt'>): ToolExecution {\n const id = nanoid();\n const result = getDb()\n .insert(schema.toolExecutions)\n .values({\n id,\n ...data,\n startedAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): ToolExecution | undefined {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.id, id))\n .get();\n },\n\n getByToolCallId(toolCallId: string): ToolExecution | undefined {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.toolCallId, toolCallId))\n .get();\n },\n\n getPendingApprovals(sessionId: string): ToolExecution[] {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(\n and(\n eq(schema.toolExecutions.sessionId, sessionId),\n eq(schema.toolExecutions.status, 'pending'),\n eq(schema.toolExecutions.requiresApproval, true)\n )\n )\n .all();\n },\n\n approve(id: string): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({ status: 'approved' })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n reject(id: string): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({ status: 'rejected' })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n complete(\n id: string,\n output: unknown,\n error?: string\n ): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({\n status: error ? 'error' : 'completed',\n output: output as any,\n error,\n completedAt: new Date(),\n })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n getBySession(sessionId: string): ToolExecution[] {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.sessionId, sessionId))\n .orderBy(schema.toolExecutions.startedAt)\n .all();\n },\n};\n\n// Todo item queries\nexport const todoQueries = {\n create(data: Omit<NewTodoItem, 'id' | 'createdAt' | 'updatedAt'>): TodoItem {\n const id = nanoid();\n const now = new Date();\n const result = getDb()\n .insert(schema.todoItems)\n .values({\n id,\n ...data,\n createdAt: now,\n updatedAt: now,\n })\n .returning()\n .get();\n return result;\n },\n\n createMany(\n sessionId: string,\n items: Array<{ content: string; order?: number }>\n ): TodoItem[] {\n const now = new Date();\n const values = items.map((item, index) => ({\n id: nanoid(),\n sessionId,\n content: item.content,\n order: item.order ?? index,\n createdAt: now,\n updatedAt: now,\n }));\n\n return getDb().insert(schema.todoItems).values(values).returning().all();\n },\n\n getBySession(sessionId: string): TodoItem[] {\n return getDb()\n .select()\n .from(schema.todoItems)\n .where(eq(schema.todoItems.sessionId, sessionId))\n .orderBy(schema.todoItems.order)\n .all();\n },\n\n updateStatus(\n id: string,\n status: TodoItem['status']\n ): TodoItem | undefined {\n return getDb()\n .update(schema.todoItems)\n .set({ status, updatedAt: new Date() })\n .where(eq(schema.todoItems.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb()\n .delete(schema.todoItems)\n .where(eq(schema.todoItems.id, id))\n .run();\n return result.changes > 0;\n },\n\n clearSession(sessionId: string): number {\n const result = getDb()\n .delete(schema.todoItems)\n .where(eq(schema.todoItems.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Loaded skills queries\nexport const skillQueries = {\n load(sessionId: string, skillName: string): schema.LoadedSkill {\n const id = nanoid();\n const result = getDb()\n .insert(schema.loadedSkills)\n .values({\n id,\n sessionId,\n skillName,\n loadedAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getBySession(sessionId: string): schema.LoadedSkill[] {\n return getDb()\n .select()\n .from(schema.loadedSkills)\n .where(eq(schema.loadedSkills.sessionId, sessionId))\n .orderBy(schema.loadedSkills.loadedAt)\n .all();\n },\n\n isLoaded(sessionId: string, skillName: string): boolean {\n const result = getDb()\n .select()\n .from(schema.loadedSkills)\n .where(\n and(\n eq(schema.loadedSkills.sessionId, sessionId),\n eq(schema.loadedSkills.skillName, skillName)\n )\n )\n .get();\n return !!result;\n },\n};\n\n// Terminal queries\nexport const terminalQueries = {\n create(data: Omit<NewTerminal, 'id' | 'createdAt'>): Terminal {\n const id = nanoid();\n const result = getDb()\n .insert(schema.terminals)\n .values({\n id,\n ...data,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): Terminal | undefined {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(eq(schema.terminals.id, id))\n .get();\n },\n\n getBySession(sessionId: string): Terminal[] {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(eq(schema.terminals.sessionId, sessionId))\n .orderBy(desc(schema.terminals.createdAt))\n .all();\n },\n\n getRunning(sessionId: string): Terminal[] {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(\n and(\n eq(schema.terminals.sessionId, sessionId),\n eq(schema.terminals.status, 'running')\n )\n )\n .all();\n },\n\n updateStatus(\n id: string,\n status: Terminal['status'],\n exitCode?: number,\n error?: string\n ): Terminal | undefined {\n return getDb()\n .update(schema.terminals)\n .set({\n status,\n exitCode,\n error,\n stoppedAt: status !== 'running' ? new Date() : undefined,\n })\n .where(eq(schema.terminals.id, id))\n .returning()\n .get();\n },\n\n updatePid(id: string, pid: number): Terminal | undefined {\n return getDb()\n .update(schema.terminals)\n .set({ pid })\n .where(eq(schema.terminals.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb()\n .delete(schema.terminals)\n .where(eq(schema.terminals.id, id))\n .run();\n return result.changes > 0;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.terminals)\n .where(eq(schema.terminals.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Active stream queries - for resumable streams\nexport const activeStreamQueries = {\n create(sessionId: string, streamId: string): ActiveStream {\n const id = nanoid();\n const result = getDb()\n .insert(schema.activeStreams)\n .values({\n id,\n sessionId,\n streamId,\n status: 'active',\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getBySessionId(sessionId: string): ActiveStream | undefined {\n return getDb()\n .select()\n .from(schema.activeStreams)\n .where(\n and(\n eq(schema.activeStreams.sessionId, sessionId),\n eq(schema.activeStreams.status, 'active')\n )\n )\n .get();\n },\n\n getByStreamId(streamId: string): ActiveStream | undefined {\n return getDb()\n .select()\n .from(schema.activeStreams)\n .where(eq(schema.activeStreams.streamId, streamId))\n .get();\n },\n\n finish(streamId: string): ActiveStream | undefined {\n return getDb()\n .update(schema.activeStreams)\n .set({ status: 'finished', finishedAt: new Date() })\n .where(eq(schema.activeStreams.streamId, streamId))\n .returning()\n .get();\n },\n\n markError(streamId: string): ActiveStream | undefined {\n return getDb()\n .update(schema.activeStreams)\n .set({ status: 'error', finishedAt: new Date() })\n .where(eq(schema.activeStreams.streamId, streamId))\n .returning()\n .get();\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.activeStreams)\n .where(eq(schema.activeStreams.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\nexport type { \n Session, \n Message, \n ToolExecution, \n TodoItem, \n SessionConfig, \n ModelMessage,\n Terminal,\n ActiveStream,\n};\n","import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';\n\n// Sessions table - represents an agent session/thread\nexport const sessions = sqliteTable('sessions', {\n id: text('id').primaryKey(),\n name: text('name'),\n workingDirectory: text('working_directory').notNull(),\n model: text('model').notNull(),\n status: text('status', { enum: ['active', 'waiting', 'completed', 'error'] })\n .notNull()\n .default('active'),\n config: text('config', { mode: 'json' }).$type<SessionConfig>(),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n updatedAt: integer('updated_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Messages table - stores AI SDK ModelMessage directly\nexport const messages = sqliteTable('messages', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n // Store the entire ModelMessage as JSON (role + content)\n modelMessage: text('model_message', { mode: 'json' }).$type<ModelMessage>().notNull(),\n // Sequence number within session to maintain exact ordering\n sequence: integer('sequence').notNull().default(0),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Tool executions - tracks all tool calls and their results\nexport const toolExecutions = sqliteTable('tool_executions', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n messageId: text('message_id').references(() => messages.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolCallId: text('tool_call_id').notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status', { enum: ['pending', 'approved', 'rejected', 'completed', 'error'] })\n .notNull()\n .default('pending'),\n requiresApproval: integer('requires_approval', { mode: 'boolean' }).notNull().default(false),\n error: text('error'),\n startedAt: integer('started_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n completedAt: integer('completed_at', { mode: 'timestamp' }),\n});\n\n// Todo items for the planning tool\nexport const todoItems = sqliteTable('todo_items', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n content: text('content').notNull(),\n status: text('status', { enum: ['pending', 'in_progress', 'completed', 'cancelled'] })\n .notNull()\n .default('pending'),\n order: integer('order').notNull().default(0),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n updatedAt: integer('updated_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Skills loaded into sessions\nexport const loadedSkills = sqliteTable('loaded_skills', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n skillName: text('skill_name').notNull(),\n loadedAt: integer('loaded_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Terminal sessions - background processes managed by agents\nexport const terminals = sqliteTable('terminals', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n name: text('name'), // Optional friendly name (e.g., \"dev-server\")\n command: text('command').notNull(), // The command that was run\n cwd: text('cwd').notNull(), // Working directory\n pid: integer('pid'), // Process ID (null if not running)\n status: text('status', { enum: ['running', 'stopped', 'error'] })\n .notNull()\n .default('running'),\n exitCode: integer('exit_code'), // Exit code if stopped\n error: text('error'), // Error message if status is 'error'\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n stoppedAt: integer('stopped_at', { mode: 'timestamp' }),\n});\n\n// Active streams - tracks resumable stream sessions for multi-client sync\nexport const activeStreams = sqliteTable('active_streams', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n streamId: text('stream_id').notNull().unique(), // Unique stream identifier\n status: text('status', { enum: ['active', 'finished', 'error'] })\n .notNull()\n .default('active'),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n finishedAt: integer('finished_at', { mode: 'timestamp' }),\n});\n\n// Types for JSON columns\nexport interface SessionConfig {\n toolApprovals?: Record<string, boolean>;\n approvalWebhook?: string;\n skillsDirectory?: string;\n maxContextChars?: number;\n}\n\n// AI SDK ModelMessage types - stored directly for accurate context passing\n// These match the exact format from AI SDK's response.messages\nexport type ModelMessage = \n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage;\n\nexport interface SystemModelMessage {\n role: 'system';\n content: string;\n}\n\nexport interface UserModelMessage {\n role: 'user';\n content: string;\n}\n\nexport interface AssistantModelMessage {\n role: 'assistant';\n content: string | AssistantContentPart[];\n}\n\nexport interface ToolModelMessage {\n role: 'tool';\n content: ToolResultPart[];\n}\n\nexport interface AssistantContentPart {\n type: 'text' | 'tool-call' | 'reasoning';\n text?: string;\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n}\n\nexport interface ToolResultPart {\n type: 'tool-result';\n toolCallId: string;\n toolName: string;\n output: unknown;\n}\n\n// Type exports for queries\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\nexport type Message = typeof messages.$inferSelect;\nexport type NewMessage = typeof messages.$inferInsert;\nexport type ToolExecution = typeof toolExecutions.$inferSelect;\nexport type NewToolExecution = typeof toolExecutions.$inferInsert;\nexport type TodoItem = typeof todoItems.$inferSelect;\nexport type NewTodoItem = typeof todoItems.$inferInsert;\nexport type LoadedSkill = typeof loadedSkills.$inferSelect;\nexport type Terminal = typeof terminals.$inferSelect;\nexport type NewTerminal = typeof terminals.$inferInsert;\nexport type ActiveStream = typeof activeStreams.$inferSelect;\nexport type NewActiveStream = typeof activeStreams.$inferInsert;"],"mappings":"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","names":["messages"]}
1
+ {"version":3,"sources":["../../src/db/index.ts","../../src/db/schema.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { drizzle } from 'drizzle-orm/better-sqlite3';\nimport { eq, desc, and, sql } from 'drizzle-orm';\nimport { nanoid } from 'nanoid';\nimport * as schema from './schema.js';\nimport type {\n Session,\n NewSession,\n Message,\n NewMessage,\n ToolExecution,\n NewToolExecution,\n TodoItem,\n NewTodoItem,\n SessionConfig,\n ModelMessage,\n Terminal,\n NewTerminal,\n ActiveStream,\n NewActiveStream,\n Checkpoint,\n NewCheckpoint,\n FileBackup,\n NewFileBackup,\n} from './schema.js';\n\nlet db: ReturnType<typeof drizzle<typeof schema>> | null = null;\nlet sqlite: Database.Database | null = null;\n\nexport function initDatabase(dbPath: string) {\n sqlite = new Database(dbPath);\n sqlite.pragma('journal_mode = WAL');\n db = drizzle(sqlite, { schema });\n\n // Create tables if they don't exist (preserves existing data)\n sqlite.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n name TEXT,\n working_directory TEXT NOT NULL,\n model TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n config TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n model_message TEXT NOT NULL,\n sequence INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS tool_executions (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_call_id TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL DEFAULT 'pending',\n requires_approval INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n started_at INTEGER NOT NULL,\n completed_at INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS todo_items (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n content TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n \"order\" INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS loaded_skills (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n skill_name TEXT NOT NULL,\n loaded_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS terminals (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n name TEXT,\n command TEXT NOT NULL,\n cwd TEXT NOT NULL,\n pid INTEGER,\n status TEXT NOT NULL DEFAULT 'running',\n exit_code INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n stopped_at INTEGER\n );\n\n -- Table for tracking active streams (for resumable streams)\n CREATE TABLE IF NOT EXISTS active_streams (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n stream_id TEXT NOT NULL UNIQUE,\n status TEXT NOT NULL DEFAULT 'active',\n created_at INTEGER NOT NULL,\n finished_at INTEGER\n );\n\n -- Checkpoints table - created before each user message\n CREATE TABLE IF NOT EXISTS checkpoints (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n message_sequence INTEGER NOT NULL,\n git_head TEXT,\n created_at INTEGER NOT NULL\n );\n\n -- File backups table - stores original file content\n CREATE TABLE IF NOT EXISTS file_backups (\n id TEXT PRIMARY KEY,\n checkpoint_id TEXT NOT NULL REFERENCES checkpoints(id) ON DELETE CASCADE,\n session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,\n file_path TEXT NOT NULL,\n original_content TEXT,\n existed INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);\n CREATE INDEX IF NOT EXISTS idx_tool_executions_session ON tool_executions(session_id);\n CREATE INDEX IF NOT EXISTS idx_todo_items_session ON todo_items(session_id);\n CREATE INDEX IF NOT EXISTS idx_loaded_skills_session ON loaded_skills(session_id);\n CREATE INDEX IF NOT EXISTS idx_terminals_session ON terminals(session_id);\n CREATE INDEX IF NOT EXISTS idx_active_streams_session ON active_streams(session_id);\n CREATE INDEX IF NOT EXISTS idx_checkpoints_session ON checkpoints(session_id);\n CREATE INDEX IF NOT EXISTS idx_file_backups_checkpoint ON file_backups(checkpoint_id);\n CREATE INDEX IF NOT EXISTS idx_file_backups_session ON file_backups(session_id);\n `);\n\n return db;\n}\n\nexport function getDb() {\n if (!db) {\n throw new Error('Database not initialized. Call initDatabase first.');\n }\n return db;\n}\n\nexport function closeDatabase() {\n if (sqlite) {\n sqlite.close();\n sqlite = null;\n db = null;\n }\n}\n\n// Session queries\nexport const sessionQueries = {\n create(data: Omit<NewSession, 'id' | 'createdAt' | 'updatedAt'>): Session {\n const id = nanoid();\n const now = new Date();\n const result = getDb()\n .insert(schema.sessions)\n .values({\n id,\n ...data,\n createdAt: now,\n updatedAt: now,\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): Session | undefined {\n return getDb().select().from(schema.sessions).where(eq(schema.sessions.id, id)).get();\n },\n\n list(limit = 50, offset = 0): Session[] {\n return getDb()\n .select()\n .from(schema.sessions)\n .orderBy(desc(schema.sessions.createdAt))\n .limit(limit)\n .offset(offset)\n .all();\n },\n\n updateStatus(id: string, status: Session['status']): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ status, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n updateModel(id: string, model: string): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ model, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n update(id: string, updates: { model?: string; name?: string; config?: SessionConfig }): Session | undefined {\n return getDb()\n .update(schema.sessions)\n .set({ ...updates, updatedAt: new Date() })\n .where(eq(schema.sessions.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb().delete(schema.sessions).where(eq(schema.sessions.id, id)).run();\n return result.changes > 0;\n },\n};\n\n// Message queries - stores AI SDK ModelMessage directly\nexport const messageQueries = {\n /**\n * Get the next sequence number for a session\n */\n getNextSequence(sessionId: string): number {\n const result = getDb()\n .select({ maxSeq: sql<number>`COALESCE(MAX(sequence), -1)` })\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .get();\n return (result?.maxSeq ?? -1) + 1;\n },\n\n /**\n * Create a single message from a ModelMessage\n */\n create(sessionId: string, modelMessage: ModelMessage): Message {\n const id = nanoid();\n const sequence = this.getNextSequence(sessionId);\n const result = getDb()\n .insert(schema.messages)\n .values({\n id,\n sessionId,\n modelMessage,\n sequence,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n /**\n * Add multiple ModelMessages at once (from response.messages)\n * Maintains insertion order via sequence numbers\n */\n addMany(sessionId: string, modelMessages: ModelMessage[]): Message[] {\n const results: Message[] = [];\n let sequence = this.getNextSequence(sessionId);\n for (const msg of modelMessages) {\n const id = nanoid();\n const result = getDb()\n .insert(schema.messages)\n .values({\n id,\n sessionId,\n modelMessage: msg,\n sequence,\n createdAt: new Date(),\n })\n .returning()\n .get();\n results.push(result);\n sequence++;\n }\n return results;\n },\n\n /**\n * Get all messages for a session as ModelMessage[]\n * Ordered by sequence to maintain exact insertion order\n */\n getBySession(sessionId: string): Message[] {\n return getDb()\n .select()\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .orderBy(schema.messages.sequence)\n .all();\n },\n\n /**\n * Get ModelMessages directly (for passing to AI SDK)\n */\n getModelMessages(sessionId: string): ModelMessage[] {\n const messages = this.getBySession(sessionId);\n return messages.map(m => m.modelMessage);\n },\n\n getRecentBySession(sessionId: string, limit = 50): Message[] {\n return getDb()\n .select()\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .orderBy(desc(schema.messages.sequence))\n .limit(limit)\n .all()\n .reverse();\n },\n\n countBySession(sessionId: string): number {\n const result = getDb()\n .select({ count: sql<number>`count(*)` })\n .from(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .get();\n return result?.count ?? 0;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.messages)\n .where(eq(schema.messages.sessionId, sessionId))\n .run();\n return result.changes;\n },\n\n /**\n * Delete all messages with sequence >= the given sequence number\n * (Used when reverting to a checkpoint)\n */\n deleteFromSequence(sessionId: string, fromSequence: number): number {\n const result = getDb()\n .delete(schema.messages)\n .where(\n and(\n eq(schema.messages.sessionId, sessionId),\n sql`sequence >= ${fromSequence}`\n )\n )\n .run();\n return result.changes;\n },\n};\n\n// Tool execution queries\nexport const toolExecutionQueries = {\n create(data: Omit<NewToolExecution, 'id' | 'startedAt'>): ToolExecution {\n const id = nanoid();\n const result = getDb()\n .insert(schema.toolExecutions)\n .values({\n id,\n ...data,\n startedAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): ToolExecution | undefined {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.id, id))\n .get();\n },\n\n getByToolCallId(toolCallId: string): ToolExecution | undefined {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.toolCallId, toolCallId))\n .get();\n },\n\n getPendingApprovals(sessionId: string): ToolExecution[] {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(\n and(\n eq(schema.toolExecutions.sessionId, sessionId),\n eq(schema.toolExecutions.status, 'pending'),\n eq(schema.toolExecutions.requiresApproval, true)\n )\n )\n .all();\n },\n\n approve(id: string): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({ status: 'approved' })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n reject(id: string): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({ status: 'rejected' })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n complete(\n id: string,\n output: unknown,\n error?: string\n ): ToolExecution | undefined {\n return getDb()\n .update(schema.toolExecutions)\n .set({\n status: error ? 'error' : 'completed',\n output: output as any,\n error,\n completedAt: new Date(),\n })\n .where(eq(schema.toolExecutions.id, id))\n .returning()\n .get();\n },\n\n getBySession(sessionId: string): ToolExecution[] {\n return getDb()\n .select()\n .from(schema.toolExecutions)\n .where(eq(schema.toolExecutions.sessionId, sessionId))\n .orderBy(schema.toolExecutions.startedAt)\n .all();\n },\n\n /**\n * Delete all tool executions after a given timestamp\n * (Used when reverting to a checkpoint)\n */\n deleteAfterTime(sessionId: string, afterTime: Date): number {\n const result = getDb()\n .delete(schema.toolExecutions)\n .where(\n and(\n eq(schema.toolExecutions.sessionId, sessionId),\n sql`started_at > ${afterTime.getTime()}`\n )\n )\n .run();\n return result.changes;\n },\n};\n\n// Todo item queries\nexport const todoQueries = {\n create(data: Omit<NewTodoItem, 'id' | 'createdAt' | 'updatedAt'>): TodoItem {\n const id = nanoid();\n const now = new Date();\n const result = getDb()\n .insert(schema.todoItems)\n .values({\n id,\n ...data,\n createdAt: now,\n updatedAt: now,\n })\n .returning()\n .get();\n return result;\n },\n\n createMany(\n sessionId: string,\n items: Array<{ content: string; order?: number }>\n ): TodoItem[] {\n const now = new Date();\n const values = items.map((item, index) => ({\n id: nanoid(),\n sessionId,\n content: item.content,\n order: item.order ?? index,\n createdAt: now,\n updatedAt: now,\n }));\n\n return getDb().insert(schema.todoItems).values(values).returning().all();\n },\n\n getBySession(sessionId: string): TodoItem[] {\n return getDb()\n .select()\n .from(schema.todoItems)\n .where(eq(schema.todoItems.sessionId, sessionId))\n .orderBy(schema.todoItems.order)\n .all();\n },\n\n updateStatus(\n id: string,\n status: TodoItem['status']\n ): TodoItem | undefined {\n return getDb()\n .update(schema.todoItems)\n .set({ status, updatedAt: new Date() })\n .where(eq(schema.todoItems.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb()\n .delete(schema.todoItems)\n .where(eq(schema.todoItems.id, id))\n .run();\n return result.changes > 0;\n },\n\n clearSession(sessionId: string): number {\n const result = getDb()\n .delete(schema.todoItems)\n .where(eq(schema.todoItems.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Loaded skills queries\nexport const skillQueries = {\n load(sessionId: string, skillName: string): schema.LoadedSkill {\n const id = nanoid();\n const result = getDb()\n .insert(schema.loadedSkills)\n .values({\n id,\n sessionId,\n skillName,\n loadedAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getBySession(sessionId: string): schema.LoadedSkill[] {\n return getDb()\n .select()\n .from(schema.loadedSkills)\n .where(eq(schema.loadedSkills.sessionId, sessionId))\n .orderBy(schema.loadedSkills.loadedAt)\n .all();\n },\n\n isLoaded(sessionId: string, skillName: string): boolean {\n const result = getDb()\n .select()\n .from(schema.loadedSkills)\n .where(\n and(\n eq(schema.loadedSkills.sessionId, sessionId),\n eq(schema.loadedSkills.skillName, skillName)\n )\n )\n .get();\n return !!result;\n },\n};\n\n// Terminal queries\nexport const terminalQueries = {\n create(data: Omit<NewTerminal, 'id' | 'createdAt'>): Terminal {\n const id = nanoid();\n const result = getDb()\n .insert(schema.terminals)\n .values({\n id,\n ...data,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): Terminal | undefined {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(eq(schema.terminals.id, id))\n .get();\n },\n\n getBySession(sessionId: string): Terminal[] {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(eq(schema.terminals.sessionId, sessionId))\n .orderBy(desc(schema.terminals.createdAt))\n .all();\n },\n\n getRunning(sessionId: string): Terminal[] {\n return getDb()\n .select()\n .from(schema.terminals)\n .where(\n and(\n eq(schema.terminals.sessionId, sessionId),\n eq(schema.terminals.status, 'running')\n )\n )\n .all();\n },\n\n updateStatus(\n id: string,\n status: Terminal['status'],\n exitCode?: number,\n error?: string\n ): Terminal | undefined {\n return getDb()\n .update(schema.terminals)\n .set({\n status,\n exitCode,\n error,\n stoppedAt: status !== 'running' ? new Date() : undefined,\n })\n .where(eq(schema.terminals.id, id))\n .returning()\n .get();\n },\n\n updatePid(id: string, pid: number): Terminal | undefined {\n return getDb()\n .update(schema.terminals)\n .set({ pid })\n .where(eq(schema.terminals.id, id))\n .returning()\n .get();\n },\n\n delete(id: string): boolean {\n const result = getDb()\n .delete(schema.terminals)\n .where(eq(schema.terminals.id, id))\n .run();\n return result.changes > 0;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.terminals)\n .where(eq(schema.terminals.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Active stream queries - for resumable streams\nexport const activeStreamQueries = {\n create(sessionId: string, streamId: string): ActiveStream {\n const id = nanoid();\n const result = getDb()\n .insert(schema.activeStreams)\n .values({\n id,\n sessionId,\n streamId,\n status: 'active',\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getBySessionId(sessionId: string): ActiveStream | undefined {\n return getDb()\n .select()\n .from(schema.activeStreams)\n .where(\n and(\n eq(schema.activeStreams.sessionId, sessionId),\n eq(schema.activeStreams.status, 'active')\n )\n )\n .get();\n },\n\n getByStreamId(streamId: string): ActiveStream | undefined {\n return getDb()\n .select()\n .from(schema.activeStreams)\n .where(eq(schema.activeStreams.streamId, streamId))\n .get();\n },\n\n finish(streamId: string): ActiveStream | undefined {\n return getDb()\n .update(schema.activeStreams)\n .set({ status: 'finished', finishedAt: new Date() })\n .where(eq(schema.activeStreams.streamId, streamId))\n .returning()\n .get();\n },\n\n markError(streamId: string): ActiveStream | undefined {\n return getDb()\n .update(schema.activeStreams)\n .set({ status: 'error', finishedAt: new Date() })\n .where(eq(schema.activeStreams.streamId, streamId))\n .returning()\n .get();\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.activeStreams)\n .where(eq(schema.activeStreams.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// Checkpoint queries - for session revert functionality\nexport const checkpointQueries = {\n create(data: { sessionId: string; messageSequence: number; gitHead?: string }): Checkpoint {\n const id = nanoid();\n const result = getDb()\n .insert(schema.checkpoints)\n .values({\n id,\n sessionId: data.sessionId,\n messageSequence: data.messageSequence,\n gitHead: data.gitHead,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getById(id: string): Checkpoint | undefined {\n return getDb()\n .select()\n .from(schema.checkpoints)\n .where(eq(schema.checkpoints.id, id))\n .get();\n },\n\n getBySession(sessionId: string): Checkpoint[] {\n return getDb()\n .select()\n .from(schema.checkpoints)\n .where(eq(schema.checkpoints.sessionId, sessionId))\n .orderBy(schema.checkpoints.messageSequence)\n .all();\n },\n\n getByMessageSequence(sessionId: string, messageSequence: number): Checkpoint | undefined {\n return getDb()\n .select()\n .from(schema.checkpoints)\n .where(\n and(\n eq(schema.checkpoints.sessionId, sessionId),\n eq(schema.checkpoints.messageSequence, messageSequence)\n )\n )\n .get();\n },\n\n getLatest(sessionId: string): Checkpoint | undefined {\n return getDb()\n .select()\n .from(schema.checkpoints)\n .where(eq(schema.checkpoints.sessionId, sessionId))\n .orderBy(desc(schema.checkpoints.messageSequence))\n .limit(1)\n .get();\n },\n\n /**\n * Delete all checkpoints after a given sequence number\n * (Used when reverting to a checkpoint)\n */\n deleteAfterSequence(sessionId: string, messageSequence: number): number {\n const result = getDb()\n .delete(schema.checkpoints)\n .where(\n and(\n eq(schema.checkpoints.sessionId, sessionId),\n sql`message_sequence > ${messageSequence}`\n )\n )\n .run();\n return result.changes;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.checkpoints)\n .where(eq(schema.checkpoints.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\n// File backup queries - for storing original file content\nexport const fileBackupQueries = {\n create(data: {\n checkpointId: string;\n sessionId: string;\n filePath: string;\n originalContent: string | null;\n existed: boolean;\n }): FileBackup {\n const id = nanoid();\n const result = getDb()\n .insert(schema.fileBackups)\n .values({\n id,\n checkpointId: data.checkpointId,\n sessionId: data.sessionId,\n filePath: data.filePath,\n originalContent: data.originalContent,\n existed: data.existed,\n createdAt: new Date(),\n })\n .returning()\n .get();\n return result;\n },\n\n getByCheckpoint(checkpointId: string): FileBackup[] {\n return getDb()\n .select()\n .from(schema.fileBackups)\n .where(eq(schema.fileBackups.checkpointId, checkpointId))\n .all();\n },\n\n getBySession(sessionId: string): FileBackup[] {\n return getDb()\n .select()\n .from(schema.fileBackups)\n .where(eq(schema.fileBackups.sessionId, sessionId))\n .orderBy(schema.fileBackups.createdAt)\n .all();\n },\n\n /**\n * Get all file backups from a given checkpoint sequence onwards (inclusive)\n * (Used when reverting - need to restore these files)\n * \n * When reverting to checkpoint X, we need backups from checkpoint X and all later ones\n * because checkpoint X's backups represent the state BEFORE processing message X.\n */\n getFromSequence(sessionId: string, messageSequence: number): FileBackup[] {\n // Get all checkpoints from this sequence onwards, then get their backups\n const checkpointsFrom = getDb()\n .select()\n .from(schema.checkpoints)\n .where(\n and(\n eq(schema.checkpoints.sessionId, sessionId),\n sql`message_sequence >= ${messageSequence}`\n )\n )\n .all();\n\n if (checkpointsFrom.length === 0) {\n return [];\n }\n\n const checkpointIds = checkpointsFrom.map(c => c.id);\n \n // Get all backups for these checkpoints\n const allBackups: FileBackup[] = [];\n for (const cpId of checkpointIds) {\n const backups = getDb()\n .select()\n .from(schema.fileBackups)\n .where(eq(schema.fileBackups.checkpointId, cpId))\n .all();\n allBackups.push(...backups);\n }\n \n return allBackups;\n },\n\n /**\n * Check if a file already has a backup in the current checkpoint\n */\n hasBackup(checkpointId: string, filePath: string): boolean {\n const result = getDb()\n .select()\n .from(schema.fileBackups)\n .where(\n and(\n eq(schema.fileBackups.checkpointId, checkpointId),\n eq(schema.fileBackups.filePath, filePath)\n )\n )\n .get();\n return !!result;\n },\n\n deleteBySession(sessionId: string): number {\n const result = getDb()\n .delete(schema.fileBackups)\n .where(eq(schema.fileBackups.sessionId, sessionId))\n .run();\n return result.changes;\n },\n};\n\nexport type { \n Session, \n Message, \n ToolExecution, \n TodoItem, \n SessionConfig, \n ModelMessage,\n Terminal,\n ActiveStream,\n Checkpoint,\n FileBackup,\n};\n","import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';\n\n// Sessions table - represents an agent session/thread\nexport const sessions = sqliteTable('sessions', {\n id: text('id').primaryKey(),\n name: text('name'),\n workingDirectory: text('working_directory').notNull(),\n model: text('model').notNull(),\n status: text('status', { enum: ['active', 'waiting', 'completed', 'error'] })\n .notNull()\n .default('active'),\n config: text('config', { mode: 'json' }).$type<SessionConfig>(),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n updatedAt: integer('updated_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Messages table - stores AI SDK ModelMessage directly\nexport const messages = sqliteTable('messages', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n // Store the entire ModelMessage as JSON (role + content)\n modelMessage: text('model_message', { mode: 'json' }).$type<ModelMessage>().notNull(),\n // Sequence number within session to maintain exact ordering\n sequence: integer('sequence').notNull().default(0),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Tool executions - tracks all tool calls and their results\nexport const toolExecutions = sqliteTable('tool_executions', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n messageId: text('message_id').references(() => messages.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolCallId: text('tool_call_id').notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status', { enum: ['pending', 'approved', 'rejected', 'completed', 'error'] })\n .notNull()\n .default('pending'),\n requiresApproval: integer('requires_approval', { mode: 'boolean' }).notNull().default(false),\n error: text('error'),\n startedAt: integer('started_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n completedAt: integer('completed_at', { mode: 'timestamp' }),\n});\n\n// Todo items for the planning tool\nexport const todoItems = sqliteTable('todo_items', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n content: text('content').notNull(),\n status: text('status', { enum: ['pending', 'in_progress', 'completed', 'cancelled'] })\n .notNull()\n .default('pending'),\n order: integer('order').notNull().default(0),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n updatedAt: integer('updated_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Skills loaded into sessions\nexport const loadedSkills = sqliteTable('loaded_skills', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n skillName: text('skill_name').notNull(),\n loadedAt: integer('loaded_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Terminal sessions - background processes managed by agents\nexport const terminals = sqliteTable('terminals', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n name: text('name'), // Optional friendly name (e.g., \"dev-server\")\n command: text('command').notNull(), // The command that was run\n cwd: text('cwd').notNull(), // Working directory\n pid: integer('pid'), // Process ID (null if not running)\n status: text('status', { enum: ['running', 'stopped', 'error'] })\n .notNull()\n .default('running'),\n exitCode: integer('exit_code'), // Exit code if stopped\n error: text('error'), // Error message if status is 'error'\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n stoppedAt: integer('stopped_at', { mode: 'timestamp' }),\n});\n\n// Active streams - tracks resumable stream sessions for multi-client sync\nexport const activeStreams = sqliteTable('active_streams', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n streamId: text('stream_id').notNull().unique(), // Unique stream identifier\n status: text('status', { enum: ['active', 'finished', 'error'] })\n .notNull()\n .default('active'),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n finishedAt: integer('finished_at', { mode: 'timestamp' }),\n});\n\n// Checkpoints - created before each user message for revert capability\nexport const checkpoints = sqliteTable('checkpoints', {\n id: text('id').primaryKey(),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n // The message sequence number this checkpoint was created BEFORE\n // (i.e., the state before this user message was processed)\n messageSequence: integer('message_sequence').notNull(),\n // Optional git commit hash if in a git repo\n gitHead: text('git_head'),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// File backups - stores original file content before modifications\nexport const fileBackups = sqliteTable('file_backups', {\n id: text('id').primaryKey(),\n checkpointId: text('checkpoint_id')\n .notNull()\n .references(() => checkpoints.id, { onDelete: 'cascade' }),\n sessionId: text('session_id')\n .notNull()\n .references(() => sessions.id, { onDelete: 'cascade' }),\n // Relative path from working directory\n filePath: text('file_path').notNull(),\n // Original content (null means file didn't exist before)\n originalContent: text('original_content'),\n // Whether the file existed before this checkpoint\n existed: integer('existed', { mode: 'boolean' }).notNull().default(true),\n createdAt: integer('created_at', { mode: 'timestamp' })\n .notNull()\n .$defaultFn(() => new Date()),\n});\n\n// Types for JSON columns\nexport interface SessionConfig {\n toolApprovals?: Record<string, boolean>;\n approvalWebhook?: string;\n skillsDirectory?: string;\n maxContextChars?: number;\n}\n\n// AI SDK ModelMessage types - stored directly for accurate context passing\n// These match the exact format from AI SDK's response.messages\nexport type ModelMessage = \n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage;\n\nexport interface SystemModelMessage {\n role: 'system';\n content: string;\n}\n\nexport interface UserModelMessage {\n role: 'user';\n content: string;\n}\n\nexport interface AssistantModelMessage {\n role: 'assistant';\n content: string | AssistantContentPart[];\n}\n\nexport interface ToolModelMessage {\n role: 'tool';\n content: ToolResultPart[];\n}\n\nexport interface AssistantContentPart {\n type: 'text' | 'tool-call' | 'reasoning';\n text?: string;\n toolCallId?: string;\n toolName?: string;\n input?: unknown;\n}\n\nexport interface ToolResultPart {\n type: 'tool-result';\n toolCallId: string;\n toolName: string;\n output: unknown;\n}\n\n// Type exports for queries\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\nexport type Message = typeof messages.$inferSelect;\nexport type NewMessage = typeof messages.$inferInsert;\nexport type ToolExecution = typeof toolExecutions.$inferSelect;\nexport type NewToolExecution = typeof toolExecutions.$inferInsert;\nexport type TodoItem = typeof todoItems.$inferSelect;\nexport type NewTodoItem = typeof todoItems.$inferInsert;\nexport type LoadedSkill = typeof loadedSkills.$inferSelect;\nexport type Terminal = typeof terminals.$inferSelect;\nexport type NewTerminal = typeof terminals.$inferInsert;\nexport type ActiveStream = typeof activeStreams.$inferSelect;\nexport type NewActiveStream = typeof activeStreams.$inferInsert;\nexport type Checkpoint = typeof checkpoints.$inferSelect;\nexport type NewCheckpoint = typeof checkpoints.$inferInsert;\nexport type FileBackup = typeof fileBackups.$inferSelect;\nexport type NewFileBackup = typeof fileBackups.$inferInsert;"],"mappings":"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","names":["messages"]}
@@ -1,5 +1,5 @@
1
1
  import { ModelMessage, streamText } from 'ai';
2
- import { S as Session, e as ToolExecution } from './schema-cUDLVN-b.js';
2
+ import { S as Session, e as ToolExecution } from './schema-CkrIadxa.js';
3
3
  import { z } from 'zod';
4
4
  import { B as BashToolProgress } from './bash-CGAqW7HR.js';
5
5
 
@@ -88,11 +88,11 @@ declare const SparkcoderConfigSchema: z.ZodObject<{
88
88
  port: z.ZodDefault<z.ZodNumber>;
89
89
  host: z.ZodDefault<z.ZodString>;
90
90
  }, "strip", z.ZodTypeAny, {
91
- host: string;
92
91
  port: number;
92
+ host: string;
93
93
  }, {
94
- host?: string | undefined;
95
94
  port?: number | undefined;
95
+ host?: string | undefined;
96
96
  }>>;
97
97
  databasePath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
98
98
  }, "strip", z.ZodTypeAny, {
@@ -114,8 +114,8 @@ declare const SparkcoderConfigSchema: z.ZodObject<{
114
114
  keepRecentMessages: number;
115
115
  };
116
116
  server: {
117
- host: string;
118
117
  port: number;
118
+ host: string;
119
119
  };
120
120
  databasePath: string;
121
121
  workingDirectory?: string | undefined;
@@ -141,8 +141,8 @@ declare const SparkcoderConfigSchema: z.ZodObject<{
141
141
  keepRecentMessages?: number | undefined;
142
142
  } | undefined;
143
143
  server?: {
144
- host?: string | undefined;
145
144
  port?: number | undefined;
145
+ host?: string | undefined;
146
146
  } | undefined;
147
147
  databasePath?: string | undefined;
148
148
  }>;