@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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{agent-candidate-3JN6DJKT.ts → agent-candidate-GNEYR225.ts} +3 -3
  3. package/dist/chunks/{agent-plan-QCUJWBP4.ts → agent-plan-K3CRYVXV.ts} +3 -3
  4. package/dist/chunks/{chunk-FQOSHGJ7.ts → chunk-5QAE3G3K.ts} +11 -6
  5. package/dist/chunks/chunk-5QAE3G3K.ts.map +7 -0
  6. package/dist/chunks/{chunk-S2FMH5FT.ts → chunk-QOC47PBC.ts} +2 -2
  7. package/dist/chunks/{chunk-5Q5SSKNG.ts → chunk-S7QS4AWK.ts} +89 -2
  8. package/dist/chunks/chunk-S7QS4AWK.ts.map +7 -0
  9. package/dist/chunks/{chunk-OTZRCKYP.ts → chunk-T3NC77TU.ts} +29 -16
  10. package/dist/chunks/chunk-T3NC77TU.ts.map +7 -0
  11. package/dist/chunks/{conflict-review-6WIEQLXW.ts → conflict-review-ZCGWFKEK.ts} +3 -3
  12. package/dist/chunks/{continuous-sync-AWAAOXK2.ts → continuous-sync-LAIMSW7D.ts} +2 -2
  13. package/dist/chunks/{sync-operations-HDUDT5PD.ts → sync-operations-W5HFFMTP.ts} +3 -3
  14. package/dist/index.ts +4 -4
  15. package/package.json +4 -2
  16. package/skills/configure-pi-sync/references/configuration.md +1 -1
  17. package/src/sync/agent-candidate.ts +8 -3
  18. package/src/sync/merged-sync.ts +1 -1
  19. package/src/sync/package-merge.ts +87 -0
  20. package/src/sync/settings-conflicts.ts +25 -13
  21. package/src/sync/settings-merge.ts +48 -0
  22. package/dist/chunks/chunk-5Q5SSKNG.ts.map +0 -7
  23. package/dist/chunks/chunk-FQOSHGJ7.ts.map +0 -7
  24. package/dist/chunks/chunk-OTZRCKYP.ts.map +0 -7
  25. /package/dist/chunks/{agent-candidate-3JN6DJKT.ts.map → agent-candidate-GNEYR225.ts.map} +0 -0
  26. /package/dist/chunks/{agent-plan-QCUJWBP4.ts.map → agent-plan-K3CRYVXV.ts.map} +0 -0
  27. /package/dist/chunks/{chunk-S2FMH5FT.ts.map → chunk-QOC47PBC.ts.map} +0 -0
  28. /package/dist/chunks/{conflict-review-6WIEQLXW.ts.map → conflict-review-ZCGWFKEK.ts.map} +0 -0
  29. /package/dist/chunks/{continuous-sync-AWAAOXK2.ts.map → continuous-sync-LAIMSW7D.ts.map} +0 -0
  30. /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-FQOSHGJ7.ts";
