@gitkraken/conflict-tools 0.2.4-beta.8 → 0.3.0
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 +32 -6
- package/README.md +262 -55
- package/dist/errors/conflict.d.ts +1 -1
- package/dist/git/port-dispatch.js +2 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/ports/git.d.ts +4 -0
- package/dist/ports/parser.d.ts +27 -6
- package/dist/ports/validator.d.ts +29 -0
- package/dist/ports/validator.js +1 -0
- package/dist/reference-integrity/detect.d.ts +39 -4
- package/dist/reference-integrity/detect.js +2 -2
- package/dist/reference-integrity/snapshot.d.ts +18 -5
- package/dist/reference-integrity/snapshot.js +1 -1
- package/dist/resolution/detect-code-loss.d.ts +23 -0
- package/dist/resolution/detect-code-loss.js +1 -0
- package/dist/resolver/deps.d.ts +1 -1
- package/dist/resolver/fix-loop.d.ts +67 -0
- package/dist/resolver/fix-loop.js +2 -0
- package/dist/resolver/model-budget.d.ts +26 -0
- package/dist/resolver/model-budget.js +1 -0
- package/dist/resolver/prompt.d.ts +8 -2
- package/dist/resolver/prompt.js +5 -3
- package/dist/resolver/refine-pass.d.ts +8 -0
- package/dist/resolver/refine-pass.js +1 -1
- package/dist/resolver/resolve-conflict.d.ts +7 -1
- package/dist/resolver/resolve-conflict.js +1 -1
- package/dist/resolver/resolve-conflicts.js +1 -1
- package/dist/resolver/summarize-operation.js +1 -1
- package/dist/resolver/validate.js +1 -1
- package/dist/types/events.d.ts +30 -3
- package/dist/types/findings.d.ts +25 -15
- package/dist/types/resolution.d.ts +11 -0
- package/dist/types/step.d.ts +27 -0
- package/dist/types/summary.d.ts +17 -10
- package/dist/validation/findings.d.ts +9 -0
- package/dist/validation/findings.js +1 -0
- package/dist/validation/markers.d.ts +11 -0
- package/dist/{ports/verify.js → validation/markers.js} +1 -1
- package/package.json +1 -1
- package/dist/ports/verify.d.ts +0 -30
|
@@ -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 s={ai:0,"take-ours":0,"take-theirs":0,deleted:0,skipped:0},c=0,l=null,u=new Map;for(let t of e.resolutions)s[t.strategy]++,c+=t.chunks?.length??0,l=l===null?t.confidence:Math.min(l,t.confidence),t.confidence<n&&u.set(t.filePath,{filePath:t.filePath,confidence:t.confidence,reason:`low-confidence`});let d=e.detection,f=d?.findings??[],p=new Map,m=!1;for(let e of f){e.severity===`error`&&(m=!0);let t=p.get(e.location.file)??new Set;t.add(e.category),p.set(e.location.file,t)}for(let[e,t]of p){let n=u.get(e);u.set(e,{filePath:e,...n?.confidence==null?{}:{confidence:n.confidence},reason:`finding`,findingCategories:[...t].sort()})}for(let t of e.skipped??[])t.reason!==`excluded`&&(u.has(t.filePath)||u.set(t.filePath,{filePath:t.filePath,reason:`unresolved`}));let h=[...u.values()].sort(a),g=d!=null&&r(d.checks.referenceIntegrity)&&r(d.checks.structural)&&i(d.scope),_=o({hasErrorFinding:m,hasWarningFinding:f.some(e=>e.severity===`warning`),needsReview:h.length>0,detectionComplete:g,hasResolutionErrors:e.errors.length>0});return{files:e.resolutions.length,conflicts:c,byStrategy:s,minConfidence:l,needsReview:h,skipped:e.skipped?.length??0,errors:e.errors.length,detectionComplete:g,findingCount:f.length,verdict:_}}function r(e){return e===`ran`||e===`partial-unsupported-language`}function i(e){return e?!e.truncated&&e.incomingDiscovered:!0}function a(e,t){return e.reason===t.reason?(e.confidence??1)-(t.confidence??1):e.reason===`finding`?-1:1}function o(e){return e.hasErrorFinding?`blocked`:e.needsReview||!e.detectionComplete||e.hasResolutionErrors||e.hasWarningFinding?`needs-review`:`clean`}async function s(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,s as summarizeOperation};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import{CONFLICT_MARKER_PATTERNS as e}from"../validation/markers.js";function t(t,n){let r=[],i=n.markers.length,a=new Set;for(let e of t)a.has(e.markerIndex)&&r.push(`Duplicate markerIndex ${e.markerIndex}.`),a.add(e.markerIndex);for(let e=0;e<i;e++)n.markers[e]?.userResolution??(a.has(e)||r.push(`Missing resolution for marker ${e}.`));for(let n of t)if(n.strategy===`merged`){let t=n.content.split(`
|
|
2
2
|
`);for(let i of t)for(let t of e)t.test(i)&&r.push(`Marker ${n.markerIndex}: resolved content contains conflict marker "${i.trim()}".`)}return r.length===0?{valid:!0}:{valid:!1,issues:r.map(e=>({severity:`error`,message:e}))}}export{t as validateChunks};
|
package/dist/types/events.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ResolutionStrategy, ResolvedChunk } from "./resolution.js";
|
|
2
2
|
import { ConflictType } from "./conflict.js";
|
|
3
|
-
import { Issue } from "./issue.js";
|
|
4
3
|
import { AiTokenUsage } from "@gitkraken/shared-tools";
|
|
5
4
|
|
|
6
5
|
//#region src/types/events.d.ts
|
|
@@ -91,14 +90,42 @@ type ConflictProgressEvent = {
|
|
|
91
90
|
type: 'refine:failed';
|
|
92
91
|
filePath: string;
|
|
93
92
|
reason: string;
|
|
93
|
+
} | {
|
|
94
|
+
type: 'refine:bailed';
|
|
95
|
+
filePath: string;
|
|
96
|
+
reason: string;
|
|
94
97
|
} | {
|
|
95
98
|
type: 'refine:touched-user-region';
|
|
96
99
|
filePath: string;
|
|
97
100
|
markerIndexes: number[];
|
|
98
101
|
} | {
|
|
99
|
-
type: '
|
|
102
|
+
type: 'fix:started';
|
|
103
|
+
filePath: string;
|
|
104
|
+
findingCount: number;
|
|
105
|
+
}
|
|
106
|
+
/** `iterations` counts refine rounds actually run for this file (0 = evaluated, nothing spent).
|
|
107
|
+
* `remainingFindings` is the error findings still standing — named apart from the model-call budget's
|
|
108
|
+
* `remaining`, which the sibling `fix:budget-exhausted` reports as `spent`/`limit`. */
|
|
109
|
+
| {
|
|
110
|
+
type: 'fix:completed';
|
|
111
|
+
filePath: string;
|
|
112
|
+
iterations: number;
|
|
113
|
+
remainingFindings: number;
|
|
114
|
+
}
|
|
115
|
+
/** `filePath` is set when one file's fix threw and the phase carried on without it; absent when the
|
|
116
|
+
* whole phase failed. */
|
|
117
|
+
| {
|
|
118
|
+
type: 'fix:failed';
|
|
119
|
+
filePath?: string;
|
|
120
|
+
reason: string;
|
|
121
|
+
} | {
|
|
122
|
+
type: 'fix:budget-exhausted';
|
|
123
|
+
spent: number;
|
|
124
|
+
limit: number;
|
|
125
|
+
} | {
|
|
126
|
+
type: 'validation:failed';
|
|
100
127
|
filePath: string;
|
|
101
|
-
|
|
128
|
+
reason: string;
|
|
102
129
|
} | {
|
|
103
130
|
type: 'resolver:tool-result';
|
|
104
131
|
filePath: string;
|
package/dist/types/findings.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
//#region src/types/findings.d.ts
|
|
2
|
-
/** The package's own detection categories. `Finding.category`
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
/** The package's own detection categories. `Finding.category` stays open so consumer validators can
|
|
3
|
+
* contribute their own kinds (e.g. `'type-error'`, `'lint:no-console'`); these are the well-known
|
|
4
|
+
* values the package itself emits. */
|
|
5
5
|
type FindingCategory = 'broken-reference' | 'duplicate-definition' | 'syntax-error' | 'dropped-side';
|
|
6
6
|
type FindingTier = 'file' | 'project';
|
|
7
7
|
interface Finding {
|
|
8
|
-
/** Finding kind.
|
|
9
|
-
*
|
|
10
|
-
category: string;
|
|
8
|
+
/** Finding kind. The package emits {@link FindingCategory} values; a consumer validator may use its
|
|
9
|
+
* own category strings, which is what the open half of the union allows. */
|
|
10
|
+
category: FindingCategory | (string & {});
|
|
11
11
|
severity: 'error' | 'warning';
|
|
12
12
|
tier: FindingTier;
|
|
13
13
|
location: {
|
|
@@ -20,27 +20,37 @@ interface Finding {
|
|
|
20
20
|
side: 'ours' | 'theirs';
|
|
21
21
|
line: number;
|
|
22
22
|
};
|
|
23
|
+
/** Present for a cross-file `broken-reference` when the parser reported the pre-merge resolution
|
|
24
|
+
* target: the file whose definition the use site expected. Lets the cross-file fix pass show the
|
|
25
|
+
* refining model what that file currently defines (a rename/move is otherwise invisible from the use
|
|
26
|
+
* site alone). Absent when the backend does not fill reference targets. */
|
|
27
|
+
definitionFile?: string;
|
|
23
28
|
message: string;
|
|
24
29
|
}
|
|
25
30
|
/** Why a check produced its result — lets a consumer tell "ran, clean" apart from "did not run".
|
|
26
31
|
* `errored` means the parser was present but threw; `partial-unsupported-language` means some files
|
|
27
|
-
* in scope could not be parsed; `
|
|
28
|
-
*
|
|
29
|
-
|
|
32
|
+
* in scope could not be parsed; `partial-no-cross-file-resolution` means the parser backend declared
|
|
33
|
+
* it does not resolve references across files, so cross-file breaks are structurally out of reach;
|
|
34
|
+
* `skipped-unreadable-source` means the parent snapshots came back empty (unreadable source), so the
|
|
35
|
+
* before/after comparison had nothing to compare against. */
|
|
36
|
+
type CheckStatus = 'ran' | 'skipped-no-parser' | 'skipped-no-refs' | 'skipped-unreadable-source' | 'partial-unsupported-language' | 'partial-no-cross-file-resolution' | 'errored';
|
|
30
37
|
interface DetectionReport {
|
|
31
38
|
findings: Finding[];
|
|
32
39
|
checks: {
|
|
33
40
|
referenceIntegrity: CheckStatus;
|
|
34
41
|
structural: CheckStatus;
|
|
35
42
|
};
|
|
36
|
-
/** Honest coverage signal so empty findings are not read as "clean"
|
|
37
|
-
*
|
|
38
|
-
* comparison had nothing to compare), and `truncated` whether the scope was capped. Present only
|
|
39
|
-
* when the reference check ran (refs available). */
|
|
43
|
+
/** Honest coverage signal so empty findings are not read as "clean". Present only when the reference
|
|
44
|
+
* check ran (refs available). */
|
|
40
45
|
scope?: {
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
/** How many files the detector took into scope, after the cap. */inScope: number;
|
|
47
|
+
/** How many scope files had loadable parent content. 0 means the before/after comparison had
|
|
48
|
+
* nothing to compare. */
|
|
49
|
+
readable: number; /** Whether the scope exceeded the cap and its tail was dropped. */
|
|
43
50
|
truncated: boolean;
|
|
51
|
+
/** Whether the merge's incoming/auto-merged set could be discovered. `false` means the git port
|
|
52
|
+
* could not answer, so scope fell back to the conflict set — a coverage gap, not an empty diff. */
|
|
53
|
+
incomingDiscovered: boolean;
|
|
44
54
|
};
|
|
45
55
|
}
|
|
46
56
|
//#endregion
|
|
@@ -26,6 +26,17 @@ interface Resolution {
|
|
|
26
26
|
confidence: number;
|
|
27
27
|
description: string;
|
|
28
28
|
note?: string;
|
|
29
|
+
/** Set when this resolution is the resolver's emergency fallback — a whole-side take after the AI
|
|
30
|
+
* path failed, not a decision. Distinguishes it from an identical-looking rule or default take, and
|
|
31
|
+
* from a genuine AI resolution that happened to pick one side; reference-integrity uses it to decide
|
|
32
|
+
* whether discarding the other side was intentional. */
|
|
33
|
+
fallback?: true;
|
|
34
|
+
/** Set when this resolution is a deliberate whole-side discard chosen by a file rule or the default
|
|
35
|
+
* strategy — the caller asked to take one side wholesale, so the fix phase must not refine it back
|
|
36
|
+
* toward the discarded side. Distinct from `fallback` (an emergency take after the AI path failed)
|
|
37
|
+
* and from an AI resolution that merely happened to pick one side unanimously (which the fix phase
|
|
38
|
+
* may still refine). */
|
|
39
|
+
deliberateTake?: true;
|
|
29
40
|
/** Non-blocking per-file findings from the consumer's validator port (post-refine). Folded into
|
|
30
41
|
* the operation's detection findings, hence into the verdict. */
|
|
31
42
|
findings?: Finding[];
|
package/dist/types/step.d.ts
CHANGED
|
@@ -23,6 +23,33 @@ interface StepConfig extends ResolverConfig {
|
|
|
23
23
|
defaultStrategy?: 'ai' | 'take-ours' | 'take-theirs' | 'skip' | 'deleted';
|
|
24
24
|
rules?: FileRule[];
|
|
25
25
|
fallbackStrategy?: 'take-ours' | 'take-theirs';
|
|
26
|
+
/** Escape hatch: apply the wholesale `fallbackStrategy` even when it would discard already-integrated
|
|
27
|
+
* work. Off by default so a lossy fallback stops for manual resolution instead of completing silently. */
|
|
28
|
+
allowLossyFallback?: boolean;
|
|
29
|
+
/** Opt in to the fix phase (default `false` → report-only). When enabled, an AI-resolved file carrying
|
|
30
|
+
* error-severity per-file findings is routed back through refine to attempt a fix; what it cannot fix
|
|
31
|
+
* remains in the findings. Requires `ResolverDeps.parser` — without a parser the fix phase is a no-op
|
|
32
|
+
* and the report-only detection path runs instead. Without `ResolutionContext.refs` (or
|
|
33
|
+
* `detectionRefs`) the per-file stage still runs on what needs no parent content — syntax errors and
|
|
34
|
+
* validator findings — but cross-file routing is skipped, since it is driven by the whole-set
|
|
35
|
+
* before/after report. Off by default so the report-only path is unchanged. */
|
|
36
|
+
fix?: boolean;
|
|
37
|
+
/** Max per-file fix iterations (refine → re-detect the file) when `fix` is on. Default 3. */
|
|
38
|
+
fixLoopMaxIterations?: number;
|
|
39
|
+
/** Max cross-file fix rounds (route project-level breaks to their use-site file → re-detect the whole
|
|
40
|
+
* set) when `fix` is on. Default 2. */
|
|
41
|
+
crossFileMaxIterations?: number;
|
|
42
|
+
/** Override the reference-integrity scope cap (default 400 files). Beyond the cap the scope is
|
|
43
|
+
* `truncated`, which holds the verdict off `clean`; raise it so a large merge stays auto-applyable. */
|
|
44
|
+
maxDetectionScopeFiles?: number;
|
|
45
|
+
/** Global cap on `model.generate` calls for the whole operation (resolve + refine + fix). Default
|
|
46
|
+
* `undefined` = unlimited. Primarily a backstop for the fix phase's multiplicative worst case
|
|
47
|
+
* (files × fixLoopMaxIterations + crossFileMaxIterations × routable calls). When spent, the fix
|
|
48
|
+
* phase stops attempting further fixes and leaves the remainder in findings — it never aborts the
|
|
49
|
+
* operation. The resolve loop is not gated by this (it is already bounded by `maxSteps`); its calls
|
|
50
|
+
* still count toward the cap. Batch-only: the fix phase is what enforces it, so it has no effect on
|
|
51
|
+
* the single-file `resolveConflict`. */
|
|
52
|
+
maxModelCalls?: number;
|
|
26
53
|
}
|
|
27
54
|
//#endregion
|
|
28
55
|
export { FileRule, StepConfig, StepResult };
|
package/dist/types/summary.d.ts
CHANGED
|
@@ -2,14 +2,18 @@ import { ResolutionStrategy } from "./resolution.js";
|
|
|
2
2
|
import { AiTokenUsage } from "@gitkraken/shared-tools";
|
|
3
3
|
|
|
4
4
|
//#region src/types/summary.d.ts
|
|
5
|
-
/** A file flagged for human review. `reason` distinguishes a low file-confidence flag
|
|
6
|
-
*
|
|
7
|
-
* auto-merged file with no resolution of its own). */
|
|
5
|
+
/** A file flagged for human review. `reason` distinguishes a low file-confidence flag, a detection
|
|
6
|
+
* finding, and a file the tool left unmerged. `confidence` is absent for files flagged purely by a
|
|
7
|
+
* finding (e.g. an auto-merged file with no resolution of its own) or as unresolved. */
|
|
8
8
|
interface ReviewItem {
|
|
9
9
|
filePath: string;
|
|
10
10
|
confidence?: number;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/** `unresolved` — an unmerged entry the tool did not resolve (no conflict markers to act on: a binary
|
|
12
|
+
* add/add, an unparseable delete-modify). It is still unmerged on disk, so the operation is not
|
|
13
|
+
* clean; a `skip`-rule exclusion is a deliberate human choice and is not flagged. */
|
|
14
|
+
reason: 'low-confidence' | 'finding' | 'unresolved';
|
|
15
|
+
/** Categories of the findings on this file, of any severity (error and warning alike); present when
|
|
16
|
+
* `reason` is `'finding'`. */
|
|
13
17
|
findingCategories?: string[];
|
|
14
18
|
}
|
|
15
19
|
/** Suggested honest verdict for the operation. `blocked` when any error-severity finding exists;
|
|
@@ -27,16 +31,19 @@ interface OperationDigest {
|
|
|
27
31
|
byStrategy: Record<ResolutionStrategy, number>;
|
|
28
32
|
/** Lowest file confidence across all resolutions; null when there are none. */
|
|
29
33
|
minConfidence: number | null;
|
|
30
|
-
/** Files needing review — low-confidence resolutions and files
|
|
31
|
-
* first, then lowest confidence first. */
|
|
34
|
+
/** Files needing review — low-confidence resolutions and files carrying any finding (error or
|
|
35
|
+
* warning), findings first, then lowest confidence first. */
|
|
32
36
|
needsReview: ReviewItem[];
|
|
33
37
|
/** Files skipped by rule or because they had no markers. */
|
|
34
38
|
skipped: number;
|
|
35
39
|
/** Files that errored during resolution. */
|
|
36
40
|
errors: number;
|
|
37
|
-
/** Whether
|
|
38
|
-
*
|
|
39
|
-
*
|
|
41
|
+
/** Whether detection achieved full coverage: both checks ran (a check that ran with some
|
|
42
|
+
* unsupported-language files in scope still counts — non-code files carry no references to break)
|
|
43
|
+
* *and* nothing was left unexamined (scope not truncated, incoming set discoverable). `false` when
|
|
44
|
+
* no detection was attached, a check was skipped/errored, the backend cannot resolve cross-file
|
|
45
|
+
* references, or part of the scope was never looked at — so empty findings must NOT be read as
|
|
46
|
+
* "clean". */
|
|
40
47
|
detectionComplete: boolean;
|
|
41
48
|
/** Total detection findings across the operation. */
|
|
42
49
|
findingCount: number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Finding } from "../types/findings.js";
|
|
2
|
+
import { ValidatorFinding } from "../ports/validator.js";
|
|
3
|
+
|
|
4
|
+
//#region src/validation/findings.d.ts
|
|
5
|
+
/** Lifts a consumer finding into the package's `Finding` shape. Validators run per file, so everything
|
|
6
|
+
* they report is `tier: 'file'`. */
|
|
7
|
+
declare function toFileFinding(finding: ValidatorFinding): Finding;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { toFileFinding };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){return{category:e.category,severity:e.severity,tier:`file`,location:{file:e.file,line:e.line??1},message:e.message}}export{e as toFileFinding};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Issue } from "../types/issue.js";
|
|
2
|
+
|
|
3
|
+
//#region src/validation/markers.d.ts
|
|
4
|
+
interface VerificationResult {
|
|
5
|
+
valid: boolean;
|
|
6
|
+
issues?: Issue[];
|
|
7
|
+
}
|
|
8
|
+
declare const CONFLICT_MARKER_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp];
|
|
9
|
+
declare function checkResidualMarkers(_filePath: string, content: string): VerificationResult;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CONFLICT_MARKER_PATTERNS, VerificationResult, checkResidualMarkers };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
const e=[/^<{7}(\s|$)/,/^\|{7}(\s|$)/,/^={7}(\s|$)/,/^>{7}(\s|$)/];function t(t,n){let r=n.split(`
|
|
2
|
-
`),i=[];for(let t=0;t<r.length;t++){let n=r[t]??``;for(let r of e)if(r.test(n)){i.push(t+1);break}}return i.length===0?{valid:!0}:{valid:!1,issues:[{severity:`error`,message:`Residual conflict markers found at line(s) ${i.join(`, `)}.`}]}}export{t as checkResidualMarkers};
|
|
2
|
+
`),i=[];for(let t=0;t<r.length;t++){let n=r[t]??``;for(let r of e)if(r.test(n)){i.push(t+1);break}}return i.length===0?{valid:!0}:{valid:!1,issues:[{severity:`error`,message:`Residual conflict markers found at line(s) ${i.join(`, `)}.`}]}}export{e as CONFLICT_MARKER_PATTERNS,t as checkResidualMarkers};
|
package/package.json
CHANGED
package/dist/ports/verify.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { SourceOverlay } from "./parser.js";
|
|
2
|
-
import { Issue } from "../types/issue.js";
|
|
3
|
-
|
|
4
|
-
//#region src/ports/verify.d.ts
|
|
5
|
-
interface VerificationResult {
|
|
6
|
-
valid: boolean;
|
|
7
|
-
issues?: Issue[];
|
|
8
|
-
}
|
|
9
|
-
interface ValidatorFinding {
|
|
10
|
-
/** Open category string set by the consumer (e.g. `'type-error'`, `'lint:no-console'`). */
|
|
11
|
-
category: string;
|
|
12
|
-
severity: 'error' | 'warning';
|
|
13
|
-
file: string;
|
|
14
|
-
/** 1-indexed. */
|
|
15
|
-
line?: number;
|
|
16
|
-
message: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* The consumer's validation port (RFC stages 5/7). Plug in any checks — syntax, real import
|
|
20
|
-
* resolution, types, lint, project rules. **Non-blocking**: runs post-refine over an overlay (one file
|
|
21
|
-
* for per-file validation, or the whole touched set for cross-file); its findings are advisory (folded
|
|
22
|
-
* into the operation's findings and verdict), never a re-resolve. The only blocking gate is residual
|
|
23
|
-
* conflict markers, checked built-in by the resolver ({@link checkResidualMarkers}) — not this port.
|
|
24
|
-
*/
|
|
25
|
-
interface Validator {
|
|
26
|
-
validate(sources: SourceOverlay): Promise<ValidatorFinding[]>;
|
|
27
|
-
}
|
|
28
|
-
declare function checkResidualMarkers(_filePath: string, content: string): VerificationResult;
|
|
29
|
-
//#endregion
|
|
30
|
-
export { Validator, ValidatorFinding, VerificationResult, checkResidualMarkers };
|