@oddessentials/odd-ai-reviewers 1.0.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/README.md +190 -0
- package/dist/__tests__/hermetic-setup.d.ts +55 -0
- package/dist/__tests__/hermetic-setup.d.ts.map +1 -0
- package/dist/__tests__/hermetic-setup.js +62 -0
- package/dist/__tests__/hermetic-setup.js.map +1 -0
- package/dist/__tests__/test-utils/hermetic.d.ts +84 -0
- package/dist/__tests__/test-utils/hermetic.d.ts.map +1 -0
- package/dist/__tests__/test-utils/hermetic.js +147 -0
- package/dist/__tests__/test-utils/hermetic.js.map +1 -0
- package/dist/agents/ai_semantic_review.d.ts +12 -0
- package/dist/agents/ai_semantic_review.d.ts.map +1 -0
- package/dist/agents/ai_semantic_review.js +317 -0
- package/dist/agents/ai_semantic_review.js.map +1 -0
- package/dist/agents/control_flow/budget.d.ts +162 -0
- package/dist/agents/control_flow/budget.d.ts.map +1 -0
- package/dist/agents/control_flow/budget.js +331 -0
- package/dist/agents/control_flow/budget.js.map +1 -0
- package/dist/agents/control_flow/cfg-builder.d.ts +26 -0
- package/dist/agents/control_flow/cfg-builder.d.ts.map +1 -0
- package/dist/agents/control_flow/cfg-builder.js +776 -0
- package/dist/agents/control_flow/cfg-builder.js.map +1 -0
- package/dist/agents/control_flow/cfg-types.d.ts +186 -0
- package/dist/agents/control_flow/cfg-types.d.ts.map +1 -0
- package/dist/agents/control_flow/cfg-types.js +114 -0
- package/dist/agents/control_flow/cfg-types.js.map +1 -0
- package/dist/agents/control_flow/finding-generator.d.ts +118 -0
- package/dist/agents/control_flow/finding-generator.d.ts.map +1 -0
- package/dist/agents/control_flow/finding-generator.js +354 -0
- package/dist/agents/control_flow/finding-generator.js.map +1 -0
- package/dist/agents/control_flow/index.d.ts +39 -0
- package/dist/agents/control_flow/index.d.ts.map +1 -0
- package/dist/agents/control_flow/index.js +270 -0
- package/dist/agents/control_flow/index.js.map +1 -0
- package/dist/agents/control_flow/logger.d.ts +333 -0
- package/dist/agents/control_flow/logger.d.ts.map +1 -0
- package/dist/agents/control_flow/logger.js +607 -0
- package/dist/agents/control_flow/logger.js.map +1 -0
- package/dist/agents/control_flow/mitigation-detector.d.ts +207 -0
- package/dist/agents/control_flow/mitigation-detector.d.ts.map +1 -0
- package/dist/agents/control_flow/mitigation-detector.js +625 -0
- package/dist/agents/control_flow/mitigation-detector.js.map +1 -0
- package/dist/agents/control_flow/mitigation-patterns.d.ts +53 -0
- package/dist/agents/control_flow/mitigation-patterns.d.ts.map +1 -0
- package/dist/agents/control_flow/mitigation-patterns.js +620 -0
- package/dist/agents/control_flow/mitigation-patterns.js.map +1 -0
- package/dist/agents/control_flow/path-analyzer.d.ts +287 -0
- package/dist/agents/control_flow/path-analyzer.d.ts.map +1 -0
- package/dist/agents/control_flow/path-analyzer.js +695 -0
- package/dist/agents/control_flow/path-analyzer.js.map +1 -0
- package/dist/agents/control_flow/pattern-validator.d.ts +132 -0
- package/dist/agents/control_flow/pattern-validator.d.ts.map +1 -0
- package/dist/agents/control_flow/pattern-validator.js +420 -0
- package/dist/agents/control_flow/pattern-validator.js.map +1 -0
- package/dist/agents/control_flow/timeout-regex.d.ts +144 -0
- package/dist/agents/control_flow/timeout-regex.d.ts.map +1 -0
- package/dist/agents/control_flow/timeout-regex.js +339 -0
- package/dist/agents/control_flow/timeout-regex.js.map +1 -0
- package/dist/agents/control_flow/types.d.ts +782 -0
- package/dist/agents/control_flow/types.d.ts.map +1 -0
- package/dist/agents/control_flow/types.js +428 -0
- package/dist/agents/control_flow/types.js.map +1 -0
- package/dist/agents/control_flow/vulnerability-detector.d.ts +85 -0
- package/dist/agents/control_flow/vulnerability-detector.d.ts.map +1 -0
- package/dist/agents/control_flow/vulnerability-detector.js +493 -0
- package/dist/agents/control_flow/vulnerability-detector.js.map +1 -0
- package/dist/agents/date-utils.d.ts +19 -0
- package/dist/agents/date-utils.d.ts.map +1 -0
- package/dist/agents/date-utils.js +29 -0
- package/dist/agents/date-utils.js.map +1 -0
- package/dist/agents/index.d.ts +25 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +50 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/json-utils.d.ts +34 -0
- package/dist/agents/json-utils.d.ts.map +1 -0
- package/dist/agents/json-utils.js +62 -0
- package/dist/agents/json-utils.js.map +1 -0
- package/dist/agents/local_llm.d.ts +24 -0
- package/dist/agents/local_llm.d.ts.map +1 -0
- package/dist/agents/local_llm.js +566 -0
- package/dist/agents/local_llm.js.map +1 -0
- package/dist/agents/metadata.d.ts +57 -0
- package/dist/agents/metadata.d.ts.map +1 -0
- package/dist/agents/metadata.js +45 -0
- package/dist/agents/metadata.js.map +1 -0
- package/dist/agents/opencode.d.ts +18 -0
- package/dist/agents/opencode.d.ts.map +1 -0
- package/dist/agents/opencode.js +364 -0
- package/dist/agents/opencode.js.map +1 -0
- package/dist/agents/path-filter.d.ts +25 -0
- package/dist/agents/path-filter.d.ts.map +1 -0
- package/dist/agents/path-filter.js +43 -0
- package/dist/agents/path-filter.js.map +1 -0
- package/dist/agents/pr_agent.d.ts +3 -0
- package/dist/agents/pr_agent.d.ts.map +1 -0
- package/dist/agents/pr_agent.js +312 -0
- package/dist/agents/pr_agent.js.map +1 -0
- package/dist/agents/retry.d.ts +12 -0
- package/dist/agents/retry.d.ts.map +1 -0
- package/dist/agents/retry.js +65 -0
- package/dist/agents/retry.js.map +1 -0
- package/dist/agents/reviewdog.d.ts +24 -0
- package/dist/agents/reviewdog.d.ts.map +1 -0
- package/dist/agents/reviewdog.js +259 -0
- package/dist/agents/reviewdog.js.map +1 -0
- package/dist/agents/security.d.ts +49 -0
- package/dist/agents/security.d.ts.map +1 -0
- package/dist/agents/security.js +302 -0
- package/dist/agents/security.js.map +1 -0
- package/dist/agents/semgrep.d.ts +8 -0
- package/dist/agents/semgrep.d.ts.map +1 -0
- package/dist/agents/semgrep.js +157 -0
- package/dist/agents/semgrep.js.map +1 -0
- package/dist/agents/types.d.ts +450 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +127 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/budget.d.ts +59 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +82 -0
- package/dist/budget.js.map +1 -0
- package/dist/cache/key.d.ts +49 -0
- package/dist/cache/key.d.ts.map +1 -0
- package/dist/cache/key.js +71 -0
- package/dist/cache/key.js.map +1 -0
- package/dist/cache/store.d.ts +47 -0
- package/dist/cache/store.d.ts.map +1 -0
- package/dist/cache/store.js +328 -0
- package/dist/cache/store.js.map +1 -0
- package/dist/cli/commands/check.d.ts +60 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +163 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/index.d.ts +12 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +12 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/local-review.d.ts +149 -0
- package/dist/cli/commands/local-review.d.ts.map +1 -0
- package/dist/cli/commands/local-review.js +755 -0
- package/dist/cli/commands/local-review.js.map +1 -0
- package/dist/cli/config-wizard.d.ts +87 -0
- package/dist/cli/config-wizard.d.ts.map +1 -0
- package/dist/cli/config-wizard.js +240 -0
- package/dist/cli/config-wizard.js.map +1 -0
- package/dist/cli/dependencies/catalog.d.ts +44 -0
- package/dist/cli/dependencies/catalog.d.ts.map +1 -0
- package/dist/cli/dependencies/catalog.js +89 -0
- package/dist/cli/dependencies/catalog.js.map +1 -0
- package/dist/cli/dependencies/checker.d.ts +42 -0
- package/dist/cli/dependencies/checker.d.ts.map +1 -0
- package/dist/cli/dependencies/checker.js +240 -0
- package/dist/cli/dependencies/checker.js.map +1 -0
- package/dist/cli/dependencies/index.d.ts +16 -0
- package/dist/cli/dependencies/index.d.ts.map +1 -0
- package/dist/cli/dependencies/index.js +16 -0
- package/dist/cli/dependencies/index.js.map +1 -0
- package/dist/cli/dependencies/messages.d.ts +58 -0
- package/dist/cli/dependencies/messages.d.ts.map +1 -0
- package/dist/cli/dependencies/messages.js +183 -0
- package/dist/cli/dependencies/messages.js.map +1 -0
- package/dist/cli/dependencies/platform.d.ts +25 -0
- package/dist/cli/dependencies/platform.d.ts.map +1 -0
- package/dist/cli/dependencies/platform.js +42 -0
- package/dist/cli/dependencies/platform.js.map +1 -0
- package/dist/cli/dependencies/schemas.d.ts +65 -0
- package/dist/cli/dependencies/schemas.d.ts.map +1 -0
- package/dist/cli/dependencies/schemas.js +42 -0
- package/dist/cli/dependencies/schemas.js.map +1 -0
- package/dist/cli/dependencies/types.d.ts +112 -0
- package/dist/cli/dependencies/types.d.ts.map +1 -0
- package/dist/cli/dependencies/types.js +6 -0
- package/dist/cli/dependencies/types.js.map +1 -0
- package/dist/cli/dependencies/version.d.ts +67 -0
- package/dist/cli/dependencies/version.d.ts.map +1 -0
- package/dist/cli/dependencies/version.js +125 -0
- package/dist/cli/dependencies/version.js.map +1 -0
- package/dist/cli/git-context.d.ts +105 -0
- package/dist/cli/git-context.d.ts.map +1 -0
- package/dist/cli/git-context.js +313 -0
- package/dist/cli/git-context.js.map +1 -0
- package/dist/cli/interactive-prompts.d.ts +126 -0
- package/dist/cli/interactive-prompts.d.ts.map +1 -0
- package/dist/cli/interactive-prompts.js +128 -0
- package/dist/cli/interactive-prompts.js.map +1 -0
- package/dist/cli/options/index.d.ts +7 -0
- package/dist/cli/options/index.d.ts.map +1 -0
- package/dist/cli/options/index.js +11 -0
- package/dist/cli/options/index.js.map +1 -0
- package/dist/cli/options/local-review-options.d.ts +221 -0
- package/dist/cli/options/local-review-options.d.ts.map +1 -0
- package/dist/cli/options/local-review-options.js +332 -0
- package/dist/cli/options/local-review-options.js.map +1 -0
- package/dist/cli/output/colors.d.ts +154 -0
- package/dist/cli/output/colors.d.ts.map +1 -0
- package/dist/cli/output/colors.js +255 -0
- package/dist/cli/output/colors.js.map +1 -0
- package/dist/cli/output/errors.d.ts +157 -0
- package/dist/cli/output/errors.d.ts.map +1 -0
- package/dist/cli/output/errors.js +266 -0
- package/dist/cli/output/errors.js.map +1 -0
- package/dist/cli/output/index.d.ts +12 -0
- package/dist/cli/output/index.d.ts.map +1 -0
- package/dist/cli/output/index.js +15 -0
- package/dist/cli/output/index.js.map +1 -0
- package/dist/cli/output/progress.d.ts +237 -0
- package/dist/cli/output/progress.d.ts.map +1 -0
- package/dist/cli/output/progress.js +405 -0
- package/dist/cli/output/progress.js.map +1 -0
- package/dist/cli/signals.d.ts +145 -0
- package/dist/cli/signals.d.ts.map +1 -0
- package/dist/cli/signals.js +223 -0
- package/dist/cli/signals.js.map +1 -0
- package/dist/cli/validation-report.d.ts +106 -0
- package/dist/cli/validation-report.d.ts.map +1 -0
- package/dist/cli/validation-report.js +108 -0
- package/dist/cli/validation-report.js.map +1 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +12 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/mitigation-config.d.ts +94 -0
- package/dist/config/mitigation-config.d.ts.map +1 -0
- package/dist/config/mitigation-config.js +430 -0
- package/dist/config/mitigation-config.js.map +1 -0
- package/dist/config/providers.d.ts +118 -0
- package/dist/config/providers.d.ts.map +1 -0
- package/dist/config/providers.js +229 -0
- package/dist/config/providers.js.map +1 -0
- package/dist/config/schemas.d.ts +278 -0
- package/dist/config/schemas.d.ts.map +1 -0
- package/dist/config/schemas.js +111 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/zero-config.d.ts +126 -0
- package/dist/config/zero-config.d.ts.map +1 -0
- package/dist/config/zero-config.js +243 -0
- package/dist/config/zero-config.js.map +1 -0
- package/dist/config.d.ts +110 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +302 -0
- package/dist/config.js.map +1 -0
- package/dist/diff.d.ts +224 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +832 -0
- package/dist/diff.js.map +1 -0
- package/dist/git-validators.d.ts +106 -0
- package/dist/git-validators.d.ts.map +1 -0
- package/dist/git-validators.js +224 -0
- package/dist/git-validators.js.map +1 -0
- package/dist/main.d.ts +61 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +704 -0
- package/dist/main.js.map +1 -0
- package/dist/phases/execute.d.ts +60 -0
- package/dist/phases/execute.d.ts.map +1 -0
- package/dist/phases/execute.js +168 -0
- package/dist/phases/execute.js.map +1 -0
- package/dist/phases/index.d.ts +9 -0
- package/dist/phases/index.d.ts.map +1 -0
- package/dist/phases/index.js +9 -0
- package/dist/phases/index.js.map +1 -0
- package/dist/phases/preflight.d.ts +40 -0
- package/dist/phases/preflight.d.ts.map +1 -0
- package/dist/phases/preflight.js +122 -0
- package/dist/phases/preflight.js.map +1 -0
- package/dist/phases/report.d.ts +51 -0
- package/dist/phases/report.d.ts.map +1 -0
- package/dist/phases/report.js +152 -0
- package/dist/phases/report.js.map +1 -0
- package/dist/policy.d.ts +33 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +34 -0
- package/dist/policy.js.map +1 -0
- package/dist/preflight.d.ts +181 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +627 -0
- package/dist/preflight.js.map +1 -0
- package/dist/report/ado.d.ts +53 -0
- package/dist/report/ado.d.ts.map +1 -0
- package/dist/report/ado.js +411 -0
- package/dist/report/ado.js.map +1 -0
- package/dist/report/agent-icons.d.ts +36 -0
- package/dist/report/agent-icons.d.ts.map +1 -0
- package/dist/report/agent-icons.js +46 -0
- package/dist/report/agent-icons.js.map +1 -0
- package/dist/report/base.d.ts +30 -0
- package/dist/report/base.d.ts.map +1 -0
- package/dist/report/base.js +64 -0
- package/dist/report/base.js.map +1 -0
- package/dist/report/formats.d.ts +206 -0
- package/dist/report/formats.d.ts.map +1 -0
- package/dist/report/formats.js +481 -0
- package/dist/report/formats.js.map +1 -0
- package/dist/report/github.d.ts +44 -0
- package/dist/report/github.d.ts.map +1 -0
- package/dist/report/github.js +409 -0
- package/dist/report/github.js.map +1 -0
- package/dist/report/line-resolver.d.ts +208 -0
- package/dist/report/line-resolver.d.ts.map +1 -0
- package/dist/report/line-resolver.js +578 -0
- package/dist/report/line-resolver.js.map +1 -0
- package/dist/report/resolution.d.ts +158 -0
- package/dist/report/resolution.d.ts.map +1 -0
- package/dist/report/resolution.js +272 -0
- package/dist/report/resolution.js.map +1 -0
- package/dist/report/sanitize.d.ts +32 -0
- package/dist/report/sanitize.d.ts.map +1 -0
- package/dist/report/sanitize.js +84 -0
- package/dist/report/sanitize.js.map +1 -0
- package/dist/report/terminal.d.ts +440 -0
- package/dist/report/terminal.d.ts.map +1 -0
- package/dist/report/terminal.js +840 -0
- package/dist/report/terminal.js.map +1 -0
- package/dist/reviewignore.d.ts +125 -0
- package/dist/reviewignore.d.ts.map +1 -0
- package/dist/reviewignore.js +335 -0
- package/dist/reviewignore.js.map +1 -0
- package/dist/security-logger.d.ts +178 -0
- package/dist/security-logger.d.ts.map +1 -0
- package/dist/security-logger.js +256 -0
- package/dist/security-logger.js.map +1 -0
- package/dist/telemetry/backends/console.d.ts +24 -0
- package/dist/telemetry/backends/console.d.ts.map +1 -0
- package/dist/telemetry/backends/console.js +54 -0
- package/dist/telemetry/backends/console.js.map +1 -0
- package/dist/telemetry/backends/jsonl.d.ts +31 -0
- package/dist/telemetry/backends/jsonl.d.ts.map +1 -0
- package/dist/telemetry/backends/jsonl.js +121 -0
- package/dist/telemetry/backends/jsonl.js.map +1 -0
- package/dist/telemetry/emitter.d.ts +43 -0
- package/dist/telemetry/emitter.d.ts.map +1 -0
- package/dist/telemetry/emitter.js +83 -0
- package/dist/telemetry/emitter.js.map +1 -0
- package/dist/telemetry/hook.d.ts +53 -0
- package/dist/telemetry/hook.d.ts.map +1 -0
- package/dist/telemetry/hook.js +118 -0
- package/dist/telemetry/hook.js.map +1 -0
- package/dist/telemetry/index.d.ts +58 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +143 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/types.d.ts +139 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +133 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/trust.d.ts +65 -0
- package/dist/trust.d.ts.map +1 -0
- package/dist/trust.js +78 -0
- package/dist/trust.js.map +1 -0
- package/dist/types/assert-never.d.ts +30 -0
- package/dist/types/assert-never.d.ts.map +1 -0
- package/dist/types/assert-never.js +32 -0
- package/dist/types/assert-never.js.map +1 -0
- package/dist/types/branded.d.ts +172 -0
- package/dist/types/branded.d.ts.map +1 -0
- package/dist/types/branded.js +262 -0
- package/dist/types/branded.js.map +1 -0
- package/dist/types/errors.d.ts +320 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +551 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +37 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +77 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/result.d.ts +323 -0
- package/dist/types/result.d.ts.map +1 -0
- package/dist/types/result.js +423 -0
- package/dist/types/result.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Reporter
|
|
3
|
+
* Posts findings as PR comments and check run summaries
|
|
4
|
+
* Includes deduplication and throttling
|
|
5
|
+
*/
|
|
6
|
+
import { Octokit } from '@octokit/rest';
|
|
7
|
+
import { deduplicateFindings, sortFindings, generateSummaryMarkdown, renderPartialFindingsSection, toGitHubAnnotation, countBySeverity, extractFingerprintMarkers, getDedupeKey, buildProximityMap, isDuplicateByProximity, identifyStaleComments, updateProximityMap, } from './formats.js';
|
|
8
|
+
import { buildCommentToMarkersMap, shouldResolveComment, getPartiallyResolvedMarkers, hasMalformedMarkers, applyPartialResolutionVisual, stripOwnFingerprintMarkers, emitResolutionLog, emitMalformedMarkerWarning, } from './resolution.js';
|
|
9
|
+
import { canonicalizeDiffFiles } from '../diff.js';
|
|
10
|
+
import { delay, INLINE_COMMENT_DELAY_MS, formatInlineComment, formatGroupedInlineComment, } from './base.js';
|
|
11
|
+
import { buildLineResolver, normalizeFindingsForDiff, computeDriftSignal, generateDriftMarkdown, } from './line-resolver.js';
|
|
12
|
+
/**
|
|
13
|
+
* Start a check run in 'in_progress' state
|
|
14
|
+
* Call this at the beginning of the review to show users the review is running
|
|
15
|
+
*/
|
|
16
|
+
export async function startCheckRun(context) {
|
|
17
|
+
const octokit = new Octokit({ auth: context.token });
|
|
18
|
+
const response = await octokit.checks.create({
|
|
19
|
+
owner: context.owner,
|
|
20
|
+
repo: context.repo,
|
|
21
|
+
name: 'AI Code Review',
|
|
22
|
+
head_sha: context.headSha,
|
|
23
|
+
status: 'in_progress',
|
|
24
|
+
started_at: new Date().toISOString(),
|
|
25
|
+
output: {
|
|
26
|
+
title: 'AI Code Review in progress...',
|
|
27
|
+
summary: 'Analyzing code changes. This may take a moment.',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
console.log(`[github] Started check run ${response.data.id} (in_progress)`);
|
|
31
|
+
return response.data.id;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Post findings to GitHub
|
|
35
|
+
*
|
|
36
|
+
* (012-fix-agent-result-regressions) - Now accepts partialFindings to include
|
|
37
|
+
* in check summaries and PR comments. Partial findings are rendered in a dedicated
|
|
38
|
+
* section that makes clear they're from failed agents and don't affect gating.
|
|
39
|
+
*/
|
|
40
|
+
export async function reportToGitHub(findings, partialFindings, context, config, diffFiles) {
|
|
41
|
+
const octokit = new Octokit({ auth: context.token });
|
|
42
|
+
const reportingConfig = config.reporting.github ?? {
|
|
43
|
+
mode: 'checks_and_comments',
|
|
44
|
+
max_inline_comments: 20,
|
|
45
|
+
summary: true,
|
|
46
|
+
};
|
|
47
|
+
// CANONICAL ENTRYPOINT: Ensure all diff paths are normalized FIRST
|
|
48
|
+
// This must happen before buildLineResolver, deleted set, or rename maps
|
|
49
|
+
const canonicalFiles = canonicalizeDiffFiles(diffFiles);
|
|
50
|
+
// Build line resolver and normalize findings from canonical files
|
|
51
|
+
const lineResolver = buildLineResolver(canonicalFiles);
|
|
52
|
+
const normalizationResult = normalizeFindingsForDiff(findings, lineResolver);
|
|
53
|
+
if (normalizationResult.stats.dropped > 0 || normalizationResult.stats.normalized > 0) {
|
|
54
|
+
console.log(`[github] Line validation: ${normalizationResult.stats.valid} valid, ` +
|
|
55
|
+
`${normalizationResult.stats.normalized} normalized, ${normalizationResult.stats.dropped} dropped`);
|
|
56
|
+
}
|
|
57
|
+
// Compute drift signal for visibility in check summary
|
|
58
|
+
const driftSignal = computeDriftSignal(normalizationResult.stats, normalizationResult.invalidDetails);
|
|
59
|
+
// Process normalized findings
|
|
60
|
+
const deduplicated = deduplicateFindings(normalizationResult.findings);
|
|
61
|
+
const sorted = sortFindings(deduplicated);
|
|
62
|
+
const counts = countBySeverity(sorted);
|
|
63
|
+
try {
|
|
64
|
+
let checkRunId;
|
|
65
|
+
let commentId;
|
|
66
|
+
let skippedDuplicates = 0;
|
|
67
|
+
// Create check run if enabled
|
|
68
|
+
if (reportingConfig.mode === 'checks_only' || reportingConfig.mode === 'checks_and_comments') {
|
|
69
|
+
checkRunId = await createCheckRun(octokit, context, sorted, partialFindings, counts, config, driftSignal);
|
|
70
|
+
}
|
|
71
|
+
// Post PR comment if enabled and we have a PR number
|
|
72
|
+
if (context.prNumber &&
|
|
73
|
+
(reportingConfig.mode === 'comments_only' || reportingConfig.mode === 'checks_and_comments')) {
|
|
74
|
+
// Build set of deleted files for belt-and-suspenders guard in postPRComment
|
|
75
|
+
// FR-003: Use canonicalFiles for path normalization consistency with findings
|
|
76
|
+
const deletedFiles = new Set(canonicalFiles.filter((f) => f.status === 'deleted').map((f) => f.path));
|
|
77
|
+
const result = await postPRComment(octokit, context, sorted, partialFindings, reportingConfig.max_inline_comments, deletedFiles);
|
|
78
|
+
commentId = result.commentId;
|
|
79
|
+
skippedDuplicates = result.skippedDuplicates;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
checkRunId,
|
|
84
|
+
commentId,
|
|
85
|
+
skippedDuplicates,
|
|
86
|
+
validationStats: normalizationResult.stats,
|
|
87
|
+
invalidLineDetails: normalizationResult.invalidDetails.length > 0
|
|
88
|
+
? normalizationResult.invalidDetails
|
|
89
|
+
: undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Create or update a GitHub check run with annotations
|
|
101
|
+
* If context.checkRunId is provided, updates existing check run (proper lifecycle)
|
|
102
|
+
* Otherwise creates a new check run (legacy/fallback behavior)
|
|
103
|
+
*
|
|
104
|
+
* (012-fix-agent-result-regressions) - Now includes partialFindings in summary
|
|
105
|
+
*/
|
|
106
|
+
async function createCheckRun(octokit, context, findings, partialFindings, counts, config, driftSignal) {
|
|
107
|
+
// Determine conclusion based on gating config
|
|
108
|
+
let conclusion = 'success';
|
|
109
|
+
if (config.gating.enabled) {
|
|
110
|
+
if (config.gating.fail_on_severity === 'error' && counts.error > 0) {
|
|
111
|
+
conclusion = 'failure';
|
|
112
|
+
}
|
|
113
|
+
else if (config.gating.fail_on_severity === 'warning' &&
|
|
114
|
+
(counts.error > 0 || counts.warning > 0)) {
|
|
115
|
+
conclusion = 'failure';
|
|
116
|
+
}
|
|
117
|
+
else if (config.gating.fail_on_severity === 'info' &&
|
|
118
|
+
(counts.error > 0 || counts.warning > 0 || counts.info > 0)) {
|
|
119
|
+
conclusion = 'failure';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Convert findings to annotations (max 50 per request)
|
|
123
|
+
const annotations = findings
|
|
124
|
+
.map(toGitHubAnnotation)
|
|
125
|
+
.filter((a) => a !== null)
|
|
126
|
+
.slice(0, 50);
|
|
127
|
+
const summary = generateSummaryMarkdown(findings);
|
|
128
|
+
// (012-fix-agent-result-regressions) - Append partial findings section if present
|
|
129
|
+
const partialSection = renderPartialFindingsSection(partialFindings);
|
|
130
|
+
// Append drift signal to summary (only shows when warn/fail threshold exceeded)
|
|
131
|
+
const driftMarkdown = generateDriftMarkdown(driftSignal);
|
|
132
|
+
const fullSummary = summary + partialSection + driftMarkdown;
|
|
133
|
+
const output = {
|
|
134
|
+
title: `AI Review: ${counts.error} errors, ${counts.warning} warnings, ${counts.info} info`,
|
|
135
|
+
summary: fullSummary,
|
|
136
|
+
annotations,
|
|
137
|
+
};
|
|
138
|
+
// If we have an existing check run ID, update it (proper lifecycle)
|
|
139
|
+
if (context.checkRunId) {
|
|
140
|
+
await octokit.checks.update({
|
|
141
|
+
owner: context.owner,
|
|
142
|
+
repo: context.repo,
|
|
143
|
+
check_run_id: context.checkRunId,
|
|
144
|
+
status: 'completed',
|
|
145
|
+
conclusion,
|
|
146
|
+
completed_at: new Date().toISOString(),
|
|
147
|
+
output,
|
|
148
|
+
});
|
|
149
|
+
console.log(`[github] Updated check run ${context.checkRunId} with conclusion: ${conclusion}`);
|
|
150
|
+
return context.checkRunId;
|
|
151
|
+
}
|
|
152
|
+
// Fallback: create new check run (legacy behavior if startCheckRun wasn't called)
|
|
153
|
+
const response = await octokit.checks.create({
|
|
154
|
+
owner: context.owner,
|
|
155
|
+
repo: context.repo,
|
|
156
|
+
name: 'AI Code Review',
|
|
157
|
+
head_sha: context.headSha,
|
|
158
|
+
status: 'completed',
|
|
159
|
+
conclusion,
|
|
160
|
+
output,
|
|
161
|
+
});
|
|
162
|
+
console.log(`[github] Created check run ${response.data.id} with conclusion: ${conclusion}`);
|
|
163
|
+
return response.data.id;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Post a summary comment on the PR with deduplication
|
|
167
|
+
*/
|
|
168
|
+
async function postPRComment(octokit, context, findings, partialFindings, maxInlineComments, deletedFiles = new Set()) {
|
|
169
|
+
if (!context.prNumber) {
|
|
170
|
+
throw new Error('PR number required for comments');
|
|
171
|
+
}
|
|
172
|
+
// (012-fix-agent-result-regressions) - Include partial findings section in PR comment
|
|
173
|
+
const summary = generateSummaryMarkdown(findings) + renderPartialFindingsSection(partialFindings);
|
|
174
|
+
// Find existing comment to update
|
|
175
|
+
const existingComments = await octokit.issues.listComments({
|
|
176
|
+
owner: context.owner,
|
|
177
|
+
repo: context.repo,
|
|
178
|
+
issue_number: context.prNumber,
|
|
179
|
+
});
|
|
180
|
+
const botComment = existingComments.data.find((c) => c.user?.type === 'Bot' && c.body?.includes('## AI Code Review Summary'));
|
|
181
|
+
let commentId;
|
|
182
|
+
if (botComment) {
|
|
183
|
+
// Update existing comment
|
|
184
|
+
const response = await octokit.issues.updateComment({
|
|
185
|
+
owner: context.owner,
|
|
186
|
+
repo: context.repo,
|
|
187
|
+
comment_id: botComment.id,
|
|
188
|
+
body: summary,
|
|
189
|
+
});
|
|
190
|
+
commentId = response.data.id;
|
|
191
|
+
console.log(`[github] Updated existing comment ${commentId}`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// Create new comment
|
|
195
|
+
const response = await octokit.issues.createComment({
|
|
196
|
+
owner: context.owner,
|
|
197
|
+
repo: context.repo,
|
|
198
|
+
issue_number: context.prNumber,
|
|
199
|
+
body: summary,
|
|
200
|
+
});
|
|
201
|
+
commentId = response.data.id;
|
|
202
|
+
console.log(`[github] Created new comment ${commentId}`);
|
|
203
|
+
}
|
|
204
|
+
// Get existing review comments for deduplication
|
|
205
|
+
const existingReviewComments = await octokit.pulls.listReviewComments({
|
|
206
|
+
owner: context.owner,
|
|
207
|
+
repo: context.repo,
|
|
208
|
+
pull_number: context.prNumber,
|
|
209
|
+
});
|
|
210
|
+
// Build set of existing comment fingerprints and map to comment IDs for resolution
|
|
211
|
+
const existingDedupeKeys = [];
|
|
212
|
+
const dedupeKeyToCommentId = new Map();
|
|
213
|
+
for (const comment of existingReviewComments.data) {
|
|
214
|
+
if (comment.body) {
|
|
215
|
+
const markers = extractFingerprintMarkers(comment.body);
|
|
216
|
+
for (const marker of markers) {
|
|
217
|
+
existingDedupeKeys.push(marker);
|
|
218
|
+
dedupeKeyToCommentId.set(marker, comment.id);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Build proximity-based deduplication structures
|
|
223
|
+
const existingFingerprintSet = new Set(existingDedupeKeys);
|
|
224
|
+
const proximityMap = buildProximityMap(existingDedupeKeys);
|
|
225
|
+
// Filter findings for inline comments
|
|
226
|
+
// Belt-and-suspenders: also filter out deleted files (should already be file-level)
|
|
227
|
+
const inlineFindings = findings
|
|
228
|
+
.filter((f) => f.line !== undefined && !deletedFiles.has(f.file))
|
|
229
|
+
.sort((a, b) => {
|
|
230
|
+
// Sort by severity (error > warning > info)
|
|
231
|
+
const severityOrder = { error: 0, warning: 1, info: 2 };
|
|
232
|
+
return (severityOrder[a.severity] ?? 2) - (severityOrder[b.severity] ?? 2);
|
|
233
|
+
});
|
|
234
|
+
// Group adjacent findings (within 3 lines of each other in same file)
|
|
235
|
+
const groupedFindings = groupAdjacentFindings(inlineFindings);
|
|
236
|
+
let skippedDuplicates = 0;
|
|
237
|
+
let postedCount = 0;
|
|
238
|
+
for (const findingOrGroup of groupedFindings) {
|
|
239
|
+
if (postedCount >= maxInlineComments)
|
|
240
|
+
break;
|
|
241
|
+
const findingsInGroup = Array.isArray(findingOrGroup) ? findingOrGroup : [findingOrGroup];
|
|
242
|
+
// Use proximity-based deduplication: skip if ALL findings in group are duplicates
|
|
243
|
+
// A finding is a duplicate if:
|
|
244
|
+
// 1. Exact dedupe key match (same fingerprint + file + line), OR
|
|
245
|
+
// 2. Same fingerprint+file within LINE_PROXIMITY_THRESHOLD lines
|
|
246
|
+
const allDuplicates = findingsInGroup.every((f) => isDuplicateByProximity(f, existingFingerprintSet, proximityMap));
|
|
247
|
+
if (allDuplicates) {
|
|
248
|
+
skippedDuplicates++;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const finding = findingsInGroup[0];
|
|
252
|
+
if (!finding)
|
|
253
|
+
continue;
|
|
254
|
+
const body = Array.isArray(findingOrGroup)
|
|
255
|
+
? formatGroupedInlineComment(findingOrGroup)
|
|
256
|
+
: formatInlineComment(finding);
|
|
257
|
+
try {
|
|
258
|
+
const commentParams = {
|
|
259
|
+
owner: context.owner,
|
|
260
|
+
repo: context.repo,
|
|
261
|
+
pull_number: context.prNumber,
|
|
262
|
+
body,
|
|
263
|
+
commit_id: context.headSha,
|
|
264
|
+
path: finding.file,
|
|
265
|
+
line: finding.line,
|
|
266
|
+
side: 'RIGHT', // Always comment on new file (right side of diff)
|
|
267
|
+
};
|
|
268
|
+
// Add multi-line comment support if endLine is present
|
|
269
|
+
if (finding.endLine && finding.endLine !== finding.line) {
|
|
270
|
+
commentParams.start_line = finding.line;
|
|
271
|
+
commentParams.start_side = 'RIGHT';
|
|
272
|
+
commentParams.line = finding.endLine;
|
|
273
|
+
}
|
|
274
|
+
await octokit.pulls.createReviewComment(commentParams);
|
|
275
|
+
postedCount++;
|
|
276
|
+
// Update tracking structures with newly posted findings
|
|
277
|
+
for (const f of findingsInGroup) {
|
|
278
|
+
const key = getDedupeKey(f);
|
|
279
|
+
existingFingerprintSet.add(key);
|
|
280
|
+
// FR-001: Update proximityMap using canonical pattern
|
|
281
|
+
updateProximityMap(proximityMap, f);
|
|
282
|
+
}
|
|
283
|
+
// Rate limiting delay
|
|
284
|
+
await delay(INLINE_COMMENT_DELAY_MS);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
// Inline comments can fail for various reasons (line not in diff, etc.)
|
|
288
|
+
console.warn(`[github] Failed to post inline comment: ${error}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Resolve stale comments (comments for issues that no longer exist)
|
|
292
|
+
// FIX: Use grouped comment resolution - only resolve when ALL markers are stale
|
|
293
|
+
const staleKeys = identifyStaleComments(existingDedupeKeys, findings);
|
|
294
|
+
const staleKeySet = new Set(staleKeys);
|
|
295
|
+
// Build reverse map: commentId -> all markers in that comment
|
|
296
|
+
const commentIdToMarkers = buildCommentToMarkersMap(dedupeKeyToCommentId);
|
|
297
|
+
// Track which comments we've already processed to avoid duplicate API calls
|
|
298
|
+
const processedCommentIds = new Set();
|
|
299
|
+
let resolvedCount = 0;
|
|
300
|
+
let partiallyResolvedCount = 0;
|
|
301
|
+
// Process each comment that has at least one stale marker
|
|
302
|
+
for (const staleKey of staleKeys) {
|
|
303
|
+
const commentIdToProcess = dedupeKeyToCommentId.get(staleKey);
|
|
304
|
+
if (!commentIdToProcess || processedCommentIds.has(commentIdToProcess))
|
|
305
|
+
continue;
|
|
306
|
+
processedCommentIds.add(commentIdToProcess);
|
|
307
|
+
// Get ALL markers for this comment
|
|
308
|
+
const allMarkersInComment = commentIdToMarkers.get(commentIdToProcess) ?? [];
|
|
309
|
+
// Emit warning if any markers are malformed (FR-010: exactly one warning per comment)
|
|
310
|
+
if (hasMalformedMarkers(allMarkersInComment)) {
|
|
311
|
+
emitMalformedMarkerWarning('github', commentIdToProcess);
|
|
312
|
+
}
|
|
313
|
+
// Check if comment should be resolved (ALL markers must be stale)
|
|
314
|
+
const shouldResolve = shouldResolveComment(allMarkersInComment, staleKeySet);
|
|
315
|
+
// Get partially resolved markers for visual indication
|
|
316
|
+
const partiallyResolved = getPartiallyResolvedMarkers(allMarkersInComment, staleKeySet);
|
|
317
|
+
// Emit resolution log (once per comment per run)
|
|
318
|
+
// FR-005: Simplified staleCount calculation for clarity
|
|
319
|
+
const staleCount = shouldResolve ? allMarkersInComment.length : partiallyResolved.length;
|
|
320
|
+
emitResolutionLog('github', commentIdToProcess, allMarkersInComment.length, staleCount, shouldResolve);
|
|
321
|
+
try {
|
|
322
|
+
// Get the existing comment to preserve its content
|
|
323
|
+
// Note: O(n) linear search is acceptable here - only called once per processed comment
|
|
324
|
+
// (not per marker), and processedCommentIds prevents duplicates. For enterprise PRs
|
|
325
|
+
// with 1000+ comments, consider indexing existingReviewComments.data by ID upfront.
|
|
326
|
+
const existingComment = existingReviewComments.data.find((c) => c.id === commentIdToProcess);
|
|
327
|
+
if (!existingComment?.body)
|
|
328
|
+
continue;
|
|
329
|
+
// Skip if already marked as fully resolved
|
|
330
|
+
if (existingComment.body.includes('✅ **Resolved**')) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (shouldResolve) {
|
|
334
|
+
// ALL markers are stale - resolve the entire comment
|
|
335
|
+
// Strip only our fingerprint markers, preserving any user-added HTML comments (FR-019)
|
|
336
|
+
const bodyWithoutOurMarkers = stripOwnFingerprintMarkers(existingComment.body);
|
|
337
|
+
const resolvedBody = `~~${bodyWithoutOurMarkers}~~\n\n` +
|
|
338
|
+
`✅ **Resolved** - This issue appears to have been fixed.\n\n` +
|
|
339
|
+
allMarkersInComment
|
|
340
|
+
.map((m) => `<!-- odd-ai-reviewers:fingerprint:v1:${m} -->`)
|
|
341
|
+
.join('\n');
|
|
342
|
+
await octokit.pulls.updateReviewComment({
|
|
343
|
+
owner: context.owner,
|
|
344
|
+
repo: context.repo,
|
|
345
|
+
comment_id: commentIdToProcess,
|
|
346
|
+
body: resolvedBody,
|
|
347
|
+
});
|
|
348
|
+
resolvedCount++;
|
|
349
|
+
}
|
|
350
|
+
else if (partiallyResolved.length > 0) {
|
|
351
|
+
// Only SOME markers are stale - apply visual indication (strikethrough)
|
|
352
|
+
const updatedBody = applyPartialResolutionVisual(existingComment.body, partiallyResolved);
|
|
353
|
+
// Only update if the body actually changed
|
|
354
|
+
if (updatedBody !== existingComment.body) {
|
|
355
|
+
await octokit.pulls.updateReviewComment({
|
|
356
|
+
owner: context.owner,
|
|
357
|
+
repo: context.repo,
|
|
358
|
+
comment_id: commentIdToProcess,
|
|
359
|
+
body: updatedBody,
|
|
360
|
+
});
|
|
361
|
+
partiallyResolvedCount++;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
await delay(INLINE_COMMENT_DELAY_MS);
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
console.warn(`[github] Failed to resolve/update comment ${commentIdToProcess}: ${error}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
console.log(`[github] Posted ${postedCount} inline comments, skipped ${skippedDuplicates} duplicates, resolved ${resolvedCount} comments, ${partiallyResolvedCount} partially resolved`);
|
|
371
|
+
return { commentId, skippedDuplicates };
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Group adjacent findings (within 3 lines in the same file)
|
|
375
|
+
*/
|
|
376
|
+
function groupAdjacentFindings(findings) {
|
|
377
|
+
if (findings.length === 0)
|
|
378
|
+
return [];
|
|
379
|
+
const result = [];
|
|
380
|
+
const firstFinding = findings[0];
|
|
381
|
+
if (!firstFinding)
|
|
382
|
+
return [];
|
|
383
|
+
let currentGroup = [firstFinding];
|
|
384
|
+
for (let i = 1; i < findings.length; i++) {
|
|
385
|
+
const prev = currentGroup[currentGroup.length - 1];
|
|
386
|
+
const curr = findings[i];
|
|
387
|
+
if (!prev || !curr)
|
|
388
|
+
continue;
|
|
389
|
+
// Group if same file and within 3 lines
|
|
390
|
+
if (prev.file === curr.file && Math.abs(curr.line - prev.line) <= 3) {
|
|
391
|
+
currentGroup.push(curr);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
// Finish current group
|
|
395
|
+
const firstInGroup = currentGroup[0];
|
|
396
|
+
if (firstInGroup) {
|
|
397
|
+
result.push(currentGroup.length === 1 ? firstInGroup : currentGroup);
|
|
398
|
+
}
|
|
399
|
+
currentGroup = [curr];
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// Don't forget the last group
|
|
403
|
+
const firstInGroup = currentGroup[0];
|
|
404
|
+
if (firstInGroup) {
|
|
405
|
+
result.push(currentGroup.length === 1 ? firstInGroup : currentGroup);
|
|
406
|
+
}
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/report/github.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,uBAAuB,EACvB,4BAA4B,EAC5B,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,mBAAmB,EACnB,4BAA4B,EAC5B,0BAA0B,EAC1B,iBAAiB,EACjB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EACL,KAAK,EACL,uBAAuB,EACvB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,kBAAkB,EAClB,qBAAqB,GAItB,MAAM,oBAAoB,CAAC;AAyB5B;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAsB;IACxD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QAC3C,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,OAAO,CAAC,OAAO;QACzB,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,MAAM,EAAE;YACN,KAAK,EAAE,+BAA+B;YACtC,OAAO,EAAE,iDAAiD;SAC3D;KACF,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,8BAA8B,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC5E,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAmB,EACnB,eAA0B,EAC1B,OAAsB,EACtB,MAAc,EACd,SAAqB;IAErB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,IAAI;QACjD,IAAI,EAAE,qBAAqB;QAC3B,mBAAmB,EAAE,EAAE;QACvB,OAAO,EAAE,IAAI;KACd,CAAC;IAEF,mEAAmE;IACnE,yEAAyE;IACzE,MAAM,cAAc,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAExD,kEAAkE;IAClE,MAAM,YAAY,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACvD,MAAM,mBAAmB,GAAG,wBAAwB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAE7E,IAAI,mBAAmB,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,IAAI,mBAAmB,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACtF,OAAO,CAAC,GAAG,CACT,6BAA6B,mBAAmB,CAAC,KAAK,CAAC,KAAK,UAAU;YACpE,GAAG,mBAAmB,CAAC,KAAK,CAAC,UAAU,gBAAgB,mBAAmB,CAAC,KAAK,CAAC,OAAO,UAAU,CACrG,CAAC;IACJ,CAAC;IAED,uDAAuD;IACvD,MAAM,WAAW,GAAG,kBAAkB,CACpC,mBAAmB,CAAC,KAAK,EACzB,mBAAmB,CAAC,cAAc,CACnC,CAAC;IAEF,8BAA8B;IAC9B,MAAM,YAAY,GAAG,mBAAmB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACvE,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEvC,IAAI,CAAC;QACH,IAAI,UAA8B,CAAC;QACnC,IAAI,SAA6B,CAAC;QAClC,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAE1B,8BAA8B;QAC9B,IAAI,eAAe,CAAC,IAAI,KAAK,aAAa,IAAI,eAAe,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YAC7F,UAAU,GAAG,MAAM,cAAc,CAC/B,OAAO,EACP,OAAO,EACP,MAAM,EACN,eAAe,EACf,MAAM,EACN,MAAM,EACN,WAAW,CACZ,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IACE,OAAO,CAAC,QAAQ;YAChB,CAAC,eAAe,CAAC,IAAI,KAAK,eAAe,IAAI,eAAe,CAAC,IAAI,KAAK,qBAAqB,CAAC,EAC5F,CAAC;YACD,4EAA4E;YAC5E,8EAA8E;YAC9E,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CACxE,CAAC;YACF,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,OAAO,EACP,OAAO,EACP,MAAM,EACN,eAAe,EACf,eAAe,CAAC,mBAAmB,EACnC,YAAY,CACb,CAAC;YACF,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;YAC7B,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;QAC/C,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,UAAU;YACV,SAAS;YACT,iBAAiB;YACjB,eAAe,EAAE,mBAAmB,CAAC,KAAK;YAC1C,kBAAkB,EAChB,mBAAmB,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;gBAC3C,CAAC,CAAC,mBAAmB,CAAC,cAAc;gBACpC,CAAC,CAAC,SAAS;SAChB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;SAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,cAAc,CAC3B,OAAgB,EAChB,OAAsB,EACtB,QAAmB,EACnB,eAA0B,EAC1B,MAAgC,EAChC,MAAc,EACd,WAAwB;IAExB,8CAA8C;IAC9C,IAAI,UAAU,GAAsC,SAAS,CAAC;IAE9D,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,OAAO,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YACnE,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;aAAM,IACL,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS;YAC5C,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,EACxC,CAAC;YACD,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;aAAM,IACL,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,MAAM;YACzC,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,EAC3D,CAAC;YACD,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,MAAM,WAAW,GAAG,QAAQ;SACzB,GAAG,CAAC,kBAAkB,CAAC;SACvB,MAAM,CAAC,CAAC,CAAC,EAA8B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SACrD,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEhB,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAElD,kFAAkF;IAClF,MAAM,cAAc,GAAG,4BAA4B,CAAC,eAAe,CAAC,CAAC;IAErE,gFAAgF;IAChF,MAAM,aAAa,GAAG,qBAAqB,CAAC,WAAW,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,OAAO,GAAG,cAAc,GAAG,aAAa,CAAC;IAE7D,MAAM,MAAM,GAAG;QACb,KAAK,EAAE,cAAc,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,OAAO,cAAc,MAAM,CAAC,IAAI,OAAO;QAC3F,OAAO,EAAE,WAAW;QACpB,WAAW;KACZ,CAAC;IAEF,oEAAoE;IACpE,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,UAAU;YAChC,MAAM,EAAE,WAAW;YACnB,UAAU;YACV,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACtC,MAAM;SACP,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,8BAA8B,OAAO,CAAC,UAAU,qBAAqB,UAAU,EAAE,CAAC,CAAC;QAC/F,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;IAED,kFAAkF;IAClF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QAC3C,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,OAAO,CAAC,OAAO;QACzB,MAAM,EAAE,WAAW;QACnB,UAAU;QACV,MAAM;KACP,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,8BAA8B,QAAQ,CAAC,IAAI,CAAC,EAAE,qBAAqB,UAAU,EAAE,CAAC,CAAC;IAC7F,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAC1B,OAAgB,EAChB,OAAsB,EACtB,QAAmB,EACnB,eAA0B,EAC1B,iBAAyB,EACzB,eAA4B,IAAI,GAAG,EAAU;IAE7C,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,sFAAsF;IACtF,MAAM,OAAO,GAAG,uBAAuB,CAAC,QAAQ,CAAC,GAAG,4BAA4B,CAAC,eAAe,CAAC,CAAC;IAElG,kCAAkC;IAClC,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;QACzD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,OAAO,CAAC,QAAQ;KAC/B,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,2BAA2B,CAAC,CAC/E,CAAC;IAEF,IAAI,SAAiB,CAAC;IAEtB,IAAI,UAAU,EAAE,CAAC;QACf,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC;YAClD,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,UAAU,CAAC,EAAE;YACzB,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;QACH,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,qCAAqC,SAAS,EAAE,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,qBAAqB;QACrB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC;YAClD,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,QAAQ;YAC9B,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;QACH,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,gCAAgC,SAAS,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,iDAAiD;IACjD,MAAM,sBAAsB,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC;QACpE,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,QAAQ;KAC9B,CAAC,CAAC;IAEH,mFAAmF;IACnF,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvD,KAAK,MAAM,OAAO,IAAI,sBAAsB,CAAC,IAAI,EAAE,CAAC;QAClD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,yBAAyB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAChC,oBAAoB,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAS,kBAAkB,CAAC,CAAC;IACnE,MAAM,YAAY,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IAE3D,sCAAsC;IACtC,oFAAoF;IACpF,MAAM,cAAc,GAAG,QAAQ;SAC5B,MAAM,CACL,CAAC,CAAC,EAAmC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAC1F;SACA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACb,4CAA4C;QAC5C,MAAM,aAAa,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEL,sEAAsE;IACtE,MAAM,eAAe,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;IAE9D,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;QAC7C,IAAI,WAAW,IAAI,iBAAiB;YAAE,MAAM;QAE5C,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QAE1F,kFAAkF;QAClF,+BAA+B;QAC/B,iEAAiE;QACjE,iEAAiE;QACjE,MAAM,aAAa,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAChD,sBAAsB,CAAC,CAAC,EAAE,sBAAsB,EAAE,YAAY,CAAC,CAChE,CAAC;QAEF,IAAI,aAAa,EAAE,CAAC;YAClB,iBAAiB,EAAE,CAAC;YACpB,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;YACxC,CAAC,CAAC,0BAA0B,CAAC,cAAc,CAAC;YAC5C,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAEjC,IAAI,CAAC;YACH,MAAM,aAAa,GAWf;gBACF,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,WAAW,EAAE,OAAO,CAAC,QAAQ;gBAC7B,IAAI;gBACJ,SAAS,EAAE,OAAO,CAAC,OAAO;gBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,EAAE,kDAAkD;aAClE,CAAC;YAEF,uDAAuD;YACvD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;gBACxD,aAAa,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;gBACxC,aAAa,CAAC,UAAU,GAAG,OAAO,CAAC;gBACnC,aAAa,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;YACvC,CAAC;YAED,MAAM,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;YACvD,WAAW,EAAE,CAAC;YAEd,wDAAwD;YACxD,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC5B,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEhC,sDAAsD;gBACtD,kBAAkB,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;YACtC,CAAC;YAED,sBAAsB;YACtB,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wEAAwE;YACxE,OAAO,CAAC,IAAI,CAAC,2CAA2C,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,oEAAoE;IACpE,gFAAgF;IAChF,MAAM,SAAS,GAAG,qBAAqB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAEvC,8DAA8D;IAC9D,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,oBAAoB,CAAC,CAAC;IAE1E,4EAA4E;IAC5E,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9C,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,sBAAsB,GAAG,CAAC,CAAC;IAE/B,0DAA0D;IAC1D,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB,IAAI,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAAE,SAAS;QAEjF,mBAAmB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAE5C,mCAAmC;QACnC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;QAE7E,sFAAsF;QACtF,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC7C,0BAA0B,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAC3D,CAAC;QAED,kEAAkE;QAClE,MAAM,aAAa,GAAG,oBAAoB,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QAE7E,uDAAuD;QACvD,MAAM,iBAAiB,GAAG,2BAA2B,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QAExF,iDAAiD;QACjD,wDAAwD;QACxD,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC;QACzF,iBAAiB,CACf,QAAQ,EACR,kBAAkB,EAClB,mBAAmB,CAAC,MAAM,EAC1B,UAAU,EACV,aAAa,CACd,CAAC;QAEF,IAAI,CAAC;YACH,mDAAmD;YACnD,uFAAuF;YACvF,oFAAoF;YACpF,oFAAoF;YACpF,MAAM,eAAe,GAAG,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,kBAAkB,CAAC,CAAC;YAC7F,IAAI,CAAC,eAAe,EAAE,IAAI;gBAAE,SAAS;YAErC,2CAA2C;YAC3C,IAAI,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACpD,SAAS;YACX,CAAC;YAED,IAAI,aAAa,EAAE,CAAC;gBAClB,qDAAqD;gBACrD,uFAAuF;gBACvF,MAAM,qBAAqB,GAAG,0BAA0B,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBAC/E,MAAM,YAAY,GAChB,KAAK,qBAAqB,QAAQ;oBAClC,6DAA6D;oBAC7D,mBAAmB;yBAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,wCAAwC,CAAC,MAAM,CAAC;yBAC3D,IAAI,CAAC,IAAI,CAAC,CAAC;gBAEhB,MAAM,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC;oBACtC,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,UAAU,EAAE,kBAAkB;oBAC9B,IAAI,EAAE,YAAY;iBACnB,CAAC,CAAC;gBACH,aAAa,EAAE,CAAC;YAClB,CAAC;iBAAM,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxC,wEAAwE;gBACxE,MAAM,WAAW,GAAG,4BAA4B,CAAC,eAAe,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;gBAE1F,2CAA2C;gBAC3C,IAAI,WAAW,KAAK,eAAe,CAAC,IAAI,EAAE,CAAC;oBACzC,MAAM,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC;wBACtC,KAAK,EAAE,OAAO,CAAC,KAAK;wBACpB,IAAI,EAAE,OAAO,CAAC,IAAI;wBAClB,UAAU,EAAE,kBAAkB;wBAC9B,IAAI,EAAE,WAAW;qBAClB,CAAC,CAAC;oBACH,sBAAsB,EAAE,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,MAAM,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,6CAA6C,kBAAkB,KAAK,KAAK,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CACT,mBAAmB,WAAW,6BAA6B,iBAAiB,yBAAyB,aAAa,cAAc,sBAAsB,qBAAqB,CAC5K,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,QAAwC;IAExC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,MAAM,GAAsE,EAAE,CAAC;IACrF,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,CAAC;IAE7B,IAAI,YAAY,GAAmC,CAAC,YAAY,CAAC,CAAC;IAElE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAEzB,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,SAAS;QAE7B,wCAAwC;QACxC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACpE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,uBAAuB;YACvB,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YACvE,CAAC;YACD,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,YAAY,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line Resolver Module
|
|
3
|
+
*
|
|
4
|
+
* Resolves and validates finding line numbers against unified diffs to prevent
|
|
5
|
+
* misaligned inline comments on GitHub and Azure DevOps.
|
|
6
|
+
*
|
|
7
|
+
* Design Philosophy:
|
|
8
|
+
* - Early normalization before deduplication (INVARIANTS #22)
|
|
9
|
+
* - Comprehensive validation with detailed reporting
|
|
10
|
+
* - Agent-aware resolution (LLMs may emit diff lines, static tools emit file lines)
|
|
11
|
+
* - Graceful degradation (drop unresolvable lines to file-level comments)
|
|
12
|
+
*/
|
|
13
|
+
import type { CanonicalDiffFile } from '../diff.js';
|
|
14
|
+
import type { Finding } from '../agents/types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Represents a single diff hunk with line tracking
|
|
17
|
+
*/
|
|
18
|
+
export interface DiffHunk {
|
|
19
|
+
/** Starting line number in the new file (from @@ header) */
|
|
20
|
+
newFileStart: number;
|
|
21
|
+
/** All valid line numbers in new file (added + context) */
|
|
22
|
+
newFileLines: number[];
|
|
23
|
+
/** Line numbers for added lines only ('+' prefix) */
|
|
24
|
+
addedLines: number[];
|
|
25
|
+
/** Line numbers for context lines only (' ' prefix) */
|
|
26
|
+
contextLines: number[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Per-file mapping of valid lines from diff
|
|
30
|
+
*/
|
|
31
|
+
export interface FileLineMapping {
|
|
32
|
+
/** All valid commentable lines (added + context) */
|
|
33
|
+
allLines: Set<number>;
|
|
34
|
+
/** Only added lines ('+' prefix in diff) */
|
|
35
|
+
addedLines: Set<number>;
|
|
36
|
+
/** Only context lines (' ' prefix in diff) */
|
|
37
|
+
contextLines: Set<number>;
|
|
38
|
+
/** Hunk metadata for debugging and summaries */
|
|
39
|
+
hunks: DiffHunk[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Result of validating a single line number
|
|
43
|
+
*/
|
|
44
|
+
export interface LineValidationResult {
|
|
45
|
+
/** Whether the line is valid for commenting */
|
|
46
|
+
valid: boolean;
|
|
47
|
+
/** The line number being validated */
|
|
48
|
+
line: number;
|
|
49
|
+
/** Whether this is an added line (vs context line) */
|
|
50
|
+
isAddition?: boolean;
|
|
51
|
+
/** Reason for invalid line (if applicable) */
|
|
52
|
+
reason?: string;
|
|
53
|
+
/** Suggested nearest valid line (if requested and available) */
|
|
54
|
+
nearestValidLine?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Statistics from finding normalization (fine-grained accounting)
|
|
58
|
+
*/
|
|
59
|
+
export interface ValidationStats {
|
|
60
|
+
/** Total findings processed */
|
|
61
|
+
total: number;
|
|
62
|
+
/** Findings with valid lines (no changes needed) */
|
|
63
|
+
valid: number;
|
|
64
|
+
/** Findings auto-fixed to nearest valid line */
|
|
65
|
+
normalized: number;
|
|
66
|
+
/** Findings downgraded to file-level (invalid line or deleted file) */
|
|
67
|
+
downgraded: number;
|
|
68
|
+
/** Findings dropped entirely (removed) */
|
|
69
|
+
dropped: number;
|
|
70
|
+
/** Subset of downgraded: findings on deleted files */
|
|
71
|
+
deletedFiles: number;
|
|
72
|
+
/** Subset of downgraded: findings on ambiguous rename paths */
|
|
73
|
+
ambiguousRenames: number;
|
|
74
|
+
/** Findings remapped from old path to new path (successful rename handling) */
|
|
75
|
+
remappedPaths: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Details about an invalid line finding
|
|
79
|
+
*/
|
|
80
|
+
export interface InvalidLineDetail {
|
|
81
|
+
file: string;
|
|
82
|
+
line?: number;
|
|
83
|
+
reason: string;
|
|
84
|
+
nearestValidLine?: number;
|
|
85
|
+
sourceAgent?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Line resolver interface for validating and normalizing line numbers
|
|
89
|
+
*/
|
|
90
|
+
export interface LineResolver {
|
|
91
|
+
/** Validate a line number for a file */
|
|
92
|
+
validateLine(filePath: string, line: number | undefined, options?: LineValidationOptions): LineValidationResult;
|
|
93
|
+
/** Get debug summary for a file */
|
|
94
|
+
getFileSummary(filePath: string): string;
|
|
95
|
+
/** Check if a file exists in the diff */
|
|
96
|
+
hasFile(filePath: string): boolean;
|
|
97
|
+
/** Check if a file is deleted (no inline comments allowed) */
|
|
98
|
+
isDeleted(filePath: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Remap an old path to its new canonical path (for renames)
|
|
101
|
+
* Returns the new path if rename mapping exists, otherwise returns original path
|
|
102
|
+
*/
|
|
103
|
+
remapPath(filePath: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* Check if a path mapping is ambiguous (multiple old paths map to same new path)
|
|
106
|
+
* Ambiguous renames should be downgraded to file-level comments
|
|
107
|
+
*/
|
|
108
|
+
isAmbiguousRename(filePath: string): boolean;
|
|
109
|
+
}
|
|
110
|
+
export interface LineValidationOptions {
|
|
111
|
+
/** Only accept added lines ('+'), not context lines */
|
|
112
|
+
additionsOnly?: boolean;
|
|
113
|
+
/** Find and suggest nearest valid line when invalid */
|
|
114
|
+
suggestNearest?: boolean;
|
|
115
|
+
/** Agent source for resolution strategy */
|
|
116
|
+
sourceAgent?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Parse unified diff hunks from a patch string
|
|
120
|
+
*
|
|
121
|
+
* Extracts line number information from diff hunks, distinguishing:
|
|
122
|
+
* - Added lines ('+' prefix) - exist in new file
|
|
123
|
+
* - Deleted lines ('-' prefix) - do NOT exist in new file
|
|
124
|
+
* - Context lines (' ' prefix) - exist in new file
|
|
125
|
+
*
|
|
126
|
+
* @param patch - Unified diff patch content
|
|
127
|
+
* @returns Array of parsed hunks with line tracking
|
|
128
|
+
*/
|
|
129
|
+
export declare function parseDiffHunks(patch: string): DiffHunk[];
|
|
130
|
+
/**
|
|
131
|
+
* Build a line resolver from diff files
|
|
132
|
+
*
|
|
133
|
+
* @param files - Array of DiffFile objects with patches
|
|
134
|
+
* @returns LineResolver instance for validation and normalization
|
|
135
|
+
*/
|
|
136
|
+
export declare function buildLineResolver(files: CanonicalDiffFile[]): LineResolver;
|
|
137
|
+
/**
|
|
138
|
+
* Normalize findings against diff, validating and adjusting line numbers
|
|
139
|
+
*
|
|
140
|
+
* Strategy:
|
|
141
|
+
* - Valid lines pass through unchanged
|
|
142
|
+
* - Invalid lines are dropped (line set to undefined) for file-level comment
|
|
143
|
+
* - Stats and invalid details are collected for reporting
|
|
144
|
+
*
|
|
145
|
+
* @param findings - Array of findings to normalize
|
|
146
|
+
* @param resolver - Line resolver built from diff
|
|
147
|
+
* @param options - Normalization options
|
|
148
|
+
* @returns Normalized findings with statistics
|
|
149
|
+
*/
|
|
150
|
+
export declare function normalizeFindingsForDiff(findings: Finding[], resolver: LineResolver, options?: {
|
|
151
|
+
additionsOnly?: boolean;
|
|
152
|
+
autoFix?: boolean;
|
|
153
|
+
}): {
|
|
154
|
+
findings: Finding[];
|
|
155
|
+
stats: ValidationStats;
|
|
156
|
+
invalidDetails: InvalidLineDetail[];
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Drift signal result - indicates overall health of line validation
|
|
160
|
+
*/
|
|
161
|
+
export interface DriftSignal {
|
|
162
|
+
/** Signal level: ok (< warn threshold), warn (< fail threshold), fail (>= fail threshold) */
|
|
163
|
+
level: 'ok' | 'warn' | 'fail';
|
|
164
|
+
/** Degradation percentage (dropped + downgraded) / total */
|
|
165
|
+
degradationPercent: number;
|
|
166
|
+
/** Auto-fix percentage (normalized) / total */
|
|
167
|
+
autoFixPercent: number;
|
|
168
|
+
/** Human-readable message explaining the signal */
|
|
169
|
+
message: string;
|
|
170
|
+
/** Top invalid samples for debugging (up to maxSamples) */
|
|
171
|
+
samples: InvalidLineDetail[];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Configuration for drift signal thresholds
|
|
175
|
+
*/
|
|
176
|
+
export interface DriftConfig {
|
|
177
|
+
/** Warn threshold for degradation percentage (default: 20) */
|
|
178
|
+
warnThresholdPercent: number;
|
|
179
|
+
/** Fail threshold for degradation percentage (default: 50) */
|
|
180
|
+
failThresholdPercent: number;
|
|
181
|
+
/** Maximum samples to include in signal (default: 5) */
|
|
182
|
+
maxSamples: number;
|
|
183
|
+
}
|
|
184
|
+
/** Default drift configuration */
|
|
185
|
+
export declare const DEFAULT_DRIFT_CONFIG: DriftConfig;
|
|
186
|
+
/**
|
|
187
|
+
* Compute drift signal from validation stats and invalid details
|
|
188
|
+
*
|
|
189
|
+
* This provides an enterprise-grade health check for line validation:
|
|
190
|
+
* - ok: Everything is fine, degradation is within acceptable limits
|
|
191
|
+
* - warn: Degradation is concerning, should investigate
|
|
192
|
+
* - fail: Degradation is too high, likely indicates a systemic issue
|
|
193
|
+
*
|
|
194
|
+
* @param stats - Validation statistics from normalizeFindingsForDiff
|
|
195
|
+
* @param invalidDetails - Details about invalid lines
|
|
196
|
+
* @param config - Optional configuration for thresholds
|
|
197
|
+
* @returns DriftSignal indicating health and samples for debugging
|
|
198
|
+
*/
|
|
199
|
+
export declare function computeDriftSignal(stats: ValidationStats, invalidDetails: InvalidLineDetail[], config?: Partial<DriftConfig>): DriftSignal;
|
|
200
|
+
/**
|
|
201
|
+
* Generate markdown section for drift signal to include in check summaries
|
|
202
|
+
* Only generates content when drift level is warn or fail
|
|
203
|
+
*
|
|
204
|
+
* @param drift - Computed drift signal
|
|
205
|
+
* @returns Markdown string (empty if level is 'ok')
|
|
206
|
+
*/
|
|
207
|
+
export declare function generateDriftMarkdown(drift: DriftSignal): string;
|
|
208
|
+
//# sourceMappingURL=line-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-resolver.d.ts","sourceRoot":"","sources":["../../src/report/line-resolver.ts"],"names":[],"mappings":"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"}
|