@gitkraken/conflict-tools 0.2.4-beta.12 → 0.2.4-beta.14
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
|
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
9
9
|
|
|
10
10
|
### Added
|
|
11
11
|
|
|
12
|
+
- Cross-file fixes in the fix phase (opt-in `ResolverConfig.fix`). After per-file convergence, a project-tier broken reference (an import/cross-file use whose target stopped resolving) is routed to the refine of its **use-site** file: the finding becomes a fix instruction, and the whole set is re-detected, up to `crossFileMaxIterations` rounds (default 2). Each cross-file fix is a single refine pass plus a mandatory per-file re-validation; the final whole-set detection also re-checks per-file for files a cross-file fix touched. **Limitation:** only use-site files that have an AI resolution are routed — a cross-file break landing on an auto-merged file (no resolution to carry the edit) is reported but not auto-fixed yet (needs a patches channel). The definition side, if broken, arrives as its own finding on its own file. Report-only (fix off) is unchanged.
|
|
12
13
|
- Per-file fix loop (opt-in via `ResolverConfig.fix`, default `false`). When enabled, an AI-resolved (`strategy: 'ai'`) text file that carries error-severity per-file findings is routed back through refine: the findings become fix instructions, the file is re-analyzed after each edit, and the loop repeats until the file is clean, a round makes no progress, or `fixLoopMaxIterations` (default 3) is reached. Whatever it cannot fix stays in the findings, so the verdict reflects the post-fix state. The no-markers invariant holds (a fix that reintroduces markers is discarded). New progress events `fix:started` / `fix:completed`. Report-only (fix off) is unchanged. Deferred for the opt-in fix path: rebase per-step-ref/transient discipline, parser/validator call caching, cross-file fixes, and a full finding-lifecycle model (double-counting is handled here by fingerprint dedup when folding findings into the report).
|
|
13
14
|
- `collectFileFindings` — a per-file detection unit (structural + intra-file broken references + consumer validator issues, all `tier: 'file'`) over already-loaded parent snapshots; the fix loop re-runs it after each edit. `detect()` remains the authoritative whole-set report.
|
|
14
15
|
- Reference-integrity detection. `resolveConflicts` now attaches a `StepResult.detection` report listing broken references (symbols that resolved in a pre-merge parent but no longer resolve in the merged result, with provenance), duplicate definitions, and syntax errors in the resolved files. Detection is opt-in via a new `ParserPort` (`ResolverDeps.parser`) that supplies parsing/symbol resolution per surface (tree-sitter, language server); when it is absent, unavailable, or a file's language is unsupported, the report says so rather than implying a clean result. Report-only in this release — no automatic fixing.
|
|
@@ -25,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
25
26
|
|
|
26
27
|
### Fixed
|
|
27
28
|
|
|
29
|
+
- `OperationDigest.verdict` can now reach `clean` on a real repository. `detectionComplete` treated `partial-unsupported-language` as "did not run", so any operation whose scope contained a non-code file (package.json, README, lockfiles — always present in a real merge) forced `verdict: 'needs-review'` even with zero findings and full confidence. Since `--fix` gates auto-apply on `verdict === 'clean'`, this made auto-apply effectively unreachable. A check now counts as complete when it ran, including when some scope files were an unsupported language (they carry no references to break); only a check that could not run at all — no parser, no refs, an unreadable parent snapshot, or a thrown parser — leaves detection incomplete.
|
|
28
30
|
- A non-abort error in the refine pass no longer destroys the pre-refine resolution. Previously the refine `catch` rethrew, bubbling to `resolveOne` and degrading a good resolve-stage result into a take-side fallback (confidence 0) — the same class of failure as a throwing validator, one stage later. The pre-refine resolution is now kept, its confidence capped (the enhancement did not complete), and the error reported via `refine:failed`. A user abort still cancels (rethrown past the fallback).
|
|
29
31
|
- A throwing consumer validator no longer destroys a good resolution. The post-refine `validator.validate()` call is now guarded: a validator error is reported via a new `validation:failed` progress event and the resolution is kept intact, instead of bubbling to `resolveOne` and degrading a successful AI resolve into a whole-file take-side fallback (confidence 0) — the exact dropped-side loss the tool guards against. The validator stays advisory.
|
|
30
32
|
- A user abort mid-resolve now cancels the operation instead of degrading into a take-side fallback. `resolveOne` rethrows when `signal.aborted` (covering aborts raised from the resolve loop, refine, or the validator), bypassing the emergency fallback rather than turning a cancellation into a whole-file take-one-side resolution.
|
package/dist/ports/model.d.ts
CHANGED
|
@@ -41,6 +41,9 @@ interface ResolverConfig {
|
|
|
41
41
|
fix?: boolean;
|
|
42
42
|
/** Max per-file fix iterations (refine → re-detect the file) when `fix` is on. Default 3. */
|
|
43
43
|
fixLoopMaxIterations?: number;
|
|
44
|
+
/** Max cross-file fix rounds (route project-level breaks to their use-site file → re-detect the whole
|
|
45
|
+
* set) when `fix` is on. Default 2. */
|
|
46
|
+
crossFileMaxIterations?: number;
|
|
44
47
|
}
|
|
45
48
|
//#endregion
|
|
46
49
|
export { ConflictModelMessage, ConflictModelParams, ConflictModelPort, ConflictModelResult, ResolverConfig };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConflictGitPort } from "../ports/git.js";
|
|
2
|
+
import { DetectionReport } from "../types/findings.js";
|
|
3
|
+
import { Resolution, ResolutionContext } from "../types/resolution.js";
|
|
2
4
|
import { ConflictModelPort, ResolverConfig } from "../ports/model.js";
|
|
3
5
|
import { ParserPort } from "../ports/parser.js";
|
|
4
6
|
import { Validator } from "../ports/verify.js";
|
|
@@ -24,5 +26,25 @@ interface FixLoopDeps {
|
|
|
24
26
|
* caller should invoke this only for AI-resolved (`strategy: 'ai'`) text files.
|
|
25
27
|
*/
|
|
26
28
|
declare function runFixLoop(resolution: Resolution, oursContent: string | undefined, theirsContent: string | undefined, deps: FixLoopDeps): Promise<Resolution>;
|
|
29
|
+
interface FixPhaseDeps {
|
|
30
|
+
model: ConflictModelPort;
|
|
31
|
+
git: ConflictGitPort;
|
|
32
|
+
parser: ParserPort;
|
|
33
|
+
validator?: Validator;
|
|
34
|
+
config?: ResolverConfig;
|
|
35
|
+
onProgress?: (event: ConflictProgressEvent) => void;
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The fix phase (opt-in). Stage 2: per-file convergence over each AI resolution ({@link runFixLoop}).
|
|
40
|
+
* Stage 3: route cross-file (`tier: 'project'`) broken references back to the refine of their use-site
|
|
41
|
+
* file and re-detect over the whole set, up to `crossFileMaxIterations` rounds. Mutates `resolutions`
|
|
42
|
+
* in place and returns the final whole-set {@link DetectionReport} — which, being whole-set, also
|
|
43
|
+
* re-checks per-file for files touched by cross-file fixes.
|
|
44
|
+
*
|
|
45
|
+
* Cross-file findings on files without an AI resolution (e.g. auto-merged) are not routed: they have no
|
|
46
|
+
* carrier for an edit yet (needs a patches channel), so they remain in the report unchanged.
|
|
47
|
+
*/
|
|
48
|
+
declare function runFixPhase(resolutions: Resolution[], context: ResolutionContext, deps: FixPhaseDeps): Promise<DetectionReport>;
|
|
27
49
|
//#endregion
|
|
28
|
-
export { FixLoopDeps, runFixLoop };
|
|
50
|
+
export { FixLoopDeps, FixPhaseDeps, runFixLoop, runFixPhase };
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildSummaryPrompt as e}from"./prompt.js";const t=.8;function n(e,n=t){let
|
|
1
|
+
import{buildSummaryPrompt as e}from"./prompt.js";const t=.8;function n(e,n=t){let o={ai:0,"take-ours":0,"take-theirs":0,deleted:0,skipped:0},s=0,c=null,l=new Map;for(let t of e.resolutions)o[t.strategy]++,s+=t.chunks?.length??0,c=c===null?t.confidence:Math.min(c,t.confidence),t.confidence<n&&l.set(t.filePath,{filePath:t.filePath,confidence:t.confidence,reason:`low-confidence`});let u=e.detection,d=u?.findings??[],f=new Map;for(let e of d){if(e.severity!==`error`)continue;let t=f.get(e.location.file)??new Set;t.add(e.category),f.set(e.location.file,t)}for(let[e,t]of f){let n=l.get(e);l.set(e,{filePath:e,...n?.confidence==null?{}:{confidence:n.confidence},reason:`finding`,findingCategories:[...t].sort()})}let p=[...l.values()].sort(i),m=u!=null&&r(u.checks.referenceIntegrity)&&r(u.checks.structural),h=a({hasErrorFinding:f.size>0,hasWarningFinding:d.some(e=>e.severity===`warning`),needsReview:p.length>0,detectionComplete:m,hasErrors:e.errors.length>0});return{files:e.resolutions.length,conflicts:s,byStrategy:o,minConfidence:c,needsReview:p,skipped:e.skipped?.length??0,errors:e.errors.length,detectionComplete:m,findingCount:d.length,verdict:h}}function r(e){return e===`ran`||e===`partial-unsupported-language`}function i(e,t){return e.reason===t.reason?(e.confidence??1)-(t.confidence??1):e.reason===`finding`?-1:1}function a(e){return e.hasErrorFinding?`blocked`:e.needsReview||!e.detectionComplete||e.hasErrors||e.hasWarningFinding?`needs-review`:`clean`}async function o(r,i={}){let a=n(r,i.reviewThreshold??t);if(!i.model)return{digest:a};let{system:o,userMessage:s}=e(r,a),c=await i.model.generate({system:o,messages:[{role:`user`,content:s}],temperature:i.temperature??0,signal:i.signal}),l=c.text?.trim();return{digest:a,...l?{prose:l}:{},...c.usage?{usage:c.usage}:{}}}export{n as buildOperationDigest,o as summarizeOperation};
|