gutterpress 0.0.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 (230) hide show
  1. package/README.md +422 -0
  2. package/dist/CGATS21_CRPC1-g0e3k7kr.icc +0 -0
  3. package/dist/api/index.d.ts +76 -0
  4. package/dist/api/index.js +272 -0
  5. package/dist/assets/preview/scripts/pagedjs-bridge.d.ts +1 -0
  6. package/dist/assets/preview/scripts/pagedjs-interface.d.ts +1 -0
  7. package/dist/assets/preview/scripts/preview-shell.d.ts +1 -0
  8. package/dist/audit-1jrwwacz.js +66 -0
  9. package/dist/build-5s92kgpc.js +77 -0
  10. package/dist/chapter-01-6fn9pvd0.md +31 -0
  11. package/dist/chapter-01-7jwqg1ct.md +20 -0
  12. package/dist/chapter-01-jj8ftn4c.md +29 -0
  13. package/dist/chapter-01-rkpyvjna.md +26 -0
  14. package/dist/checks/asset/approved-fonts.d.ts +3 -0
  15. package/dist/checks/asset/extensions.d.ts +41 -0
  16. package/dist/checks/asset/font-license.d.ts +3 -0
  17. package/dist/checks/asset/image-alpha.d.ts +3 -0
  18. package/dist/checks/asset/image-color-space.d.ts +3 -0
  19. package/dist/checks/asset/image-file-size.d.ts +3 -0
  20. package/dist/checks/asset/image-resolution.d.ts +3 -0
  21. package/dist/checks/asset/image-tac.d.ts +3 -0
  22. package/dist/checks/asset/index.d.ts +7 -0
  23. package/dist/checks/formatter.d.ts +3 -0
  24. package/dist/checks/heuristic/index.d.ts +4 -0
  25. package/dist/checks/heuristic/layer-count.d.ts +3 -0
  26. package/dist/checks/heuristic/placement-variance.d.ts +3 -0
  27. package/dist/checks/heuristic/section-density.d.ts +3 -0
  28. package/dist/checks/heuristic/text-density.d.ts +3 -0
  29. package/dist/checks/pdf/bleed.d.ts +3 -0
  30. package/dist/checks/pdf/bookmarks.d.ts +3 -0
  31. package/dist/checks/pdf/color-spaces.d.ts +3 -0
  32. package/dist/checks/pdf/cross-refs.d.ts +3 -0
  33. package/dist/checks/pdf/embedded-fonts.d.ts +3 -0
  34. package/dist/checks/pdf/image-resolution.d.ts +3 -0
  35. package/dist/checks/pdf/index.d.ts +15 -0
  36. package/dist/checks/pdf/ink-coverage.d.ts +3 -0
  37. package/dist/checks/pdf/page-labels.d.ts +3 -0
  38. package/dist/checks/pdf/page-size.d.ts +3 -0
  39. package/dist/checks/pdf/pdfx-markers.d.ts +3 -0
  40. package/dist/checks/pdf/pdfx-metadata.d.ts +3 -0
  41. package/dist/checks/pdf/pdfx-structure.d.ts +6 -0
  42. package/dist/checks/pdf/qpdf-structure.d.ts +3 -0
  43. package/dist/checks/pdf/rasterized-pages.d.ts +3 -0
  44. package/dist/checks/pdf/toc-links.d.ts +3 -0
  45. package/dist/checks/pdf/transparency.d.ts +3 -0
  46. package/dist/checks/policy.d.ts +61 -0
  47. package/dist/checks/register-builtins.d.ts +17 -0
  48. package/dist/checks/registry.d.ts +40 -0
  49. package/dist/checks/runner.d.ts +25 -0
  50. package/dist/checks/source/accessibility-alt-text.d.ts +3 -0
  51. package/dist/checks/source/accessibility-heading-order.d.ts +3 -0
  52. package/dist/checks/source/config-file.d.ts +8 -0
  53. package/dist/checks/source/htmlhint.d.ts +3 -0
  54. package/dist/checks/source/index.d.ts +6 -0
  55. package/dist/checks/source/local-refs.d.ts +3 -0
  56. package/dist/checks/source/markdownlint.d.ts +3 -0
  57. package/dist/checks/source/stylelint.d.ts +3 -0
  58. package/dist/checks/tool-check.d.ts +23 -0
  59. package/dist/checks/types.d.ts +52 -0
  60. package/dist/cli-1tyj4bk3.js +124 -0
  61. package/dist/cli-37x76zdn.js +4 -0
  62. package/dist/cli-506tg37g.js +26 -0
  63. package/dist/cli-5bxx0c4y.js +464 -0
  64. package/dist/cli-7ykx7pp0.js +12378 -0
  65. package/dist/cli-h7phg3ka.js +746 -0
  66. package/dist/cli-hvqjs342.js +284 -0
  67. package/dist/cli-yja077f6.js +92 -0
  68. package/dist/cli.js +157 -0
  69. package/dist/constants.d.ts +17 -0
  70. package/dist/doctor-25zjt8dz.js +57 -0
  71. package/dist/favicon-wkbm9cjn.ico +0 -0
  72. package/dist/git-http-yrb4ag6z.js +17 -0
  73. package/dist/index-1tyj4bk3.js +124 -0
  74. package/dist/index-37x76zdn.js +4 -0
  75. package/dist/index-3h3fef7r.js +15218 -0
  76. package/dist/index-5bxx0c4y.js +464 -0
  77. package/dist/index-yja077f6.js +92 -0
  78. package/dist/index.d.ts +32 -0
  79. package/dist/index.js +310 -0
  80. package/dist/lib/app-heartbeat.d.ts +102 -0
  81. package/dist/lib/asset-inline.d.ts +73 -0
  82. package/dist/lib/browser-pool.d.ts +17 -0
  83. package/dist/lib/build-error.d.ts +52 -0
  84. package/dist/lib/build-fingerprint.d.ts +15 -0
  85. package/dist/lib/build-preflight.d.ts +43 -0
  86. package/dist/lib/build-runner.d.ts +161 -0
  87. package/dist/lib/build-staging.d.ts +64 -0
  88. package/dist/lib/chromium.d.ts +20 -0
  89. package/dist/lib/cli-args.d.ts +45 -0
  90. package/dist/lib/desktop.d.ts +14 -0
  91. package/dist/lib/diagnostics.d.ts +64 -0
  92. package/dist/lib/embedded-assets.d.ts +29 -0
  93. package/dist/lib/exec.d.ts +84 -0
  94. package/dist/lib/fetch-timeout.d.ts +41 -0
  95. package/dist/lib/ghostscript.d.ts +48 -0
  96. package/dist/lib/host-policy.d.ts +75 -0
  97. package/dist/lib/image-inspect.d.ts +32 -0
  98. package/dist/lib/install-hints.d.ts +21 -0
  99. package/dist/lib/lint-runner.d.ts +10 -0
  100. package/dist/lib/manifest-config.d.ts +31 -0
  101. package/dist/lib/manifest-doc.d.ts +25 -0
  102. package/dist/lib/manifest.d.ts +41 -0
  103. package/dist/lib/markdown/assemble.d.ts +78 -0
  104. package/dist/lib/markdown/chapter-id.d.ts +24 -0
  105. package/dist/lib/markdown/images.d.ts +34 -0
  106. package/dist/lib/markdown/index.d.ts +78 -0
  107. package/dist/lib/markdown/markdown-it-paged.d.ts +30 -0
  108. package/dist/lib/markdown/plugins.d.ts +69 -0
  109. package/dist/lib/markdown/renderer.d.ts +111 -0
  110. package/dist/lib/npm-plugin-installer.d.ts +33 -0
  111. package/dist/lib/open-path.d.ts +5 -0
  112. package/dist/lib/output-paths.d.ts +23 -0
  113. package/dist/lib/pagedjs-marker.d.ts +42 -0
  114. package/dist/lib/pagedjs.d.ts +26 -0
  115. package/dist/lib/pagination.d.ts +169 -0
  116. package/dist/lib/pdf-inspect.d.ts +123 -0
  117. package/dist/lib/pdf-parse.d.ts +57 -0
  118. package/dist/lib/plugin-manager.d.ts +108 -0
  119. package/dist/lib/plugin-vendor.d.ts +107 -0
  120. package/dist/lib/presets.d.ts +45 -0
  121. package/dist/lib/printsafe.d.ts +17 -0
  122. package/dist/lib/project-scaffold.d.ts +116 -0
  123. package/dist/lib/project-source.d.ts +140 -0
  124. package/dist/lib/project-templates.d.ts +49 -0
  125. package/dist/lib/publish/butler.d.ts +10 -0
  126. package/dist/lib/publish/command-runner.d.ts +18 -0
  127. package/dist/lib/publish/connect.d.ts +23 -0
  128. package/dist/lib/publish/manifest-publish.d.ts +9 -0
  129. package/dist/lib/publish/providers/azure-swa.d.ts +3 -0
  130. package/dist/lib/publish/providers/drivethrurpg.d.ts +10 -0
  131. package/dist/lib/publish/providers/guided.d.ts +3 -0
  132. package/dist/lib/publish/providers/itch.d.ts +5 -0
  133. package/dist/lib/publish/providers/kdp.d.ts +9 -0
  134. package/dist/lib/publish/providers/shopify.d.ts +5 -0
  135. package/dist/lib/publish/registry.d.ts +5 -0
  136. package/dist/lib/publish/run-publish.d.ts +30 -0
  137. package/dist/lib/publish/selections.d.ts +25 -0
  138. package/dist/lib/publish/types.d.ts +258 -0
  139. package/dist/lib/remote-auth/clone.d.ts +87 -0
  140. package/dist/lib/remote-auth/conflict-resolution.d.ts +29 -0
  141. package/dist/lib/remote-auth/diagnose.d.ts +77 -0
  142. package/dist/lib/remote-auth/generic-auth.d.ts +97 -0
  143. package/dist/lib/remote-auth/git-http.d.ts +85 -0
  144. package/dist/lib/remote-auth/github-auth.d.ts +69 -0
  145. package/dist/lib/remote-auth/github-repos.d.ts +64 -0
  146. package/dist/lib/remote-auth/operation-log.d.ts +66 -0
  147. package/dist/lib/remote-auth/recovery/abort-interrupted-operation.d.ts +103 -0
  148. package/dist/lib/remote-auth/recovery/backup.d.ts +113 -0
  149. package/dist/lib/remote-auth/recovery/classify.d.ts +109 -0
  150. package/dist/lib/remote-auth/recovery/context.d.ts +47 -0
  151. package/dist/lib/remote-auth/recovery/dispatch.d.ts +33 -0
  152. package/dist/lib/remote-auth/recovery/failsafe.d.ts +33 -0
  153. package/dist/lib/remote-auth/recovery/inspect.d.ts +74 -0
  154. package/dist/lib/remote-auth/recovery/manual-guidance.d.ts +28 -0
  155. package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +58 -0
  156. package/dist/lib/remote-auth/recovery/policy.d.ts +47 -0
  157. package/dist/lib/remote-auth/recovery/recover-auth.d.ts +42 -0
  158. package/dist/lib/remote-auth/recovery/recover-binary-conflict.d.ts +37 -0
  159. package/dist/lib/remote-auth/recovery/recover-corrupt-index.d.ts +40 -0
  160. package/dist/lib/remote-auth/recovery/recover-detached-head.d.ts +70 -0
  161. package/dist/lib/remote-auth/recovery/recover-interrupted-cherry-pick.d.ts +23 -0
  162. package/dist/lib/remote-auth/recovery/recover-interrupted-merge.d.ts +28 -0
  163. package/dist/lib/remote-auth/recovery/recover-interrupted-rebase.d.ts +39 -0
  164. package/dist/lib/remote-auth/recovery/recover-merge-conflict.d.ts +34 -0
  165. package/dist/lib/remote-auth/recovery/recover-missing-git-dir.d.ts +37 -0
  166. package/dist/lib/remote-auth/recovery/recover-missing-objects.d.ts +56 -0
  167. package/dist/lib/remote-auth/recovery/recover-network.d.ts +34 -0
  168. package/dist/lib/remote-auth/recovery/recover-non-fast-forward.d.ts +27 -0
  169. package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +76 -0
  170. package/dist/lib/remote-auth/recovery/recover-unrelated-histories.d.ts +44 -0
  171. package/dist/lib/remote-auth/recovery/recover-wrong-remote.d.ts +35 -0
  172. package/dist/lib/remote-auth/recovery/types.d.ts +235 -0
  173. package/dist/lib/remote-auth/resolution-plan.d.ts +64 -0
  174. package/dist/lib/remote-auth/sync-messages.d.ts +26 -0
  175. package/dist/lib/remote-auth/sync-types.d.ts +225 -0
  176. package/dist/lib/remote-auth/sync.d.ts +45 -0
  177. package/dist/lib/remote-auth/test-access.d.ts +47 -0
  178. package/dist/lib/remote-auth/test-support/git-http-server.d.ts +71 -0
  179. package/dist/lib/remote-auth/token-store.d.ts +95 -0
  180. package/dist/lib/remote-auth/transport.d.ts +105 -0
  181. package/dist/lib/slug.d.ts +28 -0
  182. package/dist/lib/snippets.d.ts +39 -0
  183. package/dist/lib/source-provider.d.ts +244 -0
  184. package/dist/lib/static-serve.d.ts +54 -0
  185. package/dist/lib/style-resolver.d.ts +30 -0
  186. package/dist/lib/theme-import.d.ts +70 -0
  187. package/dist/lib/theme-manager.d.ts +128 -0
  188. package/dist/lib/tool-probe.d.ts +37 -0
  189. package/dist/lib/validation-exec.d.ts +47 -0
  190. package/dist/lib/validation-profile.d.ts +18 -0
  191. package/dist/lib/version.d.ts +9 -0
  192. package/dist/lint-f63nxjfj.js +65 -0
  193. package/dist/manifest-n1gh3qw5.yaml +9 -0
  194. package/dist/manifest-ryyg71nf.yaml +9 -0
  195. package/dist/manifest.schema-rn1dpdpn.json +564 -0
  196. package/dist/new-7b08a42h.js +105 -0
  197. package/dist/paged.polyfill-n95pbxfn.js +33288 -0
  198. package/dist/pagedjs-bridge-vn4hk9fx.js +111 -0
  199. package/dist/pagedjs-interface-80g3xa8p.js +498 -0
  200. package/dist/platform.d.ts +100 -0
  201. package/dist/plugin-wf2cbmwc.js +129 -0
  202. package/dist/preflight-tg4mpz1h.js +222 -0
  203. package/dist/preview/file-watcher.d.ts +174 -0
  204. package/dist/preview/http-server.d.ts +45 -0
  205. package/dist/preview/lifecycle.d.ts +67 -0
  206. package/dist/preview/server-context.d.ts +36 -0
  207. package/dist/preview-h2bwbb2x.js +102 -0
  208. package/dist/preview-shell-rghtfmc8.js +155 -0
  209. package/dist/project-source-0tg0r6vm.js +17 -0
  210. package/dist/publish-ztaet53r.js +233 -0
  211. package/dist/render.d.ts +20 -0
  212. package/dist/render.js +682 -0
  213. package/dist/repair-jkp4n3j8.js +171 -0
  214. package/dist/schema/manifest.types.d.ts +218 -0
  215. package/dist/server.d.ts +34 -0
  216. package/dist/source-provider-hp96b5jf.js +46 -0
  217. package/dist/test-helpers/testkit.d.ts +91 -0
  218. package/dist/theme-0yzvthe8.css +65 -0
  219. package/dist/theme-570zmh2t.css +58 -0
  220. package/dist/theme-6a2fngc8.json +6 -0
  221. package/dist/theme-cd6efzjw.json +6 -0
  222. package/dist/theme-nya4nqh6.css +70 -0
  223. package/dist/theme-tqfypc1w.json +6 -0
  224. package/dist/theme-xt0hjb1b.json +6 -0
  225. package/dist/theme-zz2ktzqs.css +60 -0
  226. package/dist/types.d.ts +31 -0
  227. package/dist/utils/file-utils.d.ts +53 -0
  228. package/dist/utils/logger.d.ts +59 -0
  229. package/dist/validate-k2drs19j.js +99 -0
  230. package/package.json +102 -0
