@narumitw/pi-sync 0.49.15 → 0.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +49 -16
  2. package/dist/chunks/attention-widget-Z7G3SYYJ.ts +9 -0
  3. package/dist/chunks/attention-widget-Z7G3SYYJ.ts.map +7 -0
  4. package/dist/chunks/chunk-2B2ELUF5.ts +29 -0
  5. package/dist/chunks/chunk-2B2ELUF5.ts.map +7 -0
  6. package/dist/chunks/{chunk-ARN2672F.ts → chunk-4CHTZMEO.ts} +23 -55
  7. package/dist/chunks/chunk-4CHTZMEO.ts.map +7 -0
  8. package/dist/chunks/chunk-6LP3MCR2.ts +115 -0
  9. package/dist/chunks/chunk-6LP3MCR2.ts.map +7 -0
  10. package/dist/chunks/{chunk-JF6MZCT4.ts → chunk-AUSDLD6F.ts} +4 -4
  11. package/dist/chunks/chunk-AUSDLD6F.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-CCSN3F47.ts +51 -0
  15. package/dist/chunks/chunk-CCSN3F47.ts.map +7 -0
  16. package/dist/chunks/{chunk-4U6AFLJB.ts → chunk-CHH26D4F.ts} +3 -2
  17. package/dist/chunks/chunk-CHH26D4F.ts.map +7 -0
  18. package/dist/chunks/chunk-CPEHGXJV.ts +50 -0
  19. package/dist/chunks/chunk-CPEHGXJV.ts.map +7 -0
  20. package/dist/chunks/{chunk-5MQ76BK5.ts → chunk-D5X27LCA.ts} +2 -2
  21. package/dist/chunks/chunk-D5X27LCA.ts.map +7 -0
  22. package/dist/chunks/{chunk-WSOBYHIZ.ts → chunk-ETTRJDNP.ts} +4 -4
  23. package/dist/chunks/chunk-ETTRJDNP.ts.map +7 -0
  24. package/dist/chunks/{chunk-44LPGQTI.ts → chunk-G4RNQQZS.ts} +9 -7
  25. package/dist/chunks/chunk-G4RNQQZS.ts.map +7 -0
  26. package/dist/chunks/{chunk-5LZALPCD.ts → chunk-HUDQATCL.ts} +25 -25
  27. package/dist/chunks/chunk-HUDQATCL.ts.map +7 -0
  28. package/dist/chunks/{chunk-X7SQ2EQM.ts → chunk-IJ6FJFA5.ts} +9 -9
  29. package/dist/chunks/chunk-IJ6FJFA5.ts.map +7 -0
  30. package/dist/chunks/{chunk-YQ6UW7IF.ts → chunk-JAAKLL6M.ts} +2 -2
  31. package/dist/chunks/chunk-JAAKLL6M.ts.map +7 -0
  32. package/dist/chunks/chunk-KW7YQEZN.ts +1255 -0
  33. package/dist/chunks/chunk-KW7YQEZN.ts.map +7 -0
  34. package/dist/chunks/{chunk-DFXBKHGN.ts → chunk-LCRI3ABW.ts} +21 -8
  35. package/dist/chunks/chunk-LCRI3ABW.ts.map +7 -0
  36. package/dist/chunks/chunk-LTBWGSBV.ts +12 -0
  37. package/dist/chunks/chunk-LTBWGSBV.ts.map +7 -0
  38. package/dist/chunks/chunk-NJFUIVYL.ts +17 -0
  39. package/dist/chunks/chunk-NJFUIVYL.ts.map +7 -0
  40. package/dist/chunks/{chunk-HVUSHMVL.ts → chunk-OEX4ABY6.ts} +39 -37
  41. package/dist/chunks/chunk-OEX4ABY6.ts.map +7 -0
  42. package/dist/chunks/{chunk-HGV24P4T.ts → chunk-Q2TUM5X6.ts} +3 -3
  43. package/dist/chunks/chunk-Q2TUM5X6.ts.map +7 -0
  44. package/dist/chunks/chunk-S7YBZR42.ts +146 -0
  45. package/dist/chunks/chunk-S7YBZR42.ts.map +7 -0
  46. package/dist/chunks/{chunk-GLQLN5GV.ts → chunk-SL64RLXR.ts} +8 -6
  47. package/dist/chunks/chunk-SL64RLXR.ts.map +7 -0
  48. package/dist/chunks/chunk-SZWBGPID.ts +57 -0
  49. package/dist/chunks/chunk-SZWBGPID.ts.map +7 -0
  50. package/dist/chunks/chunk-T2B5IU74.ts +25 -0
  51. package/dist/chunks/chunk-T2B5IU74.ts.map +7 -0
  52. package/dist/chunks/chunk-T3HH3UEJ.ts +96 -0
  53. package/dist/chunks/chunk-T3HH3UEJ.ts.map +7 -0
  54. package/dist/chunks/chunk-TEN2ZBJV.ts +101 -0
  55. package/dist/chunks/chunk-TEN2ZBJV.ts.map +7 -0
  56. package/dist/chunks/chunk-THMF4BVL.ts +18 -0
  57. package/dist/chunks/chunk-THMF4BVL.ts.map +7 -0
  58. package/dist/chunks/chunk-Z4DQF6L3.ts +12 -0
  59. package/dist/chunks/chunk-Z4DQF6L3.ts.map +7 -0
  60. package/dist/chunks/{chunk-F5QL2GPY.ts → chunk-ZI5MXMEX.ts} +5 -99
  61. package/dist/chunks/chunk-ZI5MXMEX.ts.map +7 -0
  62. package/dist/chunks/{file-selection-RKEHALNQ.ts → file-selection-FTTKAOYX.ts} +10 -7
  63. package/dist/chunks/file-selection-FTTKAOYX.ts.map +7 -0
  64. package/dist/chunks/{git-backend-E3UOUUOM.ts → git-backend-GMVS4PD4.ts} +39 -14
  65. package/dist/chunks/git-backend-GMVS4PD4.ts.map +7 -0
  66. package/dist/chunks/manager-result-dispatcher-FKIBM3GO.ts +22 -0
  67. package/dist/chunks/manager-ui-R3XPUFFS.ts +1680 -0
  68. package/dist/chunks/manager-ui-R3XPUFFS.ts.map +7 -0
  69. package/dist/chunks/remote-selection-ui-D7RBRJNL.ts +21 -0
  70. package/dist/chunks/{s3-backend-552LXHE4.ts → s3-backend-66O4FGBH.ts} +94 -16
  71. package/dist/chunks/s3-backend-66O4FGBH.ts.map +7 -0
  72. package/dist/chunks/{setup-switch-5YDG5YGJ.ts → setup-switch-IS2PEZ3J.ts} +9 -9
  73. package/dist/chunks/setup-wizard-IUB6ESEU.ts +89 -0
  74. package/dist/chunks/setup-wizard-IUB6ESEU.ts.map +7 -0
  75. package/dist/chunks/{snapshot-2RYBUDRA.ts → snapshot-HKEWCVK6.ts} +7 -6
  76. package/dist/chunks/sync-inspection-CST2KL65.ts +20 -0
  77. package/dist/chunks/{sync-operations-3LLIHWZO.ts → sync-operations-LBX3GKCM.ts} +369 -289
  78. package/dist/chunks/sync-operations-LBX3GKCM.ts.map +7 -0
  79. package/dist/chunks/{sync-state-SRN6YRBK.ts → sync-state-Q2FTXTW6.ts} +6 -6
  80. package/dist/chunks/sync-state-Q2FTXTW6.ts.map +7 -0
  81. package/dist/chunks/{webdav-backend-ZD5RHRIU.ts → webdav-backend-ECIKD7SO.ts} +26 -13
  82. package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +7 -0
  83. package/dist/index.ts +476 -341
  84. package/dist/index.ts.map +4 -4
  85. package/docs/settings.md +30 -6
  86. package/package.json +1 -1
  87. package/src/{backend-factory.ts → backends/backend-factory.ts} +4 -4
  88. package/src/backends/backend-identity.ts +40 -0
  89. package/src/backends/backend-types.ts +81 -0
  90. package/src/{git-backend.ts → backends/git/git-backend.ts} +43 -19
  91. package/src/{git-config.ts → backends/git/git-config.ts} +1 -0
  92. package/src/{git-storage.ts → backends/git/git-storage.ts} +2 -2
  93. package/src/{s3-backend.ts → backends/s3/s3-backend.ts} +45 -9
  94. package/src/{s3-client.ts → backends/s3/s3-client.ts} +56 -8
  95. package/src/{sync-backend.ts → backends/sync-backend.ts} +1 -1
  96. package/src/{webdav-backend.ts → backends/webdav/webdav-backend.ts} +22 -10
  97. package/src/{webdav-client.ts → backends/webdav/webdav-client.ts} +1 -1
  98. package/src/{webdav-config.ts → backends/webdav/webdav-config.ts} +1 -0
  99. package/src/commands/command-execution.ts +330 -0
  100. package/src/commands/command-handler.ts +201 -0
  101. package/src/commands/command-types.ts +18 -0
  102. package/src/{command.ts → commands/command.ts} +2 -1
  103. package/src/commands/setup-completions.ts +6 -0
  104. package/src/settings/config.ts +238 -0
  105. package/src/{settings-management.ts → settings/settings-management.ts} +39 -14
  106. package/src/settings/settings-store.ts +109 -0
  107. package/src/settings/settings-types.ts +128 -0
  108. package/src/settings/settings-validation.ts +443 -0
  109. package/src/snapshot/session-paths.ts +84 -0
  110. package/src/{snapshot-apply.ts → snapshot/snapshot-apply.ts} +3 -3
  111. package/src/{snapshot-codec.ts → snapshot/snapshot-codec.ts} +2 -2
  112. package/src/{snapshot-transaction.ts → snapshot/snapshot-transaction.ts} +5 -4
  113. package/src/snapshot/snapshot-types.ts +38 -0
  114. package/src/{snapshot.ts → snapshot/snapshot.ts} +39 -20
  115. package/src/state/json-file.ts +20 -0
  116. package/src/{lock.ts → state/lock.ts} +3 -2
  117. package/src/{operation-availability.ts → state/operation-availability.ts} +2 -2
  118. package/src/state/state-types.ts +20 -0
  119. package/src/state/sync-state-store.ts +62 -0
  120. package/src/sync/automatic-sync.ts +103 -0
  121. package/src/{remote-snapshot.ts → sync/remote-snapshot.ts} +27 -4
  122. package/src/{setup-switch.ts → sync/setup-switch.ts} +6 -7
  123. package/src/sync/signals.ts +10 -0
  124. package/src/sync/startup-check.ts +128 -0
  125. package/src/{sync-decision.ts → sync/sync-decision.ts} +6 -3
  126. package/src/sync/sync-error-guidance.ts +53 -0
  127. package/src/sync/sync-inspection.ts +51 -0
  128. package/src/sync/sync-loaders.ts +54 -0
  129. package/src/{sync-operations.ts → sync/sync-mutations.ts} +34 -325
  130. package/src/sync/sync-operations.ts +12 -0
  131. package/src/{sync-policy.ts → sync/sync-policy.ts} +2 -2
  132. package/src/sync/sync-queries.ts +235 -0
  133. package/src/{sync-state.ts → sync/sync-state.ts} +5 -4
  134. package/src/sync-extension.ts +64 -708
  135. package/src/sync.ts +8 -8
  136. package/src/types.ts +47 -286
  137. package/src/ui/attention-widget.ts +1 -0
  138. package/src/ui/automatic-sync-summary.ts +6 -0
  139. package/src/{cancellable-operation.ts → ui/cancellable-operation.ts} +4 -4
  140. package/src/{file-selection.ts → ui/file-selection.ts} +5 -3
  141. package/src/{manager-attention.ts → ui/manager-attention.ts} +5 -1
  142. package/src/{manager-recovery.ts → ui/manager-recovery.ts} +6 -2
  143. package/src/{manager-state.ts → ui/manager-state.ts} +35 -14
  144. package/src/ui/manager-ui.ts +386 -0
  145. package/src/{remote-selection-ui.ts → ui/remote-selection-ui.ts} +21 -13
  146. package/src/{secret-input.ts → ui/secret-input.ts} +22 -4
  147. package/src/{settings-ui.ts → ui/settings-ui.ts} +17 -13
  148. package/src/ui/setup/git-ui.ts +293 -0
  149. package/src/{s3-credentials-ui.ts → ui/setup/s3-credentials-ui.ts} +13 -21
  150. package/src/ui/setup/s3-ui.ts +217 -0
  151. package/src/ui/setup/setup-actions.ts +127 -0
  152. package/src/ui/setup/setup-location-ui.ts +167 -0
  153. package/src/ui/setup/setup-name-ui.ts +34 -0
  154. package/src/ui/setup/setup-prompts.ts +92 -0
  155. package/src/ui/setup/setup-review.ts +70 -0
  156. package/src/ui/setup/setup-switcher.ts +181 -0
  157. package/src/ui/setup/setup-wizard.ts +39 -0
  158. package/src/ui/setup/text-input.ts +78 -0
  159. package/src/ui/setup/webdav-ui.ts +330 -0
  160. package/src/{storage-connections-ui.ts → ui/storage-connections-ui.ts} +99 -69
  161. package/src/ui/sync-attention.ts +187 -0
  162. package/src/{sync-format.ts → ui/sync-format.ts} +7 -13
  163. package/src/{sync-resolution-ui.ts → ui/sync-resolution-ui.ts} +4 -3
  164. package/src/{sync-setups-ui.ts → ui/sync-setups-ui.ts} +23 -10
  165. package/src/ui/terminal-text.ts +4 -0
  166. package/dist/chunks/chunk-44LPGQTI.ts.map +0 -7
  167. package/dist/chunks/chunk-4U6AFLJB.ts.map +0 -7
  168. package/dist/chunks/chunk-5LZALPCD.ts.map +0 -7
  169. package/dist/chunks/chunk-5MQ76BK5.ts.map +0 -7
  170. package/dist/chunks/chunk-5T442OP3.ts.map +0 -7
  171. package/dist/chunks/chunk-ARN2672F.ts.map +0 -7
  172. package/dist/chunks/chunk-C7LXZ3UH.ts +0 -167
  173. package/dist/chunks/chunk-C7LXZ3UH.ts.map +0 -7
  174. package/dist/chunks/chunk-DFXBKHGN.ts.map +0 -7
  175. package/dist/chunks/chunk-E4COSV32.ts +0 -82
  176. package/dist/chunks/chunk-E4COSV32.ts.map +0 -7
  177. package/dist/chunks/chunk-F5QL2GPY.ts.map +0 -7
  178. package/dist/chunks/chunk-GLQLN5GV.ts.map +0 -7
  179. package/dist/chunks/chunk-HGV24P4T.ts.map +0 -7
  180. package/dist/chunks/chunk-HVUSHMVL.ts.map +0 -7
  181. package/dist/chunks/chunk-JF6MZCT4.ts.map +0 -7
  182. package/dist/chunks/chunk-WSOBYHIZ.ts.map +0 -7
  183. package/dist/chunks/chunk-X7SQ2EQM.ts.map +0 -7
  184. package/dist/chunks/chunk-YQ6UW7IF.ts.map +0 -7
  185. package/dist/chunks/file-selection-RKEHALNQ.ts.map +0 -7
  186. package/dist/chunks/git-backend-E3UOUUOM.ts.map +0 -7
  187. package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +0 -18
  188. package/dist/chunks/manager-ui-NF4RUHBY.ts +0 -2785
  189. package/dist/chunks/manager-ui-NF4RUHBY.ts.map +0 -7
  190. package/dist/chunks/remote-selection-ui-NUF5P4ZJ.ts +0 -17
  191. package/dist/chunks/s3-backend-552LXHE4.ts.map +0 -7
  192. package/dist/chunks/sync-operations-3LLIHWZO.ts.map +0 -7
  193. package/dist/chunks/webdav-backend-ZD5RHRIU.ts.map +0 -7
  194. package/src/config.ts +0 -923
  195. package/src/git-ui.ts +0 -307
  196. package/src/manager-helpers.ts +0 -64
  197. package/src/manager-ui.ts +0 -997
  198. package/src/sync-attention.ts +0 -100
  199. package/src/webdav-ui.ts +0 -421
  200. /package/dist/chunks/{manager-result-dispatcher-LWPYJAD5.ts.map → manager-result-dispatcher-FKIBM3GO.ts.map} +0 -0
  201. /package/dist/chunks/{remote-selection-ui-NUF5P4ZJ.ts.map → remote-selection-ui-D7RBRJNL.ts.map} +0 -0
  202. /package/dist/chunks/{setup-switch-5YDG5YGJ.ts.map → setup-switch-IS2PEZ3J.ts.map} +0 -0
  203. /package/dist/chunks/{snapshot-2RYBUDRA.ts.map → snapshot-HKEWCVK6.ts.map} +0 -0
  204. /package/dist/chunks/{sync-state-SRN6YRBK.ts.map → sync-inspection-CST2KL65.ts.map} +0 -0
  205. /package/src/{git-runner.ts → backends/git/git-runner.ts} +0 -0
  206. /package/src/{config-errors.ts → settings/config-errors.ts} +0 -0
  207. /package/src/{config-file.ts → settings/config-file.ts} +0 -0
  208. /package/src/{snapshot-paths.ts → snapshot/snapshot-paths.ts} +0 -0
  209. /package/src/{lock-policy.ts → state/lock-policy.ts} +0 -0
  210. /package/src/{lockfile-fs.ts → state/lockfile-fs.ts} +0 -0
  211. /package/src/{state-directory.ts → state/state-directory.ts} +0 -0
  212. /package/src/{sync-errors.ts → sync/sync-errors.ts} +0 -0
  213. /package/src/{manager-result-dispatcher.ts → ui/manager-result-dispatcher.ts} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/snapshot/snapshot.ts"],
