opencode-multidevice-sync 0.1.0

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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +15 -0
  3. package/README.md +111 -0
  4. package/README.ru.md +57 -0
  5. package/dist/cli/index.d.ts +3 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +460 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/render.d.ts +45 -0
  10. package/dist/cli/render.d.ts.map +1 -0
  11. package/dist/cli/render.js +167 -0
  12. package/dist/cli/render.js.map +1 -0
  13. package/dist/cli/theme.d.ts +45 -0
  14. package/dist/cli/theme.d.ts.map +1 -0
  15. package/dist/cli/theme.js +88 -0
  16. package/dist/cli/theme.js.map +1 -0
  17. package/dist/core/backup.d.ts +13 -0
  18. package/dist/core/backup.d.ts.map +1 -0
  19. package/dist/core/backup.js +102 -0
  20. package/dist/core/backup.js.map +1 -0
  21. package/dist/core/fsx.d.ts +81 -0
  22. package/dist/core/fsx.d.ts.map +1 -0
  23. package/dist/core/fsx.js +353 -0
  24. package/dist/core/fsx.js.map +1 -0
  25. package/dist/core/git.d.ts +62 -0
  26. package/dist/core/git.d.ts.map +1 -0
  27. package/dist/core/git.js +162 -0
  28. package/dist/core/git.js.map +1 -0
  29. package/dist/core/guard.d.ts +5 -0
  30. package/dist/core/guard.d.ts.map +1 -0
  31. package/dist/core/guard.js +97 -0
  32. package/dist/core/guard.js.map +1 -0
  33. package/dist/core/health.d.ts +18 -0
  34. package/dist/core/health.d.ts.map +1 -0
  35. package/dist/core/health.js +88 -0
  36. package/dist/core/health.js.map +1 -0
  37. package/dist/core/host.d.ts +20 -0
  38. package/dist/core/host.d.ts.map +1 -0
  39. package/dist/core/host.js +50 -0
  40. package/dist/core/host.js.map +1 -0
  41. package/dist/core/index.d.ts +18 -0
  42. package/dist/core/index.d.ts.map +1 -0
  43. package/dist/core/index.js +18 -0
  44. package/dist/core/index.js.map +1 -0
  45. package/dist/core/jsonc.d.ts +20 -0
  46. package/dist/core/jsonc.d.ts.map +1 -0
  47. package/dist/core/jsonc.js +115 -0
  48. package/dist/core/jsonc.js.map +1 -0
  49. package/dist/core/lock.d.ts +14 -0
  50. package/dist/core/lock.d.ts.map +1 -0
  51. package/dist/core/lock.js +111 -0
  52. package/dist/core/lock.js.map +1 -0
  53. package/dist/core/overrides.d.ts +43 -0
  54. package/dist/core/overrides.d.ts.map +1 -0
  55. package/dist/core/overrides.js +169 -0
  56. package/dist/core/overrides.js.map +1 -0
  57. package/dist/core/paths.d.ts +36 -0
  58. package/dist/core/paths.d.ts.map +1 -0
  59. package/dist/core/paths.js +55 -0
  60. package/dist/core/paths.js.map +1 -0
  61. package/dist/core/preview.d.ts +3 -0
  62. package/dist/core/preview.d.ts.map +1 -0
  63. package/dist/core/preview.js +56 -0
  64. package/dist/core/preview.js.map +1 -0
  65. package/dist/core/repo.d.ts +57 -0
  66. package/dist/core/repo.d.ts.map +1 -0
  67. package/dist/core/repo.js +196 -0
  68. package/dist/core/repo.js.map +1 -0
  69. package/dist/core/reporter.d.ts +50 -0
  70. package/dist/core/reporter.d.ts.map +1 -0
  71. package/dist/core/reporter.js +63 -0
  72. package/dist/core/reporter.js.map +1 -0
  73. package/dist/core/sessions.d.ts +83 -0
  74. package/dist/core/sessions.d.ts.map +1 -0
  75. package/dist/core/sessions.js +508 -0
  76. package/dist/core/sessions.js.map +1 -0
  77. package/dist/core/settings.d.ts +68 -0
  78. package/dist/core/settings.d.ts.map +1 -0
  79. package/dist/core/settings.js +126 -0
  80. package/dist/core/settings.js.map +1 -0
  81. package/dist/core/setup.d.ts +48 -0
  82. package/dist/core/setup.d.ts.map +1 -0
  83. package/dist/core/setup.js +186 -0
  84. package/dist/core/setup.js.map +1 -0
  85. package/dist/core/sqlite.d.ts +37 -0
  86. package/dist/core/sqlite.d.ts.map +1 -0
  87. package/dist/core/sqlite.js +108 -0
  88. package/dist/core/sqlite.js.map +1 -0
  89. package/dist/core/stage.d.ts +44 -0
  90. package/dist/core/stage.d.ts.map +1 -0
  91. package/dist/core/stage.js +304 -0
  92. package/dist/core/stage.js.map +1 -0
  93. package/dist/core/sync.d.ts +52 -0
  94. package/dist/core/sync.d.ts.map +1 -0
  95. package/dist/core/sync.js +423 -0
  96. package/dist/core/sync.js.map +1 -0
  97. package/dist/plugin/index.d.ts +29 -0
  98. package/dist/plugin/index.d.ts.map +1 -0
  99. package/dist/plugin/index.js +88 -0
  100. package/dist/plugin/index.js.map +1 -0
  101. package/docs/MIGRATION.md +29 -0
  102. package/docs/ROADMAP.md +29 -0
  103. package/docs/SAFETY.md +31 -0
  104. package/examples/home-laptop.jsonc +31 -0
  105. package/examples/opencode-sync.overrides.jsonc +4 -0
  106. package/examples/work-laptop.jsonc +26 -0
  107. package/package.json +81 -0
