@codraoss/core 0.9.4 → 0.9.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-XD6CGYHO.js → chunk-4XEMXRNG.js} +62 -39
- package/dist/chunk-4XEMXRNG.js.map +1 -0
- package/dist/{chunk-ILZUCIZH.js → chunk-EQL5OOEF.js} +7 -7
- package/dist/chunk-EQL5OOEF.js.map +1 -0
- package/dist/{chunk-RQ5S67XB.js → chunk-FKRCBUWZ.js} +8 -2
- package/dist/chunk-FKRCBUWZ.js.map +1 -0
- package/dist/{chunk-JC74XH7Q.js → chunk-GDX2ZEBA.js} +1 -1
- package/dist/chunk-GDX2ZEBA.js.map +1 -0
- package/dist/{chunk-OIQRTDYR.js → chunk-I5S3NBFL.js} +20 -4
- package/dist/chunk-I5S3NBFL.js.map +1 -0
- package/dist/{chunk-U3VKVDZ7.js → chunk-IKVUW4WC.js} +92 -19
- package/dist/chunk-IKVUW4WC.js.map +1 -0
- package/dist/{chunk-R2HRWFRH.js → chunk-JAF7JIZQ.js} +1 -1
- package/dist/chunk-JAF7JIZQ.js.map +1 -0
- package/dist/{chunk-V3RF6GQW.js → chunk-KTDBDKL5.js} +1 -1
- package/dist/chunk-KTDBDKL5.js.map +1 -0
- package/dist/{chunk-MMVQPGK3.js → chunk-ONJZXUQT.js} +112 -24
- package/dist/chunk-ONJZXUQT.js.map +1 -0
- package/dist/{chunk-PVXFURDR.js → chunk-QPPLO2YV.js} +2 -2
- package/dist/chunk-QPPLO2YV.js.map +1 -0
- package/dist/{chunk-FGXA7JNR.js → chunk-W3RY755V.js} +14 -2
- package/dist/chunk-W3RY755V.js.map +1 -0
- package/dist/{chunk-NSTV4TRP.js → chunk-XPYVLHSX.js} +1 -1
- package/dist/chunk-XPYVLHSX.js.map +1 -0
- package/dist/{chunk-WSK45HW4.js → chunk-Z5B5X7QP.js} +1 -1
- package/dist/chunk-Z5B5X7QP.js.map +1 -0
- package/dist/claim-checks.d.ts +8 -13
- package/dist/claim-checks.js +2 -2
- package/dist/diff/index.d.ts +3 -3
- package/dist/diff/index.js +2 -1
- package/dist/fingerprint.js +1 -1
- package/dist/formatter-CDFpqbDP.d.ts +24 -0
- package/dist/formatter.d.ts +29 -0
- package/dist/formatter.js +111 -0
- package/dist/formatter.js.map +1 -0
- package/dist/{index-BTDWXDck.d.ts → index-CrtHz4vN.d.ts} +3 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.js +239 -62
- package/dist/index.js.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/{model-gRDTk8yk.d.ts → model-BkqfyVh9.d.ts} +27 -6
- package/dist/model-output/index.d.ts +2 -2
- package/dist/model-output/index.js +9 -9
- package/dist/ports/index.d.ts +22 -18
- package/dist/ports/index.js +1 -1
- package/dist/{position-h_jdn6ZH.d.ts → position-zZl8KGVu.d.ts} +1 -1
- package/dist/prompts/file-review.d.ts +3 -3
- package/dist/prompts/file-review.js +11 -5
- package/dist/prompts/languages.d.ts +2 -1
- package/dist/prompts/languages.js +5 -3
- package/dist/prompts/verify.d.ts +1 -1
- package/dist/prompts/verify.js +1 -1
- package/dist/rules/detect.d.ts +1 -1
- package/dist/rules/detect.js +5 -5
- package/dist/rules/table.js +1 -1
- package/dist/token-tracker.js +2 -2
- package/package.json +10 -2
- package/dist/chunk-FGXA7JNR.js.map +0 -1
- package/dist/chunk-ILZUCIZH.js.map +0 -1
- package/dist/chunk-JC74XH7Q.js.map +0 -1
- package/dist/chunk-MMVQPGK3.js.map +0 -1
- package/dist/chunk-NSTV4TRP.js.map +0 -1
- package/dist/chunk-OIQRTDYR.js.map +0 -1
- package/dist/chunk-PVXFURDR.js.map +0 -1
- package/dist/chunk-R2HRWFRH.js.map +0 -1
- package/dist/chunk-RQ5S67XB.js.map +0 -1
- package/dist/chunk-U3VKVDZ7.js.map +0 -1
- package/dist/chunk-V3RF6GQW.js.map +0 -1
- package/dist/chunk-WSK45HW4.js.map +0 -1
- package/dist/chunk-XD6CGYHO.js.map +0 -1
|
@@ -3,6 +3,9 @@ var PACKABLE_MAX_DIFF_LINES = 150;
|
|
|
3
3
|
var BIN_TARGET_DIFF_LINES = 300;
|
|
4
4
|
var BIN_MAX_FILES = 4;
|
|
5
5
|
var BIN_DIFF_CHAR_BUDGET = 24e3;
|
|
6
|
+
var FRAGMENTED_HUNK_THRESHOLD = 5;
|
|
7
|
+
var FRAGMENTED_MIN_LINES = 60;
|
|
8
|
+
var MAX_TOTAL_DIFF_CHARS = 4e6;
|
|
6
9
|
var DIFF_CACHE_TTL_SECONDS = 6 * 60 * 60;
|
|
7
10
|
var REVIEW_CHUNK_WALL_CLOCK_MS = 12 * 60 * 1e3;
|
|
8
11
|
var JOB_LEASE_SECONDS = 15 * 60;
|
|
@@ -25,12 +28,18 @@ var VERIFY_MIN_ANSWER_RATIO = 0.6;
|
|
|
25
28
|
var MAX_RULE_SCAN_ADDED_LINES = 600;
|
|
26
29
|
var EXEMPLAR_BLOCK_CHARS = 700;
|
|
27
30
|
var PR_DESCRIPTION_CHARS = 2e3;
|
|
31
|
+
var CHANGELOG_EXCERPT_CHARS = 600;
|
|
32
|
+
var FILE_CONTEXT_CHAR_BUDGET = 8e3;
|
|
33
|
+
var FILE_CONTEXT_WINDOW_LINES = 120;
|
|
28
34
|
|
|
29
35
|
export {
|
|
30
36
|
PACKABLE_MAX_DIFF_LINES,
|
|
31
37
|
BIN_TARGET_DIFF_LINES,
|
|
32
38
|
BIN_MAX_FILES,
|
|
33
39
|
BIN_DIFF_CHAR_BUDGET,
|
|
40
|
+
FRAGMENTED_HUNK_THRESHOLD,
|
|
41
|
+
FRAGMENTED_MIN_LINES,
|
|
42
|
+
MAX_TOTAL_DIFF_CHARS,
|
|
34
43
|
DIFF_CACHE_TTL_SECONDS,
|
|
35
44
|
REVIEW_CHUNK_WALL_CLOCK_MS,
|
|
36
45
|
JOB_LEASE_SECONDS,
|
|
@@ -52,6 +61,9 @@ export {
|
|
|
52
61
|
VERIFY_MIN_ANSWER_RATIO,
|
|
53
62
|
MAX_RULE_SCAN_ADDED_LINES,
|
|
54
63
|
EXEMPLAR_BLOCK_CHARS,
|
|
55
|
-
PR_DESCRIPTION_CHARS
|
|
64
|
+
PR_DESCRIPTION_CHARS,
|
|
65
|
+
CHANGELOG_EXCERPT_CHARS,
|
|
66
|
+
FILE_CONTEXT_CHAR_BUDGET,
|
|
67
|
+
FILE_CONTEXT_WINDOW_LINES
|
|
56
68
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-W3RY755V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts"],"sourcesContent":["// Packing & Diff Limits\nexport const PACKABLE_MAX_DIFF_LINES = 150;\nexport const BIN_TARGET_DIFF_LINES = 300;\nexport const BIN_MAX_FILES = 4;\nexport const BIN_DIFF_CHAR_BUDGET = 24_000;\n// Files with many scattered hunks get whole-file context; the line floor excludes trivial files.\nexport const FRAGMENTED_HUNK_THRESHOLD = 5;\nexport const FRAGMENTED_MIN_LINES = 60;\n// Whole-job input ceiling: a pathological-input valve, NOT an operating limit -- `max_files` and\n// `max_diff_lines_per_file` are the controls. Deliberately a constant and not repo config: it was a\n// config field with no UI and no file source, so every stored config carried a value nobody chose,\n// and raising the schema default left those rows untouched. A 500-file review at ~7.5k chars per\n// file needs ~3.8M, so this clears the largest review `max_files` permits.\nexport const MAX_TOTAL_DIFF_CHARS = 4_000_000;\nexport const DIFF_CACHE_TTL_SECONDS = 6 * 60 * 60;\n\n// Phase Control & Timers\nexport const REVIEW_CHUNK_WALL_CLOCK_MS = 12 * 60 * 1000;\nexport const JOB_LEASE_SECONDS = 15 * 60;\nexport const BUSY_RETRY_SECONDS = 60;\nexport const RETRYABLE_MODEL_FAILURE_RETRY_DELAYS_SECONDS = [30, 2 * 60, 5 * 60];\nexport const FRESH_INVOCATION_YIELD_SECONDS = 8;\nexport const ASYNC_BATCH_POLL_DELAY_SECONDS = 20;\nexport const MAX_RETRYABLE_FILE_REVIEW_FAILURES = 6;\nexport const MAX_JOB_CONTINUATIONS = 20;\nexport const MAX_FINALIZE_CONTINUATIONS = 3;\n\n// Budget & Attempts\nexport const FILE_FIXED_SUBREQUESTS = 2;\nexport const MAX_MODEL_ATTEMPTS_ESTIMATE = 4;\nexport const MISSING_FILE_ERROR = 'Model omitted this file from a batched review; retrying later.';\n\n// Model Output Parsing\nexport const MIN_DISCRIMINATING_EVIDENCE_CHARS = 8;\nexport const NON_ANSWER_MAX_RESPONSE_CHARS = 600;\nexport const NON_ANSWER_MIN_DIFF_LINES = 200;\nexport const MAX_LOGGED_JSON_CHARS = 2_000;\nexport const SEVERITY_ORDER = ['P0', 'P1', 'P2', 'P3', 'nit'] as const;\n\n// Finding Gates\nexport const VERIFY_MIN_ANSWER_RATIO = 0.6;\n\n// Rules\nexport const MAX_RULE_SCAN_ADDED_LINES = 600;\n\n// Prompts\nexport const EXEMPLAR_BLOCK_CHARS = 700;\nexport const PR_DESCRIPTION_CHARS = 2_000;\n// Changelog entries are short; keep well under the description budget.\nexport const CHANGELOG_EXCERPT_CHARS = 600;\n// Whole-file context budget when full_file_context is on; half the bin diff budget.\nexport const FILE_CONTEXT_CHAR_BUDGET = 8_000;\n// Per-chunk window, not a repeated whole-file block, to stay within the budget above.\nexport const FILE_CONTEXT_WINDOW_LINES = 120;\n"],"mappings":";AACO,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,gBAAgB;AACtB,IAAM,uBAAuB;AAE7B,IAAM,4BAA4B;AAClC,IAAM,uBAAuB;AAM7B,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB,IAAI,KAAK;AAGxC,IAAM,6BAA6B,KAAK,KAAK;AAC7C,IAAM,oBAAoB,KAAK;AAC/B,IAAM,qBAAqB;AAC3B,IAAM,+CAA+C,CAAC,IAAI,IAAI,IAAI,IAAI,EAAE;AACxE,IAAM,iCAAiC;AACvC,IAAM,iCAAiC;AACvC,IAAM,qCAAqC;AAC3C,IAAM,wBAAwB;AAC9B,IAAM,6BAA6B;AAGnC,IAAM,yBAAyB;AAC/B,IAAM,8BAA8B;AACpC,IAAM,qBAAqB;AAG3B,IAAM,oCAAoC;AAC1C,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,wBAAwB;AAC9B,IAAM,iBAAiB,CAAC,MAAM,MAAM,MAAM,MAAM,KAAK;AAGrD,IAAM,0BAA0B;AAGhC,IAAM,4BAA4B;AAGlC,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,IAAM,0BAA0B;AAEhC,IAAM,2BAA2B;AAEjC,IAAM,4BAA4B;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fingerprint.ts"],"sourcesContent":["\nexport function fnv1a32Hex(input: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;\n }\n return hash.toString(16).padStart(8, '0');\n}\n\nexport function normalizeDiffText(input: string): string {\n return input\n .replace(/^\\s*\\d*\\s+\\d*\\s*[+\\- ]?/, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function foldEvidenceText(input: string): string {\n return normalizeDiffText(input)\n .replace(/[‘’‚‛′]/g, \"'\")\n .replace(/[“”„‟″]/g, '\"')\n .replace(/[‐-―−]/g, '-')\n .replace(/…/g, '...');\n}\n\nexport function normalizeFindingTitle(title: string): string {\n return title.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();\n}\n\nexport function buildFindingFingerprint(path: string, title: string): string {\n return fnv1a32Hex(`${path}\\u0000${normalizeFindingTitle(title)}`);\n}\n\nexport function buildFindingFingerprintV2(\n path: string,\n claimType: string | null | undefined,\n anchorHash: string | null | undefined,\n): string | null {\n if (!anchorHash) return null;\n return fnv1a32Hex(`v2 ${path} ${claimType ?? 'other'} ${anchorHash}`);\n}\n\nexport function buildAnchorHash(lineContent: string): string {\n return fnv1a32Hex(normalizeDiffText(lineContent));\n}\n"],"mappings":";AACO,SAAS,WAAW,OAAuB;AAChD,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAQ,MAAM,WAAW,CAAC;AAC1B,WAAQ,SAAS,QAAQ,MAAM,QAAQ,MAAM,QAAQ,MAAM,QAAQ,MAAM,QAAQ,SAAU;AAAA,EAC7F;AACA,SAAO,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC1C;AAEO,SAAS,kBAAkB,OAAuB;AACvD,SAAO,MACJ,QAAQ,2BAA2B,EAAE,EACrC,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEO,SAAS,iBAAiB,OAAuB;AACtD,SAAO,kBAAkB,KAAK,EAC3B,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,WAAW,GAAG,EACtB,QAAQ,MAAM,KAAK;AACxB;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,SAAO,MAAM,YAAY,EAAE,QAAQ,eAAe,GAAG,EAAE,KAAK;AAC9D;AAEO,SAAS,wBAAwB,MAAc,OAAuB;AAC3E,SAAO,WAAW,GAAG,IAAI,KAAS,sBAAsB,KAAK,CAAC,EAAE;AAClE;AAEO,SAAS,0BACd,MACA,WACA,YACe;AACf,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO,WAAW,MAAM,IAAI,IAAI,aAAa,OAAO,IAAI,UAAU,EAAE;AACtE;AAEO,SAAS,gBAAgB,aAA6B;AAC3D,SAAO,WAAW,kBAAkB,WAAW,CAAC;AAClD;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logger.ts"],"sourcesContent":["\n/**\n * The logging port. A correct implementation must:\n * - never throw, for any input, including circular objects (callers log on failure paths, so a\n * throwing logger converts a handled error into an unhandled one);\n * - never block the caller on I/O;\n * - scrub secrets before emitting, using `scrubString`/`redact` below rather than its own rules.\n * Ordering between calls is not guaranteed and callers must not rely on it.\n */\nexport interface Logger {\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n debug(message: string, data?: unknown): void;\n}\n\nconst SENSITIVE_KEYS = [\n 'api_key',\n 'api-key',\n 'apikey',\n 'secret',\n 'password',\n 'token',\n 'private_key',\n 'private-key',\n 'database_url',\n 'authorization',\n 'session',\n 'cookie',\n];\n\nconst JWT = /\\beyJ[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]*/g;\nconst BEARER = /\\b(Bearer|Basic)\\s+[A-Za-z0-9._~+/=-]{8,}/gi;\n\nexport function scrubString(value: string): string {\n return value.replace(JWT, '[REDACTED_JWT]').replace(BEARER, (m) => `${m.split(/\\s+/)[0]} [REDACTED]`);\n}\n\nexport function redact(obj: any): any {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj !== 'object') {\n return typeof obj === 'string' ? scrubString(obj) : obj;\n }\n if (Array.isArray(obj)) return obj.map(redact);\n if (obj instanceof Error) {\n return {\n name: obj.name,\n message: scrubString(obj.message),\n ...(obj.stack ? { stack: scrubString(obj.stack) } : {}),\n };\n }\n\n const redacted: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const lowerKey = key.toLowerCase();\n if (SENSITIVE_KEYS.some((sk) => lowerKey.includes(sk))) {\n redacted[key] = '[REDACTED]';\n } else {\n redacted[key] = redact(value);\n }\n }\n return redacted;\n}\n\nexport function formatLogRecord(\n level: string,\n message: string,\n contexts: Array<Record<string, any>>,\n data?: any,\n): Record<string, unknown> {\n return {\n timestamp: new Date().toISOString(),\n level,\n message: scrubString(message),\n ...contexts.reduce<Record<string, unknown>>((merged, context) => Object.assign(merged, redact(context)), {}),\n ...(data ? { data: redact(data) } : {}),\n };\n}\n\nexport const consoleLogger: Logger = {\n info: (message, data) => console.log(JSON.stringify(formatLogRecord('info', message, [], data))),\n warn: (message, data) => console.warn(JSON.stringify(formatLogRecord('warn', message, [], data))),\n error: (message, data) => console.error(JSON.stringify(formatLogRecord('error', message, [], data))),\n debug: (message, data) => console.log(JSON.stringify(formatLogRecord('debug', message, [], data))),\n};\n\nlet sink: Logger = consoleLogger;\n\n/**\n * Installs the host's logger. Called once at import scope by src/server/core/logger.ts, and by tests\n * that want to capture output.\n *\n * This is the one piece of module-level mutable state in this package, and it is deliberate: `logger`\n * below is used at import scope by fifteen modules here, several of them (model-output/*, rules/*,\n * finding-gates.ts) pure functions with no runtime parameter to hang a port off. Threading a Logger\n * argument through all of them would be by far the largest and least mechanical part of the\n * extraction, for no behavioural gain.\n */\nexport function setLoggerSink(next: Logger) {\n sink = next;\n}\n\nexport const logger: Logger = {\n info: (message, data) => sink.info(message, data),\n warn: (message, data) => sink.warn(message, data),\n error: (message, data) => sink.error(message, data),\n debug: (message, data) => sink.debug(message, data),\n};\n"],"mappings":";AAgBA,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,MAAM;AACZ,IAAM,SAAS;AAER,SAAS,YAAY,OAAuB;AACjD,SAAO,MAAM,QAAQ,KAAK,gBAAgB,EAAE,QAAQ,QAAQ,CAAC,MAAM,GAAG,EAAE,MAAM,KAAK,EAAE,CAAC,CAAC,aAAa;AACtG;AAEO,SAAS,OAAO,KAAe;AACpC,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO;AAC9C,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,OAAO,QAAQ,WAAW,YAAY,GAAG,IAAI;AAAA,EACtD;AACA,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,MAAM;AAC7C,MAAI,eAAe,OAAO;AACxB,WAAO;AAAA,MACL,MAAM,IAAI;AAAA,MACV,SAAS,YAAY,IAAI,OAAO;AAAA,MAChC,GAAI,IAAI,QAAQ,EAAE,OAAO,YAAY,IAAI,KAAK,EAAE,IAAI,CAAC;AAAA,IACvD;AAAA,EACF;AAEA,QAAM,WAAgB,CAAC;AACvB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,UAAM,WAAW,IAAI,YAAY;AACjC,QAAI,eAAe,KAAK,CAAC,OAAO,SAAS,SAAS,EAAE,CAAC,GAAG;AACtD,eAAS,GAAG,IAAI;AAAA,IAClB,OAAO;AACL,eAAS,GAAG,IAAI,OAAO,KAAK;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,gBACd,OACA,SACA,UACA,MACyB;AACzB,SAAO;AAAA,IACL,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,IACA,SAAS,YAAY,OAAO;AAAA,IAC5B,GAAG,SAAS,OAAgC,CAAC,QAAQ,YAAY,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AAAA,IAC3G,GAAI,OAAO,EAAE,MAAM,OAAO,IAAI,EAAE,IAAI,CAAC;AAAA,EACvC;AACF;AAEO,IAAM,gBAAwB;AAAA,EACnC,MAAM,CAAC,SAAS,SAAS,QAAQ,IAAI,KAAK,UAAU,gBAAgB,QAAQ,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EAC/F,MAAM,CAAC,SAAS,SAAS,QAAQ,KAAK,KAAK,UAAU,gBAAgB,QAAQ,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EAChG,OAAO,CAAC,SAAS,SAAS,QAAQ,MAAM,KAAK,UAAU,gBAAgB,SAAS,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;AAAA,EACnG,OAAO,CAAC,SAAS,SAAS,QAAQ,IAAI,KAAK,UAAU,gBAAgB,SAAS,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;AACnG;AAEA,IAAI,OAAe;AAYZ,SAAS,cAAc,MAAc;AAC1C,SAAO;AACT;AAEO,IAAM,SAAiB;AAAA,EAC5B,MAAM,CAAC,SAAS,SAAS,KAAK,KAAK,SAAS,IAAI;AAAA,EAChD,MAAM,CAAC,SAAS,SAAS,KAAK,KAAK,SAAS,IAAI;AAAA,EAChD,OAAO,CAAC,SAAS,SAAS,KAAK,MAAM,SAAS,IAAI;AAAA,EAClD,OAAO,CAAC,SAAS,SAAS,KAAK,MAAM,SAAS,IAAI;AACpD;","names":[]}
|
package/dist/claim-checks.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as FileDiff } from './position-zZl8KGVu.js';
|
|
2
2
|
|
|
3
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
|
-
*/
|
|
4
|
+
/** Refutes a claim whose truth lives outside the diff; two signals per family, since one is ordinary. */
|
|
12
5
|
declare function refuteUndecidableClaim(input: {
|
|
13
6
|
title: string;
|
|
14
7
|
body: string;
|
|
@@ -19,9 +12,10 @@ declare function isVersionClaimRefutedByPin(input: {
|
|
|
19
12
|
body: string;
|
|
20
13
|
anchorContent: string;
|
|
21
14
|
}): boolean;
|
|
15
|
+
/** One line the identifier could be found on; `hunkIndex` is null for lines from the post-image. */
|
|
22
16
|
type PresenceEntry = {
|
|
23
|
-
|
|
24
|
-
hunkIndex: number;
|
|
17
|
+
newLineNumber: number | undefined;
|
|
18
|
+
hunkIndex: number | null;
|
|
25
19
|
code: string;
|
|
26
20
|
};
|
|
27
21
|
type PresenceIndex = {
|
|
@@ -35,7 +29,7 @@ type AbsenceClaimVerdict = {
|
|
|
35
29
|
} | {
|
|
36
30
|
status: 'refuted';
|
|
37
31
|
identifier: string;
|
|
38
|
-
line:
|
|
32
|
+
line: number | undefined;
|
|
39
33
|
};
|
|
40
34
|
type CommentSyntax = {
|
|
41
35
|
line: readonly string[];
|
|
@@ -43,7 +37,8 @@ type CommentSyntax = {
|
|
|
43
37
|
};
|
|
44
38
|
declare function commentSyntaxFor(path: string): CommentSyntax;
|
|
45
39
|
declare function stripCommentsAndStrings(input: string, syntax: CommentSyntax): string | null;
|
|
46
|
-
|
|
40
|
+
/** Where each identifier appears after the change; without a post-image the index sees only the diff. */
|
|
41
|
+
declare function buildPresenceIndex(file: FileDiff, fileContent?: string | null): PresenceIndex;
|
|
47
42
|
declare function checkAbsenceClaim(input: {
|
|
48
43
|
title: string;
|
|
49
44
|
body: string;
|
package/dist/claim-checks.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
looksLikeExternalVersionClaim,
|
|
7
7
|
refuteUndecidableClaim,
|
|
8
8
|
stripCommentsAndStrings
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-IKVUW4WC.js";
|
|
10
|
+
import "./chunk-XPYVLHSX.js";
|
|
11
11
|
export {
|
|
12
12
|
buildPresenceIndex,
|
|
13
13
|
checkAbsenceClaim,
|
package/dist/diff/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import picomatch from 'picomatch';
|
|
2
2
|
import { RepoConfig } from '@codraoss/schema';
|
|
3
|
-
import { F as FileDiff } from '../position-
|
|
4
|
-
export {
|
|
3
|
+
import { F as FileDiff } from '../position-zZl8KGVu.js';
|
|
4
|
+
export { D as DiffHunk, a as DiffLine, b as DiffLineKind, c as chunkFileDiff, f as findPositionForLine, g as getValidNewLines, d as getValidPositions, t as truncateFileDiff } from '../position-zZl8KGVu.js';
|
|
5
5
|
|
|
6
6
|
declare function isReviewableFile(path: string, customMatchers: ReturnType<typeof picomatch>[]): boolean;
|
|
7
7
|
declare function parseDiffHeaderPath(line: string): string;
|
|
@@ -14,7 +14,7 @@ type DiffFileEntry = {
|
|
|
14
14
|
patch?: string | null;
|
|
15
15
|
};
|
|
16
16
|
declare function buildUnifiedDiffFromFiles(files: DiffFileEntry[]): string;
|
|
17
|
-
declare function filterReviewableFiles(files: FileDiff[], config: RepoConfig['review'], maxFiles: number): {
|
|
17
|
+
declare function filterReviewableFiles(files: FileDiff[], config: RepoConfig['review'], maxFiles: number, maxTotalDiffChars?: number): {
|
|
18
18
|
files: FileDiff[];
|
|
19
19
|
skipped: number;
|
|
20
20
|
};
|
package/dist/diff/index.js
CHANGED
package/dist/fingerprint.js
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ParsedReviewComment } from '@codraoss/schema';
|
|
2
|
+
|
|
3
|
+
interface ReviewFormatter {
|
|
4
|
+
toReviewEvent(verdict: 'approve' | 'comment'): 'APPROVE' | 'COMMENT';
|
|
5
|
+
summarizeVerdict(comments: ParsedReviewComment[], hasFailures: boolean): {
|
|
6
|
+
verdict: 'approve' | 'comment';
|
|
7
|
+
errors: number;
|
|
8
|
+
warnings: number;
|
|
9
|
+
};
|
|
10
|
+
formatInlineComment(comment: ParsedReviewComment): string;
|
|
11
|
+
formatReviewOverview(input: ReviewOverviewInput): string;
|
|
12
|
+
}
|
|
13
|
+
type ReviewOverviewInput = {
|
|
14
|
+
commitSha: string;
|
|
15
|
+
/** Comments actually posted. Zero means the header must not promise suggestions. */
|
|
16
|
+
postedFindings: number;
|
|
17
|
+
filesReviewed: number;
|
|
18
|
+
linesReviewed: number;
|
|
19
|
+
/** Candidates the gates dropped; on a clean review this is what "nothing to report" cost. */
|
|
20
|
+
withheldFindings: number;
|
|
21
|
+
filesFailed: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type { ReviewOverviewInput as R, ReviewFormatter as a };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ParsedReviewComment } from '@codraoss/schema';
|
|
2
|
+
import { R as ReviewOverviewInput } from './formatter-CDFpqbDP.js';
|
|
3
|
+
|
|
4
|
+
declare function formatFindingMarker(comment: Pick<ParsedReviewComment, 'fingerprint' | 'anchorHash' | 'fingerprintV2'>): string;
|
|
5
|
+
declare function parseFindingMarker(body: string | null | undefined): {
|
|
6
|
+
fingerprint: string;
|
|
7
|
+
anchorHash: string | null;
|
|
8
|
+
fingerprintV2: string | null;
|
|
9
|
+
} | null;
|
|
10
|
+
declare class FormatterService {
|
|
11
|
+
private baseUrl;
|
|
12
|
+
constructor(baseUrl: string);
|
|
13
|
+
toReviewEvent(verdict: 'approve' | 'comment'): "APPROVE" | "COMMENT";
|
|
14
|
+
severityIcon(severity: ParsedReviewComment['severity']): string;
|
|
15
|
+
stripLeadingTags(text: string): string;
|
|
16
|
+
formatInlineComment(comment: ParsedReviewComment): string;
|
|
17
|
+
summarizeVerdict(comments: ParsedReviewComment[], hasFailures: boolean): {
|
|
18
|
+
verdict: "comment";
|
|
19
|
+
errors: number;
|
|
20
|
+
warnings: number;
|
|
21
|
+
} | {
|
|
22
|
+
verdict: "approve";
|
|
23
|
+
errors: number;
|
|
24
|
+
warnings: number;
|
|
25
|
+
};
|
|
26
|
+
formatReviewOverview(input: ReviewOverviewInput): string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { FormatterService, formatFindingMarker, parseFindingMarker };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// src/formatter.ts
|
|
2
|
+
var FINDING_MARKER_PATTERN = /<!--\s*codra-fp:([0-9a-f]+):([0-9a-f]*)(?::([0-9a-f]*))?\s*-->/;
|
|
3
|
+
function formatFindingMarker(comment) {
|
|
4
|
+
if (!comment.fingerprint) return "";
|
|
5
|
+
return `
|
|
6
|
+
|
|
7
|
+
<!-- codra-fp:${comment.fingerprint}:${comment.anchorHash ?? ""}:${comment.fingerprintV2 ?? ""} -->`;
|
|
8
|
+
}
|
|
9
|
+
function parseFindingMarker(body) {
|
|
10
|
+
if (!body) return null;
|
|
11
|
+
const match = FINDING_MARKER_PATTERN.exec(body);
|
|
12
|
+
if (!match) return null;
|
|
13
|
+
return { fingerprint: match[1], anchorHash: match[2] || null, fingerprintV2: match[3] || null };
|
|
14
|
+
}
|
|
15
|
+
var FormatterService = class {
|
|
16
|
+
constructor(baseUrl) {
|
|
17
|
+
this.baseUrl = baseUrl;
|
|
18
|
+
}
|
|
19
|
+
toReviewEvent(verdict) {
|
|
20
|
+
return verdict === "approve" ? "APPROVE" : "COMMENT";
|
|
21
|
+
}
|
|
22
|
+
severityIcon(severity) {
|
|
23
|
+
const iconBase = `${this.baseUrl}/icons`;
|
|
24
|
+
const img = (name, alt) => `<img src="${iconBase}/${name}-icon.svg" width="20" height="20" alt="${alt}" style="vertical-align:middle" />`;
|
|
25
|
+
switch (severity) {
|
|
26
|
+
case "P0":
|
|
27
|
+
return img("p0", "P0");
|
|
28
|
+
case "P1":
|
|
29
|
+
return img("p1", "P1");
|
|
30
|
+
case "P2":
|
|
31
|
+
return img("p2", "P2");
|
|
32
|
+
case "P3":
|
|
33
|
+
return img("p3", "P3");
|
|
34
|
+
case "nit":
|
|
35
|
+
return img("nit", "nit");
|
|
36
|
+
default:
|
|
37
|
+
return "\u26AA";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Mirrors model-output cleanText; keep both in sync.
|
|
41
|
+
stripLeadingTags(text) {
|
|
42
|
+
let current = text.trim();
|
|
43
|
+
let prev = "";
|
|
44
|
+
while (current !== prev) {
|
|
45
|
+
prev = current;
|
|
46
|
+
current = current.replace(/^([\u{1F300}-\u{1F9FF}\u{2600}-\u{27BF}\u{FE00}-\u{FEFF}]|\[QUALITY\]|\[SECURITY\]|\[BUG\]|\[P[0-3]\]|\[NIT\]|QUALITY|SECURITY|BUG|P[0-3]|NIT|[:\-\s\uFE0F]|[^\w\s])+/giu, "").trim();
|
|
47
|
+
}
|
|
48
|
+
return current;
|
|
49
|
+
}
|
|
50
|
+
formatInlineComment(comment) {
|
|
51
|
+
let body = this.stripLeadingTags(comment.body);
|
|
52
|
+
const firstLine = body.split("\n")[0].trim();
|
|
53
|
+
const cleanFirstLine = this.stripLeadingTags(firstLine);
|
|
54
|
+
if (cleanFirstLine.toLowerCase().startsWith(comment.title.toLowerCase()) || comment.title.toLowerCase().startsWith(cleanFirstLine.toLowerCase())) {
|
|
55
|
+
body = body.slice(firstLine.length).replace(/^[\n\r]+/, "");
|
|
56
|
+
}
|
|
57
|
+
return `${this.severityIcon(comment.severity)} <strong>${comment.title}</strong>
|
|
58
|
+
|
|
59
|
+
${body}${formatFindingMarker(comment)}`;
|
|
60
|
+
}
|
|
61
|
+
summarizeVerdict(comments, hasFailures) {
|
|
62
|
+
const p0 = comments.filter((c) => c.severity === "P0").length;
|
|
63
|
+
const p1 = comments.filter((c) => c.severity === "P1").length;
|
|
64
|
+
const p2 = comments.filter((c) => c.severity === "P2").length;
|
|
65
|
+
if (p0 > 0 || p1 > 0 || hasFailures || p2 > 0) {
|
|
66
|
+
return { verdict: "comment", errors: p0 + p1, warnings: p2 };
|
|
67
|
+
}
|
|
68
|
+
return { verdict: "approve", errors: 0, warnings: 0 };
|
|
69
|
+
}
|
|
70
|
+
formatReviewOverview(input) {
|
|
71
|
+
const { commitSha, postedFindings, filesReviewed, linesReviewed } = input;
|
|
72
|
+
const shortSha = commitSha.slice(0, 10);
|
|
73
|
+
const plural = (n, one, many = one + "s") => `${n} ${n === 1 ? one : many}`;
|
|
74
|
+
const headline = postedFindings === 0 ? `\u2705 **Nothing to flag.** Reviewed ${plural(filesReviewed, "file")} (${plural(linesReviewed, "changed line")}) and found no issues worth raising.` : "Here are some automated review suggestions for this pull request.";
|
|
75
|
+
const notes = [];
|
|
76
|
+
if (input.filesFailed > 0) {
|
|
77
|
+
notes.push(`${plural(input.filesFailed, "file")} could not be reviewed, so this pass is incomplete.`);
|
|
78
|
+
}
|
|
79
|
+
if (postedFindings === 0 && input.withheldFindings > 0) {
|
|
80
|
+
notes.push(`${plural(input.withheldFindings, "candidate")} did not survive the evidence and claim gates \u2014 see the [dashboard](${this.baseUrl}) for what was dropped and why.`);
|
|
81
|
+
}
|
|
82
|
+
const noteBlock = notes.length > 0 ? "\n" + notes.map((line) => `> [!NOTE]
|
|
83
|
+
> ${line}`).join("\n\n") + "\n" : "";
|
|
84
|
+
const aboutOutcome = postedFindings === 0 ? "Every review posts a summary here. A clean pass also gets a \u{1F44D} on the pull request itself." : "If Codra has suggestions, it will comment; otherwise it will react with \u{1F44D}.";
|
|
85
|
+
return `### Codra Review
|
|
86
|
+
|
|
87
|
+
${headline}
|
|
88
|
+
${noteBlock}
|
|
89
|
+
**Reviewed commit:** \`${shortSha}\`
|
|
90
|
+
|
|
91
|
+
<details>
|
|
92
|
+
<summary>\u2139\uFE0F About Codra in GitHub</summary>
|
|
93
|
+
|
|
94
|
+
<br/>
|
|
95
|
+
|
|
96
|
+
[Your team has set up Codra to review pull requests in this repo](${this.baseUrl}/repos). Reviews are triggered when you:
|
|
97
|
+
|
|
98
|
+
- **Open** a pull request for review
|
|
99
|
+
- **Mark** a draft as ready
|
|
100
|
+
|
|
101
|
+
${aboutOutcome}
|
|
102
|
+
|
|
103
|
+
</details>`;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
export {
|
|
107
|
+
FormatterService,
|
|
108
|
+
formatFindingMarker,
|
|
109
|
+
parseFindingMarker
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/formatter.ts"],"sourcesContent":["import type { ParsedReviewComment } from '@codraoss/schema';\nimport type { ReviewOverviewInput } from './ports';\n\n// The third field is OPTIONAL so every comment already on GitHub still parses; requiring it would silently stop recording deletions of historical comments.\nconst FINDING_MARKER_PATTERN = /<!--\\s*codra-fp:([0-9a-f]+):([0-9a-f]*)(?::([0-9a-f]*))?\\s*-->/;\n\n// Matching on (path, line) instead would fail exactly when it matters most: GitHub nulls `line` once a comment goes outdated.\nexport function formatFindingMarker(\n comment: Pick<ParsedReviewComment, 'fingerprint' | 'anchorHash' | 'fingerprintV2'>,\n) {\n if (!comment.fingerprint) return '';\n return `\\n\\n<!-- codra-fp:${comment.fingerprint}:${comment.anchorHash ?? ''}:${comment.fingerprintV2 ?? ''} -->`;\n}\n\nexport function parseFindingMarker(body: string | null | undefined) {\n if (!body) return null;\n const match = FINDING_MARKER_PATTERN.exec(body);\n if (!match) return null;\n return { fingerprint: match[1], anchorHash: match[2] || null, fingerprintV2: match[3] || null };\n}\n\nexport class FormatterService {\n constructor(private baseUrl: string) {}\n\n toReviewEvent(verdict: 'approve' | 'comment') {\n return verdict === 'approve' ? 'APPROVE' as const : 'COMMENT' as const;\n }\n\n severityIcon(severity: ParsedReviewComment['severity']) {\n const iconBase = `${this.baseUrl}/icons`;\n const img = (name: string, alt: string) =>\n `<img src=\"${iconBase}/${name}-icon.svg\" width=\"20\" height=\"20\" alt=\"${alt}\" style=\"vertical-align:middle\" />`;\n switch (severity) {\n case 'P0': return img('p0', 'P0');\n case 'P1': return img('p1', 'P1');\n case 'P2': return img('p2', 'P2');\n case 'P3': return img('p3', 'P3');\n case 'nit': return img('nit', 'nit');\n default: return '⚪';\n }\n }\n\n // Mirrors model-output cleanText; keep both in sync.\n stripLeadingTags(text: string): string {\n let current = text.trim();\n let prev = '';\n while (current !== prev) {\n prev = current;\n current = current\n .replace(/^([\\u{1F300}-\\u{1F9FF}\\u{2600}-\\u{27BF}\\u{FE00}-\\u{FEFF}]|\\[QUALITY\\]|\\[SECURITY\\]|\\[BUG\\]|\\[P[0-3]\\]|\\[NIT\\]|QUALITY|SECURITY|BUG|P[0-3]|NIT|[:\\-\\s\\uFE0F]|[^\\w\\s])+/giu, '')\n .trim();\n }\n return current;\n }\n\n formatInlineComment(comment: ParsedReviewComment) {\n // Removes a leading line duplicating the title, which can happen with stale DB records.\n let body = this.stripLeadingTags(comment.body);\n const firstLine = body.split('\\n')[0].trim();\n const cleanFirstLine = this.stripLeadingTags(firstLine);\n if (\n cleanFirstLine.toLowerCase().startsWith(comment.title.toLowerCase()) ||\n comment.title.toLowerCase().startsWith(cleanFirstLine.toLowerCase())\n ) {\n body = body.slice(firstLine.length).replace(/^[\\n\\r]+/, '');\n }\n\n return `${this.severityIcon(comment.severity)} <strong>${comment.title}</strong>\\n\\n${body}${formatFindingMarker(comment)}`;\n }\n\n summarizeVerdict(comments: ParsedReviewComment[], hasFailures: boolean) {\n const p0 = comments.filter((c) => c.severity === 'P0').length;\n const p1 = comments.filter((c) => c.severity === 'P1').length;\n const p2 = comments.filter((c) => c.severity === 'P2').length;\n\n if (p0 > 0 || p1 > 0 || hasFailures || p2 > 0) {\n return { verdict: 'comment' as const, errors: p0 + p1, warnings: p2 };\n }\n\n return { verdict: 'approve' as const, errors: 0, warnings: 0 };\n }\n\n formatReviewOverview(input: ReviewOverviewInput) {\n const { commitSha, postedFindings, filesReviewed, linesReviewed } = input;\n const shortSha = commitSha.slice(0, 10);\n const plural = (n: number, one: string, many = one + 's') => `${n} ${n === 1 ? one : many}`;\n\n // A clean review used to say \"here are some automated review suggestions\" and then list none,\n // which reads as a failure rather than a pass. Say what was checked and that nothing came of it.\n // With findings the original wording stays.\n const headline = postedFindings === 0\n ? `✅ **Nothing to flag.** Reviewed ${plural(filesReviewed, 'file')} (${plural(linesReviewed, 'changed line')}) and found no issues worth raising.`\n : 'Here are some automated review suggestions for this pull request.';\n\n const notes: string[] = [];\n if (input.filesFailed > 0) {\n notes.push(`${plural(input.filesFailed, 'file')} could not be reviewed, so this pass is incomplete.`);\n }\n if (postedFindings === 0 && input.withheldFindings > 0) {\n // \"No issues\" is a weaker claim when candidates were dropped for failing to ground themselves,\n // and every one of them is on the dashboard.\n notes.push(`${plural(input.withheldFindings, 'candidate')} did not survive the evidence and claim gates — see the [dashboard](${this.baseUrl}) for what was dropped and why.`);\n }\n \n const noteBlock = notes.length > 0\n ? '\\n' + notes.map((line) => `> [!NOTE]\\n> ${line}`).join('\\n\\n') + '\\n'\n : '';\n\n const aboutOutcome = postedFindings === 0\n ? 'Every review posts a summary here. A clean pass also gets a 👍 on the pull request itself.'\n : 'If Codra has suggestions, it will comment; otherwise it will react with 👍.';\n\n return `### Codra Review\\n\\n${headline}\\n${noteBlock}\\n**Reviewed commit:** \\`${shortSha}\\`\\n\\n<details>\\n<summary>ℹ️ About Codra in GitHub</summary>\\n\\n<br/>\\n\\n[Your team has set up Codra to review pull requests in this repo](${this.baseUrl}/repos). Reviews are triggered when you:\\n\\n- **Open** a pull request for review\\n- **Mark** a draft as ready\\n\\n${aboutOutcome}\\n\\n</details>`;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ParsedReviewComment, batchReviewModelOutputSchema, fileReviewModelOutputSchema, ClaimType } from '@codraoss/schema';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { F as FileDiff } from './position-
|
|
3
|
+
import { F as FileDiff } from './position-zZl8KGVu.js';
|
|
4
4
|
|
|
5
5
|
type BinAmbiguityIndex = Map<string, number>;
|
|
6
6
|
|
|
@@ -65,6 +65,7 @@ type FileReviewPayload = z.infer<typeof fileReviewModelOutputSchema>;
|
|
|
65
65
|
type GroundingOptions = {
|
|
66
66
|
deniedClaimTypes?: readonly ClaimType[];
|
|
67
67
|
ambiguity?: BinAmbiguity;
|
|
68
|
+
fileContent?: string | null;
|
|
68
69
|
};
|
|
69
70
|
type GroundedFileReview = {
|
|
70
71
|
comments: ParsedReviewComment[];
|
|
@@ -78,6 +79,7 @@ type GroundedFileReview = {
|
|
|
78
79
|
unmatched: number;
|
|
79
80
|
weak: number;
|
|
80
81
|
absent: number;
|
|
82
|
+
contextOnly: number;
|
|
81
83
|
};
|
|
82
84
|
claimTypeCounts: Record<string, number>;
|
|
83
85
|
deniedClaimCounts: Record<string, number>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { RepoConfig, ParsedReviewComment, FindingDisposition, ReviewJobMessage } from '@codraoss/schema';
|
|
2
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,
|
|
4
|
-
import { R as ReviewModel } from './model-
|
|
5
|
-
export { F as FileReviewOutcome, M as ModelErrorClassifier, a as ModelResponse, b as ModelResponseSchema } from './model-
|
|
6
|
-
export { a as
|
|
7
|
-
|
|
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, ReviewSettingsReader, ReviewTelemetryEvent, SecretStore, SessionStore, SuppressedFinding, TelemetrySink, WebhookDeliveryReader } from './ports/index.js';
|
|
4
|
+
import { R as ReviewModel } from './model-BkqfyVh9.js';
|
|
5
|
+
export { F as FileReviewOutcome, M as ModelErrorClassifier, a as ModelResponse, b as ModelResponseSchema } from './model-BkqfyVh9.js';
|
|
6
|
+
export { a as ReviewFormatter, R as ReviewOverviewInput } from './formatter-CDFpqbDP.js';
|
|
7
|
+
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-CrtHz4vN.js';
|
|
8
|
+
import { F as FileDiff } from './position-zZl8KGVu.js';
|
|
8
9
|
export { Logger } from './logger.js';
|
|
9
10
|
import { WebhookEventName, WebhookPayload } from '@codraoss/schema/webhook';
|
|
10
11
|
import './token-tracker.js';
|
|
@@ -28,8 +29,8 @@ declare function getOrFetchRawDiffForCompletedJob(env: Pick<ReviewRuntime, 'kv'>
|
|
|
28
29
|
commitSha: string;
|
|
29
30
|
}, github: Pick<ReviewGitProvider, 'getCompareDiff'>): Promise<string>;
|
|
30
31
|
|
|
31
|
-
declare function budgetAwareFileLimit(remainingSafeBudget: number, configuredChunkFileLimit: number, modelChainLength?: number): number;
|
|
32
|
-
declare function estimatedSubrequestsPerFile(modelChainLength: number): number;
|
|
32
|
+
declare function budgetAwareFileLimit(remainingSafeBudget: number, configuredChunkFileLimit: number, modelChainLength?: number, fetchesFileContent?: boolean, runsSecondaryReviewer?: boolean): number;
|
|
33
|
+
declare function estimatedSubrequestsPerFile(modelChainLength: number, fetchesFileContent?: boolean, runsSecondaryReviewer?: boolean): number;
|
|
33
34
|
|
|
34
35
|
type ReviewUnit = {
|
|
35
36
|
kind: 'single';
|
|
@@ -47,6 +48,7 @@ type LedgerEntry = {
|
|
|
47
48
|
declare function unitFiles(unit: ReviewUnit): FileDiff[];
|
|
48
49
|
declare function planReviewUnits(files: readonly FileDiff[], opts: {
|
|
49
50
|
enabled: boolean;
|
|
51
|
+
fullFileContext?: boolean;
|
|
50
52
|
}): ReviewUnit[];
|
|
51
53
|
declare function narrowUnit(unit: ReviewUnit, ledger: Map<string, LedgerEntry>): ReviewUnit[];
|
|
52
54
|
|
|
@@ -67,10 +69,13 @@ type VerifyDrop = {
|
|
|
67
69
|
disposition: Extract<FindingDisposition, 'verify' | 'verify_unanswered'>;
|
|
68
70
|
reason?: string;
|
|
69
71
|
};
|
|
72
|
+
/** `null` means verification ran; any other value means findings were posted unverified. */
|
|
73
|
+
type VerifySkipReason = 'no_verifiable_candidates' | 'low_answer_ratio' | 'verify_call_failed';
|
|
70
74
|
type VerifyOutcome = {
|
|
71
75
|
comments: ParsedReviewComment[];
|
|
72
76
|
dropped: VerifyDrop[];
|
|
73
77
|
reasons: Map<ParsedReviewComment, string>;
|
|
78
|
+
skipped: VerifySkipReason | null;
|
|
74
79
|
};
|
|
75
80
|
declare function verifyFindings(params: {
|
|
76
81
|
job: VerifiableJob;
|