@mrkaran/hodor 0.5.0 → 0.6.1

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 +0,0 @@
1
- {"version":3,"sources":["../src/utils/logger.ts","../src/prompt.ts","../src/utils/exec.ts","../src/gitlab.ts","../src/model.ts","../src/metrics.ts","../src/review.ts","../src/agent.ts","../src/github.ts","../src/workspace.ts","../src/system-prompt.ts","../src/render.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nlet currentLevel: LogLevel = \"warn\";\n\nconst LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LEVELS[level] >= LEVELS[currentLevel];\n}\n\nfunction timestamp(): string {\n return new Date().toISOString();\n}\n\nexport const logger = {\n debug(msg: string): void {\n if (shouldLog(\"debug\")) {\n process.stderr.write(`${chalk.gray(timestamp())} ${chalk.gray(\"DEBUG\")} ${msg}\\n`);\n }\n },\n info(msg: string): void {\n if (shouldLog(\"info\")) {\n process.stderr.write(`${chalk.gray(timestamp())} ${chalk.blue(\"INFO\")} ${msg}\\n`);\n }\n },\n warn(msg: string): void {\n if (shouldLog(\"warn\")) {\n process.stderr.write(`${chalk.gray(timestamp())} ${chalk.yellow(\"WARN\")} ${msg}\\n`);\n }\n },\n error(msg: string): void {\n if (shouldLog(\"error\")) {\n process.stderr.write(`${chalk.gray(timestamp())} ${chalk.red(\"ERROR\")} ${msg}\\n`);\n }\n },\n};\n","import { readFileSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"./utils/logger.js\";\nimport { summarizeGitlabNotes } from \"./gitlab.js\";\nimport type { MrMetadata, Platform } from \"./types.js\";\n\n// Resolve templates directory relative to this file (works in both src/ and dist/)\nfunction getTemplatesDir(): string {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n return resolve(currentDir, \"..\", \"templates\");\n}\n\nexport function buildPrReviewPrompt(opts: {\n prUrl: string;\n platform: Platform;\n targetBranch?: string;\n diffBaseSha?: string | null;\n mrMetadata?: MrMetadata | null;\n customInstructions?: string | null;\n customPromptFile?: string | null;\n embeddedDiff?: string | null;\n previousReviewSha?: string | null;\n localMode?: boolean;\n}): string {\n const {\n prUrl,\n platform,\n targetBranch = \"main\",\n diffBaseSha,\n mrMetadata,\n customInstructions,\n customPromptFile,\n embeddedDiff,\n previousReviewSha,\n localMode = false,\n } = opts;\n\n // Step 1: Determine template (always tool submission; rendered to markdown post-hoc)\n let templateFile: string;\n if (customPromptFile) {\n templateFile = customPromptFile;\n logger.info(`Using custom prompt file: ${templateFile}`);\n } else {\n templateFile = resolve(getTemplatesDir(), \"tool-review.md\");\n logger.info(\"Using tool-based review template\");\n }\n\n // Step 2: Load template\n let templateText: string;\n try {\n templateText = readFileSync(templateFile, \"utf-8\");\n } catch (err) {\n throw new Error(`Failed to load prompt template from ${templateFile}: ${err}`);\n }\n\n // Validate ref inputs to prevent shell injection via branch/SHA names.\n // Block shell metacharacters while allowing valid git ref chars (@, +, ~, ^, etc.)\n const dangerousChars = /[;\\|`$&<>(){}\\n\\r\\0\\\\!]/;\n if (dangerousChars.test(targetBranch)) {\n throw new Error(`Invalid target branch name: ${targetBranch}`);\n }\n if (diffBaseSha && dangerousChars.test(diffBaseSha)) {\n throw new Error(`Invalid diff base SHA: ${diffBaseSha}`);\n }\n if (previousReviewSha && !/^[a-f0-9]{40}$/.test(previousReviewSha)) {\n throw new Error(`Invalid previous review SHA: ${previousReviewSha}`);\n }\n\n // Prepare platform-specific commands\n let prDiffCmd: string;\n let gitDiffCmd: string;\n\n // Incremental mode: three-dot diff from previous review SHA (excludes upstream changes)\n if (previousReviewSha) {\n prDiffCmd = `git --no-pager diff ${previousReviewSha}...HEAD --name-only`;\n gitDiffCmd = `git --no-pager diff ${previousReviewSha}...HEAD`;\n logger.info(`Incremental review: diffing from ${previousReviewSha.slice(0, 8)} to HEAD`);\n } else if (localMode) {\n // Plain two-arg diff includes uncommitted (staged + unstaged) changes\n prDiffCmd = `git --no-pager diff ${targetBranch} --name-only`;\n gitDiffCmd = `git --no-pager diff ${targetBranch}`;\n } else if (platform === \"github\") {\n prDiffCmd = `git --no-pager diff origin/${targetBranch}...HEAD --name-only`;\n gitDiffCmd = `git --no-pager diff origin/${targetBranch}...HEAD`;\n } else {\n // gitlab\n if (diffBaseSha) {\n prDiffCmd = `git --no-pager diff ${diffBaseSha} HEAD --name-only`;\n gitDiffCmd = `git --no-pager diff ${diffBaseSha} HEAD`;\n logger.info(`Using GitLab CI_MERGE_REQUEST_DIFF_BASE_SHA: ${diffBaseSha.slice(0, 8)}`);\n } else {\n prDiffCmd = `git --no-pager diff origin/${targetBranch}...HEAD --name-only`;\n gitDiffCmd = `git --no-pager diff origin/${targetBranch}...HEAD`;\n }\n }\n\n // Diff explanation\n let diffExplanation: string;\n if (previousReviewSha) {\n diffExplanation =\n `**Incremental mode**: Showing only changes since the last hodor review ` +\n `(commit \\`${previousReviewSha.slice(0, 8)}\\`).`;\n } else if (diffBaseSha) {\n diffExplanation =\n `**GitLab CI Advantage**: This uses GitLab's pre-calculated merge base SHA ` +\n `(\\`CI_MERGE_REQUEST_DIFF_BASE_SHA\\`), which matches exactly what the GitLab UI shows. ` +\n `This is more reliable than three-dot syntax because it handles force pushes, rebases, ` +\n `and messy histories correctly.`;\n } else {\n diffExplanation =\n `**Three-dot syntax** shows ONLY changes introduced on the source branch, ` +\n `excluding changes already on \\`${targetBranch}\\`.`;\n }\n\n // Step 3: Build MR sections\n const { contextSection, notesSection, reminderSection } = buildMrSections(mrMetadata);\n\n // Step 3b: Build incremental review section\n let incrementalSection = \"\";\n if (previousReviewSha) {\n incrementalSection =\n \"## Incremental Review Mode\\n\\n\" +\n `This is a follow-up review. A previous hodor review was done at commit \\`${previousReviewSha.slice(0, 8)}\\`. ` +\n \"The diff below shows ONLY changes since that review. Focus on:\\n\" +\n \"1. New code changes introduced since the last review\\n\" +\n \"2. Whether previous findings (shown in MR notes above) are still applicable\\n\" +\n \"3. Do NOT re-report issues that are already mentioned in existing notes\\n\\n\";\n }\n\n // Step 3c: Build conditional sections based on whether diff is embedded\n let embeddedDiffSection: string;\n let diffFetchInstructions: string;\n let reviewProcessSection: string;\n let startInstruction: string;\n\n if (embeddedDiff) {\n embeddedDiffSection =\n \"## Full Diff (Pre-fetched)\\n\\n\" +\n \"The complete diff for this PR is provided below. Analyze it directly. \" +\n \"Use `read` or `grep` only if you need additional file context beyond what the diff shows.\\n\\n\" +\n \"````diff\\n\" + embeddedDiff + \"\\n````\\n\";\n\n diffFetchInstructions =\n \"## Review the Diff Above\\n\\n\" +\n \"### Critical Rules\\n\" +\n \"- ONLY review files that appear in the diff above\\n\" +\n \"- ONLY analyze actual code changes (+ and - lines in the diff)\\n\" +\n \"- NEVER review files not in the diff\\n\" +\n \"- NEVER flag \\\"files will be deleted when merging\\\" (outdated branch)\\n\" +\n \"- NEVER flag \\\"dependency version downgrade\\\" (branch not rebased)\\n\" +\n `- NEVER compare entire codebase to ${targetBranch} - DIFF ONLY\\n`;\n\n reviewProcessSection =\n \"## Review Process\\n\\n\" +\n \"1. Analyze the embedded diff above thoroughly\\n\" +\n \"2. Use `grep` to search for patterns if needed\\n\" +\n \"3. Use `read` only when surrounding context is essential\\n\" +\n \"4. Submit your review using `submit_review`\\n\";\n\n startInstruction = \"Analyze the diff provided above, then submit your review using `submit_review`.\";\n } else {\n embeddedDiffSection = \"\";\n\n diffFetchInstructions =\n \"## Step 1: List Changed Files (MANDATORY FIRST STEP)\\n\\n\" +\n \"**Run this command FIRST to get the list of changed files:**\\n\" +\n \"```bash\\n\" + prDiffCmd + \"\\n```\\n\\n\" +\n \"This lists ONLY the filenames changed in this PR. **Do NOT dump the entire diff here** - \" +\n \"you'll inspect each file individually in Step 2. Only review files that appear in this output.\\n\\n\" +\n \"## Step 2: Review Changed Files Only\\n\\n\" +\n \"### Critical Rules\\n\" +\n \"- ONLY review files that appear in the diff from Step 1\\n\" +\n \"- ONLY analyze actual code changes (+ and - lines in the diff)\\n\" +\n \"- Use the most reliable diff command: `\" + gitDiffCmd + \"`\\n\" +\n \"- NEVER review files not in the diff\\n\" +\n \"- NEVER flag \\\"files will be deleted when merging\\\" (outdated branch)\\n\" +\n \"- NEVER flag \\\"dependency version downgrade\\\" (branch not rebased)\\n\" +\n `- NEVER compare entire codebase to ${targetBranch} - DIFF ONLY\\n\\n` +\n \"### Git Diff Command\\n\\n\" +\n \"**Most reliable command to see changes:**\\n\" +\n \"```bash\\n\" + gitDiffCmd + \"\\n```\\n\\n\" +\n diffExplanation;\n\n reviewProcessSection =\n \"## Review Process\\n\\n\" +\n \"**Efficient Sequential Workflow:**\\n\\n\" +\n `1. **List files first**: Run \\`${prDiffCmd}\\` to get the list of changed files (NOT full diff)\\n` +\n `2. **Per-file analysis**: For each file, run \\`${gitDiffCmd} -- path/to/file\\` to see its specific changes\\n` +\n \"3. **Batch pattern search**: Use `grep` across multiple files to find common bug patterns (null, undefined, TODO, FIXME, etc.)\\n\" +\n \"4. **Selective deep dive**: Only use `read` to read full file context when the diff alone is insufficient\\n\" +\n \"5. **Group related files**: Analyze related files together (e.g., implementation + tests, interfaces + implementations)\\n\" +\n \"6. **Avoid redundancy**: Don't re-read files unnecessarily; make decisions based on diff context\\n\";\n\n startInstruction =\n `Start by running \\`${prDiffCmd}\\` to list the changed files, then analyze each file individually using \\`${gitDiffCmd} -- path/to/file\\`.`;\n }\n\n // Step 4: Interpolate\n let prompt = templateText\n .replace(/\\{pr_url\\}/g, prUrl)\n .replace(/\\{pr_diff_cmd\\}/g, prDiffCmd)\n .replace(/\\{git_diff_cmd\\}/g, gitDiffCmd)\n .replace(/\\{target_branch\\}/g, targetBranch)\n .replace(/\\{diff_explanation\\}/g, diffExplanation)\n .replace(/\\{mr_context_section\\}/g, contextSection)\n .replace(/\\{mr_notes_section\\}/g, notesSection)\n .replace(/\\{mr_reminder_section\\}/g, reminderSection)\n .replace(/\\{incremental_section\\}/g, incrementalSection)\n .replace(/\\{embedded_diff_section\\}/g, embeddedDiffSection)\n .replace(/\\{diff_fetch_instructions\\}/g, diffFetchInstructions)\n .replace(/\\{review_process_section\\}/g, reviewProcessSection)\n .replace(/\\{start_instruction\\}/g, startInstruction);\n\n // Step 5: Append custom instructions\n if (customInstructions) {\n prompt += `\\n\\n## Additional Instructions\\n\\n${customInstructions}\\n`;\n logger.info(\"Appended custom instructions to prompt\");\n }\n\n return prompt;\n}\n\nexport function buildMrSections(mrMetadata?: MrMetadata | null): {\n contextSection: string;\n notesSection: string;\n reminderSection: string;\n} {\n if (!mrMetadata) {\n return { contextSection: \"\", notesSection: \"\", reminderSection: \"\" };\n }\n\n const contextLines: string[] = [];\n\n if (mrMetadata.title) {\n contextLines.push(`- Title: ${mrMetadata.title}`);\n }\n\n const author =\n mrMetadata.author?.username ?? mrMetadata.author?.name;\n if (author) {\n contextLines.push(`- Author: @${author}`);\n }\n\n if (mrMetadata.source_branch && mrMetadata.target_branch) {\n contextLines.push(\n `- Branches: ${mrMetadata.source_branch} → ${mrMetadata.target_branch}`,\n );\n }\n\n if (mrMetadata.changes_count) {\n contextLines.push(`- Files changed: ${mrMetadata.changes_count}`);\n }\n\n const pipelineStatus = mrMetadata.pipeline?.status;\n const pipelineUrl = mrMetadata.pipeline?.web_url;\n if (pipelineStatus) {\n const statusText = pipelineStatus.replace(/_/g, \" \");\n contextLines.push(\n pipelineUrl\n ? `- Pipeline: ${statusText} (${pipelineUrl})`\n : `- Pipeline: ${statusText}`,\n );\n }\n\n let labelNames = normalizeLabelNames(mrMetadata.label_details);\n if (labelNames.length === 0) {\n labelNames = normalizeLabelNames(mrMetadata.labels);\n }\n if (labelNames.length > 0) {\n contextLines.push(`- Labels: ${labelNames.join(\", \")}`);\n }\n\n const description = (mrMetadata.description ?? \"\").trim();\n let descriptionSection = \"\";\n if (description) {\n descriptionSection =\n \"**Author Description:**\\n\" + truncateBlock(description, 800);\n }\n\n let contextSection = \"\";\n if (contextLines.length > 0 || descriptionSection) {\n contextSection = \"## MR Context\\n\" + contextLines.join(\"\\n\");\n if (descriptionSection) {\n contextSection += \"\\n\\n\" + descriptionSection;\n }\n contextSection += \"\\n\";\n }\n\n let notesSection = \"\";\n const notesSummary = summarizeGitlabNotes(mrMetadata.Notes);\n if (notesSummary) {\n notesSection = `## Existing MR Notes\\n${notesSummary}\\n`;\n }\n\n let reminderSection = \"\";\n if (notesSummary) {\n reminderSection =\n \"## Review Note Deduplication\\n\\n\" +\n \"The discussions above may already cover some issues. Before reporting a finding:\\n\" +\n \"1. Check if it's already mentioned in existing notes\\n\" +\n \"2. Only report if your finding is materially different or more specific\\n\" +\n \"3. If an existing note is incorrect/outdated, explain why in your finding\\n\\n\" +\n \"Focus on discovering NEW issues not yet discussed.\\n\";\n }\n\n return { contextSection, notesSection, reminderSection };\n}\n\nfunction truncateBlock(text: string, limit: number): string {\n const trimmed = text.trim();\n if (trimmed.length <= limit) return trimmed;\n return trimmed.slice(0, limit - 1).trimEnd() + \"…\";\n}\n\nexport function normalizeLabelNames(\n rawLabels: unknown,\n): string[] {\n if (!rawLabels) return [];\n\n const names: string[] = [];\n\n function addLabel(value: unknown): void {\n let name = \"\";\n if (typeof value === \"string\") {\n name = value.trim();\n } else if (typeof value === \"object\" && value !== null) {\n const labelValue = (value as Record<string, unknown>).name;\n if (typeof labelValue === \"string\") {\n name = labelValue.trim();\n }\n } else if (value != null) {\n name = String(value).trim();\n }\n if (name) names.push(name);\n }\n\n if (Array.isArray(rawLabels)) {\n for (const label of rawLabels) addLabel(label);\n } else {\n addLabel(rawLabels);\n }\n\n return names;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n}\n\nexport async function exec(\n cmd: string,\n args: string[],\n opts?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n const { stdout, stderr } = await execFileAsync(cmd, args, {\n cwd: opts?.cwd,\n env: opts?.env ?? process.env,\n maxBuffer: 50 * 1024 * 1024, // 50MB\n });\n return { stdout, stderr };\n}\n\nexport async function execJson<T = Record<string, unknown>>(\n cmd: string,\n args: string[],\n opts?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<T> {\n const { stdout } = await exec(cmd, args, opts);\n return JSON.parse(stdout.trim()) as T;\n}\n","import { exec, execJson } from \"./utils/exec.js\";\nimport { logger } from \"./utils/logger.js\";\nimport type { MrMetadata, NoteEntry } from \"./types.js\";\n\nconst DEFAULT_GITLAB_HOST = \"gitlab.com\";\n\n/**\n * Parse concatenated JSON arrays from `glab api --paginate`.\n * glab outputs `[...][...][...]` — one array per page, no delimiter.\n * We track bracket depth (respecting strings/escapes) to find each\n * top-level array, parse them individually, and merge with flat().\n */\nexport function parseGlabPaginatedJson(raw: string): Array<Record<string, unknown>> {\n const trimmed = raw.trim();\n if (!trimmed) return [];\n\n const chunks: string[] = [];\n let depth = 0;\n let inString = false;\n let escaped = false;\n let start = -1;\n\n for (let i = 0; i < trimmed.length; i++) {\n const ch = trimmed[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === \"\\\\\" && inString) {\n escaped = true;\n continue;\n }\n if (ch === '\"') {\n inString = !inString;\n continue;\n }\n if (inString) continue;\n\n if (ch === \"[\") {\n if (depth === 0) start = i;\n depth++;\n } else if (ch === \"]\") {\n depth--;\n if (depth === 0 && start >= 0) {\n chunks.push(trimmed.slice(start, i + 1));\n start = -1;\n }\n }\n }\n\n const results: Array<Record<string, unknown>> = [];\n for (const chunk of chunks) {\n const parsed = JSON.parse(chunk) as Array<Record<string, unknown>>;\n if (Array.isArray(parsed)) {\n results.push(...parsed);\n }\n }\n return results;\n}\n\nexport class GitLabAPIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GitLabAPIError\";\n }\n}\n\nfunction normalizeBaseUrl(host?: string | null): string {\n const candidate =\n host ||\n process.env.GITLAB_HOST ||\n process.env.CI_SERVER_URL ||\n DEFAULT_GITLAB_HOST;\n const trimmed = candidate.trim() || DEFAULT_GITLAB_HOST;\n if (trimmed.startsWith(\"http://\") || trimmed.startsWith(\"https://\")) {\n return trimmed.replace(/\\/+$/, \"\");\n }\n return `https://${trimmed}`.replace(/\\/+$/, \"\");\n}\n\nfunction encodedProjectPath(owner: string, repo: string): string {\n const projectPath = [owner.replace(/^\\/+|\\/+$/g, \"\"), repo.replace(/^\\/+|\\/+$/g, \"\")]\n .filter(Boolean)\n .join(\"/\");\n return encodeURIComponent(projectPath);\n}\n\nfunction glabEnv(host?: string | null): NodeJS.ProcessEnv {\n const env = { ...process.env };\n // Ensure glab knows which host to talk to\n const baseUrl = normalizeBaseUrl(host);\n const hostname = baseUrl.replace(/^https?:\\/\\//, \"\");\n env.GITLAB_HOST = hostname;\n return env;\n}\n\n/**\n * Fetch merge request metadata using glab api.\n */\nexport async function fetchGitlabMrInfo(\n owner: string,\n repo: string,\n mrNumber: number | string,\n host?: string | null,\n options?: { includeComments?: boolean },\n): Promise<MrMetadata> {\n const encoded = encodedProjectPath(owner, repo);\n const env = glabEnv(host);\n\n let mrData: Record<string, unknown>;\n try {\n mrData = await execJson<Record<string, unknown>>(\n \"glab\",\n [\"api\", `projects/${encoded}/merge_requests/${mrNumber}`],\n { env },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new GitLabAPIError(`Failed to fetch MR !${mrNumber}: ${msg}`);\n }\n\n const metadata: MrMetadata = {\n title: mrData.title as string | undefined,\n description: (mrData.description as string) ?? \"\",\n source_branch: mrData.source_branch as string | undefined,\n target_branch: mrData.target_branch as string | undefined,\n changes_count: mrData.changes_count as number | undefined,\n labels: mrData.labels as string[] | undefined,\n author: mrData.author as { username?: string; name?: string } | undefined,\n pipeline: mrData.pipeline as { status?: string; web_url?: string } | undefined,\n state: mrData.state as string | undefined,\n };\n\n if (options?.includeComments) {\n try {\n // glab --paginate concatenates JSON arrays across pages (e.g., `[...][...]`).\n // Parse each top-level array separately and merge, avoiding regex on raw JSON\n // which could corrupt string values containing `][`.\n const { stdout: rawNotes } = await exec(\n \"glab\",\n [\"api\", `projects/${encoded}/merge_requests/${mrNumber}/notes`, \"--paginate\"],\n { env },\n );\n const notes = parseGlabPaginatedJson(rawNotes);\n metadata.Notes = notes.map((n) => ({\n body: (n.body as string) ?? \"\",\n author: n.author as { username?: string; name?: string } | undefined,\n created_at: n.created_at as string | undefined,\n system: n.system as boolean | undefined,\n }));\n } catch (err) {\n logger.warn(`Failed to fetch MR notes: ${err instanceof Error ? err.message : err}`);\n }\n }\n\n return metadata;\n}\n\n/**\n * Post a comment on a GitLab merge request using glab api.\n */\nexport async function postGitlabMrComment(\n owner: string,\n repo: string,\n mrNumber: number | string,\n body: string,\n host?: string | null,\n): Promise<void> {\n const encoded = encodedProjectPath(owner, repo);\n const env = glabEnv(host);\n\n try {\n await exec(\n \"glab\",\n [\n \"api\",\n `projects/${encoded}/merge_requests/${mrNumber}/notes`,\n \"--method\",\n \"POST\",\n \"--field\",\n `body=${body}`,\n ],\n { env },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new GitLabAPIError(`Failed to post comment to MR !${mrNumber}: ${msg}`);\n }\n}\n\n/**\n * Summarize GitLab notes into a human-readable bullet list.\n */\nexport function summarizeGitlabNotes(\n notes: NoteEntry[] | undefined | null,\n maxEntries = 5,\n): string {\n if (!notes || notes.length === 0) return \"\";\n\n const trivialPatterns = new Set([\n \"lgtm\",\n \"+1\",\n \"-1\",\n \"👍\",\n \"👎\",\n \"thanks\",\n \"thank you\",\n \"looks good\",\n \"approved\",\n \"🚀\",\n \"✅\",\n \"❌\",\n ]);\n\n const filtered: Array<{ username: string; body: string; createdAt: string }> = [];\n for (const note of notes) {\n const body = (note.body ?? \"\").trim();\n if (!body) continue;\n if (note.system) continue;\n if (body.length < 20) continue;\n\n const bodyLower = body.toLowerCase();\n let isTrivial = false;\n for (const pattern of trivialPatterns) {\n if (bodyLower.includes(pattern) && body.length < 50) {\n isTrivial = true;\n break;\n }\n }\n if (isTrivial) continue;\n\n const username =\n note.author?.username ?? note.author?.name ?? \"unknown\";\n filtered.push({ username, body, createdAt: note.created_at ?? \"\" });\n }\n\n // Sort oldest first\n filtered.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\n // Take most recent\n const recent = filtered.slice(-maxEntries);\n\n const lines: string[] = [];\n for (const { username, body, createdAt } of recent) {\n let timestampStr = \"\";\n if (createdAt) {\n try {\n const dt = new Date(createdAt);\n timestampStr = dt.toISOString().replace(\"T\", \" \").slice(0, 16);\n } catch {\n timestampStr = createdAt.slice(0, 10);\n }\n }\n\n const header = timestampStr\n ? `- ${timestampStr} @${username}:`\n : `- @${username}:`;\n const indentedBody = body.split(\"\\n\").join(\"\\n \");\n lines.push(`${header}\\n ${indentedBody}`);\n }\n\n return lines.join(\"\\n\");\n}\n","export interface ParsedModel {\n provider: string;\n modelId: string;\n}\n\n/**\n * Parse a model string like \"anthropic/claude-sonnet-4-5\" into { provider, modelId }.\n * Handles bare names like \"claude-sonnet-4-5\" or \"gpt-5\" via auto-detection.\n */\nexport function parseModelString(model: string): ParsedModel {\n const trimmed = model.trim();\n if (!trimmed) throw new Error(\"Model name must be provided\");\n\n const parts = trimmed.split(\"/\");\n\n // Explicit provider prefix\n if (parts.length >= 2) {\n const first = parts[0].toLowerCase();\n if (first === \"bedrock\") {\n // Map \"bedrock\" → \"amazon-bedrock\" (pi-ai SDK convention)\n // Strip optional \"converse/\" prefix from model ID\n let modelId = parts.slice(1).join(\"/\");\n if (modelId.startsWith(\"converse/\")) {\n modelId = modelId.slice(\"converse/\".length);\n }\n return { provider: \"amazon-bedrock\", modelId };\n }\n if ([\"anthropic\", \"openai\"].includes(first)) {\n return { provider: first, modelId: parts.slice(1).join(\"/\") };\n }\n }\n\n // Auto-detect provider from bare model name\n const lower = trimmed.toLowerCase();\n if (lower.includes(\"claude\") || lower.includes(\"anthropic\")) {\n return { provider: \"anthropic\", modelId: trimmed };\n }\n if (\n lower.startsWith(\"gpt\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"openai\")\n ) {\n return { provider: \"openai\", modelId: trimmed };\n }\n\n // Default to anthropic for unknown models\n return { provider: \"anthropic\", modelId: trimmed };\n}\n\n/**\n * Map reasoning effort strings to pi-ai thinking levels.\n * Returns undefined for no reasoning.\n */\nexport function mapReasoningEffort(\n effort: string | undefined,\n): \"low\" | \"medium\" | \"high\" | undefined {\n if (!effort) return undefined;\n switch (effort.toLowerCase()) {\n case \"low\":\n return \"low\";\n case \"medium\":\n return \"medium\";\n case \"high\":\n case \"xhigh\":\n return \"high\";\n default:\n return undefined;\n }\n}\n\n/**\n * Get API key with provider-aware selection.\n *\n * Priority:\n * 1. LLM_API_KEY (universal override)\n * 2. Provider-specific key (ANTHROPIC_API_KEY, OPENAI_API_KEY)\n * 3. Fallback to any available key\n *\n * Returns null for bedrock (uses AWS credentials).\n */\nexport function getApiKey(model?: string): string | null {\n // Priority 1: Universal override\n const llmKey = process.env.LLM_API_KEY;\n if (llmKey) return llmKey;\n\n // Priority 2: Provider-specific\n if (model) {\n const { provider } = parseModelString(model);\n if (provider === \"amazon-bedrock\") return null;\n if (provider === \"anthropic\") {\n const key = process.env.ANTHROPIC_API_KEY;\n if (key) return key;\n }\n if (provider === \"openai\") {\n const key = process.env.OPENAI_API_KEY;\n if (key) return key;\n }\n }\n\n // Priority 3: Fallback\n if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY;\n if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY;\n\n throw new Error(\n \"No LLM API key found. Please set one of: LLM_API_KEY, ANTHROPIC_API_KEY, or OPENAI_API_KEY\",\n );\n}\n","import chalk from \"chalk\";\nimport { logger } from \"./utils/logger.js\";\nimport type { ReviewMetrics } from \"./types.js\";\n\nfunction tok(value: number): string {\n if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(2)}M`;\n if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;\n return String(value);\n}\n\nfunction formatDuration(seconds: number): string {\n if (seconds >= 60) {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return s > 0 ? `${m}m ${s}s` : `${m}m`;\n }\n return `${seconds}s`;\n}\n\nexport function formatMetricsMarkdown(metrics: ReviewMetrics): string {\n const totalInput = metrics.inputTokens + metrics.cacheReadTokens;\n const parts = [`in \\`${tok(totalInput)}\\``];\n if (metrics.cacheReadTokens > 0) {\n parts.push(`cached \\`${tok(metrics.cacheReadTokens)}\\``);\n }\n parts.push(`out \\`${tok(metrics.outputTokens)}\\``);\n\n const lines = [\n `**Review Metrics** — ${metrics.turns} turns, ${metrics.toolCalls} tool calls, ${formatDuration(metrics.durationSeconds)}`,\n `- Tokens: ${parts.join(\" | \")} (total \\`${tok(metrics.totalTokens)}\\`)`,\n ];\n if (metrics.cost > 0) {\n lines.push(`- Cost: \\`$${metrics.cost.toFixed(4)}\\``);\n }\n return lines.join(\"\\n\");\n}\n\nexport function printMetrics(metrics: ReviewMetrics, stream: NodeJS.WritableStream = process.stderr): void {\n const dim = chalk.dim;\n const bold = chalk.bold;\n const cyan = chalk.cyan;\n\n const write = (line: string) => stream.write(line + \"\\n\");\n\n write(\"\");\n write(dim(\"─\".repeat(50)));\n\n // Tokens — inputTokens may be only fresh tokens (SDK reports cache hits separately)\n const totalInput = metrics.inputTokens + metrics.cacheReadTokens;\n let tokenLine = `${dim(\"Tokens:\")} ${bold(tok(totalInput))} in`;\n if (metrics.cacheReadTokens > 0) {\n const hitPct = ((metrics.cacheReadTokens / totalInput) * 100).toFixed(0);\n tokenLine += dim(` (${tok(metrics.cacheReadTokens)} cached ${hitPct}% · ${tok(metrics.inputTokens)} fresh)`);\n }\n tokenLine += ` ${bold(tok(metrics.outputTokens))} out`;\n tokenLine += dim(` (${tok(metrics.totalTokens)} total)`);\n write(tokenLine);\n\n // Agent work\n write(\n `${dim(\"Agent:\")} ${bold(String(metrics.turns))} turns ${bold(String(metrics.toolCalls))} tool calls ${cyan(formatDuration(metrics.durationSeconds))}`,\n );\n\n // Cost\n if (metrics.cost > 0) {\n write(`${dim(\"Cost:\")} ${bold(\"$\" + metrics.cost.toFixed(4))}`);\n }\n\n write(dim(\"─\".repeat(50)));\n}\n\n/**\n * Push review metrics to a Prometheus Pushgateway.\n * Failures are logged as warnings and never thrown.\n */\nexport async function pushMetrics(opts: {\n pushgatewayUrl: string;\n metrics: ReviewMetrics;\n labels?: Record<string, string>;\n}): Promise<void> {\n const { pushgatewayUrl, metrics, labels = {} } = opts;\n\n // Build label string for all metrics\n const labelPairs = Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`)\n .join(\",\");\n const labelSuffix = labelPairs ? `{${labelPairs}}` : \"\";\n\n const totalInput = metrics.inputTokens + metrics.cacheReadTokens;\n const lines = [\n `# HELP hodor_review_input_tokens_total Total input tokens (fresh + cached)`,\n `# TYPE hodor_review_input_tokens_total gauge`,\n `hodor_review_input_tokens_total${labelSuffix} ${totalInput}`,\n `# HELP hodor_review_output_tokens_total Total output tokens`,\n `# TYPE hodor_review_output_tokens_total gauge`,\n `hodor_review_output_tokens_total${labelSuffix} ${metrics.outputTokens}`,\n `# HELP hodor_review_cache_read_tokens_total Tokens served from prompt cache`,\n `# TYPE hodor_review_cache_read_tokens_total gauge`,\n `hodor_review_cache_read_tokens_total${labelSuffix} ${metrics.cacheReadTokens}`,\n `# HELP hodor_review_cost_dollars Cost of the review in USD`,\n `# TYPE hodor_review_cost_dollars gauge`,\n `hodor_review_cost_dollars${labelSuffix} ${metrics.cost}`,\n `# HELP hodor_review_turns_total Number of agent turns`,\n `# TYPE hodor_review_turns_total gauge`,\n `hodor_review_turns_total${labelSuffix} ${metrics.turns}`,\n `# HELP hodor_review_tool_calls_total Number of tool calls`,\n `# TYPE hodor_review_tool_calls_total gauge`,\n `hodor_review_tool_calls_total${labelSuffix} ${metrics.toolCalls}`,\n `# HELP hodor_review_duration_seconds Review duration in seconds`,\n `# TYPE hodor_review_duration_seconds gauge`,\n `hodor_review_duration_seconds${labelSuffix} ${metrics.durationSeconds}`,\n \"\",\n ];\n const body = lines.join(\"\\n\");\n\n // POST to pushgateway: /metrics/job/<job>\n const baseUrl = pushgatewayUrl.replace(/\\/+$/, \"\");\n const url = `${baseUrl}/metrics/job/hodor`;\n\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"text/plain\" },\n body,\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n logger.warn(`Pushgateway returned ${res.status}: ${text.slice(0, 200)}`);\n } else {\n logger.info(\"Metrics pushed to Pushgateway\");\n }\n } catch (err) {\n logger.warn(`Failed to push metrics to Pushgateway: ${err instanceof Error ? err.message : err}`);\n }\n}\n","import { isAbsolute } from \"node:path\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { ReviewOutput, ReviewPriority } from \"./types.js\";\n\nconst REVIEW_PRIORITY_TAGS = new Map<string, ReviewPriority>([\n [\"[P0]\", 0],\n [\"[P1]\", 1],\n [\"[P2]\", 2],\n [\"[P3]\", 3],\n]);\n\nexport const REVIEW_LOCATION_SCHEMA = Type.Object(\n {\n absolute_file_path: Type.String({ minLength: 1 }),\n line_range: Type.Object(\n {\n start: Type.Integer({ minimum: 1 }),\n end: Type.Integer({ minimum: 1 }),\n },\n { additionalProperties: false },\n ),\n },\n { additionalProperties: false },\n);\n\nexport const REVIEW_FINDING_SCHEMA = Type.Object(\n {\n title: Type.String({ minLength: 1 }),\n body: Type.String({ minLength: 1 }),\n priority: Type.Integer({ minimum: 0, maximum: 3 }),\n code_location: REVIEW_LOCATION_SCHEMA,\n },\n { additionalProperties: false },\n);\n\nexport const SUBMIT_REVIEW_SCHEMA = Type.Object(\n {\n findings: Type.Array(REVIEW_FINDING_SCHEMA),\n overall_correctness: Type.Union([\n Type.Literal(\"patch is correct\"),\n Type.Literal(\"patch is incorrect\"),\n ]),\n overall_explanation: Type.String({ minLength: 1 }),\n },\n { additionalProperties: false },\n);\n\nexport function validateReviewOutput(review: ReviewOutput): ReviewOutput {\n if (review.overall_explanation.trim().length === 0) {\n throw new Error(\"submit_review overall_explanation must be non-empty\");\n }\n\n for (const [index, finding] of review.findings.entries()) {\n const label = `submit_review finding ${index + 1}`;\n if (finding.title.trim().length === 0) {\n throw new Error(`${label} title must be non-empty`);\n }\n if (finding.body.trim().length === 0) {\n throw new Error(`${label} body must be non-empty`);\n }\n\n const taggedPriority = getPriorityFromTitle(finding.title);\n if (taggedPriority == null) {\n throw new Error(`${label} title must start with [P0], [P1], [P2], or [P3]`);\n }\n if (finding.priority !== taggedPriority) {\n throw new Error(\n `${label} priority ${finding.priority} does not match title tag ${taggedPriority}`,\n );\n }\n\n const { absolute_file_path: filePath, line_range: lineRange } = finding.code_location;\n if (!isAbsolute(filePath)) {\n throw new Error(`${label} code_location.absolute_file_path must be absolute`);\n }\n if (lineRange.start > lineRange.end) {\n throw new Error(`${label} code_location line_range start must be <= end`);\n }\n }\n\n return review;\n}\n\nfunction getPriorityFromTitle(title: string): ReviewPriority | null {\n const match = title.match(/^\\[(P[0-3])\\]/);\n if (!match) return null;\n return REVIEW_PRIORITY_TAGS.get(`[${match[1]}]`) ?? null;\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ToolDefinition } from \"@mariozechner/pi-coding-agent\";\nimport { logger } from \"./utils/logger.js\";\nimport { exec } from \"./utils/exec.js\";\nimport {\n fetchGithubPrInfo,\n normalizeGithubMetadata,\n} from \"./github.js\";\nimport {\n fetchGitlabMrInfo,\n postGitlabMrComment,\n} from \"./gitlab.js\";\nimport { setupWorkspace, cleanupWorkspace } from \"./workspace.js\";\nimport { buildPrReviewPrompt } from \"./prompt.js\";\nimport { parseModelString, mapReasoningEffort, getApiKey } from \"./model.js\";\nimport { formatMetricsMarkdown, printMetrics } from \"./metrics.js\";\nimport { SUBMIT_REVIEW_SCHEMA, validateReviewOutput } from \"./review.js\";\nimport { REVIEW_SYSTEM_PROMPT } from \"./system-prompt.js\";\nimport type {\n Platform,\n ParsedPrUrl,\n ReviewMetrics,\n PostCommentResult,\n MrMetadata,\n ReviewOutput,\n} from \"./types.js\";\n\nexport interface AgentProgressEvent {\n type: \"tool_start\" | \"tool_end\" | \"thinking\" | \"turn_start\" | \"turn_end\" | \"agent_start\" | \"agent_end\" | \"text_delta\" | \"thinking_delta\" | \"tool_result\";\n toolName?: string;\n toolArgs?: string;\n isError?: boolean;\n turnIndex?: number;\n delta?: string;\n result?: string;\n}\n\nexport function detectPlatform(prUrl: string): Platform {\n const url = new URL(prUrl);\n const hostname = url.hostname;\n if (prUrl.includes(\"/-/merge_requests/\") || hostname.includes(\"gitlab\")) {\n return \"gitlab\";\n }\n if (prUrl.includes(\"/pull/\") || hostname.includes(\"github\")) {\n return \"github\";\n }\n throw new Error(\n `Cannot detect platform for URL: ${prUrl}. Expected a GitHub pull request (/pull/) or GitLab merge request (/-/merge_requests/) URL.`,\n );\n}\n\nexport function parsePrUrl(prUrl: string): ParsedPrUrl {\n const url = new URL(prUrl);\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n const host = url.host;\n\n // GitHub format: /owner/repo/pull/123\n if (pathParts.length >= 4 && pathParts[2] === \"pull\") {\n const prNumber = parseInt(pathParts[3], 10);\n if (!Number.isSafeInteger(prNumber) || prNumber <= 0) {\n throw new Error(`Invalid PR number in URL: ${prUrl}. Expected a positive integer after /pull/.`);\n }\n return {\n owner: pathParts[0],\n repo: pathParts[1],\n prNumber,\n host,\n };\n }\n\n // GitLab format: /group/subgroup/repo/-/merge_requests/123\n const mrIndex = pathParts.indexOf(\"merge_requests\");\n if (mrIndex >= 0) {\n if (mrIndex < 2 || mrIndex + 1 >= pathParts.length) {\n throw new Error(\n `Invalid GitLab MR URL format: ${prUrl}. Expected .../-/merge_requests/<number>`,\n );\n }\n if (pathParts[mrIndex - 1] !== \"-\") {\n throw new Error(\n `Invalid GitLab MR URL format: ${prUrl}. Missing '/-/' segment before merge_requests.`,\n );\n }\n\n const repo = pathParts[mrIndex - 2];\n const ownerParts = pathParts.slice(0, mrIndex - 2);\n const owner =\n ownerParts.length > 0 ? ownerParts.join(\"/\") : pathParts[0];\n const prNumber = parseInt(pathParts[mrIndex + 1], 10);\n if (!Number.isSafeInteger(prNumber) || prNumber <= 0) {\n throw new Error(`Invalid MR number in URL: ${prUrl}. Expected a positive integer after /merge_requests/.`);\n }\n return { owner, repo, prNumber, host };\n }\n\n throw new Error(\n `Invalid PR/MR URL format: ${prUrl}. Expected GitHub pull request or GitLab merge request URL.`,\n );\n}\n\nexport async function postReviewComment(opts: {\n prUrl: string;\n reviewText: string;\n model?: string | null;\n metricsFooter?: string | null;\n headSha?: string | null;\n}): Promise<PostCommentResult> {\n const { prUrl, reviewText, model, metricsFooter, headSha } = opts;\n const platform = detectPlatform(prUrl);\n logger.info(`Posting comment to ${platform} PR/MR: ${prUrl}`);\n\n let parsed: ParsedPrUrl;\n try {\n parsed = parsePrUrl(prUrl);\n } catch (err) {\n return { success: false, error: String(err) };\n }\n\n let body = reviewText;\n if (headSha) {\n body = `<!-- hodor:sha:${headSha} -->\\n${body}`;\n }\n if (model) {\n body = `${body}\\n\\n---\\n\\nReview generated by Hodor (model: \\`${model}\\`)`;\n }\n if (metricsFooter) {\n body = `${body}\\n\\n${metricsFooter}`;\n }\n\n try {\n if (platform === \"github\") {\n await exec(\"gh\", [\n \"pr\",\n \"review\",\n String(parsed.prNumber),\n \"--repo\",\n `${parsed.owner}/${parsed.repo}`,\n \"--comment\",\n \"--body\",\n body,\n ]);\n logger.info(`Successfully posted review to GitHub PR #${parsed.prNumber}`);\n return { success: true, platform: \"github\", prNumber: parsed.prNumber };\n } else {\n await postGitlabMrComment(\n parsed.owner,\n parsed.repo,\n parsed.prNumber,\n body,\n parsed.host,\n );\n logger.info(\n `Successfully posted review to GitLab MR !${parsed.prNumber}`,\n );\n return {\n success: true,\n platform: \"gitlab\",\n mrNumber: parsed.prNumber,\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Failed to post comment: ${msg}`);\n return { success: false, error: msg };\n }\n}\n\nexport async function reviewPr(opts: {\n prUrl?: string;\n model?: string;\n reasoningEffort?: string;\n customPrompt?: string | null;\n promptFile?: string | null;\n cleanup?: boolean;\n workspaceDir?: string | null;\n includeMetricsFooter?: boolean;\n onEvent?: (event: AgentProgressEvent) => void;\n bedrockTags?: Record<string, string> | null;\n localMode?: boolean;\n diffAgainst?: string;\n}): Promise<{ review: ReviewOutput; metricsFooter: string | null; headSha: string | null; metrics: ReviewMetrics }> {\n const {\n prUrl,\n model = \"anthropic/claude-sonnet-4-5-20250929\",\n reasoningEffort,\n customPrompt,\n promptFile,\n cleanup = true,\n workspaceDir,\n includeMetricsFooter = false,\n onEvent,\n bedrockTags,\n localMode = false,\n diffAgainst,\n } = opts;\n\n logger.info(`Starting PR review for: ${localMode ? \"local diff\" : prUrl}`);\n\n let owner = \"\", repo = \"\", host = \"\";\n let prNumber = 0;\n let platform: Platform = \"github\";\n\n if (!localMode && prUrl) {\n const urlParsed = parsePrUrl(prUrl);\n owner = urlParsed.owner;\n repo = urlParsed.repo;\n prNumber = urlParsed.prNumber;\n host = urlParsed.host;\n platform = detectPlatform(prUrl);\n logger.info(`Platform: ${platform}, Repo: ${owner}/${repo}, PR: ${prNumber}, Host: ${host}`);\n }\n\n // --- Preflight: validate model + credentials before any expensive I/O ---\n const parsed = parseModelString(model);\n const thinkingLevel = mapReasoningEffort(reasoningEffort);\n\n // Resolve API key (throws if missing for non-bedrock providers)\n const apiKey = getApiKey(model);\n\n // Note: For bedrock, we don't preflight-check AWS credentials because the\n // SDK resolves them from many sources (env vars, IMDS, ECS task role, IRSA,\n // ~/.aws/credentials, etc.) and we can't reliably detect all of them.\n // If credentials are missing, the SDK will fail with a clear error.\n\n // Snapshot env vars we may mutate, restore in finally block\n const envSnapshot: Record<string, string | undefined> = {\n ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,\n OPENAI_API_KEY: process.env.OPENAI_API_KEY,\n AWS_REGION: process.env.AWS_REGION,\n };\n\n // Set API key in environment for pi-ai early so session creation can use it\n if (apiKey) {\n if (parsed.provider === \"anthropic\") {\n process.env.ANTHROPIC_API_KEY = apiKey;\n } else if (parsed.provider === \"openai\") {\n process.env.OPENAI_API_KEY = apiKey;\n }\n }\n\n // Import pi SDK\n const {\n createAgentSession,\n DefaultResourceLoader,\n SessionManager,\n SettingsManager,\n createReadTool,\n createBashTool,\n createGrepTool,\n createFindTool,\n createLsTool,\n AuthStorage,\n ModelRegistry,\n } = await import(\"@mariozechner/pi-coding-agent\");\n const { getModel } = await import(\"@mariozechner/pi-ai\");\n\n // Create an in-memory auth storage that doesn't load from ~/.pi/auth.json\n // This forces the SDK to use environment variables only\n const authStorage = AuthStorage.inMemory();\n const modelRegistry = new ModelRegistry(authStorage);\n\n // Resolve model — use registry for known models, construct manually for custom ARNs\n let piModel: ReturnType<typeof getModel>;\n if (parsed.modelId.startsWith(\"arn:\")) {\n // Custom bedrock ARN (inference profile, cross-region, etc.)\n // Extract region from ARN: arn:aws:bedrock:<region>:<account>:...\n const arnParts = parsed.modelId.split(\":\");\n const region = arnParts.length >= 4 ? arnParts[3] : \"us-east-1\";\n // Set AWS_REGION so the BedrockRuntimeClient uses the correct endpoint\n if (!process.env.AWS_REGION && !process.env.AWS_DEFAULT_REGION) {\n process.env.AWS_REGION = region;\n }\n piModel = {\n id: parsed.modelId,\n name: parsed.modelId,\n api: \"bedrock-converse-stream\",\n provider: \"amazon-bedrock\",\n baseUrl: `https://bedrock-runtime.${region}.amazonaws.com`,\n reasoning: false,\n input: [\"text\"] as (\"text\" | \"image\")[],\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n contextWindow: 200000,\n maxTokens: 16384,\n } as ReturnType<typeof getModel>;\n logger.info(`Custom bedrock ARN model — region: ${region}`);\n } else {\n try {\n piModel = getModel(parsed.provider as \"anthropic\", parsed.modelId as never);\n } catch (err) {\n throw new Error(\n `Unsupported model \"${model}\": ${err instanceof Error ? err.message : err}`,\n );\n }\n }\n logger.info(\"Preflight OK — model and credentials validated\");\n\n // --- End preflight ---\n\n // Setup workspace\n let workspacePath: string;\n let targetBranch: string;\n let diffBaseSha: string | null = null;\n let isTemporary = false;\n\n if (localMode) {\n // Resolve to git repo root so paths from git diff match tool expectations\n const cwd = workspaceDir ?? process.cwd();\n try {\n const { stdout: toplevel } = await exec(\"git\", [\"rev-parse\", \"--show-toplevel\"], { cwd });\n workspacePath = toplevel.trim();\n } catch {\n workspacePath = cwd; // fallback if not in a git repo\n }\n targetBranch = diffAgainst ?? \"origin/main\";\n logger.info(`Local mode: workspace=${workspacePath}, diffAgainst=${targetBranch}`);\n } else {\n const wsResult = await setupWorkspace({\n platform,\n owner,\n repo,\n prNumber: String(prNumber),\n host,\n workingDir: workspaceDir ?? undefined,\n reuse: workspaceDir != null,\n });\n workspacePath = wsResult.workspace;\n targetBranch = wsResult.targetBranch;\n diffBaseSha = wsResult.diffBaseSha;\n isTemporary = wsResult.isTemporary;\n }\n\n try {\n let mrMetadata: MrMetadata | null = null;\n if (!localMode && platform === \"gitlab\") {\n try {\n mrMetadata = await fetchGitlabMrInfo(owner, repo, prNumber, host, {\n includeComments: true,\n });\n } catch (err) {\n logger.warn(`Failed to fetch GitLab metadata: ${err}`);\n }\n } else if (!localMode && platform === \"github\") {\n try {\n const githubRaw = await fetchGithubPrInfo(owner, repo, prNumber);\n mrMetadata = normalizeGithubMetadata(githubRaw);\n } catch (err) {\n logger.warn(`Failed to fetch GitHub metadata: ${err}`);\n }\n }\n\n // Detect previous hodor review SHA for incremental mode\n let previousReviewSha: string | null = null;\n if (mrMetadata?.Notes) {\n for (const note of mrMetadata.Notes) {\n const match = note.body?.match(/<!-- hodor:sha:([a-f0-9]{40}) -->/);\n if (match) {\n previousReviewSha = match[1]; // take the last (most recent) match\n }\n }\n }\n if (previousReviewSha) {\n try {\n // Verify it's a commit (not a blob/tree) and is an ancestor of HEAD\n const { stdout: objType } = await exec(\"git\", [\"cat-file\", \"-t\", previousReviewSha], { cwd: workspacePath });\n if (objType.trim() !== \"commit\") throw new Error(\"not a commit\");\n await exec(\"git\", [\"merge-base\", \"--is-ancestor\", previousReviewSha, \"HEAD\"], { cwd: workspacePath });\n logger.info(`Incremental mode: previous review at ${previousReviewSha.slice(0, 8)}`);\n } catch {\n logger.info(`Previous review SHA ${previousReviewSha.slice(0, 8)} not valid ancestor of HEAD, doing full review`);\n previousReviewSha = null;\n }\n }\n\n // Get HEAD SHA for embedding in posted comments (skip in local mode — no posting)\n let headSha: string | null = null;\n if (!localMode) {\n const { stdout: headShaRaw } = await exec(\"git\", [\"rev-parse\", \"HEAD\"], { cwd: workspacePath });\n headSha = headShaRaw.trim();\n }\n\n // Pre-fetch diff for embedding in prompt (avoids per-file tool calls)\n const MAX_EMBED_BYTES = 200 * 1024; // 200KB\n let embeddedDiff: string | null = null;\n try {\n const diffArgs = previousReviewSha\n ? [\"--no-pager\", \"diff\", `${previousReviewSha}...HEAD`]\n : diffBaseSha\n ? [\"--no-pager\", \"diff\", diffBaseSha, \"HEAD\"]\n : localMode\n ? [\"--no-pager\", \"diff\", targetBranch] // includes uncommitted changes\n : [\"--no-pager\", \"diff\", `origin/${targetBranch}...HEAD`];\n const { stdout: rawDiff } = await exec(\"git\", diffArgs, { cwd: workspacePath });\n if (Buffer.byteLength(rawDiff, \"utf-8\") <= MAX_EMBED_BYTES) {\n embeddedDiff = rawDiff;\n logger.info(`Embedding diff in prompt (${Buffer.byteLength(rawDiff, \"utf-8\")} bytes)`);\n } else {\n logger.info(`Diff too large to embed (${Buffer.byteLength(rawDiff, \"utf-8\")} bytes), using command mode`);\n }\n } catch (err) {\n logger.warn(`Failed to pre-fetch diff, falling back to command mode: ${err}`);\n }\n\n // Build prompt (always uses JSON template; rendered to markdown post-hoc)\n const prompt = buildPrReviewPrompt({\n prUrl: prUrl ?? `local diff (against ${targetBranch})`,\n platform,\n targetBranch,\n diffBaseSha,\n mrMetadata,\n customInstructions: customPrompt,\n customPromptFile: promptFile,\n embeddedDiff,\n previousReviewSha,\n localMode,\n });\n\n const startTime = Date.now();\n const settingsManager = SettingsManager.inMemory({\n compaction: { enabled: true },\n });\n const skillPaths = [\n join(workspacePath, \".pi\", \"skills\"),\n join(workspacePath, \".hodor\", \"skills\"),\n ].filter((p) => existsSync(p));\n const resourceLoader = new DefaultResourceLoader({\n cwd: workspacePath,\n settingsManager,\n systemPrompt: REVIEW_SYSTEM_PROMPT,\n appendSystemPrompt: \"\",\n noExtensions: true,\n noSkills: true,\n noPromptTemplates: true,\n noThemes: true,\n additionalSkillPaths: skillPaths,\n agentsFilesOverride: () => ({ agentsFiles: [] }),\n });\n await resourceLoader.reload();\n const { skills, diagnostics: skillDiagnostics } = resourceLoader.getSkills();\n if (skills.length > 0) {\n logger.info(`Discovered ${skills.length} repository skill(s)`);\n for (const skill of skills) {\n logger.info(`Found skill: ${skill.name} (${skill.filePath})`);\n }\n }\n for (const diagnostic of skillDiagnostics) {\n const path = diagnostic.path ? ` (${diagnostic.path})` : \"\";\n logger.warn(`Skill diagnostic: ${diagnostic.message}${path}`);\n }\n\n let submittedReview: ReviewOutput | null = null;\n let submitReviewCalls = 0;\n const submitReviewTool: ToolDefinition = {\n name: \"submit_review\",\n label: \"Submit Review\",\n description: \"Submit the final structured review after the analysis is complete.\",\n promptSnippet: \"Submit the final structured review (call exactly once when done)\",\n parameters: SUBMIT_REVIEW_SCHEMA,\n execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => {\n submitReviewCalls++;\n if (submittedReview) {\n logger.warn(\"Agent called submit_review more than once; ignoring duplicate submission\");\n return {\n content: [{\n type: \"text\",\n text: \"Review already submitted. Do not call submit_review again.\",\n }],\n details: { ignoredDuplicate: true },\n };\n }\n\n submittedReview = validateReviewOutput(params as ReviewOutput);\n logger.info(\n `Received structured review via submit_review (${submittedReview.findings.length} finding(s))`,\n );\n return {\n content: [{\n type: \"text\",\n text: \"Review received. Do not output the review as normal text.\",\n }],\n details: {},\n };\n },\n };\n\n const { session } = await createAgentSession({\n cwd: workspacePath,\n model: piModel,\n thinkingLevel,\n tools: [\n createReadTool(workspacePath),\n createBashTool(workspacePath),\n createGrepTool(workspacePath),\n createFindTool(workspacePath),\n createLsTool(workspacePath),\n ],\n customTools: [submitReviewTool],\n sessionManager: SessionManager.inMemory(),\n settingsManager,\n resourceLoader,\n authStorage,\n modelRegistry,\n });\n\n // Inject Bedrock cost allocation tags into stream requests\n if (bedrockTags && parsed.provider === \"bedrock\") {\n type AgentWithStream = { agent: { streamFn: (...args: unknown[]) => unknown } };\n const agent = (session as unknown as AgentWithStream).agent;\n const originalStreamFn = agent.streamFn;\n agent.streamFn = (...args: unknown[]) => {\n const options = (args[2] ?? {}) as Record<string, unknown>;\n return originalStreamFn(args[0], args[1], { ...options, requestMetadata: bedrockTags });\n };\n logger.info(`Bedrock cost allocation tags: ${JSON.stringify(bedrockTags)}`);\n }\n\n // Subscribe to agent events for progress + metrics tracking\n let turnCount = 0;\n let toolCallCount = 0;\n\n /** Extract human-readable summary from tool args */\n function formatToolArgs(_toolName: string, args: unknown): string {\n if (typeof args === \"string\") return args.slice(0, 200);\n const obj = args as Record<string, unknown> | undefined;\n if (!obj) return \"\";\n // bash tool: show the command, strip workspace prefix\n if (obj.command) {\n return String(obj.command)\n .replace(new RegExp(`cd ${workspacePath.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")} && `), \"\")\n .slice(0, 200);\n }\n // grep/find: show pattern + path\n if (obj.pattern) {\n const path = obj.path ? ` in ${obj.path}` : \"\";\n return `${obj.pattern}${path}`;\n }\n // read/ls: show the path\n if (obj.path || obj.file_path) return String(obj.path ?? obj.file_path);\n return JSON.stringify(obj).slice(0, 200);\n }\n\n /** Extract text content from tool result */\n function formatToolResult(result: unknown): string {\n if (typeof result === \"string\") return result;\n const obj = result as Record<string, unknown> | undefined;\n if (!obj) return \"\";\n // pi-sdk wraps results as {content: [{type: \"text\", text: \"...\"}]}\n const content = obj.content as Array<{ type?: string; text?: string }> | undefined;\n if (Array.isArray(content)) {\n return content\n .filter((c) => c.type === \"text\" && c.text)\n .map((c) => c.text)\n .join(\"\\n\");\n }\n return JSON.stringify(result)?.slice(0, 500) ?? \"\";\n }\n\n session.subscribe((event) => {\n switch (event.type) {\n case \"agent_start\":\n onEvent?.({ type: \"agent_start\" });\n break;\n case \"agent_end\":\n onEvent?.({ type: \"agent_end\" });\n break;\n case \"turn_start\":\n turnCount++;\n onEvent?.({ type: \"turn_start\", turnIndex: turnCount });\n break;\n case \"turn_end\":\n onEvent?.({ type: \"turn_end\", turnIndex: turnCount });\n break;\n case \"tool_execution_start\":\n toolCallCount++;\n onEvent?.({\n type: \"tool_start\",\n toolName: event.toolName,\n toolArgs: formatToolArgs(event.toolName, event.args),\n });\n break;\n case \"tool_execution_end\":\n onEvent?.({\n type: \"tool_end\",\n toolName: event.toolName,\n isError: event.isError,\n result: formatToolResult(event.result),\n });\n break;\n case \"message_start\":\n onEvent?.({ type: \"thinking\" });\n break;\n case \"message_update\": {\n const msgEvent = (event as Record<string, unknown>).assistantMessageEvent as\n { type: string; delta?: string } | undefined;\n if (!msgEvent?.delta) break;\n if (msgEvent.type === \"text_delta\") {\n onEvent?.({ type: \"text_delta\", delta: msgEvent.delta });\n } else if (msgEvent.type === \"thinking_delta\") {\n onEvent?.({ type: \"thinking_delta\", delta: msgEvent.delta });\n }\n break;\n }\n }\n });\n\n logger.info(\"Sending prompt to agent...\");\n await session.prompt(prompt);\n\n // Check for agent errors (pi-ai swallows LLM errors into state.error)\n const agentError = (session as unknown as { state: { error?: string } }).state?.error;\n if (agentError) {\n throw new Error(`LLM request failed: ${agentError}`);\n }\n\n if (!submittedReview) {\n const rawText = session.getLastAssistantText() ?? \"\";\n if (rawText) {\n logger.debug(`Last assistant text without submit_review (first 500 chars): ${rawText.slice(0, 500)}`);\n } else {\n const messages = (session as unknown as { state: { messages: unknown[] } }).state?.messages;\n const lastMsg = messages?.[messages.length - 1];\n logger.debug(`Last message: ${JSON.stringify(lastMsg)?.slice(0, 500)}`);\n }\n if (submitReviewCalls > 0) {\n throw new Error(\"Agent called submit_review but did not provide a valid review payload\");\n }\n throw new Error(\"Agent did not call submit_review\");\n }\n\n const review = submittedReview as ReviewOutput;\n if (submitReviewCalls > 1) {\n logger.warn(`Agent called submit_review ${submitReviewCalls} times; using the first valid submission`);\n }\n logger.info(\n `Captured ${review.findings.length} finding(s), verdict: ${review.overall_correctness}`,\n );\n\n const durationSeconds = (Date.now() - startTime) / 1000;\n logger.info(`Review complete (${review.findings.length} finding(s))`);\n\n // Aggregate usage from all assistant messages\n interface MsgUsage {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n totalTokens: number;\n cost: { total: number };\n }\n interface AssistantMsg {\n role: string;\n usage?: MsgUsage;\n }\n\n const allMessages = (\n session as unknown as { state: { messages: AssistantMsg[] } }\n ).state?.messages ?? [];\n\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheReadTokens = 0;\n let cacheWriteTokens = 0;\n let totalTokens = 0;\n let cost = 0;\n\n for (const msg of allMessages) {\n if (msg.role === \"assistant\" && msg.usage) {\n inputTokens += msg.usage.input ?? 0;\n outputTokens += msg.usage.output ?? 0;\n cacheReadTokens += msg.usage.cacheRead ?? 0;\n cacheWriteTokens += msg.usage.cacheWrite ?? 0;\n totalTokens += msg.usage.totalTokens ?? 0;\n cost += msg.usage.cost?.total ?? 0;\n }\n }\n\n const metrics: ReviewMetrics = {\n inputTokens,\n outputTokens,\n cacheReadTokens,\n cacheWriteTokens,\n totalTokens,\n cost,\n turns: turnCount,\n toolCalls: toolCallCount,\n durationSeconds: Math.round(durationSeconds),\n };\n printMetrics(metrics);\n\n let metricsFooter: string | null = null;\n if (includeMetricsFooter) {\n metricsFooter = formatMetricsMarkdown(metrics);\n }\n\n return { review, metricsFooter, headSha, metrics };\n } finally {\n // Restore mutated env vars\n for (const [key, val] of Object.entries(envSnapshot)) {\n if (val === undefined) {\n delete process.env[key];\n } else {\n process.env[key] = val;\n }\n }\n\n if (cleanup && isTemporary) {\n logger.info(\"Cleaning up workspace...\");\n await cleanupWorkspace(workspacePath);\n }\n }\n}\n","import { execJson } from \"./utils/exec.js\";\nimport type { MrMetadata, NoteEntry } from \"./types.js\";\n\nexport class GitHubAPIError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GitHubAPIError\";\n }\n}\n\nexport async function fetchGithubPrInfo(\n owner: string,\n repo: string,\n prNumber: number | string,\n): Promise<Record<string, unknown>> {\n const fields = [\n \"number\",\n \"title\",\n \"body\",\n \"author\",\n \"baseRefName\",\n \"headRefName\",\n \"baseRefOid\",\n \"headRefOid\",\n \"changedFiles\",\n \"labels\",\n \"comments\",\n \"state\",\n \"isDraft\",\n \"createdAt\",\n \"updatedAt\",\n \"mergeable\",\n \"url\",\n ];\n\n const repoFullPath = `${owner}/${repo}`;\n try {\n return await execJson<Record<string, unknown>>(\"gh\", [\n \"pr\",\n \"view\",\n String(prNumber),\n \"-R\",\n repoFullPath,\n \"--json\",\n fields.join(\",\"),\n ]);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new GitHubAPIError(msg);\n }\n}\n\nexport function normalizeGithubMetadata(\n raw: Record<string, unknown>,\n): MrMetadata {\n const author = (raw.author as Record<string, string>) ?? {};\n const labels = (raw.labels as Array<Record<string, string>>) ?? [];\n const comments = raw.comments as\n | Record<string, unknown>\n | Array<Record<string, unknown>>\n | undefined;\n\n return {\n title: raw.title as string | undefined,\n description: (raw.body as string) ?? \"\",\n source_branch: raw.headRefName as string | undefined,\n target_branch: raw.baseRefName as string | undefined,\n changes_count: raw.changedFiles as number | undefined,\n labels: labels.map((lbl) => ({ name: lbl.name ?? lbl.id })),\n author: {\n username: author.login ?? author.name,\n name: author.name,\n },\n Notes: githubCommentsToNotes(comments),\n };\n}\n\nfunction githubCommentsToNotes(\n comments:\n | Record<string, unknown>\n | Array<Record<string, unknown>>\n | undefined\n | null,\n): NoteEntry[] {\n if (!comments) return [];\n\n let nodes: Array<Record<string, unknown>>;\n if (Array.isArray(comments)) {\n nodes = comments;\n } else if (typeof comments === \"object\") {\n nodes =\n (comments.nodes as Array<Record<string, unknown>>) ??\n (comments.edges as Array<Record<string, unknown>>) ??\n [];\n // Handle GraphQL edge format\n if (\n nodes.length > 0 &&\n typeof nodes[0] === \"object\" &&\n \"node\" in nodes[0]\n ) {\n nodes = nodes.map(\n (edge) =>\n (edge.node as Record<string, unknown>) ?? {},\n );\n }\n } else {\n nodes = [];\n }\n\n return nodes.map((node) => {\n const author = (node.author as Record<string, string>) ?? {};\n return {\n body: (node.body as string) ?? \"\",\n author: {\n username: author.login ?? author.name,\n name: author.name,\n },\n created_at: node.createdAt as string | undefined,\n };\n });\n}\n","import { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { exec, execJson } from \"./utils/exec.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { fetchGitlabMrInfo } from \"./gitlab.js\";\nimport type { MrMetadata, Platform } from \"./types.js\";\n\nexport class WorkspaceError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WorkspaceError\";\n }\n}\n\nexport interface WorkspaceResult {\n workspace: string;\n targetBranch: string;\n diffBaseSha: string | null;\n isTemporary: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// CI detection\n// ---------------------------------------------------------------------------\n\ninterface CiWorkspace {\n path: string | null;\n targetBranch: string | null;\n diffBaseSha: string | null;\n}\n\nfunction detectCiWorkspace(owner: string, repo: string): CiWorkspace {\n // GitLab CI\n if (process.env.GITLAB_CI === \"true\") {\n const projectDir = process.env.CI_PROJECT_DIR;\n const projectPath = process.env.CI_PROJECT_PATH;\n const targetBranch = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME ?? null;\n const diffBaseSha = process.env.CI_MERGE_REQUEST_DIFF_BASE_SHA ?? null;\n\n if (projectDir && projectPath) {\n const expected = `${owner}/${repo}`;\n if (projectPath === expected || projectPath.endsWith(`/${expected}`)) {\n logger.info(`Detected GitLab CI environment (target: ${targetBranch ?? \"unknown\"})`);\n return { path: projectDir, targetBranch, diffBaseSha };\n }\n }\n }\n\n // GitHub Actions\n if (process.env.GITHUB_ACTIONS === \"true\") {\n const workspaceDir = process.env.GITHUB_WORKSPACE;\n const repository = process.env.GITHUB_REPOSITORY;\n const baseRef = process.env.GITHUB_BASE_REF ?? null;\n\n if (workspaceDir && repository) {\n const expected = `${owner}/${repo}`;\n if (repository === expected) {\n logger.info(`Detected GitHub Actions environment (base: ${baseRef ?? \"unknown\"})`);\n return { path: workspaceDir, targetBranch: baseRef, diffBaseSha: null };\n }\n }\n }\n\n return { path: null, targetBranch: null, diffBaseSha: null };\n}\n\n// ---------------------------------------------------------------------------\n// Repo identity check\n// ---------------------------------------------------------------------------\n\n/**\n * Check if workspace is already cloned from the expected owner/repo.\n * Parses the remote URL to compare exact owner/repo, avoiding substring false positives.\n */\nasync function isSameRepo(\n workspace: string,\n owner: string,\n repo: string,\n): Promise<boolean> {\n try {\n const { stdout } = await exec(\"git\", [\"remote\", \"get-url\", \"origin\"], { cwd: workspace });\n const remoteUrl = stdout.trim();\n // Normalize: extract path from HTTPS or SSH URLs\n // HTTPS: https://host/owner/repo.git SSH: git@host:owner/repo.git\n const match = remoteUrl.match(/[/:]([\\w.\\-\\/]+?)(?:\\.git)?$/) ;\n if (!match) return false;\n const remotePath = match[1];\n const expectedPath = `${owner}/${repo}`;\n return remotePath === expectedPath;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// GitHub helpers\n// ---------------------------------------------------------------------------\n\nasync function getGithubBaseBranch(workspace: string, prNumber: string): Promise<string> {\n try {\n const prInfo = await execJson<Record<string, string>>(\n \"gh\",\n [\"pr\", \"view\", prNumber, \"--json\", \"headRefName,baseRefName\"],\n { cwd: workspace },\n );\n const baseBranch = prInfo.baseRefName ?? \"main\";\n logger.info(`Base branch: ${baseBranch}`);\n return baseBranch;\n } catch {\n logger.warn(\"Could not fetch PR metadata for base branch detection\");\n return \"main\";\n }\n}\n\nasync function fetchAndCheckoutGithubPr(\n workspace: string,\n prNumber: string,\n): Promise<string> {\n logger.info(`Fetching and checking out PR #${prNumber} in existing workspace`);\n await exec(\"git\", [\"fetch\", \"origin\"], { cwd: workspace });\n\n try {\n await exec(\"gh\", [\"pr\", \"checkout\", prNumber], { cwd: workspace });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to checkout PR #${prNumber}: ${msg}`);\n }\n\n return getGithubBaseBranch(workspace, prNumber);\n}\n\nasync function cloneAndCheckoutGithubPr(\n workspace: string,\n owner: string,\n repo: string,\n prNumber: string,\n): Promise<string> {\n logger.info(`Setting up GitHub workspace for ${owner}/${repo}/pull/${prNumber}`);\n\n try {\n await exec(\"gh\", [\"version\"]);\n } catch {\n throw new WorkspaceError(\"GitHub CLI (gh) is not available. Install it: https://cli.github.com\");\n }\n\n logger.info(`Cloning repository ${owner}/${repo}...`);\n try {\n await exec(\"gh\", [\"repo\", \"clone\", `${owner}/${repo}`, workspace]);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to clone repository ${owner}/${repo}: ${msg}`);\n }\n\n logger.info(`Checking out PR #${prNumber}...`);\n try {\n await exec(\"gh\", [\"pr\", \"checkout\", prNumber], { cwd: workspace });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to checkout PR #${prNumber}: ${msg}`);\n }\n\n return getGithubBaseBranch(workspace, prNumber);\n}\n\n// ---------------------------------------------------------------------------\n// GitLab helpers\n// ---------------------------------------------------------------------------\n\nasync function getGitlabMrBranches(\n owner: string,\n repo: string,\n prNumber: string,\n host?: string,\n): Promise<{ sourceBranch: string; targetBranch: string }> {\n const gitlabHost = host || process.env.GITLAB_HOST || \"gitlab.com\";\n let mrInfo: MrMetadata;\n try {\n mrInfo = await fetchGitlabMrInfo(owner, repo, Number(prNumber), gitlabHost);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to fetch MR info for !${prNumber}: ${msg}`);\n }\n\n const sourceBranch = mrInfo.source_branch;\n if (!sourceBranch) {\n throw new WorkspaceError(`Could not determine source branch for MR !${prNumber}`);\n }\n\n return { sourceBranch, targetBranch: mrInfo.target_branch ?? \"main\" };\n}\n\nasync function checkoutGitlabBranch(workspace: string, sourceBranch: string): Promise<void> {\n try {\n await exec(\"git\", [\"checkout\", \"-b\", sourceBranch, `origin/${sourceBranch}`], {\n cwd: workspace,\n });\n } catch {\n try {\n await exec(\"git\", [\"checkout\", sourceBranch], { cwd: workspace });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to checkout MR branch '${sourceBranch}': ${msg}`);\n }\n }\n}\n\nasync function fetchAndCheckoutGitlabMr(\n workspace: string,\n owner: string,\n repo: string,\n prNumber: string,\n host?: string,\n): Promise<string> {\n logger.info(`Fetching and checking out MR !${prNumber} in existing workspace`);\n await exec(\"git\", [\"fetch\", \"origin\"], { cwd: workspace });\n\n const { sourceBranch, targetBranch } = await getGitlabMrBranches(owner, repo, prNumber, host);\n logger.info(`Source branch: ${sourceBranch}, Target branch: ${targetBranch}`);\n await checkoutGitlabBranch(workspace, sourceBranch);\n\n return targetBranch;\n}\n\nasync function cloneAndCheckoutGitlabMr(\n workspace: string,\n owner: string,\n repo: string,\n prNumber: string,\n host?: string,\n): Promise<string> {\n const gitlabHost = host || process.env.GITLAB_HOST || \"gitlab.com\";\n logger.info(`Setting up GitLab workspace for ${owner}/${repo}/merge_requests/${prNumber}`);\n\n try {\n await exec(\"glab\", [\"version\"]);\n } catch {\n throw new WorkspaceError(\n \"GitLab CLI (glab) is not available. Install it: https://gitlab.com/gitlab-org/cli\",\n );\n }\n\n const cloneUrl = `https://${gitlabHost}/${owner}/${repo}.git`;\n logger.info(`Cloning from ${cloneUrl}...`);\n try {\n await exec(\"git\", [\"clone\", cloneUrl, workspace]);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"Permission denied\") || msg.includes(\"publickey\")) {\n throw new WorkspaceError(\n `Failed to clone ${owner}/${repo}: SSH authentication failed. ` +\n `Ensure your SSH key is available (ssh-add) or configure a GITLAB_TOKEN ` +\n `and use HTTPS: git config --global url.\"https://oauth2:$GITLAB_TOKEN@${gitlabHost}/\".insteadOf \"git@${gitlabHost}:\"`,\n );\n }\n throw new WorkspaceError(`Failed to clone ${owner}/${repo}: ${msg}`);\n }\n\n const { sourceBranch, targetBranch } = await getGitlabMrBranches(owner, repo, prNumber, host);\n logger.info(`Source branch: ${sourceBranch}, Target branch: ${targetBranch}`);\n await checkoutGitlabBranch(workspace, sourceBranch);\n\n return targetBranch;\n}\n\n// ---------------------------------------------------------------------------\n// Main entry point\n// ---------------------------------------------------------------------------\n\nexport async function setupWorkspace(opts: {\n platform: Platform;\n owner: string;\n repo: string;\n prNumber: string;\n host?: string;\n workingDir?: string;\n reuse?: boolean;\n}): Promise<WorkspaceResult> {\n const { platform, owner, repo, prNumber, host, workingDir, reuse = true } = opts;\n\n try {\n const ci = detectCiWorkspace(owner, repo);\n let detectedTargetBranch = ci.targetBranch;\n const detectedDiffBaseSha = ci.diffBaseSha;\n\n let workspace: string;\n let isTemporary = false;\n\n if (ci.path) {\n workspace = ci.path;\n } else if (!workingDir) {\n workspace = await mkdtemp(join(tmpdir(), \"hodor-review-\"));\n isTemporary = true;\n logger.info(`Created temporary workspace: ${workspace}`);\n } else {\n workspace = workingDir;\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(workspace, { recursive: true });\n\n if (reuse && (await isSameRepo(workspace, owner, repo))) {\n logger.info(`Reusing existing workspace: ${workspace}`);\n // Repo already cloned — just fetch and checkout the PR/MR branch\n if (platform === \"github\") {\n const tb = await fetchAndCheckoutGithubPr(workspace, prNumber);\n if (!detectedTargetBranch) detectedTargetBranch = tb;\n } else if (platform === \"gitlab\") {\n const tb = await fetchAndCheckoutGitlabMr(workspace, owner, repo, prNumber, host);\n if (!detectedTargetBranch) detectedTargetBranch = tb;\n }\n const finalTargetBranch = detectedTargetBranch ?? \"main\";\n logger.info(\n `Workspace ready at: ${workspace} (target: ${finalTargetBranch}, ` +\n `diff_base_sha: ${detectedDiffBaseSha?.slice(0, 8) ?? \"N/A\"})`,\n );\n return { workspace, targetBranch: finalTargetBranch, diffBaseSha: detectedDiffBaseSha, isTemporary: false };\n }\n }\n\n if (!ci.path) {\n if (platform === \"github\") {\n const tb = await cloneAndCheckoutGithubPr(workspace, owner, repo, prNumber);\n if (!detectedTargetBranch) detectedTargetBranch = tb;\n } else if (platform === \"gitlab\") {\n const tb = await cloneAndCheckoutGitlabMr(workspace, owner, repo, prNumber, host);\n if (!detectedTargetBranch) detectedTargetBranch = tb;\n } else {\n throw new WorkspaceError(`Unsupported platform: ${platform}`);\n }\n }\n\n const finalTargetBranch = detectedTargetBranch ?? \"main\";\n logger.info(\n `Workspace ready at: ${workspace} (target: ${finalTargetBranch}, ` +\n `diff_base_sha: ${detectedDiffBaseSha?.slice(0, 8) ?? \"N/A\"})`,\n );\n return { workspace, targetBranch: finalTargetBranch, diffBaseSha: detectedDiffBaseSha, isTemporary };\n } catch (err) {\n if (err instanceof WorkspaceError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n throw new WorkspaceError(`Failed to setup workspace: ${msg}`);\n }\n}\n\nexport async function cleanupWorkspace(workspace: string): Promise<void> {\n try {\n await rm(workspace, { recursive: true, force: true });\n logger.info(`Cleaned up workspace: ${workspace}`);\n } catch (err) {\n logger.warn(`Failed to cleanup workspace ${workspace}: ${err}`);\n }\n}\n","export const REVIEW_SYSTEM_PROMPT = `You are a code review agent. You analyze pull request diffs to find production bugs.\n\n<ROLE>\n* You are in READ-ONLY mode. Do NOT modify any files, create files, commit, or install dependencies.\n* Your only job is to analyze the diff, identify bugs, and produce a review.\n* Submit the final review via the \\`submit_review\\` tool. Do NOT output the final review as normal assistant text.\n* Be proportional: scale your analysis depth to the diff size. A small, single-file diff needs only a few iterations; a large multi-file refactor warrants deeper investigation.\n* Do NOT write to PLAN.md or AGENTS.md.\n* Do NOT run package managers (npm install, go mod download, pip install, etc.).\n* Follow the instructions in the user prompt exactly as given.\n</ROLE>\n\n<EFFICIENCY>\n* Combine multiple bash commands where possible (e.g. \\`cmd1 && cmd2\\`).\n* Use the grep and find tools for code search — do not shell out to grep/find.\n* Prefer \\`git diff\\` to see changes for specific files. Only use read when you need surrounding context that the diff alone cannot provide.\n* Do not use cat/head/tail to read files.\n* Keep reasoning proportional to the task. A small diff does not need extensive deliberation.\n</EFFICIENCY>`;\n","/**\n * Render structured review output into clean markdown for PR/MR comments.\n */\n\nimport type { ReviewFinding, ReviewOutput } from \"./types.js\";\n\n/**\n * Render a ReviewOutput into clean markdown for posting as a PR/MR comment.\n */\nexport function renderMarkdown(review: ReviewOutput): string {\n const lines: string[] = [];\n\n // Group findings by priority\n const critical: ReviewFinding[] = []; // P0, P1\n const important: ReviewFinding[] = []; // P2\n const minor: ReviewFinding[] = []; // P3\n\n for (const f of review.findings) {\n const p = f.priority;\n if (p <= 1) critical.push(f);\n else if (p === 2) important.push(f);\n else minor.push(f);\n }\n\n lines.push(\"### Issues Found\");\n lines.push(\"\");\n\n if (review.findings.length === 0) {\n lines.push(\"No issues found.\");\n lines.push(\"\");\n }\n\n if (critical.length > 0) {\n lines.push(\"**Critical (P0/P1)**\");\n for (const f of critical) {\n lines.push(formatFinding(f));\n }\n lines.push(\"\");\n }\n\n if (important.length > 0) {\n lines.push(\"**Important (P2)**\");\n for (const f of important) {\n lines.push(formatFinding(f));\n }\n lines.push(\"\");\n }\n\n if (minor.length > 0) {\n lines.push(\"**Minor (P3)**\");\n for (const f of minor) {\n lines.push(formatFinding(f));\n }\n lines.push(\"\");\n }\n\n // Summary\n lines.push(\"### Summary\");\n lines.push(\n `Total issues: ${critical.length} critical, ${important.length} important, ${minor.length} minor.`,\n );\n lines.push(\"\");\n\n // Overall verdict\n lines.push(\"### Overall Verdict\");\n const isCorrect = review.overall_correctness === \"patch is correct\";\n lines.push(\n `**Status**: ${isCorrect ? \"Patch is correct\" : \"Patch has blocking issues\"}`,\n );\n lines.push(\"\");\n if (review.overall_explanation) {\n lines.push(`**Explanation**: ${review.overall_explanation}`);\n }\n\n return lines.join(\"\\n\").trimEnd() + \"\\n\";\n}\n\nfunction formatFinding(f: ReviewFinding): string {\n const loc = ` (\\`${formatLocation(f.code_location)}\\`)`;\n const title = `- **${f.title}**${loc}`;\n const body = ` - ${f.body}`;\n return `${title}\\n${body}`;\n}\n\nfunction formatLocation(loc: {\n absolute_file_path: string;\n line_range: { start: number; end: number };\n}): string {\n // Strip common workspace prefixes to get a clean relative path\n let filePath = loc.absolute_file_path;\n\n // GitLab CI: /builds/owner/repo/src/file.ts → src/file.ts\n const buildsMatch = filePath.match(/\\/builds\\/[^/]+\\/[^/]+\\/(.+)/);\n if (buildsMatch) {\n filePath = buildsMatch[1];\n }\n // GitHub Actions / generic workspace\n else if (filePath.includes(\"/workspace/\")) {\n filePath = filePath.slice(filePath.indexOf(\"/workspace/\") + \"/workspace/\".length);\n }\n // Temp review dirs: /tmp/hodor-review-<id>/src/file.ts → src/file.ts\n else {\n filePath = filePath.replace(/^.*\\/hodor-review-[^/]+\\//, \"\");\n }\n\n const { start, end } = loc.line_range;\n return start === end ? `${filePath}:${start}` : `${filePath}:${start}-${end}`;\n}\n"],"mappings":"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","names":["chalk","chalk","join","finalTargetBranch","formatToolArgs","formatToolResult","join"]}