@gitkraken/conflict-tools 0.7.1-beta.1 → 0.7.1-beta.2

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/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Changed
11
+
12
+ - Merge conflicts now get `<upstream-commits>` fetched by the resolver: when `refs` are set and `upstreamCommits` is undefined, it lists the incoming branch's commits for the file (`base..theirs`), and the system prompt explains the block. Hosts that name no `operation` keep the old behavior. (#217)
13
+
10
14
  ## [0.7.0] - 2026-10-27
11
15
 
12
16
  ### Added
package/README.md CHANGED
@@ -215,7 +215,9 @@ interface ResolutionContext {
215
215
  /** Git operation being resolved; omitted and `merge` preserve the default merge prompt. */
216
216
  operation?: 'merge' | 'rebase' | 'cherry-pick';
217
217
  commitMessage?: string;
218
- /** Upstream commits that touched this file since the fork point, one `<short-sha> <subject>` per line. */
218
+ /** Upstream commits that touched this file since the fork point, one `<short-sha> <subject>` per line.
219
+ * When `refs` and `operation` are given and this is undefined, the resolver fetches `base..ours -- file` for
220
+ * rebase/cherry-pick and `base..theirs -- file` for merge; hosts only set it to override. */
219
221
  upstreamCommits?: string;
220
222
  prDescription?: string;
221
223
  previousResolutions?: Resolution[];
@@ -2,7 +2,9 @@ function e(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`
2
2
 
3
3
  You will receive a file with conflict markers. ${a.sides}, and optionally a "base" (common ancestor).${o?`
4
4
 
5
- Code that upstream removed stays removed. The <commit-message> block is the message of the replayed commit; when both sides implemented the same change differently, prefer upstream unless that message states the opposite. The <upstream-commits> block lists commits on the upstream side that touched this file since the fork point, one <short-sha> <subject> per line.`:``}
5
+ Code that upstream removed stays removed. The <commit-message> block is the message of the replayed commit; when both sides implemented the same change differently, prefer upstream unless that message states the opposite. The <upstream-commits> block lists commits on the upstream side that touched this file since the fork point, one <short-sha> <subject> per line.`:`
6
+
7
+ The <upstream-commits> block, when present, lists commits on the incoming branch that touched this file since the merge base, one <short-sha> <subject> per line. Read it before deciding what the incoming side intended.`}
6
8
 
7
9
  When provided, the "Three-way diffs" section shows what each side changed relative to the common ancestor. Prefer resolving from this data and the conflict markers. Use the tools (show_file_at_ref, grep, blame, diff, log, show) only when the provided context is insufficient.
8
10
 
@@ -1 +1 @@
1
- import{ConflictGitPortMissingOpError as e}from"../ports/git.js";import{log as t,mergeBase as n}from"../git/port-dispatch.js";import{toFileFinding as r}from"../validation/findings.js";import{resolveChunkContent as i}from"../resolution/chunk-apply.js";import{createResolution as a}from"../resolution/create-resolution.js";import{mergeUsages as o}from"../resolution/metrics.js";import{checkResidualMarkers as s}from"../validation/markers.js";import{matchFileGuidance as c}from"./file-guidance.js";import{runResolverLoop as l}from"./loop.js";import{lostAdditionFinding as u,lostAdditions as d,refineInstructions as f}from"./lost-additions.js";import{runRefinePass as p}from"./refine-pass.js";import{buildThreeWayDiff as m}from"./three-way-diff.js";const h={refineNoAction:.6,refineApplied:.9};async function g(e,t,n,g=[e.filePath]){let v={...t,fileGuidance:c(t.fileGuidance,g)},y=v;if(v.refs){let t=(v.operation===`rebase`||v.operation===`cherry-pick`)&&v.upstreamCommits===void 0,r=v.threeWayDiff??await m(e.filePath,v.refs,{git:n.git,signal:n.signal}),i=t?await _(e.filePath,v.refs,n):v.upstreamCommits;y={...v,threeWayDiff:r,...i===void 0?{}:{upstreamCommits:i}}}let{chunks:b,strategy:x,confidence:S,description:C,metrics:w,followUpInstructions:T}=await l(e,y,{model:n.model,git:n.git,config:n.config,onProgress:n.onProgress,signal:n.signal}),E=a(e,b,{confidence:S,description:C,metrics:w,...x?{fileStrategy:x}:{},...y.threeWayDiff?{threeWayDiff:y.threeWayDiff}:{}}),D=(t,r)=>{let i=y.threeWayDiff;if(e.type!==`text`||!i)return[];let a=[...d(i.oursDiff,`ours`,r),...d(i.theirsDiff,`theirs`,r)];for(let r of a)n.onProgress?.({type:`refine:lost-addition`,filePath:e.filePath,side:r.side,startLine:r.startLine,endLine:r.endLine,lines:r.lines.length,phase:t});return a},O=f(T,D(`before-refine`,E.content));if(e.type===`text`&&O.length>0){n.onProgress?.({type:`refine:started`,filePath:e.filePath});let t=0;try{let r=await p(E.content,E.description,O,{model:n.model,signal:n.signal,temperature:n.config?.temperature,refineMaxSteps:n.config?.refineMaxSteps,modelCallTimeoutMs:n.config?.modelCallTimeoutMs,fileGuidance:y.fileGuidance,onProgress:n.onProgress,filePath:e.filePath});if(r.edits.length>0){let i=s(e.filePath,r.content);if(i.valid)E={...E,content:r.content,edits:r.edits,strategy:`ai`},t=r.edits.length;else{let t=(i.issues??[]).map(e=>e.message).join(` `);n.onProgress?.({type:`refine:discarded`,filePath:e.filePath,reason:`Edits introduced conflict markers: ${t}`})}}if(t>0){E={...E,confidence:Math.min(E.confidence,h.refineApplied)};let t=[];for(let n=0;n<e.markers.length;n++){let a=e.markers[n];if(!a||a.userResolution==null)continue;let o=i({markerIndex:n,...a.userResolution},a);o!==``&&(r.content.includes(o)||t.push(n))}t.length>0&&(n.onProgress?.({type:`refine:touched-user-region`,filePath:e.filePath,markerIndexes:t}),E={...E,note:`Refine modified user-resolved region(s): marker ${t.join(`, `)}.`})}else r.edits.length===0&&r.verifies>0||(E={...E,confidence:Math.min(E.confidence,h.refineNoAction)});if(r.usage){let e=o(E.metrics??{inputTokens:0,outputTokens:0},r.usage);E={...E,metrics:{...E.metrics,...e}}}n.onProgress?.({type:`refine:completed`,filePath:e.filePath,appliedCount:t})}catch(t){if(n.signal?.aborted)throw t;let r=t instanceof Error?t.message:String(t);n.onProgress?.({type:`refine:failed`,filePath:e.filePath,reason:r}),E={...E,confidence:Math.min(E.confidence,h.refineNoAction)}}}else n.onProgress?.({type:`refine:skipped`,filePath:e.filePath,reason:`no-follow-ups`});let k=D(`after-refine`,E.content);if(k.length>0&&(E={...E,findings:[...E.findings??[],...k.map(t=>u(t,e.filePath))]}),n.validator&&e.type===`text`)try{let t=await n.validator.validate(new Map([[e.filePath,E.content]]),n.signal);t.length>0&&(E={...E,findings:[...E.findings??[],...t.map(r)]})}catch(t){if(n.signal?.aborted)throw t;let r=t instanceof Error?t.message:String(t);n.onProgress?.({type:`validation:failed`,filePath:e.filePath,reason:r})}return n.onProgress?.({type:`resolver:completed`,filePath:e.filePath,stepCount:w.stepCount??0}),E}async function _(r,i,a){try{let e=i.base??await n(a.git,i.ours,i.theirs,{signal:a.signal});return await t(a.git,{ref:`${e}..${i.ours}`,path:r,signal:a.signal})}catch(t){if(a.signal?.aborted||!(t instanceof e))throw t;return}}export{h as CONFIDENCE_CAPS,g as resolveConflict};
1
+ import{ConflictGitPortMissingOpError as e}from"../ports/git.js";import{log as t,mergeBase as n}from"../git/port-dispatch.js";import{toFileFinding as r}from"../validation/findings.js";import{resolveChunkContent as i}from"../resolution/chunk-apply.js";import{createResolution as a}from"../resolution/create-resolution.js";import{mergeUsages as o}from"../resolution/metrics.js";import{checkResidualMarkers as s}from"../validation/markers.js";import{matchFileGuidance as c}from"./file-guidance.js";import{runResolverLoop as l}from"./loop.js";import{lostAdditionFinding as u,lostAdditions as d,refineInstructions as f}from"./lost-additions.js";import{runRefinePass as p}from"./refine-pass.js";import{buildThreeWayDiff as m}from"./three-way-diff.js";const h={refineNoAction:.6,refineApplied:.9};async function g(e,t,n,g=[e.filePath]){let v={...t,fileGuidance:c(t.fileGuidance,g)},y=v;if(v.refs){let t=v.operation!==void 0&&v.upstreamCommits===void 0,r=v.threeWayDiff??await m(e.filePath,v.refs,{git:n.git,signal:n.signal}),i=t?await _(e.filePath,v.refs,v.operation===`merge`?v.refs.theirs:v.refs.ours,n):v.upstreamCommits;y={...v,threeWayDiff:r,...i===void 0?{}:{upstreamCommits:i}}}let{chunks:b,strategy:x,confidence:S,description:C,metrics:w,followUpInstructions:T}=await l(e,y,{model:n.model,git:n.git,config:n.config,onProgress:n.onProgress,signal:n.signal}),E=a(e,b,{confidence:S,description:C,metrics:w,...x?{fileStrategy:x}:{},...y.threeWayDiff?{threeWayDiff:y.threeWayDiff}:{}}),D=(t,r)=>{let i=y.threeWayDiff;if(e.type!==`text`||!i)return[];let a=[...d(i.oursDiff,`ours`,r),...d(i.theirsDiff,`theirs`,r)];for(let r of a)n.onProgress?.({type:`refine:lost-addition`,filePath:e.filePath,side:r.side,startLine:r.startLine,endLine:r.endLine,lines:r.lines.length,phase:t});return a},O=f(T,D(`before-refine`,E.content));if(e.type===`text`&&O.length>0){n.onProgress?.({type:`refine:started`,filePath:e.filePath});let t=0;try{let r=await p(E.content,E.description,O,{model:n.model,signal:n.signal,temperature:n.config?.temperature,refineMaxSteps:n.config?.refineMaxSteps,modelCallTimeoutMs:n.config?.modelCallTimeoutMs,fileGuidance:y.fileGuidance,onProgress:n.onProgress,filePath:e.filePath});if(r.edits.length>0){let i=s(e.filePath,r.content);if(i.valid)E={...E,content:r.content,edits:r.edits,strategy:`ai`},t=r.edits.length;else{let t=(i.issues??[]).map(e=>e.message).join(` `);n.onProgress?.({type:`refine:discarded`,filePath:e.filePath,reason:`Edits introduced conflict markers: ${t}`})}}if(t>0){E={...E,confidence:Math.min(E.confidence,h.refineApplied)};let t=[];for(let n=0;n<e.markers.length;n++){let a=e.markers[n];if(!a||a.userResolution==null)continue;let o=i({markerIndex:n,...a.userResolution},a);o!==``&&(r.content.includes(o)||t.push(n))}t.length>0&&(n.onProgress?.({type:`refine:touched-user-region`,filePath:e.filePath,markerIndexes:t}),E={...E,note:`Refine modified user-resolved region(s): marker ${t.join(`, `)}.`})}else r.edits.length===0&&r.verifies>0||(E={...E,confidence:Math.min(E.confidence,h.refineNoAction)});if(r.usage){let e=o(E.metrics??{inputTokens:0,outputTokens:0},r.usage);E={...E,metrics:{...E.metrics,...e}}}n.onProgress?.({type:`refine:completed`,filePath:e.filePath,appliedCount:t})}catch(t){if(n.signal?.aborted)throw t;let r=t instanceof Error?t.message:String(t);n.onProgress?.({type:`refine:failed`,filePath:e.filePath,reason:r}),E={...E,confidence:Math.min(E.confidence,h.refineNoAction)}}}else n.onProgress?.({type:`refine:skipped`,filePath:e.filePath,reason:`no-follow-ups`});let k=D(`after-refine`,E.content);if(k.length>0&&(E={...E,findings:[...E.findings??[],...k.map(t=>u(t,e.filePath))]}),n.validator&&e.type===`text`)try{let t=await n.validator.validate(new Map([[e.filePath,E.content]]),n.signal);t.length>0&&(E={...E,findings:[...E.findings??[],...t.map(r)]})}catch(t){if(n.signal?.aborted)throw t;let r=t instanceof Error?t.message:String(t);n.onProgress?.({type:`validation:failed`,filePath:e.filePath,reason:r})}return n.onProgress?.({type:`resolver:completed`,filePath:e.filePath,stepCount:w.stepCount??0}),E}async function _(r,i,a,o){try{let e=i.base??await n(o.git,i.ours,i.theirs,{signal:o.signal});return await t(o.git,{ref:`${e}..${a}`,path:r,signal:o.signal})}catch(t){if(o.signal?.aborted||!(t instanceof e))throw t;return}}export{h as CONFIDENCE_CAPS,g as resolveConflict};
@@ -86,7 +86,7 @@ interface ResolutionContext {
86
86
  /** Git operation being resolved; omitted and `merge` preserve the default merge prompt. */
87
87
  operation?: 'merge' | 'rebase' | 'cherry-pick';
88
88
  commitMessage?: string;
89
- /** Upstream commits that touched this file since the fork point, one `<short-sha> <subject>` per line. */
89
+ /** Upstream commits that touched this file since the fork point, one `<short-sha> <subject>` per line. Fetched for rebase/cherry-pick (`base..ours`) and merge (`base..theirs`) when `refs` and `operation` are set and this is undefined. */
90
90
  upstreamCommits?: string;
91
91
  prDescription?: string;
92
92
  previousResolutions?: Resolution[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitkraken/conflict-tools",
3
- "version": "0.7.1-beta.1",
3
+ "version": "0.7.1-beta.2",
4
4
  "description": "AI-powered git conflict resolution.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Axosoft, LLC dba GitKraken",