@narumitw/pi-sync 0.54.3 → 0.56.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 (179) hide show
  1. package/README.md +21 -4
  2. package/dist/chunks/agent-candidate-3JN6DJKT.ts +26 -0
  3. package/dist/chunks/agent-plan-QCUJWBP4.ts +99 -0
  4. package/dist/chunks/agent-plan-QCUJWBP4.ts.map +7 -0
  5. package/dist/chunks/agent-runner-E2JU2VZ6.ts +182 -0
  6. package/dist/chunks/agent-runner-E2JU2VZ6.ts.map +7 -0
  7. package/dist/chunks/agent-store-A3F6IYWZ.ts +152 -0
  8. package/dist/chunks/agent-store-A3F6IYWZ.ts.map +7 -0
  9. package/dist/chunks/chunk-5Q5SSKNG.ts +128 -0
  10. package/dist/chunks/chunk-5Q5SSKNG.ts.map +7 -0
  11. package/dist/chunks/chunk-5XZOC7FD.ts +215 -0
  12. package/dist/chunks/chunk-5XZOC7FD.ts.map +7 -0
  13. package/dist/chunks/{chunk-GC3QOL6J.ts → chunk-AAEEHR7H.ts} +31 -87
  14. package/dist/chunks/chunk-AAEEHR7H.ts.map +7 -0
  15. package/dist/chunks/{chunk-R35N4CL3.ts → chunk-B4QZBDBT.ts} +2 -2
  16. package/dist/chunks/{chunk-KGE47GCZ.ts → chunk-CRKTAPSL.ts} +8 -8
  17. package/dist/chunks/chunk-DT7M4VQS.ts +69 -0
  18. package/dist/chunks/chunk-DT7M4VQS.ts.map +7 -0
  19. package/dist/chunks/chunk-ED3TYIVW.ts +229 -0
  20. package/dist/chunks/chunk-ED3TYIVW.ts.map +7 -0
  21. package/dist/chunks/{chunk-HMXUKU43.ts → chunk-EUMINX7L.ts} +6 -6
  22. package/dist/chunks/chunk-FQOSHGJ7.ts +215 -0
  23. package/dist/chunks/chunk-FQOSHGJ7.ts.map +7 -0
  24. package/dist/chunks/chunk-GNH73BJ5.ts +153 -0
  25. package/dist/chunks/chunk-GNH73BJ5.ts.map +7 -0
  26. package/dist/chunks/{chunk-YTHQEW35.ts → chunk-GP5DU62N.ts} +8 -9
  27. package/dist/chunks/chunk-GP5DU62N.ts.map +7 -0
  28. package/dist/chunks/{chunk-AAZDBIBJ.ts → chunk-GSNPASKB.ts} +2 -2
  29. package/dist/chunks/{chunk-E6ONFG57.ts → chunk-IWZH5KYS.ts} +11 -8
  30. package/dist/chunks/chunk-IWZH5KYS.ts.map +7 -0
  31. package/dist/chunks/{chunk-CAGJOKB7.ts → chunk-JJTARUSO.ts} +15 -14
  32. package/dist/chunks/chunk-JJTARUSO.ts.map +7 -0
  33. package/dist/chunks/{chunk-ITFR6NNQ.ts → chunk-NLWS55B6.ts} +2 -1
  34. package/dist/chunks/{chunk-ITFR6NNQ.ts.map → chunk-NLWS55B6.ts.map} +2 -2
  35. package/dist/chunks/{chunk-2FETCGGT.ts → chunk-OEWQVWLC.ts} +4 -4
  36. package/dist/chunks/{chunk-35GM6XKM.ts → chunk-OTZRCKYP.ts} +128 -382
  37. package/dist/chunks/chunk-OTZRCKYP.ts.map +7 -0
  38. package/dist/chunks/{chunk-XU2VXGQV.ts → chunk-OWBAZA6J.ts} +14 -8
  39. package/dist/chunks/chunk-OWBAZA6J.ts.map +7 -0
  40. package/dist/chunks/chunk-PRUEIIK7.ts +24 -0
  41. package/dist/chunks/chunk-PRUEIIK7.ts.map +7 -0
  42. package/dist/chunks/chunk-QGK445K7.ts +21 -0
  43. package/dist/chunks/chunk-QGK445K7.ts.map +7 -0
  44. package/dist/chunks/{chunk-KATKRR3D.ts → chunk-QO333NM4.ts} +32 -11
  45. package/dist/chunks/chunk-QO333NM4.ts.map +7 -0
  46. package/dist/chunks/{chunk-I4JYVFUS.ts → chunk-QSHMOL3I.ts} +21 -22
  47. package/dist/chunks/chunk-QSHMOL3I.ts.map +7 -0
  48. package/dist/chunks/chunk-S2FMH5FT.ts +97 -0
  49. package/dist/chunks/chunk-S2FMH5FT.ts.map +7 -0
  50. package/dist/chunks/{chunk-BVVP33U5.ts → chunk-SWRVXVFD.ts} +12 -9
  51. package/dist/chunks/chunk-SWRVXVFD.ts.map +7 -0
  52. package/dist/chunks/{chunk-ZX2Q6THB.ts → chunk-UBV24CG4.ts} +4 -5
  53. package/dist/chunks/chunk-UBV24CG4.ts.map +7 -0
  54. package/dist/chunks/chunk-UOHR7LRO.ts +70 -0
  55. package/dist/chunks/chunk-UOHR7LRO.ts.map +7 -0
  56. package/dist/chunks/{chunk-VCL7TZYW.ts → chunk-UPNVIUBN.ts} +3 -3
  57. package/dist/chunks/chunk-VJN7KU4J.ts +350 -0
  58. package/dist/chunks/chunk-VJN7KU4J.ts.map +7 -0
  59. package/dist/chunks/chunk-YHT4YTYG.ts +31 -0
  60. package/dist/chunks/chunk-YHT4YTYG.ts.map +7 -0
  61. package/dist/chunks/{chunk-A3TFXY4O.ts → chunk-YK52VDXG.ts} +6 -5
  62. package/dist/chunks/chunk-YK52VDXG.ts.map +7 -0
  63. package/dist/chunks/config-KGIYTTXQ.ts +37 -0
  64. package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts → conflict-artifacts-FXFIIBCB.ts} +8 -7
  65. package/dist/chunks/{conflict-review-ZOTOHL2E.ts → conflict-review-6WIEQLXW.ts} +31 -25
  66. package/dist/chunks/{conflict-review-ZOTOHL2E.ts.map → conflict-review-6WIEQLXW.ts.map} +1 -1
  67. package/dist/chunks/continuous-record-LFRVXQBD.ts +30 -0
  68. package/dist/chunks/continuous-sync-AWAAOXK2.ts +545 -0
  69. package/dist/chunks/continuous-sync-AWAAOXK2.ts.map +7 -0
  70. package/dist/chunks/{file-selection-UNHBVVON.ts → file-selection-3JJYOVNR.ts} +5 -5
  71. package/dist/chunks/{git-backend-FD7AVSK6.ts → git-backend-KYDZ673X.ts} +28 -32
  72. package/dist/chunks/git-backend-KYDZ673X.ts.map +7 -0
  73. package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts → manager-result-dispatcher-AGBBVDDS.ts} +10 -9
  74. package/dist/chunks/{manager-ui-ZIN4BUSF.ts → manager-ui-KRAW3NE2.ts} +184 -45
  75. package/dist/chunks/manager-ui-KRAW3NE2.ts.map +7 -0
  76. package/dist/chunks/{merge-baseline-store-ICXVTCML.ts → merge-baseline-store-RFCAH7KL.ts} +5 -5
  77. package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts → remote-selection-ui-5725JDNC.ts} +9 -8
  78. package/dist/chunks/remote-selection-ui-5725JDNC.ts.map +7 -0
  79. package/dist/chunks/{s3-backend-Y4P3O5B5.ts → s3-backend-Y7WSCLJI.ts} +38 -38
  80. package/dist/chunks/s3-backend-Y7WSCLJI.ts.map +7 -0
  81. package/dist/chunks/{setup-switch-ZMW5C4M7.ts → setup-switch-E7PHKI6J.ts} +7 -6
  82. package/dist/chunks/setup-switch-E7PHKI6J.ts.map +7 -0
  83. package/dist/chunks/{setup-wizard-VW7F3JN4.ts → setup-wizard-65DROCIJ.ts} +14 -13
  84. package/dist/chunks/setup-wizard-65DROCIJ.ts.map +7 -0
  85. package/dist/chunks/{sync-inspection-3EMS2J5B.ts → sync-inspection-XFJOAMJD.ts} +8 -8
  86. package/dist/chunks/sync-inspection-XFJOAMJD.ts.map +7 -0
  87. package/dist/chunks/{sync-operations-2CWST333.ts → sync-operations-HDUDT5PD.ts} +62 -63
  88. package/dist/chunks/sync-operations-HDUDT5PD.ts.map +7 -0
  89. package/dist/chunks/{webdav-backend-TBILVEQK.ts → webdav-backend-6K26F6LT.ts} +39 -48
  90. package/dist/chunks/webdav-backend-6K26F6LT.ts.map +7 -0
  91. package/dist/index.ts +165 -85
  92. package/dist/index.ts.map +3 -3
  93. package/docs/agent-mode-verification.md +99 -0
  94. package/docs/continuous-sync-verification.md +87 -0
  95. package/docs/settings.md +84 -1
  96. package/package.json +3 -2
  97. package/src/backends/git/git-backend.ts +1 -4
  98. package/src/backends/git/git-runner.ts +1 -5
  99. package/src/backends/s3/s3-backend.ts +3 -25
  100. package/src/backends/s3/s3-client.ts +14 -2
  101. package/src/backends/snapshot-pointer.ts +27 -0
  102. package/src/backends/webdav/webdav-backend.ts +3 -29
  103. package/src/backends/webdav/webdav-client.ts +11 -7
  104. package/src/commands/command-execution.ts +5 -2
  105. package/src/commands/command-handler.ts +15 -3
  106. package/src/commands/command-types.ts +6 -0
  107. package/src/commands/command.ts +1 -0
  108. package/src/settings/config.ts +7 -0
  109. package/src/settings/settings-store.ts +0 -34
  110. package/src/settings/settings-types.ts +8 -0
  111. package/src/settings/settings-validation.ts +1 -1
  112. package/src/snapshot/snapshot-codec.ts +1 -5
  113. package/src/state/lock.ts +13 -10
  114. package/src/state/merge-baseline-store.ts +2 -2
  115. package/src/state/state-directory.ts +8 -1
  116. package/src/sync/agent-candidate.ts +251 -0
  117. package/src/sync/agent-plan.ts +87 -0
  118. package/src/sync/agent-policy.ts +13 -0
  119. package/src/sync/agent-request.ts +17 -0
  120. package/src/sync/agent-runner.ts +188 -0
  121. package/src/sync/agent-store.ts +151 -0
  122. package/src/sync/agent-sync.ts +91 -0
  123. package/src/sync/automatic-sync.ts +2 -1
  124. package/src/sync/continuous-errors.ts +85 -0
  125. package/src/sync/continuous-lease.ts +221 -0
  126. package/src/sync/continuous-record.ts +179 -0
  127. package/src/sync/continuous-storage.ts +55 -0
  128. package/src/sync/continuous-sync.ts +516 -0
  129. package/src/sync/continuous-watch.ts +59 -0
  130. package/src/sync/merged-sync.ts +70 -12
  131. package/src/sync/remote-snapshot.ts +2 -3
  132. package/src/sync/settings-merge.ts +19 -3
  133. package/src/sync/setup-switch.ts +1 -5
  134. package/src/sync/startup-check.ts +15 -11
  135. package/src/sync/sync-inspection.ts +8 -1
  136. package/src/sync/sync-mutations.ts +6 -17
  137. package/src/sync/sync-queries.ts +5 -0
  138. package/src/sync/text-merge.ts +3 -3
  139. package/src/sync-extension.ts +75 -19
  140. package/src/ui/agent-mode-setting.ts +91 -0
  141. package/src/ui/manager-state.ts +2 -0
  142. package/src/ui/remote-selection-ui.ts +5 -5
  143. package/src/ui/settings-ui.ts +83 -1
  144. package/src/ui/setup/s3-credentials-ui.ts +1 -5
  145. package/src/ui/setup/setup-name-ui.ts +2 -5
  146. package/src/ui/setup/setup-switcher.ts +2 -0
  147. package/src/ui/sync-setups-ui.ts +3 -5
  148. package/dist/chunks/chunk-26PMXY7E.ts +0 -362
  149. package/dist/chunks/chunk-26PMXY7E.ts.map +0 -7
  150. package/dist/chunks/chunk-35GM6XKM.ts.map +0 -7
  151. package/dist/chunks/chunk-A3TFXY4O.ts.map +0 -7
  152. package/dist/chunks/chunk-BVVP33U5.ts.map +0 -7
  153. package/dist/chunks/chunk-CAGJOKB7.ts.map +0 -7
  154. package/dist/chunks/chunk-E6ONFG57.ts.map +0 -7
  155. package/dist/chunks/chunk-GC3QOL6J.ts.map +0 -7
  156. package/dist/chunks/chunk-I4JYVFUS.ts.map +0 -7
  157. package/dist/chunks/chunk-KATKRR3D.ts.map +0 -7
  158. package/dist/chunks/chunk-XU2VXGQV.ts.map +0 -7
  159. package/dist/chunks/chunk-YTHQEW35.ts.map +0 -7
  160. package/dist/chunks/chunk-ZX2Q6THB.ts.map +0 -7
  161. package/dist/chunks/git-backend-FD7AVSK6.ts.map +0 -7
  162. package/dist/chunks/manager-ui-ZIN4BUSF.ts.map +0 -7
  163. package/dist/chunks/s3-backend-Y4P3O5B5.ts.map +0 -7
  164. package/dist/chunks/setup-wizard-VW7F3JN4.ts.map +0 -7
  165. package/dist/chunks/sync-operations-2CWST333.ts.map +0 -7
  166. package/dist/chunks/webdav-backend-TBILVEQK.ts.map +0 -7
  167. /package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts.map → agent-candidate-3JN6DJKT.ts.map} +0 -0
  168. /package/dist/chunks/{chunk-R35N4CL3.ts.map → chunk-B4QZBDBT.ts.map} +0 -0
  169. /package/dist/chunks/{chunk-KGE47GCZ.ts.map → chunk-CRKTAPSL.ts.map} +0 -0
  170. /package/dist/chunks/{chunk-HMXUKU43.ts.map → chunk-EUMINX7L.ts.map} +0 -0
  171. /package/dist/chunks/{chunk-AAZDBIBJ.ts.map → chunk-GSNPASKB.ts.map} +0 -0
  172. /package/dist/chunks/{chunk-2FETCGGT.ts.map → chunk-OEWQVWLC.ts.map} +0 -0
  173. /package/dist/chunks/{chunk-VCL7TZYW.ts.map → chunk-UPNVIUBN.ts.map} +0 -0
  174. /package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts.map → config-KGIYTTXQ.ts.map} +0 -0
  175. /package/dist/chunks/{merge-baseline-store-ICXVTCML.ts.map → conflict-artifacts-FXFIIBCB.ts.map} +0 -0
  176. /package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts.map → continuous-record-LFRVXQBD.ts.map} +0 -0
  177. /package/dist/chunks/{file-selection-UNHBVVON.ts.map → file-selection-3JJYOVNR.ts.map} +0 -0
  178. /package/dist/chunks/{setup-switch-ZMW5C4M7.ts.map → manager-result-dispatcher-AGBBVDDS.ts.map} +0 -0
  179. /package/dist/chunks/{sync-inspection-3EMS2J5B.ts.map → merge-baseline-store-RFCAH7KL.ts.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/backends/webdav/webdav-backend.ts", "../../src/backends/webdav/webdav-client.ts"],
4
+ "sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport { decodeSnapshot, encodeSnapshot } from \"../../snapshot/snapshot-codec.js\";\nimport type { Snapshot } from \"../../snapshot/snapshot-types.js\";\nimport { validatePortableSnapshot } from \"../../sync/local-fields.js\";\nimport { throwIfAborted } from \"../../sync/signals.js\";\nimport { syncErrorGuidance } from \"../../sync/sync-error-guidance.js\";\nimport { portableSnapshotSelection } from \"../../sync/sync-policy.js\";\nimport type { LatestPointer, RemoteObject, ResolvedWebDavBackend } from \"../backend-types.js\";\nimport { createLatestPointer, remoteHistoryEntry } from \"../snapshot-pointer.js\";\nimport {\n type BackendDiagnostic,\n type ExpectedRemoteHead,\n type PublishSnapshotOptions,\n type PublishSnapshotResult,\n type RemoteHead,\n type RemoteHistoryEntry,\n type SyncBackend,\n SyncBackendConflictError,\n SyncBackendPublicationOutcomeUnknownError,\n} from \"../sync-backend.js\";\nimport { WebDavClient, WebDavHttpError, WebDavPreconditionError } from \"./webdav-client.js\";\n\nconst VERSION = 1;\nconst POST_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class WebDavSyncBackend implements SyncBackend {\n readonly identity: string;\n readonly destination: string;\n private conditionalVerified = false;\n private readonly checksums = new Map<string, string>();\n private capabilityCheck?: Promise<void>;\n\n constructor(\n private readonly config: ResolvedWebDavBackend,\n private readonly postCommitTimeoutMs = POST_COMMIT_TIMEOUT_MS,\n ) {\n assertSafeDestination(config);\n this.identity = webDavBackendIdentity(config);\n this.destination = webDavStorageLocation(config);\n }\n\n get capability() {\n return this.conditionalVerified ? (\"atomic-conditional\" as const) : (\"conditional-required\" as const);\n }\n\n sameRevision(left: string, right: string) {\n return left === right;\n }\n\n async readHead(signal?: AbortSignal): Promise<RemoteHead | undefined> {\n const object = await new WebDavClient(this.config, signal).getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return undefined;\n const pointer = requirePointer(object.value, this.config.destination.namespace);\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n return remoteHead(pointer, this.identity, object.etag);\n }\n\n async readSnapshot(reference: string, signal?: AbortSignal): Promise<Snapshot> {\n requireSnapshotReference(reference);\n const expectedChecksum = this.checksums.get(reference) ?? (await this.resolveChecksum(reference, signal));\n const object = await new WebDavClient(this.config, signal).getBuffer(snapshotPath(this.config, reference));\n throwIfAborted(signal);\n if (!object.value) throw new Error(`Snapshot not found: ${reference}`);\n if (!expectedChecksum || sha256(object.value) !== expectedChecksum) {\n throw new Error(\"Remote snapshot checksum mismatch.\");\n }\n const snapshot = await decodeSnapshot(object.value, { signal });\n if (snapshot.id !== reference || snapshot.profile !== this.config.destination.namespace) {\n throw new Error(\"Remote snapshot identity mismatch.\");\n }\n validateSnapshotBundle(snapshot);\n return snapshot;\n }\n\n async publishSnapshot(\n snapshot: Snapshot,\n expected: ExpectedRemoteHead,\n options: PublishSnapshotOptions = {},\n ): Promise<PublishSnapshotResult> {\n throwIfAborted(options.signal);\n assertSnapshotIdentity(snapshot, this.config.destination.namespace);\n await this.ensureAtomicConditions(options.signal);\n throwIfAborted(options.signal);\n const client = new WebDavClient(this.config, options.signal);\n await client.ensureCollection(snapshotsPath(this.config));\n const encoded = await encodeSnapshot(snapshot);\n throwIfAborted(options.signal);\n const pointer = createLatestPointer(this.config.destination.namespace, snapshot, sha256(encoded));\n const stagedPath = snapshotPath(this.config, snapshot.id);\n try {\n await client.putBuffer(stagedPath, encoded, \"application/gzip\", { ifAbsent: true });\n } catch (error) {\n if (!(error instanceof WebDavPreconditionError)) throw error;\n const existing = await client.getBuffer(stagedPath);\n if (!existing.value || sha256(existing.value) !== pointer.sha256) {\n throw new SyncBackendConflictError(\n `Immutable snapshot id already exists with different content: ${snapshot.id}`,\n );\n }\n }\n const currentObject = await client.getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(options.signal);\n const current = currentObject.missing\n ? undefined\n : remoteHead(\n requirePointer(currentObject.value, this.config.destination.namespace),\n this.identity,\n currentObject.etag,\n );\n if (!matchesExpected(current, expected)) {\n throw new SyncBackendConflictError(\"Remote changed while pushing. Run /sync pull first, then retry.\", {\n currentHead: current,\n });\n }\n const condition = publicationCondition(currentObject, expected, this.identity);\n throwIfAborted(options.signal);\n options.onCommit?.();\n const commitClient = new WebDavClient(\n this.config,\n AbortSignal.timeout(this.postCommitTimeoutMs),\n this.postCommitTimeoutMs,\n );\n try {\n await commitClient.putJson(latestPath(this.config), pointer, condition);\n } catch (error) {\n if (error instanceof WebDavPreconditionError) {\n const latest = await this.readHeadAfterCommit(commitClient).catch(() => undefined);\n throw new SyncBackendConflictError(\"Remote changed while publishing the WebDAV pointer.\", {\n currentHead: latest,\n });\n }\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote publication outcome is unknown: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verifiedObject: RemoteObject<LatestPointer>;\n try {\n verifiedObject = await commitClient.getJson<LatestPointer>(latestPath(this.config));\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication could not be verified: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n let verified: LatestPointer;\n try {\n verified = requirePointer(verifiedObject.value, this.config.destination.namespace);\n } catch (error) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n `Remote snapshot may be active, but publication verification was malformed: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n if (!samePointer(pointer, verified)) {\n throw new SyncBackendConflictError(\n \"Remote latest changed immediately after push. Run /sync status before continuing.\",\n {\n phase: \"after-commit\",\n currentHead: remoteHead(verified, this.identity, verifiedObject.etag),\n candidateMayHaveBeenActive: true,\n },\n );\n }\n if (!strongEtag(verifiedObject.etag)) {\n throw new SyncBackendPublicationOutcomeUnknownError(\n \"Remote snapshot is active, but the WebDAV server returned no strong ETag.\",\n );\n }\n this.registerChecksum(verified.snapshot, verified.sha256);\n const head = remoteHead(verified, this.identity, verifiedObject.etag);\n const warning = await this.updateHistorySafely(commitClient, pointer);\n return { head, warnings: warning ? [warning] : [] };\n }\n\n async listHistory(signal?: AbortSignal): Promise<RemoteHistoryEntry[]> {\n const object = await new WebDavClient(this.config, signal).getJson<{\n version: number;\n snapshots: LatestPointer[];\n }>(historyPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return [];\n const pointers = requireHistory(object.value, this.config.destination.namespace);\n for (const pointer of pointers) this.registerChecksum(pointer.snapshot, pointer.sha256);\n return pointers.map(remoteHistoryEntry);\n }\n\n async diagnose(signal?: AbortSignal): Promise<BackendDiagnostic[]> {\n const diagnostics: BackendDiagnostic[] = [\n {\n key: \"webdav-url\",\n level: \"info\",\n message: `webdav URL/TLS/auth: configured (${webDavStorageLocation(this.config)})`,\n },\n {\n key: \"webdav-scope\",\n level: \"info\",\n message:\n \"webdav check scope: temporary write/delete probe; repair the active snapshot's history entry if missing. No local content is applied.\",\n },\n ];\n try {\n await this.runCapabilityProbe(signal);\n diagnostics.push(\n { key: \"webdav-collection\", level: \"info\", message: \"webdav collection read/write: ok\" },\n {\n key: \"webdav-conditional\",\n level: \"info\",\n message: \"webdav conditional publication: atomic-conditional (verified)\",\n },\n { key: \"webdav-cleanup\", level: \"info\", message: \"webdav probe cleanup: ok\" },\n );\n } catch (error) {\n this.capabilityCheck = undefined;\n this.conditionalVerified = false;\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n diagnostics.push({\n key: \"webdav-probe\",\n level: \"error\",\n message: `webdav publication is read-only until diagnostics pass: ${syncErrorGuidance(error)}`,\n });\n return diagnostics;\n }\n try {\n diagnostics.push({\n key: \"webdav-history\",\n level: \"info\",\n message: await this.reconcileActiveHistory(signal),\n });\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n diagnostics.push({\n key: \"webdav-history\",\n level: \"error\",\n message: `webdav history repair failed: ${syncErrorGuidance(error)}`,\n });\n }\n return diagnostics;\n }\n\n private ensureAtomicConditions(signal?: AbortSignal) {\n if (this.capabilityCheck) return this.capabilityCheck;\n this.conditionalVerified = false;\n const check = this.runCapabilityProbe(signal).finally(() => {\n if (this.capabilityCheck === check) this.capabilityCheck = undefined;\n });\n this.capabilityCheck = check;\n return check;\n }\n\n private async runCapabilityProbe(signal?: AbortSignal) {\n throwIfAborted(signal);\n const probeCollection = joinRemote(rootPath(this.config), \".pi-sync-probes\", randomUUID());\n const probe = `${probeCollection}/conditional.txt`;\n const client = new WebDavClient(this.config, signal);\n let created = false;\n let operationError: unknown;\n try {\n created = true;\n await client.ensureCollection(probeCollection);\n await client.listCollection(probeCollection);\n await client.putBuffer(probe, Buffer.from(\"first\"), \"text/plain\", { ifAbsent: true });\n const read = await client.getBuffer(probe);\n const etag = strongEtag(read.etag);\n if (!read.value || !etag) {\n throw new Error(\"WebDAV server did not return a strong ETag for the capability probe.\");\n }\n await expectPrecondition(\n client.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", { ifAbsent: true }),\n \"If-None-Match\",\n );\n await expectPrecondition(\n client.putBuffer(probe, Buffer.from(\"replace\"), \"text/plain\", {\n ifMatch: '\"pi-sync-deliberately-stale\"',\n }),\n \"If-Match\",\n );\n const unchanged = await client.getBuffer(probe);\n if (!unchanged.value?.equals(Buffer.from(\"first\"))) {\n throw new Error(\"WebDAV server changed a probe despite a failed precondition.\");\n }\n await client.putBuffer(probe, Buffer.from(\"second\"), \"text/plain\", { ifMatch: etag });\n const changed = await client.getBuffer(probe);\n const changedEtag = strongEtag(changed.etag);\n if (!changed.value?.equals(Buffer.from(\"second\")) || !changedEtag || changedEtag === etag) {\n throw new Error(\"WebDAV server did not rotate its strong ETag after changing the capability probe.\");\n }\n } catch (error) {\n operationError = error;\n }\n if (created) {\n try {\n await new WebDavClient(this.config, undefined).delete(probeCollection);\n } catch (cleanupError) {\n const operationDetail = operationError ? `WebDAV probe failed: ${errorMessage(operationError)}; ` : \"\";\n throw new Error(\n `${operationDetail}probe cleanup also failed; remove ${probeCollection}: ${errorMessage(cleanupError)}`,\n { cause: operationError ?? cleanupError },\n );\n }\n }\n if (operationError) throw operationError;\n this.conditionalVerified = true;\n }\n\n private async resolveChecksum(reference: string, signal?: AbortSignal) {\n await this.readHead(signal);\n if (this.checksums.has(reference)) return this.checksums.get(reference);\n await this.listHistory(signal);\n return this.checksums.get(reference);\n }\n\n private registerChecksum(reference: string, checksum: string) {\n const known = this.checksums.get(reference);\n if (known && known !== checksum) {\n throw new Error(\"Remote snapshot reference was rebound to a different checksum.\");\n }\n this.checksums.set(reference, checksum);\n }\n\n private async readHeadAfterCommit(client: WebDavClient) {\n const object = await client.getJson<LatestPointer>(latestPath(this.config));\n if (object.missing) return undefined;\n return remoteHead(requirePointer(object.value, this.config.destination.namespace), this.identity, object.etag);\n }\n\n private async reconcileActiveHistory(signal?: AbortSignal) {\n const client = new WebDavClient(this.config, signal);\n const object = await client.getJson<LatestPointer>(latestPath(this.config));\n throwIfAborted(signal);\n if (object.missing) return \"webdav history: no active snapshot\";\n const pointer = requirePointer(object.value, this.config.destination.namespace);\n this.registerChecksum(pointer.snapshot, pointer.sha256);\n const repaired = await this.ensureHistoryPointer(client, pointer);\n return repaired\n ? \"webdav history: repaired active snapshot entry\"\n : \"webdav history: active snapshot entry present\";\n }\n\n private async ensureHistoryPointer(client: WebDavClient, pointer: LatestPointer) {\n const object = await client.getJson<{ version: number; snapshots: LatestPointer[] }>(historyPath(this.config));\n const snapshots = object.missing ? [] : requireHistory(object.value, this.config.destination.namespace);\n const existing = snapshots.find((entry) => entry.snapshot === pointer.snapshot);\n if (existing) {\n if (!samePointer(existing, pointer)) {\n throw new Error(\"Remote history rebound an immutable snapshot reference.\");\n }\n return false;\n }\n const next = [...snapshots, pointer].slice(-100);\n const condition = object.missing ? { ifAbsent: true } : { ifMatch: requireStrongEtag(object.etag, \"history\") };\n await client.putJson(historyPath(this.config), { version: VERSION, snapshots: next }, condition);\n return true;\n }\n\n private async updateHistorySafely(client: WebDavClient, pointer: LatestPointer) {\n try {\n await this.ensureHistoryPointer(client, pointer);\n return undefined;\n } catch (error) {\n return `Remote snapshot is active, but history could not be updated: ${errorMessage(error)}. Run /sync doctor before relying on history.`;\n }\n }\n}\n\nexport function rootPath(config: ResolvedWebDavBackend) {\n return config.destination.path === \"./\" ? \"\" : config.destination.path;\n}\n\nexport function latestPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"latest.json\");\n}\n\nexport function historyPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"history.json\");\n}\n\nexport function snapshotsPath(config: ResolvedWebDavBackend) {\n return joinRemote(rootPath(config), \"snapshots\");\n}\n\nexport function snapshotPath(config: ResolvedWebDavBackend, reference: string) {\n requireSnapshotReference(reference);\n return joinRemote(snapshotsPath(config), `${reference}.json.gz`);\n}\n\nexport function webDavBackendIdentity(config: ResolvedWebDavBackend) {\n return `webdav:${sha256(Buffer.from(JSON.stringify([secretFreeUrl(config.profile.url), config.destination.path])))}`;\n}\n\nfunction webDavStorageLocation(config: ResolvedWebDavBackend) {\n const url = new URL(secretFreeUrl(config.profile.url));\n return `${url.host} \u00B7 ${config.destination.path}`;\n}\n\nfunction remoteHead(pointer: LatestPointer, identity: string, etag?: string): RemoteHead {\n return {\n snapshotRef: pointer.snapshot,\n snapshotId: pointer.snapshot,\n revision: encodeRevision(identity, etag, pointer),\n createdAt: pointer.createdAt,\n machine: pointer.machine,\n syncSessions: pointer.syncSessions === true,\n ...(pointer.selection === undefined ? {} : { selection: pointer.selection }),\n };\n}\n\nfunction encodeRevision(identity: string, etag: string | undefined, pointer: LatestPointer) {\n return `webdav-v1:${Buffer.from(JSON.stringify({ identity, etag: etag ?? null, pointer: sha256(Buffer.from(canonicalJson(pointer))) })).toString(\"base64url\")}`;\n}\n\nfunction decodeRevision(value: string, identity: string) {\n try {\n if (!value.startsWith(\"webdav-v1:\")) return undefined;\n const parsed = JSON.parse(Buffer.from(value.slice(10), \"base64url\").toString(\"utf8\")) as {\n identity?: unknown;\n etag?: unknown;\n };\n if (parsed.identity !== identity || typeof parsed.etag !== \"string\") return undefined;\n return strongEtag(parsed.etag);\n } catch {\n return undefined;\n }\n}\n\nfunction publicationCondition(current: RemoteObject<LatestPointer>, expected: ExpectedRemoteHead, identity: string) {\n if (expected.kind === \"missing\") return { ifAbsent: true };\n const etag = decodeRevision(expected.revision, identity) ?? strongEtag(current.etag);\n if (!etag) throw new SyncBackendConflictError(\"WebDAV head has no usable strong ETag.\");\n return { ifMatch: etag };\n}\n\nasync function expectPrecondition(operation: Promise<unknown>, header: string) {\n try {\n await operation;\n } catch (error) {\n if (error instanceof WebDavPreconditionError) return;\n throw error;\n }\n throw new Error(`WebDAV server ignored ${header}; publication is read-only for safety.`);\n}\n\nfunction requireStrongEtag(value: string | undefined, resource: string) {\n const etag = strongEtag(value);\n if (!etag) throw new Error(`WebDAV ${resource} has no strong ETag.`);\n return etag;\n}\n\nfunction strongEtag(value: string | undefined) {\n return value && !value.startsWith(\"W/\") && /^\"[^\"\\r\\n]+\"$/u.test(value) ? value : undefined;\n}\n\nfunction requirePointer(value: LatestPointer | undefined, expectedProfile: string) {\n if (\n !value ||\n value.version !== VERSION ||\n value.profile !== expectedProfile ||\n !isSafeReference(value.snapshot) ||\n !/^[0-9a-f]{64}$/u.test(value.sha256) ||\n !isSafeMetadata(value.createdAt, 64) ||\n !isSafeMetadata(value.machine, 256) ||\n (value.syncSessions !== undefined && typeof value.syncSessions !== \"boolean\")\n ) {\n throw new Error(\"Remote latest pointer is malformed.\");\n }\n if (value.selection !== undefined) portableSnapshotSelection(value.selection);\n return value;\n}\n\nfunction requireHistory(value: { version: number; snapshots: LatestPointer[] } | undefined, expectedProfile: string) {\n if (!value || value.version !== VERSION || !Array.isArray(value.snapshots)) {\n throw new Error(\"Remote history is malformed.\");\n }\n const pointers = value.snapshots.map((item) => requirePointer(item, expectedProfile));\n if (new Set(pointers.map((item) => item.snapshot)).size !== pointers.length) {\n throw new Error(\"Remote history contains duplicate snapshot references.\");\n }\n return pointers;\n}\n\nfunction assertSnapshotIdentity(snapshot: Snapshot, namespace: string) {\n validatePortableSnapshot(snapshot);\n if (\n snapshot.profile !== namespace ||\n !isSafeReference(snapshot.id) ||\n !isSafeMetadata(snapshot.createdAt, 64) ||\n !isSafeMetadata(snapshot.machine, 256) ||\n !Array.isArray(snapshot.files)\n ) {\n throw new Error(\"Invalid snapshot identity for WebDAV publication.\");\n }\n}\n\nfunction validateSnapshotBundle(snapshot: Snapshot) {\n const paths = new Set<string>();\n for (const file of snapshot.files) {\n if (\n !file ||\n !isSafeSnapshotPath(file.path) ||\n paths.has(file.path) ||\n typeof file.contentBase64 !== \"string\" ||\n typeof file.sha256 !== \"string\"\n ) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n const content = Buffer.from(file.contentBase64, \"base64\");\n if (content.toString(\"base64\") !== file.contentBase64 || sha256(content) !== file.sha256) {\n throw new Error(\"Remote snapshot bundle is malformed.\");\n }\n paths.add(file.path);\n }\n}\n\nfunction isSafeSnapshotPath(value: unknown): value is string {\n if (typeof value !== \"string\" || !value || value.length > 4096 || value.includes(\"\\\\\")) {\n return false;\n }\n if (\n [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n })\n ) {\n return false;\n }\n return value.split(\"/\").every((segment) => segment && segment !== \".\" && segment !== \"..\");\n}\n\nfunction assertSafeDestination(config: ResolvedWebDavBackend) {\n const url = new URL(config.profile.url);\n if (url.username || url.password || url.search || url.hash) throw new Error(\"Invalid WebDAV URL.\");\n for (const [label, value] of [\n [\"path\", config.destination.path],\n [\"namespace\", config.destination.namespace],\n ]) {\n if (label === \"path\" && value === \"./\") continue;\n if (\n !value ||\n value.includes(\"\\\\\") ||\n [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n }) ||\n value.split(\"/\").some((part) => part === \".\" || part === \"..\")\n ) {\n throw new Error(\"Invalid WebDAV storage location.\");\n }\n }\n}\n\nfunction isSafeMetadata(value: unknown, maxLength: number): value is string {\n return (\n typeof value === \"string\" &&\n value.length > 0 &&\n value.length <= maxLength &&\n ![...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n })\n );\n}\n\nfunction requireSnapshotReference(reference: string) {\n if (!isSafeReference(reference)) throw new Error(\"Invalid WebDAV snapshot reference.\");\n}\n\nfunction isSafeReference(value: string) {\n return (\n !!value &&\n value.length <= 512 &&\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote references cannot contain terminal controls.\n !/[\\\\/\\u0000-\\u001f\\u007f-\\u009f]/u.test(value) &&\n value !== \".\" &&\n value !== \"..\"\n );\n}\n\nfunction matchesExpected(head: RemoteHead | undefined, expected: ExpectedRemoteHead) {\n return expected.kind === \"missing\" ? head === undefined : head?.revision === expected.revision;\n}\n\nfunction samePointer(left: LatestPointer, right: LatestPointer) {\n return canonicalJson(left) === canonicalJson(right);\n}\n\nfunction canonicalJson(value: unknown): string {\n if (Array.isArray(value)) return JSON.stringify(value.map((item) => JSON.parse(canonicalJson(item))));\n if (!value || typeof value !== \"object\") return JSON.stringify(value);\n return JSON.stringify(\n Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, JSON.parse(canonicalJson((value as Record<string, unknown>)[key]))]),\n ),\n );\n}\n\nfunction joinRemote(...parts: string[]) {\n return parts\n .flatMap((part) => part.split(\"/\"))\n .filter(Boolean)\n .join(\"/\");\n}\n\nfunction secretFreeUrl(value: string) {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction errorMessage(error: unknown) {\n if (error instanceof WebDavHttpError) return error.message;\n return error instanceof Error ? error.message : String(error);\n}\n", "import { XMLParser } from \"fast-xml-parser\";\nimport { ContinuousError, continuousFailure, retryAfter } from \"../../sync/continuous-errors.js\";\nimport { throwIfAborted } from \"../../sync/signals.js\";\nimport type { RemoteObject, ResolvedWebDavBackend } from \"../backend-types.js\";\n\nconst JSON_LIMIT = 1024 * 1024;\nconst ERROR_LIMIT = 64 * 1024;\nconst SNAPSHOT_LIMIT = 256 * 1024 * 1024;\nconst XML_LIMIT = 1024 * 1024;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst MAX_REDIRECTS = 3;\n\nexport interface WebDavPutOptions {\n ifAbsent?: boolean;\n ifMatch?: string;\n}\n\nexport interface WebDavEntry {\n href: string;\n etag?: string;\n collection: boolean;\n}\n\nexport class WebDavHttpError extends Error {\n constructor(\n message: string,\n readonly status: number,\n options?: ErrorOptions,\n readonly retryAfterMs?: number,\n ) {\n super(message, options);\n this.name = \"WebDavHttpError\";\n }\n}\n\nexport class WebDavPreconditionError extends WebDavHttpError {\n constructor(message = \"WebDAV precondition failed.\") {\n super(message, 412);\n this.name = \"WebDavPreconditionError\";\n }\n}\n\nexport class WebDavClient {\n private readonly baseUrl: URL;\n private readonly authorization: string;\n\n constructor(\n private readonly config: ResolvedWebDavBackend,\n private readonly signal?: AbortSignal,\n private readonly timeoutMs = REQUEST_TIMEOUT_MS,\n ) {\n this.baseUrl = new URL(config.profile.url);\n assertSafeAuthenticatedUrl(this.baseUrl);\n if (\n !config.profile.username ||\n !config.profile.password ||\n config.profile.username.includes(\":\") ||\n hasControlCharacter(config.profile.username) ||\n hasControlCharacter(config.profile.password)\n ) {\n throw new Error(\"Invalid WebDAV credentials.\");\n }\n this.authorization = `Basic ${Buffer.from(`${config.profile.username}:${config.profile.password}`).toString(\"base64\")}`;\n }\n\n async getBuffer(remotePath: string): Promise<RemoteObject<Buffer>> {\n const response = await this.request(remotePath, { method: \"GET\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return { missing: true };\n }\n await this.requireOk(response, \"read\");\n return {\n value: await readBounded(response, SNAPSHOT_LIMIT, \"WebDAV response is too large\"),\n etag: response.headers.get(\"etag\") ?? undefined,\n missing: false,\n };\n }\n\n async getJson<T>(remotePath: string): Promise<RemoteObject<T>> {\n const response = await this.request(remotePath, { method: \"GET\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return { missing: true };\n }\n await this.requireOk(response, \"read\");\n const bytes = await readBounded(response, JSON_LIMIT, \"WebDAV JSON response is too large\");\n try {\n return {\n value: JSON.parse(bytes.toString(\"utf8\")) as T,\n etag: response.headers.get(\"etag\") ?? undefined,\n missing: false,\n };\n } catch (error) {\n throw new Error(\"WebDAV JSON response is malformed.\", { cause: error });\n }\n }\n\n async putBuffer(remotePath: string, body: Buffer, contentType: string, options: WebDavPutOptions = {}) {\n const headers: Record<string, string> = { \"content-type\": contentType };\n if (options.ifAbsent) headers[\"if-none-match\"] = \"*\";\n if (options.ifMatch) headers[\"if-match\"] = options.ifMatch;\n const response = await this.request(remotePath, {\n method: \"PUT\",\n headers,\n body: body as unknown as BodyInit,\n });\n if (response.status === 412) {\n await response.body?.cancel();\n throw new WebDavPreconditionError();\n }\n await this.requireOk(response, \"write\");\n await response.body?.cancel();\n return response.headers.get(\"etag\") ?? undefined;\n }\n\n async putJson(remotePath: string, value: unknown, options: WebDavPutOptions = {}) {\n return this.putBuffer(remotePath, Buffer.from(JSON.stringify(value)), \"application/json\", options);\n }\n\n async makeCollection(remotePath: string) {\n const response = await this.request(remotePath, { method: \"MKCOL\" });\n if (response.status === 405) {\n await response.body?.cancel();\n return false;\n }\n await this.requireOk(response, \"create collection\");\n await response.body?.cancel();\n return true;\n }\n\n async ensureCollection(remotePath: string) {\n const segments = safeSegments(remotePath);\n for (let index = 1; index <= segments.length; index += 1) {\n await this.makeCollection(segments.slice(0, index).join(\"/\"));\n }\n }\n\n async listCollection(remotePath: string): Promise<WebDavEntry[]> {\n const response = await this.request(remotePath, {\n method: \"PROPFIND\",\n headers: { depth: \"1\", \"content-type\": \"application/xml; charset=utf-8\" },\n body: '<?xml version=\"1.0\"?><d:propfind xmlns:d=\"DAV:\"><d:prop><d:getetag/><d:resourcetype/></d:prop></d:propfind>',\n });\n if (response.status === 404) {\n await response.body?.cancel();\n throw new WebDavHttpError(\"WebDAV collection is missing.\", 404);\n }\n if (response.status !== 207) await this.requireOk(response, \"list collection\");\n const xml = (await readBounded(response, XML_LIMIT, \"WebDAV directory response is too large\")).toString(\"utf8\");\n try {\n const parsed = new XMLParser({\n removeNSPrefix: true,\n ignoreAttributes: false,\n processEntities: false,\n }).parse(xml) as {\n multistatus?: { response?: unknown };\n };\n if (!parsed.multistatus || parsed.multistatus.response === undefined) {\n throw new Error(\"Missing DAV multistatus response.\");\n }\n const responses = asArray(parsed.multistatus.response);\n return responses.map(parseEntry);\n } catch (error) {\n throw new Error(\"WebDAV directory response is malformed.\", { cause: error });\n }\n }\n\n async delete(remotePath: string) {\n const response = await this.request(remotePath, { method: \"DELETE\" });\n if (response.status === 404) {\n await response.body?.cancel();\n return;\n }\n if (response.status === 207) {\n await response.body?.cancel();\n throw new WebDavHttpError(\"WebDAV probe cleanup returned a partial response.\", 207);\n }\n await this.requireOk(response, \"delete probe resource\");\n await response.body?.cancel();\n }\n\n private async request(remotePath: string, init: RequestInit) {\n throwIfAborted(this.signal);\n let url = appendRemotePath(this.baseUrl, remotePath);\n for (let redirects = 0; ; redirects += 1) {\n const timeout = AbortSignal.timeout(this.timeoutMs);\n const signal = this.signal ? AbortSignal.any([this.signal, timeout]) : timeout;\n let response: Response;\n try {\n response = await fetch(url, {\n ...init,\n headers: {\n accept: \"*/*\",\n authorization: this.authorization,\n ...headersObject(init.headers),\n },\n redirect: \"manual\",\n signal,\n });\n } catch (error) {\n throwIfAborted(this.signal);\n throw new Error(\n `WebDAV ${String(init.method ?? \"GET\")} request failed for ${redactText(safeUrl(url), this.config)}.`,\n {\n cause: redactError(error, this.config),\n },\n );\n }\n if (![301, 302, 303, 307, 308].includes(response.status)) return response;\n await response.body?.cancel();\n const method = String(init.method ?? \"GET\").toUpperCase();\n if ([301, 302, 303].includes(response.status) && method !== \"GET\" && method !== \"HEAD\") {\n throw new Error(\n `WebDAV refused an ambiguous HTTP ${response.status} redirect for ${method}; configure the canonical collection URL or require HTTP 307/308.`,\n );\n }\n if (redirects >= MAX_REDIRECTS) throw new Error(\"WebDAV redirect limit exceeded.\");\n const location = response.headers.get(\"location\");\n if (!location) throw new Error(\"WebDAV redirect is missing Location.\");\n const next = new URL(location, url);\n if (next.origin !== this.baseUrl.origin) {\n throw new Error(\"WebDAV refused a cross-origin authenticated redirect.\");\n }\n url = next;\n }\n }\n\n private async requireOk(response: Response, action: string) {\n if (response.ok) return;\n const body = (await readBounded(response, ERROR_LIMIT, \"WebDAV error body is too large\"))\n .toString(\"utf8\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote error text is untrusted terminal input.\n .replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \" \")\n .trim();\n const detail = body ? `: ${redactText(body, this.config)}` : \"\";\n throw new WebDavHttpError(\n `WebDAV ${action} failed with HTTP ${response.status}${detail}`,\n response.status,\n undefined,\n retryAfter(response),\n );\n }\n}\n\nfunction assertSafeAuthenticatedUrl(url: URL) {\n const loopback =\n url.hostname === \"127.0.0.1\" || url.hostname === \"localhost\" || url.hostname === \"[::1]\" || url.hostname === \"::1\";\n if (\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback))\n ) {\n throw new Error(\n \"Invalid WebDAV URL: HTTPS is required and embedded credentials, query, or fragment are not allowed.\",\n );\n }\n}\n\nfunction hasControlCharacter(value: string) {\n return [...value].some((character) => {\n const code = character.codePointAt(0) ?? 0;\n return code < 0x20 || (code >= 0x7f && code <= 0x9f);\n });\n}\n\nfunction appendRemotePath(base: URL, remotePath: string) {\n const url = new URL(base);\n const suffix = safeSegments(remotePath).map(encodeURIComponent).join(\"/\");\n url.pathname = `${base.pathname.replace(/\\/+$/u, \"\")}/${suffix}`;\n return url;\n}\n\nfunction safeSegments(value: string) {\n const segments = value\n .replace(/^\\/+|\\/+$/gu, \"\")\n .split(\"/\")\n .filter(Boolean);\n if (\n segments.some(\n (segment) =>\n segment === \".\" ||\n segment === \"..\" ||\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Remote path segments cannot contain controls.\n /[\\u0000-\\u001f]/u.test(segment),\n )\n ) {\n throw new Error(\"Invalid WebDAV remote path.\");\n }\n return segments;\n}\n\nasync function readBounded(response: Response, limit: number, message: string) {\n const length = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(length) && length > limit) {\n await response.body?.cancel();\n throw new Error(message);\n }\n if (!response.body) return Buffer.alloc(0);\n const reader = response.body.getReader();\n const chunks: Buffer[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > limit) throw new Error(message);\n chunks.push(Buffer.from(value));\n }\n } catch (error) {\n await reader.cancel().catch(() => undefined);\n throw error;\n }\n return Buffer.concat(chunks, total);\n}\n\nfunction parseEntry(value: unknown): WebDavEntry {\n if (!value || typeof value !== \"object\") throw new Error(\"Invalid WebDAV response entry.\");\n const record = value as Record<string, unknown>;\n const href = typeof record.href === \"string\" ? record.href : undefined;\n if (!href) throw new Error(\"Invalid WebDAV response href.\");\n const propstat = asArray(record.propstat).find((item) => {\n if (!item || typeof item !== \"object\") return false;\n return String((item as Record<string, unknown>).status ?? \"\").includes(\" 200 \");\n }) as Record<string, unknown> | undefined;\n const prop = propstat?.prop as Record<string, unknown> | undefined;\n return {\n href,\n etag: typeof prop?.getetag === \"string\" ? prop.getetag : undefined,\n collection:\n !!prop?.resourcetype && typeof prop.resourcetype === \"object\" && Object.hasOwn(prop.resourcetype, \"collection\"),\n };\n}\n\nfunction asArray(value: unknown): unknown[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\nfunction headersObject(headers: HeadersInit | undefined) {\n return Object.fromEntries(new Headers(headers).entries());\n}\n\nfunction safeUrl(url: URL) {\n return `${url.protocol}//${url.host}${url.pathname}`;\n}\n\nfunction redactError(error: unknown, config: ResolvedWebDavBackend) {\n const message = error instanceof Error ? error.message : String(error);\n const failure = continuousFailure(error);\n return new ContinuousError(failure.kind, redactText(message, config), failure.delay);\n}\n\nfunction redactText(value: string, config: ResolvedWebDavBackend) {\n let result = value;\n for (const secret of [config.profile.username, config.profile.password, config.profile.url]) {\n if (!secret) continue;\n for (const variant of new Set([secret, encodeURIComponent(secret)])) {\n result = result.replace(new RegExp(escapeRegExp(variant), \"giu\"), \"[redacted]\");\n }\n }\n return result.replace(/basic\\s+[a-z0-9+/=]+/giu, \"Basic [redacted]\").replace(/\\?[^\\s]*/gu, \"?[redacted]\");\n}\n\nfunction escapeRegExp(value: string) {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/gu, \"\\\\$&\");\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/index.ts CHANGED
@@ -1,25 +1,19 @@
1
1
  // @generated by scripts/build-runtime.mjs; do not edit.
