clud-bug 0.7.0-rc.2 β 0.7.0-rc.21
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/data/canonical-v1.json +37 -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/hooks.d.ts +51 -0
- package/dist/cli/hooks.d.ts.map +1 -0
- package/dist/cli/hooks.js +138 -0
- package/dist/cli/hooks.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +949 -35
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/post-check-run.d.ts +16 -0
- package/dist/cli/post-check-run.d.ts.map +1 -0
- package/dist/cli/post-check-run.js +93 -0
- package/dist/cli/post-check-run.js.map +1 -0
- package/dist/cli/review-prompt.d.ts +43 -0
- package/dist/cli/review-prompt.d.ts.map +1 -0
- package/dist/cli/review-prompt.js +287 -0
- package/dist/cli/review-prompt.js.map +1 -0
- package/dist/cli/skills.d.ts +7 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +42 -2
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/update-notifier.d.ts +17 -0
- package/dist/cli/update-notifier.d.ts.map +1 -0
- package/dist/cli/update-notifier.js +88 -0
- package/dist/cli/update-notifier.js.map +1 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +60 -11
- package/dist/cli/update.js.map +1 -1
- 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/budget-plan.d.ts +125 -0
- package/dist/core/budget-plan.d.ts.map +1 -0
- package/dist/core/budget-plan.js +211 -0
- package/dist/core/budget-plan.js.map +1 -0
- package/dist/core/check-verdict.d.ts +31 -0
- package/dist/core/check-verdict.d.ts.map +1 -0
- package/dist/core/check-verdict.js +66 -0
- package/dist/core/check-verdict.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/design.d.ts +37 -0
- package/dist/core/design.d.ts.map +1 -0
- package/dist/core/design.js +47 -0
- package/dist/core/design.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 +15 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +53 -1
- package/dist/core/index.js.map +1 -1
- 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/multi-pass-aggregate.d.ts +161 -0
- package/dist/core/multi-pass-aggregate.d.ts.map +1 -0
- package/dist/core/multi-pass-aggregate.js +457 -0
- package/dist/core/multi-pass-aggregate.js.map +1 -0
- package/dist/core/plan-review.d.ts +57 -0
- package/dist/core/plan-review.d.ts.map +1 -0
- package/dist/core/plan-review.js +77 -0
- package/dist/core/plan-review.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +18 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +24 -2
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/render.js +1 -19
- package/dist/core/render.js.map +1 -1
- package/dist/core/resolve-verifier.d.ts +53 -0
- package/dist/core/resolve-verifier.d.ts.map +1 -0
- package/dist/core/resolve-verifier.js +204 -0
- package/dist/core/resolve-verifier.js.map +1 -0
- package/dist/core/review-context.d.ts +39 -0
- package/dist/core/review-context.d.ts.map +1 -0
- package/dist/core/review-context.js +99 -0
- package/dist/core/review-context.js.map +1 -0
- package/dist/core/review-plan.d.ts +219 -0
- package/dist/core/review-plan.d.ts.map +1 -0
- package/dist/core/review-plan.js +274 -0
- package/dist/core/review-plan.js.map +1 -0
- package/dist/core/review-writeback.d.ts +74 -0
- package/dist/core/review-writeback.d.ts.map +1 -1
- package/dist/core/review-writeback.js +71 -4
- package/dist/core/review-writeback.js.map +1 -1
- package/dist/core/skills.d.ts +25 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +100 -4
- package/dist/core/skills.js.map +1 -1
- 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 +11 -5
- package/src/cli/configure-github.ts +329 -0
- package/src/cli/hooks.ts +155 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/main.ts +1031 -37
- package/src/cli/post-check-run.ts +115 -0
- package/src/cli/review-prompt.ts +355 -0
- package/src/cli/skills.ts +42 -2
- package/src/cli/update-notifier.ts +100 -0
- package/src/cli/update.ts +60 -11
- package/src/core/auto-resolve.ts +488 -0
- package/src/core/budget-plan.ts +324 -0
- package/src/core/check-verdict.ts +93 -0
- package/src/core/configure-github.ts +497 -0
- package/src/core/design.ts +73 -0
- package/src/core/diff-findings.ts +323 -0
- package/src/core/formal-review.ts +168 -0
- package/src/core/index.ts +188 -0
- package/src/core/inline-threads.ts +471 -0
- package/src/core/multi-pass-aggregate.ts +591 -0
- package/src/core/plan-review.ts +136 -0
- package/src/core/prompt-builder.ts +44 -2
- package/src/core/render.ts +10 -16
- package/src/core/resolve-verifier.ts +254 -0
- package/src/core/review-context.ts +106 -0
- package/src/core/review-plan.ts +485 -0
- package/src/core/review-writeback.ts +161 -4
- package/src/core/skills.ts +128 -5
- package/src/core/version.ts +3 -0
- package/templates/clud-bug-review.md.tmpl +115 -0
- package/templates/skills/design/design-system-consistency.md +41 -0
- package/templates/skills/design/frontend-a11y.md +41 -0
- package/templates/skills/design/visual-polish.md +41 -0
- package/templates/workflow-py.yml.tmpl +92 -2
- package/templates/workflow-ts.yml.tmpl +92 -2
- package/templates/workflow.yml.tmpl +173 -2
package/dist/cli/update.js
CHANGED
|
@@ -5,6 +5,7 @@ import { reviewPrompt } from '../core/prompts.js';
|
|
|
5
5
|
import { detect, buildDescriptionLine } from '../core/detect.js';
|
|
6
6
|
import { loadBaseline, readManifest, writeManifest } from './skills.js';
|
|
7
7
|
import { applyToRepo as applyAgentDocs } from './agents-md.js';
|
|
8
|
+
import { mergeLocalReviewHook, buildCommitReviewCommand, CLUD_BUG_HOOK_MARKER } from './hooks.js';
|
|
8
9
|
// Returns { changed, unchanged, skipped, ourVersion }.
|
|
9
10
|
export async function runUpdate(opts) {
|
|
10
11
|
const { cwd, templatesDir, baselineDir, ourVersion, refreshRemote = false, loadBaselineOpts } = opts;
|
|
@@ -19,17 +20,25 @@ export async function runUpdate(opts) {
|
|
|
19
20
|
const changed = [];
|
|
20
21
|
const unchanged = [];
|
|
21
22
|
const skipped = [];
|
|
22
|
-
// 1. Re-render review workflow with the latest template
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
// 1. Re-render the review workflow with the latest template β ONLY if it is
|
|
24
|
+
// already installed. A `--local-only` (max-mode) repo has no review
|
|
25
|
+
// workflow and must NOT have one created by `update`: that would
|
|
26
|
+
// re-introduce the ANTHROPIC_API_KEY Action the local install deliberately
|
|
27
|
+
// skips (dogfood caught `update` doing exactly this). Mirrors the
|
|
28
|
+
// pathExists-gating the audit + self-update workflows already use below.
|
|
29
|
+
const reviewPath = join(cwd, '.github/workflows/clud-bug-review.yml');
|
|
30
|
+
if (await pathExists(reviewPath)) {
|
|
31
|
+
const signals = await detect(cwd);
|
|
32
|
+
const tmplName = pickTemplate(signals.languages);
|
|
33
|
+
// REVIEW_SCHEMA + CCA_VERSION + CLUD_BUG_VERSION come from render.js DEFAULTS.
|
|
34
|
+
const newReview = await renderFile(join(templatesDir, tmplName), {
|
|
35
|
+
REVIEW_PROMPT: reviewPrompt({
|
|
36
|
+
projectDescription: buildDescriptionLine(signals),
|
|
37
|
+
language: templateLanguage(tmplName),
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
await maybeRefreshVersioned(reviewPath, newReview, changed, unchanged, skipped, 'review workflow');
|
|
41
|
+
}
|
|
33
42
|
// 2. Re-render audit workflow if it's installed (init from v0.3+ ships it).
|
|
34
43
|
// Routed through renderFile (was raw readFile pre-v0.5.11) so
|
|
35
44
|
// {{CCA_VERSION}} substitution lands in audit alongside review.
|
|
@@ -91,6 +100,46 @@ export async function runUpdate(opts) {
|
|
|
91
100
|
changed.push({ path: join(cwd, p), label: `agent docs: created ${p}` });
|
|
92
101
|
for (const p of agentDocs.touched)
|
|
93
102
|
changed.push({ path: join(cwd, p), label: `agent docs: ${p}` });
|
|
103
|
+
// 5b. Refresh the local-review slash command (Wave 6b) when it was scaffolded
|
|
104
|
+
// via `clud-bug init --with-local-review`. Only files carrying the
|
|
105
|
+
// `<!-- clud-bug-local-version:` marker are refreshed; a markerless file
|
|
106
|
+
// is user-owned (hand-customized) and left untouched.
|
|
107
|
+
const localReviewPath = join(cwd, '.claude', 'commands', 'clud-bug-review.md');
|
|
108
|
+
if (await pathExists(localReviewPath)) {
|
|
109
|
+
const prior = await readSafe(localReviewPath);
|
|
110
|
+
if (prior && prior.includes('<!-- clud-bug-local-version:')) {
|
|
111
|
+
const newCommand = await renderFile(join(templatesDir, 'clud-bug-review.md.tmpl'), {});
|
|
112
|
+
await maybeWrite(localReviewPath, newCommand, changed, unchanged, 'local-review slash command');
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
skipped.push({
|
|
116
|
+
path: localReviewPath,
|
|
117
|
+
label: 'local-review slash command',
|
|
118
|
+
reason: 'markerless (user-customized); delete + `clud-bug init --with-local-review` to refresh',
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 5c. Refresh the native commit-review hook (Wave 6b) in place when it was
|
|
123
|
+
// scaffolded via `clud-bug init --with-hooks` and our entry is intact (the
|
|
124
|
+
// `clud-bug-local-review` marker). settings.json is user-managed β we only
|
|
125
|
+
// re-merge OUR marked hook, never touching the user's other hooks/settings.
|
|
126
|
+
const settingsPath = join(cwd, '.claude', 'settings.json');
|
|
127
|
+
if (await pathExists(settingsPath)) {
|
|
128
|
+
const prior = await readSafe(settingsPath);
|
|
129
|
+
if (prior && prior.includes(CLUD_BUG_HOOK_MARKER)) {
|
|
130
|
+
try {
|
|
131
|
+
const merged = mergeLocalReviewHook(JSON.parse(prior), buildCommitReviewCommand());
|
|
132
|
+
await maybeWrite(settingsPath, JSON.stringify(merged, null, 2) + '\n', changed, unchanged, 'commit-review hook');
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
skipped.push({
|
|
136
|
+
path: settingsPath,
|
|
137
|
+
label: 'commit-review hook',
|
|
138
|
+
reason: 'settings.json is not valid JSON; left untouched',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
94
143
|
// 6. Stamp the manifest with the version that ran the update.
|
|
95
144
|
manifest['lastUpdate'] = new Date().toISOString();
|
|
96
145
|
manifest['lastUpdateVersion'] = ourVersion;
|
package/dist/cli/update.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAA4B,MAAM,aAAa,CAAC;AAClG,OAAO,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|