@@ -0,0 +1,508 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { gunzipSync, gzipSync } from "node:zlib";
5
+ import { createDatabaseBackup } from "./backup.js";
6
+ import { ensureDir } from "./fsx.js";
7
+ import { healthProblems, inspectDatabase } from "./health.js";
8
+ import { SESSIONS_DIR } from "./paths.js";
9
+ import { existingTables, openDatabase, tableColumns } from "./sqlite.js";
10
+ /**
11
+ * Selective session sync.
12
+ *
13
+ * The naive approach - committing `opencode.db` - stops working almost immediately.
14
+ * A real database reaches several gigabytes, dominated by tool output stored in
15
+ * `part.data`, and Git has no way to delta-compress it. Worse, copying a live
16
+ * database together with its write-ahead log can capture a torn state that only
17
+ * reveals itself much later.
18
+ *
19
+ * So sessions are exported one at a time. Each session becomes an independent,
20
+ * gzipped JSON shard containing its own rows plus the project and workspace
21
+ * rows it depends on. That buys three things:
22
+ *
23
+ * - **No large files.** Shards are individually small and compress well.
24
+ * - **Conflict isolation.** Two machines editing different sessions touch
25
+ * different files, so Git merges them without any special handling. The
26
+ * only true conflict is the same session edited in two places, where the
27
+ * newer `time_updated` wins.
28
+ * - **Selectivity.** A time window, an explicit include list, a project
29
+ * filter and a per-session size cap decide what travels. Ancient sessions
30
+ * stay on the machine that created them.
31
+ *
32
+ * Import is an upsert inside a transaction, so a failure leaves the local
33
+ * database exactly as it was.
34
+ */
35
+ /** Tables whose rows belong to exactly one session. */
36
+ const SESSION_TABLES = [
37
+ "session_message",
38
+ "message",
39
+ "part",
40
+ "todo",
41
+ "session_share",
42
+ "session_context_epoch",
43
+ "session_input",
44
+ ];
45
+ function shardPath(repoRoot, sessionId) {
46
+ return path.join(repoRoot, SESSIONS_DIR, `${sanitizeId(sessionId)}.json.gz`);
47
+ }
48
+ /** Session ids are opaque; keep them filesystem-safe without losing identity. */
49
+ export function sanitizeId(id) {
50
+ return id.replace(/[^A-Za-z0-9._-]/g, "_");
51
+ }
52
+ function readRows(db, sql, params) {
53
+ return db.prepare(sql).all(...params);
54
+ }
55
+ /**
56
+ * Choose which sessions to export.
57
+ *
58
+ * Explicitly included ids always win, even when they fall outside the window.
59
+ * Everything else must be inside the time window, pass the directory filter and
60
+ * survive the count cap, which keeps the newest sessions.
61
+ */
62
+ export function selectSessions(db, options) {
63
+ const now = options.now ?? Date.now();
64
+ const cutoff = now - options.days * 24 * 60 * 60 * 1000;
65
+ const rows = readRows(db, `SELECT id, title, directory, time_updated, time_created, project_id
66
+ FROM session
67
+ ORDER BY time_updated DESC`, []);
68
+ const exclude = new Set(options.exclude);
69
+ const include = new Set(options.include);
70
+ const directories = options.directories.map((d) => path.resolve(d));
71
+ const matchesDirectory = (directory) => {
72
+ if (directories.length === 0)
73
+ return true;
74
+ const resolved = path.resolve(String(directory ?? ""));
75
+ return directories.some((d) => resolved === d || resolved.startsWith(`${d}${path.sep}`));
76
+ };
77
+ const selected = [];
78
+ let windowCount = 0;
79
+ for (const row of rows) {
80
+ const id = String(row.id);
81
+ if (exclude.has(id))
82
+ continue;
83
+ const record = {
84
+ id,
85
+ title: String(row.title ?? ""),
86
+ directory: String(row.directory ?? ""),
87
+ timeUpdated: Number(row.time_updated ?? 0),
88
+ timeCreated: Number(row.time_created ?? 0),
89
+ projectId: String(row.project_id ?? ""),
90
+ };
91
+ if (include.has(id)) {
92
+ selected.push(record);
93
+ continue;
94
+ }
95
+ if (record.timeUpdated < cutoff)
96
+ continue;
97
+ if (!matchesDirectory(record.directory))
98
+ continue;
99
+ if (windowCount >= options.maxSessions)
100
+ continue;
101
+ windowCount++;
102
+ selected.push(record);
103
+ }
104
+ return selected;
105
+ }
106
+ function canonical(value) {
107
+ if (Array.isArray(value))
108
+ return `[${value.map(canonical).join(",")}]`;
109
+ if (value && typeof value === "object")
110
+ return `{${Object.keys(value)
111
+ .sort()
112
+ .map((k) => `${JSON.stringify(k)}:${canonical(value[k])}`)
113
+ .join(",")}}`;
114
+ return JSON.stringify(value ?? null);
115
+ }
116
+ function mapPath(value, mappings) {
117
+ if (typeof value !== "string")
118
+ return value;
119
+ const candidate = value.replace(/\\/g, "/");
120
+ for (const m of [...mappings].sort((a, b) => b.from.length - a.from.length)) {
121
+ const from = m.from.replace(/\\/g, "/").replace(/\/$/, "");
122
+ const windows = /^[a-z]:/i.test(from);
123
+ const c = windows ? candidate.toLowerCase() : candidate;
124
+ const f = windows ? from.toLowerCase() : from;
125
+ if (c === f || c.startsWith(`${f}/`))
126
+ return m.to.replace(/\\/g, "/").replace(/\/$/, "") + candidate.slice(from.length);
127
+ }
128
+ return value;
129
+ }
130
+ function mapRow(table, row, mappings) {
131
+ const copy = { ...row };
132
+ for (const key of table === "session"
133
+ ? ["directory", "path"]
134
+ : table === "project"
135
+ ? ["worktree"]
136
+ : []) {
137
+ if (key in copy)
138
+ copy[key] = mapPath(copy[key], mappings);
139
+ }
140
+ return copy;
141
+ }
142
+ function buildShard(db, id, tables, mappings = []) {
143
+ const row = readRows(db, "SELECT * FROM session WHERE id=?", [id])[0];
144
+ if (!row)
145
+ throw new Error(`Session ${id} disappeared while exporting`);
146
+ const reverse = mappings.map((m) => ({ from: m.to, to: m.from }));
147
+ const shard = {
148
+ formatVersion: 1,
149
+ session: mapRow("session", row, reverse),
150
+ tables: {},
151
+ exportedAt: Number(row.time_updated ?? 0),
152
+ };
153
+ if (row.project_id && row.project_id !== "global") {
154
+ const project = readRows(db, "SELECT * FROM project WHERE id=?", [row.project_id])[0];
155
+ if (project)
156
+ shard.project = mapRow("project", project, reverse);
157
+ }
158
+ if (row.workspace_id) {
159
+ const ws = readRows(db, "SELECT * FROM workspace WHERE id=?", [row.workspace_id])[0];
160
+ if (ws)
161
+ shard.workspace = ws;
162
+ }
163
+ for (const table of tables)
164
+ shard.tables[table] = readRows(db, `SELECT * FROM "${table}" WHERE session_id=?`, [id]).sort((a, b) => {
165
+ const x = canonical(a);
166
+ const y = canonical(b);
167
+ return x < y ? -1 : x > y ? 1 : 0;
168
+ });
169
+ return shard;
170
+ }
171
+ function contentHash(shard) {
172
+ const tables = Object.fromEntries(Object.entries(shard.tables)
173
+ .filter(([, rows]) => rows.length)
174
+ .map(([t, rows]) => [
175
+ t,
176
+ [...rows].sort((a, b) => {
177
+ const x = canonical(a);
178
+ const y = canonical(b);
179
+ return x < y ? -1 : x > y ? 1 : 0;
180
+ }),
181
+ ]));
182
+ return createHash("sha256")
183
+ .update(canonical({ session: shard.session, tables }))
184
+ .digest("hex");
185
+ }
186
+ function readBases(file) {
187
+ if (!fs.existsSync(file + ".omds-bases.json"))
188
+ return {};
189
+ const raw = JSON.parse(fs.readFileSync(file + ".omds-bases.json", "utf8"));
190
+ if (raw.version !== 1 || !raw.hashes || typeof raw.hashes !== "object")
191
+ throw new Error("Invalid local sync baseline; refusing to guess conflict resolution");
192
+ return raw.hashes;
193
+ }
194
+ function saveBases(file, hashes) {
195
+ const target = file + ".omds-bases.json";
196
+ const temp = target + `.${randomUUID()}.tmp`;
197
+ fs.writeFileSync(temp, JSON.stringify({ version: 1, hashes }), { mode: 0o600 });
198
+ fs.renameSync(temp, target);
199
+ }
200
+ function readShard(file) {
201
+ if (fs.statSync(file).size > 64 * 1024 * 1024)
202
+ throw new Error("Compressed shard exceeds 64 MiB safety limit");
203
+ const s = JSON.parse(gunzipSync(fs.readFileSync(file), { maxOutputLength: 128 * 1024 * 1024 }).toString("utf8"));
204
+ if (s.formatVersion !== 1 ||
205
+ !s.session ||
206
+ typeof s.session.id !== "string" ||
207
+ !/^[A-Za-z0-9._-]+$/.test(s.session.id))
208
+ throw new Error("Invalid session shard");
209
+ if (path.basename(file) !== `${s.session.id}.json.gz`)
210
+ throw new Error("Shard filename does not match session id");
211
+ if (!Number.isFinite(s.session.time_updated) || !s.tables || typeof s.tables !== "object")
212
+ throw new Error("Invalid shard metadata");
213
+ if (s.project && s.project.id !== s.session.project_id)
214
+ throw new Error("Project ownership mismatch");
215
+ if (s.workspace && s.workspace.id !== s.session.workspace_id)
216
+ throw new Error("Workspace ownership mismatch");
217
+ for (const [table, rows] of Object.entries(s.tables)) {
218
+ if (!SESSION_TABLES.includes(table) || !Array.isArray(rows))
219
+ throw new Error(`Unsupported shard table: ${table}`);
220
+ for (const row of rows)
221
+ if (!row || row.session_id !== s.session.id)
222
+ throw new Error(`Row ownership mismatch in ${table}`);
223
+ }
224
+ return s;
225
+ }
226
+ function availableTables(db) {
227
+ return existingTables(db, [...SESSION_TABLES]).filter((t) => tableColumns(db, t).includes("session_id"));
228
+ }
229
+ export async function exportSessions(file, repo, options, reporter) {
230
+ const result = { written: [], skippedTooLarge: [], considered: 0, conflicts: [] };
231
+ if (!fs.existsSync(file))
232
+ return result;
233
+ const bases = readBases(file);
234
+ const db = await openDatabase(file, { readOnly: true });
235
+ try {
236
+ db.exec("BEGIN");
237
+ const tables = availableTables(db);
238
+ const selected = selectSessions(db, options);
239
+ result.considered = selected.length;
240
+ ensureDir(path.join(repo, SESSIONS_DIR));
241
+ for (const session of selected) {
242
+ const shard = buildShard(db, session.id, tables, options.pathMappings ?? []);
243
+ const dest = shardPath(repo, session.id);
244
+ if (fs.existsSync(dest)) {
245
+ const remote = readShard(dest);
246
+ const remoteHash = contentHash(remote);
247
+ const localHash = contentHash(shard);
248
+ if (remoteHash !== localHash && bases[session.id] !== remoteHash) {
249
+ result.conflicts?.push(session.id);
250
+ reporter.warn(`Export conflict ${session.id}: pull/review remote changes first`);
251
+ continue;
252
+ }
253
+ }
254
+ const payload = gzipSync(Buffer.from(canonical(shard)), { level: 9 });
255
+ if (payload.length > options.maxSessionBytes) {
256
+ result.skippedTooLarge.push({
257
+ id: session.id,
258
+ title: session.title,
259
+ bytes: payload.length,
260
+ });
261
+ continue;
262
+ }
263
+ if (!fs.existsSync(dest) || !fs.readFileSync(dest).equals(payload)) {
264
+ const tmp = dest + `.${randomUUID()}.tmp`;
265
+ fs.writeFileSync(tmp, payload, { mode: 0o600 });
266
+ fs.renameSync(tmp, dest);
267
+ }
268
+ result.written.push(session.id);
269
+ }
270
+ // Never delete remote shards merely because this machine lacks a session or has a different retention window.
271
+ db.exec("COMMIT");
272
+ return result;
273
+ }
274
+ finally {
275
+ db.close();
276
+ }
277
+ }
278
+ export async function acknowledgeExport(file, repo, mappings = []) {
279
+ if (!fs.existsSync(file))
280
+ return;
281
+ const bases = readBases(file);
282
+ const db = await openDatabase(file, { readOnly: true });
283
+ try {
284
+ const tables = availableTables(db);
285
+ for (const row of readRows(db, "SELECT id FROM session", [])) {
286
+ const id = String(row.id);
287
+ const p = shardPath(repo, id);
288
+ if (!fs.existsSync(p))
289
+ continue;
290
+ const incoming = contentHash(readShard(p));
291
+ const local = contentHash(buildShard(db, id, tables, mappings));
292
+ if (incoming === local)
293
+ bases[id] = local;
294
+ }
295
+ saveBases(file, bases);
296
+ }
297
+ finally {
298
+ db.close();
299
+ }
300
+ }
301
+ function normalize(value) {
302
+ if (value === undefined)
303
+ return null;
304
+ if (typeof value === "boolean")
305
+ return value ? 1 : 0;
306
+ if (value !== null && typeof value === "object" && !Buffer.isBuffer(value))
307
+ return JSON.stringify(value);
308
+ return value;
309
+ }
310
+ function upsert(db, table, row) {
311
+ const allowed = tableColumns(db, table);
312
+ if (!allowed.length)
313
+ throw new Error(`Missing table ${table}`);
314
+ const columns = Object.keys(row).filter((c) => allowed.includes(c));
315
+ if (columns.length !== Object.keys(row).length)
316
+ throw new Error(`Schema mismatch in ${table}; unsupported columns present`);
317
+ const q = (c) => `"${c.replace(/"/g, '""')}"`;
318
+ const quoted = columns.map(q).join(",");
319
+ const places = columns.map(() => "?").join(",");
320
+ const updates = columns.map((c) => `${q(c)}=excluded.${q(c)}`).join(",");
321
+ if (allowed.includes("session_id") && allowed.includes("id") && row.id) {
322
+ const existing = readRows(db, `SELECT session_id FROM ${q(table)} WHERE id=?`, [row.id])[0];
323
+ if (existing && existing.session_id !== row.session_id)
324
+ throw new Error(`Existing row belongs to another session: ${table}`);
325
+ }
326
+ db.prepare(`INSERT INTO ${q(table)} (${quoted}) VALUES (${places}) ON CONFLICT DO UPDATE SET ${updates}`).run(...columns.map((c) => normalize(row[c])));
327
+ }
328
+ export async function importSessions(file, repo, reporter, options = {}) {
329
+ const result = {
330
+ imported: 0,
331
+ skippedOlder: 0,
332
+ conflicts: [],
333
+ failed: [],
334
+ dryRun: options.dryRun ?? false,
335
+ };
336
+ const dir = path.join(repo, SESSIONS_DIR);
337
+ if (!fs.existsSync(dir))
338
+ return result;
339
+ const files = fs
340
+ .readdirSync(dir)
341
+ .filter((f) => f.endsWith(".json.gz"))
342
+ .sort();
343
+ if (!files.length)
344
+ return result;
345
+ if (!fs.existsSync(file)) {
346
+ result.failed.push({
347
+ file: "<database>",
348
+ reason: "Start OpenCode once to initialize its schema, then pull again",
349
+ });
350
+ return result;
351
+ }
352
+ const bases = readBases(file);
353
+ const nextBases = { ...bases };
354
+ const mappings = options.pathMappings ?? [];
355
+ const db = await openDatabase(file, { readOnly: options.dryRun ?? false });
356
+ let transaction = false;
357
+ try {
358
+ db.exec(options.dryRun ? "BEGIN" : "BEGIN IMMEDIATE");
359
+ transaction = true;
360
+ const before = inspectDatabase(db);
361
+ if (!before.ok)
362
+ throw new Error(`Unsafe database: ${healthProblems(before).join("; ")}`);
363
+ const tables = availableTables(db);
364
+ const plan = [];
365
+ for (const name of files) {
366
+ try {
367
+ const shard = readShard(path.join(dir, name));
368
+ const id = String(shard.session.id);
369
+ const hash = contentHash(shard);
370
+ const localRow = readRows(db, "SELECT * FROM session WHERE id=?", [id])[0];
371
+ if (localRow) {
372
+ const localShard = buildShard(db, id, tables, mappings);
373
+ const localHash = contentHash(localShard);
374
+ if (hash === localHash) {
375
+ result.skippedOlder++;
376
+ nextBases[id] = hash;
377
+ continue;
378
+ }
379
+ const base = bases[id];
380
+ if (base === hash) {
381
+ result.skippedOlder++;
382
+ continue;
383
+ }
384
+ if (!options.preferRemote && (!base || localHash !== base)) {
385
+ if (Number(localRow.time_updated) > Number(shard.session.time_updated))
386
+ result.skippedOlder++;
387
+ result.conflicts.push({
388
+ sessionId: id,
389
+ reason: base
390
+ ? "both devices changed since last sync"
391
+ : "different local history without a common baseline",
392
+ });
393
+ continue;
394
+ }
395
+ // Do not silently prune local history, even when an incoming snapshot is newer.
396
+ for (const table of tables) {
397
+ const keys = db.prepare(`PRAGMA table_info("${table}")`).all()
398
+ .filter((c) => c.pk > 0)
399
+ .sort((a, b) => a.pk - b.pk)
400
+ .map((c) => c.name);
401
+ if (!keys.length)
402
+ throw new Error(`No primary key in ${table}`);
403
+ const identity = (row) => canonical(keys.map((k) => row[k]));
404
+ const incoming = new Set((shard.tables[table] ?? []).map(identity));
405
+ if ((localShard.tables[table] ?? []).some((row) => !incoming.has(identity(row))))
406
+ throw new Error(`Incoming snapshot would discard local ${table} rows; explicit reconciliation required`);
407
+ }
408
+ }
409
+ plan.push({ name, shard, hash });
410
+ }
411
+ catch (error) {
412
+ result.failed.push({ file: name, reason: error.message });
413
+ }
414
+ }
415
+ if (result.failed.length || result.conflicts.length) {
416
+ db.exec("ROLLBACK");
417
+ transaction = false;
418
+ result.rolledBack = true;
419
+ for (const c of result.conflicts)
420
+ reporter.warn(`Session conflict ${c.sessionId}: ${c.reason}; no sessions imported`);
421
+ return result;
422
+ }
423
+ if (options.dryRun) {
424
+ result.imported = plan.length;
425
+ db.exec("ROLLBACK");
426
+ transaction = false;
427
+ return result;
428
+ }
429
+ if (plan.length && options.backupBeforeImport !== false) {
430
+ const backup = await createDatabaseBackup(file, undefined, options.backupRetention ?? 10);
431
+ result.backup = backup.path;
432
+ reporter.detail(`Verified backup: ${backup.path}`);
433
+ }
434
+ for (const item of plan) {
435
+ const { shard } = item;
436
+ const session = mapRow("session", shard.session, mappings);
437
+ const id = String(session.id);
438
+ const projectId = session.project_id;
439
+ const project = readRows(db, "SELECT id FROM project WHERE id=?", [projectId])[0];
440
+ if (!project) {
441
+ if (projectId === "global")
442
+ throw new Error("Synthetic global project must be initialized locally by OpenCode");
443
+ if (!shard.project)
444
+ throw new Error("Missing project row in session shard");
445
+ upsert(db, "project", mapRow("project", shard.project, mappings));
446
+ }
447
+ if (shard.workspace &&
448
+ !readRows(db, "SELECT id FROM workspace WHERE id=?", [shard.workspace.id])[0])
449
+ upsert(db, "workspace", shard.workspace);
450
+ upsert(db, "session", session);
451
+ // Insert referenced messages before parts, independent of JSON object key order.
452
+ for (const table of [
453
+ "message",
454
+ "part",
455
+ ...SESSION_TABLES.filter((t) => t !== "message" && t !== "part"),
456
+ ]) {
457
+ for (const row of shard.tables[table] ?? [])
458
+ upsert(db, table, row);
459
+ }
460
+ nextBases[id] = item.hash;
461
+ result.imported++;
462
+ }
463
+ const after = inspectDatabase(db);
464
+ if (!after.ok || after.sessions < before.sessions)
465
+ throw new Error(`Post-import integrity failed: ${healthProblems(after).join("; ")}`);
466
+ db.exec("COMMIT");
467
+ transaction = false;
468
+ saveBases(file, nextBases);
469
+ return result;
470
+ }
471
+ catch (error) {
472
+ if (transaction) {
473
+ db.exec("ROLLBACK");
474
+ transaction = false;
475
+ result.imported = 0;
476
+ result.rolledBack = true;
477
+ }
478
+ result.failed.push({ file: "<transaction>", reason: error.message });
479
+ return result;
480
+ }
481
+ finally {
482
+ if (transaction)
483
+ db.exec("ROLLBACK");
484
+ db.close();
485
+ }
486
+ }
487
+ /** List sessions available locally, newest first - powers `sessions list`. */
488
+ export async function listSessions(databaseFile, limit) {
489
+ if (!fs.existsSync(databaseFile))
490
+ return [];
491
+ const db = await openDatabase(databaseFile, { readOnly: true });
492
+ try {
493
+ const rows = readRows(db, `SELECT id, title, directory, time_updated, time_created, project_id
494
+ FROM session ORDER BY time_updated DESC LIMIT ?`, [limit]);
495
+ return rows.map((row) => ({
496
+ id: String(row.id),
497
+ title: String(row.title ?? ""),
498
+ directory: String(row.directory ?? ""),
499
+ timeUpdated: Number(row.time_updated ?? 0),
500
+ timeCreated: Number(row.time_created ?? 0),
501
+ projectId: String(row.project_id ?? ""),
502
+ }));
503
+ }
504
+ finally {
505
+ db.close();
506
+ }
507
+ }
508
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/core/sessions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /** Filename of the tool's own settings (local-only, never committed). */
2
+ export declare const SETTINGS_FILE = "opencode-sync.jsonc";
3
+ /** Filename of the per-machine OpenCode config patch (local-only). */
4
+ export declare const OVERRIDES_FILE = "opencode-sync.overrides.jsonc";
5
+ export interface RepoSettings {
6
+ /** Full git remote URL. Takes precedence over owner/name. */
7
+ url?: string;
8
+ owner?: string;
9
+ name?: string;
10
+ branch?: string;
11
+ }
12
+ export interface SessionSettings {
13
+ /** Master switch. Session sync is opt-in. */
14
+ enabled: boolean;
15
+ /** Only sync sessions touched within this many days. */
16
+ days: number;
17
+ /** Hard cap on how many sessions a single push may export. */
18
+ maxSessions: number;
19
+ /**
20
+ * Skip any single session whose exported payload exceeds this many bytes.
21
+ * Tool output can make one session hundreds of megabytes; without a cap a
22
+ * single runaway session would dominate the repository.
23
+ */
24
+ maxSessionBytes: number;
25
+ /** Explicit session ids to always include, regardless of the time window. */
26
+ include: string[];
27
+ /** Session ids to never export. */
28
+ exclude: string[];
29
+ /** Only export sessions belonging to these project directories. */
30
+ directories: string[];
31
+ /** Create a consistent SQLite backup before importing remote sessions. */
32
+ backupBeforeImport: boolean;
33
+ /** Number of automatic database backups to retain. */
34
+ backupRetention: number;
35
+ /** Rewrite machine-specific path prefixes while importing sessions. */
36
+ pathMappings: Array<{
37
+ from: string;
38
+ to: string;
39
+ }>;
40
+ }
41
+ export interface Settings {
42
+ repo: RepoSettings;
43
+ /** Stable alias for this machine used in commit messages. */
44
+ machineAlias?: string;
45
+ /** Sync `auth.json` / `account.json`. Requires a private repository. */
46
+ includeCredentials: boolean;
47
+ /** Sync `~/.agents/skills`. */
48
+ includeSkills: boolean;
49
+ /** Sync `~/.local/state/opencode`. */
50
+ includeState: boolean;
51
+ /** Extra absolute paths to sync, relative to the home directory. */
52
+ extraPaths: string[];
53
+ sessions: SessionSettings;
54
+ /** Pull automatically when OpenCode starts (plugin only). */
55
+ autoPullOnStartup: boolean;
56
+ /** Push automatically when a session goes idle (plugin only). */
57
+ autoPushOnIdle: boolean;
58
+ }
59
+ export declare const DEFAULT_SETTINGS: Settings;
60
+ export declare function settingsPath(configRoot?: string): string;
61
+ export declare function overridesPath(configRoot?: string): string;
62
+ export declare function loadSettings(configRoot?: string): Settings;
63
+ export declare function saveSettings(settings: Settings, configRoot?: string): void;
64
+ export declare function repoUrl(settings: Settings): string | undefined;
65
+ export declare function repoBranch(settings: Settings): string;
66
+ export declare const SETTINGS_TEMPLATE = "{\n // opencode-multidevice-sync settings. This file is never committed.\n \"repo\": {\n \"owner\": \"YOUR_GITHUB_USERNAME\",\n \"name\": \"my-opencode-config\",\n \"branch\": \"main\"\n },\n\n // A short name for this machine, used in commit messages.\n // Leave unset to auto-generate a stable pseudonym from the hostname.\n // \"machineAlias\": \"laptop\",\n\n // Sync auth.json / account.json. Only enable for a PRIVATE repository.\n \"includeCredentials\": false,\n\n \"includeSkills\": true,\n \"includeState\": false,\n\n // Selective session sync. Off by default.\n \"sessions\": {\n \"enabled\": false,\n \"days\": 7,\n \"maxSessions\": 50,\n \"maxSessionBytes\": 5242880,\n \"include\": [],\n \"exclude\": [],\n \"directories\": [],\n \"backupBeforeImport\": true,\n \"backupRetention\": 10,\n \"pathMappings\": []\n },\n\n \"autoPullOnStartup\": true,\n \"autoPushOnIdle\": false\n}\n";
67
+ export declare const OVERRIDES_TEMPLATE = "{\n // Per-machine OpenCode configuration.\n //\n // This file is never committed. After every pull its contents are merged\n // back into opencode.json(c), so machine-specific settings survive syncing.\n //\n // Merge rules:\n // - objects merge key by key\n // - arrays and scalars replace whatever is in the shared config\n // - null deletes the key\n //\n // Example:\n // \"model\": \"github-copilot/claude-sonnet-4\",\n // \"mcp\": { \"playwright\": { \"enabled\": true } }\n}\n";
68
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/core/settings.ts"],"names":[],"mappings":"AAKA,yEAAyE;AACzE,eAAO,MAAM,aAAa,wBAAwB,CAAC;AACnD,sEAAsE;AACtE,eAAO,MAAM,cAAc,kCAAkC,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mEAAmE;IACnE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0EAA0E;IAC1E,kBAAkB,EAAE,OAAO,CAAC;IAC5B,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,+BAA+B;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,sCAAsC;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;IAC1B,6DAA6D;IAC7D,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iEAAiE;IACjE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,QAoB9B,CAAC;AAEF,wBAAgB,YAAY,CAAC,UAAU,SAAkB,GAAG,MAAM,CAEjE;AAED,wBAAgB,aAAa,CAAC,UAAU,SAAkB,GAAG,MAAM,CAElE;AAWD,wBAAgB,YAAY,CAAC,UAAU,SAAkB,GAAG,QAAQ,CAUnE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,SAAkB,GAAG,IAAI,CAGnF;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAO9D;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAErD;AAED,eAAO,MAAM,iBAAiB,07BAmC7B,CAAC;AAEF,eAAO,MAAM,kBAAkB,ggBAe9B,CAAC"}