2
2
  // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
3
  import {
4
- createSyncAttentionController,
5
- observationMatchesConfig,
6
- syncAttentionMatchesConfig
7
- } from "./chunks/chunk-AAZDBIBJ.ts";
4
+ withAgentSyncLock
5
+ } from "./chunks/chunk-S2FMH5FT.ts";
8
6
  import {
9
7
  recoverSnapshotTransactionsOnStartup
10
- } from "./chunks/chunk-KGE47GCZ.ts";
11
- import {
12
- captureMutationOwner,
13
- unlock,
14
- withLock
15
- } from "./chunks/chunk-GC3QOL6J.ts";
8
+ } from "./chunks/chunk-CRKTAPSL.ts";
16
9
  import {
17
- createStartupTimings
18
- } from "./chunks/chunk-UZPMDLTL.ts";
10
+ createSyncAttentionController,
11
+ observationMatchesConfig,
12
+ syncAttentionMatchesConfig
13
+ } from "./chunks/chunk-GSNPASKB.ts";
19
14
  import {
20
- combineSignals,
21
- throwIfAborted
22
- } from "./chunks/chunk-PWMWOJP4.ts";
15
+ captureMutationOwner
16
+ } from "./chunks/chunk-UOHR7LRO.ts";
23
17
  import {
24
18
  automaticSyncSummary
25
19
  } from "./chunks/chunk-ECYCNZOE.ts";
