1
>
/*---------------------------------------------------------------------------------------------
sessionDatabase.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import * as fs from 'fs';
7
>
import { SequencerByKey } from '../../../base/common/async.js';
8
>
import type { Database, RunResult } from '@vscode/sqlite3';
9
>
import type { IFileEditContent, IFileEditRecord, ILocalTurnRecord, IReviewedFileRecord, ISessionDatabase } from '../common/sessionDataService.js';
10
>
import { dirname } from '../../../base/common/path.js';
11
>
import { URI } from '../../../base/common/uri.js';
12
>
import type { Message } from '../common/state/sessionState.js';
13
>
14
>
/**
15
>
* A single numbered migration. Migrations are applied in order of
16
>
* {@link version} and tracked via `PRAGMA user_version`.
17
>
*/
18
>
export interface ISessionDatabaseMigration {
19
>
/** Monotonically-increasing version number (1-based). */
20
>
readonly version: number;
21
>
/** SQL to execute for this migration. */
22
>
readonly sql: string;
23
>
}
24
>
25
>
/**
26
>
* The set of migrations that define the current session database schema.
27
>
* New migrations should be **appended** to this array with the next version
28
>
* number. Never reorder or mutate existing entries.
29
>
*/
30
>
export const sessionDatabaseMigrations: readonly ISessionDatabaseMigration[] = [
31
>
{
32
>
version: 1,
33
>
sql: [
34
>
`CREATE TABLE IF NOT EXISTS turns (
35
>
id TEXT PRIMARY KEY NOT NULL
36
>
)`,
37
>
`CREATE TABLE IF NOT EXISTS file_edits (
38
>
turn_id TEXT NOT NULL REFERENCES turns(id) ON DELETE CASCADE,
39
>
tool_call_id TEXT NOT NULL,
40
>
file_path TEXT NOT NULL,
41
>
before_content BLOB NOT NULL,
42
>
after_content BLOB NOT NULL,
43
>
added_lines INTEGER,
44
>
removed_lines INTEGER,
45
>
PRIMARY KEY (tool_call_id, file_path)
46
>
)`,
47
>
].join(';\n'),
48
>
},
49
>
{
50
>
version: 2,
51
>
sql: `CREATE TABLE IF NOT EXISTS session_metadata (
52
>
key TEXT PRIMARY KEY NOT NULL,
53
>
value TEXT NOT NULL
54
>
)`,
55
>
},
56
>
{
57
>
version: 3,
58
>
sql: [
59
>
// Recreate file_edits with new columns: edit_type, original_path,
60
>
// and nullable before_content/after_content.
61
>
`CREATE TABLE file_edits_v3 (
62
>
turn_id TEXT NOT NULL REFERENCES turns(id) ON DELETE CASCADE,
63
>
tool_call_id TEXT NOT NULL,
64
>
file_path TEXT NOT NULL,
65
>
edit_type TEXT NOT NULL DEFAULT 'edit',
66
>
original_path TEXT,
67
>
before_content BLOB,
68
>
after_content BLOB,
69
>
added_lines INTEGER,
70
>
removed_lines INTEGER,
71
>
PRIMARY KEY (tool_call_id, file_path)
72
>
)`,
73
>
`INSERT INTO file_edits_v3 (turn_id, tool_call_id, file_path, edit_type, before_content, after_content, added_lines, removed_lines)
74
>
SELECT turn_id, tool_call_id, file_path, 'edit', before_content, after_content, added_lines, removed_lines FROM file_edits`,
75
>
`DROP TABLE file_edits`,
76
>
`ALTER TABLE file_edits_v3 RENAME TO file_edits`,
77
>
].join(';\n'),
78
>
},
79
>
{
80
>
version: 4,
81
>
sql: [
82
>
`ALTER TABLE turns ADD COLUMN event_id TEXT`,
83
>
`CREATE INDEX IF NOT EXISTS idx_turns_event_id ON turns(event_id)`,
84
>
].join(';\n'),
85
>
},
86
>
{
87
>
version: 5,
88
>
sql: `ALTER TABLE turns ADD COLUMN checkpoint_ref TEXT`,
89
>
},
90
>
{
91
>
version: 6,
92
>
sql: `CREATE TABLE IF NOT EXISTS chat_drafts (
93
>
chat_uri TEXT PRIMARY KEY NOT NULL,
94
>
draft TEXT NOT NULL
95
>
)`,
96
>
},
97
>
{
98
>
version: 7,
99
>
sql: `CREATE TABLE IF NOT EXISTS reviewed_files (
100
>
uri TEXT NOT NULL,
101
>
nonce TEXT NOT NULL,
102
>
PRIMARY KEY (uri, nonce)
103
>
)`,
104
>
},
105
>
{
106
>
version: 8,
107
>
sql: `CREATE TABLE IF NOT EXISTS local_turns (
108
>
turn_id TEXT PRIMARY KEY NOT NULL,
109
>
chat_uri TEXT NOT NULL,
110
>
anchor_turn_id TEXT,
111
>
seq INTEGER NOT NULL,
112
>
payload TEXT NOT NULL
113
>
)`,
114
>
},
115
>
];
116
>
117
>
// ---- Promise wrappers around callback-based @vscode/sqlite3 API -----------
118
>
119
function dbExec(db: Database, sql: string): Promise<void> {
120
return new Promise((resolve, reject) => {