@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.
Files changed (209) hide show
  1. package/README.md +49 -16
  2. package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
  3. package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
  4. package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
  5. package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
  6. package/dist/chunks/chunk-6UHKGALE.ts +134 -0
  7. package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
  8. package/dist/chunks/{chunk-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
  9. package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
  10. package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-AXXS2BPA.ts} +9 -9
  11. package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
  12. package/dist/chunks/{chunk-5T442OP3.ts → chunk-C7XY5NF5.ts} +210 -373
  13. package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
  14. package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
  15. package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
  16. package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
  17. package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
  18. package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
  19. package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
  20. package/dist/chunks/{chunk-WSOBYHIZ.ts → chunk-GWMHAQG4.ts} +4 -4
  21. package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
  22. package/dist/chunks/{chunk-5LZALPCD.ts → chunk-HUDQATCL.ts} +25 -25
  23. package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
  24. package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
  25. package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
  26. package/dist/chunks/chunk-JSYMGJQQ.ts +51 -0
  27. package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
  28. package/dist/chunks/chunk-L7TBO32M.ts +25 -0
  29. package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
  30. package/dist/chunks/{chunk-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -8
  31. package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
  32. package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
  33. package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
  34. package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
  35. package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
  36. package/dist/chunks/{chunk-HVUSHMVL.ts → chunk-OEX4ABY6.ts} +39 -37
  37. package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
  38. package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
  39. package/dist/chunks/chunk-OUHGBFYF.ts.map +7 -0
  40. package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
  41. package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
  42. package/dist/chunks/{chunk-GLQLN5GV.ts → chunk-SL64RLXR.ts} +8 -6
  43. package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
  44. package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
  45. package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
  46. package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
  47. package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
  48. package/dist/chunks/chunk-THMF4BVL.ts +18 -0
  49. package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
  50. package/dist/chunks/{chunk-44LPGQTI.ts → chunk-X5OM6GXT.ts} +9 -7
  51. package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
  52. package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
  53. package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
  54. package/dist/chunks/{chunk-ARN2672F.ts → chunk-YKJHPTGO.ts} +23 -55
  55. package/dist/chunks/chunk-YKJHPTGO.ts.map +7 -0
  56. package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
  57. package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
  58. package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
  59. package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
  60. package/dist/chunks/{file-selection-RKEHALNQ.ts → file-selection-FTTKAOYX.ts} +10 -7
  61. package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
  62. package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-OQW46G2X.ts} +42 -17
  63. package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
  64. package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
  65. package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
  66. package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
  67. package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
  68. package/dist/chunks/{s3-backend-552LXHE4.ts → s3-backend-3P33LQHU.ts} +96 -18
  69. package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
  70. package/dist/chunks/{setup-switch-5YDG5YGJ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
  71. package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
  72. package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
  73. package/dist/chunks/{snapshot-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
  74. package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
  75. package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-ONJ27QRL.ts} +374 -294
  76. package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
  77. package/dist/chunks/{sync-state-SRN6YRBK.ts → sync-state-Q2FTXTW6.ts} +6 -6
  78. package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
  79. package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
  80. package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
  81. package/dist/index.ts +477 -342
  82. package/dist/index.ts.map +4 -4
  83. package/docs/settings.md +30 -6
  84. package/package.json +1 -1
  85. package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
  86. package/src/backends/backend-identity.ts +40 -0
  87. package/src/backends/backend-types.ts +81 -0
  88. package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
  89. package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
  90. package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
  91. package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
  92. package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
  93. package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
  94. package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
  95. package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
  96. package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
  97. package/src/commands/command-execution.ts +330 -0
  98. package/src/commands/command-handler.ts +201 -0
  99. package/src/commands/command-types.ts +18 -0
  100. package/src/{command.ts → commands/command.ts} +2 -1
  101. package/src/commands/setup-completions.ts +6 -0
  102. package/src/settings/config.ts +238 -0
  103. package/src/{settings-management.ts → settings/settings-management.ts} +39 -14
  104. package/src/settings/settings-store.ts +109 -0
  105. package/src/settings/settings-types.ts +128 -0
  106. package/src/settings/settings-validation.ts +443 -0
  107. package/src/snapshot/session-paths.ts +84 -0
  108. package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
  109. package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
  110. package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
  111. package/src/snapshot/snapshot-types.ts +38 -0
  112. package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
  113. package/src/state/json-file.ts +20 -0
  114. package/src/{lock.ts → state/lock.ts} +3 -2
  115. package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
  116. package/src/state/state-types.ts +20 -0
  117. package/src/state/sync-state-store.ts +62 -0
  118. package/src/sync/automatic-sync.ts +103 -0
  119. package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
  120. package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
  121. package/src/sync/signals.ts +10 -0
  122. package/src/sync/startup-check.ts +128 -0
  123. package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
  124. package/src/sync/sync-error-guidance.ts +53 -0
  125. package/src/sync/sync-inspection.ts +51 -0
  126. package/src/sync/sync-loaders.ts +54 -0
  127. package/src/{sync-operations.ts → sync/sync-mutations.ts} +34 -325
  128. package/src/sync/sync-operations.ts +12 -0
  129. package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
  130. package/src/sync/sync-queries.ts +235 -0
  131. package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
  132. package/src/sync-extension.ts +64 -708
  133. package/src/sync.ts +8 -8
  134. package/src/types.ts +47 -286
  135. package/src/ui/automatic-sync-summary.ts +6 -0
  136. package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
  137. package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
  138. package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
  139. package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
  140. package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
  141. package/src/ui/manager-ui.ts +386 -0
  142. package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
  143. package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
  144. package/src/{settings-ui.ts → ui/settings-ui.ts} +17 -13
  145. package/src/ui/setup/git-ui.ts +293 -0
  146. package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
  147. package/src/ui/setup/s3-ui.ts +217 -0
  148. package/src/ui/setup/setup-actions.ts +127 -0
  149. package/src/ui/setup/setup-location-ui.ts +167 -0
  150. package/src/ui/setup/setup-name-ui.ts +34 -0
  151. package/src/ui/setup/setup-prompts.ts +92 -0
  152. package/src/ui/setup/setup-review.ts +70 -0
  153. package/src/ui/setup/setup-switcher.ts +181 -0
  154. package/src/ui/setup/setup-wizard.ts +39 -0
  155. package/src/ui/setup/text-input.ts +78 -0
  156. package/src/ui/setup/webdav-ui.ts +330 -0
  157. package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
  158. package/src/{sync-attention.ts → ui/sync-attention.ts} +75 -6
  159. package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
  160. package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
  161. package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
  162. package/src/ui/terminal-text.ts +4 -0
  163. package/dist/chunks/chunk-44LPGQTI.ts.map +0 -7
  164. package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
  165. package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
  166. package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
  167. package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
  168. package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
  169. package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
  170. package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
  171. package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
  172. package/dist/chunks/chunk-E4COSV32.ts +0 -82
  173. package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
  174. package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
  175. package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
  176. package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
  177. package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
  178. package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
  179. package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
  180. package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
  181. package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
  182. package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
  183. package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
  184. package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
  185. package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
  186. package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
  187. package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
  188. package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
  189. package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
  190. package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
  191. package/src/config.ts +0 -923
  192. package/src/git-ui.ts +0 -307
  193. package/src/manager-helpers.ts +0 -64
  194. package/src/manager-ui.ts +0 -997
  195. package/src/webdav-ui.ts +0 -421
  196. /package/dist/chunks/{manager-result-dispatcher-LWPYJAD5.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
  197. /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
  198. /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
  199. /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
  200. /package/dist/chunks/{sync-state-SRN6YRBK.ts.map → sync-inspection-FEP4L5TR.ts.map} +0 -0
  201. /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
  202. /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
  203. /package/src/{config-file.ts → settings/config-file.ts} +0 -0
  204. /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
  205. /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
  206. /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
  207. /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
  208. /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
  209. /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
package/src/sync.ts CHANGED
@@ -1,12 +1,12 @@
1
- export { completeSyncArguments, parseOptions, splitArgs } from "./command.js";
1
+ export { completeSyncArguments, parseOptions, splitArgs } from "./commands/command.js";
2
+ export { encodeKey, posixJoin, safeJoin, safeName } from "./paths.js";
2
3
  export {
3
- isCloudflareR2Endpoint,
4
4
  isEnabled,
5
5
  isExplicitlyEnabled,
6
6
  loadConfig,
7
7
  sessionTokenWarnings,
8
- } from "./config.js";
9
- export { encodeKey, posixJoin, safeJoin, safeName } from "./paths.js";
8
+ } from "./settings/config.js";
9
+ export { isCloudflareR2Endpoint } from "./settings/settings-validation.js";
10
10
  export {
11
11
  canonicalSnapshotPathForConfig,
12
12
  collectFiles,
@@ -19,14 +19,13 @@ export {
19
19
  scanSnapshot,
20
20
  sessionSnapshotPathFromAbsolute,
21
21
  snapshotWithoutSessions,
22
- } from "./snapshot.js";
22
+ } from "./snapshot/snapshot.js";
23
23
  export {
24
24
  addTopLevelCaseVariantDeletes,
25
25
  appliedFileHashMap,
26
26
  preflightSnapshotApply,
27
27
  protectSnapshotApplyPlan,
28
- } from "./snapshot-apply.js";
29
- export { default, type SyncDependencies } from "./sync-extension.js";
28
+ } from "./snapshot/snapshot-apply.js";
30
29
  export {
31
30
  canPullRemoteSessionsOnFirstSync,
32
31
  canPullRemoteSettingsOnFirstSync,
@@ -35,4 +34,5 @@ export {
35
34
  settingsHashesMatchState,
36
35
  settingsHashMap,
37
36
  settingsHashMapFromState,
38
- } from "./sync-state.js";
37
+ } from "./sync/sync-state.js";
38
+ export { default, type SyncDependencies } from "./sync-extension.js";
package/src/types.ts CHANGED
@@ -1,286 +1,47 @@
1
- export type StorageConnectionType = "s3" | "git" | "webdav";
2
- export type OnSwitchAction = "ask-before-pull" | "pull-after-switch" | "switch-only";
3
-
4
- export interface S3CredentialsSettings {
5
- accessKeyId: string;
6
- secretAccessKey: string;
7
- sessionToken?: string;
8
- [key: string]: unknown;
9
- }
10
-
11
- export interface WebDavCredentialsSettings {
12
- username: string;
13
- password: string;
14
- [key: string]: unknown;
15
- }
16
-
17
- export interface S3StorageConnectionSettings {
18
- type: "s3";
19
- endpoint: string;
20
- region: string;
21
- credentials: S3CredentialsSettings;
22
- remote?: never;
23
- url?: never;
24
- [key: string]: unknown;
25
- }
26
-
27
- export interface GitStorageConnectionSettings {
28
- type: "git";
29
- remote: string;
30
- endpoint?: never;
31
- region?: never;
32
- credentials?: never;
33
- url?: never;
34
- [key: string]: unknown;
35
- }
36
-
37
- export interface WebDavStorageConnectionSettings {
38
- type: "webdav";
39
- url: string;
40
- credentials: WebDavCredentialsSettings;
41
- endpoint?: never;
42
- region?: never;
43
- remote?: never;
44
- [key: string]: unknown;
45
- }
46
-
47
- export type StorageConnectionSettings =
48
- | S3StorageConnectionSettings
49
- | GitStorageConnectionSettings
50
- | WebDavStorageConnectionSettings;
51
-
52
- export interface CommonSyncSetupStorageSettings {
53
- connection: string;
54
- path: string;
55
- [key: string]: unknown;
56
- }
57
-
58
- export interface S3SyncSetupStorageSettings extends CommonSyncSetupStorageSettings {
59
- bucket: string;
60
- branch?: never;
61
- }
62
-
63
- export interface GitSyncSetupStorageSettings extends CommonSyncSetupStorageSettings {
64
- branch: string;
65
- bucket?: never;
66
- }
67
-
68
- export interface WebDavSyncSetupStorageSettings extends CommonSyncSetupStorageSettings {
69
- bucket?: never;
70
- branch?: never;
71
- }
72
-
73
- export type SyncSetupStorageSettings =
74
- | S3SyncSetupStorageSettings
75
- | GitSyncSetupStorageSettings
76
- | WebDavSyncSetupStorageSettings;
77
-
78
- export interface SyncPolicySettings {
79
- include: string[];
80
- automatic: boolean;
81
- [key: string]: unknown;
82
- }
83
-
84
- export interface SyncSetupSettings {
85
- storage: SyncSetupStorageSettings;
86
- sync: SyncPolicySettings;
87
- [key: string]: unknown;
88
- }
89
-
90
- export interface PiSyncSettingsV3 {
91
- version: 3;
92
- activeSyncSetup?: string;
93
- onSwitch: OnSwitchAction;
94
- skipSecretScan?: boolean;
95
- storageConnections: Record<string, StorageConnectionSettings>;
96
- syncSetups: Record<string, SyncSetupSettings>;
97
- [key: string]: unknown;
98
- }
99
-
100
- /** Backend-only resolved S3 connection fields. */
101
- export interface ResolvedS3StorageProfile {
102
- kind: "r2" | "s3-compatible";
103
- endpoint: string;
104
- region: string;
105
- accessKeyId: string;
106
- secretAccessKey: string;
107
- sessionToken?: string;
108
- }
109
-
110
- /** Backend-only coordinates. `prefix` is the complete reviewed v3 storage path. */
111
- export interface ResolvedS3Destination {
112
- bucket: string;
113
- prefix: string;
114
- /** Snapshot/wire identity; never derived from the local setup name. */
115
- namespace: string;
116
- }
117
-
118
- export interface ResolvedS3Backend {
119
- type: "s3";
120
- profile: ResolvedS3StorageProfile;
121
- destination: ResolvedS3Destination;
122
- }
123
-
124
- export interface ResolvedWebDavStorageProfile {
125
- kind: "webdav";
126
- url: string;
127
- username: string;
128
- password: string;
129
- }
130
-
131
- /** Backend-only coordinates. `path` is the complete reviewed v3 storage path. */
132
- export interface ResolvedWebDavDestination {
133
- path: string;
134
- namespace: string;
135
- }
136
-
137
- export interface ResolvedWebDavBackend {
138
- type: "webdav";
139
- profile: ResolvedWebDavStorageProfile;
140
- destination: ResolvedWebDavDestination;
141
- }
142
-
143
- export interface ResolvedGitStorageProfile {
144
- kind: "git";
145
- remote: string;
146
- }
147
-
148
- /** Backend-only coordinates. `directory` is the complete reviewed v3 storage path. */
149
- export interface ResolvedGitDestination {
150
- branch: string;
151
- directory: string;
152
- namespace: string;
153
- }
154
-
155
- export interface ResolvedGitBackend {
156
- type: "git";
157
- profile: ResolvedGitStorageProfile;
158
- destination: ResolvedGitDestination;
159
- }
160
-
161
- export type ResolvedSyncBackend = ResolvedS3Backend | ResolvedWebDavBackend | ResolvedGitBackend;
162
-
163
- export interface SyncConfig<Backend extends ResolvedSyncBackend = ResolvedS3Backend> {
164
- setupName: string;
165
- connectionName: string;
166
- storagePath: string;
167
- /** Snapshot/wire identity retained behind the settings normalization boundary. */
168
- snapshotIdentity: string;
169
- include: string[];
170
- automatic: boolean;
171
- onSwitch: OnSwitchAction;
172
- skipSecretScan: boolean;
173
- backend: Backend;
174
- }
175
-
176
- export type AnySyncConfig = SyncConfig<ResolvedSyncBackend>;
177
- export type CommonSyncConfig = Omit<AnySyncConfig, "backend">;
178
-
179
- /** UI projection over a fully validated v3 setup; it is never persisted directly. */
180
- export interface PartialConfig {
181
- setupName: string;
182
- connectionName: string;
183
- storageKind: StorageConnectionType;
184
- storagePath: string;
185
- include: string[];
186
- automatic: boolean;
187
- onSwitch: OnSwitchAction;
188
- bucket?: string;
189
- branch?: string;
190
- }
191
-
192
- export interface SnapshotFile {
193
- path: string;
194
- contentBase64: string;
195
- sha256: string;
196
- }
197
-
198
- export interface SnapshotSelection {
199
- version: 1;
200
- include: string[];
201
- }
202
-
203
- export interface Snapshot {
204
- version: number;
205
- id: string;
206
- createdAt: string;
207
- machine: string;
208
- /** Backend-scoped remote identity retained in the snapshot wire format. */
209
- profile: string;
210
- syncSessions?: boolean;
211
- /** Portable, credential-free included-content intent. Absent on legacy snapshots. */
212
- selection?: SnapshotSelection;
213
- files: SnapshotFile[];
214
- }
215
-
216
- export interface LatestPointer {
217
- version: number;
218
- profile: string;
219
- snapshot: string;
220
- sha256: string;
221
- createdAt: string;
222
- machine: string;
223
- syncSessions?: boolean;
224
- /** Lightweight projection; the immutable snapshot remains authoritative. */
225
- selection?: SnapshotSelection;
226
- }
227
-
228
- export interface RemoteObject<T> {
229
- value?: T;
230
- etag?: string;
231
- missing: boolean;
232
- }
233
-
234
- export interface SyncState {
235
- version: number;
236
- profile: string;
237
- lastAppliedSnapshot?: string;
238
- lastRemoteRevision?: string;
239
- lastRemoteEtag?: string;
240
- lastFileHashes: Record<string, string>;
241
- include?: string[];
242
- /** Legacy state fields are read only so v3 can detect and replace stale policy state. */
243
- syncFiles?: string[];
244
- syncSessions?: boolean;
245
- extraFiles?: string[];
246
- }
247
-
248
- export interface LockFile {
249
- id: string;
250
- pid: number;
251
- command: string;
252
- startedAt: string;
253
- }
254
-
255
- export interface CommandOptions {
256
- yes: boolean;
257
- force: boolean;
258
- stale: boolean;
259
- silent: boolean;
260
- reload: boolean;
261
- auto: boolean;
262
- setup?: string;
263
- signal?: AbortSignal;
264
- onCommit?: () => void;
265
- args: string[];
266
- }
267
-
268
- export interface CommandArgumentCompletion {
269
- value: string;
270
- label: string;
271
- description?: string;
272
- }
273
-
274
- export interface SnapshotOptions {
275
- include?: string[];
276
- sessionDir?: string;
277
- /** Temporary internal projections while snapshot storage remains wire-compatible. */
278
- syncFiles?: string[];
279
- syncSessions?: boolean;
280
- extraFiles?: string[];
281
- }
282
-
283
- export interface SnapshotApplyPlan {
284
- writes: Array<{ target: string; content: Buffer }>;
285
- deletes: string[];
286
- }
1
+ // Compatibility type surface; implementation modules import from the owning domain.
2
+
3
+ export type {
4
+ LatestPointer,
5
+ RemoteObject,
6
+ ResolvedGitBackend,
7
+ ResolvedGitDestination,
8
+ ResolvedGitStorageProfile,
9
+ ResolvedS3Backend,
10
+ ResolvedS3Destination,
11
+ ResolvedS3StorageProfile,
12
+ ResolvedSyncBackend,
13
+ ResolvedWebDavBackend,
14
+ ResolvedWebDavDestination,
15
+ ResolvedWebDavStorageProfile,
16
+ } from "./backends/backend-types.js";
17
+ export type { CommandArgumentCompletion, CommandOptions } from "./commands/command-types.js";
18
+ export type {
19
+ AnySyncConfig,
20
+ CommonSyncConfig,
21
+ CommonSyncSetupStorageSettings,
22
+ GitStorageConnectionSettings,
23
+ GitSyncSetupStorageSettings,
24
+ OnSwitchAction,
25
+ PartialConfig,
26
+ PiSyncSettingsV3,
27
+ S3CredentialsSettings,
28
+ S3StorageConnectionSettings,
29
+ S3SyncSetupStorageSettings,
30
+ StorageConnectionSettings,
31
+ StorageConnectionType,
32
+ SyncConfig,
33
+ SyncPolicySettings,
34
+ SyncSetupSettings,
35
+ SyncSetupStorageSettings,
36
+ WebDavCredentialsSettings,
37
+ WebDavStorageConnectionSettings,
38
+ WebDavSyncSetupStorageSettings,
39
+ } from "./settings/settings-types.js";
40
+ export type {
41
+ Snapshot,
42
+ SnapshotApplyPlan,
43
+ SnapshotFile,
44
+ SnapshotOptions,
45
+ SnapshotSelection,
46
+ } from "./snapshot/snapshot-types.js";
47
+ export type { LockFile, SyncState } from "./state/state-types.js";
@@ -0,0 +1,6 @@
1
+ /** Keep the setting's automatic transfer scope visible in every setup summary. */
2
+ export function automaticSyncSummary(enabled: boolean) {
3
+ return enabled
4
+ ? "On (startup check; shutdown pushes selected content if sessions included)"
5
+ : "Off";
6
+ }
@@ -5,10 +5,10 @@ import {
5
5
  } from "@earendil-works/pi-coding-agent";
