@narumitw/pi-sync 0.49.15 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +49 -16
  2. package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
  3. package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
  4. package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
  5. package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
  6. package/dist/chunks/chunk-6UHKGALE.ts +134 -0
  7. package/dist/chunks/chunk-6UHKGALE.ts.map +7 -0
  8. package/dist/chunks/{chunk-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
  9. package/dist/chunks/chunk-AUSDLD6F.ts.map +7 -0
  10. package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-AXXS2BPA.ts} +9 -9
  11. package/dist/chunks/chunk-AXXS2BPA.ts.map +7 -0
  12. package/dist/chunks/{chunk-5T442OP3.ts → chunk-C7XY5NF5.ts} +210 -373
  13. package/dist/chunks/chunk-C7XY5NF5.ts.map +7 -0
  14. package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
  15. package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
  16. package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
  17. package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
  18. package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
  19. package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
  20. package/dist/chunks/{chunk-WSOBYHIZ.ts → chunk-GWMHAQG4.ts} +4 -4
  21. package/dist/chunks/chunk-GWMHAQG4.ts.map +7 -0
  22. package/dist/chunks/{chunk-5LZALPCD.ts → chunk-HUDQATCL.ts} +25 -25
  23. package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
  24. package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
  25. package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
  26. package/dist/chunks/chunk-JSYMGJQQ.ts +51 -0
  27. package/dist/chunks/chunk-JSYMGJQQ.ts.map +7 -0
  28. package/dist/chunks/chunk-L7TBO32M.ts +25 -0
  29. package/dist/chunks/chunk-L7TBO32M.ts.map +7 -0
  30. package/dist/chunks/{chunk-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -8
  31. package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
  32. package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
  33. package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
  34. package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
  35. package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
  36. package/dist/chunks/{chunk-HVUSHMVL.ts → chunk-OEX4ABY6.ts} +39 -37
  37. package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
  38. package/dist/chunks/chunk-OUHGBFYF.ts +1255 -0
  39. package/dist/chunks/chunk-OUHGBFYF.ts.map +7 -0
  40. package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
  41. package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
  42. package/dist/chunks/{chunk-GLQLN5GV.ts → chunk-SL64RLXR.ts} +8 -6
  43. package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
  44. package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
  45. package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
  46. package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
  47. package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
  48. package/dist/chunks/chunk-THMF4BVL.ts +18 -0
  49. package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
  50. package/dist/chunks/{chunk-44LPGQTI.ts → chunk-X5OM6GXT.ts} +9 -7
  51. package/dist/chunks/chunk-X5OM6GXT.ts.map +7 -0
  52. package/dist/chunks/chunk-XBX4HBLG.ts +57 -0
  53. package/dist/chunks/chunk-XBX4HBLG.ts.map +7 -0
  54. package/dist/chunks/{chunk-ARN2672F.ts → chunk-YKJHPTGO.ts} +23 -55
  55. package/dist/chunks/chunk-YKJHPTGO.ts.map +7 -0
  56. package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
  57. package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
  58. package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
  59. package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
  60. package/dist/chunks/{file-selection-RKEHALNQ.ts → file-selection-FTTKAOYX.ts} +10 -7
  61. package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
  62. package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-OQW46G2X.ts} +42 -17
  63. package/dist/chunks/git-backend-OQW46G2X.ts.map +7 -0
  64. package/dist/chunks/manager-result-dispatcher-U23ODD32.ts +22 -0
  65. package/dist/chunks/manager-ui-ABATHC36.ts +1680 -0
  66. package/dist/chunks/manager-ui-ABATHC36.ts.map +7 -0
  67. package/dist/chunks/remote-selection-ui-ZE3TY67S.ts +21 -0
  68. package/dist/chunks/{s3-backend-552LXHE4.ts → s3-backend-3P33LQHU.ts} +96 -18
  69. package/dist/chunks/s3-backend-3P33LQHU.ts.map +7 -0
  70. package/dist/chunks/{setup-switch-5YDG5YGJ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
  71. package/dist/chunks/setup-wizard-VB3VDOV5.ts +89 -0
  72. package/dist/chunks/setup-wizard-VB3VDOV5.ts.map +7 -0
  73. package/dist/chunks/{snapshot-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
  74. package/dist/chunks/sync-inspection-FEP4L5TR.ts +20 -0
  75. package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-ONJ27QRL.ts} +374 -294
  76. package/dist/chunks/sync-operations-ONJ27QRL.ts.map +7 -0
  77. package/dist/chunks/{sync-state-SRN6YRBK.ts → sync-state-Q2FTXTW6.ts} +6 -6
  78. package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
  79. package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
  80. package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
  81. package/dist/index.ts +477 -342
  82. package/dist/index.ts.map +4 -4
  83. package/docs/settings.md +30 -6
  84. package/package.json +1 -1
  85. package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
  86. package/src/backends/backend-identity.ts +40 -0
  87. package/src/backends/backend-types.ts +81 -0
  88. package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
  89. package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
  90. package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
  91. package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
  92. package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
  93. package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
  94. package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
  95. package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
  96. package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
  97. package/src/commands/command-execution.ts +330 -0
  98. package/src/commands/command-handler.ts +201 -0
  99. package/src/commands/command-types.ts +18 -0
  100. package/src/{command.ts → commands/command.ts} +2 -1
  101. package/src/commands/setup-completions.ts +6 -0
  102. package/src/settings/config.ts +238 -0
  103. package/src/{settings-management.ts → settings/settings-management.ts} +39 -14
  104. package/src/settings/settings-store.ts +109 -0
  105. package/src/settings/settings-types.ts +128 -0
  106. package/src/settings/settings-validation.ts +443 -0
  107. package/src/snapshot/session-paths.ts +84 -0
  108. package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
  109. package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
  110. package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
  111. package/src/snapshot/snapshot-types.ts +38 -0
  112. package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
  113. package/src/state/json-file.ts +20 -0
  114. package/src/{lock.ts → state/lock.ts} +3 -2
  115. package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
  116. package/src/state/state-types.ts +20 -0
  117. package/src/state/sync-state-store.ts +62 -0
  118. package/src/sync/automatic-sync.ts +103 -0
  119. package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
  120. package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
  121. package/src/sync/signals.ts +10 -0
  122. package/src/sync/startup-check.ts +128 -0
  123. package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
  124. package/src/sync/sync-error-guidance.ts +53 -0
  125. package/src/sync/sync-inspection.ts +51 -0
  126. package/src/sync/sync-loaders.ts +54 -0
  127. package/src/{sync-operations.ts → sync/sync-mutations.ts} +34 -325
  128. package/src/sync/sync-operations.ts +12 -0
  129. package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
  130. package/src/sync/sync-queries.ts +235 -0
  131. package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
  132. package/src/sync-extension.ts +64 -708
  133. package/src/sync.ts +8 -8
  134. package/src/types.ts +47 -286
  135. package/src/ui/automatic-sync-summary.ts +6 -0
  136. package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
  137. package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
  138. package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
  139. package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
  140. package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
  141. package/src/ui/manager-ui.ts +386 -0
  142. package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
  143. package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
  144. package/src/{settings-ui.ts → ui/settings-ui.ts} +17 -13
  145. package/src/ui/setup/git-ui.ts +293 -0
  146. package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
  147. package/src/ui/setup/s3-ui.ts +217 -0
  148. package/src/ui/setup/setup-actions.ts +127 -0
  149. package/src/ui/setup/setup-location-ui.ts +167 -0
  150. package/src/ui/setup/setup-name-ui.ts +34 -0
  151. package/src/ui/setup/setup-prompts.ts +92 -0
  152. package/src/ui/setup/setup-review.ts +70 -0
  153. package/src/ui/setup/setup-switcher.ts +181 -0
  154. package/src/ui/setup/setup-wizard.ts +39 -0
  155. package/src/ui/setup/text-input.ts +78 -0
  156. package/src/ui/setup/webdav-ui.ts +330 -0
  157. package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
  158. package/src/{sync-attention.ts → ui/sync-attention.ts} +75 -6
  159. package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
  160. package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
  161. package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
  162. package/src/ui/terminal-text.ts +4 -0
  163. package/dist/chunks/chunk-44LPGQTI.ts.map +0 -7
  164. package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
  165. package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
  166. package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
  167. package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
  168. package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
  169. package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
  170. package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
  171. package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
  172. package/dist/chunks/chunk-E4COSV32.ts +0 -82
  173. package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
  174. package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
  175. package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
  176. package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
  177. package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
  178. package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
  179. package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
  180. package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
  181. package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
  182. package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
  183. package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
  184. package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
  185. package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
  186. package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
  187. package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
  188. package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
  189. package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
  190. package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
  191. package/src/config.ts +0 -923
  192. package/src/git-ui.ts +0 -307
  193. package/src/manager-helpers.ts +0 -64
  194. package/src/manager-ui.ts +0 -997
  195. package/src/webdav-ui.ts +0 -421
  196. /package/dist/chunks/{manager-result-dispatcher-LWPYJAD5.ts.map → manager-result-dispatcher-U23ODD32.ts.map} +0 -0
  197. /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-ZE3TY67S.ts.map} +0 -0
  198. /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
  199. /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
  200. /package/dist/chunks/{sync-state-SRN6YRBK.ts.map → sync-inspection-FEP4L5TR.ts.map} +0 -0
  201. /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
  202. /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
  203. /package/src/{config-file.ts → settings/config-file.ts} +0 -0
  204. /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
  205. /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
  206. /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
  207. /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
  208. /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
  209. /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
@@ -1,13 +1,14 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { truncateToWidth } from "@earendil-works/pi-tui";
3
- import { syncConfigReviewFingerprint } from "./config.js";
4
- import { safeTerminalText } from "./sync-format.js";
3
+ import { syncCheckConfigFingerprint, syncConfigReviewFingerprint } from "../settings/config.js";
4
+ import type { AnySyncConfig } from "../settings/settings-types.js";
5
+ import type { StartupObservation } from "../sync/sync-inspection.js";
5
6
  import {
6
7
  compareSyncInclude,
7
8
  type RemoteSelectionDecision,
8
9
  sameSyncInclude,
9
- } from "./sync-policy.js";
10
- import type { AnySyncConfig } from "./types.js";
10
+ } from "../sync/sync-policy.js";
11
+ import { safeTerminalText } from "./terminal-text.js";
11
12
 
12
13
  const STATUS_KEY = "sync";
13
14
  const WIDGET_KEY = "sync:attention";
@@ -29,6 +30,10 @@ export function syncAttentionMatchesConfig(attention: SyncAttentionState, config
29
30
  }
30
31
 
