@narumitw/pi-sync 0.49.14 → 0.50.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 +134 -241
- package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
- package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
- package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
- package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
- package/dist/chunks/chunk-6UHKGALE.ts +134 -0
- package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
- package/dist/chunks/{chunk-RGJ6SOYR.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-3NDD5QPM.ts → chunk-AXXS2BPA.ts} +9 -9
- package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
- package/dist/chunks/{chunk-APZVBSM6.ts → chunk-C7XY5NF5.ts} +214 -365
- package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
- package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
- package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
- package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
- package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
- package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
- package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
- package/dist/chunks/{chunk-LJDSHNS3.ts → chunk-GWMHAQG4.ts} +4 -4
- package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
- package/dist/chunks/{chunk-FR6CVXAL.ts → chunk-HUDQATCL.ts} +25 -25
- package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
- package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
- package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts +51 -0
- package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
- package/dist/chunks/chunk-L7TBO32M.ts +25 -0
- package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
- package/dist/chunks/{chunk-4F3W4CSC.ts → chunk-LCRI3ABW.ts} +22 -8
- package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
- package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
- package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
- package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
- package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
- package/dist/chunks/{chunk-EWX3TPLQ.ts → chunk-OEX4ABY6.ts} +39 -37
- package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
- package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
- package/dist/chunks/chunk-OUHGBFYF.ts.map +7 -0
- package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
- package/dist/chunks/{chunk-BHJUISB4.ts → chunk-SL64RLXR.ts} +8 -6
- package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
- package/dist/chunks/chunk-THMF4BVL.ts +18 -0
- package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
- package/dist/chunks/{chunk-LONPFFNP.ts → chunk-X5OM6GXT.ts} +9 -7
- package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
- package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
- package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
- package/dist/chunks/{chunk-5WJNWFTG.ts → chunk-YKJHPTGO.ts} +23 -55
- package/dist/chunks/chunk-YKJHPTGO.ts.map +7 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
- package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
- package/dist/chunks/{file-selection-4UABOP44.ts → file-selection-FTTKAOYX.ts} +10 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
- package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-OQW46G2X.ts} +42 -17
- package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
- package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
- package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
- package/dist/chunks/{s3-backend-3QZGO2EF.ts → s3-backend-3P33LQHU.ts} +96 -18
- package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
- package/dist/chunks/{setup-switch-X3W3FALZ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
- package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
- package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
- package/dist/chunks/{snapshot-WBSV4MQG.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
- package/dist/chunks/{sync-operations-MPAFVVHA.ts → sync-operations-ONJ27QRL.ts} +381 -299
- package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
- package/dist/chunks/{sync-state-36H7ULG2.ts → sync-state-Q2FTXTW6.ts} +6 -6
- package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
- package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
- package/dist/index.ts +477 -342
- package/dist/index.ts.map +4 -4
- package/docs/settings.md +211 -0
- package/package.json +6 -8
- package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
- package/src/backends/backend-identity.ts +40 -0
- package/src/backends/backend-types.ts +81 -0
- package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
- package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
- package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
- package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
- package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
- package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
- package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
- package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
- package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
- package/src/commands/command-execution.ts +330 -0
- package/src/commands/command-handler.ts +201 -0
- package/src/commands/command-types.ts +18 -0
- package/src/{command.ts → commands/command.ts} +2 -1
- package/src/commands/setup-completions.ts +6 -0
- package/src/settings/config.ts +238 -0
- package/src/{settings-management.ts → settings/settings-management.ts} +40 -14
- package/src/settings/settings-store.ts +109 -0
- package/src/settings/settings-types.ts +128 -0
- package/src/settings/settings-validation.ts +443 -0
- package/src/snapshot/session-paths.ts +84 -0
- package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
- package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
- package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
- package/src/snapshot/snapshot-types.ts +38 -0
- package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
- package/src/state/json-file.ts +20 -0
- package/src/{lock.ts → state/lock.ts} +3 -2
- package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
- package/src/state/state-types.ts +20 -0
- package/src/state/sync-state-store.ts +62 -0
- package/src/sync/automatic-sync.ts +103 -0
- package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
- package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
- package/src/sync/signals.ts +10 -0
- package/src/sync/startup-check.ts +128 -0
- package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
- package/src/sync/sync-error-guidance.ts +53 -0
- package/src/sync/sync-inspection.ts +51 -0
- package/src/sync/sync-loaders.ts +54 -0
- package/src/{sync-operations.ts → sync/sync-mutations.ts} +41 -330
- package/src/sync/sync-operations.ts +12 -0
- package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
- package/src/sync/sync-queries.ts +235 -0
- package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
- package/src/sync-extension.ts +64 -708
- package/src/sync.ts +8 -8
- package/src/types.ts +47 -284
- package/src/ui/automatic-sync-summary.ts +6 -0
- package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
- package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
- package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
- package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
- package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
- package/src/ui/manager-ui.ts +386 -0
- package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
- package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
- package/src/{settings-ui.ts → ui/settings-ui.ts} +42 -11
- package/src/ui/setup/git-ui.ts +293 -0
- package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
- package/src/ui/setup/s3-ui.ts +217 -0
- package/src/ui/setup/setup-actions.ts +127 -0
- package/src/ui/setup/setup-location-ui.ts +167 -0
- package/src/ui/setup/setup-name-ui.ts +34 -0
- package/src/ui/setup/setup-prompts.ts +92 -0
- package/src/ui/setup/setup-review.ts +70 -0
- package/src/ui/setup/setup-switcher.ts +181 -0
- package/src/ui/setup/setup-wizard.ts +39 -0
- package/src/ui/setup/text-input.ts +78 -0
- package/src/ui/setup/webdav-ui.ts +330 -0
- package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
- package/src/{sync-attention.ts → ui/sync-attention.ts} +75 -6
- package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
- package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
- package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
- package/src/ui/terminal-text.ts +4 -0
- package/dist/chunks/chunk-3NDD5QPM.ts.map +0 -7
- package/dist/chunks/chunk-4F3W4CSC.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5WJNWFTG.ts.map +0 -7
- package/dist/chunks/chunk-APZVBSM6.ts.map +0 -7
- package/dist/chunks/chunk-BHJUISB4.ts.map +0 -7
- package/dist/chunks/chunk-EWX3TPLQ.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-FR6CVXAL.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-JNOOSPEW.ts +0 -82
- package/dist/chunks/chunk-JNOOSPEW.ts.map +0 -7
- package/dist/chunks/chunk-LJDSHNS3.ts.map +0 -7
- package/dist/chunks/chunk-LONPFFNP.ts.map +0 -7
- package/dist/chunks/chunk-RGJ6SOYR.ts.map +0 -7
- package/dist/chunks/chunk-W64NEHXT.ts +0 -167
- package/dist/chunks/chunk-W64NEHXT.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-4UABOP44.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-RNRQA3PW.ts +0 -18
- package/dist/chunks/manager-ui-QO2P4V3Z.ts +0 -2757
- package/dist/chunks/manager-ui-QO2P4V3Z.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-LHSAGKGA.ts +0 -17
- package/dist/chunks/s3-backend-3QZGO2EF.ts.map +0 -7
- package/dist/chunks/sync-operations-MPAFVVHA.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -910
- package/src/git-ui.ts +0 -307
- package/src/manager-helpers.ts +0 -64
- package/src/manager-ui.ts +0 -997
- package/src/webdav-ui.ts +0 -421
- /package/dist/chunks/{manager-result-dispatcher-RNRQA3PW.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-X3W3FALZ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-WBSV4MQG.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-36H7ULG2.ts.map → sync-inspection-FEP4L5TR.ts.map} +0 -0
- /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
- /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
- /package/src/{config-file.ts → settings/config-file.ts} +0 -0
- /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
- /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
- /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
- /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
- /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
- /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createSyncBackend, type SyncBackendFactory } from "../backends/backend-factory.js";
|
|
2
|
+
import type { AnySyncConfig } from "../settings/settings-types.js";
|
|
3
|
+
import { createSnapshot } from "../snapshot/snapshot.js";
|
|
4
|
+
import type { SnapshotOptions } from "../snapshot/snapshot-types.js";
|
|
5
|
+
import { readStateForConfig, syncStateFingerprint } from "../state/sync-state-store.js";
|
|
6
|
+
import { throwIfAborted } from "./signals.js";
|
|
7
|
+
import { inspectRemoteSelection } from "./sync-policy.js";
|
|
8
|
+
import { hasLocalChanges, remoteChangedSinceState } from "./sync-state.js";
|
|
9
|
+
|
|
10
|
+
/** Advisory baseline-relative observation, never an authorization to transfer files. */
|
|
11
|
+
export async function inspectSync(
|
|
12
|
+
config: AnySyncConfig,
|
|
13
|
+
options: SnapshotOptions,
|
|
14
|
+
signal?: AbortSignal,
|
|
15
|
+
factory: SyncBackendFactory = createSyncBackend,
|
|
16
|
+
) {
|
|
17
|
+
throwIfAborted(signal);
|
|
18
|
+
const backend = await factory(config);
|
|
19
|
+
throwIfAborted(signal);
|
|
20
|
+
const local = await createSnapshot(config.snapshotIdentity, { ...options, signal });
|
|
21
|
+
throwIfAborted(signal);
|
|
22
|
+
const state = await readStateForConfig(config);
|
|
23
|
+
throwIfAborted(signal);
|
|
24
|
+
const head = await backend.readHead(signal);
|
|
25
|
+
throwIfAborted(signal);
|
|
26
|
+
return {
|
|
27
|
+
head,
|
|
28
|
+
selectionState: head
|
|
29
|
+
? inspectRemoteSelection(config.include, { selection: head.selection, files: [] })
|
|
30
|
+
: undefined,
|
|
31
|
+
localFiles: local.files.length,
|
|
32
|
+
localChanged: hasLocalChanges(local, state, config),
|
|
33
|
+
remoteChanged: remoteChangedSinceState(head, state, config, (left, right) =>
|
|
34
|
+
backend.sameRevision(left, right),
|
|
35
|
+
),
|
|
36
|
+
firstSync: !state.lastAppliedSnapshot,
|
|
37
|
+
emptyInclude: config.include.length === 0,
|
|
38
|
+
stateIdentity: syncStateFingerprint(state),
|
|
39
|
+
destination: backend.destination,
|
|
40
|
+
capability: backend.capability,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type SyncInspection = Awaited<ReturnType<typeof inspectSync>>;
|
|
45
|
+
|
|
46
|
+
export interface StartupObservation {
|
|
47
|
+
setupName: string;
|
|
48
|
+
configIdentity: string;
|
|
49
|
+
checkedAt: string;
|
|
50
|
+
inspection: SyncInspection;
|
|
51
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
type SetupSwitchModule = Pick<typeof import("./setup-switch.js"), "useSyncSetup">;
|
|
2
|
+
type SnapshotModule = Pick<typeof import("../snapshot/snapshot.js"), "createSnapshot">;
|
|
3
|
+
type SyncStateModule = Pick<typeof import("./sync-state.js"), "hasLocalChanges">;
|
|
4
|
+
type SyncOperations = typeof import("./sync-operations.js");
|
|
5
|
+
|
|
6
|
+
type SyncInspectionModule = Pick<typeof import("./sync-inspection.js"), "inspectSync">;
|
|
7
|
+
|
|
8
|
+
export interface SyncDependencies {
|
|
9
|
+
loadSyncInspection(): Promise<SyncInspectionModule>;
|
|
10
|
+
loadSetupSwitch(): Promise<SetupSwitchModule>;
|
|
11
|
+
loadSnapshot(): Promise<SnapshotModule>;
|
|
12
|
+
loadSyncState(): Promise<SyncStateModule>;
|
|
13
|
+
loadSyncOperations(): Promise<SyncOperations>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SyncLoaders {
|
|
17
|
+
inspection(): Promise<SyncInspectionModule>;
|
|
18
|
+
setupSwitch(): Promise<SetupSwitchModule>;
|
|
19
|
+
snapshot(): Promise<SnapshotModule>;
|
|
20
|
+
syncState(): Promise<SyncStateModule>;
|
|
21
|
+
operations(): Promise<SyncOperations>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createSyncLoaders(dependencies: Partial<SyncDependencies>): SyncLoaders {
|
|
25
|
+
const loaders: SyncLoaders = {
|
|
26
|
+
inspection: cachedModuleLoader(
|
|
27
|
+
dependencies.loadSyncInspection ?? (() => import("./sync-inspection.js")),
|
|
28
|
+
),
|
|
29
|
+
setupSwitch: cachedModuleLoader(
|
|
30
|
+
dependencies.loadSetupSwitch ?? (() => import("./setup-switch.js")),
|
|
31
|
+
),
|
|
32
|
+
snapshot: cachedModuleLoader(
|
|
33
|
+
dependencies.loadSnapshot ?? (() => import("../snapshot/snapshot.js")),
|
|
34
|
+
),
|
|
35
|
+
syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./sync-state.js"))),
|
|
36
|
+
operations: cachedModuleLoader(
|
|
37
|
+
dependencies.loadSyncOperations ?? (() => import("./sync-operations.js")),
|
|
38
|
+
),
|
|
39
|
+
};
|
|
40
|
+
return loaders;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function cachedModuleLoader<Module>(load: () => Promise<Module>): () => Promise<Module> {
|
|
44
|
+
let pending: Promise<Module> | undefined;
|
|
45
|
+
return () => {
|
|
46
|
+
if (!pending) {
|
|
47
|
+
pending = load().catch((error) => {
|
|
48
|
+
pending = undefined;
|
|
49
|
+
throw error;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return pending;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { createSyncBackend, type SyncBackendFactory } from "
|
|
4
|
+
import { createSyncBackend, type SyncBackendFactory } from "../backends/backend-factory.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "
|
|
14
|
-
import { inspectLock, isLockGuardHeld, isStaleLock, withLock } from "./lock.js";
|
|
6
|
+
expectedRemoteHead,
|
|
7
|
+
type PublishSnapshotResult,
|
|
8
|
+
type RemoteHead,
|
|
9
|
+
type SyncBackend,
|
|
10
|
+
} from "../backends/sync-backend.js";
|
|
11
|
+
import type { CommandOptions } from "../commands/command-types.js";
|
|
12
|
+
import { loadConfig } from "../settings/config.js";
|
|
13
|
+
import type { AnySyncConfig } from "../settings/settings-types.js";
|
|
15
14
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from "
|
|
15
|
+
sessionDirForApply,
|
|
16
|
+
sessionDirFromContext,
|
|
17
|
+
snapshotOptionsForContext,
|
|
18
|
+
} from "../snapshot/session-paths.js";
|
|
20
19
|
import {
|
|
21
20
|
createSnapshot,
|
|
22
21
|
filterSnapshotForConfigPolicy,
|
|
@@ -26,28 +25,28 @@ import {
|
|
|
26
25
|
sessionSnapshotPathFromAbsolute,
|
|
27
26
|
snapshotIncludesSessions,
|
|
28
27
|
snapshotWithoutSessions,
|
|
29
|
-
} from "
|
|
30
|
-
import { applySnapshot } from "
|
|
31
|
-
import { encodeSnapshot } from "
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
type SyncBackend,
|
|
37
|
-
} from "./sync-backend.js";
|
|
38
|
-
import { createSyncDecision } from "./sync-decision.js";
|
|
28
|
+
} from "../snapshot/snapshot.js";
|
|
29
|
+
import { applySnapshot } from "../snapshot/snapshot-apply.js";
|
|
30
|
+
import { encodeSnapshot } from "../snapshot/snapshot-codec.js";
|
|
31
|
+
import type { Snapshot, SnapshotOptions } from "../snapshot/snapshot-types.js";
|
|
32
|
+
import { stateDir } from "../state/state-directory.js";
|
|
33
|
+
import type { SyncState } from "../state/state-types.js";
|
|
34
|
+
import { readStateForConfig, writeStateForConfig } from "../state/sync-state-store.js";
|
|
39
35
|
import {
|
|
40
36
|
countPreservedRemoteFiles,
|
|
41
|
-
errorMessage,
|
|
42
|
-
formatDiff,
|
|
43
37
|
formatPullSummary,
|
|
44
38
|
formatPushSummary,
|
|
45
39
|
formatRollbackSummary,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
} from "../ui/sync-format.js";
|
|
41
|
+
import {
|
|
42
|
+
readRemoteSnapshot,
|
|
43
|
+
readSnapshotForHead,
|
|
44
|
+
requireCompatibleRemoteSelection,
|
|
45
|
+
} from "./remote-snapshot.js";
|
|
46
|
+
import { throwIfAborted } from "./signals.js";
|
|
47
|
+
import { createSyncDecision } from "./sync-decision.js";
|
|
48
|
+
import { errorMessage } from "./sync-errors.js";
|
|
49
|
+
import { inspectRemoteSelection } from "./sync-policy.js";
|
|
51
50
|
import {
|
|
52
51
|
canPullRemoteSessionsOnFirstSync,
|
|
53
52
|
canPullRemoteSettingsOnFirstSync,
|
|
@@ -61,17 +60,9 @@ import {
|
|
|
61
60
|
snapshotsMatch,
|
|
62
61
|
syncPolicyChanged,
|
|
63
62
|
} from "./sync-state.js";
|
|
64
|
-
import type {
|
|
65
|
-
AnySyncConfig,
|
|
66
|
-
CommandOptions,
|
|
67
|
-
Snapshot,
|
|
68
|
-
SnapshotOptions,
|
|
69
|
-
SyncState,
|
|
70
|
-
} from "./types.js";
|
|
71
63
|
|
|
72
64
|
const STATUS_KEY = "sync";
|
|
73
65
|
const VERSION = 1;
|
|
74
|
-
const DEFAULT_PROFILE = "default";
|
|
75
66
|
const POST_LOCAL_COMMIT_TIMEOUT_MS = 30_000;
|
|
76
67
|
|
|
77
68
|
export class PublicationStatePersistenceError extends Error {
|
|
@@ -109,190 +100,6 @@ interface PushInput {
|
|
|
109
100
|
backend?: SyncBackend;
|
|
110
101
|
}
|
|
111
102
|
|
|
112
|
-
function backendFor(config: AnySyncConfig, factory: SyncBackendFactory) {
|
|
113
|
-
return factory(config);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export async function status(
|
|
117
|
-
ctx: ExtensionCommandContext,
|
|
118
|
-
options: CommandOptions,
|
|
119
|
-
factory: SyncBackendFactory = createSyncBackend,
|
|
120
|
-
) {
|
|
121
|
-
const config = await loadConfig(options.setup);
|
|
122
|
-
throwIfAborted(options.signal);
|
|
123
|
-
ctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);
|
|
124
|
-
const backend = await backendFor(config, factory);
|
|
125
|
-
const local = await createSnapshot(
|
|
126
|
-
config.snapshotIdentity,
|
|
127
|
-
snapshotOptionsForContext(ctx, config),
|
|
128
|
-
);
|
|
129
|
-
throwIfAborted(options.signal);
|
|
130
|
-
const state = await readStateForConfig(config);
|
|
131
|
-
throwIfAborted(options.signal);
|
|
132
|
-
const head = await backend.readHead(options.signal);
|
|
133
|
-
throwIfAborted(options.signal);
|
|
134
|
-
const selectionState = head
|
|
135
|
-
? inspectRemoteSelection(config.include, { selection: head.selection, files: [] })
|
|
136
|
-
: undefined;
|
|
137
|
-
const localChanged = hasLocalChanges(local, state, config);
|
|
138
|
-
|
|
139
|
-
const remoteText = head
|
|
140
|
-
? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}`
|
|
141
|
-
: "remote: empty";
|
|
142
|
-
const remoteChanged = remoteChangedSinceState(head, state, config, (left, right) =>
|
|
143
|
-
backend.sameRevision(left, right),
|
|
144
|
-
);
|
|
145
|
-
const warnings = syncSessionsWarnings(config);
|
|
146
|
-
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
147
|
-
ctx.ui.notify(
|
|
148
|
-
[
|
|
149
|
-
`sync setup: ${config.setupName}`,
|
|
150
|
-
`storage connection: ${config.connectionName}`,
|
|
151
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
152
|
-
`publication safety: ${publicationCapabilityDescription(backend.capability)}`,
|
|
153
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
154
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
155
|
-
remoteText,
|
|
156
|
-
formatRemoteSelectionStatus(selectionState),
|
|
157
|
-
`local files: ${local.files.length}`,
|
|
158
|
-
`local changed since last sync: ${localChanged ? "yes" : "no"}`,
|
|
159
|
-
`remote changed since last sync: ${remoteChanged ? "yes" : "no"}`,
|
|
160
|
-
...warnings,
|
|
161
|
-
].join("\n"),
|
|
162
|
-
localChanged || remoteChanged || selectionState?.kind === "different" || warnings.length > 0
|
|
163
|
-
? "warning"
|
|
164
|
-
: "info",
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export async function diff(
|
|
169
|
-
ctx: ExtensionCommandContext,
|
|
170
|
-
options: CommandOptions,
|
|
171
|
-
factory: SyncBackendFactory = createSyncBackend,
|
|
172
|
-
) {
|
|
173
|
-
const config = await loadConfig(options.setup);
|
|
174
|
-
throwIfAborted(options.signal);
|
|
175
|
-
ctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);
|
|
176
|
-
const backend = await backendFor(config, factory);
|
|
177
|
-
const local = await createSnapshot(
|
|
178
|
-
config.snapshotIdentity,
|
|
179
|
-
snapshotOptionsForContext(ctx, config),
|
|
180
|
-
);
|
|
181
|
-
throwIfAborted(options.signal);
|
|
182
|
-
const { snapshot: remote, selectionState } = await readRemoteSnapshot(
|
|
183
|
-
backend,
|
|
184
|
-
config,
|
|
185
|
-
options.signal,
|
|
186
|
-
{ allowSelectionDifference: true },
|
|
187
|
-
);
|
|
188
|
-
throwIfAborted(options.signal);
|
|
189
|
-
ctx.ui.setStatus(STATUS_KEY, undefined);
|
|
190
|
-
|
|
191
|
-
const warnings = syncSessionsWarnings(config);
|
|
192
|
-
const header = [
|
|
193
|
-
`sync setup: ${config.setupName}`,
|
|
194
|
-
`storage connection: ${config.connectionName}`,
|
|
195
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
196
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
197
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
198
|
-
formatRemoteSelectionStatus(selectionState),
|
|
199
|
-
...warnings,
|
|
200
|
-
].join("\n");
|
|
201
|
-
const level = warnings.length > 0 || selectionState?.kind === "different" ? "warning" : "info";
|
|
202
|
-
if (!remote) {
|
|
203
|
-
ctx.ui.notify(
|
|
204
|
-
`${header}\n\n${formatSnapshotOnlyDiff("Remote is empty. Local push would upload", local)}`,
|
|
205
|
-
level,
|
|
206
|
-
);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
ctx.ui.notify(`${header}\n\n${formatDiff(local, remote)}`, level);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export async function doctor(
|
|
214
|
-
ctx: ExtensionCommandContext,
|
|
215
|
-
options: CommandOptions,
|
|
216
|
-
factory: SyncBackendFactory = createSyncBackend,
|
|
217
|
-
) {
|
|
218
|
-
const messages: string[] = [];
|
|
219
|
-
let level: "info" | "warning" = "info";
|
|
220
|
-
let snapshotOptions: SnapshotOptions = {};
|
|
221
|
-
let profile = DEFAULT_PROFILE;
|
|
222
|
-
let backend: SyncBackend | undefined;
|
|
223
|
-
let backendSummary: string[] = [];
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const config = await loadConfig(options.setup);
|
|
227
|
-
throwIfAborted(options.signal);
|
|
228
|
-
backend = await backendFor(config, factory);
|
|
229
|
-
profile = config.snapshotIdentity;
|
|
230
|
-
snapshotOptions = snapshotOptionsForContext(ctx, config);
|
|
231
|
-
messages.push(
|
|
232
|
-
`config: ok (sync setup ${config.setupName})`,
|
|
233
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
234
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
235
|
-
);
|
|
236
|
-
backendSummary = [
|
|
237
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
238
|
-
`publication safety: ${publicationCapabilityDescription(backend.capability)}`,
|
|
239
|
-
];
|
|
240
|
-
const warnings = syncSessionsWarnings(config);
|
|
241
|
-
if (warnings.length > 0) {
|
|
242
|
-
level = "warning";
|
|
243
|
-
messages.push(...warnings);
|
|
244
|
-
}
|
|
245
|
-
} catch (error) {
|
|
246
|
-
throwIfAborted(options.signal);
|
|
247
|
-
level = "warning";
|
|
248
|
-
messages.push(`config: ${errorMessage(error)}`);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const local = await createSnapshot(profile, snapshotOptions);
|
|
252
|
-
throwIfAborted(options.signal);
|
|
253
|
-
const secrets = scanSnapshot(local);
|
|
254
|
-
if (secrets.length > 0) {
|
|
255
|
-
level = "warning";
|
|
256
|
-
messages.push("secret scan: possible secrets found:");
|
|
257
|
-
messages.push(...secrets.map((secret) => `- ${secret}`));
|
|
258
|
-
} else {
|
|
259
|
-
messages.push(`secret scan: ok (${local.files.length} files checked)`);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const lock = await inspectLock();
|
|
263
|
-
throwIfAborted(options.signal);
|
|
264
|
-
if (lock.status === "valid" && isStaleLock(lock.lock)) {
|
|
265
|
-
level = "warning";
|
|
266
|
-
messages.push(
|
|
267
|
-
`lock: stale (pid ${lock.lock.pid}); run /sync unlock after verifying no sync is running`,
|
|
268
|
-
);
|
|
269
|
-
} else if (lock.status === "valid") {
|
|
270
|
-
messages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);
|
|
271
|
-
} else if (lock.status === "unreadable") {
|
|
272
|
-
level = "warning";
|
|
273
|
-
messages.push(
|
|
274
|
-
"lock: unreadable; use /sync unlock --stale only after verifying no sync is running",
|
|
275
|
-
);
|
|
276
|
-
} else if (await isLockGuardHeld()) {
|
|
277
|
-
throwIfAborted(options.signal);
|
|
278
|
-
level = "warning";
|
|
279
|
-
messages.push("lock: guard active while metadata is missing or still being initialized");
|
|
280
|
-
} else {
|
|
281
|
-
messages.push("lock: free");
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (backend) {
|
|
285
|
-
messages.push(...backendSummary);
|
|
286
|
-
const diagnostics = await backend.diagnose(options.signal);
|
|
287
|
-
throwIfAborted(options.signal);
|
|
288
|
-
for (const diagnostic of diagnostics) {
|
|
289
|
-
messages.push(diagnostic.message);
|
|
290
|
-
if (diagnostic.level !== "info") level = "warning";
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
ctx.ui.notify(messages.join("\n"), level);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
103
|
export async function push(
|
|
297
104
|
ctx: ExtensionCommandContext | ExtensionContext,
|
|
298
105
|
options: CommandOptions,
|
|
@@ -302,7 +109,7 @@ export async function push(
|
|
|
302
109
|
const config = input?.config ?? (await loadConfig(options.setup));
|
|
303
110
|
throwIfAborted(options.signal);
|
|
304
111
|
ctx.ui.setStatus(STATUS_KEY, `pushing ${config.setupName}`);
|
|
305
|
-
const backend = input?.backend ?? (await
|
|
112
|
+
const backend = input?.backend ?? (await factory(config));
|
|
306
113
|
const state = input?.state ?? (await readStateForConfig(config));
|
|
307
114
|
throwIfAborted(options.signal);
|
|
308
115
|
const local =
|
|
@@ -362,11 +169,13 @@ export async function push(
|
|
|
362
169
|
remoteForUpload,
|
|
363
170
|
options.signal,
|
|
364
171
|
);
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
172
|
+
if (!config.skipSecretScan) {
|
|
173
|
+
const secrets = scanSnapshot(local);
|
|
174
|
+
if (secrets.length > 0) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Refusing to push possible secrets:\n${secrets.map((s) => `- ${s}`).join("\n")}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
370
179
|
}
|
|
371
180
|
|
|
372
181
|
if (!(await confirmPush(ctx, options, config, backend, local, upload, head, remoteForUpload))) {
|
|
@@ -446,7 +255,7 @@ export async function pull(
|
|
|
446
255
|
const config = await loadConfig(options.setup);
|
|
447
256
|
throwIfAborted(options.signal);
|
|
448
257
|
ctx.ui.setStatus(STATUS_KEY, `pulling ${config.setupName}`);
|
|
449
|
-
const backend = await
|
|
258
|
+
const backend = await factory(config);
|
|
450
259
|
const state = await readStateForConfig(config);
|
|
451
260
|
throwIfAborted(options.signal);
|
|
452
261
|
const local = await createSnapshot(
|
|
@@ -551,7 +360,7 @@ export async function syncBoth(
|
|
|
551
360
|
) {
|
|
552
361
|
const config = await loadConfig(options.setup);
|
|
553
362
|
throwIfAborted(options.signal);
|
|
554
|
-
const backend = await
|
|
363
|
+
const backend = await factory(config);
|
|
555
364
|
const state = await readStateForConfig(config);
|
|
556
365
|
throwIfAborted(options.signal);
|
|
557
366
|
const local = await createSnapshot(
|
|
@@ -669,52 +478,6 @@ export async function syncBoth(
|
|
|
669
478
|
if (!options.silent) ctx.ui.notify("pi-sync is already up to date.", "info");
|
|
670
479
|
}
|
|
671
480
|
|
|
672
|
-
export async function history(
|
|
673
|
-
ctx: ExtensionCommandContext,
|
|
674
|
-
options: CommandOptions,
|
|
675
|
-
factory: SyncBackendFactory = createSyncBackend,
|
|
676
|
-
) {
|
|
677
|
-
const config = await loadConfig(options.setup);
|
|
678
|
-
throwIfAborted(options.signal);
|
|
679
|
-
const backend = await backendFor(config, factory);
|
|
680
|
-
const snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();
|
|
681
|
-
throwIfAborted(options.signal);
|
|
682
|
-
if (snapshots.length === 0) {
|
|
683
|
-
ctx.ui.notify("No remote pi-sync history found.", "info");
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const currentSnapshot = snapshots[0]?.snapshotId;
|
|
688
|
-
if (ctx.mode === "tui") {
|
|
689
|
-
const labels = snapshots.map(
|
|
690
|
-
(item, index) =>
|
|
691
|
-
`${index + 1}. ${item.createdAt} · ${safeTerminalText(item.machine)} · ${item.snapshotId}${item.snapshotId === currentSnapshot ? " (current)" : ""}${item.syncSessions ? " · sessions" : ""}`,
|
|
692
|
-
);
|
|
693
|
-
const selected = await ctx.ui.select(
|
|
694
|
-
`History for sync setup “${safeTerminalText(config.setupName)}”\n\nChoose a snapshot to preview rollback.`,
|
|
695
|
-
[...labels, "Back"],
|
|
696
|
-
);
|
|
697
|
-
if (!selected || selected === "Back") return;
|
|
698
|
-
throwIfAborted(options.signal);
|
|
699
|
-
const index = labels.indexOf(selected);
|
|
700
|
-
const snapshot = snapshots[index];
|
|
701
|
-
if (!snapshot) return;
|
|
702
|
-
await withLock("rollback", () =>
|
|
703
|
-
rollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {
|
|
704
|
-
backendIdentity: backend.identity,
|
|
705
|
-
setup: config.setupName,
|
|
706
|
-
}),
|
|
707
|
-
);
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
ctx.ui.notify(
|
|
711
|
-
snapshots
|
|
712
|
-
.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`)
|
|
713
|
-
.join("\n"),
|
|
714
|
-
"info",
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
481
|
export async function rollback(
|
|
719
482
|
ctx: ExtensionCommandContext,
|
|
720
483
|
options: CommandOptions,
|
|
@@ -726,7 +489,7 @@ export async function rollback(
|
|
|
726
489
|
|
|
727
490
|
const config = await loadConfig(options.setup);
|
|
728
491
|
throwIfAborted(options.signal);
|
|
729
|
-
const backend = await
|
|
492
|
+
const backend = await factory(config);
|
|
730
493
|
if (
|
|
731
494
|
expectedSelection &&
|
|
732
495
|
(backend.identity !== expectedSelection.backendIdentity ||
|
|
@@ -835,30 +598,6 @@ function protectedSessionPaths(ctx: ExtensionCommandContext | ExtensionContext)
|
|
|
835
598
|
return snapshotPath ? new Set([snapshotPath]) : new Set<string>();
|
|
836
599
|
}
|
|
837
600
|
|
|
838
|
-
function snapshotOptionsForContext(
|
|
839
|
-
ctx: ExtensionCommandContext | ExtensionContext,
|
|
840
|
-
config: AnySyncConfig,
|
|
841
|
-
): SnapshotOptions {
|
|
842
|
-
return {
|
|
843
|
-
include: config.include,
|
|
844
|
-
sessionDir: sessionDirFromContext(ctx),
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
function sessionDirFromContext(ctx: ExtensionCommandContext | ExtensionContext) {
|
|
849
|
-
const manager = ctx.sessionManager as typeof ctx.sessionManager & {
|
|
850
|
-
usesDefaultSessionDir?: () => boolean;
|
|
851
|
-
};
|
|
852
|
-
const usesDefaultSessionDir = manager.usesDefaultSessionDir;
|
|
853
|
-
if (typeof usesDefaultSessionDir === "function" && usesDefaultSessionDir.call(manager)) {
|
|
854
|
-
return undefined;
|
|
855
|
-
}
|
|
856
|
-
const getSessionDir = manager.getSessionDir;
|
|
857
|
-
return typeof getSessionDir === "function"
|
|
858
|
-
? (getSessionDir.call(manager) as string | undefined)
|
|
859
|
-
: undefined;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
601
|
async function maybeReload(ctx: ExtensionCommandContext | ExtensionContext, signal?: AbortSignal) {
|
|
863
602
|
if (signal?.aborted || !("reload" in ctx)) return;
|
|
864
603
|
if (
|
|
@@ -913,27 +652,6 @@ async function snapshotForUpload(
|
|
|
913
652
|
return mergeRemotePreservedFiles(local, snapshot, config);
|
|
914
653
|
}
|
|
915
654
|
|
|
916
|
-
async function readRemoteSnapshot(
|
|
917
|
-
backend: SyncBackend,
|
|
918
|
-
config: AnySyncConfig,
|
|
919
|
-
signal?: AbortSignal,
|
|
920
|
-
options: { allowSelectionDifference?: boolean } = {},
|
|
921
|
-
) {
|
|
922
|
-
const head = await backend.readHead(signal);
|
|
923
|
-
if (!head) return { head: undefined, snapshot: undefined, selectionState: undefined };
|
|
924
|
-
const snapshot = await readSnapshotForHead(backend, head, signal);
|
|
925
|
-
const selectionState = inspectRemoteSelection(config.include, snapshot);
|
|
926
|
-
if (!options.allowSelectionDifference && selectionState.kind === "different") {
|
|
927
|
-
const configIdentity = syncConfigReviewFingerprint(config);
|
|
928
|
-
throw remoteSelectionMismatch(config, selectionState.include, configIdentity);
|
|
929
|
-
}
|
|
930
|
-
return {
|
|
931
|
-
head,
|
|
932
|
-
snapshot: filterSnapshotForConfigPolicy(snapshot, config),
|
|
933
|
-
selectionState,
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
|
-
|
|
937
655
|
async function confirmPush(
|
|
938
656
|
ctx: ExtensionCommandContext | ExtensionContext,
|
|
939
657
|
options: CommandOptions,
|
|
@@ -965,13 +683,6 @@ async function confirmPush(
|
|
|
965
683
|
return false;
|
|
966
684
|
}
|
|
967
685
|
|
|
968
|
-
function throwIfAborted(signal?: AbortSignal) {
|
|
969
|
-
if (!signal?.aborted) return;
|
|
970
|
-
throw signal.reason instanceof Error
|
|
971
|
-
? signal.reason
|
|
972
|
-
: new DOMException("The operation was aborted", "AbortError");
|
|
973
|
-
}
|
|
974
|
-
|
|
975
686
|
function sameRemoteHead(
|
|
976
687
|
backend: SyncBackend,
|
|
977
688
|
left: RemoteHead | undefined,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// First-use operation surface for the cached loader; implementations stay lazy.
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
backupLocal,
|
|
5
|
+
PublicationStatePersistenceError,
|
|
6
|
+
pull,
|
|
7
|
+
push,
|
|
8
|
+
RollbackPublicationError,
|
|
9
|
+
rollback,
|
|
10
|
+
syncBoth,
|
|
11
|
+
} from "./sync-mutations.js";
|
|
12
|
+
export { diff, doctor, history, status } from "./sync-queries.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { isDeniedPath, toPosix } from "
|
|
3
|
-
import type { Snapshot, SnapshotSelection } from "
|
|
2
|
+
import { isDeniedPath, toPosix } from "../paths.js";
|
|
3
|
+
import type { Snapshot, SnapshotSelection } from "../snapshot/snapshot-types.js";
|
|
4
4
|
|
|
5
5
|
export const BUILT_IN_SYNC_ROOTS = [
|
|
6
6
|
"settings.json",
|