clud-bug 0.6.34 → 0.7.0-rc.11
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/README.md +20 -0
- package/bin/clud-bug.js +10 -1353
- package/data/canonical-v1.json +37 -0
- package/dist/cli/agents-md.d.ts +16 -0
- package/dist/cli/agents-md.d.ts.map +1 -0
- package/dist/cli/agents-md.js +226 -0
- package/dist/cli/agents-md.js.map +1 -0
- package/dist/cli/audit.d.ts +13 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +90 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/branch-protection.d.ts +57 -0
- package/dist/cli/branch-protection.d.ts.map +1 -0
- package/dist/cli/branch-protection.js +118 -0
- package/dist/cli/branch-protection.js.map +1 -0
- package/dist/cli/configure-github.d.ts +58 -0
- package/dist/cli/configure-github.d.ts.map +1 -0
- package/dist/cli/configure-github.js +242 -0
- package/dist/cli/configure-github.js.map +1 -0
- package/dist/cli/edit-workflow.d.ts +18 -0
- package/dist/cli/edit-workflow.d.ts.map +1 -0
- package/dist/cli/edit-workflow.js +43 -0
- package/dist/cli/edit-workflow.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +2067 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/skill-usage.d.ts +109 -0
- package/dist/cli/skill-usage.d.ts.map +1 -0
- package/dist/cli/skill-usage.js +380 -0
- package/dist/cli/skill-usage.js.map +1 -0
- package/dist/cli/skills.d.ts +56 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +292 -0
- package/dist/cli/skills.js.map +1 -0
- package/dist/cli/update.d.ts +29 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +205 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/usage.d.ts +142 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +348 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/core/audit.d.ts +8 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +47 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/auto-resolve.d.ts +235 -0
- package/dist/core/auto-resolve.d.ts.map +1 -0
- package/dist/core/auto-resolve.js +293 -0
- package/dist/core/auto-resolve.js.map +1 -0
- package/dist/core/configure-github.d.ts +179 -0
- package/dist/core/configure-github.d.ts.map +1 -0
- package/dist/core/configure-github.js +289 -0
- package/dist/core/configure-github.js.map +1 -0
- package/dist/core/detect.d.ts +77 -0
- package/dist/core/detect.d.ts.map +1 -0
- package/dist/core/detect.js +262 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/diff-findings.d.ts +96 -0
- package/dist/core/diff-findings.d.ts.map +1 -0
- package/dist/core/diff-findings.js +261 -0
- package/dist/core/diff-findings.js.map +1 -0
- package/dist/core/formal-review.d.ts +79 -0
- package/dist/core/formal-review.d.ts.map +1 -0
- package/dist/core/formal-review.js +71 -0
- package/dist/core/formal-review.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +66 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/inline-threads.d.ts +160 -0
- package/dist/core/inline-threads.d.ts.map +1 -0
- package/dist/core/inline-threads.js +369 -0
- package/dist/core/inline-threads.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +164 -0
- package/dist/core/prompt-builder.d.ts.map +1 -0
- package/dist/core/prompt-builder.js +419 -0
- package/dist/core/prompt-builder.js.map +1 -0
- package/dist/core/prompts.d.ts +9 -0
- package/dist/core/prompts.d.ts.map +1 -0
- package/dist/core/prompts.js +401 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/render-review.d.ts +6 -0
- package/dist/core/render-review.d.ts.map +1 -0
- package/dist/core/render-review.js +219 -0
- package/dist/core/render-review.js.map +1 -0
- package/dist/core/render.d.ts +13 -0
- package/dist/core/render.d.ts.map +1 -0
- package/dist/core/render.js +62 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/resolve-verifier.d.ts +46 -0
- package/dist/core/resolve-verifier.d.ts.map +1 -0
- package/dist/core/resolve-verifier.js +187 -0
- package/dist/core/resolve-verifier.js.map +1 -0
- package/dist/core/review-schema-zod.d.ts +240 -0
- package/dist/core/review-schema-zod.d.ts.map +1 -0
- package/dist/core/review-schema-zod.js +218 -0
- package/dist/core/review-schema-zod.js.map +1 -0
- package/dist/core/review-schema.d.ts +42 -0
- package/dist/core/review-schema.d.ts.map +1 -0
- package/dist/core/review-schema.js +156 -0
- package/dist/core/review-schema.js.map +1 -0
- package/dist/core/review-writeback.d.ts +193 -0
- package/dist/core/review-writeback.d.ts.map +1 -0
- package/dist/core/review-writeback.js +364 -0
- package/dist/core/review-writeback.js.map +1 -0
- package/dist/core/skills.d.ts +147 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +726 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +4 -0
- package/dist/core/version.js.map +1 -0
- package/package.json +37 -5
- package/{lib/agents-md.js → src/cli/agents-md.ts} +25 -14
- package/{lib/audit.js → src/cli/audit.ts} +37 -44
- package/{lib/branch-protection.js → src/cli/branch-protection.ts} +75 -11
- package/src/cli/configure-github.ts +329 -0
- package/{lib/edit-workflow.js → src/cli/edit-workflow.ts} +32 -11
- package/src/cli/index.ts +107 -0
- package/src/cli/main.ts +2204 -0
- package/{lib/skill-usage.js → src/cli/skill-usage.ts} +168 -94
- package/src/cli/skills.ts +386 -0
- package/{lib/update.js → src/cli/update.ts} +87 -27
- package/{lib/usage.js → src/cli/usage.ts} +167 -76
- package/src/core/audit.ts +53 -0
- package/src/core/auto-resolve.ts +488 -0
- package/src/core/configure-github.ts +497 -0
- package/{lib/detect.js → src/core/detect.ts} +100 -47
- package/src/core/diff-findings.ts +323 -0
- package/src/core/formal-review.ts +168 -0
- package/src/core/index.ts +250 -0
- package/src/core/inline-threads.ts +471 -0
- package/src/core/prompt-builder.ts +561 -0
- package/{lib/prompts.js → src/core/prompts.ts} +16 -2
- package/{lib/render-review.js → src/core/render-review.ts} +57 -25
- package/{lib/render.js → src/core/render.ts} +37 -17
- package/src/core/resolve-verifier.ts +228 -0
- package/src/core/review-schema-zod.ts +262 -0
- package/{lib/review-schema.js → src/core/review-schema.ts} +68 -5
- package/src/core/review-writeback.ts +565 -0
- package/{lib/skills.js → src/core/skills.ts} +456 -342
- package/src/core/version.ts +3 -0
- package/templates/clud-bug-review.md.tmpl +115 -0
- package/templates/workflow-py.yml.tmpl +80 -3
- package/templates/workflow-ts.yml.tmpl +80 -3
- package/templates/workflow.yml.tmpl +175 -8
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { Severity } from './inline-threads.js';
|
|
2
|
+
/** Configuration for `autoResolve` in `.clud-bug.json`. */
|
|
3
|
+
export interface AutoResolveConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Which mode the install opted into.
|
|
6
|
+
* - 'verified' (default): call the verifier per thread.
|
|
7
|
+
* - 'off': do nothing — all threads stay open, no verifier calls.
|
|
8
|
+
*/
|
|
9
|
+
mode: 'verified' | 'off';
|
|
10
|
+
/**
|
|
11
|
+
* Action to take when the verifier returns UNCERTAIN + the original
|
|
12
|
+
* finding was 🔴 critical.
|
|
13
|
+
*
|
|
14
|
+
* - 'request_changes' (default): keep open + flag REQUEST_CHANGES.
|
|
15
|
+
* - 'leave_open': keep open with a milder marker, no escalation.
|
|
16
|
+
*/
|
|
17
|
+
uncertain_critical_action: 'request_changes' | 'leave_open';
|
|
18
|
+
}
|
|
19
|
+
export declare const DEFAULT_AUTO_RESOLVE_CONFIG: AutoResolveConfig;
|
|
20
|
+
/**
|
|
21
|
+
* One open thread from a prior review pass, plus enough state to verify
|
|
22
|
+
* it. The CLI verb hands these to `runAutoResolve` after parsing the
|
|
23
|
+
* GraphQL response + the bot's comment-body markers.
|
|
24
|
+
*/
|
|
25
|
+
export interface PriorThread {
|
|
26
|
+
/** GitHub review-thread node ID (GraphQL ID). Used to resolve the thread. */
|
|
27
|
+
threadId: string;
|
|
28
|
+
/** The prior finding the thread anchors. */
|
|
29
|
+
finding: PriorFinding;
|
|
30
|
+
/** Code at the finding anchor BEFORE the fix-push. */
|
|
31
|
+
codeBefore: string;
|
|
32
|
+
/** Code at the finding anchor AFTER the fix-push. */
|
|
33
|
+
codeAfter: string;
|
|
34
|
+
/** Diff hunk at the anchor (optional). */
|
|
35
|
+
diffAtAnchor?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The minimal shape `applyResolutionRules` + the verifier need to
|
|
39
|
+
* describe a prior finding. The CLI reconstructs this from
|
|
40
|
+
* `parseThreadBody(comment.body)` + the GraphQL `path`/`line` fields.
|
|
41
|
+
*/
|
|
42
|
+
export interface PriorFinding {
|
|
43
|
+
severity: Severity;
|
|
44
|
+
/** The summary line + (optional) reasoning, joined for the verifier prompt. */
|
|
45
|
+
body: string;
|
|
46
|
+
/** The skill slug that raised the finding. */
|
|
47
|
+
skill: string;
|
|
48
|
+
/** Repo-relative path. */
|
|
49
|
+
file: string;
|
|
50
|
+
/** Optional 1-indexed line number. */
|
|
51
|
+
line?: number;
|
|
52
|
+
}
|
|
53
|
+
/** What the CLI verb should do with the thread. */
|
|
54
|
+
export type ThreadAction = {
|
|
55
|
+
kind: 'resolve';
|
|
56
|
+
markerBody: string;
|
|
57
|
+
verdict: VerifyOutcome;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'keep_open';
|
|
60
|
+
markerBody: string;
|
|
61
|
+
verdict: VerifyOutcome;
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'keep_open_request_changes';
|
|
64
|
+
markerBody: string;
|
|
65
|
+
verdict: VerifyOutcome;
|
|
66
|
+
/** True when triggered by UNCERTAIN+🔴 escalation. */
|
|
67
|
+
escalated: boolean;
|
|
68
|
+
} | {
|
|
69
|
+
kind: 'skipped';
|
|
70
|
+
reason: 'off';
|
|
71
|
+
thread?: PriorThread;
|
|
72
|
+
};
|
|
73
|
+
/** Verdict shape — re-exported from resolve-verifier for ergonomics. */
|
|
74
|
+
export interface VerifyOutcome {
|
|
75
|
+
verdict: 'ADDRESSED' | 'NOT_ADDRESSED' | 'UNCERTAIN';
|
|
76
|
+
rationale: string;
|
|
77
|
+
source: 'model' | 'api-error';
|
|
78
|
+
}
|
|
79
|
+
export interface AutoResolveInput {
|
|
80
|
+
/** Open threads from prior review passes. May be empty. */
|
|
81
|
+
priorThreads: PriorThread[];
|
|
82
|
+
/** Resolved config (after precedence merge). */
|
|
83
|
+
config: AutoResolveConfig;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the caller can actually resolve threads (a dedicated PAT is
|
|
86
|
+
* present). Drives the addressed-marker wording: PAT → "Auto-resolved";
|
|
87
|
+
* no-PAT → "Verified fixed — not auto-closed". Defaults to true (the App
|
|
88
|
+
* path / unit tests, where the App token can resolve).
|
|
89
|
+
*/
|
|
90
|
+
canResolve?: boolean;
|
|
91
|
+
/** Verifier callback. Tests inject a stub; CLI provides real Anthropic-call fn. */
|
|
92
|
+
verifier: (args: {
|
|
93
|
+
finding: PriorFinding;
|
|
94
|
+
codeBefore: string;
|
|
95
|
+
codeAfter: string;
|
|
96
|
+
diffAtAnchor?: string;
|
|
97
|
+
}) => Promise<VerifyOutcome>;
|
|
98
|
+
}
|
|
99
|
+
export interface AutoResolveResult {
|
|
100
|
+
/** One action per input thread, in input order. */
|
|
101
|
+
actions: ThreadAction[];
|
|
102
|
+
/** Total verifier calls made. */
|
|
103
|
+
verifierCallCount: number;
|
|
104
|
+
/**
|
|
105
|
+
* True when any action is `keep_open_request_changes`. The CLI verb /
|
|
106
|
+
* workflow uses this to decide whether to flip the formal review to
|
|
107
|
+
* REQUEST_CHANGES (one transition covers all flagged threads).
|
|
108
|
+
*/
|
|
109
|
+
shouldRequestChanges: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Reads `autoResolve` from a `.clud-bug.json` payload + merges with
|
|
113
|
+
* built-in defaults. Returns a fully-resolved `AutoResolveConfig`.
|
|
114
|
+
*
|
|
115
|
+
* Unknown fields tolerated (forward compat). Invalid values fall back
|
|
116
|
+
* to the default for that key + log a warning. NEVER throws — a
|
|
117
|
+
* config-validation throw on the fix-push hot path would degrade the
|
|
118
|
+
* whole step to a fail.
|
|
119
|
+
*/
|
|
120
|
+
export declare function resolveAutoResolveConfig(raw: unknown, onWarn?: (msg: string) => void): AutoResolveConfig;
|
|
121
|
+
/**
|
|
122
|
+
* Convenience: extracts the `autoResolve` block from a top-level
|
|
123
|
+
* `.clud-bug.json` config blob.
|
|
124
|
+
*/
|
|
125
|
+
export declare function readAutoResolveConfigFromCludBug(config: {
|
|
126
|
+
autoResolve?: unknown;
|
|
127
|
+
} | null | undefined, onWarn?: (msg: string) => void): AutoResolveConfig;
|
|
128
|
+
/**
|
|
129
|
+
* For each prior thread, call the injected verifier + apply the
|
|
130
|
+
* resolution rules. Returns one action per input thread, plus
|
|
131
|
+
* aggregate stats.
|
|
132
|
+
*
|
|
133
|
+
* The CLI verb executes the returned actions (GraphQL mutations);
|
|
134
|
+
* this function is pure modulo the verifier callback.
|
|
135
|
+
*/
|
|
136
|
+
export declare function runAutoResolve(input: AutoResolveInput): Promise<AutoResolveResult>;
|
|
137
|
+
/**
|
|
138
|
+
* Maps a verifier verdict + the thread context to the action the CLI
|
|
139
|
+
* verb should take. Pure function, no I/O.
|
|
140
|
+
*
|
|
141
|
+
* Resolution table:
|
|
142
|
+
* ADDRESSED, any → resolve, "Auto-resolved (verified)"
|
|
143
|
+
* NOT_ADDRESSED, 🔴 → keep_open_request_changes (escalated=false)
|
|
144
|
+
* NOT_ADDRESSED, 🟡 → keep_open, "Re-review found this still applies"
|
|
145
|
+
* UNCERTAIN, 🔴, request → keep_open_request_changes (escalated=true)
|
|
146
|
+
* UNCERTAIN, 🔴, leave → keep_open, "Auto-resolve uncertain — human review recommended"
|
|
147
|
+
* UNCERTAIN, 🟡 → keep_open, "human review recommended"
|
|
148
|
+
*/
|
|
149
|
+
export declare function applyResolutionRules(args: {
|
|
150
|
+
thread: PriorThread;
|
|
151
|
+
verdict: VerifyOutcome;
|
|
152
|
+
config: AutoResolveConfig;
|
|
153
|
+
/** Whether the resolve mutation is available (PAT present). Defaults true. */
|
|
154
|
+
canResolve?: boolean;
|
|
155
|
+
}): ThreadAction;
|
|
156
|
+
type AutoResolveMarkerInput = {
|
|
157
|
+
kind: 'verified-addressed';
|
|
158
|
+
rationale?: string;
|
|
159
|
+
resolved?: boolean;
|
|
160
|
+
} | {
|
|
161
|
+
kind: 'verified-not-addressed';
|
|
162
|
+
rationale?: string;
|
|
163
|
+
} | {
|
|
164
|
+
kind: 'verified-uncertain';
|
|
165
|
+
rationale?: string;
|
|
166
|
+
severity: Severity;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Renders the comment body the CLI verb posts as a reply on the
|
|
170
|
+
* thread before resolving (or alongside keep-open). Wording mirrors
|
|
171
|
+
* the App's `renderAutoResolveMarker` so both consumers emit a
|
|
172
|
+
* uniform audit trail.
|
|
173
|
+
*/
|
|
174
|
+
export declare function renderAutoResolveMarker(input: AutoResolveMarkerInput): string;
|
|
175
|
+
/** Which token the resolve mutation should use, and whether it's a dedicated PAT. */
|
|
176
|
+
export interface ResolveAuth {
|
|
177
|
+
token: string;
|
|
178
|
+
source: 'pat' | 'gh_token';
|
|
179
|
+
hasDedicatedPat: boolean;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Picks the token for the `resolveReviewThread` GraphQL mutation. A dedicated
|
|
183
|
+
* fine-grained PAT (`CLUD_BUG_RESOLVE_PAT`, or the `RESOLVE_PAT` alias) is
|
|
184
|
+
* preferred — the Actions `GITHUB_TOKEN` can't resolve review threads
|
|
185
|
+
* ("Resource not accessible by integration"). With no PAT the verb keeps using
|
|
186
|
+
* `GH_TOKEN` for the other gh calls and skips the resolve mutation entirely.
|
|
187
|
+
*
|
|
188
|
+
* Empty / whitespace-only values are treated as absent — GitHub renders an
|
|
189
|
+
* unset secret as the empty string, so `CLUD_BUG_RESOLVE_PAT=''` must NOT
|
|
190
|
+
* shadow a hand-set `RESOLVE_PAT` alias.
|
|
191
|
+
*/
|
|
192
|
+
export declare function selectResolveAuth(env: {
|
|
193
|
+
CLUD_BUG_RESOLVE_PAT?: string;
|
|
194
|
+
RESOLVE_PAT?: string;
|
|
195
|
+
GH_TOKEN?: string;
|
|
196
|
+
}): ResolveAuth;
|
|
197
|
+
/** Verifier verdict, as embedded in the idempotency marker. */
|
|
198
|
+
export type ResolveVerdict = 'ADDRESSED' | 'NOT_ADDRESSED' | 'UNCERTAIN';
|
|
199
|
+
/**
|
|
200
|
+
* Hidden HTML-comment marker appended to each auto-resolve reply so a later
|
|
201
|
+
* fix-push can tell whether it already replied to this thread for the current
|
|
202
|
+
* (verdict, anchor) — making the reply idempotent instead of one-per-push.
|
|
203
|
+
*/
|
|
204
|
+
export declare function renderResolveMarkerTag(verdict: ResolveVerdict, sig: string): string;
|
|
205
|
+
/** Parses the hidden marker out of a comment body. Null when absent / malformed. */
|
|
206
|
+
export declare function parseResolveMarkerTag(body: string): {
|
|
207
|
+
verdict: ResolveVerdict;
|
|
208
|
+
sig: string;
|
|
209
|
+
} | null;
|
|
210
|
+
/**
|
|
211
|
+
* 8-hex-char signature of a finding's post-fix anchor. Stable while the anchor
|
|
212
|
+
* is unchanged, changes when `codeAfter` changes — lets the verb skip
|
|
213
|
+
* re-verifying + re-replying to a thread whose anchor hasn't moved.
|
|
214
|
+
*/
|
|
215
|
+
export declare function anchorSignature(finding: {
|
|
216
|
+
file?: string;
|
|
217
|
+
line?: number;
|
|
218
|
+
}, codeAfter: string): string;
|
|
219
|
+
/**
|
|
220
|
+
* Scans a thread's comments (oldest→newest, as GraphQL returns them) for the
|
|
221
|
+
* most-recent bot-authored reply carrying a resolve marker. Returns its
|
|
222
|
+
* `{verdict, sig}` or null. Only bot-authored comments count, so a user pasting
|
|
223
|
+
* a marker can't spoof the idempotency state.
|
|
224
|
+
*/
|
|
225
|
+
export declare function latestResolveMarker(comments: Array<{
|
|
226
|
+
author?: {
|
|
227
|
+
login?: string | null;
|
|
228
|
+
} | null;
|
|
229
|
+
body?: string | null;
|
|
230
|
+
} | null | undefined>, botAuthors: Set<string>): {
|
|
231
|
+
verdict: ResolveVerdict;
|
|
232
|
+
sig: string;
|
|
233
|
+
} | null;
|
|
234
|
+
export {};
|
|
235
|
+
//# sourceMappingURL=auto-resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-resolve.d.ts","sourceRoot":"","sources":["../../src/core/auto-resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// Wave 5b — D.2.6 auto-resolve fidelity, npm-workflow flavor.
|
|
2
|
+
//
|
|
3
|
+
// On every fix-push (`pull_request.synchronize`), for each open thread
|
|
4
|
+
// posted by the bot on a prior pass, decide whether the new commit
|
|
5
|
+
// addressed the original concern, and act accordingly:
|
|
6
|
+
//
|
|
7
|
+
// ADDRESSED → resolve the thread + post "Auto-resolved (verified)"
|
|
8
|
+
// NOT_ADDRESSED → keep open + post "Re-review found this still applies"
|
|
9
|
+
// + flag REQUEST_CHANGES intent if 🔴 critical
|
|
10
|
+
// UNCERTAIN + 🟡 → keep open + post "human review recommended"
|
|
11
|
+
// UNCERTAIN + 🔴 → keep open + flag REQUEST_CHANGES + escalate. NEVER dismiss.
|
|
12
|
+
//
|
|
13
|
+
// This module owns the pure rule tables + config merge + marker
|
|
14
|
+
// rendering. The CLI verb in `src/cli/main.ts::runResolveThreads` owns
|
|
15
|
+
// the IO: fetching threads via `gh api graphql`, calling Anthropic
|
|
16
|
+
// Messages API for the verifier, applying these actions via REST/
|
|
17
|
+
// GraphQL mutations.
|
|
18
|
+
//
|
|
19
|
+
// Ported from `clud-bug-app/lib/auto-resolve.ts` (and the marker
|
|
20
|
+
// helpers from `clud-bug-app/lib/comment.ts`). Differences from the
|
|
21
|
+
// App impl:
|
|
22
|
+
// - DROP `aggregateMultiPassVerdicts` — OSS workflow is single-pass.
|
|
23
|
+
// - DROP heuristic fallback (`heuristicAction`) — OSS supports only
|
|
24
|
+
// `mode: 'verified' | 'off'` for now; heuristic adds complexity
|
|
25
|
+
// without a customer ask. Future Wave 5c can add it back if the
|
|
26
|
+
// App migrates to consume from core.
|
|
27
|
+
// - DROP per-PR budget gate — OSS workflow uses the customer's own
|
|
28
|
+
// `ANTHROPIC_API_KEY`; spend-cap is their concern, not ours.
|
|
29
|
+
import { createHash } from 'node:crypto';
|
|
30
|
+
export const DEFAULT_AUTO_RESOLVE_CONFIG = {
|
|
31
|
+
mode: 'verified',
|
|
32
|
+
uncertain_critical_action: 'request_changes',
|
|
33
|
+
};
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Config resolution
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Reads `autoResolve` from a `.clud-bug.json` payload + merges with
|
|
39
|
+
* built-in defaults. Returns a fully-resolved `AutoResolveConfig`.
|
|
40
|
+
*
|
|
41
|
+
* Unknown fields tolerated (forward compat). Invalid values fall back
|
|
42
|
+
* to the default for that key + log a warning. NEVER throws — a
|
|
43
|
+
* config-validation throw on the fix-push hot path would degrade the
|
|
44
|
+
* whole step to a fail.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveAutoResolveConfig(raw, onWarn = () => { }) {
|
|
47
|
+
const defaults = DEFAULT_AUTO_RESOLVE_CONFIG;
|
|
48
|
+
if (!raw || typeof raw !== 'object')
|
|
49
|
+
return defaults;
|
|
50
|
+
const obj = raw;
|
|
51
|
+
let mode = defaults.mode;
|
|
52
|
+
if (typeof obj.mode === 'string') {
|
|
53
|
+
if (obj.mode === 'verified' || obj.mode === 'off') {
|
|
54
|
+
mode = obj.mode;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
onWarn(`autoResolve.mode = ${JSON.stringify(obj.mode)} is invalid; falling back to "${defaults.mode}". Valid: verified, off.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
let uncertainCritical = defaults.uncertain_critical_action;
|
|
61
|
+
if (typeof obj.uncertain_critical_action === 'string') {
|
|
62
|
+
if (obj.uncertain_critical_action === 'request_changes' ||
|
|
63
|
+
obj.uncertain_critical_action === 'leave_open') {
|
|
64
|
+
uncertainCritical = obj.uncertain_critical_action;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
onWarn(`autoResolve.uncertain_critical_action = ${JSON.stringify(obj.uncertain_critical_action)} is invalid; falling back to "${defaults.uncertain_critical_action}".`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
mode,
|
|
72
|
+
uncertain_critical_action: uncertainCritical,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convenience: extracts the `autoResolve` block from a top-level
|
|
77
|
+
* `.clud-bug.json` config blob.
|
|
78
|
+
*/
|
|
79
|
+
export function readAutoResolveConfigFromCludBug(config, onWarn) {
|
|
80
|
+
if (!config)
|
|
81
|
+
return DEFAULT_AUTO_RESOLVE_CONFIG;
|
|
82
|
+
return resolveAutoResolveConfig(config.autoResolve, onWarn);
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Main entry point — pure orchestration with injected verifier
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* For each prior thread, call the injected verifier + apply the
|
|
89
|
+
* resolution rules. Returns one action per input thread, plus
|
|
90
|
+
* aggregate stats.
|
|
91
|
+
*
|
|
92
|
+
* The CLI verb executes the returned actions (GraphQL mutations);
|
|
93
|
+
* this function is pure modulo the verifier callback.
|
|
94
|
+
*/
|
|
95
|
+
export async function runAutoResolve(input) {
|
|
96
|
+
if (input.config.mode === 'off') {
|
|
97
|
+
return {
|
|
98
|
+
actions: input.priorThreads.map((thread) => ({
|
|
99
|
+
kind: 'skipped',
|
|
100
|
+
reason: 'off',
|
|
101
|
+
thread,
|
|
102
|
+
})),
|
|
103
|
+
verifierCallCount: 0,
|
|
104
|
+
shouldRequestChanges: false,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const actions = [];
|
|
108
|
+
let verifierCallCount = 0;
|
|
109
|
+
let shouldRequestChanges = false;
|
|
110
|
+
for (const thread of input.priorThreads) {
|
|
111
|
+
// Conditionally include `diffAtAnchor` only when present so the
|
|
112
|
+
// narrowed `verifier` callback type (which forbids `undefined`
|
|
113
|
+
// under `exactOptionalPropertyTypes`) stays satisfied.
|
|
114
|
+
const verifierArgs = {
|
|
115
|
+
finding: thread.finding,
|
|
116
|
+
codeBefore: thread.codeBefore,
|
|
117
|
+
codeAfter: thread.codeAfter,
|
|
118
|
+
...(thread.diffAtAnchor !== undefined
|
|
119
|
+
? { diffAtAnchor: thread.diffAtAnchor }
|
|
120
|
+
: {}),
|
|
121
|
+
};
|
|
122
|
+
const verdict = await input.verifier(verifierArgs);
|
|
123
|
+
verifierCallCount++;
|
|
124
|
+
const action = applyResolutionRules({
|
|
125
|
+
thread,
|
|
126
|
+
verdict,
|
|
127
|
+
config: input.config,
|
|
128
|
+
canResolve: input.canResolve !== false,
|
|
129
|
+
});
|
|
130
|
+
actions.push(action);
|
|
131
|
+
if (action.kind === 'keep_open_request_changes')
|
|
132
|
+
shouldRequestChanges = true;
|
|
133
|
+
}
|
|
134
|
+
return { actions, verifierCallCount, shouldRequestChanges };
|
|
135
|
+
}
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Rule table — pure function from (verdict, finding, config) → action
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
/**
|
|
140
|
+
* Maps a verifier verdict + the thread context to the action the CLI
|
|
141
|
+
* verb should take. Pure function, no I/O.
|
|
142
|
+
*
|
|
143
|
+
* Resolution table:
|
|
144
|
+
* ADDRESSED, any → resolve, "Auto-resolved (verified)"
|
|
145
|
+
* NOT_ADDRESSED, 🔴 → keep_open_request_changes (escalated=false)
|
|
146
|
+
* NOT_ADDRESSED, 🟡 → keep_open, "Re-review found this still applies"
|
|
147
|
+
* UNCERTAIN, 🔴, request → keep_open_request_changes (escalated=true)
|
|
148
|
+
* UNCERTAIN, 🔴, leave → keep_open, "Auto-resolve uncertain — human review recommended"
|
|
149
|
+
* UNCERTAIN, 🟡 → keep_open, "human review recommended"
|
|
150
|
+
*/
|
|
151
|
+
export function applyResolutionRules(args) {
|
|
152
|
+
const { verdict, thread, config } = args;
|
|
153
|
+
const canResolve = args.canResolve !== false;
|
|
154
|
+
const severity = thread.finding.severity;
|
|
155
|
+
if (verdict.verdict === 'ADDRESSED') {
|
|
156
|
+
return {
|
|
157
|
+
kind: 'resolve',
|
|
158
|
+
markerBody: renderAutoResolveMarker({
|
|
159
|
+
kind: 'verified-addressed',
|
|
160
|
+
rationale: verdict.rationale,
|
|
161
|
+
resolved: canResolve,
|
|
162
|
+
}),
|
|
163
|
+
verdict,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (verdict.verdict === 'NOT_ADDRESSED') {
|
|
167
|
+
const markerBody = renderAutoResolveMarker({
|
|
168
|
+
kind: 'verified-not-addressed',
|
|
169
|
+
rationale: verdict.rationale,
|
|
170
|
+
});
|
|
171
|
+
if (severity === 'critical') {
|
|
172
|
+
return {
|
|
173
|
+
kind: 'keep_open_request_changes',
|
|
174
|
+
markerBody,
|
|
175
|
+
verdict,
|
|
176
|
+
escalated: false,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { kind: 'keep_open', markerBody, verdict };
|
|
180
|
+
}
|
|
181
|
+
// UNCERTAIN.
|
|
182
|
+
const markerBody = renderAutoResolveMarker({
|
|
183
|
+
kind: 'verified-uncertain',
|
|
184
|
+
rationale: verdict.rationale,
|
|
185
|
+
severity,
|
|
186
|
+
});
|
|
187
|
+
if (severity === 'critical' &&
|
|
188
|
+
config.uncertain_critical_action === 'request_changes') {
|
|
189
|
+
return {
|
|
190
|
+
kind: 'keep_open_request_changes',
|
|
191
|
+
markerBody,
|
|
192
|
+
verdict,
|
|
193
|
+
escalated: true,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return { kind: 'keep_open', markerBody, verdict };
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Renders the comment body the CLI verb posts as a reply on the
|
|
200
|
+
* thread before resolving (or alongside keep-open). Wording mirrors
|
|
201
|
+
* the App's `renderAutoResolveMarker` so both consumers emit a
|
|
202
|
+
* uniform audit trail.
|
|
203
|
+
*/
|
|
204
|
+
export function renderAutoResolveMarker(input) {
|
|
205
|
+
const tail = input.rationale ? `: ${input.rationale.trim()}` : '.';
|
|
206
|
+
switch (input.kind) {
|
|
207
|
+
case 'verified-addressed':
|
|
208
|
+
// No PAT → we did NOT resolve the thread, so don't claim "Auto-resolved".
|
|
209
|
+
// Post an accurate "verified fixed" badge + the manual-Resolve hint.
|
|
210
|
+
if (input.resolved === false) {
|
|
211
|
+
return (`**✅ Verified fixed — not auto-closed**${tail} ` +
|
|
212
|
+
`_The Actions \`GITHUB_TOKEN\` can't resolve review threads; click ` +
|
|
213
|
+
`**Resolve conversation** to dismiss, or add a \`CLUD_BUG_RESOLVE_PAT\` ` +
|
|
214
|
+
`secret to auto-close (see README)._`);
|
|
215
|
+
}
|
|
216
|
+
return `**✓ Auto-resolved (verified by D.2.6 fix-check)**${tail}`;
|
|
217
|
+
case 'verified-not-addressed':
|
|
218
|
+
return `**❌ Re-review found this still applies**${tail}`;
|
|
219
|
+
case 'verified-uncertain':
|
|
220
|
+
if (input.severity === 'critical') {
|
|
221
|
+
return `**⚠ Auto-resolve uncertain on a 🔴 critical — escalated, never silently dismissed**${tail}`;
|
|
222
|
+
}
|
|
223
|
+
return `**⚠ Auto-resolve uncertain — human review recommended**${tail}`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Picks the token for the `resolveReviewThread` GraphQL mutation. A dedicated
|
|
228
|
+
* fine-grained PAT (`CLUD_BUG_RESOLVE_PAT`, or the `RESOLVE_PAT` alias) is
|
|
229
|
+
* preferred — the Actions `GITHUB_TOKEN` can't resolve review threads
|
|
230
|
+
* ("Resource not accessible by integration"). With no PAT the verb keeps using
|
|
231
|
+
* `GH_TOKEN` for the other gh calls and skips the resolve mutation entirely.
|
|
232
|
+
*
|
|
233
|
+
* Empty / whitespace-only values are treated as absent — GitHub renders an
|
|
234
|
+
* unset secret as the empty string, so `CLUD_BUG_RESOLVE_PAT=''` must NOT
|
|
235
|
+
* shadow a hand-set `RESOLVE_PAT` alias.
|
|
236
|
+
*/
|
|
237
|
+
export function selectResolveAuth(env) {
|
|
238
|
+
const pat = [env.CLUD_BUG_RESOLVE_PAT, env.RESOLVE_PAT]
|
|
239
|
+
.map((v) => (v ?? '').trim())
|
|
240
|
+
.find((v) => v !== '') ?? '';
|
|
241
|
+
if (pat)
|
|
242
|
+
return { token: pat, source: 'pat', hasDedicatedPat: true };
|
|
243
|
+
return { token: (env.GH_TOKEN ?? '').trim(), source: 'gh_token', hasDedicatedPat: false };
|
|
244
|
+
}
|
|
245
|
+
const RESOLVE_MARKER_RE = /<!--\s*clud-bug-resolve\s+v=(ADDRESSED|NOT_ADDRESSED|UNCERTAIN)\s+sig=([a-f0-9]{16})\s*-->/;
|
|
246
|
+
/**
|
|
247
|
+
* Hidden HTML-comment marker appended to each auto-resolve reply so a later
|
|
248
|
+
* fix-push can tell whether it already replied to this thread for the current
|
|
249
|
+
* (verdict, anchor) — making the reply idempotent instead of one-per-push.
|
|
250
|
+
*/
|
|
251
|
+
export function renderResolveMarkerTag(verdict, sig) {
|
|
252
|
+
return `<!-- clud-bug-resolve v=${verdict} sig=${sig} -->`;
|
|
253
|
+
}
|
|
254
|
+
/** Parses the hidden marker out of a comment body. Null when absent / malformed. */
|
|
255
|
+
export function parseResolveMarkerTag(body) {
|
|
256
|
+
const m = body.match(RESOLVE_MARKER_RE);
|
|
257
|
+
if (!m || m[1] === undefined || m[2] === undefined)
|
|
258
|
+
return null;
|
|
259
|
+
return { verdict: m[1], sig: m[2] };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* 8-hex-char signature of a finding's post-fix anchor. Stable while the anchor
|
|
263
|
+
* is unchanged, changes when `codeAfter` changes — lets the verb skip
|
|
264
|
+
* re-verifying + re-replying to a thread whose anchor hasn't moved.
|
|
265
|
+
*/
|
|
266
|
+
export function anchorSignature(finding, codeAfter) {
|
|
267
|
+
const file = finding.file ?? '<no-file>';
|
|
268
|
+
const line = finding.line ?? 0;
|
|
269
|
+
// 16 hex chars (64-bit), matching `findingId`'s convention — wide enough
|
|
270
|
+
// that a collision can't suppress a re-review marker.
|
|
271
|
+
return createHash('sha256').update(`${file}:${line}:${codeAfter}`).digest('hex').slice(0, 16);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Scans a thread's comments (oldest→newest, as GraphQL returns them) for the
|
|
275
|
+
* most-recent bot-authored reply carrying a resolve marker. Returns its
|
|
276
|
+
* `{verdict, sig}` or null. Only bot-authored comments count, so a user pasting
|
|
277
|
+
* a marker can't spoof the idempotency state.
|
|
278
|
+
*/
|
|
279
|
+
export function latestResolveMarker(comments, botAuthors) {
|
|
280
|
+
let latest = null;
|
|
281
|
+
for (const c of comments) {
|
|
282
|
+
if (!c)
|
|
283
|
+
continue;
|
|
284
|
+
const login = c.author?.login ?? '';
|
|
285
|
+
if (!botAuthors.has(login))
|
|
286
|
+
continue;
|
|
287
|
+
const tag = parseResolveMarkerTag(c.body ?? '');
|
|
288
|
+
if (tag)
|
|
289
|
+
latest = tag;
|
|
290
|
+
}
|
|
291
|
+
return latest;
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=auto-resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-resolve.js","sourceRoot":"","sources":["../../src/core/auto-resolve.ts"],"names":[],"mappings":"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"}
|