@@ -0,0 +1,464 @@
1
+ import {
2
+ capabilitiesFor,
3
+ detectProjectSource,
4
+ findEnclosingRepoDir
5
+ } from "./index-1tyj4bk3.js";
6
+
7
+ // src/lib/source-provider.ts
8
+ import * as fs from "node:fs";
9
+ import path2 from "node:path";
10
+ import git from "isomorphic-git";
11
+
12
+ // src/lib/remote-auth/operation-log.ts
13
+ import { appendFileSync, mkdirSync } from "node:fs";
14
+ import path from "node:path";
15
+ var noop = {
16
+ debug: () => {},
17
+ info: () => {},
18
+ warn: () => {},
19
+ error: () => {}
20
+ };
21
+ var LEVEL_ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
22
+ function createFileLogger(logFile, operation, minLevel = "debug") {
23
+ try {
24
+ mkdirSync(path.dirname(logFile), { recursive: true });
25
+ } catch {
26
+ return noop;
27
+ }
28
+ function write(level, step, message, data) {
29
+ if (LEVEL_ORDER[level] < LEVEL_ORDER[minLevel])
30
+ return;
31
+ const ts = new Date().toISOString();
32
+ const fields = formatData(data);
33
+ const line = `[${ts}] ${level.toUpperCase().padEnd(5)} ${operation}: step=${step}${fields} | ${message}
34
+ `;
35
+ try {
36
+ appendFileSync(logFile, line, "utf8");
37
+ } catch {}
38
+ }
39
+ return {
40
+ debug: (step, message, data) => write("debug", step, message, data),
41
+ info: (step, message, data) => write("info", step, message, data),
42
+ warn: (step, message, data) => write("warn", step, message, data),
43
+ error: (step, message, data) => write("error", step, message, data)
44
+ };
45
+ }
46
+ function resolveLogger(logFile, operation) {
47
+ if (!logFile)
48
+ return noop;
49
+ return createFileLogger(logFile, operation);
50
+ }
51
+ function formatData(data) {
52
+ if (!data)
53
+ return "";
54
+ const parts = [];
55
+ for (const [key, value] of Object.entries(data)) {
56
+ if (value === undefined)
57
+ continue;
58
+ if (Array.isArray(value)) {
59
+ parts.push(`${key}=${value.join(",")}`);
60
+ } else {
61
+ parts.push(`${key}=${String(value)}`);
62
+ }
63
+ }
64
+ return parts.length > 0 ? " " + parts.join(" ") : "";
65
+ }
66
+ function shortOid(oid) {
67
+ return oid.length >= 7 ? oid.slice(0, 7) : oid;
68
+ }
69
+
70
+ // src/lib/source-provider.ts
71
+ var noopLogger = {
72
+ debug: () => {},
73
+ info: () => {},
74
+ warn: () => {},
75
+ error: () => {}
76
+ };
77
+ function gitScopeFor(source) {
78
+ return source.repoRoot || source.path;
79
+ }
80
+ var HISTORY_PAGE_LIMIT = 100;
81
+ var DEFAULT_AUTHOR = "gutterpress";
82
+ var DEFAULT_EMAIL = "noreply@gutterpress.local";
83
+ var DEFAULT_BRANCH = "main";
84
+ var SNAPSHOT_STAGING_MARKER = "gutterpress-snapshot-staging";
85
+ var repoQueues = new Map;
86
+ function repoLockKey(projectDir) {
87
+ const resolved = path2.resolve(projectDir);
88
+ try {
89
+ return fs.realpathSync(resolved);
90
+ } catch {
91
+ return resolved;
92
+ }
93
+ }
94
+ function withRepoLock(projectDir, fn) {
95
+ const key = repoLockKey(projectDir);
96
+ const prev = repoQueues.get(key) ?? Promise.resolve();
97
+ const run = prev.then(fn, fn);
98
+ const tail = run.then(() => {
99
+ return;
100
+ }, () => {
101
+ return;
102
+ });
103
+ repoQueues.set(key, tail);
104
+ tail.then(() => {
105
+ if (repoQueues.get(key) === tail)
106
+ repoQueues.delete(key);
107
+ });
108
+ return run;
109
+ }
110
+ function __repoLockQueueSizeForTests() {
111
+ return repoQueues.size;
112
+ }
113
+ function gitAuthor(name, email) {
114
+ const n = (name ?? "").trim();
115
+ const e = (email ?? "").trim();
116
+ return { name: n || DEFAULT_AUTHOR, email: e || DEFAULT_EMAIL };
117
+ }
118
+ async function readGitAuthor(dir) {
119
+ const [name, email] = await Promise.all([
120
+ git.getConfig({ fs, dir, path: "user.name" }).catch(() => {
121
+ return;
122
+ }),
123
+ git.getConfig({ fs, dir, path: "user.email" }).catch(() => {
124
+ return;
125
+ })
126
+ ]);
127
+ return {
128
+ name: typeof name === "string" ? name : undefined,
129
+ email: typeof email === "string" ? email : undefined
130
+ };
131
+ }
132
+ async function resolveGitAuthor(dir, name, email) {
133
+ const existing = await readGitAuthor(dir);
134
+ return gitAuthor(name || existing.name, email || existing.email);
135
+ }
136
+ async function listWorkdirChanges(dir, cache = {}) {
137
+ const adds = [];
138
+ const removes = [];
139
+ await git.walk({
140
+ fs,
141
+ dir,
142
+ cache,
143
+ trees: [git.WORKDIR(), git.STAGE()],
144
+ map: async (filepath, [workdir, stage]) => {
145
+ if (filepath === ".")
146
+ return;
147
+ if (!stage && workdir && await git.isIgnored({ fs, dir, filepath })) {
148
+ return null;
149
+ }
150
+ const [wType, sType] = await Promise.all([
151
+ workdir ? workdir.type() : Promise.resolve(undefined),
152
+ stage ? stage.type() : Promise.resolve(undefined)
153
+ ]);
154
+ if (wType === "tree" || sType === "tree") {
155
+ if (sType === "blob")
156
+ removes.push(filepath);
157
+ else if (wType === "blob")
158
+ adds.push(filepath);
159
+ return;
160
+ }
161
+ if (wType === "blob" && !sType) {
162
+ adds.push(filepath);
163
+ } else if (!wType && sType === "blob") {
164
+ removes.push(filepath);
165
+ } else if (wType === "blob" && sType === "blob") {
166
+ const workdirOid = await workdir.oid();
167
+ const stageOid = await stage.oid();
168
+ if (workdirOid !== stageOid) {
169
+ adds.push(filepath);
170
+ } else {
171
+ const fileBytes = await fs.promises.readFile(path2.join(dir, filepath));
172
+ const { oid: actualOid } = await git.hashBlob({ object: fileBytes });
173
+ if (actualOid !== stageOid)
174
+ adds.push(filepath);
175
+ }
176
+ }
177
+ return;
178
+ }
179
+ });
180
+ return { adds, removes };
181
+ }
182
+ async function stageChanges(dir, changes, cache) {
183
+ if (changes.adds.length > 0) {
184
+ await git.add({ fs, dir, cache, filepath: changes.adds });
185
+ }
186
+ for (const filepath of changes.removes) {
187
+ await git.remove({ fs, dir, cache, filepath });
188
+ }
189
+ }
190
+ async function hasPendingChanges(dir, cache = {}) {
191
+ const { adds, removes } = await listWorkdirChanges(dir, cache);
192
+ return adds.length > 0 || removes.length > 0;
193
+ }
194
+ async function hasUncommittedChanges(dir, cache = {}) {
195
+ if (await hasPendingChanges(dir, cache))
196
+ return true;
197
+ return !await stageMatchesHead(dir, cache);
198
+ }
199
+ async function stageMatchesHead(dir, cache) {
200
+ let headOid;
201
+ try {
202
+ headOid = await git.resolveRef({ fs, dir, ref: "HEAD" });
203
+ } catch {
204
+ return false;
205
+ }
206
+ let differs = false;
207
+ await git.walk({
208
+ fs,
209
+ dir,
210
+ cache,
211
+ trees: [git.TREE({ ref: headOid }), git.STAGE()],
212
+ map: async (filepath, [tree, stage]) => {
213
+ if (differs || filepath === ".")
214
+ return differs ? null : undefined;
215
+ const [tType, sType] = await Promise.all([
216
+ tree ? tree.type() : Promise.resolve(undefined),
217
+ stage ? stage.type() : Promise.resolve(undefined)
218
+ ]);
219
+ if (tType === "tree" || sType === "tree")
220
+ return;
221
+ if (!tType !== !sType) {
222
+ differs = true;
223
+ return null;
224
+ }
225
+ if (!tType || !sType)
226
+ return;
227
+ const [tOid, sOid] = await Promise.all([tree.oid(), stage.oid()]);
228
+ if (tOid !== sOid)
229
+ differs = true;
230
+ return null;
231
+ }
232
+ });
233
+ return !differs;
234
+ }
235
+
236
+ class LocalFolderSourceProvider {
237
+ source;
238
+ capabilities;
239
+ constructor(source) {
240
+ this.source = source;
241
+ this.capabilities = capabilitiesFor(source);
242
+ }
243
+ async initVersionHistory(options) {
244
+ const dir = options.projectDir;
245
+ if (await findEnclosingRepoDir(dir) !== undefined) {
246
+ throw new Error("This folder is already inside a versioned project, so gutterpress " + "won't create a separate history here.");
247
+ }
248
+ return withRepoLock(dir, async () => {
249
+ const cache = {};
250
+ await git.init({ fs, dir, defaultBranch: DEFAULT_BRANCH });
251
+ await stageChanges(dir, await listWorkdirChanges(dir, cache), cache);
252
+ await git.commit({
253
+ fs,
254
+ dir,
255
+ cache,
256
+ message: options.initialMessage?.trim() || "Created project",
257
+ author: await resolveGitAuthor(dir, options.authorName, options.authorEmail)
258
+ });
259
+ return {
260
+ type: "local-git-folder",
261
+ path: dir,
262
+ repoRoot: dir,
263
+ subPath: "",
264
+ hasRemote: false,
265
+ branch: DEFAULT_BRANCH
266
+ };
267
+ });
268
+ }
269
+ snapshot() {
270
+ return Promise.reject(new Error("This project has no version history yet. Enable version history first."));
271
+ }
272
+ listHistory() {
273
+ return Promise.resolve([]);
274
+ }
275
+ listHistoryPage() {
276
+ return Promise.resolve({ entries: [], hasMore: false });
277
+ }
278
+ restore() {
279
+ return Promise.reject(new Error("This project has no version history yet. Enable version history first."));
280
+ }
281
+ }
282
+
283
+ class LocalGitSourceProvider {
284
+ source;
285
+ capabilities;
286
+ dir;
287
+ constructor(source) {
288
+ this.source = source;
289
+ this.capabilities = capabilitiesFor(source);
290
+ this.dir = gitScopeFor(source);
291
+ }
292
+ async initVersionHistory(options) {
293
+ try {
294
+ await this.snapshot({
295
+ projectDir: options.projectDir,
296
+ message: options.initialMessage?.trim() || "Created project",
297
+ authorName: options.authorName,
298
+ authorEmail: options.authorEmail
299
+ });
300
+ } catch (e) {
301
+ if (!isNoChangesError(e))
302
+ throw e;
303
+ }
304
+ return this.source;
305
+ }
306
+ snapshot(options) {
307
+ return withRepoLock(this.dir, () => this.snapshotUnlocked(options));
308
+ }
309
+ snapshotUnlocked(options) {
310
+ return snapshotWorkingTreeUnlocked({ ...options, repoRoot: this.dir });
311
+ }
312
+ async listHistory(projectDir) {
313
+ return (await this.listHistoryPage(projectDir)).entries;
314
+ }
315
+ async listHistoryPage(_projectDir, options = {}) {
316
+ const dir = this.dir;
317
+ const limit = Math.min(500, Math.max(1, options.limit ?? HISTORY_PAGE_LIMIT));
318
+ const before = options.before;
319
+ let commits;
320
+ try {
321
+ commits = await git.log({
322
+ fs,
323
+ dir,
324
+ cache: {},
325
+ depth: limit + 2,
326
+ ...before ? { ref: before } : {}
327
+ });
328
+ } catch (e) {
329
+ if (before && e?.code === "NotFoundError") {
330
+ return { entries: [], hasMore: false };
331
+ }
332
+ throw e;
333
+ }
334
+ const seen = new Set;
335
+ let filtered = commits.filter((c) => {
336
+ if (c.oid === before || seen.has(c.oid))
337
+ return false;
338
+ seen.add(c.oid);
339
+ return true;
340
+ });
341
+ const hasMore = filtered.length > limit;
342
+ if (hasMore)
343
+ filtered = filtered.slice(0, limit);
344
+ return {
345
+ entries: filtered.map((c) => ({
346
+ id: c.oid,
347
+ message: c.commit.message.trim(),
348
+ timestamp: c.commit.author.timestamp * 1000,
349
+ author: c.commit.author.name
350
+ })),
351
+ hasMore
352
+ };
353
+ }
354
+ restore(options) {
355
+ return withRepoLock(this.dir, () => this.restoreUnlocked(options));
356
+ }
357
+ async restoreUnlocked(options) {
358
+ await git.checkout({
359
+ fs,
360
+ dir: this.dir,
361
+ cache: {},
362
+ ref: options.id,
363
+ force: true,
364
+ noUpdateHead: true
365
+ });
366
+ }
367
+ }
368
+ async function snapshotWorkingTreeUnlocked(options) {
369
+ const dir = options.repoRoot ?? options.projectDir;
370
+ const logger = options.logFile ? createFileLogger(options.logFile, "snapshot") : noopLogger;
371
+ const cache = {};
372
+ const stagingMarker = snapshotStagingMarkerPath(dir);
373
+ const staleStaging = fs.existsSync(stagingMarker);
374
+ const changes = await listWorkdirChanges(dir, cache);
375
+ const workdirClean = changes.adds.length === 0 && changes.removes.length === 0;
376
+ if (workdirClean && !staleStaging) {
377
+ logger.debug("snapshot", "no changes — skipping");
378
+ throw new Error("No changes since the last snapshot — there is nothing new to save.");
379
+ }
380
+ if (workdirClean && staleStaging && await stageMatchesHead(dir, cache)) {
381
+ logger.debug("snapshot", "stale marker outlived a completed commit — clearing, not recommitting");
382
+ fs.rmSync(stagingMarker, { force: true });
383
+ const [head2] = await git.log({ fs, dir, cache, depth: 1 });
384
+ return {
385
+ id: head2.oid,
386
+ message: head2.commit.message.trim(),
387
+ timestamp: head2.commit.author.timestamp * 1000,
388
+ author: head2.commit.author.name
389
+ };
390
+ }
391
+ logger.info("snapshot", "committing", {
392
+ adds: changes.adds.length,
393
+ removes: changes.removes.length,
394
+ ...staleStaging ? { recoveredStaleStaging: true } : {}
395
+ });
396
+ fs.writeFileSync(stagingMarker, "");
397
+ await stageChanges(dir, changes, cache);
398
+ const author = await resolveGitAuthor(dir, options.authorName, options.authorEmail);
399
+ const id = await git.commit({
400
+ fs,
401
+ dir,
402
+ cache,
403
+ message: options.message,
404
+ author
405
+ });
406
+ fs.rmSync(stagingMarker, { force: true });
407
+ const [head] = await git.log({ fs, dir, cache, depth: 1 });
408
+ return {
409
+ id,
410
+ message: options.message,
411
+ timestamp: head ? head.commit.author.timestamp * 1000 : Date.now(),
412
+ author: author.name
413
+ };
414
+ }
415
+ function isNoChangesError(e) {
416
+ return e instanceof Error && /no changes since the last snapshot/i.test(e.message);
417
+ }
418
+ function providerFor(source) {
419
+ switch (source.type) {
420
+ case "local-folder":
421
+ return new LocalFolderSourceProvider(source);
422
+ case "local-git-folder":
423
+ return new LocalGitSourceProvider(source);
424
+ case "managed-github":
425
+ throw new Error("Managed GitHub projects are not supported yet (#15/#16).");
426
+ }
427
+ }
428
+ function gitDirFor(projectDir) {
429
+ return path2.join(projectDir, ".git");
430
+ }
431
+ function snapshotStagingMarkerPath(projectDir) {
432
+ return path2.join(gitDirFor(projectDir), SNAPSHOT_STAGING_MARKER);
433
+ }
434
+ var RESTORE_BACKUP_MESSAGE = "Automatic backup before restoring an earlier version";
435
+ var AUTO_SNAPSHOT_MESSAGE = "Automatic snapshot";
436
+ async function restoreVersionWithBackup(options) {
437
+ const { projectDir, id, authorName, authorEmail } = options;
438
+ const source = await detectProjectSource(projectDir);
439
+ if (source.type !== "local-git-folder") {
440
+ throw new Error("This project has no version history yet. Enable version history first.");
441
+ }
442
+ const provider = new LocalGitSourceProvider(source);
443
+ const repoDir = gitScopeFor(source);
444
+ return withRepoLock(repoDir, async () => {
445
+ let backupId;
446
+ if (await hasPendingChanges(repoDir)) {
447
+ const backup = await provider.snapshotUnlocked({
448
+ projectDir,
449
+ message: RESTORE_BACKUP_MESSAGE,
450
+ authorName,
451
+ authorEmail
452
+ });
453
+ backupId = backup.id;
454
+ }
455
+ try {
456
+ await provider.restoreUnlocked({ projectDir, id });
457
+ } catch (cause) {
458
+ throw new Error(backupId ? "The restore could not be completed, but your work is safe — it was " + `automatically saved as a backup snapshot (${backupId.slice(0, 7)}) ` + "and appears in your version history." : "The restore could not be completed. Your project files were not changed.", { cause });
459
+ }
460
+ return { restoredId: id, backupId };
461
+ });
462
+ }
463
+
464
+ export { resolveLogger, shortOid, gitScopeFor, HISTORY_PAGE_LIMIT, SNAPSHOT_STAGING_MARKER, withRepoLock, __repoLockQueueSizeForTests, gitAuthor, readGitAuthor, resolveGitAuthor, listWorkdirChanges, stageChanges, hasPendingChanges, hasUncommittedChanges, snapshotWorkingTreeUnlocked, isNoChangesError, providerFor, gitDirFor, snapshotStagingMarkerPath, RESTORE_BACKUP_MESSAGE, AUTO_SNAPSHOT_MESSAGE, restoreVersionWithBackup };
@@ -0,0 +1,92 @@
1
+ // src/lib/remote-auth/git-http.ts
2
+ import httpNode from "isomorphic-git/http/node";
3
+ var GIT_HTTP_IDLE_TIMEOUT_MS = 60000;
4
+ var GIT_HTTP_UPLOAD_TIMEOUT_MS = 30 * 60000;
5
+ var SMALL_BODY_MAX_BYTES = 256 * 1024;
6
+ function isSmallBody(body) {
7
+ if (!Array.isArray(body))
8
+ return false;
9
+ let total = 0;
10
+ for (const c of body) {
11
+ const size = c?.byteLength;
12
+ if (typeof size !== "number")
13
+ return false;
14
+ total += size;
15
+ }
16
+ return total <= SMALL_BODY_MAX_BYTES;
17
+ }
18
+ function gitTimeoutError(what, ms) {
19
+ return new Error(`Git network operation timed out after ${Math.round(ms / 1000)}s (${what}); ` + `couldn't reach the remote (ETIMEDOUT).`);
20
+ }
21
+ function withIdleTimeout(http, idleMs = GIT_HTTP_IDLE_TIMEOUT_MS, uploadMs = GIT_HTTP_UPLOAD_TIMEOUT_MS) {
22
+ return {
23
+ async request(options) {
24
+ let timer;
25
+ let trip;
26
+ const tripped = new Promise((_, reject) => {
27
+ trip = reject;
28
+ });
29
+ tripped.catch(() => {});
30
+ const arm = (ms, what) => {
31
+ if (timer)
32
+ clearTimeout(timer);
33
+ timer = setTimeout(() => trip(gitTimeoutError(what, ms)), ms);
34
+ timer.unref?.();
35
+ };
36
+ const disarm = () => {
37
+ if (timer)
38
+ clearTimeout(timer);
39
+ timer = undefined;
40
+ };
41
+ const race = (p) => Promise.race([p, tripped]).catch((e) => {
42
+ p.catch(() => {});
43
+ throw e;
44
+ });
45
+ const body = options.body;
46
+ const isLargeUpload = body != null && !isSmallBody(body);
47
+ arm(isLargeUpload ? uploadMs : idleMs, isLargeUpload ? "the upload did not complete" : "the remote did not respond");
48
+ let res;
49
+ try {
50
+ res = await race(http.request(options));
51
+ } finally {
52
+ disarm();
53
+ }
54
+ const rawBody = res.body;
55
+ if (!rawBody || typeof rawBody[Symbol.asyncIterator] !== "function") {
56
+ return res;
57
+ }
58
+ const source = rawBody[Symbol.asyncIterator]();
59
+ const guardedBody = {
60
+ async next() {
61
+ arm(idleMs, "the remote stopped sending data");
62
+ try {
63
+ const step = await race(source.next());
64
+ disarm();
65
+ return step;
66
+ } catch (e) {
67
+ disarm();
68
+ try {
69
+ Promise.resolve(source.return?.()).catch(() => {});
70
+ } catch {}
71
+ throw e;
72
+ }
73
+ },
74
+ return(value) {
75
+ disarm();
76
+ try {
77
+ return Promise.resolve(source.return?.(value) ?? { done: true, value: undefined });
78
+ } catch {
79
+ return Promise.resolve({ done: true, value: undefined });
80
+ }
81
+ },
82
+ [Symbol.asyncIterator]() {
83
+ return this;
84
+ }
85
+ };
86
+ return { ...res, body: guardedBody };
87
+ }
88
+ };
89
+ }
90
+ var defaultGitHttp = withIdleTimeout(httpNode);
91
+
92
+ export { GIT_HTTP_IDLE_TIMEOUT_MS, GIT_HTTP_UPLOAD_TIMEOUT_MS, SMALL_BODY_MAX_BYTES, isSmallBody, withIdleTimeout, defaultGitHttp };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * gutterpress — runtime library for Gutterpress.
3
+ *
4
+ * Consumed by:
5
+ * - packages/cli (commands import from here; bundled into the CLI binary + npm package)
6
+ * - packages/desktop (SvelteKit API routes import from here at runtime)
7
+ *
8
+ * Plugin authors use the type-only exports below to type their plugins without
9
+ * taking a runtime dependency on this package.
10
+ */
11
+ export * from "./api/index.ts";
12
+ export { log } from "./utils/logger.ts";
13
+ export { runLint } from "./lib/lint-runner.ts";
14
+ export { openPath } from "./lib/open-path.ts";
15
+ export { executeAndReport, executeValidation } from "./lib/validation-exec.ts";
16
+ export type { ValidationExecutionResult } from "./lib/validation-exec.ts";
17
+ export { formatReport } from "./checks/formatter.ts";
18
+ export type { OutputFormat } from "./checks/formatter.ts";
19
+ export { runChecks } from "./checks/runner.ts";
20
+ export { checkToolAvailability, reportMissingTools } from "./checks/tool-check.ts";
21
+ export type { CheckContext, CheckResult } from "./checks/types.ts";
22
+ export { resolveCheckSelectors, getChecks, getCheckById } from "./checks/registry.ts";
23
+ export type { ResolvedSelectors } from "./checks/registry.ts";
24
+ export type { CheckCategory, CheckPhase } from "./checks/types.ts";
25
+ export { loadManifest } from "./lib/manifest.ts";
26
+ export type { PlatformAdapter, FileStat, FileWriteResult } from "./platform.ts";
27
+ export { inspectImage } from "./lib/image-inspect.ts";
28
+ export type { ImageInfo, ColorSpace } from "./lib/image-inspect.ts";
29
+ export { checkCss } from "./lib/printsafe.ts";
30
+ export type { PrintSafeWarning } from "./lib/printsafe.ts";
31
+ export { ruleRemoteUrls, ruleRiskyProps, rulePagedjsCrashSelectors, ruleSyntax, } from "./lib/printsafe.ts";
32
+ export type { GutterpressPlugin, GutterpressPluginExport, GutterpressPluginMetadata, } from "./lib/markdown/plugins.ts";