@narumitw/pi-sync 0.50.3 → 0.51.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.
- package/README.md +4 -1
- package/dist/chunks/{chunk-6LP3MCR2.ts → chunk-2JZFHNLM.ts} +3 -5
- package/dist/chunks/chunk-2JZFHNLM.ts.map +7 -0
- package/dist/chunks/{chunk-LCRI3ABW.ts → chunk-2RZSQWBH.ts} +8 -19
- package/dist/chunks/chunk-2RZSQWBH.ts.map +7 -0
- package/dist/chunks/{chunk-IJ6FJFA5.ts → chunk-4AIHXRKE.ts} +11 -17
- package/dist/chunks/chunk-4AIHXRKE.ts.map +7 -0
- package/dist/chunks/{chunk-C7XY5NF5.ts → chunk-4MPIH46N.ts} +29 -51
- package/dist/chunks/chunk-4MPIH46N.ts.map +7 -0
- package/dist/chunks/{chunk-5B3FXBLE.ts → chunk-6546TS54.ts} +16 -20
- package/dist/chunks/chunk-6546TS54.ts.map +7 -0
- package/dist/chunks/{chunk-Q2TUM5X6.ts → chunk-6NT3YFGY.ts} +2 -2
- package/dist/chunks/chunk-6NT3YFGY.ts.map +7 -0
- package/dist/chunks/{chunk-2B2ELUF5.ts → chunk-7D5SF7P3.ts} +1 -1
- package/dist/chunks/chunk-7D5SF7P3.ts.map +7 -0
- package/dist/chunks/{chunk-YDWUZVPN.ts → chunk-7KHKWL3Q.ts} +28 -47
- package/dist/chunks/chunk-7KHKWL3Q.ts.map +7 -0
- package/dist/chunks/{chunk-ZI5MXMEX.ts → chunk-BVVP33U5.ts} +2 -4
- package/dist/chunks/chunk-BVVP33U5.ts.map +7 -0
- package/dist/chunks/{chunk-SZWBGPID.ts → chunk-DM4X4FIA.ts} +8 -13
- package/dist/chunks/chunk-DM4X4FIA.ts.map +7 -0
- package/dist/chunks/{chunk-SL64RLXR.ts → chunk-DZUSTGQV.ts} +8 -16
- package/dist/chunks/chunk-DZUSTGQV.ts.map +7 -0
- package/dist/chunks/{chunk-YHEMENKV.ts → chunk-E42GXD6D.ts} +13 -19
- package/dist/chunks/chunk-E42GXD6D.ts.map +7 -0
- package/dist/chunks/{chunk-Z4DQF6L3.ts → chunk-ECYCNZOE.ts} +1 -1
- package/dist/chunks/chunk-ECYCNZOE.ts.map +7 -0
- package/dist/chunks/{chunk-OEX4ABY6.ts → chunk-EEJPYTWE.ts} +11 -21
- package/dist/chunks/chunk-EEJPYTWE.ts.map +7 -0
- package/dist/chunks/{chunk-CPEHGXJV.ts → chunk-G4RUXRWZ.ts} +3 -5
- package/dist/chunks/chunk-G4RUXRWZ.ts.map +7 -0
- package/dist/chunks/{chunk-T2B5IU74.ts → chunk-HGJH56KR.ts} +4 -4
- package/dist/chunks/chunk-HGJH56KR.ts.map +7 -0
- package/dist/chunks/{chunk-JAAKLL6M.ts → chunk-IVXEDPAD.ts} +10 -34
- package/dist/chunks/chunk-IVXEDPAD.ts.map +7 -0
- package/dist/chunks/chunk-K3RIEL6J.ts +20 -0
- package/dist/chunks/chunk-K3RIEL6J.ts.map +7 -0
- package/dist/chunks/{chunk-LTBWGSBV.ts → chunk-MSSW6F3R.ts} +1 -1
- package/dist/chunks/chunk-MSSW6F3R.ts.map +7 -0
- package/dist/chunks/{chunk-T3HH3UEJ.ts → chunk-OVDTF5CH.ts} +4 -10
- package/dist/chunks/chunk-OVDTF5CH.ts.map +7 -0
- package/dist/chunks/{chunk-NJFUIVYL.ts → chunk-PWMWOJP4.ts} +1 -1
- package/dist/chunks/chunk-PWMWOJP4.ts.map +7 -0
- package/dist/chunks/{chunk-HUDQATCL.ts → chunk-Q32CQWPM.ts} +6 -8
- package/dist/chunks/chunk-Q32CQWPM.ts.map +7 -0
- package/dist/chunks/{chunk-ETTRJDNP.ts → chunk-QLSN7AGX.ts} +6 -13
- package/dist/chunks/chunk-QLSN7AGX.ts.map +7 -0
- package/dist/chunks/{chunk-THMF4BVL.ts → chunk-SWUXA3MH.ts} +1 -1
- package/dist/chunks/chunk-SWUXA3MH.ts.map +7 -0
- package/dist/chunks/{chunk-TEN2ZBJV.ts → chunk-T2SJD3N7.ts} +2 -4
- package/dist/chunks/chunk-T2SJD3N7.ts.map +7 -0
- package/dist/chunks/{chunk-AUSDLD6F.ts → chunk-T56RNRZJ.ts} +10 -26
- package/dist/chunks/chunk-T56RNRZJ.ts.map +7 -0
- package/dist/chunks/{chunk-DHVFS4QK.ts → chunk-UA7RXOIT.ts} +37 -90
- package/dist/chunks/chunk-UA7RXOIT.ts.map +7 -0
- package/dist/chunks/{chunk-D5X27LCA.ts → chunk-UETBKTDI.ts} +1 -1
- package/dist/chunks/chunk-UETBKTDI.ts.map +7 -0
- package/dist/chunks/{chunk-CHH26D4F.ts → chunk-YFADF5ZQ.ts} +7 -6
- package/dist/chunks/chunk-YFADF5ZQ.ts.map +7 -0
- package/dist/chunks/{chunk-CCSN3F47.ts → chunk-YPXGU5OR.ts} +4 -4
- package/dist/chunks/chunk-YPXGU5OR.ts.map +7 -0
- package/dist/chunks/{file-selection-FTTKAOYX.ts → file-selection-RAVHRYFG.ts} +14 -26
- package/dist/chunks/file-selection-RAVHRYFG.ts.map +7 -0
- package/dist/chunks/{git-backend-GMVS4PD4.ts → git-backend-IAANDL3K.ts} +41 -104
- package/dist/chunks/git-backend-IAANDL3K.ts.map +7 -0
- package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +23 -0
- package/dist/chunks/{manager-ui-IPAOAWZA.ts → manager-ui-763NEKJY.ts} +124 -251
- package/dist/chunks/manager-ui-763NEKJY.ts.map +7 -0
- package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +22 -0
- package/dist/chunks/{s3-backend-66O4FGBH.ts → s3-backend-XGXUOPUN.ts} +23 -54
- package/dist/chunks/s3-backend-XGXUOPUN.ts.map +7 -0
- package/dist/chunks/{setup-switch-IS2PEZ3J.ts → setup-switch-5G2VNJHL.ts} +9 -9
- package/dist/chunks/{setup-wizard-JUJZYNNM.ts → setup-wizard-YIEWGX32.ts} +12 -12
- package/dist/chunks/setup-wizard-YIEWGX32.ts.map +7 -0
- package/dist/chunks/{snapshot-HKEWCVK6.ts → snapshot-JL5DFSXI.ts} +5 -5
- package/dist/chunks/sync-inspection-P3ENJLNF.ts +20 -0
- package/dist/chunks/{sync-operations-LBX3GKCM.ts → sync-operations-AR76EB6C.ts} +85 -201
- package/dist/chunks/sync-operations-AR76EB6C.ts.map +7 -0
- package/dist/chunks/{sync-state-Q2FTXTW6.ts → sync-state-VHJUZ4YG.ts} +6 -6
- package/dist/chunks/{webdav-backend-ECIKD7SO.ts → webdav-backend-3EGUONAT.ts} +20 -51
- package/dist/chunks/webdav-backend-3EGUONAT.ts.map +7 -0
- package/dist/index.ts +49 -74
- package/dist/index.ts.map +3 -3
- package/docs/settings.md +9 -0
- package/package.json +61 -62
- package/src/backends/backend-factory.ts +15 -15
- package/src/backends/backend-identity.ts +31 -31
- package/src/backends/backend-types.ts +42 -42
- package/src/backends/git/git-backend.ts +714 -788
- package/src/backends/git/git-config.ts +104 -111
- package/src/backends/git/git-runner.ts +230 -247
- package/src/backends/git/git-storage.ts +228 -245
- package/src/backends/s3/s3-backend.ts +408 -441
- package/src/backends/s3/s3-client.ts +288 -333
- package/src/backends/sync-backend.ts +65 -65
- package/src/backends/webdav/webdav-backend.ts +542 -589
- package/src/backends/webdav/webdav-client.ts +292 -316
- package/src/backends/webdav/webdav-config.ts +57 -68
- package/src/commands/command-execution.ts +270 -289
- package/src/commands/command-handler.ts +160 -163
- package/src/commands/command-types.ts +13 -13
- package/src/commands/command.ts +190 -196
- package/src/commands/setup-completions.ts +1 -1
- package/src/paths.ts +47 -47
- package/src/settings/config-errors.ts +4 -5
- package/src/settings/config-file.ts +473 -506
- package/src/settings/config.ts +171 -174
- package/src/settings/settings-management.ts +191 -216
- package/src/settings/settings-store.ts +63 -77
- package/src/settings/settings-types.ts +78 -75
- package/src/settings/settings-validation.ts +328 -364
- package/src/snapshot/session-paths.ts +41 -55
- package/src/snapshot/snapshot-apply.ts +197 -229
- package/src/snapshot/snapshot-codec.ts +29 -31
- package/src/snapshot/snapshot-paths.ts +4 -6
- package/src/snapshot/snapshot-transaction.ts +161 -170
- package/src/snapshot/snapshot-types.ts +24 -24
- package/src/snapshot/snapshot.ts +310 -343
- package/src/state/json-file.ts +11 -11
- package/src/state/lock.ts +226 -242
- package/src/state/lockfile-fs.ts +20 -20
- package/src/state/operation-availability.ts +36 -41
- package/src/state/state-directory.ts +171 -173
- package/src/state/state-types.ts +15 -15
- package/src/state/sync-state-store.ts +23 -23
- package/src/sync/automatic-sync.ts +75 -80
- package/src/sync/remote-snapshot.ts +52 -60
- package/src/sync/setup-switch.ts +99 -114
- package/src/sync/signals.ts +3 -5
- package/src/sync/startup-check.ts +97 -111
- package/src/sync/sync-decision.ts +76 -80
- package/src/sync/sync-error-guidance.ts +41 -48
- package/src/sync/sync-errors.ts +10 -10
- package/src/sync/sync-inspection.ts +29 -33
- package/src/sync/sync-loaders.ts +28 -36
- package/src/sync/sync-mutations.ts +510 -622
- package/src/sync/sync-operations.ts +7 -7
- package/src/sync/sync-policy.ts +296 -326
- package/src/sync/sync-queries.ts +175 -194
- package/src/sync/sync-state.ts +74 -100
- package/src/sync-extension.ts +89 -101
- package/src/sync.ts +26 -26
- package/src/types.ts +37 -37
- package/src/ui/automatic-sync-summary.ts +1 -3
- package/src/ui/cancellable-operation.ts +89 -101
- package/src/ui/file-selection.ts +250 -274
- package/src/ui/manager-attention.ts +51 -63
- package/src/ui/manager-recovery.ts +48 -57
- package/src/ui/manager-result-dispatcher.ts +62 -76
- package/src/ui/manager-state.ts +200 -232
- package/src/ui/manager-ui.ts +264 -362
- package/src/ui/remote-selection-ui.ts +547 -588
- package/src/ui/secret-input.ts +197 -205
- package/src/ui/settings-ui.ts +175 -172
- package/src/ui/setup/git-ui.ts +232 -261
- package/src/ui/setup/s3-credentials-ui.ts +58 -65
- package/src/ui/setup/s3-ui.ts +171 -195
- package/src/ui/setup/setup-actions.ts +91 -101
- package/src/ui/setup/setup-location-ui.ts +121 -137
- package/src/ui/setup/setup-name-ui.ts +27 -27
- package/src/ui/setup/setup-prompts.ts +65 -65
- package/src/ui/setup/setup-review.ts +58 -59
- package/src/ui/setup/setup-switcher.ts +156 -160
- package/src/ui/setup/setup-wizard.ts +28 -28
- package/src/ui/setup/text-input.ts +54 -58
- package/src/ui/setup/webdav-ui.ts +246 -293
- package/src/ui/storage-connections-ui.ts +317 -369
- package/src/ui/sync-attention.ts +148 -164
- package/src/ui/sync-format.ts +110 -121
- package/src/ui/sync-resolution-ui.ts +147 -153
- package/src/ui/sync-setups-ui.ts +218 -238
- package/src/ui/sync-status.ts +17 -0
- package/src/ui/terminal-text.ts +2 -2
- package/dist/chunks/chunk-2B2ELUF5.ts.map +0 -7
- package/dist/chunks/chunk-5B3FXBLE.ts.map +0 -7
- package/dist/chunks/chunk-6LP3MCR2.ts.map +0 -7
- package/dist/chunks/chunk-AUSDLD6F.ts.map +0 -7
- package/dist/chunks/chunk-C7XY5NF5.ts.map +0 -7
- package/dist/chunks/chunk-CCSN3F47.ts.map +0 -7
- package/dist/chunks/chunk-CHH26D4F.ts.map +0 -7
- package/dist/chunks/chunk-CPEHGXJV.ts.map +0 -7
- package/dist/chunks/chunk-D5X27LCA.ts.map +0 -7
- package/dist/chunks/chunk-DHVFS4QK.ts.map +0 -7
- package/dist/chunks/chunk-ETTRJDNP.ts.map +0 -7
- package/dist/chunks/chunk-HUDQATCL.ts.map +0 -7
- package/dist/chunks/chunk-IJ6FJFA5.ts.map +0 -7
- package/dist/chunks/chunk-JAAKLL6M.ts.map +0 -7
- package/dist/chunks/chunk-LCRI3ABW.ts.map +0 -7
- package/dist/chunks/chunk-LTBWGSBV.ts.map +0 -7
- package/dist/chunks/chunk-NJFUIVYL.ts.map +0 -7
- package/dist/chunks/chunk-OEX4ABY6.ts.map +0 -7
- package/dist/chunks/chunk-Q2TUM5X6.ts.map +0 -7
- package/dist/chunks/chunk-SL64RLXR.ts.map +0 -7
- package/dist/chunks/chunk-SZWBGPID.ts.map +0 -7
- package/dist/chunks/chunk-T2B5IU74.ts.map +0 -7
- package/dist/chunks/chunk-T3HH3UEJ.ts.map +0 -7
- package/dist/chunks/chunk-TEN2ZBJV.ts.map +0 -7
- package/dist/chunks/chunk-THMF4BVL.ts.map +0 -7
- package/dist/chunks/chunk-YDWUZVPN.ts.map +0 -7
- package/dist/chunks/chunk-YHEMENKV.ts.map +0 -7
- package/dist/chunks/chunk-Z4DQF6L3.ts.map +0 -7
- package/dist/chunks/chunk-ZI5MXMEX.ts.map +0 -7
- package/dist/chunks/file-selection-FTTKAOYX.ts.map +0 -7
- package/dist/chunks/git-backend-GMVS4PD4.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-ASKGOSW5.ts +0 -22
- package/dist/chunks/manager-ui-IPAOAWZA.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-QDNR7WEI.ts +0 -21
- package/dist/chunks/s3-backend-66O4FGBH.ts.map +0 -7
- package/dist/chunks/setup-wizard-JUJZYNNM.ts.map +0 -7
- package/dist/chunks/sync-inspection-CST2KL65.ts +0 -20
- package/dist/chunks/sync-operations-LBX3GKCM.ts.map +0 -7
- package/dist/chunks/webdav-backend-ECIKD7SO.ts.map +0 -7
- /package/dist/chunks/{manager-result-dispatcher-ASKGOSW5.ts.map → manager-result-dispatcher-OTUMQM26.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-QDNR7WEI.ts.map → remote-selection-ui-TZTJF32Y.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-IS2PEZ3J.ts.map → setup-switch-5G2VNJHL.ts.map} +0 -0
- /package/dist/chunks/{snapshot-HKEWCVK6.ts.map → snapshot-JL5DFSXI.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-CST2KL65.ts.map → sync-inspection-P3ENJLNF.ts.map} +0 -0
- /package/dist/chunks/{sync-state-Q2FTXTW6.ts.map → sync-state-VHJUZ4YG.ts.map} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/snapshot/snapshot-transaction.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { assertWithinRoot, isPathInside } from \"../paths.js\";\nimport { withLock } from \"../state/lock.js\";\nimport { stateDir } from \"../state/state-directory.js\";\nimport { agentDir } from \"./session-paths.js\";\nimport { sessionStorageRoot } from \"./snapshot-paths.js\";\nimport type { SnapshotApplyPlan } from \"./snapshot-types.js\";\n\nconst JOURNAL_VERSION = 1;\n\ninterface TransactionEntry {\n\ttarget: string;\n\tbackupName: string;\n\tkind: \"missing\" | \"file\" | \"directory\" | \"symlink\";\n\tlinkTarget?: string;\n}\n\ninterface TransactionJournal {\n\tversion: number;\n\troot: string;\n\tsessionRoot?: string;\n\tentries: TransactionEntry[];\n}\n\nexport async function applySnapshotTransaction(\n\tplan: SnapshotApplyPlan,\n\toptions: { sessionDir?: string } = {},\n) {\n\tawait recoverPendingSnapshotTransactions();\n\tconst transaction = await prepareTransaction(plan, options.sessionDir);\n\ttry {\n\t\tfor (const target of plan.deletes) {\n\t\t\tawait fs.rm(target, { force: true, recursive: true });\n\t\t}\n\t\tfor (const item of plan.writes) {\n\t\t\tawait fs.mkdir(path.dirname(item.target), { recursive: true });\n\t\t\tawait fs.writeFile(item.target, item.content);\n\t\t}\n\t\tawait fs.rm(transaction.directory, { recursive: true, force: true });\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait restoreTransaction(transaction.directory, transaction.journal);\n\t\t} catch (recoveryError) {\n\t\t\tthrow new AggregateError(\n\t\t\t\t[error, recoveryError],\n\t\t\t\t`Snapshot apply failed and automatic recovery also failed. Transaction retained at ${transaction.directory}.`,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport async function recoverSnapshotTransactionsOnStartup() {\n\tif (!(await pendingTransactionEntries()).some((entry) => entry.isDirectory())) return;\n\tawait withLock(\"recovery\", recoverPendingSnapshotTransactions, { reclaimStale: true });\n}\n\nexport async function recoverPendingSnapshotTransactions() {\n\tconst directory = transactionRoot();\n\tconst entries = await pendingTransactionEntries();\n\tfor (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {\n\t\tif (!entry.isDirectory()) continue;\n\t\tconst transactionDirectory = path.join(directory, entry.name);\n\t\tconst journalPath = path.join(transactionDirectory, \"journal.json\");\n\t\tlet journal: TransactionJournal;\n\t\ttry {\n\t\t\tjournal = JSON.parse(await fs.readFile(journalPath, \"utf8\")) as TransactionJournal;\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\tawait fs.rm(transactionDirectory, { recursive: true, force: true });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthrow new Error(`Cannot recover malformed pi-sync transaction: ${journalPath}`, {\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t\tawait restoreTransaction(transactionDirectory, journal);\n\t}\n}\n\nasync function pendingTransactionEntries() {\n\ttry {\n\t\treturn await fs.readdir(transactionRoot(), { withFileTypes: true });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n\t\tthrow error;\n\t}\n}\n\nasync function prepareTransaction(plan: SnapshotApplyPlan, sessionDir?: string) {\n\tconst root = path.resolve(agentDir());\n\tconst sessionRoot = sessionDir ? path.resolve(sessionStorageRoot(root, sessionDir)) : undefined;\n\tconst directory = path.join(transactionRoot(), randomUUID());\n\tconst backupDirectory = path.join(directory, \"before\");\n\tawait fs.mkdir(backupDirectory, { recursive: true, mode: 0o700 });\n\tconst targets = [...new Set([...plan.deletes, ...plan.writes.map((item) => item.target)])].sort();\n\tconst entries: TransactionEntry[] = [];\n\tfor (let index = 0; index < targets.length; index += 1) {\n\t\tconst target = targets[index];\n\t\tif (!target) continue;\n\t\tassertAllowedTarget(root, sessionRoot, target);\n\t\tconst backupName = `${index}`;\n\t\tconst backupPath = path.join(backupDirectory, backupName);\n\t\ttry {\n\t\t\tconst stat = await fs.lstat(target);\n\t\t\tif (stat.isSymbolicLink()) {\n\t\t\t\tentries.push({\n\t\t\t\t\ttarget,\n\t\t\t\t\tbackupName,\n\t\t\t\t\tkind: \"symlink\",\n\t\t\t\t\tlinkTarget: await fs.readlink(target),\n\t\t\t\t});\n\t\t\t} else if (stat.isDirectory()) {\n\t\t\t\tawait fs.cp(target, backupPath, {\n\t\t\t\t\trecursive: true,\n\t\t\t\t\tdereference: false,\n\t\t\t\t\tpreserveTimestamps: true,\n\t\t\t\t});\n\t\t\t\tentries.push({ target, backupName, kind: \"directory\" });\n\t\t\t} else if (stat.isFile()) {\n\t\t\t\tawait fs.copyFile(target, backupPath);\n\t\t\t\tawait fs.chmod(backupPath, stat.mode);\n\t\t\t\tentries.push({ target, backupName, kind: \"file\" });\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Unsupported existing snapshot target: ${target}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\t\tif (code !== \"ENOENT\" && code !== \"ENOTDIR\") throw error;\n\t\t\tentries.push({ target, backupName, kind: \"missing\" });\n\t\t}\n\t}\n\tconst journal: TransactionJournal = {\n\t\tversion: JOURNAL_VERSION,\n\t\troot,\n\t\tsessionRoot,\n\t\tentries,\n\t};\n\tawait fs.writeFile(\n\t\tpath.join(directory, \"journal.json\"),\n\t\t`${JSON.stringify(journal, null, \"\\t\")}\\n`,\n\t\t{\n\t\t\tmode: 0o600,\n\t\t},\n\t);\n\treturn { directory, journal };\n}\n\nasync function restoreTransaction(directory: string, journal: TransactionJournal) {\n\tvalidateJournal(directory, journal);\n\tfor (const entry of [...journal.entries].sort(\n\t\t(left, right) => right.target.length - left.target.length,\n\t)) {\n\t\tawait fs.rm(entry.target, { recursive: true, force: true });\n\t}\n\tfor (const entry of journal.entries) {\n\t\tif (entry.kind === \"missing\") continue;\n\t\tawait fs.mkdir(path.dirname(entry.target), { recursive: true });\n\t\tconst backupPath = path.join(directory, \"before\", entry.backupName);\n\t\tassertWithinRoot(directory, backupPath);\n\t\tif (entry.kind === \"file\") await fs.copyFile(backupPath, entry.target);\n\t\telse if (entry.kind === \"directory\") {\n\t\t\tawait fs.cp(backupPath, entry.target, {\n\t\t\t\trecursive: true,\n\t\t\t\tdereference: false,\n\t\t\t\tpreserveTimestamps: true,\n\t\t\t});\n\t\t} else if (entry.kind === \"symlink\" && entry.linkTarget !== undefined) {\n\t\t\tawait fs.symlink(entry.linkTarget, entry.target);\n\t\t}\n\t}\n\tawait fs.rm(directory, { recursive: true, force: true });\n}\n\nfunction validateJournal(directory: string, journal: TransactionJournal) {\n\tif (journal.version !== JOURNAL_VERSION || !Array.isArray(journal.entries)) {\n\t\tthrow new Error(`Unsupported pi-sync transaction journal: ${directory}`);\n\t}\n\tconst expectedRoot = path.resolve(agentDir());\n\tif (path.resolve(journal.root) !== expectedRoot) {\n\t\tthrow new Error(`Transaction root no longer matches the Pi agent directory: ${directory}`);\n\t}\n\tfor (const entry of journal.entries) {\n\t\tif (\n\t\t\t!entry ||\n\t\t\ttypeof entry.target !== \"string\" ||\n\t\t\ttypeof entry.backupName !== \"string\" ||\n\t\t\t!/^\\d+$/u.test(entry.backupName)\n\t\t) {\n\t\t\tthrow new Error(`Invalid pi-sync transaction entry: ${directory}`);\n\t\t}\n\t\tassertAllowedTarget(journal.root, journal.sessionRoot, entry.target);\n\t}\n}\n\nfunction assertAllowedTarget(root: string, sessionRoot: string | undefined, target: string) {\n\tconst resolved = path.resolve(target);\n\tif (isPathInside(root, resolved)) {\n\t\tassertWithinRoot(root, resolved);\n\t\treturn;\n\t}\n\tif (sessionRoot && isPathInside(sessionRoot, resolved)) {\n\t\tassertWithinRoot(sessionRoot, resolved);\n\t\treturn;\n\t}\n\tthrow new Error(`Transaction target is outside configured roots: ${target}`);\n}\n\nfunction transactionRoot() {\n\treturn path.join(stateDir(), \"transactions\");\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/paths.ts", "../../src/sync/sync-policy.ts"],
|
|
4
|
-
"sourcesContent": ["import path from \"node:path\";\n\nexport function isDeniedPath(relativePath: string) {\n\tconst normalized = toPosix(relativePath);\n\tconst lower = normalized.toLowerCase();\n\tconst segments = lower.split(\"/\");\n\tconst base = path.posix.basename(lower);\n\treturn (\n\t\tsegments.includes(\"node_modules\") ||\n\t\tsegments.includes(\".git\") ||\n\t\tsegments.includes(\".pisync\") ||\n\t\tsegments.includes(\"pi-sync\") ||\n\t\tsegments.includes(\".pi-sync-state-migration.lock\") ||\n\t\tbase === \".env\" ||\n\t\tbase.startsWith(\".env.\") ||\n\t\tbase.endsWith(\".env\") ||\n\t\tbase.includes(\"secret\") ||\n\t\tbase.includes(\"token\") ||\n\t\tbase === \"pi-sync.json\" ||\n\t\tbase.startsWith(\"pi-sync.json.\") ||\n\t\tbase.startsWith(\".pi-sync.json.\") ||\n\t\tbase === \"pi-sync.local.json\" ||\n\t\tbase.startsWith(\"pi-sync.local.json.\") ||\n\t\tbase.startsWith(\".pi-sync.local.json.\")\n\t);\n}\n\nexport function isPathInside(parent: string, child: string) {\n\tconst relative = path.relative(path.resolve(parent), path.resolve(child));\n\treturn relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nexport function safeJoin(root: string, relativePath: string) {\n\tconst target = path.resolve(root, relativePath);\n\tassertWithinRoot(root, target, relativePath);\n\treturn target;\n}\n\nexport function assertWithinRoot(root: string, target: string, label = target) {\n\tconst resolvedRoot = path.resolve(root);\n\tconst resolvedTarget = path.resolve(target);\n\tif (resolvedTarget !== resolvedRoot && !resolvedTarget.startsWith(`${resolvedRoot}${path.sep}`)) {\n\t\tthrow new Error(`Unsafe path in snapshot: ${label}`);\n\t}\n}\n\nexport function encodeKey(key: string) {\n\treturn key.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nexport function posixJoin(...parts: string[]) {\n\treturn parts\n\t\t.map((part) => trimSlashes(part))\n\t\t.filter(Boolean)\n\t\t.join(\"/\");\n}\n\nexport function parentPaths(relativePath: string) {\n\tconst results: string[] = [];\n\tlet index = relativePath.lastIndexOf(\"/\");\n\twhile (index > 0) {\n\t\tresults.push(relativePath.slice(0, index));\n\t\tindex = relativePath.lastIndexOf(\"/\", index - 1);\n\t}\n\treturn results;\n}\n\nexport function toPosix(value: string) {\n\treturn value.split(path.sep).join(\"/\");\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/g, \"\");\n}\n\nexport function safeName(value: string) {\n\treturn value.replace(/[^A-Za-z0-9._-]/g, \"_\");\n}\n", "import path from \"node:path\";\nimport { isDeniedPath, toPosix } from \"../paths.js\";\nimport type { Snapshot, SnapshotSelection } from \"../snapshot/snapshot-types.js\";\n\nexport const BUILT_IN_SYNC_ROOTS = [\n\t\"settings.json\",\n\t\"keybindings.json\",\n\t\"models.json\",\n\t\"AGENTS.md\",\n\t\"APPEND_SYSTEM.md\",\n\t\"skills\",\n\t\"prompts\",\n\t\"themes\",\n\t\"extensions\",\n] as const;\n\nexport const DEFAULT_SYNC_INCLUDE = [...BUILT_IN_SYNC_ROOTS] as const;\nexport type BuiltInSyncFile = (typeof BUILT_IN_SYNC_ROOTS)[number];\nconst SNAPSHOT_SELECTION_VERSION = 1;\nconst MAX_SYNC_INCLUDE_ITEMS = 1_024;\nconst MAX_SYNC_INCLUDE_PATH_BYTES = 4_096;\nconst MAX_SYNC_INCLUDE_TOTAL_BYTES = 256 * 1_024;\n\ninterface IncludePathNode {\n\tselected?: string;\n\tchildren: Map<string, IncludePathNode>;\n}\n\nconst BUILT_IN_BY_LOWER = new Map<string, BuiltInSyncFile>(\n\tBUILT_IN_SYNC_ROOTS.map((fileName) => [fileName.toLowerCase(), fileName]),\n);\nconst TOP_LEVEL_FILE_PATHS = new Map<string, string>(\n\tBUILT_IN_SYNC_ROOTS.filter((fileName) => fileName.includes(\".\")).map((fileName) => [\n\t\tfileName.toLowerCase(),\n\t\tfileName,\n\t]),\n);\nconst TOP_LEVEL_DIRS = new Set<string>(\n\tBUILT_IN_SYNC_ROOTS.filter((fileName) => !fileName.includes(\".\")),\n);\nconst RESERVED_TOP_LEVEL_NAMES = new Set<string>([...BUILT_IN_BY_LOWER.keys(), \"sessions\"]);\n\nexport function normalizeSyncInclude(value: unknown): string[] {\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(\"Invalid pi-sync settings: sync.include must be an array.\");\n\t}\n\tif (value.length > MAX_SYNC_INCLUDE_ITEMS) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: sync.include has too many items; limit: ${MAX_SYNC_INCLUDE_ITEMS}.`,\n\t\t);\n\t}\n\tconst result: string[] = [];\n\tconst seen = new Set<string>();\n\tconst pathRoot: IncludePathNode = { children: new Map() };\n\tlet totalBytes = 0;\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") {\n\t\t\tthrow new Error(\"Invalid pi-sync settings: sync.include items must be strings.\");\n\t\t}\n\t\tconst itemBytes = Buffer.byteLength(item, \"utf8\");\n\t\tif (itemBytes > MAX_SYNC_INCLUDE_PATH_BYTES) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid pi-sync settings: sync.include item is too long; limit: ${MAX_SYNC_INCLUDE_PATH_BYTES} bytes.`,\n\t\t\t);\n\t\t}\n\t\ttotalBytes += itemBytes;\n\t\tif (totalBytes > MAX_SYNC_INCLUDE_TOTAL_BYTES) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid pi-sync settings: sync.include is too large; limit: ${MAX_SYNC_INCLUDE_TOTAL_BYTES} bytes.`,\n\t\t\t);\n\t\t}\n\t\tconst trimmed = item.trim();\n\t\tconst builtIn = BUILT_IN_BY_LOWER.get(trimmed.toLowerCase());\n\t\tconst normalized = builtIn ?? (trimmed.toLowerCase() === \"sessions\" ? \"sessions\" : trimmed);\n\t\tif (!builtIn && normalized !== \"sessions\") validateAgentRelativeInclude(normalized);\n\t\tconst identity = normalized.toLowerCase();\n\t\tif (seen.has(identity)) {\n\t\t\tthrow new Error(`Invalid pi-sync settings: duplicate sync.include item: ${item}`);\n\t\t}\n\t\taddIncludePath(pathRoot, identity, item);\n\t\tseen.add(identity);\n\t\tresult.push(normalized);\n\t}\n\treturn result;\n}\n\nfunction addIncludePath(root: IncludePathNode, identity: string, source: string) {\n\tlet node = root;\n\tfor (const segment of identity.split(\"/\")) {\n\t\tif (node.selected !== undefined) throwOverlappingInclude(source);\n\t\tlet child = node.children.get(segment);\n\t\tif (!child) {\n\t\t\tchild = { children: new Map() };\n\t\t\tnode.children.set(segment, child);\n\t\t}\n\t\tnode = child;\n\t}\n\tif (node.children.size > 0) throwOverlappingInclude(source);\n\tnode.selected = identity;\n}\n\nfunction throwOverlappingInclude(item: string): never {\n\tthrow new Error(\n\t\t`Invalid pi-sync settings: overlapping sync.include items are ambiguous: ${item}`,\n\t);\n}\n\nfunction validateAgentRelativeInclude(value: string) {\n\tconst normalized = toPosix(value);\n\tconst topLevel = normalized.split(\"/\")[0]?.toLowerCase();\n\tif (\n\t\t!normalized ||\n\t\tnormalized === \".\" ||\n\t\tnormalized === \"..\" ||\n\t\tnormalized.startsWith(\"../\") ||\n\t\tpath.posix.isAbsolute(normalized) ||\n\t\tnormalized.includes(\"\\\\\") ||\n\t\tpath.posix.normalize(normalized) !== normalized ||\n\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Include paths cannot contain controls.\n\t\t/[\\u0000-\\u001f\\u007f-\\u009f]/u.test(normalized)\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: sync.include item must be a safe agent-relative path: ${value}`,\n\t\t);\n\t}\n\tif (isDeniedPath(normalized)) {\n\t\tthrow new Error(`Invalid pi-sync settings: ${value} cannot be synced.`);\n\t}\n\tif (topLevel && RESERVED_TOP_LEVEL_NAMES.has(topLevel)) {\n\t\tthrow new Error(\n\t\t\t`Invalid pi-sync settings: use the canonical ${topLevel} root instead of a nested sync.include path.`,\n\t\t);\n\t}\n}\n\nexport function portableSnapshotSelection(value: unknown): SnapshotSelection {\n\tconst selection = value as Partial<SnapshotSelection> | null;\n\tif (\n\t\t!selection ||\n\t\ttypeof selection !== \"object\" ||\n\t\tArray.isArray(selection) ||\n\t\tselection.version !== SNAPSHOT_SELECTION_VERSION ||\n\t\t!Object.hasOwn(selection, \"include\") ||\n\t\tObject.keys(selection).some((key) => key !== \"version\" && key !== \"include\")\n\t) {\n\t\tthrow new Error(\"Invalid snapshot selection policy.\");\n\t}\n\treturn {\n\t\tversion: SNAPSHOT_SELECTION_VERSION,\n\t\tinclude: normalizeSyncInclude(selection.include),\n\t};\n}\n\nexport function snapshotSelectionInclude(snapshot: Pick<Snapshot, \"selection\">) {\n\treturn snapshot.selection === undefined\n\t\t? undefined\n\t\t: portableSnapshotSelection(snapshot.selection).include;\n}\n\nexport function selectionForSnapshot(include: unknown): SnapshotSelection {\n\treturn { version: SNAPSHOT_SELECTION_VERSION, include: normalizeSyncInclude(include) };\n}\n\nexport function sameSyncInclude(left: unknown, right: unknown) {\n\tconst normalizedLeft = normalizeSyncInclude(left);\n\tconst normalizedRight = normalizeSyncInclude(right);\n\treturn (\n\t\tnormalizedLeft.length === normalizedRight.length &&\n\t\tnormalizedLeft.every((item, index) => item === normalizedRight[index])\n\t);\n}\n\nexport function compareSyncInclude(local: unknown, remote: unknown) {\n\tconst localInclude = normalizeSyncInclude(local);\n\tconst remoteInclude = normalizeSyncInclude(remote);\n\tconst localSet = new Set(localInclude);\n\tconst remoteSet = new Set(remoteInclude);\n\treturn {\n\t\tsame: sameSyncInclude(localInclude, remoteInclude),\n\t\tremoteOnly: remoteInclude.filter((item) => !localSet.has(item)),\n\t\tlocalOnly: localInclude.filter((item) => !remoteSet.has(item)),\n\t};\n}\n\nexport type RemoteSelectionState =\n\t| { kind: \"legacy\"; discovered: string[] }\n\t| { kind: \"same\"; include: string[] }\n\t| {\n\t\t\tkind: \"different\";\n\t\t\tinclude: string[];\n\t\t\tremoteOnly: string[];\n\t\t\tlocalOnly: string[];\n\t };\n\nexport function inspectRemoteSelection(\n\tlocalInclude: unknown,\n\tsnapshot: Pick<Snapshot, \"selection\" | \"files\">,\n): RemoteSelectionState {\n\tconst remoteInclude = snapshotSelectionInclude(snapshot);\n\tif (!remoteInclude) {\n\t\treturn { kind: \"legacy\", discovered: discoverLegacySnapshotInclude(snapshot) };\n\t}\n\tconst comparison = compareSyncInclude(localInclude, remoteInclude);\n\treturn comparison.same\n\t\t? { kind: \"same\", include: remoteInclude }\n\t\t: { kind: \"different\", include: remoteInclude, ...comparison };\n}\n\nexport interface RemoteSelectionDecision {\n\tsetupName: string;\n\tconfigIdentity: string;\n\tlocalInclude: readonly string[];\n\tremoteInclude: readonly string[];\n}\n\nexport class RemoteSelectionMismatchError extends Error {\n\treadonly decision: RemoteSelectionDecision;\n\treadonly setupName: string;\n\treadonly localInclude: string[];\n\treadonly remoteInclude: string[];\n\n\tconstructor(\n\t\tsetupName: string,\n\t\tlocalInclude: unknown,\n\t\tremoteInclude: unknown,\n\t\tconfigIdentity = JSON.stringify([setupName, normalizeSyncInclude(localInclude)]),\n\t) {\n\t\tconst local = normalizeSyncInclude(localInclude);\n\t\tconst remote = normalizeSyncInclude(remoteInclude);\n\t\tsuper(formatRemoteSelectionMismatch(setupName, local, remote));\n\t\tthis.name = \"RemoteSelectionMismatchError\";\n\t\tthis.setupName = setupName;\n\t\tthis.localInclude = local;\n\t\tthis.remoteInclude = remote;\n\t\tthis.decision = {\n\t\t\tsetupName,\n\t\t\tconfigIdentity,\n\t\t\tlocalInclude: [...local],\n\t\t\tremoteInclude: [...remote],\n\t\t};\n\t}\n}\n\nexport function remoteSelectionMismatch(\n\tconfig: { setupName: string; include: unknown },\n\tremoteInclude: unknown,\n\tconfigIdentity?: string,\n) {\n\treturn new RemoteSelectionMismatchError(\n\t\tconfig.setupName,\n\t\tconfig.include,\n\t\tremoteInclude,\n\t\tconfigIdentity,\n\t);\n}\n\nexport function formatRemoteSelectionMismatch(\n\tsetupName: string,\n\tlocalInclude: readonly string[],\n\tremoteInclude: readonly string[],\n) {\n\tconst comparison = compareSyncInclude(localInclude, remoteInclude);\n\tconst lines = [\n\t\t`Synced content differs for sync setup \u201C${stripTerminalControls(setupName)}\u201D.`,\n\t\t`Remote-only: ${comparison.remoteOnly.join(\", \") || \"none\"}`,\n\t\t`This-device-only: ${comparison.localOnly.join(\", \") || \"none\"}`,\n\t];\n\tif (comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0) {\n\t\tlines.push(\n\t\t\t\"Only ordering differs.\",\n\t\t\t`Remote order: ${remoteInclude.join(\", \") || \"none\"}`,\n\t\t\t`This device order: ${localInclude.join(\", \") || \"none\"}`,\n\t\t);\n\t}\n\tlines.push(\"Run /sync in TUI to review both content lists and choose what happens next.\");\n\treturn lines.join(\"\\n\");\n}\n\nfunction stripTerminalControls(value: string) {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.\n\treturn value.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \"?\");\n}\n\nexport function discoverLegacySnapshotInclude(snapshot: Pick<Snapshot, \"files\">) {\n\tconst builtIns = new Set<BuiltInSyncFile>();\n\tconst custom = new Set<string>();\n\tlet sessions = false;\n\tfor (const file of snapshot.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (\n\t\t\t!normalized ||\n\t\t\tfile.path.includes(\"\\\\\") ||\n\t\t\tnormalized.length > 4096 ||\n\t\t\tnormalized.startsWith(\"../\") ||\n\t\t\tpath.posix.isAbsolute(normalized) ||\n\t\t\tpath.posix.normalize(normalized) !== normalized ||\n\t\t\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Ignore unsafe legacy paths.\n\t\t\t/[\\u0000-\\u001f\\u007f-\\u009f]/u.test(normalized) ||\n\t\t\tisDeniedPath(normalized)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst [topLevel, ...rest] = normalized.split(\"/\");\n\t\tif (!topLevel) continue;\n\t\tif (topLevel === \"sessions\" && rest.length > 0) {\n\t\t\tsessions = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst builtIn = BUILT_IN_BY_LOWER.get(topLevel.toLowerCase());\n\t\tif (\n\t\t\tbuiltIn &&\n\t\t\t((TOP_LEVEL_DIRS.has(builtIn) && rest.length > 0) ||\n\t\t\t\t(!TOP_LEVEL_DIRS.has(builtIn) && rest.length === 0))\n\t\t) {\n\t\t\tbuiltIns.add(builtIn);\n\t\t\tcontinue;\n\t\t}\n\t\tif (isSafeCustomIncludePath(topLevel)) custom.add(topLevel);\n\t}\n\treturn [\n\t\t...BUILT_IN_SYNC_ROOTS.filter((item) => builtIns.has(item)),\n\t\t...[...custom].sort((left, right) => left.localeCompare(right)),\n\t\t...(sessions ? [\"sessions\"] : []),\n\t];\n}\n\nexport function syncIncludeSelection(value: unknown) {\n\tconst include = normalizeSyncInclude(value);\n\tconst builtIns = include.filter((item): item is BuiltInSyncFile =>\n\t\tBUILT_IN_BY_LOWER.has(item.toLowerCase()),\n\t);\n\tconst custom = include.filter(\n\t\t(item) => item !== \"sessions\" && !BUILT_IN_BY_LOWER.has(item.toLowerCase()),\n\t);\n\treturn { include, builtIns, custom, sessions: include.includes(\"sessions\") };\n}\n\nexport function customIncludePathsByLower(value: unknown) {\n\treturn new Map(\n\t\tsyncIncludeSelection(value).custom.map((relativePath) => [\n\t\t\trelativePath.toLowerCase(),\n\t\t\trelativePath,\n\t\t]),\n\t);\n}\n\nexport interface SyncSelectionConfig {\n\tinclude?: unknown;\n\tsyncFiles?: unknown;\n\tsyncSessions?: boolean;\n\textraFiles?: unknown;\n}\n\nexport function includeFromSelectionConfig(config: SyncSelectionConfig) {\n\tif (config.include !== undefined) return normalizeSyncInclude(config.include);\n\treturn [\n\t\t...normalizeSyncFiles(config.syncFiles),\n\t\t...normalizeExtraFiles(config.extraFiles),\n\t\t...(config.syncSessions ? [\"sessions\"] : []),\n\t];\n}\n\nexport function isConfiguredSnapshotPath(\n\trelativePath: string,\n\tconfig: SyncSelectionConfig,\n\t_legacyExtraFiles?: Set<string>,\n) {\n\tconst normalized = toPosix(relativePath);\n\tconst selection = syncIncludeSelection(includeFromSelectionConfig(config));\n\tif (normalized.startsWith(\"sessions/\")) return selection.sessions;\n\tconst lower = normalized.toLowerCase();\n\tif (!normalized.includes(\"/\")) {\n\t\tconst builtIn = BUILT_IN_BY_LOWER.get(lower);\n\t\tif (builtIn) return selection.builtIns.includes(builtIn) && !TOP_LEVEL_DIRS.has(builtIn);\n\t}\n\tconst topLevel = normalized.slice(0, normalized.indexOf(\"/\"));\n\tif (selection.builtIns.includes(topLevel as BuiltInSyncFile) && TOP_LEVEL_DIRS.has(topLevel)) {\n\t\treturn true;\n\t}\n\treturn selection.custom.some((candidate) => {\n\t\tconst candidateLower = candidate.toLowerCase();\n\t\treturn lower === candidateLower || lower.startsWith(`${candidateLower}/`);\n\t});\n}\n\nexport function canonicalSnapshotPathForConfig(\n\trelativePath: string,\n\tincludePaths: Map<string, string>,\n) {\n\tconst normalized = toPosix(relativePath);\n\tconst lower = normalized.toLowerCase();\n\treturn TOP_LEVEL_FILE_PATHS.get(lower) ?? includePaths.get(lower) ?? normalized;\n}\n\nexport function isPreservableUnmanagedSnapshotPath(relativePath: string) {\n\tconst normalized = toPosix(relativePath);\n\tif (!normalized || isDeniedPath(normalized)) return false;\n\tif (normalized.startsWith(\"sessions/\")) return normalized.endsWith(\".jsonl\");\n\tif (!normalized.includes(\"/\")) {\n\t\tconst lower = normalized.toLowerCase();\n\t\treturn TOP_LEVEL_FILE_PATHS.has(lower) || !RESERVED_TOP_LEVEL_NAMES.has(lower);\n\t}\n\treturn true;\n}\n\nexport function isSafeCustomIncludePath(relativePath: string) {\n\ttry {\n\t\tvalidateAgentRelativeInclude(relativePath);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function isBuiltInTopLevelFile(fileName: string) {\n\treturn TOP_LEVEL_FILE_PATHS.has(path.posix.basename(fileName).toLowerCase());\n}\n\n/** Compatibility projection for backend-neutral output while callers move to sync.include. */\nexport function normalizeSyncFiles(value: unknown): BuiltInSyncFile[] {\n\tif (value === undefined) return [...DEFAULT_SYNC_INCLUDE];\n\tif (Array.isArray(value)) {\n\t\treturn normalizeSyncInclude(value).filter((item): item is BuiltInSyncFile =>\n\t\t\tBUILT_IN_BY_LOWER.has(item.toLowerCase()),\n\t\t);\n\t}\n\tthrow new Error(\"Invalid pi-sync settings: expected an include array.\");\n}\n\n/** Compatibility projection for old rendering helpers; v3 persistence never writes this split field. */\nexport function normalizeExtraFiles(value: unknown) {\n\tif (!Array.isArray(value)) return [];\n\treturn value.filter(\n\t\t(item): item is string => typeof item === \"string\" && isSafeCustomIncludePath(item),\n\t);\n}\n\nexport const extraFilePathsByLower = customIncludePathsByLower;\nexport const isSafeExtraFileName = isSafeCustomIncludePath;\nexport const selectedSyncFileSet = (value: unknown) => new Set(normalizeSyncFiles(value));\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["path", "path"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/settings/settings-management.ts"],
|
|
4
|
-
"sourcesContent": ["import { isDeepStrictEqual } from \"node:util\";\nimport { normalizeSyncInclude } from \"../sync/sync-policy.js\";\nimport { type SyncSetupStorageReview, syncSetupStorageReview } from \"./config.js\";\nimport { localConfigPath } from \"./config-file.js\";\nimport { updateLocalConfig } from \"./settings-store.js\";\nimport type {\n\tPiSyncSettingsV3,\n\tStorageConnectionSettings,\n\tSyncSetupSettings,\n} from \"./settings-types.js\";\nimport { effectiveSyncSetupRemoteIdentity, validateConfigName } from \"./settings-validation.js\";\n\nexport class SyncSetupReviewChangedError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SyncSetupReviewChangedError\";\n\t}\n}\n\nexport async function saveNewV3Settings(\n\tinput: {\n\t\tsetupName: string;\n\t\tconnectionName: string;\n\t\tconnection: StorageConnectionSettings;\n\t\tsetup: SyncSetupSettings;\n\t},\n\tsignal?: AbortSignal,\n) {\n\tvalidateConfigName(input.setupName, \"sync setup\");\n\tvalidateConfigName(input.connectionName, \"storage connection\");\n\tconst settings: PiSyncSettingsV3 = {\n\t\tversion: 3,\n\t\tactiveSyncSetup: input.setupName,\n\t\tonSwitch: \"ask-before-pull\",\n\t\tskipSecretScan: false,\n\t\tstorageConnections: { [input.connectionName]: structuredClone(input.connection) },\n\t\tsyncSetups: {\n\t\t\t[input.setupName]: {\n\t\t\t\t...structuredClone(input.setup),\n\t\t\t\tstorage: { ...input.setup.storage, connection: input.connectionName },\n\t\t\t},\n\t\t},\n\t};\n\treturn updateLocalConfig((current) => {\n\t\tif (Object.keys(current.storageConnections).length || Object.keys(current.syncSetups).length) {\n\t\t\tthrow new Error(`Settings already exist: ${localConfigPath()}`);\n\t\t}\n\t\treturn { ...current, ...settings };\n\t}, signal);\n}\n\nexport async function addStorageConnection(\n\tname: string,\n\tconnection: StorageConnectionSettings,\n\tsignal?: AbortSignal,\n) {\n\tvalidateConfigName(name, \"storage connection\");\n\tawait updateSettings((settings) => {\n\t\tif (Object.hasOwn(settings.storageConnections, name)) {\n\t\t\tthrow new Error(`Storage connection already exists: ${name}`);\n\t\t}\n\t\treturn {\n\t\t\t...settings,\n\t\t\tstorageConnections: {\n\t\t\t\t...settings.storageConnections,\n\t\t\t\t[name]: structuredClone(connection),\n\t\t\t},\n\t\t};\n\t}, signal);\n}\n\nexport async function updateStorageConnection(\n\tname: string,\n\tupdate: (connection: StorageConnectionSettings) => StorageConnectionSettings,\n\texpectedSetups?: readonly string[],\n\tsignal?: AbortSignal,\n) {\n\tvalidateConfigName(name, \"storage connection\");\n\tawait updateSettings((settings) => {\n\t\tconst connection = settings.storageConnections[name];\n\t\tif (!connection) throw new Error(`Storage connection not found: ${name}`);\n\t\tconst currentSetups = referencingSetupNames(settings.syncSetups, name);\n\t\tif (expectedSetups && !sameNames(currentSetups, expectedSetups)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Storage connection \u201C${name}\u201D usage changed while it was open; reopen it and review the affected sync setups.`,\n\t\t\t);\n\t\t}\n\t\tconst nextConnection = update(structuredClone(connection));\n\t\tconst nextConnections = { ...settings.storageConnections, [name]: nextConnection };\n\t\tassertUniqueLocations(settings.syncSetups, nextConnections);\n\t\treturn { ...settings, storageConnections: nextConnections };\n\t}, signal);\n}\n\nexport async function addSyncSetup(\n\tname: string,\n\tsetup: SyncSetupSettings,\n\tsignal?: AbortSignal,\n\texpectedConnection?: StorageConnectionSettings,\n) {\n\tvalidateConfigName(name, \"sync setup\");\n\tawait updateSettings((settings) => {\n\t\tif (Object.hasOwn(settings.syncSetups, name))\n\t\t\tthrow new Error(`Sync setup already exists: ${name}`);\n\t\tif (!Object.hasOwn(settings.storageConnections, setup.storage.connection)) {\n\t\t\tthrow new Error(`Storage connection not found: ${setup.storage.connection}`);\n\t\t}\n\t\tif (\n\t\t\texpectedConnection &&\n\t\t\t!isDeepStrictEqual(settings.storageConnections[setup.storage.connection], expectedConnection)\n\t\t) {\n\t\t\tthrow new SyncSetupReviewChangedError(\n\t\t\t\t\"Storage connection changed while the setup review was open; reopen it.\",\n\t\t\t);\n\t\t}\n\t\tconst nextSetups = { ...settings.syncSetups, [name]: structuredClone(setup) };\n\t\tassertUniqueLocations(nextSetups, settings.storageConnections);\n\t\treturn {\n\t\t\t...settings,\n\t\t\tsyncSetups: nextSetups,\n\t\t\t...(settings.activeSyncSetup ? {} : { activeSyncSetup: name }),\n\t\t};\n\t}, signal);\n}\n\nexport async function updateSyncSetup(\n\tname: string,\n\tupdate: (setup: SyncSetupSettings) => SyncSetupSettings,\n\toptions: {\n\t\texpectedStorage?: SyncSetupStorageReview;\n\t\texpectedInclude?: readonly string[];\n\t\texpectedConnection?: StorageConnectionSettings;\n\t\tsignal?: AbortSignal;\n\t} = {},\n) {\n\tvalidateConfigName(name, \"sync setup\");\n\tawait updateSettings((settings) => {\n\t\tconst setup = settings.syncSetups[name];\n\t\tif (!setup) throw new Error(`Sync setup not found: ${name}`);\n\t\tif (\n\t\t\toptions.expectedInclude &&\n\t\t\t!sameNames(normalizeSyncInclude(setup.sync.include), options.expectedInclude)\n\t\t) {\n\t\t\tthrow new SyncSetupReviewChangedError(\n\t\t\t\t`Sync setup \u201C${name}\u201D included content changed while it was open; reopen it and review the current selection.`,\n\t\t\t);\n\t\t}\n\t\tif (options.expectedStorage) {\n\t\t\tconst connectionName = setup.storage.connection;\n\t\t\tconst connection = settings.storageConnections[connectionName];\n\t\t\tif (\n\t\t\t\t!connection ||\n\t\t\t\t!sameStorageReview(\n\t\t\t\t\tsyncSetupStorageReview(name, setup, connectionName, connection),\n\t\t\t\t\toptions.expectedStorage,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tthrow new SyncSetupReviewChangedError(\n\t\t\t\t\t`Sync setup \u201C${name}\u201D storage changed while it was open; reopen it and review the current storage location.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\toptions.expectedConnection &&\n\t\t\t!isDeepStrictEqual(\n\t\t\t\tsettings.storageConnections[setup.storage.connection],\n\t\t\t\toptions.expectedConnection,\n\t\t\t)\n\t\t) {\n\t\t\tthrow new SyncSetupReviewChangedError(\n\t\t\t\t\"Storage connection changed while the setup review was open; reopen it.\",\n\t\t\t);\n\t\t}\n\t\tconst nextSetup = update(structuredClone(setup));\n\t\tif (!Object.hasOwn(settings.storageConnections, nextSetup.storage.connection)) {\n\t\t\tthrow new Error(`Storage connection not found: ${nextSetup.storage.connection}`);\n\t\t}\n\t\tconst nextSetups = { ...settings.syncSetups, [name]: nextSetup };\n\t\tassertUniqueLocations(nextSetups, settings.storageConnections);\n\t\treturn { ...settings, syncSetups: nextSetups };\n\t}, options.signal);\n}\n\nexport async function removeSyncSetup(name: string, signal?: AbortSignal) {\n\tvalidateConfigName(name, \"sync setup\");\n\tawait updateSettings((settings) => {\n\t\tif (!Object.hasOwn(settings.syncSetups, name)) throw new Error(`Sync setup not found: ${name}`);\n\t\tconst isCurrent = settings.activeSyncSetup === name;\n\t\tif (isCurrent && Object.keys(settings.syncSetups).length > 1) {\n\t\t\tthrow new Error(\"Switch to another sync setup before removing the current setup.\");\n\t\t}\n\t\tconst syncSetups = { ...settings.syncSetups };\n\t\tdelete syncSetups[name];\n\t\tconst next = { ...settings, syncSetups };\n\t\tif (isCurrent) delete next.activeSyncSetup;\n\t\treturn next;\n\t}, signal);\n}\n\nexport async function removeStorageConnection(name: string, signal?: AbortSignal) {\n\tvalidateConfigName(name, \"storage connection\");\n\tawait updateSettings((settings) => {\n\t\tconst referenced = referencingSetupNames(settings.syncSetups, name)[0];\n\t\tif (referenced) {\n\t\t\tthrow new Error(`Storage connection \u201C${name}\u201D is used by sync setup \u201C${referenced}\u201D.`);\n\t\t}\n\t\tif (!Object.hasOwn(settings.storageConnections, name)) {\n\t\t\tthrow new Error(`Storage connection not found: ${name}`);\n\t\t}\n\t\tconst storageConnections = { ...settings.storageConnections };\n\t\tdelete storageConnections[name];\n\t\treturn { ...settings, storageConnections };\n\t}, signal);\n}\n\nasync function updateSettings(\n\tupdate: (settings: PiSyncSettingsV3) => PiSyncSettingsV3,\n\tsignal?: AbortSignal,\n) {\n\treturn updateLocalConfig((settings) => {\n\t\tif (settings.version !== 3) {\n\t\t\tthrow new Error(\"Storage connections and sync setups require version 3 pi-sync settings.\");\n\t\t}\n\t\treturn update(settings);\n\t}, signal);\n}\n\nfunction referencingSetupNames(setups: Record<string, SyncSetupSettings>, connection: string) {\n\treturn Object.entries(setups)\n\t\t.filter(([, setup]) => setup.storage.connection === connection)\n\t\t.map(([name]) => name)\n\t\t.sort((left, right) => left.localeCompare(right));\n}\n\nfunction assertUniqueLocations(\n\tsetups: Record<string, SyncSetupSettings>,\n\tconnections: Record<string, StorageConnectionSettings>,\n) {\n\tconst identities = new Map<string, string>();\n\tfor (const [name, setup] of Object.entries(setups)) {\n\t\tconst connection = connections[setup.storage.connection];\n\t\tif (!connection) throw new Error(`Storage connection not found: ${setup.storage.connection}`);\n\t\tconst identity = effectiveSyncSetupRemoteIdentity(setup, connection);\n\t\tconst previous = identities.get(identity);\n\t\tif (previous) {\n\t\t\tthrow new Error(`Sync setup \u201C${name}\u201D duplicates the storage location of \u201C${previous}\u201D.`);\n\t\t}\n\t\tidentities.set(identity, name);\n\t}\n}\n\nfunction sameNames(left: readonly string[], right: readonly string[]) {\n\treturn left.length === right.length && left.every((name, index) => name === right[index]);\n}\n\nfunction sameStorageReview(left: SyncSetupStorageReview, right: SyncSetupStorageReview) {\n\treturn (\n\t\tleft.connectionName === right.connectionName &&\n\t\tleft.storageKind === right.storageKind &&\n\t\tleft.storagePath === right.storagePath &&\n\t\tleft.bucket === right.bucket &&\n\t\tleft.branch === right.branch\n\t);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/ui/terminal-text.ts"],
|
|
4
|
-
"sourcesContent": ["export function safeTerminalText(value: string) {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Escape untrusted terminal controls.\n\treturn value.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/gu, \"?\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;AAAO,SAAS,iBAAiB,OAAe;AAE/C,SAAO,MAAM,QAAQ,kCAAkC,GAAG;AAC3D;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/sync/signals.ts"],
|
|
4
|
-
"sourcesContent": ["export function 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\nexport function combineSignals(primary: AbortSignal, secondary?: AbortSignal) {\n\treturn secondary ? AbortSignal.any([primary, secondary]) : primary;\n}\n"],
|
|
5
|
-
"mappings": ";;;;AAAO,SAAS,eAAe,QAAsB;AACpD,MAAI,CAAC,QAAQ,QAAS;AACtB,QAAM,OAAO,kBAAkB,QAC5B,OAAO,SACP,IAAI,aAAa,6BAA6B,YAAY;AAC9D;AAEO,SAAS,eAAe,SAAsB,WAAyB;AAC7E,SAAO,YAAY,YAAY,IAAI,CAAC,SAAS,SAAS,CAAC,IAAI;AAC5D;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/backends/git/git-config.ts"],
|
|
4
|
-
"sourcesContent": ["const DEFAULT_GIT_BRANCH = \"pi-sync\";\nconst DEFAULT_GIT_DIRECTORY = \"pi-sync\";\n\nexport function normalizeGitRemote(value: string | undefined) {\n\tconst normalized = normalizeOptionalString(value);\n\tif (!normalized) return undefined;\n\tif (\n\t\thasControlCharacter(normalized) ||\n\t\t/\\s/u.test(normalized) ||\n\t\tnormalized.startsWith(\"-\") ||\n\t\tnormalized.includes(\"\\\\\")\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote.\");\n\t}\n\tif (\n\t\t!normalized.includes(\"://\") &&\n\t\t/^(?:[A-Za-z0-9._-]+@)?(?:\\[[0-9A-Fa-f:]+\\]|[A-Za-z0-9.-]+):(?!-)[^:].+$/u.test(normalized)\n\t) {\n\t\treturn normalized;\n\t}\n\tif (/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(normalized) && !normalized.includes(\"://\")) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: unsupported transport or remote-helper syntax.\");\n\t}\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(normalized);\n\t} catch {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: use an SSH or HTTPS remote.\");\n\t}\n\tif (url.protocol !== \"https:\" && url.protocol !== \"ssh:\") {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: only SSH and HTTPS are supported.\");\n\t}\n\tif (url.password || (url.protocol === \"https:\" && url.username)) {\n\t\tthrow new Error(\"Invalid pi-sync Git remote: URL credentials or userinfo are not allowed.\");\n\t}\n\tif (url.search || url.hash || !url.hostname || !url.pathname || url.pathname === \"/\") {\n\t\tthrow new Error(\"Invalid pi-sync Git remote.\");\n\t}\n\treturn url.toString();\n}\n\nexport function normalizeGitRemoteIdentity(value: string) {\n\tconst normalized = normalizeGitRemote(value);\n\tif (!normalized) return \"\";\n\tif (!normalized.includes(\"://\")) {\n\t\tconst match =\n\t\t\t/^(?<user>[A-Za-z0-9._-]+@)?(?<host>\\[[0-9A-Fa-f:]+\\]|[A-Za-z0-9.-]+):(?<path>.+)$/u.exec(\n\t\t\t\tnormalized,\n\t\t\t);\n\t\tif (!match?.groups) return normalized;\n\t\tconst userAndHost = `${match.groups.user ?? \"\"}${match.groups.host.toLowerCase()}`;\n\t\tconst remotePath = match.groups.path.replace(/\\/+$/gu, \"\");\n\t\treturn remotePath.startsWith(\"/\")\n\t\t\t? `scp-absolute://${userAndHost}${remotePath}`\n\t\t\t: `ssh://${userAndHost}/${remotePath}`;\n\t}\n\tconst url = new URL(normalized);\n\turl.hostname = url.hostname.toLowerCase();\n\tif (url.protocol === \"ssh:\" && url.port === \"22\") url.port = \"\";\n\turl.pathname = url.pathname.replace(/\\/+$/gu, \"\");\n\tif (url.protocol === \"ssh:\") {\n\t\treturn `ssh://${url.username ? `${url.username}@` : \"\"}${url.host}${url.pathname}`;\n\t}\n\treturn url.toString();\n}\n\nexport function normalizeGitBranch(value: string | undefined) {\n\tconst branch = normalizeOptionalString(value) ?? DEFAULT_GIT_BRANCH;\n\tif (\n\t\tbranch === \"@\" ||\n\t\tbranch.startsWith(\"-\") ||\n\t\tbranch.startsWith(\"refs/\") ||\n\t\tbranch.startsWith(\"/\") ||\n\t\tbranch.endsWith(\"/\") ||\n\t\tbranch.endsWith(\".\") ||\n\t\tbranch.includes(\"..\") ||\n\t\tbranch.includes(\"@{\") ||\n\t\tbranch.includes(\"\\\\\") ||\n\t\thasControlCharacter(branch) ||\n\t\t/[ ~^:?*[\\]]/u.test(branch) ||\n\t\tbranch\n\t\t\t.split(\"/\")\n\t\t\t.some((segment) => !segment || segment.startsWith(\".\") || segment.endsWith(\".lock\"))\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git branch.\");\n\t}\n\treturn branch;\n}\n\nexport function normalizeGitDirectory(value: string | undefined) {\n\tif (value?.trim() === \".\" || value?.trim() === \"./\") return \"./\";\n\tconst directory = trimSlashes(normalizeOptionalString(value) ?? DEFAULT_GIT_DIRECTORY);\n\tif (\n\t\t!directory ||\n\t\tdirectory.startsWith(\"-\") ||\n\t\tdirectory.includes(\"\\\\\") ||\n\t\thasControlCharacter(directory) ||\n\t\tdirectory\n\t\t\t.split(\"/\")\n\t\t\t.some((segment) => !segment || segment === \".\" || segment === \"..\" || segment === \".git\")\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git directory.\");\n\t}\n\treturn directory;\n}\n\nexport function validateGitNamespace(value: string) {\n\tif (\n\t\tvalue.length > 256 ||\n\t\tvalue === \".\" ||\n\t\tvalue === \"..\" ||\n\t\tvalue.includes(\"/\") ||\n\t\tvalue.includes(\"\\\\\") ||\n\t\thasControlCharacter(value)\n\t) {\n\t\tthrow new Error(\"Invalid pi-sync Git namespace.\");\n\t}\n}\n\nfunction normalizeOptionalString(value: unknown) {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new Error(\"Invalid pi-sync settings: expected a string.\");\n\t}\n\tconst normalized = value?.trim();\n\treturn normalized || undefined;\n}\n\nfunction trimSlashes(value: string) {\n\treturn value.replace(/^\\/+|\\/+$/gu, \"\");\n}\n\nfunction hasControlCharacter(value: string) {\n\treturn [...value].some((character) => {\n\t\tconst code = character.codePointAt(0) ?? 0;\n\t\treturn code < 0x20 || (code >= 0x7f && code <= 0x9f);\n\t});\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/snapshot/snapshot-paths.ts"],
|
|
4
|
-
"sourcesContent": ["import path from \"node:path\";\n\nfunction expandHome(value: string) {\n\tif (value === \"~\") return process.env.HOME ?? value;\n\tif (value.startsWith(\"~/\")) return path.join(process.env.HOME ?? \"~\", value.slice(2));\n\treturn value;\n}\n\nexport function sessionStorageRoot(root: string, configuredSessionDir?: string) {\n\treturn configuredSessionDir\n\t\t? path.resolve(expandHome(configuredSessionDir))\n\t\t: path.resolve(root, \"sessions\");\n}\n"],
|
|
5
|
-
"mappings": ";;;;AAAA,OAAO,UAAU;AAEjB,SAAS,WAAW,OAAe;AAClC,MAAI,UAAU,IAAK,QAAO,QAAQ,IAAI,QAAQ;AAC9C,MAAI,MAAM,WAAW,IAAI,EAAG,QAAO,KAAK,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,MAAM,CAAC,CAAC;AACpF,SAAO;AACR;AAEO,SAAS,mBAAmB,MAAc,sBAA+B;AAC/E,SAAO,uBACJ,KAAK,QAAQ,WAAW,oBAAoB,CAAC,IAC7C,KAAK,QAAQ,MAAM,UAAU;AACjC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/ui/remote-selection-ui.ts", "../../src/ui/cancellable-operation.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport type { RemoteHead, SyncBackend } from \"../backends/sync-backend.js\";\nimport {\n\tloadConfig,\n\tloadPartialConfig,\n\ttype SyncSetupStorageReview,\n\tsyncConfigReviewFingerprint,\n} from \"../settings/config.js\";\nimport { SyncSetupReviewChangedError, updateSyncSetup } from \"../settings/settings-management.js\";\nimport type { AnySyncConfig, PartialConfig } from \"../settings/settings-types.js\";\nimport { readSnapshotForHead } from \"../sync/remote-snapshot.js\";\nimport { errorMessage } from \"../sync/sync-errors.js\";\nimport {\n\tcompareSyncInclude,\n\tinspectRemoteSelection,\n\ttype RemoteSelectionDecision,\n\ttype RemoteSelectionState,\n\tsameSyncInclude,\n} from \"../sync/sync-policy.js\";\nimport {\n\ttype RunRoute,\n\ttype RunRouteResult,\n\trunCancellableOperation,\n} from \"./cancellable-operation.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\nconst STATUS_KEY = \"sync\";\n\nexport type RemoteSelectionOrigin = \"settings\" | \"sync\" | \"pull\" | \"push\";\n\nexport interface RemoteSelectionReviewOptions {\n\tdecision?: RemoteSelectionDecision;\n\torigin?: RemoteSelectionOrigin;\n\trunRoute?: RunRoute;\n\tcancelLabel?: string;\n\t/** The explicit mismatch is resolved or superseded; this does not imply file equality. */\n\tonSelectionResolved?: () => void;\n\twithStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport type RemoteSelectionReviewResult =\n\t| { kind: \"back\" }\n\t| { kind: \"closed\" }\n\t| { kind: \"done\" }\n\t| { kind: \"stale\" }\n\t| { kind: \"route-result\"; result: RunRouteResult; route: \"sync\" | \"pull\" | \"push\" };\n\nexport async function showRemoteSelectionReview(\n\tctx: ExtensionContext,\n\tsetupName?: string,\n\tsignal?: AbortSignal,\n\tfactory: SyncBackendFactory = createSyncBackend,\n\toptions: RemoteSelectionReviewOptions = {},\n): Promise<RemoteSelectionReviewResult> {\n\ttry {\n\t\tlet decision = options.decision;\n\t\tif (!decision) {\n\t\t\tconst inspected = await inspectConfiguredRemoteSelection(ctx, setupName, signal, factory);\n\t\t\tif (!inspected || signal?.aborted) return { kind: \"stale\" };\n\t\t\t// A successful fresh read can supersede an old explicit mismatch without\n\t\t\t// changing local settings. This is not user cancellation or proof of file equality.\n\t\t\tif (inspected.kind === \"empty\" || inspected.state.kind !== \"different\") {\n\t\t\t\toptions.onSelectionResolved?.();\n\t\t\t}\n\t\t\tif (inspected.kind === \"empty\") {\n\t\t\t\tctx.ui.notify(\"Remote storage has no snapshot or synced-content list yet.\", \"info\");\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t}\n\t\t\tif (inspected.state.kind === \"same\") {\n\t\t\t\tctx.ui.notify(\"Remote synced content already matches this sync setup.\", \"info\");\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t}\n\t\t\tif (inspected.state.kind === \"legacy\") {\n\t\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\t\tctx.ui.notify(formatLegacySummary(inspected.config, inspected.state.discovered), \"info\");\n\t\t\t\t\treturn { kind: \"back\" };\n\t\t\t\t}\n\t\t\t\tawait showLegacyDiscovery(ctx, inspected.config, inspected.state.discovered, signal);\n\t\t\t\treturn signal?.aborted ? { kind: \"stale\" } : { kind: \"back\" };\n\t\t\t}\n\t\t\tdecision = decisionFromState(inspected.config, inspected.state);\n\t\t}\n\n\t\tif (ctx.mode !== \"tui\") {\n\t\t\tctx.ui.notify(formatRemoteSelectionSummary(decision), \"warning\");\n\t\t\treturn { kind: \"back\" };\n\t\t}\n\n\t\tlet currentDecision = decision;\n\t\tfor (;;) {\n\t\t\tif (signal?.aborted) return { kind: \"stale\" };\n\t\t\tconst result = await showSelectionDifference(\n\t\t\t\tctx,\n\t\t\t\tcurrentDecision,\n\t\t\t\toptions.origin ?? \"settings\",\n\t\t\t\toptions.runRoute,\n\t\t\t\tsignal,\n\t\t\t\tfactory,\n\t\t\t\toptions,\n\t\t\t);\n\t\t\tif (result.kind !== \"refresh\") return result;\n\t\t\tconst refreshed = await runWithOptionalStateAccess(options, () =>\n\t\t\t\tinspectConfiguredRemoteSelection(ctx, currentDecision.setupName, signal, factory),\n\t\t\t);\n\t\t\tif (!refreshed || signal?.aborted) return { kind: \"stale\" };\n\t\t\tif (refreshed.kind === \"empty\") {\n\t\t\t\toptions.onSelectionResolved?.();\n\t\t\t\tctx.ui.notify(\"Remote storage no longer has a snapshot or synced-content list.\", \"warning\");\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t}\n\t\t\tif (refreshed.state.kind !== \"different\") {\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\trefreshed.state.kind === \"same\"\n\t\t\t\t\t\t? \"Remote synced content now matches this sync setup.\"\n\t\t\t\t\t\t: \"The refreshed legacy snapshot has no authoritative synced-content list.\",\n\t\t\t\t\t\"info\",\n\t\t\t\t);\n\t\t\t\toptions.onSelectionResolved?.();\n\t\t\t\treturn { kind: \"done\" };\n\t\t\t}\n\t\t\tcurrentDecision = decisionFromState(refreshed.config, refreshed.state);\n\t\t}\n\t} catch (error) {\n\t\tif (signal?.aborted) return { kind: \"stale\" };\n\t\tctx.ui.notify(`Could not review synced content: ${errorMessage(error)}`, \"error\");\n\t\treturn { kind: \"back\" };\n\t} finally {\n\t\tctx.ui.setStatus(STATUS_KEY, undefined);\n\t}\n}\n\ntype DifferenceFlowResult = RemoteSelectionReviewResult | { kind: \"refresh\" };\n\nasync function showSelectionDifference(\n\tctx: ExtensionContext,\n\tinitialDecision: RemoteSelectionDecision,\n\torigin: RemoteSelectionOrigin,\n\trunRoute: RunRoute | undefined,\n\tsessionSignal: AbortSignal | undefined,\n\tfactory: SyncBackendFactory,\n\toptions: Pick<\n\t\tRemoteSelectionReviewOptions,\n\t\t\"cancelLabel\" | \"onSelectionResolved\" | \"withStateAccess\"\n\t>,\n): Promise<DifferenceFlowResult> {\n\ttype Screen = \"choice\" | \"review\" | \"saved\";\n\ttype Action = \"adopt\" | \"keep\" | \"cancel\" | \"continue\" | \"done\";\n\tinterface FlowState {\n\t\tdecision: RemoteSelectionDecision;\n\t\tsaved: boolean;\n\t}\n\tlet flowState: FlowState = { decision: initialDecision, saved: false };\n\tlet continuationReview: PartialConfig | undefined;\n\tlet nextResult: RemoteSelectionReviewResult | undefined;\n\tlet refreshRequested = false;\n\tconst route = origin === \"settings\" ? \"sync\" : origin;\n\tconst menu = defineMenu<FlowState, Screen, Action, ExtensionContext>({\n\t\tstart: \"choice\",\n\t\tscreens: {\n\t\t\tchoice: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: \"Synced content differs\",\n\t\t\t\tlines: selectionSummaryLines(state.decision),\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"review\",\n\t\t\t\t\t\tlabel: \"Review all paths (recommended)\",\n\t\t\t\t\t\tdescription: \"Compare exact remote-only, device-only, and ordered lists.\",\n\t\t\t\t\t\tto: \"review\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"adopt\",\n\t\t\t\t\t\tlabel: \"Use remote content list\",\n\t\t\t\t\t\tdescription: \"Save the reviewed list on this device without pulling files.\",\n\t\t\t\t\t\taction: \"adopt\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: \"keep\",\n\t\t\t\t\t\tlabel: \"Keep this device's content list and update remote\u2026\",\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Open the existing exact force-push preview without skipping confirmation.\",\n\t\t\t\t\t\taction: \"keep\",\n\t\t\t\t\t},\n\t\t\t\t\t{ id: \"cancel\", label: options.cancelLabel ?? \"Cancel\", action: \"cancel\" },\n\t\t\t\t],\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\treview: ({ state }) => ({\n\t\t\t\tkind: \"review\",\n\t\t\t\ttitle: `Review synced content \u00B7 ${safeTerminalText(state.decision.setupName)}`,\n\t\t\t\tcontent: formatSelectionDifference(state.decision),\n\t\t\t\tformat: { kind: \"text\" },\n\t\t\t\tviewportSize: \"adaptive\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\tsaved: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: \"Remote content list saved\",\n\t\t\t\tlines: [\n\t\t\t\t\t`Sync setup: ${safeTerminalText(state.decision.setupName)}`,\n\t\t\t\t\t\"Only the included-content setting was saved.\",\n\t\t\t\t\t\"No files were pulled and sync state was not changed.\",\n\t\t\t\t],\n\t\t\t\titems: [\n\t\t\t\t\t...(runRoute\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: \"continue\",\n\t\t\t\t\t\t\t\t\tlabel: continueLabel(origin),\n\t\t\t\t\t\t\t\t\tdescription: \"Start a fresh check and exact preview for this sync setup.\",\n\t\t\t\t\t\t\t\t\taction: \"continue\" as const,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t{ id: \"done\", label: \"Done\", action: \"done\" },\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\tadopt: async ({ state, signal: actionSignal }) => {\n\t\t\t\tconst signal = combineSignals(sessionSignal, actionSignal);\n\t\t\t\ttry {\n\t\t\t\t\tconst currentConfig = await loadConfig(state.decision.setupName);\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tassertLocalSelectionCurrent(currentConfig, state.decision);\n\t\t\t\t\tif (\n\t\t\t\t\t\t!currentConfig.include.includes(\"sessions\") &&\n\t\t\t\t\t\tstate.decision.remoteInclude.includes(\"sessions\")\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst acknowledged = await ctx.ui.confirm(\n\t\t\t\t\t\t\t\"Use a content list that includes session conversations?\",\n\t\t\t\t\t\t\t\"Session JSONL may contain prompts, tool output, file paths, images, and secrets. This saves the list only; it does not pull files.\",\n\t\t\t\t\t\t\t{ signal },\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\t\tif (!acknowledged) return { kind: \"stay\" as const };\n\t\t\t\t\t}\n\t\t\t\t\tconst review = await runWithOptionalStateAccess(options, async () => {\n\t\t\t\t\t\tconst loaded = await loadAdoptionReview(state.decision, signal, factory);\n\t\t\t\t\t\tif (signal.aborted) throw signal.reason;\n\t\t\t\t\t\tawait revalidateAndAdopt(loaded, state.decision, signal);\n\t\t\t\t\t\treturn loaded;\n\t\t\t\t\t});\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\toptions.onSelectionResolved?.();\n\t\t\t\t\tcontinuationReview = {\n\t\t\t\t\t\t...review.storageReview,\n\t\t\t\t\t\tsetupName: state.decision.setupName,\n\t\t\t\t\t\tinclude: [...state.decision.remoteInclude],\n\t\t\t\t\t\tautomatic: review.config.automatic,\n\t\t\t\t\t\tonSwitch: review.config.onSwitch,\n\t\t\t\t\t};\n\t\t\t\t\tflowState = { decision: state.decision, saved: true };\n\t\t\t\t\treturn { kind: \"to\" as const, screen: \"saved\" as const };\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tif (isStaleReviewError(error)) {\n\t\t\t\t\t\tctx.ui.notify(`${errorMessage(error)} Refreshing the comparison.`, \"warning\");\n\t\t\t\t\t\trefreshRequested = true;\n\t\t\t\t\t\treturn { kind: \"close\" as const };\n\t\t\t\t\t}\n\t\t\t\t\tctx.ui.notify(`Could not save the remote content list: ${errorMessage(error)}`, \"error\");\n\t\t\t\t\treturn { kind: \"stay\" as const };\n\t\t\t\t}\n\t\t\t},\n\t\t\tkeep: async ({ state, signal: actionSignal }) => {\n\t\t\t\tif (!runRoute) {\n\t\t\t\t\tctx.ui.notify(\"The reviewed update-remote route is unavailable.\", \"error\");\n\t\t\t\t\treturn { kind: \"stay\" as const };\n\t\t\t\t}\n\t\t\t\tconst signal = combineSignals(sessionSignal, actionSignal);\n\t\t\t\ttry {\n\t\t\t\t\tconst latest = await loadConfig(state.decision.setupName);\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tassertLocalSelectionCurrent(latest, state.decision);\n\t\t\t\t\tconst result = await runCancellableOperation(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\"Preparing this device's push preview\u2026\",\n\t\t\t\t\t\t\"push --force\",\n\t\t\t\t\t\trunRoute,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcommitAware: true,\n\t\t\t\t\t\t\tcancelledMessage: \"Push preparation cancelled; no remote files were changed.\",\n\t\t\t\t\t\t\ttarget: state.decision.setupName,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn handleNestedRouteResult(result, \"push\");\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tif (isStaleReviewError(error)) {\n\t\t\t\t\t\tctx.ui.notify(`${errorMessage(error)} Refreshing the comparison.`, \"warning\");\n\t\t\t\t\t\trefreshRequested = true;\n\t\t\t\t\t\treturn { kind: \"close\" as const };\n\t\t\t\t\t}\n\t\t\t\t\tctx.ui.notify(`Could not prepare the remote update: ${errorMessage(error)}`, \"error\");\n\t\t\t\t\treturn { kind: \"stay\" as const };\n\t\t\t\t}\n\t\t\t},\n\t\t\tcontinue: async ({ state, signal: actionSignal }) => {\n\t\t\t\tif (!runRoute || !continuationReview) return { kind: \"stay\" as const };\n\t\t\t\tconst signal = combineSignals(sessionSignal, actionSignal);\n\t\t\t\ttry {\n\t\t\t\t\tconst latest = await loadPartialConfig(state.decision.setupName);\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tif (!sameContinuationReview(latest, continuationReview)) {\n\t\t\t\t\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t\t\t\t\t`Sync setup \u201C${safeTerminalText(state.decision.setupName)}\u201D changed after the remote content list was saved.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst result = await runCancellableOperation(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\tcontinueBusyLabel(origin),\n\t\t\t\t\t\troute,\n\t\t\t\t\t\trunRoute,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcommitAware: true,\n\t\t\t\t\t\t\tcancelledMessage: continuationCancelledMessage(route),\n\t\t\t\t\t\t\ttarget: state.decision.setupName,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn handleNestedRouteResult(result, route);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\t\t\t\tctx.ui.notify(`Could not continue: ${errorMessage(error)}`, \"error\");\n\t\t\t\t\treturn { kind: \"stay\" as const };\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancel: async () => ({ kind: \"back\" }),\n\t\t\tdone: async () => {\n\t\t\t\tnextResult = { kind: \"done\" };\n\t\t\t\treturn { kind: \"close\" };\n\t\t\t},\n\t\t},\n\t});\n\n\tfunction handleNestedRouteResult(\n\t\tresult: Awaited<ReturnType<typeof runCancellableOperation>>,\n\t\tnestedRoute: \"sync\" | \"pull\" | \"push\",\n\t) {\n\t\tif (result.kind === \"completed\" && result.outcome === \"applied\") {\n\t\t\toptions.onSelectionResolved?.();\n\t\t}\n\t\tif (result.kind === \"closed\") {\n\t\t\tnextResult = { kind: \"closed\" };\n\t\t\treturn { kind: \"close\" as const };\n\t\t}\n\t\tif (\n\t\t\tresult.kind === \"cancelled\" ||\n\t\t\t(result.kind === \"completed\" && result.outcome === \"cancelled\") ||\n\t\t\tresult.kind === \"failed\"\n\t\t) {\n\t\t\treturn { kind: \"stay\" as const };\n\t\t}\n\t\tnextResult = { kind: \"route-result\", result, route: nestedRoute };\n\t\treturn { kind: \"close\" as const };\n\t}\n\n\tconst menuResult = await runMenu(ctx, menu, {\n\t\tgetState: () => flowState,\n\t\tsignal: sessionSignal,\n\t\tisCurrent: () => !sessionSignal?.aborted,\n\t\tonError: (_menuCtx, error) => ctx.ui.notify(errorMessage(error), \"error\"),\n\t});\n\tif (sessionSignal?.aborted || menuResult.kind === \"stale\") return { kind: \"stale\" };\n\tif (refreshRequested) return { kind: \"refresh\" };\n\tif (nextResult) return nextResult;\n\tif (menuResult.kind === \"closed\") {\n\t\treturn menuResult.reason === \"back\" ? { kind: \"back\" } : { kind: \"closed\" };\n\t}\n\treturn { kind: \"closed\" };\n}\n\ninterface AdoptionReview {\n\tconfig: AnySyncConfig;\n\tstorageReview: SyncSetupStorageReview;\n\tbackend: SyncBackend;\n\treviewedHead: RemoteHead;\n}\n\nasync function loadAdoptionReview(\n\tdecision: RemoteSelectionDecision,\n\tsignal: AbortSignal,\n\tfactory: SyncBackendFactory,\n): Promise<AdoptionReview> {\n\tconst config = await loadConfig(decision.setupName);\n\tthrowIfAborted(signal);\n\tassertLocalSelectionCurrent(config, decision);\n\tconst partial = await loadPartialConfig(decision.setupName);\n\tthrowIfAborted(signal);\n\tif (!sameSyncInclude(partial.include, decision.localInclude)) {\n\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t`Sync setup \u201C${safeTerminalText(decision.setupName)}\u201D changed while the comparison was open.`,\n\t\t);\n\t}\n\tconst backend = await factory(config);\n\tthrowIfAborted(signal);\n\tconst reviewedHead = await backend.readHead(signal);\n\tthrowIfAborted(signal);\n\tif (!reviewedHead) {\n\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t\"Remote storage changed while the comparison was open.\",\n\t\t);\n\t}\n\tconst snapshot = await readSnapshotForHead(backend, reviewedHead, signal);\n\tthrowIfAborted(signal);\n\tconst state = inspectRemoteSelection(config.include, snapshot);\n\tif (state.kind !== \"different\" || !sameSyncInclude(state.include, decision.remoteInclude)) {\n\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t\"Remote synced content changed while the comparison was open.\",\n\t\t);\n\t}\n\treturn { config, storageReview: partial, backend, reviewedHead };\n}\n\nasync function revalidateAndAdopt(\n\treview: AdoptionReview,\n\tdecision: RemoteSelectionDecision,\n\tsignal: AbortSignal,\n) {\n\tconst currentHead = await review.backend.readHead(signal);\n\tthrowIfAborted(signal);\n\tif (\n\t\t!currentHead ||\n\t\t!review.backend.sameRevision(review.reviewedHead.revision, currentHead.revision)\n\t) {\n\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t\"Remote storage changed while the comparison was open.\",\n\t\t);\n\t}\n\tconst currentSnapshot = await readSnapshotForHead(review.backend, currentHead, signal);\n\tthrowIfAborted(signal);\n\tconst currentState = inspectRemoteSelection(review.config.include, currentSnapshot);\n\tif (\n\t\tcurrentState.kind !== \"different\" ||\n\t\t!sameSyncInclude(currentState.include, decision.remoteInclude)\n\t) {\n\t\tthrow new StaleRemoteSelectionReviewError(\n\t\t\t\"Remote synced content changed while the comparison was open.\",\n\t\t);\n\t}\n\tawait updateSyncSetup(\n\t\tdecision.setupName,\n\t\t(setup) => ({\n\t\t\t...setup,\n\t\t\tsync: { ...setup.sync, include: [...decision.remoteInclude] },\n\t\t}),\n\t\t{\n\t\t\texpectedStorage: review.storageReview,\n\t\t\texpectedInclude: decision.localInclude,\n\t\t\tsignal,\n\t\t},\n\t);\n}\n\nasync function inspectConfiguredRemoteSelection(\n\tctx: ExtensionContext,\n\tsetupName: string | undefined,\n\tsignal: AbortSignal | undefined,\n\tfactory: SyncBackendFactory,\n): Promise<\n\t| { kind: \"empty\"; config: AnySyncConfig }\n\t| { kind: \"selection\"; config: AnySyncConfig; state: RemoteSelectionState }\n\t| undefined\n> {\n\tconst config = await loadConfig(setupName);\n\tif (signal?.aborted) return undefined;\n\tctx.ui.setStatus(STATUS_KEY, `checking synced content for ${safeTerminalText(config.setupName)}`);\n\tconst backend = await factory(config);\n\tif (signal?.aborted) return undefined;\n\tconst head = await backend.readHead(signal);\n\tif (signal?.aborted) return undefined;\n\tif (!head) return { kind: \"empty\", config };\n\tconst snapshot = await readSnapshotForHead(backend, head, signal);\n\tif (signal?.aborted) return undefined;\n\treturn {\n\t\tkind: \"selection\",\n\t\tconfig,\n\t\tstate: inspectRemoteSelection(config.include, snapshot),\n\t};\n}\n\nasync function showLegacyDiscovery(\n\tctx: ExtensionContext,\n\tconfig: AnySyncConfig,\n\tdiscovered: string[],\n\tsignal?: AbortSignal,\n) {\n\tconst menu = defineMenu<undefined, \"choice\" | \"review\", \"back\", ExtensionContext>({\n\t\tstart: \"choice\",\n\t\tscreens: {\n\t\t\tchoice: () => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: `Compare synced content \u00B7 ${safeTerminalText(config.setupName)}`,\n\t\t\t\tlines: [\n\t\t\t\t\t\"This legacy snapshot has no portable synced-content list.\",\n\t\t\t\t\t\"Discovered paths are partial and read-only; preserved files may not have been selected.\",\n\t\t\t\t],\n\t\t\t\titems: [\n\t\t\t\t\t{ id: \"review\", label: \"Review discovered paths\", to: \"review\" },\n\t\t\t\t\t{ id: \"back\", label: \"Back\", action: \"back\" },\n\t\t\t\t],\n\t\t\t\thint: \"close\",\n\t\t\t}),\n\t\t\treview: () => ({\n\t\t\t\tkind: \"review\",\n\t\t\t\ttitle: \"Partial discovery from legacy snapshot\",\n\t\t\t\tcontent: [\n\t\t\t\t\t\"Partial discovery only \u2014 not an authoritative selection.\",\n\t\t\t\t\t\"\",\n\t\t\t\t\t...(discovered.length > 0\n\t\t\t\t\t\t? discovered.map((item) => `Discovered: ${safeTerminalText(item)}`)\n\t\t\t\t\t\t: [\"No safe paths were discovered.\"]),\n\t\t\t\t\t\"\",\n\t\t\t\t\t\"Use Add custom path\u2026 in the local Included Content editor if needed.\",\n\t\t\t\t].join(\"\\n\"),\n\t\t\t\tformat: { kind: \"text\" },\n\t\t\t\tviewportSize: \"adaptive\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: { back: async () => ({ kind: \"close\" }) },\n\t});\n\tawait runMenu(ctx, menu, {\n\t\tgetState: () => undefined,\n\t\tsignal,\n\t\tisCurrent: () => !signal?.aborted,\n\t});\n}\n\nfunction selectionSummaryLines(decision: RemoteSelectionDecision) {\n\tconst comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n\treturn [\n\t\t`Sync setup: ${safeTerminalText(decision.setupName)}`,\n\t\t\"Nothing changed. Review both lists before choosing what happens next.\",\n\t\t...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n\t\t\t? [\"Only the ordering differs; membership is the same.\"]\n\t\t\t: [\n\t\t\t\t\t`Remote-only paths: ${comparison.remoteOnly.length} \u00B7 Device-only paths: ${comparison.localOnly.length}`,\n\t\t\t\t]),\n\t];\n}\n\nfunction formatSelectionDifference(decision: RemoteSelectionDecision) {\n\tconst comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n\treturn [\n\t\t...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n\t\t\t? [\"Only ordering differs; both lists contain the same paths.\", \"\"]\n\t\t\t: []),\n\t\t\"Remote-only paths:\",\n\t\t...(comparison.remoteOnly.length > 0\n\t\t\t? comparison.remoteOnly.map((item) => `+ ${safeTerminalText(item)}`)\n\t\t\t: [\"(none)\"]),\n\t\t\"\",\n\t\t\"Device-only paths:\",\n\t\t...(comparison.localOnly.length > 0\n\t\t\t? comparison.localOnly.map((item) => `- ${safeTerminalText(item)}`)\n\t\t\t: [\"(none)\"]),\n\t\t\"\",\n\t\t\"Remote ordered list:\",\n\t\t...(decision.remoteInclude.length > 0\n\t\t\t? decision.remoteInclude.map((item, index) => `${index + 1}. ${safeTerminalText(item)}`)\n\t\t\t: [\"(none)\"]),\n\t\t\"\",\n\t\t\"This device's ordered list:\",\n\t\t...(decision.localInclude.length > 0\n\t\t\t? decision.localInclude.map((item, index) => `${index + 1}. ${safeTerminalText(item)}`)\n\t\t\t: [\"(none)\"]),\n\t\t\"\",\n\t\t\"Using the remote list saves settings only and does not pull files.\",\n\t].join(\"\\n\");\n}\n\nfunction formatRemoteSelectionSummary(decision: RemoteSelectionDecision) {\n\tconst comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n\treturn [\n\t\t`Synced content for \u201C${safeTerminalText(decision.setupName)}\u201D differs from this device.`,\n\t\t`Remote-only: ${safeList(comparison.remoteOnly)}`,\n\t\t`Device-only: ${safeList(comparison.localOnly)}`,\n\t\t...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n\t\t\t? [\n\t\t\t\t\t\"Only ordering differs.\",\n\t\t\t\t\t`Remote order: ${safeList(decision.remoteInclude)}`,\n\t\t\t\t\t`Device order: ${safeList(decision.localInclude)}`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t\"Run /sync in TUI to choose a content list; RPC review is read-only.\",\n\t].join(\"\\n\");\n}\n\nfunction formatLegacySummary(config: AnySyncConfig, discovered: readonly string[]) {\n\treturn `Remote snapshot for \u201C${safeTerminalText(config.setupName)}\u201D has no portable synced-content list; ${discovered.length} safe path${discovered.length === 1 ? \" was\" : \"s were\"} discovered, but the result is partial and read-only.`;\n}\n\nfunction decisionFromState(\n\tconfig: AnySyncConfig,\n\tstate: Extract<RemoteSelectionState, { kind: \"different\" }>,\n): RemoteSelectionDecision {\n\treturn {\n\t\tsetupName: config.setupName,\n\t\tconfigIdentity: syncConfigReviewFingerprint(config),\n\t\tlocalInclude: [...config.include],\n\t\tremoteInclude: [...state.include],\n\t};\n}\n\nfunction assertLocalSelectionCurrent(config: AnySyncConfig, decision: RemoteSelectionDecision) {\n\tif (\n\t\tsyncConfigReviewFingerprint(config) === decision.configIdentity &&\n\t\tsameSyncInclude(config.include, decision.localInclude)\n\t) {\n\t\treturn;\n\t}\n\tthrow new StaleRemoteSelectionReviewError(\n\t\t`Sync setup \u201C${safeTerminalText(config.setupName)}\u201D changed while the comparison was open.`,\n\t);\n}\n\nfunction sameContinuationReview(left: PartialConfig, right: PartialConfig) {\n\treturn (\n\t\tleft.setupName === right.setupName &&\n\t\tleft.connectionName === right.connectionName &&\n\t\tleft.storageKind === right.storageKind &&\n\t\tleft.storagePath === right.storagePath &&\n\t\tleft.bucket === right.bucket &&\n\t\tleft.branch === right.branch &&\n\t\tsameSyncInclude(left.include, right.include)\n\t);\n}\n\nfunction continueLabel(origin: RemoteSelectionOrigin) {\n\tif (origin === \"pull\") return \"Continue Pull now\u2026\";\n\tif (origin === \"push\") return \"Continue Push now\u2026\";\n\treturn \"Continue Sync now\u2026\";\n}\n\nfunction continueBusyLabel(origin: RemoteSelectionOrigin) {\n\tif (origin === \"pull\") return \"Checking remote changes\u2026\";\n\tif (origin === \"push\") return \"Preparing push preview\u2026\";\n\treturn \"Checking current sync setup\u2026\";\n}\n\nfunction continuationCancelledMessage(route: \"sync\" | \"pull\" | \"push\") {\n\tif (route === \"pull\") return \"Pull check cancelled; no local files were changed.\";\n\tif (route === \"push\") return \"Push preparation cancelled; no remote files were changed.\";\n\treturn \"Sync check cancelled; no settings or files were changed.\";\n}\n\nfunction safeList(values: readonly string[]) {\n\treturn values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n\nclass StaleRemoteSelectionReviewError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"StaleRemoteSelectionReviewError\";\n\t}\n}\n\nfunction isStaleReviewError(error: unknown) {\n\treturn (\n\t\terror instanceof StaleRemoteSelectionReviewError || error instanceof SyncSetupReviewChangedError\n\t);\n}\n\nfunction runWithOptionalStateAccess<T>(\n\toptions: Pick<RemoteSelectionReviewOptions, \"withStateAccess\">,\n\ttask: () => Promise<T>,\n) {\n\treturn options.withStateAccess ? options.withStateAccess(task) : task();\n}\n\nfunction combineSignals(sessionSignal: AbortSignal | undefined, actionSignal: AbortSignal) {\n\treturn sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;\n}\n\nfunction throwIfAborted(signal: AbortSignal) {\n\tif (!signal.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n", "import { BorderedLoader, type ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { Key, matchesKey, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { formatInteractionHints, runCustomInteraction } from \"@narumitw/pi-tui-kit\";\nimport type { SetupPullOutcome } from \"../sync/setup-switch.js\";\nimport type { SyncDecision } from \"../sync/sync-decision.js\";\nimport type { RemoteSelectionDecision } from \"../sync/sync-policy.js\";\n\nexport type RunRouteResult =\n\t| { kind: \"completed\"; outcome?: SetupPullOutcome }\n\t| { kind: \"decision-required\"; decision: SyncDecision }\n\t| { kind: \"remote-selection-required\"; decision: RemoteSelectionDecision }\n\t| { kind: \"failed\" };\n\nexport type RunRoute = (\n\troute: string,\n\tsignal?: AbortSignal,\n\tonCommit?: () => void,\n\ttarget?: string,\n) => Promise<RunRouteResult | undefined>;\n\nexport type CancellableOperationResult =\n\t| RunRouteResult\n\t| { kind: \"closed\" }\n\t| { kind: \"cancelled\" };\n\ninterface CancellableOperationOptions {\n\tcommitAware?: boolean;\n\tcancelledMessage?: string | null;\n\ttarget?: string;\n\tsignal?: AbortSignal;\n}\n\nexport async function runCancellableOperation(\n\tctx: ExtensionContext,\n\tmessage: string,\n\troute: string,\n\trunRoute: RunRoute,\n\toptions: CancellableOperationOptions = {},\n): Promise<CancellableOperationResult> {\n\tconst {\n\t\tcommitAware = false,\n\t\tcancelledMessage = \"Check cancelled; no settings or files were changed.\",\n\t\ttarget,\n\t\tsignal,\n\t} = options;\n\tif (ctx.mode !== \"tui\") {\n\t\treturn (await runRoute(route, signal, undefined, target)) ?? { kind: \"failed\" };\n\t}\n\tlet commitStarted = false;\n\tlet routeResult: RunRouteResult | undefined;\n\tconst interaction = await runCustomInteraction<\n\t\t{ cancelled?: boolean; error?: unknown },\n\t\tExtensionContext\n\t>(ctx, {\n\t\tsignal,\n\t\tisCurrent: () => !signal?.aborted,\n\t\tcreate: ({ tui, theme, keybindings, signal: interactionSignal, complete }) => {\n\t\t\tconst loader = new BorderedLoader(tui, theme, message, { cancellable: false });\n\t\t\tconst cancelHint = formatInteractionHints(keybindings, [\n\t\t\t\t{\n\t\t\t\t\tkeys: [\n\t\t\t\t\t\t...keybindings.getKeys(\"tui.select.cancel\").filter((key) => !hasControlCharacter(key)),\n\t\t\t\t\t\t\"ctrl+c\",\n\t\t\t\t\t],\n\t\t\t\t\tlabel: \"cancel\",\n\t\t\t\t},\n\t\t\t]);\n\t\t\tconst operation = runRoute(\n\t\t\t\troute,\n\t\t\t\tinteractionSignal,\n\t\t\t\tcommitAware ? () => (commitStarted = true) : undefined,\n\t\t\t\ttarget,\n\t\t\t).then(\n\t\t\t\t(result) => {\n\t\t\t\t\trouteResult = result;\n\t\t\t\t\tcomplete({});\n\t\t\t\t},\n\t\t\t\t(error: unknown) => complete({ error }),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\trender(width: number) {\n\t\t\t\t\tconst safeWidth = Math.max(1, width);\n\t\t\t\t\tconst lines = loader.render(safeWidth);\n\t\t\t\t\tconst bottomBorder = lines.at(-1);\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...lines.slice(0, -1),\n\t\t\t\t\t\ttruncateToWidth(theme.fg(\"dim\", cancelHint), safeWidth, \"\"),\n\t\t\t\t\t\t...(bottomBorder === undefined ? [] : [bottomBorder]),\n\t\t\t\t\t];\n\t\t\t\t},\n\t\t\t\tinvalidate: () => loader.invalidate(),\n\t\t\t\thandleInput(data: string) {\n\t\t\t\t\tif (!matchesKey(data, Key.ctrl(\"c\")) && !keybindings.matches(data, \"tui.select.cancel\")) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (commitStarted) {\n\t\t\t\t\t\tctx.ui.notify(\n\t\t\t\t\t\t\t\"Applying or publishing has started and cannot be cancelled safely.\",\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcomplete({ cancelled: true });\n\t\t\t\t},\n\t\t\t\tdispose: () => loader.dispose(),\n\t\t\t\twaitForPending: () => operation,\n\t\t\t};\n\t\t},\n\t});\n\tif (interaction.kind === \"error\") throw interaction.error;\n\tif (interaction.kind !== \"completed\") return { kind: \"closed\" };\n\tif (interaction.value.cancelled) {\n\t\tif (cancelledMessage) ctx.ui.notify(cancelledMessage, \"info\");\n\t\treturn { kind: \"cancelled\" };\n\t}\n\tif (interaction.value.error) throw interaction.value.error;\n\treturn routeResult ?? { kind: \"failed\" };\n}\n\nfunction hasControlCharacter(value: string) {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: Unsafe key labels must be omitted.\n\treturn /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(value);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/ui/sync-resolution-ui.ts", "../../src/ui/manager-result-dispatcher.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { loadConfig, syncConfigReviewIdentity } from \"../settings/config.js\";\nimport type { SyncDecision, SyncResolutionDirection } from \"../sync/sync-decision.js\";\nimport { errorMessage } from \"../sync/sync-errors.js\";\nimport {\n\ttype RunRoute,\n\ttype RunRouteResult,\n\trunCancellableOperation,\n} from \"./cancellable-operation.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\nexport type SyncResolutionResult =\n\t| { kind: \"resolved\"; direction: SyncResolutionDirection }\n\t| {\n\t\t\tkind: \"route-result\";\n\t\t\tresult: RunRouteResult;\n\t\t\troute: SyncResolutionDirection;\n\t }\n\t| { kind: \"back\" }\n\t| { kind: \"closed\" }\n\t| { kind: \"stale\" };\n\nexport async function showSyncResolution(\n\tctx: ExtensionContext,\n\tinitialDecision: SyncDecision,\n\trunRoute: RunRoute,\n\tsessionSignal?: AbortSignal,\n): Promise<SyncResolutionResult> {\n\ttype Screen = \"resolve\" | \"review\";\n\ttype Action = \"push\" | \"pull\" | \"back\";\n\tlet currentDecision = initialDecision;\n\tlet resolvedDirection: SyncResolutionDirection | undefined;\n\tlet chainedResult: { result: RunRouteResult; route: SyncResolutionDirection } | undefined;\n\tconst menu = defineMenu<SyncDecision, Screen, Action, ExtensionContext>({\n\t\tstart: \"resolve\",\n\t\tscreens: {\n\t\t\tresolve: ({ state }) => ({\n\t\t\t\tkind: \"actions\",\n\t\t\t\ttitle: resolutionTitle(state),\n\t\t\t\tlines: resolutionLines(state),\n\t\t\t\titems: [\n\t\t\t\t\t{ id: \"review\", label: \"Review differences (recommended)\", to: \"review\" },\n\t\t\t\t\t...(state.directions.includes(\"push\")\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: \"push\",\n\t\t\t\t\t\t\t\t\tlabel: pushLabel(state),\n\t\t\t\t\t\t\t\t\tdescription: \"Review an exact push before replacing the remote version.\",\n\t\t\t\t\t\t\t\t\taction: \"push\" as const,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t...(state.directions.includes(\"pull\")\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tid: \"pull\",\n\t\t\t\t\t\t\t\t\tlabel: pullLabel(state),\n\t\t\t\t\t\t\t\t\tdescription: \"Review exact local changes and create a backup before applying.\",\n\t\t\t\t\t\t\t\t\taction: \"pull\" as const,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t{ id: \"back\", label: \"Back\", action: \"back\" },\n\t\t\t\t],\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\treview: ({ state }) => ({\n\t\t\t\tkind: \"review\",\n\t\t\t\ttitle: `Review differences \u00B7 ${safeTerminalText(state.setupName)}`,\n\t\t\t\tcontent: state.review,\n\t\t\t\tformat: { kind: \"text\" },\n\t\t\t\tviewportSize: \"adaptive\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\tpush: ({ state, signal }) => resolveDirection(\"push\", state, signal),\n\t\t\tpull: ({ state, signal }) => resolveDirection(\"pull\", state, signal),\n\t\t\tback: async () => ({ kind: \"back\" }),\n\t\t},\n\t});\n\n\tasync function resolveDirection(\n\t\tdirection: SyncResolutionDirection,\n\t\tdecision: SyncDecision,\n\t\tactionSignal: AbortSignal,\n\t) {\n\t\tconst signal = sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;\n\t\tconst config = await loadConfig(decision.setupName);\n\t\tif (signal.aborted) return { kind: \"close\" as const };\n\t\tif (syncConfigReviewIdentity(config) !== decision.configIdentity) {\n\t\t\tthrow new Error(\n\t\t\t\t`Sync setup \u201C${safeTerminalText(decision.setupName)}\u201D changed while conflict resolution was open; return to the sync manager and retry.`,\n\t\t\t);\n\t\t}\n\t\tconst result = await runCancellableOperation(\n\t\t\tctx,\n\t\t\tdirection === \"push\"\n\t\t\t\t? \"Preparing local-wins push preview\u2026\"\n\t\t\t\t: \"Preparing remote-wins pull preview\u2026\",\n\t\t\t`${direction} --force`,\n\t\t\trunRoute,\n\t\t\t{\n\t\t\t\tcommitAware: true,\n\t\t\t\tcancelledMessage:\n\t\t\t\t\tdirection === \"push\"\n\t\t\t\t\t\t? \"Push preparation cancelled; no remote files were changed.\"\n\t\t\t\t\t\t: \"Pull check cancelled; no local files were changed.\",\n\t\t\t\ttarget: decision.setupName,\n\t\t\t\tsignal,\n\t\t\t},\n\t\t);\n\t\tif (result.kind === \"decision-required\") {\n\t\t\tcurrentDecision = result.decision;\n\t\t\treturn { kind: \"stay\" as const };\n\t\t}\n\t\tif (result.kind === \"remote-selection-required\") {\n\t\t\tchainedResult = { result, route: direction };\n\t\t\treturn { kind: \"close\" as const };\n\t\t}\n\t\tif (result.kind === \"completed\") {\n\t\t\tif (result.outcome === \"cancelled\") return { kind: \"stay\" as const };\n\t\t\tresolvedDirection = direction;\n\t\t\treturn { kind: \"close\" as const };\n\t\t}\n\t\treturn result.kind === \"closed\" ? { kind: \"close\" as const } : { kind: \"stay\" as const };\n\t}\n\n\tconst result = await runMenu(ctx, menu, {\n\t\tgetState: () => currentDecision,\n\t\tsignal: sessionSignal,\n\t\tisCurrent: () => !sessionSignal?.aborted,\n\t\tonError: (_menuCtx, error) => ctx.ui.notify(errorMessage(error), \"error\"),\n\t});\n\tif (sessionSignal?.aborted || result.kind === \"stale\") return { kind: \"stale\" };\n\tif (chainedResult) return { kind: \"route-result\", ...chainedResult };\n\tif (resolvedDirection) return { kind: \"resolved\", direction: resolvedDirection };\n\tif (result.kind === \"closed\") {\n\t\treturn result.reason === \"back\" ? { kind: \"back\" } : { kind: \"closed\" };\n\t}\n\treturn { kind: \"closed\" };\n}\n\nfunction resolutionTitle(decision: SyncDecision) {\n\treturn decision.kind === \"remote-empty\" ? \"Remote is empty\" : \"Resolve sync conflict\";\n}\n\nfunction resolutionLines(decision: SyncDecision) {\n\treturn [\n\t\t`Sync setup: ${safeTerminalText(decision.setupName)}`,\n\t\t...causeSummary(decision),\n\t\t\"No files have been changed by this failed operation.\",\n\t];\n}\n\nfunction causeSummary(decision: SyncDecision) {\n\tif (decision.kind === \"first-sync-settings-diverged\") {\n\t\treturn [\"This machine and the remote have different Pi settings on first sync.\"];\n\t}\n\tif (decision.kind === \"first-sync-sessions-diverged\") {\n\t\treturn [\"Pi settings match, but local and remote sessions differ on first sync.\"];\n\t}\n\tif (decision.kind === \"remote-empty\") return [\"The remote storage location has no snapshot.\"];\n\treturn [\n\t\t...(decision.causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n\t\t...(decision.causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n\t\t...(decision.causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n\t];\n}\n\nfunction pushLabel(decision: SyncDecision) {\n\tif (decision.kind === \"remote-empty\") return \"Push local content\u2026\";\n\tif (decision.kind.startsWith(\"first-sync-\")) return \"Use local as initial source\u2026\";\n\treturn \"Keep local content and replace remote\u2026\";\n}\n\nfunction pullLabel(decision: SyncDecision) {\n\treturn decision.kind.startsWith(\"first-sync-\")\n\t\t? \"Use remote as initial source\u2026\"\n\t\t: \"Use remote content and replace local\u2026\";\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type {\n\tCancellableOperationResult,\n\tRunRoute,\n\tRunRouteResult,\n} from \"./cancellable-operation.js\";\nimport { type RemoteSelectionOrigin, showRemoteSelectionReview } from \"./remote-selection-ui.js\";\nimport { showSyncResolution } from \"./sync-resolution-ui.js\";\n\nconst MAX_DECISION_TRANSITIONS = 32;\n\nexport interface ManagerResultDisposition {\n\tkind: \"close\" | \"stay\";\n\tappliedRoute?: \"sync\" | \"pull\" | \"push\";\n}\n\nexport interface ManagerResultOptions {\n\tcancelLabel?: string;\n\tonSelectionResolved?: () => void;\n\twithStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport async function dispatchManagerResult(\n\tctx: ExtensionContext,\n\tinitialResult: CancellableOperationResult,\n\torigin: Exclude<RemoteSelectionOrigin, \"settings\">,\n\trunRoute: RunRoute,\n\tsignal?: AbortSignal,\n\toptions: ManagerResultOptions = {},\n): Promise<ManagerResultDisposition> {\n\tlet result: CancellableOperationResult | RunRouteResult = initialResult;\n\tlet currentRoute: \"sync\" | \"pull\" | \"push\" = origin;\n\tlet resolving = false;\n\n\tfor (let transition = 0; transition < MAX_DECISION_TRANSITIONS; transition += 1) {\n\t\tif (signal?.aborted) return { kind: \"close\" };\n\t\tif (result.kind === \"remote-selection-required\") {\n\t\t\tresolving = true;\n\t\t\tconst resolution = await showRemoteSelectionReview(\n\t\t\t\tctx,\n\t\t\t\tresult.decision.setupName,\n\t\t\t\tsignal,\n\t\t\t\tundefined,\n\t\t\t\t{\n\t\t\t\t\tdecision: result.decision,\n\t\t\t\t\torigin: currentRoute,\n\t\t\t\t\trunRoute,\n\t\t\t\t\tcancelLabel: options.cancelLabel,\n\t\t\t\t\tonSelectionResolved: options.onSelectionResolved,\n\t\t\t\t\twithStateAccess: options.withStateAccess,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (resolution.kind === \"route-result\") {\n\t\t\t\tresult = resolution.result;\n\t\t\t\tcurrentRoute = resolution.route;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn resolution.kind === \"closed\" || resolution.kind === \"stale\"\n\t\t\t\t? { kind: \"close\" }\n\t\t\t\t: { kind: \"stay\" };\n\t\t}\n\t\tif (result.kind === \"decision-required\") {\n\t\t\tresolving = true;\n\t\t\tconst resolution = await showSyncResolution(ctx, result.decision, runRoute, signal);\n\t\t\tif (resolution.kind === \"route-result\") {\n\t\t\t\tresult = resolution.result;\n\t\t\t\tcurrentRoute = resolution.route;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (resolution.kind === \"resolved\") {\n\t\t\t\treturn { kind: \"close\", appliedRoute: resolution.direction };\n\t\t\t}\n\t\t\treturn resolution.kind === \"closed\" || resolution.kind === \"stale\"\n\t\t\t\t? { kind: \"close\" }\n\t\t\t\t: { kind: \"stay\" };\n\t\t}\n\t\tif (result.kind === \"closed\") return { kind: \"close\" };\n\t\tif (result.kind === \"completed\") {\n\t\t\tconst appliedRoute = result.outcome === \"applied\" ? currentRoute : undefined;\n\t\t\tif (resolving || (origin === \"pull\" && result.outcome === \"applied\")) {\n\t\t\t\treturn { kind: \"close\", ...(appliedRoute ? { appliedRoute } : {}) };\n\t\t\t}\n\t\t\treturn { kind: \"stay\", ...(appliedRoute ? { appliedRoute } : {}) };\n\t\t}\n\t\treturn { kind: \"stay\" };\n\t}\n\n\tctx.ui.notify(\n\t\t\"Sync resolution stopped after too many state changes. Start /sync again to review fresh state.\",\n\t\t\"warning\",\n\t);\n\treturn { kind: \"stay\" };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["result"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/ui/automatic-sync-summary.ts"],
|
|
4
|
-
"sourcesContent": ["/** Keep the setting's automatic transfer scope visible in every setup summary. */\nexport function automaticSyncSummary(enabled: boolean) {\n\treturn enabled\n\t\t? \"On (startup check; shutdown pushes selected content if sessions included)\"\n\t\t: \"Off\";\n}\n"],
|
|
5
|
-
"mappings": ";;;;AACO,SAAS,qBAAqB,SAAkB;AACtD,SAAO,UACJ,8EACA;AACJ;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/state/state-directory.ts", "../../src/state/lock-policy.ts", "../../src/state/lockfile-fs.ts"],
|
|
4
|
-
"sourcesContent": ["import { lstatSync } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\nimport lockfile from \"proper-lockfile\";\nimport { LOCK_GUARD_STALE_MS } from \"./lock-policy.js\";\nimport { LOCKFILE_FS_ADAPTER } from \"./lockfile-fs.js\";\n\nconst CANONICAL_DIRECTORY_NAME = \"pi-sync\";\nconst LEGACY_DIRECTORY_NAME = \".pisync\";\nconst MIGRATION_LOCK_NAME = \".pi-sync-state-migration.lock\";\nconst MIGRATION_LOCK_STALE_MS = 30_000;\nconst MIGRATION_LOCK_UPDATE_MS = 10_000;\n\nexport type StateDirectoryPreparation =\n\t| { status: \"ready\" }\n\t| { status: \"migrated\"; message: string }\n\t| { status: \"deferred\"; message: string };\n\ninterface StateDirectoryGuard {\n\trelease: () => Promise<void>;\n\tthrowIfCompromised: () => void;\n}\n\ninterface SharedStateDirectoryGuard {\n\tguard: Promise<StateDirectoryGuard>;\n\tusers: number;\n\tclosing?: Promise<void>;\n}\n\nconst sharedStateDirectoryGuards = new Map<string, SharedStateDirectoryGuard>();\n\nexport function stateDir() {\n\tconst roots = inspectStateRoots();\n\tif (roots.canonical) return canonicalStateDir();\n\tif (roots.legacy) return legacyStateDir();\n\treturn canonicalStateDir();\n}\n\nexport function legacyStateDir() {\n\treturn path.join(getAgentDir(), LEGACY_DIRECTORY_NAME);\n}\n\nexport function stateDirectoryMigrationNotice() {\n\tconst roots = inspectStateRoots();\n\tif (!roots.legacy) return undefined;\n\treturn \"Legacy pi-sync state is still stored in .pisync. Close other Pi sessions, then run /sync migrate-state to move it to pi-sync/.\";\n}\n\nexport async function withStateDirectoryAccess<T>(fn: () => Promise<T>): Promise<T> {\n\tconst roots = inspectStateRoots();\n\tif (!roots.legacy) return fn();\n\treturn runWithStateDirectoryGuard(await acquireSharedStateDirectoryGuard(), fn);\n}\n\nexport async function migrateLegacyStateDirectory(): Promise<StateDirectoryPreparation> {\n\tconst initial = inspectStateRoots();\n\tif (initial.canonical || !initial.legacy) return { status: \"ready\" };\n\n\tlet guard: StateDirectoryGuard;\n\ttry {\n\t\tguard = await acquireStateDirectoryGuard();\n\t} catch (error) {\n\t\tif (!isLockHeldError(error)) throw error;\n\t\treturn {\n\t\t\tstatus: \"deferred\",\n\t\t\tmessage:\n\t\t\t\t\"pi-sync state migration was deferred because another state user is active. Close other Pi sessions and retry.\",\n\t\t};\n\t}\n\treturn runWithStateDirectoryGuard(guard, async () => {\n\t\tconst roots = inspectStateRoots();\n\t\tif (roots.canonical || !roots.legacy) return { status: \"ready\" };\n\n\t\tconst legacyLock = path.join(legacyStateDir(), \"lock\");\n\t\tconst legacyGuardHeld = await lockfile.check(legacyLock, {\n\t\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\t\tlockfilePath: `${legacyLock}.guard`,\n\t\t\trealpath: false,\n\t\t\tstale: LOCK_GUARD_STALE_MS,\n\t\t});\n\t\tif (legacyGuardHeld || (await pathExists(legacyLock))) {\n\t\t\treturn {\n\t\t\t\tstatus: \"deferred\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"pi-sync state migration was deferred because the legacy directory is busy. Close other Pi sessions, clear any confirmed stale sync lock, and retry.\",\n\t\t\t};\n\t\t}\n\t\tguard.throwIfCompromised();\n\t\tawait fs.rename(legacyStateDir(), canonicalStateDir());\n\t\tguard.throwIfCompromised();\n\t\tinspectStateRoots();\n\t\treturn {\n\t\t\tstatus: \"migrated\",\n\t\t\tmessage: `Migrated pi-sync state from ${legacyStateDir()} to ${canonicalStateDir()}.`,\n\t\t};\n\t});\n}\n\nasync function acquireSharedStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n\tconst key = migrationLockPath();\n\tfor (;;) {\n\t\tlet shared = sharedStateDirectoryGuards.get(key);\n\t\tif (shared?.closing) {\n\t\t\tawait shared.closing;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!shared) {\n\t\t\tshared = { guard: acquireStateDirectoryGuard(), users: 0 };\n\t\t\tsharedStateDirectoryGuards.set(key, shared);\n\t\t}\n\t\tshared.users += 1;\n\t\tlet guard: StateDirectoryGuard;\n\t\ttry {\n\t\t\tguard = await shared.guard;\n\t\t} catch (error) {\n\t\t\tif (sharedStateDirectoryGuards.get(key) === shared) {\n\t\t\t\tsharedStateDirectoryGuards.delete(key);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tlet released = false;\n\t\treturn {\n\t\t\tthrowIfCompromised: guard.throwIfCompromised,\n\t\t\trelease: async () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tshared.users -= 1;\n\t\t\t\tif (shared.users > 0) return;\n\t\t\t\tconst closing = guard.release();\n\t\t\t\tshared.closing = closing;\n\t\t\t\ttry {\n\t\t\t\t\tawait closing;\n\t\t\t\t} finally {\n\t\t\t\t\tif (sharedStateDirectoryGuards.get(key) === shared) {\n\t\t\t\t\t\tsharedStateDirectoryGuards.delete(key);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n}\n\nasync function acquireStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n\tlet compromisedError: Error | undefined;\n\tconst release = await lockfile.lock(getAgentDir(), {\n\t\tfs: LOCKFILE_FS_ADAPTER,\n\t\tlockfilePath: migrationLockPath(),\n\t\trealpath: false,\n\t\tstale: MIGRATION_LOCK_STALE_MS,\n\t\tupdate: MIGRATION_LOCK_UPDATE_MS,\n\t\tretries: { retries: 20, minTimeout: 10, maxTimeout: 50 },\n\t\tonCompromised: (error) => {\n\t\t\tcompromisedError = error;\n\t\t},\n\t});\n\treturn {\n\t\trelease,\n\t\tthrowIfCompromised: () => {\n\t\t\tif (compromisedError) throw compromisedError;\n\t\t},\n\t};\n}\n\nasync function runWithStateDirectoryGuard<T>(guard: StateDirectoryGuard, fn: () => Promise<T>) {\n\tlet result: T | undefined;\n\tlet failed = false;\n\tlet failure: unknown;\n\ttry {\n\t\tguard.throwIfCompromised();\n\t\tresult = await fn();\n\t\tguard.throwIfCompromised();\n\t} catch (error) {\n\t\tfailed = true;\n\t\tfailure = error;\n\t}\n\ttry {\n\t\tawait guard.release();\n\t} catch (error) {\n\t\tif (!failed) {\n\t\t\tfailed = true;\n\t\t\tfailure = error;\n\t\t}\n\t}\n\tif (failed) throw failure;\n\treturn result as T;\n}\n\nfunction isLockHeldError(error: unknown) {\n\treturn (error as NodeJS.ErrnoException).code === \"ELOCKED\";\n}\n\nfunction canonicalStateDir() {\n\treturn path.join(getAgentDir(), CANONICAL_DIRECTORY_NAME);\n}\n\nfunction migrationLockPath() {\n\treturn path.join(getAgentDir(), MIGRATION_LOCK_NAME);\n}\n\nfunction inspectStateRoots() {\n\tconst canonical = isDirectoryRoot(canonicalStateDir(), \"canonical\");\n\tconst legacy = isDirectoryRoot(legacyStateDir(), \"legacy\");\n\tif (canonical && legacy) {\n\t\tthrow new Error(\n\t\t\t`Both legacy ${legacyStateDir()} and canonical ${canonicalStateDir()} pi-sync state directories exist. Close all Pi sessions and reconcile the directories manually; pi-sync will not merge or delete either directory.`,\n\t\t);\n\t}\n\treturn { canonical, legacy };\n}\n\nfunction isDirectoryRoot(directory: string, label: string) {\n\ttry {\n\t\tconst entry = lstatSync(directory);\n\t\tif (entry.isSymbolicLink()) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to use ${label} pi-sync state directory symbolic link: ${directory}`,\n\t\t\t);\n\t\t}\n\t\tif (!entry.isDirectory()) {\n\t\t\tthrow new Error(`${label} pi-sync state path is not a directory: ${directory}`);\n\t\t}\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n\nasync function pathExists(filePath: string) {\n\ttry {\n\t\tawait fs.lstat(filePath);\n\t\treturn true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n\t\tthrow error;\n\t}\n}\n", "export const LOCK_GUARD_STALE_MS = 30_000;\nexport const LOCK_GUARD_UPDATE_MS = 10_000;\n", "import {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n} from \"node:fs\";\n\nexport const LOCKFILE_FS_ADAPTER = {\n\tmkdir,\n\tmkdirSync,\n\trealpath,\n\trealpathSync,\n\trmdir,\n\trmdirSync,\n\tstat,\n\tstatSync,\n\tutimes,\n\tutimesSync,\n};\n"],
|
|
5
|
-
"mappings": ";;;;AAAA,SAAS,iBAAiB;AAC1B,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,mBAAmB;AAC5B,OAAO,cAAc;;;ACJd,IAAM,sBAAsB;AAC5B,IAAM,uBAAuB;;;ACDpC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAEA,IAAM,sBAAsB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;;;AFhBA,IAAM,2BAA2B;AACjC,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AAC5B,IAAM,0BAA0B;AAChC,IAAM,2BAA2B;AAkBjC,IAAM,6BAA6B,oBAAI,IAAuC;AAEvE,SAAS,WAAW;AAC1B,QAAM,QAAQ,kBAAkB;AAChC,MAAI,MAAM,UAAW,QAAO,kBAAkB;AAC9C,MAAI,MAAM,OAAQ,QAAO,eAAe;AACxC,SAAO,kBAAkB;AAC1B;AAEO,SAAS,iBAAiB;AAChC,SAAO,KAAK,KAAK,YAAY,GAAG,qBAAqB;AACtD;AAEO,SAAS,gCAAgC;AAC/C,QAAM,QAAQ,kBAAkB;AAChC,MAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,SAAO;AACR;AAEA,eAAsB,yBAA4B,IAAkC;AACnF,QAAM,QAAQ,kBAAkB;AAChC,MAAI,CAAC,MAAM,OAAQ,QAAO,GAAG;AAC7B,SAAO,2BAA2B,MAAM,iCAAiC,GAAG,EAAE;AAC/E;AAEA,eAAsB,8BAAkE;AACvF,QAAM,UAAU,kBAAkB;AAClC,MAAI,QAAQ,aAAa,CAAC,QAAQ,OAAQ,QAAO,EAAE,QAAQ,QAAQ;AAEnE,MAAI;AACJ,MAAI;AACH,YAAQ,MAAM,2BAA2B;AAAA,EAC1C,SAAS,OAAO;AACf,QAAI,CAAC,gBAAgB,KAAK,EAAG,OAAM;AACnC,WAAO;AAAA,MACN,QAAQ;AAAA,MACR,SACC;AAAA,IACF;AAAA,EACD;AACA,SAAO,2BAA2B,OAAO,YAAY;AACpD,UAAM,QAAQ,kBAAkB;AAChC,QAAI,MAAM,aAAa,CAAC,MAAM,OAAQ,QAAO,EAAE,QAAQ,QAAQ;AAE/D,UAAM,aAAa,KAAK,KAAK,eAAe,GAAG,MAAM;AACrD,UAAM,kBAAkB,MAAM,SAAS,MAAM,YAAY;AAAA,MACxD,IAAI;AAAA,MACJ,cAAc,GAAG,UAAU;AAAA,MAC3B,UAAU;AAAA,MACV,OAAO;AAAA,IACR,CAAC;AACD,QAAI,mBAAoB,MAAM,WAAW,UAAU,GAAI;AACtD,aAAO;AAAA,QACN,QAAQ;AAAA,QACR,SACC;AAAA,MACF;AAAA,IACD;AACA,UAAM,mBAAmB;AACzB,UAAM,GAAG,OAAO,eAAe,GAAG,kBAAkB,CAAC;AACrD,UAAM,mBAAmB;AACzB,sBAAkB;AAClB,WAAO;AAAA,MACN,QAAQ;AAAA,MACR,SAAS,+BAA+B,eAAe,CAAC,OAAO,kBAAkB,CAAC;AAAA,IACnF;AAAA,EACD,CAAC;AACF;AAEA,eAAe,mCAAiE;AAC/E,QAAM,MAAM,kBAAkB;AAC9B,aAAS;AACR,QAAI,SAAS,2BAA2B,IAAI,GAAG;AAC/C,QAAI,QAAQ,SAAS;AACpB,YAAM,OAAO;AACb;AAAA,IACD;AACA,QAAI,CAAC,QAAQ;AACZ,eAAS,EAAE,OAAO,2BAA2B,GAAG,OAAO,EAAE;AACzD,iCAA2B,IAAI,KAAK,MAAM;AAAA,IAC3C;AACA,WAAO,SAAS;AAChB,QAAI;AACJ,QAAI;AACH,cAAQ,MAAM,OAAO;AAAA,IACtB,SAAS,OAAO;AACf,UAAI,2BAA2B,IAAI,GAAG,MAAM,QAAQ;AACnD,mCAA2B,OAAO,GAAG;AAAA,MACtC;AACA,YAAM;AAAA,IACP;AACA,QAAI,WAAW;AACf,WAAO;AAAA,MACN,oBAAoB,MAAM;AAAA,MAC1B,SAAS,YAAY;AACpB,YAAI,SAAU;AACd,mBAAW;AACX,eAAO,SAAS;AAChB,YAAI,OAAO,QAAQ,EAAG;AACtB,cAAM,UAAU,MAAM,QAAQ;AAC9B,eAAO,UAAU;AACjB,YAAI;AACH,gBAAM;AAAA,QACP,UAAE;AACD,cAAI,2BAA2B,IAAI,GAAG,MAAM,QAAQ;AACnD,uCAA2B,OAAO,GAAG;AAAA,UACtC;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAEA,eAAe,6BAA2D;AACzE,MAAI;AACJ,QAAM,UAAU,MAAM,SAAS,KAAK,YAAY,GAAG;AAAA,IAClD,IAAI;AAAA,IACJ,cAAc,kBAAkB;AAAA,IAChC,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS,EAAE,SAAS,IAAI,YAAY,IAAI,YAAY,GAAG;AAAA,IACvD,eAAe,CAAC,UAAU;AACzB,yBAAmB;AAAA,IACpB;AAAA,EACD,CAAC;AACD,SAAO;AAAA,IACN;AAAA,IACA,oBAAoB,MAAM;AACzB,UAAI,iBAAkB,OAAM;AAAA,IAC7B;AAAA,EACD;AACD;AAEA,eAAe,2BAA8B,OAA4B,IAAsB;AAC9F,MAAI;AACJ,MAAI,SAAS;AACb,MAAI;AACJ,MAAI;AACH,UAAM,mBAAmB;AACzB,aAAS,MAAM,GAAG;AAClB,UAAM,mBAAmB;AAAA,EAC1B,SAAS,OAAO;AACf,aAAS;AACT,cAAU;AAAA,EACX;AACA,MAAI;AACH,UAAM,MAAM,QAAQ;AAAA,EACrB,SAAS,OAAO;AACf,QAAI,CAAC,QAAQ;AACZ,eAAS;AACT,gBAAU;AAAA,IACX;AAAA,EACD;AACA,MAAI,OAAQ,OAAM;AAClB,SAAO;AACR;AAEA,SAAS,gBAAgB,OAAgB;AACxC,SAAQ,MAAgC,SAAS;AAClD;AAEA,SAAS,oBAAoB;AAC5B,SAAO,KAAK,KAAK,YAAY,GAAG,wBAAwB;AACzD;AAEA,SAAS,oBAAoB;AAC5B,SAAO,KAAK,KAAK,YAAY,GAAG,mBAAmB;AACpD;AAEA,SAAS,oBAAoB;AAC5B,QAAM,YAAY,gBAAgB,kBAAkB,GAAG,WAAW;AAClE,QAAM,SAAS,gBAAgB,eAAe,GAAG,QAAQ;AACzD,MAAI,aAAa,QAAQ;AACxB,UAAM,IAAI;AAAA,MACT,eAAe,eAAe,CAAC,kBAAkB,kBAAkB,CAAC;AAAA,IACrE;AAAA,EACD;AACA,SAAO,EAAE,WAAW,OAAO;AAC5B;AAEA,SAAS,gBAAgB,WAAmB,OAAe;AAC1D,MAAI;AACH,UAAM,QAAQ,UAAU,SAAS;AACjC,QAAI,MAAM,eAAe,GAAG;AAC3B,YAAM,IAAI;AAAA,QACT,mBAAmB,KAAK,2CAA2C,SAAS;AAAA,MAC7E;AAAA,IACD;AACA,QAAI,CAAC,MAAM,YAAY,GAAG;AACzB,YAAM,IAAI,MAAM,GAAG,KAAK,2CAA2C,SAAS,EAAE;AAAA,IAC/E;AACA,WAAO;AAAA,EACR,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACP;AACD;AAEA,eAAe,WAAW,UAAkB;AAC3C,MAAI;AACH,UAAM,GAAG,MAAM,QAAQ;AACvB,WAAO;AAAA,EACR,SAAS,OAAO;AACf,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACP;AACD;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|