@@ -36,21 +30,23 @@ import {
36
30
  startupTransferSummary,
37
31
  usage,
38
32
  validateCommandOptions
39
- } from "./chunks/chunk-ITFR6NNQ.ts";
33
+ } from "./chunks/chunk-NLWS55B6.ts";
40
34
  import {
41
35
  safeTerminalText
42
36
  } from "./chunks/chunk-AMJRUXFT.ts";
43
- import "./chunks/chunk-76NB4R7U.ts";
44
37
  import {
45
- ensureStateDir,
46
- readStateForConfig,
47
- syncStateFingerprint
48
- } from "./chunks/chunk-VCL7TZYW.ts";
38
+ createStartupTimings
39
+ } from "./chunks/chunk-UZPMDLTL.ts";
40
+ import "./chunks/chunk-UBV24CG4.ts";
49
41
  import {
50
- migrateLegacyStateDirectory,
51
- stateDirectoryMigrationNotice,
52
- withStateDirectoryAccess
53
- } from "./chunks/chunk-BVVP33U5.ts";
42
+ syncErrorGuidance
43
+ } from "./chunks/chunk-G4RUXRWZ.ts";
44
+ import {
45
+ SetupPullRequiresUiError,
46
+ errorMessage,
47
+ isSyncDecisionRequiredError
48
+ } from "./chunks/chunk-7D5SF7P3.ts";
49
+ import "./chunks/chunk-QGK445K7.ts";
54
50
  import {
55
51
  activeLocalConfigPath,
56
52
  consumeLocalConfigMigrationNotice,
@@ -64,26 +60,41 @@ import {
64
60
  sessionTokenWarnings,
65
61
  syncCheckConfigFingerprint,
66
62
  syncSessionsWarnings
67
- } from "./chunks/chunk-KATKRR3D.ts";
68
- import "./chunks/chunk-2JZFHNLM.ts";
69
- import "./chunks/chunk-T2SJD3N7.ts";
70
- import "./chunks/chunk-ZX2Q6THB.ts";
63
+ } from "./chunks/chunk-QO333NM4.ts";
64
+ import "./chunks/chunk-A6HU4ERM.ts";
71
65
  import {
72
- syncErrorGuidance
73
- } from "./chunks/chunk-G4RUXRWZ.ts";
66
+ unlock,
67
+ withLock
68
+ } from "./chunks/chunk-AAEEHR7H.ts";
74
69
  import {
75
- SetupPullRequiresUiError,
76
- errorMessage,
77
- isSyncDecisionRequiredError
78
- } from "./chunks/chunk-7D5SF7P3.ts";
79
- import "./chunks/chunk-A6HU4ERM.ts";
70
+ combineSignals,
71
+ throwIfAborted
72
+ } from "./chunks/chunk-PWMWOJP4.ts";
73
+ import "./chunks/chunk-DT7M4VQS.ts";
74
+ import "./chunks/chunk-YDVQYUHE.ts";
80
75
  import {
81
76
  RemoteSelectionMismatchError,
82
77
  formatRemoteSelectionMismatch,
83
78
  sessionDirFromContext,
84
79
  snapshotOptionsForContext
85
80
  } from "./chunks/chunk-QOFMXPM5.ts";
