@codraoss/core 0.9.5 → 0.9.13

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.
@@ -1,9 +1,20 @@
1
+ import {
2
+ findPositionForLine,
3
+ getValidPositions
4
+ } from "./chunk-I5S3NBFL.js";
1
5
  import {
2
6
  generatorFindingCap
3
7
  } from "./chunk-ONJZXUQT.js";
4
8
  import {
5
9
  renderDiffSnippet
6
10
  } from "./chunk-KTDBDKL5.js";
11
+ import {
12
+ MAX_LOGGED_JSON_CHARS,
13
+ MIN_DISCRIMINATING_EVIDENCE_CHARS,
14
+ NON_ANSWER_MAX_RESPONSE_CHARS,
15
+ NON_ANSWER_MIN_DIFF_LINES,
16
+ SEVERITY_ORDER
17
+ } from "./chunk-W3RY755V.js";
7
18
  import {
8
19
  buildPresenceIndex,
9
20
  checkAbsenceClaim,
@@ -21,17 +32,6 @@ import {
21
32
  import {
22
33
  logger
23
34
  } from "./chunk-Z5B5X7QP.js";
24
- import {
25
- findPositionForLine,
26
- getValidPositions
27
- } from "./chunk-I5S3NBFL.js";
28
- import {
29
- MAX_LOGGED_JSON_CHARS,
30
- MIN_DISCRIMINATING_EVIDENCE_CHARS,
31
- NON_ANSWER_MAX_RESPONSE_CHARS,
32
- NON_ANSWER_MIN_DIFF_LINES,
33
- SEVERITY_ORDER
34
- } from "./chunk-W3RY755V.js";
35
35
 
36
36
  // src/model-output/index.ts
37
37
  import {
@@ -913,4 +913,4 @@ export {
913
913
  groundParsedFindings,
914
914
  parseFileReviewResponse
915
915
  };
916
- //# sourceMappingURL=chunk-2TF4DSRX.js.map
916
+ //# sourceMappingURL=chunk-4XEMXRNG.js.map
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  RULES
3
3
  } from "./chunk-JAF7JIZQ.js";
4
+ import {
5
+ MAX_RULE_SCAN_ADDED_LINES
6
+ } from "./chunk-W3RY755V.js";
4
7
  import {
5
8
  commentSyntaxFor,
6
9
  stripCommentsAndStrings
@@ -11,9 +14,6 @@ import {
11
14
  buildFindingFingerprintV2,
12
15
  normalizeDiffText
13
16
  } from "./chunk-XPYVLHSX.js";
14
- import {
15
- MAX_RULE_SCAN_ADDED_LINES
16
- } from "./chunk-W3RY755V.js";
17
17
 
18
18
  // src/rules/detect.ts
19
19
  import { CLAIM_TYPE_CATEGORY } from "@codraoss/schema";
@@ -114,4 +114,4 @@ export {
114
114
  scanFileForRuleHits,
115
115
  ruleHitsToComments
116
116
  };
117
- //# sourceMappingURL=chunk-754NO4DH.js.map
117
+ //# sourceMappingURL=chunk-EQL5OOEF.js.map
@@ -64,4 +64,4 @@ export {
64
64
  InMemoryOrchestrator,
65
65
  InMemorySessionStore
66
66
  };
67
- //# sourceMappingURL=chunk-JC74XH7Q.js.map
67
+ //# sourceMappingURL=chunk-GDX2ZEBA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports/in-memory.ts"],"sourcesContent":["import type { KeyValueStore } from './kv';\nimport type { QueueProducer } from './queue';\nimport type { JobOrchestrator } from './orchestrator';\nimport type { SessionStore, DashboardSessionUser } from './session-store';\nimport type { ReviewJobMessage } from '@codraoss/schema';\n\nexport class InMemoryKV implements KeyValueStore {\n private store = new Map<string, { value: string; expiresAt?: number }>();\n\n async put(key: string, value: string, options?: { expirationTtl?: number }): Promise<void> {\n const expiresAt = options?.expirationTtl ? Date.now() + options.expirationTtl * 1000 : undefined;\n this.store.set(key, { value, expiresAt });\n }\n\n async get(key: string, type?: 'json' | 'text'): Promise<any> {\n const entry = this.store.get(key);\n if (!entry) return null;\n if (entry.expiresAt && Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return null;\n }\n if (type === 'json') {\n try { return JSON.parse(entry.value); } catch { return null; }\n }\n return entry.value;\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\nexport class InMemoryQueue<T> implements QueueProducer<T> {\n public messages: Array<{ message: T; delaySeconds?: number }> = [];\n\n async send(message: T, options?: { delaySeconds?: number }): Promise<void> {\n this.messages.push({ message, delaySeconds: options?.delaySeconds });\n }\n}\n\nexport class InMemoryOrchestrator implements JobOrchestrator {\n public jobs: Map<string, ReviewJobMessage> = new Map();\n\n async startReviewJob(id: string, params: ReviewJobMessage): Promise<void> {\n this.jobs.set(id, params);\n }\n}\n\nexport class InMemorySessionStore implements SessionStore {\n private kv = new InMemoryKV();\n\n async createSession(session: DashboardSessionUser): Promise<string> {\n const token = Math.random().toString(36).substring(2);\n await this.kv.put(`session:${token}`, JSON.stringify(session), { expirationTtl: 60 * 60 * 24 * 7 });\n return token;\n }\n\n async readSession(token: string): Promise<DashboardSessionUser | null> {\n return this.kv.get(`session:${token}`, 'json');\n }\n\n async destroySession(token: string): Promise<void> {\n await this.kv.delete(`session:${token}`);\n }\n\n async renewSession(token: string): Promise<void> {\n const session = await this.readSession(token);\n if (session) {\n await this.kv.put(`session:${token}`, JSON.stringify(session), { expirationTtl: 60 * 60 * 24 * 7 });\n }\n }\n}\n"],"mappings":";AAMO,IAAM,aAAN,MAA0C;AAAA,EACvC,QAAQ,oBAAI,IAAmD;AAAA,EAEvE,MAAM,IAAI,KAAa,OAAe,SAAqD;AACzF,UAAM,YAAY,SAAS,gBAAgB,KAAK,IAAI,IAAI,QAAQ,gBAAgB,MAAO;AACvF,SAAK,MAAM,IAAI,KAAK,EAAE,OAAO,UAAU,CAAC;AAAA,EAC1C;AAAA,EAEA,MAAM,IAAI,KAAa,MAAsC;AAC3D,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,MAAM,aAAa,KAAK,IAAI,IAAI,MAAM,WAAW;AACnD,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AACA,QAAI,SAAS,QAAQ;AACnB,UAAI;AAAE,eAAO,KAAK,MAAM,MAAM,KAAK;AAAA,MAAG,QAAQ;AAAE,eAAO;AAAA,MAAM;AAAA,IAC/D;AACA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AACF;AAEO,IAAM,gBAAN,MAAmD;AAAA,EACjD,WAAyD,CAAC;AAAA,EAEjE,MAAM,KAAK,SAAY,SAAoD;AACzE,SAAK,SAAS,KAAK,EAAE,SAAS,cAAc,SAAS,aAAa,CAAC;AAAA,EACrE;AACF;AAEO,IAAM,uBAAN,MAAsD;AAAA,EACpD,OAAsC,oBAAI,IAAI;AAAA,EAErD,MAAM,eAAe,IAAY,QAAyC;AACxE,SAAK,KAAK,IAAI,IAAI,MAAM;AAAA,EAC1B;AACF;AAEO,IAAM,uBAAN,MAAmD;AAAA,EAChD,KAAK,IAAI,WAAW;AAAA,EAE5B,MAAM,cAAc,SAAgD;AAClE,UAAM,QAAQ,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AACpD,UAAM,KAAK,GAAG,IAAI,WAAW,KAAK,IAAI,KAAK,UAAU,OAAO,GAAG,EAAE,eAAe,KAAK,KAAK,KAAK,EAAE,CAAC;AAClG,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,OAAqD;AACrE,WAAO,KAAK,GAAG,IAAI,WAAW,KAAK,IAAI,MAAM;AAAA,EAC/C;AAAA,EAEA,MAAM,eAAe,OAA8B;AACjD,UAAM,KAAK,GAAG,OAAO,WAAW,KAAK,EAAE;AAAA,EACzC;AAAA,EAEA,MAAM,aAAa,OAA8B;AAC/C,UAAM,UAAU,MAAM,KAAK,YAAY,KAAK;AAC5C,QAAI,SAAS;AACX,YAAM,KAAK,GAAG,IAAI,WAAW,KAAK,IAAI,KAAK,UAAU,OAAO,GAAG,EAAE,eAAe,KAAK,KAAK,KAAK,EAAE,CAAC;AAAA,IACpG;AAAA,EACF;AACF;","names":[]}
@@ -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":[]}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
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, ReviewFormatter, ReviewOverviewInput, ReviewSettingsReader, ReviewTelemetryEvent, SecretStore, SessionStore, SuppressedFinding, TelemetrySink, WebhookDeliveryReader } 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, ReviewSettingsReader, ReviewTelemetryEvent, SecretStore, SessionStore, SuppressedFinding, TelemetrySink, WebhookDeliveryReader } from './ports/index.js';
4
4
  import { R as ReviewModel } from './model-BkqfyVh9.js';
5
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';
6
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';
7
8
  import { F as FileDiff } from './position-zZl8KGVu.js';
8
9
  export { Logger } from './logger.js';
package/dist/index.js CHANGED
@@ -1,17 +1,10 @@
1
1
  import {
2
2
  dedupeFindings
3
- } from "./chunk-2TF4DSRX.js";
3
+ } from "./chunk-4XEMXRNG.js";
4
4
  import {
5
- InMemoryKV,
6
- InMemoryOrchestrator,
7
- InMemoryQueue,
8
- InMemorySessionStore
9
- } from "./chunk-JC74XH7Q.js";
10
- import {
11
- ruleHitsToComments,
12
- scanFileForRuleHits
13
- } from "./chunk-754NO4DH.js";
14
- import "./chunk-JAF7JIZQ.js";
5
+ filterReviewableFiles,
6
+ parseUnifiedDiff
7
+ } from "./chunk-I5S3NBFL.js";
15
8
  import {
16
9
  changelogExcerptFromDiff,
17
10
  renderFileDiff,
@@ -25,16 +18,17 @@ import {
25
18
  parseVerifyResponse,
26
19
  renderDiffSnippet
27
20
  } from "./chunk-KTDBDKL5.js";
28
- import "./chunk-IKVUW4WC.js";
29
- import "./chunk-XPYVLHSX.js";
30
- import "./chunk-QPPLO2YV.js";
31
21
  import {
32
- logger
33
- } from "./chunk-Z5B5X7QP.js";
22
+ InMemoryKV,
23
+ InMemoryOrchestrator,
24
+ InMemoryQueue,
25
+ InMemorySessionStore
26
+ } from "./chunk-GDX2ZEBA.js";
34
27
  import {
35
- filterReviewableFiles,
36
- parseUnifiedDiff
37
- } from "./chunk-I5S3NBFL.js";
28
+ ruleHitsToComments,
29
+ scanFileForRuleHits
30
+ } from "./chunk-EQL5OOEF.js";
31
+ import "./chunk-JAF7JIZQ.js";
38
32
  import {
39
33
  ASYNC_BATCH_POLL_DELAY_SECONDS,
40
34
  BIN_DIFF_CHAR_BUDGET,
@@ -57,6 +51,12 @@ import {
57
51
  REVIEW_CHUNK_WALL_CLOCK_MS,
58
52
  VERIFY_MIN_ANSWER_RATIO
59
53
  } from "./chunk-W3RY755V.js";
54
+ import "./chunk-IKVUW4WC.js";
55
+ import "./chunk-XPYVLHSX.js";
56
+ import "./chunk-QPPLO2YV.js";
57
+ import {
58
+ logger
59
+ } from "./chunk-Z5B5X7QP.js";
60
60
 
61
61
  // src/review/index.ts
62
62
  import "@codraoss/schema/webhook";
@@ -222,8 +222,6 @@ var NextPhaseError = class extends Error {
222
222
  this.phase = phase;
223
223
  this.delaySeconds = delaySeconds;
224
224
  }
225
- phase;
226
- delaySeconds;
227
225
  };
228
226
  async function enqueueJobPhase(env, jobId, phase, delaySeconds = 0) {
229
227
  await env.jobs.markJobContinuationQueued(jobId, delaySeconds);