6
6
  import { Key, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
7
7
  import { runCustomInteraction } from "@narumitw/pi-tui-kit";
8
- import { safeTerminalText } from "./manager-helpers.js";
9
- import type { SetupPullOutcome } from "./setup-switch.js";
10
- import type { SyncDecision } from "./sync-decision.js";
11
- import type { RemoteSelectionDecision } from "./sync-policy.js";
8
+ import type { SetupPullOutcome } from "../sync/setup-switch.js";
9
+ import type { SyncDecision } from "../sync/sync-decision.js";
10
+ import type { RemoteSelectionDecision } from "../sync/sync-policy.js";
11
+ import { safeTerminalText } from "./terminal-text.js";
12
12
 
13
13
  export type RunRouteResult =
14
14
  | { kind: "completed"; outcome?: SetupPullOutcome }
@@ -1,14 +1,16 @@
1
1
  import fs from "node:fs/promises";
2
2
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
3
3
  import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
4
- import { agentDir, loadConfig, localConfigPath } from "./config.js";
5
- import { updateSyncSetup } from "./settings-management.js";
4
+ import { loadConfig } from "../settings/config.js";
5
+ import { localConfigPath } from "../settings/config-file.js";
6
+ import { updateSyncSetup } from "../settings/settings-management.js";
7
+ import { agentDir } from "../snapshot/session-paths.js";
6
8
  import {
7
9
  BUILT_IN_SYNC_ROOTS,
8
10
  isSafeCustomIncludePath,
9
11
  normalizeSyncInclude,
10
12
  syncIncludeSelection,
11
- } from "./sync-policy.js";
13
+ } from "../sync/sync-policy.js";
12
14
 
