@narumitw/pi-sync 0.57.0 → 0.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chunks/{agent-candidate-3JN6DJKT.ts → agent-candidate-GNEYR225.ts} +3 -3
- package/dist/chunks/{agent-plan-QCUJWBP4.ts → agent-plan-K3CRYVXV.ts} +3 -3
- package/dist/chunks/{chunk-FQOSHGJ7.ts → chunk-5QAE3G3K.ts} +11 -6
- package/dist/chunks/chunk-5QAE3G3K.ts.map +7 -0
- package/dist/chunks/{chunk-S2FMH5FT.ts → chunk-QOC47PBC.ts} +2 -2
- package/dist/chunks/{chunk-5Q5SSKNG.ts → chunk-S7QS4AWK.ts} +89 -2
- package/dist/chunks/chunk-S7QS4AWK.ts.map +7 -0
- package/dist/chunks/{chunk-OTZRCKYP.ts → chunk-T3NC77TU.ts} +29 -16
- package/dist/chunks/chunk-T3NC77TU.ts.map +7 -0
- package/dist/chunks/{conflict-review-6WIEQLXW.ts → conflict-review-ZCGWFKEK.ts} +3 -3
- package/dist/chunks/{continuous-sync-AWAAOXK2.ts → continuous-sync-LAIMSW7D.ts} +2 -2
- package/dist/chunks/{sync-operations-HDUDT5PD.ts → sync-operations-W5HFFMTP.ts} +3 -3
- package/dist/index.ts +4 -4
- package/package.json +4 -2
- package/skills/configure-pi-sync/references/configuration.md +1 -1
- package/src/sync/agent-candidate.ts +8 -3
- package/src/sync/merged-sync.ts +1 -1
- package/src/sync/package-merge.ts +87 -0
- package/src/sync/settings-conflicts.ts +25 -13
- package/src/sync/settings-merge.ts +48 -0
- package/dist/chunks/chunk-5Q5SSKNG.ts.map +0 -7
- package/dist/chunks/chunk-FQOSHGJ7.ts.map +0 -7
- package/dist/chunks/chunk-OTZRCKYP.ts.map +0 -7
- /package/dist/chunks/{agent-candidate-3JN6DJKT.ts.map → agent-candidate-GNEYR225.ts.map} +0 -0
- /package/dist/chunks/{agent-plan-QCUJWBP4.ts.map → agent-plan-K3CRYVXV.ts.map} +0 -0
- /package/dist/chunks/{chunk-S2FMH5FT.ts.map → chunk-QOC47PBC.ts.map} +0 -0
- /package/dist/chunks/{conflict-review-6WIEQLXW.ts.map → conflict-review-ZCGWFKEK.ts.map} +0 -0
- /package/dist/chunks/{continuous-sync-AWAAOXK2.ts.map → continuous-sync-LAIMSW7D.ts.map} +0 -0
- /package/dist/chunks/{sync-operations-HDUDT5PD.ts.map → sync-operations-W5HFFMTP.ts.map} +0 -0
package/README.md
CHANGED
|
@@ -186,7 +186,7 @@ Shutdown behavior is unchanged: when **Automatic sync** is On and sessions are i
|
|
|
186
186
|
|
|
187
187
|
**Warning:** eligible conflict text is sent to the selected Pi model and can incur costs. Accepted results can replace/delete selected local and remote content without another transfer prompt. The resolver has no tools or parent conversation, and validates candidate ownership and current versions before using the existing publication/backup/journal flow. Validation is not a guarantee of semantic correctness or lossless editing against other local processes.
|
|
188
188
|
|
|
189
|
-
The first implementation resolves bounded overlapping `AGENTS.md` and prompt/skill Markdown/plain-text edits, and selects complete atomic global settings units. Verified ancestors are required. Code, session histories, deletion conflicts and path collisions are not model-resolved; unsupported/refused work pauses, unless existing partial-sync policy permits independent progress. No resources reload automatically. Disabling stops subsequent authorization, not completed writes or provider charges. Read [Agent mode settings, limits, privacy and recovery](./skills/configure-pi-sync/references/configuration.md#experimental-agent-mode) before enabling.
|
|
189
|
+
The first implementation resolves bounded overlapping `AGENTS.md` and prompt/skill Markdown/plain-text edits, and selects complete atomic global settings units. For `settings.json` packages, it keeps the higher explicit npm SemVer version from local and remote without a registry lookup; incompatible filters and non-comparable sources retain existing conflict handling. Verified ancestors are required. Code, session histories, deletion conflicts and path collisions are not model-resolved; unsupported/refused work pauses, unless existing partial-sync policy permits independent progress. No resources reload automatically. Disabling stops subsequent authorization, not completed writes or provider charges. Read [Agent mode settings, limits, privacy and recovery](./skills/configure-pi-sync/references/configuration.md#experimental-agent-mode) before enabling.
|
|
190
190
|
|
|
191
191
|
### Experimental Continuous sync
|
|
192
192
|
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
buildAgentEvidence,
|
|
6
6
|
digest,
|
|
7
7
|
parseAgentCandidate
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-5QAE3G3K.ts";
|
|
9
|
+
import "./chunk-S7QS4AWK.ts";
|
|
10
10
|
import "./chunk-QOFMXPM5.ts";
|
|
11
11
|
import "./chunk-IWZH5KYS.ts";
|
|
12
12
|
import "./chunk-76NB4R7U.ts";
|
|
@@ -23,4 +23,4 @@ export {
|
|
|
23
23
|
digest,
|
|
24
24
|
parseAgentCandidate
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=agent-candidate-
|
|
26
|
+
//# sourceMappingURL=agent-candidate-GNEYR225.ts.map
|
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
applyAgentCandidate,
|
|
20
20
|
buildAgentEvidence,
|
|
21
21
|
digest
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-5QAE3G3K.ts";
|
|
23
|
+
import "./chunk-S7QS4AWK.ts";
|
|
24
24
|
import {
|
|
25
25
|
createSnapshot
|
|
26
26
|
} from "./chunk-QOFMXPM5.ts";
|
|
@@ -96,4 +96,4 @@ async function resolveAgentPlan(ctx, options, config, backend, state, local, loc
|
|
|
96
96
|
export {
|
|
97
97
|
resolveAgentPlan
|
|
98
98
|
};
|
|
99
|
-
//# sourceMappingURL=agent-plan-
|
|
99
|
+
//# sourceMappingURL=agent-plan-K3CRYVXV.ts.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
COUPLED_FIELDS,
|
|
5
5
|
mergeSettingsJson,
|
|
6
6
|
snapshotFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-S7QS4AWK.ts";
|
|
8
8
|
import {
|
|
9
9
|
scanSnapshot
|
|
10
10
|
} from "./chunk-QOFMXPM5.ts";
|
|
@@ -87,9 +87,13 @@ function buildAgentEvidence(plan, local, remote, ancestors) {
|
|
|
87
87
|
let units;
|
|
88
88
|
if (conflict.path === "settings.json") {
|
|
89
89
|
const documents = versions.map((value) => parseSettingsDocument(Buffer.from(value)));
|
|
90
|
-
const merge = mergeSettingsJson(
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const merge = mergeSettingsJson(
|
|
91
|
+
...versions.map((value) => Buffer.from(value)),
|
|
92
|
+
void 0,
|
|
93
|
+
true
|
|
94
|
+
);
|
|
95
|
+
if (merge.kind === "review" && merge.reason !== "field-conflict") throw new Error("unsupported settings");
|
|
96
|
+
const fields = new Set(merge.kind === "review" ? merge.fields : []);
|
|
93
97
|
const groups = COUPLED_FIELDS.map((group) => [...group]);
|
|
94
98
|
const coupled = new Set(groups.flat());
|
|
95
99
|
groups.push(...[...fields].filter((key) => !coupled.has(key)).map((key) => [key]));
|
|
@@ -187,7 +191,8 @@ function applyAgentCandidate(plan, evidence, candidate) {
|
|
|
187
191
|
Buffer.from(file.base),
|
|
188
192
|
Buffer.from(file.local),
|
|
189
193
|
Buffer.from(file.remote),
|
|
190
|
-
selections
|
|
194
|
+
selections,
|
|
195
|
+
true
|
|
191
196
|
);
|
|
192
197
|
if (merged.kind !== "merged") throw new Error("Agent settings units remain unresolved.");
|
|
193
198
|
parseSettingsDocument(merged.content);
|
|
@@ -212,4 +217,4 @@ export {
|
|
|
212
217
|
parseAgentCandidate,
|
|
213
218
|
applyAgentCandidate
|
|
214
219
|
};
|
|
215
|
-
//# sourceMappingURL=chunk-
|
|
220
|
+
//# sourceMappingURL=chunk-5QAE3G3K.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/agent-candidate.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { scanSnapshot } from \"../snapshot/snapshot.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport { AGENT_INPUT_BYTES, AGENT_MAX_UNITS, AGENT_OUTPUT_BYTES } from \"./agent-policy.js\";\nimport { snapshotFile } from \"./content-conflicts.js\";\nimport type { FileMergePlan } from \"./file-merge-planner.js\";\nimport { parseJsonObjectDocument, parseSettingsDocument } from \"./json-document.js\";\nimport { COUPLED_FIELDS, mergeSettingsJson } from \"./settings-merge.js\";\nimport { edits, type Hunk, isMergeTextPath, lines, text } from \"./text-merge.js\";\n\nexport interface AgentUnit {\n id: string;\n path: string;\n kind: \"text\" | \"settings\";\n base: string;\n local: string;\n remote: string;\n}\ninterface CandidateFile {\n path: string;\n base: string;\n local: string;\n remote: string;\n parts?: (string | AgentUnit)[];\n fields?: { id: string; key: string }[];\n}\nexport interface AgentEvidence {\n units: AgentUnit[];\n files: CandidateFile[];\n unsupported: string[];\n}\nexport interface AgentCandidate {\n version: 1;\n results: (\n | { id: string; content: string }\n | { id: string; source: \"local\" | \"remote\" }\n | { id: string; refuse: true }\n )[];\n}\nexport const digest = (value: unknown) => createHash(\"sha256\").update(JSON.stringify(value)).digest(\"hex\");\n\nfunction overlaps(a: Hunk, b: Hunk) {\n return a.start === a.end || b.start === b.end\n ? a.start <= b.end && b.start <= a.end\n : a.start < b.end && b.start < a.end;\n}\n\n/** Only overlapping edit regions are model-writable; all other bytes are assembled by code. */\nfunction textParts(filePath: string, baseText: string, localText: string, remoteText: string): (string | AgentUnit)[] {\n const base = lines(baseText);\n const changes = [\n ...edits(base, lines(localText)).map((hunk) => ({ ...hunk, side: \"local\" as const })),\n ...edits(base, lines(remoteText)).map((hunk) => ({ ...hunk, side: \"remote\" as const })),\n ].sort((a, b) => a.start - b.start || a.end - b.end);\n const clusters: (typeof changes)[] = [];\n for (const change of changes) {\n const last = clusters.at(-1);\n if (last?.some((item) => overlaps(item, change))) last.push(change);\n else clusters.push([change]);\n }\n const result: (string | AgentUnit)[] = [];\n let cursor = 0;\n for (const cluster of clusters) {\n const start = Math.min(...cluster.map((item) => item.start));\n const end = Math.max(...cluster.map((item) => item.end));\n result.push(base.slice(cursor, start).join(\"\"));\n const image = (side: \"local\" | \"remote\") => {\n let position = start;\n const output: string[] = [];\n for (const hunk of cluster.filter((item) => item.side === side)) {\n output.push(...base.slice(position, hunk.start), ...hunk.lines);\n position = hunk.end;\n }\n return [...output, ...base.slice(position, end)].join(\"\");\n };\n const local = image(\"local\");\n const remote = image(\"remote\");\n const original = base.slice(start, end).join(\"\");\n if (local === remote || local === original || remote === original) result.push(local === original ? remote : local);\n else result.push({ id: \"\", path: filePath, kind: \"text\", base: original, local, remote });\n cursor = end;\n }\n result.push(base.slice(cursor).join(\"\"));\n return result;\n}\n\nexport function buildAgentEvidence(\n plan: FileMergePlan,\n local: Snapshot,\n remote: Snapshot,\n ancestors: SnapshotFile[],\n): AgentEvidence {\n const evidence: AgentEvidence = { units: [], files: [], unsupported: [] };\n if (plan.kind !== \"planned\") return evidence;\n if (plan.conflicts.length > AGENT_MAX_UNITS)\n throw new Error(\"Agent mode paused: too many conflict paths for bounded analysis.\");\n for (const conflict of plan.conflicts) {\n try {\n if (conflict.reason !== \"both-changed\") throw new Error(\"unsupported conflict\");\n const versions = [ancestors, local.files, remote.files].map((files) => {\n const file = files.find((item) => item.path === conflict.path);\n if (!file) throw new Error(\"missing ancestor/version\");\n const bytes = Buffer.from(file.contentBase64, \"base64\");\n if (bytes.length > 8192) throw new Error(\"file bound\");\n return text(bytes);\n }) as [string, string, string];\n const [base, left, right] = versions;\n const file: CandidateFile = { path: conflict.path, base, local: left, remote: right };\n let units: AgentUnit[];\n if (conflict.path === \"settings.json\") {\n const documents = versions.map((value) => parseSettingsDocument(Buffer.from(value)));\n const merge = mergeSettingsJson(\n ...(versions.map((value) => Buffer.from(value)) as [Buffer, Buffer, Buffer]),\n undefined,\n true,\n );\n if (merge.kind === \"review\" && merge.reason !== \"field-conflict\") throw new Error(\"unsupported settings\");\n const fields = new Set(merge.kind === \"review\" ? merge.fields : []);\n const groups = COUPLED_FIELDS.map((group) => [...group] as string[]);\n const coupled = new Set(groups.flat());\n groups.push(...[...fields].filter((key) => !coupled.has(key)).map((key) => [key]));\n file.fields = [];\n units = groups\n .filter((group) => group.some((key) => fields.has(key)))\n .map((group) => {\n const values = documents.map((document) =>\n JSON.stringify(\n Object.fromEntries(\n group.flatMap((key) => {\n const node = document.root.members.get(key)?.node;\n return node ? [[key, node.value]] : [];\n }),\n ),\n ),\n );\n const unit: AgentUnit = {\n id: \"\",\n path: file.path,\n kind: \"settings\",\n base: values[0] ?? \"{}\",\n local: values[1] ?? \"{}\",\n remote: values[2] ?? \"{}\",\n };\n file.fields?.push({ id: String(evidence.units.length + file.fields.length), key: group[0] ?? \"\" });\n return unit;\n });\n } else {\n if (!isMergeTextPath(conflict.path)) throw new Error(\"unsupported path\");\n file.parts = textParts(file.path, base, left, right);\n units = file.parts.filter((part): part is AgentUnit => typeof part !== \"string\");\n }\n for (const unit of units) {\n unit.id = String(evidence.units.length);\n evidence.units.push(unit);\n }\n evidence.files.push(file);\n } catch {\n evidence.unsupported.push(conflict.path);\n }\n }\n if (evidence.units.length > AGENT_MAX_UNITS || Buffer.byteLength(JSON.stringify(evidence.units)) > AGENT_INPUT_BYTES)\n throw new Error(\"Agent mode paused: conflict evidence exceeds its input bound.\");\n // Scan only the actual disclosure image; skipSecretScan never authorizes model disclosure.\n if (\n scanSnapshot({\n ...local,\n files: evidence.units.flatMap((unit) =>\n [unit.path, unit.base, unit.local, unit.remote].map((value) => snapshotFile(unit.path, Buffer.from(value))),\n ),\n }).length\n )\n throw new Error(\"Agent mode paused: possible secrets in model evidence; nothing was disclosed.\");\n return evidence;\n}\n\nexport function parseAgentCandidate(raw: string, evidence: AgentEvidence): AgentCandidate {\n if (Buffer.byteLength(raw) > AGENT_OUTPUT_BYTES) throw new Error(\"Agent output exceeds its bound.\");\n const parsed = parseJsonObjectDocument(Buffer.from(raw)).root.value as Record<string, unknown>;\n if (\n Object.keys(parsed).sort().join(\",\") !== \"results,version\" ||\n parsed.version !== 1 ||\n !Array.isArray(parsed.results) ||\n parsed.results.length !== evidence.units.length\n )\n throw new Error(\"Invalid agent candidate contract.\");\n const seen = new Set<string>();\n for (const result of parsed.results) {\n if (!result || typeof result !== \"object\" || Array.isArray(result)) throw new Error(\"Invalid agent result.\");\n const row = result as Record<string, unknown>;\n const unit = evidence.units.find((unit) => unit.id === row.id);\n if (!unit || seen.has(unit.id)) throw new Error(\"Unowned or duplicate agent unit.\");\n seen.add(unit.id);\n const keys = Object.keys(row).sort().join(\",\");\n if (keys === \"id,refuse\" && row.refuse === true) continue;\n if (unit.kind === \"settings\" && keys === \"id,source\" && (row.source === \"local\" || row.source === \"remote\"))\n continue;\n if (unit.kind === \"text\" && keys === \"content,id\" && typeof row.content === \"string\" && row.content.length > 0) {\n text(Buffer.from(row.content));\n if (/^(?:<{7}|={7}|>{7}|\\|{7})/mu.test(row.content)) throw new Error(\"Unresolved conflict markers.\");\n continue;\n }\n throw new Error(\"Unsupported agent action.\");\n }\n return parsed as unknown as AgentCandidate;\n}\n\nexport function applyAgentCandidate(\n plan: FileMergePlan,\n evidence: AgentEvidence,\n candidate: AgentCandidate,\n): FileMergePlan {\n // Persisted candidates cross a trust boundary too.\n parseAgentCandidate(JSON.stringify(candidate), evidence);\n if (plan.kind !== \"planned\") throw new Error(\"Unverified merge plan.\");\n const results = new Map(candidate.results.map((row) => [row.id, row]));\n const replacements = new Map<string, SnapshotFile>();\n for (const file of evidence.files) {\n const units = evidence.units.filter((unit) => unit.path === file.path);\n if (units.some((unit) => results.get(unit.id) && \"refuse\" in (results.get(unit.id) ?? {}))) continue;\n let bytes: Buffer;\n if (file.parts) {\n bytes = Buffer.from(\n file.parts\n .map((part) => (typeof part === \"string\" ? part : (results.get(part.id) as { content: string }).content))\n .join(\"\"),\n );\n } else {\n const selections = new Map(\n (file.fields ?? []).map(({ id, key }) => [key, (results.get(id) as { source: \"local\" | \"remote\" }).source]),\n );\n const merged = mergeSettingsJson(\n Buffer.from(file.base),\n Buffer.from(file.local),\n Buffer.from(file.remote),\n selections,\n true,\n );\n if (merged.kind !== \"merged\") throw new Error(\"Agent settings units remain unresolved.\");\n // The existing renderer/parser retains atomic values, unknown members and exact numeric policy.\n parseSettingsDocument(merged.content);\n for (const { key } of file.fields ?? []) {\n if (!selections.has(key)) throw new Error(\"Missing atomic settings selection.\");\n }\n bytes = merged.content;\n }\n if (bytes.length > AGENT_OUTPUT_BYTES) throw new Error(\"Agent file exceeds output bound.\");\n replacements.set(file.path, snapshotFile(file.path, bytes));\n }\n const decisions = plan.decisions.map((decision) => {\n const file = replacements.get(decision.path);\n return file && decision.kind === \"conflict\"\n ? { kind: \"accepted\" as const, path: file.path, source: \"merged\" as const, file }\n : decision;\n });\n return { kind: \"planned\", decisions, conflicts: decisions.filter((item) => item.kind === \"conflict\") };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["file", "unit"]
|
|
7
|
+
}
|
|
@@ -27,7 +27,7 @@ async function withAgentSyncLock(ctx, options, run) {
|
|
|
27
27
|
request = error;
|
|
28
28
|
}
|
|
29
29
|
const { withAgentClaim, readAgentCandidate, saveAgentCandidate } = await import("./agent-store-A3F6IYWZ.ts");
|
|
30
|
-
const { parseAgentCandidate } = await import("./agent-candidate-
|
|
30
|
+
const { parseAgentCandidate } = await import("./agent-candidate-GNEYR225.ts");
|
|
31
31
|
const { runAgentResolver } = await import("./agent-runner-E2JU2VZ6.ts");
|
|
32
32
|
return withAgentClaim(async (assertOwner) => {
|
|
33
33
|
const clearStatus = () => setSyncStatus(ctx, void 0);
|
|
@@ -94,4 +94,4 @@ async function withAgentSyncLock(ctx, options, run) {
|
|
|
94
94
|
export {
|
|
95
95
|
withAgentSyncLock
|
|
96
96
|
};
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
97
|
+
//# sourceMappingURL=chunk-QOC47PBC.ts.map
|
|
@@ -74,6 +74,58 @@ async function resolveContentConflicts(config, state, local, remote, plan, prote
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// src/sync/package-merge.ts
|
|
78
|
+
import { compare, valid } from "semver";
|
|
79
|
+
function entries(value) {
|
|
80
|
+
if (!Array.isArray(value)) return void 0;
|
|
81
|
+
const result = /* @__PURE__ */ new Map();
|
|
82
|
+
for (const item of value) {
|
|
83
|
+
if (typeof item !== "string" && (!item || Array.isArray(item) || typeof item !== "object")) return void 0;
|
|
84
|
+
const source = typeof item === "string" ? item : item.source;
|
|
85
|
+
if (typeof source !== "string") return void 0;
|
|
86
|
+
const spec = source.startsWith("npm:") ? source.slice(4).trim() : void 0;
|
|
87
|
+
const match = spec?.match(/^(@?[^@]+(?:\/[^@]+)?)(?:@(.+))?$/u);
|
|
88
|
+
const key = match ? `npm:${match[1]}` : source;
|
|
89
|
+
if (result.has(key)) return void 0;
|
|
90
|
+
const options = typeof item === "string" ? null : Object.fromEntries(Object.entries(item).filter(([key2]) => key2 !== "source"));
|
|
91
|
+
result.set(key, { value: item, options, version: match?.[2] });
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
function mergePackageVersions(base, local, remote) {
|
|
96
|
+
const ancestor = entries(base ?? []);
|
|
97
|
+
const left = entries(local);
|
|
98
|
+
const right = entries(remote);
|
|
99
|
+
if (!ancestor || !left || !right) return void 0;
|
|
100
|
+
const otherEntries = (items) => [...items].filter(([key]) => !key.startsWith("npm:")).map(([, entry]) => entry.value);
|
|
101
|
+
if (!jsonEqual(otherEntries(ancestor), otherEntries(left)) || !jsonEqual(otherEntries(ancestor), otherEntries(right)))
|
|
102
|
+
return void 0;
|
|
103
|
+
const baseKeys = [...ancestor.keys()];
|
|
104
|
+
const leftKeys = [...left.keys()];
|
|
105
|
+
const rightKeys = [...right.keys()];
|
|
106
|
+
const order = jsonEqual(leftKeys, rightKeys) ? leftKeys : jsonEqual(leftKeys, baseKeys) ? rightKeys : jsonEqual(rightKeys, baseKeys) ? leftKeys : void 0;
|
|
107
|
+
if (!order) return void 0;
|
|
108
|
+
const output = [];
|
|
109
|
+
for (const key of /* @__PURE__ */ new Set([...order, ...baseKeys])) {
|
|
110
|
+
const a = ancestor.get(key);
|
|
111
|
+
const l = left.get(key);
|
|
112
|
+
const r = right.get(key);
|
|
113
|
+
let chosen;
|
|
114
|
+
if (l && r && key.startsWith("npm:") && l.version && r.version && valid(l.version) && valid(r.version) && jsonEqual(l.options, r.options)) {
|
|
115
|
+
const precedence = compare(l.version, r.version);
|
|
116
|
+
if (precedence !== 0) chosen = precedence > 0 ? l : r;
|
|
117
|
+
}
|
|
118
|
+
if (!chosen) {
|
|
119
|
+
if (jsonEqual(l?.value, r?.value)) chosen = l;
|
|
120
|
+
else if (jsonEqual(l?.value, a?.value)) chosen = r;
|
|
121
|
+
else if (jsonEqual(r?.value, a?.value)) chosen = l;
|
|
122
|
+
else return void 0;
|
|
123
|
+
}
|
|
124
|
+
if (chosen) output.push(chosen.value);
|
|
125
|
+
}
|
|
126
|
+
return output;
|
|
127
|
+
}
|
|
128
|
+
|
|
77
129
|
// src/sync/settings-merge.ts
|
|
78
130
|
var COUPLED_FIELDS = [
|
|
79
131
|
["defaultProvider", "defaultModel"],
|
|
@@ -82,7 +134,34 @@ var COUPLED_FIELDS = [
|
|
|
82
134
|
["skills", "enableSkillCommands"],
|
|
83
135
|
["enableAnalytics", "trackingId"]
|
|
84
136
|
];
|
|
85
|
-
function
|
|
137
|
+
function selectPackages(base, left, right) {
|
|
138
|
+
const packages = mergePackageVersions(
|
|
139
|
+
base.root.members.get("packages")?.node.value,
|
|
140
|
+
left.root.members.get("packages")?.node.value,
|
|
141
|
+
right.root.members.get("packages")?.node.value
|
|
142
|
+
);
|
|
143
|
+
if (!packages) return void 0;
|
|
144
|
+
const document = [left, right].find((source) => jsonEqual(source.root.members.get("packages")?.node.value, packages)) ?? parseSettingsDocument(Buffer.from(JSON.stringify({ packages })));
|
|
145
|
+
const node = document.root.members.get("packages")?.node;
|
|
146
|
+
return node ? { document, node } : void 0;
|
|
147
|
+
}
|
|
148
|
+
function mergeAcceptedSettingsPackages(ancestor, local, remote, accepted) {
|
|
149
|
+
try {
|
|
150
|
+
const base = parseSettingsDocument(ancestor);
|
|
151
|
+
const left = parseSettingsDocument(local);
|
|
152
|
+
const right = parseSettingsDocument(remote);
|
|
153
|
+
const document = parseSettingsDocument(accepted);
|
|
154
|
+
const packages = selectPackages(base, left, right);
|
|
155
|
+
if (!packages || jsonEqual(packages.node.value, document.root.members.get("packages")?.node.value))
|
|
156
|
+
return void 0;
|
|
157
|
+
const selected = new Map([...document.root.members].map(([key, member]) => [key, { document, node: member.node }]));
|
|
158
|
+
selected.set("packages", packages);
|
|
159
|
+
return renderSettingsMembers(document, selected);
|
|
160
|
+
} catch {
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function mergeSettingsJson(ancestor, local, remote, selections = /* @__PURE__ */ new Map(), preferHigherPackageVersions = false) {
|
|
86
165
|
let documents;
|
|
87
166
|
try {
|
|
88
167
|
documents = [ancestor, local, remote].map(parseSettingsDocument);
|
|
@@ -97,6 +176,13 @@ function mergeSettingsJson(ancestor, local, remote, selections = /* @__PURE__ */
|
|
|
97
176
|
units.push(...[...fields].filter((field) => !coupled.has(field)).map((field) => [field]));
|
|
98
177
|
const conflicts = [];
|
|
99
178
|
for (const unit of units) {
|
|
179
|
+
if (preferHigherPackageVersions && unit[0] === "packages") {
|
|
180
|
+
const packages = selectPackages(base, left, right);
|
|
181
|
+
if (packages) {
|
|
182
|
+
selected.set("packages", packages);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
100
186
|
const equal = (first, second) => unit.every(
|
|
101
187
|
(field) => jsonEqual(first.root.members.get(field)?.node.value, second.root.members.get(field)?.node.value)
|
|
102
188
|
);
|
|
@@ -123,6 +209,7 @@ export {
|
|
|
123
209
|
snapshotFile,
|
|
124
210
|
resolveContentConflicts,
|
|
125
211
|
COUPLED_FIELDS,
|
|
212
|
+
mergeAcceptedSettingsPackages,
|
|
126
213
|
mergeSettingsJson
|
|
127
214
|
};
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
215
|
+
//# sourceMappingURL=chunk-S7QS4AWK.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/sync/content-conflicts.ts", "../../src/sync/package-merge.ts", "../../src/sync/settings-merge.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport { readMergeAncestors } from \"../state/merge-baseline-store.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { type FileMergePlan, mergePathIdentity } from \"./file-merge-planner.js\";\nimport { mergeSession } from \"./session-merge.js\";\nimport { isMergeTextPath, mergeText, TEXT_MERGE_WORK_LIMIT, type TextMergeBudget } from \"./text-merge.js\";\nexport function snapshotFile(filePath: string, bytes: Buffer): SnapshotFile {\n return {\n path: filePath,\n contentBase64: bytes.toString(\"base64\"),\n sha256: createHash(\"sha256\").update(bytes).digest(\"hex\"),\n };\n}\nexport async function resolveContentConflicts(\n config: AnySyncConfig,\n state: SyncState,\n local: Snapshot,\n remote: Snapshot,\n plan: FileMergePlan,\n protectedPaths: ReadonlySet<string>,\n options: { textBudget?: TextMergeBudget; signal?: AbortSignal } = {},\n): Promise<FileMergePlan> {\n if (plan.kind !== \"planned\" || !config.mergeContent) return plan;\n options.signal?.throwIfAborted();\n const budget = options.textBudget ?? { remaining: TEXT_MERGE_WORK_LIMIT };\n const decisions = [...plan.decisions];\n let ancestors: SnapshotFile[] = [];\n try {\n ancestors = (await readMergeAncestors(config, state)) ?? [];\n } catch {\n options.signal?.throwIfAborted();\n return plan;\n }\n options.signal?.throwIfAborted();\n const oursByPath = new Map(local.files.map((file) => [file.path, file]));\n const theirsByPath = new Map(remote.files.map((file) => [file.path, file]));\n const ancestorsByPath = new Map(ancestors.map((file) => [file.path, file]));\n const decisionIndex = new Map(decisions.map((decision, index) => [decision.path, index]));\n const protectedKeys = new Set([...protectedPaths].map(mergePathIdentity));\n for (const conflict of plan.conflicts) {\n options.signal?.throwIfAborted();\n if (conflict.reason !== \"both-changed\" || protectedKeys.has(mergePathIdentity(conflict.path))) continue;\n const session = conflict.path.startsWith(\"sessions/\") && conflict.path.endsWith(\".jsonl\");\n if (!session && (!isMergeTextPath(conflict.path) || budget.remaining === 0)) continue;\n const ours = oursByPath.get(conflict.path);\n const theirs = theirsByPath.get(conflict.path);\n if (!ours || !theirs) continue;\n const ancestor = ancestorsByPath.get(conflict.path);\n const base = ancestor ? Buffer.from(ancestor.contentBase64, \"base64\") : undefined;\n if (!base) continue;\n const localBytes = Buffer.from(ours.contentBase64, \"base64\");\n const remoteBytes = Buffer.from(theirs.contentBase64, \"base64\");\n const bytes = session\n ? mergeSession(base, localBytes, remoteBytes)\n : mergeText(base, localBytes, remoteBytes, { budget, signal: options.signal });\n if (!bytes) continue;\n const index = decisionIndex.get(conflict.path);\n if (index === undefined) continue;\n decisions[index] = {\n kind: \"accepted\",\n path: conflict.path,\n source: \"merged\",\n file: snapshotFile(conflict.path, bytes),\n };\n }\n return {\n kind: \"planned\",\n decisions,\n conflicts: decisions.filter((item): item is Extract<typeof item, { kind: \"conflict\" }> => item.kind === \"conflict\"),\n };\n}\n", "import { compare, valid } from \"semver\";\nimport { type JsonValue, jsonEqual } from \"./json-document.js\";\n\ninterface Entry {\n value: JsonValue;\n version?: string;\n options: JsonValue;\n}\n\nfunction entries(value: JsonValue | undefined): Map<string, Entry> | undefined {\n if (!Array.isArray(value)) return undefined;\n const result = new Map<string, Entry>();\n for (const item of value) {\n if (typeof item !== \"string\" && (!item || Array.isArray(item) || typeof item !== \"object\")) return undefined;\n const source = typeof item === \"string\" ? item : item.source;\n if (typeof source !== \"string\") return undefined;\n const spec = source.startsWith(\"npm:\") ? source.slice(4).trim() : undefined;\n const match = spec?.match(/^(@?[^@]+(?:\\/[^@]+)?)(?:@(.+))?$/u);\n const key = match ? `npm:${match[1]}` : source;\n if (result.has(key)) return undefined;\n const options =\n typeof item === \"string\" ? null : Object.fromEntries(Object.entries(item).filter(([key]) => key !== \"source\"));\n result.set(key, { value: item, options, version: match?.[2] });\n }\n return result;\n}\n\n/** Compare only explicit npm versions; do not resolve ranges, tags, Git refs or registry state. */\nexport function mergePackageVersions(\n base: JsonValue | undefined,\n local: JsonValue | undefined,\n remote: JsonValue | undefined,\n): JsonValue[] | undefined {\n const ancestor = entries(base ?? []);\n const left = entries(local);\n const right = entries(remote);\n if (!ancestor || !left || !right) return undefined;\n // Raw Git refs and local path aliases do not prove distinct package identities.\n // Leave changes to those sources under the existing atomic field policy.\n const otherEntries = (items: Map<string, Entry>) =>\n [...items].filter(([key]) => !key.startsWith(\"npm:\")).map(([, entry]) => entry.value);\n if (!jsonEqual(otherEntries(ancestor), otherEntries(left)) || !jsonEqual(otherEntries(ancestor), otherEntries(right)))\n return undefined;\n\n // Package order affects resource precedence. Merge the ordered identity list\n // atomically, then select versions without changing that order.\n const baseKeys = [...ancestor.keys()];\n const leftKeys = [...left.keys()];\n const rightKeys = [...right.keys()];\n const order = jsonEqual(leftKeys, rightKeys)\n ? leftKeys\n : jsonEqual(leftKeys, baseKeys)\n ? rightKeys\n : jsonEqual(rightKeys, baseKeys)\n ? leftKeys\n : undefined;\n if (!order) return undefined;\n const output: JsonValue[] = [];\n for (const key of new Set([...order, ...baseKeys])) {\n const a = ancestor.get(key);\n const l = left.get(key);\n const r = right.get(key);\n let chosen: Entry | undefined;\n if (\n l &&\n r &&\n key.startsWith(\"npm:\") &&\n l.version &&\n r.version &&\n valid(l.version) &&\n valid(r.version) &&\n jsonEqual(l.options, r.options)\n ) {\n const precedence = compare(l.version, r.version);\n if (precedence !== 0) chosen = precedence > 0 ? l : r;\n }\n // Build metadata and equivalent version spelling do not establish a higher version.\n if (!chosen) {\n if (jsonEqual(l?.value, r?.value)) chosen = l;\n else if (jsonEqual(l?.value, a?.value)) chosen = r;\n else if (jsonEqual(r?.value, a?.value)) chosen = l;\n else return undefined;\n }\n if (chosen) output.push(chosen.value);\n }\n return output;\n}\n", "import {\n type JsonDocument,\n type JsonNode,\n jsonEqual,\n parseSettingsDocument,\n renderSettingsMembers,\n} from \"./json-document.js\";\n\nimport { mergePackageVersions } from \"./package-merge.js\";\n\nexport type SettingsMergeResult =\n | { kind: \"merged\"; content: Buffer }\n | { kind: \"review\"; reason: \"unsupported-format\" | \"field-conflict\"; fields: string[] };\n\nexport const COUPLED_FIELDS = [\n [\"defaultProvider\", \"defaultModel\"],\n [\"queueMode\", \"steeringMode\"],\n [\"websockets\", \"transport\"],\n [\"skills\", \"enableSkillCommands\"],\n [\"enableAnalytics\", \"trackingId\"],\n] as const;\n\nfunction selectPackages(base: JsonDocument, left: JsonDocument, right: JsonDocument) {\n const packages = mergePackageVersions(\n base.root.members.get(\"packages\")?.node.value,\n left.root.members.get(\"packages\")?.node.value,\n right.root.members.get(\"packages\")?.node.value,\n );\n if (!packages) return undefined;\n const document =\n [left, right].find((source) => jsonEqual(source.root.members.get(\"packages\")?.node.value, packages)) ??\n parseSettingsDocument(Buffer.from(JSON.stringify({ packages })));\n const node = document.root.members.get(\"packages\")?.node;\n return node ? { document, node } : undefined;\n}\n\n/** Accepted files need only a package override, not another full-document field merge. */\nexport function mergeAcceptedSettingsPackages(\n ancestor: Buffer,\n local: Buffer,\n remote: Buffer,\n accepted: Buffer,\n): Buffer | undefined {\n try {\n const base = parseSettingsDocument(ancestor);\n const left = parseSettingsDocument(local);\n const right = parseSettingsDocument(remote);\n const document = parseSettingsDocument(accepted);\n const packages = selectPackages(base, left, right);\n if (!packages || jsonEqual(packages.node.value, document.root.members.get(\"packages\")?.node.value))\n return undefined;\n const selected = new Map([...document.root.members].map(([key, member]) => [key, { document, node: member.node }]));\n selected.set(\"packages\", packages);\n return renderSettingsMembers(document, selected);\n } catch {\n // Unsupported settings must not replace an accepted file with a reconstructed document.\n return undefined;\n }\n}\n\n/** Only global settings.json; objects/arrays are atomic units until their invariants are proven. */\nexport function mergeSettingsJson(\n ancestor: Buffer,\n local: Buffer,\n remote: Buffer,\n selections: ReadonlyMap<string, \"local\" | \"remote\"> = new Map(),\n preferHigherPackageVersions = false,\n): SettingsMergeResult {\n let documents: JsonDocument[];\n try {\n documents = [ancestor, local, remote].map(parseSettingsDocument);\n } catch {\n return { kind: \"review\", reason: \"unsupported-format\", fields: [] };\n }\n const [base, left, right] = documents as [JsonDocument, JsonDocument, JsonDocument];\n const selected = new Map<string, { document: JsonDocument; node: JsonNode }>();\n const fields = new Set(documents.flatMap((document) => [...document.root.members.keys()]));\n const units: string[][] = COUPLED_FIELDS.map((group) => [...group]);\n const coupled = new Set(units.flat());\n units.push(...[...fields].filter((field) => !coupled.has(field)).map((field) => [field]));\n const conflicts: string[] = [];\n for (const unit of units) {\n if (preferHigherPackageVersions && unit[0] === \"packages\") {\n const packages = selectPackages(base, left, right);\n if (packages) {\n selected.set(\"packages\", packages);\n continue;\n }\n }\n const equal = (first: JsonDocument, second: JsonDocument) =>\n unit.every((field) =>\n jsonEqual(first.root.members.get(field)?.node.value, second.root.members.get(field)?.node.value),\n );\n const choice = selections.get(unit[0] ?? \"\");\n const source = equal(left, right)\n ? left\n : equal(left, base)\n ? right\n : equal(right, base)\n ? left\n : choice === \"local\"\n ? left\n : choice === \"remote\"\n ? right\n : undefined;\n if (!source) {\n conflicts.push(...unit.filter((field) => fields.has(field)));\n continue;\n }\n for (const field of unit) {\n const member = source.root.members.get(field);\n if (member) selected.set(field, { document: source, node: member.node });\n }\n }\n if (conflicts.length) return { kind: \"review\", reason: \"field-conflict\", fields: conflicts };\n try {\n return { kind: \"merged\", content: renderSettingsMembers(left, selected) };\n } catch {\n return { kind: \"review\", reason: \"unsupported-format\", fields: [] };\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAQpB,SAAS,aAAa,UAAkB,OAA6B;AAC1E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,MAAM,SAAS,QAAQ;AAAA,IACtC,QAAQ,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,EACzD;AACF;AACA,eAAsB,wBACpB,QACA,OACA,OACA,QACA,MACA,gBACA,UAAkE,CAAC,GAC3C;AACxB,MAAI,KAAK,SAAS,aAAa,CAAC,OAAO,aAAc,QAAO;AAC5D,UAAQ,QAAQ,eAAe;AAC/B,QAAM,SAAS,QAAQ,cAAc,EAAE,WAAW,sBAAsB;AACxE,QAAM,YAAY,CAAC,GAAG,KAAK,SAAS;AACpC,MAAI,YAA4B,CAAC;AACjC,MAAI;AACF,gBAAa,MAAM,mBAAmB,QAAQ,KAAK,KAAM,CAAC;AAAA,EAC5D,QAAQ;AACN,YAAQ,QAAQ,eAAe;AAC/B,WAAO;AAAA,EACT;AACA,UAAQ,QAAQ,eAAe;AAC/B,QAAM,aAAa,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AACvE,QAAM,eAAe,IAAI,IAAI,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAC1E,QAAM,kBAAkB,IAAI,IAAI,UAAU,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAC1E,QAAM,gBAAgB,IAAI,IAAI,UAAU,IAAI,CAAC,UAAU,UAAU,CAAC,SAAS,MAAM,KAAK,CAAC,CAAC;AACxF,QAAM,gBAAgB,IAAI,IAAI,CAAC,GAAG,cAAc,EAAE,IAAI,iBAAiB,CAAC;AACxE,aAAW,YAAY,KAAK,WAAW;AACrC,YAAQ,QAAQ,eAAe;AAC/B,QAAI,SAAS,WAAW,kBAAkB,cAAc,IAAI,kBAAkB,SAAS,IAAI,CAAC,EAAG;AAC/F,UAAM,UAAU,SAAS,KAAK,WAAW,WAAW,KAAK,SAAS,KAAK,SAAS,QAAQ;AACxF,QAAI,CAAC,YAAY,CAAC,gBAAgB,SAAS,IAAI,KAAK,OAAO,cAAc,GAAI;AAC7E,UAAM,OAAO,WAAW,IAAI,SAAS,IAAI;AACzC,UAAM,SAAS,aAAa,IAAI,SAAS,IAAI;AAC7C,QAAI,CAAC,QAAQ,CAAC,OAAQ;AACtB,UAAM,WAAW,gBAAgB,IAAI,SAAS,IAAI;AAClD,UAAM,OAAO,WAAW,OAAO,KAAK,SAAS,eAAe,QAAQ,IAAI;AACxE,QAAI,CAAC,KAAM;AACX,UAAM,aAAa,OAAO,KAAK,KAAK,eAAe,QAAQ;AAC3D,UAAM,cAAc,OAAO,KAAK,OAAO,eAAe,QAAQ;AAC9D,UAAM,QAAQ,UACV,aAAa,MAAM,YAAY,WAAW,IAC1C,UAAU,MAAM,YAAY,aAAa,EAAE,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAC/E,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,cAAc,IAAI,SAAS,IAAI;AAC7C,QAAI,UAAU,OAAW;AACzB,cAAU,KAAK,IAAI;AAAA,MACjB,MAAM;AAAA,MACN,MAAM,SAAS;AAAA,MACf,QAAQ;AAAA,MACR,MAAM,aAAa,SAAS,MAAM,KAAK;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,WAAW,UAAU,OAAO,CAAC,SAA6D,KAAK,SAAS,UAAU;AAAA,EACpH;AACF;;;ACxEA,SAAS,SAAS,aAAa;AAS/B,SAAS,QAAQ,OAA8D;AAC7E,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,QAAM,SAAS,oBAAI,IAAmB;AACtC,aAAW,QAAQ,OAAO;AACxB,QAAI,OAAO,SAAS,aAAa,CAAC,QAAQ,MAAM,QAAQ,IAAI,KAAK,OAAO,SAAS,UAAW,QAAO;AACnG,UAAM,SAAS,OAAO,SAAS,WAAW,OAAO,KAAK;AACtD,QAAI,OAAO,WAAW,SAAU,QAAO;AACvC,UAAM,OAAO,OAAO,WAAW,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,IAAI;AAClE,UAAM,QAAQ,MAAM,MAAM,oCAAoC;AAC9D,UAAM,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,KAAK;AACxC,QAAI,OAAO,IAAI,GAAG,EAAG,QAAO;AAC5B,UAAM,UACJ,OAAO,SAAS,WAAW,OAAO,OAAO,YAAY,OAAO,QAAQ,IAAI,EAAE,OAAO,CAAC,CAACA,IAAG,MAAMA,SAAQ,QAAQ,CAAC;AAC/G,WAAO,IAAI,KAAK,EAAE,OAAO,MAAM,SAAS,SAAS,QAAQ,CAAC,EAAE,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAGO,SAAS,qBACd,MACA,OACA,QACyB;AACzB,QAAM,WAAW,QAAQ,QAAQ,CAAC,CAAC;AACnC,QAAM,OAAO,QAAQ,KAAK;AAC1B,QAAM,QAAQ,QAAQ,MAAM;AAC5B,MAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAO,QAAO;AAGzC,QAAM,eAAe,CAAC,UACpB,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,WAAW,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,MAAM,KAAK;AACtF,MAAI,CAAC,UAAU,aAAa,QAAQ,GAAG,aAAa,IAAI,CAAC,KAAK,CAAC,UAAU,aAAa,QAAQ,GAAG,aAAa,KAAK,CAAC;AAClH,WAAO;AAIT,QAAM,WAAW,CAAC,GAAG,SAAS,KAAK,CAAC;AACpC,QAAM,WAAW,CAAC,GAAG,KAAK,KAAK,CAAC;AAChC,QAAM,YAAY,CAAC,GAAG,MAAM,KAAK,CAAC;AAClC,QAAM,QAAQ,UAAU,UAAU,SAAS,IACvC,WACA,UAAU,UAAU,QAAQ,IAC1B,YACA,UAAU,WAAW,QAAQ,IAC3B,WACA;AACR,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,SAAsB,CAAC;AAC7B,aAAW,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG;AAClD,UAAM,IAAI,SAAS,IAAI,GAAG;AAC1B,UAAM,IAAI,KAAK,IAAI,GAAG;AACtB,UAAM,IAAI,MAAM,IAAI,GAAG;AACvB,QAAI;AACJ,QACE,KACA,KACA,IAAI,WAAW,MAAM,KACrB,EAAE,WACF,EAAE,WACF,MAAM,EAAE,OAAO,KACf,MAAM,EAAE,OAAO,KACf,UAAU,EAAE,SAAS,EAAE,OAAO,GAC9B;AACA,YAAM,aAAa,QAAQ,EAAE,SAAS,EAAE,OAAO;AAC/C,UAAI,eAAe,EAAG,UAAS,aAAa,IAAI,IAAI;AAAA,IACtD;AAEA,QAAI,CAAC,QAAQ;AACX,UAAI,UAAU,GAAG,OAAO,GAAG,KAAK,EAAG,UAAS;AAAA,eACnC,UAAU,GAAG,OAAO,GAAG,KAAK,EAAG,UAAS;AAAA,eACxC,UAAU,GAAG,OAAO,GAAG,KAAK,EAAG,UAAS;AAAA,UAC5C,QAAO;AAAA,IACd;AACA,QAAI,OAAQ,QAAO,KAAK,OAAO,KAAK;AAAA,EACtC;AACA,SAAO;AACT;;;ACxEO,IAAM,iBAAiB;AAAA,EAC5B,CAAC,mBAAmB,cAAc;AAAA,EAClC,CAAC,aAAa,cAAc;AAAA,EAC5B,CAAC,cAAc,WAAW;AAAA,EAC1B,CAAC,UAAU,qBAAqB;AAAA,EAChC,CAAC,mBAAmB,YAAY;AAClC;AAEA,SAAS,eAAe,MAAoB,MAAoB,OAAqB;AACnF,QAAM,WAAW;AAAA,IACf,KAAK,KAAK,QAAQ,IAAI,UAAU,GAAG,KAAK;AAAA,IACxC,KAAK,KAAK,QAAQ,IAAI,UAAU,GAAG,KAAK;AAAA,IACxC,MAAM,KAAK,QAAQ,IAAI,UAAU,GAAG,KAAK;AAAA,EAC3C;AACA,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,WACJ,CAAC,MAAM,KAAK,EAAE,KAAK,CAAC,WAAW,UAAU,OAAO,KAAK,QAAQ,IAAI,UAAU,GAAG,KAAK,OAAO,QAAQ,CAAC,KACnG,sBAAsB,OAAO,KAAK,KAAK,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AACjE,QAAM,OAAO,SAAS,KAAK,QAAQ,IAAI,UAAU,GAAG;AACpD,SAAO,OAAO,EAAE,UAAU,KAAK,IAAI;AACrC;AAGO,SAAS,8BACd,UACA,OACA,QACA,UACoB;AACpB,MAAI;AACF,UAAM,OAAO,sBAAsB,QAAQ;AAC3C,UAAM,OAAO,sBAAsB,KAAK;AACxC,UAAM,QAAQ,sBAAsB,MAAM;AAC1C,UAAM,WAAW,sBAAsB,QAAQ;AAC/C,UAAM,WAAW,eAAe,MAAM,MAAM,KAAK;AACjD,QAAI,CAAC,YAAY,UAAU,SAAS,KAAK,OAAO,SAAS,KAAK,QAAQ,IAAI,UAAU,GAAG,KAAK,KAAK;AAC/F,aAAO;AACT,UAAM,WAAW,IAAI,IAAI,CAAC,GAAG,SAAS,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,EAAE,UAAU,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC;AAClH,aAAS,IAAI,YAAY,QAAQ;AACjC,WAAO,sBAAsB,UAAU,QAAQ;AAAA,EACjD,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,kBACd,UACA,OACA,QACA,aAAsD,oBAAI,IAAI,GAC9D,8BAA8B,OACT;AACrB,MAAI;AACJ,MAAI;AACF,gBAAY,CAAC,UAAU,OAAO,MAAM,EAAE,IAAI,qBAAqB;AAAA,EACjE,QAAQ;AACN,WAAO,EAAE,MAAM,UAAU,QAAQ,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACpE;AACA,QAAM,CAAC,MAAM,MAAM,KAAK,IAAI;AAC5B,QAAM,WAAW,oBAAI,IAAwD;AAC7E,QAAM,SAAS,IAAI,IAAI,UAAU,QAAQ,CAAC,aAAa,CAAC,GAAG,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC;AACzF,QAAM,QAAoB,eAAe,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;AAClE,QAAM,UAAU,IAAI,IAAI,MAAM,KAAK,CAAC;AACpC,QAAM,KAAK,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACxF,QAAM,YAAsB,CAAC;AAC7B,aAAW,QAAQ,OAAO;AACxB,QAAI,+BAA+B,KAAK,CAAC,MAAM,YAAY;AACzD,YAAM,WAAW,eAAe,MAAM,MAAM,KAAK;AACjD,UAAI,UAAU;AACZ,iBAAS,IAAI,YAAY,QAAQ;AACjC;AAAA,MACF;AAAA,IACF;AACA,UAAM,QAAQ,CAAC,OAAqB,WAClC,KAAK;AAAA,MAAM,CAAC,UACV,UAAU,MAAM,KAAK,QAAQ,IAAI,KAAK,GAAG,KAAK,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,GAAG,KAAK,KAAK;AAAA,IACjG;AACF,UAAM,SAAS,WAAW,IAAI,KAAK,CAAC,KAAK,EAAE;AAC3C,UAAM,SAAS,MAAM,MAAM,KAAK,IAC5B,OACA,MAAM,MAAM,IAAI,IACd,QACA,MAAM,OAAO,IAAI,IACf,OACA,WAAW,UACT,OACA,WAAW,WACT,QACA;AACZ,QAAI,CAAC,QAAQ;AACX,gBAAU,KAAK,GAAG,KAAK,OAAO,CAAC,UAAU,OAAO,IAAI,KAAK,CAAC,CAAC;AAC3D;AAAA,IACF;AACA,eAAW,SAAS,MAAM;AACxB,YAAM,SAAS,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC5C,UAAI,OAAQ,UAAS,IAAI,OAAO,EAAE,UAAU,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,IACzE;AAAA,EACF;AACA,MAAI,UAAU,OAAQ,QAAO,EAAE,MAAM,UAAU,QAAQ,kBAAkB,QAAQ,UAAU;AAC3F,MAAI;AACF,WAAO,EAAE,MAAM,UAAU,SAAS,sBAAsB,MAAM,QAAQ,EAAE;AAAA,EAC1E,QAAQ;AACN,WAAO,EAAE,MAAM,UAAU,QAAQ,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACpE;AACF;",
|
|
6
|
+
"names": ["key"]
|
|
7
|
+
}
|
|
@@ -66,9 +66,10 @@ import {
|
|
|
66
66
|
expectedRemoteHead
|
|
67
67
|
} from "./chunk-YDVQYUHE.ts";
|
|
68
68
|
import {
|
|
69
|
+
mergeAcceptedSettingsPackages,
|
|
69
70
|
mergeSettingsJson,
|
|
70
71
|
resolveContentConflicts
|
|
71
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-S7QS4AWK.ts";
|
|
72
73
|
import {
|
|
73
74
|
agentDir,
|
|
74
75
|
createSnapshot,
|
|
@@ -1025,21 +1026,33 @@ async function resolveSettingsConflicts(config, state, local, remote, plan) {
|
|
|
1025
1026
|
const decisions = [...plan.decisions];
|
|
1026
1027
|
for (let index = 0; index < decisions.length; index++) {
|
|
1027
1028
|
const decision = decisions[index];
|
|
1028
|
-
if (decision?.
|
|
1029
|
-
|
|
1029
|
+
if (decision?.path !== "settings.json") continue;
|
|
1030
|
+
if (decision.kind === "conflict" ? decision.reason !== "both-changed" : !config.agentMode) continue;
|
|
1030
1031
|
const left = local.files.find((file) => file.path === decision.path);
|
|
1031
1032
|
const right = remote.files.find((file) => file.path === decision.path);
|
|
1032
1033
|
if (!left || !right) continue;
|
|
1033
1034
|
const ancestor = await readMergeAncestor(config, state, decision.path);
|
|
1034
1035
|
if (!ancestor) continue;
|
|
1035
|
-
const
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1036
|
+
const leftBytes = Buffer.from(left.contentBase64, "base64");
|
|
1037
|
+
const rightBytes = Buffer.from(right.contentBase64, "base64");
|
|
1038
|
+
let content;
|
|
1039
|
+
if (decision.kind === "accepted") {
|
|
1040
|
+
if (!decision.file) continue;
|
|
1041
|
+
const patched = mergeAcceptedSettingsPackages(
|
|
1042
|
+
ancestor,
|
|
1043
|
+
leftBytes,
|
|
1044
|
+
rightBytes,
|
|
1045
|
+
Buffer.from(decision.file.contentBase64, "base64")
|
|
1046
|
+
);
|
|
1047
|
+
if (!patched) continue;
|
|
1048
|
+
content = patched;
|
|
1049
|
+
} else {
|
|
1050
|
+
const merged = mergeSettingsJson(ancestor, leftBytes, rightBytes, void 0, Boolean(config.agentMode));
|
|
1051
|
+
if (merged.kind === "review") {
|
|
1052
|
+
fields.push(...merged.fields);
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
content = merged.content;
|
|
1043
1056
|
}
|
|
1044
1057
|
decisions[index] = {
|
|
1045
1058
|
kind: "accepted",
|
|
@@ -1047,8 +1060,8 @@ async function resolveSettingsConflicts(config, state, local, remote, plan) {
|
|
|
1047
1060
|
source: "merged",
|
|
1048
1061
|
file: {
|
|
1049
1062
|
path: decision.path,
|
|
1050
|
-
contentBase64:
|
|
1051
|
-
sha256: createHash3("sha256").update(
|
|
1063
|
+
contentBase64: content.toString("base64"),
|
|
1064
|
+
sha256: createHash3("sha256").update(content).digest("hex")
|
|
1052
1065
|
}
|
|
1053
1066
|
};
|
|
1054
1067
|
}
|
|
@@ -1409,7 +1422,7 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1409
1422
|
);
|
|
1410
1423
|
await validate();
|
|
1411
1424
|
let resolved = { plan, fields: [] };
|
|
1412
|
-
if (config.mergeSettings) {
|
|
1425
|
+
if (config.mergeSettings || config.agentMode) {
|
|
1413
1426
|
try {
|
|
1414
1427
|
resolved = await timings.measure(
|
|
1415
1428
|
"transfer settings merge",
|
|
@@ -1443,7 +1456,7 @@ async function mergeSync(ctx, options, factory = createSyncBackend, resolution)
|
|
|
1443
1456
|
await validate();
|
|
1444
1457
|
}
|
|
1445
1458
|
if (config.agentMode && !resolution) {
|
|
1446
|
-
const { resolveAgentPlan } = await import("./agent-plan-
|
|
1459
|
+
const { resolveAgentPlan } = await import("./agent-plan-K3CRYVXV.ts");
|
|
1447
1460
|
await validate();
|
|
1448
1461
|
plan = await resolveAgentPlan(
|
|
1449
1462
|
ctx,
|
|
@@ -1937,4 +1950,4 @@ export {
|
|
|
1937
1950
|
createSyncDecision,
|
|
1938
1951
|
mergeSync
|
|
1939
1952
|
};
|
|
1940
|
-
//# sourceMappingURL=chunk-
|
|
1953
|
+
//# sourceMappingURL=chunk-T3NC77TU.ts.map
|