@narumitw/pi-sync 0.50.3 → 0.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -0,0 +1,7 @@
|
|
|
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 loadConfig,\n loadPartialConfig,\n type SyncSetupStorageReview,\n syncConfigReviewFingerprint,\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 compareSyncInclude,\n inspectRemoteSelection,\n type RemoteSelectionDecision,\n type RemoteSelectionState,\n sameSyncInclude,\n} from \"../sync/sync-policy.js\";\nimport { type RunRoute, type RunRouteResult, runCancellableOperation } from \"./cancellable-operation.js\";\nimport { setSyncStatus } from \"./sync-status.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\nexport type RemoteSelectionOrigin = \"settings\" | \"sync\" | \"pull\" | \"push\";\n\nexport interface RemoteSelectionReviewOptions {\n decision?: RemoteSelectionDecision;\n origin?: RemoteSelectionOrigin;\n runRoute?: RunRoute;\n cancelLabel?: string;\n /** The explicit mismatch is resolved or superseded; this does not imply file equality. */\n onSelectionResolved?: () => void;\n withStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport type RemoteSelectionReviewResult =\n | { kind: \"back\" }\n | { kind: \"closed\" }\n | { kind: \"done\" }\n | { kind: \"stale\" }\n | { kind: \"route-result\"; result: RunRouteResult; route: \"sync\" | \"pull\" | \"push\" };\n\nexport async function showRemoteSelectionReview(\n ctx: ExtensionContext,\n setupName?: string,\n signal?: AbortSignal,\n factory: SyncBackendFactory = createSyncBackend,\n options: RemoteSelectionReviewOptions = {},\n): Promise<RemoteSelectionReviewResult> {\n try {\n let decision = options.decision;\n if (!decision) {\n const inspected = await inspectConfiguredRemoteSelection(ctx, setupName, signal, factory);\n if (!inspected || signal?.aborted) return { kind: \"stale\" };\n // A successful fresh read can supersede an old explicit mismatch without\n // changing local settings. This is not user cancellation or proof of file equality.\n if (inspected.kind === \"empty\" || inspected.state.kind !== \"different\") {\n options.onSelectionResolved?.();\n }\n if (inspected.kind === \"empty\") {\n ctx.ui.notify(\"Remote storage has no snapshot or synced-content list yet.\", \"info\");\n return { kind: \"back\" };\n }\n if (inspected.state.kind === \"same\") {\n ctx.ui.notify(\"Remote synced content already matches this sync setup.\", \"info\");\n return { kind: \"back\" };\n }\n if (inspected.state.kind === \"legacy\") {\n if (ctx.mode !== \"tui\") {\n ctx.ui.notify(formatLegacySummary(inspected.config, inspected.state.discovered), \"info\");\n return { kind: \"back\" };\n }\n await showLegacyDiscovery(ctx, inspected.config, inspected.state.discovered, signal);\n return signal?.aborted ? { kind: \"stale\" } : { kind: \"back\" };\n }\n decision = decisionFromState(inspected.config, inspected.state);\n }\n\n if (ctx.mode !== \"tui\") {\n ctx.ui.notify(formatRemoteSelectionSummary(decision), \"warning\");\n return { kind: \"back\" };\n }\n\n let currentDecision = decision;\n for (;;) {\n if (signal?.aborted) return { kind: \"stale\" };\n const result = await showSelectionDifference(\n ctx,\n currentDecision,\n options.origin ?? \"settings\",\n options.runRoute,\n signal,\n factory,\n options,\n );\n if (result.kind !== \"refresh\") return result;\n const refreshed = await runWithOptionalStateAccess(options, () =>\n inspectConfiguredRemoteSelection(ctx, currentDecision.setupName, signal, factory),\n );\n if (!refreshed || signal?.aborted) return { kind: \"stale\" };\n if (refreshed.kind === \"empty\") {\n options.onSelectionResolved?.();\n ctx.ui.notify(\"Remote storage no longer has a snapshot or synced-content list.\", \"warning\");\n return { kind: \"back\" };\n }\n if (refreshed.state.kind !== \"different\") {\n ctx.ui.notify(\n refreshed.state.kind === \"same\"\n ? \"Remote synced content now matches this sync setup.\"\n : \"The refreshed legacy snapshot has no authoritative synced-content list.\",\n \"info\",\n );\n options.onSelectionResolved?.();\n return { kind: \"done\" };\n }\n currentDecision = decisionFromState(refreshed.config, refreshed.state);\n }\n } catch (error) {\n if (signal?.aborted) return { kind: \"stale\" };\n ctx.ui.notify(`Could not review synced content: ${errorMessage(error)}`, \"error\");\n return { kind: \"back\" };\n } finally {\n setSyncStatus(ctx, undefined);\n }\n}\n\ntype DifferenceFlowResult = RemoteSelectionReviewResult | { kind: \"refresh\" };\n\nasync function showSelectionDifference(\n ctx: ExtensionContext,\n initialDecision: RemoteSelectionDecision,\n origin: RemoteSelectionOrigin,\n runRoute: RunRoute | undefined,\n sessionSignal: AbortSignal | undefined,\n factory: SyncBackendFactory,\n options: Pick<RemoteSelectionReviewOptions, \"cancelLabel\" | \"onSelectionResolved\" | \"withStateAccess\">,\n): Promise<DifferenceFlowResult> {\n type Screen = \"choice\" | \"review\" | \"saved\";\n type Action = \"adopt\" | \"keep\" | \"cancel\" | \"continue\" | \"done\";\n interface FlowState {\n decision: RemoteSelectionDecision;\n saved: boolean;\n }\n let flowState: FlowState = { decision: initialDecision, saved: false };\n let continuationReview: PartialConfig | undefined;\n let nextResult: RemoteSelectionReviewResult | undefined;\n let refreshRequested = false;\n const route = origin === \"settings\" ? \"sync\" : origin;\n const menu = defineMenu<FlowState, Screen, Action, ExtensionContext>({\n start: \"choice\",\n screens: {\n choice: ({ state }) => ({\n kind: \"actions\",\n title: \"Synced content differs\",\n lines: selectionSummaryLines(state.decision),\n items: [\n {\n id: \"review\",\n label: \"Review all paths (recommended)\",\n description: \"Compare exact remote-only, device-only, and ordered lists.\",\n to: \"review\",\n },\n {\n id: \"adopt\",\n label: \"Use remote content list\",\n description: \"Save the reviewed list on this device without pulling files.\",\n action: \"adopt\",\n },\n {\n id: \"keep\",\n label: \"Keep this device's content list and update remote\u2026\",\n description: \"Open the existing exact force-push preview without skipping confirmation.\",\n action: \"keep\",\n },\n { id: \"cancel\", label: options.cancelLabel ?? \"Cancel\", action: \"cancel\" },\n ],\n hint: \"back\",\n }),\n review: ({ state }) => ({\n kind: \"review\",\n title: `Review synced content \u00B7 ${safeTerminalText(state.decision.setupName)}`,\n content: formatSelectionDifference(state.decision),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n saved: ({ state }) => ({\n kind: \"actions\",\n title: \"Remote content list saved\",\n lines: [\n `Sync setup: ${safeTerminalText(state.decision.setupName)}`,\n \"Only the included-content setting was saved.\",\n \"No files were pulled and sync state was not changed.\",\n ],\n items: [\n ...(runRoute\n ? [\n {\n id: \"continue\",\n label: continueLabel(origin),\n description: \"Start a fresh check and exact preview for this sync setup.\",\n action: \"continue\" as const,\n },\n ]\n : []),\n { id: \"done\", label: \"Done\", action: \"done\" },\n ],\n hint: \"close\",\n }),\n },\n actions: {\n adopt: async ({ state, signal: actionSignal }) => {\n const signal = combineSignals(sessionSignal, actionSignal);\n try {\n const currentConfig = await loadConfig(state.decision.setupName);\n if (signal.aborted) return { kind: \"close\" as const };\n assertLocalSelectionCurrent(currentConfig, state.decision);\n if (!currentConfig.include.includes(\"sessions\") && state.decision.remoteInclude.includes(\"sessions\")) {\n const acknowledged = await ctx.ui.confirm(\n \"Use a content list that includes session conversations?\",\n \"Session JSONL may contain prompts, tool output, file paths, images, and secrets. This saves the list only; it does not pull files.\",\n { signal },\n );\n if (signal.aborted) return { kind: \"close\" as const };\n if (!acknowledged) return { kind: \"stay\" as const };\n }\n const review = await runWithOptionalStateAccess(options, async () => {\n const loaded = await loadAdoptionReview(state.decision, signal, factory);\n if (signal.aborted) throw signal.reason;\n await revalidateAndAdopt(loaded, state.decision, signal);\n return loaded;\n });\n if (signal.aborted) return { kind: \"close\" as const };\n options.onSelectionResolved?.();\n continuationReview = {\n ...review.storageReview,\n setupName: state.decision.setupName,\n include: [...state.decision.remoteInclude],\n automatic: review.config.automatic,\n onSwitch: review.config.onSwitch,\n showStatus: review.config.showStatus,\n };\n flowState = { decision: state.decision, saved: true };\n return { kind: \"to\" as const, screen: \"saved\" as const };\n } catch (error) {\n if (signal.aborted) return { kind: \"close\" as const };\n if (isStaleReviewError(error)) {\n ctx.ui.notify(`${errorMessage(error)} Refreshing the comparison.`, \"warning\");\n refreshRequested = true;\n return { kind: \"close\" as const };\n }\n ctx.ui.notify(`Could not save the remote content list: ${errorMessage(error)}`, \"error\");\n return { kind: \"stay\" as const };\n }\n },\n keep: async ({ state, signal: actionSignal }) => {\n if (!runRoute) {\n ctx.ui.notify(\"The reviewed update-remote route is unavailable.\", \"error\");\n return { kind: \"stay\" as const };\n }\n const signal = combineSignals(sessionSignal, actionSignal);\n try {\n const latest = await loadConfig(state.decision.setupName);\n if (signal.aborted) return { kind: \"close\" as const };\n assertLocalSelectionCurrent(latest, state.decision);\n const result = await runCancellableOperation(\n ctx,\n \"Preparing this device's push preview\u2026\",\n \"push --force\",\n runRoute,\n {\n commitAware: true,\n cancelledMessage: \"Push preparation cancelled; no remote files were changed.\",\n target: state.decision.setupName,\n signal,\n },\n );\n return handleNestedRouteResult(result, \"push\");\n } catch (error) {\n if (signal.aborted) return { kind: \"close\" as const };\n if (isStaleReviewError(error)) {\n ctx.ui.notify(`${errorMessage(error)} Refreshing the comparison.`, \"warning\");\n refreshRequested = true;\n return { kind: \"close\" as const };\n }\n ctx.ui.notify(`Could not prepare the remote update: ${errorMessage(error)}`, \"error\");\n return { kind: \"stay\" as const };\n }\n },\n continue: async ({ state, signal: actionSignal }) => {\n if (!runRoute || !continuationReview) return { kind: \"stay\" as const };\n const signal = combineSignals(sessionSignal, actionSignal);\n try {\n const latest = await loadPartialConfig(state.decision.setupName);\n if (signal.aborted) return { kind: \"close\" as const };\n if (!sameContinuationReview(latest, continuationReview)) {\n throw new StaleRemoteSelectionReviewError(\n `Sync setup \u201C${safeTerminalText(state.decision.setupName)}\u201D changed after the remote content list was saved.`,\n );\n }\n const result = await runCancellableOperation(ctx, continueBusyLabel(origin), route, runRoute, {\n commitAware: true,\n cancelledMessage: continuationCancelledMessage(route),\n target: state.decision.setupName,\n signal,\n });\n return handleNestedRouteResult(result, route);\n } catch (error) {\n if (signal.aborted) return { kind: \"close\" as const };\n ctx.ui.notify(`Could not continue: ${errorMessage(error)}`, \"error\");\n return { kind: \"stay\" as const };\n }\n },\n cancel: async () => ({ kind: \"back\" }),\n done: async () => {\n nextResult = { kind: \"done\" };\n return { kind: \"close\" };\n },\n },\n });\n\n function handleNestedRouteResult(\n result: Awaited<ReturnType<typeof runCancellableOperation>>,\n nestedRoute: \"sync\" | \"pull\" | \"push\",\n ) {\n if (result.kind === \"completed\" && result.outcome === \"applied\") {\n options.onSelectionResolved?.();\n }\n if (result.kind === \"closed\") {\n nextResult = { kind: \"closed\" };\n return { kind: \"close\" as const };\n }\n if (\n result.kind === \"cancelled\" ||\n (result.kind === \"completed\" && result.outcome === \"cancelled\") ||\n result.kind === \"failed\"\n ) {\n return { kind: \"stay\" as const };\n }\n nextResult = { kind: \"route-result\", result, route: nestedRoute };\n return { kind: \"close\" as const };\n }\n\n const menuResult = await runMenu(ctx, menu, {\n getState: () => flowState,\n signal: sessionSignal,\n isCurrent: () => !sessionSignal?.aborted,\n onError: (_menuCtx, error) => ctx.ui.notify(errorMessage(error), \"error\"),\n });\n if (sessionSignal?.aborted || menuResult.kind === \"stale\") return { kind: \"stale\" };\n if (refreshRequested) return { kind: \"refresh\" };\n if (nextResult) return nextResult;\n if (menuResult.kind === \"closed\") {\n return menuResult.reason === \"back\" ? { kind: \"back\" } : { kind: \"closed\" };\n }\n return { kind: \"closed\" };\n}\n\ninterface AdoptionReview {\n config: AnySyncConfig;\n storageReview: SyncSetupStorageReview;\n backend: SyncBackend;\n reviewedHead: RemoteHead;\n}\n\nasync function loadAdoptionReview(\n decision: RemoteSelectionDecision,\n signal: AbortSignal,\n factory: SyncBackendFactory,\n): Promise<AdoptionReview> {\n const config = await loadConfig(decision.setupName);\n throwIfAborted(signal);\n assertLocalSelectionCurrent(config, decision);\n const partial = await loadPartialConfig(decision.setupName);\n throwIfAborted(signal);\n if (!sameSyncInclude(partial.include, decision.localInclude)) {\n throw new StaleRemoteSelectionReviewError(\n `Sync setup \u201C${safeTerminalText(decision.setupName)}\u201D changed while the comparison was open.`,\n );\n }\n const backend = await factory(config);\n throwIfAborted(signal);\n const reviewedHead = await backend.readHead(signal);\n throwIfAborted(signal);\n if (!reviewedHead) {\n throw new StaleRemoteSelectionReviewError(\"Remote storage changed while the comparison was open.\");\n }\n const snapshot = await readSnapshotForHead(backend, reviewedHead, signal);\n throwIfAborted(signal);\n const state = inspectRemoteSelection(config.include, snapshot);\n if (state.kind !== \"different\" || !sameSyncInclude(state.include, decision.remoteInclude)) {\n throw new StaleRemoteSelectionReviewError(\"Remote synced content changed while the comparison was open.\");\n }\n return { config, storageReview: partial, backend, reviewedHead };\n}\n\nasync function revalidateAndAdopt(review: AdoptionReview, decision: RemoteSelectionDecision, signal: AbortSignal) {\n const currentHead = await review.backend.readHead(signal);\n throwIfAborted(signal);\n if (!currentHead || !review.backend.sameRevision(review.reviewedHead.revision, currentHead.revision)) {\n throw new StaleRemoteSelectionReviewError(\"Remote storage changed while the comparison was open.\");\n }\n const currentSnapshot = await readSnapshotForHead(review.backend, currentHead, signal);\n throwIfAborted(signal);\n const currentState = inspectRemoteSelection(review.config.include, currentSnapshot);\n if (currentState.kind !== \"different\" || !sameSyncInclude(currentState.include, decision.remoteInclude)) {\n throw new StaleRemoteSelectionReviewError(\"Remote synced content changed while the comparison was open.\");\n }\n await updateSyncSetup(\n decision.setupName,\n (setup) => ({\n ...setup,\n sync: { ...setup.sync, include: [...decision.remoteInclude] },\n }),\n {\n expectedStorage: review.storageReview,\n expectedInclude: decision.localInclude,\n signal,\n },\n );\n}\n\nasync function inspectConfiguredRemoteSelection(\n ctx: ExtensionContext,\n setupName: string | undefined,\n signal: AbortSignal | undefined,\n factory: SyncBackendFactory,\n): Promise<\n | { kind: \"empty\"; config: AnySyncConfig }\n | { kind: \"selection\"; config: AnySyncConfig; state: RemoteSelectionState }\n | undefined\n> {\n const config = await loadConfig(setupName);\n if (signal?.aborted) return undefined;\n setSyncStatus(ctx, `checking synced content for ${safeTerminalText(config.setupName)}`);\n const backend = await factory(config);\n if (signal?.aborted) return undefined;\n const head = await backend.readHead(signal);\n if (signal?.aborted) return undefined;\n if (!head) return { kind: \"empty\", config };\n const snapshot = await readSnapshotForHead(backend, head, signal);\n if (signal?.aborted) return undefined;\n return {\n kind: \"selection\",\n config,\n state: inspectRemoteSelection(config.include, snapshot),\n };\n}\n\nasync function showLegacyDiscovery(\n ctx: ExtensionContext,\n config: AnySyncConfig,\n discovered: string[],\n signal?: AbortSignal,\n) {\n const menu = defineMenu<undefined, \"choice\" | \"review\", \"back\", ExtensionContext>({\n start: \"choice\",\n screens: {\n choice: () => ({\n kind: \"actions\",\n title: `Compare synced content \u00B7 ${safeTerminalText(config.setupName)}`,\n lines: [\n \"This legacy snapshot has no portable synced-content list.\",\n \"Discovered paths are partial and read-only; preserved files may not have been selected.\",\n ],\n items: [\n { id: \"review\", label: \"Review discovered paths\", to: \"review\" },\n { id: \"back\", label: \"Back\", action: \"back\" },\n ],\n hint: \"close\",\n }),\n review: () => ({\n kind: \"review\",\n title: \"Partial discovery from legacy snapshot\",\n content: [\n \"Partial discovery only \u2014 not an authoritative selection.\",\n \"\",\n ...(discovered.length > 0\n ? discovered.map((item) => `Discovered: ${safeTerminalText(item)}`)\n : [\"No safe paths were discovered.\"]),\n \"\",\n \"Use Add custom path\u2026 in the local Included Content editor if needed.\",\n ].join(\"\\n\"),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n },\n actions: { back: async () => ({ kind: \"close\" }) },\n });\n await runMenu(ctx, menu, {\n getState: () => undefined,\n signal,\n isCurrent: () => !signal?.aborted,\n });\n}\n\nfunction selectionSummaryLines(decision: RemoteSelectionDecision) {\n const comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n return [\n `Sync setup: ${safeTerminalText(decision.setupName)}`,\n \"Nothing changed. Review both lists before choosing what happens next.\",\n ...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n ? [\"Only the ordering differs; membership is the same.\"]\n : [`Remote-only paths: ${comparison.remoteOnly.length} \u00B7 Device-only paths: ${comparison.localOnly.length}`]),\n ];\n}\n\nfunction formatSelectionDifference(decision: RemoteSelectionDecision) {\n const comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n return [\n ...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n ? [\"Only ordering differs; both lists contain the same paths.\", \"\"]\n : []),\n \"Remote-only paths:\",\n ...(comparison.remoteOnly.length > 0\n ? comparison.remoteOnly.map((item) => `+ ${safeTerminalText(item)}`)\n : [\"(none)\"]),\n \"\",\n \"Device-only paths:\",\n ...(comparison.localOnly.length > 0\n ? comparison.localOnly.map((item) => `- ${safeTerminalText(item)}`)\n : [\"(none)\"]),\n \"\",\n \"Remote ordered list:\",\n ...(decision.remoteInclude.length > 0\n ? decision.remoteInclude.map((item, index) => `${index + 1}. ${safeTerminalText(item)}`)\n : [\"(none)\"]),\n \"\",\n \"This device's ordered list:\",\n ...(decision.localInclude.length > 0\n ? decision.localInclude.map((item, index) => `${index + 1}. ${safeTerminalText(item)}`)\n : [\"(none)\"]),\n \"\",\n \"Using the remote list saves settings only and does not pull files.\",\n ].join(\"\\n\");\n}\n\nfunction formatRemoteSelectionSummary(decision: RemoteSelectionDecision) {\n const comparison = compareSyncInclude(decision.localInclude, decision.remoteInclude);\n return [\n `Synced content for \u201C${safeTerminalText(decision.setupName)}\u201D differs from this device.`,\n `Remote-only: ${safeList(comparison.remoteOnly)}`,\n `Device-only: ${safeList(comparison.localOnly)}`,\n ...(comparison.remoteOnly.length === 0 && comparison.localOnly.length === 0\n ? [\n \"Only ordering differs.\",\n `Remote order: ${safeList(decision.remoteInclude)}`,\n `Device order: ${safeList(decision.localInclude)}`,\n ]\n : []),\n \"Run /sync in TUI to choose a content list; RPC review is read-only.\",\n ].join(\"\\n\");\n}\n\nfunction formatLegacySummary(config: AnySyncConfig, discovered: readonly string[]) {\n return `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 config: AnySyncConfig,\n state: Extract<RemoteSelectionState, { kind: \"different\" }>,\n): RemoteSelectionDecision {\n return {\n setupName: config.setupName,\n configIdentity: syncConfigReviewFingerprint(config),\n localInclude: [...config.include],\n remoteInclude: [...state.include],\n };\n}\n\nfunction assertLocalSelectionCurrent(config: AnySyncConfig, decision: RemoteSelectionDecision) {\n if (\n syncConfigReviewFingerprint(config) === decision.configIdentity &&\n sameSyncInclude(config.include, decision.localInclude)\n ) {\n return;\n }\n throw new StaleRemoteSelectionReviewError(\n `Sync setup \u201C${safeTerminalText(config.setupName)}\u201D changed while the comparison was open.`,\n );\n}\n\nfunction sameContinuationReview(left: PartialConfig, right: PartialConfig) {\n return (\n left.setupName === right.setupName &&\n left.connectionName === right.connectionName &&\n left.storageKind === right.storageKind &&\n left.storagePath === right.storagePath &&\n left.bucket === right.bucket &&\n left.branch === right.branch &&\n sameSyncInclude(left.include, right.include)\n );\n}\n\nfunction continueLabel(origin: RemoteSelectionOrigin) {\n if (origin === \"pull\") return \"Continue Pull now\u2026\";\n if (origin === \"push\") return \"Continue Push now\u2026\";\n return \"Continue Sync now\u2026\";\n}\n\nfunction continueBusyLabel(origin: RemoteSelectionOrigin) {\n if (origin === \"pull\") return \"Checking remote changes\u2026\";\n if (origin === \"push\") return \"Preparing push preview\u2026\";\n return \"Checking current sync setup\u2026\";\n}\n\nfunction continuationCancelledMessage(route: \"sync\" | \"pull\" | \"push\") {\n if (route === \"pull\") return \"Pull check cancelled; no local files were changed.\";\n if (route === \"push\") return \"Push preparation cancelled; no remote files were changed.\";\n return \"Sync check cancelled; no settings or files were changed.\";\n}\n\nfunction safeList(values: readonly string[]) {\n return values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n\nclass StaleRemoteSelectionReviewError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StaleRemoteSelectionReviewError\";\n }\n}\n\nfunction isStaleReviewError(error: unknown) {\n return error instanceof StaleRemoteSelectionReviewError || error instanceof SyncSetupReviewChangedError;\n}\n\nfunction runWithOptionalStateAccess<T>(\n options: Pick<RemoteSelectionReviewOptions, \"withStateAccess\">,\n task: () => Promise<T>,\n) {\n return options.withStateAccess ? options.withStateAccess(task) : task();\n}\n\nfunction combineSignals(sessionSignal: AbortSignal | undefined, actionSignal: AbortSignal) {\n return sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;\n}\n\nfunction throwIfAborted(signal: AbortSignal) {\n if (!signal.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : 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 | { kind: \"completed\"; outcome?: SetupPullOutcome }\n | { kind: \"decision-required\"; decision: SyncDecision }\n | { kind: \"remote-selection-required\"; decision: RemoteSelectionDecision }\n | { kind: \"failed\" };\n\nexport type RunRoute = (\n route: string,\n signal?: AbortSignal,\n onCommit?: () => void,\n target?: string,\n) => Promise<RunRouteResult | undefined>;\n\nexport type CancellableOperationResult = RunRouteResult | { kind: \"closed\" } | { kind: \"cancelled\" };\n\ninterface CancellableOperationOptions {\n commitAware?: boolean;\n cancelledMessage?: string | null;\n target?: string;\n signal?: AbortSignal;\n}\n\nexport async function runCancellableOperation(\n ctx: ExtensionContext,\n message: string,\n route: string,\n runRoute: RunRoute,\n options: CancellableOperationOptions = {},\n): Promise<CancellableOperationResult> {\n const {\n commitAware = false,\n cancelledMessage = \"Check cancelled; no settings or files were changed.\",\n target,\n signal,\n } = options;\n if (ctx.mode !== \"tui\") {\n return (await runRoute(route, signal, undefined, target)) ?? { kind: \"failed\" };\n }\n let commitStarted = false;\n let routeResult: RunRouteResult | undefined;\n const interaction = await runCustomInteraction<{ cancelled?: boolean; error?: unknown }, ExtensionContext>(ctx, {\n signal,\n isCurrent: () => !signal?.aborted,\n create: ({ tui, theme, keybindings, signal: interactionSignal, complete }) => {\n const loader = new BorderedLoader(tui, theme, message, { cancellable: false });\n const cancelHint = formatInteractionHints(keybindings, [\n {\n keys: [...keybindings.getKeys(\"tui.select.cancel\").filter((key) => !hasControlCharacter(key)), \"ctrl+c\"],\n label: \"cancel\",\n },\n ]);\n const operation = runRoute(\n route,\n interactionSignal,\n commitAware ? () => (commitStarted = true) : undefined,\n target,\n ).then(\n (result) => {\n routeResult = result;\n complete({});\n },\n (error: unknown) => complete({ error }),\n );\n return {\n render(width: number) {\n const safeWidth = Math.max(1, width);\n const lines = loader.render(safeWidth);\n const bottomBorder = lines.at(-1);\n return [\n ...lines.slice(0, -1),\n truncateToWidth(theme.fg(\"dim\", cancelHint), safeWidth, \"\"),\n ...(bottomBorder === undefined ? [] : [bottomBorder]),\n ];\n },\n invalidate: () => loader.invalidate(),\n handleInput(data: string) {\n if (!matchesKey(data, Key.ctrl(\"c\")) && !keybindings.matches(data, \"tui.select.cancel\")) {\n return;\n }\n if (commitStarted) {\n ctx.ui.notify(\"Applying or publishing has started and cannot be cancelled safely.\", \"warning\");\n return;\n }\n complete({ cancelled: true });\n },\n dispose: () => loader.dispose(),\n waitForPending: () => operation,\n };\n },\n });\n if (interaction.kind === \"error\") throw interaction.error;\n if (interaction.kind !== \"completed\") return { kind: \"closed\" };\n if (interaction.value.cancelled) {\n if (cancelledMessage) ctx.ui.notify(cancelledMessage, \"info\");\n return { kind: \"cancelled\" };\n }\n if (interaction.value.error) throw interaction.value.error;\n return routeResult ?? { kind: \"failed\" };\n}\n\nfunction hasControlCharacter(value: string) {\n // biome-ignore lint/suspicious/noControlCharactersInRegex: Unsafe key labels must be omitted.\n return /[\\u0000-\\u001f\\u007f-\\u009f]/u.test(value);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,YAAY,eAAe;;;ACDpC,SAAS,sBAA6C;AACtD,SAAS,KAAK,YAAY,uBAAuB;AACjD,SAAS,wBAAwB,4BAA4B;AA2B7D,eAAsB,wBACpB,KACA,SACA,OACA,UACA,UAAuC,CAAC,GACH;AACrC,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,IAAI,SAAS,OAAO;AACtB,WAAQ,MAAM,SAAS,OAAO,QAAQ,QAAW,MAAM,KAAM,EAAE,MAAM,SAAS;AAAA,EAChF;AACA,MAAI,gBAAgB;AACpB,MAAI;AACJ,QAAM,cAAc,MAAM,qBAAiF,KAAK;AAAA,IAC9G;AAAA,IACA,WAAW,MAAM,CAAC,QAAQ;AAAA,IAC1B,QAAQ,CAAC,EAAE,KAAK,OAAO,aAAa,QAAQ,mBAAmB,SAAS,MAAM;AAC5E,YAAM,SAAS,IAAI,eAAe,KAAK,OAAO,SAAS,EAAE,aAAa,MAAM,CAAC;AAC7E,YAAM,aAAa,uBAAuB,aAAa;AAAA,QACrD;AAAA,UACE,MAAM,CAAC,GAAG,YAAY,QAAQ,mBAAmB,EAAE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,GAAG,CAAC,GAAG,QAAQ;AAAA,UACvG,OAAO;AAAA,QACT;AAAA,MACF,CAAC;AACD,YAAM,YAAY;AAAA,QAChB;AAAA,QACA;AAAA,QACA,cAAc,MAAO,gBAAgB,OAAQ;AAAA,QAC7C;AAAA,MACF,EAAE;AAAA,QACA,CAAC,WAAW;AACV,wBAAc;AACd,mBAAS,CAAC,CAAC;AAAA,QACb;AAAA,QACA,CAAC,UAAmB,SAAS,EAAE,MAAM,CAAC;AAAA,MACxC;AACA,aAAO;AAAA,QACL,OAAO,OAAe;AACpB,gBAAM,YAAY,KAAK,IAAI,GAAG,KAAK;AACnC,gBAAM,QAAQ,OAAO,OAAO,SAAS;AACrC,gBAAM,eAAe,MAAM,GAAG,EAAE;AAChC,iBAAO;AAAA,YACL,GAAG,MAAM,MAAM,GAAG,EAAE;AAAA,YACpB,gBAAgB,MAAM,GAAG,OAAO,UAAU,GAAG,WAAW,EAAE;AAAA,YAC1D,GAAI,iBAAiB,SAAY,CAAC,IAAI,CAAC,YAAY;AAAA,UACrD;AAAA,QACF;AAAA,QACA,YAAY,MAAM,OAAO,WAAW;AAAA,QACpC,YAAY,MAAc;AACxB,cAAI,CAAC,WAAW,MAAM,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,YAAY,QAAQ,MAAM,mBAAmB,GAAG;AACvF;AAAA,UACF;AACA,cAAI,eAAe;AACjB,gBAAI,GAAG,OAAO,sEAAsE,SAAS;AAC7F;AAAA,UACF;AACA,mBAAS,EAAE,WAAW,KAAK,CAAC;AAAA,QAC9B;AAAA,QACA,SAAS,MAAM,OAAO,QAAQ;AAAA,QAC9B,gBAAgB,MAAM;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AACD,MAAI,YAAY,SAAS,QAAS,OAAM,YAAY;AACpD,MAAI,YAAY,SAAS,YAAa,QAAO,EAAE,MAAM,SAAS;AAC9D,MAAI,YAAY,MAAM,WAAW;AAC/B,QAAI,iBAAkB,KAAI,GAAG,OAAO,kBAAkB,MAAM;AAC5D,WAAO,EAAE,MAAM,YAAY;AAAA,EAC7B;AACA,MAAI,YAAY,MAAM,MAAO,OAAM,YAAY,MAAM;AACrD,SAAO,eAAe,EAAE,MAAM,SAAS;AACzC;AAEA,SAAS,oBAAoB,OAAe;AAE1C,SAAO,gCAAgC,KAAK,KAAK;AACnD;;;ADlEA,eAAsB,0BACpB,KACA,WACA,QACA,UAA8B,mBAC9B,UAAwC,CAAC,GACH;AACtC,MAAI;AACF,QAAI,WAAW,QAAQ;AACvB,QAAI,CAAC,UAAU;AACb,YAAM,YAAY,MAAM,iCAAiC,KAAK,WAAW,QAAQ,OAAO;AACxF,UAAI,CAAC,aAAa,QAAQ,QAAS,QAAO,EAAE,MAAM,QAAQ;AAG1D,UAAI,UAAU,SAAS,WAAW,UAAU,MAAM,SAAS,aAAa;AACtE,gBAAQ,sBAAsB;AAAA,MAChC;AACA,UAAI,UAAU,SAAS,SAAS;AAC9B,YAAI,GAAG,OAAO,8DAA8D,MAAM;AAClF,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB;AACA,UAAI,UAAU,MAAM,SAAS,QAAQ;AACnC,YAAI,GAAG,OAAO,0DAA0D,MAAM;AAC9E,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB;AACA,UAAI,UAAU,MAAM,SAAS,UAAU;AACrC,YAAI,IAAI,SAAS,OAAO;AACtB,cAAI,GAAG,OAAO,oBAAoB,UAAU,QAAQ,UAAU,MAAM,UAAU,GAAG,MAAM;AACvF,iBAAO,EAAE,MAAM,OAAO;AAAA,QACxB;AACA,cAAM,oBAAoB,KAAK,UAAU,QAAQ,UAAU,MAAM,YAAY,MAAM;AACnF,eAAO,QAAQ,UAAU,EAAE,MAAM,QAAQ,IAAI,EAAE,MAAM,OAAO;AAAA,MAC9D;AACA,iBAAW,kBAAkB,UAAU,QAAQ,UAAU,KAAK;AAAA,IAChE;AAEA,QAAI,IAAI,SAAS,OAAO;AACtB,UAAI,GAAG,OAAO,6BAA6B,QAAQ,GAAG,SAAS;AAC/D,aAAO,EAAE,MAAM,OAAO;AAAA,IACxB;AAEA,QAAI,kBAAkB;AACtB,eAAS;AACP,UAAI,QAAQ,QAAS,QAAO,EAAE,MAAM,QAAQ;AAC5C,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA,QAAQ,UAAU;AAAA,QAClB,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,UAAI,OAAO,SAAS,UAAW,QAAO;AACtC,YAAM,YAAY,MAAM;AAAA,QAA2B;AAAA,QAAS,MAC1D,iCAAiC,KAAK,gBAAgB,WAAW,QAAQ,OAAO;AAAA,MAClF;AACA,UAAI,CAAC,aAAa,QAAQ,QAAS,QAAO,EAAE,MAAM,QAAQ;AAC1D,UAAI,UAAU,SAAS,SAAS;AAC9B,gBAAQ,sBAAsB;AAC9B,YAAI,GAAG,OAAO,mEAAmE,SAAS;AAC1F,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB;AACA,UAAI,UAAU,MAAM,SAAS,aAAa;AACxC,YAAI,GAAG;AAAA,UACL,UAAU,MAAM,SAAS,SACrB,uDACA;AAAA,UACJ;AAAA,QACF;AACA,gBAAQ,sBAAsB;AAC9B,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB;AACA,wBAAkB,kBAAkB,UAAU,QAAQ,UAAU,KAAK;AAAA,IACvE;AAAA,EACF,SAAS,OAAO;AACd,QAAI,QAAQ,QAAS,QAAO,EAAE,MAAM,QAAQ;AAC5C,QAAI,GAAG,OAAO,oCAAoC,aAAa,KAAK,CAAC,IAAI,OAAO;AAChF,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB,UAAE;AACA,kBAAc,KAAK,MAAS;AAAA,EAC9B;AACF;AAIA,eAAe,wBACb,KACA,iBACA,QACA,UACA,eACA,SACA,SAC+B;AAO/B,MAAI,YAAuB,EAAE,UAAU,iBAAiB,OAAO,MAAM;AACrE,MAAI;AACJ,MAAI;AACJ,MAAI,mBAAmB;AACvB,QAAM,QAAQ,WAAW,aAAa,SAAS;AAC/C,QAAM,OAAO,WAAwD;AAAA,IACnE,OAAO;AAAA,IACP,SAAS;AAAA,MACP,QAAQ,CAAC,EAAE,MAAM,OAAO;AAAA,QACtB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,sBAAsB,MAAM,QAAQ;AAAA,QAC3C,OAAO;AAAA,UACL;AAAA,YACE,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,IAAI;AAAA,UACN;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,QAAQ;AAAA,UACV;AAAA,UACA;AAAA,YACE,IAAI;AAAA,YACJ,OAAO;AAAA,YACP,aAAa;AAAA,YACb,QAAQ;AAAA,UACV;AAAA,UACA,EAAE,IAAI,UAAU,OAAO,QAAQ,eAAe,UAAU,QAAQ,SAAS;AAAA,QAC3E;AAAA,QACA,MAAM;AAAA,MACR;AAAA,MACA,QAAQ,CAAC,EAAE,MAAM,OAAO;AAAA,QACtB,MAAM;AAAA,QACN,OAAO,8BAA2B,iBAAiB,MAAM,SAAS,SAAS,CAAC;AAAA,QAC5E,SAAS,0BAA0B,MAAM,QAAQ;AAAA,QACjD,QAAQ,EAAE,MAAM,OAAO;AAAA,QACvB,cAAc;AAAA,QACd,MAAM;AAAA,MACR;AAAA,MACA,OAAO,CAAC,EAAE,MAAM,OAAO;AAAA,QACrB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,UACL,eAAe,iBAAiB,MAAM,SAAS,SAAS,CAAC;AAAA,UACzD;AAAA,UACA;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,GAAI,WACA;AAAA,YACE;AAAA,cACE,IAAI;AAAA,cACJ,OAAO,cAAc,MAAM;AAAA,cAC3B,aAAa;AAAA,cACb,QAAQ;AAAA,YACV;AAAA,UACF,IACA,CAAC;AAAA,UACL,EAAE,IAAI,QAAQ,OAAO,QAAQ,QAAQ,OAAO;AAAA,QAC9C;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,OAAO,OAAO,EAAE,OAAO,QAAQ,aAAa,MAAM;AAChD,cAAM,SAAS,eAAe,eAAe,YAAY;AACzD,YAAI;AACF,gBAAM,gBAAgB,MAAM,WAAW,MAAM,SAAS,SAAS;AAC/D,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,sCAA4B,eAAe,MAAM,QAAQ;AACzD,cAAI,CAAC,cAAc,QAAQ,SAAS,UAAU,KAAK,MAAM,SAAS,cAAc,SAAS,UAAU,GAAG;AACpG,kBAAM,eAAe,MAAM,IAAI,GAAG;AAAA,cAChC;AAAA,cACA;AAAA,cACA,EAAE,OAAO;AAAA,YACX;AACA,gBAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,gBAAI,CAAC,aAAc,QAAO,EAAE,MAAM,OAAgB;AAAA,UACpD;AACA,gBAAM,SAAS,MAAM,2BAA2B,SAAS,YAAY;AACnE,kBAAM,SAAS,MAAM,mBAAmB,MAAM,UAAU,QAAQ,OAAO;AACvE,gBAAI,OAAO,QAAS,OAAM,OAAO;AACjC,kBAAM,mBAAmB,QAAQ,MAAM,UAAU,MAAM;AACvD,mBAAO;AAAA,UACT,CAAC;AACD,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,kBAAQ,sBAAsB;AAC9B,+BAAqB;AAAA,YACnB,GAAG,OAAO;AAAA,YACV,WAAW,MAAM,SAAS;AAAA,YAC1B,SAAS,CAAC,GAAG,MAAM,SAAS,aAAa;AAAA,YACzC,WAAW,OAAO,OAAO;AAAA,YACzB,UAAU,OAAO,OAAO;AAAA,YACxB,YAAY,OAAO,OAAO;AAAA,UAC5B;AACA,sBAAY,EAAE,UAAU,MAAM,UAAU,OAAO,KAAK;AACpD,iBAAO,EAAE,MAAM,MAAe,QAAQ,QAAiB;AAAA,QACzD,SAAS,OAAO;AACd,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,cAAI,mBAAmB,KAAK,GAAG;AAC7B,gBAAI,GAAG,OAAO,GAAG,aAAa,KAAK,CAAC,+BAA+B,SAAS;AAC5E,+BAAmB;AACnB,mBAAO,EAAE,MAAM,QAAiB;AAAA,UAClC;AACA,cAAI,GAAG,OAAO,2CAA2C,aAAa,KAAK,CAAC,IAAI,OAAO;AACvF,iBAAO,EAAE,MAAM,OAAgB;AAAA,QACjC;AAAA,MACF;AAAA,MACA,MAAM,OAAO,EAAE,OAAO,QAAQ,aAAa,MAAM;AAC/C,YAAI,CAAC,UAAU;AACb,cAAI,GAAG,OAAO,oDAAoD,OAAO;AACzE,iBAAO,EAAE,MAAM,OAAgB;AAAA,QACjC;AACA,cAAM,SAAS,eAAe,eAAe,YAAY;AACzD,YAAI;AACF,gBAAM,SAAS,MAAM,WAAW,MAAM,SAAS,SAAS;AACxD,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,sCAA4B,QAAQ,MAAM,QAAQ;AAClD,gBAAM,SAAS,MAAM;AAAA,YACnB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,cACE,aAAa;AAAA,cACb,kBAAkB;AAAA,cAClB,QAAQ,MAAM,SAAS;AAAA,cACvB;AAAA,YACF;AAAA,UACF;AACA,iBAAO,wBAAwB,QAAQ,MAAM;AAAA,QAC/C,SAAS,OAAO;AACd,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,cAAI,mBAAmB,KAAK,GAAG;AAC7B,gBAAI,GAAG,OAAO,GAAG,aAAa,KAAK,CAAC,+BAA+B,SAAS;AAC5E,+BAAmB;AACnB,mBAAO,EAAE,MAAM,QAAiB;AAAA,UAClC;AACA,cAAI,GAAG,OAAO,wCAAwC,aAAa,KAAK,CAAC,IAAI,OAAO;AACpF,iBAAO,EAAE,MAAM,OAAgB;AAAA,QACjC;AAAA,MACF;AAAA,MACA,UAAU,OAAO,EAAE,OAAO,QAAQ,aAAa,MAAM;AACnD,YAAI,CAAC,YAAY,CAAC,mBAAoB,QAAO,EAAE,MAAM,OAAgB;AACrE,cAAM,SAAS,eAAe,eAAe,YAAY;AACzD,YAAI;AACF,gBAAM,SAAS,MAAM,kBAAkB,MAAM,SAAS,SAAS;AAC/D,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,cAAI,CAAC,uBAAuB,QAAQ,kBAAkB,GAAG;AACvD,kBAAM,IAAI;AAAA,cACR,oBAAe,iBAAiB,MAAM,SAAS,SAAS,CAAC;AAAA,YAC3D;AAAA,UACF;AACA,gBAAM,SAAS,MAAM,wBAAwB,KAAK,kBAAkB,MAAM,GAAG,OAAO,UAAU;AAAA,YAC5F,aAAa;AAAA,YACb,kBAAkB,6BAA6B,KAAK;AAAA,YACpD,QAAQ,MAAM,SAAS;AAAA,YACvB;AAAA,UACF,CAAC;AACD,iBAAO,wBAAwB,QAAQ,KAAK;AAAA,QAC9C,SAAS,OAAO;AACd,cAAI,OAAO,QAAS,QAAO,EAAE,MAAM,QAAiB;AACpD,cAAI,GAAG,OAAO,uBAAuB,aAAa,KAAK,CAAC,IAAI,OAAO;AACnE,iBAAO,EAAE,MAAM,OAAgB;AAAA,QACjC;AAAA,MACF;AAAA,MACA,QAAQ,aAAa,EAAE,MAAM,OAAO;AAAA,MACpC,MAAM,YAAY;AAChB,qBAAa,EAAE,MAAM,OAAO;AAC5B,eAAO,EAAE,MAAM,QAAQ;AAAA,MACzB;AAAA,IACF;AAAA,EACF,CAAC;AAED,WAAS,wBACP,QACA,aACA;AACA,QAAI,OAAO,SAAS,eAAe,OAAO,YAAY,WAAW;AAC/D,cAAQ,sBAAsB;AAAA,IAChC;AACA,QAAI,OAAO,SAAS,UAAU;AAC5B,mBAAa,EAAE,MAAM,SAAS;AAC9B,aAAO,EAAE,MAAM,QAAiB;AAAA,IAClC;AACA,QACE,OAAO,SAAS,eACf,OAAO,SAAS,eAAe,OAAO,YAAY,eACnD,OAAO,SAAS,UAChB;AACA,aAAO,EAAE,MAAM,OAAgB;AAAA,IACjC;AACA,iBAAa,EAAE,MAAM,gBAAgB,QAAQ,OAAO,YAAY;AAChE,WAAO,EAAE,MAAM,QAAiB;AAAA,EAClC;AAEA,QAAM,aAAa,MAAM,QAAQ,KAAK,MAAM;AAAA,IAC1C,UAAU,MAAM;AAAA,IAChB,QAAQ;AAAA,IACR,WAAW,MAAM,CAAC,eAAe;AAAA,IACjC,SAAS,CAAC,UAAU,UAAU,IAAI,GAAG,OAAO,aAAa,KAAK,GAAG,OAAO;AAAA,EAC1E,CAAC;AACD,MAAI,eAAe,WAAW,WAAW,SAAS,QAAS,QAAO,EAAE,MAAM,QAAQ;AAClF,MAAI,iBAAkB,QAAO,EAAE,MAAM,UAAU;AAC/C,MAAI,WAAY,QAAO;AACvB,MAAI,WAAW,SAAS,UAAU;AAChC,WAAO,WAAW,WAAW,SAAS,EAAE,MAAM,OAAO,IAAI,EAAE,MAAM,SAAS;AAAA,EAC5E;AACA,SAAO,EAAE,MAAM,SAAS;AAC1B;AASA,eAAe,mBACb,UACA,QACA,SACyB;AACzB,QAAM,SAAS,MAAM,WAAW,SAAS,SAAS;AAClD,iBAAe,MAAM;AACrB,8BAA4B,QAAQ,QAAQ;AAC5C,QAAM,UAAU,MAAM,kBAAkB,SAAS,SAAS;AAC1D,iBAAe,MAAM;AACrB,MAAI,CAAC,gBAAgB,QAAQ,SAAS,SAAS,YAAY,GAAG;AAC5D,UAAM,IAAI;AAAA,MACR,oBAAe,iBAAiB,SAAS,SAAS,CAAC;AAAA,IACrD;AAAA,EACF;AACA,QAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,iBAAe,MAAM;AACrB,QAAM,eAAe,MAAM,QAAQ,SAAS,MAAM;AAClD,iBAAe,MAAM;AACrB,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,gCAAgC,uDAAuD;AAAA,EACnG;AACA,QAAM,WAAW,MAAM,oBAAoB,SAAS,cAAc,MAAM;AACxE,iBAAe,MAAM;AACrB,QAAM,QAAQ,uBAAuB,OAAO,SAAS,QAAQ;AAC7D,MAAI,MAAM,SAAS,eAAe,CAAC,gBAAgB,MAAM,SAAS,SAAS,aAAa,GAAG;AACzF,UAAM,IAAI,gCAAgC,8DAA8D;AAAA,EAC1G;AACA,SAAO,EAAE,QAAQ,eAAe,SAAS,SAAS,aAAa;AACjE;AAEA,eAAe,mBAAmB,QAAwB,UAAmC,QAAqB;AAChH,QAAM,cAAc,MAAM,OAAO,QAAQ,SAAS,MAAM;AACxD,iBAAe,MAAM;AACrB,MAAI,CAAC,eAAe,CAAC,OAAO,QAAQ,aAAa,OAAO,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpG,UAAM,IAAI,gCAAgC,uDAAuD;AAAA,EACnG;AACA,QAAM,kBAAkB,MAAM,oBAAoB,OAAO,SAAS,aAAa,MAAM;AACrF,iBAAe,MAAM;AACrB,QAAM,eAAe,uBAAuB,OAAO,OAAO,SAAS,eAAe;AAClF,MAAI,aAAa,SAAS,eAAe,CAAC,gBAAgB,aAAa,SAAS,SAAS,aAAa,GAAG;AACvG,UAAM,IAAI,gCAAgC,8DAA8D;AAAA,EAC1G;AACA,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,CAAC,WAAW;AAAA,MACV,GAAG;AAAA,MACH,MAAM,EAAE,GAAG,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,aAAa,EAAE;AAAA,IAC9D;AAAA,IACA;AAAA,MACE,iBAAiB,OAAO;AAAA,MACxB,iBAAiB,SAAS;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,iCACb,KACA,WACA,QACA,SAKA;AACA,QAAM,SAAS,MAAM,WAAW,SAAS;AACzC,MAAI,QAAQ,QAAS,QAAO;AAC5B,gBAAc,KAAK,+BAA+B,iBAAiB,OAAO,SAAS,CAAC,EAAE;AACtF,QAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,MAAI,QAAQ,QAAS,QAAO;AAC5B,QAAM,OAAO,MAAM,QAAQ,SAAS,MAAM;AAC1C,MAAI,QAAQ,QAAS,QAAO;AAC5B,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,SAAS,OAAO;AAC1C,QAAM,WAAW,MAAM,oBAAoB,SAAS,MAAM,MAAM;AAChE,MAAI,QAAQ,QAAS,QAAO;AAC5B,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,OAAO,uBAAuB,OAAO,SAAS,QAAQ;AAAA,EACxD;AACF;AAEA,eAAe,oBACb,KACA,QACA,YACA,QACA;AACA,QAAM,OAAO,WAAqE;AAAA,IAChF,OAAO;AAAA,IACP,SAAS;AAAA,MACP,QAAQ,OAAO;AAAA,QACb,MAAM;AAAA,QACN,OAAO,+BAA4B,iBAAiB,OAAO,SAAS,CAAC;AAAA,QACrE,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,QACA,OAAO;AAAA,UACL,EAAE,IAAI,UAAU,OAAO,2BAA2B,IAAI,SAAS;AAAA,UAC/D,EAAE,IAAI,QAAQ,OAAO,QAAQ,QAAQ,OAAO;AAAA,QAC9C;AAAA,QACA,MAAM;AAAA,MACR;AAAA,MACA,QAAQ,OAAO;AAAA,QACb,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA,GAAI,WAAW,SAAS,IACpB,WAAW,IAAI,CAAC,SAAS,eAAe,iBAAiB,IAAI,CAAC,EAAE,IAChE,CAAC,gCAAgC;AAAA,UACrC;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,QAAQ,EAAE,MAAM,OAAO;AAAA,QACvB,cAAc;AAAA,QACd,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,SAAS,EAAE,MAAM,aAAa,EAAE,MAAM,QAAQ,GAAG;AAAA,EACnD,CAAC;AACD,QAAM,QAAQ,KAAK,MAAM;AAAA,IACvB,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,WAAW,MAAM,CAAC,QAAQ;AAAA,EAC5B,CAAC;AACH;AAEA,SAAS,sBAAsB,UAAmC;AAChE,QAAM,aAAa,mBAAmB,SAAS,cAAc,SAAS,aAAa;AACnF,SAAO;AAAA,IACL,eAAe,iBAAiB,SAAS,SAAS,CAAC;AAAA,IACnD;AAAA,IACA,GAAI,WAAW,WAAW,WAAW,KAAK,WAAW,UAAU,WAAW,IACtE,CAAC,oDAAoD,IACrD,CAAC,sBAAsB,WAAW,WAAW,MAAM,4BAAyB,WAAW,UAAU,MAAM,EAAE;AAAA,EAC/G;AACF;AAEA,SAAS,0BAA0B,UAAmC;AACpE,QAAM,aAAa,mBAAmB,SAAS,cAAc,SAAS,aAAa;AACnF,SAAO;AAAA,IACL,GAAI,WAAW,WAAW,WAAW,KAAK,WAAW,UAAU,WAAW,IACtE,CAAC,6DAA6D,EAAE,IAChE,CAAC;AAAA,IACL;AAAA,IACA,GAAI,WAAW,WAAW,SAAS,IAC/B,WAAW,WAAW,IAAI,CAAC,SAAS,KAAK,iBAAiB,IAAI,CAAC,EAAE,IACjE,CAAC,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA,GAAI,WAAW,UAAU,SAAS,IAC9B,WAAW,UAAU,IAAI,CAAC,SAAS,KAAK,iBAAiB,IAAI,CAAC,EAAE,IAChE,CAAC,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA,GAAI,SAAS,cAAc,SAAS,IAChC,SAAS,cAAc,IAAI,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,iBAAiB,IAAI,CAAC,EAAE,IACrF,CAAC,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA,GAAI,SAAS,aAAa,SAAS,IAC/B,SAAS,aAAa,IAAI,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,iBAAiB,IAAI,CAAC,EAAE,IACpF,CAAC,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,6BAA6B,UAAmC;AACvE,QAAM,aAAa,mBAAmB,SAAS,cAAc,SAAS,aAAa;AACnF,SAAO;AAAA,IACL,4BAAuB,iBAAiB,SAAS,SAAS,CAAC;AAAA,IAC3D,gBAAgB,SAAS,WAAW,UAAU,CAAC;AAAA,IAC/C,gBAAgB,SAAS,WAAW,SAAS,CAAC;AAAA,IAC9C,GAAI,WAAW,WAAW,WAAW,KAAK,WAAW,UAAU,WAAW,IACtE;AAAA,MACE;AAAA,MACA,iBAAiB,SAAS,SAAS,aAAa,CAAC;AAAA,MACjD,iBAAiB,SAAS,SAAS,YAAY,CAAC;AAAA,IAClD,IACA,CAAC;AAAA,IACL;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,oBAAoB,QAAuB,YAA+B;AACjF,SAAO,6BAAwB,iBAAiB,OAAO,SAAS,CAAC,+CAA0C,WAAW,MAAM,aAAa,WAAW,WAAW,IAAI,SAAS,QAAQ;AACtL;AAEA,SAAS,kBACP,QACA,OACyB;AACzB,SAAO;AAAA,IACL,WAAW,OAAO;AAAA,IAClB,gBAAgB,4BAA4B,MAAM;AAAA,IAClD,cAAc,CAAC,GAAG,OAAO,OAAO;AAAA,IAChC,eAAe,CAAC,GAAG,MAAM,OAAO;AAAA,EAClC;AACF;AAEA,SAAS,4BAA4B,QAAuB,UAAmC;AAC7F,MACE,4BAA4B,MAAM,MAAM,SAAS,kBACjD,gBAAgB,OAAO,SAAS,SAAS,YAAY,GACrD;AACA;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR,oBAAe,iBAAiB,OAAO,SAAS,CAAC;AAAA,EACnD;AACF;AAEA,SAAS,uBAAuB,MAAqB,OAAsB;AACzE,SACE,KAAK,cAAc,MAAM,aACzB,KAAK,mBAAmB,MAAM,kBAC9B,KAAK,gBAAgB,MAAM,eAC3B,KAAK,gBAAgB,MAAM,eAC3B,KAAK,WAAW,MAAM,UACtB,KAAK,WAAW,MAAM,UACtB,gBAAgB,KAAK,SAAS,MAAM,OAAO;AAE/C;AAEA,SAAS,cAAc,QAA+B;AACpD,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO;AACT;AAEA,SAAS,kBAAkB,QAA+B;AACxD,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO;AACT;AAEA,SAAS,6BAA6B,OAAiC;AACrE,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,OAAQ,QAAO;AAC7B,SAAO;AACT;AAEA,SAAS,SAAS,QAA2B;AAC3C,SAAO,OAAO,SAAS,IAAI,OAAO,IAAI,gBAAgB,EAAE,KAAK,IAAI,IAAI;AACvE;AAEA,IAAM,kCAAN,cAA8C,MAAM;AAAA,EAClD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,SAAS,mBAAmB,OAAgB;AAC1C,SAAO,iBAAiB,mCAAmC,iBAAiB;AAC9E;AAEA,SAAS,2BACP,SACA,MACA;AACA,SAAO,QAAQ,kBAAkB,QAAQ,gBAAgB,IAAI,IAAI,KAAK;AACxE;AAEA,SAAS,eAAe,eAAwC,cAA2B;AACzF,SAAO,gBAAgB,YAAY,IAAI,CAAC,eAAe,YAAY,CAAC,IAAI;AAC1E;AAEA,SAAS,eAAe,QAAqB;AAC3C,MAAI,CAAC,OAAO,QAAS;AACrB,QAAM,OAAO,kBAAkB,QAAQ,OAAO,SAAS,IAAI,aAAa,6BAA6B,YAAY;AACnH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -212,9 +212,7 @@ function isDirectoryRoot(directory, label) {
|
|
|
212
212
|
try {
|
|
213
213
|
const entry = lstatSync(directory);
|
|
214
214
|
if (entry.isSymbolicLink()) {
|
|
215
|
-
throw new Error(
|
|
216
|
-
`Refusing to use ${label} pi-sync state directory symbolic link: ${directory}`
|
|
217
|
-
);
|
|
215
|
+
throw new Error(`Refusing to use ${label} pi-sync state directory symbolic link: ${directory}`);
|
|
218
216
|
}
|
|
219
217
|
if (!entry.isDirectory()) {
|
|
220
218
|
throw new Error(`${label} pi-sync state path is not a directory: ${directory}`);
|
|
@@ -244,4 +242,4 @@ export {
|
|
|
244
242
|
withStateDirectoryAccess,
|
|
245
243
|
migrateLegacyStateDirectory
|
|
246
244
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
245
|
+
//# sourceMappingURL=chunk-BVVP33U5.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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 | { status: \"ready\" }\n | { status: \"migrated\"; message: string }\n | { status: \"deferred\"; message: string };\n\ninterface StateDirectoryGuard {\n release: () => Promise<void>;\n throwIfCompromised: () => void;\n}\n\ninterface SharedStateDirectoryGuard {\n guard: Promise<StateDirectoryGuard>;\n users: number;\n closing?: Promise<void>;\n}\n\nconst sharedStateDirectoryGuards = new Map<string, SharedStateDirectoryGuard>();\n\nexport function stateDir() {\n const roots = inspectStateRoots();\n if (roots.canonical) return canonicalStateDir();\n if (roots.legacy) return legacyStateDir();\n return canonicalStateDir();\n}\n\nexport function legacyStateDir() {\n return path.join(getAgentDir(), LEGACY_DIRECTORY_NAME);\n}\n\nexport function stateDirectoryMigrationNotice() {\n const roots = inspectStateRoots();\n if (!roots.legacy) return undefined;\n return \"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 const roots = inspectStateRoots();\n if (!roots.legacy) return fn();\n return runWithStateDirectoryGuard(await acquireSharedStateDirectoryGuard(), fn);\n}\n\nexport async function migrateLegacyStateDirectory(): Promise<StateDirectoryPreparation> {\n const initial = inspectStateRoots();\n if (initial.canonical || !initial.legacy) return { status: \"ready\" };\n\n let guard: StateDirectoryGuard;\n try {\n guard = await acquireStateDirectoryGuard();\n } catch (error) {\n if (!isLockHeldError(error)) throw error;\n return {\n status: \"deferred\",\n message:\n \"pi-sync state migration was deferred because another state user is active. Close other Pi sessions and retry.\",\n };\n }\n return runWithStateDirectoryGuard(guard, async () => {\n const roots = inspectStateRoots();\n if (roots.canonical || !roots.legacy) return { status: \"ready\" };\n\n const legacyLock = path.join(legacyStateDir(), \"lock\");\n const legacyGuardHeld = await lockfile.check(legacyLock, {\n fs: LOCKFILE_FS_ADAPTER,\n lockfilePath: `${legacyLock}.guard`,\n realpath: false,\n stale: LOCK_GUARD_STALE_MS,\n });\n if (legacyGuardHeld || (await pathExists(legacyLock))) {\n return {\n status: \"deferred\",\n message:\n \"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 };\n }\n guard.throwIfCompromised();\n await fs.rename(legacyStateDir(), canonicalStateDir());\n guard.throwIfCompromised();\n inspectStateRoots();\n return {\n status: \"migrated\",\n message: `Migrated pi-sync state from ${legacyStateDir()} to ${canonicalStateDir()}.`,\n };\n });\n}\n\nasync function acquireSharedStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n const key = migrationLockPath();\n for (;;) {\n let shared = sharedStateDirectoryGuards.get(key);\n if (shared?.closing) {\n await shared.closing;\n continue;\n }\n if (!shared) {\n shared = { guard: acquireStateDirectoryGuard(), users: 0 };\n sharedStateDirectoryGuards.set(key, shared);\n }\n shared.users += 1;\n let guard: StateDirectoryGuard;\n try {\n guard = await shared.guard;\n } catch (error) {\n if (sharedStateDirectoryGuards.get(key) === shared) {\n sharedStateDirectoryGuards.delete(key);\n }\n throw error;\n }\n let released = false;\n return {\n throwIfCompromised: guard.throwIfCompromised,\n release: async () => {\n if (released) return;\n released = true;\n shared.users -= 1;\n if (shared.users > 0) return;\n const closing = guard.release();\n shared.closing = closing;\n try {\n await closing;\n } finally {\n if (sharedStateDirectoryGuards.get(key) === shared) {\n sharedStateDirectoryGuards.delete(key);\n }\n }\n },\n };\n }\n}\n\nasync function acquireStateDirectoryGuard(): Promise<StateDirectoryGuard> {\n let compromisedError: Error | undefined;\n const release = await lockfile.lock(getAgentDir(), {\n fs: LOCKFILE_FS_ADAPTER,\n lockfilePath: migrationLockPath(),\n realpath: false,\n stale: MIGRATION_LOCK_STALE_MS,\n update: MIGRATION_LOCK_UPDATE_MS,\n retries: { retries: 20, minTimeout: 10, maxTimeout: 50 },\n onCompromised: (error) => {\n compromisedError = error;\n },\n });\n return {\n release,\n throwIfCompromised: () => {\n if (compromisedError) throw compromisedError;\n },\n };\n}\n\nasync function runWithStateDirectoryGuard<T>(guard: StateDirectoryGuard, fn: () => Promise<T>) {\n let result: T | undefined;\n let failed = false;\n let failure: unknown;\n try {\n guard.throwIfCompromised();\n result = await fn();\n guard.throwIfCompromised();\n } catch (error) {\n failed = true;\n failure = error;\n }\n try {\n await guard.release();\n } catch (error) {\n if (!failed) {\n failed = true;\n failure = error;\n }\n }\n if (failed) throw failure;\n return result as T;\n}\n\nfunction isLockHeldError(error: unknown) {\n return (error as NodeJS.ErrnoException).code === \"ELOCKED\";\n}\n\nfunction canonicalStateDir() {\n return path.join(getAgentDir(), CANONICAL_DIRECTORY_NAME);\n}\n\nfunction migrationLockPath() {\n return path.join(getAgentDir(), MIGRATION_LOCK_NAME);\n}\n\nfunction inspectStateRoots() {\n const canonical = isDirectoryRoot(canonicalStateDir(), \"canonical\");\n const legacy = isDirectoryRoot(legacyStateDir(), \"legacy\");\n if (canonical && legacy) {\n throw new Error(\n `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 );\n }\n return { canonical, legacy };\n}\n\nfunction isDirectoryRoot(directory: string, label: string) {\n try {\n const entry = lstatSync(directory);\n if (entry.isSymbolicLink()) {\n throw new Error(`Refusing to use ${label} pi-sync state directory symbolic link: ${directory}`);\n }\n if (!entry.isDirectory()) {\n throw new Error(`${label} pi-sync state path is not a directory: ${directory}`);\n }\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n\nasync function pathExists(filePath: string) {\n try {\n await fs.lstat(filePath);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n", "export const LOCK_GUARD_STALE_MS = 30_000;\nexport const LOCK_GUARD_UPDATE_MS = 10_000;\n", "import {\n mkdir,\n mkdirSync,\n realpath,\n realpathSync,\n rmdir,\n rmdirSync,\n stat,\n statSync,\n utimes,\n utimesSync,\n} from \"node:fs\";\n\nexport const LOCKFILE_FS_ADAPTER = {\n mkdir,\n mkdirSync,\n realpath,\n realpathSync,\n rmdir,\n rmdirSync,\n stat,\n statSync,\n utimes,\n utimesSync,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
createSyncBackend
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HGJH56KR.ts";
|
|
6
6
|
import {
|
|
7
7
|
hasLocalChanges,
|
|
8
8
|
remoteChangedSinceState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-T56RNRZJ.ts";
|
|
10
10
|
import {
|
|
11
11
|
throwIfAborted
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-PWMWOJP4.ts";
|
|
13
13
|
import {
|
|
14
14
|
readStateForConfig,
|
|
15
15
|
syncStateFingerprint
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YPXGU5OR.ts";
|
|
17
17
|
import {
|
|
18
18
|
createSnapshot
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-EEJPYTWE.ts";
|
|
20
20
|
import {
|
|
21
21
|
inspectRemoteSelection
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IVXEDPAD.ts";
|
|
23
23
|
|
|
24
24
|
// src/sync/sync-inspection.ts
|
|
25
25
|
async function inspectSync(config, options, signal, factory = createSyncBackend) {
|
|
@@ -37,12 +37,7 @@ async function inspectSync(config, options, signal, factory = createSyncBackend)
|
|
|
37
37
|
selectionState: head ? inspectRemoteSelection(config.include, { selection: head.selection, files: [] }) : void 0,
|
|
38
38
|
localFiles: local.files.length,
|
|
39
39
|
localChanged: hasLocalChanges(local, state, config),
|
|
40
|
-
remoteChanged: remoteChangedSinceState(
|
|
41
|
-
head,
|
|
42
|
-
state,
|
|
43
|
-
config,
|
|
44
|
-
(left, right) => backend.sameRevision(left, right)
|
|
45
|
-
),
|
|
40
|
+
remoteChanged: remoteChangedSinceState(head, state, config, (left, right) => backend.sameRevision(left, right)),
|
|
46
41
|
firstSync: !state.lastAppliedSnapshot,
|
|
47
42
|
emptyInclude: config.include.length === 0,
|
|
48
43
|
stateIdentity: syncStateFingerprint(state),
|
|
@@ -54,4 +49,4 @@ async function inspectSync(config, options, signal, factory = createSyncBackend)
|
|
|
54
49
|
export {
|
|
55
50
|
inspectSync
|
|
56
51
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-DM4X4FIA.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/sync-inspection.ts"],
|
|
4
|
+
"sourcesContent": ["import { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { createSnapshot } from \"../snapshot/snapshot.js\";\nimport type { SnapshotOptions } from \"../snapshot/snapshot-types.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { inspectRemoteSelection } from \"./sync-policy.js\";\nimport { hasLocalChanges, remoteChangedSinceState } from \"./sync-state.js\";\n\n/** Advisory baseline-relative observation, never an authorization to transfer files. */\nexport async function inspectSync(\n config: AnySyncConfig,\n options: SnapshotOptions,\n signal?: AbortSignal,\n factory: SyncBackendFactory = createSyncBackend,\n) {\n throwIfAborted(signal);\n const backend = await factory(config);\n throwIfAborted(signal);\n const local = await createSnapshot(config.snapshotIdentity, { ...options, signal });\n throwIfAborted(signal);\n const state = await readStateForConfig(config);\n throwIfAborted(signal);\n const head = await backend.readHead(signal);\n throwIfAborted(signal);\n return {\n head,\n selectionState: head ? inspectRemoteSelection(config.include, { selection: head.selection, files: [] }) : undefined,\n localFiles: local.files.length,\n localChanged: hasLocalChanges(local, state, config),\n remoteChanged: remoteChangedSinceState(head, state, config, (left, right) => backend.sameRevision(left, right)),\n firstSync: !state.lastAppliedSnapshot,\n emptyInclude: config.include.length === 0,\n stateIdentity: syncStateFingerprint(state),\n destination: backend.destination,\n capability: backend.capability,\n };\n}\n\nexport type SyncInspection = Awaited<ReturnType<typeof inspectSync>>;\n\nexport interface StartupObservation {\n setupName: string;\n configIdentity: string;\n checkedAt: string;\n inspection: SyncInspection;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAUA,eAAsB,YACpB,QACA,SACA,QACA,UAA8B,mBAC9B;AACA,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,IACL;AAAA,IACA,gBAAgB,OAAO,uBAAuB,OAAO,SAAS,EAAE,WAAW,KAAK,WAAW,OAAO,CAAC,EAAE,CAAC,IAAI;AAAA,IAC1G,YAAY,MAAM,MAAM;AAAA,IACxB,cAAc,gBAAgB,OAAO,OAAO,MAAM;AAAA,IAClD,eAAe,wBAAwB,MAAM,OAAO,QAAQ,CAAC,MAAM,UAAU,QAAQ,aAAa,MAAM,KAAK,CAAC;AAAA,IAC9G,WAAW,CAAC,MAAM;AAAA,IAClB,cAAc,OAAO,QAAQ,WAAW;AAAA,IACxC,eAAe,qBAAqB,KAAK;AAAA,IACzC,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,EACtB;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
setSyncSetupCompletions
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-YFADF5ZQ.ts";
|
|
6
6
|
import {
|
|
7
7
|
safeTerminalText
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-MSSW6F3R.ts";
|
|
9
9
|
import {
|
|
10
10
|
configuredSyncSetupNames,
|
|
11
11
|
loadConfig,
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
syncConfigReviewIdentity,
|
|
14
14
|
syncSetupReviewIdentity,
|
|
15
15
|
updateLocalConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-4MPIH46N.ts";
|
|
17
17
|
import {
|
|
18
18
|
SetupPullRequiresUiError
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-7D5SF7P3.ts";
|
|
20
20
|
|
|
21
21
|
// src/sync/setup-switch.ts
|
|
22
22
|
var SETUP_SWITCH_ACTION_OPTIONS = [
|
|
@@ -58,9 +58,7 @@ async function useSyncSetup(ctx, name, pullCurrentSetup, expectedAction, signal,
|
|
|
58
58
|
}
|
|
59
59
|
switchResult.action = normalizeOnSwitch(current.onSwitch);
|
|
60
60
|
if (expectedAction !== void 0 && switchResult.action !== expectedAction) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
"Setup-switch behavior changed while the preview was open; reopen it and retry."
|
|
63
|
-
);
|
|
61
|
+
throw new Error("Setup-switch behavior changed while the preview was open; reopen it and retry.");
|
|
64
62
|
}
|
|
65
63
|
if (switchResult.action === "pull-after-switch" && !ctx.hasUI) {
|
|
66
64
|
throw new SetupPullRequiresUiError(
|
|
@@ -97,17 +95,11 @@ async function useSyncSetup(ctx, name, pullCurrentSetup, expectedAction, signal,
|
|
|
97
95
|
);
|
|
98
96
|
throwIfAborted(signal);
|
|
99
97
|
if (!confirmed) {
|
|
100
|
-
ctx.ui.notify(
|
|
101
|
-
`Switched to \u201C${safeTerminalText(normalized)}\u201D; files were not pulled.`,
|
|
102
|
-
"info"
|
|
103
|
-
);
|
|
98
|
+
ctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D; files were not pulled.`, "info");
|
|
104
99
|
return { pullApplied: false };
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
|
-
ctx.ui.notify(
|
|
108
|
-
`Switched to \u201C${safeTerminalText(normalized)}\u201D. Checking remote files for a reviewed pull\u2026`,
|
|
109
|
-
"info"
|
|
110
|
-
);
|
|
102
|
+
ctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D. Checking remote files for a reviewed pull\u2026`, "info");
|
|
111
103
|
if (!pullCurrentSetup) {
|
|
112
104
|
throw new Error(`Switched to \u201C${safeTerminalText(normalized)}\u201D, but pull is unavailable.`);
|
|
113
105
|
}
|
|
@@ -133,4 +125,4 @@ export {
|
|
|
133
125
|
saveOnSwitch,
|
|
134
126
|
useSyncSetup
|
|
135
127
|
};
|
|
136
|
-
//# sourceMappingURL=chunk-
|
|
128
|
+
//# sourceMappingURL=chunk-DZUSTGQV.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/setup-switch.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { setSyncSetupCompletions } from \"../commands/command.js\";\nimport { loadConfig, syncConfigReviewIdentity, syncSetupReviewIdentity } 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 label: string;\n value: OnSwitchAction;\n}> = [\n { label: \"Ask before pull\", value: \"ask-before-pull\" },\n { label: \"Start pull\", value: \"pull-after-switch\" },\n { label: \"Switch only\", value: \"switch-only\" },\n];\n\nexport function setupSwitchActionLabel(action: OnSwitchAction) {\n return SETUP_SWITCH_ACTION_OPTIONS.find((option) => option.value === action)?.label ?? action;\n}\n\nexport function setupSwitchActionFromLabel(label: string): OnSwitchAction | undefined {\n return SETUP_SWITCH_ACTION_OPTIONS.find((option) => option.label === label)?.value;\n}\n\nexport async function saveOnSwitch(action: OnSwitchAction, signal?: AbortSignal) {\n await updateLocalConfig((settings) => ({ ...settings, onSwitch: action }), signal);\n}\n\nexport type SetupPullOutcome = \"applied\" | \"cancelled\";\n\nexport interface SetupSwitchResult {\n pullApplied: boolean;\n}\n\nexport async function useSyncSetup(\n ctx: ExtensionCommandContext,\n name: string,\n pullCurrentSetup?: (setup: string) => Promise<SetupPullOutcome | undefined>,\n expectedAction?: OnSwitchAction,\n signal?: AbortSignal,\n expectedSetupIdentity?: string,\n): Promise<SetupSwitchResult> {\n const normalized = name.trim();\n if (!normalized) throw new Error(\"Usage: /sync use <setup>\");\n const loadedConfig = await loadConfig(normalized);\n const reviewedSetupIdentity = expectedSetupIdentity ?? syncConfigReviewIdentity(loadedConfig);\n throwIfAborted(signal);\n const switchResult: { action: OnSwitchAction; switched: boolean } = {\n action: \"ask-before-pull\",\n switched: false,\n };\n await updateLocalConfig((current) => {\n throwIfAborted(signal);\n const setup = current.syncSetups[normalized];\n if (!setup) {\n throw new Error(`Sync setup \u201C${safeTerminalText(normalized)}\u201D no longer exists.`);\n }\n const connectionName = setup.storage.connection;\n const connection = current.storageConnections[connectionName];\n if (\n !connection ||\n syncSetupReviewIdentity(normalized, setup, connectionName, connection) !== reviewedSetupIdentity\n ) {\n throw new Error(\n `Sync setup \u201C${safeTerminalText(normalized)}\u201D changed while the switch preview was open; reopen it and review the current destination.`,\n );\n }\n switchResult.action = normalizeOnSwitch(current.onSwitch);\n if (expectedAction !== undefined && switchResult.action !== expectedAction) {\n throw new Error(\"Setup-switch behavior changed while the preview was open; reopen it and retry.\");\n }\n if (switchResult.action === \"pull-after-switch\" && !ctx.hasUI) {\n throw new SetupPullRequiresUiError(\n `Automatic setup pulls require interactive confirmation; sync setup \u201C${safeTerminalText(normalized)}\u201D was not switched. Use TUI or RPC mode.`,\n );\n }\n if (current.activeSyncSetup === normalized) return current;\n switchResult.switched = true;\n return { ...current, activeSyncSetup: normalized };\n }, signal);\n throwIfAborted(signal);\n if (!switchResult.switched) {\n ctx.ui.notify(`Sync setup \u201C${safeTerminalText(normalized)}\u201D is already current.`, \"info\");\n return { pullApplied: false };\n }\n setSyncSetupCompletions(await configuredSyncSetupNames());\n throwIfAborted(signal);\n\n if (switchResult.action === \"switch-only\") {\n ctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D. No files were pulled.`, \"info\");\n return { pullApplied: false };\n }\n if (switchResult.action === \"ask-before-pull\") {\n if (ctx.mode !== \"tui\") {\n ctx.ui.notify(\n `Switched to \u201C${safeTerminalText(normalized)}\u201D. No files were pulled because confirmation requires TUI mode; run /sync pull to apply this setup.`,\n \"info\",\n );\n return { pullApplied: false };\n }\n const confirmed = await ctx.ui.confirm(\n `Review a pull for sync setup \u201C${safeTerminalText(normalized)}\u201D now?`,\n \"pi-sync will check the remote snapshot and show the exact local writes and deletions before applying anything.\",\n { signal },\n );\n throwIfAborted(signal);\n if (!confirmed) {\n ctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D; files were not pulled.`, \"info\");\n return { pullApplied: false };\n }\n }\n\n ctx.ui.notify(`Switched to \u201C${safeTerminalText(normalized)}\u201D. Checking remote files for a reviewed pull\u2026`, \"info\");\n if (!pullCurrentSetup) {\n throw new Error(`Switched to \u201C${safeTerminalText(normalized)}\u201D, but pull is unavailable.`);\n }\n const pullOutcome = await pullCurrentSetup(normalized);\n throwIfAborted(signal);\n if (pullOutcome === \"cancelled\") {\n ctx.ui.notify(\n `Pull cancelled; sync setup \u201C${safeTerminalText(normalized)}\u201D remains current and synced files were not changed.`,\n \"info\",\n );\n }\n return { pullApplied: pullOutcome === \"applied\" };\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
import {
|
|
4
4
|
runCancellableOperation,
|
|
5
5
|
showRemoteSelectionReview
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7KHKWL3Q.ts";
|
|
7
7
|
import {
|
|
8
8
|
safeTerminalText
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-MSSW6F3R.ts";
|
|
10
10
|
import {
|
|
11
11
|
loadConfig,
|
|
12
12
|
syncConfigReviewIdentity
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-4MPIH46N.ts";
|
|
14
14
|
import {
|
|
15
15
|
errorMessage
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7D5SF7P3.ts";
|
|
17
17
|
|
|
18
18
|
// src/ui/sync-resolution-ui.ts
|
|
19
19
|
import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
|
|
@@ -158,20 +158,14 @@ async function dispatchManagerResult(ctx, initialResult, origin, runRoute, signa
|
|
|
158
158
|
if (signal?.aborted) return { kind: "close" };
|
|
159
159
|
if (result.kind === "remote-selection-required") {
|
|
160
160
|
resolving = true;
|
|
161
|
-
const resolution = await showRemoteSelectionReview(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
runRoute,
|
|
170
|
-
cancelLabel: options.cancelLabel,
|
|
171
|
-
onSelectionResolved: options.onSelectionResolved,
|
|
172
|
-
withStateAccess: options.withStateAccess
|
|
173
|
-
}
|
|
174
|
-
);
|
|
161
|
+
const resolution = await showRemoteSelectionReview(ctx, result.decision.setupName, signal, void 0, {
|
|
162
|
+
decision: result.decision,
|
|
163
|
+
origin: currentRoute,
|
|
164
|
+
runRoute,
|
|
165
|
+
cancelLabel: options.cancelLabel,
|
|
166
|
+
onSelectionResolved: options.onSelectionResolved,
|
|
167
|
+
withStateAccess: options.withStateAccess
|
|
168
|
+
});
|
|
175
169
|
if (resolution.kind === "route-result") {
|
|
176
170
|
result = resolution.result;
|
|
177
171
|
currentRoute = resolution.route;
|
|
@@ -212,4 +206,4 @@ async function dispatchManagerResult(ctx, initialResult, origin, runRoute, signa
|
|
|
212
206
|
export {
|
|
213
207
|
dispatchManagerResult
|
|
214
208
|
};
|
|
215
|
-
//# sourceMappingURL=chunk-
|
|
209
|
+
//# sourceMappingURL=chunk-E42GXD6D.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
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 { type RunRoute, type RunRouteResult, runCancellableOperation } from \"./cancellable-operation.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\nexport type SyncResolutionResult =\n | { kind: \"resolved\"; direction: SyncResolutionDirection }\n | {\n kind: \"route-result\";\n result: RunRouteResult;\n route: SyncResolutionDirection;\n }\n | { kind: \"back\" }\n | { kind: \"closed\" }\n | { kind: \"stale\" };\n\nexport async function showSyncResolution(\n ctx: ExtensionContext,\n initialDecision: SyncDecision,\n runRoute: RunRoute,\n sessionSignal?: AbortSignal,\n): Promise<SyncResolutionResult> {\n type Screen = \"resolve\" | \"review\";\n type Action = \"push\" | \"pull\" | \"back\";\n let currentDecision = initialDecision;\n let resolvedDirection: SyncResolutionDirection | undefined;\n let chainedResult: { result: RunRouteResult; route: SyncResolutionDirection } | undefined;\n const menu = defineMenu<SyncDecision, Screen, Action, ExtensionContext>({\n start: \"resolve\",\n screens: {\n resolve: ({ state }) => ({\n kind: \"actions\",\n title: resolutionTitle(state),\n lines: resolutionLines(state),\n items: [\n { id: \"review\", label: \"Review differences (recommended)\", to: \"review\" },\n ...(state.directions.includes(\"push\")\n ? [\n {\n id: \"push\",\n label: pushLabel(state),\n description: \"Review an exact push before replacing the remote version.\",\n action: \"push\" as const,\n },\n ]\n : []),\n ...(state.directions.includes(\"pull\")\n ? [\n {\n id: \"pull\",\n label: pullLabel(state),\n description: \"Review exact local changes and create a backup before applying.\",\n action: \"pull\" as const,\n },\n ]\n : []),\n { id: \"back\", label: \"Back\", action: \"back\" },\n ],\n hint: \"back\",\n }),\n review: ({ state }) => ({\n kind: \"review\",\n title: `Review differences \u00B7 ${safeTerminalText(state.setupName)}`,\n content: state.review,\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n },\n actions: {\n push: ({ state, signal }) => resolveDirection(\"push\", state, signal),\n pull: ({ state, signal }) => resolveDirection(\"pull\", state, signal),\n back: async () => ({ kind: \"back\" }),\n },\n });\n\n async function resolveDirection(\n direction: SyncResolutionDirection,\n decision: SyncDecision,\n actionSignal: AbortSignal,\n ) {\n const signal = sessionSignal ? AbortSignal.any([sessionSignal, actionSignal]) : actionSignal;\n const config = await loadConfig(decision.setupName);\n if (signal.aborted) return { kind: \"close\" as const };\n if (syncConfigReviewIdentity(config) !== decision.configIdentity) {\n throw new Error(\n `Sync setup \u201C${safeTerminalText(decision.setupName)}\u201D changed while conflict resolution was open; return to the sync manager and retry.`,\n );\n }\n const result = await runCancellableOperation(\n ctx,\n direction === \"push\" ? \"Preparing local-wins push preview\u2026\" : \"Preparing remote-wins pull preview\u2026\",\n `${direction} --force`,\n runRoute,\n {\n commitAware: true,\n cancelledMessage:\n direction === \"push\"\n ? \"Push preparation cancelled; no remote files were changed.\"\n : \"Pull check cancelled; no local files were changed.\",\n target: decision.setupName,\n signal,\n },\n );\n if (result.kind === \"decision-required\") {\n currentDecision = result.decision;\n return { kind: \"stay\" as const };\n }\n if (result.kind === \"remote-selection-required\") {\n chainedResult = { result, route: direction };\n return { kind: \"close\" as const };\n }\n if (result.kind === \"completed\") {\n if (result.outcome === \"cancelled\") return { kind: \"stay\" as const };\n resolvedDirection = direction;\n return { kind: \"close\" as const };\n }\n return result.kind === \"closed\" ? { kind: \"close\" as const } : { kind: \"stay\" as const };\n }\n\n const result = await runMenu(ctx, menu, {\n getState: () => currentDecision,\n signal: sessionSignal,\n isCurrent: () => !sessionSignal?.aborted,\n onError: (_menuCtx, error) => ctx.ui.notify(errorMessage(error), \"error\"),\n });\n if (sessionSignal?.aborted || result.kind === \"stale\") return { kind: \"stale\" };\n if (chainedResult) return { kind: \"route-result\", ...chainedResult };\n if (resolvedDirection) return { kind: \"resolved\", direction: resolvedDirection };\n if (result.kind === \"closed\") {\n return result.reason === \"back\" ? { kind: \"back\" } : { kind: \"closed\" };\n }\n return { kind: \"closed\" };\n}\n\nfunction resolutionTitle(decision: SyncDecision) {\n return decision.kind === \"remote-empty\" ? \"Remote is empty\" : \"Resolve sync conflict\";\n}\n\nfunction resolutionLines(decision: SyncDecision) {\n return [\n `Sync setup: ${safeTerminalText(decision.setupName)}`,\n ...causeSummary(decision),\n \"No files have been changed by this failed operation.\",\n ];\n}\n\nfunction causeSummary(decision: SyncDecision) {\n if (decision.kind === \"first-sync-settings-diverged\") {\n return [\"This machine and the remote have different Pi settings on first sync.\"];\n }\n if (decision.kind === \"first-sync-sessions-diverged\") {\n return [\"Pi settings match, but local and remote sessions differ on first sync.\"];\n }\n if (decision.kind === \"remote-empty\") return [\"The remote storage location has no snapshot.\"];\n return [\n ...(decision.causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n ...(decision.causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n ...(decision.causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n ];\n}\n\nfunction pushLabel(decision: SyncDecision) {\n if (decision.kind === \"remote-empty\") return \"Push local content\u2026\";\n if (decision.kind.startsWith(\"first-sync-\")) return \"Use local as initial source\u2026\";\n return \"Keep local content and replace remote\u2026\";\n}\n\nfunction pullLabel(decision: SyncDecision) {\n return decision.kind.startsWith(\"first-sync-\")\n ? \"Use remote as initial source\u2026\"\n : \"Use remote content and replace local\u2026\";\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport type { CancellableOperationResult, RunRoute, RunRouteResult } 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 kind: \"close\" | \"stay\";\n appliedRoute?: \"sync\" | \"pull\" | \"push\";\n}\n\nexport interface ManagerResultOptions {\n cancelLabel?: string;\n onSelectionResolved?: () => void;\n withStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n}\n\nexport async function dispatchManagerResult(\n ctx: ExtensionContext,\n initialResult: CancellableOperationResult,\n origin: Exclude<RemoteSelectionOrigin, \"settings\">,\n runRoute: RunRoute,\n signal?: AbortSignal,\n options: ManagerResultOptions = {},\n): Promise<ManagerResultDisposition> {\n let result: CancellableOperationResult | RunRouteResult = initialResult;\n let currentRoute: \"sync\" | \"pull\" | \"push\" = origin;\n let resolving = false;\n\n for (let transition = 0; transition < MAX_DECISION_TRANSITIONS; transition += 1) {\n if (signal?.aborted) return { kind: \"close\" };\n if (result.kind === \"remote-selection-required\") {\n resolving = true;\n const resolution = await showRemoteSelectionReview(ctx, result.decision.setupName, signal, undefined, {\n decision: result.decision,\n origin: currentRoute,\n runRoute,\n cancelLabel: options.cancelLabel,\n onSelectionResolved: options.onSelectionResolved,\n withStateAccess: options.withStateAccess,\n });\n if (resolution.kind === \"route-result\") {\n result = resolution.result;\n currentRoute = resolution.route;\n continue;\n }\n return resolution.kind === \"closed\" || resolution.kind === \"stale\" ? { kind: \"close\" } : { kind: \"stay\" };\n }\n if (result.kind === \"decision-required\") {\n resolving = true;\n const resolution = await showSyncResolution(ctx, result.decision, runRoute, signal);\n if (resolution.kind === \"route-result\") {\n result = resolution.result;\n currentRoute = resolution.route;\n continue;\n }\n if (resolution.kind === \"resolved\") {\n return { kind: \"close\", appliedRoute: resolution.direction };\n }\n return resolution.kind === \"closed\" || resolution.kind === \"stale\" ? { kind: \"close\" } : { kind: \"stay\" };\n }\n if (result.kind === \"closed\") return { kind: \"close\" };\n if (result.kind === \"completed\") {\n const appliedRoute = result.outcome === \"applied\" ? currentRoute : undefined;\n if (resolving || (origin === \"pull\" && result.outcome === \"applied\")) {\n return { kind: \"close\", ...(appliedRoute ? { appliedRoute } : {}) };\n }\n return { kind: \"stay\", ...(appliedRoute ? { appliedRoute } : {}) };\n }\n return { kind: \"stay\" };\n }\n\n ctx.ui.notify(\n \"Sync resolution stopped after too many state changes. Start /sync again to review fresh state.\",\n \"warning\",\n );\n return { kind: \"stay\" };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["result"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
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 return enabled ? \"On (startup check; shutdown pushes selected content if sessions included)\" : \"Off\";\n}\n"],
|
|
5
|
+
"mappings": ";;;;AACO,SAAS,qBAAqB,SAAkB;AACrD,SAAO,UAAU,8EAA8E;AACjG;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
sessionStorageRoot
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SWUXA3MH.ts";
|
|
6
6
|
import {
|
|
7
7
|
agentDir,
|
|
8
8
|
configuredSessionDir
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OVDTF5CH.ts";
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_SYNC_INCLUDE,
|
|
12
12
|
canonicalSnapshotPathForConfig,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
snapshotSelectionInclude,
|
|
24
24
|
syncIncludeSelection,
|
|
25
25
|
toPosix
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-IVXEDPAD.ts";
|
|
27
27
|
|
|
28
28
|
// src/snapshot/snapshot.ts
|
|
29
29
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -31,9 +31,7 @@ import fs from "node:fs/promises";
|
|
|
31
31
|
import os from "node:os";
|
|
32
32
|
import path from "node:path";
|
|
33
33
|
var VERSION = 1;
|
|
34
|
-
var TOP_LEVEL_FILES = DEFAULT_SYNC_INCLUDE.filter(
|
|
35
|
-
(name) => name.includes(".")
|
|
36
|
-
);
|
|
34
|
+
var TOP_LEVEL_FILES = DEFAULT_SYNC_INCLUDE.filter((name) => name.includes("."));
|
|
37
35
|
var TOP_LEVEL_DIRS = new Set(DEFAULT_SYNC_INCLUDE.filter((name) => !name.includes(".")));
|
|
38
36
|
var SECRET_PATTERNS = [
|
|
39
37
|
/AWS_SECRET_ACCESS_KEY\s*[=:]\s*['"]?[A-Za-z0-9/+]{35,}/i,
|
|
@@ -187,9 +185,7 @@ function isSessionFilePath(relativePath) {
|
|
|
187
185
|
return isSessionPath(normalized) && normalized.endsWith(".jsonl");
|
|
188
186
|
}
|
|
189
187
|
function sessionSnapshotPathFromAbsolute(sessionFile, configuredSessionDir2) {
|
|
190
|
-
const relativePath = toPosix(
|
|
191
|
-
path.relative(sessionStorageRoot(agentDir(), configuredSessionDir2), sessionFile)
|
|
192
|
-
);
|
|
188
|
+
const relativePath = toPosix(path.relative(sessionStorageRoot(agentDir(), configuredSessionDir2), sessionFile));
|
|
193
189
|
if (!relativePath || relativePath.startsWith("../") || path.posix.isAbsolute(relativePath)) {
|
|
194
190
|
return void 0;
|
|
195
191
|
}
|
|
@@ -198,10 +194,7 @@ function sessionSnapshotPathFromAbsolute(sessionFile, configuredSessionDir2) {
|
|
|
198
194
|
}
|
|
199
195
|
function snapshotTarget(root, relativePath, configuredSessionDir2) {
|
|
200
196
|
if (isSessionPath(relativePath)) {
|
|
201
|
-
return safeJoin(
|
|
202
|
-
sessionStorageRoot(root, configuredSessionDir2),
|
|
203
|
-
relativePath.slice("sessions/".length)
|
|
204
|
-
);
|
|
197
|
+
return safeJoin(sessionStorageRoot(root, configuredSessionDir2), relativePath.slice("sessions/".length));
|
|
205
198
|
}
|
|
206
199
|
return safeJoin(root, relativePath);
|
|
207
200
|
}
|
|
@@ -248,10 +241,9 @@ function canonicalizeSnapshotFilesForConfig(files, config, includePaths) {
|
|
|
248
241
|
extraCandidates.set(topLevelPath.toLowerCase(), candidate);
|
|
249
242
|
}
|
|
250
243
|
}
|
|
251
|
-
return [
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
].sort((left, right) => left.path.localeCompare(right.path));
|
|
244
|
+
return [...configuredFiles, ...[...extraCandidates.values()].map((candidate) => candidate.file)].sort(
|
|
245
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
246
|
+
);
|
|
255
247
|
}
|
|
256
248
|
function isPreferredExtraCandidate(left, right) {
|
|
257
249
|
if (left.exact !== right.exact) return left.exact;
|
|
@@ -307,9 +299,7 @@ function mergeRemotePreservedFiles(local, remote, config) {
|
|
|
307
299
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
308
300
|
machine: os.hostname(),
|
|
309
301
|
syncSessions: snapshotIncludesSessions(local) || snapshotIncludesSessions(remote),
|
|
310
|
-
files: [...local.files, ...preserved].sort(
|
|
311
|
-
(left, right) => left.path.localeCompare(right.path)
|
|
312
|
-
)
|
|
302
|
+
files: [...local.files, ...preserved].sort((left, right) => left.path.localeCompare(right.path))
|
|
313
303
|
};
|
|
314
304
|
}
|
|
315
305
|
function mergeRemoteSessionFiles(local, remote) {
|
|
@@ -355,4 +345,4 @@ export {
|
|
|
355
345
|
mergeRemotePreservedFiles,
|
|
356
346
|
mergeRemoteSessionFiles
|
|
357
347
|
};
|
|
358
|
-
//# sourceMappingURL=chunk-
|
|
348
|
+
//# sourceMappingURL=chunk-EEJPYTWE.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/snapshot/snapshot.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { isDeniedPath, posixJoin, safeJoin, toPosix } from \"../paths.js\";\nimport { agentDir, configuredSessionDir } from \"./session-paths.js\";\nimport { sessionStorageRoot } from \"./snapshot-paths.js\";\n\nexport { isDeniedPath } from \"../paths.js\";\nexport { sessionStorageRoot } from \"./snapshot-paths.js\";\n\nimport {\n canonicalSnapshotPathForConfig,\n customIncludePathsByLower,\n DEFAULT_SYNC_INCLUDE,\n includeFromSelectionConfig,\n isConfiguredSnapshotPath,\n isPreservableUnmanagedSnapshotPath,\n normalizeExtraFiles,\n normalizeSyncFiles,\n type SyncSelectionConfig,\n selectionForSnapshot,\n snapshotSelectionInclude,\n syncIncludeSelection,\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) => name.includes(\".\"));\nconst TOP_LEVEL_DIRS = new Set<string>(DEFAULT_SYNC_INCLUDE.filter((name) => !name.includes(\".\")));\nconst SECRET_PATTERNS = [\n /AWS_SECRET_ACCESS_KEY\\s*[=:]\\s*['\"]?[A-Za-z0-9/+]{35,}/i,\n /(ANTHROPIC|OPENAI|GEMINI|GOOGLE|FIRECRAWL|GITHUB|CLOUDFLARE|R2|S3)_[A-Z0-9_]*(KEY|TOKEN|SECRET)\\s*[=:]\\s*['\"]?[^\\s'\"]{12,}/i,\n /sk-ant-[A-Za-z0-9_-]{20,}/,\n /sk-[A-Za-z0-9]{20,}/,\n /gh[pousr]_[A-Za-z0-9_]{20,}/,\n];\n\nfunction selectTopLevelFileEntry(entries: Dirent[], fileName: string) {\n const exact = entries.find((entry) => entry.isFile() && entry.name === fileName);\n if (exact) return exact;\n const lower = fileName.toLowerCase();\n return entries\n .filter((entry) => entry.isFile() && entry.name.toLowerCase() === lower)\n .sort((left, right) => left.name.localeCompare(right.name))[0];\n}\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction isSafeSnapshotPath(relativePath: string) {\n if (relativePath.includes(\"\\\\\")) return false;\n const normalized = toPosix(relativePath);\n return (\n Boolean(normalized) &&\n normalized !== \".\" &&\n normalized !== \"..\" &&\n !normalized.startsWith(\"../\") &&\n !path.posix.isAbsolute(normalized) &&\n path.posix.normalize(normalized) === normalized &&\n !isDeniedPath(normalized)\n );\n}\n\nfunction snapshotsMatch(left: Snapshot, right: Snapshot) {\n const leftHashes = new Map(left.files.map((file) => [file.path, file.sha256]));\n const rightHashes = new Map(right.files.map((file) => [file.path, file.sha256]));\n return (\n left.syncSessions === right.syncSessions &&\n sameOptionalInclude(snapshotSelectionInclude(left), snapshotSelectionInclude(right)) &&\n leftHashes.size === rightHashes.size &&\n [...leftHashes].every(([filePath, hash]) => rightHashes.get(filePath) === hash)\n );\n}\n\nfunction snapshotId() {\n return `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${randomUUID().slice(0, 8)}`;\n}\n\nexport function regenerateSnapshotIdentity(snapshot: Snapshot): Snapshot {\n return {\n ...snapshot,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n };\n}\n\nexport async function createSnapshot(profile: string, options: SnapshotOptions = {}): Promise<Snapshot> {\n options.signal?.throwIfAborted();\n const include = effectiveInclude(options);\n const syncSessions = include.includes(\"sessions\");\n const sessionDir = options.sessionDir ?? (await configuredSessionDir());\n options.signal?.throwIfAborted();\n const files = await collectFiles(agentDir(), { include, sessionDir, signal: options.signal });\n options.signal?.throwIfAborted();\n return {\n version: VERSION,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n profile,\n syncSessions,\n selection: selectionForSnapshot(include),\n files,\n };\n}\n\nfunction effectiveInclude(options: SnapshotOptions) {\n if (options.include) return options.include;\n return [\n ...normalizeSyncFiles(options.syncFiles),\n ...normalizeExtraFiles(options.extraFiles),\n ...(options.syncSessions ? [\"sessions\"] : []),\n ];\n}\n\nexport async function collectFiles(root: string, options: SnapshotOptions = {}): Promise<SnapshotFile[]> {\n const signal = options.signal;\n signal?.throwIfAborted();\n const results: SnapshotFile[] = [];\n const entries = await fs.readdir(root, { withFileTypes: true });\n signal?.throwIfAborted();\n const selection = syncIncludeSelection(effectiveInclude(options));\n const selectedFiles = new Set<string>(selection.builtIns);\n for (const entry of entries) {\n if (entry.isDirectory() && TOP_LEVEL_DIRS.has(entry.name) && selectedFiles.has(entry.name)) {\n await collectDirectory(results, root, entry.name, { signal });\n }\n }\n for (const fileName of TOP_LEVEL_FILES) {\n if (!selectedFiles.has(fileName)) continue;\n const entry = selectTopLevelFileEntry(entries, fileName);\n if (entry) await addFile(results, root, entry.name, fileName, signal);\n }\n for (const relativePath of selection.custom) {\n await collectIncludedPath(results, root, relativePath, signal);\n }\n if (selection.sessions) {\n try {\n await collectDirectory(results, sessionStorageRoot(root, options.sessionDir), \"\", {\n sessionsOnly: true,\n virtualPrefix: \"sessions\",\n signal,\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n }\n signal?.throwIfAborted();\n return results.sort((left, right) => left.path.localeCompare(right.path));\n}\n\nasync function collectIncludedPath(results: SnapshotFile[], root: string, relativePath: string, signal?: AbortSignal) {\n signal?.throwIfAborted();\n const absolutePath = safeJoin(root, relativePath);\n try {\n const stat = await fs.lstat(absolutePath);\n signal?.throwIfAborted();\n if (stat.isFile()) await addFile(results, root, relativePath, relativePath, signal);\n else if (stat.isDirectory()) await collectDirectory(results, root, relativePath, { signal });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n if (!relativePath.includes(\"/\")) {\n const entries = await fs.readdir(root, { withFileTypes: true });\n signal?.throwIfAborted();\n const entry = selectTopLevelFileEntry(entries, relativePath);\n if (entry) await addFile(results, root, entry.name, relativePath, signal);\n }\n }\n}\n\nasync function collectDirectory(\n results: SnapshotFile[],\n root: string,\n relativeDirectory: string,\n options: { sessionsOnly?: boolean; virtualPrefix?: string; signal?: AbortSignal } = {},\n) {\n options.signal?.throwIfAborted();\n const absoluteDirectory = path.join(root, relativeDirectory);\n for (const entry of await fs.readdir(absoluteDirectory, { withFileTypes: true })) {\n options.signal?.throwIfAborted();\n const relativePath = relativeDirectory ? posixJoin(relativeDirectory, entry.name) : entry.name;\n const snapshotPath = options.virtualPrefix ? posixJoin(options.virtualPrefix, relativePath) : relativePath;\n if (isDeniedPath(snapshotPath)) continue;\n if (entry.isDirectory()) {\n await collectDirectory(results, root, relativePath, options);\n } else if (entry.isFile() && (!options.sessionsOnly || isSessionFilePath(snapshotPath))) {\n await addFile(results, root, relativePath, snapshotPath, options.signal);\n }\n }\n}\n\nasync function addFile(\n results: SnapshotFile[],\n root: string,\n relativePath: string,\n snapshotPath = relativePath,\n signal?: AbortSignal,\n) {\n signal?.throwIfAborted();\n if (!isSafeSnapshotPath(snapshotPath)) return;\n const absolutePath = safeJoin(root, relativePath);\n const content = await fs.readFile(absolutePath, { signal });\n signal?.throwIfAborted();\n results.push({\n path: snapshotPath,\n contentBase64: content.toString(\"base64\"),\n sha256: sha256(content),\n });\n}\n\nexport function isSessionPath(relativePath: string) {\n return toPosix(relativePath).startsWith(\"sessions/\");\n}\n\nexport function isSessionFilePath(relativePath: string) {\n const normalized = toPosix(relativePath);\n return isSessionPath(normalized) && normalized.endsWith(\".jsonl\");\n}\n\nexport function sessionSnapshotPathFromAbsolute(sessionFile: string, configuredSessionDir?: string) {\n const relativePath = toPosix(path.relative(sessionStorageRoot(agentDir(), configuredSessionDir), sessionFile));\n if (!relativePath || relativePath.startsWith(\"../\") || path.posix.isAbsolute(relativePath)) {\n return undefined;\n }\n const snapshotPath = posixJoin(\"sessions\", relativePath);\n return isSessionFilePath(snapshotPath) ? snapshotPath : undefined;\n}\n\nexport function snapshotTarget(root: string, relativePath: string, configuredSessionDir?: string) {\n if (isSessionPath(relativePath)) {\n return safeJoin(sessionStorageRoot(root, configuredSessionDir), relativePath.slice(\"sessions/\".length));\n }\n return safeJoin(root, relativePath);\n}\n\nexport function snapshotIncludesSessions(snapshot: Snapshot) {\n return (\n snapshot.syncSessions === true ||\n snapshotSelectionInclude(snapshot)?.includes(\"sessions\") === true ||\n snapshot.files.some((file) => isSessionPath(file.path))\n );\n}\n\nexport function filterSnapshotForConfigPolicy(\n snapshot: Snapshot,\n config: SyncSelectionConfig,\n options: { regenerateId?: boolean } = {},\n) {\n const include = includeFromSelectionConfig(config);\n const includePaths = customIncludePathsByLower(include);\n const filtered = {\n ...snapshot,\n syncSessions: include.includes(\"sessions\") ? snapshot.syncSessions : false,\n selection: selectionForSnapshot(include),\n files: canonicalizeSnapshotFilesForConfig(snapshot.files, config, includePaths),\n };\n if (!options.regenerateId || snapshotsMatch(snapshot, filtered)) return filtered;\n return {\n ...filtered,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n };\n}\n\nfunction canonicalizeSnapshotFilesForConfig(\n files: SnapshotFile[],\n config: SyncSelectionConfig,\n includePaths: Map<string, string>,\n) {\n const configuredFiles: SnapshotFile[] = [];\n const extraCandidates = new Map<string, { exact: boolean; file: SnapshotFile; originalPath: string }>();\n for (const file of files) {\n const normalized = toPosix(file.path);\n if (!isSafeSnapshotPath(file.path) || !isConfiguredSnapshotPath(normalized, config)) {\n continue;\n }\n if (normalized.includes(\"/\")) {\n configuredFiles.push(normalized === file.path ? file : { ...file, path: normalized });\n continue;\n }\n const topLevelPath = canonicalSnapshotPathForConfig(normalized, includePaths);\n const candidate = {\n exact: normalized === topLevelPath,\n file: { ...file, path: topLevelPath },\n originalPath: normalized,\n };\n const current = extraCandidates.get(topLevelPath.toLowerCase());\n if (!current || isPreferredExtraCandidate(candidate, current)) {\n extraCandidates.set(topLevelPath.toLowerCase(), candidate);\n }\n }\n return [...configuredFiles, ...[...extraCandidates.values()].map((candidate) => candidate.file)].sort((left, right) =>\n left.path.localeCompare(right.path),\n );\n}\n\nfunction isPreferredExtraCandidate(\n left: { exact: boolean; originalPath: string },\n right: { exact: boolean; originalPath: string },\n) {\n if (left.exact !== right.exact) return left.exact;\n return left.originalPath.localeCompare(right.originalPath) < 0;\n}\n\nexport function snapshotWithoutSessions(snapshot: Snapshot) {\n const files = snapshot.files.filter((file) => !isSessionPath(file.path));\n const include = snapshotSelectionInclude(snapshot)?.filter((item) => item !== \"sessions\");\n if (\n files.length === snapshot.files.length &&\n snapshot.syncSessions !== true &&\n include?.length === snapshot.selection?.include.length\n ) {\n return snapshot;\n }\n return {\n ...snapshot,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n syncSessions: false,\n ...(include ? { selection: selectionForSnapshot(include) } : {}),\n files,\n };\n}\n\nexport function scanSnapshot(snapshot: Snapshot) {\n const findings: string[] = [];\n for (const file of snapshot.files) {\n const content = Buffer.from(file.contentBase64, \"base64\");\n if (content.includes(0)) continue;\n const text = content.toString(\"utf8\");\n for (const pattern of SECRET_PATTERNS) {\n if (pattern.test(text)) {\n findings.push(file.path);\n break;\n }\n }\n }\n return findings;\n}\n\nexport function mergeRemotePreservedFiles(local: Snapshot, remote: Snapshot, config: SyncSelectionConfig) {\n const localPathNames = new Set(local.files.map((file) => file.path.toLowerCase()));\n const preservedPathNames = new Set<string>();\n const preserved = remote.files.filter((file) => {\n const normalized = toPosix(file.path);\n const lower = normalized.toLowerCase();\n if (\n localPathNames.has(lower) ||\n preservedPathNames.has(lower) ||\n !isSafeSnapshotPath(file.path) ||\n isConfiguredSnapshotPath(normalized, config) ||\n !isPreservableUnmanagedSnapshotPath(normalized)\n ) {\n return false;\n }\n preservedPathNames.add(lower);\n return true;\n });\n if (preserved.length === 0) return local;\n return {\n ...local,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n syncSessions: snapshotIncludesSessions(local) || snapshotIncludesSessions(remote),\n files: [...local.files, ...preserved].sort((left, right) => left.path.localeCompare(right.path)),\n };\n}\n\nexport function mergeRemoteSessionFiles(local: Snapshot, remote: Snapshot) {\n const remoteSessions = remote.files.filter((file) => {\n const normalized = toPosix(file.path);\n return isSessionFilePath(normalized) && isSafeSnapshotPath(file.path);\n });\n if (remoteSessions.length === 0 && !snapshotIncludesSessions(remote)) return local;\n const localInclude = snapshotSelectionInclude(local);\n return {\n ...local,\n id: snapshotId(),\n createdAt: new Date().toISOString(),\n machine: os.hostname(),\n syncSessions: true,\n ...(localInclude\n ? {\n selection: selectionForSnapshot(\n localInclude.includes(\"sessions\") ? localInclude : [...localInclude, \"sessions\"],\n ),\n }\n : {}),\n files: [...local.files.filter((file) => !isSessionPath(file.path)), ...remoteSessions].sort((left, right) =>\n left.path.localeCompare(right.path),\n ),\n };\n}\n\nfunction sameOptionalInclude(left: string[] | undefined, right: string[] | undefined) {\n if (!left || !right) return left === right;\n return left.length === right.length && left.every((item, index) => item === right[index]);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["configuredSessionDir"]
|
|
7
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
3
|
import {
|
|
4
4
|
errorMessage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7D5SF7P3.ts";
|
|
6
6
|
|
|
7
7
|
// src/sync/sync-error-guidance.ts
|
|
8
8
|
function syncErrorGuidance(error) {
|
|
@@ -25,9 +25,7 @@ function syncErrorGuidance(error) {
|
|
|
25
25
|
next = "Verify the connection address and setup's bucket, branch, or path with your provider; this response alone does not prove which resource is missing.";
|
|
26
26
|
} else if (status !== void 0 && status >= 500) {
|
|
27
27
|
next = "Check your storage provider's service status, then retry Check setup before syncing.";
|
|
28
|
-
} else if (/timed out|timeout|request failed|resolve host|Could not resolve|ENOTFOUND|ECONNREFUSED/iu.test(
|
|
29
|
-
message
|
|
30
|
-
)) {
|
|
28
|
+
} else if (/timed out|timeout|request failed|resolve host|Could not resolve|ENOTFOUND|ECONNREFUSED/iu.test(message)) {
|
|
31
29
|
next = "Check the server address and network connection, then run /sync doctor for the affected setup.";
|
|
32
30
|
} else if (/strong ETag|If-Match|If-None-Match|precondition|conditional header/iu.test(message)) {
|
|
33
31
|
next = "Ask your provider to check strong ETags and conditional writes, including proxy behavior, or choose compatible storage. Do not bypass these safety checks.";
|
|
@@ -47,4 +45,4 @@ ${next}`;
|
|
|
47
45
|
export {
|
|
48
46
|
syncErrorGuidance
|
|
49
47
|
};
|
|
50
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-G4RUXRWZ.ts.map
|