@narumitw/pi-sync 0.51.1 → 0.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -5
- package/dist/chunks/{chunk-7KHKWL3Q.ts → chunk-2CBF6SMT.ts} +8 -7
- package/dist/chunks/chunk-2CBF6SMT.ts.map +7 -0
- package/dist/chunks/{chunk-YFADF5ZQ.ts → chunk-2DI6PDZV.ts} +5 -1
- package/dist/chunks/chunk-2DI6PDZV.ts.map +7 -0
- package/dist/chunks/chunk-2GUXI2XT.ts +1702 -0
- package/dist/chunks/chunk-2GUXI2XT.ts.map +7 -0
- package/dist/chunks/{chunk-4MPIH46N.ts → chunk-3B4Z2SKV.ts} +40 -6
- package/dist/chunks/chunk-3B4Z2SKV.ts.map +7 -0
- package/dist/chunks/{chunk-YPXGU5OR.ts → chunk-4QVPTIZB.ts} +16 -6
- package/dist/chunks/{chunk-YPXGU5OR.ts.map → chunk-4QVPTIZB.ts.map} +2 -2
- package/dist/chunks/{chunk-UA7RXOIT.ts → chunk-4SBTAVFL.ts} +6 -6
- package/dist/chunks/{chunk-6546TS54.ts → chunk-5RZPINUQ.ts} +7 -4
- package/dist/chunks/{chunk-6546TS54.ts.map → chunk-5RZPINUQ.ts.map} +2 -2
- package/dist/chunks/chunk-76NB4R7U.ts +107 -0
- package/dist/chunks/chunk-76NB4R7U.ts.map +7 -0
- package/dist/chunks/{chunk-DM4X4FIA.ts → chunk-7D6RDCVC.ts} +8 -10
- package/dist/chunks/{chunk-DM4X4FIA.ts.map → chunk-7D6RDCVC.ts.map} +2 -2
- package/dist/chunks/chunk-A6HU4ERM.ts +124 -0
- package/dist/chunks/chunk-A6HU4ERM.ts.map +7 -0
- package/dist/chunks/chunk-AMJRUXFT.ts +17 -0
- package/dist/chunks/chunk-AMJRUXFT.ts.map +7 -0
- package/dist/chunks/chunk-ANWNQIR7.ts +1013 -0
- package/dist/chunks/chunk-ANWNQIR7.ts.map +7 -0
- package/dist/chunks/{chunk-T56RNRZJ.ts → chunk-BDB4IDM3.ts} +19 -10
- package/dist/chunks/chunk-BDB4IDM3.ts.map +7 -0
- package/dist/chunks/{chunk-2RZSQWBH.ts → chunk-CHSIAC4N.ts} +5 -5
- package/dist/chunks/{chunk-2RZSQWBH.ts.map → chunk-CHSIAC4N.ts.map} +2 -2
- package/dist/chunks/chunk-HUZ5CR4W.ts +110 -0
- package/dist/chunks/chunk-HUZ5CR4W.ts.map +7 -0
- package/dist/chunks/{chunk-QLSN7AGX.ts → chunk-IJ6VV6FN.ts} +81 -19
- package/dist/chunks/chunk-IJ6VV6FN.ts.map +7 -0
- package/dist/chunks/chunk-ORQRHEEO.ts +362 -0
- package/dist/chunks/chunk-ORQRHEEO.ts.map +7 -0
- package/dist/chunks/chunk-QE7NZZWT.ts +380 -0
- package/dist/chunks/chunk-QE7NZZWT.ts.map +7 -0
- package/dist/chunks/{chunk-HGJH56KR.ts → chunk-QHSQCK7L.ts} +4 -4
- package/dist/chunks/chunk-QOFMXPM5.ts +735 -0
- package/dist/chunks/chunk-QOFMXPM5.ts.map +7 -0
- package/dist/chunks/{chunk-DZUSTGQV.ts → chunk-UQ3ALBIB.ts} +4 -4
- package/dist/chunks/{chunk-Q32CQWPM.ts → chunk-V6VZ5TLG.ts} +13 -6
- package/dist/chunks/chunk-V6VZ5TLG.ts.map +7 -0
- package/dist/chunks/{chunk-E42GXD6D.ts → chunk-WKPX2SIC.ts} +4 -4
- package/dist/chunks/chunk-ZW5ZLGBI.ts +154 -0
- package/dist/chunks/chunk-ZW5ZLGBI.ts.map +7 -0
- package/dist/chunks/{chunk-6NT3YFGY.ts → chunk-ZX2Q6THB.ts} +8 -3
- package/dist/chunks/{chunk-6NT3YFGY.ts.map → chunk-ZX2Q6THB.ts.map} +2 -2
- package/dist/chunks/conflict-artifacts-BB2FZMIE.ts +27 -0
- package/dist/chunks/conflict-review-T3PB7ZSD.ts +175 -0
- package/dist/chunks/conflict-review-T3PB7ZSD.ts.map +7 -0
- package/dist/chunks/{file-selection-RAVHRYFG.ts → file-selection-WZX7HAY2.ts} +8 -7
- package/dist/chunks/{file-selection-RAVHRYFG.ts.map → file-selection-WZX7HAY2.ts.map} +1 -1
- package/dist/chunks/{git-backend-IAANDL3K.ts → git-backend-HLGKUQJT.ts} +19 -7
- package/dist/chunks/git-backend-HLGKUQJT.ts.map +7 -0
- package/dist/chunks/local-fields-6DGYOOIK.ts +22 -0
- package/dist/chunks/manager-result-dispatcher-VIDT3QBU.ts +23 -0
- package/dist/chunks/{manager-ui-763NEKJY.ts → manager-ui-HSMHS3OK.ts} +236 -57
- package/dist/chunks/manager-ui-HSMHS3OK.ts.map +7 -0
- package/dist/chunks/merge-baseline-store-EVQAAML6.ts +22 -0
- package/dist/chunks/remote-selection-ui-SMF5CLFO.ts +22 -0
- package/dist/chunks/{s3-backend-XGXUOPUN.ts → s3-backend-DJ2NT3SZ.ts} +16 -9
- package/dist/chunks/s3-backend-DJ2NT3SZ.ts.map +7 -0
- package/dist/chunks/{setup-switch-5G2VNJHL.ts → setup-switch-KTUWL6DE.ts} +9 -6
- package/dist/chunks/{setup-wizard-YIEWGX32.ts → setup-wizard-GSDPDFC4.ts} +10 -7
- package/dist/chunks/{setup-wizard-YIEWGX32.ts.map → setup-wizard-GSDPDFC4.ts.map} +1 -1
- package/dist/chunks/{snapshot-JL5DFSXI.ts → snapshot-THS5EY2L.ts} +6 -9
- package/dist/chunks/snapshot-THS5EY2L.ts.map +7 -0
- package/dist/chunks/{sync-inspection-P3ENJLNF.ts → sync-inspection-VBJF2FWC.ts} +10 -10
- package/dist/chunks/sync-inspection-VBJF2FWC.ts.map +7 -0
- package/dist/chunks/{sync-operations-AR76EB6C.ts → sync-operations-27VQUDH2.ts} +309 -508
- package/dist/chunks/sync-operations-27VQUDH2.ts.map +7 -0
- package/dist/chunks/{sync-state-VHJUZ4YG.ts → sync-state-CFL4RRRB.ts} +6 -6
- package/dist/chunks/sync-state-CFL4RRRB.ts.map +7 -0
- package/dist/chunks/{webdav-backend-3EGUONAT.ts → webdav-backend-ETQGSI6I.ts} +13 -7
- package/dist/chunks/webdav-backend-ETQGSI6I.ts.map +7 -0
- package/dist/index.ts +142 -43
- package/dist/index.ts.map +2 -2
- package/docs/content-merge-audit.md +156 -0
- package/docs/merge-implementation-audit.md +312 -0
- package/docs/settings-merge-audit.md +153 -0
- package/docs/settings.md +36 -0
- package/package.json +5 -5
- package/src/backends/git/git-backend.ts +2 -0
- package/src/backends/git/git-storage.ts +8 -3
- package/src/backends/s3/s3-backend.ts +2 -1
- package/src/backends/webdav/webdav-backend.ts +2 -1
- package/src/commands/command-execution.ts +10 -0
- package/src/commands/command.ts +4 -0
- package/src/settings/config.ts +12 -0
- package/src/settings/settings-management.ts +2 -2
- package/src/settings/settings-types.ts +14 -1
- package/src/settings/settings-validation.ts +24 -3
- package/src/snapshot/session-paths.ts +34 -7
- package/src/snapshot/snapshot-apply.ts +81 -32
- package/src/snapshot/snapshot-case-replacement.ts +80 -0
- package/src/snapshot/snapshot-codec.ts +6 -1
- package/src/snapshot/snapshot-root-transition.ts +154 -0
- package/src/snapshot/snapshot-transaction-plan.ts +72 -0
- package/src/snapshot/snapshot-transaction.ts +844 -102
- package/src/snapshot/snapshot-types.ts +5 -0
- package/src/state/json-file.ts +32 -5
- package/src/state/merge-baseline-store.ts +182 -0
- package/src/state/mutation-directory-sync.ts +34 -0
- package/src/state/state-types.ts +4 -0
- package/src/state/sync-state-store.ts +14 -1
- package/src/sync/automatic-sync.ts +11 -3
- package/src/sync/conflict-artifact-ownership.ts +63 -0
- package/src/sync/conflict-artifacts.ts +195 -0
- package/src/sync/conflict-groups.ts +68 -0
- package/src/sync/conflict-preview.ts +56 -0
- package/src/sync/conflict-resolution.ts +93 -0
- package/src/sync/conflict-retention.ts +72 -0
- package/src/sync/conflict-review.ts +95 -0
- package/src/sync/content-conflicts.ts +73 -0
- package/src/sync/field-migration.ts +39 -0
- package/src/sync/file-merge-planner.ts +143 -0
- package/src/sync/json-document.ts +184 -0
- package/src/sync/local-fields.ts +134 -0
- package/src/sync/merge-apply.ts +380 -0
- package/src/sync/merge-journal.ts +219 -0
- package/src/sync/merged-sync.ts +723 -0
- package/src/sync/partial-progress.ts +54 -0
- package/src/sync/remote-snapshot.ts +6 -0
- package/src/sync/session-merge.ts +194 -0
- package/src/sync/settings-conflicts.ts +52 -0
- package/src/sync/settings-merge.ts +57 -0
- package/src/sync/startup-check.ts +90 -5
- package/src/sync/sync-inspection.ts +1 -0
- package/src/sync/sync-local.ts +61 -0
- package/src/sync/sync-mutations.ts +256 -114
- package/src/sync/sync-queries.ts +6 -2
- package/src/sync/sync-state.ts +14 -5
- package/src/sync/text-merge.ts +133 -0
- package/src/sync-extension.ts +8 -0
- package/src/ui/manager-state.ts +12 -1
- package/src/ui/manager-ui.ts +10 -0
- package/src/ui/merge-review.ts +28 -0
- package/src/ui/remote-selection-ui.ts +1 -0
- package/src/ui/settings-ui.ts +183 -2
- package/src/ui/setup/setup-actions.ts +2 -2
- package/src/ui/setup/setup-switcher.ts +2 -1
- package/src/ui/storage-connections-ui.ts +11 -7
- package/src/ui/sync-attention.ts +3 -0
- package/src/ui/sync-format.ts +16 -12
- package/src/ui/sync-setups-ui.ts +1 -0
- package/src/ui/terminal-text.ts +9 -2
- package/dist/chunks/chunk-4AIHXRKE.ts +0 -197
- package/dist/chunks/chunk-4AIHXRKE.ts.map +0 -7
- package/dist/chunks/chunk-4MPIH46N.ts.map +0 -7
- package/dist/chunks/chunk-7KHKWL3Q.ts.map +0 -7
- package/dist/chunks/chunk-EEJPYTWE.ts +0 -348
- package/dist/chunks/chunk-EEJPYTWE.ts.map +0 -7
- package/dist/chunks/chunk-IVXEDPAD.ts +0 -370
- package/dist/chunks/chunk-IVXEDPAD.ts.map +0 -7
- package/dist/chunks/chunk-MSSW6F3R.ts +0 -12
- package/dist/chunks/chunk-MSSW6F3R.ts.map +0 -7
- package/dist/chunks/chunk-OVDTF5CH.ts +0 -90
- package/dist/chunks/chunk-OVDTF5CH.ts.map +0 -7
- package/dist/chunks/chunk-Q32CQWPM.ts.map +0 -7
- package/dist/chunks/chunk-QLSN7AGX.ts.map +0 -7
- package/dist/chunks/chunk-SWUXA3MH.ts +0 -18
- package/dist/chunks/chunk-SWUXA3MH.ts.map +0 -7
- package/dist/chunks/chunk-T56RNRZJ.ts.map +0 -7
- package/dist/chunks/chunk-YFADF5ZQ.ts.map +0 -7
- package/dist/chunks/git-backend-IAANDL3K.ts.map +0 -7
- package/dist/chunks/manager-result-dispatcher-OTUMQM26.ts +0 -23
- package/dist/chunks/manager-ui-763NEKJY.ts.map +0 -7
- package/dist/chunks/remote-selection-ui-TZTJF32Y.ts +0 -22
- package/dist/chunks/s3-backend-XGXUOPUN.ts.map +0 -7
- package/dist/chunks/sync-operations-AR76EB6C.ts.map +0 -7
- package/dist/chunks/webdav-backend-3EGUONAT.ts.map +0 -7
- /package/dist/chunks/{chunk-UA7RXOIT.ts.map → chunk-4SBTAVFL.ts.map} +0 -0
- /package/dist/chunks/{chunk-HGJH56KR.ts.map → chunk-QHSQCK7L.ts.map} +0 -0
- /package/dist/chunks/{chunk-DZUSTGQV.ts.map → chunk-UQ3ALBIB.ts.map} +0 -0
- /package/dist/chunks/{chunk-E42GXD6D.ts.map → chunk-WKPX2SIC.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-OTUMQM26.ts.map → conflict-artifacts-BB2FZMIE.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-TZTJF32Y.ts.map → local-fields-6DGYOOIK.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-5G2VNJHL.ts.map → manager-result-dispatcher-VIDT3QBU.ts.map} +0 -0
- /package/dist/chunks/{snapshot-JL5DFSXI.ts.map → merge-baseline-store-EVQAAML6.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-P3ENJLNF.ts.map → remote-selection-ui-SMF5CLFO.ts.map} +0 -0
- /package/dist/chunks/{sync-state-VHJUZ4YG.ts.map → setup-switch-KTUWL6DE.ts.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/conflict-artifacts.ts", "../../src/sync/conflict-groups.ts", "../../src/sync/merge-journal.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash, randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport { syncDirectory, writeJson } from \"../state/json-file.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { statePathForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { planFileMerge } from \"./file-merge-planner.js\";\n\nexport { conflictGroups } from \"./conflict-groups.js\";\n\nimport { mergeJournalIdentity } from \"./merge-journal.js\";\nexport interface ConflictArtifact {\n version: 1;\n identity: string;\n ancestors?: SnapshotFile[];\n state: SyncState;\n local: Snapshot;\n remote: Snapshot;\n groups: { paths: string[]; reasons: string[] }[];\n observed: { snapshotId: string; revision: string };\n}\nconst LIMIT = 192 * 1024 * 1024;\nexport function conflictArtifactFingerprint(artifact: ConflictArtifact) {\n return createHash(\"sha256\").update(JSON.stringify(artifact)).digest(\"hex\");\n}\nexport function conflictDirectory(config: AnySyncConfig) {\n return `${statePathForConfig(config)}.conflicts`;\n}\nasync function directory(config: AnySyncConfig, create = false) {\n const target = conflictDirectory(config);\n if (create) await fs.mkdir(target, { recursive: true, mode: 0o700 });\n const stat = await fs.lstat(target);\n if (!stat.isDirectory() || stat.isSymbolicLink() || (process.platform !== \"win32\" && (stat.mode & 0o077) !== 0))\n throw new Error(\"Unsafe private conflict directory.\");\n return target;\n}\nfunction tokenPath(config: AnySyncConfig, token: string) {\n if (!/^[a-f0-9-]{36}$/u.test(token)) throw new Error(\"Invalid conflict token.\");\n return path.join(conflictDirectory(config), `${token}.json`);\n}\nexport interface CreatedConflictArtifact {\n token: string;\n target: string;\n dev: number;\n ino: number;\n size: number;\n fingerprint: string;\n}\nexport async function saveConflictArtifact(\n config: AnySyncConfig,\n backend: string,\n artifact: Omit<ConflictArtifact, \"version\" | \"identity\">,\n validate: () => void,\n onCreated?: (created: CreatedConflictArtifact) => void,\n) {\n validate();\n const identity = mergeJournalIdentity(config, backend);\n const local = Object.fromEntries(artifact.local.files.map((file) => [file.path, file.sha256]));\n const remote = Object.fromEntries(artifact.remote.files.map((file) => [file.path, file.sha256]));\n const fingerprint = createHash(\"sha256\")\n .update(\n JSON.stringify([\n identity,\n artifact.groups.map((group) =>\n group.paths.map((filePath) => [\n filePath,\n artifact.state.lastFileHashes[filePath] ?? null,\n local[filePath] ?? null,\n remote[filePath] ?? null,\n ]),\n ),\n ]),\n )\n .digest(\"hex\")\n .slice(0, 32);\n const token = `${fingerprint.slice(0, 8)}-${fingerprint.slice(8, 12)}-${fingerprint.slice(12, 16)}-${fingerprint.slice(16, 20)}-${fingerprint.slice(20)}`;\n await directory(config, true);\n validate();\n const reuse = async () => {\n const existing = await readConflictArtifact(config, backend, token);\n validate();\n const oldLocal = Object.fromEntries(existing.local.files.map((file) => [file.path, file.sha256]));\n const oldRemote = Object.fromEntries(existing.remote.files.map((file) => [file.path, file.sha256]));\n if (\n JSON.stringify(existing.groups.map((group) => group.paths)) !==\n JSON.stringify(artifact.groups.map((group) => group.paths)) ||\n artifact.groups.some((group) =>\n group.paths.some(\n (filePath) =>\n existing.state.lastFileHashes[filePath] !== artifact.state.lastFileHashes[filePath] ||\n oldLocal[filePath] !== local[filePath] ||\n oldRemote[filePath] !== remote[filePath],\n ),\n )\n )\n throw new Error(\"Conflict identity does not match retained immutable evidence.\");\n return token;\n };\n const target = tokenPath(config, token);\n try {\n await fs.lstat(target);\n validate();\n return await reuse();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n const temporary = `${target}.${randomUUID()}.pending`;\n const candidate: ConflictArtifact = { version: 1, identity, ...artifact };\n try {\n await writeJson(temporary, candidate, { maxBytes: LIMIT });\n validate();\n const stat = await fs.lstat(temporary);\n validate();\n try {\n // Publish immutable evidence without replacing a concurrent/pre-existing owner.\n await fs.link(temporary, target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n validate();\n return await reuse();\n }\n // Register ownership before any cancellation or durability await can fail.\n onCreated?.({\n token,\n target,\n dev: stat.dev,\n ino: stat.ino,\n size: stat.size,\n fingerprint: conflictArtifactFingerprint(candidate),\n });\n validate();\n await syncDirectory(path.dirname(target));\n validate();\n await syncDirectory(path.dirname(conflictDirectory(config)));\n validate();\n return token;\n } finally {\n await fs.rm(temporary, { force: true });\n }\n}\nexport async function readConflictArtifact(config: AnySyncConfig, backend: string, token: string) {\n try {\n await directory(config);\n const target = tokenPath(config, token);\n const stat = await fs.lstat(target);\n if (!stat.isFile() || stat.size > LIMIT || (process.platform !== \"win32\" && (stat.mode & 0o077) !== 0))\n throw new Error(\"Unsafe conflict artifact.\");\n const artifact = JSON.parse(await fs.readFile(target, \"utf8\")) as ConflictArtifact;\n if (\n artifact.version !== 1 ||\n artifact.identity !== mergeJournalIdentity(config, backend) ||\n !Array.isArray(artifact.groups) ||\n artifact.groups.length > 16_384 ||\n artifact.groups.some(\n (group) =>\n !Array.isArray(group.paths) ||\n !group.paths.length ||\n group.paths.length > 16_384 ||\n !Array.isArray(group.reasons),\n )\n )\n throw new Error(\"Invalid conflict artifact.\");\n const plan = planFileMerge({\n baseline: artifact.state.lastFileHashes,\n local: artifact.local.files,\n remote: artifact.remote.files,\n selectionCompatible: true,\n });\n if (plan.kind !== \"planned\") throw new Error(\"Invalid conflict versions.\");\n const known = new Set(plan.decisions.map((item) => item.path));\n if (artifact.groups.some((group) => group.paths.some((value) => !known.has(value))))\n throw new Error(\"Invalid conflict paths.\");\n if (artifact.ancestors) {\n if (\n !Array.isArray(artifact.ancestors) ||\n artifact.ancestors.length > 16_384 ||\n artifact.ancestors.some((file) => artifact.state.lastFileHashes[file.path] !== file.sha256)\n )\n throw new Error(\"Invalid artifact ancestor.\");\n const basePlan = planFileMerge({\n baseline: {},\n local: artifact.ancestors,\n remote: [],\n selectionCompatible: true,\n });\n if (basePlan.kind !== \"planned\" || basePlan.conflicts.length) throw new Error(\"Invalid ancestor bytes.\");\n }\n syncStateFingerprint(artifact.state);\n return artifact;\n } catch {\n throw new Error(\"Cannot verify private conflict artifact; preserve evidence and review a fresh sync.\");\n }\n}\n", "import type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { type FileMergePlan, mergePathIdentity } from \"./file-merge-planner.js\";\n\n/** Indexed connected closure; path relationships are identical to the conservative merge policy. */\nexport function conflictGroups(plan: Extract<FileMergePlan, { kind: \"planned\" }>, config: AnySyncConfig) {\n const paths = plan.decisions.map((item) => item.path);\n const parents = paths.map((_, index) => index);\n const ranks = paths.map(() => 0);\n const find = (index: number): number => {\n while (parents[index] !== index) {\n parents[index] = parents[parents[index] ?? index] ?? index;\n index = parents[index] ?? index;\n }\n return index;\n };\n const join = (left: number, right: number) => {\n let a = find(left);\n let b = find(right);\n if (a === b) return;\n if ((ranks[a] ?? 0) < (ranks[b] ?? 0)) [a, b] = [b, a];\n parents[b] = a;\n if (ranks[a] === ranks[b]) ranks[a] = (ranks[a] ?? 0) + 1;\n };\n const identities = paths.map(mergePathIdentity);\n const byIdentity = new Map<string, number>();\n const byPath = new Map(paths.map((value, index) => [value, index]));\n identities.forEach((value, index) => {\n const previous = byIdentity.get(value);\n if (previous !== undefined) join(index, previous);\n else byIdentity.set(value, index);\n });\n const includes = new Set(\n config.include\n .filter((value) => ![\"settings.json\", \"AGENTS.md\", \"sessions\"].includes(value))\n .map(mergePathIdentity),\n );\n const buckets = new Map<string, number>();\n const bucket = (key: string, index: number) => {\n const previous = buckets.get(key);\n if (previous === undefined) buckets.set(key, index);\n else join(index, previous);\n };\n paths.forEach((value, index) => {\n const root = value.split(\"/\")[0] ?? \"\";\n if ([\"extensions\", \"themes\", \"skills\", \"prompts\"].includes(root)) bucket(`resource:${root}`, index);\n const segments = (identities[index] ?? \"\").split(\"/\");\n let ancestor = \"\";\n for (let length = 0; length < segments.length - 1; length++) {\n ancestor = ancestor ? `${ancestor}/${segments[length]}` : (segments[length] ?? \"\");\n const parent = byIdentity.get(ancestor);\n if (parent !== undefined) join(index, parent);\n if (includes.has(ancestor)) bucket(`include:${ancestor}`, index);\n }\n });\n const groups = new Map<number, { paths: string[]; reasons: string[] }>();\n for (const conflict of plan.conflicts) {\n const index = byPath.get(conflict.path);\n if (index === undefined) throw new Error(\"Conflict is missing from managed decisions.\");\n const key = find(index);\n const group = groups.get(key) ?? { paths: [], reasons: [] };\n if (!group.reasons.includes(conflict.reason)) group.reasons.push(conflict.reason);\n groups.set(key, group);\n }\n paths.forEach((value, index) => {\n groups.get(find(index))?.paths.push(value);\n });\n return [...groups.values()].map((group) => ({ ...group, paths: group.paths.sort() }));\n}\n", "import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { RemoteHead } from \"../backends/sync-backend.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { readJsonIfExists, syncDirectory, writeJson } from \"../state/json-file.js\";\nimport { statePathForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { planFileMerge } from \"./file-merge-planner.js\";\nimport {\n portableSnapshot,\n sameLocalFields,\n validatePortableSnapshot,\n validateSnapshotFieldPolicy,\n} from \"./local-fields.js\";\nimport type { PartialProgress } from \"./partial-progress.js\";\nimport { fileHashMap, sameHashes } from \"./sync-state.js\";\n\nexport interface MergeJournal {\n version: 1;\n identity: string;\n before: Snapshot;\n after: Snapshot;\n accepted?: Snapshot;\n progress?: PartialProgress;\n upload: Snapshot;\n expectedHead: RemoteHead;\n committedHead?: RemoteHead;\n /** No remote publication was attempted; a stale candidate can retire if local preimages remain intact. */\n applyOnly?: boolean;\n backup: string;\n stateIdentity: string;\n /** Effective collection/apply root; absent legacy evidence cannot authorize session recovery. */\n sessionRoot?: string;\n warnings?: string[];\n}\n\nexport function mergeJournalIdentity(config: AnySyncConfig, backendIdentity: string) {\n return JSON.stringify([config.setupName, backendIdentity, [...config.include].sort(), config.localFields ?? null]);\n}\n\nexport function mergeJournalPath(config: AnySyncConfig) {\n return `${statePathForConfig(config)}.merge-journal.json`;\n}\n\nexport async function readMergeJournal(config: AnySyncConfig): Promise<MergeJournal | undefined> {\n let journal: MergeJournal | undefined;\n try {\n const stat = await fs.lstat(mergeJournalPath(config));\n if (!stat.isFile() || stat.size > 384 * 1024 * 1024) throw new Error(\"Unsafe or oversized journal.\");\n journal = await readJsonIfExists<MergeJournal>(mergeJournalPath(config));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n // A JSON parser error may quote sensitive journal contents; do not retain it in a public error.\n throw new Error(\"Cannot read the private merge journal; preserve it and review recovery.\");\n }\n if (!journal) return;\n if (\n journal.version !== 1 ||\n typeof journal.identity !== \"string\" ||\n typeof journal.backup !== \"string\" ||\n typeof journal.stateIdentity !== \"string\" ||\n (journal.applyOnly !== undefined &&\n (journal.applyOnly !== true ||\n !journal.committedHead ||\n journal.committedHead.revision !== journal.expectedHead?.revision ||\n journal.committedHead.snapshotId !== journal.expectedHead?.snapshotId ||\n journal.upload?.id !== journal.expectedHead?.snapshotId)) ||\n (journal.sessionRoot !== undefined &&\n (typeof journal.sessionRoot !== \"string\" ||\n !path.isAbsolute(journal.sessionRoot) ||\n path.resolve(journal.sessionRoot) !== journal.sessionRoot)) ||\n (journal.warnings !== undefined &&\n (!Array.isArray(journal.warnings) ||\n journal.warnings.length > 64 ||\n journal.warnings.some((item) => typeof item !== \"string\"))) ||\n !journal.expectedHead ||\n typeof journal.expectedHead.revision !== \"string\" ||\n !journal.before ||\n !journal.after ||\n !journal.upload ||\n !Array.isArray(journal.before.files) ||\n !Array.isArray(journal.after.files) ||\n !Array.isArray(journal.upload.files)\n )\n throw new Error(\"Unsupported or damaged merge journal; preserve it and review recovery before syncing.\");\n // Verify every path and byte, including the unmanaged remote files retained for publication.\n try {\n const pinnedPaths = new Set(journal.progress?.groups.flatMap((group) => group.paths) ?? []);\n for (const snapshot of [\n journal.before,\n journal.after,\n journal.upload,\n ...(journal.accepted ? [journal.accepted] : []),\n ]) {\n validateSnapshotFieldPolicy(snapshot);\n if (\n (snapshot.version !== 1 && snapshot.version !== 2 && snapshot.version !== 3) ||\n typeof snapshot.id !== \"string\" ||\n typeof snapshot.profile !== \"string\" ||\n snapshot.files.length > 16_384 ||\n snapshot.files.reduce(\n (bytes, file) =>\n bytes + (typeof file?.contentBase64 === \"string\" ? file.contentBase64.length * 0.75 : Infinity),\n 0,\n ) >\n 64 * 1024 * 1024\n )\n throw new Error(\"Invalid journal input.\");\n const plan = planFileMerge({ baseline: {}, local: snapshot.files, remote: [], selectionCompatible: true });\n if (\n plan.kind !== \"planned\" ||\n plan.conflicts.some((conflict) => conflict.reason !== \"path-collision\" || !pinnedPaths.has(conflict.path))\n )\n throw new Error(\"Invalid journal collision group.\");\n }\n validatePortableSnapshot(journal.upload);\n if ((journal.upload.version === 2 || journal.upload.version === 3) && !journal.accepted)\n throw new Error(\"Portable merge journal requires an explicit accepted projection.\");\n if (journal.accepted) validatePortableSnapshot(journal.accepted);\n } catch {\n throw new Error(\"Invalid merge journal paths, metadata, or bytes; preserve evidence for review.\");\n }\n // Integrity is intrinsic to the recorded transaction, not the user's current recovery policy.\n // completeJournal separately checks that the recorded policy matches the current setup.\n try {\n if (\n journal.accepted &&\n (!sameLocalFields(journal.accepted.localFields, journal.upload.localFields) ||\n !sameHashes(\n fileHashMap(portableSnapshot(journal.after, journal.upload.localFields)),\n fileHashMap(portableSnapshot(journal.accepted, journal.upload.localFields)),\n ))\n )\n throw new Error(\"Projection mismatch.\");\n } catch {\n throw new Error(\"Invalid accepted merge projection; preserve journal evidence.\");\n }\n if (journal.progress) {\n const known = new Set([\n ...Object.keys(journal.progress.previous?.lastFileHashes ?? {}),\n ...[...journal.before.files, ...journal.after.files, ...journal.upload.files].map((file) => file.path),\n ]);\n const progress = journal.progress;\n if (\n !config.partialSync ||\n !progress.previous ||\n syncStateFingerprint(progress.previous) !== journal.stateIdentity ||\n !Array.isArray(progress.groups) ||\n progress.groups.length > 16_384 ||\n progress.groups.some(\n (group) =>\n !Array.isArray(group.paths) ||\n !group.paths.length ||\n group.paths.length > 16_384 ||\n group.paths.some((filePath) => !known.has(filePath)) ||\n !/^[a-f0-9-]{36}$/u.test(group.artifact),\n )\n )\n throw new Error(\"Invalid partial acceptance metadata; preserve journal evidence.\");\n }\n if (journal.progress) {\n const before = fileHashMap(journal.before);\n const after = fileHashMap(journal.after);\n const { readConflictArtifact } = await import(\"./conflict-artifacts.js\");\n const backendIdentity = (JSON.parse(journal.identity) as unknown[])[1];\n if (typeof backendIdentity !== \"string\") throw new Error(\"Invalid partial backend identity.\");\n const byArtifact = new Map<string, typeof journal.progress.groups>();\n for (const group of journal.progress.groups) {\n const groups = byArtifact.get(group.artifact) ?? [];\n groups.push(group);\n byArtifact.set(group.artifact, groups);\n }\n for (const [token, groups] of byArtifact) {\n const artifact = await readConflictArtifact(config, backendIdentity, token);\n const retainedGroups = new Set(artifact.groups.map((group) => JSON.stringify(group.paths)));\n const remote = fileHashMap(artifact.remote);\n const upload = fileHashMap(journal.upload);\n for (const group of groups) {\n if (!retainedGroups.has(JSON.stringify(group.paths)))\n throw new Error(\"Partial group does not match retained artifact evidence.\");\n for (const filePath of group.paths)\n if (\n before[filePath] !== after[filePath] ||\n remote[filePath] !== upload[filePath] ||\n journal.progress.previous.lastFileHashes[filePath] !== artifact.state.lastFileHashes[filePath]\n )\n throw new Error(\"Withheld version changed in journal; preserve evidence.\");\n }\n }\n }\n return journal;\n}\n\nexport async function writeMergeJournal(config: AnySyncConfig, journal: MergeJournal) {\n await writeJson(mergeJournalPath(config), journal, { maxBytes: 384 * 1024 * 1024 });\n}\n\nexport async function clearMergeJournal(config: AnySyncConfig) {\n await fs.rm(mergeJournalPath(config), { force: true });\n await syncDirectory(path.dirname(mergeJournalPath(config)));\n}\n\nexport async function retireMergeJournal(config: AnySyncConfig) {\n if (!(await readMergeJournal(config))) return;\n const file = mergeJournalPath(config);\n await fs.rename(file, `${file}.${randomUUID()}.resolved`);\n await syncDirectory(path.dirname(file));\n}\n\nexport async function requireNoMergeJournal(config: AnySyncConfig, options: { force?: boolean } = {}) {\n const journal = await readMergeJournal(config);\n if (options.force || !journal) return;\n if (journal) {\n throw new Error(\n \"A merged transfer needs recovery. Run /sync sync to reconcile it. If newer local edits or remote revisions prevent recovery, review /sync diff and explicitly choose push --force or pull --force; the selected directional result will archive the old journal, not restore old bytes. Keep its backup; do not downgrade while recovery is pending.\",\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["randomUUID", "fs", "path", "readConflictArtifact", "fs", "path", "randomUUID"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
|
+
// @ts-nocheck -- generated JavaScript uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
collidingPaths,
|
|
5
|
+
planFileMerge
|
|
6
|
+
} from "./chunk-76NB4R7U.ts";
|
|
7
|
+
import {
|
|
8
|
+
statePathForConfig,
|
|
9
|
+
syncStateFingerprint
|
|
10
|
+
} from "./chunk-4QVPTIZB.ts";
|
|
11
|
+
import {
|
|
12
|
+
backendIdentityCoordinates
|
|
13
|
+
} from "./chunk-2JZFHNLM.ts";
|
|
14
|
+
import {
|
|
15
|
+
parseJsonObjectDocument,
|
|
16
|
+
parseSettingsDocument
|
|
17
|
+
} from "./chunk-ZW5ZLGBI.ts";
|
|
18
|
+
import {
|
|
19
|
+
syncDirectory,
|
|
20
|
+
writeJson
|
|
21
|
+
} from "./chunk-HUZ5CR4W.ts";
|
|
22
|
+
|
|
23
|
+
// src/state/merge-baseline-store.ts
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
import fs from "node:fs/promises";
|
|
26
|
+
import path2 from "node:path";
|
|
27
|
+
|
|
28
|
+
// src/sync/session-merge.ts
|
|
29
|
+
import { CURRENT_SESSION_VERSION } from "@earendil-works/pi-coding-agent";
|
|
30
|
+
|
|
31
|
+
// src/sync/text-merge.ts
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
var TEXT_LIMIT = 1024 * 1024;
|
|
34
|
+
var TEXT_MERGE_WORK_LIMIT = 8e6;
|
|
35
|
+
function charge(budget, work) {
|
|
36
|
+
if (work > budget.remaining) throw new Error("Text merge operation complexity bound exceeded.");
|
|
37
|
+
budget.remaining -= work;
|
|
38
|
+
}
|
|
39
|
+
function isMergeTextPath(filePath) {
|
|
40
|
+
return filePath === "AGENTS.md" || /\.(?:md|txt)$/u.test(filePath) && ["prompts", "skills"].includes(filePath.split("/")[0] ?? "") && path.posix.basename(filePath) !== "keybindings.json";
|
|
41
|
+
}
|
|
42
|
+
function text(bytes) {
|
|
43
|
+
if (bytes.length > TEXT_LIMIT) throw new Error("Text merge bound exceeded.");
|
|
44
|
+
const decoded = bytes.toString("utf8");
|
|
45
|
+
if (!Buffer.from(decoded).equals(bytes) || bytes.some((byte) => byte < 32 && byte !== 9 && byte !== 10 && byte !== 13 || byte === 127))
|
|
46
|
+
throw new Error("Unsupported text encoding.");
|
|
47
|
+
return decoded;
|
|
48
|
+
}
|
|
49
|
+
function lines(value) {
|
|
50
|
+
return value.match(/[^\n]*\n|[^\n]+$/gu) ?? [];
|
|
51
|
+
}
|
|
52
|
+
function edits(base, next, signal) {
|
|
53
|
+
const width = next.length + 1;
|
|
54
|
+
if ((base.length + 1) * width > 4e6) throw new Error("Text merge complexity bound exceeded.");
|
|
55
|
+
const ids = /* @__PURE__ */ new Map();
|
|
56
|
+
const intern = (line) => {
|
|
57
|
+
let id2 = ids.get(line);
|
|
58
|
+
if (id2 === void 0) {
|
|
59
|
+
id2 = ids.size;
|
|
60
|
+
ids.set(line, id2);
|
|
61
|
+
}
|
|
62
|
+
return id2;
|
|
63
|
+
};
|
|
64
|
+
const baseIds = base.map(intern);
|
|
65
|
+
const nextIds = next.map(intern);
|
|
66
|
+
const grid = new Uint32Array((base.length + 1) * width);
|
|
67
|
+
for (let i2 = base.length - 1; i2 >= 0; i2--) {
|
|
68
|
+
signal?.throwIfAborted();
|
|
69
|
+
for (let j2 = next.length - 1; j2 >= 0; j2--)
|
|
70
|
+
grid[i2 * width + j2] = baseIds[i2] === nextIds[j2] ? 1 + (grid[(i2 + 1) * width + j2 + 1] ?? 0) : Math.max(grid[(i2 + 1) * width + j2] ?? 0, grid[i2 * width + j2 + 1] ?? 0);
|
|
71
|
+
}
|
|
72
|
+
const result = [];
|
|
73
|
+
let i = 0;
|
|
74
|
+
let j = 0;
|
|
75
|
+
let active;
|
|
76
|
+
while (i < base.length || j < next.length) {
|
|
77
|
+
if (i < base.length && j < next.length && baseIds[i] === nextIds[j]) {
|
|
78
|
+
if (active) {
|
|
79
|
+
result.push(active);
|
|
80
|
+
active = void 0;
|
|
81
|
+
}
|
|
82
|
+
i++;
|
|
83
|
+
j++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
active ??= { start: i, end: i, lines: [] };
|
|
87
|
+
if (j < next.length && (i === base.length || (grid[i * width + j + 1] ?? 0) >= (grid[(i + 1) * width + j] ?? 0)))
|
|
88
|
+
active.lines.push(next[j++] ?? "");
|
|
89
|
+
else active.end = ++i;
|
|
90
|
+
}
|
|
91
|
+
if (active) result.push(active);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function mergeText(baseBytes, localBytes, remoteBytes, options = {}) {
|
|
95
|
+
const budget = options.budget ?? { remaining: TEXT_MERGE_WORK_LIMIT };
|
|
96
|
+
try {
|
|
97
|
+
options.signal?.throwIfAborted();
|
|
98
|
+
const base = lines(text(baseBytes));
|
|
99
|
+
const ours = lines(text(localBytes));
|
|
100
|
+
const theirs = lines(text(remoteBytes));
|
|
101
|
+
const cells = [ours, theirs].map((next) => (base.length + 1) * (next.length + 1));
|
|
102
|
+
if (cells.some((count) => count > 4e6)) return;
|
|
103
|
+
charge(budget, (cells[0] ?? 0) + (cells[1] ?? 0));
|
|
104
|
+
const local = edits(base, ours, options.signal);
|
|
105
|
+
const remote = edits(base, theirs, options.signal);
|
|
106
|
+
const combined = [...local];
|
|
107
|
+
for (const right of remote) {
|
|
108
|
+
let same = false;
|
|
109
|
+
for (const left of local) {
|
|
110
|
+
options.signal?.throwIfAborted();
|
|
111
|
+
charge(budget, 1);
|
|
112
|
+
if (left.start === right.start && left.end === right.end && left.lines.join("") === right.lines.join("")) {
|
|
113
|
+
same = true;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const overlap = left.start === left.end || right.start === right.end ? left.start <= right.end && right.start <= left.end : left.start < right.end && right.start < left.end;
|
|
117
|
+
if (overlap) return;
|
|
118
|
+
}
|
|
119
|
+
if (!same) combined.push(right);
|
|
120
|
+
}
|
|
121
|
+
combined.sort((left, right) => left.start - right.start || left.end - right.end);
|
|
122
|
+
let cursor = 0;
|
|
123
|
+
const output = [];
|
|
124
|
+
for (const edit of combined) {
|
|
125
|
+
output.push(...base.slice(cursor, edit.start), ...edit.lines);
|
|
126
|
+
cursor = edit.end;
|
|
127
|
+
}
|
|
128
|
+
output.push(...base.slice(cursor));
|
|
129
|
+
const result = Buffer.from(output.join(""));
|
|
130
|
+
text(result);
|
|
131
|
+
return result;
|
|
132
|
+
} catch {
|
|
133
|
+
options.signal?.throwIfAborted();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/sync/session-merge.ts
|
|
139
|
+
var sessionId = (value) => typeof value === "string" && /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/u.test(value);
|
|
140
|
+
var id = (value) => typeof value === "string" && /^[a-zA-Z0-9_-]{1,128}$/u.test(value);
|
|
141
|
+
var content = (value, types = ["text", "image", "thinking", "toolCall"]) => typeof value === "string" || Array.isArray(value) && value.every(
|
|
142
|
+
(block) => object(block) && types.includes(String(block.type)) && (block.type === "text" && typeof block.text === "string" || block.type === "image" && typeof block.data === "string" && typeof block.mimeType === "string" || block.type === "thinking" && typeof block.thinking === "string" || block.type === "toolCall" && typeof block.id === "string" && typeof block.name === "string" && object(block.arguments))
|
|
143
|
+
);
|
|
144
|
+
var message = (value) => {
|
|
145
|
+
if (!object(value) || typeof value.timestamp !== "number" || !Number.isFinite(value.timestamp)) return false;
|
|
146
|
+
switch (value.role) {
|
|
147
|
+
case "system":
|
|
148
|
+
return content(value.content, ["text"]) && (value.sections === void 0 || object(value.sections) && Object.values(value.sections).every((section) => section === null || typeof section === "string")) && (value.toolsAdded === void 0 || Array.isArray(value.toolsAdded) && value.toolsAdded.every(
|
|
149
|
+
(tool) => object(tool) && typeof tool.name === "string" && typeof tool.description === "string" && object(tool.parameters)
|
|
150
|
+
)) && (value.toolsRemoved === void 0 || Array.isArray(value.toolsRemoved) && value.toolsRemoved.every((tool) => object(tool) && typeof tool.name === "string"));
|
|
151
|
+
case "user":
|
|
152
|
+
return content(value.content, ["text", "image"]);
|
|
153
|
+
case "assistant":
|
|
154
|
+
return Array.isArray(value.content) && content(value.content, ["text", "thinking", "toolCall"]) && typeof value.api === "string" && typeof value.provider === "string" && typeof value.model === "string" && object(value.usage) && ["pending", "stop", "length", "toolUse", "error", "aborted", "deferred"].includes(String(value.stopReason));
|
|
155
|
+
case "toolResult":
|
|
156
|
+
return typeof value.toolCallId === "string" && typeof value.toolName === "string" && Array.isArray(value.content) && content(value.content, ["text", "image"]) && typeof value.isError === "boolean";
|
|
157
|
+
case "custom":
|
|
158
|
+
return typeof value.customType === "string" && content(value.content, ["text", "image"]) && typeof value.display === "boolean";
|
|
159
|
+
case "bashExecution":
|
|
160
|
+
return typeof value.command === "string" && typeof value.output === "string" && typeof value.cancelled === "boolean" && typeof value.truncated === "boolean";
|
|
161
|
+
case "branchSummary":
|
|
162
|
+
return typeof value.summary === "string" && (value.fromId === null || typeof value.fromId === "string");
|
|
163
|
+
case "compactionSummary":
|
|
164
|
+
return typeof value.summary === "string" && typeof value.tokensBefore === "number" && Number.isFinite(value.tokensBefore) && value.tokensBefore >= 0;
|
|
165
|
+
default:
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var object = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
170
|
+
function validateSession(bytes) {
|
|
171
|
+
if (CURRENT_SESSION_VERSION !== 3) throw new Error("Unaudited Pi session format; require review.");
|
|
172
|
+
const raw = text(bytes);
|
|
173
|
+
if (!raw.endsWith("\n")) throw new Error("Incomplete session tail.");
|
|
174
|
+
const rows = raw.slice(0, -1).split("\n").map((line) => {
|
|
175
|
+
if (line.startsWith("\uFEFF")) throw new Error("Unexpected session-record BOM; require review.");
|
|
176
|
+
return parseJsonObjectDocument(Buffer.from(line)).root.value;
|
|
177
|
+
});
|
|
178
|
+
if (rows.length > 16384) throw new Error("Session entry bound exceeded.");
|
|
179
|
+
const header = rows[0];
|
|
180
|
+
if (!object(header) || header.type !== "session" || header.version !== CURRENT_SESSION_VERSION || !sessionId(header.id) || typeof header.cwd !== "string" || typeof header.timestamp !== "string" || !Number.isFinite(Date.parse(header.timestamp)) || header.parentSession !== void 0 && typeof header.parentSession !== "string")
|
|
181
|
+
throw new Error("Unsupported session header.");
|
|
182
|
+
const ids = /* @__PURE__ */ new Set();
|
|
183
|
+
const known = (value) => id(value) && ids.has(value);
|
|
184
|
+
for (const row of rows.slice(1)) {
|
|
185
|
+
if (!object(row) || !id(row.id) || ids.has(row.id) || typeof row.timestamp !== "string" || !Number.isFinite(Date.parse(row.timestamp)) || row.parentId !== null && !known(row.parentId))
|
|
186
|
+
throw new Error("Invalid session graph.");
|
|
187
|
+
const strings = (...keys) => keys.every((key) => typeof row[key] === "string");
|
|
188
|
+
let valid = false;
|
|
189
|
+
switch (row.type) {
|
|
190
|
+
case "message":
|
|
191
|
+
valid = message(row.message);
|
|
192
|
+
break;
|
|
193
|
+
case "thinking_level_change":
|
|
194
|
+
valid = strings("thinkingLevel");
|
|
195
|
+
break;
|
|
196
|
+
case "model_change":
|
|
197
|
+
valid = strings("provider", "modelId");
|
|
198
|
+
break;
|
|
199
|
+
case "usage":
|
|
200
|
+
valid = strings("kind", "provider", "model") && object(row.usage);
|
|
201
|
+
break;
|
|
202
|
+
case "compaction":
|
|
203
|
+
valid = strings("summary") && (known(row.firstKeptEntryId) || row.firstKeptEntryId === row.id) && (row.systemMessage === void 0 || object(row.systemMessage) && row.systemMessage.role === "system" && message(row.systemMessage)) && typeof row.tokensBefore === "number" && Number.isFinite(row.tokensBefore) && row.tokensBefore >= 0;
|
|
204
|
+
break;
|
|
205
|
+
case "branch_summary":
|
|
206
|
+
valid = strings("summary") && (known(row.fromId) || row.fromId === "root");
|
|
207
|
+
break;
|
|
208
|
+
case "custom":
|
|
209
|
+
valid = strings("customType");
|
|
210
|
+
break;
|
|
211
|
+
case "custom_message":
|
|
212
|
+
valid = strings("customType") && typeof row.display === "boolean" && content(row.content, ["text", "image"]);
|
|
213
|
+
break;
|
|
214
|
+
case "context_edit":
|
|
215
|
+
valid = known(row.targetId) && (row.replacement === null || object(row.replacement) && content(row.replacement.content));
|
|
216
|
+
break;
|
|
217
|
+
case "label":
|
|
218
|
+
valid = known(row.targetId) && (row.label === void 0 || typeof row.label === "string");
|
|
219
|
+
break;
|
|
220
|
+
case "session_info":
|
|
221
|
+
valid = row.name === void 0 || typeof row.name === "string";
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
if (!valid) throw new Error("Unsupported session entry.");
|
|
225
|
+
ids.add(row.id);
|
|
226
|
+
}
|
|
227
|
+
return header.id;
|
|
228
|
+
}
|
|
229
|
+
function mergeSession(base, local, remote) {
|
|
230
|
+
try {
|
|
231
|
+
const identity2 = validateSession(base);
|
|
232
|
+
if (validateSession(local) !== identity2 || validateSession(remote) !== identity2) return;
|
|
233
|
+
const prefix = (left, right) => right.length >= left.length && right.subarray(0, left.length).equals(left);
|
|
234
|
+
if (!prefix(base, local) || !prefix(base, remote)) return;
|
|
235
|
+
if (prefix(local, remote)) return remote;
|
|
236
|
+
if (prefix(remote, local)) return local;
|
|
237
|
+
} catch {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/state/merge-baseline-store.ts
|
|
243
|
+
var MAX_BYTES = 192 * 1024 * 1024;
|
|
244
|
+
function eligible(file) {
|
|
245
|
+
try {
|
|
246
|
+
const bytes = Buffer.from(file.contentBase64, "base64");
|
|
247
|
+
if (file.path === "settings.json") parseSettingsDocument(bytes);
|
|
248
|
+
else if (isMergeTextPath(file.path)) text(bytes);
|
|
249
|
+
else if (file.path.startsWith("sessions/") && file.path.endsWith(".jsonl")) validateSession(bytes);
|
|
250
|
+
else return false;
|
|
251
|
+
return true;
|
|
252
|
+
} catch {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function identity(config) {
|
|
257
|
+
return JSON.stringify([
|
|
258
|
+
config.setupName,
|
|
259
|
+
backendIdentityCoordinates(config),
|
|
260
|
+
config.include,
|
|
261
|
+
config.localFields ?? []
|
|
262
|
+
]);
|
|
263
|
+
}
|
|
264
|
+
function directory(config) {
|
|
265
|
+
return `${statePathForConfig(config)}.ancestors`;
|
|
266
|
+
}
|
|
267
|
+
async function checkDirectory(config, create = false) {
|
|
268
|
+
const target = directory(config);
|
|
269
|
+
if (create) await fs.mkdir(target, { recursive: true, mode: 448 });
|
|
270
|
+
const stat = await fs.lstat(target);
|
|
271
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || process.platform !== "win32" && (stat.mode & 63) !== 0)
|
|
272
|
+
throw new Error("Unsafe private ancestor directory; preserve evidence.");
|
|
273
|
+
}
|
|
274
|
+
function baselinePath(config, state) {
|
|
275
|
+
return path2.join(directory(config), `${syncStateFingerprint(state)}.json`);
|
|
276
|
+
}
|
|
277
|
+
async function stageMergeBaseline(config, snapshot, accepted, previous) {
|
|
278
|
+
const collisions = collidingPaths(snapshot.files.map((file) => file.path));
|
|
279
|
+
const files = snapshot.files.filter((file) => {
|
|
280
|
+
return !collisions.has(file.path) && accepted.lastFileHashes[file.path] === file.sha256 && (file.path === "settings.json" || config.mergeContent) && eligible(file);
|
|
281
|
+
});
|
|
282
|
+
if (previous) {
|
|
283
|
+
const stagedPaths = new Set(files.map((file) => file.path));
|
|
284
|
+
let ancestors = [];
|
|
285
|
+
try {
|
|
286
|
+
ancestors = await readMergeAncestors(config, previous) ?? [];
|
|
287
|
+
} catch {
|
|
288
|
+
}
|
|
289
|
+
for (const ancestor of ancestors)
|
|
290
|
+
if (!collisions.has(ancestor.path) && accepted.lastFileHashes[ancestor.path] === ancestor.sha256 && !stagedPaths.has(ancestor.path)) {
|
|
291
|
+
files.push(ancestor);
|
|
292
|
+
stagedPaths.add(ancestor.path);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
const plan = planFileMerge({ baseline: {}, local: files, remote: [], selectionCompatible: true });
|
|
296
|
+
if (plan.kind !== "planned" || plan.conflicts.length)
|
|
297
|
+
throw new Error("Cannot stage unverified merge ancestor bytes.");
|
|
298
|
+
const record = {
|
|
299
|
+
version: 1,
|
|
300
|
+
identity: identity(config),
|
|
301
|
+
acceptedState: syncStateFingerprint(accepted),
|
|
302
|
+
files
|
|
303
|
+
};
|
|
304
|
+
await checkDirectory(config, true);
|
|
305
|
+
await writeJson(baselinePath(config, accepted), record, { maxBytes: MAX_BYTES });
|
|
306
|
+
}
|
|
307
|
+
async function readBaselineRecord(config, target, acceptedState, validate = () => {
|
|
308
|
+
}) {
|
|
309
|
+
const stat = await fs.lstat(target);
|
|
310
|
+
validate();
|
|
311
|
+
if (!stat.isFile() || stat.size > MAX_BYTES || process.platform !== "win32" && (stat.mode & 63) !== 0)
|
|
312
|
+
throw new Error("Unsafe cache.");
|
|
313
|
+
const record = JSON.parse(await fs.readFile(target, "utf8"));
|
|
314
|
+
validate();
|
|
315
|
+
if (record.version !== 1 || record.identity !== identity(config) || record.acceptedState !== acceptedState || !Array.isArray(record.files) || record.files.length > 16384 || record.files.some((file) => !eligible(file)))
|
|
316
|
+
throw new Error("Invalid cache identity.");
|
|
317
|
+
const plan = planFileMerge({ baseline: {}, local: record.files, remote: [], selectionCompatible: true });
|
|
318
|
+
if (plan.kind !== "planned" || plan.conflicts.length) throw new Error("Invalid cache bytes.");
|
|
319
|
+
return record;
|
|
320
|
+
}
|
|
321
|
+
async function readMergeAncestors(config, state) {
|
|
322
|
+
let record;
|
|
323
|
+
try {
|
|
324
|
+
await checkDirectory(config);
|
|
325
|
+
record = await readBaselineRecord(config, baselinePath(config, state), syncStateFingerprint(state));
|
|
326
|
+
for (const file of record.files) {
|
|
327
|
+
if (state.lastFileHashes[file.path] !== file.sha256 || createHash("sha256").update(Buffer.from(file.contentBase64, "base64")).digest("hex") !== file.sha256)
|
|
328
|
+
throw new Error("Cache hash mismatch.");
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (error.code === "ENOENT") return;
|
|
332
|
+
throw new Error("Merge ancestor is invalid; preserve its private cache and review the conflict.");
|
|
333
|
+
}
|
|
334
|
+
return record.files;
|
|
335
|
+
}
|
|
336
|
+
async function readMergeAncestor(config, state, filePath) {
|
|
337
|
+
const file = (await readMergeAncestors(config, state))?.find((file2) => file2.path === filePath);
|
|
338
|
+
return file ? Buffer.from(file.contentBase64, "base64") : void 0;
|
|
339
|
+
}
|
|
340
|
+
async function pruneMergeBaselines(config, state, validate) {
|
|
341
|
+
validate();
|
|
342
|
+
const keep = path2.basename(baselinePath(config, state));
|
|
343
|
+
let names;
|
|
344
|
+
try {
|
|
345
|
+
await checkDirectory(config);
|
|
346
|
+
validate();
|
|
347
|
+
names = await fs.readdir(directory(config));
|
|
348
|
+
} catch (error) {
|
|
349
|
+
if (error.code === "ENOENT") return;
|
|
350
|
+
throw error;
|
|
351
|
+
}
|
|
352
|
+
for (const name of names) {
|
|
353
|
+
validate();
|
|
354
|
+
if (name === keep || !/^[a-f0-9]{64}\.json$/u.test(name)) continue;
|
|
355
|
+
const target = path2.join(directory(config), name);
|
|
356
|
+
try {
|
|
357
|
+
await readBaselineRecord(config, target, name.slice(0, -5), validate);
|
|
358
|
+
} catch {
|
|
359
|
+
validate();
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
validate();
|
|
363
|
+
await fs.rm(target);
|
|
364
|
+
validate();
|
|
365
|
+
}
|
|
366
|
+
await syncDirectory(directory(config));
|
|
367
|
+
validate();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export {
|
|
371
|
+
TEXT_MERGE_WORK_LIMIT,
|
|
372
|
+
isMergeTextPath,
|
|
373
|
+
mergeText,
|
|
374
|
+
mergeSession,
|
|
375
|
+
stageMergeBaseline,
|
|
376
|
+
readMergeAncestors,
|
|
377
|
+
readMergeAncestor,
|
|
378
|
+
pruneMergeBaselines
|
|
379
|
+
};
|
|
380
|
+
//# sourceMappingURL=chunk-QE7NZZWT.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/state/merge-baseline-store.ts", "../../src/sync/session-merge.ts", "../../src/sync/text-merge.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { backendIdentityCoordinates } from \"../backends/backend-identity.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport { collidingPaths, planFileMerge } from \"../sync/file-merge-planner.js\";\nimport { parseSettingsDocument } from \"../sync/json-document.js\";\nimport { validateSession } from \"../sync/session-merge.js\";\nimport { isMergeTextPath, text } from \"../sync/text-merge.js\";\nimport { syncDirectory, writeJson } from \"./json-file.js\";\nimport type { SyncState } from \"./state-types.js\";\nimport { statePathForConfig, syncStateFingerprint } from \"./sync-state-store.js\";\n\ninterface MergeBaseline {\n version: 1;\n identity: string;\n acceptedState: string;\n files: SnapshotFile[];\n}\nconst MAX_BYTES = 192 * 1024 * 1024;\nfunction eligible(file: SnapshotFile) {\n try {\n const bytes = Buffer.from(file.contentBase64, \"base64\");\n if (file.path === \"settings.json\") parseSettingsDocument(bytes);\n else if (isMergeTextPath(file.path)) text(bytes);\n else if (file.path.startsWith(\"sessions/\") && file.path.endsWith(\".jsonl\")) validateSession(bytes);\n else return false;\n return true;\n } catch {\n return false;\n }\n}\n\nfunction identity(config: AnySyncConfig) {\n return JSON.stringify([\n config.setupName,\n backendIdentityCoordinates(config),\n config.include,\n config.localFields ?? [],\n ]);\n}\nfunction directory(config: AnySyncConfig) {\n return `${statePathForConfig(config)}.ancestors`;\n}\nasync function checkDirectory(config: AnySyncConfig, create = false) {\n const target = directory(config);\n if (create) await fs.mkdir(target, { recursive: true, mode: 0o700 });\n const stat = await fs.lstat(target);\n if (!stat.isDirectory() || stat.isSymbolicLink() || (process.platform !== \"win32\" && (stat.mode & 0o077) !== 0))\n throw new Error(\"Unsafe private ancestor directory; preserve evidence.\");\n}\nfunction baselinePath(config: AnySyncConfig, state: SyncState) {\n return path.join(directory(config), `${syncStateFingerprint(state)}.json`);\n}\n\n/** Stage before accepted state, retain its previous ancestor until journal retirement. Never bootstrap from current edits. */\nexport async function stageMergeBaseline(\n config: AnySyncConfig,\n snapshot: Snapshot,\n accepted: SyncState,\n previous?: SyncState,\n) {\n const collisions = collidingPaths(snapshot.files.map((file) => file.path));\n const files = snapshot.files.filter((file) => {\n return (\n !collisions.has(file.path) &&\n accepted.lastFileHashes[file.path] === file.sha256 &&\n (file.path === \"settings.json\" || config.mergeContent) &&\n eligible(file)\n );\n });\n if (previous) {\n const stagedPaths = new Set(files.map((file) => file.path));\n let ancestors: SnapshotFile[] = [];\n try {\n ancestors = (await readMergeAncestors(config, previous)) ?? [];\n } catch {\n /* Keep unknown evidence; missing bytes are never invented. */\n }\n for (const ancestor of ancestors)\n if (\n !collisions.has(ancestor.path) &&\n accepted.lastFileHashes[ancestor.path] === ancestor.sha256 &&\n !stagedPaths.has(ancestor.path)\n ) {\n files.push(ancestor);\n stagedPaths.add(ancestor.path);\n }\n }\n const plan = planFileMerge({ baseline: {}, local: files, remote: [], selectionCompatible: true });\n if (plan.kind !== \"planned\" || plan.conflicts.length)\n throw new Error(\"Cannot stage unverified merge ancestor bytes.\");\n const record: MergeBaseline = {\n version: 1,\n identity: identity(config),\n acceptedState: syncStateFingerprint(accepted),\n files,\n };\n await checkDirectory(config, true);\n await writeJson(baselinePath(config, accepted), record, { maxBytes: MAX_BYTES });\n}\n\nasync function readBaselineRecord(\n config: AnySyncConfig,\n target: string,\n acceptedState: string,\n validate: () => void = () => {},\n): Promise<MergeBaseline> {\n const stat = await fs.lstat(target);\n validate();\n if (!stat.isFile() || stat.size > MAX_BYTES || (process.platform !== \"win32\" && (stat.mode & 0o077) !== 0))\n throw new Error(\"Unsafe cache.\");\n const record = JSON.parse(await fs.readFile(target, \"utf8\")) as MergeBaseline;\n validate();\n if (\n record.version !== 1 ||\n record.identity !== identity(config) ||\n record.acceptedState !== acceptedState ||\n !Array.isArray(record.files) ||\n record.files.length > 16_384 ||\n record.files.some((file) => !eligible(file))\n )\n throw new Error(\"Invalid cache identity.\");\n const plan = planFileMerge({ baseline: {}, local: record.files, remote: [], selectionCompatible: true });\n if (plan.kind !== \"planned\" || plan.conflicts.length) throw new Error(\"Invalid cache bytes.\");\n return record;\n}\n\nexport async function readMergeAncestors(config: AnySyncConfig, state: SyncState): Promise<SnapshotFile[] | undefined> {\n let record: MergeBaseline;\n try {\n await checkDirectory(config);\n record = await readBaselineRecord(config, baselinePath(config, state), syncStateFingerprint(state));\n for (const file of record.files) {\n if (\n state.lastFileHashes[file.path] !== file.sha256 ||\n createHash(\"sha256\").update(Buffer.from(file.contentBase64, \"base64\")).digest(\"hex\") !== file.sha256\n )\n throw new Error(\"Cache hash mismatch.\");\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw new Error(\"Merge ancestor is invalid; preserve its private cache and review the conflict.\");\n }\n return record.files;\n}\nexport async function readMergeAncestor(config: AnySyncConfig, state: SyncState, filePath: string) {\n const file = (await readMergeAncestors(config, state))?.find((file) => file.path === filePath);\n return file ? Buffer.from(file.contentBase64, \"base64\") : undefined;\n}\n\n/** Caller must hold the sync operation lock and retire the commit journal before pruning. */\nexport async function pruneMergeBaselines(config: AnySyncConfig, state: SyncState, validate: () => void) {\n validate();\n const keep = path.basename(baselinePath(config, state));\n let names: string[];\n try {\n await checkDirectory(config);\n validate();\n names = await fs.readdir(directory(config));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n }\n for (const name of names) {\n validate();\n if (name === keep || !/^[a-f0-9]{64}\\.json$/u.test(name)) continue;\n const target = path.join(directory(config), name);\n try {\n await readBaselineRecord(config, target, name.slice(0, -5), validate);\n } catch {\n validate();\n continue; // Unknown/corrupted evidence is not an owned pruning candidate.\n }\n validate();\n await fs.rm(target);\n validate();\n }\n await syncDirectory(directory(config));\n validate();\n}\n", "import { CURRENT_SESSION_VERSION } from \"@earendil-works/pi-coding-agent\";\nimport { parseJsonObjectDocument } from \"./json-document.js\";\nimport { text } from \"./text-merge.js\";\n\n// Public header IDs use Pi assertValidSessionId; generated entry IDs have a separate grammar.\nconst sessionId = (value: unknown): value is string =>\n typeof value === \"string\" && /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/u.test(value);\nconst id = (value: unknown): value is string => typeof value === \"string\" && /^[a-zA-Z0-9_-]{1,128}$/u.test(value);\nconst content = (value: unknown, types = [\"text\", \"image\", \"thinking\", \"toolCall\"]): boolean =>\n typeof value === \"string\" ||\n (Array.isArray(value) &&\n value.every(\n (block) =>\n object(block) &&\n types.includes(String(block.type)) &&\n ((block.type === \"text\" && typeof block.text === \"string\") ||\n (block.type === \"image\" && typeof block.data === \"string\" && typeof block.mimeType === \"string\") ||\n (block.type === \"thinking\" && typeof block.thinking === \"string\") ||\n (block.type === \"toolCall\" &&\n typeof block.id === \"string\" &&\n typeof block.name === \"string\" &&\n object(block.arguments))),\n ));\nconst message = (value: unknown) => {\n if (!object(value) || typeof value.timestamp !== \"number\" || !Number.isFinite(value.timestamp)) return false;\n switch (value.role) {\n case \"system\":\n return (\n content(value.content, [\"text\"]) &&\n (value.sections === undefined ||\n (object(value.sections) &&\n Object.values(value.sections).every((section) => section === null || typeof section === \"string\"))) &&\n (value.toolsAdded === undefined ||\n (Array.isArray(value.toolsAdded) &&\n value.toolsAdded.every(\n (tool) =>\n object(tool) &&\n typeof tool.name === \"string\" &&\n typeof tool.description === \"string\" &&\n object(tool.parameters),\n ))) &&\n (value.toolsRemoved === undefined ||\n (Array.isArray(value.toolsRemoved) &&\n value.toolsRemoved.every((tool) => object(tool) && typeof tool.name === \"string\")))\n );\n case \"user\":\n return content(value.content, [\"text\", \"image\"]);\n case \"assistant\":\n return (\n Array.isArray(value.content) &&\n content(value.content, [\"text\", \"thinking\", \"toolCall\"]) &&\n typeof value.api === \"string\" &&\n typeof value.provider === \"string\" &&\n typeof value.model === \"string\" &&\n object(value.usage) &&\n [\"pending\", \"stop\", \"length\", \"toolUse\", \"error\", \"aborted\", \"deferred\"].includes(String(value.stopReason))\n );\n case \"toolResult\":\n return (\n typeof value.toolCallId === \"string\" &&\n typeof value.toolName === \"string\" &&\n Array.isArray(value.content) &&\n content(value.content, [\"text\", \"image\"]) &&\n typeof value.isError === \"boolean\"\n );\n case \"custom\":\n return (\n typeof value.customType === \"string\" &&\n content(value.content, [\"text\", \"image\"]) &&\n typeof value.display === \"boolean\"\n );\n case \"bashExecution\":\n return (\n typeof value.command === \"string\" &&\n typeof value.output === \"string\" &&\n typeof value.cancelled === \"boolean\" &&\n typeof value.truncated === \"boolean\"\n );\n case \"branchSummary\":\n return typeof value.summary === \"string\" && (value.fromId === null || typeof value.fromId === \"string\");\n case \"compactionSummary\":\n return (\n typeof value.summary === \"string\" &&\n typeof value.tokensBefore === \"number\" &&\n Number.isFinite(value.tokensBefore) &&\n value.tokensBefore >= 0\n );\n default:\n return false;\n }\n};\nconst object = (value: unknown): value is Record<string, unknown> =>\n Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n/** Stricter than Pi's repair-tolerant reader: never skip malformed lines or migrate a log. */\nexport function validateSession(bytes: Buffer) {\n if (CURRENT_SESSION_VERSION !== 3) throw new Error(\"Unaudited Pi session format; require review.\");\n const raw = text(bytes);\n if (!raw.endsWith(\"\\n\")) throw new Error(\"Incomplete session tail.\");\n const rows: unknown[] = raw\n .slice(0, -1)\n .split(\"\\n\")\n .map((line) => {\n if (line.startsWith(\"\\uFEFF\")) throw new Error(\"Unexpected session-record BOM; require review.\");\n return parseJsonObjectDocument(Buffer.from(line)).root.value;\n });\n if (rows.length > 16_384) throw new Error(\"Session entry bound exceeded.\");\n const header = rows[0];\n if (\n !object(header) ||\n header.type !== \"session\" ||\n header.version !== CURRENT_SESSION_VERSION ||\n !sessionId(header.id) ||\n typeof header.cwd !== \"string\" ||\n typeof header.timestamp !== \"string\" ||\n !Number.isFinite(Date.parse(header.timestamp)) ||\n (header.parentSession !== undefined && typeof header.parentSession !== \"string\")\n )\n throw new Error(\"Unsupported session header.\");\n const ids = new Set<string>();\n const known = (value: unknown) => id(value) && ids.has(value);\n for (const row of rows.slice(1)) {\n if (\n !object(row) ||\n !id(row.id) ||\n ids.has(row.id) ||\n typeof row.timestamp !== \"string\" ||\n !Number.isFinite(Date.parse(row.timestamp)) ||\n (row.parentId !== null && !known(row.parentId))\n )\n throw new Error(\"Invalid session graph.\");\n const strings = (...keys: string[]) => keys.every((key) => typeof row[key] === \"string\");\n let valid = false;\n switch (row.type) {\n case \"message\":\n valid = message(row.message);\n break;\n case \"thinking_level_change\":\n valid = strings(\"thinkingLevel\");\n break;\n case \"model_change\":\n valid = strings(\"provider\", \"modelId\");\n break;\n case \"usage\":\n valid = strings(\"kind\", \"provider\", \"model\") && object(row.usage);\n break;\n case \"compaction\":\n valid =\n strings(\"summary\") &&\n (known(row.firstKeptEntryId) || row.firstKeptEntryId === row.id) &&\n (row.systemMessage === undefined ||\n (object(row.systemMessage) && row.systemMessage.role === \"system\" && message(row.systemMessage))) &&\n typeof row.tokensBefore === \"number\" &&\n Number.isFinite(row.tokensBefore) &&\n row.tokensBefore >= 0;\n break;\n case \"branch_summary\":\n valid = strings(\"summary\") && (known(row.fromId) || row.fromId === \"root\");\n break;\n case \"custom\":\n valid = strings(\"customType\");\n break;\n case \"custom_message\":\n valid = strings(\"customType\") && typeof row.display === \"boolean\" && content(row.content, [\"text\", \"image\"]);\n break;\n case \"context_edit\":\n valid =\n known(row.targetId) &&\n (row.replacement === null || (object(row.replacement) && content(row.replacement.content)));\n break;\n case \"label\":\n valid = known(row.targetId) && (row.label === undefined || typeof row.label === \"string\");\n break;\n case \"session_info\":\n valid = row.name === undefined || typeof row.name === \"string\";\n break;\n }\n if (!valid) throw new Error(\"Unsupported session entry.\");\n ids.add(row.id);\n }\n return header.id;\n}\nexport function mergeSession(base: Buffer, local: Buffer, remote: Buffer): Buffer | undefined {\n try {\n const identity = validateSession(base);\n if (validateSession(local) !== identity || validateSession(remote) !== identity) return;\n const prefix = (left: Buffer, right: Buffer) =>\n right.length >= left.length && right.subarray(0, left.length).equals(left);\n if (!prefix(base, local) || !prefix(base, remote)) return;\n if (prefix(local, remote)) return remote;\n if (prefix(remote, local)) return local;\n } catch {\n return;\n }\n}\n", "import path from \"node:path\";\nexport const TEXT_LIMIT = 1024 * 1024;\nexport const TEXT_MERGE_WORK_LIMIT = 8_000_000;\nexport interface TextMergeBudget {\n remaining: number;\n}\nexport interface TextMergeOptions {\n budget?: TextMergeBudget;\n signal?: AbortSignal;\n}\nfunction charge(budget: TextMergeBudget, work: number) {\n if (work > budget.remaining) throw new Error(\"Text merge operation complexity bound exceeded.\");\n budget.remaining -= work;\n}\nexport function isMergeTextPath(filePath: string) {\n return (\n filePath === \"AGENTS.md\" ||\n (/\\.(?:md|txt)$/u.test(filePath) &&\n [\"prompts\", \"skills\"].includes(filePath.split(\"/\")[0] ?? \"\") &&\n path.posix.basename(filePath) !== \"keybindings.json\")\n );\n}\nexport function text(bytes: Buffer) {\n if (bytes.length > TEXT_LIMIT) throw new Error(\"Text merge bound exceeded.\");\n const decoded = bytes.toString(\"utf8\");\n if (\n !Buffer.from(decoded).equals(bytes) ||\n bytes.some((byte) => (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) || byte === 127)\n )\n throw new Error(\"Unsupported text encoding.\");\n return decoded;\n}\ntype Hunk = { start: number; end: number; lines: string[] };\nfunction lines(value: string) {\n return value.match(/[^\\n]*\\n|[^\\n]+$/gu) ?? [];\n}\nfunction edits(base: string[], next: string[], signal?: AbortSignal): Hunk[] {\n const width = next.length + 1;\n if ((base.length + 1) * width > 4_000_000) throw new Error(\"Text merge complexity bound exceeded.\");\n // Intern once so each charged DP cell compares fixed-size IDs, not long line strings.\n const ids = new Map<string, number>();\n const intern = (line: string) => {\n let id = ids.get(line);\n if (id === undefined) {\n id = ids.size;\n ids.set(line, id);\n }\n return id;\n };\n const baseIds = base.map(intern);\n const nextIds = next.map(intern);\n const grid = new Uint32Array((base.length + 1) * width);\n for (let i = base.length - 1; i >= 0; i--) {\n signal?.throwIfAborted();\n for (let j = next.length - 1; j >= 0; j--)\n grid[i * width + j] =\n baseIds[i] === nextIds[j]\n ? 1 + (grid[(i + 1) * width + j + 1] ?? 0)\n : Math.max(grid[(i + 1) * width + j] ?? 0, grid[i * width + j + 1] ?? 0);\n }\n const result: Hunk[] = [];\n let i = 0;\n let j = 0;\n let active: Hunk | undefined;\n while (i < base.length || j < next.length) {\n if (i < base.length && j < next.length && baseIds[i] === nextIds[j]) {\n if (active) {\n result.push(active);\n active = undefined;\n }\n i++;\n j++;\n continue;\n }\n active ??= { start: i, end: i, lines: [] };\n if (j < next.length && (i === base.length || (grid[i * width + j + 1] ?? 0) >= (grid[(i + 1) * width + j] ?? 0)))\n active.lines.push(next[j++] ?? \"\");\n else active.end = ++i;\n }\n if (active) result.push(active);\n return result;\n}\nexport function mergeText(\n baseBytes: Buffer,\n localBytes: Buffer,\n remoteBytes: Buffer,\n options: TextMergeOptions = {},\n): Buffer | undefined {\n const budget = options.budget ?? { remaining: TEXT_MERGE_WORK_LIMIT };\n try {\n options.signal?.throwIfAborted();\n const base = lines(text(baseBytes));\n const ours = lines(text(localBytes));\n const theirs = lines(text(remoteBytes));\n const cells = [ours, theirs].map((next) => (base.length + 1) * (next.length + 1));\n if (cells.some((count) => count > 4_000_000)) return;\n charge(budget, (cells[0] ?? 0) + (cells[1] ?? 0));\n const local = edits(base, ours, options.signal);\n const remote = edits(base, theirs, options.signal);\n const combined = [...local];\n for (const right of remote) {\n let same = false;\n for (const left of local) {\n options.signal?.throwIfAborted();\n charge(budget, 1);\n if (left.start === right.start && left.end === right.end && left.lines.join(\"\") === right.lines.join(\"\")) {\n same = true;\n continue;\n }\n const overlap =\n left.start === left.end || right.start === right.end\n ? left.start <= right.end && right.start <= left.end\n : left.start < right.end && right.start < left.end;\n if (overlap) return;\n }\n if (!same) combined.push(right);\n }\n combined.sort((left, right) => left.start - right.start || left.end - right.end);\n let cursor = 0;\n const output: string[] = [];\n for (const edit of combined) {\n output.push(...base.slice(cursor, edit.start), ...edit.lines);\n cursor = edit.end;\n }\n output.push(...base.slice(cursor));\n const result = Buffer.from(output.join(\"\"));\n text(result);\n return result;\n } catch {\n options.signal?.throwIfAborted();\n return;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "id", "i", "j", "identity", "path", "file"]
|
|
7
|
+
}
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
var createSyncBackend = async (config) => {
|
|
6
6
|
switch (config.backend.type) {
|
|
7
7
|
case "s3": {
|
|
8
|
-
const { S3SyncBackend } = await import("./s3-backend-
|
|
8
|
+
const { S3SyncBackend } = await import("./s3-backend-DJ2NT3SZ.ts");
|
|
9
9
|
return new S3SyncBackend(config.backend);
|
|
10
10
|
}
|
|
11
11
|
case "webdav": {
|
|
12
|
-
const { WebDavSyncBackend } = await import("./webdav-backend-
|
|
12
|
+
const { WebDavSyncBackend } = await import("./webdav-backend-ETQGSI6I.ts");
|
|
13
13
|
return new WebDavSyncBackend(config.backend);
|
|
14
14
|
}
|
|
15
15
|
case "git": {
|
|
16
|
-
const { GitSyncBackend } = await import("./git-backend-
|
|
16
|
+
const { GitSyncBackend } = await import("./git-backend-HLGKUQJT.ts");
|
|
17
17
|
return new GitSyncBackend(config.backend);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -22,4 +22,4 @@ var createSyncBackend = async (config) => {
|
|
|
22
22
|
export {
|
|
23
23
|
createSyncBackend
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
25
|
+
//# sourceMappingURL=chunk-QHSQCK7L.ts.map
|