4
+ "sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { isDeniedPath, posixJoin, safeJoin, toPosix } from \"../paths.js\";\nimport { agentDir, configuredSessionDir } from \"./session-paths.js\";\nimport { sessionStorageRoot } from \"./snapshot-paths.js\";\n\nexport { isDeniedPath } from \"../paths.js\";\nexport { sessionStorageRoot } from \"./snapshot-paths.js\";\n\nimport {\n\tcanonicalSnapshotPathForConfig,\n\tcustomIncludePathsByLower,\n\tDEFAULT_SYNC_INCLUDE,\n\tincludeFromSelectionConfig,\n\tisConfiguredSnapshotPath,\n\tisPreservableUnmanagedSnapshotPath,\n\tnormalizeExtraFiles,\n\tnormalizeSyncFiles,\n\ttype SyncSelectionConfig,\n\tselectionForSnapshot,\n\tsnapshotSelectionInclude,\n\tsyncIncludeSelection,\n} from \"../sync/sync-policy.js\";\nimport type { Snapshot, SnapshotFile, SnapshotOptions } from \"./snapshot-types.js\";\n\nexport { canonicalSnapshotPathForConfig, isConfiguredSnapshotPath } from \"../sync/sync-policy.js\";\n\nconst VERSION = 1;\nconst TOP_LEVEL_FILES: readonly string[] = DEFAULT_SYNC_INCLUDE.filter((name) =>\n\tname.includes(\".\"),\n);\nconst TOP_LEVEL_DIRS = new Set<string>(DEFAULT_SYNC_INCLUDE.filter((name) => !name.includes(\".\")));\nconst SECRET_PATTERNS = [\n\t/AWS_SECRET_ACCESS_KEY\\s*[=:]\\s*['\"]?[A-Za-z0-9/+]{35,}/i,\n\t/(ANTHROPIC|OPENAI|GEMINI|GOOGLE|FIRECRAWL|GITHUB|CLOUDFLARE|R2|S3)_[A-Z0-9_]*(KEY|TOKEN|SECRET)\\s*[=:]\\s*['\"]?[^\\s'\"]{12,}/i,\n\t/sk-ant-[A-Za-z0-9_-]{20,}/,\n\t/sk-[A-Za-z0-9]{20,}/,\n\t/gh[pousr]_[A-Za-z0-9_]{20,}/,\n];\n\nfunction selectTopLevelFileEntry(entries: Dirent[], fileName: string) {\n\tconst exact = entries.find((entry) => entry.isFile() && entry.name === fileName);\n\tif (exact) return exact;\n\tconst lower = fileName.toLowerCase();\n\treturn entries\n\t\t.filter((entry) => entry.isFile() && entry.name.toLowerCase() === lower)\n\t\t.sort((left, right) => left.name.localeCompare(right.name))[0];\n}\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction isSafeSnapshotPath(relativePath: string) {\n\tif (relativePath.includes(\"\\\\\")) return false;\n\tconst normalized = toPosix(relativePath);\n\treturn (\n\t\tBoolean(normalized) &&\n\t\tnormalized !== \".\" &&\n\t\tnormalized !== \"..\" &&\n\t\t!normalized.startsWith(\"../\") &&\n\t\t!path.posix.isAbsolute(normalized) &&\n\t\tpath.posix.normalize(normalized) === normalized &&\n\t\t!isDeniedPath(normalized)\n\t);\n}\n\nfunction snapshotsMatch(left: Snapshot, right: Snapshot) {\n\tconst leftHashes = new Map(left.files.map((file) => [file.path, file.sha256]));\n\tconst rightHashes = new Map(right.files.map((file) => [file.path, file.sha256]));\n\treturn (\n\t\tleft.syncSessions === right.syncSessions &&\n\t\tsameOptionalInclude(snapshotSelectionInclude(left), snapshotSelectionInclude(right)) &&\n\t\tleftHashes.size === rightHashes.size &&\n\t\t[...leftHashes].every(([filePath, hash]) => rightHashes.get(filePath) === hash)\n\t);\n}\n\nfunction snapshotId() {\n\treturn `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${randomUUID().slice(0, 8)}`;\n}\n\nexport function regenerateSnapshotIdentity(snapshot: Snapshot): Snapshot {\n\treturn {\n\t\t...snapshot,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t};\n}\n\nexport async function createSnapshot(\n\tprofile: string,\n\toptions: SnapshotOptions = {},\n): Promise<Snapshot> {\n\toptions.signal?.throwIfAborted();\n\tconst include = effectiveInclude(options);\n\tconst syncSessions = include.includes(\"sessions\");\n\tconst sessionDir = options.sessionDir ?? (await configuredSessionDir());\n\toptions.signal?.throwIfAborted();\n\tconst files = await collectFiles(agentDir(), { include, sessionDir, signal: options.signal });\n\toptions.signal?.throwIfAborted();\n\treturn {\n\t\tversion: VERSION,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t\tprofile,\n\t\tsyncSessions,\n\t\tselection: selectionForSnapshot(include),\n\t\tfiles,\n\t};\n}\n\nfunction effectiveInclude(options: SnapshotOptions) {\n\tif (options.include) return options.include;\n\treturn [\n\t\t...normalizeSyncFiles(options.syncFiles),\n\t\t...normalizeExtraFiles(options.extraFiles),\n\t\t...(options.syncSessions ? [\"sessions\"] : []),\n\t];\n}\n\nexport async function collectFiles(\n\troot: string,\n\toptions: SnapshotOptions = {},\n): Promise<SnapshotFile[]> {\n\tconst signal = options.signal;\n\tsignal?.throwIfAborted();\n\tconst results: SnapshotFile[] = [];\n\tconst entries = await fs.readdir(root, { withFileTypes: true });\n\tsignal?.throwIfAborted();\n\tconst selection = syncIncludeSelection(effectiveInclude(options));\n\tconst selectedFiles = new Set<string>(selection.builtIns);\n\tfor (const entry of entries) {\n\t\tif (entry.isDirectory() && TOP_LEVEL_DIRS.has(entry.name) && selectedFiles.has(entry.name)) {\n\t\t\tawait collectDirectory(results, root, entry.name, { signal });\n\t\t}\n\t}\n\tfor (const fileName of TOP_LEVEL_FILES) {\n\t\tif (!selectedFiles.has(fileName)) continue;\n\t\tconst entry = selectTopLevelFileEntry(entries, fileName);\n\t\tif (entry) await addFile(results, root, entry.name, fileName, signal);\n\t}\n\tfor (const relativePath of selection.custom) {\n\t\tawait collectIncludedPath(results, root, relativePath, signal);\n\t}\n\tif (selection.sessions) {\n\t\ttry {\n\t\t\tawait collectDirectory(results, sessionStorageRoot(root, options.sessionDir), \"\", {\n\t\t\t\tsessionsOnly: true,\n\t\t\t\tvirtualPrefix: \"sessions\",\n\t\t\t\tsignal,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tsignal?.throwIfAborted();\n\treturn results.sort((left, right) => left.path.localeCompare(right.path));\n}\n\nasync function collectIncludedPath(\n\tresults: SnapshotFile[],\n\troot: string,\n\trelativePath: string,\n\tsignal?: AbortSignal,\n) {\n\tsignal?.throwIfAborted();\n\tconst absolutePath = safeJoin(root, relativePath);\n\ttry {\n\t\tconst stat = await fs.lstat(absolutePath);\n\t\tsignal?.throwIfAborted();\n\t\tif (stat.isFile()) await addFile(results, root, relativePath, relativePath, signal);\n\t\telse if (stat.isDirectory()) await collectDirectory(results, root, relativePath, { signal });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\tif (!relativePath.includes(\"/\")) {\n\t\t\tconst entries = await fs.readdir(root, { withFileTypes: true });\n\t\t\tsignal?.throwIfAborted();\n\t\t\tconst entry = selectTopLevelFileEntry(entries, relativePath);\n\t\t\tif (entry) await addFile(results, root, entry.name, relativePath, signal);\n\t\t}\n\t}\n}\n\nasync function collectDirectory(\n\tresults: SnapshotFile[],\n\troot: string,\n\trelativeDirectory: string,\n\toptions: { sessionsOnly?: boolean; virtualPrefix?: string; signal?: AbortSignal } = {},\n) {\n\toptions.signal?.throwIfAborted();\n\tconst absoluteDirectory = path.join(root, relativeDirectory);\n\tfor (const entry of await fs.readdir(absoluteDirectory, { withFileTypes: true })) {\n\t\toptions.signal?.throwIfAborted();\n\t\tconst relativePath = relativeDirectory ? posixJoin(relativeDirectory, entry.name) : entry.name;\n\t\tconst snapshotPath = options.virtualPrefix\n\t\t\t? posixJoin(options.virtualPrefix, relativePath)\n\t\t\t: relativePath;\n\t\tif (isDeniedPath(snapshotPath)) continue;\n\t\tif (entry.isDirectory()) {\n\t\t\tawait collectDirectory(results, root, relativePath, options);\n\t\t} else if (entry.isFile() && (!options.sessionsOnly || isSessionFilePath(snapshotPath))) {\n\t\t\tawait addFile(results, root, relativePath, snapshotPath, options.signal);\n\t\t}\n\t}\n}\n\nasync function addFile(\n\tresults: SnapshotFile[],\n\troot: string,\n\trelativePath: string,\n\tsnapshotPath = relativePath,\n\tsignal?: AbortSignal,\n) {\n\tsignal?.throwIfAborted();\n\tif (!isSafeSnapshotPath(snapshotPath)) return;\n\tconst absolutePath = safeJoin(root, relativePath);\n\tconst content = await fs.readFile(absolutePath, { signal });\n\tsignal?.throwIfAborted();\n\tresults.push({\n\t\tpath: snapshotPath,\n\t\tcontentBase64: content.toString(\"base64\"),\n\t\tsha256: sha256(content),\n\t});\n}\n\nexport function isSessionPath(relativePath: string) {\n\treturn toPosix(relativePath).startsWith(\"sessions/\");\n}\n\nexport function isSessionFilePath(relativePath: string) {\n\tconst normalized = toPosix(relativePath);\n\treturn isSessionPath(normalized) && normalized.endsWith(\".jsonl\");\n}\n\nexport function sessionSnapshotPathFromAbsolute(\n\tsessionFile: string,\n\tconfiguredSessionDir?: string,\n) {\n\tconst relativePath = toPosix(\n\t\tpath.relative(sessionStorageRoot(agentDir(), configuredSessionDir), sessionFile),\n\t);\n\tif (!relativePath || relativePath.startsWith(\"../\") || path.posix.isAbsolute(relativePath)) {\n\t\treturn undefined;\n\t}\n\tconst snapshotPath = posixJoin(\"sessions\", relativePath);\n\treturn isSessionFilePath(snapshotPath) ? snapshotPath : undefined;\n}\n\nexport function snapshotTarget(root: string, relativePath: string, configuredSessionDir?: string) {\n\tif (isSessionPath(relativePath)) {\n\t\treturn safeJoin(\n\t\t\tsessionStorageRoot(root, configuredSessionDir),\n\t\t\trelativePath.slice(\"sessions/\".length),\n\t\t);\n\t}\n\treturn safeJoin(root, relativePath);\n}\n\nexport function snapshotIncludesSessions(snapshot: Snapshot) {\n\treturn (\n\t\tsnapshot.syncSessions === true ||\n\t\tsnapshotSelectionInclude(snapshot)?.includes(\"sessions\") === true ||\n\t\tsnapshot.files.some((file) => isSessionPath(file.path))\n\t);\n}\n\nexport function filterSnapshotForConfigPolicy(\n\tsnapshot: Snapshot,\n\tconfig: SyncSelectionConfig,\n\toptions: { regenerateId?: boolean } = {},\n) {\n\tconst include = includeFromSelectionConfig(config);\n\tconst includePaths = customIncludePathsByLower(include);\n\tconst filtered = {\n\t\t...snapshot,\n\t\tsyncSessions: include.includes(\"sessions\") ? snapshot.syncSessions : false,\n\t\tselection: selectionForSnapshot(include),\n\t\tfiles: canonicalizeSnapshotFilesForConfig(snapshot.files, config, includePaths),\n\t};\n\tif (!options.regenerateId || snapshotsMatch(snapshot, filtered)) return filtered;\n\treturn {\n\t\t...filtered,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t};\n}\n\nfunction canonicalizeSnapshotFilesForConfig(\n\tfiles: SnapshotFile[],\n\tconfig: SyncSelectionConfig,\n\tincludePaths: Map<string, string>,\n) {\n\tconst configuredFiles: SnapshotFile[] = [];\n\tconst extraCandidates = new Map<\n\t\tstring,\n\t\t{ exact: boolean; file: SnapshotFile; originalPath: string }\n\t>();\n\tfor (const file of files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!isSafeSnapshotPath(file.path) || !isConfiguredSnapshotPath(normalized, config)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (normalized.includes(\"/\")) {\n\t\t\tconfiguredFiles.push(normalized === file.path ? file : { ...file, path: normalized });\n\t\t\tcontinue;\n\t\t}\n\t\tconst topLevelPath = canonicalSnapshotPathForConfig(normalized, includePaths);\n\t\tconst candidate = {\n\t\t\texact: normalized === topLevelPath,\n\t\t\tfile: { ...file, path: topLevelPath },\n\t\t\toriginalPath: normalized,\n\t\t};\n\t\tconst current = extraCandidates.get(topLevelPath.toLowerCase());\n\t\tif (!current || isPreferredExtraCandidate(candidate, current)) {\n\t\t\textraCandidates.set(topLevelPath.toLowerCase(), candidate);\n\t\t}\n\t}\n\treturn [\n\t\t...configuredFiles,\n\t\t...[...extraCandidates.values()].map((candidate) => candidate.file),\n\t].sort((left, right) => left.path.localeCompare(right.path));\n}\n\nfunction isPreferredExtraCandidate(\n\tleft: { exact: boolean; originalPath: string },\n\tright: { exact: boolean; originalPath: string },\n) {\n\tif (left.exact !== right.exact) return left.exact;\n\treturn left.originalPath.localeCompare(right.originalPath) < 0;\n}\n\nexport function snapshotWithoutSessions(snapshot: Snapshot) {\n\tconst files = snapshot.files.filter((file) => !isSessionPath(file.path));\n\tconst include = snapshotSelectionInclude(snapshot)?.filter((item) => item !== \"sessions\");\n\tif (\n\t\tfiles.length === snapshot.files.length &&\n\t\tsnapshot.syncSessions !== true &&\n\t\tinclude?.length === snapshot.selection?.include.length\n\t) {\n\t\treturn snapshot;\n\t}\n\treturn {\n\t\t...snapshot,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t\tsyncSessions: false,\n\t\t...(include ? { selection: selectionForSnapshot(include) } : {}),\n\t\tfiles,\n\t};\n}\n\nexport function scanSnapshot(snapshot: Snapshot) {\n\tconst findings: string[] = [];\n\tfor (const file of snapshot.files) {\n\t\tconst content = Buffer.from(file.contentBase64, \"base64\");\n\t\tif (content.includes(0)) continue;\n\t\tconst text = content.toString(\"utf8\");\n\t\tfor (const pattern of SECRET_PATTERNS) {\n\t\t\tif (pattern.test(text)) {\n\t\t\t\tfindings.push(file.path);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn findings;\n}\n\nexport function mergeRemotePreservedFiles(\n\tlocal: Snapshot,\n\tremote: Snapshot,\n\tconfig: SyncSelectionConfig,\n) {\n\tconst localPathNames = new Set(local.files.map((file) => file.path.toLowerCase()));\n\tconst preservedPathNames = new Set<string>();\n\tconst preserved = remote.files.filter((file) => {\n\t\tconst normalized = toPosix(file.path);\n\t\tconst lower = normalized.toLowerCase();\n\t\tif (\n\t\t\tlocalPathNames.has(lower) ||\n\t\t\tpreservedPathNames.has(lower) ||\n\t\t\t!isSafeSnapshotPath(file.path) ||\n\t\t\tisConfiguredSnapshotPath(normalized, config) ||\n\t\t\t!isPreservableUnmanagedSnapshotPath(normalized)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\tpreservedPathNames.add(lower);\n\t\treturn true;\n\t});\n\tif (preserved.length === 0) return local;\n\treturn {\n\t\t...local,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t\tsyncSessions: snapshotIncludesSessions(local) || snapshotIncludesSessions(remote),\n\t\tfiles: [...local.files, ...preserved].sort((left, right) =>\n\t\t\tleft.path.localeCompare(right.path),\n\t\t),\n\t};\n}\n\nexport function mergeRemoteSessionFiles(local: Snapshot, remote: Snapshot) {\n\tconst remoteSessions = remote.files.filter((file) => {\n\t\tconst normalized = toPosix(file.path);\n\t\treturn isSessionFilePath(normalized) && isSafeSnapshotPath(file.path);\n\t});\n\tif (remoteSessions.length === 0 && !snapshotIncludesSessions(remote)) return local;\n\tconst localInclude = snapshotSelectionInclude(local);\n\treturn {\n\t\t...local,\n\t\tid: snapshotId(),\n\t\tcreatedAt: new Date().toISOString(),\n\t\tmachine: os.hostname(),\n\t\tsyncSessions: true,\n\t\t...(localInclude\n\t\t\t? {\n\t\t\t\t\tselection: selectionForSnapshot(\n\t\t\t\t\t\tlocalInclude.includes(\"sessions\") ? localInclude : [...localInclude, \"sessions\"],\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t\tfiles: [...local.files.filter((file) => !isSessionPath(file.path)), ...remoteSessions].sort(\n\t\t\t(left, right) => left.path.localeCompare(right.path),\n\t\t),\n\t};\n}\n\nfunction sameOptionalInclude(left: string[] | undefined, right: string[] | undefined) {\n\tif (!left || !right) return left === right;\n\treturn left.length === right.length && left.every((item, index) => item === right[index]);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["configuredSessionDir"]
7
+ }
@@ -2,9 +2,9 @@
2
2
  // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