31
32
  export interface SyncAttentionController {
33
+ observe(observation: StartupObservation): void;
34
+ observation(): StartupObservation | undefined;
35
+ clearObservation(): void;
36
+ notifyObservation(ctx: ExtensionContext): void;
32
37
  set(decision: RemoteSelectionDecision, origin: SyncAttentionOrigin): void;
33
38
  current(): SyncAttentionState | undefined;
34
39
  markOffered(): boolean;
@@ -39,8 +44,23 @@ export interface SyncAttentionController {
39
44
 
40
45
  export function createSyncAttentionController(): SyncAttentionController {
41
46
  let state: SyncAttentionState | undefined;
47
+ let observation: StartupObservation | undefined;
42
48
 
43
49
  return {
50
+ observe(value) {
51
+ observation = value;
52
+ },
53
+ observation() {
54
+ return observation;
55
+ },
56
+ clearObservation() {
57
+ observation = undefined;
58
+ },
59
+ notifyObservation(ctx) {
60
+ if (observation && observationNeedsAttention(observation)) {
61
+ ctx.ui.notify(observationLines(observation).join("\n"), "warning");
62
+ }
63
+ },
44
64
  set(decision, origin) {
45
65
  state = { decision, origin, offered: false };
46
66
  },
@@ -58,14 +78,20 @@ export function createSyncAttentionController(): SyncAttentionController {
58
78
  },
59
79
  reset(ctx) {
60
80
  state = undefined;
81
+ observation = undefined;
61
82
  clearAttentionPresentation(ctx);
62
83
  },
63
84
  publish(ctx) {
64
- if (!state) {
85
+ if (!state && (!observation || !observationNeedsAttention(observation))) {
65
86
  clearAttentionPresentation(ctx);
66
87
  return;
67
88
  }
68
- const presentation = attentionPresentation(state.decision);
89
+ const presentation = state
90
+ ? attentionPresentation(state.decision)
91
+ : {
92
+ status: "changes to review",
93
+ lines: observationLines(observation as StartupObservation),
94
+ };
69
95
  ctx.ui.setStatus(STATUS_KEY, presentation.status);
70
96
  if (ctx.mode !== "tui") return;
71
97
  ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => ({
@@ -94,6 +120,49 @@ function attentionPresentation(decision: RemoteSelectionDecision) {
94
120
  };
95
121
  }
96
122
 
123
+ export function observationMatchesConfig(observation: StartupObservation, config: AnySyncConfig) {
124
+ return observation.configIdentity === syncCheckConfigFingerprint(config);
125
+ }
126
+
127
+ export function observationSummary(observation: StartupObservation) {
128
+ const result = observation.inspection;
129
+ if (result.emptyInclude) return "No included content selected";
130
+ if (result.selectionState?.kind === "different")
131
+ return "Synced-content list differs; review needed";
132
+ if (result.firstSync)
133
+ return result.head
134
+ ? "No sync baseline; review remote and local content"
135
+ : "Remote empty; no sync baseline";
136
+ if (!result.head) return "Remote snapshot missing; review needed";
137
+ if (result.localChanged && result.remoteChanged)
138
+ return "Local and remote changed since last sync; review needed";
139
+ if (result.remoteChanged) return "Remote changed since last sync";
140
+ if (result.localChanged) return "Local content changed since last sync";
141
+ if (result.selectionState?.kind === "legacy")
142
+ return "Legacy remote has no authoritative content list";
143
+ return "No changes detected since last sync";
144
+ }
145
+
146
+ export function observationNeedsAttention(observation: StartupObservation) {
147
+ const result = observation.inspection;
148
+ return (
149
+ result.emptyInclude ||
150
+ result.firstSync ||
151
+ !result.head ||
152
+ result.localChanged ||
153
+ result.remoteChanged ||
154
+ result.selectionState?.kind !== "same"
155
+ );
156
+ }
157
+
158
+ function observationLines(observation: StartupObservation) {
159
+ return [
160
+ `Pi Sync check · ${safeTerminalText(observation.setupName)}`,
161
+ observationSummary(observation),
162
+ "No startup transfer · Run /sync to review",
163
+ ];
164
+ }
165
+
97
166
  function clearAttentionPresentation(ctx: ExtensionContext) {
98
167
  ctx.ui.setStatus(STATUS_KEY, undefined);
99
168
  ctx.ui.setWidget(WIDGET_KEY, undefined);
@@ -1,11 +1,10 @@
1
- import { agentDir } from "./config.js";
2
-
3
- export { errorMessage } from "./sync-errors.js";
4
-
5
- import type { PublicationCapability, RemoteHead } from "./sync-backend.js";
6
- import { inspectRemoteSelection } from "./sync-policy.js";
7
- import { fileHashMap } from "./sync-state.js";
8
- import type { CommonSyncConfig, Snapshot } from "./types.js";
1
+ import type { PublicationCapability, RemoteHead } from "../backends/sync-backend.js";
2
+ import type { CommonSyncConfig } from "../settings/settings-types.js";
3
+ import { agentDir } from "../snapshot/session-paths.js";
4
+ import type { Snapshot } from "../snapshot/snapshot-types.js";
5
+ import { inspectRemoteSelection } from "../sync/sync-policy.js";
6
+ import { fileHashMap } from "../sync/sync-state.js";
7
+ import { safeTerminalText } from "./terminal-text.js";
9
8
 
10
9
  export function formatDiff(local: Snapshot, remote: Snapshot) {
11
10
  const localMap = fileHashMap(local);
@@ -161,11 +160,6 @@ export function publicationCapabilityDescription(capability: PublicationCapabili
161
160
  }
162
161
  }
163
162
 
164
- export function safeTerminalText(value: string) {
165
- // biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.
166
- return value.replace(/[\u0000-\u001f\u007f-\u009f]/gu, "?");
167
- }
168
-
169
163
  export function redact(value: string) {
170
164
  return value.length <= 8 ? "configured" : `${value.slice(0, 4)}…${value.slice(-4)}`;
171
165
  }
@@ -1,13 +1,14 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
3
+ import { loadConfig, syncConfigReviewIdentity } from "../settings/config.js";
4
+ import type { SyncDecision, SyncResolutionDirection } from "../sync/sync-decision.js";
5
+ import { errorMessage } from "../sync/sync-errors.js";
3
6
  import {
4
7
  type RunRoute,
5
8
  type RunRouteResult,
6
9
  runCancellableOperation,
7
10
  } from "./cancellable-operation.js";
8
- import { loadConfig, syncConfigReviewIdentity } from "./config.js";
9
- import type { SyncDecision, SyncResolutionDirection } from "./sync-decision.js";
10
- import { errorMessage, safeTerminalText } from "./sync-format.js";
11
+ import { safeTerminalText } from "./terminal-text.js";
11
12
 
12
13
  export type SyncResolutionResult =
13
14
  | { kind: "resolved"; direction: SyncResolutionDirection }
@@ -1,8 +1,11 @@
1
1
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
2
  import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
3
- import { loadConfig, readLocalConfigObject } from "./config.js";
4
- import { errorMessage, ownRecord, safeTerminalText } from "./manager-helpers.js";
5
- import { syncIncludeSelection } from "./sync-policy.js";
3
+ import { loadConfig } from "../settings/config.js";
4
+ import { readLocalConfigObject } from "../settings/settings-store.js";
5
+ import { ownRecord } from "../settings/settings-validation.js";
6
+ import { syncErrorGuidance } from "../sync/sync-error-guidance.js";
7
+ import { syncIncludeSelection } from "../sync/sync-policy.js";
8
+ import { safeTerminalText } from "./terminal-text.js";
6
9
 
7
10
  export async function countValidSyncSetups(
8
11
  setups: Record<string, unknown> | undefined,
@@ -68,6 +71,7 @@ export async function showSyncSetups(
68
71
  return {
69
72
  kind: "actions",
70
73
  title: "Sync setups",
74
+ lines: ["What to sync, where to store it, and when to sync."],
71
75
  items: [
72
76
  { id: "add", label: "Add sync setup", action: "add" },
73
77
  ...names.map((name, index) => {
@@ -76,6 +80,7 @@ export async function showSyncSetups(
76
80
  return {
77
81
  id,
78
82
  label: `${safeTerminalText(name)}${name === state.active ? " (current)" : ""}`,
83
+ description: setupSummary(state.setups[name]),
79
84
  action: "select" as const,
80
85
  };
81
86
  }),
@@ -102,7 +107,7 @@ export async function showSyncSetups(
102
107
  action: "make-current" as const,
103
108
  },
104
109
  ]),
105
- { id: "edit", label: "Edit sync setup…", action: "edit" },
110
+ { id: "edit", label: "Edit storage location…", action: "edit" },
106
111
  ...(state.selected.removeUnavailable
107
112
  ? []
108
113
  : [
@@ -124,10 +129,7 @@ export async function showSyncSetups(
124
129
  await actions.add(signal);
125
130
  } catch (error) {
126
131
  if (!signal?.aborted) {
127
- ctx.ui.notify(
128
- `Sync setup was not added: ${menuErrorMessage(error)} Retry from Add sync setup.`,
129
- "error",
130
- );
132
+ ctx.ui.notify(`Sync setup was not added: ${menuErrorMessage(error)}`, "error");
131
133
  }
132
134
  }
133
135
  return { kind: "stay" };
@@ -206,6 +208,9 @@ async function loadSetupMenuState(
206
208
  `Included content: ${selection.builtIns.length} built-in groups · ${selection.custom.length} extra paths`,
207
209
  `Sessions: ${selection.sessions ? "On — privacy-sensitive" : "Off"}`,
208
210
  `Automatic sync: ${config.automatic ? "On" : "Off"}`,
211
+ isCurrent
212
+ ? "Edit included content and automatic sync in /sync → Settings."
213
+ : "To edit included content or automatic sync, make this setup current, then open /sync → Settings.",
209
214
  ];
210
215
  } catch (error) {
211
216
  valid = false;
@@ -232,13 +237,21 @@ function notifySetupChangeError(
232
237
  ) {
233
238
  if (signal?.aborted) return;
234
239
  ctx.ui.notify(
235
- `Sync setup “${safeTerminalText(name)}” was not changed: ${menuErrorMessage(error)} Reopen it and retry.`,
240
+ `Sync setup “${safeTerminalText(name)}” was not changed: ${menuErrorMessage(error)}`,
236
241
  "error",
237
242
  );
238
243
  }
239
244
 
240
245
  function menuErrorMessage(error: unknown) {
241
- return safeTerminalText(errorMessage(error));
246
+ return syncErrorGuidance(error);
247
+ }
248
+
249
+ function setupSummary(value: unknown) {
250
+ const storage = ownRecord(ownRecord(value)?.storage);
251
+ if (!storage || typeof storage.connection !== "string") return "Invalid storage reference";
252
+ return safeTerminalText(
253
+ `${storage.connection} · ${storage.bucket ?? storage.branch ?? "WebDAV"} · ${storage.path ?? "missing path"}`,
254
+ );
242
255
  }
243
256
 
244
257
  function storageEndpoint(config: Awaited<ReturnType<typeof loadConfig>>) {
@@ -0,0 +1,4 @@
1
+ export function safeTerminalText(value: string) {
2
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.
3
+ return value.replace(/[\u0000-\u001f\u007f-\u009f]/gu, "?");
4
+ }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sync-resolution-ui.ts", "../../src/manager-result-dispatcher.ts"],
4
- "sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport {\n\ttype RunRoute,\n\ttype RunRouteResult,\n\trunCancellableOperation,\n} from \"./cancellable-operation.js\";\nimport { loadConfig, syncConfigReviewIdentity } from \"./config.js\";\nimport type { SyncDecision, SyncResolutionDirection } from \"./sync-decision.js\";\nimport { errorMessage, safeTerminalText } from \"./sync-format.js\";\n\nexport type SyncResolutionResult =\n\t| { kind: \"resolved\"; direction: SyncResolutionDirection }\n\t| {\n\t\t\tkind: \"route-result\";\n\t\t\tresult: RunRouteResult;\n\t\t\troute: SyncResolutionDirection;\n\t }\n\t| { kind: \"back\" }\n\t| { kind: \"closed\" }\n\t| { kind: \"stale\" };\n\nexport async function showSyncResolution(\n\tctx: ExtensionContext,\n\tinitialDecision: SyncDecision,\n\trunRoute: RunRoute,\n\tsessionSignal?: AbortSignal,\n): Promise<SyncResolutionResult> {\n\ttype Screen = \"resolve\" | \"review\";\n\ttype Action = \"push\" | \"pull\" | \"back\";\n\tlet currentDecision = initialDecision;\n\tlet resolvedDirection: SyncResolutionDirection | undefined;\n\tlet chainedResult: { result: RunRouteResult; route: SyncResolutionDirection } | undefined;\n\tconst menu = defineMenu<SyncDecision, Screen, Action, ExtensionContext>({\n\t\tstart: \"resolve\",\n\t\tscreens: {\n\t\t\tresolve: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: resolutionTitle(state),\n\t\t\t\tlines: resolutionLines(state),\n\t\t\t\titems: [\n\t\t\t\t\t{ id: \"review\", label: \"Review differences (recommended)\", to: \"review\" },\n\t\t\t\t\t...(state.directions.includes(\"push\")\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: \"push\",\n\t\t\t\t\t\t\t\t\tlabel: pushLabel(state),\n\t\t\t\t\t\t\t\t\tdescription: \"Review an exact push before replacing the remote version.\",\n\t\t\t\t\t\t\t\t\taction: \"push\" as const,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t...(state.directions.includes(\"pull\")\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: \"pull\",\n\t\t\t\t\t\t\t\t\tlabel: pullLabel(state),\n\t\t\t\t\t\t\t\t\tdescription: \"Review exact local changes and create a backup before applying.\",\n\t\t\t\t\t\t\t\t\taction: \"pull\" as const,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t{ id: \"back\", label: \"Back\", action: \"back\" },\n\t\t\t\t],\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\treview: ({ state }) => ({\n\t\t\t\tkind: \"review\",\n\t\t\t\ttitle: `Review differences \u00B7 ${safeTerminalText(state.setupName)}`,\n\t\t\t\tcontent: state.review,\n\t\t\t\tformat: { kind: \"text\" },\n\t\t\t\tviewportSize: \"adaptive\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\tpush: ({ state, signal }) => resolveDirection(\"push\", state, signal),\n\t\t\tpull: ({ state, signal }) => resolveDirection(\"pull\", state, signal),\n\t\t\tback: async () => ({ kind: \"back\" }),\n\t\t},\n\t});\n\n\tasync function resolveDirection(\n\t\tdirection: SyncResolutionDirection,\n\t\tdecision: SyncDecision,\n\t\tactionSignal: AbortSignal,\n\t) {\n\t\tconst signal = sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;\n\t\tconst config = await loadConfig(decision.setupName);\n\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\tif (syncConfigReviewIdentity(config) !== decision.configIdentity) {\n\t\t\tthrow new Error(\n\t\t\t\t`Sync setup \u201C${safeTerminalText(decision.setupName)}\u201D changed while conflict resolution was open; return to the sync manager and retry.`,\n\t\t\t);\n\t\t}\n\t\tconst result = await runCancellableOperation(\n\t\t\tctx,\n\t\t\tdirection === \"push\"\n\t\t\t\t? \"Preparing local-wins push preview\u2026\"\n\t\t\t\t: \"Preparing remote-wins pull preview\u2026\",\n\t\t\t`${direction} --force`,\n\t\t\trunRoute,\n\t\t\t{\n\t\t\t\tcommitAware: true,\n\t\t\t\tcancelledMessage:\n\t\t\t\t\tdirection === \"push\"\n\t\t\t\t\t\t? \"Push preparation cancelled; no remote files were changed.\"\n\t\t\t\t\t\t: \"Pull check cancelled; no local files were changed.\",\n\t\t\t\ttarget: decision.setupName,\n\t\t\t\tsignal,\n\t\t\t},\n\t\t);\n\t\tif (result.kind === \"decision-required\") {\n\t\t\tcurrentDecision = result.decision;\n\t\t\treturn { kind: \"stay\" as const };\n\t\t}\n\t\tif (result.kind === \"remote-selection-required\") {\n\t\t\tchainedResult = { result, route: direction };\n\t\t\treturn { kind: \"close\" as const };\n\t\t}\n\t\tif (result.kind === \"completed\") {\n\t\t\tif (result.outcome === \"cancelled\") return { kind: \"stay\" as const };\n\t\t\tresolvedDirection = direction;\n\t\t\treturn { kind: \"close\" as const };\n\t\t}\n\t\treturn result.kind === \"closed\" ? { kind: \"close\" as const } : { kind: \"stay\" as const };\n\t}\n\n\tconst result = await runMenu(ctx, menu, {\n\t\tgetState: () => currentDecision,\n\t\tsignal: sessionSignal,\n\t\tisCurrent: () => !sessionSignal?.aborted,\n\t\tonError: (_menuCtx, error) => ctx.ui.notify(errorMessage(error), \"error\"),\n\t});\n\tif (sessionSignal?.aborted || result.kind === \"stale\") return { kind: \"stale\" };\n\tif (chainedResult) return { kind: \"route-result\", ...chainedResult };\n\tif (resolvedDirection) return { kind: \"resolved\", direction: resolvedDirection };\n\tif (result.kind === \"closed\") {\n\t\treturn result.reason === \"back\" ? { kind: \"back\" } : { kind: \"closed\" };\n\t}\n\treturn { kind: \"closed\" };\n}\n\nfunction resolutionTitle(decision: SyncDecision) {\n\treturn decision.kind === \"remote-empty\" ? \"Remote is empty\" : \"Resolve sync conflict\";\n}\n\nfunction resolutionLines(decision: SyncDecision) {\n\treturn [\n\t\t`Sync setup: ${safeTerminalText(decision.setupName)}`,\n\t\t...causeSummary(decision),\n\t\t\"No files have been changed by this failed operation.\",\n\t];\n}\n\nfunction causeSummary(decision: SyncDecision) {\n\tif (decision.kind === \"first-sync-settings-diverged\") {\n\t\treturn [\"This machine and the remote have different Pi settings on first sync.\"];\n\t}\n\tif (decision.kind === \"first-sync-sessions-diverged\") {\n\t\treturn [\"Pi settings match, but local and remote sessions differ on first sync.\"];\n\t}\n\tif (decision.kind === \"remote-empty\") return [\"The remote storage location has no snapshot.\"];\n\treturn [\n\t\t...(decision.causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n\t\t...(decision.causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n\t\t...(decision.causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n\t];\n}\n\nfunction pushLabel(decision: SyncDecision) {\n\tif (decision.kind === \"remote-empty\") return \"Push local content\u2026\";\n\tif (decision.kind.startsWith(\"first-sync-\")) return \"Use local as initial source\u2026\";\n\treturn \"Keep local content and replace remote\u2026\";\n}\n\nfunction pullLabel(decision: SyncDecision) {\n\treturn decision.kind.startsWith(\"first-sync-\")\n\t\t? \"Use remote as initial source\u2026\"\n\t\t: \"Use remote content and replace local\u2026\";\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type {\n\tCancellableOperationResult,\n\tRunRoute,\n\tRunRouteResult,\n} from \"./cancellable-operation.js\";\nimport { type RemoteSelectionOrigin, showRemoteSelectionReview } from \"./remote-selection-ui.js\";\nimport { showSyncResolution } from \"./sync-resolution-ui.js\";\n\nconst MAX_DECISION_TRANSITIONS = 32;\n\nexport interface ManagerResultDisposition {\n\tkind: \"close\" | \"stay\";\n\tappliedRoute?: \"sync\" | \"pull\" | \"push\";\n}\n\nexport interface ManagerResultOptions {\n\tcancelLabel?: string;\n\tonSelectionResolved?: () => void;\n\twithStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport async function dispatchManagerResult(\n\tctx: ExtensionContext,\n\tinitialResult: CancellableOperationResult,\n\torigin: Exclude<RemoteSelectionOrigin, \"settings\">,\n\trunRoute: RunRoute,\n\tsignal?: AbortSignal,\n\toptions: ManagerResultOptions = {},\n): Promise<ManagerResultDisposition> {\n\tlet result: CancellableOperationResult | RunRouteResult = initialResult;\n\tlet currentRoute: \"sync\" | \"pull\" | \"push\" = origin;\n\tlet resolving = false;\n\n\tfor (let transition = 0; transition < MAX_DECISION_TRANSITIONS; transition += 1) {\n\t\tif (signal?.aborted) return { kind: \"close\" };\n\t\tif (result.kind === \"remote-selection-required\") {\n\t\t\tresolving = true;\n\t\t\tconst resolution = await showRemoteSelectionReview(\n\t\t\t\tctx,\n\t\t\t\tresult.decision.setupName,\n\t\t\t\tsignal,\n\t\t\t\tundefined,\n\t\t\t\t{\n\t\t\t\t\tdecision: result.decision,\n\t\t\t\t\torigin: currentRoute,\n\t\t\t\t\trunRoute,\n\t\t\t\t\tcancelLabel: options.cancelLabel,\n\t\t\t\t\tonSelectionResolved: options.onSelectionResolved,\n\t\t\t\t\twithStateAccess: options.withStateAccess,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (resolution.kind === \"route-result\") {\n\t\t\t\tresult = resolution.result;\n\t\t\t\tcurrentRoute = resolution.route;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn resolution.kind === \"closed\" || resolution.kind === \"stale\"\n\t\t\t\t? { kind: \"close\" }\n\t\t\t\t: { kind: \"stay\" };\n\t\t}\n\t\tif (result.kind === \"decision-required\") {\n\t\t\tresolving = true;\n\t\t\tconst resolution = await showSyncResolution(ctx, result.decision, runRoute, signal);\n\t\t\tif (resolution.kind === \"route-result\") {\n\t\t\t\tresult = resolution.result;\n\t\t\t\tcurrentRoute = resolution.route;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (resolution.kind === \"resolved\") {\n\t\t\t\treturn { kind: \"close\", appliedRoute: resolution.direction };\n\t\t\t}\n\t\t\treturn resolution.kind === \"closed\" || resolution.kind === \"stale\"\n\t\t\t\t? { kind: \"close\" }\n\t\t\t\t: { kind: \"stay\" };\n\t\t}\n\t\tif (result.kind === \"closed\") return { kind: \"close\" };\n\t\tif (result.kind === \"completed\") {\n\t\t\tconst appliedRoute = result.outcome === \"applied\" ? currentRoute : undefined;\n\t\t\tif (resolving || (origin === \"pull\" && result.outcome === \"applied\")) {\n\t\t\t\treturn { kind: \"close\", ...(appliedRoute ? { appliedRoute } : {}) };\n\t\t\t}\n\t\t\treturn { kind: \"stay\", ...(appliedRoute ? { appliedRoute } : {}) };\n\t\t}\n\t\treturn { kind: \"stay\" };\n\t}\n\n\tctx.ui.notify(\n\t\t\"Sync resolution stopped after too many state changes. Start /sync again to review fresh state.\",\n\t\t\"warning\",\n\t);\n\treturn { kind: \"stay\" };\n}\n"],
5
- "mappings": "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",
6
- "names": ["result"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/command.ts"],
4
- "sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport type { CommandArgumentCompletion, CommandOptions } from \"./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\"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/backend-factory.ts", "../../src/remote-snapshot.ts"],
4
- "sourcesContent": ["import type { SyncBackend } from \"./sync-backend.js\";\nimport type { AnySyncConfig } from \"./types.js\";\n\nexport type SyncBackendFactory = {\n\tbivarianceHack(config: AnySyncConfig): SyncBackend | Promise<SyncBackend>;\n}[\"bivarianceHack\"];\n\nexport const createSyncBackend: SyncBackendFactory = async (config) => {\n\tswitch (config.backend.type) {\n\t\tcase \"s3\": {\n\t\t\tconst { S3SyncBackend } = await import(\"./s3-backend.js\");\n\t\t\treturn new S3SyncBackend(config.backend);\n\t\t}\n\t\tcase \"webdav\": {\n\t\t\tconst { WebDavSyncBackend } = await import(\"./webdav-backend.js\");\n\t\t\treturn new WebDavSyncBackend(config.backend);\n\t\t}\n\t\tcase \"git\": {\n\t\t\tconst { GitSyncBackend } = await import(\"./git-backend.js\");\n\t\t\treturn new GitSyncBackend(config.backend);\n\t\t}\n\t}\n};\n", "import { syncConfigReviewFingerprint } from \"./config.js\";\nimport type { RemoteHead, SyncBackend } from \"./sync-backend.js\";\nimport { safeTerminalText } from \"./sync-format.js\";\nimport {\n\tinspectRemoteSelection,\n\ttype RemoteSelectionState,\n\tremoteSelectionMismatch,\n\tsameSyncInclude,\n\tsnapshotSelectionInclude,\n} from \"./sync-policy.js\";\nimport type { AnySyncConfig, Snapshot } from \"./types.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"],
5
- "mappings": ";;;;;;;;;;;;;;;;AAOO,IAAM,oBAAwC,OAAO,WAAW;AACtE,UAAQ,OAAO,QAAQ,MAAM;AAAA,IAC5B,KAAK,MAAM;AACV,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,0BAAiB;AACxD,aAAO,IAAI,cAAc,OAAO,OAAO;AAAA,IACxC;AAAA,IACA,KAAK,UAAU;AACd,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,8BAAqB;AAChE,aAAO,IAAI,kBAAkB,OAAO,OAAO;AAAA,IAC5C;AAAA,IACA,KAAK,OAAO;AACX,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,2BAAkB;AAC1D,aAAO,IAAI,eAAe,OAAO,OAAO;AAAA,IACzC;AAAA,EACD;AACD;;;ACVA,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;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/sync-backend.ts"],
4
- "sourcesContent": ["import type { Snapshot, SnapshotSelection } from \"./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/config-file.ts", "../../src/config.ts", "../../src/webdav-config.ts", "../../src/config-errors.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 { createHash, randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport {\n\ttype ExtensionCommandContext,\n\ttype ExtensionContext,\n\tgetAgentDir,\n} from \"@earendil-works/pi-coding-agent\";\nimport {\n\tactiveLocalConfigPath,\n\tconsumeLocalConfigMigrationNotice,\n\tcreateLocalConfigDocument,\n\tlegacyLocalConfigPath,\n\tlocalConfigPath,\n\tquarantineAndRemoveConfigIfMatches,\n\treadActiveLocalConfigDocumentForRepair,\n\treadMigratingLocalConfigDocument,\n\treplaceLocalConfigDocument,\n\tupdateLocalConfigDocument,\n} from \"./config-file.js\";\nimport {\n\tnormalizeGitBranch,\n\tnormalizeGitDirectory,\n\tnormalizeGitRemote,\n\tnormalizeGitRemoteIdentity,\n} from \"./git-config.js\";\nimport { safeName } from \"./paths.js\";\nimport { stateDir } from \"./state-directory.js\";\nimport { normalizeSyncInclude } from \"./sync-policy.js\";\nimport type {\n\tAnySyncConfig,\n\tOnSwitchAction,\n\tPartialConfig,\n\tPiSyncSettingsV3,\n\tSnapshot,\n\tStorageConnectionSettings,\n\tSyncSetupSettings,\n\tSyncState,\n} from \"./types.js\";\nimport {\n\tnormalizeWebDavIdentityUrl,\n\tnormalizeWebDavPath,\n\tnormalizeWebDavUrl,\n\tvalidateWebDavCredentials,\n} from \"./webdav-config.js\";\n\nconst STATE_VERSION = 2;\nexport const DEFAULT_ON_SWITCH: OnSwitchAction = \"ask-before-pull\";\n\nexport { normalizeExtraFiles, normalizeSyncFiles } from \"./sync-policy.js\";\nexport {\n\tactiveLocalConfigPath,\n\tconsumeLocalConfigMigrationNotice,\n\tcreateLocalConfigDocument,\n\tlegacyLocalConfigPath,\n\tlocalConfigPath,\n\tnormalizeSyncInclude,\n\tquarantineAndRemoveConfigIfMatches,\n\treadActiveLocalConfigDocumentForRepair,\n\treplaceLocalConfigDocument,\n\tupdateLocalConfigDocument,\n};\n\nfunction sessionDirFromContext(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst manager = ctx.sessionManager as typeof ctx.sessionManager & {\n\t\tusesDefaultSessionDir?: () => boolean;\n\t};\n\tif (manager.usesDefaultSessionDir?.call(manager)) return undefined;\n\treturn typeof manager.getSessionDir === \"function\"\n\t\t? (manager.getSessionDir.call(manager) as string | undefined)\n\t\t: undefined;\n}\n\nexport async function loadConfig(setupName?: string): Promise<AnySyncConfig> {\n\tconst settings = await requireSettings();\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\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\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 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\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 = 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\nasync function requireSettings() {\n\tconst settings = await readLocalConfigObject();\n\tif (!settings) {\n\t\tthrow new Error(`Missing pi-sync settings. Use /sync setup or create ${localConfigPath()}.`);\n\t}\n\treturn settings;\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\nfunction ownObject<T extends object>(value: Record<string, unknown>, key: string): 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\nfunction 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\nfunction 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\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\nfunction 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\nfunction 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 normalizeEndpointIdentity(endpoint: string) {\n\ttry {\n\t\tconst url = new URL(endpoint.trim());\n\t\turl.hostname = url.hostname.toLowerCase();\n\t\turl.pathname = url.pathname.replace(/\\/+$/gu, \"\");\n\t\treturn url.toString().replace(/\\/$/u, \"\");\n\t} catch {\n\t\treturn endpoint.trim();\n\t}\n}\n\nexport async function configuredSessionDir() {\n\tconst settings = await readJsonIfExists<{ sessionDir?: string }>(\n\t\tpath.join(agentDir(), \"settings.json\"),\n\t);\n\treturn settings?.sessionDir ? expandHome(settings.sessionDir) : undefined;\n}\n\nexport async function sessionDirForApply(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\tsnapshot: Snapshot,\n) {\n\tconst contextSessionDir = sessionDirFromContext(ctx);\n\tconst localSessionDir = await configuredSessionDir();\n\tif (\n\t\tcontextSessionDir &&\n\t\tpath.resolve(contextSessionDir) !== path.resolve(localSessionDir ?? \"\")\n\t) {\n\t\treturn contextSessionDir;\n\t}\n\treturn sessionDirFromSnapshot(snapshot) ?? contextSessionDir;\n}\n\nfunction sessionDirFromSnapshot(snapshot: Snapshot) {\n\tconst settingsFile = snapshot.files.find((file) => file.path === \"settings.json\");\n\tif (!settingsFile) return undefined;\n\ttry {\n\t\tconst settings = JSON.parse(\n\t\t\tdecodeBase64Strict(settingsFile.contentBase64, settingsFile.path).toString(\"utf8\"),\n\t\t) as { sessionDir?: string };\n\t\treturn settings.sessionDir ? expandHome(settings.sessionDir) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction decodeBase64Strict(value: string, filePath: string) {\n\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {\n\t\tthrow new Error(`Invalid base64 content in snapshot file: ${filePath}`);\n\t}\n\treturn Buffer.from(value, \"base64\");\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 backendIdentityCoordinates(config: AnySyncConfig) {\n\tswitch (config.backend.type) {\n\t\tcase \"s3\":\n\t\t\treturn JSON.stringify([\n\t\t\t\t\"s3\",\n\t\t\t\tnormalizeEndpointIdentity(config.backend.profile.endpoint),\n\t\t\t\tconfig.backend.destination.bucket,\n\t\t\t\tconfig.storagePath,\n\t\t\t]);\n\t\tcase \"git\":\n\t\t\treturn JSON.stringify([\n\t\t\t\t\"git\",\n\t\t\t\tnormalizeGitRemoteIdentity(config.backend.profile.remote),\n\t\t\t\tconfig.backend.destination.branch,\n\t\t\t\tconfig.storagePath,\n\t\t\t]);\n\t\tcase \"webdav\":\n\t\t\treturn JSON.stringify([\n\t\t\t\t\"webdav\",\n\t\t\t\tnormalizeWebDavIdentityUrl(config.backend.profile.url),\n\t\t\t\tconfig.backend.profile.username,\n\t\t\t\tconfig.storagePath,\n\t\t\t]);\n\t}\n}\n\nexport function agentDir() {\n\treturn getAgentDir();\n}\n\nfunction expandHome(value: string) {\n\treturn value === \"~\" || value.startsWith(\"~/\") ? path.join(os.homedir(), value.slice(2)) : value;\n}\n\nexport { stateDir } from \"./state-directory.js\";\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\nlet configUpdateQueue: Promise<void> = Promise.resolve();\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\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\nasync function readJsonIfExists<T>(filePath: string): Promise<T | undefined> {\n\ttry {\n\t\treturn JSON.parse(await fs.readFile(filePath, \"utf8\")) as T;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n}\n\nexport async function writeJson(filePath: string, value: unknown) {\n\tawait fs.mkdir(path.dirname(filePath), { recursive: true });\n\tconst temp = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n\tawait fs.writeFile(temp, `${JSON.stringify(value, null, \"\\t\")}\\n`, { mode: 0o600 });\n\tif (process.platform !== \"win32\") await fs.chmod(temp, 0o600);\n\tawait fs.rename(temp, filePath);\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 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 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\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 { isMissingConfigError } from \"./config-errors.js\";\n", "const DEFAULT_PATH = \"pi-sync\";\n\nexport function normalizeWebDavIdentityUrl(value: string) {\n\ttry {\n\t\tconst url = new URL(value.trim());\n\t\turl.username = \"\";\n\t\turl.password = \"\";\n\t\turl.search = \"\";\n\t\turl.hash = \"\";\n\t\turl.pathname = `${url.pathname.replace(/\\/+$/u, \"\")}/`;\n\t\treturn url.toString();\n\t} catch {\n\t\treturn value.trim();\n\t}\n}\n\nexport function normalizeWebDavUrl(value: string | undefined) {\n\tconst normalized = normalizeOptionalString(value);\n\tif (!normalized) return undefined;\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(normalized);\n\t} catch {\n\t\tthrow new Error(\"Invalid pi-sync WebDAV URL.\");\n\t}\n\tif (url.username || url.password || url.search || url.hash) {\n\t\tthrow new Error(\n\t\t\t\"Invalid pi-sync WebDAV URL: credentials, query, and fragment are not allowed.\",\n\t\t);\n\t}\n\tconst loopback =\n\t\turl.hostname === \"127.0.0.1\" ||\n\t\turl.hostname === \"localhost\" ||\n\t\turl.hostname === \"[::1]\" ||\n\t\turl.hostname === \"::1\";\n\tif (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback)) {\n\t\tthrow new Error(\"Invalid pi-sync WebDAV URL: HTTPS is required except for loopback.\");\n\t}\n\turl.pathname = `${url.pathname.replace(/\\/+$/u, \"\")}/`;\n\treturn url.toString();\n}\n\nexport function normalizeWebDavPath(value: string | undefined) {\n\tconst normalized = trimSlashes(normalizeOptionalString(value) ?? DEFAULT_PATH);\n\tif (\n\t\t!normalized ||\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 WebDAV path.\");\n\t}\n\treturn normalized;\n}\n\nexport function validateWebDavNamespace(value: string) {\n\tif (\n\t\tvalue === \".\" ||\n\t\tvalue === \"..\" ||\n\t\tvalue.includes(\"/\") ||\n\t\tvalue.includes(\"\\\\\") ||\n\t\thasControlCharacter(value)\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync WebDAV namespace.\");\n\t}\n}\n\nexport function validateWebDavCredentials(username: string, password?: string) {\n\tif (\n\t\tusername.includes(\":\") ||\n\t\thasControlCharacter(username) ||\n\t\t(password !== undefined && hasControlCharacter(password))\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync WebDAV credentials.\");\n\t}\n}\n\nfunction normalizeOptionalString(value: string | undefined) {\n\tconst normalized = value?.trim();\n\treturn normalized || undefined;\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/gu, \"\");\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", "export function isMissingConfigError(error: unknown) {\n\treturn (\n\t\terror instanceof Error &&\n\t\t(error.message.startsWith(\"Missing pi-sync settings.\") ||\n\t\t\terror.message === \"No sync setups are configured.\")\n\t);\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,mBAAmB;AAC5B,OAAO,cAAc;AAErB,IAAM,mBAAmB;AACzB,IAAM,0BAA0B;AAChC,IAAM,yBAAyB,oBAAI,IAAoB;AACvD,IAAM,wBAAwB,oBAAI,IAAY;AAC9C,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAGA,IAAI,oBAAiC;AACrC,IAAI,8BAAmD,YAAY;AACnE,IAAI,kCAAuD,YAAY;AACvE,IAAI,gCAAqD,YAAY;AACrE,IAAI,6BAAkD,YAAY;AA6E3D,SAAS,kBAAkB;AACjC,SAAO,KAAK,KAAK,YAAY,GAAG,gBAAgB;AACjD;AAEO,SAAS,wBAAwB;AACvC,SAAO,KAAK,KAAK,YAAY,GAAG,uBAAuB;AACxD;AAEA,eAAsB,wBAAwB;AAC7C,QAAM,gBAAgB,gBAAgB;AACtC,QAAM,aAAa,sBAAsB;AACzC,SAAO,gCAAgC,YAAY;AAClD,QAAI,MAAM,WAAW,aAAa,EAAG,QAAO;AAC5C,WAAQ,MAAM,WAAW,UAAU,IAAK,aAAa;AAAA,EACtD,CAAC;AACF;AAEO,SAAS,oCAAoC;AACnD,QAAM,aAAa,gBAAgB;AACnC,QAAM,SAAS,uBAAuB,IAAI,UAAU;AACpD,yBAAuB,OAAO,UAAU;AACxC,SAAO;AACR;AAcA,eAAsB,iCACrB,sBAC2C;AAC3C,SAAO,gCAAgC,YAAY;AAClD,UAAM,aAAa,MAAM,uBAAuB,oBAAoB;AACpE,UAAM,WAAW,MAAM,2BAA2B,UAAU;AAC5D,WAAO,WAAW,EAAE,MAAM,YAAY,GAAG,SAAS,IAAI;AAAA,EACvD,CAAC;AACF;AAEA,eAAe,gCAAmC,MAAoC;AACrF,MAAK,MAAM,WAAW,gBAAgB,CAAC,KAAO,MAAM,WAAW,sBAAsB,CAAC,GAAI;AACzF,WAAO,wBAAwB,IAAI;AAAA,EACpC;AACA,QAAM,gCAAgC;AACtC,MAAI,MAAM,WAAW,uBAAuB,CAAC,EAAG,QAAO,wBAAwB,IAAI;AACnF,SAAO,KAAK;AACb;AAEO,SAAS,0BACf,cACA,QACA,UACA,QACa;AACb,SAAO,wBAAwB,YAAY;AAC1C,YAAQ,eAAe;AACvB,UAAM,aAAa,MAAM,uBAAuB,QAAQ;AACxD,UAAM,WAAW,MAAM,2BAA2B,UAAU;AAC5D,UAAM,WAAW,WAAW,EAAE,MAAM,YAAY,GAAG,SAAS,IAAI;AAChE,UAAM,UAAU,WACZ,gBAAgB,SAAS,MAAM,IAChC,gBAAgB,YAAY;AAC/B,UAAM,OAAO,OAAO,OAAO;AAC3B,aAAS,IAAI;AACb,YAAQ,eAAe;AACvB,QAAI,YAAY,KAAK,UAAU,SAAS,MAAM,MAAM,KAAK,UAAU,IAAI,EAAG,QAAO;AACjF,QAAI,SAAU,OAAM,mCAAmC,UAAU,IAAI;AAAA,QAChE,OAAM,gCAAgC,gBAAgB,GAAG,iBAAiB,IAAI,CAAC;AACpF,WAAO;AAAA,EACR,CAAC;AACF;AAEO,SAAS,0BAA0B,OAAgC;AACzE,SAAO,wBAAwB,YAAY;AAC1C,UAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAI;AACH,YAAM,gCAAgC,gBAAgB,GAAG,KAAK;AAAA,IAC/D,SAAS,OAAO;AACf,UAAK,MAAgC,SAAS,UAAU;AACvD,cAAM,IAAI,MAAM,wEAAwE;AAAA,MACzF;AACA,YAAM;AAAA,IACP;AAAA,EACD,CAAC;AACF;AASA,eAAe,mCACd,UACA,OACC;AACD,QAAM,YAAY,iBAAiB,KAAK;AACxC,QAAM,gBAAgB,gBAAgB;AACtC,MAAI,SAAS,SAAS,eAAe;AACpC,QAAI,CAAE,MAAM,2BAA2B,QAAQ,EAAI,OAAM,qBAAqB;AAC9E,QAAIA;AACJ,QAAI;AACH,MAAAA,aAAY,MAAM,gCAAgC,eAAe,SAAS;AAAA,IAC3E,SAAS,OAAO;AACf,UAAK,MAAgC,SAAS,UAAU;AACvD,cAAM,IAAI,MAAM,0EAA0E;AAAA,MAC3F;AACA,YAAM;AAAA,IACP;AACA,QAAI,CAAE,MAAM,2BAA2B,QAAQ,GAAI;AAClD,YAAM,2CAA2C,eAAeA,YAAW,SAAS;AACpF,YAAM,qBAAqB;AAAA,IAC5B;AACA;AAAA,EACD;AAEA,QAAM,iBAAiB,MAAM,6BAA6B,QAAQ;AAClE,MAAI;AACJ,MAAI;AACH,gBAAY,MAAM,gCAAgC,eAAe,SAAS;AAAA,EAC3E,SAAS,OAAO;AACf,UAAM,yBAAyB,eAAe,cAAc;AAC5D,QAAK,MAAgC,SAAS,UAAU;AACvD,YAAM,IAAI,MAAM,qEAAqE;AAAA,IACtF;AACA,UAAM;AAAA,EACP;AACA,MAAI;AACH,UAAM,8BAA8B;AACpC,QAAI,CAAE,MAAM,6BAA6B,gBAAgB,SAAS,UAAU,SAAS,KAAK,GAAI;AAC7F,YAAM,qBAAqB;AAAA,IAC5B;AACA,QAAI,QAAQ,aAAa,QAAS,OAAM,GAAG,MAAM,gBAAgB,GAAK;AAAA,EACvE,SAAS,OAAO;AACf,UAAM,2CAA2C,eAAe,WAAW,SAAS;AACpF,UAAM,yBAAyB,eAAe,cAAc;AAC5D,UAAM;AAAA,EACP;AACA,QAAM,GAAG,GAAG,cAAc,EAAE,MAAM,MAAM,MAAS;AACjD,QAAM,oBAAoB,aAAa,EAAE,MAAM,MAAM,MAAS;AAC/D;AAEA,eAAe,uBACd,sBACC;AACD,QAAM,gBAAgB,gBAAgB;AACtC,QAAM,aAAa,sBAAsB;AACzC,MAAI,MAAM,WAAW,aAAa,GAAG;AACpC,UAAM,eAAe,MAAM,6BAA6B,UAAU;AAClE,QAAI,iBAAiB,aAAa,CAAC,sBAAsB,IAAI,aAAa,GAAG;AAC5E,4BAAsB,IAAI,aAAa;AACvC;AAAA,QACC;AAAA,QACA,iBAAiB,YACd,GAAG,uBAAuB,yCAAyC,gBAAgB,6BAA6B,uBAAuB,qCACvI,GAAG,uBAAuB,yCAAyC,gBAAgB;AAAA,MACvF;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAEA,QAAM,SAAS,MAAM,2BAA2B,UAAU;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,uBAAqB,OAAO,MAAM;AAElC,MAAI;AACJ,MAAI;AACH,wBAAoB,MAAM,gCAAgC,eAAe,OAAO,KAAK;AAAA,EACtF,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,UAAU;AACvD;AAAA,QACC;AAAA,QACA,GAAG,uBAAuB,yCAAyC,gBAAgB;AAAA,MACpF;AACA,aAAO;AAAA,IACR;AACA;AAAA,MACC;AAAA,MACA,qBAAqB,uBAAuB,OAAO,gBAAgB;AAAA,IACpE;AACA,WAAO;AAAA,EACR;AAEA,MAAI,CAAE,MAAM,2BAA2B,YAAY,MAAM,GAAI;AAC5D,UAAM,UAAU,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACR;AACA;AAAA,MACC;AAAA,MACA,UACG,GAAG,uBAAuB,wCAAwC,gBAAgB,0EAClF,GAAG,uBAAuB,kCAAkC,gBAAgB;AAAA,IAChF;AACA,WAAO,UAAU,aAAa;AAAA,EAC/B;AAEA,wBAAsB,IAAI,aAAa;AACvC;AAAA,IACC;AAAA,IACA,kCAAkC,uBAAuB,OAAO,gBAAgB;AAAA,EACjF;AACA,SAAO;AACR;AAEA,eAAe,6BAA6B,UAAkB;AAC7D,MAAI;AACJ,MAAI;AACH,eAAW,MAAM,GAAG,MAAM,QAAQ;AAAA,EACnC,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,WAAO;AAAA,EACR;AACA,MAAI,SAAS,eAAe,KAAK,CAAC,SAAS,OAAO,EAAG,QAAO;AAE5D,MAAI;AACJ,MAAI;AACH,aAAS,MAAM,GAAG,KAAK,UAAU,GAAG;AACpC,UAAM,aAAa,MAAM,OAAO,KAAK;AACrC,QAAI,WAAW,QAAQ,SAAS,OAAO,WAAW,QAAQ,SAAS,KAAK;AACvE,aAAO;AAAA,IACR;AACA,QAAI,QAAQ,aAAa,YAAY,WAAW,OAAO,SAAW,KAAO;AACxE,YAAM,OAAO,MAAM,GAAK;AAAA,IACzB;AACA,WAAO;AAAA,EACR,QAAQ;AACP,WAAO;AAAA,EACR,UAAE;AACD,UAAM,QAAQ,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,EAC5C;AACD;AAEA,eAAe,2BAA2B,UAAuD;AAChG,MAAI;AACJ,MAAI;AACH,eAAW,MAAM,GAAG,MAAM,QAAQ;AAAA,EACnC,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACP;AACA,MAAI,SAAS,eAAe,GAAG;AAC9B,UAAM,IAAI,MAAM,8CAA8C,QAAQ,EAAE;AAAA,EACzE;AACA,MAAI,CAAC,SAAS,OAAO,EAAG,OAAM,IAAI,MAAM,yCAAyC,QAAQ,EAAE;AAE3F,QAAM,SAAS,MAAM,GAAG,KAAK,UAAU,GAAG;AAC1C,MAAI;AACH,UAAM,aAAa,MAAM,OAAO,KAAK;AACrC,QAAI,WAAW,QAAQ,SAAS,OAAO,WAAW,QAAQ,SAAS,KAAK;AACvE,YAAM,IAAI,MAAM,yCAAyC,QAAQ,EAAE;AAAA,IACpE;AACA,QAAI,QAAQ,aAAa,YAAY,WAAW,OAAO,SAAW,KAAO;AACxE,YAAM,OAAO,MAAM,GAAK;AAAA,IACzB;AACA,UAAM,QAAQ,MAAM,OAAO,SAAS;AACpC,WAAO;AAAA,MACN;AAAA,MACA,UAAU,EAAE,KAAK,WAAW,KAAK,KAAK,WAAW,IAAI;AAAA,MACrD,QAAQ,kBAAkB,OAAO,QAAQ;AAAA,IAC1C;AAAA,EACD,UAAE;AACD,UAAM,OAAO,MAAM;AAAA,EACpB;AACD;AAEA,SAAS,iBAAiB,OAAgC;AACzD,SAAO,OAAO,KAAK,GAAG,KAAK,UAAU,OAAO,MAAM,GAAI,CAAC;AAAA,GAAM,MAAM;AACpE;AAEA,SAAS,kBAAkB,OAAe,UAAkB;AAC3D,MAAI;AACJ,MAAI;AACH,aAAS,KAAK,MAAM,MAAM,SAAS,MAAM,CAAC;AAAA,EAC3C,QAAQ;AACP,UAAM,IAAI,YAAY,mCAAmC,QAAQ,EAAE;AAAA,EACpE;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACnE,UAAM,IAAI,MAAM,8CAA8C,QAAQ,EAAE;AAAA,EACzE;AACA,SAAO;AACR;AAEA,eAAe,gCAAgC,UAAkB,OAAe;AAC/E,QAAM,GAAG,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,QAAM,gBAAgB,KAAK;AAAA,IAC1B,KAAK,QAAQ,QAAQ;AAAA,IACrB,IAAI,KAAK,SAAS,QAAQ,CAAC,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AAAA,EAC3D;AACA,MAAI;AACJ,MAAI;AACH,aAAS,MAAM,GAAG,KAAK,eAAe,MAAM,GAAK;AACjD,UAAM,OAAO,UAAU,KAAK;AAC5B,QAAI,QAAQ,aAAa,QAAS,OAAM,OAAO,MAAM,GAAK;AAC1D,UAAM,OAAO,KAAK;AAClB,UAAM,OAAO,MAAM;AACnB,aAAS;AACT,UAAM,kBAAkB,eAAe,QAAQ;AAC/C,UAAM,YAAY,MAAM,GAAG,MAAM,QAAQ;AACzC,QAAI;AACJ,QAAI;AACJ,QAAI;AACH,UAAI,UAAU,eAAe,KAAK,CAAC,UAAU,OAAO,GAAG;AACtD,cAAM,IAAI,MAAM,sDAAsD,QAAQ,EAAE;AAAA,MACjF;AACA,wBAAkB,MAAM,GAAG,KAAK,UAAU,IAAI;AAC9C,YAAM,YAAY,MAAM,gBAAgB,KAAK;AAC7C,UAAI,UAAU,QAAQ,UAAU,OAAO,UAAU,QAAQ,UAAU,KAAK;AACvE,cAAM,IAAI,MAAM,qDAAqD,QAAQ,EAAE;AAAA,MAChF;AACA,UAAI,QAAQ,aAAa,QAAS,OAAM,gBAAgB,MAAM,GAAK;AACnE,YAAM,gBAAgB,KAAK;AAC3B,YAAM,oBAAoB,QAAQ;AAAA,IACnC,SAAS,OAAO;AACf,yBAAmB;AAAA,IACpB,UAAE;AACD,YAAM,iBAAiB,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IACrD;AACA,QAAI,kBAAkB;AACrB,YAAM;AAAA,QACL;AAAA,QACA,EAAE,KAAK,UAAU,KAAK,KAAK,UAAU,IAAI;AAAA,QACzC;AAAA,MACD;AACA,YAAM;AAAA,IACP;AACA,WAAO,EAAE,KAAK,UAAU,KAAK,KAAK,UAAU,IAAI;AAAA,EACjD,UAAE;AACD,UAAM,QAAQ,MAAM,EAAE,MAAM,MAAM,MAAS;AAC3C,UAAM,GAAG,GAAG,eAAe,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAClE;AACD;AAEA,eAAe,2BAA2B,UAA+B;AACxE,SAAO,6BAA6B,SAAS,MAAM,SAAS,UAAU,SAAS,KAAK;AACrF;AAEA,eAAe,6BAA6B,UAA+B;AAC1E,QAAM,iBAAiB,KAAK;AAAA,IAC3B,KAAK,QAAQ,SAAS,IAAI;AAAA,IAC1B,IAAI,KAAK,SAAS,SAAS,IAAI,CAAC,IAAI,WAAW,CAAC;AAAA,EACjD;AACA,MAAI;AACH,UAAM,GAAG,OAAO,SAAS,MAAM,cAAc;AAC7C,UAAM,oBAAoB,SAAS,IAAI;AAAA,EACxC,SAAS,OAAO;AACf,UAAM,yBAAyB,SAAS,MAAM,cAAc;AAC5D,UAAM;AAAA,EACP;AACA,MAAI,CAAE,MAAM,6BAA6B,gBAAgB,SAAS,UAAU,SAAS,KAAK,GAAI;AAC7F,UAAM,yBAAyB,SAAS,MAAM,cAAc;AAC5D,UAAM,qBAAqB;AAAA,EAC5B;AACA,MAAI,MAAM,WAAW,SAAS,IAAI,GAAG;AACpC,UAAM,yBAAyB,SAAS,MAAM,cAAc;AAC5D,UAAM,IAAI,MAAM,qEAAqE;AAAA,EACtF;AACA,SAAO;AACR;AAEA,SAAS,uBAAuB;AAC/B,SAAO,IAAI,MAAM,uEAAuE;AACzF;AAEA,eAAe,2BAA2B,UAAkB,UAA0B;AACrF,SAAO,6BAA6B,UAAU,SAAS,UAAU,SAAS,KAAK;AAChF;AAYA,eAAe,2CACd,UACA,UACA,eACC;AACD,QAAM,iBAAiB,KAAK;AAAA,IAC3B,KAAK,QAAQ,QAAQ;AAAA,IACrB,IAAI,KAAK,SAAS,QAAQ,CAAC,IAAI,WAAW,CAAC;AAAA,EAC5C;AACA,MAAI;AACH,UAAM,GAAG,OAAO,UAAU,cAAc;AAAA,EACzC,QAAQ;AACP,WAAO;AAAA,EACR;AACA,QAAM,2BAA2B;AACjC,MAAI;AACH,UAAM,oBAAoB,QAAQ;AAAA,EACnC,QAAQ;AACP,UAAM,yBAAyB,UAAU,cAAc;AACvD,WAAO;AAAA,EACR;AAEA,QAAM,UAAU,MAAM,6BAA6B,gBAAgB,UAAU,aAAa;AAC1F,MAAI,CAAC,SAAS;AACb,UAAM,yBAAyB,UAAU,cAAc;AACvD,WAAO;AAAA,EACR;AACA,MAAI,MAAM,WAAW,QAAQ,GAAG;AAC/B,UAAM,GAAG,GAAG,gBAAgB,EAAE,OAAO,KAAK,CAAC;AAC3C,UAAM,oBAAoB,QAAQ;AAClC,WAAO;AAAA,EACR;AACA,QAAM,GAAG,GAAG,cAAc;AAC1B,QAAM,oBAAoB,QAAQ;AAClC,SAAO;AACR;AAEA,eAAe,6BACd,UACA,UACA,eACC;AACD,MAAI;AACH,UAAM,UAAU,MAAM,GAAG,MAAM,QAAQ;AACvC,QAAI,QAAQ,eAAe,EAAG,QAAO;AACrC,QAAI,QAAQ,QAAQ,SAAS,OAAO,QAAQ,QAAQ,SAAS,IAAK,QAAO;AACzE,YAAQ,MAAM,GAAG,SAAS,QAAQ,GAAG,OAAO,aAAa;AAAA,EAC1D,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,eAAe,yBAAyB,UAAkB,gBAAwB;AACjF,MAAI;AACH,UAAM,6BAA6B,gBAAgB,QAAQ;AAC3D,QAAI,QAAQ,aAAa,QAAS,OAAM,GAAG,MAAM,UAAU,GAAK;AAChE,UAAM,oBAAoB,QAAQ;AAClC;AAAA,EACD,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU;AAAA,EACzD;AACA,MAAI;AACH,QAAI,QAAQ,aAAa,QAAS,OAAM,GAAG,MAAM,gBAAgB,GAAK;AACtE,UAAM,oBAAoB,QAAQ;AAAA,EACnC,QAAQ;AAAA,EAER;AACD;AAEA,SAAS,yBAAyB;AACjC,SAAO,GAAG,gBAAgB,CAAC;AAC5B;AAEA,eAAsB,wBAA2B,KAAmC;AACnF,QAAM,aAAa,gBAAgB;AACnC,QAAM,GAAG,MAAM,KAAK,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5D,MAAI;AACJ,QAAM,UAAU,MAAM,SAAS,KAAK,YAAY;AAAA,IAC/C,IAAI;AAAA,IACJ,cAAc,uBAAuB;AAAA,IACrC,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS,EAAE,SAAS,KAAK,QAAQ,KAAK,YAAY,IAAI,YAAY,IAAI;AAAA,IACtE,eAAe,CAAC,UAAU;AACzB,yBAAmB;AAAA,IACpB;AAAA,EACD,CAAC;AACD,MAAI;AACH,UAAM,SAAS,MAAM,IAAI;AACzB,QAAI,iBAAkB,OAAM;AAC5B,WAAO;AAAA,EACR,UAAE;AACD,UAAM,QAAQ;AAAA,EACf;AACD;AAEA,eAAe,oBAAoB,UAAkB;AACpD,MAAI,QAAQ,aAAa,QAAS;AAClC,MAAI;AACJ,MAAI;AACH,aAAS,MAAM,GAAG,KAAK,KAAK,QAAQ,QAAQ,GAAG,GAAG;AAClD,UAAM,OAAO,KAAK;AAAA,EACnB,UAAE;AACD,UAAM,QAAQ,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,EAC5C;AACD;AAEA,eAAe,8BAA8B,QAAgB,aAAqB;AACjF,QAAM,4BAA4B;AAClC,QAAM,6BAA6B,QAAQ,WAAW;AACvD;AAEA,eAAe,6BAA6B,QAAgB,aAAqB;AAChF,MAAI,MAAM,WAAW,WAAW,GAAG;AAClC,UAAM,OAAO,OAAO,IAAI,MAAM,2BAA2B,WAAW,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,EAC5F;AACA,QAAM,GAAG,OAAO,QAAQ,WAAW;AACpC;AAEA,eAAe,WAAW,UAAkB;AAC3C,MAAI;AACH,UAAM,GAAG,MAAM,QAAQ;AACvB,WAAO;AAAA,EACR,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACP;AACD;AAEA,SAAS,4BAA4B,YAAoB,QAAgB;AACxE,MAAI,CAAC,uBAAuB,IAAI,UAAU,EAAG,wBAAuB,IAAI,YAAY,MAAM;AAC3F;;;AC9nBA,SAAS,YAAY,cAAAC,mBAAkB;AACvC,OAAOC,SAAQ;AACf,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB;AAAA,EAGC,eAAAC;AAAA,OACM;;;ACRP,IAAM,eAAe;AAEd,SAAS,2BAA2B,OAAe;AACzD,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC;AAChC,QAAI,WAAW;AACf,QAAI,WAAW;AACf,QAAI,SAAS;AACb,QAAI,OAAO;AACX,QAAI,WAAW,GAAG,IAAI,SAAS,QAAQ,SAAS,EAAE,CAAC;AACnD,WAAO,IAAI,SAAS;AAAA,EACrB,QAAQ;AACP,WAAO,MAAM,KAAK;AAAA,EACnB;AACD;AAEO,SAAS,mBAAmB,OAA2B;AAC7D,QAAM,aAAa,wBAAwB,KAAK;AAChD,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI;AACJ,MAAI;AACH,UAAM,IAAI,IAAI,UAAU;AAAA,EACzB,QAAQ;AACP,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC9C;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,UAAU,IAAI,MAAM;AAC3D,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,QAAM,WACL,IAAI,aAAa,eACjB,IAAI,aAAa,eACjB,IAAI,aAAa,WACjB,IAAI,aAAa;AAClB,MAAI,IAAI,aAAa,YAAY,EAAE,IAAI,aAAa,WAAW,WAAW;AACzE,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACrF;AACA,MAAI,WAAW,GAAG,IAAI,SAAS,QAAQ,SAAS,EAAE,CAAC;AACnD,SAAO,IAAI,SAAS;AACrB;AAEO,SAAS,oBAAoB,OAA2B;AAC9D,QAAM,aAAa,YAAY,wBAAwB,KAAK,KAAK,YAAY;AAC7E,MACC,CAAC,cACD,WAAW,SAAS,IAAI,KACxB,oBAAoB,UAAU,KAC9B,WAAW,MAAM,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,YAAY,OAAO,YAAY,IAAI,GACtF;AACD,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAC/C;AACA,SAAO;AACR;AAEO,SAAS,wBAAwB,OAAe;AACtD,MACC,UAAU,OACV,UAAU,QACV,MAAM,SAAS,GAAG,KAClB,MAAM,SAAS,IAAI,KACnB,oBAAoB,KAAK,GACxB;AACD,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACpD;AACD;AAEO,SAAS,0BAA0B,UAAkB,UAAmB;AAC9E,MACC,SAAS,SAAS,GAAG,KACrB,oBAAoB,QAAQ,KAC3B,aAAa,UAAa,oBAAoB,QAAQ,GACtD;AACD,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACtD;AACD;AAEA,SAAS,wBAAwB,OAA2B;AAC3D,QAAM,aAAa,OAAO,KAAK;AAC/B,SAAO,cAAc;AACtB;AAEA,SAAS,YAAY,OAAe;AACnC,SAAO,MAAM,QAAQ,eAAe,EAAE;AACvC;AAEA,SAAS,oBAAoB,OAAe;AAC3C,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,cAAc;AACrC,UAAM,OAAO,UAAU,YAAY,CAAC,KAAK;AACzC,WAAO,OAAO,MAAS,QAAQ,OAAQ,QAAQ;AAAA,EAChD,CAAC;AACF;;;AC3FO,SAAS,qBAAqB,OAAgB;AACpD,SACC,iBAAiB,UAChB,MAAM,QAAQ,WAAW,2BAA2B,KACpD,MAAM,YAAY;AAErB;;;AFyCA,IAAM,gBAAgB;AACf,IAAM,oBAAoC;AAgBjD,SAAS,sBAAsB,KAAiD;AAC/E,QAAM,UAAU,IAAI;AAGpB,MAAI,QAAQ,uBAAuB,KAAK,OAAO,EAAG,QAAO;AACzD,SAAO,OAAO,QAAQ,kBAAkB,aACpC,QAAQ,cAAc,KAAK,OAAO,IACnC;AACJ;AAEA,eAAsB,WAAW,WAA4C;AAC5E,QAAM,WAAW,MAAM,gBAAgB;AACvC,QAAM,eAAe,aAAa,SAAS;AAC3C,MAAI,CAAC,aAAc,OAAM,IAAI,MAAM,gCAAgC;AACnE,qBAAmB,cAAc,YAAY;AAC7C,QAAM,QAAQ,UAA6B,SAAS,YAAY,YAAY;AAC5E,MAAI,CAAC;AACJ,UAAM,IAAI,MAAM,8CAAyC,YAAY,uBAAkB;AACxF,QAAM,iBAAiB,MAAM,QAAQ;AACrC,QAAM,aAAa;AAAA,IAClB,SAAS;AAAA,IACT;AAAA,EACD;AACA,MAAI,CAAC,YAAY;AAChB,UAAM,IAAI;AAAA,MACT,8CAAyC,YAAY,sDAA4C,cAAc;AAAA,IAChH;AAAA,EACD;AACA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,SAAS,kBAAkB;AAAA,EAC5B;AACD;AAQA,eAAsB,kBAAkB,WAA4C;AACnF,QAAM,SAAS,MAAM,WAAW,SAAS;AACzC,SAAO;AAAA,IACN,WAAW,OAAO;AAAA,IAClB,GAAG,wBAAwB,MAAM;AAAA,IACjC,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,IAC3B,WAAW,OAAO;AAAA,IAClB,UAAU,OAAO;AAAA,EAClB;AACD;AAEO,SAAS,uBACf,WACA,OACA,gBACA,YACyB;AACzB,SAAO;AAAA,IACN,kBAAkB,WAAW,OAAO,gBAAgB,YAAY,mBAAmB,KAAK;AAAA,EACzF;AACD;AAEO,SAAS,wBACf,WACA,OACA,gBACA,YACC;AACD,SAAO;AAAA,IACN,kBAAkB,WAAW,OAAO,gBAAgB,YAAY,mBAAmB,KAAK;AAAA,EACzF;AACD;AAEO,SAAS,yBAAyB,QAAuB;AAC/D,SAAO,KAAK,UAAU;AAAA,IACrB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,2BAA2B,MAAM;AAAA,IACjC,OAAO;AAAA,IACP,OAAO;AAAA,EACR,CAAC;AACF;AAEO,SAAS,4BAA4B,QAAuB;AAClE,SAAO,WAAW,QAAQ,EAAE,OAAO,yBAAyB,MAAM,CAAC,EAAE,OAAO,KAAK;AAClF;AAEA,SAAS,wBAAwB,QAA+C;AAC/E,SAAO;AAAA,IACN,gBAAgB,OAAO;AAAA,IACvB,aAAa,OAAO,QAAQ;AAAA,IAC5B,aAAa,OAAO;AAAA,IACpB,GAAI,OAAO,QAAQ,SAAS,OACzB,EAAE,QAAQ,OAAO,QAAQ,YAAY,OAAO,IAC5C,OAAO,QAAQ,SAAS,QACvB,EAAE,QAAQ,OAAO,QAAQ,YAAY,OAAO,IAC5C,CAAC;AAAA,EACN;AACD;AAEA,eAAsB,2BAA2B;AAChD,QAAM,WAAW,MAAM,sBAAsB;AAC7C,SAAO,WACJ,OAAO,KAAK,SAAS,UAAU,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC,IAChF,CAAC;AACL;AAEA,eAAsB,eAAwC;AAC7D,UAAQ,MAAM,gBAAgB,GAAG;AAClC;AAEO,SAAS,kBAAkB,OAAgC;AACjE,MAAI,UAAU,qBAAqB,UAAU,uBAAuB,UAAU,eAAe;AAC5F,WAAO;AAAA,EACR;AACA,QAAM,IAAI;AAAA,IACT;AAAA,EACD;AACD;AAEA,SAAS,kBACR,WACA,OACA,gBACA,YACA,UACA,gBACgB;AAChB,QAAM,cAAc,qBAAqB,MAAM,QAAQ,IAAI;AAC3D,QAAM,YAAY,YAAY,MAAM,YAAY,YAAY,GAAG,IAAI,CAAC;AACpE,QAAM,UAAU,qBAAqB,MAAM,KAAK,OAAO;AACvD,QAAM,SAAS;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA,WAAW,MAAM,KAAK;AAAA,IACtB;AAAA,IACA;AAAA,EACD;AACA,MAAI,WAAW,SAAS,OAAO;AAC9B,WAAO;AAAA,MACN,GAAG;AAAA,MACH,SAAS;AAAA,QACR,MAAM;AAAA,QACN,SAAS,EAAE,MAAM,OAAO,QAAQ,mBAAmB,WAAW,MAAM,EAAY;AAAA,QAChF,aAAa;AAAA,UACZ,QAAQ,mBAAmB,MAAM,QAAQ,MAAM;AAAA,UAC/C,WAAW,sBAAsB,WAAW;AAAA,UAC5C;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,MAAI,WAAW,SAAS,UAAU;AACjC,WAAO;AAAA,MACN,GAAG;AAAA,MACH,SAAS;AAAA,QACR,MAAM;AAAA,QACN,SAAS;AAAA,UACR,MAAM;AAAA,UACN,KAAK,mBAAmB,WAAW,GAAG;AAAA,UACtC,UAAU,WAAW,YAAY;AAAA,UACjC,UAAU,WAAW,YAAY;AAAA,QAClC;AAAA,QACA,aAAa,EAAE,MAAM,oBAAoB,WAAW,GAAG,UAAU;AAAA,MAClE;AAAA,IACD;AAAA,EACD;AACA,SAAO;AAAA,IACN,GAAG;AAAA,IACH,SAAS;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACR,MAAM,uBAAuB,WAAW,QAAQ,IAAI,OAAO;AAAA,QAC3D,UAAU,oBAAoB,WAAW,QAAQ;AAAA,QACjD,QAAQ,eAAe,WAAW,QAAQ,WAAW;AAAA,QACrD,aAAa,WAAW,YAAY;AAAA,QACpC,iBAAiB,WAAW,YAAY;AAAA,QACxC,cAAc,eAAe,WAAW,YAAY,cAAc,kBAAkB;AAAA,MACrF;AAAA,MACA,aAAa;AAAA,QACZ,QAAQ,kBAAkB,MAAM,QAAQ,MAAM;AAAA,QAC9C,QAAQ;AAAA,QACR;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,eAAe,kBAAkB;AAChC,QAAM,WAAW,MAAM,sBAAsB;AAC7C,MAAI,CAAC,UAAU;AACd,UAAM,IAAI,MAAM,uDAAuD,gBAAgB,CAAC,GAAG;AAAA,EAC5F;AACA,SAAO;AACR;AAEO,SAAS,yBAAyB,OAAkD;AAC1F,MAAI,MAAM,YAAY,GAAG;AACxB,UAAM,IAAI;AAAA,MACT,yHAAyHC,MAAK,SAAS,gBAAgB,CAAC,CAAC;AAAA,IAC1J;AAAA,EACD;AACA;AAAA,IACC;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,EACD;AACA,oBAAkB,MAAM,QAAQ;AAChC,MAAI,MAAM,mBAAmB,UAAa,OAAO,MAAM,mBAAmB,WAAW;AACpF,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC5E;AACA,QAAM,qBAAqB;AAAA,IAC1B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACD;AACA,QAAM,aAAa,sBAAsB,MAAM,YAAY,cAAc,YAAY;AACrF,aAAW,QAAQ,OAAO,KAAK,kBAAkB,GAAG;AACnD;AAAA,MACC;AAAA,MACA,iBAAiB,oBAAoB,MAAM,oBAAoB;AAAA,IAChE;AAAA,EACD;AACA,aAAW,QAAQ,OAAO,KAAK,UAAU,GAAG;AAC3C;AAAA,MACC;AAAA,MACA,iBAAiB,YAAY,MAAM,YAAY;AAAA,MAC/C;AAAA,IACD;AAAA,EACD;AACA,QAAM,QAAQ,OAAO,KAAK,UAAU;AACpC,QAAM,kBAAkB,2BAA2B,MAAM,iBAAiB,iBAAiB;AAC3F,MAAI,MAAM,WAAW,GAAG;AACvB,QAAI,oBAAoB,QAAW;AAClC,YAAM,IAAI,MAAM,yEAAyE;AAAA,IAC1F;AAAA,EACD,WAAW,CAAC,mBAAmB,CAAC,OAAO,OAAO,YAAY,eAAe,GAAG;AAC3E,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,iCAA+B,YAAY,kBAAkB;AAC7D,SAAO;AACR;AAEA,SAAS,0BAA0B,MAAc,OAAgC;AAChF;AAAA,IACC;AAAA,IACA,CAAC,QAAQ,eAAe,mBAAmB,gBAAgB,YAAY,UAAU;AAAA,IACjF,4BAAuB,IAAI;AAAA,EAC5B;AACA,QAAM,OAAO,eAAe,MAAM,MAAM,4BAAuB,IAAI,aAAQ;AAC3E,MAAI,SAAS,QAAQ,SAAS,SAAS,SAAS,UAAU;AACzD,UAAM,IAAI,MAAM,sDAAiD,IAAI,8BAAyB;AAAA,EAC/F;AACA,QAAM,QAAQ,CAAC,YAAY,UAAU,UAAU,OAAO,aAAa;AACnE,QAAM,UACL,SAAS,OACN,oBAAI,IAAI,CAAC,YAAY,UAAU,aAAa,CAAC,IAC7C,SAAS,QACR,oBAAI,IAAI,CAAC,QAAQ,CAAC,IAClB,oBAAI,IAAI,CAAC,OAAO,aAAa,CAAC;AACnC,MAAI,MAAM,KAAK,CAAC,UAAU,OAAO,OAAO,OAAO,KAAK,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG;AAC9E,UAAM,IAAI;AAAA,MACT,6BAA6B,KAAK,YAAY,CAAC,6BAAwB,IAAI;AAAA,IAC5E;AAAA,EACD;AACA,MAAI,SAAS,OAAO;AACnB,QAAI,CAAC,mBAAmB,eAAe,MAAM,QAAQ,wBAAmB,IAAI,QAAG,CAAC,GAAG;AAClF,YAAM,IAAI,MAAM,kDAA6C,IAAI,qBAAgB;AAAA,IAClF;AACA;AAAA,EACD;AACA,QAAM,cAAc;AAAA,IACnB,MAAM;AAAA,IACN,4CAAuC,IAAI;AAAA,EAC5C;AACA,MAAI,SAAS,UAAU;AACtB,uBAAmB,eAAe,MAAM,KAAK,wBAAmB,IAAI,QAAG,CAAC;AACxE,UAAM,WAAW,eAAe,YAAY,UAAU,6BAAwB,IAAI,QAAG;AACrF,UAAM,WAAW,eAAe,YAAY,UAAU,6BAAwB,IAAI,QAAG;AACrF,QACC,CAAC,eAAe,mBAAmB,cAAc,EAAE;AAAA,MAAK,CAAC,UACxD,OAAO,OAAO,aAAa,KAAK;AAAA,IACjC,GACC;AACD,YAAM,IAAI,MAAM,0DAAqD,IAAI,oBAAe;AAAA,IACzF;AACA,8BAA0B,UAAU,QAAQ;AAC5C;AAAA,EACD;AACA,sBAAoB,eAAe,MAAM,UAAU,yBAAoB,IAAI,QAAG,CAAC;AAC/E,iBAAe,MAAM,QAAQ,uBAAkB,IAAI,QAAG;AACtD,iBAAe,YAAY,aAAa,8BAAyB,IAAI,QAAG;AACxE,iBAAe,YAAY,iBAAiB,kCAA6B,IAAI,QAAG;AAChF,iBAAe,YAAY,cAAc,8BAAyB,IAAI,QAAG;AACzE,MAAI,CAAC,YAAY,UAAU,EAAE,KAAK,CAAC,UAAU,OAAO,OAAO,aAAa,KAAK,CAAC,GAAG;AAChF,UAAM,IAAI,MAAM,sDAAiD,IAAI,oBAAe;AAAA,EACrF;AACD;AAEA,SAAS,kBACR,MACA,OACA,aACC;AACD;AAAA,IACC;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,IACA,oBAAe,IAAI;AAAA,EACpB;AACA,QAAM,UAAU,cAAc,MAAM,SAAS,gCAA2B,IAAI,QAAG;AAC/E,QAAM,OAAO,cAAc,MAAM,MAAM,oCAA+B,IAAI,QAAG;AAC7E;AAAA,IACC;AAAA,IACA,CAAC,WAAW,UAAU,aAAa,WAAW;AAAA,IAC9C,gCAA2B,IAAI;AAAA,EAChC;AACA;AAAA,IACC;AAAA,IACA,CAAC,YAAY,aAAa,gBAAgB,YAAY;AAAA,IACtD,oCAA+B,IAAI;AAAA,EACpC;AACA,QAAM,iBAAiB;AAAA,IACtB,QAAQ;AAAA,IACR,qDAAgD,IAAI;AAAA,EACrD;AACA,qBAAmB,gBAAgB,8BAA8B;AACjE,QAAM,aAAa,UAAmC,aAAa,cAAc;AACjF,MAAI,CAAC,YAAY;AAChB,UAAM,IAAI;AAAA,MACT,8CAAyC,IAAI,sDAA4C,cAAc;AAAA,IACxG;AAAA,EACD;AACA,QAAM,OAAO,WAAW;AACxB,uBAAqB,eAAe,QAAQ,MAAM,qCAAgC,IAAI,QAAG,CAAC;AAC1F,MAAI,SAAS,MAAM;AAClB,sBAAkB,eAAe,QAAQ,QAAQ,kCAA6B,IAAI,QAAG,CAAC;AACtF,QAAI,OAAO,OAAO,SAAS,QAAQ,EAAG,iBAAgB,MAAM,IAAI;AAAA,EACjE,WAAW,SAAS,OAAO;AAC1B,uBAAmB,eAAe,QAAQ,QAAQ,mCAA8B,IAAI,QAAG,CAAC;AACxF,QAAI,OAAO,OAAO,SAAS,QAAQ,EAAG,iBAAgB,OAAO,IAAI;AAAA,EAClE,WAAW,SAAS,UAAU;AAC7B,QAAI,OAAO,OAAO,SAAS,QAAQ,KAAK,OAAO,OAAO,SAAS,QAAQ,GAAG;AACzE,sBAAgB,UAAU,IAAI;AAAA,IAC/B;AAAA,EACD;AACA,MAAI,CAAC,OAAO,OAAO,MAAM,SAAS,GAAG;AACpC,UAAM,IAAI,MAAM,8CAAyC,IAAI,iCAA4B;AAAA,EAC1F;AACA,uBAAqB,KAAK,OAAO;AACjC,MAAI,OAAO,KAAK,cAAc,WAAW;AACxC,UAAM,IAAI;AAAA,MACT,8CAAyC,IAAI;AAAA,IAC9C;AAAA,EACD;AACD;AAEA,SAAS,gBAAgB,MAAc,MAAqB;AAC3D,QAAM,IAAI,MAAM,6BAA6B,IAAI,qBAAgB,IAAI,8BAAyB;AAC/F;AAEO,SAAS,+BACf,QACA,aACC;AACD,QAAM,aAAa,oBAAI,IAAoB;AAC3C,aAAW,QAAQ,OAAO,KAAK,MAAM,GAAG;AACvC,UAAM,QAAQ,iBAAiB,QAAQ,MAAM,YAAY;AACzD,UAAM,aAAa;AAAA,MAClB;AAAA,MACA,MAAM,QAAQ;AAAA,MACd;AAAA,IACD;AACA,UAAM,WAAW,iCAAiC,OAAO,UAAU;AACnE,UAAM,WAAW,WAAW,IAAI,QAAQ;AACxC,QAAI,UAAU;AACb,YAAM,IAAI;AAAA,QACT,+CAA0C,QAAQ,oBAAU,IAAI;AAAA,MACjE;AAAA,IACD;AACA,eAAW,IAAI,UAAU,IAAI;AAAA,EAC9B;AACD;AAEO,SAAS,iCACf,OACA,YACC;AACD,QAAM,cAAc,qBAAqB,MAAM,QAAQ,IAAI;AAC3D,MAAI,WAAW,SAAS,OAAO;AAC9B,WAAO,KAAK,UAAU;AAAA,MACrB;AAAA,MACA,2BAA2B,WAAW,MAAM;AAAA,MAC5C,mBAAmB,MAAM,QAAQ,MAAM;AAAA,MACvC,sBAAsB,WAAW;AAAA,IAClC,CAAC;AAAA,EACF;AACA,MAAI,WAAW,SAAS,UAAU;AACjC,WAAO,KAAK,UAAU;AAAA,MACrB;AAAA,MACA,2BAA2B,WAAW,GAAG;AAAA,MACzC,WAAW,YAAY,SAAS,KAAK;AAAA,MACrC,oBAAoB,WAAW;AAAA,IAChC,CAAC;AAAA,EACF;AACA,SAAO,KAAK,UAAU;AAAA,IACrB;AAAA,IACA,0BAA0B,WAAW,QAAQ;AAAA,IAC7C,kBAAkB,MAAM,QAAQ,MAAM;AAAA,IACtC;AAAA,EACD,CAAC;AACF;AAEA,SAAS,mBACR,OACA,QACA,SACC;AACD,QAAM,QAAQ,OAAO,KAAK,CAAC,cAAc,OAAO,OAAO,OAAO,SAAS,CAAC;AACxE,MAAI,OAAO;AACV,UAAM,IAAI;AAAA,MACT,6BAA6B,OAAO,iDAA4C,KAAK;AAAA,IACtF;AAAA,EACD;AACD;AAEA,SAAS,sBAAsB,OAAgB,OAAe,WAAmB;AAChF,QAAM,SAAS,cAAc,OAAO,KAAK;AACzC,aAAW,QAAQ,OAAO,KAAK,MAAM,EAAG,oBAAmB,MAAM,SAAS;AAC1E,SAAO;AACR;AAEA,SAAS,iBAAiB,OAAgC,KAAa,OAAe;AACrF,QAAM,OAAO,UAAU,OAAO,GAAG;AACjC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,KAAK,UAAK,GAAG,2BAAsB;AAC3F,SAAO;AACR;AAEA,SAAS,UAA4B,OAAgC,KAA4B;AAChG,MAAI,CAAC,OAAO,OAAO,OAAO,GAAG,EAAG,QAAO;AACvC,QAAM,OAAO,MAAM,GAAG;AACtB,SAAO,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,IAAK,OAAa;AACjF;AAEA,SAAS,cAAc,OAAgB,OAAwC;AAC9E,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAChE,UAAM,IAAI,MAAM,6BAA6B,KAAK,qBAAqB;AAAA,EACxE;AACA,SAAO;AACR;AAEO,SAAS,mBAAmB,OAAe,OAAe;AAChE,MACC,CAAC,MAAM,KAAK,KACZ,UAAU,MAAM,KAAK,KACrB,MAAM,SAAS,OACf,UAAU,eACV,UAAU,eACV,UAAU,iBACVC,qBAAoB,KAAK,GACxB;AACD,UAAM,IAAI,MAAM,qCAAqC,KAAK,QAAQ;AAAA,EACnE;AACD;AAEA,SAAS,eAAe,OAAgB,OAAe;AACtD,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,KAAK,KAAKA,qBAAoB,KAAK,GAAG;AAC7E,UAAM,IAAI,MAAM,6BAA6B,KAAK,8BAA8B;AAAA,EACjF;AACA,SAAO,MAAM,KAAK;AACnB;AAEA,SAAS,2BAA2B,OAAgB,OAAe;AAClE,QAAM,aAAa,eAAe,OAAO,KAAK;AAC9C,MAAI,UAAU,YAAY;AACzB,UAAM,IAAI,MAAM,6BAA6B,KAAK,wCAAwC;AAAA,EAC3F;AACA,SAAO;AACR;AAEA,SAAS,2BAA2B,OAAgB,OAAe;AAClE,QAAM,aAAa,eAAe,OAAO,KAAK;AAC9C,MAAI,eAAe,UAAa,UAAU,YAAY;AACrD,UAAM,IAAI,MAAM,6BAA6B,KAAK,wCAAwC;AAAA,EAC3F;AACA,SAAO;AACR;AAEA,SAAS,eAAe,OAAgB,OAAe;AACtD,MAAI,OAAO,UAAU,YAAY,CAAC,SAASA,qBAAoB,KAAK,GAAG;AACtE,UAAM,IAAI,MAAM,6BAA6B,KAAK,sBAAsB;AAAA,EACzE;AACA,SAAO;AACR;AAEA,SAAS,eAAe,OAAgB,OAAe;AACtD,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,YAAYA,qBAAoB,KAAK,GAAG;AAC5D,UAAM,IAAI,MAAM,6BAA6B,KAAK,oBAAoB;AAAA,EACvE;AACA,SAAO,MAAM,KAAK,KAAK;AACxB;AAEO,SAAS,qBAAqB,OAAe;AACnD,QAAM,aAAa,MAAM,KAAK,EAAE,QAAQ,eAAe,EAAE;AACzD,MACC,CAAC,cACD,WAAW,SAAS,QACpB,WAAW,WAAW,GAAG,KACzB,WAAW,SAAS,IAAI,KACxBA,qBAAoB,UAAU,KAC9B,WAAW,MAAM,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,YAAY,OAAO,YAAY,IAAI,GACtF;AACD,UAAM,IAAI,MAAM,sEAAsE;AAAA,EACvF;AACA,SAAO;AACR;AAEA,SAAS,oBAAoB,OAAe;AAC3C,MAAI;AACJ,MAAI;AACH,UAAM,IAAI,IAAI,MAAM,KAAK,CAAC;AAAA,EAC3B,QAAQ;AACP,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAC/C;AACA,QAAM,WACL,IAAI,aAAa,eAAe,IAAI,aAAa,eAAe,IAAI,aAAa;AAClF,MACE,IAAI,aAAa,YAAY,EAAE,IAAI,aAAa,WAAW,aAC5D,IAAI,YACJ,IAAI,YACJ,IAAI,UACJ,IAAI,MACH;AACD,UAAM,IAAI,MAAM,qEAAqE;AAAA,EACtF;AACA,MAAI,WAAW,IAAI,SAAS,QAAQ,UAAU,EAAE;AAChD,SAAO,IAAI,SAAS,EAAE,QAAQ,QAAQ,EAAE;AACzC;AAEA,SAAS,kBAAkB,OAA2B;AACrD,QAAM,SAAS,eAAe,OAAO,WAAW;AAChD,MAAI,OAAO,SAAS,GAAG,KAAK,OAAO,SAAS,IAAI,KAAK,OAAO,WAAW,GAAG,GAAG;AAC5E,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC7C;AACA,SAAO;AACR;AAEA,SAAS,0BAA0B,UAAkB;AACpD,MAAI;AACH,UAAM,MAAM,IAAI,IAAI,SAAS,KAAK,CAAC;AACnC,QAAI,WAAW,IAAI,SAAS,YAAY;AACxC,QAAI,WAAW,IAAI,SAAS,QAAQ,UAAU,EAAE;AAChD,WAAO,IAAI,SAAS,EAAE,QAAQ,QAAQ,EAAE;AAAA,EACzC,QAAQ;AACP,WAAO,SAAS,KAAK;AAAA,EACtB;AACD;AAEA,eAAsB,uBAAuB;AAC5C,QAAM,WAAW,MAAM;AAAA,IACtBD,MAAK,KAAK,SAAS,GAAG,eAAe;AAAA,EACtC;AACA,SAAO,UAAU,aAAa,WAAW,SAAS,UAAU,IAAI;AACjE;AAEA,eAAsB,mBACrB,KACA,UACC;AACD,QAAM,oBAAoB,sBAAsB,GAAG;AACnD,QAAM,kBAAkB,MAAM,qBAAqB;AACnD,MACC,qBACAA,MAAK,QAAQ,iBAAiB,MAAMA,MAAK,QAAQ,mBAAmB,EAAE,GACrE;AACD,WAAO;AAAA,EACR;AACA,SAAO,uBAAuB,QAAQ,KAAK;AAC5C;AAEA,SAAS,uBAAuB,UAAoB;AACnD,QAAM,eAAe,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,eAAe;AAChF,MAAI,CAAC,aAAc,QAAO;AAC1B,MAAI;AACH,UAAM,WAAW,KAAK;AAAA,MACrB,mBAAmB,aAAa,eAAe,aAAa,IAAI,EAAE,SAAS,MAAM;AAAA,IAClF;AACA,WAAO,SAAS,aAAa,WAAW,SAAS,UAAU,IAAI;AAAA,EAChE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEA,SAAS,mBAAmB,OAAe,UAAkB;AAC5D,MAAI,CAAC,yBAAyB,KAAK,KAAK,KAAK,MAAM,SAAS,MAAM,GAAG;AACpE,UAAM,IAAI,MAAM,4CAA4C,QAAQ,EAAE;AAAA,EACvE;AACA,SAAO,OAAO,KAAK,OAAO,QAAQ;AACnC;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,SAAOE,MAAK,KAAK,SAAS,GAAG,UAAU,GAAG,OAAO,QAAQ,IAAI,IAAI,IAAI,aAAa;AACnF;AAEA,SAAS,2BAA2B,QAAuB;AAC1D,UAAQ,OAAO,QAAQ,MAAM;AAAA,IAC5B,KAAK;AACJ,aAAO,KAAK,UAAU;AAAA,QACrB;AAAA,QACA,0BAA0B,OAAO,QAAQ,QAAQ,QAAQ;AAAA,QACzD,OAAO,QAAQ,YAAY;AAAA,QAC3B,OAAO;AAAA,MACR,CAAC;AAAA,IACF,KAAK;AACJ,aAAO,KAAK,UAAU;AAAA,QACrB;AAAA,QACA,2BAA2B,OAAO,QAAQ,QAAQ,MAAM;AAAA,QACxD,OAAO,QAAQ,YAAY;AAAA,QAC3B,OAAO;AAAA,MACR,CAAC;AAAA,IACF,KAAK;AACJ,aAAO,KAAK,UAAU;AAAA,QACrB;AAAA,QACA,2BAA2B,OAAO,QAAQ,QAAQ,GAAG;AAAA,QACrD,OAAO,QAAQ,QAAQ;AAAA,QACvB,OAAO;AAAA,MACR,CAAC;AAAA,EACH;AACD;AAEO,SAAS,WAAW;AAC1B,SAAOC,aAAY;AACpB;AAEA,SAAS,WAAW,OAAe;AAClC,SAAO,UAAU,OAAO,MAAM,WAAW,IAAI,IAAID,MAAK,KAAK,GAAG,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC,IAAI;AAC5F;AAIO,SAAS,sBAAwC;AACvD,SAAO;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,oBAAoB,CAAC;AAAA,IACrB,YAAY,CAAC;AAAA,EACd;AACD;AAEA,eAAsB,0BAA0B;AAC/C,QAAM,WAAW,MAAM,iCAAiC,CAAC,aAAa;AACrE,6BAAyB,QAAQ;AAAA,EAClC,CAAC;AACD,MAAI,SAAU,0BAAyB,SAAS,MAAM;AACtD,SAAO;AACR;AAEA,eAAsB,wBAA+D;AACpF,UAAQ,MAAM,wBAAwB,IAAI;AAC3C;AAEA,IAAI,oBAAmC,QAAQ,QAAQ;AAEhD,SAAS,kBACf,QACA,QACC;AACD,QAAM,YAAY,kBAAkB,KAAK,MAAM;AAC9C,YAAQ,eAAe;AACvB,WAAO,yBAAyB,QAAQ,MAAM;AAAA,EAC/C,CAAC;AACD,sBAAoB,UAAU;AAAA,IAC7B,MAAM;AAAA,IACN,MAAM;AAAA,EACP;AACA,SAAO;AACR;AAEA,eAAe,yBACd,QACA,QACC;AACD,SAAO,0BAA0B,oBAAoB,GAAG,QAAQ,0BAA0B,MAAM;AACjG;AAsCO,SAAS,WAAW;AAC1B,SAAOE,MAAK,KAAK,SAAS,GAAG,MAAM;AACpC;AAEA,eAAsB,iBAAiB;AACtC,QAAMC,IAAG,MAAM,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C;AAEA,eAAe,iBAAoB,UAA0C;AAC5E,MAAI;AACH,WAAO,KAAK,MAAM,MAAMA,IAAG,SAAS,UAAU,MAAM,CAAC;AAAA,EACtD,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACP;AACD;AAEA,eAAsB,UAAU,UAAkB,OAAgB;AACjE,QAAMA,IAAG,MAAMD,MAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,QAAM,OAAO,GAAG,QAAQ,IAAI,QAAQ,GAAG,IAAIE,YAAW,CAAC;AACvD,QAAMD,IAAG,UAAU,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,GAAI,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AAClF,MAAI,QAAQ,aAAa,QAAS,OAAMA,IAAG,MAAM,MAAM,GAAK;AAC5D,QAAMA,IAAG,OAAO,MAAM,QAAQ;AAC/B;AAEO,SAAS,qBAAqB,QAAsD;AAC1F,MAAI,CAAC,uBAAuB,OAAO,QAAQ,KAAK,CAAC,OAAO,aAAc,QAAO,CAAC;AAC9E,SAAO;AAAA,IACN;AAAA,EACD;AACD;AAEO,SAAS,qBAAqB,QAAwC;AAC5E,MAAI,CAAC,OAAO,QAAQ,SAAS,UAAU,EAAG,QAAO,CAAC;AAClD,SAAO;AAAA,IACN;AAAA,EACD;AACD;AAEO,SAAS,uBAAuB,UAA8B;AACpE,QAAM,QAAQ,UAAU,KAAK;AAC7B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACH,UAAM,WAAW,IAAI,IAAI,KAAK,EAAE,SAAS,YAAY;AACrD,WACC,aAAa,8BAA8B,SAAS,SAAS,2BAA2B;AAAA,EAE1F,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAaA,SAASE,qBAAoB,OAAe;AAE3C,SAAO,gCAAgC,KAAK,KAAK;AAClD;",
6
- "names": ["installed", "randomUUID", "fs", "path", "getAgentDir", "path", "hasControlCharacter", "path", "getAgentDir", "path", "fs", "randomUUID", "hasControlCharacter"]
7
- }