81
+ import "./chunks/chunk-76NB4R7U.ts";
86
82
  import "./chunks/chunk-ZW5ZLGBI.ts";
83
+ import {
84
+ startupTransferEnabled
85
+ } from "./chunks/chunk-PRUEIIK7.ts";
86
+ import {
87
+ ensureStateDir,
88
+ readStateForConfig,
89
+ syncStateFingerprint
90
+ } from "./chunks/chunk-UPNVIUBN.ts";
91
+ import {
92
+ migrateLegacyStateDirectory,
93
+ stateDirectoryMigrationNotice,
94
+ withStateDirectoryAccess
95
+ } from "./chunks/chunk-SWRVXVFD.ts";
96
+ import "./chunks/chunk-2JZFHNLM.ts";
97
+ import "./chunks/chunk-T2SJD3N7.ts";
87
98
  import "./chunks/chunk-HUZ5CR4W.ts";
88
99
 
89
100
  // src/ui/operation-dialogs.ts
@@ -133,7 +144,7 @@ async function executeRecoveryCommand(rawArgs, ctx, signal, loaders, onCommit, s
133
144
  const outcome = await withLock("pull", () => operations.pull(ctx, options));
134
145
  return { kind: "completed", ...outcome ? { outcome } : {} };
135
146
  }
