@narumitw/pi-sync 0.49.13 → 0.49.15
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 +98 -238
- package/dist/chunks/{chunk-LONPFFNP.ts → chunk-44LPGQTI.ts} +4 -4
- package/dist/chunks/{chunk-FR6CVXAL.ts → chunk-5LZALPCD.ts} +4 -4
- package/dist/chunks/{chunk-APZVBSM6.ts → chunk-5T442OP3.ts} +18 -6
- package/dist/chunks/chunk-5T442OP3.ts.map +7 -0
- package/dist/chunks/{chunk-5WJNWFTG.ts → chunk-ARN2672F.ts} +5 -5
- package/dist/chunks/{chunk-W64NEHXT.ts → chunk-C7LXZ3UH.ts} +3 -3
- package/dist/chunks/{chunk-4F3W4CSC.ts → chunk-DFXBKHGN.ts} +3 -2
- package/dist/chunks/chunk-DFXBKHGN.ts.map +7 -0
- package/dist/chunks/{chunk-JNOOSPEW.ts → chunk-E4COSV32.ts} +3 -3
- package/dist/chunks/{chunk-BHJUISB4.ts → chunk-GLQLN5GV.ts} +3 -3
- package/dist/chunks/{chunk-EWX3TPLQ.ts → chunk-HVUSHMVL.ts} +2 -2
- package/dist/chunks/{chunk-RGJ6SOYR.ts → chunk-JF6MZCT4.ts} +2 -2
- package/dist/chunks/{chunk-LJDSHNS3.ts → chunk-WSOBYHIZ.ts} +2 -2
- package/dist/chunks/{chunk-3NDD5QPM.ts → chunk-X7SQ2EQM.ts} +4 -4
- package/dist/chunks/{file-selection-4UABOP44.ts → file-selection-RKEHALNQ.ts} +3 -3
- package/dist/chunks/manager-result-dispatcher-LWPYJAD5.ts +18 -0
- package/dist/chunks/{manager-ui-QO2P4V3Z.ts → manager-ui-NF4RUHBY.ts} +42 -14
- package/dist/chunks/manager-ui-NF4RUHBY.ts.map +7 -0
- package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts → remote-selection-ui-NUF5P4ZJ.ts} +8 -8
- package/dist/chunks/{s3-backend-3QZGO2EF.ts → s3-backend-552LXHE4.ts} +2 -2
- package/dist/chunks/{setup-switch-X3W3FALZ.ts → setup-switch-5YDG5YGJ.ts} +6 -6
- package/dist/chunks/{snapshot-WBSV4MQG.ts → snapshot-2RYBUDRA.ts} +3 -3
- package/dist/chunks/{sync-operations-MPAFVVHA.ts → sync-operations-3LLIHWZO.ts} +15 -13
- package/dist/chunks/sync-operations-3LLIHWZO.ts.map +7 -0
- package/dist/chunks/{sync-state-36H7ULG2.ts → sync-state-SRN6YRBK.ts} +4 -4
- package/dist/index.ts +15 -15
- package/docs/settings.md +187 -0
- package/package.json +7 -9
- package/src/config.ts +16 -3
- package/src/settings-management.ts +1 -0
- package/src/settings-ui.ts +29 -2
- package/src/sync-operations.ts +7 -5
- package/src/types.ts +2 -0
- package/dist/chunks/chunk-4F3W4CSC.ts.map +0 -7
- package/dist/chunks/chunk-APZVBSM6.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-RNRQA3PW.ts +0 -18
- package/dist/chunks/manager-ui-QO2P4V3Z.ts.map +0 -7
- package/dist/chunks/sync-operations-MPAFVVHA.ts.map +0 -7
- /package/dist/chunks/{chunk-LONPFFNP.ts.map → chunk-44LPGQTI.ts.map} +0 -0
- /package/dist/chunks/{chunk-FR6CVXAL.ts.map → chunk-5LZALPCD.ts.map} +0 -0
- /package/dist/chunks/{chunk-5WJNWFTG.ts.map → chunk-ARN2672F.ts.map} +0 -0
- /package/dist/chunks/{chunk-W64NEHXT.ts.map → chunk-C7LXZ3UH.ts.map} +0 -0
- /package/dist/chunks/{chunk-JNOOSPEW.ts.map → chunk-E4COSV32.ts.map} +0 -0
- /package/dist/chunks/{chunk-BHJUISB4.ts.map → chunk-GLQLN5GV.ts.map} +0 -0
- /package/dist/chunks/{chunk-EWX3TPLQ.ts.map → chunk-HVUSHMVL.ts.map} +0 -0
- /package/dist/chunks/{chunk-RGJ6SOYR.ts.map → chunk-JF6MZCT4.ts.map} +0 -0
- /package/dist/chunks/{chunk-LJDSHNS3.ts.map → chunk-WSOBYHIZ.ts.map} +0 -0
- /package/dist/chunks/{chunk-3NDD5QPM.ts.map → chunk-X7SQ2EQM.ts.map} +0 -0
- /package/dist/chunks/{file-selection-4UABOP44.ts.map → file-selection-RKEHALNQ.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-RNRQA3PW.ts.map → manager-result-dispatcher-LWPYJAD5.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-LHSAGKGA.ts.map → remote-selection-ui-NUF5P4ZJ.ts.map} +0 -0
- /package/dist/chunks/{s3-backend-3QZGO2EF.ts.map → s3-backend-552LXHE4.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-X3W3FALZ.ts.map → setup-switch-5YDG5YGJ.ts.map} +0 -0
- /package/dist/chunks/{snapshot-WBSV4MQG.ts.map → snapshot-2RYBUDRA.ts.map} +0 -0
- /package/dist/chunks/{sync-state-36H7ULG2.ts.map → sync-state-SRN6YRBK.ts.map} +0 -0
|
@@ -5,17 +5,17 @@ import {
|
|
|
5
5
|
formatRemoteSelectionStatus,
|
|
6
6
|
readSnapshotForHead,
|
|
7
7
|
requireCompatibleRemoteSelection
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5LZALPCD.ts";
|
|
9
9
|
import {
|
|
10
10
|
applySnapshotTransaction,
|
|
11
11
|
recoverPendingSnapshotTransactions
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-X7SQ2EQM.ts";
|
|
13
13
|
import {
|
|
14
14
|
inspectLock,
|
|
15
15
|
isLockGuardHeld,
|
|
16
16
|
isStaleLock,
|
|
17
17
|
withLock
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-WSOBYHIZ.ts";
|
|
19
19
|
import {
|
|
20
20
|
SyncDecisionRequiredError,
|
|
21
21
|
countPreservedRemoteFiles,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
formatSnapshotOnlyDiff,
|
|
28
28
|
publicationCapabilityDescription,
|
|
29
29
|
safeTerminalText
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-C7LXZ3UH.ts";
|
|
31
31
|
import {
|
|
32
32
|
canPullRemoteSessionsOnFirstSync,
|
|
33
33
|
canPullRemoteSettingsOnFirstSync,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
snapshotHashesMatchState,
|
|
41
41
|
snapshotsMatch,
|
|
42
42
|
syncPolicyChanged
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-JF6MZCT4.ts";
|
|
44
44
|
import {
|
|
45
45
|
createSnapshot,
|
|
46
46
|
filterSnapshotForConfigPolicy,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
snapshotIncludesSessions,
|
|
55
55
|
snapshotTarget,
|
|
56
56
|
snapshotWithoutSessions
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-HVUSHMVL.ts";
|
|
58
58
|
import {
|
|
59
59
|
agentDir,
|
|
60
60
|
loadConfig,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
syncConfigReviewIdentity,
|
|
65
65
|
syncSessionsWarnings,
|
|
66
66
|
writeStateForConfig
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-5T442OP3.ts";
|
|
68
68
|
import {
|
|
69
69
|
encodeSnapshot
|
|
70
70
|
} from "./chunk-HGV24P4T.ts";
|
|
@@ -586,12 +586,14 @@ async function push(ctx, options, input, factory = createSyncBackend) {
|
|
|
586
586
|
remoteForUpload,
|
|
587
587
|
options.signal
|
|
588
588
|
);
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
589
|
+
if (!config.skipSecretScan) {
|
|
590
|
+
const secrets = scanSnapshot(local);
|
|
591
|
+
if (secrets.length > 0) {
|
|
592
|
+
throw new Error(
|
|
593
|
+
`Refusing to push possible secrets:
|
|
593
594
|
${secrets.map((s) => `- ${s}`).join("\n")}`
|
|
594
|
-
|
|
595
|
+
);
|
|
596
|
+
}
|
|
595
597
|
}
|
|
596
598
|
if (!await confirmPush(ctx, options, config, backend, local, upload, head, remoteForUpload)) {
|
|
597
599
|
return "cancelled";
|
|
@@ -1109,4 +1111,4 @@ export {
|
|
|
1109
1111
|
status,
|
|
1110
1112
|
syncBoth
|
|
1111
1113
|
};
|
|
1112
|
-
//# sourceMappingURL=sync-operations-
|
|
1114
|
+
//# sourceMappingURL=sync-operations-3LLIHWZO.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync-operations.ts", "../../src/snapshot-apply.ts", "../../src/sync-decision.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { createSyncBackend, type SyncBackendFactory } from \"./backend-factory.js\";\nimport {\n\tloadConfig,\n\treadStateForConfig,\n\tsessionDirForApply,\n\tstateDir,\n\tsyncConfigReviewFingerprint,\n\tsyncSessionsWarnings,\n\twriteStateForConfig,\n} from \"./config.js\";\nimport { inspectLock, isLockGuardHeld, isStaleLock, withLock } from \"./lock.js\";\nimport {\n\tformatRemoteSelectionStatus,\n\treadSnapshotForHead,\n\trequireCompatibleRemoteSelection,\n} from \"./remote-snapshot.js\";\nimport {\n\tcreateSnapshot,\n\tfilterSnapshotForConfigPolicy,\n\tmergeRemotePreservedFiles,\n\tregenerateSnapshotIdentity,\n\tscanSnapshot,\n\tsessionSnapshotPathFromAbsolute,\n\tsnapshotIncludesSessions,\n\tsnapshotWithoutSessions,\n} from \"./snapshot.js\";\nimport { applySnapshot } from \"./snapshot-apply.js\";\nimport { encodeSnapshot } from \"./snapshot-codec.js\";\nimport {\n\texpectedRemoteHead,\n\ttype PublishSnapshotResult,\n\ttype RemoteHead,\n\ttype SyncBackend,\n} from \"./sync-backend.js\";\nimport { createSyncDecision } from \"./sync-decision.js\";\nimport {\n\tcountPreservedRemoteFiles,\n\terrorMessage,\n\tformatDiff,\n\tformatPullSummary,\n\tformatPushSummary,\n\tformatRollbackSummary,\n\tformatSnapshotOnlyDiff,\n\tpublicationCapabilityDescription,\n\tsafeTerminalText,\n} from \"./sync-format.js\";\nimport { inspectRemoteSelection, remoteSelectionMismatch } from \"./sync-policy.js\";\nimport {\n\tcanPullRemoteSessionsOnFirstSync,\n\tcanPullRemoteSettingsOnFirstSync,\n\tfileHashMap,\n\thasLocalChanges,\n\thasRemoteChanges,\n\tremoteChangedSinceState,\n\tsameHashes,\n\tshouldRefreshSyncedState,\n\tsnapshotHashesMatchState,\n\tsnapshotsMatch,\n\tsyncPolicyChanged,\n} from \"./sync-state.js\";\nimport type {\n\tAnySyncConfig,\n\tCommandOptions,\n\tSnapshot,\n\tSnapshotOptions,\n\tSyncState,\n} from \"./types.js\";\n\nconst STATUS_KEY = \"sync\";\nconst VERSION = 1;\nconst DEFAULT_PROFILE = \"default\";\nconst POST_LOCAL_COMMIT_TIMEOUT_MS = 30_000;\n\nexport class PublicationStatePersistenceError extends Error {\n\treadonly head: RemoteHead;\n\treadonly backupPath?: string;\n\n\tconstructor(head: RemoteHead, cause: unknown, backupPath?: string) {\n\t\tsuper(\n\t\t\t`Remote publication ${head.snapshotId} is active, but local sync state could not be saved${backupPath ? `; local backup: ${backupPath}` : \"\"}: ${errorMessage(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = \"PublicationStatePersistenceError\";\n\t\tthis.head = head;\n\t\tthis.backupPath = backupPath;\n\t}\n}\n\nexport class RollbackPublicationError extends Error {\n\treadonly backupPath: string;\n\n\tconstructor(backupPath: string, cause: unknown) {\n\t\tsuper(\n\t\t\t`Rollback applied locally with backup ${backupPath}, but remote publication failed: ${errorMessage(cause)}`,\n\t\t\t{ cause },\n\t\t);\n\t\tthis.name = \"RollbackPublicationError\";\n\t\tthis.backupPath = backupPath;\n\t}\n}\n\ninterface PushInput {\n\tconfig: AnySyncConfig;\n\tstate: SyncState;\n\tlocal: Snapshot;\n\tbackend?: SyncBackend;\n}\n\nfunction backendFor(config: AnySyncConfig, factory: SyncBackendFactory) {\n\treturn factory(config);\n}\n\nexport async function status(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst head = await backend.readHead(options.signal);\n\tthrowIfAborted(options.signal);\n\tconst selectionState = head\n\t\t? inspectRemoteSelection(config.include, { selection: head.selection, files: [] })\n\t\t: undefined;\n\tconst localChanged = hasLocalChanges(local, state, config);\n\n\tconst remoteText = head\n\t\t? `remote: ${head.snapshotId} from ${head.machine} at ${head.createdAt}`\n\t\t: \"remote: empty\";\n\tconst remoteChanged = remoteChangedSinceState(head, state, config, (left, right) =>\n\t\tbackend.sameRevision(left, right),\n\t);\n\tconst warnings = syncSessionsWarnings(config);\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.notify(\n\t\t[\n\t\t\t`sync setup: ${config.setupName}`,\n\t\t\t`storage connection: ${config.connectionName}`,\n\t\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t\t`publication safety: ${publicationCapabilityDescription(backend.capability)}`,\n\t\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\t\tremoteText,\n\t\t\tformatRemoteSelectionStatus(selectionState),\n\t\t\t`local files: ${local.files.length}`,\n\t\t\t`local changed since last sync: ${localChanged ? \"yes\" : \"no\"}`,\n\t\t\t`remote changed since last sync: ${remoteChanged ? \"yes\" : \"no\"}`,\n\t\t\t...warnings,\n\t\t].join(\"\\n\"),\n\t\tlocalChanged || remoteChanged || selectionState?.kind === \"different\" || warnings.length > 0\n\t\t\t? \"warning\"\n\t\t\t: \"info\",\n\t);\n}\n\nexport async function diff(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `checking ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst { snapshot: remote, selectionState } = await readRemoteSnapshot(\n\t\tbackend,\n\t\tconfig,\n\t\toptions.signal,\n\t\t{ allowSelectionDifference: true },\n\t);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\n\tconst warnings = syncSessionsWarnings(config);\n\tconst header = [\n\t\t`sync setup: ${config.setupName}`,\n\t\t`storage connection: ${config.connectionName}`,\n\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\tformatRemoteSelectionStatus(selectionState),\n\t\t...warnings,\n\t].join(\"\\n\");\n\tconst level = warnings.length > 0 || selectionState?.kind === \"different\" ? \"warning\" : \"info\";\n\tif (!remote) {\n\t\tctx.ui.notify(\n\t\t\t`${header}\\n\\n${formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local)}`,\n\t\t\tlevel,\n\t\t);\n\t\treturn;\n\t}\n\n\tctx.ui.notify(`${header}\\n\\n${formatDiff(local, remote)}`, level);\n}\n\nexport async function doctor(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst messages: string[] = [];\n\tlet level: \"info\" | \"warning\" = \"info\";\n\tlet snapshotOptions: SnapshotOptions = {};\n\tlet profile = DEFAULT_PROFILE;\n\tlet backend: SyncBackend | undefined;\n\tlet backendSummary: string[] = [];\n\n\ttry {\n\t\tconst config = await loadConfig(options.setup);\n\t\tthrowIfAborted(options.signal);\n\t\tbackend = await backendFor(config, factory);\n\t\tprofile = config.snapshotIdentity;\n\t\tsnapshotOptions = snapshotOptionsForContext(ctx, config);\n\t\tmessages.push(\n\t\t\t`config: ok (sync setup ${config.setupName})`,\n\t\t\t`included content: ${config.include.join(\", \") || \"none\"}`,\n\t\t\t`sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"excluded\"}`,\n\t\t);\n\t\tbackendSummary = [\n\t\t\t`storage location: ${safeTerminalText(backend.destination)}`,\n\t\t\t`publication safety: ${publicationCapabilityDescription(backend.capability)}`,\n\t\t];\n\t\tconst warnings = syncSessionsWarnings(config);\n\t\tif (warnings.length > 0) {\n\t\t\tlevel = \"warning\";\n\t\t\tmessages.push(...warnings);\n\t\t}\n\t} catch (error) {\n\t\tthrowIfAborted(options.signal);\n\t\tlevel = \"warning\";\n\t\tmessages.push(`config: ${errorMessage(error)}`);\n\t}\n\n\tconst local = await createSnapshot(profile, snapshotOptions);\n\tthrowIfAborted(options.signal);\n\tconst secrets = scanSnapshot(local);\n\tif (secrets.length > 0) {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\"secret scan: possible secrets found:\");\n\t\tmessages.push(...secrets.map((secret) => `- ${secret}`));\n\t} else {\n\t\tmessages.push(`secret scan: ok (${local.files.length} files checked)`);\n\t}\n\n\tconst lock = await inspectLock();\n\tthrowIfAborted(options.signal);\n\tif (lock.status === \"valid\" && isStaleLock(lock.lock)) {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\n\t\t\t`lock: stale (pid ${lock.lock.pid}); run /sync unlock after verifying no sync is running`,\n\t\t);\n\t} else if (lock.status === \"valid\") {\n\t\tmessages.push(`lock: held by pid ${lock.lock.pid} since ${lock.lock.startedAt}`);\n\t} else if (lock.status === \"unreadable\") {\n\t\tlevel = \"warning\";\n\t\tmessages.push(\n\t\t\t\"lock: unreadable; use /sync unlock --stale only after verifying no sync is running\",\n\t\t);\n\t} else if (await isLockGuardHeld()) {\n\t\tthrowIfAborted(options.signal);\n\t\tlevel = \"warning\";\n\t\tmessages.push(\"lock: guard active while metadata is missing or still being initialized\");\n\t} else {\n\t\tmessages.push(\"lock: free\");\n\t}\n\n\tif (backend) {\n\t\tmessages.push(...backendSummary);\n\t\tconst diagnostics = await backend.diagnose(options.signal);\n\t\tthrowIfAborted(options.signal);\n\t\tfor (const diagnostic of diagnostics) {\n\t\t\tmessages.push(diagnostic.message);\n\t\t\tif (diagnostic.level !== \"info\") level = \"warning\";\n\t\t}\n\t}\n\tctx.ui.notify(messages.join(\"\\n\"), level);\n}\n\nexport async function push(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tinput?: PushInput,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = input?.config ?? (await loadConfig(options.setup));\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `pushing ${config.setupName}`);\n\tconst backend = input?.backend ?? (await backendFor(config, factory));\n\tconst state = input?.state ?? (await readStateForConfig(config));\n\tthrowIfAborted(options.signal);\n\tconst local =\n\t\tinput?.local ??\n\t\t(await createSnapshot(config.snapshotIdentity, snapshotOptionsForContext(ctx, config)));\n\tthrowIfAborted(options.signal);\n\n\tlet head = await backend.readHead(options.signal);\n\tlet remoteForUpload = await readRemoteSnapshotForUpload(\n\t\tbackend,\n\t\tconfig,\n\t\thead,\n\t\tstate,\n\t\toptions.signal,\n\t);\n\tif (\n\t\t!options.force &&\n\t\t!remoteForUpload &&\n\t\thead?.selection &&\n\t\tinspectRemoteSelection(config.include, { selection: head.selection, files: [] }).kind ===\n\t\t\t\"different\"\n\t) {\n\t\tremoteForUpload = await readSnapshotForHead(backend, head, options.signal);\n\t}\n\tif (remoteForUpload && !options.force) {\n\t\trequireCompatibleRemoteSelection(config, remoteForUpload);\n\t}\n\tif (\n\t\tremoteChangedSinceState(head, state, config, (left, right) =>\n\t\t\tbackend.sameRevision(left, right),\n\t\t) &&\n\t\t!options.force\n\t) {\n\t\tconst remoteForConflict = remoteForUpload\n\t\t\t? filterSnapshotForConfigPolicy(remoteForUpload, config)\n\t\t\t: undefined;\n\t\tif (!remoteForConflict || !snapshotHashesMatchState(remoteForConflict, state, config)) {\n\t\t\tthrow createSyncDecision({\n\t\t\t\tkind: head ? \"remote-or-policy-changed\" : \"remote-empty\",\n\t\t\t\tconfig,\n\t\t\t\tstate,\n\t\t\t\tlocal,\n\t\t\t\tremote: remoteForConflict,\n\t\t\t\tlocalChanged: hasLocalChanges(local, state, config),\n\t\t\t\tremoteChanged: true,\n\t\t\t\tdirectMessage:\n\t\t\t\t\t\"Remote or sync policy changed since last sync. Run /sync pull first or /sync push --force.\",\n\t\t\t});\n\t\t}\n\t}\n\n\tlet upload = await snapshotForUpload(\n\t\tbackend,\n\t\tconfig,\n\t\tlocal,\n\t\thead,\n\t\tremoteForUpload,\n\t\toptions.signal,\n\t);\n\tif (!config.skipSecretScan) {\n\t\tconst secrets = scanSnapshot(local);\n\t\tif (secrets.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Refusing to push possible secrets:\\n${secrets.map((s) => `- ${s}`).join(\"\\n\")}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (!(await confirmPush(ctx, options, config, backend, local, upload, head, remoteForUpload))) {\n\t\treturn \"cancelled\" as const;\n\t}\n\n\tif (options.force) {\n\t\tconst refreshedHead = await backend.readHead(options.signal);\n\t\tif (!sameRemoteHead(backend, head, refreshedHead)) {\n\t\t\thead = refreshedHead;\n\t\t\tremoteForUpload = head\n\t\t\t\t? await backend.readSnapshot(head.snapshotRef, options.signal)\n\t\t\t\t: undefined;\n\t\t\tupload = await snapshotForUpload(\n\t\t\t\tbackend,\n\t\t\t\tconfig,\n\t\t\t\tlocal,\n\t\t\t\thead,\n\t\t\t\tremoteForUpload,\n\t\t\t\toptions.signal,\n\t\t\t);\n\t\t\tif (\n\t\t\t\t!(await confirmPush(\n\t\t\t\t\tctx,\n\t\t\t\t\toptions,\n\t\t\t\t\tconfig,\n\t\t\t\t\tbackend,\n\t\t\t\t\tlocal,\n\t\t\t\t\tupload,\n\t\t\t\t\thead,\n\t\t\t\t\tremoteForUpload,\n\t\t\t\t\t\"Remote changed during review. Push the refreshed plan?\",\n\t\t\t\t))\n\t\t\t) {\n\t\t\t\treturn \"cancelled\" as const;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result = await backend.publishSnapshot(upload, expectedRemoteHead(head), {\n\t\tsignal: options.signal,\n\t\tonCommit: options.onCommit,\n\t});\n\ttry {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: result.head.snapshotId,\n\t\t\tlastRemoteRevision: result.head.revision,\n\t\t\tlastFileHashes: fileHashMap(local),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t} catch (error) {\n\t\tthrow new PublicationStatePersistenceError(result.head, error);\n\t}\n\tif (options.signal?.aborted) return;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tif (!options.silent) {\n\t\tctx.ui.notify(\n\t\t\t[\n\t\t\t\t`Pushed ${upload.files.length} files from sync setup \u201C${config.setupName}\u201D as ${result.head.snapshotId}.`,\n\t\t\t\t...result.warnings,\n\t\t\t]\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\"\\n\"),\n\t\t\tresult.warnings.length > 0 ? \"warning\" : \"info\",\n\t\t);\n\t}\n\treturn \"applied\" as const;\n}\n\nexport async function pull(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tctx.ui.setStatus(STATUS_KEY, `pulling ${config.setupName}`);\n\tconst backend = await backendFor(config, factory);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tconst { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n\tthrowIfAborted(options.signal);\n\tconst localChanged = hasLocalChanges(local, state, config);\n\tif (!remote) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"remote-empty\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged: false,\n\t\t\tdirectMessage: \"Remote is empty. Run /sync push from a configured machine first.\",\n\t\t});\n\t}\n\n\tconst remoteChanged = hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx));\n\tif (localChanged && remoteChanged && state.lastAppliedSnapshot && !options.force) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"both-changed\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tremote,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged,\n\t\t\tdirectMessage:\n\t\t\t\t\"Both local and remote changed since last sync. Run /sync diff, then choose /sync pull --force or /sync push --force.\",\n\t\t});\n\t}\n\n\tif (\n\t\t!options.yes &&\n\t\t!(await ctx.ui.confirm(\n\t\t\tsnapshotIncludesSessions(remote) ? \"Pull pi settings and sessions?\" : \"Pull pi settings?\",\n\t\t\tformatPullSummary(\n\t\t\t\tconfig,\n\t\t\t\tbackend.destination,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\tprotectedSessionPaths(ctx).size,\n\t\t\t),\n\t\t))\n\t) {\n\t\tctx.ui.setStatus(STATUS_KEY, undefined);\n\t\tctx.ui.notify(\"Pull cancelled.\", \"info\");\n\t\treturn \"cancelled\" as const;\n\t}\n\n\tthrowIfAborted(options.signal);\n\tconst backup = await backupLocal(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t\toptions.signal,\n\t);\n\tconst applySessionDir = await sessionDirForApply(ctx, remote);\n\tthrowIfAborted(options.signal);\n\toptions.onCommit?.();\n\tconst lastFileHashes = await applySnapshot(remote, protectedSessionPaths(ctx), {\n\t\tinclude: config.include,\n\t\tsessionDir: applySessionDir,\n\t});\n\tawait writeStateForConfig(config, {\n\t\tversion: VERSION,\n\t\tprofile: config.snapshotIdentity,\n\t\tlastAppliedSnapshot: remote.id,\n\t\tlastRemoteRevision: head?.revision,\n\t\tlastFileHashes,\n\t\tinclude: [...config.include],\n\t});\n\tif (options.signal?.aborted) return \"applied\" as const;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tif (!options.silent) {\n\t\tctx.ui.notify(\n\t\t\t`Pulled ${remote.files.length} files from ${remote.id}. Backup: ${backup}`,\n\t\t\t\"info\",\n\t\t);\n\t} else if (\n\t\toptions.auto &&\n\t\tconfig.include.includes(\"sessions\") &&\n\t\tsnapshotIncludesSessions(remote)\n\t) {\n\t\tctx.ui.notify(\n\t\t\t\"Pulled Pi sessions after startup selected the current session. Restart Pi or resume a pulled session to use newly synced conversations.\",\n\t\t\t\"warning\",\n\t\t);\n\t}\n\tif (options.reload) await maybeReload(ctx, options.signal);\n\treturn \"applied\" as const;\n}\n\nexport async function syncBoth(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tconst state = await readStateForConfig(config);\n\tthrowIfAborted(options.signal);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tthrowIfAborted(options.signal);\n\tif (config.include.length === 0) {\n\t\tif (!options.silent) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Sync setup \u201C${config.setupName}\u201D includes no files. Choose included content in /sync Settings before syncing.`,\n\t\t\t\t\"warning\",\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\tconst { head, snapshot: remote } = await readRemoteSnapshot(backend, config, options.signal);\n\tthrowIfAborted(options.signal);\n\tconst localChanged = hasLocalChanges(local, state, config);\n\tconst remoteChanged = remote\n\t\t? hasRemoteChanges(remote, state, config, protectedSessionPaths(ctx))\n\t\t: false;\n\tconst firstSync = !state.lastAppliedSnapshot;\n\n\tif (firstSync && remote && remote.files.length > 0 && local.files.length > 0) {\n\t\tif (!canPullRemoteSettingsOnFirstSync(local, remote)) {\n\t\t\tthrow createSyncDecision({\n\t\t\t\tkind: \"first-sync-settings-diverged\",\n\t\t\t\tconfig,\n\t\t\t\tstate,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\tlocalChanged: true,\n\t\t\t\tremoteChanged: true,\n\t\t\t\tdirectMessage:\n\t\t\t\t\t\"Remote settings exist and this machine has different local Pi settings. Run /sync diff, then manually choose /sync pull or /sync push.\",\n\t\t\t});\n\t\t}\n\t\tif (!sameHashes(fileHashMap(local), fileHashMap(remote))) {\n\t\t\tif (!canPullRemoteSessionsOnFirstSync(local, remote)) {\n\t\t\t\tthrow createSyncDecision({\n\t\t\t\t\tkind: \"first-sync-sessions-diverged\",\n\t\t\t\t\tconfig,\n\t\t\t\t\tstate,\n\t\t\t\t\tlocal,\n\t\t\t\t\tremote,\n\t\t\t\t\tlocalChanged: true,\n\t\t\t\t\tremoteChanged: true,\n\t\t\t\t\tdirectMessage:\n\t\t\t\t\t\t\"Remote settings match, but local and remote Pi sessions differ. Run /sync diff, then manually choose /sync pull or /sync push.\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait pull(ctx, options, factory);\n\t\t\treturn;\n\t\t}\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t\tif (!options.silent)\n\t\t\tctx.ui.notify(\"pi-sync state initialized; local settings already match remote.\", \"info\");\n\t\treturn;\n\t}\n\tif (localChanged && remoteChanged && remote && snapshotsMatch(local, remote)) {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t\tif (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n\t\treturn;\n\t}\n\tif (localChanged && remoteChanged && state.lastAppliedSnapshot) {\n\t\tthrow createSyncDecision({\n\t\t\tkind: \"both-changed\",\n\t\t\tconfig,\n\t\t\tstate,\n\t\t\tlocal,\n\t\t\tremote,\n\t\t\tlocalChanged,\n\t\t\tremoteChanged,\n\t\t\tdirectMessage:\n\t\t\t\t\"Both local and remote changed. Run /sync diff and resolve with push --force or pull --force.\",\n\t\t});\n\t}\n\tif (remoteChanged) {\n\t\tawait pull(ctx, options, factory);\n\t\treturn;\n\t}\n\tif (localChanged || !remote) {\n\t\tawait push(ctx, options, undefined, factory);\n\t\treturn;\n\t}\n\tif (\n\t\tshouldRefreshSyncedState(remote, head, state, config, (left, right) =>\n\t\t\tbackend.sameRevision(left, right),\n\t\t)\n\t) {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: remote.id,\n\t\t\tlastRemoteRevision: head?.revision,\n\t\t\tlastFileHashes: fileHashMap(remote),\n\t\t\tinclude: [...config.include],\n\t\t});\n\t}\n\tif (!options.silent) ctx.ui.notify(\"pi-sync is already up to date.\", \"info\");\n}\n\nexport async function history(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n) {\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tconst snapshots = (await backend.listHistory(options.signal)).slice(-20).reverse();\n\tthrowIfAborted(options.signal);\n\tif (snapshots.length === 0) {\n\t\tctx.ui.notify(\"No remote pi-sync history found.\", \"info\");\n\t\treturn;\n\t}\n\n\tconst currentSnapshot = snapshots[0]?.snapshotId;\n\tif (ctx.mode === \"tui\") {\n\t\tconst labels = snapshots.map(\n\t\t\t(item, index) =>\n\t\t\t\t`${index + 1}. ${item.createdAt} \u00B7 ${safeTerminalText(item.machine)} \u00B7 ${item.snapshotId}${item.snapshotId === currentSnapshot ? \" (current)\" : \"\"}${item.syncSessions ? \" \u00B7 sessions\" : \"\"}`,\n\t\t);\n\t\tconst selected = await ctx.ui.select(\n\t\t\t`History for sync setup \u201C${safeTerminalText(config.setupName)}\u201D\\n\\nChoose a snapshot to preview rollback.`,\n\t\t\t[...labels, \"Back\"],\n\t\t);\n\t\tif (!selected || selected === \"Back\") return;\n\t\tthrowIfAborted(options.signal);\n\t\tconst index = labels.indexOf(selected);\n\t\tconst snapshot = snapshots[index];\n\t\tif (!snapshot) return;\n\t\tawait withLock(\"rollback\", () =>\n\t\t\trollback(ctx, { ...options, args: [snapshot.snapshotRef], yes: false }, factory, {\n\t\t\t\tbackendIdentity: backend.identity,\n\t\t\t\tsetup: config.setupName,\n\t\t\t}),\n\t\t);\n\t\treturn;\n\t}\n\tctx.ui.notify(\n\t\tsnapshots\n\t\t\t.map((item) => `${item.snapshotRef} ${item.createdAt} ${safeTerminalText(item.machine)}`)\n\t\t\t.join(\"\\n\"),\n\t\t\"info\",\n\t);\n}\n\nexport async function rollback(\n\tctx: ExtensionCommandContext,\n\toptions: CommandOptions,\n\tfactory: SyncBackendFactory = createSyncBackend,\n\texpectedSelection?: { backendIdentity: string; setup?: string },\n) {\n\tconst target = options.args[0];\n\tif (!target) throw new Error(\"Usage: /sync rollback <snapshot-id> [--yes]\");\n\n\tconst config = await loadConfig(options.setup);\n\tthrowIfAborted(options.signal);\n\tconst backend = await backendFor(config, factory);\n\tif (\n\t\texpectedSelection &&\n\t\t(backend.identity !== expectedSelection.backendIdentity ||\n\t\t\tconfig.setupName !== expectedSelection.setup)\n\t) {\n\t\tthrow new Error(\n\t\t\t\"Sync setup or storage location changed while history was open; reopen history and retry.\",\n\t\t);\n\t}\n\tconst decoded = await backend.readSnapshot(target, options.signal);\n\tconst selected = filterSnapshotForConfigPolicy(\n\t\tconfig.include.includes(\"sessions\") ? decoded : snapshotWithoutSessions(decoded),\n\t\tconfig,\n\t);\n\tconst remote = regenerateSnapshotIdentity(selected);\n\tconst local = await createSnapshot(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t);\n\tconst expectedHead = await backend.readHead(options.signal);\n\tthrowIfAborted(options.signal);\n\n\tif (\n\t\t!options.yes &&\n\t\t!(await ctx.ui.confirm(\n\t\t\tsnapshotIncludesSessions(remote)\n\t\t\t\t? \"Rollback pi settings and sessions?\"\n\t\t\t\t: \"Rollback pi settings?\",\n\t\t\tformatRollbackSummary(\n\t\t\t\tconfig,\n\t\t\t\tbackend.destination,\n\t\t\t\tlocal,\n\t\t\t\tremote,\n\t\t\t\ttarget,\n\t\t\t\tprotectedSessionPaths(ctx).size,\n\t\t\t),\n\t\t))\n\t) {\n\t\tctx.ui.notify(\"Rollback cancelled.\", \"info\");\n\t\treturn;\n\t}\n\n\tthrowIfAborted(options.signal);\n\tconst backup = await backupLocal(\n\t\tconfig.snapshotIdentity,\n\t\tsnapshotOptionsForContext(ctx, config),\n\t\toptions.signal,\n\t);\n\tconst applySessionDir = await sessionDirForApply(ctx, remote);\n\tthrowIfAborted(options.signal);\n\toptions.onCommit?.();\n\tconst lastFileHashes = await applySnapshot(remote, protectedSessionPaths(ctx), {\n\t\tinclude: config.include,\n\t\tsessionDir: applySessionDir,\n\t});\n\tlet result: PublishSnapshotResult;\n\ttry {\n\t\tconst completionSignal = AbortSignal.timeout(POST_LOCAL_COMMIT_TIMEOUT_MS);\n\t\tconst upload = await snapshotForUpload(\n\t\t\tbackend,\n\t\t\tconfig,\n\t\t\tremote,\n\t\t\texpectedHead,\n\t\t\tundefined,\n\t\t\tcompletionSignal,\n\t\t\t{ ignoreUnreadableRemote: true },\n\t\t);\n\t\tresult = await backend.publishSnapshot(upload, expectedRemoteHead(expectedHead), {\n\t\t\tsignal: completionSignal,\n\t\t});\n\t} catch (error) {\n\t\tthrow new RollbackPublicationError(backup, error);\n\t}\n\ttry {\n\t\tawait writeStateForConfig(config, {\n\t\t\tversion: VERSION,\n\t\t\tprofile: config.snapshotIdentity,\n\t\t\tlastAppliedSnapshot: result.head.snapshotId,\n\t\t\tlastRemoteRevision: result.head.revision,\n\t\t\tlastFileHashes,\n\t\t\tinclude: [...config.include],\n\t\t});\n\t} catch (error) {\n\t\tthrow new PublicationStatePersistenceError(result.head, error, backup);\n\t}\n\tif (options.signal?.aborted) return;\n\tctx.ui.notify(\n\t\t[\n\t\t\t`Rolled back sync setup \u201C${config.setupName}\u201D to ${target}; latest: ${result.head.snapshotId}. Backup: ${backup}`,\n\t\t\t...result.warnings,\n\t\t]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\"\\n\"),\n\t\tresult.warnings.length > 0 ? \"warning\" : \"info\",\n\t);\n\tawait maybeReload(ctx, options.signal);\n}\n\nfunction protectedSessionPaths(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst getSessionFile = ctx.sessionManager.getSessionFile;\n\tif (typeof getSessionFile !== \"function\") return new Set<string>();\n\tconst sessionFile = getSessionFile.call(ctx.sessionManager) as string | undefined;\n\tconst snapshotPath = sessionFile\n\t\t? sessionSnapshotPathFromAbsolute(sessionFile, sessionDirFromContext(ctx))\n\t\t: undefined;\n\treturn snapshotPath ? new Set([snapshotPath]) : new Set<string>();\n}\n\nfunction snapshotOptionsForContext(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\tconfig: AnySyncConfig,\n): SnapshotOptions {\n\treturn {\n\t\tinclude: config.include,\n\t\tsessionDir: sessionDirFromContext(ctx),\n\t};\n}\n\nfunction sessionDirFromContext(ctx: ExtensionCommandContext | ExtensionContext) {\n\tconst manager = ctx.sessionManager as typeof ctx.sessionManager & {\n\t\tusesDefaultSessionDir?: () => boolean;\n\t};\n\tconst usesDefaultSessionDir = manager.usesDefaultSessionDir;\n\tif (typeof usesDefaultSessionDir === \"function\" && usesDefaultSessionDir.call(manager)) {\n\t\treturn undefined;\n\t}\n\tconst getSessionDir = manager.getSessionDir;\n\treturn typeof getSessionDir === \"function\"\n\t\t? (getSessionDir.call(manager) as string | undefined)\n\t\t: undefined;\n}\n\nasync function maybeReload(ctx: ExtensionCommandContext | ExtensionContext, signal?: AbortSignal) {\n\tif (signal?.aborted || !(\"reload\" in ctx)) return;\n\tif (\n\t\tctx.hasUI &&\n\t\t(await ctx.ui.confirm(\n\t\t\t\"Reload Pi resources now?\",\n\t\t\t\"This reloads extensions, skills, prompts, themes, and context files.\",\n\t\t))\n\t) {\n\t\tif (signal?.aborted) return;\n\t\tawait ctx.reload();\n\t}\n}\n\nasync function readRemoteSnapshotForUpload(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\thead: RemoteHead | undefined,\n\tstate: SyncState,\n\tsignal?: AbortSignal,\n) {\n\tif (\n\t\t!head ||\n\t\t(head.snapshotId === state.lastAppliedSnapshot &&\n\t\t\t!syncPolicyChanged(state, config) &&\n\t\t\t(!state.lastRemoteRevision || backend.sameRevision(head.revision, state.lastRemoteRevision)))\n\t) {\n\t\treturn undefined;\n\t}\n\treturn backend.readSnapshot(head.snapshotRef, signal);\n}\n\nasync function snapshotForUpload(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\tlocal: Snapshot,\n\thead: RemoteHead | undefined,\n\tremote?: Snapshot,\n\tsignal?: AbortSignal,\n\toptions: { ignoreUnreadableRemote?: boolean } = {},\n) {\n\tif (!head) return local;\n\tlet snapshot = remote;\n\tif (!snapshot) {\n\t\ttry {\n\t\t\tsnapshot = await backend.readSnapshot(head.snapshotRef, signal);\n\t\t} catch (error) {\n\t\t\tif (options.ignoreUnreadableRemote) return local;\n\t\t\tthrow error;\n\t\t}\n\t}\n\treturn mergeRemotePreservedFiles(local, snapshot, config);\n}\n\nasync function readRemoteSnapshot(\n\tbackend: SyncBackend,\n\tconfig: AnySyncConfig,\n\tsignal?: AbortSignal,\n\toptions: { allowSelectionDifference?: boolean } = {},\n) {\n\tconst head = await backend.readHead(signal);\n\tif (!head) return { head: undefined, snapshot: undefined, selectionState: undefined };\n\tconst snapshot = await readSnapshotForHead(backend, head, signal);\n\tconst selectionState = inspectRemoteSelection(config.include, snapshot);\n\tif (!options.allowSelectionDifference && selectionState.kind === \"different\") {\n\t\tconst configIdentity = syncConfigReviewFingerprint(config);\n\t\tthrow remoteSelectionMismatch(config, selectionState.include, configIdentity);\n\t}\n\treturn {\n\t\thead,\n\t\tsnapshot: filterSnapshotForConfigPolicy(snapshot, config),\n\t\tselectionState,\n\t};\n}\n\nasync function confirmPush(\n\tctx: ExtensionCommandContext | ExtensionContext,\n\toptions: CommandOptions,\n\tconfig: AnySyncConfig,\n\tbackend: SyncBackend,\n\tlocal: Snapshot,\n\tupload: Snapshot,\n\thead: RemoteHead | undefined,\n\tremote: Snapshot | undefined,\n\ttitle = snapshotIncludesSessions(upload) ? \"Push pi settings and sessions?\" : \"Push pi settings?\",\n) {\n\tthrowIfAborted(options.signal);\n\tif (options.yes) return true;\n\tconst confirmed = await ctx.ui.confirm(\n\t\ttitle,\n\t\tformatPushSummary(\n\t\t\tconfig,\n\t\t\tbackend.destination,\n\t\t\tupload,\n\t\t\thead,\n\t\t\tcountPreservedRemoteFiles(local, upload),\n\t\t\tremote,\n\t\t),\n\t);\n\tthrowIfAborted(options.signal);\n\tif (confirmed) return true;\n\tctx.ui.setStatus(STATUS_KEY, undefined);\n\tctx.ui.notify(\"Push cancelled.\", \"info\");\n\treturn false;\n}\n\nfunction throwIfAborted(signal?: AbortSignal) {\n\tif (!signal?.aborted) return;\n\tthrow signal.reason instanceof Error\n\t\t? signal.reason\n\t\t: new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n\nfunction sameRemoteHead(\n\tbackend: SyncBackend,\n\tleft: RemoteHead | undefined,\n\tright: RemoteHead | undefined,\n) {\n\tif (!left || !right) return left === right;\n\treturn backend.sameRevision(left.revision, right.revision);\n}\n\nexport async function backupLocal(\n\tprofile: string,\n\toptions: SnapshotOptions = {},\n\tsignal?: AbortSignal,\n) {\n\tthrowIfAborted(signal);\n\tconst snapshot = await createSnapshot(profile, options);\n\tthrowIfAborted(signal);\n\tconst backupDirectory = path.join(stateDir(), \"backups\");\n\tawait fs.mkdir(backupDirectory, { recursive: true });\n\tthrowIfAborted(signal);\n\tconst backupPath = path.join(backupDirectory, `${snapshot.id}.json.gz`);\n\tconst encoded = await encodeSnapshot(snapshot);\n\tthrowIfAborted(signal);\n\tawait fs.writeFile(backupPath, encoded, { signal });\n\treturn backupPath;\n}\n", "import { createHash } from \"node:crypto\";\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { agentDir } from \"./config.js\";\nimport {\n\tassertWithinRoot,\n\tisDeniedPath,\n\tisPathInside,\n\tparentPaths,\n\tsafeJoin,\n\ttoPosix,\n} from \"./paths.js\";\nimport {\n\tcreateSnapshot,\n\tisSessionFilePath,\n\tisSessionPath,\n\tsessionStorageRoot,\n\tsnapshotIncludesSessions,\n\tsnapshotTarget,\n} from \"./snapshot.js\";\nimport {\n\tapplySnapshotTransaction,\n\trecoverPendingSnapshotTransactions,\n} from \"./snapshot-transaction.js\";\nimport type { Snapshot, SnapshotApplyPlan, SnapshotOptions } from \"./types.js\";\n\nfunction sha256(value: Buffer) {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction fileHashMap(snapshot: Snapshot) {\n\treturn Object.fromEntries(snapshot.files.map((file) => [file.path, file.sha256]));\n}\n\nexport async function applySnapshot(\n\tsnapshot: Snapshot,\n\tprotectedRelativePaths = new Set<string>(),\n\toptions: Pick<\n\t\tSnapshotOptions,\n\t\t\"include\" | \"sessionDir\" | \"syncFiles\" | \"syncSessions\" | \"extraFiles\"\n\t> = {},\n) {\n\tconst root = agentDir();\n\tconst { sessionDir } = options;\n\tawait recoverPendingSnapshotTransactions();\n\tconst current = await createSnapshot(snapshot.profile, {\n\t\t...options,\n\t\t...(options.include === undefined ? { syncSessions: snapshotIncludesSessions(snapshot) } : {}),\n\t\tsessionDir,\n\t});\n\tconst plan = await addTopLevelCaseVariantDeletes(\n\t\troot,\n\t\tprotectSnapshotApplyPlan(\n\t\t\troot,\n\t\t\tpreflightSnapshotApply(root, snapshot, current, { sessionDir }),\n\t\t\tprotectedRelativePaths,\n\t\t\tsessionDir,\n\t\t),\n\t\tsnapshot,\n\t);\n\tawait preflightSnapshotMutations(root, plan, sessionDir);\n\tawait applySnapshotTransaction(plan, { sessionDir });\n\treturn appliedFileHashMap(snapshot, current, protectedRelativePaths);\n}\n\nexport function preflightSnapshotApply(\n\troot: string,\n\tsnapshot: Snapshot,\n\tcurrent: Snapshot,\n\toptions: { sessionDir?: string } = {},\n): SnapshotApplyPlan {\n\tconst seenPaths = new Set<string>();\n\tconst remotePaths = new Set<string>();\n\tconst writes: Array<{ target: string; content: Buffer }> = [];\n\tconst deletes: string[] = [];\n\n\tfor (const file of snapshot.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!isSafeSnapshotPath(file.path)) {\n\t\t\tthrow new Error(`Unsafe path in snapshot: ${file.path}`);\n\t\t}\n\t\tif (isSessionPath(normalized) && !isSessionFilePath(normalized)) {\n\t\t\tthrow new Error(`Unsafe session path in snapshot: ${file.path}`);\n\t\t}\n\t\tif (seenPaths.has(normalized)) throw new Error(`Duplicate path in snapshot: ${normalized}`);\n\t\tseenPaths.add(normalized);\n\t\tremotePaths.add(normalized);\n\n\t\tconst target = snapshotTarget(root, normalized, options.sessionDir);\n\t\tconst content = decodeBase64Strict(file.contentBase64, normalized);\n\t\tif (sha256(content) !== file.sha256)\n\t\t\tthrow new Error(`Checksum mismatch in snapshot file: ${normalized}`);\n\t\twrites.push({ target, content });\n\t}\n\n\tconst deletePaths = new Set<string>();\n\tfor (const file of current.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!remotePaths.has(normalized)) {\n\t\t\tdeletePaths.add(snapshotTarget(root, normalized, options.sessionDir));\n\t\t}\n\t\tfor (const remotePath of parentPaths(normalized)) {\n\t\t\tif (remotePaths.has(remotePath)) {\n\t\t\t\tdeletePaths.add(snapshotTarget(root, remotePath, options.sessionDir));\n\t\t\t}\n\t\t}\n\t}\n\tdeletes.push(...deletePaths);\n\n\treturn { writes, deletes };\n}\n\nexport function protectSnapshotApplyPlan(\n\troot: string,\n\tplan: SnapshotApplyPlan,\n\tprotectedRelativePaths: Set<string>,\n\tsessionDir?: string,\n): SnapshotApplyPlan {\n\tif (protectedRelativePaths.size === 0) return plan;\n\tconst protectedTargets = new Set(\n\t\t[...protectedRelativePaths].map((relativePath) =>\n\t\t\tsnapshotTarget(root, relativePath, sessionDir),\n\t\t),\n\t);\n\treturn {\n\t\twrites: plan.writes.filter((item) => !protectedTargets.has(item.target)),\n\t\tdeletes: plan.deletes.filter((target) => !protectedTargets.has(target)),\n\t};\n}\n\nexport async function addTopLevelCaseVariantDeletes(\n\troot: string,\n\tplan: SnapshotApplyPlan,\n\tsnapshot: Pick<Snapshot, \"files\">,\n): Promise<SnapshotApplyPlan> {\n\tconst topLevelPaths = new Map<string, string>();\n\tfor (const file of snapshot.files) {\n\t\tconst normalized = toPosix(file.path);\n\t\tif (!normalized.includes(\"/\") && isSafeSnapshotPath(file.path)) {\n\t\t\ttopLevelPaths.set(normalized.toLowerCase(), normalized);\n\t\t}\n\t}\n\tif (topLevelPaths.size === 0) return plan;\n\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = await fs.readdir(root, { withFileTypes: true });\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return plan;\n\t\tthrow error;\n\t}\n\n\tconst deletes = new Set(plan.deletes);\n\tfor (const entry of entries) {\n\t\tconst canonicalPath = topLevelPaths.get(entry.name.toLowerCase());\n\t\tif (\n\t\t\tcanonicalPath &&\n\t\t\tentry.name !== canonicalPath &&\n\t\t\t(entry.isFile() || entry.isSymbolicLink())\n\t\t) {\n\t\t\tdeletes.add(safeJoin(root, entry.name));\n\t\t}\n\t}\n\treturn { ...plan, deletes: [...deletes] };\n}\n\nexport function appliedFileHashMap(\n\tsnapshot: Snapshot,\n\tcurrent: Snapshot,\n\tprotectedRelativePaths: Set<string>,\n) {\n\tconst hashes = fileHashMap(snapshot);\n\tif (protectedRelativePaths.size === 0) return hashes;\n\tconst currentHashes = fileHashMap(current);\n\tfor (const relativePath of protectedRelativePaths) {\n\t\tconst normalized = toPosix(relativePath);\n\t\tif (currentHashes[normalized]) {\n\t\t\thashes[normalized] = currentHashes[normalized];\n\t\t} else {\n\t\t\tdelete hashes[normalized];\n\t\t}\n\t}\n\treturn hashes;\n}\n\nfunction isSafeSnapshotPath(relativePath: string) {\n\tif (relativePath.includes(\"\\\\\")) return false;\n\tconst normalized = toPosix(relativePath);\n\treturn (\n\t\tBoolean(normalized) &&\n\t\tnormalized !== \".\" &&\n\t\tnormalized !== \"..\" &&\n\t\t!normalized.startsWith(\"../\") &&\n\t\t!path.posix.isAbsolute(normalized) &&\n\t\tpath.posix.normalize(normalized) === normalized &&\n\t\t!isDeniedPath(normalized)\n\t);\n}\n\nfunction decodeBase64Strict(value: string, filePath: string) {\n\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {\n\t\tthrow new Error(`Invalid base64 content in snapshot file: ${filePath}`);\n\t}\n\treturn Buffer.from(value, \"base64\");\n}\n\nasync function preflightSnapshotMutations(\n\troot: string,\n\tplan: { deletes: string[]; writes: Array<{ target: string; content: Buffer }> },\n\tsessionDir?: string,\n) {\n\tconst deletePaths = new Set(plan.deletes);\n\tfor (const target of plan.deletes) {\n\t\tawait assertNoSymlinkParents(rootForTarget(root, target, sessionDir), target);\n\t}\n\tfor (const item of plan.writes) {\n\t\tawait prepareSnapshotWrite(\n\t\t\trootForTarget(root, item.target, sessionDir),\n\t\t\titem.target,\n\t\t\tdeletePaths,\n\t\t);\n\t}\n}\n\nfunction rootForTarget(root: string, target: string, sessionDir?: string) {\n\tconst sessionRoot = sessionDir ? sessionStorageRoot(root, sessionDir) : undefined;\n\tif (sessionRoot && isPathInside(sessionRoot, target)) return sessionRoot;\n\treturn root;\n}\n\nasync function prepareSnapshotWrite(root: string, target: string, deletePaths: Set<string>) {\n\tconst parentWillBeReplaced = await ensureSafeDirectory(root, path.dirname(target), deletePaths);\n\tif (parentWillBeReplaced) return;\n\ttry {\n\t\tconst stat = await fs.lstat(target);\n\t\tif (stat.isSymbolicLink())\n\t\t\tthrow new Error(`Refusing to overwrite symlink during snapshot apply: ${target}`);\n\t\tif (stat.isDirectory() && !deletePaths.has(target)) {\n\t\t\tthrow new Error(`Refusing to overwrite directory during snapshot apply: ${target}`);\n\t\t}\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t}\n}\n\nasync function ensureSafeDirectory(root: string, directory: string, deletePaths: Set<string>) {\n\tassertWithinRoot(root, directory);\n\tconst rootPath = path.resolve(root);\n\tconst relative = path.relative(rootPath, path.resolve(directory));\n\tlet current = rootPath;\n\tfor (const part of relative.split(path.sep).filter(Boolean)) {\n\t\tcurrent = path.join(current, part);\n\t\ttry {\n\t\t\tconst stat = await fs.lstat(current);\n\t\t\tif (stat.isSymbolicLink())\n\t\t\t\tthrow new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n\t\t\tif (!stat.isDirectory()) {\n\t\t\t\tif (deletePaths.has(current)) return true;\n\t\t\t\tthrow new Error(`Snapshot path parent is not a directory: ${current}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t\tawait fs.mkdir(current);\n\t\t}\n\t}\n\treturn false;\n}\n\nasync function assertNoSymlinkParents(root: string, target: string) {\n\tassertWithinRoot(root, target);\n\tconst rootPath = path.resolve(root);\n\tconst relative = path.relative(rootPath, path.resolve(target));\n\tlet current = rootPath;\n\tconst parts = relative.split(path.sep).filter(Boolean);\n\tfor (const part of parts.slice(0, -1)) {\n\t\tcurrent = path.join(current, part);\n\t\ttry {\n\t\t\tconst stat = await fs.lstat(current);\n\t\t\tif (stat.isSymbolicLink())\n\t\t\t\tthrow new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n\t\t\tif (!stat.isDirectory())\n\t\t\t\tthrow new Error(`Snapshot path parent is not a directory: ${current}`);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n", "import { syncConfigReviewIdentity } from \"./config.js\";\nimport { SyncDecisionRequiredError } from \"./sync-errors.js\";\nimport { formatDiff, formatSnapshotOnlyDiff, safeTerminalText } from \"./sync-format.js\";\nimport { includeFromSelectionConfig } from \"./sync-policy.js\";\nimport { syncPolicyChanged } from \"./sync-state.js\";\nimport type { AnySyncConfig, Snapshot, SyncState } from \"./types.js\";\n\nexport type SyncDecisionKind =\n\t| \"remote-or-policy-changed\"\n\t| \"both-changed\"\n\t| \"first-sync-settings-diverged\"\n\t| \"first-sync-sessions-diverged\"\n\t| \"remote-empty\";\n\nexport type SyncResolutionDirection = \"push\" | \"pull\";\n\nexport interface SyncDecision {\n\tkind: SyncDecisionKind;\n\tsetupName: string;\n\tconfigIdentity: string;\n\tcauses: {\n\t\tlocalChanged: boolean;\n\t\tremoteChanged: boolean;\n\t\tpolicyChanged: boolean;\n\t};\n\tpreviousInclude?: readonly string[];\n\tcurrentInclude: readonly string[];\n\treview: string;\n\tdirections: readonly SyncResolutionDirection[];\n\tdirectMessage: string;\n}\n\nexport {\n\tisSyncDecisionRequiredError,\n\tSyncDecisionRequiredError,\n} from \"./sync-errors.js\";\n\ninterface CreateSyncDecisionOptions {\n\tkind: SyncDecisionKind;\n\tconfig: AnySyncConfig;\n\tstate: SyncState;\n\tlocal: Snapshot;\n\tremote?: Snapshot;\n\tlocalChanged: boolean;\n\tremoteChanged: boolean;\n\tdirectMessage: string;\n}\n\nexport function createSyncDecision(options: CreateSyncDecisionOptions) {\n\tconst { config, state, local, remote, kind } = options;\n\tconst policyChanged = Boolean(state.lastAppliedSnapshot) && syncPolicyChanged(state, config);\n\tconst previousInclude = includeFromSelectionConfig(state);\n\tconst currentInclude = [...config.include];\n\tconst causes = {\n\t\tlocalChanged: options.localChanged,\n\t\tremoteChanged: options.remoteChanged,\n\t\tpolicyChanged,\n\t};\n\tconst causeLines =\n\t\tkind === \"first-sync-settings-diverged\"\n\t\t\t? [\"This machine and the remote have different Pi settings on first sync.\"]\n\t\t\t: kind === \"first-sync-sessions-diverged\"\n\t\t\t\t? [\"Pi settings match, but local and remote sessions differ on first sync.\"]\n\t\t\t\t: kind === \"remote-empty\"\n\t\t\t\t\t? [\"The remote storage location is empty.\"]\n\t\t\t\t\t: [\n\t\t\t\t\t\t\t...(causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n\t\t\t\t\t\t\t...(causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n\t\t\t\t\t\t\t...(causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n\t\t\t\t\t\t];\n\tconst comparison = remote\n\t\t? formatDiff(local, remote)\n\t\t: formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local);\n\tconst review = [\n\t\t`Sync setup: ${safeTerminalText(config.setupName)}`,\n\t\t\"\",\n\t\t\"Why a decision is required:\",\n\t\t...causeLines,\n\t\t...(policyChanged\n\t\t\t? [\n\t\t\t\t\t\"\",\n\t\t\t\t\t`Previously included: ${safeList(previousInclude)}`,\n\t\t\t\t\t`Currently included: ${safeList(currentInclude)}`,\n\t\t\t\t]\n\t\t\t: []),\n\t\t\"\",\n\t\t\"Observed differences:\",\n\t\t...comparison.split(\"\\n\").map(safeTerminalText),\n\t].join(\"\\n\");\n\treturn new SyncDecisionRequiredError({\n\t\tkind,\n\t\tsetupName: config.setupName,\n\t\tconfigIdentity: syncConfigReviewIdentity(config),\n\t\tcauses,\n\t\t...(policyChanged ? { previousInclude: [...previousInclude] } : {}),\n\t\tcurrentInclude,\n\t\treview,\n\t\tdirections: kind === \"remote-empty\" ? [\"push\"] : [\"push\", \"pull\"],\n\t\tdirectMessage: options.directMessage,\n\t});\n}\n\nfunction safeList(values: readonly string[]) {\n\treturn values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["fs", "path", "fileHashMap", "index", "path", "fs"]
|
|
7
|
+
}
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
snapshotHashesMatchState,
|
|
17
17
|
snapshotsMatch,
|
|
18
18
|
syncPolicyChanged
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-JF6MZCT4.ts";
|
|
20
|
+
import "./chunk-HVUSHMVL.ts";
|
|
21
|
+
import "./chunk-5T442OP3.ts";
|
|
22
22
|
import "./chunk-F5QL2GPY.ts";
|
|
23
23
|
import "./chunk-YQ6UW7IF.ts";
|
|
24
24
|
export {
|
|
@@ -38,4 +38,4 @@ export {
|
|
|
38
38
|
snapshotsMatch,
|
|
39
39
|
syncPolicyChanged
|
|
40
40
|
};
|
|
41
|
-
//# sourceMappingURL=sync-state-
|
|
41
|
+
//# sourceMappingURL=sync-state-SRN6YRBK.ts.map
|
package/dist/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
createSyncAttentionController,
|
|
5
5
|
syncAttentionMatchesConfig
|
|
6
|
-
} from "./chunks/chunk-
|
|
6
|
+
} from "./chunks/chunk-E4COSV32.ts";
|
|
7
7
|
import {
|
|
8
8
|
completeSyncArguments,
|
|
9
9
|
parseOptions,
|
|
@@ -15,18 +15,18 @@ import {
|
|
|
15
15
|
} from "./chunks/chunk-4U6AFLJB.ts";
|
|
16
16
|
import {
|
|
17
17
|
recoverSnapshotTransactionsOnStartup
|
|
18
|
-
} from "./chunks/chunk-
|
|
18
|
+
} from "./chunks/chunk-X7SQ2EQM.ts";
|
|
19
19
|
import {
|
|
20
20
|
unlock,
|
|
21
21
|
withLock
|
|
22
|
-
} from "./chunks/chunk-
|
|
22
|
+
} from "./chunks/chunk-WSOBYHIZ.ts";
|
|
23
23
|
import {
|
|
24
24
|
SetupPullRequiresUiError,
|
|
25
25
|
errorMessage,
|
|
26
26
|
isSyncDecisionRequiredError
|
|
27
|
-
} from "./chunks/chunk-
|
|
28
|
-
import "./chunks/chunk-
|
|
29
|
-
import "./chunks/chunk-
|
|
27
|
+
} from "./chunks/chunk-C7LXZ3UH.ts";
|
|
28
|
+
import "./chunks/chunk-JF6MZCT4.ts";
|
|
29
|
+
import "./chunks/chunk-HVUSHMVL.ts";
|
|
30
30
|
import {
|
|
31
31
|
activeLocalConfigPath,
|
|
32
32
|
configuredSyncSetupNames,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
readStateForConfig,
|
|
43
43
|
sessionTokenWarnings,
|
|
44
44
|
syncSessionsWarnings
|
|
45
|
-
} from "./chunks/chunk-
|
|
45
|
+
} from "./chunks/chunk-5T442OP3.ts";
|
|
46
46
|
import {
|
|
47
47
|
migrateLegacyStateDirectory,
|
|
48
48
|
stateDirectoryMigrationNotice,
|
|
@@ -67,12 +67,12 @@ var AUTO_SYNC_OPTIONS = {
|
|
|
67
67
|
function sync(pi, dependencies = {}) {
|
|
68
68
|
const loaders = {
|
|
69
69
|
setupSwitch: cachedModuleLoader(
|
|
70
|
-
dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-
|
|
70
|
+
dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-5YDG5YGJ.ts"))
|
|
71
71
|
),
|
|
72
|
-
snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import("./chunks/snapshot-
|
|
73
|
-
syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./chunks/sync-state-
|
|
72
|
+
snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import("./chunks/snapshot-2RYBUDRA.ts"))),
|
|
73
|
+
syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./chunks/sync-state-SRN6YRBK.ts"))),
|
|
74
74
|
operations: cachedModuleLoader(
|
|
75
|
-
dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-
|
|
75
|
+
dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-3LLIHWZO.ts"))
|
|
76
76
|
)
|
|
77
77
|
};
|
|
78
78
|
const attention = createSyncAttentionController();
|
|
@@ -185,7 +185,7 @@ async function startSession(ctx, signal, loaders) {
|
|
|
185
185
|
async function handleCommand(rawArgs, ctx, sessionSignal, loaders, attention) {
|
|
186
186
|
if (!rawArgs.trim()) {
|
|
187
187
|
try {
|
|
188
|
-
const { showSyncManager } = await import("./chunks/manager-ui-
|
|
188
|
+
const { showSyncManager } = await import("./chunks/manager-ui-NF4RUHBY.ts");
|
|
189
189
|
if (sessionSignal.aborted) return;
|
|
190
190
|
await showSyncManager(
|
|
191
191
|
ctx,
|
|
@@ -269,7 +269,7 @@ function directSelectionOrigin(rawArgs) {
|
|
|
269
269
|
async function resolveSelectionAttention(ctx, attention, signal, loaders, options = {}) {
|
|
270
270
|
const current = attention.current();
|
|
271
271
|
if (!current || signal.aborted) return;
|
|
272
|
-
const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-
|
|
272
|
+
const { dispatchManagerResult } = await import("./chunks/manager-result-dispatcher-LWPYJAD5.ts");
|
|
273
273
|
if (signal.aborted || attention.current() !== current) return;
|
|
274
274
|
await dispatchManagerResult(
|
|
275
275
|
ctx,
|
|
@@ -374,7 +374,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup) {
|
|
|
374
374
|
await showConfig(ctx, options);
|
|
375
375
|
return { kind: "completed" };
|
|
376
376
|
case "files": {
|
|
377
|
-
const { showFileSelection } = await import("./chunks/file-selection-
|
|
377
|
+
const { showFileSelection } = await import("./chunks/file-selection-RKEHALNQ.ts");
|
|
378
378
|
throwIfAborted(options.signal);
|
|
379
379
|
await showFileSelection(ctx, options.setup, options.signal);
|
|
380
380
|
return { kind: "completed" };
|
|
@@ -540,7 +540,7 @@ async function initConfig(ctx, signal) {
|
|
|
540
540
|
return;
|
|
541
541
|
}
|
|
542
542
|
if (ctx.mode === "tui") {
|
|
543
|
-
const { showSetupWizard } = await import("./chunks/manager-ui-
|
|
543
|
+
const { showSetupWizard } = await import("./chunks/manager-ui-NF4RUHBY.ts");
|
|
544
544
|
throwIfAborted(signal);
|
|
545
545
|
await showSetupWizard(ctx, signal);
|
|
546
546
|
return;
|
package/docs/settings.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Pi Sync settings reference
|
|
2
|
+
|
|
3
|
+
[Back to README](../README.md)
|
|
4
|
+
|
|
5
|
+
- [Complete version 3 example](#complete-version-3-example)
|
|
6
|
+
- [Required backend shapes](#required-backend-shapes)
|
|
7
|
+
- [Secret scanning](#secret-scanning)
|
|
8
|
+
- [Included content](#included-content)
|
|
9
|
+
- [Unsupported old settings and recovery](#unsupported-old-settings-and-recovery)
|
|
10
|
+
|
|
11
|
+
## ⚙️ Settings
|
|
12
|
+
|
|
13
|
+
The canonical private user file is:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
~/.pi/agent/pi-sync.json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Pi's configured agent directory replaces `~/.pi/agent` when applicable.
|
|
20
|
+
Missing settings load as unconfigured without creating an agent directory, file, temporary file, or lock.
|
|
21
|
+
|
|
22
|
+
An explicit setup creates the file atomically.
|
|
23
|
+
On POSIX, pi-sync creates and replaces it with mode `0600`.
|
|
24
|
+
Pi-sync processes coordinate settings access through `pi-sync.json.mutation-lock`; lock-unaware editors are outside that serialization boundary and should not save the file while a pi-sync settings operation is running.
|
|
25
|
+
Credentials stay in this canonical private file and are never shown in menus, reviews, status, notifications, errors, logs, or completion metadata.
|
|
26
|
+
|
|
27
|
+
A private `pi-sync.local.json` containing a valid version 3 document is copied byte-for-byte to `pi-sync.json`.
|
|
28
|
+
The old file remains as a recovery copy.
|
|
29
|
+
If both paths exist, `pi-sync.json` wins and the legacy file remains untouched.
|
|
30
|
+
|
|
31
|
+
### Complete version 3 example
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"version": 3,
|
|
36
|
+
"activeSyncSetup": "home",
|
|
37
|
+
"onSwitch": "ask-before-pull",
|
|
38
|
+
"skipSecretScan": false,
|
|
39
|
+
"storageConnections": {
|
|
40
|
+
"r2": {
|
|
41
|
+
"type": "s3",
|
|
42
|
+
"endpoint": "https://example.r2.cloudflarestorage.com",
|
|
43
|
+
"region": "auto",
|
|
44
|
+
"credentials": {
|
|
45
|
+
"accessKeyId": "<access-key-id>",
|
|
46
|
+
"secretAccessKey": "<secret-access-key>"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"github": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"remote": "git@github.com:owner/private-pi-sync.git"
|
|
52
|
+
},
|
|
53
|
+
"nextcloud": {
|
|
54
|
+
"type": "webdav",
|
|
55
|
+
"url": "https://cloud.example.com/remote.php/dav/files/user",
|
|
56
|
+
"credentials": {
|
|
57
|
+
"username": "user",
|
|
58
|
+
"password": "<app-password>"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"syncSetups": {
|
|
63
|
+
"home": {
|
|
64
|
+
"storage": {
|
|
65
|
+
"connection": "r2",
|
|
66
|
+
"bucket": "personal-pi",
|
|
67
|
+
"path": "pi-sync/home"
|
|
68
|
+
},
|
|
69
|
+
"sync": {
|
|
70
|
+
"include": ["settings.json", "AGENTS.md", "skills", "prompts", "themes"],
|
|
71
|
+
"automatic": true
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"git-backup": {
|
|
75
|
+
"storage": {
|
|
76
|
+
"connection": "github",
|
|
77
|
+
"branch": "pi-sync/home",
|
|
78
|
+
"path": "pi-sync/home"
|
|
79
|
+
},
|
|
80
|
+
"sync": {
|
|
81
|
+
"include": ["settings.json", "AGENTS.md"],
|
|
82
|
+
"automatic": false
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"webdav-backup": {
|
|
86
|
+
"storage": {
|
|
87
|
+
"connection": "nextcloud",
|
|
88
|
+
"path": "pi-sync/home"
|
|
89
|
+
},
|
|
90
|
+
"sync": {
|
|
91
|
+
"include": ["settings.json", "sessions"],
|
|
92
|
+
"automatic": false
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Cloudflare R2 is persisted as `"type": "s3"`; R2 is a setup preset, not another schema type.
|
|
100
|
+
Temporary S3 credentials may additionally include `credentials.sessionToken`.
|
|
101
|
+
|
|
102
|
+
### Required backend shapes
|
|
103
|
+
|
|
104
|
+
- **S3/R2 connection:** `type`, `endpoint`, `region`, and `credentials.accessKeyId` / `credentials.secretAccessKey`.
|
|
105
|
+
- **S3/R2 setup storage:** `connection`, `bucket`, and complete relative `path`; `branch` is rejected.
|
|
106
|
+
- **Git connection:** `type` and a credential-free SSH or HTTPS `remote`.
|
|
107
|
+
- **Git setup storage:** `connection`, `branch`, and complete repository `path`; `bucket` is rejected.
|
|
108
|
+
- **WebDAV connection:** `type`, HTTPS `url`, and `credentials.username` / `credentials.password`.
|
|
109
|
+
- **WebDAV setup storage:** `connection` and complete relative `path`; `bucket` and `branch` are rejected.
|
|
110
|
+
|
|
111
|
+
Every setup requires `sync.include` and explicit `sync.automatic`.
|
|
112
|
+
`activeSyncSetup` must reference an own-property setup when any setups exist and must be absent when the setup catalog is empty.
|
|
113
|
+
A referenced connection cannot be removed.
|
|
114
|
+
The current setup must be switched before removal.
|
|
115
|
+
Two setups cannot resolve to the same normalized backend location.
|
|
116
|
+
|
|
117
|
+
`onSwitch` accepts:
|
|
118
|
+
|
|
119
|
+
- `ask-before-pull` — switch, then ask in TUI whether to start a reviewed pull;
|
|
120
|
+
- `pull-after-switch` — require observable UI and start the normal reviewed pull;
|
|
121
|
+
- `switch-only` — switch without reading or applying remote content.
|
|
122
|
+
|
|
123
|
+
### Secret scanning
|
|
124
|
+
|
|
125
|
+
The global `skipSecretScan` setting accepts a boolean and defaults to `false`, including when omitted from an existing version 3 document.
|
|
126
|
+
Set it through **/sync → Settings → Skip secret scan**; changes are saved immediately and apply to subsequent pushes for every sync setup, including automatic pushes.
|
|
127
|
+
When `true`, pushes skip the local secret scan; other safety checks and confirmations remain unchanged.
|
|
128
|
+
Enable it only after reviewing the destination and selected content because files containing secrets can be uploaded.
|
|
129
|
+
`/sync doctor` still scans and reports possible secrets regardless of this setting.
|
|
130
|
+
|
|
131
|
+
### Included content
|
|
132
|
+
|
|
133
|
+
`sync.include` is ordered and duplicate-free.
|
|
134
|
+
Supported Pi roots are:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
settings.json, keybindings.json, models.json, AGENTS.md, APPEND_SYSTEM.md,
|
|
138
|
+
skills, prompts, themes, extensions, sessions
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Safe agent-relative custom files or directories may also be included.
|
|
142
|
+
Absolute paths, `..`, backslashes, controls, denied secret/settings paths, duplicate case variants, and ambiguous nested paths under reserved roots are rejected.
|
|
143
|
+
|
|
144
|
+
An empty array is valid.
|
|
145
|
+
It means no useful transfer is selected: **Sync now** reports the condition and does not claim that the setup is up to date.
|
|
146
|
+
Unselected content remains unmanaged locally and is preserved when republishing existing remote snapshots.
|
|
147
|
+
|
|
148
|
+
The Included Content editor is a standard bounded multi-select backed by one in-memory draft.
|
|
149
|
+
Toggles never write settings.
|
|
150
|
+
**Add custom path…** accepts a safe agent-relative file or directory even when it does not exist locally yet, allowing a new environment to select content that exists only in the remote snapshot.
|
|
151
|
+
Leaving the editor opens an exact Include/Exclude review with **Save changes**, **Discard changes**, and **Continue editing**; only reviewed Save publishes, while Continue preserves the draft and Discard/cancellation preserves the settings bytes.
|
|
152
|
+
RPC remains a read-only summary with the manual `sync.include` path.
|
|
153
|
+
|
|
154
|
+
Every new snapshot stores the normalized included-content selection separately from the files that happened to exist.
|
|
155
|
+
This preserves selected-but-missing paths without syncing `pi-sync.json`, storage credentials, automatic-sync preferences, or setup names.
|
|
156
|
+
**Settings → Compare synced content** opens the same review-first flow as a manager operation when local and remote lists differ.
|
|
157
|
+
Adoption revalidates the remote head, immutable snapshot, reviewed storage coordinates, and local include list before one atomic settings update.
|
|
158
|
+
The saved state changes only `sync.include`, preserves unknown settings fields, and never pulls files or writes sync state.
|
|
159
|
+
Its explicit Continue action starts a fresh **Sync now** route, while **Done** leaves the reviewed settings change saved without implying a file operation.
|
|
160
|
+
Keeping this device's list opens the reviewed force-push path and explicitly replaces the remote policy while preserving eligible unmanaged remote files.
|
|
161
|
+
|
|
162
|
+
Automatic sync and pull, including forced pull, pause on an explicit remote-policy difference rather than silently expanding local scope.
|
|
163
|
+
Status reports matches and exact local-only/remote-only paths.
|
|
164
|
+
Old snapshots remain readable.
|
|
165
|
+
Because they have no authoritative selection, pi-sync offers only a clearly labeled read-only partial discovery from safe remote file roots; selected-but-missing and preserved-unmanaged intent cannot be reconstructed.
|
|
166
|
+
Use **Add custom path…** for any needed path.
|
|
167
|
+
|
|
168
|
+
Adding `sessions` requires a privacy acknowledgement in interactive flows.
|
|
169
|
+
Session JSONL can contain prompts, tool output, file paths, images, and secrets.
|
|
170
|
+
Automatic apply protects the currently open session file; restart Pi or resume a pulled session to use newly synchronized conversations.
|
|
171
|
+
|
|
172
|
+
### Unsupported old settings and recovery
|
|
173
|
+
|
|
174
|
+
Version 1, version 2, and non-empty unversioned documents are unsupported after the version 3 schema reset.
|
|
175
|
+
Pi Sync does **not** migrate, partially interpret, downgrade, or overwrite them.
|
|
176
|
+
Automatic sync pauses and reports an actionable version 3 error without displaying secrets.
|
|
177
|
+
|
|
178
|
+
Recovery:
|
|
179
|
+
|
|
180
|
+
1. retain the old file byte-for-byte;
|
|
181
|
+
2. move it aside manually;
|
|
182
|
+
3. create a new version 3 document or run the setup manager;
|
|
183
|
+
4. run `/sync doctor`, inspect the exact storage path, and review the first pull or push;
|
|
184
|
+
5. restore the retained file and a compatible older package only if rolling back.
|
|
185
|
+
|
|
186
|
+
Malformed, invalid, unsupported, symlinked, or concurrently changed documents remain untouched.
|
|
187
|
+
Failed UI saves keep the previous file and displayed/effective state.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-sync",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.15",
|
|
4
4
|
"description": "Pi extension that syncs Pi configuration through Git, WebDAV, Cloudflare R2, or S3-compatible storage.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"src",
|
|
25
25
|
"dist",
|
|
26
|
+
"docs",
|
|
26
27
|
"README.md",
|
|
27
28
|
"LICENSE"
|
|
28
29
|
],
|
|
@@ -31,9 +32,6 @@
|
|
|
31
32
|
"./dist/index.ts"
|
|
32
33
|
]
|
|
33
34
|
},
|
|
34
|
-
"piExtension": {
|
|
35
|
-
"lifecycle": "stable"
|
|
36
|
-
},
|
|
37
35
|
"scripts": {
|
|
38
36
|
"build": "node scripts/build-runtime.mjs",
|
|
39
37
|
"check": "npm run build && biome check . && npm run typecheck",
|
|
@@ -42,14 +40,14 @@
|
|
|
42
40
|
"typecheck": "tsc --noEmit"
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
|
-
"@narumitw/pi-tui-kit": "^0.
|
|
46
|
-
"fast-xml-parser": "^5.11.
|
|
43
|
+
"@narumitw/pi-tui-kit": "^0.59.0",
|
|
44
|
+
"fast-xml-parser": "^5.11.1",
|
|
47
45
|
"proper-lockfile": "^4.1.2"
|
|
48
46
|
},
|
|
49
47
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "2.5.
|
|
51
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
52
|
-
"@earendil-works/pi-tui": "0.
|
|
48
|
+
"@biomejs/biome": "2.5.11",
|
|
49
|
+
"@earendil-works/pi-coding-agent": "0.85.0",
|
|
50
|
+
"@earendil-works/pi-tui": "0.85.0",
|
|
53
51
|
"@types/proper-lockfile": "^4.1.4",
|
|
54
52
|
"esbuild": "0.28.2",
|
|
55
53
|
"typescript": "7.0.2"
|