9
- import "./chunk-5Q5SSKNG.ts";
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-3JN6DJKT.ts.map
26
+ //# sourceMappingURL=agent-candidate-GNEYR225.ts.map
@@ -19,8 +19,8 @@ import {
19
19
  applyAgentCandidate,
20
20
  buildAgentEvidence,
21
21
  digest
22
- } from "./chunk-FQOSHGJ7.ts";
23
- import "./chunk-5Q5SSKNG.ts";
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-QCUJWBP4.ts.map
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-5Q5SSKNG.ts";
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(...versions.map((value) => Buffer.from(value)));
91
- if (merge.kind !== "review" || merge.reason !== "field-conflict") throw new Error("unsupported settings");
92
- const fields = new Set(merge.fields);
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-FQOSHGJ7.ts.map
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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAuCpB,IAAM,SAAS,CAAC,UAAmB,WAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,KAAK,CAAC,EAAE,OAAO,KAAK;AAEzG,SAAS,SAAS,GAAS,GAAS;AAClC,SAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MACtC,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MACjC,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;AACrC;AAGA,SAAS,UAAU,UAAkB,UAAkB,WAAmB,YAA4C;AACpH,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU;AAAA,IACd,GAAG,MAAM,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,QAAiB,EAAE;AAAA,IACpF,GAAG,MAAM,MAAM,MAAM,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,MAAM,SAAkB,EAAE;AAAA,EACxF,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG;AACnD,QAAM,WAA+B,CAAC;AACtC,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,SAAS,GAAG,EAAE;AAC3B,QAAI,MAAM,KAAK,CAAC,SAAS,SAAS,MAAM,MAAM,CAAC,EAAG,MAAK,KAAK,MAAM;AAAA,QAC7D,UAAS,KAAK,CAAC,MAAM,CAAC;AAAA,EAC7B;AACA,QAAM,SAAiC,CAAC;AACxC,MAAI,SAAS;AACb,aAAW,WAAW,UAAU;AAC9B,UAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAC3D,UAAM,MAAM,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,SAAS,KAAK,GAAG,CAAC;AACvD,WAAO,KAAK,KAAK,MAAM,QAAQ,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9C,UAAM,QAAQ,CAAC,SAA6B;AAC1C,UAAI,WAAW;AACf,YAAM,SAAmB,CAAC;AAC1B,iBAAW,QAAQ,QAAQ,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG;AAC/D,eAAO,KAAK,GAAG,KAAK,MAAM,UAAU,KAAK,KAAK,GAAG,GAAG,KAAK,KAAK;AAC9D,mBAAW,KAAK;AAAA,MAClB;AACA,aAAO,CAAC,GAAG,QAAQ,GAAG,KAAK,MAAM,UAAU,GAAG,CAAC,EAAE,KAAK,EAAE;AAAA,IAC1D;AACA,UAAM,QAAQ,MAAM,OAAO;AAC3B,UAAM,SAAS,MAAM,QAAQ;AAC7B,UAAM,WAAW,KAAK,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE;AAC/C,QAAI,UAAU,UAAU,UAAU,YAAY,WAAW,SAAU,QAAO,KAAK,UAAU,WAAW,SAAS,KAAK;AAAA,QAC7G,QAAO,KAAK,EAAE,IAAI,IAAI,MAAM,UAAU,MAAM,QAAQ,MAAM,UAAU,OAAO,OAAO,CAAC;AACxF,aAAS;AAAA,EACX;AACA,SAAO,KAAK,KAAK,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;AACvC,SAAO;AACT;AAEO,SAAS,mBACd,MACA,OACA,QACA,WACe;AACf,QAAM,WAA0B,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE;AACxE,MAAI,KAAK,SAAS,UAAW,QAAO;AACpC,MAAI,KAAK,UAAU,SAAS;AAC1B,UAAM,IAAI,MAAM,kEAAkE;AACpF,aAAW,YAAY,KAAK,WAAW;AACrC,QAAI;AACF,UAAI,SAAS,WAAW,eAAgB,OAAM,IAAI,MAAM,sBAAsB;AAC9E,YAAM,WAAW,CAAC,WAAW,MAAM,OAAO,OAAO,KAAK,EAAE,IAAI,CAAC,UAAU;AACrE,cAAMA,QAAO,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,IAAI;AAC7D,YAAI,CAACA,MAAM,OAAM,IAAI,MAAM,0BAA0B;AACrD,cAAM,QAAQ,OAAO,KAAKA,MAAK,eAAe,QAAQ;AACtD,YAAI,MAAM,SAAS,KAAM,OAAM,IAAI,MAAM,YAAY;AACrD,eAAO,KAAK,KAAK;AAAA,MACnB,CAAC;AACD,YAAM,CAAC,MAAM,MAAM,KAAK,IAAI;AAC5B,YAAM,OAAsB,EAAE,MAAM,SAAS,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM;AACpF,UAAI;AACJ,UAAI,SAAS,SAAS,iBAAiB;AACrC,cAAM,YAAY,SAAS,IAAI,CAAC,UAAU,sBAAsB,OAAO,KAAK,KAAK,CAAC,CAAC;AACnF,cAAM,QAAQ;AAAA,UACZ,GAAI,SAAS,IAAI,CAAC,UAAU,OAAO,KAAK,KAAK,CAAC;AAAA,UAC9C;AAAA,UACA;AAAA,QACF;AACA,YAAI,MAAM,SAAS,YAAY,MAAM,WAAW,iBAAkB,OAAM,IAAI,MAAM,sBAAsB;AACxG,cAAM,SAAS,IAAI,IAAI,MAAM,SAAS,WAAW,MAAM,SAAS,CAAC,CAAC;AAClE,cAAM,SAAS,eAAe,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAa;AACnE,cAAM,UAAU,IAAI,IAAI,OAAO,KAAK,CAAC;AACrC,eAAO,KAAK,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACjF,aAAK,SAAS,CAAC;AACf,gBAAQ,OACL,OAAO,CAAC,UAAU,MAAM,KAAK,CAAC,QAAQ,OAAO,IAAI,GAAG,CAAC,CAAC,EACtD,IAAI,CAAC,UAAU;AACd,gBAAM,SAAS,UAAU;AAAA,YAAI,CAAC,aAC5B,KAAK;AAAA,cACH,OAAO;AAAA,gBACL,MAAM,QAAQ,CAAC,QAAQ;AACrB,wBAAM,OAAO,SAAS,KAAK,QAAQ,IAAI,GAAG,GAAG;AAC7C,yBAAO,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC;AAAA,gBACvC,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF;AACA,gBAAM,OAAkB;AAAA,YACtB,IAAI;AAAA,YACJ,MAAM,KAAK;AAAA,YACX,MAAM;AAAA,YACN,MAAM,OAAO,CAAC,KAAK;AAAA,YACnB,OAAO,OAAO,CAAC,KAAK;AAAA,YACpB,QAAQ,OAAO,CAAC,KAAK;AAAA,UACvB;AACA,eAAK,QAAQ,KAAK,EAAE,IAAI,OAAO,SAAS,MAAM,SAAS,KAAK,OAAO,MAAM,GAAG,KAAK,MAAM,CAAC,KAAK,GAAG,CAAC;AACjG,iBAAO;AAAA,QACT,CAAC;AAAA,MACL,OAAO;AACL,YAAI,CAAC,gBAAgB,SAAS,IAAI,EAAG,OAAM,IAAI,MAAM,kBAAkB;AACvE,aAAK,QAAQ,UAAU,KAAK,MAAM,MAAM,MAAM,KAAK;AACnD,gBAAQ,KAAK,MAAM,OAAO,CAAC,SAA4B,OAAO,SAAS,QAAQ;AAAA,MACjF;AACA,iBAAW,QAAQ,OAAO;AACxB,aAAK,KAAK,OAAO,SAAS,MAAM,MAAM;AACtC,iBAAS,MAAM,KAAK,IAAI;AAAA,MAC1B;AACA,eAAS,MAAM,KAAK,IAAI;AAAA,IAC1B,QAAQ;AACN,eAAS,YAAY,KAAK,SAAS,IAAI;AAAA,IACzC;AAAA,EACF;AACA,MAAI,SAAS,MAAM,SAAS,mBAAmB,OAAO,WAAW,KAAK,UAAU,SAAS,KAAK,CAAC,IAAI;AACjG,UAAM,IAAI,MAAM,+DAA+D;AAEjF,MACE,aAAa;AAAA,IACX,GAAG;AAAA,IACH,OAAO,SAAS,MAAM;AAAA,MAAQ,CAAC,SAC7B,CAAC,KAAK,MAAM,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,EAAE,IAAI,CAAC,UAAU,aAAa,KAAK,MAAM,OAAO,KAAK,KAAK,CAAC,CAAC;AAAA,IAC5G;AAAA,EACF,CAAC,EAAE;AAEH,UAAM,IAAI,MAAM,+EAA+E;AACjG,SAAO;AACT;AAEO,SAAS,oBAAoB,KAAa,UAAyC;AACxF,MAAI,OAAO,WAAW,GAAG,IAAI,mBAAoB,OAAM,IAAI,MAAM,iCAAiC;AAClG,QAAM,SAAS,wBAAwB,OAAO,KAAK,GAAG,CAAC,EAAE,KAAK;AAC9D,MACE,OAAO,KAAK,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,qBACzC,OAAO,YAAY,KACnB,CAAC,MAAM,QAAQ,OAAO,OAAO,KAC7B,OAAO,QAAQ,WAAW,SAAS,MAAM;AAEzC,UAAM,IAAI,MAAM,mCAAmC;AACrD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,UAAU,OAAO,SAAS;AACnC,QAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,EAAG,OAAM,IAAI,MAAM,uBAAuB;AAC3G,UAAM,MAAM;AACZ,UAAM,OAAO,SAAS,MAAM,KAAK,CAACC,UAASA,MAAK,OAAO,IAAI,EAAE;AAC7D,QAAI,CAAC,QAAQ,KAAK,IAAI,KAAK,EAAE,EAAG,OAAM,IAAI,MAAM,kCAAkC;AAClF,SAAK,IAAI,KAAK,EAAE;AAChB,UAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG;AAC7C,QAAI,SAAS,eAAe,IAAI,WAAW,KAAM;AACjD,QAAI,KAAK,SAAS,cAAc,SAAS,gBAAgB,IAAI,WAAW,WAAW,IAAI,WAAW;AAChG;AACF,QAAI,KAAK,SAAS,UAAU,SAAS,gBAAgB,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS,GAAG;AAC9G,WAAK,OAAO,KAAK,IAAI,OAAO,CAAC;AAC7B,UAAI,8BAA8B,KAAK,IAAI,OAAO,EAAG,OAAM,IAAI,MAAM,8BAA8B;AACnG;AAAA,IACF;AACA,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,oBACd,MACA,UACA,WACe;AAEf,sBAAoB,KAAK,UAAU,SAAS,GAAG,QAAQ;AACvD,MAAI,KAAK,SAAS,UAAW,OAAM,IAAI,MAAM,wBAAwB;AACrE,QAAM,UAAU,IAAI,IAAI,UAAU,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;AACrE,QAAM,eAAe,oBAAI,IAA0B;AACnD,aAAW,QAAQ,SAAS,OAAO;AACjC,UAAM,QAAQ,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,KAAK,IAAI;AACrE,QAAI,MAAM,KAAK,CAAC,SAAS,QAAQ,IAAI,KAAK,EAAE,KAAK,aAAa,QAAQ,IAAI,KAAK,EAAE,KAAK,CAAC,EAAE,EAAG;AAC5F,QAAI;AACJ,QAAI,KAAK,OAAO;AACd,cAAQ,OAAO;AAAA,QACb,KAAK,MACF,IAAI,CAAC,SAAU,OAAO,SAAS,WAAW,OAAQ,QAAQ,IAAI,KAAK,EAAE,EAA0B,OAAQ,EACvG,KAAK,EAAE;AAAA,MACZ;AAAA,IACF,OAAO;AACL,YAAM,aAAa,IAAI;AAAA,SACpB,KAAK,UAAU,CAAC,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,MAAM,CAAC,KAAM,QAAQ,IAAI,EAAE,EAAqC,MAAM,CAAC;AAAA,MAC5G;AACA,YAAM,SAAS;AAAA,QACb,OAAO,KAAK,KAAK,IAAI;AAAA,QACrB,OAAO,KAAK,KAAK,KAAK;AAAA,QACtB,OAAO,KAAK,KAAK,MAAM;AAAA,QACvB;AAAA,QACA;AAAA,MACF;AACA,UAAI,OAAO,SAAS,SAAU,OAAM,IAAI,MAAM,yCAAyC;AAEvF,4BAAsB,OAAO,OAAO;AACpC,iBAAW,EAAE,IAAI,KAAK,KAAK,UAAU,CAAC,GAAG;AACvC,YAAI,CAAC,WAAW,IAAI,GAAG,EAAG,OAAM,IAAI,MAAM,oCAAoC;AAAA,MAChF;AACA,cAAQ,OAAO;AAAA,IACjB;AACA,QAAI,MAAM,SAAS,mBAAoB,OAAM,IAAI,MAAM,kCAAkC;AACzF,iBAAa,IAAI,KAAK,MAAM,aAAa,KAAK,MAAM,KAAK,CAAC;AAAA,EAC5D;AACA,QAAM,YAAY,KAAK,UAAU,IAAI,CAAC,aAAa;AACjD,UAAM,OAAO,aAAa,IAAI,SAAS,IAAI;AAC3C,WAAO,QAAQ,SAAS,SAAS,aAC7B,EAAE,MAAM,YAAqB,MAAM,KAAK,MAAM,QAAQ,UAAmB,KAAK,IAC9E;AAAA,EACN,CAAC;AACD,SAAO,EAAE,MAAM,WAAW,WAAW,WAAW,UAAU,OAAO,CAAC,SAAS,KAAK,SAAS,UAAU,EAAE;AACvG;",
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-3JN6DJKT.ts");
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-S2FMH5FT.ts.map
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 mergeSettingsJson(ancestor, local, remote, selections = /* @__PURE__ */ new Map()) {
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-5Q5SSKNG.ts.map
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-5Q5SSKNG.ts";
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?.kind !== "conflict" || decision.reason !== "both-changed" || decision.path !== "settings.json")
1029
- continue;
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 merged = mergeSettingsJson(
1036
- ancestor,
1037
- Buffer.from(left.contentBase64, "base64"),
1038
- Buffer.from(right.contentBase64, "base64")
1039
- );
1040
- if (merged.kind === "review") {
1041
- fields.push(...merged.fields);
1042
- continue;
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: merged.content.toString("base64"),
1051
- sha256: createHash3("sha256").update(merged.content).digest("hex")
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-QCUJWBP4.ts");
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-OTZRCKYP.ts.map
1953
+ //# sourceMappingURL=chunk-T3NC77TU.ts.map