136
- await withLock("sync", () => operations.syncBoth(ctx, options));
147
+ await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));
137
148
  return { kind: "completed" };
138
149
  } catch (error) {
139
150
  if (signal?.aborted) return { kind: "failed" };
@@ -186,7 +197,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
186
197
  await showConfig(ctx, options);
187
198
  return { kind: "completed" };
188
199
  case "files": {
189
- const { showFileSelection } = await import("./chunks/file-selection-UNHBVVON.ts");
200
+ const { showFileSelection } = await import("./chunks/file-selection-3JJYOVNR.ts");
190
201
  throwIfAborted(options.signal);
191
202
  await showFileSelection(ctx, options.setup, options.signal);
192
203
  return { kind: "completed" };
@@ -204,7 +215,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
204
215
  return { kind: "completed" };
205
216
  }
206
217
  case "conflicts": {
207
- const { showConflicts } = await import("./chunks/conflict-review-ZOTOHL2E.ts");
218
+ const { showConflicts } = await import("./chunks/conflict-review-6WIEQLXW.ts");
208
219
  throwIfAborted(options.signal);
209
220
  await withLock("sync", () => showConflicts(ctx, options));
210
221
  return { kind: "completed" };
@@ -230,7 +241,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
230
241
  case "sync": {
231
242
  const operations = await loaders.operations();
232
243
  throwIfAborted(options.signal);
233
- await withLock("sync", () => operations.syncBoth(ctx, options));
244
+ await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));
234
245
  return { kind: "completed" };
235
246
  }
