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,196 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { ensureFile, writeIfDiffers } from "./fsx.js";
4
+ import { git, isGitRepo, toGitError } from "./git.js";
5
+ import { AGENTS_DIR, DATA_DIR, SESSIONS_DIR, STATE_DIR } from "./paths.js";
6
+ import { OVERRIDES_FILE, SETTINGS_FILE } from "./settings.js";
7
+ /**
8
+ * Files the sync repository must never track.
9
+ *
10
+ * Three categories:
11
+ * - local-only settings (`opencode-sync*.jsonc`)
12
+ * - the SQLite database and its journals, which are gigabytes and are
13
+ * represented instead by the shards in `_sessions/`
14
+ * - caches, logs and OS junk
15
+ */
16
+ export const DEFAULT_GITIGNORE = `# opencode-github-sync — machine-local, never committed
17
+ ${SETTINGS_FILE}
18
+ ${OVERRIDES_FILE}
19
+ .opencode-sync.lock
20
+
21
+ # Runtime / generated
22
+ node_modules/
23
+ *.backup-*
24
+ *.bak-*
25
+ *.omds-*
26
+ *.edit-tmp
27
+ .env
28
+ .env.*
29
+ _state/locks/
30
+ bun.lock
31
+ logs/
32
+ **/__pycache__/
33
+ *.pyc
34
+
35
+ # Session storage lives in ${SESSIONS_DIR}/ as portable shards.
36
+ # The raw database is far too large for git and cannot be merged.
37
+ ${DATA_DIR}/opencode.db
38
+ ${DATA_DIR}/opencode.db-shm
39
+ ${DATA_DIR}/opencode.db-wal
40
+ ${DATA_DIR}/bin/
41
+ ${DATA_DIR}/log/
42
+ ${DATA_DIR}/tool-output/
43
+ ${DATA_DIR}/snapshot/
44
+ ${DATA_DIR}/storage/session
45
+ ${DATA_DIR}/storage/session_diff
46
+
47
+ # Machine-local UI state
48
+ ${STATE_DIR}/session.json
49
+
50
+ # Empty directories recreated by OpenCode at runtime
51
+ plugin/
52
+
53
+ # OS files
54
+ .DS_Store
55
+ Thumbs.db
56
+ desktop.ini
57
+ `;
58
+ export const DEFAULT_GITATTRIBUTES = `# Store and check out everything with LF.
59
+ # "text=auto" alone would rewrite files to CRLF on Windows, which silently
60
+ # breaks shell scripts shipped inside skills and makes every cross-platform
61
+ # pull look like a whole-file change.
62
+ * text=auto eol=lf
63
+
64
+ # Append-only history files merge cleanly by taking both sides
65
+ ${STATE_DIR}/prompt-history.jsonl text eol=lf merge=union
66
+
67
+ # Session shards are gzipped JSON — binary, and never line-merged
68
+ ${SESSIONS_DIR}/*.json.gz binary
69
+ `;
70
+ /**
71
+ * Paths that exist inside the worktree but must stay out of every commit.
72
+ *
73
+ * These are runtime artefacts of the machine, not configuration. They are
74
+ * excluded from `add`, from stashing and from `clean`, so a sync can never
75
+ * delete a user's local database or tool output.
76
+ */
77
+ export const LOCAL_RUNTIME_PATHS = [
78
+ `${DATA_DIR}/opencode.db`,
79
+ `${DATA_DIR}/opencode.db-shm`,
80
+ `${DATA_DIR}/opencode.db-wal`,
81
+ `${DATA_DIR}/storage/session`,
82
+ `${DATA_DIR}/storage/session_diff`,
83
+ `${DATA_DIR}/tool-output`,
84
+ `${DATA_DIR}/snapshot`,
85
+ ];
86
+ export function isLocalRuntimePath(candidate) {
87
+ const normalized = String(candidate ?? "").replace(/\\/g, "/");
88
+ return LOCAL_RUNTIME_PATHS.some((prefix) => {
89
+ const clean = prefix.replace(/\/$/, "");
90
+ return normalized === clean || normalized.startsWith(`${clean}/`);
91
+ });
92
+ }
93
+ export function excludePathspecs() {
94
+ return LOCAL_RUNTIME_PATHS.map((p) => `:(exclude)${p}`);
95
+ }
96
+ /** Unstage runtime paths in a single git call — subprocesses are slow on Windows. */
97
+ export function unstageLocalRuntimePaths(root) {
98
+ git(["reset", "-q", "HEAD", "--", ...LOCAL_RUNTIME_PATHS], { cwd: root });
99
+ }
100
+ /** Configure identity and metadata files. Safe to call repeatedly. */
101
+ export function ensureGitIdentity(root) {
102
+ const name = git(["config", "user.name"], { cwd: root });
103
+ if (!name.ok || !name.stdout) {
104
+ git(["config", "user.name", "OpenCode Sync"], { cwd: root });
105
+ }
106
+ const email = git(["config", "user.email"], { cwd: root });
107
+ if (!email.ok || !email.stdout) {
108
+ git(["config", "user.email", "sync@opencode.local"], { cwd: root });
109
+ }
110
+ }
111
+ export function writeRepoMetadata(root) {
112
+ const ignore = path.join(root, ".gitignore");
113
+ const current = fs.existsSync(ignore) ? fs.readFileSync(ignore, "utf8") : "";
114
+ const missing = DEFAULT_GITIGNORE.split("\n").filter((l) => l && !l.startsWith("#") && !current.split(/\r?\n/).includes(l));
115
+ if (missing.length)
116
+ writeIfDiffers(ignore, current + (current.endsWith("\n") ? "" : "\n") + missing.join("\n") + "\n");
117
+ writeIfDiffers(path.join(root, ".gitattributes"), DEFAULT_GITATTRIBUTES);
118
+ }
119
+ /**
120
+ * Make `root` a git worktree pointing at `remote`.
121
+ *
122
+ * Returns `adopted` when the remote already had commits (they become the local
123
+ * state) and `fresh` when the remote exists but is empty.
124
+ */
125
+ export function initRepo(options) {
126
+ const { root, remote, branch } = options;
127
+ ensureFile(path.join(root, ".gitignore"), DEFAULT_GITIGNORE);
128
+ ensureFile(path.join(root, ".gitattributes"), DEFAULT_GITATTRIBUTES);
129
+ git(["init", "-b", branch], { cwd: root });
130
+ const existingRemote = git(["remote", "get-url", "origin"], { cwd: root });
131
+ if (existingRemote.ok) {
132
+ if (existingRemote.stdout !== remote) {
133
+ git(["remote", "set-url", "origin", remote], { cwd: root });
134
+ }
135
+ }
136
+ else {
137
+ git(["remote", "add", "origin", remote], { cwd: root });
138
+ }
139
+ ensureGitIdentity(root);
140
+ const fetched = git(["fetch", "origin", branch], { cwd: root });
141
+ if (fetched.ok && git(["rev-parse", `origin/${branch}`], { cwd: root }).ok) {
142
+ git(["reset", "--hard", `origin/${branch}`], { cwd: root });
143
+ git(["branch", `--set-upstream-to=origin/${branch}`, branch], { cwd: root });
144
+ return "adopted";
145
+ }
146
+ if (!fetched.ok && !isMissingBranch(fetched))
147
+ throw toGitError("Initial fetch", fetched);
148
+ return "fresh";
149
+ }
150
+ function isMissingBranch(result) {
151
+ return /couldn't find remote ref|remote branch .* not found/i.test(`${result.stderr}\n${result.stdout}`);
152
+ }
153
+ export function ensureRepo(options) {
154
+ if (!isGitRepo(options.root))
155
+ return initRepo(options);
156
+ ensureGitIdentity(options.root);
157
+ const remote = git(["remote", "get-url", "origin"], { cwd: options.root });
158
+ if (!remote.ok) {
159
+ git(["remote", "add", "origin", options.remote], { cwd: options.root });
160
+ }
161
+ else if (remote.stdout !== options.remote) {
162
+ git(["remote", "set-url", "origin", options.remote], { cwd: options.root });
163
+ }
164
+ return "ready";
165
+ }
166
+ /** Fail fast when the remote is unreachable, distinguishing auth from network. */
167
+ export function assertRemoteReachable(root, branch, operation, allowMissingBranch = false) {
168
+ const result = git(["ls-remote", "--exit-code", "origin", `refs/heads/${branch}`], { cwd: root });
169
+ if (result.ok)
170
+ return;
171
+ if (allowMissingBranch && git(["ls-remote", "origin"], { cwd: root }).ok)
172
+ return;
173
+ throw toGitError(operation, result);
174
+ }
175
+ /**
176
+ * Verify the commit really landed on the remote.
177
+ *
178
+ * `git push` can exit zero against a misconfigured proxy or a stale credential
179
+ * helper without the remote actually moving, so success is confirmed by reading
180
+ * the remote head back.
181
+ */
182
+ export function assertPushLanded(root, branch, operation) {
183
+ const local = git(["rev-parse", "HEAD"], { cwd: root });
184
+ const remote = git(["ls-remote", "origin", `refs/heads/${branch}`], { cwd: root });
185
+ if (!remote.ok)
186
+ throw toGitError(operation, remote);
187
+ if (!local.ok)
188
+ throw toGitError(operation, local);
189
+ const remoteHead = remote.stdout.split(/\s+/)[0] ?? "";
190
+ if (remoteHead === local.stdout)
191
+ return;
192
+ throw new Error(`${operation} reported success but the remote did not move.\n` +
193
+ ` local: ${local.stdout}\n remote: ${remoteHead || "(empty)"}`);
194
+ }
195
+ export const REPO_DIRS = { DATA_DIR, STATE_DIR, AGENTS_DIR, SESSIONS_DIR };
196
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../src/core/repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Terminal presentation layer.
3
+ *
4
+ * The core never writes to stdout directly. It emits structured events through
5
+ * a `Reporter`, so the same sync logic can render as a pretty CLI, as silent
6
+ * JSON, or as OpenCode toast notifications from inside the plugin.
7
+ */
8
+ export type ChangeKind = "added" | "modified" | "deleted" | "renamed";
9
+ export interface ChangeSummary {
10
+ added: number;
11
+ modified: number;
12
+ deleted: number;
13
+ renamed: number;
14
+ }
15
+ export interface ChangedFile {
16
+ kind: ChangeKind;
17
+ path: string;
18
+ }
19
+ export interface Reporter {
20
+ step(message: string): void;
21
+ info(message: string): void;
22
+ success(message: string): void;
23
+ warn(message: string): void;
24
+ error(message: string): void;
25
+ detail(message: string): void;
26
+ changes(summary: ChangeSummary, files: ChangedFile[]): void;
27
+ }
28
+ export declare const silentReporter: Reporter;
29
+ /** Collects everything for later inspection — used by the plugin and tests. */
30
+ export declare class CollectingReporter implements Reporter {
31
+ readonly lines: {
32
+ level: string;
33
+ message: string;
34
+ }[];
35
+ summary: ChangeSummary;
36
+ files: ChangedFile[];
37
+ private push;
38
+ step(message: string): void;
39
+ info(message: string): void;
40
+ success(message: string): void;
41
+ warn(message: string): void;
42
+ error(message: string): void;
43
+ detail(message: string): void;
44
+ changes(summary: ChangeSummary, files: ChangedFile[]): void;
45
+ get text(): string;
46
+ }
47
+ export declare function emptySummary(): ChangeSummary;
48
+ export declare function summarize(files: ChangedFile[]): ChangeSummary;
49
+ export declare function totalChanges(summary: ChangeSummary): number;
50
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;CAC7D;AAED,eAAO,MAAM,cAAc,EAAE,QAQ5B,CAAC;AAEF,+EAA+E;AAC/E,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,QAAQ,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAC1D,OAAO,EAAE,aAAa,CAAqD;IAC3E,KAAK,EAAE,WAAW,EAAE,CAAM;IAE1B,OAAO,CAAC,IAAI;IAIZ,IAAI,CAAC,OAAO,EAAE,MAAM;IAGpB,IAAI,CAAC,OAAO,EAAE,MAAM;IAGpB,OAAO,CAAC,OAAO,EAAE,MAAM;IAGvB,IAAI,CAAC,OAAO,EAAE,MAAM;IAGpB,KAAK,CAAC,OAAO,EAAE,MAAM;IAGrB,MAAM,CAAC,OAAO,EAAE,MAAM;IAGtB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE;IAKpD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED,wBAAgB,YAAY,IAAI,aAAa,CAE5C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,aAAa,CAI7D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAE3D"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Terminal presentation layer.
3
+ *
4
+ * The core never writes to stdout directly. It emits structured events through
5
+ * a `Reporter`, so the same sync logic can render as a pretty CLI, as silent
6
+ * JSON, or as OpenCode toast notifications from inside the plugin.
7
+ */
8
+ export const silentReporter = {
9
+ step() { },
10
+ info() { },
11
+ success() { },
12
+ warn() { },
13
+ error() { },
14
+ detail() { },
15
+ changes() { },
16
+ };
17
+ /** Collects everything for later inspection — used by the plugin and tests. */
18
+ export class CollectingReporter {
19
+ lines = [];
20
+ summary = { added: 0, modified: 0, deleted: 0, renamed: 0 };
21
+ files = [];
22
+ push(level, message) {
23
+ this.lines.push({ level, message });
24
+ }
25
+ step(message) {
26
+ this.push("step", message);
27
+ }
28
+ info(message) {
29
+ this.push("info", message);
30
+ }
31
+ success(message) {
32
+ this.push("success", message);
33
+ }
34
+ warn(message) {
35
+ this.push("warn", message);
36
+ }
37
+ error(message) {
38
+ this.push("error", message);
39
+ }
40
+ detail(message) {
41
+ this.push("detail", message);
42
+ }
43
+ changes(summary, files) {
44
+ this.summary = summary;
45
+ this.files = files;
46
+ }
47
+ get text() {
48
+ return this.lines.map((l) => l.message).join("\n");
49
+ }
50
+ }
51
+ export function emptySummary() {
52
+ return { added: 0, modified: 0, deleted: 0, renamed: 0 };
53
+ }
54
+ export function summarize(files) {
55
+ const summary = emptySummary();
56
+ for (const file of files)
57
+ summary[file.kind]++;
58
+ return summary;
59
+ }
60
+ export function totalChanges(summary) {
61
+ return summary.added + summary.modified + summary.deleted + summary.renamed;
62
+ }
63
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA0BH,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,IAAI,KAAI,CAAC;IACT,IAAI,KAAI,CAAC;IACT,OAAO,KAAI,CAAC;IACZ,IAAI,KAAI,CAAC;IACT,KAAK,KAAI,CAAC;IACV,MAAM,KAAI,CAAC;IACX,OAAO,KAAI,CAAC;CACb,CAAC;AAEF,+EAA+E;AAC/E,MAAM,OAAO,kBAAkB;IACpB,KAAK,GAAyC,EAAE,CAAC;IAC1D,OAAO,GAAkB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC3E,KAAK,GAAkB,EAAE,CAAC;IAElB,IAAI,CAAC,KAAa,EAAE,OAAe;QACzC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,OAAe;QACrB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,CAAC,OAAe;QACpB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,OAAsB,EAAE,KAAoB;QAClD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;CACF;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAoB;IAC5C,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,OAAO,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,83 @@
1
+ import type { Reporter } from "./reporter.js";
2
+ import type { SessionSettings } from "./settings.js";
3
+ import { type SqliteDatabase } from "./sqlite.js";
4
+ /**
5
+ * `event` and `event_sequence` are deliberately excluded. They are an internal
6
+ * append-only runtime log, they dwarf everything else in row count, and nothing
7
+ * about resuming a conversation on another machine depends on them.
8
+ */
9
+ export interface SessionRecord {
10
+ id: string;
11
+ title: string;
12
+ directory: string;
13
+ timeUpdated: number;
14
+ timeCreated: number;
15
+ projectId: string;
16
+ }
17
+ export interface SessionShard {
18
+ formatVersion: 1;
19
+ session: Record<string, unknown>;
20
+ project?: Record<string, unknown>;
21
+ workspace?: Record<string, unknown>;
22
+ tables: Record<string, Record<string, unknown>[]>;
23
+ exportedAt: number;
24
+ }
25
+ export interface SelectOptions extends SessionSettings {
26
+ now?: number;
27
+ }
28
+ export interface ExportResult {
29
+ written: string[];
30
+ skippedTooLarge: {
31
+ id: string;
32
+ title: string;
33
+ bytes: number;
34
+ }[];
35
+ considered: number;
36
+ conflicts?: string[];
37
+ }
38
+ export interface ImportResult {
39
+ imported: number;
40
+ skippedOlder: number;
41
+ conflicts: {
42
+ sessionId: string;
43
+ reason: string;
44
+ }[];
45
+ failed: {
46
+ file: string;
47
+ reason: string;
48
+ }[];
49
+ backup?: string;
50
+ rolledBack?: boolean;
51
+ dryRun?: boolean;
52
+ }
53
+ export interface ImportOptions {
54
+ dryRun?: boolean;
55
+ preferRemote?: boolean;
56
+ backupBeforeImport?: boolean;
57
+ backupRetention?: number;
58
+ pathMappings?: Array<{
59
+ from: string;
60
+ to: string;
61
+ }>;
62
+ }
63
+ /** Session ids are opaque; keep them filesystem-safe without losing identity. */
64
+ export declare function sanitizeId(id: string): string;
65
+ /**
66
+ * Choose which sessions to export.
67
+ *
68
+ * Explicitly included ids always win, even when they fall outside the window.
69
+ * Everything else must be inside the time window, pass the directory filter and
70
+ * survive the count cap, which keeps the newest sessions.
71
+ */
72
+ export declare function selectSessions(db: SqliteDatabase, options: SelectOptions): SessionRecord[];
73
+ type Mapping = {
74
+ from: string;
75
+ to: string;
76
+ };
77
+ export declare function exportSessions(file: string, repo: string, options: SelectOptions, reporter: Reporter): Promise<ExportResult>;
78
+ export declare function acknowledgeExport(file: string, repo: string, mappings?: Mapping[]): Promise<void>;
79
+ export declare function importSessions(file: string, repo: string, reporter: Reporter, options?: ImportOptions): Promise<ImportResult>;
80
+ /** List sessions available locally, newest first - powers `sessions list`. */
81
+ export declare function listSessions(databaseFile: string, limit: number): Promise<SessionRecord[]>;
82
+ export {};
83
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/core/sessions.ts"],"names":[],"mappings":"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"}