@codraoss/core 0.9.4
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/LICENSE +625 -0
- package/README.md +15 -0
- package/dist/chunk-FGXA7JNR.js +57 -0
- package/dist/chunk-FGXA7JNR.js.map +1 -0
- package/dist/chunk-ILZUCIZH.js +117 -0
- package/dist/chunk-ILZUCIZH.js.map +1 -0
- package/dist/chunk-JC74XH7Q.js +67 -0
- package/dist/chunk-JC74XH7Q.js.map +1 -0
- package/dist/chunk-MMVQPGK3.js +341 -0
- package/dist/chunk-MMVQPGK3.js.map +1 -0
- package/dist/chunk-NSTV4TRP.js +39 -0
- package/dist/chunk-NSTV4TRP.js.map +1 -0
- package/dist/chunk-OIQRTDYR.js +337 -0
- package/dist/chunk-OIQRTDYR.js.map +1 -0
- package/dist/chunk-PVXFURDR.js +90 -0
- package/dist/chunk-PVXFURDR.js.map +1 -0
- package/dist/chunk-R2HRWFRH.js +108 -0
- package/dist/chunk-R2HRWFRH.js.map +1 -0
- package/dist/chunk-RQ5S67XB.js +82 -0
- package/dist/chunk-RQ5S67XB.js.map +1 -0
- package/dist/chunk-U3VKVDZ7.js +266 -0
- package/dist/chunk-U3VKVDZ7.js.map +1 -0
- package/dist/chunk-V3RF6GQW.js +137 -0
- package/dist/chunk-V3RF6GQW.js.map +1 -0
- package/dist/chunk-WSK45HW4.js +79 -0
- package/dist/chunk-WSK45HW4.js.map +1 -0
- package/dist/chunk-XD6CGYHO.js +893 -0
- package/dist/chunk-XD6CGYHO.js.map +1 -0
- package/dist/claim-checks.d.ts +54 -0
- package/dist/claim-checks.js +20 -0
- package/dist/claim-checks.js.map +1 -0
- package/dist/diff/index.d.ts +22 -0
- package/dist/diff/index.js +25 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/fingerprint.d.ts +9 -0
- package/dist/fingerprint.js +19 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/index-BTDWXDck.d.ts +93 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.js +1755 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +32 -0
- package/dist/logger.js +17 -0
- package/dist/logger.js.map +1 -0
- package/dist/model-gRDTk8yk.d.ts +117 -0
- package/dist/model-output/index.d.ts +4 -0
- package/dist/model-output/index.js +32 -0
- package/dist/model-output/index.js.map +1 -0
- package/dist/ports/index.d.ts +512 -0
- package/dist/ports/index.js +13 -0
- package/dist/ports/index.js.map +1 -0
- package/dist/position-h_jdn6ZH.d.ts +30 -0
- package/dist/prompts/file-review.d.ts +6 -0
- package/dist/prompts/file-review.js +25 -0
- package/dist/prompts/file-review.js.map +1 -0
- package/dist/prompts/languages.d.ts +9 -0
- package/dist/prompts/languages.js +7 -0
- package/dist/prompts/languages.js.map +1 -0
- package/dist/prompts/summary.d.ts +12 -0
- package/dist/prompts/summary.js +50 -0
- package/dist/prompts/summary.js.map +1 -0
- package/dist/prompts/verify.d.ts +71 -0
- package/dist/prompts/verify.js +15 -0
- package/dist/prompts/verify.js.map +1 -0
- package/dist/rules/detect.d.ts +32 -0
- package/dist/rules/detect.js +13 -0
- package/dist/rules/detect.js.map +1 -0
- package/dist/rules/table.d.ts +18 -0
- package/dist/rules/table.js +7 -0
- package/dist/rules/table.js.map +1 -0
- package/dist/timeout.d.ts +6 -0
- package/dist/timeout.js +26 -0
- package/dist/timeout.js.map +1 -0
- package/dist/token-tracker.d.ts +38 -0
- package/dist/token-tracker.js +8 -0
- package/dist/token-tracker.js.map +1 -0
- package/dist/verify.d.ts +3 -0
- package/dist/verify.js +21 -0
- package/dist/verify.js.map +1 -0
- package/package.json +181 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/model-output/index.ts","../src/model-output/json.ts","../src/model-output/evidence.ts","../src/model-output/dedupe.ts","../src/model-output/non-answer.ts","../src/model-output/json-batch.ts","../src/model-output/batch.ts"],"sourcesContent":["import {\r\n fileReviewModelOutputSchema,\r\n parsedReviewCommentSchema,\r\n toClaimType,\r\n CLAIM_TYPE_CATEGORY,\r\n type ClaimType,\r\n type ParsedReviewComment,\r\n reviewSeverities,\r\n} from '@codraoss/schema';\r\nimport { renderDiffSnippet } from '../prompts/verify';\r\nimport { logger } from '../logger';\r\nimport { z } from 'zod';\r\nimport { findPositionForLine, getValidPositions, type DiffLine, type FileDiff } from '../diff';\r\nimport {\r\n buildAnchorHash,\r\n buildFindingFingerprint,\r\n buildFindingFingerprintV2,\r\n} from '../fingerprint';\r\nimport {\r\n buildPresenceIndex,\r\n checkAbsenceClaim,\r\n isVersionClaimRefutedByPin,\r\n looksLikeExternalVersionClaim,\r\n refuteUndecidableClaim,\r\n} from '../claim-checks';\r\nimport { parseRawPayload } from './json';\r\nimport {\r\n type BinAmbiguityIndex,\r\n type EvidenceIndex,\r\n buildEvidenceIndex,\r\n foldFirstEvidenceLine,\r\n resolveEvidence,\r\n} from './evidence';\r\n\r\nexport function samePath(a: string, b: string): boolean {\r\n const strip = (p: string) => p.trim().replace(/^\\.\\//, '').replace(/^[ab]\\//, '').replace(/^\\//, '');\r\n return strip(a) === strip(b);\r\n}\r\n\r\nexport type BinAmbiguity = {\r\n index: BinAmbiguityIndex;\r\n filePath: string;\r\n stats: { ambiguousAcrossBin: number };\r\n};\r\n\r\nfunction withSuggestion(body: string, codeSuggestion?: string) {\r\n if (!codeSuggestion) return body;\r\n\r\n const cleanSuggestion = codeSuggestion.replace(/```suggestion\\n?|```/g, '').trim();\r\n\r\n const cleanBody = body.split('```suggestion')[0].trim();\r\n\r\n return `${cleanBody}\\n\\n\\`\\`\\`suggestion\\n${cleanSuggestion}\\n\\`\\`\\``;\r\n}\r\n\r\nconst CLAIM_TYPE_REPAIRS: ReadonlyArray<{ pattern: RegExp; claimType: ClaimType }> = [\r\n { pattern: /dependenc(?:y|ies)\\s+array|exhaustive[- ]deps/i, claimType: 'react_hook_missing_deps' },\r\n { pattern: /redos|catastrophic backtrack|exponential backtrack/i, claimType: 'redos_regex' },\r\n];\r\n\r\nfunction repairClaimType(claimType: ClaimType, title: string, body: string, onRepair: () => void): ClaimType {\r\n if (claimType !== 'other') return claimType;\r\n const text = `${title}\\n${body}`;\r\n\r\n if (looksLikeExternalVersionClaim(title, body)) {\r\n onRepair();\r\n return 'external_version_claim';\r\n }\r\n\r\n for (const { pattern, claimType: repaired } of CLAIM_TYPE_REPAIRS) {\r\n if (pattern.test(text)) {\r\n onRepair();\r\n return repaired;\r\n }\r\n }\r\n return claimType;\r\n}\r\n\r\ntype RawFinding = z.infer<typeof fileReviewModelOutputSchema>['findings'][number];\r\n\r\ntype Withheld = { title: string; body: string; tag?: string };\r\n\r\nfunction formatWithheld(w: Withheld): string {\r\n return w.tag ? `- **[${w.tag}] ${w.title}:** ${w.body}` : `- **${w.title}:** ${w.body}`;\r\n}\r\n\r\nfunction groundFindingInEvidence(\r\n finding: RawFinding,\r\n evidenceIndex: EvidenceIndex,\r\n evidenceStats: { total: number; matched: number; unmatched: number; weak: number; absent: number },\r\n ambiguity?: BinAmbiguity,\r\n): { diffLine: DiffLine } | { withheld: Withheld } {\r\n const reportedLine = finding.code_location.line || finding.code_location.line_range?.start;\r\n\r\n evidenceStats.total += 1;\r\n const evidence = resolveEvidence(finding.evidence, evidenceIndex, reportedLine);\r\n if (evidence.status === 'matched') evidenceStats.matched += 1;\r\n else if (evidence.status === 'unmatched') evidenceStats.unmatched += 1;\r\n else if (evidence.status === 'weak') evidenceStats.weak += 1;\r\n else if (evidence.status === 'absent') evidenceStats.absent += 1;\r\n\r\n if (evidence.status !== 'matched') {\r\n return { withheld: { title: finding.title, body: finding.body, tag: `unverified:${evidence.status}` } };\r\n }\r\n\r\n if (ambiguity) {\r\n const firstLine = foldFirstEvidenceLine(finding.evidence);\r\n const claimedPath = finding.code_location.absolute_file_path?.trim();\r\n const ambiguousAcrossBin = firstLine ? (ambiguity.index.get(firstLine) ?? 0) > 1 : false;\r\n if (ambiguousAcrossBin && claimedPath && !samePath(claimedPath, ambiguity.filePath)) {\r\n ambiguity.stats.ambiguousAcrossBin += 1;\r\n return {\r\n withheld: {\r\n title: finding.title,\r\n body: finding.body,\r\n tag: 'unverified:ambiguous-across-bin',\r\n },\r\n };\r\n }\r\n }\r\n\r\n return { diffLine: evidence.line };\r\n}\r\n\r\nfunction anchorToDiffPosition(\r\n file: FileDiff,\r\n diffLine: DiffLine,\r\n validPositions: Set<number>,\r\n finding: RawFinding,\r\n): { line: number; position: number } | { withheld: Withheld } {\r\n const line = diffLine.newLineNumber!;\r\n const position = findPositionForLine(file, line);\r\n\r\n if (position === undefined || !validPositions.has(position)) {\r\n return { withheld: { title: finding.title, body: finding.body } };\r\n }\r\n\r\n return { line, position };\r\n}\r\n\r\nfunction validateFindingShape(finding: RawFinding): { severity: typeof reviewSeverities[number]; title: string; body: string } {\r\n const priorityMap: Record<number, typeof reviewSeverities[number]> = {\r\n 0: 'P0',\r\n 1: 'P1',\r\n 2: 'P2',\r\n 3: 'P3',\r\n 4: 'nit',\r\n };\r\n const severity = finding.priority !== undefined\r\n ? priorityMap[finding.priority] || 'P3'\r\n : 'P3';\r\n\r\n const cleanText = (text: string) => {\r\n let current = text.trim();\r\n let prev = '';\r\n while (current !== prev) {\r\n prev = current;\r\n current = current\r\n .replace(/^(?:[^\\w\\s]+|(?:QUALITY|SECURITY|BUG|PERFORMANCE|CORRECTNESS|P[0-3]|NIT)\\b)+/giu, '')\r\n .replace(/\\n\\s*/g, ' ')\r\n .trim();\r\n }\r\n return current;\r\n };\r\n\r\n const title = cleanText(finding.title);\r\n let body = cleanText(finding.body);\r\n\r\n const bodyPrefix = cleanText(body.split('\\n')[0]);\r\n if (bodyPrefix.toLowerCase().startsWith(title.toLowerCase()) || title.toLowerCase().startsWith(bodyPrefix.toLowerCase())) {\r\n body = cleanText(body.slice(body.split('\\n')[0].length));\r\n }\r\n\r\n return { severity, title, body };\r\n}\r\n\r\nfunction applyClaimGate(\r\n finding: RawFinding,\r\n title: string,\r\n body: string,\r\n anchorContent: string,\r\n deniedClaimTypes: Set<ClaimType>,\r\n claimTypeCounts: Record<string, number>,\r\n deniedClaimCounts: Record<string, number>,\r\n): { claimType: ClaimType } | { withheld: Withheld } {\r\n const claimType = repairClaimType(toClaimType(finding.claim_type), title, body, () => {\r\n claimTypeCounts.__repaired = (claimTypeCounts.__repaired ?? 0) + 1;\r\n });\r\n\r\n claimTypeCounts[claimType] = (claimTypeCounts[claimType] ?? 0) + 1;\r\n\r\n if (deniedClaimTypes.has(claimType)) {\r\n deniedClaimCounts[claimType] = (deniedClaimCounts[claimType] ?? 0) + 1;\r\n return { withheld: { title, body, tag: `claim-denied:${claimType}` } };\r\n }\r\n\r\n if (isVersionClaimRefutedByPin({ title, body, anchorContent })) {\r\n deniedClaimCounts.version_claim_on_pinned_sha = (deniedClaimCounts.version_claim_on_pinned_sha ?? 0) + 1;\r\n return { withheld: { title, body, tag: 'refuted:pinned-sha' } };\r\n }\r\n\r\n const undecidable = refuteUndecidableClaim({ title, body });\r\n if (undecidable) {\r\n const key = `undecidable_${undecidable.replace('-', '_')}`;\r\n deniedClaimCounts[key] = (deniedClaimCounts[key] ?? 0) + 1;\r\n return { withheld: { title, body, tag: `refuted:${undecidable}` } };\r\n }\r\n\r\n return { claimType };\r\n}\r\n\r\nfunction buildParsedComment(params: {\r\n file: FileDiff;\r\n line: number;\r\n position: number;\r\n severity: typeof reviewSeverities[number];\r\n title: string;\r\n body: string;\r\n claimType: ClaimType;\r\n anchorContent: string;\r\n finding: RawFinding;\r\n presenceIndex: ReturnType<typeof buildPresenceIndex>;\r\n absenceCheckStats: { absenceShaped: number; identifierExtracted: number; refuted: number };\r\n}): ParsedReviewComment {\r\n const { file, line, position, severity, title, body, claimType, anchorContent, finding, presenceIndex, absenceCheckStats } = params;\r\n\r\n const absence = checkAbsenceClaim({ title, body, anchorLine: line, index: presenceIndex });\r\n if (absence.status === 'refuted') {\r\n absenceCheckStats.absenceShaped += 1;\r\n absenceCheckStats.identifierExtracted += 1;\r\n absenceCheckStats.refuted += 1;\r\n } else if (absence.reason !== 'not_absence_shaped') {\r\n absenceCheckStats.absenceShaped += 1;\r\n if (absence.reason !== 'no_identifier' && absence.reason !== 'ambiguous_identifier') {\r\n absenceCheckStats.identifierExtracted += 1;\r\n }\r\n }\r\n\r\n const confidenceScore = typeof finding.confidence_score === 'number'\r\n ? finding.confidence_score\r\n : 0;\r\n\r\n const codeSuggestion = typeof finding.code_suggestion === 'string' && finding.code_suggestion.trim()\r\n ? finding.code_suggestion\r\n : undefined;\r\n\r\n return parsedReviewCommentSchema.parse({\r\n path: file.path,\r\n line,\r\n position,\r\n severity,\r\n category: CLAIM_TYPE_CATEGORY[claimType],\r\n claimType,\r\n contextSnippet: renderDiffSnippet(file, line) || undefined,\r\n title,\r\n body: withSuggestion(body, codeSuggestion),\r\n codeSuggestion,\r\n confidenceScore,\r\n evidence: typeof finding.evidence === 'string' && finding.evidence.trim() ? finding.evidence.trim() : undefined,\r\n fingerprint: buildFindingFingerprint(file.path, title),\r\n anchorHash: anchorContent ? buildAnchorHash(anchorContent) : undefined,\r\n fingerprintV2: buildFindingFingerprintV2(\r\n file.path,\r\n claimType,\r\n anchorContent ? buildAnchorHash(anchorContent) : undefined,\r\n ) ?? undefined,\r\n });\r\n}\r\n\r\nexport type FileReviewPayload = z.infer<typeof fileReviewModelOutputSchema>;\r\n\r\nexport type GroundingOptions = {\r\n deniedClaimTypes?: readonly ClaimType[];\r\n ambiguity?: BinAmbiguity;\r\n};\r\n\r\nexport type GroundedFileReview = {\r\n comments: ParsedReviewComment[];\r\n verdict: 'approve' | 'comment';\r\n fileSummary: string;\r\n overallCorrectness?: string;\r\n confidenceScore?: number;\r\n evidenceStats: { total: number; matched: number; unmatched: number; weak: number; absent: number };\r\n claimTypeCounts: Record<string, number>;\r\n deniedClaimCounts: Record<string, number>;\r\n absenceCheckStats: { absenceShaped: number; identifierExtracted: number; refuted: number };\r\n};\r\n\r\nexport function groundParsedFindings(\r\n parsed: FileReviewPayload,\r\n file: FileDiff,\r\n options?: GroundingOptions,\r\n): GroundedFileReview {\r\n const validPositions = getValidPositions(file);\r\n const evidenceIndex = buildEvidenceIndex(file);\r\n const evidenceStats = { total: 0, matched: 0, unmatched: 0, weak: 0, absent: 0 };\r\n const claimTypeCounts: Record<string, number> = {};\r\n const deniedClaimCounts: Record<string, number> = {};\r\n const deniedClaimTypes = new Set<ClaimType>(options?.deniedClaimTypes ?? []);\r\n const presenceIndex = buildPresenceIndex(file);\r\n const absenceCheckStats = { absenceShaped: 0, identifierExtracted: 0, refuted: 0 };\r\n const orphanedComments: string[] = [];\r\n\r\n const comments = (parsed.findings || [])\r\n .map((finding): ParsedReviewComment | null => {\r\n const grounded = groundFindingInEvidence(finding, evidenceIndex, evidenceStats, options?.ambiguity);\r\n if ('withheld' in grounded) {\r\n orphanedComments.push(formatWithheld(grounded.withheld));\r\n return null;\r\n }\r\n\r\n const anchored = anchorToDiffPosition(file, grounded.diffLine, validPositions, finding);\r\n if ('withheld' in anchored) {\r\n orphanedComments.push(formatWithheld(anchored.withheld));\r\n return null;\r\n }\r\n\r\n const { severity, title, body } = validateFindingShape(finding);\r\n\r\n const anchorContent = grounded.diffLine.content\r\n ?? file.hunks.flatMap((h) => h.lines).find((l) => l.newLineNumber === anchored.line)?.content\r\n ?? '';\r\n\r\n const gated = applyClaimGate(finding, title, body, anchorContent, deniedClaimTypes, claimTypeCounts, deniedClaimCounts);\r\n if ('withheld' in gated) {\r\n orphanedComments.push(formatWithheld(gated.withheld));\r\n return null;\r\n }\r\n\r\n try {\r\n return buildParsedComment({\r\n file,\r\n line: anchored.line,\r\n position: anchored.position,\r\n severity,\r\n title,\r\n body,\r\n claimType: gated.claimType,\r\n anchorContent,\r\n finding,\r\n presenceIndex,\r\n absenceCheckStats,\r\n });\r\n } catch (error) {\r\n if (!(error instanceof z.ZodError)) throw error;\r\n\r\n orphanedComments.push(formatWithheld({\r\n title: finding.title,\r\n body: finding.body,\r\n tag: 'unverified:unassemblable',\r\n }));\r\n logger.warn('Dropped a finding that could not be assembled', {\r\n path: file.path,\r\n title: finding.title,\r\n error: error.message,\r\n });\r\n return null;\r\n }\r\n })\r\n .filter((comment): comment is ParsedReviewComment => Boolean(comment));\r\n\r\n const verdict = parsed.overall_correctness.toLowerCase().includes('patch is correct') ? 'approve' : 'comment';\r\n let fileSummary = parsed.overall_explanation;\r\n\r\n if (orphanedComments.length > 0) {\r\n fileSummary += `\\n\\n### Additional Comments (Off-diff)\\n${orphanedComments.join('\\n')}`;\r\n }\r\n\r\n return {\r\n comments,\r\n verdict: comments.length > 0 ? 'comment' : verdict,\r\n fileSummary,\r\n overallCorrectness: parsed.overall_correctness,\r\n confidenceScore: parsed.overall_confidence_score,\r\n evidenceStats,\r\n claimTypeCounts,\r\n deniedClaimCounts,\r\n absenceCheckStats,\r\n };\r\n}\r\n\r\nexport function parseFileReviewResponse(\r\n raw: string,\r\n file: FileDiff,\r\n options?: GroundingOptions,\r\n): GroundedFileReview {\r\n return groundParsedFindings(parseRawPayload(raw), file, options);\r\n}\r\n\r\n\r\nexport { dedupeFindings } from './dedupe';\r\nexport { isNonAnswerReview } from './non-answer';\r\nexport {\r\n NON_ANSWER_MAX_RESPONSE_CHARS,\r\n NON_ANSWER_MIN_DIFF_LINES,\r\n} from '../constants';\r\nexport { parseRawBatchPayload, type RawBatchPayload } from './json-batch';\r\nexport { parseBatchReviewResponse, type BatchParseStats, type BatchReviewResult } from './batch';\r\n","import { fileReviewModelOutputSchema } from '@codraoss/schema';\r\nimport { jsonrepair } from 'jsonrepair';\r\nimport { z } from 'zod';\r\nimport { logger } from '../logger';\r\n\r\nimport { MAX_LOGGED_JSON_CHARS } from '../constants';\r\n\r\nexport function truncateJsonForLog(value: string) {\r\n if (value.length <= MAX_LOGGED_JSON_CHARS) return value;\r\n return `${value.slice(0, MAX_LOGGED_JSON_CHARS)}... [truncated ${value.length - MAX_LOGGED_JSON_CHARS} chars]`;\r\n}\r\n\r\nexport function hasReviewKeys(input: string) {\r\n return /\"(files|findings|overall_explanation|overall_correctness|overall_confidence_score|summary)\"\\s*:/.test(input);\r\n}\r\n\r\nfunction scanBalanced(raw: string, startIdx: number, open: string, close: string): string | null {\r\n let stack = 0;\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (let i = startIdx; i < raw.length; i++) {\r\n const char = raw[i];\r\n\r\n if (escape) {\r\n escape = false;\r\n continue;\r\n }\r\n if (char === '\\\\') {\r\n escape = true;\r\n continue;\r\n }\r\n if (char === '\"') {\r\n inString = !inString;\r\n continue;\r\n }\r\n if (inString) continue;\r\n\r\n if (char === open) stack++;\r\n else if (char === close) {\r\n stack--;\r\n if (stack === 0) return raw.slice(startIdx, i + 1);\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function extractJson(raw: string, anchorKey: 'findings' | 'files' = 'findings') {\r\n const jsonBlocks = Array.from(raw.matchAll(/```json([\\s\\S]*?)```/gi));\r\n if (jsonBlocks.length > 0) {\r\n return jsonBlocks[jsonBlocks.length - 1][1].trim();\r\n }\r\n\r\n const genericBlocks = Array.from(raw.matchAll(/```(?:[\\w+-]+)?([\\s\\S]*?)```/gi));\r\n if (genericBlocks.length > 0) {\r\n const candidates = genericBlocks.filter(b => b[1].includes('{') && b[1].includes('}') && hasReviewKeys(b[1]));\r\n if (candidates.length > 0) {\r\n const content = candidates[candidates.length - 1][1].trim();\r\n const start = content.indexOf('{');\r\n const end = content.lastIndexOf('}');\r\n if (start !== -1 && end !== -1 && end > start) {\r\n return content.slice(start, end + 1);\r\n }\r\n return content;\r\n }\r\n }\r\n\r\n const arrayStart = raw.indexOf('[');\r\n if (arrayStart !== -1 && raw.slice(0, arrayStart).trim() === '') {\r\n const matched = scanBalanced(raw, arrayStart, '[', ']');\r\n if (matched && hasReviewKeys(matched)) return matched;\r\n }\r\n\r\n const anchorIdx = anchorKey === 'files' ? raw.indexOf('\"files\"') : -1;\r\n const findingsIdx = anchorIdx !== -1 ? anchorIdx : raw.indexOf('\"findings\"');\r\n const summaryIdx = raw.indexOf('\"summary\"');\r\n const targetIdx = findingsIdx !== -1 ? findingsIdx : (summaryIdx !== -1 ? summaryIdx : -1);\r\n\r\n let firstBrace = -1;\r\n if (targetIdx !== -1) {\r\n firstBrace = raw.lastIndexOf('{', targetIdx);\r\n }\r\n\r\n if (firstBrace === -1) {\r\n const allBraces = Array.from(raw.matchAll(/\\{/g));\r\n let bestIdx = -1;\r\n let bestScore = -1;\r\n\r\n for (const match of allBraces) {\r\n const idx = match.index!;\r\n const excerpt = raw.slice(idx, idx + 200);\r\n let score = 0;\r\n\r\n if (excerpt.includes('\"files\"')) score += 100;\r\n if (excerpt.includes('\"findings\"')) score += 100;\r\n if (excerpt.includes('\"summary\"')) score += 50;\r\n if (excerpt.includes('\"overall_explanation\"')) score += 50;\r\n\r\n if (excerpt.includes('\" : ') || excerpt.includes('\":')) score += 10;\r\n if (excerpt.includes('\"[')) score += 5;\r\n\r\n if (excerpt.includes(': number;') || excerpt.includes(': string;')) score -= 80;\r\n if (excerpt.includes('export ') || excerpt.includes('function ')) score -= 80;\r\n if (excerpt.includes('interface ') || excerpt.includes('type ')) score -= 80;\r\n if (excerpt.includes(' + ')) score -= 20; // Looks like a diff hunk\r\n\r\n if (score > bestScore) {\r\n bestScore = score;\r\n bestIdx = idx;\r\n }\r\n }\r\n\r\n if (bestIdx !== -1 && bestScore > 0) {\r\n firstBrace = bestIdx;\r\n }\r\n }\r\n\r\n if (firstBrace === -1) {\r\n const start = raw.indexOf('{');\r\n if (start !== -1) {\r\n const excerpt = raw.slice(start, start + 50);\r\n if (excerpt.includes('\"') && excerpt.includes(':')) {\r\n firstBrace = start;\r\n }\r\n }\r\n }\r\n\r\n if (firstBrace !== -1) {\r\n let stack = 0;\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (let i = firstBrace; i < raw.length; i++) {\r\n const char = raw[i];\r\n\r\n if (escape) {\r\n escape = false;\r\n continue;\r\n }\r\n\r\n if (char === '\\\\') {\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (char === '\"') {\r\n inString = !inString;\r\n continue;\r\n }\r\n\r\n if (!inString) {\r\n if (char === '{') stack++;\r\n else if (char === '}') {\r\n stack--;\r\n if (stack === 0) {\r\n return raw.slice(firstBrace, i + 1);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const partial = raw.slice(firstBrace).trim();\r\n let closing = '';\r\n if (inString) closing += '\"';\r\n closing += '}'.repeat(Math.max(1, stack));\r\n return `${partial}${closing}`;\r\n }\r\n\r\n return raw.trim();\r\n}\r\n\r\nexport function preprocessJson(json: string): string {\r\n let result = '';\r\n let inString = false;\r\n let escape = false;\r\n\r\n for (let i = 0; i < json.length; i++) {\r\n const char = json[i];\r\n\r\n if (escape) {\r\n result += char;\r\n escape = false;\r\n continue;\r\n }\r\n\r\n if (char === '\\\\') {\r\n result += char;\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (char === '\"') {\r\n inString = !inString;\r\n result += char;\r\n continue;\r\n }\r\n\r\n if (inString) {\r\n if (char === '\\n') {\r\n result += '\\\\n';\r\n } else if (char === '\\r') {\r\n result += '\\\\r';\r\n } else {\r\n result += char;\r\n }\r\n } else {\r\n result += char;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Deletes every `null`-valued key, recursively, before Zod sees the payload.\r\n *\r\n * The model output schemas mark optional fields `.optional()`, which accepts an ABSENT key and rejects\r\n * an explicit `null` -- and these models routinely emit `\"code_suggestion\": null` for a finding that\r\n * carries no suggestion. On the batched path that single null failed\r\n * `batchReviewModelOutputSchema.parse`, so `parseBatchReviewResponse` threw and the response for EVERY\r\n * file in the bin was discarded, then reported as an unreadable answer and failed over to the next\r\n * model. Measured on this repository's own review: 37 of 88 rejected payloads were otherwise complete\r\n * and readable.\r\n *\r\n * Stripping rather than widening each field is deliberate: absent and null mean the same thing to every\r\n * one of these schemas, one pass covers the fields nobody has thought of yet, and no downstream type\r\n * has to learn about `null`.\r\n */\r\nexport function stripNulls<T>(value: T): T {\r\n if (Array.isArray(value)) return value.map(stripNulls) as unknown as T;\r\n if (value === null || typeof value !== 'object') return value;\r\n\r\n const out: Record<string, unknown> = {};\r\n for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {\r\n if (entry === null) continue;\r\n out[key] = stripNulls(entry);\r\n }\r\n return out as T;\r\n}\r\n\r\nfunction isPlaceholderString(value: unknown) {\r\n return typeof value === 'string' && /^<[^>]+>$/.test(value.trim());\r\n}\r\n\r\nfunction coerceReviewNumber(value: unknown) {\r\n if (typeof value === 'number' && Number.isFinite(value)) return value;\r\n if (typeof value === 'string' && !isPlaceholderString(value)) {\r\n const parsed = Number(value);\r\n if (Number.isFinite(parsed)) return parsed;\r\n }\r\n return undefined;\r\n}\r\n\r\nexport function normalizeFinding(finding: unknown) {\r\n if (!finding || typeof finding !== 'object') return null;\r\n const f = finding as Record<string, unknown>;\r\n if (isPlaceholderString(f.title) || isPlaceholderString(f.body) || isPlaceholderString(f.evidence)) return null;\r\n\r\n const location = f.code_location && typeof f.code_location === 'object' ? (f.code_location as Record<string, unknown>) : {};\r\n const line = coerceReviewNumber(location.line);\r\n const start = coerceReviewNumber(location.line_range && typeof location.line_range === 'object' ? (location.line_range as Record<string, unknown>).start : undefined);\r\n const end = coerceReviewNumber(location.line_range && typeof location.line_range === 'object' ? (location.line_range as Record<string, unknown>).end : undefined);\r\n const priority = coerceReviewNumber(f.priority);\r\n\r\n const codeLocation: Record<string, unknown> = {\r\n absolute_file_path: location.absolute_file_path || f.path || '',\r\n };\r\n if (line !== undefined) {\r\n codeLocation.line = Math.trunc(line as number);\r\n }\r\n if (start !== undefined || end !== undefined) {\r\n codeLocation.line_range = {\r\n start: Math.trunc((start as number) ?? (end as number)!),\r\n end: Math.trunc((end as number) ?? (start as number)!),\r\n };\r\n }\r\n\r\n return {\r\n ...f,\r\n title: (f.title ? String(f.title) : '').trim().slice(0, 100).replace(/[\\uD800-\\uDBFF]$/, '') || 'Code finding',\r\n priority: priority === undefined ? undefined : Math.max(0, Math.min(4, Math.trunc(priority as number))),\r\n code_location: codeLocation,\r\n confidence_score: typeof f.confidence_score === 'number'\r\n ? Math.max(0, Math.min(1, f.confidence_score > 1 ? f.confidence_score / 10 : f.confidence_score))\r\n : undefined,\r\n };\r\n}\r\n\r\nexport function parseRawPayload(raw: string): z.infer<typeof fileReviewModelOutputSchema> {\r\n let extracted: string;\r\n try {\r\n extracted = extractJson(raw);\r\n if (!hasReviewKeys(extracted)) {\r\n throw new Error('Model response did not contain review JSON keys.');\r\n }\r\n } catch (e) {\r\n logger.error('Failed to extract JSON from model response', {\r\n rawLength: raw.length,\r\n rawPrefix: raw.slice(0, 500),\r\n error: e instanceof Error ? e.message : String(e),\r\n });\r\n throw new Error('Could not find JSON root in model response.', { cause: e });\r\n }\r\n\r\n let preprocessed: string;\r\n try {\r\n preprocessed = preprocessJson(extracted);\r\n } catch (e) {\r\n logger.warn('JSON preprocessing partially failed, continuing...', { extracted, error: e });\r\n preprocessed = extracted;\r\n }\r\n\r\n let repaired = preprocessed;\r\n try {\r\n repaired = jsonrepair(preprocessed);\r\n } catch (e) {\r\n logger.warn('jsonrepair failed to fix model output, using preprocessed text', { preprocessed: truncateJsonForLog(preprocessed), error: e });\r\n }\r\n\r\n let parsedJson: unknown;\r\n try {\r\n parsedJson = stripNulls(JSON.parse(repaired));\r\n } catch (e) {\r\n logger.error('Critical JSON parse error after extraction and repair', { repaired: truncateJsonForLog(repaired), error: e });\r\n throw new Error(`Invalid JSON format: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e });\r\n }\r\n\r\n try {\r\n const findReviewObject = (arr: unknown[]): unknown | null => {\r\n const best = arr.find(i => i && typeof i === 'object' && Array.isArray((i as Record<string, unknown>).findings) && typeof (i as Record<string, unknown>).summary === 'string');\r\n if (best) return best;\r\n\r\n const good = arr.find(i => i && typeof i === 'object' && Array.isArray((i as Record<string, unknown>).findings));\r\n if (good) return good;\r\n\r\n return arr.find(i =>\r\n i && typeof i === 'object' &&\r\n ('findings' in i || 'overall_explanation' in i || 'summary' in i || 'overall_correctness' in i)\r\n );\r\n };\r\n\r\n let data = Array.isArray(parsedJson) ? (findReviewObject(parsedJson) || parsedJson[0] || {}) : parsedJson;\r\n\r\n if (data && typeof data === 'object') {\r\n const obj = data as Record<string, unknown>;\r\n if (!obj.findings) obj.findings = [];\r\n if (!obj.overall_explanation) obj.overall_explanation = 'No explanation provided.';\r\n if (!obj.overall_correctness) obj.overall_correctness = 'Uncertain';\r\n\r\n if (typeof obj.overall_confidence_score === 'number') {\r\n if (obj.overall_confidence_score > 1) {\r\n obj.overall_confidence_score = Math.min(obj.overall_confidence_score / 10, 1);\r\n } else if (obj.overall_confidence_score < 0) {\r\n obj.overall_confidence_score = 0;\r\n }\r\n } else {\r\n obj.overall_confidence_score = 0.5;\r\n }\r\n\r\n if (Array.isArray(obj.findings)) {\r\n obj.findings = obj.findings.flatMap((finding: unknown) => {\r\n const normalized = normalizeFinding(finding);\r\n return normalized ? [normalized] : [];\r\n });\r\n }\r\n data = obj;\r\n }\r\n\r\n return fileReviewModelOutputSchema.parse(data);\r\n } catch (e) {\r\n logger.error('Model response failed schema validation', { parsedJson, error: e });\r\n throw new Error(`Response schema mismatch: ${e instanceof Error ? e.message : 'Check logs'}`, { cause: e });\r\n }\r\n}\r\n","import { foldEvidenceText } from '../fingerprint';\r\nimport type { DiffLine, FileDiff } from '../diff';\r\n\r\nimport { MIN_DISCRIMINATING_EVIDENCE_CHARS } from '../constants';\r\n\r\nexport type EvidenceIndex = {\r\n byContent: Map<string, DiffLine[]>;\r\n lines: { normalized: string; line: DiffLine }[];\r\n};\r\n\r\nexport function buildEvidenceIndex(file: FileDiff): EvidenceIndex {\r\n const byContent = new Map<string, DiffLine[]>();\r\n const lines: { normalized: string; line: DiffLine }[] = [];\r\n\r\n for (const hunk of file.hunks) {\r\n const postable = hunk.lines.filter((line) => line.kind !== 'del' && line.newLineNumber !== undefined);\r\n if (postable.length === 0) continue;\r\n\r\n hunk.lines.forEach((line, lineIndex) => {\r\n const normalized = foldEvidenceText(line.content);\r\n if (!normalized) return;\r\n\r\n let anchor = line;\r\n if (line.kind === 'del' || line.newLineNumber === undefined) {\r\n anchor = hunk.lines.slice(lineIndex + 1).find((l) => l.kind !== 'del' && l.newLineNumber !== undefined)\r\n ?? hunk.lines.slice(0, lineIndex).reverse().find((l) => l.kind !== 'del' && l.newLineNumber !== undefined)\r\n ?? postable[0];\r\n }\r\n\r\n lines.push({ normalized, line: anchor });\r\n const existing = byContent.get(normalized);\r\n if (existing) existing.push(anchor);\r\n else byContent.set(normalized, [anchor]);\r\n });\r\n }\r\n\r\n return { byContent, lines };\r\n}\r\n\r\nexport function foldFirstEvidenceLine(evidence: unknown): string | null {\r\n if (typeof evidence !== 'string') return null;\r\n return evidence.split('\\n').map(foldEvidenceText).find((l) => l.length > 0) ?? null;\r\n}\r\n\r\nexport type BinAmbiguityIndex = Map<string, number>;\r\n\r\nexport function buildBinAmbiguityIndex(files: readonly FileDiff[]): BinAmbiguityIndex {\r\n const filesPerLine = new Map<string, Set<string>>();\r\n\r\n for (const file of files) {\r\n for (const hunk of file.hunks) {\r\n for (const line of hunk.lines) {\r\n const normalized = foldEvidenceText(line.content);\r\n if (normalized.length < MIN_DISCRIMINATING_EVIDENCE_CHARS) continue;\r\n const paths = filesPerLine.get(normalized);\r\n if (paths) paths.add(file.path);\r\n else filesPerLine.set(normalized, new Set([file.path]));\r\n }\r\n }\r\n }\r\n\r\n const index: BinAmbiguityIndex = new Map();\r\n for (const [normalized, paths] of filesPerLine) {\r\n if (paths.size > 1) index.set(normalized, paths.size);\r\n }\r\n return index;\r\n}\r\n\r\nexport type EvidenceResolution =\r\n | { status: 'absent' }\r\n | { status: 'weak' }\r\n | { status: 'matched'; line: DiffLine }\r\n | { status: 'unmatched' };\r\n\r\nexport function resolveEvidence(\r\n evidence: unknown,\r\n index: EvidenceIndex,\r\n reportedLine: number | undefined,\r\n): EvidenceResolution {\r\n if (typeof evidence !== 'string') return { status: 'absent' };\r\n\r\n const firstLine = foldFirstEvidenceLine(evidence);\r\n if (!firstLine) return { status: 'absent' };\r\n if (firstLine.length < MIN_DISCRIMINATING_EVIDENCE_CHARS) return { status: 'weak' };\r\n\r\n const nearest = (candidates: DiffLine[]) => {\r\n if (reportedLine === undefined) return candidates[0];\r\n return candidates.reduce((best, candidate) =>\r\n Math.abs((candidate.newLineNumber ?? 0) - reportedLine) < Math.abs((best.newLineNumber ?? 0) - reportedLine)\r\n ? candidate\r\n : best,\r\n );\r\n };\r\n\r\n const exact = index.byContent.get(firstLine);\r\n if (exact && exact.length > 0) return { status: 'matched', line: nearest(exact) };\r\n\r\n const contained = index.lines.flatMap(({ normalized, line }) =>\r\n normalized.length >= MIN_DISCRIMINATING_EVIDENCE_CHARS\r\n && (normalized.includes(firstLine) || firstLine.includes(normalized))\r\n ? [line]\r\n : []);\r\n if (contained.length > 0) return { status: 'matched', line: nearest(contained) };\r\n\r\n return { status: 'unmatched' };\r\n}\r\n","import type { ParsedReviewComment } from '@codraoss/schema';\r\nimport { normalizeFindingTitle } from '../fingerprint';\r\n\r\nconst SEVERITY_RANK: Record<string, number> = { P0: 0, P1: 1, P2: 2, P3: 3, nit: 4 };\r\n\r\nconst NUL = String.fromCharCode(0);\r\n\r\nexport function dedupeFindings(comments: ParsedReviewComment[]): ParsedReviewComment[] {\r\n const best = new Map<string, ParsedReviewComment>();\r\n for (const comment of comments) {\r\n const key = comment.source === 'rule'\r\n ? `rule${NUL}${comment.ruleId ?? ''}${NUL}${comment.path}${NUL}${comment.anchorHash ?? ''}`\r\n : normalizeFindingTitle(comment.title);\r\n if (!key) {\r\n best.set(`__unique__${best.size}`, comment);\r\n continue;\r\n }\r\n const existing = best.get(key);\r\n if (!existing) {\r\n best.set(key, comment);\r\n continue;\r\n }\r\n const rank = SEVERITY_RANK[comment.severity] ?? 4;\r\n const existingRank = SEVERITY_RANK[existing.severity] ?? 4;\r\n const isBetter =\r\n rank < existingRank ||\r\n (rank === existingRank && (comment.confidenceScore ?? 0) > (existing.confidenceScore ?? 0));\r\n if (isBetter) best.set(key, comment);\r\n }\r\n return Array.from(best.values());\r\n}\r\n","\r\nimport type { FileDiff } from '../diff';\r\n\r\nimport {\r\n NON_ANSWER_MAX_RESPONSE_CHARS,\r\n NON_ANSWER_MIN_DIFF_LINES,\r\n} from '../constants';\r\n\r\n/**\r\n * True when a review response is a non-answer: a substantive diff dismissed in a sentence with no\r\n * findings. Deliberately conservative -- it must never fire on a small diff, and never when the model\r\n * actually engaged, because the cost of a false positive is an escalation that spends real quota.\r\n */\r\nexport function isNonAnswerReview(input: {\r\n rawText: string;\r\n file: Pick<FileDiff, 'lineCount'>;\r\n findingCount: number;\r\n minDiffLines?: number;\r\n}): boolean {\r\n if (input.findingCount > 0) return false;\r\n if (input.file.lineCount < (input.minDiffLines ?? NON_ANSWER_MIN_DIFF_LINES)) return false;\r\n return input.rawText.trim().length < NON_ANSWER_MAX_RESPONSE_CHARS;\r\n}\r\n","import { batchReviewModelOutputSchema, fileReviewModelOutputSchema } from '@codraoss/schema';\r\nimport { jsonrepair } from 'jsonrepair';\r\nimport { z } from 'zod';\r\nimport { logger } from '../logger';\r\nimport {\r\n extractJson,\r\n hasReviewKeys,\r\n normalizeFinding,\r\n parseRawPayload,\r\n preprocessJson,\r\n stripNulls,\r\n truncateJsonForLog,\r\n} from './json';\r\n\r\nfunction readEntryPath(entry: Record<string, unknown>): string | null {\r\n for (const key of ['absolute_file_path', 'path', 'file', 'file_path', 'filename'] as const) {\r\n const value = entry[key];\r\n if (typeof value === 'string' && value.trim()) return value.trim();\r\n }\r\n return null;\r\n}\r\n\r\nfunction normalizeConfidence(value: unknown): number | undefined {\r\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\r\n if (value > 1) return Math.min(value / 10, 1);\r\n if (value < 0) return 0;\r\n return value;\r\n}\r\n\r\nfunction normalizeBatchFileEntry(entry: unknown, fallbackPath?: string): unknown | null {\r\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return null;\r\n const e = entry as Record<string, unknown>;\r\n const path = readEntryPath(e) ?? fallbackPath;\r\n if (!path) return null;\r\n\r\n if (!Array.isArray(e.findings)) return null;\r\n\r\n return {\r\n absolute_file_path: path,\r\n findings: e.findings.flatMap((finding) => {\r\n const normalized = normalizeFinding(finding);\r\n return normalized ? [normalized] : [];\r\n }),\r\n overall_correctness: typeof e.overall_correctness === 'string' && e.overall_correctness ? e.overall_correctness : undefined,\r\n overall_explanation: typeof e.overall_explanation === 'string' && e.overall_explanation ? e.overall_explanation : undefined,\r\n overall_confidence_score: normalizeConfidence(e.overall_confidence_score),\r\n };\r\n}\r\n\r\nfunction collectBatchEntries(parsedJson: unknown): unknown[] | null {\r\n const root = parsedJson && typeof parsedJson === 'object' ? (parsedJson as Record<string, unknown>) : null;\r\n const files = root?.files ?? (Array.isArray(parsedJson) ? parsedJson : undefined);\r\n\r\n if (Array.isArray(files)) {\r\n return files.flatMap((entry) => {\r\n const normalized = normalizeBatchFileEntry(entry);\r\n return normalized ? [normalized] : [];\r\n });\r\n }\r\n if (files && typeof files === 'object') {\r\n return Object.entries(files as Record<string, unknown>).flatMap(([path, entry]) => {\r\n const normalized = normalizeBatchFileEntry(entry, path);\r\n return normalized ? [normalized] : [];\r\n });\r\n }\r\n return null;\r\n}\r\n\r\nexport type RawBatchPayload =\r\n | { shape: 'nested'; data: z.infer<typeof batchReviewModelOutputSchema> }\r\n | { shape: 'flat'; data: z.infer<typeof fileReviewModelOutputSchema> };\r\n\r\nexport function parseRawBatchPayload(raw: string): RawBatchPayload {\r\n let extracted: string;\r\n try {\r\n extracted = extractJson(raw, 'files');\r\n if (!hasReviewKeys(extracted)) {\r\n throw new Error('Model response did not contain review JSON keys.');\r\n }\r\n } catch (e) {\r\n logger.error('Failed to extract JSON from batched model response', {\r\n rawLength: raw.length,\r\n rawPrefix: raw.slice(0, 500),\r\n error: e instanceof Error ? e.message : String(e),\r\n });\r\n throw new Error('Could not find JSON root in batched model response.', { cause: e });\r\n }\r\n\r\n let preprocessed: string;\r\n try {\r\n preprocessed = preprocessJson(extracted);\r\n } catch (e) {\r\n logger.warn('JSON preprocessing partially failed, continuing...', { extracted, error: e });\r\n preprocessed = extracted;\r\n }\r\n\r\n let repaired = preprocessed;\r\n try {\r\n repaired = jsonrepair(preprocessed);\r\n } catch (e) {\r\n logger.warn('jsonrepair failed to fix batched model output, using preprocessed text', { preprocessed: truncateJsonForLog(preprocessed), error: e });\r\n }\r\n\r\n let parsedJson: unknown;\r\n try {\r\n parsedJson = stripNulls(JSON.parse(repaired));\r\n } catch (e) {\r\n logger.error('Critical JSON parse error after extraction and repair', { repaired: truncateJsonForLog(repaired), error: e });\r\n throw new Error(`Invalid JSON format: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e });\r\n }\r\n\r\n const entries = collectBatchEntries(parsedJson);\r\n const root = parsedJson && typeof parsedJson === 'object' && !Array.isArray(parsedJson)\r\n ? (parsedJson as Record<string, unknown>)\r\n : {};\r\n\r\n if (!entries?.length) {\r\n if (Array.isArray(root.findings)) return { shape: 'flat', data: parseRawPayload(raw) };\r\n logger.error('Batched model response contained no recognisable file entries', {\r\n parsedJson: truncateJsonForLog(JSON.stringify(parsedJson ?? null)),\r\n });\r\n throw new Error('Batched response contained no recognisable file entries.');\r\n }\r\n\r\n try {\r\n return {\r\n shape: 'nested',\r\n data: batchReviewModelOutputSchema.parse({\r\n files: entries,\r\n overall_confidence_score: normalizeConfidence(root.overall_confidence_score) ?? 0.5,\r\n }),\r\n };\r\n } catch (e) {\r\n logger.error('Batched model response failed schema validation', { parsedJson, error: e });\r\n throw new Error(`Batched response schema mismatch: ${e instanceof Error ? e.message : 'Check logs'}`, { cause: e });\r\n }\r\n}\r\n","import type { ClaimType } from '@codraoss/schema';\r\nimport type { FileDiff } from '../diff';\r\nimport { generatorFindingCap } from '../prompts/file-review';\r\nimport { logger } from '../logger';\r\nimport { buildBinAmbiguityIndex } from './evidence';\r\nimport { type GroundedFileReview, groundParsedFindings, samePath } from './index';\r\nimport { parseRawBatchPayload } from './json-batch';\r\n\r\nexport type BatchParseStats = {\r\n unroutableEntries: number;\r\n pathMismatchFindings: number;\r\n ambiguousAcrossBin: number;\r\n flatFallback: number;\r\n overCap: number;\r\n entriesReturned: number;\r\n};\r\n\r\nexport type BatchReviewResult = {\r\n reviews: Map<string, GroundedFileReview>;\r\n missing: string[];\r\n stats: BatchParseStats;\r\n};\r\n\r\ntype Ambiguity = { index: ReturnType<typeof buildBinAmbiguityIndex>; stats: { ambiguousAcrossBin: number } };\r\ntype RawEntry = { findings: unknown[]; overall_correctness: string; overall_explanation: string };\r\n\r\nconst basename = (path: string) => path.split('/').pop() ?? path;\r\nimport { SEVERITY_ORDER } from '../constants';\r\n\r\nfunction resolveEntryPath(reported: string, candidates: readonly FileDiff[], claimed: Set<string>): FileDiff | null {\r\n const unclaimed = (matches: readonly FileDiff[]) => matches.find((f) => !claimed.has(f.path)) ?? null;\r\n\r\n const exact = candidates.filter((f) => samePath(f.path, reported));\r\n const renamed = candidates.filter((f) => f.previousPath && samePath(f.previousPath, reported));\r\n if (exact.length > 0 || renamed.length > 0) return unclaimed(exact) ?? unclaimed(renamed);\r\n\r\n const stripped = reported.trim().replace(/^\\.\\//, '').replace(/^[ab]\\//, '').replace(/^\\//, '');\r\n const suffixed = candidates.filter((f) => f.path.endsWith(`/${stripped}`));\r\n if (suffixed.length === 1) return unclaimed(suffixed);\r\n\r\n const named = candidates.filter((f) => basename(f.path) === basename(stripped));\r\n return named.length === 1 ? unclaimed(named) : null;\r\n}\r\n\r\nfunction groundEntry(\r\n file: FileDiff,\r\n entry: RawEntry,\r\n deniedClaimTypes: readonly ClaimType[] | undefined,\r\n ambiguity: Ambiguity,\r\n confidenceScore: number | undefined,\r\n stats: BatchParseStats,\r\n): GroundedFileReview {\r\n for (const finding of entry.findings as Array<{ code_location?: { absolute_file_path?: string } }>) {\r\n const claimed = finding.code_location?.absolute_file_path?.trim();\r\n if (claimed && !samePath(claimed, file.path)) stats.pathMismatchFindings += 1;\r\n }\r\n\r\n return groundParsedFindings(\r\n { ...entry, findings: entry.findings as never, overall_confidence_score: confidenceScore },\r\n file,\r\n { deniedClaimTypes, ambiguity: { index: ambiguity.index, filePath: file.path, stats: ambiguity.stats } },\r\n );\r\n}\r\n\r\nfunction trimOverCap(reviews: Map<string, GroundedFileReview>, cap: number, stats: BatchParseStats) {\r\n for (const [path, review] of reviews) {\r\n if (review.comments.length <= cap) continue;\r\n\r\n const ranked = review.comments.toSorted((a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity));\r\n const dropped = ranked.slice(cap);\r\n stats.overCap += dropped.length;\r\n\r\n const header = '### Additional Comments (Off-diff)';\r\n const bullets = dropped.map((c) => `- **[over-cap] ${c.title}:** ${c.body}`).join('\\n');\r\n reviews.set(path, {\r\n ...review,\r\n comments: ranked.slice(0, cap),\r\n fileSummary: review.fileSummary.includes(header)\r\n ? `${review.fileSummary}\\n${bullets}`\r\n : `${review.fileSummary}\\n\\n${header}\\n${bullets}`,\r\n });\r\n }\r\n}\r\n\r\nexport function parseBatchReviewResponse(\r\n raw: string,\r\n files: readonly FileDiff[],\r\n options?: { deniedClaimTypes?: readonly ClaimType[]; maxCommentsPerFile?: number },\r\n): BatchReviewResult {\r\n const stats: BatchParseStats = {\r\n unroutableEntries: 0, pathMismatchFindings: 0, ambiguousAcrossBin: 0,\r\n flatFallback: 0, overCap: 0, entriesReturned: 0,\r\n };\r\n const payload = parseRawBatchPayload(raw);\r\n const reviews = new Map<string, GroundedFileReview>();\r\n const ambiguity: Ambiguity = { index: buildBinAmbiguityIndex(files), stats: { ambiguousAcrossBin: 0 } };\r\n const claimed = new Set<string>();\r\n\r\n const ground = (file: FileDiff, entry: RawEntry, confidence: number | undefined) =>\r\n reviews.set(file.path, groundEntry(file, entry, options?.deniedClaimTypes, ambiguity, confidence, stats));\r\n\r\n if (payload.shape === 'flat') {\r\n stats.flatFallback = 1;\r\n stats.entriesReturned = 1;\r\n\r\n const byFile = new Map<string, { file: FileDiff; findings: typeof payload.data.findings }>();\r\n for (const finding of payload.data.findings) {\r\n const reported = finding.code_location.absolute_file_path?.trim();\r\n const target = !reported && files.length === 1 ? files[0] : resolveEntryPath(reported ?? '', files, claimed);\r\n if (!target) {\r\n stats.unroutableEntries += 1;\r\n continue;\r\n }\r\n const bucket = byFile.get(target.path);\r\n if (bucket) bucket.findings.push(finding);\r\n else byFile.set(target.path, { file: target, findings: [finding] });\r\n }\r\n\r\n for (const { file, findings } of byFile.values()) {\r\n ground(file, {\r\n findings,\r\n overall_correctness: payload.data.overall_correctness,\r\n overall_explanation: payload.data.overall_explanation,\r\n }, payload.data.overall_confidence_score);\r\n }\r\n } else {\r\n stats.entriesReturned = payload.data.files.length;\r\n for (const entry of payload.data.files) {\r\n const file = resolveEntryPath(entry.absolute_file_path, files, claimed);\r\n if (!file) {\r\n stats.unroutableEntries += 1;\r\n logger.warn('Batched review returned an entry for an unknown path', { reported: entry.absolute_file_path });\r\n continue;\r\n }\r\n claimed.add(file.path);\r\n ground(file, entry, entry.overall_confidence_score ?? payload.data.overall_confidence_score);\r\n }\r\n }\r\n\r\n stats.ambiguousAcrossBin = ambiguity.stats.ambiguousAcrossBin;\r\n if (options?.maxCommentsPerFile) trimOverCap(reviews, generatorFindingCap(options.maxCommentsPerFile), stats);\r\n\r\n return { reviews, missing: files.flatMap((f) => (reviews.has(f.path) ? [] : [f.path])), stats };\r\n}\r\n"],"mappings":"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","names":["z","jsonrepair","jsonrepair","z"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { D as DiffLine, F as FileDiff } from './position-h_jdn6ZH.js';
|
|
2
|
+
|
|
3
|
+
type UndecidableClaimReason = 'cross-file' | 'environment' | 'callee-errors';
|
|
4
|
+
/**
|
|
5
|
+
* Refutes a claim whose truth lives outside the diff, returning the family it belongs to or null.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately requires TWO independent signals per family -- a subject and a consequence -- because
|
|
8
|
+
* either alone is ordinary review language. "This breaks the build" is a normal thing to say about
|
|
9
|
+
* code in the diff; "other modules import this" is a normal aside. Only together do they describe a
|
|
10
|
+
* consequence in a file nobody showed the model.
|
|
11
|
+
*/
|
|
12
|
+
declare function refuteUndecidableClaim(input: {
|
|
13
|
+
title: string;
|
|
14
|
+
body: string;
|
|
15
|
+
}): UndecidableClaimReason | null;
|
|
16
|
+
declare function looksLikeExternalVersionClaim(title: string, body: string): boolean;
|
|
17
|
+
declare function isVersionClaimRefutedByPin(input: {
|
|
18
|
+
title: string;
|
|
19
|
+
body: string;
|
|
20
|
+
anchorContent: string;
|
|
21
|
+
}): boolean;
|
|
22
|
+
type PresenceEntry = {
|
|
23
|
+
line: DiffLine;
|
|
24
|
+
hunkIndex: number;
|
|
25
|
+
code: string;
|
|
26
|
+
};
|
|
27
|
+
type PresenceIndex = {
|
|
28
|
+
byToken: Map<string, PresenceEntry[]>;
|
|
29
|
+
entries: PresenceEntry[];
|
|
30
|
+
hunkByLine: Map<number, number>;
|
|
31
|
+
};
|
|
32
|
+
type AbsenceClaimVerdict = {
|
|
33
|
+
status: 'unknown';
|
|
34
|
+
reason: 'not_absence_shaped' | 'no_identifier' | 'ambiguous_identifier' | 'stoplisted' | 'not_present' | 'out_of_window';
|
|
35
|
+
} | {
|
|
36
|
+
status: 'refuted';
|
|
37
|
+
identifier: string;
|
|
38
|
+
line: DiffLine;
|
|
39
|
+
};
|
|
40
|
+
type CommentSyntax = {
|
|
41
|
+
line: readonly string[];
|
|
42
|
+
block: boolean;
|
|
43
|
+
};
|
|
44
|
+
declare function commentSyntaxFor(path: string): CommentSyntax;
|
|
45
|
+
declare function stripCommentsAndStrings(input: string, syntax: CommentSyntax): string | null;
|
|
46
|
+
declare function buildPresenceIndex(file: FileDiff): PresenceIndex;
|
|
47
|
+
declare function checkAbsenceClaim(input: {
|
|
48
|
+
title: string;
|
|
49
|
+
body: string;
|
|
50
|
+
anchorLine: number | undefined;
|
|
51
|
+
index: PresenceIndex;
|
|
52
|
+
}): AbsenceClaimVerdict;
|
|
53
|
+
|
|
54
|
+
export { type AbsenceClaimVerdict, type PresenceIndex, type UndecidableClaimReason, buildPresenceIndex, checkAbsenceClaim, commentSyntaxFor, isVersionClaimRefutedByPin, looksLikeExternalVersionClaim, refuteUndecidableClaim, stripCommentsAndStrings };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPresenceIndex,
|
|
3
|
+
checkAbsenceClaim,
|
|
4
|
+
commentSyntaxFor,
|
|
5
|
+
isVersionClaimRefutedByPin,
|
|
6
|
+
looksLikeExternalVersionClaim,
|
|
7
|
+
refuteUndecidableClaim,
|
|
8
|
+
stripCommentsAndStrings
|
|
9
|
+
} from "./chunk-U3VKVDZ7.js";
|
|
10
|
+
import "./chunk-NSTV4TRP.js";
|
|
11
|
+
export {
|
|
12
|
+
buildPresenceIndex,
|
|
13
|
+
checkAbsenceClaim,
|
|
14
|
+
commentSyntaxFor,
|
|
15
|
+
isVersionClaimRefutedByPin,
|
|
16
|
+
looksLikeExternalVersionClaim,
|
|
17
|
+
refuteUndecidableClaim,
|
|
18
|
+
stripCommentsAndStrings
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=claim-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import picomatch from 'picomatch';
|
|
2
|
+
import { RepoConfig } from '@codraoss/schema';
|
|
3
|
+
import { F as FileDiff } from '../position-h_jdn6ZH.js';
|
|
4
|
+
export { a as DiffHunk, D as DiffLine, b as DiffLineKind, c as chunkFileDiff, f as findPositionForLine, g as getValidNewLines, d as getValidPositions, t as truncateFileDiff } from '../position-h_jdn6ZH.js';
|
|
5
|
+
|
|
6
|
+
declare function isReviewableFile(path: string, customMatchers: ReturnType<typeof picomatch>[]): boolean;
|
|
7
|
+
declare function parseDiffHeaderPath(line: string): string;
|
|
8
|
+
declare function parseUnifiedDiff(rawDiff: string, reviewConfig?: RepoConfig['review']): FileDiff[];
|
|
9
|
+
/** Shape returned by forge compare/files endpoints. Maps to GitHub's pulls/files JSON. */
|
|
10
|
+
type DiffFileEntry = {
|
|
11
|
+
filename: string;
|
|
12
|
+
previous_filename?: string | null;
|
|
13
|
+
status?: string;
|
|
14
|
+
patch?: string | null;
|
|
15
|
+
};
|
|
16
|
+
declare function buildUnifiedDiffFromFiles(files: DiffFileEntry[]): string;
|
|
17
|
+
declare function filterReviewableFiles(files: FileDiff[], config: RepoConfig['review'], maxFiles: number): {
|
|
18
|
+
files: FileDiff[];
|
|
19
|
+
skipped: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { type DiffFileEntry, FileDiff, buildUnifiedDiffFromFiles, filterReviewableFiles, isReviewableFile, parseDiffHeaderPath, parseUnifiedDiff };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildUnifiedDiffFromFiles,
|
|
3
|
+
chunkFileDiff,
|
|
4
|
+
filterReviewableFiles,
|
|
5
|
+
findPositionForLine,
|
|
6
|
+
getValidNewLines,
|
|
7
|
+
getValidPositions,
|
|
8
|
+
isReviewableFile,
|
|
9
|
+
parseDiffHeaderPath,
|
|
10
|
+
parseUnifiedDiff,
|
|
11
|
+
truncateFileDiff
|
|
12
|
+
} from "../chunk-OIQRTDYR.js";
|
|
13
|
+
export {
|
|
14
|
+
buildUnifiedDiffFromFiles,
|
|
15
|
+
chunkFileDiff,
|
|
16
|
+
filterReviewableFiles,
|
|
17
|
+
findPositionForLine,
|
|
18
|
+
getValidNewLines,
|
|
19
|
+
getValidPositions,
|
|
20
|
+
isReviewableFile,
|
|
21
|
+
parseDiffHeaderPath,
|
|
22
|
+
parseUnifiedDiff,
|
|
23
|
+
truncateFileDiff
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare function fnv1a32Hex(input: string): string;
|
|
2
|
+
declare function normalizeDiffText(input: string): string;
|
|
3
|
+
declare function foldEvidenceText(input: string): string;
|
|
4
|
+
declare function normalizeFindingTitle(title: string): string;
|
|
5
|
+
declare function buildFindingFingerprint(path: string, title: string): string;
|
|
6
|
+
declare function buildFindingFingerprintV2(path: string, claimType: string | null | undefined, anchorHash: string | null | undefined): string | null;
|
|
7
|
+
declare function buildAnchorHash(lineContent: string): string;
|
|
8
|
+
|
|
9
|
+
export { buildAnchorHash, buildFindingFingerprint, buildFindingFingerprintV2, fnv1a32Hex, foldEvidenceText, normalizeDiffText, normalizeFindingTitle };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildAnchorHash,
|
|
3
|
+
buildFindingFingerprint,
|
|
4
|
+
buildFindingFingerprintV2,
|
|
5
|
+
fnv1a32Hex,
|
|
6
|
+
foldEvidenceText,
|
|
7
|
+
normalizeDiffText,
|
|
8
|
+
normalizeFindingTitle
|
|
9
|
+
} from "./chunk-NSTV4TRP.js";
|
|
10
|
+
export {
|
|
11
|
+
buildAnchorHash,
|
|
12
|
+
buildFindingFingerprint,
|
|
13
|
+
buildFindingFingerprintV2,
|
|
14
|
+
fnv1a32Hex,
|
|
15
|
+
foldEvidenceText,
|
|
16
|
+
normalizeDiffText,
|
|
17
|
+
normalizeFindingTitle
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ParsedReviewComment, batchReviewModelOutputSchema, fileReviewModelOutputSchema, ClaimType } from '@codraoss/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { F as FileDiff } from './position-h_jdn6ZH.js';
|
|
4
|
+
|
|
5
|
+
type BinAmbiguityIndex = Map<string, number>;
|
|
6
|
+
|
|
7
|
+
declare function dedupeFindings(comments: ParsedReviewComment[]): ParsedReviewComment[];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* True when a review response is a non-answer: a substantive diff dismissed in a sentence with no
|
|
11
|
+
* findings. Deliberately conservative -- it must never fire on a small diff, and never when the model
|
|
12
|
+
* actually engaged, because the cost of a false positive is an escalation that spends real quota.
|
|
13
|
+
*/
|
|
14
|
+
declare function isNonAnswerReview(input: {
|
|
15
|
+
rawText: string;
|
|
16
|
+
file: Pick<FileDiff, 'lineCount'>;
|
|
17
|
+
findingCount: number;
|
|
18
|
+
minDiffLines?: number;
|
|
19
|
+
}): boolean;
|
|
20
|
+
|
|
21
|
+
declare const PACKABLE_MAX_DIFF_LINES = 150;
|
|
22
|
+
declare const BIN_TARGET_DIFF_LINES = 300;
|
|
23
|
+
declare const BIN_MAX_FILES = 4;
|
|
24
|
+
declare const BIN_DIFF_CHAR_BUDGET = 24000;
|
|
25
|
+
declare const FRESH_INVOCATION_YIELD_SECONDS = 8;
|
|
26
|
+
declare const NON_ANSWER_MAX_RESPONSE_CHARS = 600;
|
|
27
|
+
declare const NON_ANSWER_MIN_DIFF_LINES = 200;
|
|
28
|
+
|
|
29
|
+
type RawBatchPayload = {
|
|
30
|
+
shape: 'nested';
|
|
31
|
+
data: z.infer<typeof batchReviewModelOutputSchema>;
|
|
32
|
+
} | {
|
|
33
|
+
shape: 'flat';
|
|
34
|
+
data: z.infer<typeof fileReviewModelOutputSchema>;
|
|
35
|
+
};
|
|
36
|
+
declare function parseRawBatchPayload(raw: string): RawBatchPayload;
|
|
37
|
+
|
|
38
|
+
type BatchParseStats = {
|
|
39
|
+
unroutableEntries: number;
|
|
40
|
+
pathMismatchFindings: number;
|
|
41
|
+
ambiguousAcrossBin: number;
|
|
42
|
+
flatFallback: number;
|
|
43
|
+
overCap: number;
|
|
44
|
+
entriesReturned: number;
|
|
45
|
+
};
|
|
46
|
+
type BatchReviewResult = {
|
|
47
|
+
reviews: Map<string, GroundedFileReview>;
|
|
48
|
+
missing: string[];
|
|
49
|
+
stats: BatchParseStats;
|
|
50
|
+
};
|
|
51
|
+
declare function parseBatchReviewResponse(raw: string, files: readonly FileDiff[], options?: {
|
|
52
|
+
deniedClaimTypes?: readonly ClaimType[];
|
|
53
|
+
maxCommentsPerFile?: number;
|
|
54
|
+
}): BatchReviewResult;
|
|
55
|
+
|
|
56
|
+
declare function samePath(a: string, b: string): boolean;
|
|
57
|
+
type BinAmbiguity = {
|
|
58
|
+
index: BinAmbiguityIndex;
|
|
59
|
+
filePath: string;
|
|
60
|
+
stats: {
|
|
61
|
+
ambiguousAcrossBin: number;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
type FileReviewPayload = z.infer<typeof fileReviewModelOutputSchema>;
|
|
65
|
+
type GroundingOptions = {
|
|
66
|
+
deniedClaimTypes?: readonly ClaimType[];
|
|
67
|
+
ambiguity?: BinAmbiguity;
|
|
68
|
+
};
|
|
69
|
+
type GroundedFileReview = {
|
|
70
|
+
comments: ParsedReviewComment[];
|
|
71
|
+
verdict: 'approve' | 'comment';
|
|
72
|
+
fileSummary: string;
|
|
73
|
+
overallCorrectness?: string;
|
|
74
|
+
confidenceScore?: number;
|
|
75
|
+
evidenceStats: {
|
|
76
|
+
total: number;
|
|
77
|
+
matched: number;
|
|
78
|
+
unmatched: number;
|
|
79
|
+
weak: number;
|
|
80
|
+
absent: number;
|
|
81
|
+
};
|
|
82
|
+
claimTypeCounts: Record<string, number>;
|
|
83
|
+
deniedClaimCounts: Record<string, number>;
|
|
84
|
+
absenceCheckStats: {
|
|
85
|
+
absenceShaped: number;
|
|
86
|
+
identifierExtracted: number;
|
|
87
|
+
refuted: number;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
declare function groundParsedFindings(parsed: FileReviewPayload, file: FileDiff, options?: GroundingOptions): GroundedFileReview;
|
|
91
|
+
declare function parseFileReviewResponse(raw: string, file: FileDiff, options?: GroundingOptions): GroundedFileReview;
|
|
92
|
+
|
|
93
|
+
export { type BatchReviewResult as B, FRESH_INVOCATION_YIELD_SECONDS as F, type GroundedFileReview as G, NON_ANSWER_MAX_RESPONSE_CHARS as N, PACKABLE_MAX_DIFF_LINES as P, type RawBatchPayload as R, BIN_DIFF_CHAR_BUDGET as a, BIN_MAX_FILES as b, BIN_TARGET_DIFF_LINES as c, type BatchParseStats as d, type BinAmbiguity as e, type FileReviewPayload as f, type GroundingOptions as g, NON_ANSWER_MIN_DIFF_LINES as h, dedupeFindings as i, groundParsedFindings as j, isNonAnswerReview as k, parseBatchReviewResponse as l, parseRawBatchPayload as m, parseFileReviewResponse as p, samePath as s };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { RepoConfig, ParsedReviewComment, FindingDisposition, ReviewJobMessage } from '@codraoss/schema';
|
|
2
|
+
import { ReviewRuntime, ReviewGitProvider, PersistedReviewJob } from './ports/index.js';
|
|
3
|
+
export { AuthorizationResult, BulkFileReviewInput, Clock, DashboardSessionUser, FileReviewRow, FileReviewStore, GitProviderFactory, IdGenerator, IdentityProvider, InMemoryKV, InMemoryOrchestrator, InMemoryQueue, InMemorySessionStore, InstanceIdStore, JobLeaseClaim, JobOrchestrator, JobRow, JobStore, KeyValueStore, KvStore, LearningStore, ModelConfigReader, PullRequestRecord, QueueProducer, RepoConfigLoader, RepoConfigStore, ReviewComment, ReviewFormatter, ReviewSettingsReader, ReviewTelemetryEvent, SecretStore, SessionStore, SuppressedFinding, TelemetrySink, WebhookDeliveryReader } from './ports/index.js';
|
|
4
|
+
import { R as ReviewModel } from './model-gRDTk8yk.js';
|
|
5
|
+
export { F as FileReviewOutcome, M as ModelErrorClassifier, a as ModelResponse, b as ModelResponseSchema } from './model-gRDTk8yk.js';
|
|
6
|
+
export { a as BIN_DIFF_CHAR_BUDGET, b as BIN_MAX_FILES, c as BIN_TARGET_DIFF_LINES, F as FRESH_INVOCATION_YIELD_SECONDS, P as PACKABLE_MAX_DIFF_LINES } from './index-BTDWXDck.js';
|
|
7
|
+
import { F as FileDiff } from './position-h_jdn6ZH.js';
|
|
8
|
+
export { Logger } from './logger.js';
|
|
9
|
+
import { WebhookEventName, WebhookPayload } from '@codraoss/schema/webhook';
|
|
10
|
+
import './token-tracker.js';
|
|
11
|
+
import './prompts/verify.js';
|
|
12
|
+
import 'zod';
|
|
13
|
+
|
|
14
|
+
declare function getDiffFiles(env: Pick<ReviewRuntime, 'kv'>, job: {
|
|
15
|
+
id: string;
|
|
16
|
+
owner: string;
|
|
17
|
+
repo: string;
|
|
18
|
+
prNumber: number;
|
|
19
|
+
}, github: Pick<ReviewGitProvider, 'getPullRequestDiff'>, config: RepoConfig, maxFiles?: number): Promise<{
|
|
20
|
+
files: FileDiff[];
|
|
21
|
+
skipped: number;
|
|
22
|
+
}>;
|
|
23
|
+
declare function getOrFetchRawDiffForCompletedJob(env: Pick<ReviewRuntime, 'kv'>, job: {
|
|
24
|
+
id: string;
|
|
25
|
+
owner: string;
|
|
26
|
+
repo: string;
|
|
27
|
+
baseSha: string;
|
|
28
|
+
commitSha: string;
|
|
29
|
+
}, github: Pick<ReviewGitProvider, 'getCompareDiff'>): Promise<string>;
|
|
30
|
+
|
|
31
|
+
declare function budgetAwareFileLimit(remainingSafeBudget: number, configuredChunkFileLimit: number, modelChainLength?: number): number;
|
|
32
|
+
declare function estimatedSubrequestsPerFile(modelChainLength: number): number;
|
|
33
|
+
|
|
34
|
+
type ReviewUnit = {
|
|
35
|
+
kind: 'single';
|
|
36
|
+
file: FileDiff;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'bin';
|
|
39
|
+
files: FileDiff[];
|
|
40
|
+
diffLineCount: number;
|
|
41
|
+
diffChars: number;
|
|
42
|
+
};
|
|
43
|
+
type LedgerEntry = {
|
|
44
|
+
handled: boolean;
|
|
45
|
+
transientErrorCount: number;
|
|
46
|
+
};
|
|
47
|
+
declare function unitFiles(unit: ReviewUnit): FileDiff[];
|
|
48
|
+
declare function planReviewUnits(files: readonly FileDiff[], opts: {
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
}): ReviewUnit[];
|
|
51
|
+
declare function narrowUnit(unit: ReviewUnit, ledger: Map<string, LedgerEntry>): ReviewUnit[];
|
|
52
|
+
|
|
53
|
+
declare class NextPhaseError extends Error {
|
|
54
|
+
phase: 'prepare' | 'review' | 'finalize';
|
|
55
|
+
delaySeconds: number;
|
|
56
|
+
constructor(phase: 'prepare' | 'review' | 'finalize', delaySeconds: number);
|
|
57
|
+
}
|
|
58
|
+
declare function failJobAndCheckRun(env: ReviewRuntime, job: Pick<PersistedReviewJob, 'id' | 'owner' | 'repo' | 'checkRunId'>, github: Pick<ReviewGitProvider, 'updateCheckRun'>, message: string): Promise<void>;
|
|
59
|
+
|
|
60
|
+
declare function proportionalSplit(total: number, weights: number[]): number[];
|
|
61
|
+
|
|
62
|
+
type VerifiableJob = {
|
|
63
|
+
id: string;
|
|
64
|
+
};
|
|
65
|
+
type VerifyDrop = {
|
|
66
|
+
comment: ParsedReviewComment;
|
|
67
|
+
disposition: Extract<FindingDisposition, 'verify' | 'verify_unanswered'>;
|
|
68
|
+
reason?: string;
|
|
69
|
+
};
|
|
70
|
+
type VerifyOutcome = {
|
|
71
|
+
comments: ParsedReviewComment[];
|
|
72
|
+
dropped: VerifyDrop[];
|
|
73
|
+
reasons: Map<ParsedReviewComment, string>;
|
|
74
|
+
};
|
|
75
|
+
declare function verifyFindings(params: {
|
|
76
|
+
job: VerifiableJob;
|
|
77
|
+
config: RepoConfig;
|
|
78
|
+
files: FileDiff[];
|
|
79
|
+
comments: ParsedReviewComment[];
|
|
80
|
+
model: Pick<ReviewModel, 'verifyFindings'>;
|
|
81
|
+
maxCandidates?: number;
|
|
82
|
+
}): Promise<VerifyOutcome>;
|
|
83
|
+
|
|
84
|
+
type ReviewRequest = {
|
|
85
|
+
installationId: string;
|
|
86
|
+
owner: string;
|
|
87
|
+
repo: string;
|
|
88
|
+
prNumber: number;
|
|
89
|
+
prTitle: string | null;
|
|
90
|
+
prAuthor: string | null;
|
|
91
|
+
commitSha: string;
|
|
92
|
+
baseSha: string;
|
|
93
|
+
headRef: string | null;
|
|
94
|
+
baseRef: string | null;
|
|
95
|
+
trigger: 'auto' | 'mention';
|
|
96
|
+
};
|
|
97
|
+
declare function extractReviewRequest(input: {
|
|
98
|
+
eventName: WebhookEventName;
|
|
99
|
+
payload: WebhookPayload;
|
|
100
|
+
botUsername: string;
|
|
101
|
+
config: RepoConfig;
|
|
102
|
+
}): ReviewRequest | null;
|
|
103
|
+
|
|
104
|
+
type ReviewJobRunResult = {
|
|
105
|
+
action: 'ack';
|
|
106
|
+
} | {
|
|
107
|
+
action: 'retry';
|
|
108
|
+
delaySeconds: number;
|
|
109
|
+
} | {
|
|
110
|
+
action: 'next_phase';
|
|
111
|
+
phase: 'prepare' | 'review' | 'finalize';
|
|
112
|
+
delaySeconds: number;
|
|
113
|
+
jobId?: string;
|
|
114
|
+
freshInstance?: boolean;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* The engine's entrypoint. Runs EXACTLY ONE phase of a review job and returns what the caller should
|
|
118
|
+
* do next; the caller owns the loop.
|
|
119
|
+
*
|
|
120
|
+
* Deliberately not a loop. Every `next_phase` result exists because the next phase needs a fresh
|
|
121
|
+
* host invocation to get a clean subrequest budget, and only the driver can hibernate long enough to
|
|
122
|
+
* produce one (see FRESH_INVOCATION_YIELD_SECONDS in ./phase-control). A loop in here would run the
|
|
123
|
+
* next phase on the current one's spent budget while its TokenTracker restarted at zero -- the exact
|
|
124
|
+
* failure that constant was introduced to fix.
|
|
125
|
+
*
|
|
126
|
+
* Contract for a driver:
|
|
127
|
+
* - 'ack': the job is finished or not ours. Stop.
|
|
128
|
+
* - 'retry': re-deliver the SAME message after `delaySeconds`. Admission was throttled or the lease
|
|
129
|
+
* is held elsewhere; no work happened.
|
|
130
|
+
* - 'next_phase': re-invoke with `{ jobId, phase }` after `delaySeconds`. `freshInstance` means the
|
|
131
|
+
* delay must be long enough to actually hibernate, not merely to wait.
|
|
132
|
+
*
|
|
133
|
+
* Safe to call repeatedly for the same job: it claims a lease first, and every phase is idempotent
|
|
134
|
+
* enough to resume. It throws only on a programming error -- job failures are recorded and acked.
|
|
135
|
+
*/
|
|
136
|
+
declare function runReview(env: ReviewRuntime, message: ReviewJobMessage): Promise<ReviewJobRunResult>;
|
|
137
|
+
|
|
138
|
+
export { type LedgerEntry, NextPhaseError, PersistedReviewJob, ReviewGitProvider, type ReviewJobRunResult, ReviewModel, type ReviewRequest, ReviewRuntime, type ReviewUnit, type VerifyDrop, type VerifyOutcome, budgetAwareFileLimit, estimatedSubrequestsPerFile, extractReviewRequest, failJobAndCheckRun, getDiffFiles, getOrFetchRawDiffForCompletedJob, narrowUnit, planReviewUnits, proportionalSplit, runReview, unitFiles, verifyFindings };
|