@gitkraken/conflict-tools 0.2.0 → 0.2.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/CHANGELOG.md +9 -0
- package/dist/index.d.ts +2 -2
- package/dist/resolution/create-resolution.d.ts +3 -1
- package/dist/resolution/create-resolution.js +1 -1
- package/dist/resolution/raw-signals.d.ts +12 -0
- package/dist/resolution/raw-signals.js +3 -0
- package/dist/resolver/loop.js +1 -1
- package/dist/resolver/resolve-conflict.js +1 -1
- package/dist/resolver/three-way-diff.d.ts +4 -2
- package/dist/resolver/three-way-diff.js +2 -1
- package/dist/types/resolution.d.ts +28 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-06-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `Resolution.rawSignals?: ResolutionRawSignals` exposes policy-free measurements of a conflict and its resolution (conflict type, line counts per side, marker statistics, step/retry counts) for consumers to feed into their own assessment logic.
|
|
15
|
+
- Exported `ResolutionRawSignals` and `DiffStats` types from the package root.
|
|
16
|
+
- `ThreeWayDiff` gained optional `oursStats?: DiffStats` and `theirsStats?: DiffStats`, carrying parsed insertion/deletion counts per side.
|
|
17
|
+
- `ResolutionMetrics.retryCount?: number` tracks re-prompts after parse/validation/verification failures, excluding tool-call steps.
|
|
18
|
+
|
|
10
19
|
## [0.2.0] - 2026-06-02
|
|
11
20
|
|
|
12
21
|
### Added
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ConflictError, ConflictErrorCode } from "./errors/conflict.js";
|
|
|
3
3
|
import { BlameOptions, ConflictDiffOptions, ConflictGitOps, ConflictGitPort, ConflictGitPortMissingOpError, GrepOptions, LogOptions, OpOptions, ShowFileOptions, ShowOptions, UnmergedEntry, UnmergedReason } from "./ports/git.js";
|
|
4
4
|
import { IntraFileEditOp } from "./types/hints.js";
|
|
5
5
|
import { Issue } from "./types/issue.js";
|
|
6
|
-
import { Resolution, ResolutionContext, ResolutionMetrics, ResolutionRefs, ResolutionStrategy, ResolvedChunk, ThreeWayDiff } from "./types/resolution.js";
|
|
6
|
+
import { DiffStats, Resolution, ResolutionContext, ResolutionMetrics, ResolutionRawSignals, ResolutionRefs, ResolutionStrategy, ResolvedChunk, ThreeWayDiff } from "./types/resolution.js";
|
|
7
7
|
import { Conflict, ConflictMarker, ConflictMarkerUserInput, ConflictType } from "./types/conflict.js";
|
|
8
8
|
import { extractConflict } from "./extraction/extract.js";
|
|
9
9
|
import { checkoutFile, removeFile, show } from "./git/port-dispatch.js";
|
|
@@ -17,4 +17,4 @@ import { ConflictProgressEvent } from "./types/events.js";
|
|
|
17
17
|
import { resolveConflict } from "./resolver/resolve-conflict.js";
|
|
18
18
|
import { FileRule, StepConfig, StepResult } from "./types/step.js";
|
|
19
19
|
import { resolveConflicts } from "./resolver/resolve-conflicts.js";
|
|
20
|
-
export { AIError, type AIErrorCode, type BlameOptions, type Conflict, type ConflictDiffOptions, ConflictError, type ConflictErrorCode, type ConflictGitOps, type ConflictGitPort, ConflictGitPortMissingOpError, type ConflictMarker, type ConflictMarkerUserInput, type ConflictModelMessage, type ConflictModelParams, type ConflictModelPort, type ConflictModelResult, type ConflictProgressEvent, type ConflictType, type FileRule, type GrepOptions, type IntraFileEditOp, type Issue, type LogOptions, type OpOptions, type Resolution, type ResolutionContext, type ResolutionMetrics, type ResolutionRefs, type ResolutionStrategy, type ResolutionVerifier, type ResolvedChunk, type ResolverConfig, type ShowFileOptions, type ShowOptions, type StepConfig, type StepResult, type ThreeWayDiff, type ToolCall, type ToolDefinition, type ToolResult, type UnmergedEntry, type UnmergedReason, type VerificationResult, applyResolutions, checkoutFile, createResolution, defaultVerifier, extractConflict, removeFile, resolveConflict, resolveConflicts, show, takeOurs, takeTheirs };
|
|
20
|
+
export { AIError, type AIErrorCode, type BlameOptions, type Conflict, type ConflictDiffOptions, ConflictError, type ConflictErrorCode, type ConflictGitOps, type ConflictGitPort, ConflictGitPortMissingOpError, type ConflictMarker, type ConflictMarkerUserInput, type ConflictModelMessage, type ConflictModelParams, type ConflictModelPort, type ConflictModelResult, type ConflictProgressEvent, type ConflictType, type DiffStats, type FileRule, type GrepOptions, type IntraFileEditOp, type Issue, type LogOptions, type OpOptions, type Resolution, type ResolutionContext, type ResolutionMetrics, type ResolutionRawSignals, type ResolutionRefs, type ResolutionStrategy, type ResolutionVerifier, type ResolvedChunk, type ResolverConfig, type ShowFileOptions, type ShowOptions, type StepConfig, type StepResult, type ThreeWayDiff, type ToolCall, type ToolDefinition, type ToolResult, type UnmergedEntry, type UnmergedReason, type VerificationResult, applyResolutions, checkoutFile, createResolution, defaultVerifier, extractConflict, removeFile, resolveConflict, resolveConflicts, show, takeOurs, takeTheirs };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Resolution, ResolutionMetrics, ResolvedChunk } from "../types/resolution.js";
|
|
1
|
+
import { Resolution, ResolutionMetrics, ResolvedChunk, ThreeWayDiff } from "../types/resolution.js";
|
|
2
2
|
import { Conflict } from "../types/conflict.js";
|
|
3
3
|
|
|
4
4
|
//#region src/resolution/create-resolution.d.ts
|
|
@@ -7,6 +7,8 @@ interface CreateResolutionOptions {
|
|
|
7
7
|
description?: string;
|
|
8
8
|
metrics?: ResolutionMetrics;
|
|
9
9
|
fileStrategy?: 'ours' | 'theirs' | 'deleted';
|
|
10
|
+
/** Source for `rawSignals.combinedDiffLines`; absent for non-AI strategies (reports 0). */
|
|
11
|
+
threeWayDiff?: ThreeWayDiff;
|
|
10
12
|
}
|
|
11
13
|
declare function createResolution(conflict: Conflict, chunks: ResolvedChunk[], options: CreateResolutionOptions): Resolution;
|
|
12
14
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{applyChunks as e}from"./chunk-apply.js";function
|
|
1
|
+
import{applyChunks as e}from"./chunk-apply.js";import{computeRawSignals as t}from"./raw-signals.js";function n(n,a,o){let s=a;o.fileStrategy&&o.fileStrategy!==`deleted`&&(s=n.markers.map((e,t)=>({markerIndex:t,strategy:o.fileStrategy})));let c=o.description!==void 0&&o.description.trim().length>0?o.description:i(s),l;l=o.fileStrategy===`deleted`?`deleted`:o.fileStrategy?o.fileStrategy===`ours`?`take-ours`:`take-theirs`:r(s);let u=o.fileStrategy===`deleted`||s.length===0?``:e(n.rawContent,n.markers,s);return{filePath:n.filePath,content:u,strategy:l,confidence:o.confidence,description:c,chunks:s,...o.metrics?{metrics:o.metrics}:{},rawSignals:t(n,{threeWayDiff:o.threeWayDiff,stepCount:o.metrics?.stepCount,retryCount:o.metrics?.retryCount})}}function r(e){if(e.length===0)return`skipped`;let t=new Set(e.map(e=>e.strategy));if(t.size===1){if(t.has(`ours`))return`take-ours`;if(t.has(`theirs`))return`take-theirs`}return`ai`}function i(e){if(e.length===0)return`No markers resolved.`;let t=new Set(e.map(e=>e.strategy));if(t.size===1){if(t.has(`ours`))return`All markers resolved by taking ours.`;if(t.has(`theirs`))return`All markers resolved by taking theirs.`}return`Resolved ${e.length} marker(s) with mixed strategies.`}export{n as createResolution};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResolutionRawSignals, ThreeWayDiff } from "../types/resolution.js";
|
|
2
|
+
import { Conflict } from "../types/conflict.js";
|
|
3
|
+
|
|
4
|
+
//#region src/resolution/raw-signals.d.ts
|
|
5
|
+
interface RawSignalsInput {
|
|
6
|
+
threeWayDiff?: ThreeWayDiff;
|
|
7
|
+
stepCount?: number;
|
|
8
|
+
retryCount?: number;
|
|
9
|
+
}
|
|
10
|
+
declare function computeRawSignals(conflict: Conflict, input?: RawSignalsInput): ResolutionRawSignals;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { RawSignalsInput, computeRawSignals };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
function e(e,i={}){let a=n(i.threeWayDiff?.oursStats),o=n(i.threeWayDiff?.theirsStats);return{conflictType:e.type,maxSideLines:t(e),oursDiffLines:a,theirsDiffLines:o,combinedDiffLines:a+o,markersCount:e.markers.length,markersWithMissingBase:r(e),emptySideMarkersCount:e.markers.filter(e=>e.ours===``||e.theirs===``).length,stepCount:i.stepCount??0,retryCount:i.retryCount??0}}function t(e){let t=0;for(let n of e.markers){let e=i(n.ours),r=i(n.theirs);e>t&&(t=e),r>t&&(t=r)}return t}function n(e){return e?e.insertions+e.deletions:0}function r(e){return e.markers.some(e=>e.base!==null)?e.markers.filter(e=>e.base===null).length:0}function i(e){return e===``?0:(e.endsWith(`
|
|
2
|
+
`)?e.slice(0,-1):e).split(`
|
|
3
|
+
`).length}export{e as computeRawSignals};
|
package/dist/resolver/loop.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AIError as e}from"../errors/ai.js";import{applyChunks as t}from"../resolution/chunk-apply.js";import{sumUsages as n}from"../resolution/metrics.js";import{parseModelResponse as r}from"./parse-response.js";import{buildPrompt as i}from"./prompt.js";import{createResolverTools as a}from"./tools.js";import{validateChunks as o}from"./validate.js";async function s(n,s,u){let d=u.config?.maxSteps??15,f=u.config?.temperature??0,{definitions:p,execute:m}=a(u.git),{system:h,userMessage:g}=i(n,s,{maxSteps:d}),_=[{role:`user`,content:g}],v=u.signal?{signal:u.signal}:void 0,y=0,b=0,x=[],
|
|
1
|
+
import{AIError as e}from"../errors/ai.js";import{applyChunks as t}from"../resolution/chunk-apply.js";import{sumUsages as n}from"../resolution/metrics.js";import{parseModelResponse as r}from"./parse-response.js";import{buildPrompt as i}from"./prompt.js";import{createResolverTools as a}from"./tools.js";import{validateChunks as o}from"./validate.js";async function s(n,s,u){let d=u.config?.maxSteps??15,f=u.config?.temperature??0,{definitions:p,execute:m}=a(u.git),{system:h,userMessage:g}=i(n,s,{maxSteps:d}),_=[{role:`user`,content:g}],v=u.signal?{signal:u.signal}:void 0,y=0,b=0,x=0,S=[],C=n.markers.some(e=>e.userResolution!=null),w;for(;y<d;){y++;let e=await u.model.generate({system:h,messages:[..._],tools:p,temperature:f,signal:u.signal});if(e.usage&&(S.push(e.usage),u.onProgress?.({type:`resolver:step-usage`,filePath:n.filePath,stepNumber:y,usage:e.usage})),e.toolCalls&&e.toolCalls.length>0){_.push({role:`assistant`,content:e.text,toolCalls:e.toolCalls});for(let t of e.toolCalls){let e=typeof t.args.reason==`string`?t.args.reason:void 0;u.onProgress?.({type:`resolver:tool-call`,filePath:n.filePath,tool:t.name,args:t.args,stepNumber:y,reason:e}),b++;let r=await m(t,v);u.onProgress?.({type:`resolver:tool-result`,filePath:n.filePath,tool:t.name,stepNumber:y,content:r.content}),_.push({role:`tool`,toolCallId:r.toolCallId,toolName:t.name,content:r.content})}continue}let i=e.text??``;if(!i.trim()){x++,_.push({role:`assistant`,content:``}),_.push({role:`user`,content:`[Step ${y}/${d}] Your response was empty. Please respond with a valid JSON object containing "confidence" (0-1), "description" (1-2 sentences), and either "strategy" ("ours", "theirs", or "deleted") for a file-level decision, or "chunks" (array of { markerIndex, strategy, content? }).`});continue}let a;try{a=r(i,n.markers.length)}catch(e){x++;let t=e instanceof Error?e.message:String(e);_.push({role:`assistant`,content:i}),_.push({role:`user`,content:`[Step ${y}/${d}] Failed to parse your response: ${t}. Please respond with a valid JSON object containing "confidence" (0-1), "description" (1-2 sentences), and either "strategy" ("ours", "theirs", or "deleted") for a file-level decision, or "chunks" (array of { markerIndex, strategy, content? }).`});continue}if(a.strategy===`deleted`&&n.type!==`delete-modify`){x++,_.push({role:`assistant`,content:i}),_.push({role:`user`,content:`[Step ${y}/${d}] Strategy "deleted" is only valid for delete-modify conflicts. This is a text conflict — respond with "chunks" or a file-level "ours"/"theirs" strategy.`});continue}if(a.strategy){let e=a.strategy;if((e===`ours`||e===`theirs`)&&C)a.chunks=n.markers.map((t,n)=>t.userResolution==null?{markerIndex:n,strategy:e}:null).filter(e=>e!==null),a.strategy=void 0;else return u.onProgress?.({type:`resolver:response`,filePath:n.filePath,chunks:a.chunks,strategy:e,confidence:a.confidence,description:a.description,...a.followUpInstructions?{followUpInstructions:a.followUpInstructions}:{}}),{chunks:a.chunks,strategy:e,confidence:a.confidence,description:a.description,metrics:l(S,y,b,x),...a.followUpInstructions?{followUpInstructions:a.followUpInstructions}:{}}}if(n.markers.length===0&&!a.strategy){x++,_.push({role:`assistant`,content:i}),_.push({role:`user`,content:`[Step ${y}/${d}] Delete-modify conflicts require a file-level strategy field ("ours", "theirs", or "deleted"). Please respond with a JSON object containing "strategy".`});continue}let s=a.chunks.filter(e=>n.markers[e.markerIndex]?.userResolution==null),g=o(s,n);if(!g.valid){x++;let e=(g.issues??[]).map(e=>e.message).join(` `);_.push({role:`assistant`,content:i}),_.push({role:`user`,content:`[Step ${y}/${d}] Validation failed: ${e}\nPlease fix the issues and respond with a corrected JSON object. Make sure every marker index appears exactly once, or use a top-level "strategy" field.`});continue}let T=c(s,n);if(u.verifier&&n.type===`text`){let e=t(n.rawContent,n.markers,T),r=await u.verifier.verify(n.filePath,e);if(!r.valid){x++;let e=(r.issues??[]).filter(e=>e.severity===`error`).map(e=>e.message).join(` `)||`Content did not pass verification.`;_.push({role:`assistant`,content:i}),_.push({role:`user`,content:`[Step ${y}/${d}] Verification failed: ${e}\nPlease fix and respond with corrected JSON.`});continue}let a=(r.issues??[]).filter(e=>e.severity===`warning`);a.length>0&&(w=a,u.onProgress?.({type:`verification:issues`,filePath:n.filePath,issues:a}))}return u.onProgress?.({type:`resolver:response`,filePath:n.filePath,chunks:a.chunks,confidence:a.confidence,description:a.description,...a.followUpInstructions?{followUpInstructions:a.followUpInstructions}:{}}),{chunks:T,confidence:a.confidence,description:a.description,metrics:l(S,y,b,x),...a.followUpInstructions?{followUpInstructions:a.followUpInstructions}:{},...w&&w.length>0?{issues:w}:{}}}throw new e(`VALIDATION_EXHAUSTED`,`Resolver exhausted ${d} steps without producing a valid resolution for ${n.filePath}.`)}function c(e,t){let n=[...e];for(let e=0;e<t.markers.length;e++){let r=t.markers[e]?.userResolution;r!=null&&n.push({markerIndex:e,...r})}return n.sort((e,t)=>e.markerIndex-t.markerIndex),n}function l(e,t,r,i){return{...n(e)??{inputTokens:0,outputTokens:0},stepCount:t,toolCallCount:r,retryCount:i}}export{s as runResolverLoop};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{checkResidualMarkers as e}from"../ports/verify.js";import{resolveChunkContent as t}from"../resolution/chunk-apply.js";import{createResolution as n}from"../resolution/create-resolution.js";import{mergeUsages as r}from"../resolution/metrics.js";import{runResolverLoop as i}from"./loop.js";import{runRefinePass as a}from"./refine-pass.js";import{buildThreeWayDiff as o}from"./three-way-diff.js";const s={refineNoAction:.6,refineApplied:.9};async function c(c,l,u){let
|
|
1
|
+
import{checkResidualMarkers as e}from"../ports/verify.js";import{resolveChunkContent as t}from"../resolution/chunk-apply.js";import{createResolution as n}from"../resolution/create-resolution.js";import{mergeUsages as r}from"../resolution/metrics.js";import{runResolverLoop as i}from"./loop.js";import{runRefinePass as a}from"./refine-pass.js";import{buildThreeWayDiff as o}from"./three-way-diff.js";const s={refineNoAction:.6,refineApplied:.9};async function c(c,l,u){let d=l.threeWayDiff||!l.refs?l:{...l,threeWayDiff:await o(c.filePath,l.refs,{git:u.git,signal:u.signal})},{chunks:f,strategy:p,confidence:m,description:h,metrics:g,followUpInstructions:_,issues:v}=await i(c,d,{model:u.model,git:u.git,config:u.config,onProgress:u.onProgress,signal:u.signal,verifier:u.verifier}),y=n(c,f,{confidence:m,description:h,metrics:g,...p?{fileStrategy:p}:{},...d.threeWayDiff?{threeWayDiff:d.threeWayDiff}:{}});v&&v.length>0&&(y={...y,issues:v});let b=_&&_.length>0;if(c.type===`text`&&b){u.onProgress?.({type:`refine:started`,filePath:c.filePath});let n=0;try{let i=await a(y.content,y.description,_,{model:u.model,signal:u.signal,temperature:u.config?.temperature,refineMaxSteps:u.config?.refineMaxSteps,onProgress:u.onProgress,filePath:c.filePath});if(i.edits.length>0){let t=e(c.filePath,i.content);if(t.valid)y={...y,content:i.content,edits:i.edits,strategy:`ai`},n=i.edits.length;else{let e=(t.issues??[]).map(e=>e.message).join(` `);u.onProgress?.({type:`refine:discarded`,filePath:c.filePath,reason:`Edits introduced conflict markers: ${e}`})}}if(n>0){y={...y,confidence:Math.min(y.confidence,s.refineApplied)};let e=[];for(let n=0;n<c.markers.length;n++){let r=c.markers[n];if(!r||r.userResolution==null)continue;let a=t({markerIndex:n,...r.userResolution},r);a!==``&&(i.content.includes(a)||e.push(n))}e.length>0&&(u.onProgress?.({type:`refine:touched-user-region`,filePath:c.filePath,markerIndexes:e}),y={...y,note:`Refine modified user-resolved region(s): marker ${e.join(`, `)}.`})}else i.edits.length===0&&i.verifies>0||(y={...y,confidence:Math.min(y.confidence,s.refineNoAction)});if(i.usage){let e=r(y.metrics??{inputTokens:0,outputTokens:0},i.usage);y={...y,metrics:{...y.metrics,...e}}}u.onProgress?.({type:`refine:completed`,filePath:c.filePath,appliedCount:n})}catch(e){let t=e instanceof Error?e.message:String(e);throw u.onProgress?.({type:`refine:failed`,filePath:c.filePath,reason:t}),e}}else u.onProgress?.({type:`refine:skipped`,filePath:c.filePath,reason:`no-follow-ups`});return u.onProgress?.({type:`resolver:completed`,filePath:c.filePath,stepCount:g.stepCount??0}),y}export{c as resolveConflict};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ConflictGitPort } from "../ports/git.js";
|
|
2
|
-
import { ResolutionRefs, ThreeWayDiff } from "../types/resolution.js";
|
|
2
|
+
import { DiffStats, ResolutionRefs, ThreeWayDiff } from "../types/resolution.js";
|
|
3
3
|
|
|
4
4
|
//#region src/resolver/three-way-diff.d.ts
|
|
5
5
|
declare function buildThreeWayDiff(filePath: string, refs: ResolutionRefs, deps: {
|
|
6
6
|
git: ConflictGitPort;
|
|
7
7
|
signal?: AbortSignal;
|
|
8
8
|
}): Promise<ThreeWayDiff>;
|
|
9
|
+
/** Counts +/- content lines, ignoring the `+++`/`---` file headers. */
|
|
10
|
+
declare function parseDiffStats(unifiedDiff: string): DiffStats;
|
|
9
11
|
//#endregion
|
|
10
|
-
export { buildThreeWayDiff };
|
|
12
|
+
export { buildThreeWayDiff, parseDiffStats };
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{diff as e,mergeBase as t}from"../git/port-dispatch.js";async function n(n,
|
|
1
|
+
import{diff as e,mergeBase as t}from"../git/port-dispatch.js";async function n(n,i,a){let o=i.base??await t(a.git,i.ours,i.theirs,{signal:a.signal}),[s,c]=await Promise.all([e(a.git,o,i.ours,{path:n,signal:a.signal}),e(a.git,o,i.theirs,{path:n,signal:a.signal})]);return{oursDiff:s,theirsDiff:c,oursStats:r(s),theirsStats:r(c)}}function r(e){let t=0,n=0;for(let r of e.split(`
|
|
2
|
+
`))r.startsWith(`+++ `)||r.startsWith(`--- `)||(r.startsWith(`+`)?t++:r.startsWith(`-`)&&n++);return{insertions:t,deletions:n}}export{n as buildThreeWayDiff,r as parseDiffStats};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { IntraFileEditOp } from "./hints.js";
|
|
2
2
|
import { Issue } from "./issue.js";
|
|
3
|
+
import { ConflictType } from "./conflict.js";
|
|
3
4
|
import { AiTokenUsage } from "@gitkraken/shared-tools";
|
|
4
5
|
|
|
5
6
|
//#region src/types/resolution.d.ts
|
|
@@ -24,15 +25,39 @@ interface Resolution {
|
|
|
24
25
|
chunks?: ResolvedChunk[];
|
|
25
26
|
edits?: IntraFileEditOp[];
|
|
26
27
|
metrics?: ResolutionMetrics;
|
|
28
|
+
rawSignals?: ResolutionRawSignals;
|
|
29
|
+
}
|
|
30
|
+
/** Policy-free measurements of a conflict and its resolution; consumers feed these into their own assessment. */
|
|
31
|
+
interface ResolutionRawSignals {
|
|
32
|
+
conflictType: ConflictType;
|
|
33
|
+
maxSideLines: number;
|
|
34
|
+
/** Changed lines per side and combined; 0 when no three-way diff was available. */
|
|
35
|
+
oursDiffLines: number;
|
|
36
|
+
theirsDiffLines: number;
|
|
37
|
+
combinedDiffLines: number;
|
|
38
|
+
markersCount: number;
|
|
39
|
+
/** Only counted when the style provides base on some marker (diff3); 0 otherwise. */
|
|
40
|
+
markersWithMissingBase: number;
|
|
41
|
+
/** Markers with an empty ours or theirs side. */
|
|
42
|
+
emptySideMarkersCount: number;
|
|
43
|
+
stepCount: number;
|
|
44
|
+
/** Re-prompts after parse/validation/verification failures, excluding tool-call steps. */
|
|
45
|
+
retryCount: number;
|
|
27
46
|
}
|
|
28
47
|
interface ResolutionRefs {
|
|
29
48
|
ours: string;
|
|
30
49
|
theirs: string;
|
|
31
50
|
base?: string;
|
|
32
51
|
}
|
|
52
|
+
interface DiffStats {
|
|
53
|
+
insertions: number;
|
|
54
|
+
deletions: number;
|
|
55
|
+
}
|
|
33
56
|
interface ThreeWayDiff {
|
|
34
57
|
oursDiff: string;
|
|
35
58
|
theirsDiff: string;
|
|
59
|
+
oursStats?: DiffStats;
|
|
60
|
+
theirsStats?: DiffStats;
|
|
36
61
|
}
|
|
37
62
|
interface ResolutionContext {
|
|
38
63
|
commitMessage?: string;
|
|
@@ -50,8 +75,10 @@ interface ResolutionContext {
|
|
|
50
75
|
interface ResolutionMetrics extends AiTokenUsage {
|
|
51
76
|
stepCount?: number;
|
|
52
77
|
toolCallCount?: number;
|
|
78
|
+
/** Re-prompts after parse/validation/verification failures, excluding tool-call steps. */
|
|
79
|
+
retryCount?: number;
|
|
53
80
|
durationMs?: number;
|
|
54
81
|
metadata?: Record<string, unknown>;
|
|
55
82
|
}
|
|
56
83
|
//#endregion
|
|
57
|
-
export { ChunkResolution, Resolution, ResolutionContext, ResolutionMetrics, ResolutionRefs, ResolutionStrategy, ResolvedChunk, ThreeWayDiff };
|
|
84
|
+
export { ChunkResolution, DiffStats, Resolution, ResolutionContext, ResolutionMetrics, ResolutionRawSignals, ResolutionRefs, ResolutionStrategy, ResolvedChunk, ThreeWayDiff };
|