@deftai/directive-core 0.93.0 → 0.94.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/dist/cache/fetch.d.ts +29 -0
- package/dist/cache/fetch.js +131 -4
- package/dist/cache/operations.d.ts +8 -0
- package/dist/cache/operations.js +67 -4
- package/dist/check/cached-orchestrator.js +11 -0
- package/dist/check/consumer-gate-integrity.d.ts +68 -0
- package/dist/check/consumer-gate-integrity.js +265 -0
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/orchestrator.js +10 -0
- package/dist/content-contracts/skills/greptile-detector.d.ts +9 -0
- package/dist/content-contracts/skills/greptile-detector.js +9 -2
- package/dist/doctor/main.js +57 -0
- package/dist/finish-loop/pr-finish-loop.js +1 -0
- package/dist/hooks/dispatcher.d.ts +24 -2
- package/dist/hooks/dispatcher.js +122 -11
- package/dist/hooks/readonly.d.ts +14 -0
- package/dist/hooks/readonly.js +126 -0
- package/dist/intake/issue-ingest.d.ts +20 -0
- package/dist/intake/issue-ingest.js +58 -0
- package/dist/policy/index.d.ts +1 -0
- package/dist/policy/index.js +15 -1
- package/dist/policy/min-greptile-confidence.d.ts +57 -0
- package/dist/policy/min-greptile-confidence.js +123 -0
- package/dist/pr-merge-readiness/compute.d.ts +11 -1
- package/dist/pr-merge-readiness/compute.js +17 -4
- package/dist/pr-merge-readiness/evaluate.d.ts +8 -1
- package/dist/pr-merge-readiness/evaluate.js +7 -4
- package/dist/pr-merge-readiness/mergeability.d.ts +7 -1
- package/dist/pr-merge-readiness/mergeability.js +14 -2
- package/dist/pr-monitor/main.d.ts +2 -0
- package/dist/pr-monitor/main.js +31 -1
- package/dist/pr-monitor/monitor.js +5 -1
- package/dist/pr-monitor/readiness.js +3 -1
- package/dist/pr-monitor/types.d.ts +8 -0
- package/dist/pr-wait-mergeable/cascade.d.ts +8 -0
- package/dist/pr-wait-mergeable/cascade.js +28 -1
- package/dist/pr-wait-mergeable/main.d.ts +2 -0
- package/dist/pr-wait-mergeable/main.js +16 -0
- package/dist/pr-wait-mergeable/types.d.ts +3 -1
- package/dist/pr-wait-mergeable/wrappers.d.ts +6 -0
- package/dist/pr-wait-mergeable/wrappers.js +3 -0
- package/dist/pr-watch/constants.d.ts +4 -1
- package/dist/pr-watch/constants.js +5 -2
- package/dist/pr-watch/main.js +1 -0
- package/dist/pr-watch/probe.d.ts +1 -1
- package/dist/pr-watch/probe.js +4 -1
- package/dist/pr-watch/types.d.ts +7 -1
- package/dist/pr-watch/watch.js +3 -2
- package/dist/review-monitor/index.d.ts +1 -0
- package/dist/review-monitor/index.js +1 -0
- package/dist/review-monitor/l4-owner.d.ts +46 -0
- package/dist/review-monitor/l4-owner.js +262 -0
- package/dist/tool-events/classify.js +1 -0
- package/dist/triage/welcome/writers.js +16 -7
- package/dist/umbrella-current-shape/index.d.ts +45 -0
- package/dist/umbrella-current-shape/index.js +162 -8
- package/dist/vbrief-reconcile/index.d.ts +2 -2
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +31 -2
- package/dist/vbrief-reconcile/umbrellas.js +231 -19
- package/package.json +3 -3
package/dist/hooks/readonly.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
/** Session posture env for assist/research low-ceremony writes (#1802). */
|
|
2
|
+
export declare const ASSIST_SESSION_POSTURE_ENV = "DEFT_SESSION_POSTURE";
|
|
1
3
|
/** Best-effort read-only explore signal from host payload (#1185). */
|
|
2
4
|
export declare function hookReadOnlyFromPayload(payload: unknown): boolean;
|
|
3
5
|
/** Read-only hook context: env override or host payload marker (#1185). */
|
|
4
6
|
export declare function isReadOnlyHookContext(payload: unknown, environ?: NodeJS.ProcessEnv): boolean;
|
|
5
7
|
/** Explore sub-agent spawns are exempt from the implementation gate stack (#1185). */
|
|
6
8
|
export declare function isExploreSpawn(payload: unknown): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Assist / research / ephemeral session posture for low-ceremony scratch writes (#1802).
|
|
11
|
+
* Structural markers only (env, payload posture fields, worker_role/subagent_type).
|
|
12
|
+
* Absent marker → false (fail closed). Compose with allowlisted scratch path fence.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isAssistPosture(payload: unknown, environ?: NodeJS.ProcessEnv): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Ephemeral / assist / docs spawns skip active-xBRIEF implementation gates (#3080).
|
|
17
|
+
* True only with an explicit allowlisted marker. Absent marker → false (fail closed).
|
|
18
|
+
* When an ephemeral marker conflicts with implement envelope signals, implement wins.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isEphemeralSpawn(payload: unknown): boolean;
|
|
7
21
|
//# sourceMappingURL=readonly.d.ts.map
|
package/dist/hooks/readonly.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { READ_ONLY_HOOK_ENV } from "./tools.js";
|
|
2
2
|
const TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
3
|
+
/** Session posture env for assist/research low-ceremony writes (#1802). */
|
|
4
|
+
export const ASSIST_SESSION_POSTURE_ENV = "DEFT_SESSION_POSTURE";
|
|
5
|
+
/** Explicit non-lifecycle assist markers (#3080 / #1802). Primary: ephemeral; aliases: docs, assist. */
|
|
6
|
+
const EPHEMERAL_ROLE_MARKERS = new Set(["ephemeral", "docs", "assist"]);
|
|
7
|
+
/** Assist/research session posture tokens (structural; not free-text NLP) (#1802). */
|
|
8
|
+
const ASSIST_POSTURE_MARKERS = new Set([
|
|
9
|
+
"assist",
|
|
10
|
+
"ephemeral",
|
|
11
|
+
"docs",
|
|
12
|
+
"research",
|
|
13
|
+
"research-notes",
|
|
14
|
+
"research_notes",
|
|
15
|
+
"scratch",
|
|
16
|
+
]);
|
|
3
17
|
function record(value) {
|
|
4
18
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
5
19
|
? value
|
|
@@ -28,6 +42,9 @@ function isReadOnlyCapability(value) {
|
|
|
28
42
|
const normalized = value.toLowerCase().replace(/[_\s-]/g, "");
|
|
29
43
|
return normalized === "readonly";
|
|
30
44
|
}
|
|
45
|
+
function normalizePostureToken(value) {
|
|
46
|
+
return value.toLowerCase().replace(/[_\s]/g, "-");
|
|
47
|
+
}
|
|
31
48
|
/** Best-effort read-only explore signal from host payload (#1185). */
|
|
32
49
|
export function hookReadOnlyFromPayload(payload) {
|
|
33
50
|
const input = record(payload);
|
|
@@ -80,4 +97,113 @@ export function isExploreSpawn(payload) {
|
|
|
80
97
|
fieldString(input, "workerRole");
|
|
81
98
|
return workerRole?.toLowerCase() === "explore";
|
|
82
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Assist / research / ephemeral session posture for low-ceremony scratch writes (#1802).
|
|
102
|
+
* Structural markers only (env, payload posture fields, worker_role/subagent_type).
|
|
103
|
+
* Absent marker → false (fail closed). Compose with allowlisted scratch path fence.
|
|
104
|
+
*/
|
|
105
|
+
export function isAssistPosture(payload, environ = process.env) {
|
|
106
|
+
const envPosture = (environ[ASSIST_SESSION_POSTURE_ENV] ?? "").trim();
|
|
107
|
+
if (envPosture.length > 0 && ASSIST_POSTURE_MARKERS.has(normalizePostureToken(envPosture))) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
// Explicit assist env override (truthy), separate from posture token names.
|
|
111
|
+
if (envTruthy(environ, "DEFT_HOOK_ASSIST"))
|
|
112
|
+
return true;
|
|
113
|
+
const input = record(payload);
|
|
114
|
+
if (input === null)
|
|
115
|
+
return false;
|
|
116
|
+
const toolInput = toolInputRecord(input) ?? input;
|
|
117
|
+
const posture = fieldString(toolInput, "posture") ??
|
|
118
|
+
fieldString(toolInput, "session_posture") ??
|
|
119
|
+
fieldString(toolInput, "sessionPosture") ??
|
|
120
|
+
fieldString(input, "posture") ??
|
|
121
|
+
fieldString(input, "session_posture") ??
|
|
122
|
+
fieldString(input, "sessionPosture");
|
|
123
|
+
if (posture !== null && ASSIST_POSTURE_MARKERS.has(normalizePostureToken(posture))) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// Shared taxonomy with #3080 ephemeral spawn markers.
|
|
127
|
+
if (isEphemeralSpawn(payload))
|
|
128
|
+
return true;
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Structural implement signals that win over an ephemeral marker (fail closed, #3080).
|
|
133
|
+
* Detected from envelope fields only — never free-text prompt heuristics.
|
|
134
|
+
*/
|
|
135
|
+
function hasImplementConflictSignal(toolInput, input) {
|
|
136
|
+
const driveTo = fieldString(toolInput, "drive_to") ??
|
|
137
|
+
fieldString(toolInput, "driveTo") ??
|
|
138
|
+
fieldString(toolInput, "drive-to") ??
|
|
139
|
+
fieldString(input, "drive_to") ??
|
|
140
|
+
fieldString(input, "driveTo") ??
|
|
141
|
+
fieldString(input, "drive-to");
|
|
142
|
+
if (driveTo !== null) {
|
|
143
|
+
const normalized = driveTo.toLowerCase().replace(/[_\s]/g, "-");
|
|
144
|
+
if (normalized === "merge-ready" ||
|
|
145
|
+
normalized === "merge" ||
|
|
146
|
+
normalized.startsWith("merge-") ||
|
|
147
|
+
normalized.includes("implement")) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Non-ephemeral worker roles that imply product implementation / swarm leaf.
|
|
152
|
+
// Skip when this field is itself the ephemeral marker (conflict is via other fields).
|
|
153
|
+
const workerRole = fieldString(toolInput, "worker_role") ??
|
|
154
|
+
fieldString(toolInput, "workerRole") ??
|
|
155
|
+
fieldString(input, "worker_role") ??
|
|
156
|
+
fieldString(input, "workerRole");
|
|
157
|
+
if (workerRole !== null && !EPHEMERAL_ROLE_MARKERS.has(workerRole.toLowerCase())) {
|
|
158
|
+
const role = workerRole.toLowerCase().replace(/[_\s]/g, "-");
|
|
159
|
+
if (role === "leaf-implementation" ||
|
|
160
|
+
role === "implementation" ||
|
|
161
|
+
role === "implement" ||
|
|
162
|
+
role.includes("implement")) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const dispatchKind = fieldString(toolInput, "dispatch_kind") ??
|
|
167
|
+
fieldString(toolInput, "dispatchKind") ??
|
|
168
|
+
fieldString(input, "dispatch_kind") ??
|
|
169
|
+
fieldString(input, "dispatchKind");
|
|
170
|
+
if (dispatchKind !== null) {
|
|
171
|
+
const kind = dispatchKind.toLowerCase().replace(/[_\s]/g, "-");
|
|
172
|
+
if (kind === "swarm-cohort" || kind === "swarm-leaf" || kind.includes("implement")) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Ephemeral / assist / docs spawns skip active-xBRIEF implementation gates (#3080).
|
|
180
|
+
* True only with an explicit allowlisted marker. Absent marker → false (fail closed).
|
|
181
|
+
* When an ephemeral marker conflicts with implement envelope signals, implement wins.
|
|
182
|
+
*/
|
|
183
|
+
export function isEphemeralSpawn(payload) {
|
|
184
|
+
const input = record(payload);
|
|
185
|
+
if (input === null)
|
|
186
|
+
return false;
|
|
187
|
+
const toolInput = toolInputRecord(input) ?? input;
|
|
188
|
+
const subagentType = fieldString(toolInput, "subagent_type") ??
|
|
189
|
+
fieldString(toolInput, "subagentType") ??
|
|
190
|
+
fieldString(input, "subagent_type") ??
|
|
191
|
+
fieldString(input, "subagentType");
|
|
192
|
+
const workerRole = fieldString(toolInput, "worker_role") ??
|
|
193
|
+
fieldString(toolInput, "workerRole") ??
|
|
194
|
+
fieldString(input, "worker_role") ??
|
|
195
|
+
fieldString(input, "workerRole");
|
|
196
|
+
const marker = (workerRole !== null && EPHEMERAL_ROLE_MARKERS.has(workerRole.toLowerCase())
|
|
197
|
+
? workerRole.toLowerCase()
|
|
198
|
+
: null) ??
|
|
199
|
+
(subagentType !== null && EPHEMERAL_ROLE_MARKERS.has(subagentType.toLowerCase())
|
|
200
|
+
? subagentType.toLowerCase()
|
|
201
|
+
: null);
|
|
202
|
+
if (marker === null)
|
|
203
|
+
return false;
|
|
204
|
+
// Implement signals win over ephemeral markers (fail closed).
|
|
205
|
+
if (hasImplementConflictSignal(toolInput, input))
|
|
206
|
+
return false;
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
83
209
|
//# sourceMappingURL=readonly.js.map
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ScanFlag } from "../cache/scanner.js";
|
|
2
|
+
import { type IssueComment as ShapeIssueComment } from "../umbrella-current-shape/index.js";
|
|
2
3
|
import { LEGACY_ARTIFACT_SUFFIX, LEGACY_INFO_ROOT_KEY, MIGRATED_ARTIFACT_SUFFIX, MIGRATED_INFO_ROOT_KEY } from "../xbrief-migrate/constants.js";
|
|
3
4
|
import { type ScmCallFn } from "./reconcile-issues.js";
|
|
5
|
+
/** Reference type pointing at the canonical current-shape comment permalink (#1870). */
|
|
6
|
+
export declare const CURRENT_SHAPE_REF_TYPE: "x-xbrief/current-shape";
|
|
4
7
|
export declare const INGEST_STATUSES: readonly ["proposed", "pending", "active"];
|
|
5
8
|
export type IngestStatus = (typeof INGEST_STATUSES)[number];
|
|
6
9
|
/**
|
|
@@ -21,9 +24,26 @@ export interface IssueComment {
|
|
|
21
24
|
readonly login?: string;
|
|
22
25
|
};
|
|
23
26
|
readonly created_at?: string;
|
|
27
|
+
readonly updated_at?: string;
|
|
28
|
+
readonly html_url?: string;
|
|
29
|
+
readonly author_association?: string;
|
|
24
30
|
}
|
|
25
31
|
/** Enriched on issues after `fetchIssue` when the comment thread is non-empty (#2143). */
|
|
26
32
|
export declare const ISSUE_COMMENT_THREAD_KEY: "issueCommentThread";
|
|
33
|
+
/**
|
|
34
|
+
* Map ingest/REST comment rows onto the umbrella-current-shape selector input
|
|
35
|
+
* so #1152 pass-N + #2307 maintainer provenance rules apply (#1870).
|
|
36
|
+
*/
|
|
37
|
+
export declare function mapIngestCommentsToShapeComments(comments: readonly IssueComment[]): ShapeIssueComment[];
|
|
38
|
+
/**
|
|
39
|
+
* Select the canonical current-shape comment from an ingest comment thread.
|
|
40
|
+
* Returns null when none is maintainer-authored / header-matched.
|
|
41
|
+
*/
|
|
42
|
+
export declare function selectIngestCurrentShape(comments: readonly IssueComment[]): (ShapeIssueComment & {
|
|
43
|
+
pass: number;
|
|
44
|
+
}) | null;
|
|
45
|
+
/** Count maintainer current-shape comments (lint surface for !=1). */
|
|
46
|
+
export declare function countIngestCurrentShapeComments(comments: readonly IssueComment[]): number;
|
|
27
47
|
export declare function bodyControlCharacterLabels(body: string): string[];
|
|
28
48
|
export declare function warnBodyControlCharacters(number: number, body: string): void;
|
|
29
49
|
export declare function extractPlanItems(body: string): Record<string, string>[];
|
|
@@ -7,11 +7,14 @@ import { hasArtifactSuffix, resolveLifecycleRoot } from "../layout/resolve.js";
|
|
|
7
7
|
import { call } from "../scm/call.js";
|
|
8
8
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
9
9
|
import { resolveProjectRepo } from "../slice/project-context.js";
|
|
10
|
+
import { countMaintainerCurrentShapeComments, mapIssueCommentEntry, RAW_ISSUE_COMMENTS_KEY, selectCurrentShapeComment, } from "../umbrella-current-shape/index.js";
|
|
10
11
|
import { slugify, TODAY } from "../vbrief-build/build.js";
|
|
11
12
|
import { EMITTED_VBRIEF_VERSION } from "../vbrief-build/constants.js";
|
|
12
13
|
import { LEGACY_ARTIFACT_SUFFIX, LEGACY_INFO_ROOT_KEY, MIGRATED_ARTIFACT_DIR, MIGRATED_ARTIFACT_SUFFIX, MIGRATED_INFO_ROOT_KEY, VBRIEF_VERSION, } from "../xbrief-migrate/constants.js";
|
|
13
14
|
import { findAcHeading, parseCheckboxItems, parseListItems, sliceAcSection, stripCodeBlocks, stripFencedCodeBlocks, } from "./markdown-scanners.js";
|
|
14
15
|
import { detectRepo, extractReferencesFromVbrief, fetchOpenIssues, GITHUB_ISSUE_REF_TYPES, LIFECYCLE_FOLDERS, parseIssueNumber, } from "./reconcile-issues.js";
|
|
16
|
+
/** Reference type pointing at the canonical current-shape comment permalink (#1870). */
|
|
17
|
+
export const CURRENT_SHAPE_REF_TYPE = "x-xbrief/current-shape";
|
|
15
18
|
export const INGEST_STATUSES = ["proposed", "pending", "active"];
|
|
16
19
|
/**
|
|
17
20
|
* Thrown when the quarantine scanner hard-fails (credential-shaped content) on
|
|
@@ -36,6 +39,31 @@ export class ScannerHardFailError extends Error {
|
|
|
36
39
|
}
|
|
37
40
|
/** Enriched on issues after `fetchIssue` when the comment thread is non-empty (#2143). */
|
|
38
41
|
export const ISSUE_COMMENT_THREAD_KEY = "issueCommentThread";
|
|
42
|
+
/**
|
|
43
|
+
* Map ingest/REST comment rows onto the umbrella-current-shape selector input
|
|
44
|
+
* so #1152 pass-N + #2307 maintainer provenance rules apply (#1870).
|
|
45
|
+
*/
|
|
46
|
+
export function mapIngestCommentsToShapeComments(comments) {
|
|
47
|
+
const out = [];
|
|
48
|
+
for (const comment of comments) {
|
|
49
|
+
const mapped = mapIssueCommentEntry(comment);
|
|
50
|
+
if (mapped !== null) {
|
|
51
|
+
out.push(mapped);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Select the canonical current-shape comment from an ingest comment thread.
|
|
58
|
+
* Returns null when none is maintainer-authored / header-matched.
|
|
59
|
+
*/
|
|
60
|
+
export function selectIngestCurrentShape(comments) {
|
|
61
|
+
return selectCurrentShapeComment(mapIngestCommentsToShapeComments(comments));
|
|
62
|
+
}
|
|
63
|
+
/** Count maintainer current-shape comments (lint surface for !=1). */
|
|
64
|
+
export function countIngestCurrentShapeComments(comments) {
|
|
65
|
+
return countMaintainerCurrentShapeComments(mapIngestCommentsToShapeComments(comments));
|
|
66
|
+
}
|
|
39
67
|
const STATUS_MAP = {
|
|
40
68
|
proposed: ["proposed", "proposed"],
|
|
41
69
|
pending: ["pending", "pending"],
|
|
@@ -326,6 +354,11 @@ export function buildIssueVbrief(issue, status, repoUrl, options = {}) {
|
|
|
326
354
|
const bodyStr = typeof bodyRaw === "string" && bodyRaw.length > 0 ? bodyRaw : "";
|
|
327
355
|
const commentThread = issueCommentThread(issue);
|
|
328
356
|
const overviewSource = commentThread.length > 0 ? composeOverviewWithComments(bodyStr, commentThread) : bodyStr;
|
|
357
|
+
// #1870 / #1152: materialize the canonical Current shape comment as its own
|
|
358
|
+
// narrative so agents cannot plan umbrellas from the stale body alone. Prefer
|
|
359
|
+
// the same selector as `task umbrella:current-shape` (highest pass-N,
|
|
360
|
+
// maintainer-authored only — #2307).
|
|
361
|
+
const currentShape = selectIngestCurrentShape(commentThread);
|
|
329
362
|
const labelsRaw = issue.labels;
|
|
330
363
|
const labelNames = [];
|
|
331
364
|
if (Array.isArray(labelsRaw)) {
|
|
@@ -366,6 +399,10 @@ export function buildIssueVbrief(issue, status, repoUrl, options = {}) {
|
|
|
366
399
|
}
|
|
367
400
|
narratives.Overview = scanResult.transformed_content;
|
|
368
401
|
}
|
|
402
|
+
if (currentShape !== null) {
|
|
403
|
+
// Scan shape body under the same fail-closed contract as Overview (#2306).
|
|
404
|
+
narratives.CurrentShape = scanUntrustedIngestText(number, currentShape.body);
|
|
405
|
+
}
|
|
369
406
|
if (labelNames.length > 0) {
|
|
370
407
|
narratives.Labels = labelNames.join(", ");
|
|
371
408
|
}
|
|
@@ -392,6 +429,16 @@ export function buildIssueVbrief(issue, status, repoUrl, options = {}) {
|
|
|
392
429
|
title: `Issue #${number}: ${title}`,
|
|
393
430
|
},
|
|
394
431
|
];
|
|
432
|
+
if (currentShape !== null) {
|
|
433
|
+
const shapeUri = currentShape.htmlUrl.length > 0
|
|
434
|
+
? currentShape.htmlUrl
|
|
435
|
+
: `${url}#issuecomment-${currentShape.id}`;
|
|
436
|
+
references.push({
|
|
437
|
+
uri: shapeUri,
|
|
438
|
+
type: CURRENT_SHAPE_REF_TYPE,
|
|
439
|
+
title: `Current shape (pass-${currentShape.pass}) for #${number}`,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
395
442
|
if (overviewSource.length > 0 && repoUrl.length > 0) {
|
|
396
443
|
references.push(...extractCrossRefs(overviewSource, repoUrl, new Set([number])));
|
|
397
444
|
}
|
|
@@ -446,6 +493,12 @@ export function fetchFromCache(repo, number, options = {}) {
|
|
|
446
493
|
// the quarantine transform. When content.md is absent (e.g. a credential
|
|
447
494
|
// hard-fail deleted it), the raw body falls through and is re-scanned in
|
|
448
495
|
// buildIssueVbrief.
|
|
496
|
+
//
|
|
497
|
+
// #1870 note: content.md may also include the appended Canonical current
|
|
498
|
+
// shape section. That is intentional for agent-facing cache reads. When
|
|
499
|
+
// raw.comments is present we also restore the comment thread so
|
|
500
|
+
// narratives.CurrentShape + the current-shape reference can be materialised
|
|
501
|
+
// offline (without a live comments fetch).
|
|
449
502
|
if (result.contentPath !== null) {
|
|
450
503
|
try {
|
|
451
504
|
// #2314: content.md is `renderContent`-prefixed with a `# #<n>: <title>`
|
|
@@ -458,6 +511,11 @@ export function fetchFromCache(repo, number, options = {}) {
|
|
|
458
511
|
// fall back to the raw body (re-scanned downstream)
|
|
459
512
|
}
|
|
460
513
|
}
|
|
514
|
+
// #1870: restore comment thread from cache raw so CurrentShape survives
|
|
515
|
+
// offline / no-live-gh paths (fetchIssue still prefers live comments).
|
|
516
|
+
if (!issueCommentsAlreadyFetched(issue) && Array.isArray(issue[RAW_ISSUE_COMMENTS_KEY])) {
|
|
517
|
+
return attachIssueCommentThread(issue, issue[RAW_ISSUE_COMMENTS_KEY]);
|
|
518
|
+
}
|
|
461
519
|
return issue;
|
|
462
520
|
}
|
|
463
521
|
catch {
|
package/dist/policy/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./host-hooks.js";
|
|
|
9
9
|
export * from "./host-slash-commands.js";
|
|
10
10
|
export * from "./hotfix-criteria.js";
|
|
11
11
|
export * from "./intent-ceiling.js";
|
|
12
|
+
export * from "./min-greptile-confidence.js";
|
|
12
13
|
export * from "./no-deft-directive.js";
|
|
13
14
|
export * from "./org-force-on-migration.js";
|
|
14
15
|
export * from "./plan-extensions.js";
|
package/dist/policy/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { FIELD_DELIVERY_BRANCH, FIELD_DELIVERY_BRANCH_CLI_ALIAS, inspectDelivery
|
|
|
4
4
|
import { FIELD_HOST_HOOKS, FIELD_HOST_HOOKS_CLI_ALIAS, inspectHostHooks } from "./host-hooks.js";
|
|
5
5
|
import { FIELD_HOST_SLASH_COMMANDS, FIELD_HOST_SLASH_COMMANDS_CLI_ALIAS, inspectHostSlashCommands, } from "./host-slash-commands.js";
|
|
6
6
|
import { FIELD_HOTFIX_CRITERIA, FIELD_HOTFIX_CRITERIA_CLI_ALIAS, inspectHotfixCriteria, } from "./hotfix-criteria.js";
|
|
7
|
+
import { FIELD_MIN_GREPTILE_CONFIDENCE, FIELD_MIN_GREPTILE_CONFIDENCE_CLI_ALIAS, inspectMinGreptileConfidence, } from "./min-greptile-confidence.js";
|
|
7
8
|
import { readPlanPolicy } from "./plan-extensions.js";
|
|
8
9
|
import { FIELD_PRODUCT_SIGNAL, FIELD_PRODUCT_SIGNAL_CLI_ALIAS, inspectProductSignal, } from "./product-signal.js";
|
|
9
10
|
import { FIELD_REQUIRE_HUMAN_MERGE, FIELD_REQUIRE_HUMAN_MERGE_CLI_ALIAS, inspectRequireHumanMerge, } from "./require-human-merge.js";
|
|
@@ -23,6 +24,7 @@ export * from "./host-hooks.js";
|
|
|
23
24
|
export * from "./host-slash-commands.js";
|
|
24
25
|
export * from "./hotfix-criteria.js";
|
|
25
26
|
export * from "./intent-ceiling.js";
|
|
27
|
+
export * from "./min-greptile-confidence.js";
|
|
26
28
|
export * from "./no-deft-directive.js";
|
|
27
29
|
export * from "./org-force-on-migration.js";
|
|
28
30
|
export * from "./plan-extensions.js";
|
|
@@ -340,6 +342,15 @@ function inspectDeliveryBranchField(data, projectRoot) {
|
|
|
340
342
|
source: field.source,
|
|
341
343
|
};
|
|
342
344
|
}
|
|
345
|
+
function inspectMinGreptileConfidenceField(data, projectRoot) {
|
|
346
|
+
const field = inspectMinGreptileConfidence(data, projectRoot);
|
|
347
|
+
return {
|
|
348
|
+
name: field.name,
|
|
349
|
+
current: field.current,
|
|
350
|
+
default: field.default,
|
|
351
|
+
source: field.source,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
343
354
|
const REGISTERED_POLICIES = [
|
|
344
355
|
inspectAllowDirectCommits,
|
|
345
356
|
inspectWipCap,
|
|
@@ -353,6 +364,7 @@ const REGISTERED_POLICIES = [
|
|
|
353
364
|
}),
|
|
354
365
|
inspectSwarmSubagentBackend,
|
|
355
366
|
inspectDeliveryBranchField,
|
|
367
|
+
inspectMinGreptileConfidenceField,
|
|
356
368
|
inspectHostHooksField,
|
|
357
369
|
inspectHostSlashCommandsField,
|
|
358
370
|
inspectOpenClawProductCommandsField,
|
|
@@ -393,7 +405,9 @@ export function inspectOnePolicy(name, projectRoot) {
|
|
|
393
405
|
? FIELD_HOTFIX_CRITERIA
|
|
394
406
|
: name === FIELD_DELIVERY_BRANCH_CLI_ALIAS
|
|
395
407
|
? FIELD_DELIVERY_BRANCH
|
|
396
|
-
: name
|
|
408
|
+
: name === FIELD_MIN_GREPTILE_CONFIDENCE_CLI_ALIAS
|
|
409
|
+
? FIELD_MIN_GREPTILE_CONFIDENCE
|
|
410
|
+
: name;
|
|
397
411
|
for (const field of inspectAllPolicies(projectRoot)) {
|
|
398
412
|
if (field.name === normalized)
|
|
399
413
|
return field;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed plan.policy.review.minGreptileConfidence (#3095).
|
|
3
|
+
*
|
|
4
|
+
* CLEAN / merge-ready require Greptile confidence >= min (score out of 5).
|
|
5
|
+
* Resolution order: explicit project policy > framework dogfood detect > consumer default.
|
|
6
|
+
*
|
|
7
|
+
* - Consumer default: 4 (legacy bar confidence > 3, i.e. 4/5 or 5/5)
|
|
8
|
+
* - Directive dogfood (framework source checkout): 5 (5/5 required)
|
|
9
|
+
*/
|
|
10
|
+
/** Canonical dotted path for policy:show / PROJECT-DEFINITION. */
|
|
11
|
+
export declare const FIELD_MIN_GREPTILE_CONFIDENCE = "plan.policy.review.minGreptileConfidence";
|
|
12
|
+
/** CLI alias for `task policy:show --field=minGreptileConfidence`. */
|
|
13
|
+
export declare const FIELD_MIN_GREPTILE_CONFIDENCE_CLI_ALIAS = "minGreptileConfidence";
|
|
14
|
+
/**
|
|
15
|
+
* Consumer default minimum confidence that still CLEANs (#3095).
|
|
16
|
+
* Matches the historical gate `confidence > 3` (i.e. score >= 4).
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE = 4;
|
|
19
|
+
/** Directive dogfood bar: CLEAN requires confidence == 5/5. */
|
|
20
|
+
export declare const DOGFOOD_MIN_GREPTILE_CONFIDENCE = 5;
|
|
21
|
+
export declare const MIN_GREPTILE_CONFIDENCE_FLOOR = 1;
|
|
22
|
+
export declare const MIN_GREPTILE_CONFIDENCE_CEILING = 5;
|
|
23
|
+
export type MinGreptileConfidenceSource = "typed" | "dogfood" | "default" | "default-on-error";
|
|
24
|
+
export interface MinGreptileConfidenceResolved {
|
|
25
|
+
/** Minimum score (1–5) that satisfies CLEAN; score must be >= min. */
|
|
26
|
+
readonly min: number;
|
|
27
|
+
readonly source: MinGreptileConfidenceSource;
|
|
28
|
+
readonly error: string | null;
|
|
29
|
+
}
|
|
30
|
+
/** True when score is present and meets the minimum floor. */
|
|
31
|
+
export declare function meetsMinGreptileConfidence(confidence: number | null | undefined, min: number): boolean;
|
|
32
|
+
/** Human-facing phrase for the active bar (legacy "> 3" when min is 4). */
|
|
33
|
+
export declare function formatMinConfidenceRequirement(min: number): string;
|
|
34
|
+
/** Validate a raw integer-ish min confidence value. */
|
|
35
|
+
export declare function validateMinGreptileConfidence(raw: unknown): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Read nested plan.policy.review.minGreptileConfidence from a policy block.
|
|
38
|
+
* Returns undefined when the key is absent.
|
|
39
|
+
*/
|
|
40
|
+
export declare function readMinGreptileConfidenceFromPolicyBlock(policyBlock: unknown): unknown | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve min Greptile confidence for CLEAN gates (#3095).
|
|
43
|
+
*
|
|
44
|
+
* 1. Explicit typed plan.policy.review.minGreptileConfidence
|
|
45
|
+
* 2. Framework dogfood detection (framework source repo root) → 5
|
|
46
|
+
* 3. Consumer default → 4
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveMinGreptileConfidence(projectRoot?: string | null): MinGreptileConfidenceResolved;
|
|
49
|
+
export interface MinGreptileConfidencePolicyField {
|
|
50
|
+
readonly name: typeof FIELD_MIN_GREPTILE_CONFIDENCE;
|
|
51
|
+
readonly current: number;
|
|
52
|
+
readonly default: number;
|
|
53
|
+
readonly source: string;
|
|
54
|
+
}
|
|
55
|
+
/** Inspector row for `task policy:show --field=minGreptileConfidence` (#3095). */
|
|
56
|
+
export declare function inspectMinGreptileConfidence(_data: Record<string, unknown> | null, projectRoot?: string): MinGreptileConfidencePolicyField;
|
|
57
|
+
//# sourceMappingURL=min-greptile-confidence.d.ts.map
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed plan.policy.review.minGreptileConfidence (#3095).
|
|
3
|
+
*
|
|
4
|
+
* CLEAN / merge-ready require Greptile confidence >= min (score out of 5).
|
|
5
|
+
* Resolution order: explicit project policy > framework dogfood detect > consumer default.
|
|
6
|
+
*
|
|
7
|
+
* - Consumer default: 4 (legacy bar confidence > 3, i.e. 4/5 or 5/5)
|
|
8
|
+
* - Directive dogfood (framework source checkout): 5 (5/5 required)
|
|
9
|
+
*/
|
|
10
|
+
import { isFrameworkRepoRoot } from "../check/context.js";
|
|
11
|
+
import { readPlanPolicy } from "./plan-extensions.js";
|
|
12
|
+
import { loadProjectDefinition } from "./resolve.js";
|
|
13
|
+
/** Canonical dotted path for policy:show / PROJECT-DEFINITION. */
|
|
14
|
+
export const FIELD_MIN_GREPTILE_CONFIDENCE = "plan.policy.review.minGreptileConfidence";
|
|
15
|
+
/** CLI alias for `task policy:show --field=minGreptileConfidence`. */
|
|
16
|
+
export const FIELD_MIN_GREPTILE_CONFIDENCE_CLI_ALIAS = "minGreptileConfidence";
|
|
17
|
+
/**
|
|
18
|
+
* Consumer default minimum confidence that still CLEANs (#3095).
|
|
19
|
+
* Matches the historical gate `confidence > 3` (i.e. score >= 4).
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE = 4;
|
|
22
|
+
/** Directive dogfood bar: CLEAN requires confidence == 5/5. */
|
|
23
|
+
export const DOGFOOD_MIN_GREPTILE_CONFIDENCE = 5;
|
|
24
|
+
export const MIN_GREPTILE_CONFIDENCE_FLOOR = 1;
|
|
25
|
+
export const MIN_GREPTILE_CONFIDENCE_CEILING = 5;
|
|
26
|
+
function defaultResolved(source, min, error = null) {
|
|
27
|
+
return { min, source, error };
|
|
28
|
+
}
|
|
29
|
+
/** True when score is present and meets the minimum floor. */
|
|
30
|
+
export function meetsMinGreptileConfidence(confidence, min) {
|
|
31
|
+
if (confidence === null || confidence === undefined) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return confidence >= min;
|
|
35
|
+
}
|
|
36
|
+
/** Human-facing phrase for the active bar (legacy "> 3" when min is 4). */
|
|
37
|
+
export function formatMinConfidenceRequirement(min) {
|
|
38
|
+
if (min === DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE) {
|
|
39
|
+
return `> ${min - 1} (i.e. ${min}/5+)`;
|
|
40
|
+
}
|
|
41
|
+
return `>= ${min}/5`;
|
|
42
|
+
}
|
|
43
|
+
/** Validate a raw integer-ish min confidence value. */
|
|
44
|
+
export function validateMinGreptileConfidence(raw) {
|
|
45
|
+
if (typeof raw !== "number" || !Number.isInteger(raw)) {
|
|
46
|
+
return `${FIELD_MIN_GREPTILE_CONFIDENCE} must be an integer ${MIN_GREPTILE_CONFIDENCE_FLOOR}–${MIN_GREPTILE_CONFIDENCE_CEILING}; got ${typeof raw}`;
|
|
47
|
+
}
|
|
48
|
+
if (raw < MIN_GREPTILE_CONFIDENCE_FLOOR || raw > MIN_GREPTILE_CONFIDENCE_CEILING) {
|
|
49
|
+
return `${FIELD_MIN_GREPTILE_CONFIDENCE} must be between ${MIN_GREPTILE_CONFIDENCE_FLOOR} and ${MIN_GREPTILE_CONFIDENCE_CEILING}; got ${raw}`;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Read nested plan.policy.review.minGreptileConfidence from a policy block.
|
|
55
|
+
* Returns undefined when the key is absent.
|
|
56
|
+
*/
|
|
57
|
+
export function readMinGreptileConfidenceFromPolicyBlock(policyBlock) {
|
|
58
|
+
if (typeof policyBlock !== "object" || policyBlock === null || Array.isArray(policyBlock)) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const rec = policyBlock;
|
|
62
|
+
if (!("review" in rec)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const review = rec.review;
|
|
66
|
+
if (typeof review !== "object" || review === null || Array.isArray(review)) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const reviewRec = review;
|
|
70
|
+
if (!("minGreptileConfidence" in reviewRec)) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return reviewRec.minGreptileConfidence;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve min Greptile confidence for CLEAN gates (#3095).
|
|
77
|
+
*
|
|
78
|
+
* 1. Explicit typed plan.policy.review.minGreptileConfidence
|
|
79
|
+
* 2. Framework dogfood detection (framework source repo root) → 5
|
|
80
|
+
* 3. Consumer default → 4
|
|
81
|
+
*/
|
|
82
|
+
export function resolveMinGreptileConfidence(projectRoot) {
|
|
83
|
+
if (projectRoot !== undefined && projectRoot !== null && projectRoot.length > 0) {
|
|
84
|
+
const [data, err] = loadProjectDefinition(projectRoot);
|
|
85
|
+
if (data !== null) {
|
|
86
|
+
const policyBlock = readPlanPolicy(data.plan);
|
|
87
|
+
const raw = readMinGreptileConfidenceFromPolicyBlock(policyBlock);
|
|
88
|
+
if (raw !== undefined) {
|
|
89
|
+
const validationError = validateMinGreptileConfidence(raw);
|
|
90
|
+
if (validationError !== null) {
|
|
91
|
+
// Invalid typed value: fall through to dogfood/default with error recorded.
|
|
92
|
+
if (isFrameworkRepoRoot(projectRoot)) {
|
|
93
|
+
return defaultResolved("dogfood", DOGFOOD_MIN_GREPTILE_CONFIDENCE, validationError);
|
|
94
|
+
}
|
|
95
|
+
return defaultResolved("default-on-error", DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE, validationError);
|
|
96
|
+
}
|
|
97
|
+
return defaultResolved("typed", raw, null);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (err !== null && err.length > 0) {
|
|
101
|
+
// Missing PROJECT-DEFINITION is not fatal; dogfood/default still apply.
|
|
102
|
+
if (isFrameworkRepoRoot(projectRoot)) {
|
|
103
|
+
return defaultResolved("dogfood", DOGFOOD_MIN_GREPTILE_CONFIDENCE, null);
|
|
104
|
+
}
|
|
105
|
+
return defaultResolved("default", DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE, err);
|
|
106
|
+
}
|
|
107
|
+
if (isFrameworkRepoRoot(projectRoot)) {
|
|
108
|
+
return defaultResolved("dogfood", DOGFOOD_MIN_GREPTILE_CONFIDENCE, null);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return defaultResolved("default", DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE, null);
|
|
112
|
+
}
|
|
113
|
+
/** Inspector row for `task policy:show --field=minGreptileConfidence` (#3095). */
|
|
114
|
+
export function inspectMinGreptileConfidence(_data, projectRoot) {
|
|
115
|
+
const resolved = resolveMinGreptileConfidence(projectRoot);
|
|
116
|
+
return {
|
|
117
|
+
name: FIELD_MIN_GREPTILE_CONFIDENCE,
|
|
118
|
+
current: resolved.min,
|
|
119
|
+
default: DEFAULT_CONSUMER_MIN_GREPTILE_CONFIDENCE,
|
|
120
|
+
source: resolved.source,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=min-greptile-confidence.js.map
|
|
@@ -4,7 +4,7 @@ import { type InlineGreptileFindings } from "./greptile-inline.js";
|
|
|
4
4
|
import { type MergeabilitySignal } from "./mergeability.js";
|
|
5
5
|
import type { SlizardGateOptions } from "./slizard-gate.js";
|
|
6
6
|
import type { GateResult, RunGhFn } from "./types.js";
|
|
7
|
-
declare function buildGateResult(prNumber: number, repo: string | null, headSha: string | null, body: string, via: string, partialData?: Record<string, unknown>, error?: string | null, inline?: InlineGreptileFindings | null): GateResult;
|
|
7
|
+
declare function buildGateResult(prNumber: number, repo: string | null, headSha: string | null, body: string, via: string, partialData?: Record<string, unknown>, error?: string | null, inline?: InlineGreptileFindings | null, minConfidence?: number): GateResult;
|
|
8
8
|
/** Injectable GitHub-mergeability read seam (#2260) — keeps unit tests hermetic. */
|
|
9
9
|
export type FetchMergeabilityFn = (prNumber: number, repo: string, runGh: RunGhFn) => MergeabilitySignal;
|
|
10
10
|
export interface ComputeGateOptions extends CiGateOptions, SlizardGateOptions {
|
|
@@ -15,6 +15,16 @@ export interface ComputeGateOptions extends CiGateOptions, SlizardGateOptions {
|
|
|
15
15
|
* off, an absent/stale review verdict blocks even on a GitHub-CLEAN PR.
|
|
16
16
|
*/
|
|
17
17
|
readonly disableMergeabilityReconcile?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Project root for resolving plan.policy.review.minGreptileConfidence (#3095).
|
|
20
|
+
* Defaults to process.cwd() when omitted.
|
|
21
|
+
*/
|
|
22
|
+
readonly projectRoot?: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Override the resolved min confidence (1–5). When set, skips policy resolve.
|
|
25
|
+
* Tests and injectors use this; production callers leave it unset.
|
|
26
|
+
*/
|
|
27
|
+
readonly minConfidence?: number;
|
|
18
28
|
}
|
|
19
29
|
/** Run the primary->fallback1->fallback2 cascade and return a result. */
|
|
20
30
|
export declare function computeGateResult(prNumber: number, repo: string | null, runGh: RunGhFn, options?: ComputeGateOptions): GateResult;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveMinGreptileConfidence } from "../policy/min-greptile-confidence.js";
|
|
1
2
|
import { buildCiSummaryLine, evaluateCiGate } from "./ci-gate.js";
|
|
2
3
|
import { FALLBACK2_NOT_CLEAN_MSG, VIA_ERROR, VIA_FALLBACK1, VIA_FALLBACK2, VIA_PRIMARY, } from "./constants.js";
|
|
3
4
|
import { evaluateGates, isMergeReady } from "./evaluate.js";
|
|
@@ -6,9 +7,11 @@ import { fetchUnresolvedGreptileInlineFindings, inlineFindingsToDict, } from "./
|
|
|
6
7
|
import { fetchMergeability, isGithubMergeableClean, mergeabilityToDict, verdictBlockIsSoftOnly, verdictShaIsStale, } from "./mergeability.js";
|
|
7
8
|
import { emptyVerdict, parseGreptileBody } from "./parse.js";
|
|
8
9
|
import { evaluateSlizardGate, isSlizardCheck } from "./slizard-gate.js";
|
|
9
|
-
function buildGateResult(prNumber, repo, headSha, body, via, partialData = {}, error = null, inline = null) {
|
|
10
|
+
function buildGateResult(prNumber, repo, headSha, body, via, partialData = {}, error = null, inline = null, minConfidence) {
|
|
10
11
|
const verdict = parseGreptileBody(body);
|
|
11
|
-
const failures = evaluateGates(prNumber, headSha, verdict, inline
|
|
12
|
+
const failures = evaluateGates(prNumber, headSha, verdict, inline, {
|
|
13
|
+
minConfidence,
|
|
14
|
+
});
|
|
12
15
|
return {
|
|
13
16
|
prNumber,
|
|
14
17
|
repo,
|
|
@@ -20,6 +23,12 @@ function buildGateResult(prNumber, repo, headSha, body, via, partialData = {}, e
|
|
|
20
23
|
error,
|
|
21
24
|
};
|
|
22
25
|
}
|
|
26
|
+
function resolvedMinConfidence(options) {
|
|
27
|
+
if (options.minConfidence !== undefined) {
|
|
28
|
+
return options.minConfidence;
|
|
29
|
+
}
|
|
30
|
+
return resolveMinGreptileConfidence(options.projectRoot ?? process.cwd()).min;
|
|
31
|
+
}
|
|
23
32
|
/** Run the CI + SLizard gates off a single check-runs fetch (#2169 / #2189). */
|
|
24
33
|
function evaluateCiAndSlizard(checkRuns, options) {
|
|
25
34
|
const slizardResult = evaluateSlizardGate(checkRuns, options);
|
|
@@ -110,7 +119,11 @@ function finalizeVerdictGate(prNumber, repo, headSha, verdict, runGh, options) {
|
|
|
110
119
|
const resolved = resolveRepo(repo, runGh);
|
|
111
120
|
const inline = loadInlineGreptileFindings(prNumber, repo, headSha, runGh);
|
|
112
121
|
partialData.greptile_inline = inlineFindingsToDict(inline);
|
|
113
|
-
const
|
|
122
|
+
const minConfidence = resolvedMinConfidence(options);
|
|
123
|
+
partialData.min_greptile_confidence = minConfidence;
|
|
124
|
+
const failures = evaluateGates(prNumber, headSha, verdict, inline, {
|
|
125
|
+
minConfidence,
|
|
126
|
+
});
|
|
114
127
|
if (failures.length === 0) {
|
|
115
128
|
const ci = applyCiGateForHead(resolved.repo, headSha, runGh, options);
|
|
116
129
|
failures.push(...ci.failures);
|
|
@@ -123,7 +136,7 @@ function finalizeVerdictGate(prNumber, repo, headSha, verdict, runGh, options) {
|
|
|
123
136
|
// blocking. Only reconcile a SOFT block (verdict absent / stale head SHA).
|
|
124
137
|
if (options.disableMergeabilityReconcile === true ||
|
|
125
138
|
resolved.repo === null ||
|
|
126
|
-
!verdictBlockIsSoftOnly(verdict, headSha, inline)) {
|
|
139
|
+
!verdictBlockIsSoftOnly(verdict, headSha, inline, minConfidence)) {
|
|
127
140
|
return { failures, partialData };
|
|
128
141
|
}
|
|
129
142
|
const ci = applyCiGateForHead(resolved.repo, headSha, runGh, options);
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type { InlineGreptileFindings } from "./greptile-inline.js";
|
|
2
2
|
import type { GreptileVerdict } from "./types.js";
|
|
3
|
+
export interface EvaluateGatesOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Minimum Greptile confidence (1–5) that satisfies CLEAN (#3095).
|
|
6
|
+
* Defaults to the consumer bar (4 == legacy confidence > 3).
|
|
7
|
+
*/
|
|
8
|
+
readonly minConfidence?: number;
|
|
9
|
+
}
|
|
3
10
|
/** Return failure messages (empty list == merge-ready). */
|
|
4
|
-
export declare function evaluateGates(_prNumber: number, headSha: string | null, verdict: GreptileVerdict, inline?: InlineGreptileFindings | null): string[];
|
|
11
|
+
export declare function evaluateGates(_prNumber: number, headSha: string | null, verdict: GreptileVerdict, inline?: InlineGreptileFindings | null, options?: EvaluateGatesOptions): string[];
|
|
5
12
|
export declare function isMergeReady(failures: readonly string[]): boolean;
|
|
6
13
|
//# sourceMappingURL=evaluate.d.ts.map
|