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.
- package/README.md +422 -0
- package/dist/CGATS21_CRPC1-g0e3k7kr.icc +0 -0
- package/dist/api/index.d.ts +76 -0
- package/dist/api/index.js +272 -0
- package/dist/assets/preview/scripts/pagedjs-bridge.d.ts +1 -0
- package/dist/assets/preview/scripts/pagedjs-interface.d.ts +1 -0
- package/dist/assets/preview/scripts/preview-shell.d.ts +1 -0
- package/dist/audit-1jrwwacz.js +66 -0
- package/dist/build-5s92kgpc.js +77 -0
- package/dist/chapter-01-6fn9pvd0.md +31 -0
- package/dist/chapter-01-7jwqg1ct.md +20 -0
- package/dist/chapter-01-jj8ftn4c.md +29 -0
- package/dist/chapter-01-rkpyvjna.md +26 -0
- package/dist/checks/asset/approved-fonts.d.ts +3 -0
- package/dist/checks/asset/extensions.d.ts +41 -0
- package/dist/checks/asset/font-license.d.ts +3 -0
- package/dist/checks/asset/image-alpha.d.ts +3 -0
- package/dist/checks/asset/image-color-space.d.ts +3 -0
- package/dist/checks/asset/image-file-size.d.ts +3 -0
- package/dist/checks/asset/image-resolution.d.ts +3 -0
- package/dist/checks/asset/image-tac.d.ts +3 -0
- package/dist/checks/asset/index.d.ts +7 -0
- package/dist/checks/formatter.d.ts +3 -0
- package/dist/checks/heuristic/index.d.ts +4 -0
- package/dist/checks/heuristic/layer-count.d.ts +3 -0
- package/dist/checks/heuristic/placement-variance.d.ts +3 -0
- package/dist/checks/heuristic/section-density.d.ts +3 -0
- package/dist/checks/heuristic/text-density.d.ts +3 -0
- package/dist/checks/pdf/bleed.d.ts +3 -0
- package/dist/checks/pdf/bookmarks.d.ts +3 -0
- package/dist/checks/pdf/color-spaces.d.ts +3 -0
- package/dist/checks/pdf/cross-refs.d.ts +3 -0
- package/dist/checks/pdf/embedded-fonts.d.ts +3 -0
- package/dist/checks/pdf/image-resolution.d.ts +3 -0
- package/dist/checks/pdf/index.d.ts +15 -0
- package/dist/checks/pdf/ink-coverage.d.ts +3 -0
- package/dist/checks/pdf/page-labels.d.ts +3 -0
- package/dist/checks/pdf/page-size.d.ts +3 -0
- package/dist/checks/pdf/pdfx-markers.d.ts +3 -0
- package/dist/checks/pdf/pdfx-metadata.d.ts +3 -0
- package/dist/checks/pdf/pdfx-structure.d.ts +6 -0
- package/dist/checks/pdf/qpdf-structure.d.ts +3 -0
- package/dist/checks/pdf/rasterized-pages.d.ts +3 -0
- package/dist/checks/pdf/toc-links.d.ts +3 -0
- package/dist/checks/pdf/transparency.d.ts +3 -0
- package/dist/checks/policy.d.ts +61 -0
- package/dist/checks/register-builtins.d.ts +17 -0
- package/dist/checks/registry.d.ts +40 -0
- package/dist/checks/runner.d.ts +25 -0
- package/dist/checks/source/accessibility-alt-text.d.ts +3 -0
- package/dist/checks/source/accessibility-heading-order.d.ts +3 -0
- package/dist/checks/source/config-file.d.ts +8 -0
- package/dist/checks/source/htmlhint.d.ts +3 -0
- package/dist/checks/source/index.d.ts +6 -0
- package/dist/checks/source/local-refs.d.ts +3 -0
- package/dist/checks/source/markdownlint.d.ts +3 -0
- package/dist/checks/source/stylelint.d.ts +3 -0
- package/dist/checks/tool-check.d.ts +23 -0
- package/dist/checks/types.d.ts +52 -0
- package/dist/cli-1tyj4bk3.js +124 -0
- package/dist/cli-37x76zdn.js +4 -0
- package/dist/cli-506tg37g.js +26 -0
- package/dist/cli-5bxx0c4y.js +464 -0
- package/dist/cli-7ykx7pp0.js +12378 -0
- package/dist/cli-h7phg3ka.js +746 -0
- package/dist/cli-hvqjs342.js +284 -0
- package/dist/cli-yja077f6.js +92 -0
- package/dist/cli.js +157 -0
- package/dist/constants.d.ts +17 -0
- package/dist/doctor-25zjt8dz.js +57 -0
- package/dist/favicon-wkbm9cjn.ico +0 -0
- package/dist/git-http-yrb4ag6z.js +17 -0
- package/dist/index-1tyj4bk3.js +124 -0
- package/dist/index-37x76zdn.js +4 -0
- package/dist/index-3h3fef7r.js +15218 -0
- package/dist/index-5bxx0c4y.js +464 -0
- package/dist/index-yja077f6.js +92 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +310 -0
- package/dist/lib/app-heartbeat.d.ts +102 -0
- package/dist/lib/asset-inline.d.ts +73 -0
- package/dist/lib/browser-pool.d.ts +17 -0
- package/dist/lib/build-error.d.ts +52 -0
- package/dist/lib/build-fingerprint.d.ts +15 -0
- package/dist/lib/build-preflight.d.ts +43 -0
- package/dist/lib/build-runner.d.ts +161 -0
- package/dist/lib/build-staging.d.ts +64 -0
- package/dist/lib/chromium.d.ts +20 -0
- package/dist/lib/cli-args.d.ts +45 -0
- package/dist/lib/desktop.d.ts +14 -0
- package/dist/lib/diagnostics.d.ts +64 -0
- package/dist/lib/embedded-assets.d.ts +29 -0
- package/dist/lib/exec.d.ts +84 -0
- package/dist/lib/fetch-timeout.d.ts +41 -0
- package/dist/lib/ghostscript.d.ts +48 -0
- package/dist/lib/host-policy.d.ts +75 -0
- package/dist/lib/image-inspect.d.ts +32 -0
- package/dist/lib/install-hints.d.ts +21 -0
- package/dist/lib/lint-runner.d.ts +10 -0
- package/dist/lib/manifest-config.d.ts +31 -0
- package/dist/lib/manifest-doc.d.ts +25 -0
- package/dist/lib/manifest.d.ts +41 -0
- package/dist/lib/markdown/assemble.d.ts +78 -0
- package/dist/lib/markdown/chapter-id.d.ts +24 -0
- package/dist/lib/markdown/images.d.ts +34 -0
- package/dist/lib/markdown/index.d.ts +78 -0
- package/dist/lib/markdown/markdown-it-paged.d.ts +30 -0
- package/dist/lib/markdown/plugins.d.ts +69 -0
- package/dist/lib/markdown/renderer.d.ts +111 -0
- package/dist/lib/npm-plugin-installer.d.ts +33 -0
- package/dist/lib/open-path.d.ts +5 -0
- package/dist/lib/output-paths.d.ts +23 -0
- package/dist/lib/pagedjs-marker.d.ts +42 -0
- package/dist/lib/pagedjs.d.ts +26 -0
- package/dist/lib/pagination.d.ts +169 -0
- package/dist/lib/pdf-inspect.d.ts +123 -0
- package/dist/lib/pdf-parse.d.ts +57 -0
- package/dist/lib/plugin-manager.d.ts +108 -0
- package/dist/lib/plugin-vendor.d.ts +107 -0
- package/dist/lib/presets.d.ts +45 -0
- package/dist/lib/printsafe.d.ts +17 -0
- package/dist/lib/project-scaffold.d.ts +116 -0
- package/dist/lib/project-source.d.ts +140 -0
- package/dist/lib/project-templates.d.ts +49 -0
- package/dist/lib/publish/butler.d.ts +10 -0
- package/dist/lib/publish/command-runner.d.ts +18 -0
- package/dist/lib/publish/connect.d.ts +23 -0
- package/dist/lib/publish/manifest-publish.d.ts +9 -0
- package/dist/lib/publish/providers/azure-swa.d.ts +3 -0
- package/dist/lib/publish/providers/drivethrurpg.d.ts +10 -0
- package/dist/lib/publish/providers/guided.d.ts +3 -0
- package/dist/lib/publish/providers/itch.d.ts +5 -0
- package/dist/lib/publish/providers/kdp.d.ts +9 -0
- package/dist/lib/publish/providers/shopify.d.ts +5 -0
- package/dist/lib/publish/registry.d.ts +5 -0
- package/dist/lib/publish/run-publish.d.ts +30 -0
- package/dist/lib/publish/selections.d.ts +25 -0
- package/dist/lib/publish/types.d.ts +258 -0
- package/dist/lib/remote-auth/clone.d.ts +87 -0
- package/dist/lib/remote-auth/conflict-resolution.d.ts +29 -0
- package/dist/lib/remote-auth/diagnose.d.ts +77 -0
- package/dist/lib/remote-auth/generic-auth.d.ts +97 -0
- package/dist/lib/remote-auth/git-http.d.ts +85 -0
- package/dist/lib/remote-auth/github-auth.d.ts +69 -0
- package/dist/lib/remote-auth/github-repos.d.ts +64 -0
- package/dist/lib/remote-auth/operation-log.d.ts +66 -0
- package/dist/lib/remote-auth/recovery/abort-interrupted-operation.d.ts +103 -0
- package/dist/lib/remote-auth/recovery/backup.d.ts +113 -0
- package/dist/lib/remote-auth/recovery/classify.d.ts +109 -0
- package/dist/lib/remote-auth/recovery/context.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/dispatch.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/failsafe.d.ts +33 -0
- package/dist/lib/remote-auth/recovery/inspect.d.ts +74 -0
- package/dist/lib/remote-auth/recovery/manual-guidance.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/outcome-mapping.d.ts +58 -0
- package/dist/lib/remote-auth/recovery/policy.d.ts +47 -0
- package/dist/lib/remote-auth/recovery/recover-auth.d.ts +42 -0
- package/dist/lib/remote-auth/recovery/recover-binary-conflict.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-corrupt-index.d.ts +40 -0
- package/dist/lib/remote-auth/recovery/recover-detached-head.d.ts +70 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-cherry-pick.d.ts +23 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-merge.d.ts +28 -0
- package/dist/lib/remote-auth/recovery/recover-interrupted-rebase.d.ts +39 -0
- package/dist/lib/remote-auth/recovery/recover-merge-conflict.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-missing-git-dir.d.ts +37 -0
- package/dist/lib/remote-auth/recovery/recover-missing-objects.d.ts +56 -0
- package/dist/lib/remote-auth/recovery/recover-network.d.ts +34 -0
- package/dist/lib/remote-auth/recovery/recover-non-fast-forward.d.ts +27 -0
- package/dist/lib/remote-auth/recovery/recover-stale-lock.d.ts +76 -0
- package/dist/lib/remote-auth/recovery/recover-unrelated-histories.d.ts +44 -0
- package/dist/lib/remote-auth/recovery/recover-wrong-remote.d.ts +35 -0
- package/dist/lib/remote-auth/recovery/types.d.ts +235 -0
- package/dist/lib/remote-auth/resolution-plan.d.ts +64 -0
- package/dist/lib/remote-auth/sync-messages.d.ts +26 -0
- package/dist/lib/remote-auth/sync-types.d.ts +225 -0
- package/dist/lib/remote-auth/sync.d.ts +45 -0
- package/dist/lib/remote-auth/test-access.d.ts +47 -0
- package/dist/lib/remote-auth/test-support/git-http-server.d.ts +71 -0
- package/dist/lib/remote-auth/token-store.d.ts +95 -0
- package/dist/lib/remote-auth/transport.d.ts +105 -0
- package/dist/lib/slug.d.ts +28 -0
- package/dist/lib/snippets.d.ts +39 -0
- package/dist/lib/source-provider.d.ts +244 -0
- package/dist/lib/static-serve.d.ts +54 -0
- package/dist/lib/style-resolver.d.ts +30 -0
- package/dist/lib/theme-import.d.ts +70 -0
- package/dist/lib/theme-manager.d.ts +128 -0
- package/dist/lib/tool-probe.d.ts +37 -0
- package/dist/lib/validation-exec.d.ts +47 -0
- package/dist/lib/validation-profile.d.ts +18 -0
- package/dist/lib/version.d.ts +9 -0
- package/dist/lint-f63nxjfj.js +65 -0
- package/dist/manifest-n1gh3qw5.yaml +9 -0
- package/dist/manifest-ryyg71nf.yaml +9 -0
- package/dist/manifest.schema-rn1dpdpn.json +564 -0
- package/dist/new-7b08a42h.js +105 -0
- package/dist/paged.polyfill-n95pbxfn.js +33288 -0
- package/dist/pagedjs-bridge-vn4hk9fx.js +111 -0
- package/dist/pagedjs-interface-80g3xa8p.js +498 -0
- package/dist/platform.d.ts +100 -0
- package/dist/plugin-wf2cbmwc.js +129 -0
- package/dist/preflight-tg4mpz1h.js +222 -0
- package/dist/preview/file-watcher.d.ts +174 -0
- package/dist/preview/http-server.d.ts +45 -0
- package/dist/preview/lifecycle.d.ts +67 -0
- package/dist/preview/server-context.d.ts +36 -0
- package/dist/preview-h2bwbb2x.js +102 -0
- package/dist/preview-shell-rghtfmc8.js +155 -0
- package/dist/project-source-0tg0r6vm.js +17 -0
- package/dist/publish-ztaet53r.js +233 -0
- package/dist/render.d.ts +20 -0
- package/dist/render.js +682 -0
- package/dist/repair-jkp4n3j8.js +171 -0
- package/dist/schema/manifest.types.d.ts +218 -0
- package/dist/server.d.ts +34 -0
- package/dist/source-provider-hp96b5jf.js +46 -0
- package/dist/test-helpers/testkit.d.ts +91 -0
- package/dist/theme-0yzvthe8.css +65 -0
- package/dist/theme-570zmh2t.css +58 -0
- package/dist/theme-6a2fngc8.json +6 -0
- package/dist/theme-cd6efzjw.json +6 -0
- package/dist/theme-nya4nqh6.css +70 -0
- package/dist/theme-tqfypc1w.json +6 -0
- package/dist/theme-xt0hjb1b.json +6 -0
- package/dist/theme-zz2ktzqs.css +60 -0
- package/dist/types.d.ts +31 -0
- package/dist/utils/file-utils.d.ts +53 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/validate-k2drs19j.js +99 -0
- package/package.json +102 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recover-network.ts — Offline: keep local work, schedule retry.
|
|
3
|
+
*
|
|
4
|
+
* WHY this module exists: when gutterpress can't reach the server (ECONNREFUSED,
|
|
5
|
+
* ETIMEDOUT, or any other network error), the right behavior is:
|
|
6
|
+
*
|
|
7
|
+
* 1. Snapshot any unsaved work locally so nothing is lost (sync.ts already
|
|
8
|
+
* does this as its first step — "snapshot-first" invariant from ADR 0006 D5).
|
|
9
|
+
* 2. Tell the host to retry later with an exponential backoff delay.
|
|
10
|
+
* 3. Do NOT create a backup zip (risk is "none" — no data is at risk).
|
|
11
|
+
* 4. Do NOT ask the user for confirmation (no repair is being attempted).
|
|
12
|
+
* 5. Do NOT force-push, do NOT touch the remote.
|
|
13
|
+
*
|
|
14
|
+
* This is a THIN WRAPPER around syncProject from sync.ts. The snapshot step,
|
|
15
|
+
* the network call, and the "offline" classification all live there. The only
|
|
16
|
+
* delta this module adds is translating SyncOutcome { status: "offline" } →
|
|
17
|
+
* RecoveryResult { status: "retry_later", retryAfterMs }.
|
|
18
|
+
*
|
|
19
|
+
* Backoff: fixed 30 s delay before the next automated retry.
|
|
20
|
+
*/
|
|
21
|
+
import type { RecoveryContext, RecoveryResult } from "./types.ts";
|
|
22
|
+
/**
|
|
23
|
+
* Handle a `network_unavailable` classification:
|
|
24
|
+
*
|
|
25
|
+
* - Delegates entirely to `syncProject` (which snapshots unsaved work first,
|
|
26
|
+
* then attempts fetch + merge + push through the injectable httpClient).
|
|
27
|
+
* - When the outcome is `offline`, returns `retry_later` with a sane backoff.
|
|
28
|
+
* - When the outcome is anything else (e.g. the network recovered mid-call),
|
|
29
|
+
* passes the outcome through as a `recovered` result so the host can refresh.
|
|
30
|
+
*
|
|
31
|
+
* The `error` argument is accepted per the dispatcher contract but is not
|
|
32
|
+
* needed here: syncProject already re-classifies the live error internally.
|
|
33
|
+
*/
|
|
34
|
+
export declare function recover(ctx: RecoveryContext, _error?: unknown): Promise<RecoveryResult>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recover-non-fast-forward.ts — thin wrapper over syncProject.
|
|
3
|
+
*
|
|
4
|
+
* WHY this exists: when a push is rejected because the online copy has commits
|
|
5
|
+
* this computer doesn't have, the correct fix is pull-then-push — which is
|
|
6
|
+
* exactly what syncProject already does. This handler just calls syncProject
|
|
7
|
+
* and maps its typed SyncOutcome to the RecoveryResult contract.
|
|
8
|
+
*
|
|
9
|
+
* NO backup is created (policy.createBackup = false for non_fast_forward):
|
|
10
|
+
* syncProject takes its own snapshot before touching anything (ADR 0006 D5),
|
|
11
|
+
* so the user's work is safe without an additional zip.
|
|
12
|
+
*
|
|
13
|
+
* NO force-push is ever used: syncProject/pullChanges/pushChanges use only
|
|
14
|
+
* the normal git.push(), which the server rejects when a force-push would be
|
|
15
|
+
* needed. The safety invariant is proved by gitSpy in the test.
|
|
16
|
+
*
|
|
17
|
+
* Outcome mapping:
|
|
18
|
+
* SyncOutcome.status → RecoveryResult.status
|
|
19
|
+
* 'synced' → 'recovered'
|
|
20
|
+
* 'up-to-date' → 'recovered' (local commits all landed; nothing new)
|
|
21
|
+
* 'conflict' → 'needs_user' (let the user choose per file)
|
|
22
|
+
* 'auth' → 'needs_user' (guidance: reconnect)
|
|
23
|
+
* 'offline' → 'retry_later'
|
|
24
|
+
* 'error' → 'failed_no_changes_made'
|
|
25
|
+
*/
|
|
26
|
+
import type { RecoverFn } from "./types.ts";
|
|
27
|
+
export declare const recover: RecoverFn;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recover-stale-lock.ts — remove stale .git lock files left by a crash.
|
|
3
|
+
*
|
|
4
|
+
* WHY: When a write operation is interrupted (power loss, forced kill, crash)
|
|
5
|
+
* the version-tracking system leaves a lock file behind. Every subsequent
|
|
6
|
+
* operation fails until the lock is removed. This handler automates that
|
|
7
|
+
* cleanup with a conservative age check and a user confirmation gate.
|
|
8
|
+
*
|
|
9
|
+
* A crash does NOT only leave `.git/index.lock`. Depending on what was being
|
|
10
|
+
* written when the process died, git can leave any of:
|
|
11
|
+
* - index.lock (staging the index)
|
|
12
|
+
* - HEAD.lock (moving HEAD)
|
|
13
|
+
* - config.lock (writing config)
|
|
14
|
+
* - packed-refs.lock (repacking refs)
|
|
15
|
+
* - refs/**\/<name>.lock (updating a single ref, e.g. refs/heads/main.lock)
|
|
16
|
+
* If the stuck lock is any of these and we only ever looked at index.lock, the
|
|
17
|
+
* repo would stay unusable forever. So this handler scans the known top-level
|
|
18
|
+
* lock files PLUS a shallow scan of `.git/refs/**` for `*.lock` files.
|
|
19
|
+
*
|
|
20
|
+
* Decision logic (applied to the WHOLE candidate set, not just index.lock):
|
|
21
|
+
* NO lock at all → the race was already won; return retry_later (safe to
|
|
22
|
+
* retry the original operation immediately).
|
|
23
|
+
* ANY lock is FRESH (age < STALE_THRESHOLD_MS) → a live process may still
|
|
24
|
+
* hold the repo. Deleting a lock another process holds would corrupt an
|
|
25
|
+
* in-flight write, so we delete NOTHING and return retry_later — even if
|
|
26
|
+
* other locks in the set are stale. One fresh lock blocks the whole sweep.
|
|
27
|
+
* ALL locks are STALE (age ≥ STALE_THRESHOLD_MS) → request user confirmation
|
|
28
|
+
* once, then remove every stale lock; return recovered.
|
|
29
|
+
*
|
|
30
|
+
* Why "any fresh → retry_later" (and not "remove the stale ones"): the locks
|
|
31
|
+
* in the set may belong to the SAME interrupted-or-live operation. We cannot
|
|
32
|
+
* tell a crashed lock from a live one except by age, so the safe rule is: if
|
|
33
|
+
* the youngest lock could still be held, leave them all alone for now.
|
|
34
|
+
*
|
|
35
|
+
* Safety invariants:
|
|
36
|
+
* - Never force-pushes (this repair is entirely local).
|
|
37
|
+
* - No backup zip (policy.createBackup = false for stale_lock; a lock file
|
|
38
|
+
* is trivially recreatable and contains no user data).
|
|
39
|
+
* - Confirmation required (policy.requireConfirmation = true).
|
|
40
|
+
* - Fault hook ctx.faults?.before("remove_index_lock") fires once, just
|
|
41
|
+
* before the FIRST unlink, so tests can assert the fail-safe path. If it
|
|
42
|
+
* throws, nothing is removed.
|
|
43
|
+
* - Only locks proven stale are removed; a fresh lock is never touched.
|
|
44
|
+
* - User content files are never touched.
|
|
45
|
+
*
|
|
46
|
+
* Author-facing copy lives in manual-guidance.ts (stale_lock case). No git
|
|
47
|
+
* words, no file paths, no tokens in any user-visible string — the copy here
|
|
48
|
+
* says "leftover lock" / "temporary lock", never "lock file"/"index"/"ref".
|
|
49
|
+
*/
|
|
50
|
+
import type { RecoveryContext, RecoveryResult } from "./types.ts";
|
|
51
|
+
/**
|
|
52
|
+
* Known top-level lock files git may leave directly under `.git/`. These are
|
|
53
|
+
* scanned in addition to a shallow walk of `.git/refs/**` for `*.lock` files.
|
|
54
|
+
* Exported (with findLockCandidates) as the SINGLE lock-discovery
|
|
55
|
+
* implementation — inspect.ts's health probe consumes the same scan, so
|
|
56
|
+
* health and handler can never disagree about which locks exist.
|
|
57
|
+
*/
|
|
58
|
+
export declare const TOP_LEVEL_LOCK_NAMES: readonly ["index.lock", "HEAD.lock", "config.lock", "packed-refs.lock"];
|
|
59
|
+
export interface LockCandidate {
|
|
60
|
+
/** Absolute path to the lock file. */
|
|
61
|
+
path: string;
|
|
62
|
+
/** Age in ms relative to `now` (now - mtime). */
|
|
63
|
+
ageMs: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Gather every candidate lock file (top-level + refs/**) with its age.
|
|
67
|
+
* Locks that vanish between discovery and stat are simply dropped (a racing
|
|
68
|
+
* delete is fine to ignore). Never throws.
|
|
69
|
+
*/
|
|
70
|
+
export declare function findLockCandidates(gitDir: string, now: number): Promise<LockCandidate[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Attempt to recover from stale .git lock files (index.lock and friends).
|
|
73
|
+
*
|
|
74
|
+
* Implements the RecoverFn contract from types.ts.
|
|
75
|
+
*/
|
|
76
|
+
export declare function recover(ctx: RecoveryContext, _error?: unknown): Promise<RecoveryResult>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recover-unrelated-histories.ts — Combine local and remote when they share
|
|
3
|
+
* no history.
|
|
4
|
+
*
|
|
5
|
+
* WHY this is needed:
|
|
6
|
+
* If a user's local project and the configured online project were created
|
|
7
|
+
* independently — with no shared starting point — a normal merge cannot
|
|
8
|
+
* combine them. This handler creates a backup, asks the user to confirm,
|
|
9
|
+
* then performs the combination locally:
|
|
10
|
+
*
|
|
11
|
+
* 1. Fetches the remote tip.
|
|
12
|
+
* 2. Merges the remote into the local branch with
|
|
13
|
+
* `allowUnrelatedHistories: true`.
|
|
14
|
+
* 3. On clean merge → combined successfully.
|
|
15
|
+
* 4. On file conflicts → surfaces `needs_user` with the conflict file list
|
|
16
|
+
* and the local/remote OIDs, so the host can show the per-file version
|
|
17
|
+
* chooser and call `resolveConflicts({ allowUnrelatedHistories: true })`
|
|
18
|
+
* with the user's choices ("keep mine", "keep theirs", "keep both").
|
|
19
|
+
*
|
|
20
|
+
* The per-file resolution (merge driver, binary safety, "keep both" →
|
|
21
|
+
* "(online copy)" rename, delete-conflict equalization, push) is handled
|
|
22
|
+
* entirely by `sync.ts:resolveConflicts` — this handler just sets up the
|
|
23
|
+
* merge and surfaces the conflict, exactly like `recover-merge-conflict.ts`
|
|
24
|
+
* and `recover-binary-conflict.ts`.
|
|
25
|
+
*
|
|
26
|
+
* Safety invariants:
|
|
27
|
+
* - NEVER pushes to the remote (mayChangeRemote:false in policy). The push
|
|
28
|
+
* happens later in `resolveConflicts` AFTER the user makes their choices.
|
|
29
|
+
* - Remote is fetched but never written to.
|
|
30
|
+
* - Backup zip created and verified BEFORE any repair.
|
|
31
|
+
* - backup_create fault → failed_no_changes_made, no further writes.
|
|
32
|
+
* - mid-repair fault → failed_backup_available, backup readable.
|
|
33
|
+
* - User DENY → blocked, local + remote unchanged, backup still readable.
|
|
34
|
+
* - No remoteUrl → blocked with guidance.
|
|
35
|
+
* - Merge conflict → branch unchanged (abortOnConflict:true is the default);
|
|
36
|
+
* local commits preserved on the branch and in the backup zip. The
|
|
37
|
+
* conflict file list + OIDs are threaded through so the host can call
|
|
38
|
+
* `resolveConflicts` after the user decides.
|
|
39
|
+
*
|
|
40
|
+
* Fault injection points:
|
|
41
|
+
* after_backup_before_repair, fetch, merge
|
|
42
|
+
*/
|
|
43
|
+
import type { RecoverFn } from "./types.ts";
|
|
44
|
+
export declare const recover: RecoverFn;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recover-wrong-remote.ts — Wrong remote / missing destination.
|
|
3
|
+
*
|
|
4
|
+
* WHAT: When the project's configured online destination is unreachable,
|
|
5
|
+
* returns 404, or the destination section (path) does not exist on the
|
|
6
|
+
* server, syncing cannot proceed. This handler:
|
|
7
|
+
* 1. Uses diagnoseProjectRemote + parseRemoteOrigin (CLAUDE.md §7 mandated
|
|
8
|
+
* reuses) to obtain the project's remote URL, host, and protocol facts.
|
|
9
|
+
* 2. Probes the remote using isomorphic-git listServerRefs via httpClient
|
|
10
|
+
* (no system git binary) to detect whether the configured destination
|
|
11
|
+
* is actually present on the server.
|
|
12
|
+
* 3. Returns status "blocked" with reconnect/choose-destination guidance.
|
|
13
|
+
* The supportDetails reflect whether the destination was found or absent,
|
|
14
|
+
* so the guidance can distinguish "destination missing" from "wrong address".
|
|
15
|
+
* 4. NEVER creates a destination on the server automatically.
|
|
16
|
+
* 5. NEVER pushes to the remote.
|
|
17
|
+
* 6. Leaves all local files and remote state completely unchanged.
|
|
18
|
+
*
|
|
19
|
+
* Policy: createBackup:false — pure block, no repair attempted.
|
|
20
|
+
* requireConfirmation:false — confirmation gate is never called.
|
|
21
|
+
*
|
|
22
|
+
* WHY this is always "blocked": the handler is invoked ONLY after the
|
|
23
|
+
* classifier has determined the remote or destination is wrong. There is no
|
|
24
|
+
* safe automated fix — the author must update the project settings.
|
|
25
|
+
*/
|
|
26
|
+
import type { RecoverFn } from "./types.ts";
|
|
27
|
+
/**
|
|
28
|
+
* Block sync and return author-facing reconnect guidance.
|
|
29
|
+
* Never pushes, never modifies local files or remote state.
|
|
30
|
+
*
|
|
31
|
+
* Uses diagnoseProjectRemote to get remote/protocol facts, and
|
|
32
|
+
* listServerRefs to detect whether the configured destination exists
|
|
33
|
+
* on the server — all read-only operations.
|
|
34
|
+
*/
|
|
35
|
+
export declare const recover: RecoverFn;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and dispatcher contract for the sync-recovery subsystem.
|
|
3
|
+
*
|
|
4
|
+
* Every recover-<x>.ts handler imports from here. This module contains ZERO
|
|
5
|
+
* logic — it is a pure type surface. The dispatcher (dispatch.ts) maps a
|
|
6
|
+
* SyncErrorKind to its handler and is wired in the Integrate phase.
|
|
7
|
+
*
|
|
8
|
+
* Author-facing copy rules: no git words, no tokens, no internal paths visible
|
|
9
|
+
* to users. Every user-visible string lives in manual-guidance.ts.
|
|
10
|
+
*/
|
|
11
|
+
import type httpNode from "isomorphic-git/http/node";
|
|
12
|
+
import type { ProjectSource } from "../../project-source.ts";
|
|
13
|
+
import type { ConflictFile } from "../sync.ts";
|
|
14
|
+
import type { HostCredential, TokenStore } from "../token-store.ts";
|
|
15
|
+
/**
|
|
16
|
+
* Every failure mode the recovery subsystem can handle. The classifier
|
|
17
|
+
* (classify.ts) maps a thrown error + repo health facts to one of these.
|
|
18
|
+
*/
|
|
19
|
+
export type SyncErrorKind = "non_fast_forward" | "merge_conflict" | "binary_conflict" | "auth_required" | "network_unavailable" | "insecure_transport" | "detached_head" | "stale_lock" | "corrupt_index" | "missing_git_dir" | "missing_or_corrupt_objects" | "unrelated_histories" | "wrong_remote_or_branch" | "interrupted_rebase" | "interrupted_cherry_pick" | "interrupted_merge" | "unknown";
|
|
20
|
+
/**
|
|
21
|
+
* Machine token for the primary CTA in the guidance dialog. The host switches
|
|
22
|
+
* on this to route the button to the right flow. The human-readable label the
|
|
23
|
+
* button shows lives in `ManualGuidance.recommendedAction` (never this token).
|
|
24
|
+
*/
|
|
25
|
+
export type RecoveryActionKey = "sync" | "reconnect" | "resolve_conflict" | "restore_repo" | "check_connection";
|
|
26
|
+
/**
|
|
27
|
+
* How much irreversible change a repair makes. The confirmation gate shows
|
|
28
|
+
* a plain-language summary appropriate to the risk level.
|
|
29
|
+
*/
|
|
30
|
+
export type RecoveryRisk = "none" | "low" | "medium" | "high";
|
|
31
|
+
/**
|
|
32
|
+
* Jargon-free guidance the host shows when a repair is blocked or fails.
|
|
33
|
+
* No git words, no tokens, no internal paths.
|
|
34
|
+
*/
|
|
35
|
+
export interface ManualGuidance {
|
|
36
|
+
/** One-sentence plain-language summary of what went wrong. */
|
|
37
|
+
userSummary: string;
|
|
38
|
+
/** The single most important action the user should take next. */
|
|
39
|
+
recommendedNextStep: string;
|
|
40
|
+
/** Action label for the primary button in the UI. */
|
|
41
|
+
recommendedAction: string;
|
|
42
|
+
/** Machine token the host switches on to route the primary button's action. */
|
|
43
|
+
recommendedActionKey: RecoveryActionKey;
|
|
44
|
+
/** Optional secondary steps (shown as a list). */
|
|
45
|
+
safeNextSteps?: string[];
|
|
46
|
+
/** Details for a support ticket — may contain technical info. */
|
|
47
|
+
supportDetails?: string;
|
|
48
|
+
/** Path to the backup zip, when one was created before the failure. */
|
|
49
|
+
backupZipPath?: string;
|
|
50
|
+
}
|
|
51
|
+
/** The backup zip created before a risky repair. */
|
|
52
|
+
export interface RecoveryBackup {
|
|
53
|
+
/** Absolute path to the zip file under os.tmpdir()/print-sync-recovery/. */
|
|
54
|
+
zipPath: string;
|
|
55
|
+
/** ISO timestamp the backup was created. */
|
|
56
|
+
createdAt: string;
|
|
57
|
+
/** Files included in the backup (relative paths). */
|
|
58
|
+
entries: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* What a confirmation gate shows the user before a risky repair.
|
|
62
|
+
* The UI must render this information — never silently start a risky repair.
|
|
63
|
+
*/
|
|
64
|
+
export interface RepairConfirmation {
|
|
65
|
+
repair: SyncErrorKind;
|
|
66
|
+
risk: RecoveryRisk;
|
|
67
|
+
/** Plain-language summary of what the repair will do. */
|
|
68
|
+
summary: string;
|
|
69
|
+
/** Path to the backup zip (already created and verified). */
|
|
70
|
+
backupZipPath: string;
|
|
71
|
+
willChangeLocalFiles: boolean;
|
|
72
|
+
willChangeGitMetadata: boolean;
|
|
73
|
+
willChangeRemote: boolean;
|
|
74
|
+
/** True when the backup alone is enough to undo the repair. */
|
|
75
|
+
canBeUndoneFromBackup: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** Gate the host must satisfy: show the user what will happen and ask. */
|
|
78
|
+
export interface ConfirmationGate {
|
|
79
|
+
confirmRepair(req: RepairConfirmation): Promise<boolean>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Outcome of a recovery attempt. Each status maps to a host-side action:
|
|
83
|
+
* - recovered → refresh the project; show a success toast.
|
|
84
|
+
* - retry_later → schedule a retry after retryAfterMs; show a soft message.
|
|
85
|
+
* - needs_user → show the conflict chooser / reconnect dialog.
|
|
86
|
+
* - blocked → show guidance and a "what do I do?" panel.
|
|
87
|
+
* - failed_no_changes_made → show guidance; nothing was changed locally or remotely.
|
|
88
|
+
* - failed_backup_available → show guidance + "open backup folder" button.
|
|
89
|
+
*/
|
|
90
|
+
export type RecoveryResult = {
|
|
91
|
+
status: "recovered";
|
|
92
|
+
message: string;
|
|
93
|
+
backupZipPath?: string;
|
|
94
|
+
} | {
|
|
95
|
+
status: "retry_later";
|
|
96
|
+
message: string;
|
|
97
|
+
retryAfterMs: number;
|
|
98
|
+
} | {
|
|
99
|
+
status: "needs_user";
|
|
100
|
+
message: string;
|
|
101
|
+
guidance: ManualGuidance;
|
|
102
|
+
files?: ConflictFile[];
|
|
103
|
+
backupZipPath?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Conflict tip OIDs threaded through to the host so it can call
|
|
106
|
+
* resolveConflicts with the correct local/remote versions after the user
|
|
107
|
+
* chooses. Present on the per-file conflict-chooser paths only.
|
|
108
|
+
*/
|
|
109
|
+
localId?: string;
|
|
110
|
+
remoteId?: string;
|
|
111
|
+
} | {
|
|
112
|
+
status: "blocked";
|
|
113
|
+
message: string;
|
|
114
|
+
guidance: ManualGuidance;
|
|
115
|
+
backupZipPath?: string;
|
|
116
|
+
} | {
|
|
117
|
+
status: "failed_no_changes_made";
|
|
118
|
+
message: string;
|
|
119
|
+
guidance: ManualGuidance;
|
|
120
|
+
} | {
|
|
121
|
+
status: "failed_backup_available";
|
|
122
|
+
message: string;
|
|
123
|
+
backupZipPath: string;
|
|
124
|
+
guidance: ManualGuidance;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Preflight health snapshot of a local repo. Populated by inspectRepo()
|
|
128
|
+
* (inspect.ts) before any recovery decision is made.
|
|
129
|
+
*/
|
|
130
|
+
export interface RepoHealth {
|
|
131
|
+
/** True when .git/ exists and looks like a valid git dir. */
|
|
132
|
+
hasGitDir: boolean;
|
|
133
|
+
/** Current branch name, or undefined when HEAD is detached. */
|
|
134
|
+
currentBranch?: string;
|
|
135
|
+
/** True when HEAD is detached (no named branch). */
|
|
136
|
+
isDetachedHead: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* True when HEAD (or the ref store) could not even be READ — distinct from
|
|
139
|
+
* a clean detached HEAD, where HEAD resolves fine but points at a commit
|
|
140
|
+
* instead of a branch. This means the repo's ref store or HEAD file is
|
|
141
|
+
* missing/corrupt, and routes to `missing_or_corrupt_objects` instead of
|
|
142
|
+
* `detached_head` (see classifyFromHealth).
|
|
143
|
+
*/
|
|
144
|
+
headUnreadable: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* True when a leftover git lock file exists (a previous operation may have
|
|
147
|
+
* died). Detects any of index.lock, HEAD.lock, config.lock, packed-refs.lock,
|
|
148
|
+
* or a per-ref refs/**\/*.lock — the same set the stale-lock handler scans.
|
|
149
|
+
*/
|
|
150
|
+
hasStaleLock: boolean;
|
|
151
|
+
/** How old the YOUNGEST detected lock file is in milliseconds, when present. */
|
|
152
|
+
lockAgeMs?: number;
|
|
153
|
+
/** True when a MERGE_HEAD file exists (interrupted merge). */
|
|
154
|
+
hasInterruptedMerge: boolean;
|
|
155
|
+
/** True when a rebase-in-progress directory exists. */
|
|
156
|
+
hasInterruptedRebase: boolean;
|
|
157
|
+
/** True when CHERRY_PICK_HEAD exists. */
|
|
158
|
+
hasInterruptedCherryPick: boolean;
|
|
159
|
+
/** True when the working tree has uncommitted changes. */
|
|
160
|
+
hasLocalChanges: boolean;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Named fault injection points every risky repair MUST call via
|
|
164
|
+
* `ctx.faults?.before(point)`. Throwing from this hook simulates a failure
|
|
165
|
+
* at that exact point so failsafe invariants can be asserted.
|
|
166
|
+
*/
|
|
167
|
+
export type FaultPoint = "backup_create" | "backup_verify" | "after_backup_before_repair" | "fetch" | "merge" | "checkout_branch" | "abort_interrupted_operation" | "remove_operation_state" | "create_recovery_branch" | "commit_recovery_snapshot" | "remove_index_lock" | "remove_index" | "rebuild_index" | "clone_temp_repo" | "replace_git_dir" | "push" | "write_conflict_snapshot";
|
|
168
|
+
export interface FaultInjector {
|
|
169
|
+
before(point: FaultPoint): Promise<void>;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Everything a recover-<x>.ts handler needs. Extends SyncProjectOptions with
|
|
173
|
+
* the repo-level facts that the dispatcher resolves once and passes down.
|
|
174
|
+
*/
|
|
175
|
+
export interface RecoveryContext {
|
|
176
|
+
/** The project directory the user opened (may be a repo subfolder). */
|
|
177
|
+
projectDir: string;
|
|
178
|
+
/** Absolute path to the git repository root. */
|
|
179
|
+
repoDir: string;
|
|
180
|
+
/**
|
|
181
|
+
* The projectDir's classification, resolved ONCE by buildRecoveryContext and
|
|
182
|
+
* threaded to every consumer (inspectRepo, diagnoseProjectRemote) so the
|
|
183
|
+
* recovery path never re-walks parent dirs to re-classify the same folder.
|
|
184
|
+
* `null` records that classification failed; omitted means "not resolved" —
|
|
185
|
+
* consumers classify themselves in both cases.
|
|
186
|
+
*/
|
|
187
|
+
source?: ProjectSource | null;
|
|
188
|
+
/** Current branch name (may be empty on detached HEAD). */
|
|
189
|
+
branch: string;
|
|
190
|
+
/** Sanitized HTTPS remote URL (no embedded credentials). */
|
|
191
|
+
remoteUrl?: string;
|
|
192
|
+
/** Short identifier for the repo used in backup paths. */
|
|
193
|
+
repoSlug: string;
|
|
194
|
+
/** Resolved credential for the remote host. */
|
|
195
|
+
credential?: HostCredential;
|
|
196
|
+
/** Host-keyed credential store (for clearing stale tokens). */
|
|
197
|
+
tokenStore?: TokenStore;
|
|
198
|
+
/** Injectable HTTP transport (real or test mock). */
|
|
199
|
+
httpClient?: typeof httpNode;
|
|
200
|
+
/** The user's display name for snapshot commits. */
|
|
201
|
+
authorName?: string;
|
|
202
|
+
/** The user's email for snapshot commits. Paired with `authorName` — a
|
|
203
|
+
* recovery commit must carry the SAME identity a normal snapshot does. */
|
|
204
|
+
authorEmail?: string;
|
|
205
|
+
/** Gate the host must satisfy before a risky repair starts. */
|
|
206
|
+
confirmation: ConfirmationGate;
|
|
207
|
+
/** Fault injection hooks (tests only — omit in production). */
|
|
208
|
+
faults?: FaultInjector;
|
|
209
|
+
/** Clock override (tests only). Returns epoch ms. */
|
|
210
|
+
now?: () => number;
|
|
211
|
+
/**
|
|
212
|
+
* Optional path to a log file for debugging. When set, each recovery step
|
|
213
|
+
* (backup, fetch, merge, checkout, etc.) is appended as a timestamped line.
|
|
214
|
+
* Never logs secrets — only repo slug, branch, short OIDs, outcome status.
|
|
215
|
+
*/
|
|
216
|
+
logFile?: string;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The signature every recover-<x>.ts module MUST export.
|
|
220
|
+
* The dispatcher (dispatch.ts) maps SyncErrorKind → RecoverFn.
|
|
221
|
+
*/
|
|
222
|
+
export type RecoverFn = (ctx: RecoveryContext, error?: unknown) => Promise<RecoveryResult>;
|
|
223
|
+
/**
|
|
224
|
+
* Optional per-kind precondition probe a recover-<x>.ts module MAY export as
|
|
225
|
+
* `stillApplies`. The dispatcher calls it — for serializeRepo:true kinds only,
|
|
226
|
+
* INSIDE withRepoLock, immediately before invoking the handler body — to catch
|
|
227
|
+
* the case where the condition that justified this kind was already resolved
|
|
228
|
+
* (externally, or by a previous attempt) between classification and dispatch.
|
|
229
|
+
* Returning false means there is nothing left to repair; the dispatcher
|
|
230
|
+
* returns a benign no-op RecoveryResult without running the handler at all.
|
|
231
|
+
* Must be read-only and throw-free from the caller's perspective (probes
|
|
232
|
+
* should catch their own errors and resolve `true` — "assume it still
|
|
233
|
+
* applies" — rather than reject, so a probe failure never blocks recovery).
|
|
234
|
+
*/
|
|
235
|
+
export type StillAppliesFn = (ctx: RecoveryContext) => Promise<boolean>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure per-file resolution PLAN builder for {@link resolveConflicts} (#15,
|
|
3
|
+
* ADR 0006 D5). Given the author's per-file choices and the two commit tips,
|
|
4
|
+
* it decides — for EACH conflicted file — what the merge driver should return
|
|
5
|
+
* ("mine"/"theirs"), what to write/delete on the LOCAL side before the merge
|
|
6
|
+
* (delete-conflict equalization + "(online copy)" files), what to restore
|
|
7
|
+
* after the merge, and which decided files need a raw-bytes binary fix.
|
|
8
|
+
*
|
|
9
|
+
* It is intentionally free of git/fs coupling: the only IO it needs — reading
|
|
10
|
+
* a file's blob from a commit, and picking a collision-free "(online copy)"
|
|
11
|
+
* name — is injected via {@link ResolutionPlanDeps}, so the whole decision
|
|
12
|
+
* table is unit-testable with plain fakes. sync.ts owns the git side-effects
|
|
13
|
+
* of ACTUALLY writing/deleting/merging/pushing; this module owns only the
|
|
14
|
+
* decisions.
|
|
15
|
+
*/
|
|
16
|
+
/** Author's per-file decision for a conflicted file (mirror of sync.ts). */
|
|
17
|
+
export interface ResolutionInput {
|
|
18
|
+
path: string;
|
|
19
|
+
choice: "mine" | "theirs" | "both";
|
|
20
|
+
}
|
|
21
|
+
/** A file to write with exact bytes (never decoded through a string). */
|
|
22
|
+
export interface PlanWrite {
|
|
23
|
+
path: string;
|
|
24
|
+
content: Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The decisions {@link resolveConflicts} executes, in order:
|
|
28
|
+
*
|
|
29
|
+
* - `driverChoice` — the side the custom mergeDriver returns per decided file.
|
|
30
|
+
* - `preWrites` / `preDeletes` — applied on the LOCAL side BEFORE the merge
|
|
31
|
+
* ("(online copy)" files + delete-conflict equalization) so the merge is
|
|
32
|
+
* clean and both parents stay honest.
|
|
33
|
+
* - `postWrites` / `postDeletes` — applied AFTER the merge to restore the
|
|
34
|
+
* author's chosen side for delete-involved files equalized the other way.
|
|
35
|
+
* - `postBinaryFixes` — decided files overwritten with raw git-object bytes
|
|
36
|
+
* after checkout, guarding against UTF-8 round-trip corruption of binaries
|
|
37
|
+
* in the string-based merge driver (a no-op for text files).
|
|
38
|
+
*/
|
|
39
|
+
export interface ResolutionPlan {
|
|
40
|
+
driverChoice: Map<string, "mine" | "theirs">;
|
|
41
|
+
preWrites: PlanWrite[];
|
|
42
|
+
preDeletes: string[];
|
|
43
|
+
postWrites: PlanWrite[];
|
|
44
|
+
postDeletes: string[];
|
|
45
|
+
postBinaryFixes: PlanWrite[];
|
|
46
|
+
}
|
|
47
|
+
/** Injected IO the plan builder needs (kept out of this pure module). */
|
|
48
|
+
export interface ResolutionPlanDeps {
|
|
49
|
+
/** Read a file's blob from a commit oid, or null when absent in that tree. */
|
|
50
|
+
readBlob: (oid: string, filepath: string) => Promise<Uint8Array | null>;
|
|
51
|
+
/**
|
|
52
|
+
* First "(online copy)" name for `filepath` that collides with nothing in
|
|
53
|
+
* the working dir or in either side's tree (given by `oids`).
|
|
54
|
+
*/
|
|
55
|
+
uniqueOnlineCopyPath: (filepath: string, oids: string[]) => Promise<string>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Build the per-file plan. "mine" is read from `localTip` (the CURRENT local
|
|
59
|
+
* tip, so edits made after the conflict was reported count as the author's
|
|
60
|
+
* version); "theirs" is read from `remoteId` (the online tip). Files present
|
|
61
|
+
* on BOTH sides are settled inside the merge by the driver; delete-involved
|
|
62
|
+
* files are equalized before the merge and restored after.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildResolutionPlan(resolutions: ResolutionInput[], localTip: string, remoteId: string, deps: ResolutionPlanDeps): Promise<ResolutionPlan>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Author-language copy for sync / pull / push / conflict-resolution (never raw
|
|
3
|
+
* git words). Extracted from sync.ts so the transport, conflict-resolution and
|
|
4
|
+
* orchestrator modules share ONE source of these strings — their exact wording
|
|
5
|
+
* is part of the observable contract (the host renders them verbatim).
|
|
6
|
+
*/
|
|
7
|
+
export declare const MSG_UP_TO_DATE = "Everything is in sync.";
|
|
8
|
+
export declare const MSG_UP_TO_DATE_PULLED = "Everything is in sync. The latest online changes were downloaded to this computer.";
|
|
9
|
+
export declare const MSG_SYNCED = "Your changes are online.";
|
|
10
|
+
export declare const MSG_SYNCED_MERGED = "Your changes are online, combined with changes from the online copy.";
|
|
11
|
+
export declare const MSG_OFFLINE = "Your changes are saved on this computer. gutterpress couldn't reach the online repository \u2014 try syncing again when you're back online.";
|
|
12
|
+
export declare const MSG_AUTH = "The online repository didn't accept the saved connection. Reconnect and try again.";
|
|
13
|
+
export declare const MSG_INSECURE_TRANSPORT = "This project's online address isn't secure, so the saved connection wasn't sent \u2014 connections are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to sync.";
|
|
14
|
+
export declare const MSG_RACE = "Someone else synced changes at the same moment. Your work is saved on this computer \u2014 please try Sync again.";
|
|
15
|
+
export declare const MSG_CONFLICT = "Your copy and the online copy both changed. Choose which version to keep for each file \u2014 a safety snapshot of your work was taken first.";
|
|
16
|
+
export declare const MSG_NO_REMOTE = "This project isn't connected to an online repository yet.";
|
|
17
|
+
export declare const MSG_SSH_REMOTE = "This project's online address uses SSH (git@\u2026), which gutterpress can't sync to. Switch it to the web (HTTPS) address to sync from here.";
|
|
18
|
+
export declare const MSG_NO_BRANCH = "This project's version history isn't on a named branch, so it can't be synced right now.";
|
|
19
|
+
export declare const MSG_PULLED = "The latest online changes were downloaded to this computer.";
|
|
20
|
+
export declare const MSG_PULLED_MERGED = "The latest online changes were combined with your changes on this computer.";
|
|
21
|
+
export declare const MSG_PULL_UP_TO_DATE = "You already have the latest online changes.";
|
|
22
|
+
export declare const MSG_PUSH_UP_TO_DATE = "There's nothing new to send \u2014 everything is already online.";
|
|
23
|
+
export declare const MSG_PULL_FIRST = "The online copy has changes you don't have yet. Get the latest changes first, then send yours.";
|
|
24
|
+
export declare const MSG_EXPIRED_CHOICES = "Those combine choices have expired. Please run Sync again.";
|
|
25
|
+
/** Message recorded on the automatic pre-sync snapshot (D5 invariant). */
|
|
26
|
+
export declare const SYNC_SNAPSHOT_MESSAGE = "Snapshot before syncing";
|