3
  import {
4
4
  snapshotSelectionInclude
5
- } from "./chunk-YQ6UW7IF.ts";
5
+ } from "./chunk-JAAKLL6M.ts";
6
6
 
7
- // src/snapshot-codec.ts
7
+ // src/snapshot/snapshot-codec.ts
8
8
  import { Readable, Writable } from "node:stream";
9
9
  import { pipeline } from "node:stream/promises";
10
10
  import { promisify } from "node:util";
@@ -50,4 +50,4 @@ export {
50
50
  encodeSnapshot,
51
51
  decodeSnapshot
52
52
  };
53
- //# sourceMappingURL=chunk-HGV24P4T.ts.map
53
+ //# sourceMappingURL=chunk-Q2TUM5X6.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/snapshot/snapshot-codec.ts"],
4
+ "sourcesContent": ["import { Readable, Writable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { promisify } from \"node:util\";\nimport { createGunzip, gzip } from \"node:zlib\";\nimport { snapshotSelectionInclude } from \"../sync/sync-policy.js\";\nimport type { Snapshot } from \"./snapshot-types.js\";\n\nconst VERSION = 1;\nconst MAX_DECOMPRESSED_SNAPSHOT_BYTES = 512 * 1024 * 1024;\nconst gzipAsync = promisify(gzip);\n\nexport async function encodeSnapshot(snapshot: Snapshot) {\n\tsnapshotSelectionInclude(snapshot);\n\treturn gzipAsync(Buffer.from(JSON.stringify(snapshot), \"utf8\"));\n}\n\nexport async function decodeSnapshot(\n\tbuffer: Buffer,\n\toptions: { signal?: AbortSignal; maxOutputLength?: number } = {},\n): Promise<Snapshot> {\n\tthrowIfAborted(options.signal);\n\tconst limit = options.maxOutputLength ?? MAX_DECOMPRESSED_SNAPSHOT_BYTES;\n\tconst chunks: Buffer[] = [];\n\tlet total = 0;\n\tconst sink = new Writable({\n\t\twrite(chunk: Buffer, _encoding, callback) {\n\t\t\ttotal += chunk.byteLength;\n\t\t\tif (total > limit) {\n\t\t\t\tcallback(new Error(`Decompressed snapshot exceeds the ${limit}-byte limit.`));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tchunks.push(Buffer.from(chunk));\n\t\t\tcallback();\n\t\t},\n\t});\n\tawait pipeline(Readable.from([buffer]), createGunzip(), sink, { signal: options.signal });\n\tthrowIfAborted(options.signal);\n\tconst parsed = JSON.parse(Buffer.concat(chunks, total).toString(\"utf8\")) as Snapshot;\n\tif (parsed.version !== VERSION || !Array.isArray(parsed.files)) {\n\t\tthrow new Error(\"Unsupported snapshot format.\");\n\t}\n\tsnapshotSelectionInclude(parsed);\n\treturn parsed;\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],
5
+ "mappings": ";;;;;;;AAAA,SAAS,UAAU,gBAAgB;AACnC,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,cAAc,YAAY;AAInC,IAAM,UAAU;AAChB,IAAM,kCAAkC,MAAM,OAAO;AACrD,IAAM,YAAY,UAAU,IAAI;AAEhC,eAAsB,eAAe,UAAoB;AACxD,2BAAyB,QAAQ;AACjC,SAAO,UAAU,OAAO,KAAK,KAAK,UAAU,QAAQ,GAAG,MAAM,CAAC;AAC/D;AAEA,eAAsB,eACrB,QACA,UAA8D,CAAC,GAC3C;AACpB,iBAAe,QAAQ,MAAM;AAC7B,QAAM,QAAQ,QAAQ,mBAAmB;AACzC,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,QAAM,OAAO,IAAI,SAAS;AAAA,IACzB,MAAM,OAAe,WAAW,UAAU;AACzC,eAAS,MAAM;AACf,UAAI,QAAQ,OAAO;AAClB,iBAAS,IAAI,MAAM,qCAAqC,KAAK,cAAc,CAAC;AAC5E;AAAA,MACD;AACA,aAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAC9B,eAAS;AAAA,IACV;AAAA,EACD,CAAC;AACD,QAAM,SAAS,SAAS,KAAK,CAAC,MAAM,CAAC,GAAG,aAAa,GAAG,MAAM,EAAE,QAAQ,QAAQ,OAAO,CAAC;AACxF,iBAAe,QAAQ,MAAM;AAC7B,QAAM,SAAS,KAAK,MAAM,OAAO,OAAO,QAAQ,KAAK,EAAE,SAAS,MAAM,CAAC;AACvE,MAAI,OAAO,YAAY,WAAW,CAAC,MAAM,QAAQ,OAAO,KAAK,GAAG;AAC/D,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAC/C;AACA,2BAAyB,MAAM;AAC/B,SAAO;AACR;AAEA,SAAS,eAAe,QAAsB;AAC7C,MAAI,CAAC,QAAQ,QAAS;AACtB,QAAM,OAAO,kBAAkB,QAC5B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAC9D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,146 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+ import {
4
+ safeTerminalText
5
+ } from "./chunk-LTBWGSBV.ts";
6
+ import {
7
+ syncCheckConfigFingerprint,
8
+ syncConfigReviewFingerprint
9
+ } from "./chunk-C7XY5NF5.ts";
10
+ import {
11
+ compareSyncInclude,
12
+ sameSyncInclude
13
+ } from "./chunk-JAAKLL6M.ts";
14
+
15
+ // src/ui/sync-attention.ts
16
+ import { truncateToWidth } from "@earendil-works/pi-tui";
17
+ var STATUS_KEY = "sync";
18
+ var WIDGET_KEY = "sync:attention";
19
+ function syncAttentionMatchesConfig(attention, config) {
20
+ return attention.decision.setupName === config.setupName && attention.decision.configIdentity === syncConfigReviewFingerprint(config) && sameSyncInclude(attention.decision.localInclude, config.include);
21
+ }
22
+ function createSyncAttentionController() {
23
+ let state;
24
+ let observation;
25
+ let generation = 0;
26
+ return {
27
+ observe(value) {
28
+ generation++;
29
+ observation = value;
30
+ },
31
+ observation() {
32
+ return observation;
33
+ },
34
+ clearObservation() {
35
+ generation++;
36
+ observation = void 0;
37
+ },
38
+ notifyObservation(ctx) {
39
+ if (observation && observationNeedsAttention(observation)) {
40
+ ctx.ui.notify(observationLines(observation).join("\n"), "warning");
41
+ }
42
+ },
43
+ set(decision, origin) {
44
+ generation++;
45
+ state = { decision, origin, offered: false };
46
+ },
47
+ current() {
48
+ return state;
49
+ },
50
+ markOffered() {
51
+ if (!state || state.offered) return false;
52
+ state = { ...state, offered: true };
53
+ return true;
54
+ },
55
+ clear(ctx) {
56
+ generation++;
57
+ state = void 0;
58
+ clearAttentionPresentation(ctx);
59
+ },
60
+ reset(ctx) {
61
+ generation++;
62
+ state = void 0;
63
+ observation = void 0;
64
+ clearAttentionPresentation(ctx);
65
+ },
66
+ async publish(ctx, signal) {
67
+ const currentGeneration = ++generation;
68
+ if (signal?.aborted) return;
69
+ if (!state && (!observation || !observationNeedsAttention(observation))) {
70
+ clearAttentionPresentation(ctx);
71
+ return;
72
+ }
73
+ const presentation = state ? attentionPresentation(state.decision) : {
74
+ status: "changes to review",
75
+ lines: observationLines(observation)
76
+ };
77
+ if (ctx.mode !== "tui") {
78
+ ctx.ui.setStatus(STATUS_KEY, presentation.status);
79
+ return;
80
+ }
81
+ const { EditorStatusWidget } = await import("./attention-widget-Z7G3SYYJ.ts");
82
+ if (generation !== currentGeneration || signal?.aborted) return;
83
+ ctx.ui.setStatus(STATUS_KEY, presentation.status);
84
+ ctx.ui.setWidget(
85
+ WIDGET_KEY,
86
+ (_tui, theme) => new EditorStatusWidget({
87
+ theme,
88
+ renderBody: (width) => presentation.lines.map(
89
+ (line, index) => width === 0 ? "" : truncateToWidth(theme.fg(index === 0 ? "warning" : "muted", line), width, "\u2026")
90
+ )
91
+ })
92
+ );
93
+ }
94
+ };
95
+ }
96
+ function attentionPresentation(decision) {
97
+ const setupName = safeTerminalText(decision.setupName);
98
+ const comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);
99
+ const difference = comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0 ? "Only list order differs" : `Remote ${comparison.remoteOnly.length} \xB7 Device ${comparison.localOnly.length}`;
100
+ return {
101
+ status: "review needed",
102
+ lines: [`Pi Sync needs review \xB7 ${setupName}`, difference, "No changes \xB7 Run /sync to review"]
103
+ };
104
+ }
105
+ function observationMatchesConfig(observation, config) {
106
+ return observation.configIdentity === syncCheckConfigFingerprint(config);
107
+ }
108
+ function observationSummary(observation) {
109
+ const result = observation.inspection;
110
+ if (result.emptyInclude) return "No included content selected";
111
+ if (result.selectionState?.kind === "different")
112
+ return "Synced-content list differs; review needed";
113
+ if (result.firstSync)
114
+ return result.head ? "No sync baseline; review remote and local content" : "Remote empty; no sync baseline";
115
+ if (!result.head) return "Remote snapshot missing; review needed";
116
+ if (result.localChanged && result.remoteChanged)
117
+ return "Local and remote changed since last sync; review needed";
118
+ if (result.remoteChanged) return "Remote changed since last sync";
119
+ if (result.localChanged) return "Local content changed since last sync";
120
+ if (result.selectionState?.kind === "legacy")
121
+ return "Legacy remote has no authoritative content list";
122
+ return "No changes detected since last sync";
123
+ }
124
+ function observationNeedsAttention(observation) {
125
+ const result = observation.inspection;
126
+ return result.emptyInclude || result.firstSync || !result.head || result.localChanged || result.remoteChanged || result.selectionState?.kind !== "same";
127
+ }
128
+ function observationLines(observation) {
129
+ return [
130
+ `Pi Sync check \xB7 ${safeTerminalText(observation.setupName)}`,
131
+ observationSummary(observation),
132
+ "No startup transfer \xB7 Run /sync to review"
133
+ ];
134
+ }
135
+ function clearAttentionPresentation(ctx) {
136
+ ctx.ui.setStatus(STATUS_KEY, void 0);
137
+ ctx.ui.setWidget(WIDGET_KEY, void 0);
138
+ }
139
+
140
+ export {
141
+ syncAttentionMatchesConfig,
142
+ createSyncAttentionController,
143
+ observationMatchesConfig,
144
+ observationSummary
145
+ };
146
+ //# sourceMappingURL=chunk-S7YBZR42.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ui/sync-attention.ts"],
4
+ "sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { syncCheckConfigFingerprint, syncConfigReviewFingerprint } from \"../settings/config.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { StartupObservation } from \"../sync/sync-inspection.js\";\nimport {\n\tcompareSyncInclude,\n\ttype RemoteSelectionDecision,\n\tsameSyncInclude,\n} from \"../sync/sync-policy.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\nconst STATUS_KEY = \"sync\";\nconst WIDGET_KEY = \"sync:attention\";\n\nexport type SyncAttentionOrigin = \"sync\" | \"pull\" | \"push\";\n\nexport interface SyncAttentionState {\n\tdecision: RemoteSelectionDecision;\n\torigin: SyncAttentionOrigin;\n\toffered: boolean;\n}\n\nexport function syncAttentionMatchesConfig(attention: SyncAttentionState, config: AnySyncConfig) {\n\treturn (\n\t\tattention.decision.setupName === config.setupName &&\n\t\tattention.decision.configIdentity === syncConfigReviewFingerprint(config) &&\n\t\tsameSyncInclude(attention.decision.localInclude, config.include)\n\t);\n}\n\nexport interface SyncAttentionController {\n\tobserve(observation: StartupObservation): void;\n\tobservation(): StartupObservation | undefined;\n\tclearObservation(): void;\n\tnotifyObservation(ctx: ExtensionContext): void;\n\tset(decision: RemoteSelectionDecision, origin: SyncAttentionOrigin): void;\n\tcurrent(): SyncAttentionState | undefined;\n\tmarkOffered(): boolean;\n\tclear(ctx: ExtensionContext): void;\n\treset(ctx: ExtensionContext): void;\n\tpublish(ctx: ExtensionContext, signal?: AbortSignal): Promise<void>;\n}\n\nexport function createSyncAttentionController(): SyncAttentionController {\n\tlet state: SyncAttentionState | undefined;\n\tlet observation: StartupObservation | undefined;\n\tlet generation = 0;\n\n\treturn {\n\t\tobserve(value) {\n\t\t\tgeneration++;\n\t\t\tobservation = value;\n\t\t},\n\t\tobservation() {\n\t\t\treturn observation;\n\t\t},\n\t\tclearObservation() {\n\t\t\tgeneration++;\n\t\t\tobservation = undefined;\n\t\t},\n\t\tnotifyObservation(ctx) {\n\t\t\tif (observation && observationNeedsAttention(observation)) {\n\t\t\t\tctx.ui.notify(observationLines(observation).join(\"\\n\"), \"warning\");\n\t\t\t}\n\t\t},\n\t\tset(decision, origin) {\n\t\t\tgeneration++;\n\t\t\tstate = { decision, origin, offered: false };\n\t\t},\n\t\tcurrent() {\n\t\t\treturn state;\n\t\t},\n\t\tmarkOffered() {\n\t\t\tif (!state || state.offered) return false;\n\t\t\tstate = { ...state, offered: true };\n\t\t\treturn true;\n\t\t},\n\t\tclear(ctx) {\n\t\t\tgeneration++;\n\t\t\tstate = undefined;\n\t\t\tclearAttentionPresentation(ctx);\n\t\t},\n\t\treset(ctx) {\n\t\t\tgeneration++;\n\t\t\tstate = undefined;\n\t\t\tobservation = undefined;\n\t\t\tclearAttentionPresentation(ctx);\n\t\t},\n\t\tasync publish(ctx, signal) {\n\t\t\tconst currentGeneration = ++generation;\n\t\t\tif (signal?.aborted) return;\n\t\t\tif (!state && (!observation || !observationNeedsAttention(observation))) {\n\t\t\t\tclearAttentionPresentation(ctx);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst presentation = state\n\t\t\t\t? attentionPresentation(state.decision)\n\t\t\t\t: {\n\t\t\t\t\t\tstatus: \"changes to review\",\n\t\t\t\t\t\tlines: observationLines(observation as StartupObservation),\n\t\t\t\t\t};\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.setStatus(STATUS_KEY, presentation.status);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Keep Kit outside the eager startup graph; module loading owns no cancellable resources.\n\t\t\tconst { EditorStatusWidget } = await import(\"./attention-widget.js\");\n\t\t\tif (generation !== currentGeneration || signal?.aborted) return;\n\t\t\tctx.ui.setStatus(STATUS_KEY, presentation.status);\n\t\t\tctx.ui.setWidget(\n\t\t\t\tWIDGET_KEY,\n\t\t\t\t(_tui, theme) =>\n\t\t\t\t\tnew EditorStatusWidget({\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t\trenderBody: (width) =>\n\t\t\t\t\t\t\tpresentation.lines.map((line, index) =>\n\t\t\t\t\t\t\t\twidth === 0\n\t\t\t\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t\t\t\t: truncateToWidth(theme.fg(index === 0 ? \"warning\" : \"muted\", line), width, \"\u2026\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t};\n}\n\nfunction attentionPresentation(decision: RemoteSelectionDecision) {\n\tconst setupName = safeTerminalText(decision.setupName);\n\tconst comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n\tconst difference =\n\t\tcomparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n\t\t\t? \"Only list order differs\"\n\t\t\t: `Remote ${comparison.remoteOnly.length} \u00B7 Device ${comparison.localOnly.length}`;\n\treturn {\n\t\tstatus: \"review needed\",\n\t\tlines: [`Pi Sync needs review \u00B7 ${setupName}`, difference, \"No changes \u00B7 Run /sync to review\"],\n\t};\n}\n\nexport function observationMatchesConfig(observation: StartupObservation, config: AnySyncConfig) {\n\treturn observation.configIdentity === syncCheckConfigFingerprint(config);\n}\n\nexport function observationSummary(observation: StartupObservation) {\n\tconst result = observation.inspection;\n\tif (result.emptyInclude) return \"No included content selected\";\n\tif (result.selectionState?.kind === \"different\")\n\t\treturn \"Synced-content list differs; review needed\";\n\tif (result.firstSync)\n\t\treturn result.head\n\t\t\t? \"No sync baseline; review remote and local content\"\n\t\t\t: \"Remote empty; no sync baseline\";\n\tif (!result.head) return \"Remote snapshot missing; review needed\";\n\tif (result.localChanged && result.remoteChanged)\n\t\treturn \"Local and remote changed since last sync; review needed\";\n\tif (result.remoteChanged) return \"Remote changed since last sync\";\n\tif (result.localChanged) return \"Local content changed since last sync\";\n\tif (result.selectionState?.kind === \"legacy\")\n\t\treturn \"Legacy remote has no authoritative content list\";\n\treturn \"No changes detected since last sync\";\n}\n\nexport function observationNeedsAttention(observation: StartupObservation) {\n\tconst result = observation.inspection;\n\treturn (\n\t\tresult.emptyInclude ||\n\t\tresult.firstSync ||\n\t\t!result.head ||\n\t\tresult.localChanged ||\n\t\tresult.remoteChanged ||\n\t\tresult.selectionState?.kind !== \"same\"\n\t);\n}\n\nfunction observationLines(observation: StartupObservation) {\n\treturn [\n\t\t`Pi Sync check \u00B7 ${safeTerminalText(observation.setupName)}`,\n\t\tobservationSummary(observation),\n\t\t\"No startup transfer \u00B7 Run /sync to review\",\n\t];\n}\n\nfunction clearAttentionPresentation(ctx: ExtensionContext) {\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.setWidget(WIDGET_KEY, undefined);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -2,11 +2,10 @@
2
2
  // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