236
247
  case "history": {
@@ -301,7 +312,7 @@ async function initConfig(ctx, signal) {
301
312
  return;
302
313
  }
303
314
  if (ctx.mode === "tui") {
304
- const { showSetupWizard } = await import("./chunks/setup-wizard-VW7F3JN4.ts");
315
+ const { showSetupWizard } = await import("./chunks/setup-wizard-65DROCIJ.ts");
305
316
  throwIfAborted(signal);
306
317
  await showSetupWizard(ctx, signal);
307
318
  return;
@@ -327,6 +338,8 @@ async function showConfig(ctx, options) {
327
338
  `settings field merge: ${config.mergeSettings ? "On (experimental)" : "Off"}`,
328
339
  `machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(", ") || "none"}`,
329
340
  `startup transfer: ${startupTransferSummary(config)}`,
341
+ `agent mode: ${config.agentMode ? "On (experimental)" : "Off"}`,
342
+ `continuous sync: ${config.continuous ? config.agentMode ? "On (experimental)" : "paused; Agent mode is Off" : "Off"}`,
330
343
  `included content: ${config.include.join(", ") || "none"}`,
331
344
  `sessions: ${config.include.includes("sessions") ? "included" : "not included"}`,
332
345
  `settings file: ${localConfigPath()}`,
@@ -391,21 +404,32 @@ function displayWebDavUrl(value, username) {
391
404
  }
392
405
 
393
406
  // src/commands/command-handler.ts
394
- async function handleCommand(rawArgs, ctx, sessionSignal, loaders, attention) {
407
+ async function handleCommand(rawArgs, ctx, sessionSignal, loaders, attention, onExplicitSync) {
395
408
  await reconcileObservation(attention, sessionSignal);
396
409
  if (sessionSignal.aborted) return;
397
- const run = (route, signal, onCommit, target, onDialog) => executeCommand(
398
- route,
399
- ctx,
400
- combineSignals(sessionSignal, signal),
401
- loaders,
402
- observationCommitCallback(attention, sessionSignal, onCommit),
403
- target,
404
- onDialog
405
- );
410
+ const run = (route, signal, onCommit, target, onDialog) => {
411
+ const [command, ...args] = splitArgs(route);
412
+ if (command === "sync") {
413
+ try {
414
+ const options = parseOptions(args);
415
+ validateCommandOptions("sync", options);
416
+ onExplicitSync?.(target ?? options.setup);
417
+ } catch {
418
+ }
419
+ }
420
+ return executeCommand(
421
+ route,
422
+ ctx,
423
+ combineSignals(sessionSignal, signal),
424
+ loaders,
425
+ observationCommitCallback(attention, sessionSignal, onCommit),
426
+ target,
427
+ onDialog
428
+ );
429
+ };
406
430
  if (!rawArgs.trim()) {
407
431
  try {
408
- const { showSyncManager } = await import("./chunks/manager-ui-ZIN4BUSF.ts");
432
+ const { showSyncManager } = await import("./chunks/manager-ui-KRAW3NE2.ts");
409
433
  if (sessionSignal.aborted) return;
410
434
  await showSyncManager(ctx, run, sessionSignal, {
411
435
  getAttention: () => attention.current(),
@@ -505,7 +529,7 @@ function directSelectionOrigin(rawArgs) {
505
529
  async function resolveSelectionAttention(ctx, attention, signal, loaders, options = {}) {
506
530
  const current = attention.current();
507
531
  if (!current || signal.aborted) return;
508
- const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-HVRTPEVK.ts");
532
+ const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-AGBBVDDS.ts");
509
533
  if (signal.aborted || attention.current() !== current) return;
510
534
  await dispatchManagerResult(
511
535
  ctx,
@@ -588,7 +612,7 @@ async function startSession(ctx, signal) {
588
612
  throwIfAborted(signal);
589
613
  configureSyncStatus(ctx, config.showStatus);
590
614
  outcome = "completed";
591
- return config.automatic || config.automaticTransfer ? config : void 0;
615
+ return config.automatic || startupTransferEnabled(config) ? config : void 0;
592
616
  } catch (error) {
593
617
  throwIfAborted(signal);
594
618
  if (!isMissingConfigError(error)) {
@@ -654,7 +678,7 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
654
678
  },
655
679
  start(ctx, sessionSignal, initialConfig) {
656
680
  if (!ctx.hasUI || sessionSignal.aborted) return;
657
- if (initialConfig?.automaticTransfer && !ctx.isIdle()) {
681
+ if (initialConfig && startupTransferEnabled(initialConfig) && !ctx.isIdle()) {
658
682
  pending = { ctx, signal: sessionSignal, config: initialConfig };
659
683
  return;
660
684
  }
@@ -666,7 +690,7 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
666
690
  controller,
667
691
  owner: ctx.sessionManager,
668
692
  promise: Promise.resolve(),
669
- transfer: Boolean(initialConfig?.automaticTransfer)
693
+ transfer: Boolean(initialConfig && startupTransferEnabled(initialConfig))
670
694
  };
671
695
  active = task;
672
696
  const isCurrent = () => !sessionSignal.aborted && active === task && task.owner === ctx.sessionManager;
@@ -681,9 +705,9 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
681
705
  try {
682
706
  throwIfAborted(signal);
683
707
  config = initialConfig ?? await loadConfigForCheck();
684
- task.transfer = Boolean(config.automaticTransfer);
708
+ task.transfer = startupTransferEnabled(config);
685
709
  throwIfAborted(signal);
686
- if (!config.automatic && !config.automaticTransfer) return;
710
+ if (!config.automatic && !startupTransferEnabled(config)) return;
687
711
  const captured = config;
688
712
  const identity = syncCheckConfigFingerprint(captured);
689
713
  checking = true;
@@ -715,9 +739,9 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
715
739
  configIdentity: identity,
716
740
  checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
717
741
  inspection,
718
- automaticTransfer: captured.automaticTransfer
742
+ automaticTransfer: startupTransferEnabled(captured)
719
743
  });
720
- if (captured.automaticTransfer && !inspection.firstSync && inspection.head && inspection.selectionState?.kind === "same") {
744
+ if (startupTransferEnabled(captured) && !inspection.firstSync && inspection.head && inspection.selectionState?.kind === "same") {
721
745
  const operations = await timings.measure("operations import", () => loaders.operations());
722
746
  throwIfAborted(signal);
723
747
  if (!isCurrent()) return;
@@ -728,9 +752,9 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
728
752
  await timings.measure(
729
753
  "automatic transfer",
730
754
  () => withStateDirectoryAccess(
731
- () => withLock(
732
- "startup-transfer",
733
- () => operations.syncBoth(ctx, {
755
+ () => withAgentSyncLock(
756
+ ctx,
757
+ {
734
758
  args: [],
735
759
  yes: true,
736
760
  force: false,
@@ -741,7 +765,8 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
741
765
  signal,
742
766
  startupTimings: timings,
743
767
  onCommit: () => attention.clearObservation()
744
- })
768
+ },
769
+ (options) => operations.syncBoth(ctx, options)
745
770
  )
746
771
  )
747
772
  );
@@ -755,7 +780,7 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
755
780
  configIdentity: identity,
756
781
  checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
757
782
  inspection,
758
- automaticTransfer: captured.automaticTransfer
783
+ automaticTransfer: startupTransferEnabled(captured)
759
784
  });
760
785
  if (ctx.mode === "rpc") attention.notifyObservation(ctx);
761
786
  } catch (error) {
@@ -768,7 +793,7 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
768
793
  if (!latest || syncCheckConfigFingerprint(latest) !== syncCheckConfigFingerprint(config)) return;
769
794
  }
770
795
  ctx.ui.notify(
771
- config?.automaticTransfer ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.` : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,
796
+ config && startupTransferEnabled(config) ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.` : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,
772
797
  "warning"
773
798
  );
774
799
  } finally {
@@ -815,11 +840,11 @@ function createStartupCheck(loaders, attention, timeoutMs = 3e4) {
815
840
  // src/sync/sync-loaders.ts
816
841
  function createSyncLoaders(dependencies) {
817
842
  const loaders = {
818
- inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import("./chunks/sync-inspection-3EMS2J5B.ts"))),
819
- setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-ZMW5C4M7.ts"))),
843
+ inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import("./chunks/sync-inspection-XFJOAMJD.ts"))),
844
+ setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-E7PHKI6J.ts"))),
820
845
  snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import("./chunks/snapshot-THS5EY2L.ts"))),
821
846
  syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./chunks/sync-state-CFL4RRRB.ts"))),
822
- operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-2CWST333.ts")))
847
+ operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-HDUDT5PD.ts")))
823
848
  };
824
849
  return loaders;
825
850
  }
@@ -844,6 +869,30 @@ function sync(pi, dependencies = {}) {
844
869
  let sessionAbort = new AbortController();
845
870
  let shutdownAbort;
846
871
  let initialization = Promise.resolve(void 0);
872
+ let continuous;
873
+ let owner;
874
+ let continuousPossible = false;
875
+ const foreground = /* @__PURE__ */ new Map();
876
+ async function resumeContinuous(ctx, signal, retry) {
877
+ const isCurrent = () => !signal.aborted && !foreground.has(ctx.sessionManager) && owner === ctx.sessionManager;
878
+ if (!isCurrent() || !ctx.hasUI) return;
879
+ try {
880
+ const { loadConfigForCheck: loadConfigForCheck2 } = await import("./chunks/config-KGIYTTXQ.ts");
881
+ if (!isCurrent()) return;
882
+ const config = await loadConfigForCheck2();
883
+ if (!isCurrent()) return;
884
+ continuousPossible = Boolean(config.continuous && config.agentMode);
885
+ if (!continuousPossible) {
886
+ await continuous?.stop(ctx.sessionManager);
887
+ return;
888
+ }
889
+ const { createContinuousSync } = await import("./chunks/continuous-sync-AWAAOXK2.ts");
890
+ if (!isCurrent()) return;
891
+ continuous ??= createContinuousSync(loaders);
892
+ continuous.start(ctx, signal, Boolean(retry && (retry.setup === void 0 || retry.setup === config.setupName)));
893
+ } catch {
894
+ }
895
+ }
847
896
  pi.registerCommand("sync", {
848
897
  description: "Sync Pi settings through Git, WebDAV, R2, or S3-compatible storage",
849
898
  getArgumentCompletions: completeSyncArguments,
@@ -852,21 +901,37 @@ function sync(pi, dependencies = {}) {
852
901
  throw new Error("/sync requires TUI or RPC mode so results and safety prompts are observable.");
853
902
  }
854
903
  const signal = sessionAbort.signal;
855
- const ready = await initialization;
856
- if (signal.aborted) return;
857
- await check.stop();
858
- if (signal.aborted) return;
904
+ const manager = ctx.sessionManager;
859
905
  const command = splitArgs(args)[0];
860
- if (ready === false && command !== "help" && command !== "unlock" && command !== "migrate-state") {
861
- ctx.ui.notify(
862
- "pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.",
863
- "error"
864
- );
865
- return;
906
+ let retry;
907
+ let mayResume = false;
908
+ foreground.set(manager, (foreground.get(manager) ?? 0) + 1);
909
+ try {
910
+ const ready = await initialization;
911
+ mayResume = ready !== false;
912
+ if (signal.aborted) return;
913
+ await continuous?.stop(manager);
914
+ if (signal.aborted) return;
915
+ await check.stop();
916
+ if (signal.aborted) return;
917
+ if (ready === false && command !== "help" && command !== "unlock" && command !== "migrate-state") {
918
+ ctx.ui.notify(
919
+ "pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.",
920
+ "error"
921
+ );
922
+ return;
923
+ }
924
+ const run = () => handleCommand(args, ctx, signal, loaders, attention, (setup) => {
925
+ retry = { setup };
926
+ });
927
+ if (command === "migrate-state" || command === "help") await run();
928
+ else await withStateDirectoryAccess(run);
929
+ } finally {
930
+ const count = (foreground.get(manager) ?? 1) - 1;
931
+ if (count) foreground.set(manager, count);
932
+ else foreground.delete(manager);
933
+ if (mayResume) await resumeContinuous(ctx, signal, retry);
866
934
  }
867
- const run = () => handleCommand(args, ctx, signal, loaders, attention);
868
- if (command === "migrate-state" || command === "help") await run();
869
- else await withStateDirectoryAccess(run);
870
935
  }
871
936
  });
872
937
  pi.on("session_start", async (_event, ctx) => {
@@ -875,11 +940,15 @@ function sync(pi, dependencies = {}) {
875
940
  sessionAbort.abort(new DOMException("Session replaced", "AbortError"));
876
941
  sessionAbort = new AbortController();
877
942
  const signal = sessionAbort.signal;
943
+ owner = ctx.sessionManager;
944
+ continuousPossible = false;
878
945
  attention.reset(ctx);
879
946
  const previous = initialization;
880
947
  initialization = (async () => {
881
948
  await previous;
882
949
  if (signal.aborted) return false;
950
+ await continuous?.stop();
951
+ if (signal.aborted) return false;
883
952
  await check.stop();
884
953
  if (signal.aborted) return false;
885
954
  try {
@@ -893,15 +962,24 @@ function sync(pi, dependencies = {}) {
893
962
  }
894
963
  })();
895
964
  const ready = await initialization;
896
- if (ready && !signal.aborted) check.start(ctx, signal, ready);
965
+ if (ready && !signal.aborted) {
966
+ if (ready.continuous && ready.agentMode) await resumeContinuous(ctx, signal);
967
+ else check.start(ctx, signal, ready);
968
+ }
897
969
  });
898
970
  pi.on("agent_start", async (_event, ctx) => {
971
+ await continuous?.stop(ctx.sessionManager);
899
972
  await check.interrupt(ctx);
900
973
  });
901
- pi.on("agent_settled", (_event, ctx) => {
902
- if (!sessionAbort.signal.aborted) check.settled(ctx);
974
+ pi.on("agent_settled", async (_event, ctx) => {
975
+ const signal = sessionAbort.signal;
976
+ if (!signal.aborted) {
977
+ check.settled(ctx);
978
+ if (continuousPossible) await resumeContinuous(ctx, signal);
979
+ }
903
980
  });
904
981
  pi.on("session_shutdown", async (event, ctx) => {
982
+ if (continuous && owner && owner !== ctx.sessionManager) return;
905
983
  sessionAbort.abort(new DOMException("Session shut down", "AbortError"));
906
984
  attention.reset(ctx);
907
985
  shutdownAbort?.abort(new DOMException("Session shut down again", "AbortError"));
@@ -912,6 +990,8 @@ function sync(pi, dependencies = {}) {
912
990
  try {
913
991
  const ready = await initialization;
914
992
  if (signal.aborted) return;
993
+ await continuous?.stop(ctx.sessionManager);
994
+ if (signal.aborted) return;
915
995
  await check.stop();
916
996
  if (signal.aborted) return;
917
997
  if (ready !== false && reason !== "reload") {