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,353 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ /**
4
+ * Filesystem helpers used by staging.
5
+ *
6
+ * Two properties matter throughout this module:
7
+ *
8
+ * 1. **Symlinks are refused, never followed.** A sync repo that follows a
9
+ * symlink can be tricked into copying arbitrary files off the machine, and
10
+ * on Windows a directory junction silently turns a delete into a delete of
11
+ * something else entirely.
12
+ * 2. **Replacements are atomic.** Destinations are built beside the target and
13
+ * renamed into place, so a crash mid-copy can never leave a half-written
14
+ * config that stops OpenCode from starting.
15
+ */
16
+ export function ensureDir(dir) {
17
+ fs.mkdirSync(dir, { recursive: true });
18
+ }
19
+ export function exists(target) {
20
+ return fs.existsSync(target);
21
+ }
22
+ export function removeRecursive(target) {
23
+ fs.rmSync(target, { recursive: true, force: true });
24
+ }
25
+ export class SymlinkRefusedError extends Error {
26
+ constructor(role, target) {
27
+ super(`Refusing to sync ${role} symlink/junction: ${target}`);
28
+ this.name = "SymlinkRefusedError";
29
+ }
30
+ }
31
+ export function rejectLink(target, role) {
32
+ try {
33
+ if (fs.lstatSync(target).isSymbolicLink())
34
+ throw new SymlinkRefusedError(role, target);
35
+ }
36
+ catch (err) {
37
+ if (err instanceof SymlinkRefusedError)
38
+ throw err;
39
+ if (err?.code !== "ENOENT")
40
+ throw err;
41
+ }
42
+ }
43
+ /** Write only when the content actually differs. Returns true if written. */
44
+ export function writeIfDiffers(filePath, content) {
45
+ if (fs.existsSync(filePath) && fs.readFileSync(filePath, "utf8") === content)
46
+ return false;
47
+ ensureDir(path.dirname(filePath));
48
+ fs.writeFileSync(filePath, content);
49
+ return true;
50
+ }
51
+ /** Create the file only when missing. Returns true if created. */
52
+ export function ensureFile(filePath, content) {
53
+ if (fs.existsSync(filePath))
54
+ return false;
55
+ ensureDir(path.dirname(filePath));
56
+ fs.writeFileSync(filePath, content);
57
+ return true;
58
+ }
59
+ export function copyFileIfExists(src, dst) {
60
+ if (!fs.existsSync(src))
61
+ return false;
62
+ rejectLink(src, "source");
63
+ rejectLink(dst, "target");
64
+ ensureDir(path.dirname(dst));
65
+ fs.copyFileSync(src, dst);
66
+ return true;
67
+ }
68
+ /** Copy `src` onto `dst`, deleting `dst` when `src` does not exist. */
69
+ export function mirrorFile(src, dst) {
70
+ rejectLink(src, "source");
71
+ rejectLink(dst, "target");
72
+ if (!fs.existsSync(src)) {
73
+ fs.rmSync(dst, { recursive: true, force: true });
74
+ return 0;
75
+ }
76
+ return copyFileIfExists(src, dst) ? 1 : 0;
77
+ }
78
+ export function copyDirRecursive(src, dst, options = {}) {
79
+ const { excludeFiles = new Set(), excludeDirs = new Set() } = options;
80
+ if (!fs.existsSync(src))
81
+ return 0;
82
+ rejectLink(src, "source");
83
+ rejectLink(dst, "target");
84
+ ensureDir(dst);
85
+ let count = 0;
86
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
87
+ const srcPath = path.join(src, entry.name);
88
+ if (entry.isSymbolicLink())
89
+ throw new SymlinkRefusedError("source", srcPath);
90
+ const dstPath = path.join(dst, entry.name);
91
+ if (entry.isDirectory()) {
92
+ if (excludeDirs.has(entry.name))
93
+ continue;
94
+ rejectLink(dstPath, "target");
95
+ count += copyDirRecursive(srcPath, dstPath, options);
96
+ }
97
+ else {
98
+ if (excludeFiles.has(entry.name))
99
+ continue;
100
+ rejectLink(dstPath, "target");
101
+ fs.copyFileSync(srcPath, dstPath);
102
+ count++;
103
+ }
104
+ }
105
+ return count;
106
+ }
107
+ /**
108
+ * Mirror `srcDir` into `dstDir`, copying only what changed.
109
+ *
110
+ * Change detection compares size and modification time at **one-second
111
+ * granularity**, then falls back to a content compare. Whole seconds are
112
+ * exactly representable on every filesystem we support; sub-second precision
113
+ * drifts between NTFS and APFS and would make every run re-copy the entire
114
+ * tree, which defeats the point.
115
+ */
116
+ export function syncDirIncremental(srcDir, dstDir, options = {}) {
117
+ const { excludeFiles = new Set(), excludeDirs = new Set(), deleteExtraneous = true, } = options;
118
+ rejectLink(srcDir, "source");
119
+ rejectLink(dstDir, "target");
120
+ if (!fs.existsSync(srcDir)) {
121
+ // Source gone means the user deleted it; mirror that so the repo stays
122
+ // an accurate reflection of the machine rather than growing forever.
123
+ if (fs.existsSync(dstDir))
124
+ fs.rmSync(dstDir, { recursive: true, force: true });
125
+ return { copied: 0, deleted: 0 };
126
+ }
127
+ ensureDir(dstDir);
128
+ let copied = 0;
129
+ let deleted = 0;
130
+ const walkSource = (rel) => {
131
+ const srcAbs = rel ? path.join(srcDir, rel) : srcDir;
132
+ const dstAbs = rel ? path.join(dstDir, rel) : dstDir;
133
+ let entries;
134
+ try {
135
+ entries = fs.readdirSync(srcAbs, { withFileTypes: true });
136
+ }
137
+ catch {
138
+ return;
139
+ }
140
+ for (const entry of entries) {
141
+ const srcPath = path.join(srcAbs, entry.name);
142
+ if (entry.isSymbolicLink())
143
+ throw new SymlinkRefusedError("source", srcPath);
144
+ if (entry.isDirectory()) {
145
+ if (excludeDirs.has(entry.name))
146
+ continue;
147
+ const childRel = rel ? path.join(rel, entry.name) : entry.name;
148
+ const dstChild = path.join(dstDir, childRel);
149
+ rejectLink(dstChild, "target");
150
+ ensureDir(dstChild);
151
+ walkSource(childRel);
152
+ continue;
153
+ }
154
+ if (excludeFiles.has(entry.name))
155
+ continue;
156
+ const dstFile = path.join(dstAbs, entry.name);
157
+ rejectLink(dstFile, "target");
158
+ const srcStat = fs.statSync(srcPath);
159
+ const srcSeconds = Math.floor(srcStat.mtimeMs / 1000);
160
+ let needCopy = true;
161
+ try {
162
+ const dstStat = fs.statSync(dstFile);
163
+ if (dstStat.size === srcStat.size && Math.floor(dstStat.mtimeMs / 1000) === srcSeconds) {
164
+ needCopy = !fs.readFileSync(srcPath).equals(fs.readFileSync(dstFile));
165
+ }
166
+ }
167
+ catch {
168
+ // Missing destination — copy.
169
+ }
170
+ if (needCopy) {
171
+ fs.copyFileSync(srcPath, dstFile);
172
+ try {
173
+ const stamp = new Date(srcSeconds * 1000);
174
+ fs.utimesSync(dstFile, stamp, stamp);
175
+ }
176
+ catch {
177
+ // Best effort; a failed utimes only costs one redundant copy later.
178
+ }
179
+ copied++;
180
+ }
181
+ }
182
+ };
183
+ const walkDestination = (rel) => {
184
+ const srcAbs = rel ? path.join(srcDir, rel) : srcDir;
185
+ const dstAbs = rel ? path.join(dstDir, rel) : dstDir;
186
+ let entries;
187
+ try {
188
+ entries = fs.readdirSync(dstAbs, { withFileTypes: true });
189
+ }
190
+ catch {
191
+ return;
192
+ }
193
+ for (const entry of entries) {
194
+ const childRel = rel ? path.join(rel, entry.name) : entry.name;
195
+ const srcChild = path.join(srcAbs, entry.name);
196
+ const dstChild = path.join(dstDir, childRel);
197
+ if (entry.isSymbolicLink())
198
+ throw new SymlinkRefusedError("target", dstChild);
199
+ if (entry.isDirectory()) {
200
+ if (excludeDirs.has(entry.name))
201
+ continue;
202
+ if (!fs.existsSync(srcChild)) {
203
+ fs.rmSync(dstChild, { recursive: true, force: true });
204
+ deleted++;
205
+ }
206
+ else {
207
+ walkDestination(childRel);
208
+ }
209
+ continue;
210
+ }
211
+ if (excludeFiles.has(entry.name))
212
+ continue;
213
+ if (!fs.existsSync(srcChild)) {
214
+ fs.unlinkSync(dstChild);
215
+ deleted++;
216
+ }
217
+ }
218
+ };
219
+ walkSource("");
220
+ if (deleteExtraneous)
221
+ walkDestination("");
222
+ return { copied, deleted };
223
+ }
224
+ /** Replace a single file atomically. */
225
+ export function replaceFileAtomically(src, dst, options = {}) {
226
+ rejectLink(src, "source");
227
+ rejectLink(dst, "target");
228
+ if (!fs.existsSync(src)) {
229
+ if (!options.preserveMissing)
230
+ fs.rmSync(dst, { recursive: true, force: true });
231
+ return 0;
232
+ }
233
+ ensureDir(path.dirname(dst));
234
+ const temp = `${dst}.sync-${process.pid}-${Date.now()}`;
235
+ const backup = `${temp}.old`;
236
+ try {
237
+ fs.copyFileSync(src, temp);
238
+ fs.rmSync(backup, { recursive: true, force: true });
239
+ if (fs.existsSync(dst))
240
+ fs.renameSync(dst, backup);
241
+ fs.renameSync(temp, dst);
242
+ fs.rmSync(backup, { recursive: true, force: true });
243
+ return 1;
244
+ }
245
+ catch (err) {
246
+ fs.rmSync(temp, { recursive: true, force: true });
247
+ if (!fs.existsSync(dst) && fs.existsSync(backup))
248
+ fs.renameSync(backup, dst);
249
+ throw err;
250
+ }
251
+ }
252
+ /** Replace a whole directory atomically. */
253
+ export function replaceDirAtomically(src, dst, options = {}) {
254
+ rejectLink(src, "source");
255
+ rejectLink(dst, "target");
256
+ if (!fs.existsSync(src)) {
257
+ removeRecursive(dst);
258
+ return 0;
259
+ }
260
+ const parent = path.dirname(dst);
261
+ ensureDir(parent);
262
+ const temp = path.join(parent, `.${path.basename(dst)}.sync-${process.pid}-${Date.now()}`);
263
+ const backup = `${temp}.old`;
264
+ removeRecursive(temp);
265
+ try {
266
+ const count = copyDirRecursive(src, temp, options);
267
+ for (const file of options.preserveRootFiles ?? []) {
268
+ copyFileIfExists(path.join(dst, file), path.join(temp, file));
269
+ }
270
+ if (fs.existsSync(dst))
271
+ fs.renameSync(dst, backup);
272
+ fs.renameSync(temp, dst);
273
+ removeRecursive(backup);
274
+ return count;
275
+ }
276
+ catch (err) {
277
+ removeRecursive(temp);
278
+ if (!fs.existsSync(dst) && fs.existsSync(backup))
279
+ fs.renameSync(backup, dst);
280
+ throw err;
281
+ }
282
+ }
283
+ /**
284
+ * Copy a path that may be either a file or a directory.
285
+ *
286
+ * OpenCode's `storage/migration` is a one-byte file while `storage/project` is
287
+ * a directory, and which is which has changed between releases — so the type is
288
+ * decided by looking at the source, not by assumption.
289
+ */
290
+ export function copyPath(src, dst) {
291
+ rejectLink(src, "source");
292
+ rejectLink(dst, "target");
293
+ let stat;
294
+ try {
295
+ stat = fs.statSync(src);
296
+ }
297
+ catch {
298
+ fs.rmSync(dst, { recursive: true, force: true });
299
+ return 0;
300
+ }
301
+ return stat.isDirectory() ? replaceDirAtomically(src, dst) : replaceFileAtomically(src, dst);
302
+ }
303
+ /**
304
+ * Strip nested `.git` directories from a staging copy.
305
+ *
306
+ * The `skills` CLI installs by cloning, which leaves a `.git` inside the skill
307
+ * directory. Git records a nested repository as a gitlink instead of tracking
308
+ * the files, so the skill's contents become invisible to every other machine.
309
+ * Only staging copies are touched; the real source directories are never
310
+ * modified.
311
+ */
312
+ export function removeNestedGitDirs(...dirs) {
313
+ let removed = 0;
314
+ const walk = (dir) => {
315
+ let entries;
316
+ try {
317
+ entries = fs.readdirSync(dir, { withFileTypes: true });
318
+ }
319
+ catch {
320
+ return;
321
+ }
322
+ for (const entry of entries) {
323
+ const child = path.join(dir, entry.name);
324
+ if (entry.name === ".git") {
325
+ fs.rmSync(child, { recursive: true, force: true });
326
+ removed++;
327
+ continue;
328
+ }
329
+ if (entry.isDirectory())
330
+ walk(child);
331
+ }
332
+ };
333
+ for (const dir of dirs) {
334
+ if (!fs.existsSync(dir))
335
+ continue;
336
+ // Walk the children rather than `dir` itself so the sync repo's own
337
+ // top-level `.git` is never deleted.
338
+ let entries;
339
+ try {
340
+ entries = fs.readdirSync(dir, { withFileTypes: true });
341
+ }
342
+ catch {
343
+ continue;
344
+ }
345
+ for (const entry of entries) {
346
+ if (!entry.isDirectory() || entry.name === ".git")
347
+ continue;
348
+ walk(path.join(dir, entry.name));
349
+ }
350
+ }
351
+ return removed;
352
+ }
353
+ //# sourceMappingURL=fsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsx.js","sourceRoot":"","sources":["../../src/core/fsx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ export interface GitResult {
2
+ ok: boolean;
3
+ stdout: string;
4
+ stderr: string;
5
+ code: number | null;
6
+ }
7
+ export interface GitOptions {
8
+ cwd: string;
9
+ /** Allow git to prompt on the terminal. Off by default so we never hang. */
10
+ interactive?: boolean;
11
+ timeoutMs?: number;
12
+ }
13
+ /**
14
+ * Run git and never throw.
15
+ *
16
+ * Every caller wants to inspect the failure rather than unwind, so the exit
17
+ * status is returned as data. Terminal prompting is disabled by default: a sync
18
+ * that silently blocks on a hidden credential prompt is far worse than one that
19
+ * fails fast with an actionable message.
20
+ */
21
+ export declare function git(args: string[], options: GitOptions): GitResult;
22
+ export declare function gitAsync(args: string[], options: GitOptions): Promise<GitResult>;
23
+ export declare function isGitRepo(dir: string): boolean;
24
+ export declare function firstLine(text: string): string;
25
+ /** True when a git failure is really "your GitHub credentials are not working". */
26
+ export declare function isAuthFailure(result: GitResult): boolean;
27
+ export declare class GitAuthError extends Error {
28
+ readonly result: GitResult;
29
+ constructor(operation: string, result: GitResult);
30
+ }
31
+ export declare class GitError extends Error {
32
+ readonly result: GitResult;
33
+ constructor(operation: string, result: GitResult);
34
+ }
35
+ /** Convert a failed `GitResult` into the most specific error we can. */
36
+ export declare function toGitError(operation: string, result: GitResult): Error;
37
+ /**
38
+ * Extract the file paths from `git status --porcelain` output.
39
+ *
40
+ * The format is fixed-width — two status columns, a space, then the path — but
41
+ * this deliberately does not slice at a fixed offset. Output here is trimmed
42
+ * before parsing, which eats the leading space of an unstaged entry (` M file`)
43
+ * and shifts every subsequent column. Matching the status field by pattern
44
+ * instead survives that, as well as the quoting git applies to paths with
45
+ * unusual characters.
46
+ *
47
+ * Renames appear as `old -> new`; the destination is reported, since that is
48
+ * what exists afterwards.
49
+ */
50
+ export declare function parsePorcelainPaths(output: string): string[];
51
+ export interface NameStatusEntry {
52
+ kind: "added" | "modified" | "deleted" | "renamed";
53
+ path: string;
54
+ }
55
+ /**
56
+ * Parse `git diff --name-status` output.
57
+ *
58
+ * Rename entries carry three tab-separated fields (`R100 old new`); we report
59
+ * the destination path because that is what exists after the operation.
60
+ */
61
+ export declare function parseNameStatus(output: string): NameStatusEntry[];
62
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,4EAA4E;IAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD;;;;;;;GAOG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,CAkBlE;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAiBtF;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C;AAgBD,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAExD;AAED,qBAAa,YAAa,SAAQ,KAAK;IAGnC,QAAQ,CAAC,MAAM,EAAE,SAAS;gBAD1B,SAAS,EAAE,MAAM,EACR,MAAM,EAAE,SAAS;CAQ7B;AAED,qBAAa,QAAS,SAAQ,KAAK;IAG/B,QAAQ,CAAC,MAAM,EAAE,SAAS;gBAD1B,SAAS,EAAE,MAAM,EACR,MAAM,EAAE,SAAS;CAO7B;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,CAItE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAY5D;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACnD,IAAI,EAAE,MAAM,CAAC;CACd;AAWD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAajE"}
@@ -0,0 +1,162 @@
1
+ import { execFile, execFileSync } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execFileAsync = promisify(execFile);
4
+ const NO_PROMPT_ENV = {
5
+ GIT_TERMINAL_PROMPT: "0",
6
+ GIT_ASKPASS: "",
7
+ GCM_INTERACTIVE: "never",
8
+ };
9
+ /**
10
+ * Run git and never throw.
11
+ *
12
+ * Every caller wants to inspect the failure rather than unwind, so the exit
13
+ * status is returned as data. Terminal prompting is disabled by default: a sync
14
+ * that silently blocks on a hidden credential prompt is far worse than one that
15
+ * fails fast with an actionable message.
16
+ */
17
+ export function git(args, options) {
18
+ try {
19
+ const stdout = execFileSync("git", args, {
20
+ cwd: options.cwd,
21
+ encoding: "utf8",
22
+ stdio: "pipe",
23
+ timeout: options.timeoutMs ?? 0,
24
+ env: options.interactive ? process.env : { ...process.env, ...NO_PROMPT_ENV },
25
+ });
26
+ return { ok: true, stdout: stdout.trim(), stderr: "", code: 0 };
27
+ }
28
+ catch (e) {
29
+ return {
30
+ ok: false,
31
+ stdout: String(e.stdout ?? "").trim(),
32
+ stderr: String(e.stderr ?? e.message ?? "").trim(),
33
+ code: typeof e.status === "number" ? e.status : null,
34
+ };
35
+ }
36
+ }
37
+ export async function gitAsync(args, options) {
38
+ try {
39
+ const { stdout, stderr } = await execFileAsync("git", args, {
40
+ cwd: options.cwd,
41
+ encoding: "utf8",
42
+ maxBuffer: 64 * 1024 * 1024,
43
+ env: options.interactive ? process.env : { ...process.env, ...NO_PROMPT_ENV },
44
+ });
45
+ return { ok: true, stdout: stdout.trim(), stderr: stderr.trim(), code: 0 };
46
+ }
47
+ catch (e) {
48
+ return {
49
+ ok: false,
50
+ stdout: String(e.stdout ?? "").trim(),
51
+ stderr: String(e.stderr ?? e.message ?? "").trim(),
52
+ code: typeof e.code === "number" ? e.code : null,
53
+ };
54
+ }
55
+ }
56
+ export function isGitRepo(dir) {
57
+ return git(["rev-parse", "--is-inside-work-tree"], { cwd: dir }).stdout === "true";
58
+ }
59
+ export function firstLine(text) {
60
+ return (String(text ?? "")
61
+ .split("\n")
62
+ .find((line) => line.trim().length > 0)
63
+ ?.trim() ?? "");
64
+ }
65
+ const AUTH_FAILURE = new RegExp([
66
+ "Authentication failed",
67
+ "could not read Username",
68
+ "terminal prompts disabled",
69
+ "Repository not found",
70
+ "Permission denied",
71
+ "access denied",
72
+ "\\b401\\b",
73
+ "\\b403\\b",
74
+ ].join("|"), "i");
75
+ /** True when a git failure is really "your GitHub credentials are not working". */
76
+ export function isAuthFailure(result) {
77
+ return AUTH_FAILURE.test(`${result.stderr}\n${result.stdout}`);
78
+ }
79
+ export class GitAuthError extends Error {
80
+ result;
81
+ constructor(operation, result) {
82
+ super(`${operation} failed: GitHub credentials are missing or lack access.\n` +
83
+ `Run: gh auth login -h github.com (the token needs the "repo" scope for private repositories)`);
84
+ this.result = result;
85
+ this.name = "GitAuthError";
86
+ }
87
+ }
88
+ export class GitError extends Error {
89
+ result;
90
+ constructor(operation, result) {
91
+ super(`${operation} failed: ${firstLine(result.stderr || result.stdout) || "unknown git error"}`);
92
+ this.result = result;
93
+ this.name = "GitError";
94
+ }
95
+ }
96
+ /** Convert a failed `GitResult` into the most specific error we can. */
97
+ export function toGitError(operation, result) {
98
+ return isAuthFailure(result)
99
+ ? new GitAuthError(operation, result)
100
+ : new GitError(operation, result);
101
+ }
102
+ /**
103
+ * Extract the file paths from `git status --porcelain` output.
104
+ *
105
+ * The format is fixed-width — two status columns, a space, then the path — but
106
+ * this deliberately does not slice at a fixed offset. Output here is trimmed
107
+ * before parsing, which eats the leading space of an unstaged entry (` M file`)
108
+ * and shifts every subsequent column. Matching the status field by pattern
109
+ * instead survives that, as well as the quoting git applies to paths with
110
+ * unusual characters.
111
+ *
112
+ * Renames appear as `old -> new`; the destination is reported, since that is
113
+ * what exists afterwards.
114
+ */
115
+ export function parsePorcelainPaths(output) {
116
+ const paths = [];
117
+ for (const line of String(output ?? "").split("\n")) {
118
+ if (!line.trim())
119
+ continue;
120
+ const withoutStatus = line.replace(/^\s*[MADRCU?!]{1,2}\s+/, "");
121
+ if (withoutStatus === line.trim() && !/^\s*[MADRCU?!]/.test(line))
122
+ continue;
123
+ const arrow = withoutStatus.lastIndexOf(" -> ");
124
+ const raw = arrow === -1 ? withoutStatus : withoutStatus.slice(arrow + 4);
125
+ const unquoted = raw.trim().replace(/^"(.*)"$/, "$1");
126
+ if (unquoted)
127
+ paths.push(unquoted);
128
+ }
129
+ return paths;
130
+ }
131
+ const STATUS_MAP = {
132
+ A: "added",
133
+ M: "modified",
134
+ D: "deleted",
135
+ R: "renamed",
136
+ C: "added",
137
+ T: "modified",
138
+ };
139
+ /**
140
+ * Parse `git diff --name-status` output.
141
+ *
142
+ * Rename entries carry three tab-separated fields (`R100 old new`); we report
143
+ * the destination path because that is what exists after the operation.
144
+ */
145
+ export function parseNameStatus(output) {
146
+ const entries = [];
147
+ for (const line of String(output ?? "").split("\n")) {
148
+ if (!line.trim())
149
+ continue;
150
+ const parts = line.split("\t");
151
+ const statusChar = (parts[0] ?? "").charAt(0).toUpperCase();
152
+ const kind = STATUS_MAP[statusChar];
153
+ if (!kind)
154
+ continue;
155
+ const filePath = parts.length > 2 ? parts.slice(2).join("\t").trim() : (parts[1] ?? "").trim();
156
+ if (!filePath)
157
+ continue;
158
+ entries.push({ kind, path: filePath });
159
+ }
160
+ return entries;
161
+ }
162
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Settings } from "./settings.js";
2
+ export declare function assertPrivateRemote(remote: string, settings: Settings): void;
3
+ export declare function assertSafeTrackedFiles(root: string, settings: Settings): void;
4
+ export declare function createConfigBackup(config: string, data: string): void;
5
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/core/guard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAmB5E;AACD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAkC7E;AACD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CA4CrE"}