3
  import {
4
4
  setSyncSetupCompletions
5
- } from "./chunk-4U6AFLJB.ts";
5
+ } from "./chunk-CHH26D4F.ts";
6
6
  import {
7
- SetupPullRequiresUiError,
8
7
  safeTerminalText
9
- } from "./chunk-C7LXZ3UH.ts";
8
+ } from "./chunk-LTBWGSBV.ts";
10
9
  import {
11
10
  configuredSyncSetupNames,
12
11
  loadConfig,
@@ -14,9 +13,12 @@ import {
14
13
  syncConfigReviewIdentity,
15
14
  syncSetupReviewIdentity,
16
15
  updateLocalConfig
17
- } from "./chunk-5T442OP3.ts";
16
+ } from "./chunk-C7XY5NF5.ts";
17
+ import {
18
+ SetupPullRequiresUiError
19
+ } from "./chunk-2B2ELUF5.ts";
18
20
 
19
- // src/setup-switch.ts
21
+ // src/sync/setup-switch.ts
20
22
  var SETUP_SWITCH_ACTION_OPTIONS = [
21
23
  { label: "Ask before pull", value: "ask-before-pull" },
22
24
  { label: "Start pull", value: "pull-after-switch" },
@@ -131,4 +133,4 @@ export {
131
133
  saveOnSwitch,
132
134
  useSyncSetup
133
135
  };
134
- //# sourceMappingURL=chunk-GLQLN5GV.ts.map
136
+ //# sourceMappingURL=chunk-SL64RLXR.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/sync/setup-switch.ts"],
4
+ "sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { setSyncSetupCompletions } from \"../commands/command.js\";\nimport {\n\tloadConfig,\n\tsyncConfigReviewIdentity,\n\tsyncSetupReviewIdentity,\n} from \"../settings/config.js\";\nimport { configuredSyncSetupNames, updateLocalConfig } from \"../settings/settings-store.js\";\nimport type { OnSwitchAction } from \"../settings/settings-types.js\";\nimport { normalizeOnSwitch } from \"../settings/settings-validation.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { SetupPullRequiresUiError } from \"./sync-errors.js\";\n\nexport { SetupPullRequiresUiError } from \"./sync-errors.js\";\n\nexport const SETUP_SWITCH_ACTION_OPTIONS: ReadonlyArray<{\n\tlabel: string;\n\tvalue: OnSwitchAction;\n}> = [\n\t{ label: \"Ask before pull\", value: \"ask-before-pull\" },\n\t{ label: \"Start pull\", value: \"pull-after-switch\" },\n\t{ label: \"Switch only\", value: \"switch-only\" },\n];\n\nexport function setupSwitchActionLabel(action: OnSwitchAction) {\n\treturn SETUP_SWITCH_ACTION_OPTIONS.find((option) => option.value === action)?.label ?? action;\n}\n\nexport function setupSwitchActionFromLabel(label: string): OnSwitchAction | undefined {\n\treturn SETUP_SWITCH_ACTION_OPTIONS.find((option) => option.label === label)?.value;\n}\n\nexport async function saveOnSwitch(action: OnSwitchAction, signal?: AbortSignal) {\n\tawait updateLocalConfig((settings) => ({ ...settings, onSwitch: action }), signal);\n}\n\nexport type SetupPullOutcome = \"applied\" | \"cancelled\";\n\nexport interface SetupSwitchResult {\n\tpullApplied: boolean;\n}\n\nexport async function useSyncSetup(\n\tctx: ExtensionCommandContext,\n\tname: string,\n\tpullCurrentSetup?: (setup: string) => Promise<SetupPullOutcome | undefined>,\n\texpectedAction?: OnSwitchAction,\n\tsignal?: AbortSignal,\n\texpectedSetupIdentity?: string,\n): Promise<SetupSwitchResult> {\n\tconst normalized = name.trim();\n\tif (!normalized) throw new Error(\"Usage: /sync use <setup>\");\n\tconst loadedConfig = await loadConfig(normalized);\n\tconst reviewedSetupIdentity = expectedSetupIdentity ?? syncConfigReviewIdentity(loadedConfig);\n\tthrowIfAborted(signal);\n\tconst switchResult: { action: OnSwitchAction; switched: boolean } = {\n\t\taction: \"ask-before-pull\",\n\t\tswitched: false,\n\t};\n\tawait updateLocalConfig((current) => {\n\t\tthrowIfAborted(signal);\n\t\tconst setup = current.syncSetups[normalized];\n\t\tif (!setup) {\n\t\t\tthrow new Error(`Sync setup \u201C${safeTerminalText(normalized)}\u201D no longer exists.`);\n\t\t}\n\t\tconst connectionName = setup.storage.connection;\n\t\tconst connection = current.storageConnections[connectionName];\n\t\tif (\n\t\t\t!connection ||\n\t\t\tsyncSetupReviewIdentity(normalized, setup, connectionName, connection) !==\n\t\t\t\treviewedSetupIdentity\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Sync setup \u201C${safeTerminalText(normalized)}\u201D changed while the switch preview was open; reopen it and review the current destination.`,\n\t\t\t);\n\t\t}\n\t\tswitchResult.action = normalizeOnSwitch(current.onSwitch);\n\t\tif (expectedAction !== undefined && switchResult.action !== expectedAction) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Setup-switch behavior changed while the preview was open; reopen it and retry.\",\n\t\t\t);\n\t\t}\n\t\tif (switchResult.action === \"pull-after-switch\" && !ctx.hasUI) {\n\t\t\tthrow new SetupPullRequiresUiError(\n\t\t\t\t`Automatic setup pulls require interactive confirmation; sync setup \u201C${safeTerminalText(normalized)}\u201D was not switched. Use TUI or RPC mode.`,\n\t\t\t);\n\t\t}\n\t\tif (current.activeSyncSetup === normalized) return current;\n\t\tswitchResult.switched = true;\n\t\treturn { ...current, activeSyncSetup: normalized };\n\t}, signal);\n\tthrowIfAborted(signal);\n\tif (!switchResult.switched) {\n\t\tctx.ui.notify(`Sync setup \u201C${safeTerminalText(normalized)}\u201D is already current.`, \"info\");\n\t\treturn { pullApplied: false };\n\t}\n\tsetSyncSetupCompletions(await configuredSyncSetupNames());\n\tthrowIfAborted(signal);\n\n\tif (switchResult.action === \"switch-only\") {\n\t\tctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D. No files were pulled.`, \"info\");\n\t\treturn { pullApplied: false };\n\t}\n\tif (switchResult.action === \"ask-before-pull\") {\n\t\tif (ctx.mode !== \"tui\") {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Switched to \u201C${safeTerminalText(normalized)}\u201D. No files were pulled because confirmation requires TUI mode; run /sync pull to apply this setup.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t\treturn { pullApplied: false };\n\t\t}\n\t\tconst confirmed = await ctx.ui.confirm(\n\t\t\t`Review a pull for sync setup \u201C${safeTerminalText(normalized)}\u201D now?`,\n\t\t\t\"pi-sync will check the remote snapshot and show the exact local writes and deletions before applying anything.\",\n\t\t\t{ signal },\n\t\t);\n\t\tthrowIfAborted(signal);\n\t\tif (!confirmed) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Switched to \u201C${safeTerminalText(normalized)}\u201D; files were not pulled.`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t\treturn { pullApplied: false };\n\t\t}\n\t}\n\n\tctx.ui.notify(\n\t\t`Switched to \u201C${safeTerminalText(normalized)}\u201D. Checking remote files for a reviewed pull\u2026`,\n\t\t\"info\",\n\t);\n\tif (!pullCurrentSetup) {\n\t\tthrow new Error(`Switched to \u201C${safeTerminalText(normalized)}\u201D, but pull is unavailable.`);\n\t}\n\tconst pullOutcome = await pullCurrentSetup(normalized);\n\tthrowIfAborted(signal);\n\tif (pullOutcome === \"cancelled\") {\n\t\tctx.ui.notify(\n\t\t\t`Pull cancelled; sync setup \u201C${safeTerminalText(normalized)}\u201D remains current and synced files were not changed.`,\n\t\t\t\"info\",\n\t\t);\n\t}\n\treturn { pullApplied: pullOutcome === \"applied\" };\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,57 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+ import {
4
+ createSyncBackend
5
+ } from "./chunk-T2B5IU74.ts";
6
+ import {
7
+ hasLocalChanges,
8
+ remoteChangedSinceState
9
+ } from "./chunk-AUSDLD6F.ts";
10
+ import {
11
+ throwIfAborted
12
+ } from "./chunk-NJFUIVYL.ts";
13
+ import {
14
+ readStateForConfig,
15
+ syncStateFingerprint
16
+ } from "./chunk-CCSN3F47.ts";
17
+ import {
18
+ createSnapshot
19
+ } from "./chunk-OEX4ABY6.ts";
20
+ import {
21
+ inspectRemoteSelection
22
+ } from "./chunk-JAAKLL6M.ts";
23
+
24
+ // src/sync/sync-inspection.ts
25
+ async function inspectSync(config, options, signal, factory = createSyncBackend) {
26
+ throwIfAborted(signal);
27
+ const backend = await factory(config);
28
+ throwIfAborted(signal);
29
+ const local = await createSnapshot(config.snapshotIdentity, { ...options, signal });
30
+ throwIfAborted(signal);
31
+ const state = await readStateForConfig(config);
32
+ throwIfAborted(signal);
33
+ const head = await backend.readHead(signal);
34
+ throwIfAborted(signal);
35
+ return {
36
+ head,
37
+ selectionState: head ? inspectRemoteSelection(config.include, { selection: head.selection, files: [] }) : void 0,
38
+ localFiles: local.files.length,
39
+ localChanged: hasLocalChanges(local, state, config),
40
+ remoteChanged: remoteChangedSinceState(
41
+ head,
42
+ state,
43
+ config,
44
+ (left, right) => backend.sameRevision(left, right)
45
+ ),
46
+ firstSync: !state.lastAppliedSnapshot,
47
+ emptyInclude: config.include.length === 0,
48
+ stateIdentity: syncStateFingerprint(state),
49
+ destination: backend.destination,
50
+ capability: backend.capability
51
+ };
52
+ }
53
+
54
+ export {
55
+ inspectSync
56
+ };
57
+ //# sourceMappingURL=chunk-SZWBGPID.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/sync/sync-inspection.ts"],
4
+ "sourcesContent": ["import { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { createSnapshot } from \"../snapshot/snapshot.js\";\nimport type { SnapshotOptions } from \"../snapshot/snapshot-types.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { inspectRemoteSelection } from \"./sync-policy.js\";\nimport { hasLocalChanges, remoteChangedSinceState } from \"./sync-state.js\";\n\n/** Advisory baseline-relative observation, never an authorization to transfer files. */\nexport async function inspectSync(\n\tconfig: AnySyncConfig,\n\toptions: SnapshotOptions,\n\tsignal?: AbortSignal,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tthrowIfAborted(signal);\n\tconst backend = await factory(config);\n\tthrowIfAborted(signal);\n\tconst local = await createSnapshot(config.snapshotIdentity, { ...options, signal });\n\tthrowIfAborted(signal);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(signal);\n\tconst head = await backend.readHead(signal);\n\tthrowIfAborted(signal);\n\treturn {\n\t\thead,\n\t\tselectionState: head\n\t\t\t? inspectRemoteSelection(config.include, { selection: head.selection, files: [] })\n\t\t\t: undefined,\n\t\tlocalFiles: local.files.length,\n\t\tlocalChanged: hasLocalChanges(local, state, config),\n\t\tremoteChanged: remoteChangedSinceState(head, state, config, (left, right) =>\n\t\t\tbackend.sameRevision(left, right),\n\t\t),\n\t\tfirstSync: !state.lastAppliedSnapshot,\n\t\temptyInclude: config.include.length === 0,\n\t\tstateIdentity: syncStateFingerprint(state),\n\t\tdestination: backend.destination,\n\t\tcapability: backend.capability,\n\t};\n}\n\nexport type SyncInspection = Awaited<ReturnType<typeof inspectSync>>;\n\nexport interface StartupObservation {\n\tsetupName: string;\n\tconfigIdentity: string;\n\tcheckedAt: string;\n\tinspection: SyncInspection;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAUA,eAAsB,YACrB,QACA,SACA,QACA,UAA8B,mBAC7B;AACD,iBAAe,MAAM;AACrB,QAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,iBAAe,MAAM;AACrB,QAAM,QAAQ,MAAM,eAAe,OAAO,kBAAkB,EAAE,GAAG,SAAS,OAAO,CAAC;AAClF,iBAAe,MAAM;AACrB,QAAM,QAAQ,MAAM,mBAAmB,MAAM;AAC7C,iBAAe,MAAM;AACrB,QAAM,OAAO,MAAM,QAAQ,SAAS,MAAM;AAC1C,iBAAe,MAAM;AACrB,SAAO;AAAA,IACN;AAAA,IACA,gBAAgB,OACb,uBAAuB,OAAO,SAAS,EAAE,WAAW,KAAK,WAAW,OAAO,CAAC,EAAE,CAAC,IAC/E;AAAA,IACH,YAAY,MAAM,MAAM;AAAA,IACxB,cAAc,gBAAgB,OAAO,OAAO,MAAM;AAAA,IAClD,eAAe;AAAA,MAAwB;AAAA,MAAM;AAAA,MAAO;AAAA,MAAQ,CAAC,MAAM,UAClE,QAAQ,aAAa,MAAM,KAAK;AAAA,IACjC;AAAA,IACA,WAAW,CAAC,MAAM;AAAA,IAClB,cAAc,OAAO,QAAQ,WAAW;AAAA,IACxC,eAAe,qBAAqB,KAAK;AAAA,IACzC,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,EACrB;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+
4
+ // src/backends/backend-factory.ts
5
+ var createSyncBackend = async (config) => {
6
+ switch (config.backend.type) {
7
+ case "s3": {
8
+ const { S3SyncBackend } = await import("./s3-backend-66O4FGBH.ts");
9
+ return new S3SyncBackend(config.backend);
10
+ }
11
+ case "webdav": {
12
+ const { WebDavSyncBackend } = await import("./webdav-backend-ECIKD7SO.ts");
13
+ return new WebDavSyncBackend(config.backend);
14
+ }
15
+ case "git": {
16
+ const { GitSyncBackend } = await import("./git-backend-GMVS4PD4.ts");
17
+ return new GitSyncBackend(config.backend);
18
+ }
19
+ }
20
+ };
21
+
22
+ export {
23
+ createSyncBackend
24
+ };
25
+ //# sourceMappingURL=chunk-T2B5IU74.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/backends/backend-factory.ts"],
4
+ "sourcesContent": ["import type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { SyncBackend } from \"./sync-backend.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/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/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/git-backend.js\");\n\t\t\treturn new GitSyncBackend(config.backend);\n\t\t}\n\t}\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,0BAAoB;AAC3D,aAAO,IAAI,cAAc,OAAO,OAAO;AAAA,IACxC;AAAA,IACA,KAAK,UAAU;AACd,YAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,8BAA4B;AACvE,aAAO,IAAI,kBAAkB,OAAO,OAAO;AAAA,IAC5C;AAAA,IACA,KAAK,OAAO;AACX,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,2BAAsB;AAC9D,aAAO,IAAI,eAAe,OAAO,OAAO;AAAA,IACzC;AAAA,EACD;AACD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,96 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
3
+
4
+ // src/snapshot/session-paths.ts
5
+ import os from "node:os";
6
+ import path2 from "node:path";
7
+ import {
8
+ getAgentDir
9
+ } from "@earendil-works/pi-coding-agent";
10
+
11
+ // src/state/json-file.ts
12
+ import { randomUUID } from "node:crypto";
13
+ import fs from "node:fs/promises";
14
+ import path from "node:path";
15
+ async function readJsonIfExists(filePath) {
16
+ try {
17
+ return JSON.parse(await fs.readFile(filePath, "utf8"));
18
+ } catch (error) {
19
+ if (error.code === "ENOENT") return void 0;
20
+ throw error;
21
+ }
22
+ }
23
+ async function writeJson(filePath, value) {
24
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
25
+ const temp = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
26
+ await fs.writeFile(temp, `${JSON.stringify(value, null, " ")}
27
+ `, { mode: 384 });
28
+ if (process.platform !== "win32") await fs.chmod(temp, 384);
29
+ await fs.rename(temp, filePath);
30
+ }
31
+
32
+ // src/snapshot/session-paths.ts
33
+ function sessionDirFromContext(ctx) {
34
+ const manager = ctx.sessionManager;
35
+ const usesDefaultSessionDir = manager.usesDefaultSessionDir;
36
+ if (typeof usesDefaultSessionDir === "function" && usesDefaultSessionDir.call(manager)) {
37
+ return void 0;
38
+ }
39
+ const getSessionDir = manager.getSessionDir;
40
+ return typeof getSessionDir === "function" ? getSessionDir.call(manager) : void 0;
41
+ }
42
+ async function configuredSessionDir() {
43
+ const settings = await readJsonIfExists(
44
+ path2.join(agentDir(), "settings.json")
45
+ );
46
+ return settings?.sessionDir ? expandHome(settings.sessionDir) : void 0;
47
+ }
48
+ async function sessionDirForApply(ctx, snapshot) {
49
+ const contextSessionDir = sessionDirFromContext(ctx);
50
+ const localSessionDir = await configuredSessionDir();
51
+ if (contextSessionDir && path2.resolve(contextSessionDir) !== path2.resolve(localSessionDir ?? "")) {
52
+ return contextSessionDir;
53
+ }
54
+ return sessionDirFromSnapshot(snapshot) ?? contextSessionDir;
55
+ }
56
+ function sessionDirFromSnapshot(snapshot) {
57
+ const settingsFile = snapshot.files.find((file) => file.path === "settings.json");
58
+ if (!settingsFile) return void 0;
59
+ try {
60
+ const settings = JSON.parse(
61
+ decodeBase64Strict(settingsFile.contentBase64, settingsFile.path).toString("utf8")
62
+ );
63
+ return settings.sessionDir ? expandHome(settings.sessionDir) : void 0;
64
+ } catch {
65
+ return void 0;
66
+ }
67
+ }
68
+ function decodeBase64Strict(value, filePath) {
69
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {
70
+ throw new Error(`Invalid base64 content in snapshot file: ${filePath}`);
71
+ }
72
+ return Buffer.from(value, "base64");
73
+ }
74
+ function agentDir() {
75
+ return getAgentDir();
76
+ }
77
+ function expandHome(value) {
78
+ return value === "~" || value.startsWith("~/") ? path2.join(os.homedir(), value.slice(2)) : value;
79
+ }
80
+ function snapshotOptionsForContext(ctx, config) {
81
+ return {
82
+ include: config.include,
83
+ sessionDir: sessionDirFromContext(ctx)
84
+ };
85
+ }
86
+
87
+ export {
88
+ readJsonIfExists,
89
+ writeJson,
90
+ sessionDirFromContext,
91
+ configuredSessionDir,
92
+ sessionDirForApply,
93
+ agentDir,
94
+ snapshotOptionsForContext
95
+ };
96
+ //# sourceMappingURL=chunk-T3HH3UEJ.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/snapshot/session-paths.ts", "../../src/state/json-file.ts"],
4
+ "sourcesContent": ["import 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 type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { readJsonIfExists } from \"../state/json-file.js\";\nimport type { Snapshot, SnapshotOptions } from \"./snapshot-types.js\";\n\nexport function sessionDirFromContext(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst manager = ctx.sessionManager as typeof ctx.sessionManager & {\n\t\tusesDefaultSessionDir?: () => boolean;\n\t};\n\tconst usesDefaultSessionDir = manager.usesDefaultSessionDir;\n\tif (typeof usesDefaultSessionDir === \"function\" && usesDefaultSessionDir.call(manager)) {\n\t\treturn undefined;\n\t}\n\tconst getSessionDir = manager.getSessionDir;\n\treturn typeof getSessionDir === \"function\"\n\t\t? (getSessionDir.call(manager) as string | undefined)\n\t\t: undefined;\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 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 function snapshotOptionsForContext(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\tconfig: AnySyncConfig,\n): SnapshotOptions {\n\treturn {\n\t\tinclude: config.include,\n\t\tsessionDir: sessionDirFromContext(ctx),\n\t};\n}\n", "import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport async 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"],
5
+ "mappings": ";;;;AAAA,OAAO,QAAQ;AACf,OAAOA,WAAU;AACjB;AAAA,EAGC;AAAA,OACM;;;ACNP,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,iBAAoB,UAA0C;AACnF,MAAI;AACH,WAAO,KAAK,MAAM,MAAM,GAAG,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,QAAM,GAAG,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,QAAM,OAAO,GAAG,QAAQ,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AACvD,QAAM,GAAG,UAAU,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,GAAI,CAAC;AAAA,GAAM,EAAE,MAAM,IAAM,CAAC;AAClF,MAAI,QAAQ,aAAa,QAAS,OAAM,GAAG,MAAM,MAAM,GAAK;AAC5D,QAAM,GAAG,OAAO,MAAM,QAAQ;AAC/B;;;ADRO,SAAS,sBAAsB,KAAiD;AACtF,QAAM,UAAU,IAAI;AAGpB,QAAM,wBAAwB,QAAQ;AACtC,MAAI,OAAO,0BAA0B,cAAc,sBAAsB,KAAK,OAAO,GAAG;AACvF,WAAO;AAAA,EACR;AACA,QAAM,gBAAgB,QAAQ;AAC9B,SAAO,OAAO,kBAAkB,aAC5B,cAAc,KAAK,OAAO,IAC3B;AACJ;AAEA,eAAsB,uBAAuB;AAC5C,QAAM,WAAW,MAAM;AAAA,IACtBC,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;AAEO,SAAS,WAAW;AAC1B,SAAO,YAAY;AACpB;AAEA,SAAS,WAAW,OAAe;AAClC,SAAO,UAAU,OAAO,MAAM,WAAW,IAAI,IAAIA,MAAK,KAAK,GAAG,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC,IAAI;AAC5F;AAEO,SAAS,0BACf,KACA,QACkB;AAClB,SAAO;AAAA,IACN,SAAS,OAAO;AAAA,IAChB,YAAY,sBAAsB,GAAG;AAAA,EACtC;AACD;",
6
+ "names": ["path", "path"]
7
+ }