om-memory-system 3.1.0-next.3 → 3.1.1
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.
|
@@ -4,6 +4,8 @@ import { join } from "node:path";
|
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { DatabaseSync } from "node:sqlite";
|
|
6
6
|
import { INTERNAL_CAPTURE_SESSION_TITLES } from "../services/ai/internal-capture-sessions.js";
|
|
7
|
+
import { log } from "../services/logger.js";
|
|
8
|
+
import { withSqliteFileLockRetry } from "../services/turso/sqlite-handle-release.js";
|
|
7
9
|
function validateSchema(db) {
|
|
8
10
|
const required = {
|
|
9
11
|
session: ["id", "directory", "project_id", "parent_id", "time_created"],
|
|
@@ -117,9 +119,25 @@ function fileStamp(path) {
|
|
|
117
119
|
* way to see uncheckpointed turns while leaving every source file untouched.
|
|
118
120
|
* A copy that raced a write or checkpoint is discarded and retried.
|
|
119
121
|
*/
|
|
122
|
+
/**
|
|
123
|
+
* Remove a snapshot folder without ever failing the import. Windows can hold
|
|
124
|
+
* SQLite files briefly after close, so retry lock errors; if the lock
|
|
125
|
+
* outlasts the retries, log the leftover path instead of throwing.
|
|
126
|
+
*/
|
|
127
|
+
async function removeSnapshotDir(dir) {
|
|
128
|
+
try {
|
|
129
|
+
await withSqliteFileLockRetry(() => rmSync(dir, { recursive: true, force: true }));
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
log("OpenCode import: could not remove the temporary database copy", {
|
|
133
|
+
dir,
|
|
134
|
+
error: String(error),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
120
138
|
function snapshotWalDatabase(dbPath) {
|
|
121
139
|
const dir = mkdtempSync(join(tmpdir(), "omms-opencode-"));
|
|
122
|
-
const cleanup = () =>
|
|
140
|
+
const cleanup = () => removeSnapshotDir(dir);
|
|
123
141
|
const copy = join(dir, "opencode.db");
|
|
124
142
|
try {
|
|
125
143
|
for (let attempt = 0; attempt < 5; attempt++) {
|
|
@@ -133,24 +151,24 @@ function snapshotWalDatabase(dbPath) {
|
|
|
133
151
|
}
|
|
134
152
|
}
|
|
135
153
|
catch (error) {
|
|
136
|
-
cleanup();
|
|
154
|
+
void cleanup();
|
|
137
155
|
throw error;
|
|
138
156
|
}
|
|
139
|
-
cleanup();
|
|
157
|
+
void cleanup();
|
|
140
158
|
throw new Error("OpenCode database kept changing while it was copied; retry the import");
|
|
141
159
|
}
|
|
142
160
|
function openSnapshot(dbPath) {
|
|
143
161
|
if (!existsSync(`${dbPath}-wal`)) {
|
|
144
162
|
// No WAL: every committed page is in the main file, so read it in place.
|
|
145
163
|
const uri = `${pathToFileURL(dbPath).href}?immutable=1`;
|
|
146
|
-
return { db: new DatabaseSync(uri, { readOnly: true }), cleanup: () => { } };
|
|
164
|
+
return { db: new DatabaseSync(uri, { readOnly: true }), cleanup: async () => { } };
|
|
147
165
|
}
|
|
148
166
|
const snapshot = snapshotWalDatabase(dbPath);
|
|
149
167
|
try {
|
|
150
168
|
return { db: new DatabaseSync(snapshot.path), cleanup: snapshot.cleanup };
|
|
151
169
|
}
|
|
152
170
|
catch (error) {
|
|
153
|
-
snapshot.cleanup();
|
|
171
|
+
void snapshot.cleanup();
|
|
154
172
|
throw error;
|
|
155
173
|
}
|
|
156
174
|
}
|
|
@@ -159,9 +177,9 @@ export function readOpencodeHistory(dbPath, filters = {}) {
|
|
|
159
177
|
if (!existsSync(dbPath))
|
|
160
178
|
throw new Error(`OpenCode database not found: ${dbPath}`);
|
|
161
179
|
const { db, cleanup } = openSnapshot(dbPath);
|
|
162
|
-
const close = () => {
|
|
180
|
+
const close = async () => {
|
|
163
181
|
db.close();
|
|
164
|
-
cleanup();
|
|
182
|
+
await cleanup();
|
|
165
183
|
};
|
|
166
184
|
try {
|
|
167
185
|
validateSchema(db);
|
|
@@ -201,14 +219,15 @@ export function readOpencodeHistory(dbPath, filters = {}) {
|
|
|
201
219
|
}
|
|
202
220
|
}
|
|
203
221
|
finally {
|
|
204
|
-
close();
|
|
222
|
+
await close();
|
|
205
223
|
}
|
|
206
224
|
},
|
|
207
225
|
};
|
|
208
226
|
return { childSessions, topLevelSessions, sessions };
|
|
209
227
|
}
|
|
210
228
|
catch (error) {
|
|
211
|
-
|
|
229
|
+
// Cleanup never throws, so the original error is what the caller sees.
|
|
230
|
+
void close();
|
|
212
231
|
throw error;
|
|
213
232
|
}
|
|
214
233
|
}
|