@narumitw/pi-sync 0.50.2 → 0.51.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 +4 -1
- package/dist/chunks/{chunk-6LP3MCR2.ts → chunk-2JZFHNLM.ts} +3 -5
- package/dist/chunks/chunk-2JZFHNLM.ts.map +7 -0
- package/dist/chunks/{chunk-LCRI3ABW.ts → chunk-2RZSQWBH.ts} +8 -19
- package/dist/chunks/chunk-2RZSQWBH.ts.map +7 -0
- package/dist/chunks/{chunk-IJ6FJFA5.ts → chunk-4AIHXRKE.ts} +11 -17
- package/dist/chunks/chunk-4AIHXRKE.ts.map +7 -0
- package/dist/chunks/{chunk-C7XY5NF5.ts → chunk-4MPIH46N.ts} +29 -51
- package/dist/chunks/chunk-4MPIH46N.ts.map +7 -0
- package/dist/chunks/{chunk-5B3FXBLE.ts → chunk-6546TS54.ts} +16 -20
- package/dist/chunks/chunk-6546TS54.ts.map +7 -0
- package/dist/chunks/{chunk-Q2TUM5X6.ts → chunk-6NT3YFGY.ts} +2 -2
- package/dist/chunks/chunk-6NT3YFGY.ts.map +7 -0
- package/dist/chunks/{chunk-2B2ELUF5.ts → chunk-7D5SF7P3.ts} +1 -1
- package/dist/chunks/chunk-7D5SF7P3.ts.map +7 -0
- package/dist/chunks/{chunk-4CHTZMEO.ts → chunk-7KHKWL3Q.ts} +37 -55
- package/dist/chunks/chunk-7KHKWL3Q.ts.map +7 -0
- package/dist/chunks/{chunk-ZI5MXMEX.ts → chunk-BVVP33U5.ts} +2 -4
- package/dist/chunks/chunk-BVVP33U5.ts.map +7 -0
- package/dist/chunks/{chunk-SZWBGPID.ts → chunk-DM4X4FIA.ts} +8 -13
- package/dist/chunks/chunk-DM4X4FIA.ts.map +7 -0
- package/dist/chunks/{chunk-SL64RLXR.ts → chunk-DZUSTGQV.ts} +8 -16
- package/dist/chunks/chunk-DZUSTGQV.ts.map +7 -0
- package/dist/chunks/{chunk-G4RNQQZS.ts → chunk-E42GXD6D.ts} +13 -19
- package/dist/chunks/chunk-E42GXD6D.ts.map +7 -0
- package/dist/chunks/{chunk-Z4DQF6L3.ts → chunk-ECYCNZOE.ts} +1 -1
- package/dist/chunks/chunk-ECYCNZOE.ts.map +7 -0
- package/dist/chunks/{chunk-OEX4ABY6.ts → chunk-EEJPYTWE.ts} +11 -21
- package/dist/chunks/chunk-EEJPYTWE.ts.map +7 -0
- package/dist/chunks/{chunk-CPEHGXJV.ts → chunk-G4RUXRWZ.ts} +3 -5
- package/dist/chunks/chunk-G4RUXRWZ.ts.map +7 -0
- package/dist/chunks/{chunk-T2B5IU74.ts → chunk-HGJH56KR.ts} +4 -4
- package/dist/chunks/chunk-HGJH56KR.ts.map +7 -0
- package/dist/chunks/{chunk-JAAKLL6M.ts → chunk-IVXEDPAD.ts} +10 -34
- package/dist/chunks/chunk-IVXEDPAD.ts.map +7 -0
- package/dist/chunks/chunk-K3RIEL6J.ts +20 -0
- package/dist/chunks/chunk-K3RIEL6J.ts.map +7 -0
- package/dist/chunks/{chunk-LTBWGSBV.ts → chunk-MSSW6F3R.ts} +1 -1
- package/dist/chunks/chunk-MSSW6F3R.ts.map +7 -0
- package/dist/chunks/{chunk-T3HH3UEJ.ts → chunk-OVDTF5CH.ts} +4 -10
- package/dist/chunks/chunk-OVDTF5CH.ts.map +7 -0
- package/dist/chunks/{chunk-NJFUIVYL.ts → chunk-PWMWOJP4.ts} +1 -1
- package/dist/chunks/chunk-PWMWOJP4.ts.map +7 -0
- package/dist/chunks/{chunk-HUDQATCL.ts → chunk-Q32CQWPM.ts} +6 -8
- package/dist/chunks/chunk-Q32CQWPM.ts.map +7 -0
- package/dist/chunks/{chunk-ETTRJDNP.ts → chunk-QLSN7AGX.ts} +6 -13
- package/dist/chunks/chunk-QLSN7AGX.ts.map +7 -0
- package/dist/chunks/{chunk-THMF4BVL.ts → chunk-SWUXA3MH.ts} +1 -1
- package/dist/chunks/chunk-SWUXA3MH.ts.map +7 -0
- package/dist/chunks/{chunk-TEN2ZBJV.ts → chunk-T2SJD3N7.ts} +2 -4
- package/dist/chunks/chunk-T2SJD3N7.ts.map +7 -0
- package/dist/chunks/{chunk-AUSDLD6F.ts → chunk-T56RNRZJ.ts} +10 -26
- package/dist/chunks/chunk-T56RNRZJ.ts.map +7 -0
- package/dist/chunks/{chunk-KW7YQEZN.ts → chunk-UA7RXOIT.ts} +48 -100
- package/dist/chunks/chunk-UA7RXOIT.ts.map +7 -0
- package/dist/chunks/{chunk-D5X27LCA.ts → chunk-UETBKTDI.ts} +1 -1
- package/dist/chunks/chunk-UETBKTDI.ts.map +7 -0
- package/dist/chunks/{chunk-CHH26D4F.ts → chunk-YFADF5ZQ.ts} +7 -6
- package/dist/chunks/chunk-YFADF5ZQ.ts.map +7 -0
- package/dist/chunks/{chunk-CCSN3F47.ts → chunk-YPXGU5OR.ts} +4 -4
- package/dist/chunks/chunk-YPXGU5OR.ts.map +7 -0
- package/dist/chunks/{file-selection-FTTKAOYX.ts → file-selection-RAVHRYFG.ts} +14 -26
- package/dist/chunks/file-selection-RAVHRYFG.ts.map +7 -0
- package/dist/chunks/{git-backend-GMVS4PD4.ts → git-backend-IAANDL3K.ts} +41 -104
- package/dist/chunks/git-backend-IAANDL3K.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +23 -0
- package/dist/chunks/{manager-ui-5KLKVMRC.ts → manager-ui-763NEKJY.ts} +124 -251
- package/dist/chunks/manager-ui-763NEKJY.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +22 -0
- package/dist/chunks/{s3-backend-66O4FGBH.ts → s3-backend-XGXUOPUN.ts} +23 -54
- package/dist/chunks/s3-backend-XGXUOPUN.ts.map +7 -0
- package/dist/chunks/{setup-switch-IS2PEZ3J.ts → setup-switch-5G2VNJHL.ts} +9 -9
- package/dist/chunks/{setup-wizard-IUB6ESEU.ts → setup-wizard-YIEWGX32.ts} +12 -12
- package/dist/chunks/setup-wizard-YIEWGX32.ts.map +7 -0
- package/dist/chunks/{snapshot-HKEWCVK6.ts → snapshot-JL5DFSXI.ts} +5 -5
- package/dist/chunks/sync-inspection-P3ENJLNF.ts +20 -0
- package/dist/chunks/{sync-operations-LBX3GKCM.ts → sync-operations-AR76EB6C.ts} +85 -201
- package/dist/chunks/sync-operations-AR76EB6C.ts.map +7 -0
- package/dist/chunks/{sync-state-Q2FTXTW6.ts → sync-state-VHJUZ4YG.ts} +6 -6
- package/dist/chunks/{webdav-backend-ECIKD7SO.ts → webdav-backend-3EGUONAT.ts} +20 -51
- package/dist/chunks/webdav-backend-3EGUONAT.ts.map +7 -0
- package/dist/index.ts +49 -74
- package/dist/index.ts.map +3 -3
- package/docs/settings.md +9 -0
- package/package.json +61 -62
- package/src/backends/backend-factory.ts +15 -15
- package/src/backends/backend-identity.ts +31 -31
- package/src/backends/backend-types.ts +42 -42
- package/src/backends/git/git-backend.ts +714 -788
- package/src/backends/git/git-config.ts +104 -111
- package/src/backends/git/git-runner.ts +230 -247
- package/src/backends/git/git-storage.ts +228 -245
- package/src/backends/s3/s3-backend.ts +408 -441
- package/src/backends/s3/s3-client.ts +288 -333
- package/src/backends/sync-backend.ts +65 -65
- package/src/backends/webdav/webdav-backend.ts +542 -589
- package/src/backends/webdav/webdav-client.ts +292 -316
- package/src/backends/webdav/webdav-config.ts +57 -68
- package/src/commands/command-execution.ts +270 -289
- package/src/commands/command-handler.ts +160 -163
- package/src/commands/command-types.ts +13 -13
- package/src/commands/command.ts +190 -196
- package/src/commands/setup-completions.ts +1 -1
- package/src/paths.ts +47 -47
- package/src/settings/config-errors.ts +4 -5
- package/src/settings/config-file.ts +473 -506
- package/src/settings/config.ts +171 -174
- package/src/settings/settings-management.ts +191 -216
- package/src/settings/settings-store.ts +63 -77
- package/src/settings/settings-types.ts +78 -75
- package/src/settings/settings-validation.ts +328 -364
- package/src/snapshot/session-paths.ts +41 -55
- package/src/snapshot/snapshot-apply.ts +197 -229
- package/src/snapshot/snapshot-codec.ts +29 -31
- package/src/snapshot/snapshot-paths.ts +4 -6
- package/src/snapshot/snapshot-transaction.ts +161 -170
- package/src/snapshot/snapshot-types.ts +24 -24
- package/src/snapshot/snapshot.ts +310 -343
- package/src/state/json-file.ts +11 -11
- package/src/state/lock.ts +226 -242
- package/src/state/lockfile-fs.ts +20 -20
- package/src/state/operation-availability.ts +36 -41
- package/src/state/state-directory.ts +171 -173
- package/src/state/state-types.ts +15 -15
- package/src/state/sync-state-store.ts +23 -23
- package/src/sync/automatic-sync.ts +75 -80
- package/src/sync/remote-snapshot.ts +52 -60
- package/src/sync/setup-switch.ts +99 -114
- package/src/sync/signals.ts +3 -5
- package/src/sync/startup-check.ts +97 -111
- package/src/sync/sync-decision.ts +76 -80
- package/src/sync/sync-error-guidance.ts +41 -48
- package/src/sync/sync-errors.ts +10 -10
- package/src/sync/sync-inspection.ts +29 -33
- package/src/sync/sync-loaders.ts +28 -36
- package/src/sync/sync-mutations.ts +510 -622
- package/src/sync/sync-operations.ts +7 -7
- package/src/sync/sync-policy.ts +296 -326
- package/src/sync/sync-queries.ts +175 -194
- package/src/sync/sync-state.ts +74 -100
- package/src/sync-extension.ts +89 -101
- package/src/sync.ts +26 -26
- package/src/types.ts +37 -37
- package/src/ui/automatic-sync-summary.ts +1 -3
- package/src/ui/cancellable-operation.ts +92 -112
- package/src/ui/file-selection.ts +250 -274
- package/src/ui/manager-attention.ts +51 -63
- package/src/ui/manager-recovery.ts +48 -57
- package/src/ui/manager-result-dispatcher.ts +62 -76
- package/src/ui/manager-state.ts +200 -232
- package/src/ui/manager-ui.ts +264 -362
- package/src/ui/remote-selection-ui.ts +547 -588
- package/src/ui/secret-input.ts +198 -214
- package/src/ui/settings-ui.ts +175 -172
- package/src/ui/setup/git-ui.ts +232 -261
- package/src/ui/setup/s3-credentials-ui.ts +58 -65
- package/src/ui/setup/s3-ui.ts +171 -195
- package/src/ui/setup/setup-actions.ts +91 -101
- package/src/ui/setup/setup-location-ui.ts +121 -137
- package/src/ui/setup/setup-name-ui.ts +27 -27
- package/src/ui/setup/setup-prompts.ts +65 -65
- package/src/ui/setup/setup-review.ts +58 -59
- package/src/ui/setup/setup-switcher.ts +156 -160
- package/src/ui/setup/setup-wizard.ts +28 -28
- package/src/ui/setup/text-input.ts +54 -58
- package/src/ui/setup/webdav-ui.ts +246 -293
- package/src/ui/storage-connections-ui.ts +317 -369
- package/src/ui/sync-attention.ts +148 -164
- package/src/ui/sync-format.ts +110 -121
- package/src/ui/sync-resolution-ui.ts +147 -153
- package/src/ui/sync-setups-ui.ts +218 -238
- package/src/ui/sync-status.ts +17 -0
- package/src/ui/terminal-text.ts +2 -2
- package/dist/chunks/chunk-2B2ELUF5.ts.map +0 -7
- package/dist/chunks/chunk-4CHTZMEO.ts.map +0 -7
- package/dist/chunks/chunk-5B3FXBLE.ts.map +0 -7
- package/dist/chunks/chunk-6LP3MCR2.ts.map +0 -7
- package/dist/chunks/chunk-AUSDLD6F.ts.map +0 -7
- package/dist/chunks/chunk-C7XY5NF5.ts.map +0 -7
- package/dist/chunks/chunk-CCSN3F47.ts.map +0 -7
- package/dist/chunks/chunk-CHH26D4F.ts.map +0 -7
- package/dist/chunks/chunk-CPEHGXJV.ts.map +0 -7
- package/dist/chunks/chunk-D5X27LCA.ts.map +0 -7
- package/dist/chunks/chunk-ETTRJDNP.ts.map +0 -7
- package/dist/chunks/chunk-G4RNQQZS.ts.map +0 -7
- package/dist/chunks/chunk-HUDQATCL.ts.map +0 -7
- package/dist/chunks/chunk-IJ6FJFA5.ts.map +0 -7
- package/dist/chunks/chunk-JAAKLL6M.ts.map +0 -7
- package/dist/chunks/chunk-KW7YQEZN.ts.map +0 -7
- package/dist/chunks/chunk-LCRI3ABW.ts.map +0 -7
- package/dist/chunks/chunk-LTBWGSBV.ts.map +0 -7
- package/dist/chunks/chunk-NJFUIVYL.ts.map +0 -7
- package/dist/chunks/chunk-OEX4ABY6.ts.map +0 -7
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +0 -7
- package/dist/chunks/chunk-SL64RLXR.ts.map +0 -7
- package/dist/chunks/chunk-SZWBGPID.ts.map +0 -7
- package/dist/chunks/chunk-T2B5IU74.ts.map +0 -7
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +0 -7
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +0 -7
- package/dist/chunks/chunk-THMF4BVL.ts.map +0 -7
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +0 -7
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +0 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +0 -7
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-FKIBM3GO.ts +0 -22
- package/dist/chunks/manager-ui-5KLKVMRC.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-D7RBRJNL.ts +0 -21
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
- package/dist/chunks/setup-wizard-IUB6ESEU.ts.map +0 -7
- package/dist/chunks/sync-inspection-CST2KL65.ts +0 -20
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +0 -7
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +0 -7
- /package/dist/chunks/{manager-result-dispatcher-FKIBM3GO.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-D7RBRJNL.ts.map → remote-selection-ui-TZTJF32Y.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-IS2PEZ3J.ts.map → setup-switch-5G2VNJHL.ts.map} +0 -0
- /package/dist/chunks/{snapshot-HKEWCVK6.ts.map → snapshot-JL5DFSXI.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-CST2KL65.ts.map → sync-inspection-P3ENJLNF.ts.map} +0 -0
- /package/dist/chunks/{sync-state-Q2FTXTW6.ts.map → sync-state-VHJUZ4YG.ts.map} +0 -0
package/src/ui/manager-state.ts
CHANGED
|
@@ -5,10 +5,10 @@ import { readLocalConfigObject } from "../settings/settings-store.js";
|
|
|
5
5
|
import type { AnySyncConfig } from "../settings/settings-types.js";
|
|
6
6
|
import { isCloudflareR2Endpoint, ownRecord } from "../settings/settings-validation.js";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
inspectOperationAvailability,
|
|
9
|
+
type OperationAvailability,
|
|
10
|
+
operationBlocksChanges,
|
|
11
|
+
operationCanRecover,
|
|
12
12
|
} from "../state/operation-availability.js";
|
|
13
13
|
import { readStateForConfig, syncStateFingerprint } from "../state/sync-state-store.js";
|
|
14
14
|
import { errorMessage } from "../sync/sync-errors.js";
|
|
@@ -16,254 +16,222 @@ import type { StartupObservation } from "../sync/sync-inspection.js";
|
|
|
16
16
|
import { compareSyncInclude, syncIncludeSelection } from "../sync/sync-policy.js";
|
|
17
17
|
import { automaticSyncSummary } from "./automatic-sync-summary.js";
|
|
18
18
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
observationMatchesConfig,
|
|
20
|
+
observationSummary,
|
|
21
|
+
type SyncAttentionState,
|
|
22
|
+
syncAttentionMatchesConfig,
|
|
23
23
|
} from "./sync-attention.js";
|
|
24
24
|
import { countValidSyncSetups } from "./sync-setups-ui.js";
|
|
25
25
|
import { safeTerminalText } from "./terminal-text.js";
|
|
26
26
|
|
|
27
27
|
export const MAIN_MENU_ACTIONS = [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
"Sync now (recommended)",
|
|
29
|
+
"Switch sync setup",
|
|
30
|
+
"Status & changes",
|
|
31
|
+
"Settings",
|
|
32
|
+
"More…",
|
|
33
33
|
] as const;
|
|
34
34
|
|
|
35
35
|
export interface ManagerDescription {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
title: string;
|
|
37
|
+
actions: string[];
|
|
38
|
+
operation?: OperationAvailability;
|
|
39
|
+
attention?: SyncAttentionState;
|
|
40
|
+
observation?: StartupObservation;
|
|
41
|
+
attentionBlocksSync?: boolean;
|
|
42
|
+
attentionReviewDisabled?: boolean;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export async function describeManagerState(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
signal?: AbortSignal,
|
|
47
|
+
attention?: SyncAttentionState,
|
|
48
|
+
inspectOperation: () => Promise<OperationAvailability> = inspectOperationAvailability,
|
|
49
|
+
observation?: StartupObservation,
|
|
50
50
|
): Promise<ManagerDescription> {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} catch (error) {
|
|
185
|
-
if (signal?.aborted) throw error;
|
|
186
|
-
return {
|
|
187
|
-
title: [
|
|
188
|
-
"Manage sync",
|
|
189
|
-
"",
|
|
190
|
-
"Settings need attention. Automatic sync is paused.",
|
|
191
|
-
`Current sync setup: ${safeTerminalText(typeof raw.activeSyncSetup === "string" ? raw.activeSyncSetup : "none")}`,
|
|
192
|
-
`Error: ${safeTerminalText(errorMessage(error))}`,
|
|
193
|
-
`File: ${safeTerminalText(await activeLocalConfigPath())}`,
|
|
194
|
-
"",
|
|
195
|
-
"What do you want to do?",
|
|
196
|
-
].join("\n"),
|
|
197
|
-
actions: ["Sync setups…", "Storage connections…", "History & recovery…", "Help"],
|
|
198
|
-
};
|
|
199
|
-
}
|
|
51
|
+
let raw: Record<string, unknown> | undefined;
|
|
52
|
+
try {
|
|
53
|
+
raw = await readLocalConfigObject();
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
title: [
|
|
57
|
+
"Manage sync",
|
|
58
|
+
"",
|
|
59
|
+
"Settings file needs repair. Automatic sync and settings writes are paused.",
|
|
60
|
+
`Error: ${safeTerminalText(errorMessage(error))}`,
|
|
61
|
+
`File: ${safeTerminalText(await activeLocalConfigPath())}`,
|
|
62
|
+
"",
|
|
63
|
+
"Repair the JSON file, then reopen /sync.",
|
|
64
|
+
].join("\n"),
|
|
65
|
+
actions: ["Help"],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (!raw) {
|
|
69
|
+
return {
|
|
70
|
+
title: ["Manage sync", "", "Not set up.", "", "What do you want to do?"].join("\n"),
|
|
71
|
+
actions: ["Set up sync", "Help"],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const configuredTargets = ownRecord(raw.syncSetups);
|
|
75
|
+
if (raw.version === 3 && configuredTargets && Object.keys(configuredTargets).length === 0) {
|
|
76
|
+
return {
|
|
77
|
+
title: [
|
|
78
|
+
"Manage sync",
|
|
79
|
+
"",
|
|
80
|
+
"No sync setups are configured.",
|
|
81
|
+
"Add a sync setup using an existing storage connection.",
|
|
82
|
+
"",
|
|
83
|
+
"What do you want to do?",
|
|
84
|
+
].join("\n"),
|
|
85
|
+
actions: ["Sync setups…", "Storage connections…", "Help"],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const config = await loadConfig();
|
|
90
|
+
const operation = await inspectOperation();
|
|
91
|
+
const changesBlocked = operationBlocksChanges(operation);
|
|
92
|
+
const selection = syncIncludeSelection(config.include);
|
|
93
|
+
let currentAttention: SyncAttentionState | undefined;
|
|
94
|
+
if (attention) {
|
|
95
|
+
try {
|
|
96
|
+
const attentionConfig =
|
|
97
|
+
attention.decision.setupName === config.setupName ? config : await loadConfig(attention.decision.setupName);
|
|
98
|
+
if (syncAttentionMatchesConfig(attention, attentionConfig)) currentAttention = attention;
|
|
99
|
+
} catch {
|
|
100
|
+
currentAttention = undefined;
|
|
101
|
+
}
|
|
102
|
+
if (signal?.aborted) throw signal.reason;
|
|
103
|
+
}
|
|
104
|
+
const attentionComparison = currentAttention
|
|
105
|
+
? compareSyncInclude(currentAttention.decision.localInclude, currentAttention.decision.remoteInclude)
|
|
106
|
+
: undefined;
|
|
107
|
+
const noSyncedContent = config.include.length === 0;
|
|
108
|
+
const syncState = changesBlocked ? undefined : await readStateForConfig(config).catch(() => undefined);
|
|
109
|
+
const currentObservation =
|
|
110
|
+
observation &&
|
|
111
|
+
observationMatchesConfig(observation, config) &&
|
|
112
|
+
syncState &&
|
|
113
|
+
syncStateFingerprint(syncState) === observation.inspection.stateIdentity
|
|
114
|
+
? observation
|
|
115
|
+
: undefined;
|
|
116
|
+
const lastAppliedSnapshot = changesBlocked
|
|
117
|
+
? "Unavailable while operations are locked"
|
|
118
|
+
: syncState?.lastAppliedSnapshot
|
|
119
|
+
? safeTerminalText(syncState.lastAppliedSnapshot)
|
|
120
|
+
: syncState
|
|
121
|
+
? "Never synced"
|
|
122
|
+
: "Unavailable";
|
|
123
|
+
const canSwitch = (await countValidSyncSetups(configuredTargets, signal)) > 1;
|
|
124
|
+
const mainActions = MAIN_MENU_ACTIONS.filter((action) => action !== "Switch sync setup" || canSwitch);
|
|
125
|
+
const ordinaryTitle = [
|
|
126
|
+
"Manage sync",
|
|
127
|
+
"",
|
|
128
|
+
`Current sync setup: ${safeTerminalText(config.setupName)}`,
|
|
129
|
+
`Storage: ${backendStorageDescription(config)}`,
|
|
130
|
+
`Included: ${selection.builtIns.length} built-in group${selection.builtIns.length === 1 ? "" : "s"} · ${selection.custom.length} extra path${selection.custom.length === 1 ? "" : "s"} · Sessions ${selection.sessions ? "on" : "off"}`,
|
|
131
|
+
`Automatic sync: ${automaticSyncSummary(config.automatic)}`,
|
|
132
|
+
`Last applied: ${lastAppliedSnapshot}`,
|
|
133
|
+
...(currentAttention
|
|
134
|
+
? [
|
|
135
|
+
currentAttention.decision.setupName === config.setupName
|
|
136
|
+
? "Sync status: Review needed"
|
|
137
|
+
: `Sync status: Review needed for setup ${safeTerminalText(currentAttention.decision.setupName)}`,
|
|
138
|
+
attentionComparison?.remoteOnly.length === 0 && attentionComparison.localOnly.length === 0
|
|
139
|
+
? "Only the synced-content order differs."
|
|
140
|
+
: `Remote-only paths: ${attentionComparison?.remoteOnly.length ?? 0} · Device-only paths: ${attentionComparison?.localOnly.length ?? 0}`,
|
|
141
|
+
"Nothing has been changed.",
|
|
142
|
+
]
|
|
143
|
+
: currentObservation
|
|
144
|
+
? [
|
|
145
|
+
`Startup check (${safeTerminalText(currentObservation.checkedAt)}): ${observationSummary(currentObservation)}`,
|
|
146
|
+
"Check-time observation only; synchronization rechecks current content.",
|
|
147
|
+
]
|
|
148
|
+
: ["Remote status: Not checked"]),
|
|
149
|
+
...(noSyncedContent
|
|
150
|
+
? ["", "No included content is selected. Choose included content in Settings before syncing."]
|
|
151
|
+
: []),
|
|
152
|
+
"",
|
|
153
|
+
"What do you want to do?",
|
|
154
|
+
];
|
|
155
|
+
return {
|
|
156
|
+
title: (changesBlocked ? ["Manage sync", ...operationStatusLines(operation)] : ordinaryTitle).join("\n"),
|
|
157
|
+
actions: operationActions(operation, noSyncedContent, canSwitch, mainActions),
|
|
158
|
+
operation,
|
|
159
|
+
...(currentObservation ? { observation: currentObservation } : {}),
|
|
160
|
+
...(currentAttention
|
|
161
|
+
? {
|
|
162
|
+
attention: currentAttention,
|
|
163
|
+
attentionBlocksSync: currentAttention.decision.setupName === config.setupName,
|
|
164
|
+
attentionReviewDisabled: changesBlocked,
|
|
165
|
+
}
|
|
166
|
+
: {}),
|
|
167
|
+
};
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (signal?.aborted) throw error;
|
|
170
|
+
return {
|
|
171
|
+
title: [
|
|
172
|
+
"Manage sync",
|
|
173
|
+
"",
|
|
174
|
+
"Settings need attention. Automatic sync is paused.",
|
|
175
|
+
`Current sync setup: ${safeTerminalText(typeof raw.activeSyncSetup === "string" ? raw.activeSyncSetup : "none")}`,
|
|
176
|
+
`Error: ${safeTerminalText(errorMessage(error))}`,
|
|
177
|
+
`File: ${safeTerminalText(await activeLocalConfigPath())}`,
|
|
178
|
+
"",
|
|
179
|
+
"What do you want to do?",
|
|
180
|
+
].join("\n"),
|
|
181
|
+
actions: ["Sync setups…", "Storage connections…", "History & recovery…", "Help"],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
200
184
|
}
|
|
201
185
|
|
|
202
186
|
function operationActions(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
187
|
+
operation: OperationAvailability,
|
|
188
|
+
noSyncedContent: boolean,
|
|
189
|
+
canSwitch: boolean,
|
|
190
|
+
mainActions: string[],
|
|
207
191
|
) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return ["Refresh operation status", "Status & changes", "History & recovery…", "Help"];
|
|
218
|
-
}
|
|
219
|
-
return noSyncedContent
|
|
220
|
-
? ["Settings", ...(canSwitch ? ["Switch sync setup"] : []), "Status & changes", "More…"]
|
|
221
|
-
: mainActions;
|
|
192
|
+
if (operationCanRecover(operation)) {
|
|
193
|
+
return ["Restore sync access… (recommended)", "Status & changes", "History & recovery…", "Help"];
|
|
194
|
+
}
|
|
195
|
+
if (operation.kind !== "free") {
|
|
196
|
+
return ["Refresh operation status", "Status & changes", "History & recovery…", "Help"];
|
|
197
|
+
}
|
|
198
|
+
return noSyncedContent
|
|
199
|
+
? ["Settings", ...(canSwitch ? ["Switch sync setup"] : []), "Status & changes", "More…"]
|
|
200
|
+
: mainActions;
|
|
222
201
|
}
|
|
223
202
|
|
|
224
203
|
function operationStatusLines(operation: OperationAvailability): string[] {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
];
|
|
242
|
-
case "recoverable-unreadable":
|
|
243
|
-
return [
|
|
244
|
-
"Sync paused: owner unknown. Close other Pi sessions then restore; Settings and More return.",
|
|
245
|
-
];
|
|
246
|
-
case "inspection-error":
|
|
247
|
-
return [
|
|
248
|
-
"Lock check failed. Fix path access, then refresh; Settings and More remain unavailable.",
|
|
249
|
-
];
|
|
250
|
-
}
|
|
204
|
+
switch (operation.kind) {
|
|
205
|
+
case "free":
|
|
206
|
+
return [];
|
|
207
|
+
case "live": {
|
|
208
|
+
const command = truncateToWidth(safeTerminalText(operation.lock.command), 16, "…");
|
|
209
|
+
return [`Running: ${command} (pid ${operation.lock.pid}). Wait, then refresh; Settings and More return.`];
|
|
210
|
+
}
|
|
211
|
+
case "busy":
|
|
212
|
+
return ["Pi-sync may be starting or finishing. Wait, then refresh; Settings and More remain unavailable."];
|
|
213
|
+
case "recoverable-stale":
|
|
214
|
+
return ["Sync paused: old lock remains. Close other Pi sessions then restore; Settings and More return."];
|
|
215
|
+
case "recoverable-unreadable":
|
|
216
|
+
return ["Sync paused: owner unknown. Close other Pi sessions then restore; Settings and More return."];
|
|
217
|
+
case "inspection-error":
|
|
218
|
+
return ["Lock check failed. Fix path access, then refresh; Settings and More remain unavailable."];
|
|
219
|
+
}
|
|
251
220
|
}
|
|
252
221
|
|
|
253
222
|
export function backendStorageDescription(config: AnySyncConfig) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
223
|
+
const connection = safeTerminalText(config.connectionName);
|
|
224
|
+
switch (config.backend.type) {
|
|
225
|
+
case "s3": {
|
|
226
|
+
const type =
|
|
227
|
+
config.backend.profile.kind === "r2" || isCloudflareR2Endpoint(config.backend.profile.endpoint)
|
|
228
|
+
? "Cloudflare R2"
|
|
229
|
+
: "S3-compatible";
|
|
230
|
+
return `${type} · ${connection} · ${safeTerminalText(config.backend.destination.bucket)}`;
|
|
231
|
+
}
|
|
232
|
+
case "webdav":
|
|
233
|
+
return `WebDAV · ${connection} · ${safeTerminalText(config.backend.destination.path)}`;
|
|
234
|
+
case "git":
|
|
235
|
+
return `Git · ${connection} · ${safeTerminalText(config.backend.destination.branch)}`;
|
|
236
|
+
}
|
|
269
237
|
}
|