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,74 @@
1
+ /**
2
+ * Preflight repo health probe for the sync-recovery subsystem.
3
+ *
4
+ * inspectRepo() reads local filesystem state ONLY — no network, no git objects,
5
+ * never throws. It returns a RepoHealth snapshot that the classifier and policy
6
+ * lookup use to decide which recovery path to take.
7
+ *
8
+ * Reuses:
9
+ * - gitDirFor (source-provider.ts) for the .git dir path
10
+ * - hasPendingChanges (source-provider.ts) for local-changes detection
11
+ *
12
+ * Notes on two health facts:
13
+ * - hasGitDir is true whenever `.git/` EXISTS, even with a missing/corrupt
14
+ * HEAD (a damaged repo is still a repo — see the inline note at the check).
15
+ * - hasStaleLock uses the stale-lock handler's OWN lock scanner
16
+ * (findLockCandidates in recover-stale-lock.ts) — one implementation, so
17
+ * health and handler can never disagree about which locks exist.
18
+ *
19
+ * All probes are best-effort and throw-free (the caller must never see an
20
+ * exception from a preflight probe).
21
+ */
22
+ import type { LogData } from "../operation-log.ts";
23
+ import type { RepoHealth, RecoveryContext, SyncErrorKind } from "./types.ts";
24
+ /**
25
+ * Probe the local repository and return a RepoHealth snapshot.
26
+ * Never throws — on any error the relevant flag is set conservatively.
27
+ *
28
+ * `checkLocalChanges: false` skips the hasPendingChanges working-tree walk
29
+ * (the one non-trivial probe) and reports hasLocalChanges=false. Use it when
30
+ * only the structural flags matter — e.g. syncProject's preflight, whose
31
+ * pull step immediately performs the same walk anyway (sync-simplicity
32
+ * mandate: no redundant walks on the hot path).
33
+ */
34
+ export declare function inspectRepo(ctx: Pick<RecoveryContext, "repoDir" | "source">, opts?: {
35
+ checkLocalChanges?: boolean;
36
+ }): Promise<RepoHealth>;
37
+ /**
38
+ * Confirm the repo's object store is actually readable: resolve HEAD, read
39
+ * its commit, and read its root tree. Throws when any step fails (missing or
40
+ * corrupt object/ref); resolves when the repo is fully readable.
41
+ *
42
+ * This is the SAME verification recover-missing-objects.ts performs to check
43
+ * whether a fetch actually repaired the object store — it is exported here so
44
+ * that check and the repair command's diagnosis step share ONE implementation
45
+ * rather than two copies that could drift. `inspectRepo`'s health flags are
46
+ * all filesystem-presence checks (no object is ever read), so they cannot
47
+ * detect object-store corruption on their own — callers that need to catch
48
+ * `corrupt_index` / `missing_or_corrupt_objects` / `unrelated_histories` /
49
+ * `wrong_remote_or_branch` must run this probe and feed a caught error
50
+ * through `classifyGitError`.
51
+ */
52
+ export declare function verifyRepoReadable(dir: string): Promise<void>;
53
+ /**
54
+ * True when HEAD names a branch that simply has no commits yet — a fresh
55
+ * `git init` before the first snapshot. In that state `verifyRepoReadable`
56
+ * throws the SAME NotFoundError as a damaged ref store, but the repo is
57
+ * healthy, not corrupt. The distinguishing signal is the object store: a
58
+ * fresh repo has NO objects at all, while ref damage on a real repo leaves
59
+ * loose objects and/or packfiles behind.
60
+ */
61
+ export declare function isUnbornRepo(repoDir: string): boolean;
62
+ /**
63
+ * The SINGLE health signal that drove classification. Derived from the KIND
64
+ * classifyFromHealth returned (a pure mapping — it cannot drift from the
65
+ * classifier's decision order, because it never re-implements it).
66
+ */
67
+ export declare function preflightStructuralReason(kind: SyncErrorKind | null): string;
68
+ /**
69
+ * Build a flat, secret-free record of the preflight decision inputs for the
70
+ * operation log. Every health boolean is recorded (so support can see the FULL
71
+ * picture, not just the one-word kind), plus the opened dir vs repo root, the
72
+ * chosen kind, and the single reason that drove it.
73
+ */
74
+ export declare function buildPreflightDiagnostics(openedDir: string, repoDir: string, health: RepoHealth, kind: SyncErrorKind | null): LogData;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Plain-language guidance builders for the sync-recovery subsystem.
3
+ *
4
+ * AUTHOR-FACING COPY RULES (non-negotiable):
5
+ * - No git words ("branch", "commit", "rebase", "ref", "HEAD", etc.)
6
+ * - No tokens or credentials
7
+ * - No internal file paths (no .git/, no /tmp paths in userSummary)
8
+ * - No technical error codes in user-facing fields
9
+ * - supportDetails MAY contain technical info for support tickets
10
+ *
11
+ * Each SyncErrorKind gets its own copy block. The host maps the
12
+ * ManualGuidance to its display surface.
13
+ */
14
+ import type { ManualGuidance, RecoveryContext, SyncErrorKind } from "./types.ts";
15
+ /**
16
+ * Build a ManualGuidance for a given error kind. The guidance is shown when
17
+ * a repair is blocked, failed, or needs user action. Never throws.
18
+ *
19
+ * SAFETY-COPY HONESTY: the "a safety copy was saved" reassurance is generated
20
+ * in ONE place, from the actual `backupZipPath` — never hardcoded per kind.
21
+ * The backup gate creates (and verifies) the zip BEFORE confirmation, so
22
+ * whenever this guidance is shown for a backup-requiring kind, a present
23
+ * backupZipPath means the copy really exists, and an absent one means backup
24
+ * creation FAILED and nothing was changed (failsafe.ts returns
25
+ * failed_no_changes_made without any writes). Promising a safety copy in that
26
+ * second case would be false — the one moment the promise matters most.
27
+ */
28
+ export declare function makeManualGuidance(ctx: Pick<RecoveryContext, "repoSlug" | "remoteUrl">, kind: SyncErrorKind, error?: unknown, backupZipPath?: string): ManualGuidance;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * outcome-mapping.ts — shared SyncOutcome/PullOutcome → RecoveryResult mapping.
3
+ *
4
+ * WHY this exists: five thin recovery handlers (recover-non-fast-forward,
5
+ * recover-auth, recover-network, recover-merge-conflict, recover-binary-conflict)
6
+ * all build the SAME syncProject/pullChanges options object from the context and
7
+ * then translate the typed outcome union into a RecoveryResult. The option
8
+ * object was copied verbatim five times, and the outcome→result maps had drifted
9
+ * apart (e.g. an `offline` outcome mapped to `retry_later` in one handler and to
10
+ * `needs_user` in another). This module owns the ONE default map; each handler
11
+ * passes only the per-status `overrides` where its behavior INTENTIONALLY
12
+ * differs, so the disagreements are explicit rather than accidental copies.
13
+ *
14
+ * DEFAULT OUTCOME MAP (what a handler gets with no overrides):
15
+ * synced → recovered { message: outcome.message }
16
+ * pulled → recovered { message: outcome.message }
17
+ * up-to-date → recovered { message: outcome.message }
18
+ * conflict → needs_user { message, guidance: merge_conflict, files }
19
+ * auth → needs_user { message, guidance: auth_required }
20
+ * offline → retry_later { message, retryAfterMs: RETRY_AFTER_MS }
21
+ * error / → failed_no_changes_made { message, guidance: unknown }
22
+ * (unknown)
23
+ *
24
+ * An override wins over the default for its status. An UNKNOWN/future status
25
+ * routes to the `error` builder (override first, then default) — mirroring the
26
+ * `default:` arm every handler used to carry.
27
+ */
28
+ import type { PullOutcome, SyncOutcome } from "../sync.ts";
29
+ import type { RecoveryContext, RecoveryResult } from "./types.ts";
30
+ /** Fixed delay before the next automated retry (30 seconds). */
31
+ export declare const RETRY_AFTER_MS = 30000;
32
+ /** The typed outcome unions the recovery handlers translate. */
33
+ export type AnyOutcome = SyncOutcome | PullOutcome;
34
+ /** Every status either outcome union can carry. */
35
+ export type OutcomeStatus = AnyOutcome["status"];
36
+ /** Builds a RecoveryResult from the context and the (already-classified) outcome. */
37
+ export type OutcomeBuilder = (ctx: RecoveryContext, outcome: AnyOutcome) => RecoveryResult;
38
+ /** Per-status overrides a handler supplies where it intentionally differs. */
39
+ export type OutcomeOverrides = Partial<Record<OutcomeStatus, OutcomeBuilder>>;
40
+ /**
41
+ * The shared options object every handler feeds to syncProject / pullChanges.
42
+ * Extracted so the five copies can never drift.
43
+ */
44
+ export declare function syncOptionsFrom(ctx: RecoveryContext): {
45
+ projectDir: string;
46
+ credential: import("../token-store.ts").HostCredential | undefined;
47
+ tokenStore: import("../token-store.ts").TokenStore | undefined;
48
+ authorName: string | undefined;
49
+ authorEmail: string | undefined;
50
+ httpClient: typeof import("isomorphic-git/http/node").default | undefined;
51
+ };
52
+ /**
53
+ * Translate a SyncOutcome/PullOutcome into a RecoveryResult using the default
54
+ * map, letting per-status `overrides` win. Any status not present in the map
55
+ * (a future/unknown status) falls through to the `error` builder — override
56
+ * first, then default — matching each handler's original `default:` arm.
57
+ */
58
+ export declare function mapOutcomeToResult(ctx: RecoveryContext, outcome: AnyOutcome, overrides?: OutcomeOverrides): RecoveryResult;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Recovery policy matrix — pure data, no I/O.
3
+ *
4
+ * Each SyncErrorKind maps to a policy that controls:
5
+ * - risk: how much irreversible change the repair makes
6
+ * - createBackup: whether the repair MUST create a /tmp zip before running
7
+ * - requireConfirmation: whether the user must approve the repair
8
+ * - mayChangeLocalFiles: whether the repair can modify user-visible files
9
+ * - mayChangeGitMetadata: whether the repair can modify .git/ metadata
10
+ * - mayChangeRemote: whether the repair can push to the remote
11
+ * - automate: whether the repair can run without user interaction at all
12
+ *
13
+ * Safety invariants (from the spec):
14
+ * - detached_head, corrupt_index, missing_git_dir, missing_or_corrupt_objects,
15
+ * unrelated_histories → always backup + confirm
16
+ * - auth_required, network_unavailable, non_fast_forward → no backup needed,
17
+ * no confirmation required (they are thin delegates to sync.ts)
18
+ * - wrong_remote_or_branch → no repair attempted (pure block with guidance),
19
+ * so no backup is needed either
20
+ */
21
+ import type { RecoveryRisk, SyncErrorKind } from "./types.ts";
22
+ export interface RecoveryPolicy {
23
+ risk: RecoveryRisk;
24
+ createBackup: boolean;
25
+ requireConfirmation: boolean;
26
+ mayChangeLocalFiles: boolean;
27
+ mayChangeGitMetadata: boolean;
28
+ mayChangeRemote: boolean;
29
+ /** True when the repair can run transparently without prompting the user. */
30
+ automate: boolean;
31
+ /**
32
+ * True when the dispatcher must run the handler inside withRepoLock (the
33
+ * per-repo FIFO queue): every handler that mutates `.git` via RAW git.* /
34
+ * node:fs calls. MUST be false for the thin sync.ts delegates — they call
35
+ * lock-wrapped functions (syncProject/pullChanges) internally, and the FIFO
36
+ * queue is non-reentrant (locking them at the dispatcher would deadlock).
37
+ */
38
+ serializeRepo: boolean;
39
+ }
40
+ export declare const recoveryPolicy: Record<SyncErrorKind, RecoveryPolicy>;
41
+ /** Look up the policy for a kind (always succeeds — every kind has an entry). */
42
+ export declare function policyFor(kind: SyncErrorKind): RecoveryPolicy;
43
+ /**
44
+ * Refinement: detached HEAD with local changes is riskier — escalate to high
45
+ * risk and always require confirmation regardless of the base policy.
46
+ */
47
+ export declare function detachedHeadWithLocalChangesPolicy(hasLocalChanges: boolean): RecoveryPolicy;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * recover-auth.ts — Auth failure: clear the bad credential, ask the author
3
+ * to reconnect.
4
+ *
5
+ * WHY this module exists: when the remote rejects the saved connection
6
+ * (401 / 403), the right behavior is:
7
+ *
8
+ * 1. Attempt sync so the snapshot-first invariant (ADR 0006 D5) still runs
9
+ * if possible — any unsaved local work gets committed before the network
10
+ * call, so nothing is lost regardless of what the server says.
11
+ * 2. If the result is `auth`, delete the stale credential from the token
12
+ * store so the next reconnect flow starts clean.
13
+ * 3. Return `needs_user` with plain-language reconnect guidance.
14
+ * recommendedAction is always "Reconnect" — no git words, no tokens.
15
+ * 4. Never create a backup zip (policy.createBackup = false for auth_required
16
+ * — there is nothing locally at risk; the author's work is already
17
+ * committed by the snapshot-first step in sync.ts).
18
+ * 5. Never ask for confirmation (no repair changes anything).
19
+ * 6. Never force-push (syncProject / pushChanges never does this either).
20
+ *
21
+ * This is a THIN WRAPPER around syncProject from sync.ts. The snapshot step,
22
+ * the network call, and the "auth" classification all live there. The only
23
+ * delta this module adds is:
24
+ * - Calling ctx.tokenStore.delete(host) when the outcome is `auth`.
25
+ * - Translating SyncOutcome { status: "auth" } → RecoveryResult { status:
26
+ * "needs_user" } with the auth_required ManualGuidance.
27
+ */
28
+ import type { RecoveryContext, RecoveryResult } from "./types.ts";
29
+ /**
30
+ * Handle an `auth_required` classification.
31
+ *
32
+ * - Delegates the sync attempt (including the snapshot-first step) to
33
+ * `syncProject` from sync.ts.
34
+ * - On `auth` outcome: clears the bad credential from ctx.tokenStore (best-
35
+ * effort — missing store is silently ignored) and returns `needs_user` with
36
+ * author-friendly reconnect guidance.
37
+ * - On any successful outcome (the good-credential path): returns `recovered`
38
+ * so the host can refresh. The credential is NOT cleared on success.
39
+ * - On other failure outcomes (offline, conflict, error): passes through an
40
+ * appropriate RecoveryResult without touching the credential store.
41
+ */
42
+ export declare function recover(ctx: RecoveryContext, _error?: unknown): Promise<RecoveryResult>;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * recover-binary-conflict.ts — never auto-merge binary files.
3
+ *
4
+ * WHY this exists: binary files (images, PDFs, audio, etc.) cannot be
5
+ * line-merged. When both the local copy and the online copy changed the same
6
+ * binary file, the only honest answer is: show the user the list of clashing
7
+ * files and let them choose which version to keep. The "Keep both" option
8
+ * works for binary files too — it keeps the author's version alongside an
9
+ * "(online copy)" rename.
10
+ *
11
+ * This handler is intentionally identical in shape to recover-merge-conflict.ts.
12
+ * The distinction between text and binary conflicts is made at a higher level
13
+ * (classify.ts / the merge engine) — by the time recover() is called we already
14
+ * know the conflict involves binary content, so we surface it the same way:
15
+ * a 'needs_user' result with the conflicted file list.
16
+ *
17
+ * Reuses:
18
+ * pullChanges — snapshot → fetch → merge (abortOnConflict). On a binary
19
+ * file isomorphic-git still throws MergeConflictError with the
20
+ * conflicting filepath in data.filepaths.
21
+ * makeManualGuidance — jargon-free copy for binary_conflict.
22
+ *
23
+ * Policy (policy.ts): createBackup=false, requireConfirmation=false.
24
+ * The working tree is left completely untouched by pullChanges
25
+ * (abortOnConflict), so no backup is needed to surface the conflict to the
26
+ * user. The confirmation gate is the per-file UI chooser, not withBackupGate.
27
+ *
28
+ * Safety invariants (see test file):
29
+ * - NO force-push: pullChanges never pushes; this handler never calls push.
30
+ * - Remote HEAD is NEVER advanced: we stop at conflict, surface needs_user.
31
+ * - Both blob versions are preserved in local history (pullChanges snapshots
32
+ * the working tree before merge, then aborts — no side is silently dropped).
33
+ * - write_conflict_snapshot fault hook is called and, if it throws, the error
34
+ * is caught and a safe fallback is returned (no unhandled throw to caller).
35
+ */
36
+ import type { RecoverFn } from "./types.ts";
37
+ export declare const recover: RecoverFn;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * recover-corrupt-index.ts — repair a corrupt or unreadable .git/index.
3
+ *
4
+ * WHY this is needed:
5
+ * The git index (staging area) can become corrupt if gutterpress or the OS
6
+ * crashes mid-operation. When the index is unreadable, virtually every
7
+ * git operation fails — status checks, sync, everything. The fix is simple:
8
+ * delete the bad index and let git rebuild it from the last saved snapshot.
9
+ * User-visible content files are NEVER touched — uncommitted edits survive.
10
+ *
11
+ * Safety invariants:
12
+ * - Backup created and verified BEFORE anything is deleted.
13
+ * - User must confirm before the repair runs.
14
+ * - If backup creation fails → failed_no_changes_made, no further writes.
15
+ * - If removal or rebuild throws after backup → failed_backup_available.
16
+ * - User DENY → blocked (index left exactly as-is).
17
+ * - Never force-pushes; the repair is entirely local (no remote contact).
18
+ * - Uncommitted edits in the working tree are NEVER overwritten or discarded.
19
+ *
20
+ * Repair steps (all inside withBackupGate's risky callback):
21
+ * 1. ctx.faults?.before("remove_index") — fault injection point
22
+ * 2. Delete .git/index
23
+ * 3. ctx.faults?.before("rebuild_index") — fault injection point
24
+ * 4. Walk HEAD's tree, call git.resetIndex({ filepath }) for each tracked file.
25
+ * resetIndex ONLY updates the index metadata (mode/oid/stat) — it does NOT
26
+ * write to the working-tree file, so uncommitted edits remain byte-for-byte.
27
+ * 5. Return status=recovered
28
+ */
29
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
30
+ /**
31
+ * Precondition probe (see types.ts `StillAppliesFn`): re-probe whether the
32
+ * index is still unreadable right before the dispatcher hands off to
33
+ * `recover` below. `git.listFiles` with no `ref` reads the current staging
34
+ * area directly from `.git/index` — the same file this handler deletes and
35
+ * rebuilds — so a successful read here means the corruption is already gone
36
+ * (e.g. a previous attempt already rebuilt it, or the author replaced the
37
+ * file externally) and there is nothing left to repair.
38
+ */
39
+ export declare const stillApplies: StillAppliesFn;
40
+ export declare const recover: RecoverFn;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * recover-detached-head.ts — recover from a detached HEAD state.
3
+ *
4
+ * WHY: When an author's version history ends up in "detached" mode, syncing
5
+ * fails completely. This happens when the working copy landed on a specific
6
+ * saved point rather than the live named copy of the work.
7
+ * The repair re-attaches the copy to the named working version.
8
+ *
9
+ * All cases use a unified path through withBackupGate so fault injection
10
+ * points are consistent and predictable:
11
+ *
12
+ * Case A — clean working tree, current point IS reachable from the
13
+ * configured version line:
14
+ * Backup → create local rescue copy at current HEAD →
15
+ * checkout named version → 'recovered'.
16
+ *
17
+ * Case B — orphan saved point (NOT reachable from the named version line):
18
+ * Same path as Case A; the rescue copy preserves the orphan.
19
+ *
20
+ * Case C — uncommitted edits in the working tree:
21
+ * Backup → stage + commit edits to rescue copy →
22
+ * checkout named version → 'recovered'.
23
+ * DENY → blocked, everything unchanged.
24
+ *
25
+ * Branch resolution (which named version to re-attach to): the detached commit
26
+ * usually belongs to the author's real working branch, which is NOT always
27
+ * "main" (it may be "master", "trunk", …). The handler DISCOVERS that branch
28
+ * (resolveTargetBranch) instead of assuming "main": an explicit ctx.branch
29
+ * wins; otherwise it prefers a sole local branch, then the unique local branch
30
+ * the detached commit belongs to, then the remote's default
31
+ * (refs/remotes/origin/HEAD), and only finally "main". Discovery never throws.
32
+ *
33
+ * The final checkout is FORCED. By that point the prior state is preserved both
34
+ * on the rescue branch and in the verified /tmp backup, so forcing cannot lose
35
+ * work — and it avoids a spurious CheckoutConflictError from an untracked /
36
+ * ignored / stat-dirty file colliding with the target version.
37
+ *
38
+ * Fault injection points (called via ctx.faults?.before()):
39
+ * backup_create — before the zip is written
40
+ * backup_verify — after the zip is written, before verifying
41
+ * commit_recovery_snapshot — before staging + committing local edits (Case C)
42
+ * create_recovery_branch — before writing the rescue branch ref
43
+ * checkout_branch — before the final checkout
44
+ *
45
+ * Safety invariants:
46
+ * - NEVER force-push (push is never called; the rescue copy is local-only).
47
+ * - /tmp zip backup created and verified BEFORE any branch/checkout op.
48
+ * - backup_create fault → failed_no_changes_made, no writes after.
49
+ * - mid-repair fault → failed_backup_available, backup readable, remote unchanged.
50
+ * - confirmation DENIED → blocked, local + remote unchanged.
51
+ *
52
+ * Author-facing copy: no git words, no tokens, no internal paths in userSummary.
53
+ */
54
+ import type { RecoveryContext, RecoveryResult, StillAppliesFn } from "./types.ts";
55
+ /**
56
+ * Precondition probe (see types.ts `StillAppliesFn`): re-probe whether HEAD is
57
+ * still detached right before the dispatcher hands off to `recover` below.
58
+ * HEAD may have been re-attached externally (e.g. the author ran a checkout
59
+ * in a terminal) between classification and dispatch. A thrown
60
+ * `currentBranch` read (HEAD/ref store unreadable) is a DIFFERENT, worse
61
+ * condition than detachment — conservatively report "still applies" so that
62
+ * case surfaces through the normal repair path rather than being swallowed
63
+ * here as a false no-op.
64
+ */
65
+ export declare const stillApplies: StillAppliesFn;
66
+ /**
67
+ * Recover from a detached HEAD state.
68
+ * Implements the RecoverFn contract (types.ts).
69
+ */
70
+ export declare function recover(ctx: RecoveryContext, _error?: unknown): Promise<RecoveryResult>;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * recover-interrupted-cherry-pick.ts — abort a cherry-pick left unfinished.
3
+ *
4
+ * WHY: A conflicted cherry-pick stops BEFORE committing, so — unlike a rebase —
5
+ * it does NOT advance HEAD. There is no branch ref to rewind: only the
6
+ * half-applied index/worktree conflict state and the `.git/CHERRY_PICK_HEAD`
7
+ * marker (plus MERGE_MSG / sequencer) to clear. For a non-technical author the
8
+ * safe move is to UNDO the unfinished update and return to the last working
9
+ * state — which is a force-checkout of the current branch + marker cleanup.
10
+ *
11
+ * The shared skeleton in abort-interrupted-operation.ts owns the backup gate,
12
+ * TOCTOU guard, hadLocalChanges capture, fault ordering, checkout, cleanup and
13
+ * re-verify; this module only supplies the cherry-pick-specific config (default
14
+ * branch resolution: ctx.branch → git.currentBranch → "HEAD", HEAD stays
15
+ * attached during a cherry-pick).
16
+ */
17
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
18
+ /**
19
+ * Precondition probe (see types.ts `StillAppliesFn`) — the dispatcher's
20
+ * replacement for the abort skeleton's old hand-rolled TOCTOU guard.
21
+ */
22
+ export declare const stillApplies: StillAppliesFn;
23
+ export declare const recover: RecoverFn;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * recover-interrupted-merge.ts — abort a merge left unfinished.
3
+ *
4
+ * WHY: gutterpress itself never leaves a merge half-done (isomorphic-git's merge
5
+ * either completes or aborts in memory and never writes MERGE_HEAD), so this
6
+ * state comes from OUTSIDE the app: the author ran `git merge`/`git pull` in a
7
+ * terminal, hit conflicts, and walked away. The repo then has
8
+ * `.git/MERGE_HEAD` plus conflict markers in tracked files, and every sync
9
+ * would otherwise snapshot those markers into history. For a non-technical
10
+ * author the safe move is to UNDO the unfinished merge and return to the last
11
+ * working state.
12
+ *
13
+ * A conflicted merge stops BEFORE committing, so — like a cherry-pick and
14
+ * unlike a rebase — HEAD stays attached and no branch ref moved. The abort is a
15
+ * force-checkout of the current branch (resets index + worktree to HEAD) plus
16
+ * removal of the merge marker files. The shared skeleton in
17
+ * abort-interrupted-operation.ts owns the backup gate, TOCTOU guard,
18
+ * hadLocalChanges capture, fault ordering, checkout, cleanup and re-verify; this
19
+ * module only supplies the merge-specific config (default branch resolution:
20
+ * ctx.branch → git.currentBranch → "HEAD").
21
+ */
22
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
23
+ /**
24
+ * Precondition probe (see types.ts `StillAppliesFn`) — the dispatcher's
25
+ * replacement for the abort skeleton's old hand-rolled TOCTOU guard.
26
+ */
27
+ export declare const stillApplies: StillAppliesFn;
28
+ export declare const recover: RecoverFn;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * recover-interrupted-rebase.ts — abort a rebase that was left unfinished.
3
+ *
4
+ * WHY: If gutterpress or the OS dies partway through combining versions, the repo
5
+ * can be left mid-rebase: `.git/rebase-merge/` (merge/interactive backend) or
6
+ * `.git/rebase-apply/` (am backend) exists and HEAD is usually detached at a
7
+ * replay commit. Every sync then fails. There is nothing to "finish" for a
8
+ * non-technical author — the only safe move is to UNDO the unfinished update and
9
+ * return the project to its last working state. That is exactly what an abort is.
10
+ *
11
+ * Unlike a merge/cherry-pick (which stop before committing and only need the
12
+ * current branch reset), a rebase advances HEAD, so the abort must rewind the
13
+ * real branch ref to the pre-rebase commit. The shared skeleton in
14
+ * abort-interrupted-operation.ts owns the backup gate, TOCTOU guard,
15
+ * hadLocalChanges capture, fault ordering, checkout, cleanup and re-verify; this
16
+ * module supplies the rebase-specific `resolveTarget` that:
17
+ * 1. Reads the pre-rebase commit from `<stateDir>/orig-head` (fallback:
18
+ * `.git/ORIG_HEAD`). If it cannot be resolved → THROW (the backup gate
19
+ * converts it to failed_backup_available; the backup is safe).
20
+ * 2. Resolves the branch from `<stateDir>/head-name` — but ONLY when it is a
21
+ * genuine `refs/heads/<x>` path. A sentinel like "detached HEAD" (the
22
+ * rebase started from a detached HEAD) is NOT a branch. Falls back to
23
+ * ctx.branch only when head-name was ABSENT.
24
+ * 3a. Named branch → rewind the branch ref to the pre-rebase commit and
25
+ * force-checkout it (re-attaches HEAD, resets tree + index to the tip).
26
+ * 3b. No branch (detached-HEAD rebase) → force-checkout the pre-rebase commit
27
+ * directly, leaving HEAD detached at it; no branch ref is touched.
28
+ *
29
+ * resolveTarget reads state with DIRECT fs checks (not inspectRepo) — the one
30
+ * narrow fact it needs is which backend dir still exists, not a broad preflight
31
+ * probe that would re-enter the per-repo lock.
32
+ */
33
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
34
+ /**
35
+ * Precondition probe (see types.ts `StillAppliesFn`) — the dispatcher's
36
+ * replacement for the abort skeleton's old hand-rolled TOCTOU guard.
37
+ */
38
+ export declare const stillApplies: StillAppliesFn;
39
+ export declare const recover: RecoverFn;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Recovery handler for merge_conflict — thin wrapper over pullChanges.
3
+ *
4
+ * WHY a thin wrapper: merge_conflict is NOT a broken repo. The working tree is
5
+ * always left clean by pullChanges (abortOnConflict keeps the tree at the
6
+ * pre-merge snapshot). This handler's only job is to translate a
7
+ * `{ status: "conflict" }` PullOutcome into a `{ status: "needs_user" }`
8
+ * RecoveryResult so the host can show the per-file version chooser.
9
+ *
10
+ * No merge logic is re-implemented here. All the snapshot-first invariant,
11
+ * conflict detection, and two-parent merge machinery lives in sync.ts.
12
+ *
13
+ * SAFETY PROPERTIES (tested in recover-merge-conflict.test.ts):
14
+ * 1. Result is 'needs_user' with ConflictFile[] attached.
15
+ * 2. Working file NEVER contains '<<<<<<<' or '>>>>>>>' markers.
16
+ * 3. Remote HEAD + tree UNCHANGED after recover() returns.
17
+ * 4. User-visible local files preserved (snapshot kept both copies).
18
+ * 5. No force-push is attempted (policy mayChangeRemote=false).
19
+ * 6. Confirmation gate is NEVER called (requireConfirmation=false).
20
+ * 7. No backup zip created (createBackup=false — risk is "none").
21
+ *
22
+ * Policy: merge_conflict has risk="none", createBackup=false,
23
+ * requireConfirmation=false. The repair is fully safe and reversible via the
24
+ * snapshot pullChanges takes before attempting the merge.
25
+ */
26
+ import type { RecoverFn } from "./types.ts";
27
+ /**
28
+ * Translate a sync.ts PullOutcome into a RecoveryResult.
29
+ *
30
+ * - conflict → needs_user (the intended outcome: surface the per-file chooser)
31
+ * - pulled / up-to-date → recovered (the pull succeeded; no conflict after all)
32
+ * - auth / offline / error → needs_user with guidance (pass the guidance through)
33
+ */
34
+ export declare const recover: RecoverFn;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * recover-missing-git-dir.ts — reclone-and-reattach when .git/ is missing.
3
+ *
4
+ * WHY this is needed:
5
+ * A project folder can lose its .git/ directory if the user copied the
6
+ * project from a zip archive that stripped hidden directories, or if .git/
7
+ * was accidentally deleted. Without .git/, no sync operation can run.
8
+ *
9
+ * What this repair does:
10
+ * 1. Creates a /tmp backup of the current folder (user files preserved).
11
+ * 2. Asks the user to confirm the repair.
12
+ * 3. Clones the remote into a TEMP directory (NEVER into the project dir).
13
+ * 4. Copies only the .git/ metadata from the temp clone into the project dir.
14
+ * 5. Cleans up the temp clone directory.
15
+ * 6. Returns status=recovered with user files intact and .git/ restored.
16
+ *
17
+ * Safety invariants:
18
+ * - The project folder is NEVER deleted or replaced.
19
+ * - The clone target is always a separate temp dir, never projectDir.
20
+ * - User content files (outside .git/) are NEVER overwritten.
21
+ * - No force-push is ever issued.
22
+ * - Backup created and verified BEFORE any repair runs.
23
+ * - Backup failure → failed_no_changes_made, no further writes.
24
+ * - User DENY → blocked, no changes.
25
+ * - Mid-repair failure → failed_backup_available, backup readable, remote unchanged.
26
+ * - No remoteUrl → blocked with guidance (reclone is impossible).
27
+ */
28
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
29
+ /**
30
+ * Precondition probe (see types.ts `StillAppliesFn`): `.git/` may have
31
+ * reappeared between classification and dispatch (e.g. the author restored
32
+ * the folder or ran an init in a terminal). The dispatcher calls this INSIDE
33
+ * withRepoLock, immediately before invoking `recover` below, replacing what
34
+ * used to be a hand-rolled upfront check duplicated here.
35
+ */
36
+ export declare const stillApplies: StillAppliesFn;
37
+ export declare const recover: RecoverFn;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * recover-missing-objects.ts — safe fetch attempt for missing/corrupt loose objects.
3
+ *
4
+ * WHY this exists:
5
+ * When isomorphic-git raises a "ReadObjectFail" or similar "missing/corrupt
6
+ * object" error, the repo's on-disk object store has gaps. The safest repair
7
+ * is a fetch from the remote: git.fetch() downloads only the objects the
8
+ * remote has that the local repo is missing. If the remote can fill the gap,
9
+ * the repo becomes healthy again. If there is no remote, or the fetch cannot
10
+ * cover the damage, we stop with guidance and a backup.
11
+ *
12
+ * IMPORTANT — why we must verify after fetching:
13
+ * git.fetch() downloads MISSING objects into the pack store. However, it
14
+ * NEVER overwrites an already-existing (corrupt) loose object file on disk.
15
+ * Git's loose-object format uses a content-hash filename; if the file at
16
+ * .git/objects/xx/yyyy... already exists (even if corrupted), git skips it.
17
+ * So a corrupt loose object that the remote also has will remain corrupt on
18
+ * disk after a successful fetch() call. We MUST verify that the object store
19
+ * is healthy after the fetch — if any read still fails, the repair did not
20
+ * work and we stop with needs_user guidance instead of a false 'recovered'.
21
+ *
22
+ * Safety invariants (every test asserts these):
23
+ * I1. We NEVER push — not even a no-op push. Remote history is read-only here.
24
+ * I2. No force-push (we never call git.push at all).
25
+ * I3. Remote HEAD and tree are unchanged after this handler runs.
26
+ * I4. User-visible content files are preserved at all times.
27
+ * I5. A backup zip is created and verified BEFORE any repair attempt.
28
+ * I6. If backup creation fails → failed_no_changes_made; no further writes.
29
+ * I7. If the fetch throws AFTER backup → failed_backup_available; zip readable.
30
+ * I8. If the user denies the confirmation dialog → blocked, no-op.
31
+ * I9. All non-recovered results include ManualGuidance with jargon-free copy.
32
+ *
33
+ * Repair flow (inside withBackupGate's risky callback):
34
+ * 1. If no remote URL is configured → stop with needs_user guidance.
35
+ * 2. ctx.faults?.before("fetch") — fault injection point for tests.
36
+ * 3. git.fetch() from the remote (no push, read-only, tags=false).
37
+ * 4. Verify the repair: resolve HEAD + read commit + read tree. If any read
38
+ * fails, the corrupt object is still on disk → needs_user guidance.
39
+ * 5. If verification succeeds → recovered with the backup path.
40
+ * 6. If fetch throws → withBackupGate catches it → failed_backup_available.
41
+ *
42
+ * No merge logic, no push logic. All structural guard-rails live in
43
+ * withBackupGate (backup → confirm → risky → failsafe on throw).
44
+ */
45
+ import type { RecoverFn, StillAppliesFn } from "./types.ts";
46
+ /**
47
+ * Precondition probe (see types.ts `StillAppliesFn`): re-probe object-store
48
+ * readability right before the dispatcher hands off to `recover` below,
49
+ * reusing the SAME verifyRepoReadable check the handler itself uses to
50
+ * confirm a fetch actually repaired the store (inspect.ts) — one
51
+ * implementation, not a second copy that could drift. A successful read means
52
+ * the damage is already gone (e.g. a previous fetch attempt already fixed
53
+ * it), so there is nothing left to repair.
54
+ */
55
+ export declare const stillApplies: StillAppliesFn;
56
+ export declare const recover: RecoverFn;