@narumitw/pi-sync 0.49.15 → 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 +49 -16
- 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-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
- package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
- package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-AXXS2BPA.ts} +9 -9
- package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
- package/dist/chunks/{chunk-5T442OP3.ts → chunk-C7XY5NF5.ts} +210 -373
- 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-WSOBYHIZ.ts → chunk-GWMHAQG4.ts} +4 -4
- package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
- package/dist/chunks/{chunk-5LZALPCD.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-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -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-HVUSHMVL.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-GLQLN5GV.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-44LPGQTI.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-ARN2672F.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-RKEHALNQ.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-552LXHE4.ts → s3-backend-3P33LQHU.ts} +96 -18
- package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
- package/dist/chunks/{setup-switch-5YDG5YGJ.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-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
- package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
- package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-ONJ27QRL.ts} +374 -294
- package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
- package/dist/chunks/{sync-state-SRN6YRBK.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 +30 -6
- package/package.json +1 -1
- 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} +39 -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} +34 -325
- 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 -286
- 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} +17 -13
- 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-44LPGQTI.ts.map +0 -7
- package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
- package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
- package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
- package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
- package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
- package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
- package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
- package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
- package/dist/chunks/chunk-E4COSV32.ts +0 -82
- package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
- package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
- package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
- package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
- package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
- package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
- package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
- package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
- package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
- package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
- package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
- package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
- package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
- package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
- package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
- package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
- package/src/config.ts +0 -923
- 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-LWPYJAD5.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
- /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
- /package/dist/chunks/{sync-state-SRN6YRBK.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
|
@@ -1,33 +1,8 @@
|
|
|
1
1
|
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readSnapshotForHead,
|
|
7
|
-
requireCompatibleRemoteSelection
|
|
8
|
-
} from "./chunk-5LZALPCD.ts";
|
|
9
|
-
import {
|
|
10
|
-
applySnapshotTransaction,
|
|
11
|
-
recoverPendingSnapshotTransactions
|
|
12
|
-
} from "./chunk-X7SQ2EQM.ts";
|
|
13
|
-
import {
|
|
14
|
-
inspectLock,
|
|
15
|
-
isLockGuardHeld,
|
|
16
|
-
isStaleLock,
|
|
17
|
-
withLock
|
|
18
|
-
} from "./chunk-WSOBYHIZ.ts";
|
|
19
|
-
import {
|
|
20
|
-
SyncDecisionRequiredError,
|
|
21
|
-
countPreservedRemoteFiles,
|
|
22
|
-
errorMessage,
|
|
23
|
-
formatDiff,
|
|
24
|
-
formatPullSummary,
|
|
25
|
-
formatPushSummary,
|
|
26
|
-
formatRollbackSummary,
|
|
27
|
-
formatSnapshotOnlyDiff,
|
|
28
|
-
publicationCapabilityDescription,
|
|
29
|
-
safeTerminalText
|
|
30
|
-
} from "./chunk-C7LXZ3UH.ts";
|
|
4
|
+
inspectSync
|
|
5
|
+
} from "./chunk-XBX4HBLG.ts";
|
|
31
6
|
import {
|
|
32
7
|
canPullRemoteSessionsOnFirstSync,
|
|
33
8
|
canPullRemoteSettingsOnFirstSync,
|
|
@@ -40,7 +15,56 @@ import {
|
|
|
40
15
|
snapshotHashesMatchState,
|
|
41
16
|
snapshotsMatch,
|
|
42
17
|
syncPolicyChanged
|
|
43
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-AUSDLD6F.ts";
|
|
19
|
+
import {
|
|
20
|
+
applySnapshotTransaction,
|
|
21
|
+
recoverPendingSnapshotTransactions
|
|
22
|
+
} from "./chunk-AXXS2BPA.ts";
|
|
23
|
+
import {
|
|
24
|
+
inspectLock,
|
|
25
|
+
isLockGuardHeld,
|
|
26
|
+
isStaleLock,
|
|
27
|
+
withLock
|
|
28
|
+
} from "./chunk-GWMHAQG4.ts";
|
|
29
|
+
import {
|
|
30
|
+
throwIfAborted
|
|
31
|
+
} from "./chunk-NJFUIVYL.ts";
|
|
32
|
+
import {
|
|
33
|
+
readStateForConfig,
|
|
34
|
+
writeStateForConfig
|
|
35
|
+
} from "./chunk-JSYMGJQQ.ts";
|
|
36
|
+
import {
|
|
37
|
+
encodeSnapshot
|
|
38
|
+
} from "./chunk-Q2TUM5X6.ts";
|
|
39
|
+
import {
|
|
40
|
+
stateDir
|
|
41
|
+
} from "./chunk-ZI5MXMEX.ts";
|
|
42
|
+
import {
|
|
43
|
+
expectedRemoteHead
|
|
44
|
+
} from "./chunk-D5X27LCA.ts";
|
|
45
|
+
import {
|
|
46
|
+
formatRemoteSelectionStatus,
|
|
47
|
+
readRemoteSnapshot,
|
|
48
|
+
readSnapshotForHead,
|
|
49
|
+
requireCompatibleRemoteSelection
|
|
50
|
+
} from "./chunk-HUDQATCL.ts";
|
|
51
|
+
import {
|
|
52
|
+
createSyncBackend
|
|
53
|
+
} from "./chunk-L7TBO32M.ts";
|
|
54
|
+
import {
|
|
55
|
+
safeTerminalText
|
|
56
|
+
} from "./chunk-LTBWGSBV.ts";
|
|
57
|
+
import {
|
|
58
|
+
loadConfig,
|
|
59
|
+
syncConfigReviewIdentity,
|
|
60
|
+
syncSessionsWarnings
|
|
61
|
+
} from "./chunk-C7XY5NF5.ts";
|
|
62
|
+
import "./chunk-6LP3MCR2.ts";
|
|
63
|
+
import "./chunk-TEN2ZBJV.ts";
|
|
64
|
+
import {
|
|
65
|
+
SyncDecisionRequiredError,
|
|
66
|
+
errorMessage
|
|
67
|
+
} from "./chunk-2B2ELUF5.ts";
|
|
44
68
|
import {
|
|
45
69
|
createSnapshot,
|
|
46
70
|
filterSnapshotForConfigPolicy,
|
|
@@ -50,30 +74,19 @@ import {
|
|
|
50
74
|
regenerateSnapshotIdentity,
|
|
51
75
|
scanSnapshot,
|
|
52
76
|
sessionSnapshotPathFromAbsolute,
|
|
53
|
-
sessionStorageRoot,
|
|
54
77
|
snapshotIncludesSessions,
|
|
55
78
|
snapshotTarget,
|
|
56
79
|
snapshotWithoutSessions
|
|
57
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-OEX4ABY6.ts";
|
|
81
|
+
import {
|
|
82
|
+
sessionStorageRoot
|
|
83
|
+
} from "./chunk-THMF4BVL.ts";
|
|
58
84
|
import {
|
|
59
85
|
agentDir,
|
|
60
|
-
loadConfig,
|
|
61
|
-
readStateForConfig,
|
|
62
86
|
sessionDirForApply,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
writeStateForConfig
|
|
67
|
-
} from "./chunk-5T442OP3.ts";
|
|
68
|
-
import {
|
|
69
|
-
encodeSnapshot
|
|
70
|
-
} from "./chunk-HGV24P4T.ts";
|
|
71
|
-
import {
|
|
72
|
-
stateDir
|
|
73
|
-
} from "./chunk-F5QL2GPY.ts";
|
|
74
|
-
import {
|
|
75
|
-
expectedRemoteHead
|
|
76
|
-
} from "./chunk-5MQ76BK5.ts";
|
|
87
|
+
sessionDirFromContext,
|
|
88
|
+
snapshotOptionsForContext
|
|
89
|
+
} from "./chunk-T3HH3UEJ.ts";
|
|
77
90
|
import {
|
|
78
91
|
assertWithinRoot,
|
|
79
92
|
includeFromSelectionConfig,
|
|
@@ -81,16 +94,15 @@ import {
|
|
|
81
94
|
isDeniedPath,
|
|
82
95
|
isPathInside,
|
|
83
96
|
parentPaths,
|
|
84
|
-
remoteSelectionMismatch,
|
|
85
97
|
safeJoin,
|
|
86
98
|
toPosix
|
|
87
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-JAAKLL6M.ts";
|
|
88
100
|
|
|
89
|
-
// src/sync-
|
|
101
|
+
// src/sync/sync-mutations.ts
|
|
90
102
|
import fs2 from "node:fs/promises";
|
|
91
103
|
import path2 from "node:path";
|
|
92
104
|
|
|
93
|
-
// src/snapshot-apply.ts
|
|
105
|
+
// src/snapshot/snapshot-apply.ts
|
|
94
106
|
import { createHash } from "node:crypto";
|
|
95
107
|
import fs from "node:fs/promises";
|
|
96
108
|
import path from "node:path";
|
|
@@ -297,7 +309,125 @@ async function assertNoSymlinkParents(root, target) {
|
|
|
297
309
|
}
|
|
298
310
|
}
|
|
299
311
|
|
|
300
|
-
// src/sync-
|
|
312
|
+
// src/ui/sync-format.ts
|
|
313
|
+
function formatDiff(local, remote) {
|
|
314
|
+
const localMap = fileHashMap(local);
|
|
315
|
+
const remoteMap = fileHashMap(remote);
|
|
316
|
+
const allPaths = [.../* @__PURE__ */ new Set([...Object.keys(localMap), ...Object.keys(remoteMap)])].sort();
|
|
317
|
+
const lines = [
|
|
318
|
+
`local: ${local.files.length} files`,
|
|
319
|
+
`remote: ${remote.id} (${remote.files.length} files)`,
|
|
320
|
+
""
|
|
321
|
+
];
|
|
322
|
+
let changed = 0;
|
|
323
|
+
for (const filePath of allPaths) {
|
|
324
|
+
if (!localMap[filePath]) {
|
|
325
|
+
lines.push(`Remote only: ${filePath}`);
|
|
326
|
+
changed += 1;
|
|
327
|
+
} else if (!remoteMap[filePath]) {
|
|
328
|
+
lines.push(`Local only: ${filePath}`);
|
|
329
|
+
changed += 1;
|
|
330
|
+
} else if (localMap[filePath] !== remoteMap[filePath]) {
|
|
331
|
+
lines.push(`Different: ${filePath}`);
|
|
332
|
+
changed += 1;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (changed === 0) lines.push("No file differences.");
|
|
336
|
+
return lines.join("\n");
|
|
337
|
+
}
|
|
338
|
+
function formatSnapshotOnlyDiff(title, snapshot) {
|
|
339
|
+
return [`${title}: ${snapshot.id}`, ...snapshot.files.map((file) => `Add: ${file.path}`)].join(
|
|
340
|
+
"\n"
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
function formatPushSummary(config, destination, upload, head, preservedRemoteFileCount = 0, remote) {
|
|
344
|
+
return [
|
|
345
|
+
`Sync setup: ${safeTerminalText(config.setupName)}`,
|
|
346
|
+
`Storage location: ${safeTerminalText(destination)}`,
|
|
347
|
+
`Upload ${upload.files.length} files from ${safeTerminalText(agentDir())}.`,
|
|
348
|
+
`Sessions: ${upload.syncSessions ? "included \u2014 may contain private conversations" : "not included"}`,
|
|
349
|
+
head ? `Remote latest: ${head.snapshotId}` : "Remote latest: empty",
|
|
350
|
+
"Publication effect: the backend's active head will reference the new immutable snapshot.",
|
|
351
|
+
...remote && inspectRemoteSelection(config.include, remote).kind === "different" ? [
|
|
352
|
+
"Included-content policy effect: replace the differing remote selection with this setup's local selection."
|
|
353
|
+
] : [],
|
|
354
|
+
formatPublicationPreview(remote, upload),
|
|
355
|
+
preservedRemoteFileCount > 0 ? `Possible secrets in locally managed files were scanned before this prompt; ${preservedRemoteFileCount} preserved remote file(s) were not rescanned.` : "Possible secrets were scanned before this prompt."
|
|
356
|
+
].join("\n");
|
|
357
|
+
}
|
|
358
|
+
function formatApplyPreview(local, remote) {
|
|
359
|
+
return formatDirectionalChanges(local, remote, {
|
|
360
|
+
add: "Add locally",
|
|
361
|
+
update: "Update locally",
|
|
362
|
+
remove: "Remove locally"
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function formatPullSummary(config, destination, local, remote, protectedSessionCount) {
|
|
366
|
+
return [
|
|
367
|
+
`Sync setup: ${safeTerminalText(config.setupName)}`,
|
|
368
|
+
`Storage location: ${safeTerminalText(destination)}`,
|
|
369
|
+
`Snapshot: ${safeTerminalText(remote.id)}`,
|
|
370
|
+
`Sessions: ${remote.syncSessions ? "included \u2014 may contain private conversations" : "not included"}`,
|
|
371
|
+
`Protected live sessions: ${protectedSessionCount || "none"}`,
|
|
372
|
+
formatApplyPreview(local, remote),
|
|
373
|
+
"A local backup is created before these writes/deletes. The remote active snapshot is unchanged."
|
|
374
|
+
].join("\n");
|
|
375
|
+
}
|
|
376
|
+
function formatRollbackSummary(config, destination, local, remote, requestedSnapshot, protectedSessionCount) {
|
|
377
|
+
return [
|
|
378
|
+
`Sync setup: ${safeTerminalText(config.setupName)}`,
|
|
379
|
+
`Storage location: ${safeTerminalText(destination)}`,
|
|
380
|
+
`Snapshot: ${safeTerminalText(requestedSnapshot)}`,
|
|
381
|
+
`Sessions: ${remote.syncSessions ? "included \u2014 may contain private conversations" : "not included"}`,
|
|
382
|
+
`Protected live sessions: ${protectedSessionCount || "none"}`,
|
|
383
|
+
formatApplyPreview(local, remote),
|
|
384
|
+
"A local backup is created before applying; the backend's active head will change."
|
|
385
|
+
].join("\n");
|
|
386
|
+
}
|
|
387
|
+
function formatPublicationPreview(remote, upload) {
|
|
388
|
+
if (!remote) {
|
|
389
|
+
return ["Remote is empty.", ...upload.files.map((file) => `Add remotely: ${file.path}`)].join(
|
|
390
|
+
"\n"
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return formatDirectionalChanges(remote, upload, {
|
|
394
|
+
add: "Add remotely",
|
|
395
|
+
update: "Update remotely",
|
|
396
|
+
remove: "Remove remotely"
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function formatDirectionalChanges(before, after, labels) {
|
|
400
|
+
const beforeMap = fileHashMap(before);
|
|
401
|
+
const afterMap = fileHashMap(after);
|
|
402
|
+
const paths = [.../* @__PURE__ */ new Set([...Object.keys(beforeMap), ...Object.keys(afterMap)])].sort();
|
|
403
|
+
const lines = [];
|
|
404
|
+
for (const filePath of paths) {
|
|
405
|
+
if (!beforeMap[filePath]) lines.push(`${labels.add}: ${filePath}`);
|
|
406
|
+
else if (!afterMap[filePath]) lines.push(`${labels.remove}: ${filePath}`);
|
|
407
|
+
else if (beforeMap[filePath] !== afterMap[filePath])
|
|
408
|
+
lines.push(`${labels.update}: ${filePath}`);
|
|
409
|
+
}
|
|
410
|
+
if (lines.length === 0) lines.push("No file changes.");
|
|
411
|
+
return lines.join("\n");
|
|
412
|
+
}
|
|
413
|
+
function countPreservedRemoteFiles(local, upload) {
|
|
414
|
+
const localPaths = new Set(local.files.map((file) => file.path));
|
|
415
|
+
return upload.files.filter((file) => !localPaths.has(file.path)).length;
|
|
416
|
+
}
|
|
417
|
+
function publicationCapabilityDescription(capability) {
|
|
418
|
+
switch (capability) {
|
|
419
|
+
case "lease-protected":
|
|
420
|
+
return "lease-protected (exact expected-ref update)";
|
|
421
|
+
case "atomic-conditional":
|
|
422
|
+
return "atomic-conditional (verified atomic precondition)";
|
|
423
|
+
case "conditional-required":
|
|
424
|
+
return "conditional-required (read-only until atomic preconditions are verified)";
|
|
425
|
+
case "read-check-write-verify":
|
|
426
|
+
return "read-check-write-verify (visible races rejected; simultaneous unseen races remain possible)";
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/sync/sync-decision.ts
|
|
301
431
|
function createSyncDecision(options) {
|
|
302
432
|
const { config, state, local, remote, kind } = options;
|
|
303
433
|
const policyChanged = Boolean(state.lastAppliedSnapshot) && syncPolicyChanged(state, config);
|
|
@@ -344,10 +474,9 @@ function safeList(values) {
|
|
|
344
474
|
return values.length > 0 ? values.map(safeTerminalText).join(", ") : "none";
|
|
345
475
|
}
|
|
346
476
|
|
|
347
|
-
// src/sync-
|
|
477
|
+
// src/sync/sync-mutations.ts
|
|
348
478
|
var STATUS_KEY = "sync";
|
|
349
479
|
var VERSION = 1;
|
|
350
|
-
var DEFAULT_PROFILE = "default";
|
|
351
480
|
var POST_LOCAL_COMMIT_TIMEOUT_MS = 3e4;
|
|
352
481
|
var PublicationStatePersistenceError = class extends Error {
|
|
353
482
|
head;
|
|
@@ -373,173 +502,11 @@ var RollbackPublicationError = class extends Error {
|
|
|
373
502
|
this.backupPath = backupPath;
|
|
374
503
|
}
|
|
375
504
|
};
|
|
376
|
-
function backendFor(config, factory) {
|
|
377
|
-
return factory(config);
|
|
378
|
-
}
|
|
379
|
-
async function status(ctx, options, factory = createSyncBackend) {
|
|
380
|
-
const config = await loadConfig(options.setup);
|
|
381
|
-
throwIfAborted(options.signal);
|
|
382
|
-
ctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);
|
|
383
|
-
const backend = await backendFor(config, factory);
|
|
384
|
-
const local = await createSnapshot(
|
|
385
|
-
config.snapshotIdentity,
|
|
386
|
-
snapshotOptionsForContext(ctx, config)
|
|
387
|
-
);
|
|
388
|
-
throwIfAborted(options.signal);
|
|
389
|
-
const state = await readStateForConfig(config);
|
|
390
|
-
throwIfAborted(options.signal);
|
|
391
|
-
const head = await backend.readHead(options.signal);
|
|
392
|
-
throwIfAborted(options.signal);
|
|
393
|
-
const selectionState = head ? inspectRemoteSelection(config.include, { selection: head.selection, files: [] }) : void 0;
|
|
394
|
-
const localChanged = hasLocalChanges(local, state, config);
|
|
395
|
-
const remoteText = head ? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}` : "remote: empty";
|
|
396
|
-
const remoteChanged = remoteChangedSinceState(
|
|
397
|
-
head,
|
|
398
|
-
state,
|
|
399
|
-
config,
|
|
400
|
-
(left, right) => backend.sameRevision(left, right)
|
|
401
|
-
);
|
|
402
|
-
const warnings = syncSessionsWarnings(config);
|
|
403
|
-
ctx.ui.setStatus(STATUS_KEY, void 0);
|
|
404
|
-
ctx.ui.notify(
|
|
405
|
-
[
|
|
406
|
-
`sync setup: ${config.setupName}`,
|
|
407
|
-
`storage connection: ${config.connectionName}`,
|
|
408
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
409
|
-
`publication safety: ${publicationCapabilityDescription(backend.capability)}`,
|
|
410
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
411
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
412
|
-
remoteText,
|
|
413
|
-
formatRemoteSelectionStatus(selectionState),
|
|
414
|
-
`local files: ${local.files.length}`,
|
|
415
|
-
`local changed since last sync: ${localChanged ? "yes" : "no"}`,
|
|
416
|
-
`remote changed since last sync: ${remoteChanged ? "yes" : "no"}`,
|
|
417
|
-
...warnings
|
|
418
|
-
].join("\n"),
|
|
419
|
-
localChanged || remoteChanged || selectionState?.kind === "different" || warnings.length > 0 ? "warning" : "info"
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
async function diff(ctx, options, factory = createSyncBackend) {
|
|
423
|
-
const config = await loadConfig(options.setup);
|
|
424
|
-
throwIfAborted(options.signal);
|
|
425
|
-
ctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);
|
|
426
|
-
const backend = await backendFor(config, factory);
|
|
427
|
-
const local = await createSnapshot(
|
|
428
|
-
config.snapshotIdentity,
|
|
429
|
-
snapshotOptionsForContext(ctx, config)
|
|
430
|
-
);
|
|
431
|
-
throwIfAborted(options.signal);
|
|
432
|
-
const { snapshot: remote, selectionState } = await readRemoteSnapshot(
|
|
433
|
-
backend,
|
|
434
|
-
config,
|
|
435
|
-
options.signal,
|
|
436
|
-
{ allowSelectionDifference: true }
|
|
437
|
-
);
|
|
438
|
-
throwIfAborted(options.signal);
|
|
439
|
-
ctx.ui.setStatus(STATUS_KEY, void 0);
|
|
440
|
-
const warnings = syncSessionsWarnings(config);
|
|
441
|
-
const header = [
|
|
442
|
-
`sync setup: ${config.setupName}`,
|
|
443
|
-
`storage connection: ${config.connectionName}`,
|
|
444
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
445
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
446
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
447
|
-
formatRemoteSelectionStatus(selectionState),
|
|
448
|
-
...warnings
|
|
449
|
-
].join("\n");
|
|
450
|
-
const level = warnings.length > 0 || selectionState?.kind === "different" ? "warning" : "info";
|
|
451
|
-
if (!remote) {
|
|
452
|
-
ctx.ui.notify(
|
|
453
|
-
`${header}
|
|
454
|
-
|
|
455
|
-
${formatSnapshotOnlyDiff("Remote is empty. Local push would upload", local)}`,
|
|
456
|
-
level
|
|
457
|
-
);
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
ctx.ui.notify(`${header}
|
|
461
|
-
|
|
462
|
-
${formatDiff(local, remote)}`, level);
|
|
463
|
-
}
|
|
464
|
-
async function doctor(ctx, options, factory = createSyncBackend) {
|
|
465
|
-
const messages = [];
|
|
466
|
-
let level = "info";
|
|
467
|
-
let snapshotOptions = {};
|
|
468
|
-
let profile = DEFAULT_PROFILE;
|
|
469
|
-
let backend;
|
|
470
|
-
let backendSummary = [];
|
|
471
|
-
try {
|
|
472
|
-
const config = await loadConfig(options.setup);
|
|
473
|
-
throwIfAborted(options.signal);
|
|
474
|
-
backend = await backendFor(config, factory);
|
|
475
|
-
profile = config.snapshotIdentity;
|
|
476
|
-
snapshotOptions = snapshotOptionsForContext(ctx, config);
|
|
477
|
-
messages.push(
|
|
478
|
-
`config: ok (sync setup ${config.setupName})`,
|
|
479
|
-
`included content: ${config.include.join(", ") || "none"}`,
|
|
480
|
-
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`
|
|
481
|
-
);
|
|
482
|
-
backendSummary = [
|
|
483
|
-
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
484
|
-
`publication safety: ${publicationCapabilityDescription(backend.capability)}`
|
|
485
|
-
];
|
|
486
|
-
const warnings = syncSessionsWarnings(config);
|
|
487
|
-
if (warnings.length > 0) {
|
|
488
|
-
level = "warning";
|
|
489
|
-
messages.push(...warnings);
|
|
490
|
-
}
|
|
491
|
-
} catch (error) {
|
|
492
|
-
throwIfAborted(options.signal);
|
|
493
|
-
level = "warning";
|
|
494
|
-
messages.push(`config: ${errorMessage(error)}`);
|
|
495
|
-
}
|
|
496
|
-
const local = await createSnapshot(profile, snapshotOptions);
|
|
497
|
-
throwIfAborted(options.signal);
|
|
498
|
-
const secrets = scanSnapshot(local);
|
|
499
|
-
if (secrets.length > 0) {
|
|
500
|
-
level = "warning";
|
|
501
|
-
messages.push("secret scan: possible secrets found:");
|
|
502
|
-
messages.push(...secrets.map((secret) => `- ${secret}`));
|
|
503
|
-
} else {
|
|
504
|
-
messages.push(`secret scan: ok (${local.files.length} files checked)`);
|
|
505
|
-
}
|
|
506
|
-
const lock = await inspectLock();
|
|
507
|
-
throwIfAborted(options.signal);
|
|
508
|
-
if (lock.status === "valid" && isStaleLock(lock.lock)) {
|
|
509
|
-
level = "warning";
|
|
510
|
-
messages.push(
|
|
511
|
-
`lock: stale (pid ${lock.lock.pid}); run /sync unlock after verifying no sync is running`
|
|
512
|
-
);
|
|
513
|
-
} else if (lock.status === "valid") {
|
|
514
|
-
messages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);
|
|
515
|
-
} else if (lock.status === "unreadable") {
|
|
516
|
-
level = "warning";
|
|
517
|
-
messages.push(
|
|
518
|
-
"lock: unreadable; use /sync unlock --stale only after verifying no sync is running"
|
|
519
|
-
);
|
|
520
|
-
} else if (await isLockGuardHeld()) {
|
|
521
|
-
throwIfAborted(options.signal);
|
|
522
|
-
level = "warning";
|
|
523
|
-
messages.push("lock: guard active while metadata is missing or still being initialized");
|
|
524
|
-
} else {
|
|
525
|
-
messages.push("lock: free");
|
|
526
|
-
}
|
|
527
|
-
if (backend) {
|
|
528
|
-
messages.push(...backendSummary);
|
|
529
|
-
const diagnostics = await backend.diagnose(options.signal);
|
|
530
|
-
throwIfAborted(options.signal);
|
|
531
|
-
for (const diagnostic of diagnostics) {
|
|
532
|
-
messages.push(diagnostic.message);
|
|
533
|
-
if (diagnostic.level !== "info") level = "warning";
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
ctx.ui.notify(messages.join("\n"), level);
|
|
537
|
-
}
|
|
538
505
|
async function push(ctx, options, input, factory = createSyncBackend) {
|
|
539
506
|
const config = input?.config ?? await loadConfig(options.setup);
|
|
540
507
|
throwIfAborted(options.signal);
|
|
541
508
|
ctx.ui.setStatus(STATUS_KEY, `pushing ${config.setupName}`);
|
|
542
|
-
const backend = input?.backend ?? await
|
|
509
|
+
const backend = input?.backend ?? await factory(config);
|
|
543
510
|
const state = input?.state ?? await readStateForConfig(config);
|
|
544
511
|
throwIfAborted(options.signal);
|
|
545
512
|
const local = input?.local ?? await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config));
|
|
@@ -659,7 +626,7 @@ async function pull(ctx, options, factory = createSyncBackend) {
|
|
|
659
626
|
const config = await loadConfig(options.setup);
|
|
660
627
|
throwIfAborted(options.signal);
|
|
661
628
|
ctx.ui.setStatus(STATUS_KEY, `pulling ${config.setupName}`);
|
|
662
|
-
const backend = await
|
|
629
|
+
const backend = await factory(config);
|
|
663
630
|
const state = await readStateForConfig(config);
|
|
664
631
|
throwIfAborted(options.signal);
|
|
665
632
|
const local = await createSnapshot(
|
|
@@ -748,7 +715,7 @@ async function pull(ctx, options, factory = createSyncBackend) {
|
|
|
748
715
|
async function syncBoth(ctx, options, factory = createSyncBackend) {
|
|
749
716
|
const config = await loadConfig(options.setup);
|
|
750
717
|
throwIfAborted(options.signal);
|
|
751
|
-
const backend = await
|
|
718
|
+
const backend = await factory(config);
|
|
752
719
|
const state = await readStateForConfig(config);
|
|
753
720
|
throwIfAborted(options.signal);
|
|
754
721
|
const local = await createSnapshot(
|
|
@@ -861,52 +828,12 @@ async function syncBoth(ctx, options, factory = createSyncBackend) {
|
|
|
861
828
|
}
|
|
862
829
|
if (!options.silent) ctx.ui.notify("pi-sync is already up to date.", "info");
|
|
863
830
|
}
|
|
864
|
-
async function history(ctx, options, factory = createSyncBackend) {
|
|
865
|
-
const config = await loadConfig(options.setup);
|
|
866
|
-
throwIfAborted(options.signal);
|
|
867
|
-
const backend = await backendFor(config, factory);
|
|
868
|
-
const snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();
|
|
869
|
-
throwIfAborted(options.signal);
|
|
870
|
-
if (snapshots.length === 0) {
|
|
871
|
-
ctx.ui.notify("No remote pi-sync history found.", "info");
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
const currentSnapshot = snapshots[0]?.snapshotId;
|
|
875
|
-
if (ctx.mode === "tui") {
|
|
876
|
-
const labels = snapshots.map(
|
|
877
|
-
(item, index2) => `${index2 + 1}. ${item.createdAt} \xB7 ${safeTerminalText(item.machine)} \xB7 ${item.snapshotId}${item.snapshotId === currentSnapshot ? " (current)" : ""}${item.syncSessions ? " \xB7 sessions" : ""}`
|
|
878
|
-
);
|
|
879
|
-
const selected = await ctx.ui.select(
|
|
880
|
-
`History for sync setup \u201C${safeTerminalText(config.setupName)}\u201D
|
|
881
|
-
|
|
882
|
-
Choose a snapshot to preview rollback.`,
|
|
883
|
-
[...labels, "Back"]
|
|
884
|
-
);
|
|
885
|
-
if (!selected || selected === "Back") return;
|
|
886
|
-
throwIfAborted(options.signal);
|
|
887
|
-
const index = labels.indexOf(selected);
|
|
888
|
-
const snapshot = snapshots[index];
|
|
889
|
-
if (!snapshot) return;
|
|
890
|
-
await withLock(
|
|
891
|
-
"rollback",
|
|
892
|
-
() => rollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {
|
|
893
|
-
backendIdentity: backend.identity,
|
|
894
|
-
setup: config.setupName
|
|
895
|
-
})
|
|
896
|
-
);
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
ctx.ui.notify(
|
|
900
|
-
snapshots.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`).join("\n"),
|
|
901
|
-
"info"
|
|
902
|
-
);
|
|
903
|
-
}
|
|
904
831
|
async function rollback(ctx, options, factory = createSyncBackend, expectedSelection) {
|
|
905
832
|
const target = options.args[0];
|
|
906
833
|
if (!target) throw new Error("Usage: /sync rollback <snapshot-id> [--yes]");
|
|
907
834
|
const config = await loadConfig(options.setup);
|
|
908
835
|
throwIfAborted(options.signal);
|
|
909
|
-
const backend = await
|
|
836
|
+
const backend = await factory(config);
|
|
910
837
|
if (expectedSelection && (backend.identity !== expectedSelection.backendIdentity || config.setupName !== expectedSelection.setup)) {
|
|
911
838
|
throw new Error(
|
|
912
839
|
"Sync setup or storage location changed while history was open; reopen history and retry."
|
|
@@ -998,21 +925,6 @@ function protectedSessionPaths(ctx) {
|
|
|
998
925
|
const snapshotPath = sessionFile ? sessionSnapshotPathFromAbsolute(sessionFile, sessionDirFromContext(ctx)) : void 0;
|
|
999
926
|
return snapshotPath ? /* @__PURE__ */ new Set([snapshotPath]) : /* @__PURE__ */ new Set();
|
|
1000
927
|
}
|
|
1001
|
-
function snapshotOptionsForContext(ctx, config) {
|
|
1002
|
-
return {
|
|
1003
|
-
include: config.include,
|
|
1004
|
-
sessionDir: sessionDirFromContext(ctx)
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
function sessionDirFromContext(ctx) {
|
|
1008
|
-
const manager = ctx.sessionManager;
|
|
1009
|
-
const usesDefaultSessionDir = manager.usesDefaultSessionDir;
|
|
1010
|
-
if (typeof usesDefaultSessionDir === "function" && usesDefaultSessionDir.call(manager)) {
|
|
1011
|
-
return void 0;
|
|
1012
|
-
}
|
|
1013
|
-
const getSessionDir = manager.getSessionDir;
|
|
1014
|
-
return typeof getSessionDir === "function" ? getSessionDir.call(manager) : void 0;
|
|
1015
|
-
}
|
|
1016
928
|
async function maybeReload(ctx, signal) {
|
|
1017
929
|
if (signal?.aborted || !("reload" in ctx)) return;
|
|
1018
930
|
if (ctx.hasUI && await ctx.ui.confirm(
|
|
@@ -1042,21 +954,6 @@ async function snapshotForUpload(backend, config, local, head, remote, signal, o
|
|
|
1042
954
|
}
|
|
1043
955
|
return mergeRemotePreservedFiles(local, snapshot, config);
|
|
1044
956
|
}
|
|
1045
|
-
async function readRemoteSnapshot(backend, config, signal, options = {}) {
|
|
1046
|
-
const head = await backend.readHead(signal);
|
|
1047
|
-
if (!head) return { head: void 0, snapshot: void 0, selectionState: void 0 };
|
|
1048
|
-
const snapshot = await readSnapshotForHead(backend, head, signal);
|
|
1049
|
-
const selectionState = inspectRemoteSelection(config.include, snapshot);
|
|
1050
|
-
if (!options.allowSelectionDifference && selectionState.kind === "different") {
|
|
1051
|
-
const configIdentity = syncConfigReviewFingerprint(config);
|
|
1052
|
-
throw remoteSelectionMismatch(config, selectionState.include, configIdentity);
|
|
1053
|
-
}
|
|
1054
|
-
return {
|
|
1055
|
-
head,
|
|
1056
|
-
snapshot: filterSnapshotForConfigPolicy(snapshot, config),
|
|
1057
|
-
selectionState
|
|
1058
|
-
};
|
|
1059
|
-
}
|
|
1060
957
|
async function confirmPush(ctx, options, config, backend, local, upload, head, remote, title = snapshotIncludesSessions(upload) ? "Push pi settings and sessions?" : "Push pi settings?") {
|
|
1061
958
|
throwIfAborted(options.signal);
|
|
1062
959
|
if (options.yes) return true;
|
|
@@ -1077,10 +974,6 @@ async function confirmPush(ctx, options, config, backend, local, upload, head, r
|
|
|
1077
974
|
ctx.ui.notify("Push cancelled.", "info");
|
|
1078
975
|
return false;
|
|
1079
976
|
}
|
|
1080
|
-
function throwIfAborted(signal) {
|
|
1081
|
-
if (!signal?.aborted) return;
|
|
1082
|
-
throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted", "AbortError");
|
|
1083
|
-
}
|
|
1084
977
|
function sameRemoteHead(backend, left, right) {
|
|
1085
978
|
if (!left || !right) return left === right;
|
|
1086
979
|
return backend.sameRevision(left.revision, right.revision);
|
|
@@ -1098,6 +991,193 @@ async function backupLocal(profile, options = {}, signal) {
|
|
|
1098
991
|
await fs2.writeFile(backupPath, encoded, { signal });
|
|
1099
992
|
return backupPath;
|
|
1100
993
|
}
|
|
994
|
+
|
|
995
|
+
// src/sync/sync-queries.ts
|
|
996
|
+
var STATUS_KEY2 = "sync";
|
|
997
|
+
var DEFAULT_PROFILE = "default";
|
|
998
|
+
async function status(ctx, options, factory = createSyncBackend) {
|
|
999
|
+
const config = await loadConfig(options.setup);
|
|
1000
|
+
throwIfAborted(options.signal);
|
|
1001
|
+
ctx.ui.setStatus(STATUS_KEY2, `checking ${config.setupName}`);
|
|
1002
|
+
const { head, selectionState, localChanged, remoteChanged, localFiles, destination, capability } = await inspectSync(config, snapshotOptionsForContext(ctx, config), options.signal, factory);
|
|
1003
|
+
throwIfAborted(options.signal);
|
|
1004
|
+
const remoteText = head ? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}` : "remote: empty";
|
|
1005
|
+
const warnings = syncSessionsWarnings(config);
|
|
1006
|
+
ctx.ui.setStatus(STATUS_KEY2, void 0);
|
|
1007
|
+
ctx.ui.notify(
|
|
1008
|
+
[
|
|
1009
|
+
`sync setup: ${config.setupName}`,
|
|
1010
|
+
`storage connection: ${config.connectionName}`,
|
|
1011
|
+
`storage location: ${safeTerminalText(destination)}`,
|
|
1012
|
+
`publication safety: ${publicationCapabilityDescription(capability)}`,
|
|
1013
|
+
`included content: ${config.include.join(", ") || "none"}`,
|
|
1014
|
+
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
1015
|
+
remoteText,
|
|
1016
|
+
formatRemoteSelectionStatus(selectionState),
|
|
1017
|
+
`local files: ${localFiles}`,
|
|
1018
|
+
`local changed since last sync: ${localChanged ? "yes" : "no"}`,
|
|
1019
|
+
`remote changed since last sync: ${remoteChanged ? "yes" : "no"}`,
|
|
1020
|
+
...warnings
|
|
1021
|
+
].join("\n"),
|
|
1022
|
+
localChanged || remoteChanged || selectionState?.kind === "different" || warnings.length > 0 ? "warning" : "info"
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
async function diff(ctx, options, factory = createSyncBackend) {
|
|
1026
|
+
const config = await loadConfig(options.setup);
|
|
1027
|
+
throwIfAborted(options.signal);
|
|
1028
|
+
ctx.ui.setStatus(STATUS_KEY2, `checking ${config.setupName}`);
|
|
1029
|
+
const backend = await factory(config);
|
|
1030
|
+
const local = await createSnapshot(
|
|
1031
|
+
config.snapshotIdentity,
|
|
1032
|
+
snapshotOptionsForContext(ctx, config)
|
|
1033
|
+
);
|
|
1034
|
+
throwIfAborted(options.signal);
|
|
1035
|
+
const { snapshot: remote, selectionState } = await readRemoteSnapshot(
|
|
1036
|
+
backend,
|
|
1037
|
+
config,
|
|
1038
|
+
options.signal,
|
|
1039
|
+
{ allowSelectionDifference: true }
|
|
1040
|
+
);
|
|
1041
|
+
throwIfAborted(options.signal);
|
|
1042
|
+
ctx.ui.setStatus(STATUS_KEY2, void 0);
|
|
1043
|
+
const warnings = syncSessionsWarnings(config);
|
|
1044
|
+
const header = [
|
|
1045
|
+
`sync setup: ${config.setupName}`,
|
|
1046
|
+
`storage connection: ${config.connectionName}`,
|
|
1047
|
+
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
1048
|
+
`included content: ${config.include.join(", ") || "none"}`,
|
|
1049
|
+
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`,
|
|
1050
|
+
formatRemoteSelectionStatus(selectionState),
|
|
1051
|
+
...warnings
|
|
1052
|
+
].join("\n");
|
|
1053
|
+
const level = warnings.length > 0 || selectionState?.kind === "different" ? "warning" : "info";
|
|
1054
|
+
if (!remote) {
|
|
1055
|
+
ctx.ui.notify(
|
|
1056
|
+
`${header}
|
|
1057
|
+
|
|
1058
|
+
${formatSnapshotOnlyDiff("Remote is empty. Local push would upload", local)}`,
|
|
1059
|
+
level
|
|
1060
|
+
);
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
ctx.ui.notify(`${header}
|
|
1064
|
+
|
|
1065
|
+
${formatDiff(local, remote)}`, level);
|
|
1066
|
+
}
|
|
1067
|
+
async function doctor(ctx, options, factory = createSyncBackend) {
|
|
1068
|
+
const messages = [];
|
|
1069
|
+
let level = "info";
|
|
1070
|
+
let snapshotOptions = {};
|
|
1071
|
+
let profile = DEFAULT_PROFILE;
|
|
1072
|
+
let backend;
|
|
1073
|
+
let backendSummary = [];
|
|
1074
|
+
try {
|
|
1075
|
+
const config = await loadConfig(options.setup);
|
|
1076
|
+
throwIfAborted(options.signal);
|
|
1077
|
+
backend = await factory(config);
|
|
1078
|
+
profile = config.snapshotIdentity;
|
|
1079
|
+
snapshotOptions = snapshotOptionsForContext(ctx, config);
|
|
1080
|
+
messages.push(
|
|
1081
|
+
`config: ok (sync setup ${config.setupName})`,
|
|
1082
|
+
`included content: ${config.include.join(", ") || "none"}`,
|
|
1083
|
+
`sessions: ${config.include.includes("sessions") ? "included" : "excluded"}`
|
|
1084
|
+
);
|
|
1085
|
+
backendSummary = [
|
|
1086
|
+
`storage location: ${safeTerminalText(backend.destination)}`,
|
|
1087
|
+
`publication safety: ${publicationCapabilityDescription(backend.capability)}`
|
|
1088
|
+
];
|
|
1089
|
+
const warnings = syncSessionsWarnings(config);
|
|
1090
|
+
if (warnings.length > 0) {
|
|
1091
|
+
level = "warning";
|
|
1092
|
+
messages.push(...warnings);
|
|
1093
|
+
}
|
|
1094
|
+
} catch (error) {
|
|
1095
|
+
throwIfAborted(options.signal);
|
|
1096
|
+
level = "warning";
|
|
1097
|
+
messages.push(`config: ${errorMessage(error)}`);
|
|
1098
|
+
}
|
|
1099
|
+
const local = await createSnapshot(profile, snapshotOptions);
|
|
1100
|
+
throwIfAborted(options.signal);
|
|
1101
|
+
const secrets = scanSnapshot(local);
|
|
1102
|
+
if (secrets.length > 0) {
|
|
1103
|
+
level = "warning";
|
|
1104
|
+
messages.push("secret scan: possible secrets found:");
|
|
1105
|
+
messages.push(...secrets.map((secret) => `- ${secret}`));
|
|
1106
|
+
} else {
|
|
1107
|
+
messages.push(`secret scan: ok (${local.files.length} files checked)`);
|
|
1108
|
+
}
|
|
1109
|
+
const lock = await inspectLock();
|
|
1110
|
+
throwIfAborted(options.signal);
|
|
1111
|
+
if (lock.status === "valid" && isStaleLock(lock.lock)) {
|
|
1112
|
+
level = "warning";
|
|
1113
|
+
messages.push(
|
|
1114
|
+
`lock: stale (pid ${lock.lock.pid}); run /sync unlock --stale after verifying no sync is running`
|
|
1115
|
+
);
|
|
1116
|
+
} else if (lock.status === "valid") {
|
|
1117
|
+
messages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);
|
|
1118
|
+
} else if (lock.status === "unreadable") {
|
|
1119
|
+
level = "warning";
|
|
1120
|
+
messages.push(
|
|
1121
|
+
"lock: unreadable; use /sync unlock --stale only after verifying no sync is running"
|
|
1122
|
+
);
|
|
1123
|
+
} else if (await isLockGuardHeld()) {
|
|
1124
|
+
throwIfAborted(options.signal);
|
|
1125
|
+
level = "warning";
|
|
1126
|
+
messages.push("lock: guard active while metadata is missing or still being initialized");
|
|
1127
|
+
} else {
|
|
1128
|
+
messages.push("lock: free");
|
|
1129
|
+
}
|
|
1130
|
+
if (backend) {
|
|
1131
|
+
messages.push(...backendSummary);
|
|
1132
|
+
const diagnostics = await backend.diagnose(options.signal);
|
|
1133
|
+
throwIfAborted(options.signal);
|
|
1134
|
+
for (const diagnostic of diagnostics) {
|
|
1135
|
+
messages.push(diagnostic.message);
|
|
1136
|
+
if (diagnostic.level !== "info") level = "warning";
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
ctx.ui.notify(messages.join("\n"), level);
|
|
1140
|
+
}
|
|
1141
|
+
async function history(ctx, options, factory = createSyncBackend) {
|
|
1142
|
+
const config = await loadConfig(options.setup);
|
|
1143
|
+
throwIfAborted(options.signal);
|
|
1144
|
+
const backend = await factory(config);
|
|
1145
|
+
const snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();
|
|
1146
|
+
throwIfAborted(options.signal);
|
|
1147
|
+
if (snapshots.length === 0) {
|
|
1148
|
+
ctx.ui.notify("No remote pi-sync history found.", "info");
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
const currentSnapshot = snapshots[0]?.snapshotId;
|
|
1152
|
+
if (ctx.mode === "tui") {
|
|
1153
|
+
const labels = snapshots.map(
|
|
1154
|
+
(item, index2) => `${index2 + 1}. ${item.createdAt} \xB7 ${safeTerminalText(item.machine)} \xB7 ${item.snapshotId}${item.snapshotId === currentSnapshot ? " (current)" : ""}${item.syncSessions ? " \xB7 sessions" : ""}`
|
|
1155
|
+
);
|
|
1156
|
+
const selected = await ctx.ui.select(
|
|
1157
|
+
`History for sync setup \u201C${safeTerminalText(config.setupName)}\u201D
|
|
1158
|
+
|
|
1159
|
+
Choose a snapshot to preview rollback.`,
|
|
1160
|
+
[...labels, "Back"]
|
|
1161
|
+
);
|
|
1162
|
+
if (!selected || selected === "Back") return;
|
|
1163
|
+
throwIfAborted(options.signal);
|
|
1164
|
+
const index = labels.indexOf(selected);
|
|
1165
|
+
const snapshot = snapshots[index];
|
|
1166
|
+
if (!snapshot) return;
|
|
1167
|
+
await withLock(
|
|
1168
|
+
"rollback",
|
|
1169
|
+
() => rollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {
|
|
1170
|
+
backendIdentity: backend.identity,
|
|
1171
|
+
setup: config.setupName
|
|
1172
|
+
})
|
|
1173
|
+
);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
ctx.ui.notify(
|
|
1177
|
+
snapshots.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`).join("\n"),
|
|
1178
|
+
"info"
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1101
1181
|
export {
|
|
1102
1182
|
PublicationStatePersistenceError,
|
|
1103
1183
|
RollbackPublicationError,
|
|
@@ -1111,4 +1191,4 @@ export {
|
|
|
1111
1191
|
status,
|
|
1112
1192
|
syncBoth
|
|
1113
1193
|
};
|
|
1114
|
-
//# sourceMappingURL=sync-operations-
|
|
1194
|
+
//# sourceMappingURL=sync-operations-ONJ27QRL.ts.map
|