13
15
  const BUILT_IN_PREFIX = "builtin:";
14
16
  const CUSTOM_PREFIX = "custom:";
@@ -1,11 +1,14 @@
1
1
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import type { ActionMenuItem } from "@narumitw/pi-tui-kit";
3
+ import type { StartupObservation } from "../sync/sync-inspection.js";
3
4
  import type { RunRoute } from "./cancellable-operation.js";
4
5
  import { dispatchManagerResult } from "./manager-result-dispatcher.js";
5
6
  import type { ManagerDescription } from "./manager-state.js";
6
7
  import type { SyncAttentionState } from "./sync-attention.js";
7
8
 
8
9
  export interface SyncManagerAttentionOptions {
10
+ getObservation?: () => StartupObservation | undefined;
11
+ onObservationInvalidated?: () => void;
9
12
  getAttention?: () => SyncAttentionState | undefined;
10
13
  onSelectionResolved?: (expected: SyncAttentionState) => void;
11
14
  }
@@ -13,7 +16,8 @@ export interface SyncManagerAttentionOptions {
13
16
  export function attentionMainMenuItems(
14
17
  manager: ManagerDescription,
15
18
  ): ActionMenuItem<"main" | "more" | "recovery", "review-attention">[] {
16
- if (!manager.attention) return [];
19
+ if (!manager.attention && manager.observation?.inspection.selectionState?.kind !== "different")
20
+ return [];
17
21
  const disabled = manager.attentionReviewDisabled === true;
18
22
  return [
19
23
  {
@@ -1,9 +1,13 @@
1
1
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { runConfirmation } from "@narumitw/pi-tui-kit";
3
+ import {
4
+ inspectOperationAvailability,
5
+ operationCanRecover,
6
+ } from "../state/operation-availability.js";
7
+ import { errorMessage } from "../sync/sync-errors.js";
3
8
  import type { RunRoute } from "./cancellable-operation.js";
4
- import { errorMessage, safeTerminalText } from "./manager-helpers.js";
5
9
  import type { ManagerDescription } from "./manager-state.js";
6
- import { inspectOperationAvailability, operationCanRecover } from "./operation-availability.js";
10
+ import { safeTerminalText } from "./terminal-text.js";
7
11
 
8
12
  export type RecoveryDisposition = "restored" | "stay" | "close";
9
13
 
@@ -1,22 +1,28 @@
1
1
  import { truncateToWidth } from "@earendil-works/pi-tui";
2
- import {
3
- activeLocalConfigPath,
4
- isCloudflareR2Endpoint,
5
- loadConfig,
6
- readLocalConfigObject,
7
- readStateForConfig,
8
- } from "./config.js";
9
- import { errorMessage, ownRecord, safeTerminalText } from "./manager-helpers.js";
2
+ import { loadConfig } from "../settings/config.js";
3
+ import { activeLocalConfigPath } from "../settings/config-file.js";
4
+ import { readLocalConfigObject } from "../settings/settings-store.js";
5
+ import type { AnySyncConfig } from "../settings/settings-types.js";
6
+ import { isCloudflareR2Endpoint, ownRecord } from "../settings/settings-validation.js";
10
7
  import {
11
8
  inspectOperationAvailability,
12
9
  type OperationAvailability,
13
10
  operationBlocksChanges,
14
11
  operationCanRecover,
15
- } from "./operation-availability.js";
16
- import { type SyncAttentionState, syncAttentionMatchesConfig } from "./sync-attention.js";
17
- import { compareSyncInclude, syncIncludeSelection } from "./sync-policy.js";
12
+ } from "../state/operation-availability.js";
13
+ import { readStateForConfig, syncStateFingerprint } from "../state/sync-state-store.js";
14
+ import { errorMessage } from "../sync/sync-errors.js";
15
+ import type { StartupObservation } from "../sync/sync-inspection.js";
16
+ import { compareSyncInclude, syncIncludeSelection } from "../sync/sync-policy.js";
17
+ import { automaticSyncSummary } from "./automatic-sync-summary.js";
18
+ import {
19
+ observationMatchesConfig,
20
+ observationSummary,
21
+ type SyncAttentionState,
22
+ syncAttentionMatchesConfig,
23
+ } from "./sync-attention.js";
18
24
  import { countValidSyncSetups } from "./sync-setups-ui.js";
19
- import type { AnySyncConfig } from "./types.js";
25
+ import { safeTerminalText } from "./terminal-text.js";
20
26
 
21
27
  export const MAIN_MENU_ACTIONS = [
22
28
  "Sync now (recommended)",
@@ -31,6 +37,7 @@ export interface ManagerDescription {
31
37
  actions: string[];
32
38
  operation?: OperationAvailability;
33
39
  attention?: SyncAttentionState;
40
+ observation?: StartupObservation;
34
41
  attentionBlocksSync?: boolean;
35
42
  attentionReviewDisabled?: boolean;
36
43
  }
@@ -39,6 +46,7 @@ export async function describeManagerState(
39
46
  signal?: AbortSignal,
40
47
  attention?: SyncAttentionState,
41
48
  inspectOperation: () => Promise<OperationAvailability> = inspectOperationAvailability,
49
+ observation?: StartupObservation,
42
50
  ): Promise<ManagerDescription> {
43
51
  let raw: Record<string, unknown> | undefined;
44
52
  try {
@@ -105,6 +113,13 @@ export async function describeManagerState(
105
113
  const syncState = changesBlocked
106
114
  ? undefined
107
115
  : await readStateForConfig(config).catch(() => undefined);
116
+ const currentObservation =
117
+ observation &&
118
+ observationMatchesConfig(observation, config) &&
119
+ syncState &&
120
+ syncStateFingerprint(syncState) === observation.inspection.stateIdentity
121
+ ? observation
122
+ : undefined;
108
123
  const lastAppliedSnapshot = changesBlocked
109
124
  ? "Unavailable while operations are locked"
110
125
  : syncState?.lastAppliedSnapshot
@@ -122,7 +137,7 @@ export async function describeManagerState(
122
137
  `Current sync setup: ${safeTerminalText(config.setupName)}`,
123
138
  `Storage: ${backendStorageDescription(config)}`,
124
139
  `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"}`,
125
- `Automatic sync: ${config.automatic ? "On" : "Off"}`,
140
+ `Automatic sync: ${automaticSyncSummary(config.automatic)}`,
126
141
  `Last applied: ${lastAppliedSnapshot}`,
127
142
  ...(currentAttention
128
143
  ? [
@@ -135,7 +150,12 @@ export async function describeManagerState(
135
150
  : `Remote-only paths: ${attentionComparison?.remoteOnly.length ?? 0} · Device-only paths: ${attentionComparison?.localOnly.length ?? 0}`,
136
151
  "Nothing has been changed.",
137
152
  ]
138
- : ["Remote status: Not checked"]),
153
+ : currentObservation
154
+ ? [
155
+ `Startup check (${safeTerminalText(currentObservation.checkedAt)}): ${observationSummary(currentObservation)}`,
156
+ "Check-time observation only; synchronization rechecks current content.",
157
+ ]
158
+ : ["Remote status: Not checked"]),
139
159
  ...(noSyncedContent
140
160
  ? [
141
161
  "",
@@ -152,6 +172,7 @@ export async function describeManagerState(
152
172
  ).join("\n"),
153
173
  actions: operationActions(operation, noSyncedContent, canSwitch, mainActions),
154
174
  operation,
175
+ ...(currentObservation ? { observation: currentObservation } : {}),
155
176
  ...(currentAttention
156
177
  ? {
157
178
  attention: currentAttention,