@narumitw/pi-sync 0.50.3 → 0.51.1

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 (218) hide show
  1. package/README.md +4 -1
  2. package/dist/chunks/{chunk-6LP3MCR2.ts → chunk-2JZFHNLM.ts} +3 -5
  3. package/dist/chunks/chunk-2JZFHNLM.ts.map +7 -0
  4. package/dist/chunks/{chunk-LCRI3ABW.ts → chunk-2RZSQWBH.ts} +8 -19
  5. package/dist/chunks/chunk-2RZSQWBH.ts.map +7 -0
  6. package/dist/chunks/{chunk-IJ6FJFA5.ts → chunk-4AIHXRKE.ts} +11 -17
  7. package/dist/chunks/chunk-4AIHXRKE.ts.map +7 -0
  8. package/dist/chunks/{chunk-C7XY5NF5.ts → chunk-4MPIH46N.ts} +29 -51
  9. package/dist/chunks/chunk-4MPIH46N.ts.map +7 -0
  10. package/dist/chunks/{chunk-5B3FXBLE.ts → chunk-6546TS54.ts} +16 -20
  11. package/dist/chunks/chunk-6546TS54.ts.map +7 -0
  12. package/dist/chunks/{chunk-Q2TUM5X6.ts → chunk-6NT3YFGY.ts} +2 -2
  13. package/dist/chunks/chunk-6NT3YFGY.ts.map +7 -0
  14. package/dist/chunks/{chunk-2B2ELUF5.ts → chunk-7D5SF7P3.ts} +1 -1
  15. package/dist/chunks/chunk-7D5SF7P3.ts.map +7 -0
  16. package/dist/chunks/{chunk-YDWUZVPN.ts → chunk-7KHKWL3Q.ts} +28 -47
  17. package/dist/chunks/chunk-7KHKWL3Q.ts.map +7 -0
  18. package/dist/chunks/{chunk-ZI5MXMEX.ts → chunk-BVVP33U5.ts} +2 -4
  19. package/dist/chunks/chunk-BVVP33U5.ts.map +7 -0
  20. package/dist/chunks/{chunk-SZWBGPID.ts → chunk-DM4X4FIA.ts} +8 -13
  21. package/dist/chunks/chunk-DM4X4FIA.ts.map +7 -0
  22. package/dist/chunks/{chunk-SL64RLXR.ts → chunk-DZUSTGQV.ts} +8 -16
  23. package/dist/chunks/chunk-DZUSTGQV.ts.map +7 -0
  24. package/dist/chunks/{chunk-YHEMENKV.ts → chunk-E42GXD6D.ts} +13 -19
  25. package/dist/chunks/chunk-E42GXD6D.ts.map +7 -0
  26. package/dist/chunks/{chunk-Z4DQF6L3.ts → chunk-ECYCNZOE.ts} +1 -1
  27. package/dist/chunks/chunk-ECYCNZOE.ts.map +7 -0
  28. package/dist/chunks/{chunk-OEX4ABY6.ts → chunk-EEJPYTWE.ts} +11 -21
  29. package/dist/chunks/chunk-EEJPYTWE.ts.map +7 -0
  30. package/dist/chunks/{chunk-CPEHGXJV.ts → chunk-G4RUXRWZ.ts} +3 -5
  31. package/dist/chunks/chunk-G4RUXRWZ.ts.map +7 -0
  32. package/dist/chunks/{chunk-T2B5IU74.ts → chunk-HGJH56KR.ts} +4 -4
  33. package/dist/chunks/chunk-HGJH56KR.ts.map +7 -0
  34. package/dist/chunks/{chunk-JAAKLL6M.ts → chunk-IVXEDPAD.ts} +10 -34
  35. package/dist/chunks/chunk-IVXEDPAD.ts.map +7 -0
  36. package/dist/chunks/chunk-K3RIEL6J.ts +20 -0
  37. package/dist/chunks/chunk-K3RIEL6J.ts.map +7 -0
  38. package/dist/chunks/{chunk-LTBWGSBV.ts → chunk-MSSW6F3R.ts} +1 -1
  39. package/dist/chunks/chunk-MSSW6F3R.ts.map +7 -0
  40. package/dist/chunks/{chunk-T3HH3UEJ.ts → chunk-OVDTF5CH.ts} +4 -10
  41. package/dist/chunks/chunk-OVDTF5CH.ts.map +7 -0
  42. package/dist/chunks/{chunk-NJFUIVYL.ts → chunk-PWMWOJP4.ts} +1 -1
  43. package/dist/chunks/chunk-PWMWOJP4.ts.map +7 -0
  44. package/dist/chunks/{chunk-HUDQATCL.ts → chunk-Q32CQWPM.ts} +6 -8
  45. package/dist/chunks/chunk-Q32CQWPM.ts.map +7 -0
  46. package/dist/chunks/{chunk-ETTRJDNP.ts → chunk-QLSN7AGX.ts} +6 -13
  47. package/dist/chunks/chunk-QLSN7AGX.ts.map +7 -0
  48. package/dist/chunks/{chunk-THMF4BVL.ts → chunk-SWUXA3MH.ts} +1 -1
  49. package/dist/chunks/chunk-SWUXA3MH.ts.map +7 -0
  50. package/dist/chunks/{chunk-TEN2ZBJV.ts → chunk-T2SJD3N7.ts} +2 -4
  51. package/dist/chunks/chunk-T2SJD3N7.ts.map +7 -0
  52. package/dist/chunks/{chunk-AUSDLD6F.ts → chunk-T56RNRZJ.ts} +10 -26
  53. package/dist/chunks/chunk-T56RNRZJ.ts.map +7 -0
  54. package/dist/chunks/{chunk-DHVFS4QK.ts → chunk-UA7RXOIT.ts} +37 -90
  55. package/dist/chunks/chunk-UA7RXOIT.ts.map +7 -0
  56. package/dist/chunks/{chunk-D5X27LCA.ts → chunk-UETBKTDI.ts} +1 -1
  57. package/dist/chunks/chunk-UETBKTDI.ts.map +7 -0
  58. package/dist/chunks/{chunk-CHH26D4F.ts → chunk-YFADF5ZQ.ts} +7 -6
  59. package/dist/chunks/chunk-YFADF5ZQ.ts.map +7 -0
  60. package/dist/chunks/{chunk-CCSN3F47.ts → chunk-YPXGU5OR.ts} +4 -4
  61. package/dist/chunks/chunk-YPXGU5OR.ts.map +7 -0
  62. package/dist/chunks/{file-selection-FTTKAOYX.ts → file-selection-RAVHRYFG.ts} +14 -26
  63. package/dist/chunks/file-selection-RAVHRYFG.ts.map +7 -0
  64. package/dist/chunks/{git-backend-GMVS4PD4.ts → git-backend-IAANDL3K.ts} +41 -104
  65. package/dist/chunks/git-backend-IAANDL3K.ts.map +7 -0
  66. package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +23 -0
  67. package/dist/chunks/{manager-ui-IPAOAWZA.ts → manager-ui-763NEKJY.ts} +124 -251
  68. package/dist/chunks/manager-ui-763NEKJY.ts.map +7 -0
  69. package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +22 -0
  70. package/dist/chunks/{s3-backend-66O4FGBH.ts → s3-backend-XGXUOPUN.ts} +23 -54
  71. package/dist/chunks/s3-backend-XGXUOPUN.ts.map +7 -0
  72. package/dist/chunks/{setup-switch-IS2PEZ3J.ts → setup-switch-5G2VNJHL.ts} +9 -9
  73. package/dist/chunks/{setup-wizard-JUJZYNNM.ts → setup-wizard-YIEWGX32.ts} +12 -12
  74. package/dist/chunks/setup-wizard-YIEWGX32.ts.map +7 -0
  75. package/dist/chunks/{snapshot-HKEWCVK6.ts → snapshot-JL5DFSXI.ts} +5 -5
  76. package/dist/chunks/sync-inspection-P3ENJLNF.ts +20 -0
  77. package/dist/chunks/{sync-operations-LBX3GKCM.ts → sync-operations-AR76EB6C.ts} +85 -201
  78. package/dist/chunks/sync-operations-AR76EB6C.ts.map +7 -0
  79. package/dist/chunks/{sync-state-Q2FTXTW6.ts → sync-state-VHJUZ4YG.ts} +6 -6
  80. package/dist/chunks/{webdav-backend-ECIKD7SO.ts → webdav-backend-3EGUONAT.ts} +20 -51
  81. package/dist/chunks/webdav-backend-3EGUONAT.ts.map +7 -0
  82. package/dist/index.ts +49 -74
  83. package/dist/index.ts.map +3 -3
  84. package/docs/settings.md +9 -0
  85. package/package.json +61 -62
  86. package/src/backends/backend-factory.ts +15 -15
  87. package/src/backends/backend-identity.ts +31 -31
  88. package/src/backends/backend-types.ts +42 -42
  89. package/src/backends/git/git-backend.ts +714 -788
  90. package/src/backends/git/git-config.ts +104 -111
  91. package/src/backends/git/git-runner.ts +230 -247
  92. package/src/backends/git/git-storage.ts +228 -245
  93. package/src/backends/s3/s3-backend.ts +408 -441
  94. package/src/backends/s3/s3-client.ts +288 -333
  95. package/src/backends/sync-backend.ts +65 -65
  96. package/src/backends/webdav/webdav-backend.ts +542 -589
  97. package/src/backends/webdav/webdav-client.ts +292 -316
  98. package/src/backends/webdav/webdav-config.ts +57 -68
  99. package/src/commands/command-execution.ts +270 -289
  100. package/src/commands/command-handler.ts +160 -163
  101. package/src/commands/command-types.ts +13 -13
  102. package/src/commands/command.ts +190 -196
  103. package/src/commands/setup-completions.ts +1 -1
  104. package/src/paths.ts +47 -47
  105. package/src/settings/config-errors.ts +4 -5
  106. package/src/settings/config-file.ts +473 -506
  107. package/src/settings/config.ts +171 -174
  108. package/src/settings/settings-management.ts +191 -216
  109. package/src/settings/settings-store.ts +63 -77
  110. package/src/settings/settings-types.ts +78 -75
  111. package/src/settings/settings-validation.ts +328 -364
  112. package/src/snapshot/session-paths.ts +41 -55
  113. package/src/snapshot/snapshot-apply.ts +197 -229
  114. package/src/snapshot/snapshot-codec.ts +29 -31
  115. package/src/snapshot/snapshot-paths.ts +4 -6
  116. package/src/snapshot/snapshot-transaction.ts +161 -170
  117. package/src/snapshot/snapshot-types.ts +24 -24
  118. package/src/snapshot/snapshot.ts +310 -343
  119. package/src/state/json-file.ts +11 -11
  120. package/src/state/lock.ts +226 -242
  121. package/src/state/lockfile-fs.ts +20 -20
  122. package/src/state/operation-availability.ts +36 -41
  123. package/src/state/state-directory.ts +171 -173
  124. package/src/state/state-types.ts +15 -15
  125. package/src/state/sync-state-store.ts +23 -23
  126. package/src/sync/automatic-sync.ts +75 -80
  127. package/src/sync/remote-snapshot.ts +52 -60
  128. package/src/sync/setup-switch.ts +99 -114
  129. package/src/sync/signals.ts +3 -5
  130. package/src/sync/startup-check.ts +97 -111
  131. package/src/sync/sync-decision.ts +76 -80
  132. package/src/sync/sync-error-guidance.ts +41 -48
  133. package/src/sync/sync-errors.ts +10 -10
  134. package/src/sync/sync-inspection.ts +29 -33
  135. package/src/sync/sync-loaders.ts +28 -36
  136. package/src/sync/sync-mutations.ts +510 -622
  137. package/src/sync/sync-operations.ts +7 -7
  138. package/src/sync/sync-policy.ts +296 -326
  139. package/src/sync/sync-queries.ts +175 -194
  140. package/src/sync/sync-state.ts +74 -100
  141. package/src/sync-extension.ts +89 -101
  142. package/src/sync.ts +26 -26
  143. package/src/types.ts +37 -37
  144. package/src/ui/automatic-sync-summary.ts +1 -3
  145. package/src/ui/cancellable-operation.ts +89 -101
  146. package/src/ui/file-selection.ts +250 -274
  147. package/src/ui/manager-attention.ts +51 -63
  148. package/src/ui/manager-recovery.ts +48 -57
  149. package/src/ui/manager-result-dispatcher.ts +62 -76
  150. package/src/ui/manager-state.ts +200 -232
  151. package/src/ui/manager-ui.ts +264 -362
  152. package/src/ui/remote-selection-ui.ts +547 -588
  153. package/src/ui/secret-input.ts +197 -205
  154. package/src/ui/settings-ui.ts +175 -172
  155. package/src/ui/setup/git-ui.ts +232 -261
  156. package/src/ui/setup/s3-credentials-ui.ts +58 -65
  157. package/src/ui/setup/s3-ui.ts +171 -195
  158. package/src/ui/setup/setup-actions.ts +91 -101
  159. package/src/ui/setup/setup-location-ui.ts +121 -137
  160. package/src/ui/setup/setup-name-ui.ts +27 -27
  161. package/src/ui/setup/setup-prompts.ts +65 -65
  162. package/src/ui/setup/setup-review.ts +58 -59
  163. package/src/ui/setup/setup-switcher.ts +156 -160
  164. package/src/ui/setup/setup-wizard.ts +28 -28
  165. package/src/ui/setup/text-input.ts +54 -58
  166. package/src/ui/setup/webdav-ui.ts +246 -293
  167. package/src/ui/storage-connections-ui.ts +317 -369
  168. package/src/ui/sync-attention.ts +148 -164
  169. package/src/ui/sync-format.ts +110 -121
  170. package/src/ui/sync-resolution-ui.ts +147 -153
  171. package/src/ui/sync-setups-ui.ts +218 -238
  172. package/src/ui/sync-status.ts +17 -0
  173. package/src/ui/terminal-text.ts +2 -2
  174. package/dist/chunks/chunk-2B2ELUF5.ts.map +0 -7
  175. package/dist/chunks/chunk-5B3FXBLE.ts.map +0 -7
  176. package/dist/chunks/chunk-6LP3MCR2.ts.map +0 -7
  177. package/dist/chunks/chunk-AUSDLD6F.ts.map +0 -7
  178. package/dist/chunks/chunk-C7XY5NF5.ts.map +0 -7
  179. package/dist/chunks/chunk-CCSN3F47.ts.map +0 -7
  180. package/dist/chunks/chunk-CHH26D4F.ts.map +0 -7
  181. package/dist/chunks/chunk-CPEHGXJV.ts.map +0 -7
  182. package/dist/chunks/chunk-D5X27LCA.ts.map +0 -7
  183. package/dist/chunks/chunk-DHVFS4QK.ts.map +0 -7
  184. package/dist/chunks/chunk-ETTRJDNP.ts.map +0 -7
  185. package/dist/chunks/chunk-HUDQATCL.ts.map +0 -7
  186. package/dist/chunks/chunk-IJ6FJFA5.ts.map +0 -7
  187. package/dist/chunks/chunk-JAAKLL6M.ts.map +0 -7
  188. package/dist/chunks/chunk-LCRI3ABW.ts.map +0 -7
  189. package/dist/chunks/chunk-LTBWGSBV.ts.map +0 -7
  190. package/dist/chunks/chunk-NJFUIVYL.ts.map +0 -7
  191. package/dist/chunks/chunk-OEX4ABY6.ts.map +0 -7
  192. package/dist/chunks/chunk-Q2TUM5X6.ts.map +0 -7
  193. package/dist/chunks/chunk-SL64RLXR.ts.map +0 -7
  194. package/dist/chunks/chunk-SZWBGPID.ts.map +0 -7
  195. package/dist/chunks/chunk-T2B5IU74.ts.map +0 -7
  196. package/dist/chunks/chunk-T3HH3UEJ.ts.map +0 -7
  197. package/dist/chunks/chunk-TEN2ZBJV.ts.map +0 -7
  198. package/dist/chunks/chunk-THMF4BVL.ts.map +0 -7
  199. package/dist/chunks/chunk-YDWUZVPN.ts.map +0 -7
  200. package/dist/chunks/chunk-YHEMENKV.ts.map +0 -7
  201. package/dist/chunks/chunk-Z4DQF6L3.ts.map +0 -7
  202. package/dist/chunks/chunk-ZI5MXMEX.ts.map +0 -7
  203. package/dist/chunks/file-selection-FTTKAOYX.ts.map +0 -7
  204. package/dist/chunks/git-backend-GMVS4PD4.ts.map +0 -7
  205. package/dist/chunks/manager-result-dispatcher-ASKGOSW5.ts +0 -22
  206. package/dist/chunks/manager-ui-IPAOAWZA.ts.map +0 -7
  207. package/dist/chunks/remote-selection-ui-QDNR7WEI.ts +0 -21
  208. package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
  209. package/dist/chunks/setup-wizard-JUJZYNNM.ts.map +0 -7
  210. package/dist/chunks/sync-inspection-CST2KL65.ts +0 -20
  211. package/dist/chunks/sync-operations-LBX3GKCM.ts.map +0 -7
  212. package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +0 -7
  213. /package/dist/chunks/{manager-result-dispatcher-ASKGOSW5.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
  214. /package/dist/chunks/{remote-selection-ui-QDNR7WEI.ts.map → remote-selection-ui-TZTJF32Y.ts.map} +0 -0
  215. /package/dist/chunks/{setup-switch-IS2PEZ3J.ts.map → setup-switch-5G2VNJHL.ts.map} +0 -0
  216. /package/dist/chunks/{snapshot-HKEWCVK6.ts.map → snapshot-JL5DFSXI.ts.map} +0 -0
  217. /package/dist/chunks/{sync-inspection-CST2KL65.ts.map → sync-inspection-P3ENJLNF.ts.map} +0 -0
  218. /package/dist/chunks/{sync-state-Q2FTXTW6.ts.map → sync-state-VHJUZ4YG.ts.map} +0 -0
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/settings/config-file.ts", "../../src/settings/settings-validation.ts", "../../src/settings/settings-store.ts", "../../src/settings/config.ts"],
4
- "sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n} from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\nimport lockfile from \"proper-lockfile\";\n\nconst CONFIG_FILE_NAME = \"pi-sync.json\";\nconst LEGACY_CONFIG_FILE_NAME = \"pi-sync.local.json\";\nconst configMigrationNotices = new Map<string, string>();\nconst legacyPresenceNoticed = new Set<string>();\nconst CONFIG_LOCK_STALE_MS = 30_000;\nconst CONFIG_LOCK_UPDATE_MS = 10_000;\nconst LOCKFILE_FS_ADAPTER = {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n};\n\ntype PublishFile = (source: string, destination: string) => Promise<void>;\nlet publishConfigFile: PublishFile = publishFileWithoutReplacement;\nlet beforeConfigPublicationHook: () => Promise<void> = async () => undefined;\nlet afterMissingConfigReadProbeHook: () => Promise<void> = async () => undefined;\nlet afterReplacementInstalledHook: () => Promise<void> = async () => undefined;\nlet afterConfigQuarantinedHook: () => Promise<void> = async () => undefined;\n\nexport type FileIdentity = { dev: number; ino: number };\n\nexport async function withConfigFilePublicationForTest<T>(\n\tpublish: PublishFile,\n\trun: () => Promise<T>,\n): Promise<T> {\n\tconst previous = publishConfigFile;\n\tpublishConfigFile = publish;\n\ttry {\n\t\treturn await run();\n\t} finally {\n\t\tpublishConfigFile = previous;\n\t}\n}\n\nexport async function withConfigPublicationReadyHookForTest<T>(\n\thook: () => Promise<void>,\n\trun: () => Promise<T>,\n): Promise<T> {\n\tconst previous = beforeConfigPublicationHook;\n\tbeforeConfigPublicationHook = hook;\n\ttry {\n\t\treturn await run();\n\t} finally {\n\t\tbeforeConfigPublicationHook = previous;\n\t}\n}\n\nexport async function withMissingConfigReadProbeHookForTest<T>(\n\thook: () => Promise<void>,\n\trun: () => Promise<T>,\n): Promise<T> {\n\tconst previous = afterMissingConfigReadProbeHook;\n\tafterMissingConfigReadProbeHook = hook;\n\ttry {\n\t\treturn await run();\n\t} finally {\n\t\tafterMissingConfigReadProbeHook = previous;\n\t}\n}\n\nexport async function withConfigReplacementInstalledHookForTest<T>(\n\thook: () => Promise<void>,\n\trun: () => Promise<T>,\n): Promise<T> {\n\tconst previous = afterReplacementInstalledHook;\n\tafterReplacementInstalledHook = hook;\n\ttry {\n\t\treturn await run();\n\t} finally {\n\t\tafterReplacementInstalledHook = previous;\n\t}\n}\n\nexport async function withConfigQuarantinedHookForTest<T>(\n\thook: () => Promise<void>,\n\trun: () => Promise<T>,\n): Promise<T> {\n\tconst previous = afterConfigQuarantinedHook;\n\tafterConfigQuarantinedHook = hook;\n\ttry {\n\t\treturn await run();\n\t} finally {\n\t\tafterConfigQuarantinedHook = previous;\n\t}\n}\n\ntype ConfigSnapshot = {\n\tbytes: Buffer;\n\tidentity: FileIdentity;\n\tparsed: Record<string, unknown>;\n};\n\nexport type LocalConfigDocument = ConfigSnapshot & { path: string };\n\nexport function localConfigPath() {\n\treturn path.join(getAgentDir(), CONFIG_FILE_NAME);\n}\n\nexport function legacyLocalConfigPath() {\n\treturn path.join(getAgentDir(), LEGACY_CONFIG_FILE_NAME);\n}\n\nexport async function activeLocalConfigPath() {\n\tconst canonicalPath = localConfigPath();\n\tconst legacyPath = legacyLocalConfigPath();\n\treturn withLocalConfigReadLockIfNeeded(async () => {\n\t\tif (await pathExists(canonicalPath)) return canonicalPath;\n\t\treturn (await pathExists(legacyPath)) ? legacyPath : canonicalPath;\n\t});\n}\n\nexport function consumeLocalConfigMigrationNotice() {\n\tconst configPath = localConfigPath();\n\tconst notice = configMigrationNotices.get(configPath);\n\tconfigMigrationNotices.delete(configPath);\n\treturn notice;\n}\n\nexport async function readActiveLocalConfigDocumentForRepair(): Promise<\n\tLocalConfigDocument | undefined\n> {\n\tconst canonicalPath = localConfigPath();\n\tconst legacyPath = legacyLocalConfigPath();\n\treturn withLocalConfigReadLockIfNeeded(async () => {\n\t\tconst filePath = (await pathExists(canonicalPath)) ? canonicalPath : legacyPath;\n\t\tconst snapshot = await readConfigSnapshotIfExists(filePath);\n\t\treturn snapshot ? { path: filePath, ...snapshot } : undefined;\n\t});\n}\n\nexport async function readMigratingLocalConfigDocument(\n\tvalidateForMigration: (settings: Record<string, unknown>) => void,\n): Promise<LocalConfigDocument | undefined> {\n\treturn withLocalConfigReadLockIfNeeded(async () => {\n\t\tconst configPath = await prepareLocalConfigPath(validateForMigration);\n\t\tconst snapshot = await readConfigSnapshotIfExists(configPath);\n\t\treturn snapshot ? { path: configPath, ...snapshot } : undefined;\n\t});\n}\n\nasync function withLocalConfigReadLockIfNeeded<T>(read: () => Promise<T>): Promise<T> {\n\tif ((await pathExists(localConfigPath())) || (await pathExists(legacyLocalConfigPath()))) {\n\t\treturn withLocalConfigFileLock(read);\n\t}\n\tawait afterMissingConfigReadProbeHook();\n\tif (await pathExists(configMutationLockPath())) return withLocalConfigFileLock(read);\n\treturn read();\n}\n\nexport function updateLocalConfigDocument<T extends Record<string, unknown>>(\n\tdefaultValue: T,\n\tupdate: (current: T) => T,\n\tvalidate: (value: Record<string, unknown>) => void,\n\tsignal?: AbortSignal,\n): Promise<T> {\n\treturn withLocalConfigFileLock(async () => {\n\t\tsignal?.throwIfAborted();\n\t\tconst configPath = await prepareLocalConfigPath(validate);\n\t\tconst snapshot = await readConfigSnapshotIfExists(configPath);\n\t\tconst document = snapshot ? { path: configPath, ...snapshot } : undefined;\n\t\tconst current = document\n\t\t\t? (structuredClone(document.parsed) as T)\n\t\t\t: structuredClone(defaultValue);\n\t\tconst next = update(current);\n\t\tvalidate(next);\n\t\tsignal?.throwIfAborted();\n\t\tif (document && JSON.stringify(document.parsed) === JSON.stringify(next)) return next;\n\t\tif (document) await replaceLocalConfigDocumentUnlocked(document, next);\n\t\telse await installPrivateConfigExclusively(localConfigPath(), serializedConfig(next));\n\t\treturn next;\n\t});\n}\n\nexport function createLocalConfigDocument(value: Record<string, unknown>) {\n\treturn withLocalConfigFileLock(async () => {\n\t\tconst bytes = serializedConfig(value);\n\t\ttry {\n\t\t\tawait installPrivateConfigExclusively(localConfigPath(), bytes);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\t\tthrow new Error(\"Pi-sync settings were created concurrently; reopen settings and retry.\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t});\n}\n\nexport function replaceLocalConfigDocument(\n\tdocument: LocalConfigDocument,\n\tvalue: Record<string, unknown>,\n) {\n\treturn withLocalConfigFileLock(() => replaceLocalConfigDocumentUnlocked(document, value));\n}\n\nasync function replaceLocalConfigDocumentUnlocked(\n\tdocument: LocalConfigDocument,\n\tvalue: Record<string, unknown>,\n) {\n\tconst nextBytes = serializedConfig(value);\n\tconst canonicalPath = localConfigPath();\n\tif (document.path !== canonicalPath) {\n\t\tif (!(await configDocumentStillMatches(document))) throw settingsChangedError();\n\t\tlet installed: FileIdentity;\n\t\ttry {\n\t\t\tinstalled = await installPrivateConfigExclusively(canonicalPath, nextBytes);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\t\tthrow new Error(\"Canonical settings were created concurrently; no settings were replaced.\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (!(await configDocumentStillMatches(document))) {\n\t\t\tawait quarantineAndRemoveConfigIfMatchesUnlocked(canonicalPath, installed, nextBytes);\n\t\t\tthrow settingsChangedError();\n\t\t}\n\t\treturn;\n\t}\n\n\tconst quarantinePath = await claimCanonicalConfigDocument(document);\n\tlet installed: FileIdentity;\n\ttry {\n\t\tinstalled = await installPrivateConfigExclusively(canonicalPath, nextBytes);\n\t} catch (error) {\n\t\tawait restoreQuarantinedConfig(canonicalPath, quarantinePath);\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Canonical settings changed concurrently; no settings were replaced.\");\n\t\t}\n\t\tthrow error;\n\t}\n\ttry {\n\t\tawait afterReplacementInstalledHook();\n\t\tif (!(await fileIdentityAndContentsMatch(quarantinePath, document.identity, document.bytes))) {\n\t\t\tthrow settingsChangedError();\n\t\t}\n\t\tif (process.platform !== \"win32\") await fs.chmod(quarantinePath, 0o600);\n\t} catch (error) {\n\t\tawait quarantineAndRemoveConfigIfMatchesUnlocked(canonicalPath, installed, nextBytes);\n\t\tawait restoreQuarantinedConfig(canonicalPath, quarantinePath);\n\t\tthrow error;\n\t}\n\tawait fs.rm(quarantinePath).catch(() => undefined);\n\tawait syncParentDirectory(canonicalPath).catch(() => undefined);\n}\n\nasync function prepareLocalConfigPath(\n\tvalidateForMigration: (settings: Record<string, unknown>) => void,\n) {\n\tconst canonicalPath = localConfigPath();\n\tconst legacyPath = legacyLocalConfigPath();\n\tif (await pathExists(canonicalPath)) {\n\t\tconst legacyStatus = await secureIgnoredLegacyIfPresent(legacyPath);\n\t\tif (legacyStatus !== \"missing\" && !legacyPresenceNoticed.has(canonicalPath)) {\n\t\t\tlegacyPresenceNoticed.add(canonicalPath);\n\t\t\trecordConfigMigrationNotice(\n\t\t\t\tcanonicalPath,\n\t\t\t\tlegacyStatus === \"private\"\n\t\t\t\t\t? `${LEGACY_CONFIG_FILE_NAME} legacy settings were ignored because ${CONFIG_FILE_NAME} takes precedence. Delete ${LEGACY_CONFIG_FILE_NAME} after confirming your settings.`\n\t\t\t\t\t: `${LEGACY_CONFIG_FILE_NAME} legacy settings were ignored because ${CONFIG_FILE_NAME} takes precedence, but pi-sync could not verify them as a private regular file. Secure or delete the legacy path after confirming your settings.`,\n\t\t\t);\n\t\t}\n\t\treturn canonicalPath;\n\t}\n\n\tconst legacy = await readConfigSnapshotIfExists(legacyPath);\n\tif (!legacy) return canonicalPath;\n\tvalidateForMigration(legacy.parsed);\n\n\tlet installedIdentity: FileIdentity;\n\ttry {\n\t\tinstalledIdentity = await installPrivateConfigExclusively(canonicalPath, legacy.bytes);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\trecordConfigMigrationNotice(\n\t\t\t\tcanonicalPath,\n\t\t\t\t`${LEGACY_CONFIG_FILE_NAME} legacy settings were ignored because ${CONFIG_FILE_NAME} was created concurrently and takes precedence.`,\n\t\t\t);\n\t\t\treturn canonicalPath;\n\t\t}\n\t\trecordConfigMigrationNotice(\n\t\t\tcanonicalPath,\n\t\t\t`Could not migrate ${LEGACY_CONFIG_FILE_NAME} to ${CONFIG_FILE_NAME}; the legacy settings were used for this session and were not changed.`,\n\t\t);\n\t\treturn legacyPath;\n\t}\n\n\tif (!(await configSnapshotStillMatches(legacyPath, legacy))) {\n\t\tconst removed = await quarantineAndRemoveConfigIfMatchesUnlocked(\n\t\t\tcanonicalPath,\n\t\t\tinstalledIdentity,\n\t\t\tlegacy.bytes,\n\t\t);\n\t\trecordConfigMigrationNotice(\n\t\t\tcanonicalPath,\n\t\t\tremoved\n\t\t\t\t? `${LEGACY_CONFIG_FILE_NAME} changed during migration; the stale ${CONFIG_FILE_NAME} copy was removed and the legacy settings were used for this session.`\n\t\t\t\t: `${LEGACY_CONFIG_FILE_NAME} changed during migration, but ${CONFIG_FILE_NAME} was replaced concurrently and takes precedence.`,\n\t\t);\n\t\treturn removed ? legacyPath : canonicalPath;\n\t}\n\n\tlegacyPresenceNoticed.add(canonicalPath);\n\trecordConfigMigrationNotice(\n\t\tcanonicalPath,\n\t\t`pi-sync settings migrated from ${LEGACY_CONFIG_FILE_NAME} to ${CONFIG_FILE_NAME}; the private legacy file was retained as a recovery copy and can be deleted after verification.`,\n\t);\n\treturn canonicalPath;\n}\n\nasync function secureIgnoredLegacyIfPresent(filePath: string) {\n\tlet pathStat: Awaited<ReturnType<typeof fs.lstat>>;\n\ttry {\n\t\tpathStat = await fs.lstat(filePath);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return \"missing\" as const;\n\t\treturn \"unsafe\" as const;\n\t}\n\tif (pathStat.isSymbolicLink() || !pathStat.isFile()) return \"unsafe\" as const;\n\n\tlet handle: fs.FileHandle | undefined;\n\ttry {\n\t\thandle = await fs.open(filePath, \"r\");\n\t\tconst openedStat = await handle.stat();\n\t\tif (openedStat.dev !== pathStat.dev || openedStat.ino !== pathStat.ino) {\n\t\t\treturn \"unsafe\" as const;\n\t\t}\n\t\tif (process.platform !== \"win32\" && (openedStat.mode & 0o777) !== 0o600) {\n\t\t\tawait handle.chmod(0o600);\n\t\t}\n\t\treturn \"private\" as const;\n\t} catch {\n\t\treturn \"unsafe\" as const;\n\t} finally {\n\t\tawait handle?.close().catch(() => undefined);\n\t}\n}\n\nasync function readConfigSnapshotIfExists(filePath: string): Promise<ConfigSnapshot | undefined> {\n\tlet pathStat: Awaited<ReturnType<typeof fs.lstat>>;\n\ttry {\n\t\tpathStat = await fs.lstat(filePath);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n\tif (pathStat.isSymbolicLink()) {\n\t\tthrow new Error(`Refusing to read symlinked pi-sync config: ${filePath}`);\n\t}\n\tif (!pathStat.isFile()) throw new Error(`pi-sync config is not a regular file: ${filePath}`);\n\n\tconst handle = await fs.open(filePath, \"r\");\n\ttry {\n\t\tconst openedStat = await handle.stat();\n\t\tif (openedStat.dev !== pathStat.dev || openedStat.ino !== pathStat.ino) {\n\t\t\tthrow new Error(`pi-sync config changed while opening: ${filePath}`);\n\t\t}\n\t\tif (process.platform !== \"win32\" && (openedStat.mode & 0o777) !== 0o600) {\n\t\t\tawait handle.chmod(0o600);\n\t\t}\n\t\tconst bytes = await handle.readFile();\n\t\treturn {\n\t\t\tbytes,\n\t\t\tidentity: { dev: openedStat.dev, ino: openedStat.ino },\n\t\t\tparsed: parseConfigObject(bytes, filePath),\n\t\t};\n\t} finally {\n\t\tawait handle.close();\n\t}\n}\n\nfunction serializedConfig(value: Record<string, unknown>) {\n\treturn Buffer.from(`${JSON.stringify(value, null, \"\\t\")}\\n`, \"utf8\");\n}\n\nfunction parseConfigObject(bytes: Buffer, filePath: string) {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(bytes.toString(\"utf8\"));\n\t} catch {\n\t\tthrow new SyntaxError(`Invalid JSON in pi-sync config: ${filePath}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`pi-sync config must contain a JSON object: ${filePath}`);\n\t}\n\treturn parsed as Record<string, unknown>;\n}\n\nasync function installPrivateConfigExclusively(filePath: string, bytes: Buffer) {\n\tawait fs.mkdir(path.dirname(filePath), { recursive: true });\n\tconst temporaryPath = path.join(\n\t\tpath.dirname(filePath),\n\t\t`.${path.basename(filePath)}.${process.pid}.${randomUUID()}.migrate`,\n\t);\n\tlet handle: fs.FileHandle | undefined;\n\ttry {\n\t\thandle = await fs.open(temporaryPath, \"wx\", 0o600);\n\t\tawait handle.writeFile(bytes);\n\t\tif (process.platform !== \"win32\") await handle.chmod(0o600);\n\t\tawait handle.sync();\n\t\tawait handle.close();\n\t\thandle = undefined;\n\t\tawait publishConfigFile(temporaryPath, filePath);\n\t\tconst installed = await fs.lstat(filePath);\n\t\tlet publishedHandle: fs.FileHandle | undefined;\n\t\tlet publicationError: unknown;\n\t\ttry {\n\t\t\tif (installed.isSymbolicLink() || !installed.isFile()) {\n\t\t\t\tthrow new Error(`Published pi-sync settings are not a regular file: ${filePath}`);\n\t\t\t}\n\t\t\tpublishedHandle = await fs.open(filePath, \"r+\");\n\t\t\tconst published = await publishedHandle.stat();\n\t\t\tif (published.dev !== installed.dev || published.ino !== installed.ino) {\n\t\t\t\tthrow new Error(`Published pi-sync settings changed while opening: ${filePath}`);\n\t\t\t}\n\t\t\tif (process.platform !== \"win32\") await publishedHandle.chmod(0o600);\n\t\t\tawait publishedHandle.sync();\n\t\t\tawait syncParentDirectory(filePath);\n\t\t} catch (error) {\n\t\t\tpublicationError = error;\n\t\t} finally {\n\t\t\tawait publishedHandle?.close().catch(() => undefined);\n\t\t}\n\t\tif (publicationError) {\n\t\t\tawait quarantineAndRemoveConfigIfMatchesUnlocked(\n\t\t\t\tfilePath,\n\t\t\t\t{ dev: installed.dev, ino: installed.ino },\n\t\t\t\tbytes,\n\t\t\t);\n\t\t\tthrow publicationError;\n\t\t}\n\t\treturn { dev: installed.dev, ino: installed.ino };\n\t} finally {\n\t\tawait handle?.close().catch(() => undefined);\n\t\tawait fs.rm(temporaryPath, { force: true }).catch(() => undefined);\n\t}\n}\n\nasync function configDocumentStillMatches(document: LocalConfigDocument) {\n\treturn fileIdentityAndContentsMatch(document.path, document.identity, document.bytes);\n}\n\nasync function claimCanonicalConfigDocument(document: LocalConfigDocument) {\n\tconst quarantinePath = path.join(\n\t\tpath.dirname(document.path),\n\t\t`.${path.basename(document.path)}.${randomUUID()}.schema-migration-source`,\n\t);\n\ttry {\n\t\tawait fs.rename(document.path, quarantinePath);\n\t\tawait syncParentDirectory(document.path);\n\t} catch (error) {\n\t\tawait restoreQuarantinedConfig(document.path, quarantinePath);\n\t\tthrow error;\n\t}\n\tif (!(await fileIdentityAndContentsMatch(quarantinePath, document.identity, document.bytes))) {\n\t\tawait restoreQuarantinedConfig(document.path, quarantinePath);\n\t\tthrow settingsChangedError();\n\t}\n\tif (await pathExists(document.path)) {\n\t\tawait restoreQuarantinedConfig(document.path, quarantinePath);\n\t\tthrow new Error(\"Canonical settings changed concurrently; no settings were replaced.\");\n\t}\n\treturn quarantinePath;\n}\n\nfunction settingsChangedError() {\n\treturn new Error(\"pi-sync settings changed during migration; no settings were replaced.\");\n}\n\nasync function configSnapshotStillMatches(filePath: string, snapshot: ConfigSnapshot) {\n\treturn fileIdentityAndContentsMatch(filePath, snapshot.identity, snapshot.bytes);\n}\n\nexport function quarantineAndRemoveConfigIfMatches(\n\tfilePath: string,\n\tidentity: FileIdentity,\n\texpectedBytes: Buffer,\n) {\n\treturn withLocalConfigFileLock(() =>\n\t\tquarantineAndRemoveConfigIfMatchesUnlocked(filePath, identity, expectedBytes),\n\t);\n}\n\nasync function quarantineAndRemoveConfigIfMatchesUnlocked(\n\tfilePath: string,\n\tidentity: FileIdentity,\n\texpectedBytes: Buffer,\n) {\n\tconst quarantinePath = path.join(\n\t\tpath.dirname(filePath),\n\t\t`.${path.basename(filePath)}.${randomUUID()}.migration-retired`,\n\t);\n\ttry {\n\t\tawait fs.rename(filePath, quarantinePath);\n\t} catch {\n\t\treturn false;\n\t}\n\tawait afterConfigQuarantinedHook();\n\ttry {\n\t\tawait syncParentDirectory(filePath);\n\t} catch {\n\t\tawait restoreQuarantinedConfig(filePath, quarantinePath);\n\t\treturn false;\n\t}\n\n\tconst matches = await fileIdentityAndContentsMatch(quarantinePath, identity, expectedBytes);\n\tif (!matches) {\n\t\tawait restoreQuarantinedConfig(filePath, quarantinePath);\n\t\treturn false;\n\t}\n\tif (await pathExists(filePath)) {\n\t\tawait fs.rm(quarantinePath, { force: true });\n\t\tawait syncParentDirectory(filePath);\n\t\treturn false;\n\t}\n\tawait fs.rm(quarantinePath);\n\tawait syncParentDirectory(filePath);\n\treturn true;\n}\n\nasync function fileIdentityAndContentsMatch(\n\tfilePath: string,\n\tidentity: FileIdentity,\n\texpectedBytes: Buffer,\n) {\n\ttry {\n\t\tconst current = await fs.lstat(filePath);\n\t\tif (current.isSymbolicLink()) return false;\n\t\tif (current.dev !== identity.dev || current.ino !== identity.ino) return false;\n\t\treturn (await fs.readFile(filePath)).equals(expectedBytes);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function restoreQuarantinedConfig(filePath: string, quarantinePath: string) {\n\ttry {\n\t\tawait renameFileWithoutReplacement(quarantinePath, filePath);\n\t\tif (process.platform !== \"win32\") await fs.chmod(filePath, 0o600);\n\t\tawait syncParentDirectory(filePath);\n\t\treturn;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return;\n\t}\n\ttry {\n\t\tif (process.platform !== \"win32\") await fs.chmod(quarantinePath, 0o600);\n\t\tawait syncParentDirectory(filePath);\n\t} catch {\n\t\t// Preserve the quarantine rather than risk deleting settings that changed concurrently.\n\t}\n}\n\nfunction configMutationLockPath() {\n\treturn `${localConfigPath()}.mutation-lock`;\n}\n\nexport async function withLocalConfigFileLock<T>(run: () => Promise<T>): Promise<T> {\n\tconst configPath = localConfigPath();\n\tawait fs.mkdir(path.dirname(configPath), { recursive: true });\n\tlet compromisedError: Error | undefined;\n\tconst release = await lockfile.lock(configPath, {\n\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\tlockfilePath: configMutationLockPath(),\n\t\trealpath: false,\n\t\tstale: CONFIG_LOCK_STALE_MS,\n\t\tupdate: CONFIG_LOCK_UPDATE_MS,\n\t\tretries: { retries: 100, factor: 1.2, minTimeout: 10, maxTimeout: 100 },\n\t\tonCompromised: (error) => {\n\t\t\tcompromisedError = error;\n\t\t},\n\t});\n\ttry {\n\t\tconst result = await run();\n\t\tif (compromisedError) throw compromisedError;\n\t\treturn result;\n\t} finally {\n\t\tawait release();\n\t}\n}\n\nasync function syncParentDirectory(filePath: string) {\n\tif (process.platform === \"win32\") return;\n\tlet handle: fs.FileHandle | undefined;\n\ttry {\n\t\thandle = await fs.open(path.dirname(filePath), \"r\");\n\t\tawait handle.sync();\n\t} finally {\n\t\tawait handle?.close().catch(() => undefined);\n\t}\n}\n\nasync function publishFileWithoutReplacement(source: string, destination: string) {\n\tawait beforeConfigPublicationHook();\n\tawait renameFileWithoutReplacement(source, destination);\n}\n\nasync function renameFileWithoutReplacement(source: string, destination: string) {\n\tif (await pathExists(destination)) {\n\t\tthrow Object.assign(new Error(`Settings already exist: ${destination}`), { code: \"EEXIST\" });\n\t}\n\tawait fs.rename(source, destination);\n}\n\nasync function pathExists(filePath: string) {\n\ttry {\n\t\tawait fs.lstat(filePath);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n\nfunction recordConfigMigrationNotice(configPath: string, notice: string) {\n\tif (!configMigrationNotices.has(configPath)) configMigrationNotices.set(configPath, notice);\n}\n", "import path from \"node:path\";\nimport { normalizeEndpointIdentity } from \"../backends/backend-identity.js\";\nimport {\n\tnormalizeGitBranch,\n\tnormalizeGitDirectory,\n\tnormalizeGitRemote,\n\tnormalizeGitRemoteIdentity,\n} from \"../backends/git/git-config.js\";\nimport {\n\tnormalizeWebDavIdentityUrl,\n\tnormalizeWebDavPath,\n\tnormalizeWebDavUrl,\n\tvalidateWebDavCredentials,\n} from \"../backends/webdav/webdav-config.js\";\nimport { normalizeSyncInclude } from \"../sync/sync-policy.js\";\nimport { localConfigPath } from \"./config-file.js\";\nimport type {\n\tOnSwitchAction,\n\tPiSyncSettingsV3,\n\tStorageConnectionSettings,\n\tSyncSetupSettings,\n} from \"./settings-types.js\";\n\nexport const DEFAULT_ON_SWITCH: OnSwitchAction = \"ask-before-pull\";\n\nexport function normalizeOnSwitch(value: unknown): OnSwitchAction {\n\tif (value === \"ask-before-pull\" || value === \"pull-after-switch\" || value === \"switch-only\") {\n\t\treturn value;\n\t}\n\tthrow new Error(\n\t\t'Invalid pi-sync settings: onSwitch must be \"ask-before-pull\", \"pull-after-switch\", or \"switch-only\".',\n\t);\n}\n\nexport function validateSettingsDocument(value: Record<string, unknown>): PiSyncSettingsV3 {\n\tif (value.version !== 3) {\n\t\tthrow new Error(\n\t\t\t`Unsupported pi-sync settings: version 3 is required. Keep the existing file for recovery, then create a new version 3 ${path.basename(localConfigPath())}; pi-sync will not migrate or overwrite old settings.`,\n\t\t);\n\t}\n\trejectLegacyFields(\n\t\tvalue,\n\t\t[\n\t\t\t\"profiles\",\n\t\t\t\"targets\",\n\t\t\t\"activeTarget\",\n\t\t\t\"targetSwitchAction\",\n\t\t\t\"endpoint\",\n\t\t\t\"bucket\",\n\t\t\t\"region\",\n\t\t\t\"accessKeyId\",\n\t\t\t\"secretAccessKey\",\n\t\t\t\"sessionToken\",\n\t\t\t\"profile\",\n\t\t\t\"prefix\",\n\t\t\t\"autoSync\",\n\t\t\t\"syncFiles\",\n\t\t\t\"syncSessions\",\n\t\t\t\"extraFiles\",\n\t\t],\n\t\t\"top level\",\n\t);\n\tnormalizeOnSwitch(value.onSwitch);\n\tif (value.skipSecretScan !== undefined && typeof value.skipSecretScan !== \"boolean\") {\n\t\tthrow new Error(\"Invalid pi-sync settings: skipSecretScan must be boolean.\");\n\t}\n\tconst storageConnections = requireNamedObjectMap(\n\t\tvalue.storageConnections,\n\t\t\"storageConnections\",\n\t\t\"storage connection\",\n\t);\n\tconst syncSetups = requireNamedObjectMap(value.syncSetups, \"syncSetups\", \"sync setup\");\n\tfor (const name of Object.keys(storageConnections)) {\n\t\tvalidateStorageConnection(\n\t\t\tname,\n\t\t\trequireOwnObject(storageConnections, name, \"storage connection\") as Record<string, unknown>,\n\t\t);\n\t}\n\tfor (const name of Object.keys(syncSetups)) {\n\t\tvalidateSyncSetup(\n\t\t\tname,\n\t\t\trequireOwnObject(syncSetups, name, \"sync setup\") as Record<string, unknown>,\n\t\t\tstorageConnections,\n\t\t);\n\t}\n\tconst names = Object.keys(syncSetups);\n\tconst activeSyncSetup = optionalCanonicalReference(value.activeSyncSetup, \"activeSyncSetup\");\n\tif (names.length === 0) {\n\t\tif (activeSyncSetup !== undefined) {\n\t\t\tthrow new Error(\"Invalid pi-sync settings: empty syncSetups cannot have activeSyncSetup.\");\n\t\t}\n\t} else if (!activeSyncSetup || !Object.hasOwn(syncSetups, activeSyncSetup)) {\n\t\tthrow new Error(\n\t\t\t\"Invalid pi-sync settings: activeSyncSetup must reference an existing own-property sync setup.\",\n\t\t);\n\t}\n\tvalidateUniqueRemoteSyncSetups(syncSetups, storageConnections);\n\treturn value as PiSyncSettingsV3;\n}\n\nfunction validateStorageConnection(name: string, value: Record<string, unknown>) {\n\trejectLegacyFields(\n\t\tvalue,\n\t\t[\"kind\", \"accessKeyId\", \"secretAccessKey\", \"sessionToken\", \"username\", \"password\"],\n\t\t`storage connection \u201C${name}\u201D`,\n\t);\n\tconst type = requiredString(value.type, `storage connection \u201C${name}\u201D type`);\n\tif (type !== \"s3\" && type !== \"git\" && type !== \"webdav\") {\n\t\tthrow new Error(`Invalid pi-sync settings: storage connection \u201C${name}\u201D has unsupported type.`);\n\t}\n\tconst known = [\"endpoint\", \"region\", \"remote\", \"url\", \"credentials\"];\n\tconst allowed =\n\t\ttype === \"s3\"\n\t\t\t? new Set([\"endpoint\", \"region\", \"credentials\"])\n\t\t\t: type === \"git\"\n\t\t\t\t? new Set([\"remote\"])\n\t\t\t\t: new Set([\"url\", \"credentials\"]);\n\tif (known.some((field) => Object.hasOwn(value, field) && !allowed.has(field))) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: ${type.toUpperCase()} storage connection \u201C${name}\u201D mixes backend fields.`,\n\t\t);\n\t}\n\tif (type === \"git\") {\n\t\tif (!normalizeGitRemote(requiredString(value.remote, `Git remote for \u201C${name}\u201D`))) {\n\t\t\tthrow new Error(`Invalid pi-sync settings: Git remote for \u201C${name}\u201D is required.`);\n\t\t}\n\t\treturn;\n\t}\n\tconst credentials = requireRecord(\n\t\tvalue.credentials,\n\t\t`credentials for storage connection \u201C${name}\u201D`,\n\t);\n\tif (type === \"webdav\") {\n\t\tnormalizeWebDavUrl(requiredString(value.url, `WebDAV URL for \u201C${name}\u201D`));\n\t\tconst username = requiredString(credentials.username, `WebDAV username for \u201C${name}\u201D`);\n\t\tconst password = requiredSecret(credentials.password, `WebDAV password for \u201C${name}\u201D`);\n\t\tif (\n\t\t\t[\"accessKeyId\", \"secretAccessKey\", \"sessionToken\"].some((field) =>\n\t\t\t\tObject.hasOwn(credentials, field),\n\t\t\t)\n\t\t) {\n\t\t\tthrow new Error(`Invalid pi-sync settings: WebDAV credentials for \u201C${name}\u201D mix fields.`);\n\t\t}\n\t\tvalidateWebDavCredentials(username, password);\n\t\treturn;\n\t}\n\tnormalizeS3Endpoint(requiredString(value.endpoint, `S3 endpoint for \u201C${name}\u201D`));\n\trequiredString(value.region, `S3 region for \u201C${name}\u201D`);\n\trequiredString(credentials.accessKeyId, `S3 access key id for \u201C${name}\u201D`);\n\trequiredSecret(credentials.secretAccessKey, `S3 secret access key for \u201C${name}\u201D`);\n\toptionalString(credentials.sessionToken, `S3 session token for \u201C${name}\u201D`);\n\tif ([\"username\", \"password\"].some((field) => Object.hasOwn(credentials, field))) {\n\t\tthrow new Error(`Invalid pi-sync settings: S3 credentials for \u201C${name}\u201D mix fields.`);\n\t}\n}\n\nfunction validateSyncSetup(\n\tname: string,\n\tvalue: Record<string, unknown>,\n\tconnections: Record<string, unknown>,\n) {\n\trejectLegacyFields(\n\t\tvalue,\n\t\t[\n\t\t\t\"profile\",\n\t\t\t\"bucket\",\n\t\t\t\"branch\",\n\t\t\t\"path\",\n\t\t\t\"prefix\",\n\t\t\t\"directory\",\n\t\t\t\"namespace\",\n\t\t\t\"autoSync\",\n\t\t\t\"syncFiles\",\n\t\t\t\"syncSessions\",\n\t\t\t\"extraFiles\",\n\t\t],\n\t\t`sync setup \u201C${name}\u201D`,\n\t);\n\tconst storage = requireRecord(value.storage, `storage for sync setup \u201C${name}\u201D`);\n\tconst sync = requireRecord(value.sync, `sync policy for sync setup \u201C${name}\u201D`);\n\trejectLegacyFields(\n\t\tstorage,\n\t\t[\"profile\", \"prefix\", \"directory\", \"namespace\"],\n\t\t`storage for sync setup \u201C${name}\u201D`,\n\t);\n\trejectLegacyFields(\n\t\tsync,\n\t\t[\"autoSync\", \"syncFiles\", \"syncSessions\", \"extraFiles\"],\n\t\t`sync policy for sync setup \u201C${name}\u201D`,\n\t);\n\tconst connectionName = requiredCanonicalReference(\n\t\tstorage.connection,\n\t\t`storage connection reference for sync setup \u201C${name}\u201D`,\n\t);\n\tvalidateConfigName(connectionName, \"storage connection reference\");\n\tconst connection = ownObject<Record<string, unknown>>(connections, connectionName);\n\tif (!connection) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: sync setup \u201C${name}\u201D references missing storage connection \u201C${connectionName}\u201D.`,\n\t\t);\n\t}\n\tconst type = connection.type;\n\tnormalizeStoragePath(requiredString(storage.path, `storage path for sync setup \u201C${name}\u201D`));\n\tif (type === \"s3\") {\n\t\tnormalizeS3Bucket(requiredString(storage.bucket, `S3 bucket for sync setup \u201C${name}\u201D`));\n\t\tif (Object.hasOwn(storage, \"branch\")) mixedSetupError(\"S3\", name);\n\t} else if (type === \"git\") {\n\t\tnormalizeGitBranch(requiredString(storage.branch, `Git branch for sync setup \u201C${name}\u201D`));\n\t\tif (Object.hasOwn(storage, \"bucket\")) mixedSetupError(\"Git\", name);\n\t} else if (type === \"webdav\") {\n\t\tif (Object.hasOwn(storage, \"bucket\") || Object.hasOwn(storage, \"branch\")) {\n\t\t\tmixedSetupError(\"WebDAV\", name);\n\t\t}\n\t}\n\tif (!Object.hasOwn(sync, \"include\")) {\n\t\tthrow new Error(`Invalid pi-sync settings: sync setup \u201C${name}\u201D is missing sync.include.`);\n\t}\n\tnormalizeSyncInclude(sync.include);\n\tif (typeof sync.automatic !== \"boolean\") {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: sync setup \u201C${name}\u201D sync.automatic must be boolean.`,\n\t\t);\n\t}\n}\n\nfunction mixedSetupError(type: string, name: string): never {\n\tthrow new Error(`Invalid pi-sync settings: ${type} sync setup \u201C${name}\u201D mixes backend fields.`);\n}\n\nexport function validateUniqueRemoteSyncSetups(\n\tsetups: Record<string, unknown>,\n\tconnections: Record<string, unknown>,\n) {\n\tconst identities = new Map<string, string>();\n\tfor (const name of Object.keys(setups)) {\n\t\tconst setup = requireOwnObject(setups, name, \"sync setup\") as unknown as SyncSetupSettings;\n\t\tconst connection = requireOwnObject(\n\t\t\tconnections,\n\t\t\tsetup.storage.connection,\n\t\t\t\"storage connection\",\n\t\t) as unknown as StorageConnectionSettings;\n\t\tconst identity = effectiveSyncSetupRemoteIdentity(setup, connection);\n\t\tconst existing = identities.get(identity);\n\t\tif (existing) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid pi-sync settings: sync setups \u201C${existing}\u201D and \u201C${name}\u201D use the same normalized remote location.`,\n\t\t\t);\n\t\t}\n\t\tidentities.set(identity, name);\n\t}\n}\n\nexport function effectiveSyncSetupRemoteIdentity(\n\tsetup: SyncSetupSettings,\n\tconnection: StorageConnectionSettings,\n) {\n\tconst storagePath = normalizeStoragePath(setup.storage.path);\n\tif (connection.type === \"git\") {\n\t\treturn JSON.stringify([\n\t\t\t\"git\",\n\t\t\tnormalizeGitRemoteIdentity(connection.remote),\n\t\t\tnormalizeGitBranch(setup.storage.branch),\n\t\t\tnormalizeGitDirectory(storagePath),\n\t\t]);\n\t}\n\tif (connection.type === \"webdav\") {\n\t\treturn JSON.stringify([\n\t\t\t\"webdav\",\n\t\t\tnormalizeWebDavIdentityUrl(connection.url),\n\t\t\tconnection.credentials.username.trim(),\n\t\t\tnormalizeWebDavPath(storagePath),\n\t\t]);\n\t}\n\treturn JSON.stringify([\n\t\t\"s3\",\n\t\tnormalizeEndpointIdentity(connection.endpoint),\n\t\tnormalizeS3Bucket(setup.storage.bucket),\n\t\tstoragePath,\n\t]);\n}\n\nfunction rejectLegacyFields(\n\tvalue: Record<string, unknown>,\n\tfields: readonly string[],\n\tcontext: string,\n) {\n\tconst field = fields.find((candidate) => Object.hasOwn(value, candidate));\n\tif (field) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: ${context} contains unsupported version 1/2 field \u201C${field}\u201D.`,\n\t\t);\n\t}\n}\n\nfunction requireNamedObjectMap(value: unknown, field: string, itemLabel: string) {\n\tconst result = requireRecord(value, field);\n\tfor (const name of Object.keys(result)) validateConfigName(name, itemLabel);\n\treturn result;\n}\n\nfunction requireOwnObject(value: Record<string, unknown>, key: string, label: string) {\n\tconst item = ownObject(value, key);\n\tif (!item) throw new Error(`Invalid pi-sync settings: ${label} \u201C${key}\u201D must be an object.`);\n\treturn item;\n}\n\nexport function ownObject<T extends object>(\n\tvalue: Record<string, unknown>,\n\tkey: string,\n): T | undefined {\n\tif (!Object.hasOwn(value, key)) return undefined;\n\tconst item = value[key];\n\treturn item && typeof item === \"object\" && !Array.isArray(item) ? (item as T) : undefined;\n}\n\nfunction requireRecord(value: unknown, field: string): Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must be an object.`);\n\t}\n\treturn value as Record<string, unknown>;\n}\n\nexport function validateConfigName(value: string, field: string) {\n\tif (\n\t\t!value.trim() ||\n\t\tvalue !== value.trim() ||\n\t\tvalue.length > 100 ||\n\t\tvalue === \"__proto__\" ||\n\t\tvalue === \"prototype\" ||\n\t\tvalue === \"constructor\" ||\n\t\thasControlCharacter(value)\n\t) {\n\t\tthrow new Error(`Invalid pi-sync settings: invalid ${field} name.`);\n\t}\n}\n\nexport function requiredString(value: unknown, field: string) {\n\tif (typeof value !== \"string\" || !value.trim() || hasControlCharacter(value)) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must be a non-empty string.`);\n\t}\n\treturn value.trim();\n}\n\nfunction requiredCanonicalReference(value: unknown, field: string) {\n\tconst normalized = requiredString(value, field);\n\tif (value !== normalized) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must not have surrounding whitespace.`);\n\t}\n\treturn normalized;\n}\n\nfunction optionalCanonicalReference(value: unknown, field: string) {\n\tconst normalized = optionalString(value, field);\n\tif (normalized !== undefined && value !== normalized) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must not have surrounding whitespace.`);\n\t}\n\treturn normalized;\n}\n\nfunction requiredSecret(value: unknown, field: string) {\n\tif (typeof value !== \"string\" || !value || hasControlCharacter(value)) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must be configured.`);\n\t}\n\treturn value;\n}\n\nexport function optionalString(value: unknown, field: string) {\n\tif (value === undefined) return undefined;\n\tif (typeof value !== \"string\" || hasControlCharacter(value)) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${field} must be a string.`);\n\t}\n\treturn value.trim() || undefined;\n}\n\nexport function normalizeStoragePath(value: string) {\n\tif (value.trim() === \".\" || value.trim() === \"./\") return \"./\";\n\tconst normalized = value.trim().replace(/^\\/+|\\/+$/gu, \"\");\n\tif (\n\t\t!normalized ||\n\t\tnormalized.length > 1024 ||\n\t\tnormalized.startsWith(\"-\") ||\n\t\tnormalized.includes(\"\\\\\") ||\n\t\thasControlCharacter(normalized) ||\n\t\tnormalized.split(\"/\").some((segment) => !segment || segment === \".\" || segment === \"..\")\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync settings: storage.path must be a safe relative path.\");\n\t}\n\treturn normalized;\n}\n\nexport function normalizeS3Endpoint(value: string) {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value.trim());\n\t} catch {\n\t\tthrow new Error(\"Invalid pi-sync S3 endpoint.\");\n\t}\n\tconst loopback =\n\t\turl.hostname === \"127.0.0.1\" || url.hostname === \"localhost\" || url.hostname === \"[::1]\";\n\tif (\n\t\t(url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback)) ||\n\t\turl.username ||\n\t\turl.password ||\n\t\turl.search ||\n\t\turl.hash\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync S3 endpoint: HTTPS is required except for loopback.\");\n\t}\n\turl.pathname = url.pathname.replace(/\\/+$/gu, \"\");\n\treturn url.toString().replace(/\\/$/u, \"\");\n}\n\nexport function normalizeS3Bucket(value: string | undefined) {\n\tconst bucket = requiredString(value, \"S3 bucket\");\n\tif (bucket.includes(\"/\") || bucket.includes(\"\\\\\") || bucket.startsWith(\"-\")) {\n\t\tthrow new Error(\"Invalid pi-sync S3 bucket.\");\n\t}\n\treturn bucket;\n}\n\nfunction hasControlCharacter(value: string) {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Stored settings cannot contain controls.\n\treturn /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(value);\n}\n\nexport function isCloudflareR2Endpoint(endpoint: string | undefined) {\n\tconst value = endpoint?.trim();\n\tif (!value) return false;\n\ttry {\n\t\tconst hostname = new URL(value).hostname.toLowerCase();\n\t\treturn (\n\t\t\thostname === \"r2.cloudflarestorage.com\" || hostname.endsWith(\".r2.cloudflarestorage.com\")\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function ownRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn value && typeof value === \"object\" && !Array.isArray(value)\n\t\t? (value as Record<string, unknown>)\n\t\t: undefined;\n}\n", "import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n\tlocalConfigPath,\n\treadMigratingLocalConfigDocument,\n\tupdateLocalConfigDocument,\n} from \"./config-file.js\";\nimport type { OnSwitchAction, PiSyncSettingsV3 } from \"./settings-types.js\";\nimport { DEFAULT_ON_SWITCH, validateSettingsDocument } from \"./settings-validation.js\";\n\nlet configUpdateQueue: Promise<void> = Promise.resolve();\n\nexport async function requireSettings() {\n\tconst settings = await readLocalConfigObject();\n\tif (!settings) {\n\t\tthrow new Error(\n\t\t\t`Missing pi-sync settings. Open /sync and choose Set up sync, or create ${localConfigPath()}.`,\n\t\t);\n\t}\n\treturn settings;\n}\n\nexport async function configuredSyncSetupNames() {\n\tconst settings = await readLocalConfigObject();\n\treturn settings\n\t\t? Object.keys(settings.syncSetups).sort((left, right) => left.localeCompare(right))\n\t\t: [];\n}\n\nexport async function loadOnSwitch(): Promise<OnSwitchAction> {\n\treturn (await requireSettings()).onSwitch;\n}\n\nexport function localConfigTemplate(): PiSyncSettingsV3 {\n\treturn {\n\t\tversion: 3,\n\t\tonSwitch: DEFAULT_ON_SWITCH,\n\t\tskipSecretScan: false,\n\t\tstorageConnections: {},\n\t\tsyncSetups: {},\n\t};\n}\n\nexport async function readLocalConfigDocument() {\n\tconst document = await readMigratingLocalConfigDocument((settings) => {\n\t\tvalidateSettingsDocument(settings);\n\t});\n\tif (document) validateSettingsDocument(document.parsed);\n\treturn document;\n}\n\nexport async function readLocalConfigObject(): Promise<PiSyncSettingsV3 | undefined> {\n\treturn (await readLocalConfigDocument())?.parsed as PiSyncSettingsV3 | undefined;\n}\n\nexport function updateLocalConfig(\n\tupdate: (current: PiSyncSettingsV3) => PiSyncSettingsV3,\n\tsignal?: AbortSignal,\n) {\n\tconst operation = configUpdateQueue.then(() => {\n\t\tsignal?.throwIfAborted();\n\t\treturn performLocalConfigUpdate(update, signal);\n\t});\n\tconfigUpdateQueue = operation.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\treturn operation;\n}\n\nasync function performLocalConfigUpdate(\n\tupdate: (current: PiSyncSettingsV3) => PiSyncSettingsV3,\n\tsignal?: AbortSignal,\n) {\n\treturn updateLocalConfigDocument(localConfigTemplate(), update, validateSettingsDocument, signal);\n}\n\nexport async function writeLocalConfigObject(value: PiSyncSettingsV3 | Record<string, unknown>) {\n\tvalidateSettingsDocument(value as Record<string, unknown>);\n\tconst configPath = localConfigPath();\n\tawait fs.mkdir(path.dirname(configPath), { recursive: true });\n\ttry {\n\t\tconst stat = await fs.lstat(configPath);\n\t\tif (stat.isSymbolicLink())\n\t\t\tthrow new Error(`Refusing to overwrite symlinked pi-sync settings: ${configPath}`);\n\t\tif (!stat.isFile()) throw new Error(`pi-sync settings are not a regular file: ${configPath}`);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t}\n\tconst temporaryPath = path.join(\n\t\tpath.dirname(configPath),\n\t\t`.${path.basename(configPath)}.${process.pid}.${randomUUID()}.tmp`,\n\t);\n\tlet handle: fs.FileHandle | undefined;\n\ttry {\n\t\thandle = await fs.open(temporaryPath, \"wx\", 0o600);\n\t\tawait handle.writeFile(`${JSON.stringify(value, null, \"\\t\")}\\n`, \"utf8\");\n\t\tif (process.platform !== \"win32\") await handle.chmod(0o600);\n\t\tawait handle.sync();\n\t\tawait handle.close();\n\t\thandle = undefined;\n\t\tawait fs.rename(temporaryPath, configPath);\n\t} catch (error) {\n\t\tawait handle?.close().catch(() => undefined);\n\t\tawait fs.rm(temporaryPath, { force: true }).catch(() => undefined);\n\t\tthrow error;\n\t}\n}\n", "import { createHash } from \"node:crypto\";\nimport { backendIdentityCoordinates } from \"../backends/backend-identity.js\";\nimport {\n\tnormalizeGitBranch,\n\tnormalizeGitDirectory,\n\tnormalizeGitRemote,\n} from \"../backends/git/git-config.js\";\nimport { normalizeWebDavPath, normalizeWebDavUrl } from \"../backends/webdav/webdav-config.js\";\nimport { normalizeSyncInclude } from \"../sync/sync-policy.js\";\nimport { localConfigPath, readActiveLocalConfigDocumentForRepair } from \"./config-file.js\";\nimport { requireSettings } from \"./settings-store.js\";\nimport type {\n\tAnySyncConfig,\n\tOnSwitchAction,\n\tPartialConfig,\n\tPiSyncSettingsV3,\n\tStorageConnectionSettings,\n\tSyncSetupSettings,\n} from \"./settings-types.js\";\nimport {\n\tDEFAULT_ON_SWITCH,\n\tisCloudflareR2Endpoint,\n\tnormalizeS3Bucket,\n\tnormalizeS3Endpoint,\n\tnormalizeStoragePath,\n\toptionalString,\n\townObject,\n\trequiredString,\n\tvalidateConfigName,\n\tvalidateSettingsDocument,\n} from \"./settings-validation.js\";\n\nexport async function loadConfig(setupName?: string): Promise<AnySyncConfig> {\n\treturn configFromSettings(await requireSettings(), setupName);\n}\n\n/** A background freshness read must never trigger legacy-file publication. */\nexport async function loadConfigForCheck(): Promise<AnySyncConfig> {\n\tconst document = await readActiveLocalConfigDocumentForRepair();\n\tif (!document) throw new Error(`Missing pi-sync settings: ${localConfigPath()}`);\n\tvalidateSettingsDocument(document.parsed);\n\treturn configFromSettings(document.parsed as PiSyncSettingsV3);\n}\n\nfunction configFromSettings(settings: PiSyncSettingsV3, setupName?: string): AnySyncConfig {\n\tconst selectedName = setupName ?? settings.activeSyncSetup;\n\tif (!selectedName) throw new Error(\"No sync setups are configured.\");\n\tvalidateConfigName(selectedName, \"sync setup\");\n\tconst setup = ownObject<SyncSetupSettings>(settings.syncSetups, selectedName);\n\tif (!setup)\n\t\tthrow new Error(`Invalid pi-sync settings: sync setup \u201C${selectedName}\u201D was not found.`);\n\tconst connectionName = setup.storage.connection;\n\tconst connection = ownObject<StorageConnectionSettings>(\n\t\tsettings.storageConnections,\n\t\tconnectionName,\n\t);\n\tif (!connection) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: sync setup \u201C${selectedName}\u201D references missing storage connection \u201C${connectionName}\u201D.`,\n\t\t);\n\t}\n\treturn resolveSyncConfig(\n\t\tselectedName,\n\t\tsetup,\n\t\tconnectionName,\n\t\tconnection,\n\t\tsettings.onSwitch,\n\t\tsettings.skipSecretScan ?? false,\n\t);\n}\n\nexport type SyncSetupStorageReview = Pick<\n\tPartialConfig,\n\t\"connectionName\" | \"storageKind\" | \"storagePath\" | \"bucket\" | \"branch\"\n>;\n\n/** A validated setup-facing projection used by manager and settings UI. */\nexport async function loadPartialConfig(setupName?: string): Promise<PartialConfig> {\n\tconst config = await loadConfig(setupName);\n\treturn {\n\t\tsetupName: config.setupName,\n\t\t...storageReviewFromConfig(config),\n\t\tinclude: [...config.include],\n\t\tautomatic: config.automatic,\n\t\tonSwitch: config.onSwitch,\n\t};\n}\n\nexport function syncSetupStorageReview(\n\tsetupName: string,\n\tsetup: SyncSetupSettings,\n\tconnectionName: string,\n\tconnection: StorageConnectionSettings,\n): SyncSetupStorageReview {\n\treturn storageReviewFromConfig(\n\t\tresolveSyncConfig(setupName, setup, connectionName, connection, DEFAULT_ON_SWITCH, false),\n\t);\n}\n\nexport function syncSetupReviewIdentity(\n\tsetupName: string,\n\tsetup: SyncSetupSettings,\n\tconnectionName: string,\n\tconnection: StorageConnectionSettings,\n) {\n\treturn syncConfigReviewIdentity(\n\t\tresolveSyncConfig(setupName, setup, connectionName, connection, DEFAULT_ON_SWITCH, false),\n\t);\n}\n\nexport function syncConfigReviewIdentity(config: AnySyncConfig) {\n\treturn JSON.stringify([\n\t\tconfig.setupName,\n\t\tconfig.connectionName,\n\t\tbackendIdentityCoordinates(config),\n\t\tconfig.include,\n\t\tconfig.automatic,\n\t]);\n}\n\nexport function syncConfigReviewFingerprint(config: AnySyncConfig) {\n\treturn createHash(\"sha256\").update(syncConfigReviewIdentity(config)).digest(\"hex\");\n}\n\n/** Internal freshness token, including credentials; never display or persist it. */\nexport function syncCheckConfigFingerprint(config: AnySyncConfig) {\n\treturn createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n}\n\nfunction storageReviewFromConfig(config: AnySyncConfig): SyncSetupStorageReview {\n\treturn {\n\t\tconnectionName: config.connectionName,\n\t\tstorageKind: config.backend.type,\n\t\tstoragePath: config.storagePath,\n\t\t...(config.backend.type === \"s3\"\n\t\t\t? { bucket: config.backend.destination.bucket }\n\t\t\t: config.backend.type === \"git\"\n\t\t\t\t? { branch: config.backend.destination.branch }\n\t\t\t\t: {}),\n\t};\n}\n\nfunction resolveSyncConfig(\n\tsetupName: string,\n\tsetup: SyncSetupSettings,\n\tconnectionName: string,\n\tconnection: StorageConnectionSettings,\n\tonSwitch: OnSwitchAction,\n\tskipSecretScan: boolean,\n): AnySyncConfig {\n\tconst storagePath = normalizeStoragePath(setup.storage.path);\n\tconst namespace =\n\t\tstoragePath === \"./\" ? \"root\" : storagePath.slice(storagePath.lastIndexOf(\"/\") + 1);\n\tconst include = normalizeSyncInclude(setup.sync.include);\n\tconst common = {\n\t\tsetupName,\n\t\tconnectionName,\n\t\tstoragePath,\n\t\tsnapshotIdentity: namespace,\n\t\tinclude,\n\t\tautomatic: setup.sync.automatic,\n\t\tonSwitch,\n\t\tskipSecretScan,\n\t};\n\tif (connection.type === \"git\") {\n\t\treturn {\n\t\t\t...common,\n\t\t\tbackend: {\n\t\t\t\ttype: \"git\",\n\t\t\t\tprofile: { kind: \"git\", remote: normalizeGitRemote(connection.remote) as string },\n\t\t\t\tdestination: {\n\t\t\t\t\tbranch: normalizeGitBranch(setup.storage.branch),\n\t\t\t\t\tdirectory: normalizeGitDirectory(storagePath),\n\t\t\t\t\tnamespace,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\tif (connection.type === \"webdav\") {\n\t\treturn {\n\t\t\t...common,\n\t\t\tbackend: {\n\t\t\t\ttype: \"webdav\",\n\t\t\t\tprofile: {\n\t\t\t\t\tkind: \"webdav\",\n\t\t\t\t\turl: normalizeWebDavUrl(connection.url) as string,\n\t\t\t\t\tusername: connection.credentials.username,\n\t\t\t\t\tpassword: connection.credentials.password,\n\t\t\t\t},\n\t\t\t\tdestination: { path: normalizeWebDavPath(storagePath), namespace },\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\t...common,\n\t\tbackend: {\n\t\t\ttype: \"s3\",\n\t\t\tprofile: {\n\t\t\t\tkind: isCloudflareR2Endpoint(connection.endpoint) ? \"r2\" : \"s3-compatible\",\n\t\t\t\tendpoint: normalizeS3Endpoint(connection.endpoint),\n\t\t\t\tregion: requiredString(connection.region, \"S3 region\"),\n\t\t\t\taccessKeyId: connection.credentials.accessKeyId,\n\t\t\t\tsecretAccessKey: connection.credentials.secretAccessKey,\n\t\t\t\tsessionToken: optionalString(connection.credentials.sessionToken, \"S3 session token\"),\n\t\t\t},\n\t\t\tdestination: {\n\t\t\t\tbucket: normalizeS3Bucket(setup.storage.bucket),\n\t\t\t\tprefix: storagePath,\n\t\t\t\tnamespace,\n\t\t\t},\n\t\t},\n\t};\n}\n\nexport function sessionTokenWarnings(config: { endpoint?: string; sessionToken?: string }) {\n\tif (!isCloudflareR2Endpoint(config.endpoint) || !config.sessionToken) return [];\n\treturn [\n\t\t\"session token: configured for Cloudflare R2; if R2 rejects X-Amz-Security-Token, pi-sync retries once without it. R2 static access keys usually do not need a session token.\",\n\t];\n}\n\nexport function syncSessionsWarnings(config: { include: readonly string[] }) {\n\tif (!config.include.includes(\"sessions\")) return [];\n\treturn [\n\t\t\"sessions: included; Pi session JSONL can contain prompts, tool output, file paths, images, and secrets. Sync sessions only to storage you trust.\",\n\t];\n}\n\nexport function isEnabled(value: boolean | string | undefined, defaultValue: boolean) {\n\tif (value === undefined) return defaultValue;\n\tif (typeof value === \"boolean\") return value;\n\treturn ![\"0\", \"false\", \"no\", \"off\"].includes(value.trim().toLowerCase());\n}\n\nexport function isExplicitlyEnabled(value: boolean | string | undefined) {\n\tif (typeof value === \"boolean\") return value;\n\treturn [\"1\", \"true\", \"yes\", \"on\"].includes(value?.trim().toLowerCase() ?? \"\");\n}\n"],
5
- "mappings": "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",
6
- "names": ["installed", "path", "path"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/state/sync-state-store.ts"],
4
- "sourcesContent": ["import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { backendIdentityCoordinates } from \"../backends/backend-identity.js\";\nimport { safeName } from \"../paths.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { readJsonIfExists, writeJson } from \"./json-file.js\";\nimport { stateDir } from \"./state-directory.js\";\nimport type { SyncState } from \"./state-types.js\";\n\nconst STATE_VERSION = 2;\n\n/** Bounded observation token; do not retain the full baseline in passive UI state. */\nexport function syncStateFingerprint(state: SyncState) {\n\treturn createHash(\"sha256\").update(JSON.stringify(state)).digest(\"hex\");\n}\n\nexport async function readState(profile: string): Promise<SyncState> {\n\treturn (\n\t\t(await readJsonIfExists<SyncState>(statePath(profile))) ?? {\n\t\t\tversion: STATE_VERSION,\n\t\t\tprofile,\n\t\t\tlastFileHashes: {},\n\t\t}\n\t);\n}\n\nexport async function writeState(profile: string, state: SyncState) {\n\tawait writeJson(statePath(profile), state);\n}\n\nexport async function readStateForConfig(config: AnySyncConfig): Promise<SyncState> {\n\treturn (\n\t\t(await readJsonIfExists<SyncState>(statePathForConfig(config))) ?? {\n\t\t\tversion: STATE_VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastFileHashes: {},\n\t\t}\n\t);\n}\n\nexport async function writeStateForConfig(config: AnySyncConfig, state: SyncState) {\n\tawait writeJson(statePathForConfig(config), state);\n}\n\nexport function statePathForConfig(config: AnySyncConfig) {\n\tconst identity = backendIdentityCoordinates(config);\n\tconst hash = createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 16);\n\treturn path.join(stateDir(), \"setups\", `${config.backend.type}-${hash}.state.json`);\n}\n\nfunction statePath(profile: string) {\n\treturn path.join(stateDir(), `${safeName(profile)}.state.json`);\n}\n\nexport function lockPath() {\n\treturn path.join(stateDir(), \"lock\");\n}\n\nexport async function ensureStateDir() {\n\tawait fs.mkdir(stateDir(), { recursive: true });\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AACf,OAAO,UAAU;AAQjB,IAAM,gBAAgB;AAGf,SAAS,qBAAqB,OAAkB;AACtD,SAAO,WAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,KAAK,CAAC,EAAE,OAAO,KAAK;AACvE;AAgBA,eAAsB,mBAAmB,QAA2C;AACnF,SACE,MAAM,iBAA4B,mBAAmB,MAAM,CAAC,KAAM;AAAA,IAClE,SAAS;AAAA,IACT,SAAS,OAAO;AAAA,IAChB,gBAAgB,CAAC;AAAA,EAClB;AAEF;AAEA,eAAsB,oBAAoB,QAAuB,OAAkB;AAClF,QAAM,UAAU,mBAAmB,MAAM,GAAG,KAAK;AAClD;AAEO,SAAS,mBAAmB,QAAuB;AACzD,QAAM,WAAW,2BAA2B,MAAM;AAClD,QAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAC5E,SAAO,KAAK,KAAK,SAAS,GAAG,UAAU,GAAG,OAAO,QAAQ,IAAI,IAAI,IAAI,aAAa;AACnF;AAMO,SAAS,WAAW;AAC1B,SAAO,KAAK,KAAK,SAAS,GAAG,MAAM;AACpC;AAEA,eAAsB,iBAAiB;AACtC,QAAM,GAAG,MAAM,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/commands/command.ts"],
4
- "sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport type { CommandArgumentCompletion, CommandOptions } from \"./command-types.js\";\n\nconst YES_FLAG_COMPLETIONS: readonly CommandArgumentCompletion[] = [\n\t{ value: \"--yes\", label: \"--yes\", description: \"Skip confirmation prompts\" },\n\t{ value: \"-y\", label: \"-y\", description: \"Skip confirmation prompts\" },\n];\nexport const SYNC_COMMANDS = [\n\t{ name: \"help\", description: \"Show command usage\" },\n\t{ name: \"use\", description: \"Switch the current sync setup\", usageSuffix: \" <setup>\" },\n\t{ name: \"init\", description: \"Create local config template\" },\n\t{ name: \"config\", description: \"Show resolved configuration\" },\n\t{ name: \"files\", description: \"Choose included content\" },\n\t{ name: \"status\", description: \"Show sync status\" },\n\t{ name: \"diff\", description: \"Show local/remote diff\" },\n\t{ name: \"doctor\", description: \"Check config, secrets, and lock state\" },\n\t{ name: \"push\", description: \"Upload local settings\" },\n\t{ name: \"pull\", description: \"Apply remote settings\" },\n\t{ name: \"sync\", description: \"Push or pull as needed\" },\n\t{ name: \"history\", description: \"Show recent remote snapshots\" },\n\t{ name: \"rollback\", description: \"Apply a previous snapshot\", usageSuffix: \" <snapshot>\" },\n\t{ name: \"migrate-state\", description: \"Move legacy state into pi-sync/\" },\n\t{ name: \"unlock\", description: \"Remove a stale local lock\", usageSuffix: \" --stale\" },\n] as const;\n\nexport type SyncCommandName = (typeof SYNC_COMMANDS)[number][\"name\"];\n\nconst SYNC_COMMAND_COMPLETIONS: readonly CommandArgumentCompletion[] = SYNC_COMMANDS.map(\n\t({ name, description }) => ({ value: name, label: name, description }),\n);\nlet setupCompletionNames: string[] = [];\n\nexport function setSyncSetupCompletions(names: readonly string[]) {\n\tsetupCompletionNames = [...new Set(names)].sort((left, right) => left.localeCompare(right));\n}\nconst SETUP_FLAG_COMPLETION = {\n\tvalue: \"--setup\",\n\tlabel: \"--setup\",\n\tdescription: \"Address a sync setup without switching\",\n} as const;\nconst SYNC_FLAG_COMPLETIONS: Record<string, readonly CommandArgumentCompletion[]> = {\n\tconfig: [SETUP_FLAG_COMPLETION],\n\tfiles: [SETUP_FLAG_COMPLETION],\n\tstatus: [SETUP_FLAG_COMPLETION],\n\tdiff: [SETUP_FLAG_COMPLETION],\n\tdoctor: [SETUP_FLAG_COMPLETION],\n\tpush: [\n\t\t...YES_FLAG_COMPLETIONS,\n\t\t{ value: \"--force\", label: \"--force\", description: \"Overwrite visible remote changes\" },\n\t\tSETUP_FLAG_COMPLETION,\n\t],\n\tpull: [\n\t\t...YES_FLAG_COMPLETIONS,\n\t\t{ value: \"--force\", label: \"--force\", description: \"Overwrite local changes\" },\n\t\tSETUP_FLAG_COMPLETION,\n\t],\n\tsync: [\n\t\t...YES_FLAG_COMPLETIONS,\n\t\t{ value: \"--force\", label: \"--force\", description: \"Resolve conflicts by forcing action\" },\n\t\tSETUP_FLAG_COMPLETION,\n\t],\n\thistory: [SETUP_FLAG_COMPLETION],\n\trollback: [...YES_FLAG_COMPLETIONS, SETUP_FLAG_COMPLETION],\n\t\"migrate-state\": YES_FLAG_COMPLETIONS,\n\tunlock: [{ value: \"--stale\", label: \"--stale\", description: \"Remove only a stale lock\" }],\n};\n\nexport function splitArgs(input: string) {\n\treturn (\n\t\tinput.match(/(?:[^\\s\"']+|\"[^\"]*\"|'[^']*')+/g)?.map((arg) => arg.replace(/^['\"]|['\"]$/g, \"\")) ??\n\t\t[]\n\t);\n}\n\nexport function parseOptions(args: string[]): CommandOptions {\n\tconst values: string[] = [];\n\tlet yes = false;\n\tlet force = false;\n\tlet stale = false;\n\tlet setup: string | undefined;\n\tfor (let index = 0; index < args.length; index += 1) {\n\t\tconst arg = args[index];\n\t\tif (arg === \"--yes\" || arg === \"-y\") yes = true;\n\t\telse if (arg === \"--force\") force = true;\n\t\telse if (arg === \"--stale\") stale = true;\n\t\telse if (arg === \"--setup\") {\n\t\t\tconst name = args[index + 1];\n\t\t\tif (!name || name.startsWith(\"-\")) throw new Error(\"--setup requires a sync setup name.\");\n\t\t\tif (setup !== undefined) throw new Error(\"--setup may be provided only once.\");\n\t\t\tsetup = name;\n\t\t\tindex += 1;\n\t\t} else if (arg.startsWith(\"-\")) {\n\t\t\tthrow new Error(`Unknown sync option: ${arg}`);\n\t\t} else values.push(arg);\n\t}\n\treturn {\n\t\tyes,\n\t\tforce,\n\t\tstale,\n\t\tsilent: false,\n\t\treload: true,\n\t\tauto: false,\n\t\t...(setup === undefined ? {} : { setup }),\n\t\targs: values,\n\t};\n}\n\nexport function validateCommandOptions(command: string, options: CommandOptions) {\n\tconst setupAllowed = new Set([\n\t\t\"config\",\n\t\t\"files\",\n\t\t\"status\",\n\t\t\"diff\",\n\t\t\"doctor\",\n\t\t\"push\",\n\t\t\"pull\",\n\t\t\"sync\",\n\t\t\"history\",\n\t\t\"rollback\",\n\t]);\n\tif (options.setup && !setupAllowed.has(command)) {\n\t\tthrow new Error(`--setup is not supported by /sync ${command}.`);\n\t}\n\tif (options.yes && ![\"push\", \"pull\", \"sync\", \"rollback\", \"migrate-state\"].includes(command)) {\n\t\tthrow new Error(`Confirmation/force options are not supported by /sync ${command}.`);\n\t}\n\tif (options.force && ![\"push\", \"pull\", \"sync\", \"rollback\"].includes(command)) {\n\t\tthrow new Error(`Confirmation/force options are not supported by /sync ${command}.`);\n\t}\n\tif (options.stale && command !== \"unlock\") {\n\t\tthrow new Error(`--stale is not supported by /sync ${command}.`);\n\t}\n\tconst expectedValues = command === \"rollback\" || command === \"use\" ? 1 : 0;\n\tif (options.args.length !== expectedValues) {\n\t\tif (command === \"rollback\")\n\t\t\tthrow new Error(\"Usage: /sync rollback <snapshot-id> [--yes] [--setup <name>]\");\n\t\tif (command === \"use\") throw new Error(\"Usage: /sync use <setup>\");\n\t\tthrow new Error(`Unexpected argument for /sync ${command}: ${options.args.join(\" \")}`);\n\t}\n}\n\nexport function completeSyncArguments(argumentPrefix: string): CommandArgumentCompletion[] | null {\n\tconst prefix = argumentPrefix.trimStart();\n\tif (prefix === \"\") return [...SYNC_COMMAND_COMPLETIONS];\n\n\tconst trailingSpace = /\\s$/.test(prefix);\n\tconst tokens = splitArgs(prefix);\n\tif (tokens.length === 0) return [...SYNC_COMMAND_COMPLETIONS];\n\n\tconst [command] = tokens;\n\tif (tokens.length === 1 && !trailingSpace) {\n\t\tconst matches = SYNC_COMMAND_COMPLETIONS.filter((item) => item.value.startsWith(command));\n\t\treturn matches.length > 0 ? [...matches] : null;\n\t}\n\n\tconst args = tokens.slice(1);\n\tif (command === \"use\") {\n\t\tif (args.length > 1 || (trailingSpace && args.length > 0)) return null;\n\t\treturn completeSetupValue(prefix, trailingSpace ? \"\" : (args[0] ?? \"\"));\n\t}\n\tconst setupFlagIndex = args.lastIndexOf(\"--setup\");\n\tif (setupFlagIndex >= 0 && setupFlagIndex === args.length - (trailingSpace ? 1 : 2)) {\n\t\tconst currentSetup = trailingSpace ? \"\" : (args.at(-1) ?? \"\");\n\t\tif (!currentSetup.startsWith(\"-\")) return completeSetupValue(prefix, currentSetup);\n\t}\n\n\tconst flagCompletions = SYNC_FLAG_COMPLETIONS[command];\n\tif (!flagCompletions) return null;\n\n\tconst completedArgs = trailingSpace ? args : args.slice(0, -1);\n\tconst completedValues = completedArgs.filter((arg) => !arg.startsWith(\"-\"));\n\tif (command === \"rollback\" ? completedValues.length > 1 : completedValues.length > 0) {\n\t\treturn null;\n\t}\n\n\tconst current = trailingSpace ? \"\" : (args.at(-1) ?? \"\");\n\tif (current && !current.startsWith(\"-\")) return null;\n\n\tconst currentRaw = trailingSpace ? \"\" : (prefix.match(/\\S+$/)?.[0] ?? \"\");\n\tconst completionPrefix = trailingSpace\n\t\t? prefix\n\t\t: prefix.slice(0, prefix.length - currentRaw.length);\n\tconst matches = flagCompletions.filter((item) => item.value.startsWith(current));\n\treturn matches.length > 0\n\t\t? matches.map((item) => ({ ...item, value: `${completionPrefix}${item.value}` }))\n\t\t: null;\n}\n\nfunction completeSetupValue(prefix: string, current: string) {\n\tconst currentRaw = current ? (prefix.match(/\\S+$/u)?.[0] ?? \"\") : \"\";\n\tconst completionPrefix = currentRaw ? prefix.slice(0, prefix.length - currentRaw.length) : prefix;\n\tconst matches = setupCompletionNames.filter((name) => name.startsWith(current));\n\treturn matches.length > 0\n\t\t? matches.map((name) => ({\n\t\t\t\tvalue: `${completionPrefix}${name}`,\n\t\t\t\tlabel: name,\n\t\t\t\tdescription: \"Sync setup\",\n\t\t\t}))\n\t\t: null;\n}\n\nexport function syncMenuOptions() {\n\treturn SYNC_COMMANDS.map(({ name, description }) => `${name} \u2014 ${description}`);\n}\n\nexport function syncCommandFromMenuOption(option: string): SyncCommandName | undefined {\n\treturn SYNC_COMMANDS.find(({ name, description }) => option === `${name} \u2014 ${description}`)?.name;\n}\n\nexport async function resolveSyncCommand(input: string, ctx: ExtensionCommandContext) {\n\tconst [subcommand, ...rest] = splitArgs(input);\n\tif (subcommand) return { subcommand, rest };\n\tif (!ctx.hasUI) {\n\t\tctx.ui.notify(usage(), \"info\");\n\t\treturn undefined;\n\t}\n\n\tconst selectedOption = await ctx.ui.select(\"pi-sync\", syncMenuOptions());\n\tconst selected = selectedOption ? syncCommandFromMenuOption(selectedOption) : undefined;\n\tif (!selected) return undefined;\n\tif (selected !== \"rollback\") return { subcommand: selected, rest: [] };\n\n\tconst target = (await ctx.ui.input(\"Rollback snapshot\", \"snapshot id\"))?.trim();\n\tif (!target) {\n\t\tctx.ui.notify(\"Rollback cancelled.\", \"info\");\n\t\treturn undefined;\n\t}\n\treturn { subcommand: selected, rest: [target] };\n}\n\nexport function usage() {\n\tconst commands = SYNC_COMMANDS.map(\n\t\t(command) => `${command.name}${\"usageSuffix\" in command ? command.usageSuffix : \"\"}`,\n\t).join(\", \");\n\treturn [\n\t\t\"Usage: /sync <command>\",\n\t\t`Commands: ${commands}`,\n\t\t\"Automatic sync: background startup checks only; use /sync to review and transfer. At shutdown, selected content is pushed automatically only when sessions are included. Startup checks run in TUI/RPC, not print/JSON.\",\n\t\t\"Settings: use /sync init or edit storage connections and sync setups in ~/.pi/agent/pi-sync.json (or the configured Pi agent directory). Version 1 and version 2 settings are unsupported and are never rewritten.\",\n\t].join(\"\\n\");\n}\n"],
5
- "mappings": "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",
6
- "names": ["matches"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sync/sync-error-guidance.ts"],
4
- "sourcesContent": ["import { errorMessage } from \"./sync-errors.js\";\n\n/** Add recovery advice without changing backend outcome semantics or printing error causes. */\nexport function syncErrorGuidance(error: unknown): string {\n\tconst detail = errorMessage(error);\n\tconst message = detail.length > 1200 ? `${detail.slice(0, 1200)}\u2026 (details truncated)` : detail;\n\tconst code = (error as NodeJS.ErrnoException | undefined)?.code;\n\tconst status = (error as { status?: number } | undefined)?.status;\n\tlet next: string;\n\tif (code === \"ENOSPC\") {\n\t\tnext = \"Free disk space for the private pi-sync settings/state directory, then retry.\";\n\t} else if (code && [\"EACCES\", \"EPERM\", \"EROFS\"].includes(code)) {\n\t\tnext = \"Check write access to the private pi-sync settings/state directory, then retry.\";\n\t} else if (code && [\"EBUSY\", \"EIO\", \"EMFILE\", \"ENFILE\"].includes(code)) {\n\t\tnext =\n\t\t\t\"Check local disk availability and other processes using the private settings file, then retry.\";\n\t} else if (/changed while|type changed|reopen/iu.test(message)) {\n\t\tnext = \"Reopen the item in /sync and review its current settings before saving again.\";\n\t} else if (\n\t\tstatus === 401 ||\n\t\tstatus === 403 ||\n\t\t/Permission denied|Authentication failed|HTTP (401|403)|failed \\((401|403)\\)/iu.test(message)\n\t) {\n\t\tnext =\n\t\t\t\"Check the storage connection's credentials and remote permissions in /sync \u2192 More \u2192 Storage connections.\";\n\t} else if (status === 404 || /HTTP 404|failed \\(404\\)/iu.test(message)) {\n\t\tnext =\n\t\t\t\"Verify the connection address and setup's bucket, branch, or path with your provider; this response alone does not prove which resource is missing.\";\n\t} else if (status !== undefined && status >= 500) {\n\t\tnext = \"Check your storage provider's service status, then retry Check setup before syncing.\";\n\t} else if (\n\t\t/timed out|timeout|request failed|resolve host|Could not resolve|ENOTFOUND|ECONNREFUSED/iu.test(\n\t\t\tmessage,\n\t\t)\n\t) {\n\t\tnext =\n\t\t\t\"Check the server address and network connection, then run /sync doctor for the affected setup.\";\n\t} else if (/strong ETag|If-Match|If-None-Match|precondition|conditional header/iu.test(message)) {\n\t\tnext =\n\t\t\t\"Ask your provider to check strong ETags and conditional writes, including proxy behavior, or choose compatible storage. Do not bypass these safety checks.\";\n\t} else if (/spawn git ENOENT/iu.test(message)) {\n\t\tnext = \"Install Git 2.30 or newer and make sure Pi can find git on PATH, then retry.\";\n\t} else if (/response exceeds.*byte limit/iu.test(message)) {\n\t\tnext =\n\t\t\t\"Verify the storage endpoint; the server returned an unexpectedly large response. Check your provider's logs before retrying.\";\n\t} else if (/settings|config|already exists|duplicates|same normalized/iu.test(message)) {\n\t\tnext =\n\t\t\t\"Correct the named field or item in /sync. If the settings file is invalid, repair it before retrying; do not replace it with defaults.\";\n\t} else {\n\t\tnext = \"Open /sync \u2192 More \u2192 Check setup and review the reported checks before retrying.\";\n\t}\n\treturn `${message}\\n${next}`;\n}\n"],
5
- "mappings": ";;;;;;;AAGO,SAAS,kBAAkB,OAAwB;AACzD,QAAM,SAAS,aAAa,KAAK;AACjC,QAAM,UAAU,OAAO,SAAS,OAAO,GAAG,OAAO,MAAM,GAAG,IAAI,CAAC,+BAA0B;AACzF,QAAM,OAAQ,OAA6C;AAC3D,QAAM,SAAU,OAA2C;AAC3D,MAAI;AACJ,MAAI,SAAS,UAAU;AACtB,WAAO;AAAA,EACR,WAAW,QAAQ,CAAC,UAAU,SAAS,OAAO,EAAE,SAAS,IAAI,GAAG;AAC/D,WAAO;AAAA,EACR,WAAW,QAAQ,CAAC,SAAS,OAAO,UAAU,QAAQ,EAAE,SAAS,IAAI,GAAG;AACvE,WACC;AAAA,EACF,WAAW,sCAAsC,KAAK,OAAO,GAAG;AAC/D,WAAO;AAAA,EACR,WACC,WAAW,OACX,WAAW,OACX,gFAAgF,KAAK,OAAO,GAC3F;AACD,WACC;AAAA,EACF,WAAW,WAAW,OAAO,4BAA4B,KAAK,OAAO,GAAG;AACvE,WACC;AAAA,EACF,WAAW,WAAW,UAAa,UAAU,KAAK;AACjD,WAAO;AAAA,EACR,WACC,2FAA2F;AAAA,IAC1F;AAAA,EACD,GACC;AACD,WACC;AAAA,EACF,WAAW,uEAAuE,KAAK,OAAO,GAAG;AAChG,WACC;AAAA,EACF,WAAW,qBAAqB,KAAK,OAAO,GAAG;AAC9C,WAAO;AAAA,EACR,WAAW,iCAAiC,KAAK,OAAO,GAAG;AAC1D,WACC;AAAA,EACF,WAAW,8DAA8D,KAAK,OAAO,GAAG;AACvF,WACC;AAAA,EACF,OAAO;AACN,WAAO;AAAA,EACR;AACA,SAAO,GAAG,OAAO;AAAA,EAAK,IAAI;AAC3B;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/backends/sync-backend.ts"],
4
- "sourcesContent": ["import type { Snapshot, SnapshotSelection } from \"../snapshot/snapshot-types.js\";\n\nexport type PublicationCapability =\n\t| \"read-check-write-verify\"\n\t| \"conditional-required\"\n\t| \"atomic-conditional\"\n\t| \"lease-protected\";\n\nexport interface RemoteHead {\n\t/** Backend-owned reference used only to retrieve this immutable snapshot. */\n\tsnapshotRef: string;\n\t/** Backend-neutral snapshot content identity retained in local sync state. */\n\tsnapshotId: string;\n\trevision: string;\n\tcreatedAt: string;\n\tmachine: string;\n\tsyncSessions: boolean;\n\t/** Validated lightweight projection; revalidate it against the immutable snapshot before adoption. */\n\tselection?: SnapshotSelection;\n}\n\nexport interface RemoteHistoryEntry {\n\tsnapshotRef: string;\n\tsnapshotId: string;\n\tcreatedAt: string;\n\tmachine: string;\n\tsyncSessions: boolean;\n}\n\nexport type ExpectedRemoteHead = { kind: \"missing\" } | { kind: \"revision\"; revision: string };\n\nexport interface PublishSnapshotOptions {\n\tsignal?: AbortSignal;\n\t/** Called at the backend's active-head commit boundary. */\n\tonCommit?: () => void;\n}\n\nexport interface PublishSnapshotResult {\n\thead: RemoteHead;\n\twarnings: string[];\n}\n\nexport interface BackendDiagnostic {\n\tkey: string;\n\tlevel: \"info\" | \"warning\" | \"error\";\n\tmessage: string;\n}\n\nexport interface SyncBackend {\n\treadonly identity: string;\n\treadonly destination: string;\n\treadonly capability: PublicationCapability;\n\t/** Compare opaque revisions produced by this backend identity. */\n\tsameRevision(left: string, right: string): boolean;\n\treadHead(signal?: AbortSignal): Promise<RemoteHead | undefined>;\n\treadSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot>;\n\tpublishSnapshot(\n\t\tsnapshot: Snapshot,\n\t\texpected: ExpectedRemoteHead,\n\t\toptions?: PublishSnapshotOptions,\n\t): Promise<PublishSnapshotResult>;\n\tlistHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]>;\n\tdiagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]>;\n}\n\nexport class SyncBackendConflictError extends Error {\n\treadonly code = \"SYNC_BACKEND_CONFLICT\";\n\treadonly phase: \"before-commit\" | \"after-commit\";\n\treadonly currentHead?: RemoteHead;\n\treadonly candidateMayHaveBeenActive: boolean;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions: ErrorOptions & {\n\t\t\tphase?: \"before-commit\" | \"after-commit\";\n\t\t\tcurrentHead?: RemoteHead;\n\t\t\tcandidateMayHaveBeenActive?: boolean;\n\t\t} = {},\n\t) {\n\t\tsuper(message, options);\n\t\tthis.name = \"SyncBackendConflictError\";\n\t\tthis.phase = options.phase ?? \"before-commit\";\n\t\tthis.currentHead = options.currentHead;\n\t\tthis.candidateMayHaveBeenActive = options.candidateMayHaveBeenActive ?? false;\n\t}\n}\n\nexport class SyncBackendPublicationOutcomeUnknownError extends Error {\n\treadonly code = \"SYNC_BACKEND_PUBLICATION_OUTCOME_UNKNOWN\";\n\n\tconstructor(message: string, options?: ErrorOptions) {\n\t\tsuper(message, options);\n\t\tthis.name = \"SyncBackendPublicationOutcomeUnknownError\";\n\t}\n}\n\nexport function expectedRemoteHead(head: RemoteHead | undefined): ExpectedRemoteHead {\n\treturn head ? { kind: \"revision\", revision: head.revision } : { kind: \"missing\" };\n}\n"],
5
- "mappings": ";;;;AAiEO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EAC1C,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACC,SACA,UAII,CAAC,GACJ;AACD,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AACZ,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,cAAc,QAAQ;AAC3B,SAAK,6BAA6B,QAAQ,8BAA8B;AAAA,EACzE;AACD;AAEO,IAAM,4CAAN,cAAwD,MAAM;AAAA,EAC3D,OAAO;AAAA,EAEhB,YAAY,SAAiB,SAAwB;AACpD,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AAAA,EACb;AACD;AAEO,SAAS,mBAAmB,MAAkD;AACpF,SAAO,OAAO,EAAE,MAAM,YAAY,UAAU,KAAK,SAAS,IAAI,EAAE,MAAM,UAAU;AACjF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/commands/setup-completions.ts", "../../src/ui/setup/text-input.ts", "../../src/ui/setup/setup-location-ui.ts", "../../src/ui/setup/setup-prompts.ts", "../../src/ui/setup/setup-review.ts", "../../src/ui/setup/git-ui.ts", "../../src/ui/secret-input.ts", "../../src/ui/setup/s3-credentials-ui.ts", "../../src/ui/setup/s3-ui.ts", "../../src/ui/setup/webdav-ui.ts"],
4
- "sourcesContent": ["import { configuredSyncSetupNames } from \"../settings/settings-store.js\";\nimport { setSyncSetupCompletions } from \"./command.js\";\n\nexport async function refreshTargetCompletions() {\n\tsetSyncSetupCompletions(await configuredSyncSetupNames());\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { normalizeS3Bucket, requiredString } from \"../../settings/settings-validation.js\";\nimport { errorMessage } from \"../../sync/sync-errors.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\n\nexport type ValidateInput = (value: string) => string | Promise<string>;\n\nexport async function requiredExistingBucket(\n\tctx: ExtensionCommandContext,\n\texample: string,\n\tsignal?: AbortSignal,\n) {\n\treturn requiredValueInput(\n\t\tctx,\n\t\t\"Existing bucket\\n\\nThe bucket must already exist; pi-sync will not create it.\",\n\t\texample,\n\t\tsignal,\n\t\tnormalizeS3Bucket,\n\t);\n}\n\nexport async function requiredInput(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\tdefaultValue: string,\n\tsignal?: AbortSignal,\n\tvalidate?: ValidateInput,\n) {\n\treturn promptTextInput(ctx, title, { defaultValue, validate, rejectPlaceholders: true }, signal);\n}\n\nexport async function requiredValueInput(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\texample: string,\n\tsignal?: AbortSignal,\n\tvalidate?: ValidateInput,\n) {\n\treturn promptTextInput(ctx, title, { example, validate, rejectPlaceholders: true }, signal);\n}\n\nexport async function promptTextInput(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\toptions: {\n\t\tdefaultValue?: string;\n\t\texample?: string;\n\t\tvalidate?: ValidateInput;\n\t\trejectPlaceholders?: boolean;\n\t},\n\tsignal?: AbortSignal,\n) {\n\t// Pi ignores placeholders. Keep defaults/examples visible; only an explicit blank accepts a default.\n\tconst hint =\n\t\toptions.defaultValue !== undefined\n\t\t\t? `Default: ${safeTerminalText(options.defaultValue)} (leave blank to keep)`\n\t\t\t: `Example: ${safeTerminalText(options.example ?? \"\")}\\nEnter your own value; this example is not a default.`;\n\twhile (true) {\n\t\tsignal?.throwIfAborted();\n\t\tconst value = await ctx.ui.input(`${title}\\n\\n${hint}`, undefined, { signal });\n\t\tsignal?.throwIfAborted();\n\t\tif (value === undefined) return undefined;\n\t\ttry {\n\t\t\tconst normalized = value.trim() || options.defaultValue;\n\t\t\tif (!normalized) throw new Error(`${title.split(\"\\n\")[0]} is required.`);\n\t\t\tif (options.rejectPlaceholders && /[<>]/u.test(normalized)) {\n\t\t\t\tthrow new Error(\"Replace example placeholders such as <account-id> with your own value.\");\n\t\t\t}\n\t\t\tconst checked = requiredString(normalized, title.split(\"\\n\")[0] ?? \"value\");\n\t\t\tconst result = options.validate ? await options.validate(checked) : checked;\n\t\t\tsignal?.throwIfAborted();\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tsignal?.throwIfAborted();\n\t\t\tctx.ui.notify(`${errorMessage(error)} Enter a corrected value, or cancel.`, \"warning\");\n\t\t}\n\t}\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { normalizeGitBranch } from \"../../backends/git/git-config.js\";\nimport { readLocalConfigObject } from \"../../settings/settings-store.js\";\nimport type {\n\tStorageConnectionSettings,\n\tSyncSetupSettings,\n} from \"../../settings/settings-types.js\";\nimport {\n\teffectiveSyncSetupRemoteIdentity,\n\tnormalizeStoragePath,\n\townRecord,\n} from \"../../settings/settings-validation.js\";\nimport { errorMessage } from \"../../sync/sync-errors.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport {\n\tpromptTextInput,\n\trequiredExistingBucket,\n\trequiredInput,\n\trequiredValueInput,\n} from \"./text-input.js\";\n\ninterface ChosenRemoteLocation {\n\tconnectionName: string;\n\tbucket: string;\n\tpath: string;\n}\n\nexport async function chooseInitialRemoteLocation(\n\tctx: ExtensionCommandContext,\n\t_preset: string,\n\tsetupName: string,\n\tsignal?: AbortSignal,\n): Promise<ChosenRemoteLocation | undefined> {\n\tconst choice = await ctx.ui.select(\n\t\t\"Choose storage location\\n\\nUse an existing bucket. ./ stores snapshots at the bucket root; a custom path keeps them in a separate folder.\",\n\t\t[\"Use an existing bucket at ./\", \"Customize remote location\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tif (signal?.aborted || !choice || choice === \"Cancel\") return undefined;\n\tif (choice === \"Customize remote location\")\n\t\treturn chooseCustomRemoteLocation(ctx, setupName, signal);\n\tconst bucket = await requiredExistingBucket(ctx, \"pi-sync\", signal);\n\treturn bucket ? { connectionName: setupName, bucket, path: \"./\" } : undefined;\n}\n\nexport async function chooseAdditionalRemoteLocation(\n\tctx: ExtensionCommandContext,\n\tsettings: Record<string, unknown>,\n\tconnectionName: string,\n\tsetupName: string,\n\tsignal?: AbortSignal,\n): Promise<Omit<ChosenRemoteLocation, \"connectionName\"> | undefined> {\n\tconst setups = ownRecord(settings.syncSetups) ?? {};\n\tconst currentSetup =\n\t\ttypeof settings.activeSyncSetup === \"string\" ? settings.activeSyncSetup : undefined;\n\tconst candidates = Object.entries(setups)\n\t\t.map(([name, value]) => ({ name, storage: ownRecord(ownRecord(value)?.storage) }))\n\t\t.filter(\n\t\t\t(item): item is { name: string; storage: Record<string, unknown> } =>\n\t\t\t\titem.storage?.connection === connectionName && typeof item.storage.bucket === \"string\",\n\t\t);\n\tconst source =\n\t\tcandidates.find((item) => item.name === currentSetup) ??\n\t\tcandidates.sort((left, right) => left.name.localeCompare(right.name))[0];\n\tif (source) {\n\t\tconst suggestedPath = \"./\";\n\t\tconst sameBucketLabel = `Same bucket as \u201C${safeTerminalText(source.name)}\u201D`;\n\t\tconst choice = await ctx.ui.select(\n\t\t\t[\n\t\t\t\t`Storage location for \u201C${safeTerminalText(setupName)}\u201D`,\n\t\t\t\t\"\",\n\t\t\t\t`Existing bucket: ${safeTerminalText(String(source.storage.bucket))}`,\n\t\t\t\t`Remote path: ${safeTerminalText(suggestedPath)}`,\n\t\t\t\t\"./ uses the bucket root. Use a different path or bucket for independent setups.\",\n\t\t\t].join(\"\\n\"),\n\t\t\t[sameBucketLabel, \"Use a different bucket\", \"Customize remote location\", \"Cancel\"],\n\t\t\t{ signal },\n\t\t);\n\t\tif (signal?.aborted || !choice || choice === \"Cancel\") return undefined;\n\t\tif (choice === sameBucketLabel) {\n\t\t\treturn { bucket: String(source.storage.bucket), path: suggestedPath };\n\t\t}\n\t\tif (choice === \"Use a different bucket\") {\n\t\t\tconst bucket = await requiredExistingBucket(ctx, \"pi-sync\", signal);\n\t\t\treturn bucket ? { bucket, path: \"./\" } : undefined;\n\t\t}\n\t\tconst custom = await chooseCustomRemoteLocation(ctx, connectionName, signal);\n\t\treturn custom ? { bucket: custom.bucket, path: custom.path } : undefined;\n\t}\n\n\tconst location = await chooseInitialRemoteLocation(ctx, \"S3\", setupName, signal);\n\treturn location ? { bucket: location.bucket, path: location.path } : undefined;\n}\n\nasync function chooseCustomRemoteLocation(\n\tctx: ExtensionCommandContext,\n\tconnectionName: string,\n\tsignal?: AbortSignal,\n): Promise<ChosenRemoteLocation | undefined> {\n\tconst bucket = await requiredExistingBucket(ctx, \"pi-sync\", signal);\n\tif (!bucket) return undefined;\n\tconst storagePath = await requiredInput(\n\t\tctx,\n\t\t\"Storage path\\n\\nPath inside the bucket, not your local filesystem.\\n./ uses the bucket root. Use different paths for independent setups.\",\n\t\t\"./\",\n\t\tsignal,\n\t\tnormalizeStoragePath,\n\t);\n\tif (!storagePath) return undefined;\n\treturn { connectionName, bucket, path: normalizeStoragePath(storagePath) };\n}\n\n/** Early UI check only; the settings writer still validates uniqueness under its lock. */\nexport async function promptAvailableSetupStorage<T extends SyncSetupSettings[\"storage\"]>(\n\tctx: ExtensionCommandContext,\n\tinitial: T,\n\tsignal?: AbortSignal,\n): Promise<T | undefined> {\n\tlet storage = initial;\n\twhile (!signal?.aborted) {\n\t\tconst settings = await readLocalConfigObject();\n\t\tif (signal?.aborted) return undefined;\n\t\tconst connection = settings?.storageConnections[storage.connection];\n\t\tif (!settings || !connection) throw new Error(\"Storage connection changed; reopen setup.\");\n\t\tconst identity = setupPublicationIdentity(storage, connection);\n\t\tconst occupied = Object.entries(settings.syncSetups).find(\n\t\t\t([, setup]) =>\n\t\t\t\tsetupPublicationIdentity(\n\t\t\t\t\tsetup.storage,\n\t\t\t\t\tsettings.storageConnections[setup.storage.connection],\n\t\t\t\t) === identity,\n\t\t);\n\t\tif (!occupied) return storage;\n\t\tconst git = connection.type === \"git\";\n\t\tconst message = `${git ? \"Git branch\" : \"Storage location\"} is already used by \u201C${safeTerminalText(occupied[0])}\u201D. ${git ? \"Use a different branch; pi-sync owns the entire branch.\" : \"Enter a different storage path, or cancel to choose another connection or bucket.\"}`;\n\t\tctx.ui.notify(message, \"warning\");\n\t\tconst title = `${git ? \"Git branch for the new setup\" : \"Storage path for the new setup\"}\\n\\n${message}`;\n\t\tconst example = git ? \"pi-sync/work\" : \"backups/work\";\n\t\tconst value =\n\t\t\tconnection.type === \"webdav\"\n\t\t\t\t? await promptTextInput(ctx, title, { example }, signal)\n\t\t\t\t: await requiredValueInput(ctx, title, example, signal);\n\t\tif (signal?.aborted || value === undefined) return undefined;\n\t\ttry {\n\t\t\tstorage = git\n\t\t\t\t? { ...storage, branch: normalizeGitBranch(value) }\n\t\t\t\t: { ...storage, path: normalizeStoragePath(value) };\n\t\t} catch (error) {\n\t\t\tctx.ui.notify(safeTerminalText(errorMessage(error)), \"warning\");\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction setupPublicationIdentity(\n\tstorage: SyncSetupSettings[\"storage\"],\n\tconnection: StorageConnectionSettings,\n) {\n\t// Git publications own a complete branch tree; changing only its directory is not isolation.\n\treturn effectiveSyncSetupRemoteIdentity(\n\t\t{\n\t\t\tstorage: connection.type === \"git\" ? { ...storage, path: \"./\" } : storage,\n\t\t\tsync: { include: [], automatic: false },\n\t\t},\n\t\tconnection,\n\t);\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { readLocalConfigObject } from \"../../settings/settings-store.js\";\nimport { validateConfigName } from \"../../settings/settings-validation.js\";\nimport { DEFAULT_SYNC_INCLUDE } from \"../../sync/sync-policy.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport { promptTextInput } from \"./text-input.js\";\n\nexport async function readSetupConnection(name: string, signal?: AbortSignal) {\n\tconst connection = (await readLocalConfigObject())?.storageConnections[name];\n\tsignal?.throwIfAborted();\n\tif (!connection) throw new Error(\"Storage connection changed; reopen setup.\");\n\treturn connection;\n}\n\nexport const AUTOMATIC_SYNC_DESCRIPTION =\n\t\"Check the current setup in the background at startup; review changes in /sync before transferring. At shutdown, automatically push selected content only when sessions are included. No startup dialogs.\";\n\nexport async function chooseSetupContent(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\tconst choice = await ctx.ui.select(\n\t\t\"Choose included content\\n\\nRecommended: Pi settings, instructions, skills, prompts, themes, and extensions.\\nMinimal: settings.json and AGENTS.md.\\nReview the exact paths before saving.\",\n\t\t[\"Recommended Pi settings\", \"Minimal settings\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tsignal?.throwIfAborted();\n\tif (!choice || choice === \"Cancel\") return undefined;\n\treturn choice === \"Minimal settings\" ? [\"settings.json\", \"AGENTS.md\"] : [...DEFAULT_SYNC_INCLUDE];\n}\n\nexport async function chooseAutomaticSync(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\tconst choice = await ctx.ui.select(\n\t\t`Automatic sync for this setup\\n\\n${AUTOMATIC_SYNC_DESCRIPTION}`,\n\t\t[\"Keep automatic sync off\", \"Enable automatic sync\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tsignal?.throwIfAborted();\n\treturn !choice || choice === \"Cancel\" ? undefined : choice === \"Enable automatic sync\";\n}\n\nexport async function chooseSessions(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\tconst choice = await ctx.ui.select(\n\t\t\"Session conversations\\n\\nSessions can contain prompts, tool output, paths, screenshots, and secrets.\",\n\t\t[\"Keep sessions off (recommended)\", \"Include session conversations\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tsignal?.throwIfAborted();\n\tif (!choice || choice === \"Cancel\") return undefined;\n\tif (choice !== \"Include session conversations\") return false;\n\tconst confirmed = await ctx.ui.confirm(\n\t\t\"Include session conversations?\",\n\t\t\"I understand that session JSONL can contain prompts, tool output, paths, screenshots, and secrets.\",\n\t\t{ signal },\n\t);\n\tsignal?.throwIfAborted();\n\treturn confirmed ? true : undefined;\n}\n\nexport function includedContentLines(include: readonly string[], sessions = false) {\n\tconst paths = [...include, ...(sessions && !include.includes(\"sessions\") ? [\"sessions\"] : [])];\n\treturn [\n\t\t`Included content: ${paths.length} paths`,\n\t\t...paths.map((item) => ` ${safeTerminalText(item)}`),\n\t\t`Sessions: ${sessions ? \"On \u2014 privacy warning acknowledged\" : \"Off\"}`,\n\t];\n}\n\nexport async function promptResourceName(\n\tctx: ExtensionCommandContext,\n\tkind: \"sync setup\" | \"storage connection\",\n\tdefaultValue: string,\n\tsignal?: AbortSignal,\n\tliteralBrackets = false,\n) {\n\treturn promptTextInput(\n\t\tctx,\n\t\t`Name this ${kind}\\n\\nA local label, such as home or work.`,\n\t\t{\n\t\t\tdefaultValue,\n\t\t\trejectPlaceholders: !literalBrackets,\n\t\t\tvalidate: async (name) => {\n\t\t\t\tvalidateConfigName(name, kind);\n\t\t\t\tconst settings = await readLocalConfigObject();\n\t\t\t\tsignal?.throwIfAborted();\n\t\t\t\tconst names = kind === \"sync setup\" ? settings?.syncSetups : settings?.storageConnections;\n\t\t\t\tif (names && Object.hasOwn(names, name)) {\n\t\t\t\t\tthrow new Error(`A ${kind} with this name already exists. Choose a different name.`);\n\t\t\t\t}\n\t\t\t\treturn name;\n\t\t\t},\n\t\t},\n\t\tsignal,\n\t);\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\n\n/** A settings draft is committed only after review; retryable I/O failures retain the same draft. */\nexport async function saveReviewedDraft(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\tlines: readonly string[],\n\tlabel: string,\n\tsave: (signal: AbortSignal) => Promise<unknown>,\n\tsignal?: AbortSignal,\n) {\n\tlet saved = false;\n\tlet failure: unknown;\n\tlet failureText: string | undefined;\n\tconst menu = defineMenu<undefined, \"review\", \"save\", ExtensionCommandContext>({\n\t\tstart: \"review\",\n\t\tscreens: {\n\t\t\treview: () => ({\n\t\t\t\tkind: \"review\",\n\t\t\t\ttitle,\n\t\t\t\tcontent: [...(failureText ? [failureText, \"\"] : []), ...lines].join(\"\\n\"),\n\t\t\t\tlines: [\"Review before saving. Back cancels this draft.\"],\n\t\t\t\tformat: { kind: \"text\" },\n\t\t\t\tviewportSize: \"adaptive\",\n\t\t\t\tconfirm: { id: \"save\", label, action: \"save\" },\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\tsave: async ({ signal: actionSignal }) => {\n\t\t\t\ttry {\n\t\t\t\t\tactionSignal.throwIfAborted();\n\t\t\t\t\tawait save(actionSignal);\n\t\t\t\t\tsaved = true;\n\t\t\t\t\treturn { kind: \"close\" };\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (actionSignal.aborted) return { kind: \"close\" };\n\t\t\t\t\t// Do not silently rebase a stale review or overwrite an invalid settings file.\n\t\t\t\t\t// The caller must reopen current settings for those failures.\n\t\t\t\t\tif (!retryableSettingsError(error)) {\n\t\t\t\t\t\tfailure = error;\n\t\t\t\t\t\treturn { kind: \"close\" };\n\t\t\t\t\t}\n\t\t\t\t\tfailureText = `Not saved. ${syncErrorGuidance(error)}\\nYour draft is retained. Fix the problem, then save again, or cancel.`;\n\t\t\t\t\tctx.ui.notify(failureText, \"error\");\n\t\t\t\t\treturn { kind: \"stay\" };\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t});\n\tconst result = await runMenu(ctx, menu, {\n\t\tgetState: () => undefined,\n\t\tsignal,\n\t\tisCurrent: () => !signal?.aborted,\n\t});\n\tif (signal?.aborted) return false;\n\tif (failure) throw failure;\n\tif (result.kind === \"error\") throw result.error;\n\treturn saved;\n}\n\nfunction retryableSettingsError(error: unknown) {\n\tconst code = (error as NodeJS.ErrnoException | undefined)?.code;\n\treturn (\n\t\tcode !== undefined &&\n\t\t[\"EACCES\", \"EPERM\", \"ENOSPC\", \"EBUSY\", \"EIO\", \"EMFILE\", \"ENFILE\", \"EROFS\"].includes(code)\n\t);\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n\tnormalizeGitBranch,\n\tnormalizeGitDirectory,\n\tnormalizeGitRemote,\n} from \"../../backends/git/git-config.js\";\nimport {\n\taddStorageConnection,\n\taddSyncSetup,\n\tsaveNewV3Settings,\n\tupdateStorageConnection,\n\tupdateSyncSetup,\n} from \"../../settings/settings-management.js\";\nimport type { PartialConfig } from \"../../settings/settings-types.js\";\nimport { automaticSyncSummary } from \"../automatic-sync-summary.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport { promptAvailableSetupStorage } from \"./setup-location-ui.js\";\nimport {\n\tchooseAutomaticSync,\n\tchooseSetupContent,\n\tincludedContentLines,\n\tpromptResourceName,\n\treadSetupConnection,\n} from \"./setup-prompts.js\";\nimport { saveReviewedDraft } from \"./setup-review.js\";\nimport { requiredInput, requiredValueInput } from \"./text-input.js\";\n\nexport async function showGitSetup(\n\tctx: ExtensionCommandContext,\n\ttargetName: string,\n\tsignal?: AbortSignal,\n) {\n\tconst remote = await promptGitRemote(ctx, signal);\n\tif (!remote) return false;\n\tconst destination = await promptGitDestination(ctx, signal);\n\tif (!destination) return false;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return false;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review Git sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(targetName)}`,\n\t\t\t`Storage connection: ${safeTerminalText(targetName)} (Git)`,\n\t\t\t`Remote: ${safeTerminalText(remote)}`,\n\t\t\t`Sync branch: ${safeTerminalText(destination.branch)}`,\n\t\t\t`Storage location: ${safeTerminalText(destination.directory)}`,\n\t\t\t...includedContentLines(include),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t\"Authentication: existing Git credential helper or SSH configuration (not stored by pi-sync).\",\n\t\t\t\"pi-sync manages the entire branch. The repository must already exist; a new branch is created on first push.\",\n\t\t\t\"Saving does not contact remote storage or start syncing.\",\n\t\t],\n\t\t\"Save setup\",\n\t\t(saveSignal) =>\n\t\t\tsaveNewV3Settings(\n\t\t\t\t{\n\t\t\t\t\tsetupName: targetName,\n\t\t\t\t\tconnectionName: targetName,\n\t\t\t\t\tconnection: { type: \"git\", remote },\n\t\t\t\t\tsetup: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\tconnection: targetName,\n\t\t\t\t\t\t\tbranch: destination.branch,\n\t\t\t\t\t\t\tpath: destination.directory,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsync: { include, automatic },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(\n\t\t\t`Saved Git sync setup \u201C${safeTerminalText(targetName)}\u201D. Choose Sync now to start.`,\n\t\t\t\"info\",\n\t\t);\n\treturn saved;\n}\n\nexport async function showAddGitStorageProfile(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\tconst name = await promptResourceName(ctx, \"storage connection\", \"git\", signal);\n\tif (!name) return false;\n\tconst remote = await promptGitRemote(ctx, signal);\n\tif (!remote) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review storage connection\",\n\t\t[\n\t\t\t`Name: ${safeTerminalText(name)}`,\n\t\t\t\"Type: Git\",\n\t\t\t`Remote: ${safeTerminalText(remote)}`,\n\t\t\t\"Credentials: existing Git/SSH authentication (not stored)\",\n\t\t\t\"Adding a connection does not contact the remote or start syncing.\",\n\t\t],\n\t\t\"Add storage connection\",\n\t\t(saveSignal) => addStorageConnection(name, { type: \"git\", remote }, saveSignal),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Added storage connection \u201C${safeTerminalText(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showEditGitStorageProfile(\n\tctx: ExtensionCommandContext,\n\tname: string,\n\tprofile: Record<string, unknown>,\n\tsignal?: AbortSignal,\n\taffectedSetups?: string[],\n) {\n\tconst remote = await promptGitRemote(\n\t\tctx,\n\t\tsignal,\n\t\ttypeof profile.remote === \"string\" ? profile.remote : undefined,\n\t);\n\tif (!remote) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review storage connection\",\n\t\t[\n\t\t\t`Storage connection: ${safeTerminalText(name)}`,\n\t\t\t`Remote: ${safeTerminalText(String(profile.remote ?? \"missing\"))} \u2192 ${safeTerminalText(remote)}`,\n\t\t\t`Affected sync setups: ${affectedSetups?.length ? affectedSetups.map(safeTerminalText).join(\", \") : \"None\"}`,\n\t\t\t\"Saving changes future storage access for every affected setup; it does not move or delete remote history.\",\n\t\t],\n\t\t\"Save storage connection\",\n\t\t(saveSignal) =>\n\t\t\tupdateStorageConnection(\n\t\t\t\tname,\n\t\t\t\t(current) => {\n\t\t\t\t\tif (current.type !== \"git\" || current.remote !== profile.remote)\n\t\t\t\t\t\tthrow new Error(\"Storage connection changed while it was open; reopen it.\");\n\t\t\t\t\treturn { ...current, remote };\n\t\t\t\t},\n\t\t\t\taffectedSetups,\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Saved storage connection \u201C${safeTerminalText(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showAddGitTarget(\n\tctx: ExtensionCommandContext,\n\tname: string,\n\tprofile: string,\n\tsignal?: AbortSignal,\n) {\n\tconst selected = await promptGitDestination(ctx, signal);\n\tif (!selected) return false;\n\tconst storage = await promptAvailableSetupStorage(\n\t\tctx,\n\t\t{ connection: profile, branch: selected.branch, path: selected.directory },\n\t\tsignal,\n\t);\n\tif (!storage) return false;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return false;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return false;\n\tconst connection = await readSetupConnection(profile, signal);\n\tif (connection?.type !== \"git\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review Git sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(name)}`,\n\t\t\t`Storage connection: ${safeTerminalText(profile)}`,\n\t\t\t`Remote: ${safeTerminalText(connection.remote)}`,\n\t\t\t`Sync branch: ${safeTerminalText(storage.branch)}`,\n\t\t\t`Storage location: ${safeTerminalText(storage.path)}`,\n\t\t\t...includedContentLines(include),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t\"pi-sync manages the entire branch. Adding this setup does not sync or modify remote data.\",\n\t\t],\n\t\t\"Add sync setup\",\n\t\t(saveSignal) =>\n\t\t\taddSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Added sync setup \u201C${safeTerminalText(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showEditGitTarget(\n\tctx: ExtensionCommandContext,\n\tpartial: PartialConfig,\n\tsignal?: AbortSignal,\n) {\n\tlet destination = await promptGitDestination(ctx, signal, partial);\n\tif (!destination) return false;\n\twhile (destination.directory !== partial.storagePath && destination.branch === partial.branch) {\n\t\tctx.ui.notify(\n\t\t\t\"Changing a Git storage path requires a new Git branch so the existing branch remains readable.\",\n\t\t\t\"warning\",\n\t\t);\n\t\tconst branch = await requiredValueInput(\n\t\t\tctx,\n\t\t\t\"New Git branch\\n\\nKeep the previous branch unchanged; enter a new branch for this path.\",\n\t\t\t\"pi-sync/archive\",\n\t\t\tsignal,\n\t\t\tnormalizeGitBranch,\n\t\t);\n\t\tif (!branch) return false;\n\t\tdestination = { ...destination, branch };\n\t}\n\tconst chosen = destination;\n\tconst connection = await readSetupConnection(partial.connectionName, signal);\n\tif (connection.type !== \"git\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(partial.setupName)}`,\n\t\t\t`Storage connection: ${safeTerminalText(partial.connectionName)}`,\n\t\t\t`Remote: ${safeTerminalText(connection.remote)}`,\n\t\t\t`Branch: ${safeTerminalText(partial.branch ?? \"missing\")} \u2192 ${safeTerminalText(chosen.branch)}`,\n\t\t\t`Storage path: ${safeTerminalText(partial.storagePath)} \u2192 ${safeTerminalText(chosen.directory)}`,\n\t\t\t\"Saving changes the future storage location only; it does not move or delete remote history.\",\n\t\t],\n\t\t\"Save sync setup\",\n\t\t(saveSignal) =>\n\t\t\tupdateSyncSetup(\n\t\t\t\tpartial.setupName,\n\t\t\t\t(setup) => {\n\t\t\t\t\tif (typeof setup.storage.branch !== \"string\")\n\t\t\t\t\t\tthrow new Error(\"Sync setup storage type changed; reopen it.\");\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...setup,\n\t\t\t\t\t\tstorage: { ...setup.storage, branch: chosen.branch, path: chosen.directory },\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Saved sync setup \u201C${safeTerminalText(partial.setupName)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nasync function promptGitRemote(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n\tcurrent?: string,\n) {\n\tconst title =\n\t\t\"Git remote URL (SSH or HTTPS)\\n\\nUse an existing private repository with Git/SSH authentication already configured.\";\n\tconst validate = (value: string) => {\n\t\tconst remote = normalizeGitRemote(value);\n\t\tif (!remote) throw new Error(\"Git remote URL is required.\");\n\t\treturn remote;\n\t};\n\treturn current\n\t\t? requiredInput(ctx, title, current, signal, validate)\n\t\t: requiredValueInput(\n\t\t\t\tctx,\n\t\t\t\ttitle,\n\t\t\t\t\"git@github.com:owner/private-pi-sync.git (SSH) or https://github.com/owner/private-pi-sync.git (HTTPS)\",\n\t\t\t\tsignal,\n\t\t\t\tvalidate,\n\t\t\t);\n}\n\nasync function promptGitDestination(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n\tcurrent: Partial<PartialConfig> = {},\n) {\n\tconst branch = await requiredInput(\n\t\tctx,\n\t\t\"Git branch for sync snapshots\\n\\npi-sync manages this entire branch, not your local working branch.\\nUse a new branch or one already used by pi-sync; unrelated content is rejected.\",\n\t\tcurrent.branch ?? \"main\",\n\t\tsignal,\n\t\tnormalizeGitBranch,\n\t);\n\tif (!branch) return undefined;\n\tconst directory = await requiredInput(\n\t\tctx,\n\t\t\"Git storage path\\n\\nRelative to the repository root, not your local filesystem.\\n./ stores manifest.json and files/ at the repository root.\",\n\t\tcurrent.storagePath ?? \"./\",\n\t\tsignal,\n\t\tnormalizeGitDirectory,\n\t);\n\treturn directory ? { branch, directory } : undefined;\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n\tCURSOR_MARKER,\n\tdecodeKittyPrintable,\n\ttype Focusable,\n\tKey,\n\ttype KeybindingsManager,\n\tmatchesKey,\n\tText,\n\ttruncateToWidth,\n} from \"@earendil-works/pi-tui\";\nimport { formatInteractionHints, runCustomInteraction } from \"@narumitw/pi-tui-kit\";\n\nconst MASK = \"\u2022\";\n\nexport async function promptSecret(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\toptions: { required?: boolean; signal?: AbortSignal } = { required: true },\n) {\n\tif (ctx.mode !== \"tui\" || options.signal?.aborted) return undefined;\n\tconst result = await runCustomInteraction<string | undefined>(ctx, {\n\t\tsignal: options.signal,\n\t\tisCurrent: () => !options.signal?.aborted,\n\t\tcreate: ({ tui, theme, keybindings, complete }) => {\n\t\t\tconst heading = new Text(\"\", 0, 0);\n\t\t\tconst hint = new Text(\"\", 0, 0);\n\t\t\tconst interactionHint = formatInteractionHints(keybindings, [\n\t\t\t\t{\n\t\t\t\t\tkeys: keybindings.getKeys(\"tui.input.submit\").filter((key) => !hasControlCharacter(key)),\n\t\t\t\t\tlabel: \"continue\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tkeys: [\n\t\t\t\t\t\t...keybindings.getKeys(\"tui.select.cancel\").filter((key) => !hasControlCharacter(key)),\n\t\t\t\t\t\t\"ctrl+c\",\n\t\t\t\t\t],\n\t\t\t\t\tlabel: \"cancel\",\n\t\t\t\t},\n\t\t\t]);\n\t\t\tconst applyTheme = () => {\n\t\t\t\theading.setText(theme.fg(\"accent\", theme.bold(title)));\n\t\t\t\thint.setText(theme.fg(\"dim\", `${interactionHint} \u2022 Input is hidden`));\n\t\t\t};\n\t\t\tapplyTheme();\n\t\t\tconst input = new MaskedInput(keybindings);\n\t\t\tconst component: Focusable & {\n\t\t\t\trender(width: number): string[];\n\t\t\t\tinvalidate(): void;\n\t\t\t\thandleInput(data: string): void;\n\t\t\t\tdispose(): void;\n\t\t\t} = {\n\t\t\t\tget focused() {\n\t\t\t\t\treturn input.focused;\n\t\t\t\t},\n\t\t\t\tset focused(focused: boolean) {\n\t\t\t\t\tinput.focused = focused;\n\t\t\t\t},\n\t\t\t\trender(width: number) {\n\t\t\t\t\tconst safeWidth = Math.max(1, width);\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...heading.render(safeWidth),\n\t\t\t\t\t\t...input.render(safeWidth),\n\t\t\t\t\t\t...hint.render(safeWidth),\n\t\t\t\t\t].map((line) => truncateToWidth(line, safeWidth));\n\t\t\t\t},\n\t\t\t\tinvalidate() {\n\t\t\t\t\tapplyTheme();\n\t\t\t\t\theading.invalidate();\n\t\t\t\t\tinput.invalidate();\n\t\t\t\t\thint.invalidate();\n\t\t\t\t},\n\t\t\t\thandleInput(data: string) {\n\t\t\t\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\n\t\t\t\t\t\tcomplete(undefined);\n\t\t\t\t\t} else if (input.isPasting || data.includes(\"\\u001b[200~\")) {\n\t\t\t\t\t\tinput.handleInput(data);\n\t\t\t\t\t} else if (keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\tcomplete(undefined);\n\t\t\t\t\t} else if (keybindings.matches(data, \"tui.input.submit\")) {\n\t\t\t\t\t\tif (options.required !== false && input.getValue().length === 0) {\n\t\t\t\t\t\t\tctx.ui.notify(`${title} is required. Enter a value, or cancel.`, \"warning\");\n\t\t\t\t\t\t} else if (hasControlCharacter(input.getValue())) {\n\t\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\t`${title} contains control characters. Remove them or re-enter the value, then continue.`,\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else complete(input.getValue());\n\t\t\t\t\t} else input.handleInput(data);\n\t\t\t\t\ttui.requestRender();\n\t\t\t\t},\n\t\t\t\tdispose() {\n\t\t\t\t\tinput.clear();\n\t\t\t\t},\n\t\t\t};\n\t\t\treturn component;\n\t\t},\n\t});\n\tif (result.kind === \"error\") throw result.error;\n\tif (result.kind !== \"completed\" || result.value === undefined) return undefined;\n\tconst value = result.value;\n\tif (options.required !== false && value.length === 0) {\n\t\tctx.ui.notify(`${title} is required.`, \"warning\");\n\t\treturn undefined;\n\t}\n\treturn value;\n}\n\nclass MaskedInput implements Focusable {\n\tfocused = false;\n\tprivate value: string[] = [];\n\tprivate cursor = 0;\n\tprivate paste = \"\";\n\tprivate pasting = false;\n\n\tconstructor(private readonly keybindings: KeybindingsManager) {}\n\n\tget isPasting() {\n\t\treturn this.pasting;\n\t}\n\n\tgetValue() {\n\t\treturn this.value.join(\"\");\n\t}\n\n\thandleInput(data: string) {\n\t\tif (data.includes(\"\\u001b[200~\")) {\n\t\t\tthis.pasting = true;\n\t\t\tthis.paste = \"\";\n\t\t\tdata = data.replace(\"\\u001b[200~\", \"\");\n\t\t}\n\t\tif (this.pasting) {\n\t\t\tthis.paste += data;\n\t\t\tconst end = this.paste.indexOf(\"\\u001b[201~\");\n\t\t\tif (end < 0) return;\n\t\t\tconst pasted = this.paste\n\t\t\t\t.slice(0, end)\n\t\t\t\t.replace(/[\\r\\n]/gu, \"\")\n\t\t\t\t.replace(/\\t/gu, \" \");\n\t\t\tthis.insert(pasted);\n\t\t\tconst remaining = this.paste.slice(end + 6);\n\t\t\tthis.paste = \"\";\n\t\t\tthis.pasting = false;\n\t\t\tif (remaining) this.handleInput(remaining);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\t\tif (this.cursor > 0) this.value.splice(--this.cursor, 1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\t\tif (this.cursor < this.value.length) this.value.splice(this.cursor, 1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.cursorLeft\")) {\n\t\t\tthis.cursor = Math.max(0, this.cursor - 1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.cursorRight\")) {\n\t\t\tthis.cursor = Math.min(this.value.length, this.cursor + 1);\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.cursorLineStart\")) {\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.cursorLineEnd\")) {\n\t\t\tthis.cursor = this.value.length;\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\t\tthis.value.splice(0, this.cursor);\n\t\t\tthis.cursor = 0;\n\t\t\treturn;\n\t\t}\n\t\tif (this.keybindings.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\t\tthis.value.splice(this.cursor);\n\t\t\treturn;\n\t\t}\n\t\tconst printable = decodeKittyPrintable(data) ?? data;\n\t\tif (!hasControlCharacter(printable)) this.insert(printable);\n\t}\n\n\trender(width: number) {\n\t\tconst prompt = \"> \";\n\t\tconst available = width - prompt.length;\n\t\tif (available <= 0) return [truncateToWidth(prompt, Math.max(1, width))];\n\t\tconst contentWidth = Math.max(0, available - 1);\n\t\tlet start = 0;\n\t\tif (this.value.length > contentWidth) {\n\t\t\tstart = Math.max(\n\t\t\t\t0,\n\t\t\t\tMath.min(this.cursor - Math.floor(contentWidth / 2), this.value.length - contentWidth),\n\t\t\t);\n\t\t}\n\t\tconst end = Math.min(this.value.length, start + contentWidth);\n\t\tconst visibleCursor = Math.max(0, Math.min(this.cursor - start, end - start));\n\t\tconst masks = Array.from({ length: end - start }, () => MASK);\n\t\tconst before = masks.slice(0, visibleCursor).join(\"\");\n\t\tconst atCursor = visibleCursor < masks.length ? MASK : \" \";\n\t\tconst after = masks.slice(visibleCursor + (visibleCursor < masks.length ? 1 : 0)).join(\"\");\n\t\tconst marker = this.focused ? CURSOR_MARKER : \"\";\n\t\tconst line = `${prompt}${before}${marker}\\u001b[7m${atCursor}\\u001b[27m${after}`;\n\t\treturn [truncateToWidth(line, width, \"\")];\n\t}\n\n\tinvalidate() {}\n\n\tclear() {\n\t\tthis.value.fill(\"\");\n\t\tthis.value = [];\n\t\tthis.paste = \"\";\n\t\tthis.cursor = 0;\n\t\tthis.pasting = false;\n\t}\n\n\tprivate insert(value: string) {\n\t\tconst characters = Array.from(value);\n\t\tthis.value.splice(this.cursor, 0, ...characters);\n\t\tthis.cursor += characters.length;\n\t}\n}\n\nfunction hasControlCharacter(value: string) {\n\treturn [...value].some((character) => {\n\t\tconst code = character.codePointAt(0) ?? 0;\n\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t});\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { promptSecret } from \"../secret-input.js\";\nimport { requiredValueInput } from \"./text-input.js\";\n\nexport interface ChosenS3Credentials {\n\tprofileFields: { accessKeyId?: string; secretAccessKey?: string };\n\tsummary: string;\n\tready: boolean;\n\treplace?: boolean;\n}\n\nexport async function chooseS3CredentialUpdate(\n\tctx: ExtensionCommandContext,\n\tprofile: Record<string, unknown>,\n\tsignal?: AbortSignal,\n) {\n\tconst hasStored =\n\t\ttypeof profile.accessKeyId === \"string\" &&\n\t\tprofile.accessKeyId.length > 0 &&\n\t\ttypeof profile.secretAccessKey === \"string\" &&\n\t\tprofile.secretAccessKey.length > 0;\n\tif (hasStored) {\n\t\tconst action = await ctx.ui.select(\n\t\t\t\"Credentials\",\n\t\t\t[\"Keep current credentials\", \"Replace credentials\", \"Cancel\"],\n\t\t\t{ signal },\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (!action || action === \"Cancel\") return undefined;\n\t\tif (action === \"Keep current credentials\") {\n\t\t\treturn { profileFields: {}, summary: \"Unchanged (values hidden)\", ready: true };\n\t\t}\n\t}\n\tconst selected = await chooseS3Credentials(ctx, signal);\n\treturn selected ? { ...selected, replace: true } : undefined;\n}\n\nexport function applyS3CredentialUpdate(\n\tprofile: Record<string, unknown>,\n\tcredentials: ChosenS3Credentials,\n) {\n\tconst next = { ...profile };\n\tif (credentials.replace) {\n\t\tdelete next.accessKeyId;\n\t\tdelete next.secretAccessKey;\n\t\tdelete next.sessionToken;\n\t}\n\treturn { ...next, ...credentials.profileFields };\n}\n\nexport async function chooseS3Credentials(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n): Promise<ChosenS3Credentials | undefined> {\n\tconst choice = await ctx.ui.select(\n\t\t\"Credentials\\n\\nCredentials are stored in the private pi-sync settings file. Secret values are masked during input and never shown afterward.\",\n\t\t[\"Store credentials privately\", \"Cancel\"],\n\t\t{ signal },\n\t);\n\tthrowIfAborted(signal);\n\tif (choice !== \"Store credentials privately\") return undefined;\n\tconst accessKeyId = await requiredValueInput(\n\t\tctx,\n\t\t\"Access key ID\\n\\nUse the S3 API access key ID issued by your provider, not the secret access key.\",\n\t\t\"access-key-id\",\n\t\tsignal,\n\t);\n\tif (!accessKeyId) return undefined;\n\tconst secretAccessKey = await promptSecret(ctx, \"Secret access key\", { signal });\n\tthrowIfAborted(signal);\n\tif (secretAccessKey === undefined) return undefined;\n\treturn {\n\t\tprofileFields: { accessKeyId, secretAccessKey },\n\t\tsummary: \"Stored privately (values hidden)\",\n\t\tready: true,\n\t};\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { refreshTargetCompletions } from \"../../commands/setup-completions.js\";\nimport {\n\taddSyncSetup,\n\tsaveNewV3Settings,\n\tupdateSyncSetup,\n} from \"../../settings/settings-management.js\";\nimport type { PartialConfig } from \"../../settings/settings-types.js\";\nimport {\n\tnormalizeS3Bucket,\n\tnormalizeS3Endpoint,\n\tnormalizeStoragePath,\n} from \"../../settings/settings-validation.js\";\nimport { automaticSyncSummary } from \"../automatic-sync-summary.js\";\nimport { safeTerminalText } from \"../terminal-text.js\";\nimport { chooseS3Credentials } from \"./s3-credentials-ui.js\";\nimport {\n\tchooseAdditionalRemoteLocation,\n\tchooseInitialRemoteLocation,\n\tpromptAvailableSetupStorage,\n} from \"./setup-location-ui.js\";\nimport {\n\tchooseAutomaticSync,\n\tchooseSessions,\n\tchooseSetupContent,\n\tincludedContentLines,\n\treadSetupConnection,\n} from \"./setup-prompts.js\";\nimport { saveReviewedDraft } from \"./setup-review.js\";\nimport { requiredInput, requiredValueInput } from \"./text-input.js\";\n\nexport async function showS3Setup(\n\tctx: ExtensionCommandContext,\n\tpreset: string,\n\ttargetName: string,\n\tsignal?: AbortSignal,\n) {\n\tconst endpoint = await requiredValueInput(\n\t\tctx,\n\t\tpreset === \"Cloudflare R2\"\n\t\t\t? \"Cloudflare R2 endpoint\\n\\nCopy the S3 API endpoint from your R2 account; replace <account-id>.\"\n\t\t\t: \"S3-compatible endpoint\\n\\nUse your provider's S3 API URL, not its web console.\",\n\t\tpreset === \"Cloudflare R2\"\n\t\t\t? \"https://<account-id>.r2.cloudflarestorage.com\"\n\t\t\t: \"https://s3.example.com\",\n\t\tsignal,\n\t\tnormalizeS3Endpoint,\n\t);\n\tif (!endpoint) return false;\n\tconst region =\n\t\tpreset === \"Cloudflare R2\"\n\t\t\t? \"auto\"\n\t\t\t: await requiredInput(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"Storage region\\n\\nUse the region assigned to your bucket by the provider.\",\n\t\t\t\t\t\"us-east-1\",\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\tif (!region) return false;\n\tconst location = await chooseInitialRemoteLocation(ctx, preset, targetName, signal);\n\tif (!location) return false;\n\tconst credentials = await chooseS3Credentials(ctx, signal);\n\tif (!credentials) return false;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return false;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return false;\n\tconst sessions = await chooseSessions(ctx, signal);\n\tif (sessions === undefined) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(targetName)}`,\n\t\t\t`Storage connection: ${safeTerminalText(location.connectionName)} (${preset})`,\n\t\t\t`Endpoint: ${safeTerminalText(endpoint)}`,\n\t\t\t`Region: ${safeTerminalText(region)}`,\n\t\t\t`Bucket: ${safeTerminalText(location.bucket)}`,\n\t\t\t`Storage location: ${safeTerminalText(location.path)}`,\n\t\t\t...includedContentLines(include, sessions),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t`Credentials: ${credentials.summary}`,\n\t\t\t\"The bucket must already exist. Saving does not contact remote storage or start syncing.\",\n\t\t],\n\t\t\"Save sync setup\",\n\t\t(saveSignal) =>\n\t\t\tsaveNewV3Settings(\n\t\t\t\t{\n\t\t\t\t\tsetupName: targetName,\n\t\t\t\t\tconnectionName: location.connectionName,\n\t\t\t\t\tconnection: {\n\t\t\t\t\t\ttype: \"s3\",\n\t\t\t\t\t\tendpoint,\n\t\t\t\t\t\tregion,\n\t\t\t\t\t\tcredentials: {\n\t\t\t\t\t\t\taccessKeyId: credentials.profileFields.accessKeyId ?? \"\",\n\t\t\t\t\t\t\tsecretAccessKey: credentials.profileFields.secretAccessKey ?? \"\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tsetup: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\tconnection: location.connectionName,\n\t\t\t\t\t\t\tbucket: location.bucket,\n\t\t\t\t\t\t\tpath: location.path,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsync: { include: [...include, ...(sessions ? [\"sessions\"] : [])], automatic },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (!saved || signal?.aborted) return false;\n\tawait refreshTargetCompletions();\n\tif (!signal?.aborted)\n\t\tctx.ui.notify(\n\t\t\t`Sync setup \u201C${safeTerminalText(targetName)}\u201D saved. Choose Sync now to start.`,\n\t\t\t\"info\",\n\t\t);\n\treturn true;\n}\n\nexport async function showAddS3Target(\n\tctx: ExtensionCommandContext,\n\traw: Record<string, unknown>,\n\tprofile: string,\n\tname: string,\n\tsignal?: AbortSignal,\n) {\n\tconst location = await chooseAdditionalRemoteLocation(ctx, raw, profile, name, signal);\n\tif (!location) return;\n\tconst storage = await promptAvailableSetupStorage(\n\t\tctx,\n\t\t{ connection: profile, ...location },\n\t\tsignal,\n\t);\n\tif (!storage) return;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return;\n\tconst connection = await readSetupConnection(profile, signal);\n\tif (connection.type !== \"s3\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review new sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(name)}`,\n\t\t\t`Storage connection: ${safeTerminalText(profile)}`,\n\t\t\t`Endpoint: ${safeTerminalText(connection.endpoint)}`,\n\t\t\t`Bucket: ${safeTerminalText(storage.bucket)}`,\n\t\t\t`Storage location: ${safeTerminalText(storage.path)}`,\n\t\t\t...includedContentLines(include),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t\"Only the current setup is checked at startup. Shutdown can push selected content when sessions are included.\",\n\t\t\t\"The bucket must already exist. Adding this setup does not sync or modify remote data.\",\n\t\t],\n\t\t\"Add sync setup\",\n\t\t(saveSignal) =>\n\t\t\taddSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),\n\t\tsignal,\n\t);\n\tif (!saved || signal?.aborted) return;\n\tawait refreshTargetCompletions();\n\tif (!signal?.aborted) ctx.ui.notify(`Added sync setup \u201C${safeTerminalText(name)}\u201D.`, \"info\");\n}\n\nexport async function showEditS3Target(\n\tctx: ExtensionCommandContext,\n\tpartial: PartialConfig,\n\tsignal?: AbortSignal,\n) {\n\tconst bucket = await requiredInput(\n\t\tctx,\n\t\t\"Bucket\\n\\nUse an existing bucket; pi-sync will not create it.\",\n\t\tpartial.bucket ?? \"pi-sync\",\n\t\tsignal,\n\t\tnormalizeS3Bucket,\n\t);\n\tif (!bucket) return;\n\tconst storagePath = await requiredInput(\n\t\tctx,\n\t\t\"Storage path\\n\\nPath inside the bucket, not your local filesystem. ./ uses the bucket root.\",\n\t\tpartial.storagePath,\n\t\tsignal,\n\t\tnormalizeStoragePath,\n\t);\n\tif (!storagePath) return;\n\tconst connection = await readSetupConnection(partial.connectionName, signal);\n\tif (connection.type !== \"s3\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safeTerminalText(partial.setupName)}`,\n\t\t\t`Storage connection: ${safeTerminalText(partial.connectionName)}`,\n\t\t\t`Endpoint: ${safeTerminalText(connection.endpoint)}`,\n\t\t\t`Bucket: ${safeTerminalText(partial.bucket ?? \"missing\")} \u2192 ${safeTerminalText(bucket)}`,\n\t\t\t`Storage path: ${safeTerminalText(partial.storagePath)} \u2192 ${safeTerminalText(storagePath)}`,\n\t\t\t\"Saving changes the future storage location only; it does not move or delete remote data.\",\n\t\t],\n\t\t\"Save sync setup\",\n\t\t(saveSignal) =>\n\t\t\tupdateSyncSetup(\n\t\t\t\tpartial.setupName,\n\t\t\t\t(setup) => {\n\t\t\t\t\tif (typeof setup.storage.bucket !== \"string\")\n\t\t\t\t\t\tthrow new Error(\"Sync setup storage type changed; reopen it.\");\n\t\t\t\t\treturn { ...setup, storage: { ...setup.storage, bucket, path: storagePath } };\n\t\t\t\t},\n\t\t\t\t{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Saved sync setup \u201C${safeTerminalText(partial.setupName)}\u201D.`, \"info\");\n}\n", "import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n\tnormalizeWebDavPath,\n\tnormalizeWebDavUrl,\n\tvalidateWebDavCredentials,\n} from \"../../backends/webdav/webdav-config.js\";\nimport {\n\taddStorageConnection,\n\taddSyncSetup,\n\tsaveNewV3Settings,\n\tupdateStorageConnection,\n\tupdateSyncSetup,\n} from \"../../settings/settings-management.js\";\nimport type { PartialConfig } from \"../../settings/settings-types.js\";\nimport { automaticSyncSummary } from \"../automatic-sync-summary.js\";\nimport { promptSecret } from \"../secret-input.js\";\nimport { safeTerminalText as safe } from \"../terminal-text.js\";\nimport { promptAvailableSetupStorage } from \"./setup-location-ui.js\";\nimport {\n\tchooseAutomaticSync,\n\tchooseSessions,\n\tchooseSetupContent,\n\tincludedContentLines,\n\tpromptResourceName,\n\treadSetupConnection,\n} from \"./setup-prompts.js\";\nimport { saveReviewedDraft } from \"./setup-review.js\";\nimport { promptTextInput } from \"./text-input.js\";\n\nexport async function showWebDavSetup(\n\tctx: ExtensionCommandContext,\n\ttargetName: string,\n\tsignal?: AbortSignal,\n) {\n\tconst url = await promptWebDavUrl(ctx, signal);\n\tif (!url) return false;\n\tconst username = await promptUsername(ctx, signal);\n\tif (!username) return false;\n\tconst password = await promptSecret(ctx, \"WebDAV password\", { signal });\n\tsignal?.throwIfAborted();\n\tif (password === undefined) return false;\n\tconst remotePath = await chooseDestination(ctx, signal);\n\tif (!remotePath) return false;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return false;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return false;\n\tconst sessions = await chooseSessions(ctx, signal);\n\tif (sessions === undefined) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review WebDAV setup\",\n\t\t[\n\t\t\t`Sync setup: ${safe(targetName)}`,\n\t\t\t`Storage connection: ${safe(targetName)} (WebDAV)`,\n\t\t\t`URL: ${safe(url)}`,\n\t\t\t`Storage location: ${safe(remotePath)}`,\n\t\t\t\"Username and password: stored privately (values hidden)\",\n\t\t\t...includedContentLines(include, sessions),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t\"Check setup tests whether this server can safely save sync updates using a temporary probe.\",\n\t\t\t\"Saving does not contact remote storage or start syncing.\",\n\t\t],\n\t\t\"Save setup\",\n\t\t(saveSignal) =>\n\t\t\tsaveNewV3Settings(\n\t\t\t\t{\n\t\t\t\t\tsetupName: targetName,\n\t\t\t\t\tconnectionName: targetName,\n\t\t\t\t\tconnection: { type: \"webdav\", url, credentials: { username, password } },\n\t\t\t\t\tsetup: {\n\t\t\t\t\t\tstorage: { connection: targetName, path: remotePath },\n\t\t\t\t\t\tsync: { include: [...include, ...(sessions ? [\"sessions\"] : [])], automatic },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Sync setup \u201C${safe(targetName)}\u201D saved. Choose Sync now to start.`, \"info\");\n\treturn saved;\n}\n\nexport async function showAddWebDavTarget(\n\tctx: ExtensionCommandContext,\n\tname: string,\n\tprofile: string,\n\tsignal?: AbortSignal,\n) {\n\tconst remotePath = await chooseDestination(ctx, signal);\n\tif (!remotePath) return false;\n\tconst storage = await promptAvailableSetupStorage(\n\t\tctx,\n\t\t{ connection: profile, path: remotePath },\n\t\tsignal,\n\t);\n\tif (!storage) return false;\n\tconst include = await chooseSetupContent(ctx, signal);\n\tif (!include) return false;\n\tconst automatic = await chooseAutomaticSync(ctx, signal);\n\tif (automatic === undefined) return false;\n\tconst connection = await readSetupConnection(profile, signal);\n\tif (connection.type !== \"webdav\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review WebDAV sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safe(name)}`,\n\t\t\t`Storage connection: ${safe(profile)}`,\n\t\t\t`URL: ${safe(connection.url)}`,\n\t\t\t`Storage location: ${safe(storage.path)}`,\n\t\t\t...includedContentLines(include),\n\t\t\t`Automatic sync: ${automaticSyncSummary(automatic)}`,\n\t\t\t\"Adding this setup does not sync or modify remote data.\",\n\t\t],\n\t\t\"Add sync setup\",\n\t\t(saveSignal) =>\n\t\t\taddSyncSetup(name, { storage, sync: { include, automatic } }, saveSignal, connection),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted) ctx.ui.notify(`Added sync setup \u201C${safe(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showEditWebDavTarget(\n\tctx: ExtensionCommandContext,\n\tpartial: PartialConfig,\n\tsignal?: AbortSignal,\n) {\n\tconst remotePath = await chooseDestination(ctx, signal, partial.storagePath);\n\tif (!remotePath) return false;\n\tconst connection = await readSetupConnection(partial.connectionName, signal);\n\tif (connection.type !== \"webdav\") throw new Error(\"Storage connection changed; reopen setup.\");\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review sync setup\",\n\t\t[\n\t\t\t`Sync setup: ${safe(partial.setupName)}`,\n\t\t\t`Storage connection: ${safe(partial.connectionName)}`,\n\t\t\t`URL: ${safe(connection.url)}`,\n\t\t\t`Storage path: ${safe(partial.storagePath)} \u2192 ${safe(remotePath)}`,\n\t\t\t\"Saving changes the future storage location only; it does not move or delete remote data.\",\n\t\t],\n\t\t\"Save sync setup\",\n\t\t(saveSignal) =>\n\t\t\tupdateSyncSetup(\n\t\t\t\tpartial.setupName,\n\t\t\t\t(setup) => ({\n\t\t\t\t\t...setup,\n\t\t\t\t\tstorage: { ...setup.storage, path: remotePath },\n\t\t\t\t}),\n\t\t\t\t{ expectedStorage: partial, expectedConnection: connection, signal: saveSignal },\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted)\n\t\tctx.ui.notify(`Saved sync setup \u201C${safe(partial.setupName)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showAddWebDavStorageProfile(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n) {\n\tconst name = await promptResourceName(ctx, \"storage connection\", \"webdav\", signal, true);\n\tif (!name) return false;\n\tconst url = await promptWebDavUrl(ctx, signal);\n\tif (!url) return false;\n\tconst username = await promptUsername(ctx, signal);\n\tif (!username) return false;\n\tconst password = await promptSecret(ctx, \"WebDAV password\", { signal });\n\tsignal?.throwIfAborted();\n\tif (password === undefined) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review storage connection\",\n\t\t[\n\t\t\t`Name: ${safe(name)}`,\n\t\t\t\"Type: WebDAV\",\n\t\t\t`URL: ${safe(url)}`,\n\t\t\t\"Username and password: stored privately (values hidden)\",\n\t\t\t\"Adding a connection does not contact the server or start syncing.\",\n\t\t],\n\t\t\"Add storage connection\",\n\t\t(saveSignal) =>\n\t\t\taddStorageConnection(\n\t\t\t\tname,\n\t\t\t\t{ type: \"webdav\", url, credentials: { username, password } },\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted) ctx.ui.notify(`Added storage connection \u201C${safe(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nexport async function showEditWebDavStorageProfile(\n\tctx: ExtensionCommandContext,\n\tname: string,\n\tprofile: Record<string, unknown>,\n\tsignal?: AbortSignal,\n\taffectedSetups?: string[],\n) {\n\tconst url = await promptWebDavUrl(\n\t\tctx,\n\t\tsignal,\n\t\ttypeof profile.url === \"string\" ? profile.url : undefined,\n\t);\n\tif (!url) return false;\n\tconst username = await promptUsername(ctx, signal);\n\tif (!username) return false;\n\tconst hasPassword = typeof profile.password === \"string\" && profile.password.length > 0;\n\tconst passwordAction = hasPassword\n\t\t? await select(\n\t\t\t\tctx,\n\t\t\t\t\"WebDAV password\",\n\t\t\t\t[\"Keep current password\", \"Replace password\", \"Cancel\"],\n\t\t\t\tsignal,\n\t\t\t)\n\t\t: \"Replace password\";\n\tif (!passwordAction || passwordAction === \"Cancel\") return false;\n\tconst replacePassword = passwordAction === \"Replace password\";\n\tconst password = replacePassword\n\t\t? await promptSecret(ctx, \"New WebDAV password\", { signal })\n\t\t: undefined;\n\tsignal?.throwIfAborted();\n\tif (replacePassword && password === undefined) return false;\n\tconst saved = await saveReviewedDraft(\n\t\tctx,\n\t\t\"Review storage connection\",\n\t\t[\n\t\t\t`Storage connection: ${safe(name)}`,\n\t\t\t`URL: ${safe(String(profile.url))} \u2192 ${safe(url)}`,\n\t\t\t\"Username: stored privately (value hidden)\",\n\t\t\t`Password: ${replacePassword ? \"will be replaced\" : \"unchanged\"} (value hidden)`,\n\t\t\t`Affected sync setups: ${affectedSetups?.length ? affectedSetups.map(safe).join(\", \") : \"None\"}`,\n\t\t\t\"Saving changes future storage access for every affected setup; it does not move remote data.\",\n\t\t],\n\t\t\"Save storage connection\",\n\t\t(saveSignal) =>\n\t\t\tupdateStorageConnection(\n\t\t\t\tname,\n\t\t\t\t(current) => {\n\t\t\t\t\tif (\n\t\t\t\t\t\tcurrent.type !== \"webdav\" ||\n\t\t\t\t\t\tcurrent.url !== profile.url ||\n\t\t\t\t\t\tcurrent.credentials.username !== profile.username ||\n\t\t\t\t\t\tcurrent.credentials.password !== profile.password\n\t\t\t\t\t)\n\t\t\t\t\t\tthrow new Error(\"Storage connection changed while it was open; reopen it.\");\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...current,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tcredentials: {\n\t\t\t\t\t\t\t...current.credentials,\n\t\t\t\t\t\t\tusername,\n\t\t\t\t\t\t\tpassword: password ?? current.credentials.password,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\taffectedSetups,\n\t\t\t\tsaveSignal,\n\t\t\t),\n\t\tsignal,\n\t);\n\tif (saved && !signal?.aborted) ctx.ui.notify(`Saved storage connection \u201C${safe(name)}\u201D.`, \"info\");\n\treturn saved;\n}\n\nasync function chooseDestination(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n\tcurrent = \"./\",\n) {\n\treturn promptTextInput(\n\t\tctx,\n\t\t\"WebDAV storage path\\n\\nFolder relative to the collection URL, not your local filesystem.\\n./ uses the collection root. Use different folders for independent setups.\",\n\t\t{ defaultValue: current, validate: normalizeWebDavPath },\n\t\tsignal,\n\t);\n}\n\nasync function promptUsername(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n\treturn promptTextInput(\n\t\tctx,\n\t\t\"WebDAV username\\n\\nEnter the account username; stored values remain hidden.\",\n\t\t{\n\t\t\texample: \"user\",\n\t\t\tvalidate: (value) => {\n\t\t\t\tvalidateWebDavCredentials(value);\n\t\t\t\treturn value;\n\t\t\t},\n\t\t},\n\t\tsignal,\n\t);\n}\n\nasync function promptWebDavUrl(\n\tctx: ExtensionCommandContext,\n\tsignal?: AbortSignal,\n\tcurrent?: string,\n) {\n\treturn promptTextInput(\n\t\tctx,\n\t\t\"WebDAV collection URL\\n\\nUse the HTTPS WebDAV URL from your provider, not its web login page.\",\n\t\t{\n\t\t\t...(current\n\t\t\t\t? { defaultValue: current }\n\t\t\t\t: { example: \"https://cloud.example.com/remote.php/dav/files/user\" }),\n\t\t\tvalidate: (value) => {\n\t\t\t\tconst url = normalizeWebDavUrl(value);\n\t\t\t\tif (!url) throw new Error(\"WebDAV URL is required.\");\n\t\t\t\treturn url;\n\t\t\t},\n\t\t},\n\t\tsignal,\n\t);\n}\n\nasync function select(\n\tctx: ExtensionCommandContext,\n\ttitle: string,\n\toptions: string[],\n\tsignal?: AbortSignal,\n) {\n\tconst value = await ctx.ui.select(title, options, { signal });\n\tsignal?.throwIfAborted();\n\treturn value;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/state/lock.ts"],
4
- "sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport lockfile from \"proper-lockfile\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { LOCK_GUARD_STALE_MS, LOCK_GUARD_UPDATE_MS } from \"./lock-policy.js\";\nimport { LOCKFILE_FS_ADAPTER } from \"./lockfile-fs.js\";\nimport type { LockFile } from \"./state-types.js\";\nimport { ensureStateDir, lockPath } from \"./sync-state-store.js\";\n\nconst LOCK_STALE_MS = 30 * 60 * 1000;\nconst MAX_PROCESS_ID = 2_147_483_647;\n\ninterface Guard {\n\trelease: () => Promise<void>;\n\tthrowIfCompromised: () => void;\n\tisCompromised: () => boolean;\n}\n\nexport type LockInspection =\n\t| { status: \"missing\" }\n\t| { status: \"unreadable\" }\n\t| { status: \"valid\"; lock: LockFile };\n\nexport async function withLock<T>(\n\tcommand: string,\n\tfn: () => Promise<T>,\n\toptions: { reclaimStale?: boolean } = {},\n): Promise<T> {\n\tawait ensureStateDir();\n\tconst lock: LockFile = {\n\t\tid: randomUUID(),\n\t\tpid: process.pid,\n\t\tcommand,\n\t\tstartedAt: new Date().toISOString(),\n\t};\n\tlet guard: Guard | undefined;\n\tlet result: T | undefined;\n\tlet failed = false;\n\tlet failure: unknown;\n\ttry {\n\t\ttry {\n\t\t\tguard = await acquireGuard();\n\t\t} catch (error) {\n\t\t\tif (!isLockHeldError(error)) throw error;\n\t\t\tthrow await describeHeldLock();\n\t\t}\n\n\t\tlet inspection = await inspectLock();\n\t\tif (inspection.status === \"valid\" && isStaleLock(inspection.lock)) {\n\t\t\tif (!options.reclaimStale) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`pi-sync lock is stale (pid ${inspection.lock.pid}). Run /sync unlock --stale, then retry.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tguard.throwIfCompromised();\n\t\t\tconst rechecked = await inspectLock();\n\t\t\tif (\n\t\t\t\trechecked.status !== \"valid\" ||\n\t\t\t\trechecked.lock.id !== inspection.lock.id ||\n\t\t\t\t!isStaleLock(rechecked.lock)\n\t\t\t) {\n\t\t\t\tthrow new Error(\"pi-sync lock changed while preparing transaction recovery; retry.\");\n\t\t\t}\n\t\t\tawait fs.rm(lockPath(), { force: true });\n\t\t\tinspection = { status: \"missing\" };\n\t\t}\n\t\tif (inspection.status === \"valid\") {\n\t\t\tthrow new Error(\n\t\t\t\t`pi-sync is already running (${inspection.lock.command}, pid ${inspection.lock.pid}, started ${inspection.lock.startedAt}).`,\n\t\t\t);\n\t\t}\n\t\tif (inspection.status === \"unreadable\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"pi-sync lock metadata is unreadable. Run /sync unlock --stale after verifying no sync is running.\",\n\t\t\t);\n\t\t}\n\n\t\tawait fs.writeFile(lockPath(), JSON.stringify(lock, null, \"\\t\"), { flag: \"wx\" });\n\t\tguard.throwIfCompromised();\n\t\tresult = await fn();\n\t\tguard.throwIfCompromised();\n\t} catch (error) {\n\t\tfailed = true;\n\t\tfailure = error;\n\t}\n\n\ttry {\n\t\tconst current = await readLock();\n\t\tif (current?.id === lock.id) await fs.rm(lockPath(), { force: true });\n\t} catch (error) {\n\t\tif (!failed) {\n\t\t\tfailed = true;\n\t\t\tfailure = error;\n\t\t}\n\t}\n\tif (guard) {\n\t\tconst releaseError = await releaseGuard(guard);\n\t\tif (releaseError && !failed) {\n\t\t\tfailed = true;\n\t\t\tfailure = releaseError;\n\t\t}\n\t}\n\tif (failed) throw failure;\n\treturn result as T;\n}\n\nexport async function inspectLock(): Promise<LockInspection> {\n\ttry {\n\t\tconst text = await fs.readFile(lockPath(), \"utf8\");\n\t\tif (text.trim().length === 0) return { status: \"unreadable\" };\n\t\tconst parsed = JSON.parse(text) as unknown;\n\t\treturn isLockFile(parsed) ? { status: \"valid\", lock: parsed } : { status: \"unreadable\" };\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return { status: \"missing\" };\n\t\tif (error instanceof SyntaxError) return { status: \"unreadable\" };\n\t\tthrow error;\n\t}\n}\n\nexport async function readLock(): Promise<LockFile | undefined> {\n\tconst inspection = await inspectLock();\n\treturn inspection.status === \"valid\" ? inspection.lock : undefined;\n}\n\nexport async function lockFileExists(): Promise<boolean> {\n\ttry {\n\t\tawait fs.stat(lockPath());\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n\nexport function isLockGuardHeld() {\n\treturn lockfile.check(lockPath(), {\n\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\tlockfilePath: `${lockPath()}.guard`,\n\t\trealpath: false,\n\t\tstale: LOCK_GUARD_STALE_MS,\n\t});\n}\n\nexport function isStaleLock(lock: LockFile) {\n\ttry {\n\t\tprocess.kill(lock.pid, 0);\n\t\treturn false;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ESRCH\") return true;\n\t\treturn Date.now() - Date.parse(lock.startedAt) > LOCK_STALE_MS;\n\t}\n}\n\nexport async function unlock(ctx: ExtensionCommandContext, options: CommandOptions) {\n\tthrowIfAborted(options.signal);\n\tawait ensureStateDir();\n\tthrowIfAborted(options.signal);\n\tlet guard: Guard;\n\ttry {\n\t\tguard = await acquireGuard();\n\t} catch (error) {\n\t\tif (!isLockHeldError(error)) throw error;\n\t\tctx.ui.notify((await describeHeldLock()).message, \"warning\");\n\t\treturn;\n\t}\n\n\tlet failed = false;\n\tlet failure: unknown;\n\ttry {\n\t\tawait unlockGuarded(ctx, options);\n\t} catch (error) {\n\t\tfailed = true;\n\t\tfailure = error;\n\t}\n\tconst releaseError = await releaseGuard(guard);\n\tif (releaseError && !failed) {\n\t\tfailed = true;\n\t\tfailure = releaseError;\n\t}\n\tif (failed) throw failure;\n}\n\nasync function unlockGuarded(ctx: ExtensionCommandContext, options: CommandOptions) {\n\tthrowIfAborted(options.signal);\n\tlet inspection = await inspectLock();\n\tthrowIfAborted(options.signal);\n\tif (inspection.status === \"missing\") {\n\t\tctx.ui.notify(\"No pi-sync lock is present.\", \"info\");\n\t\treturn;\n\t}\n\tif (inspection.status === \"unreadable\") {\n\t\tif (!options.stale) {\n\t\t\tctx.ui.notify(\n\t\t\t\t\"Pi-sync lock metadata is unreadable. Use /sync unlock --stale only after verifying no sync is running.\",\n\t\t\t\t\"warning\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tinspection = await inspectLock();\n\t\tthrowIfAborted(options.signal);\n\t\tif (inspection.status === \"unreadable\") {\n\t\t\t// Legacy writers expose an empty file before writing owner metadata, so no\n\t\t\t// automatic test can prove this file is abandoned. The explicit --stale\n\t\t\t// flag is the user's confirmation that no legacy sync is still running.\n\t\t\tthrowIfAborted(options.signal);\n\t\t\tawait fs.rm(lockPath(), { force: true });\n\t\t\tif (!options.signal?.aborted) {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\"Removed unreadable pi-sync lock. No settings, files, sync state, or remote data were changed.\",\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (inspection.status === \"missing\") {\n\t\t\tctx.ui.notify(\"No pi-sync lock is present.\", \"info\");\n\t\t\treturn;\n\t\t}\n\t}\n\tif (!isStaleLock(inspection.lock)) {\n\t\tctx.ui.notify(\"Lock owner is still live; refusing to remove it.\", \"warning\");\n\t\treturn;\n\t}\n\tthrowIfAborted(options.signal);\n\tawait fs.rm(lockPath(), { force: true });\n\tif (!options.signal?.aborted) {\n\t\tctx.ui.notify(\n\t\t\t\"Removed stale pi-sync lock. No settings, files, sync state, or remote data were changed.\",\n\t\t\t\"info\",\n\t\t);\n\t}\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nasync function releaseGuard(guard: Guard) {\n\ttry {\n\t\tawait guard.release();\n\t\treturn undefined;\n\t} catch (error) {\n\t\treturn guard.isCompromised() ? undefined : error;\n\t}\n}\n\nasync function acquireGuard(): Promise<Guard> {\n\tlet compromisedError: Error | undefined;\n\tconst release = await lockfile.lock(lockPath(), {\n\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\tlockfilePath: `${lockPath()}.guard`,\n\t\trealpath: false,\n\t\tstale: LOCK_GUARD_STALE_MS,\n\t\tupdate: LOCK_GUARD_UPDATE_MS,\n\t\tonCompromised: (error) => {\n\t\t\tcompromisedError = error;\n\t\t},\n\t});\n\treturn {\n\t\trelease,\n\t\tthrowIfCompromised: () => {\n\t\t\tif (compromisedError) throw compromisedError;\n\t\t},\n\t\tisCompromised: () => compromisedError !== undefined,\n\t};\n}\n\nasync function describeHeldLock() {\n\tconst current = await readLock();\n\tif (current && isStaleLock(current)) {\n\t\treturn new Error(\"pi-sync lock owner exited; retry shortly while the lock guard expires.\");\n\t}\n\tif (current) {\n\t\treturn new Error(\n\t\t\t`Pi-sync is currently running (${current.command}, pid ${current.pid}, started ${current.startedAt}).`,\n\t\t);\n\t}\n\treturn new Error(\n\t\t\"Pi-sync is currently running (lock metadata is unreadable or still being written).\",\n\t);\n}\n\nfunction isLockHeldError(error: unknown) {\n\treturn (error as NodeJS.ErrnoException).code === \"ELOCKED\";\n}\n\nfunction isLockFile(value: unknown): value is LockFile {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n\tconst lock = value as Partial<LockFile>;\n\treturn (\n\t\ttypeof lock.id === \"string\" &&\n\t\tlock.id.length > 0 &&\n\t\tNumber.isInteger(lock.pid) &&\n\t\t(lock.pid ?? 0) > 0 &&\n\t\t(lock.pid ?? 0) <= MAX_PROCESS_ID &&\n\t\ttypeof lock.command === \"string\" &&\n\t\tlock.command.length > 0 &&\n\t\ttypeof lock.startedAt === \"string\" &&\n\t\tNumber.isFinite(Date.parse(lock.startedAt))\n\t);\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sync/remote-snapshot.ts"],
4
- "sourcesContent": ["import type { RemoteHead, SyncBackend } from \"../backends/sync-backend.js\";\nimport { syncConfigReviewFingerprint } from \"../settings/config.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { filterSnapshotForConfigPolicy } from \"../snapshot/snapshot.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport {\n\tinspectRemoteSelection,\n\ttype RemoteSelectionState,\n\tremoteSelectionMismatch,\n\tsameSyncInclude,\n\tsnapshotSelectionInclude,\n} from \"./sync-policy.js\";\n\nexport async function readSnapshotForHead(\n\tbackend: SyncBackend,\n\thead: RemoteHead,\n\tsignal?: AbortSignal,\n) {\n\tconst snapshot = await backend.readSnapshot(head.snapshotRef, signal);\n\tif (signal?.aborted) {\n\t\tthrow signal.reason instanceof Error\n\t\t\t? signal.reason\n\t\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n\t}\n\tif (snapshot.id !== head.snapshotId) {\n\t\tthrow new Error(\n\t\t\t`Remote head ${head.snapshotId} resolved to unexpected snapshot ${snapshot.id}.`,\n\t\t);\n\t}\n\tif (head.selection) {\n\t\tconst snapshotInclude = snapshotSelectionInclude(snapshot);\n\t\tif (!snapshotInclude || !sameSyncInclude(head.selection.include, snapshotInclude)) {\n\t\t\tthrow new Error(\"Remote head selection does not match its immutable snapshot.\");\n\t\t}\n\t}\n\treturn snapshot;\n}\n\nexport function requireCompatibleRemoteSelection(config: AnySyncConfig, snapshot: Snapshot) {\n\tconst state = inspectRemoteSelection(config.include, snapshot);\n\tif (state.kind === \"different\") {\n\t\tthrow remoteSelectionMismatch(config, state.include, syncConfigReviewFingerprint(config));\n\t}\n}\n\nexport function formatRemoteSelectionStatus(state: RemoteSelectionState | undefined) {\n\tif (!state) return \"remote included content: unavailable (remote is empty)\";\n\tif (state.kind === \"same\") return \"remote included content: matches this setup\";\n\tif (state.kind === \"legacy\") {\n\t\treturn `remote included content: unavailable in legacy snapshot (${state.discovered.length} path${state.discovered.length === 1 ? \"\" : \"s\"} discovered, partial)`;\n\t}\n\treturn [\n\t\t\"remote included content: differs from this setup\",\n\t\t`remote-only selection: ${safeList(state.remoteOnly)}`,\n\t\t`local-only selection: ${safeList(state.localOnly)}`,\n\t].join(\"\\n\");\n}\n\nfunction safeList(values: readonly string[]) {\n\treturn values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n\nexport async function readRemoteSnapshot(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\tsignal?: AbortSignal,\n\toptions: { allowSelectionDifference?: boolean } = {},\n) {\n\tconst head = await backend.readHead(signal);\n\tif (!head) return { head: undefined, snapshot: undefined, selectionState: undefined };\n\tconst snapshot = await readSnapshotForHead(backend, head, signal);\n\tconst selectionState = inspectRemoteSelection(config.include, snapshot);\n\tif (!options.allowSelectionDifference && selectionState.kind === \"different\") {\n\t\tconst configIdentity = syncConfigReviewFingerprint(config);\n\t\tthrow remoteSelectionMismatch(config, selectionState.include, configIdentity);\n\t}\n\treturn {\n\t\thead,\n\t\tsnapshot: filterSnapshotForConfigPolicy(snapshot, config),\n\t\tselectionState,\n\t};\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAcA,eAAsB,oBACrB,SACA,MACA,QACC;AACD,QAAM,WAAW,MAAM,QAAQ,aAAa,KAAK,aAAa,MAAM;AACpE,MAAI,QAAQ,SAAS;AACpB,UAAM,OAAO,kBAAkB,QAC5B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAAA,EAC9D;AACA,MAAI,SAAS,OAAO,KAAK,YAAY;AACpC,UAAM,IAAI;AAAA,MACT,eAAe,KAAK,UAAU,oCAAoC,SAAS,EAAE;AAAA,IAC9E;AAAA,EACD;AACA,MAAI,KAAK,WAAW;AACnB,UAAM,kBAAkB,yBAAyB,QAAQ;AACzD,QAAI,CAAC,mBAAmB,CAAC,gBAAgB,KAAK,UAAU,SAAS,eAAe,GAAG;AAClF,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAC/E;AAAA,EACD;AACA,SAAO;AACR;AAEO,SAAS,iCAAiC,QAAuB,UAAoB;AAC3F,QAAM,QAAQ,uBAAuB,OAAO,SAAS,QAAQ;AAC7D,MAAI,MAAM,SAAS,aAAa;AAC/B,UAAM,wBAAwB,QAAQ,MAAM,SAAS,4BAA4B,MAAM,CAAC;AAAA,EACzF;AACD;AAEO,SAAS,4BAA4B,OAAyC;AACpF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,MAAI,MAAM,SAAS,UAAU;AAC5B,WAAO,4DAA4D,MAAM,WAAW,MAAM,QAAQ,MAAM,WAAW,WAAW,IAAI,KAAK,GAAG;AAAA,EAC3I;AACA,SAAO;AAAA,IACN;AAAA,IACA,0BAA0B,SAAS,MAAM,UAAU,CAAC;AAAA,IACpD,yBAAyB,SAAS,MAAM,SAAS,CAAC;AAAA,EACnD,EAAE,KAAK,IAAI;AACZ;AAEA,SAAS,SAAS,QAA2B;AAC5C,SAAO,OAAO,SAAS,IAAI,OAAO,IAAI,gBAAgB,EAAE,KAAK,IAAI,IAAI;AACtE;AAEA,eAAsB,mBACrB,SACA,QACA,QACA,UAAkD,CAAC,GAClD;AACD,QAAM,OAAO,MAAM,QAAQ,SAAS,MAAM;AAC1C,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,QAAW,UAAU,QAAW,gBAAgB,OAAU;AACpF,QAAM,WAAW,MAAM,oBAAoB,SAAS,MAAM,MAAM;AAChE,QAAM,iBAAiB,uBAAuB,OAAO,SAAS,QAAQ;AACtE,MAAI,CAAC,QAAQ,4BAA4B,eAAe,SAAS,aAAa;AAC7E,UAAM,iBAAiB,4BAA4B,MAAM;AACzD,UAAM,wBAAwB,QAAQ,eAAe,SAAS,cAAc;AAAA,EAC7E;AACA,SAAO;AAAA,IACN;AAAA,IACA,UAAU,8BAA8B,UAAU,MAAM;AAAA,IACxD;AAAA,EACD;AACD;",
6
- "names": []
7
- }