revdeck 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/CONTRIBUTING.md +98 -0
  3. package/LICENSE +21 -0
  4. package/README.md +223 -2
  5. package/README.ru.md +210 -0
  6. package/SECURITY.md +45 -0
  7. package/dist/cli.js +2669 -0
  8. package/dist/cli.js.map +7 -0
  9. package/dist/daemon.js +3715 -0
  10. package/dist/daemon.js.map +7 -0
  11. package/dist/mcp.js +885 -0
  12. package/dist/mcp.js.map +7 -0
  13. package/dist/ui/assets/index-ByfGHwCb.css +1 -0
  14. package/dist/ui/assets/index-mvPA8Avw.js +10 -0
  15. package/dist/ui/favicon.svg +4 -0
  16. package/dist/ui/index.html +16 -0
  17. package/docs/README.md +17 -0
  18. package/docs/adr/0001-daemon-first.md +63 -0
  19. package/docs/architecture.md +91 -0
  20. package/docs/configuration.md +121 -0
  21. package/docs/integrations.md +84 -0
  22. package/docs/protocol.md +96 -0
  23. package/docs/ru/README.md +17 -0
  24. package/docs/ru/adr/0001-daemon-first.md +61 -0
  25. package/docs/ru/architecture.md +91 -0
  26. package/docs/ru/configuration.md +119 -0
  27. package/docs/ru/integrations.md +82 -0
  28. package/docs/ru/protocol.md +96 -0
  29. package/docs/ru/threat-model.md +50 -0
  30. package/docs/screenshot.png +0 -0
  31. package/docs/screenshot.ru.png +0 -0
  32. package/docs/threat-model.md +51 -0
  33. package/examples/monorepo.yml +38 -0
  34. package/examples/simple.yml +36 -0
  35. package/examples/web-chat-core.yml +45 -0
  36. package/package.json +79 -4
  37. package/skills/revdeck/en/Criteria.md +265 -0
  38. package/skills/revdeck/en/Feedback.md +64 -0
  39. package/skills/revdeck/en/Review.md +157 -0
  40. package/skills/revdeck/en/Rules.md +75 -0
  41. package/skills/revdeck/en/SKILL.md +78 -0
  42. package/skills/revdeck/en/Sources.md +47 -0
  43. package/skills/revdeck/ru/Criteria.md +249 -0
  44. package/skills/revdeck/ru/Feedback.md +64 -0
  45. package/skills/revdeck/ru/Review.md +148 -0
  46. package/skills/revdeck/ru/Rules.md +69 -0
  47. package/skills/revdeck/ru/SKILL.md +73 -0
  48. package/skills/revdeck/ru/Sources.md +46 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/redact.ts", "../src/core/locale.ts", "../src/core/errors.ts", "../src/core/diff.ts", "../src/core/exec.ts", "../src/providers/util.ts", "../src/providers/gitlab.ts", "../src/providers/github.ts", "../src/daemon/main.ts", "../src/core/paths.ts", "../src/version.ts", "../src/daemon/store.ts", "../src/core/types.ts", "../src/core/refs.ts", "../src/daemon/service.ts", "../src/core/config.ts", "../src/core/glob.ts", "../src/core/rules.ts", "../src/core/sanitize.ts", "../src/core/findings.ts", "../src/core/canonical.ts", "../src/core/git.ts", "../src/providers/provider.ts", "../src/daemon/view.ts", "../src/daemon/http.ts", "../src/daemon/rpc.ts"],
4
+ "sourcesContent": ["const TOKEN_PATTERNS: [RegExp, string][] = [\n [/\\bgl[a-z]{2,6}-[A-Za-z0-9_-]{10,}/g, 'gl-***'],\n [/\\bgh[pousr]_[A-Za-z0-9]{20,}/g, 'gh-***'],\n [/\\bgithub_pat_[A-Za-z0-9_]{20,}/g, 'gh-***'],\n [/\\bxox[baprs]-[A-Za-z0-9-]{10,}/g, 'xox-***'],\n [/\\bAKIA[0-9A-Z]{16}\\b/g, 'AKIA***'],\n [/\\bsk-[A-Za-z0-9]{20,}/g, 'sk-***'],\n [/\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}/g, 'jwt-***'],\n [/\\b[0-9a-f]{40,}\\b/gi, 'hex-***'],\n [/((?:private[-_]token|access[-_]token|authorization|bearer|password|passwd|secret)\\s*[:=]\\s*)(?:\"[^\"]*\"|'[^']*'|\\S+)/gi, '$1***'],\n [/([?&](?:private_token|access_token|token|key)=)[^&\\s]+/gi, '$1***'],\n];\n\n/** \u0423\u0431\u0438\u0440\u0430\u0435\u0442 ANSI, \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u0438 \u0441\u0435\u043A\u0440\u0435\u0442\u044B \u0438\u0437 \u0442\u0435\u043A\u0441\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0443\u0445\u043E\u0434\u0438\u0442 \u0432 \u043B\u043E\u0433/UI. */\nexport function redact(value: unknown): string {\n let text = String(value ?? '')\n .replace(/\\u001b\\[[0-9;?]*[ -/]*[@-~]/g, '')\n .replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f]/g, ' ');\n for (const [pattern, replacement] of TOKEN_PATTERNS) {\n text = text.replace(pattern, replacement);\n }\n return text.slice(0, 4000);\n}\n\n/** \u041E\u0434\u043D\u043E\u0441\u0442\u0440\u043E\u0447\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u043B\u044F \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430. */\nexport function redactLine(value: unknown, max = 300): string {\n return redact(value).replace(/\\s+/g, ' ').trim().slice(0, max);\n}\n", "export type Locale = 'ru' | 'en';\n\n/**\n * \u041B\u043E\u043A\u0430\u043B\u044C \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430/CLI. \u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442: REVDECK_LANG \u2192 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0430\u044F LANG/LC_ALL \u2192 en.\n * \u042F\u0437\u044B\u043A \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u043E\u0432 \u0440\u0435\u0432\u044C\u044E \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E (output.language) \u0438 \u043C\u043E\u0436\u0435\u0442 \u043E\u0442\u043B\u0438\u0447\u0430\u0442\u044C\u0441\u044F.\n */\nexport function detectLocale(explicit?: string): Locale {\n const value = (explicit ?? process.env.REVDECK_LANG ?? process.env.LC_ALL ?? process.env.LANG ?? '').toLowerCase();\n return value.startsWith('ru') ? 'ru' : 'en';\n}\n\nexport function isLocale(value: unknown): value is Locale {\n return value === 'ru' || value === 'en';\n}\n\nlet current: Locale = detectLocale();\n\nexport function locale(): Locale {\n return current;\n}\n\nexport function setLocale(value: Locale): void {\n current = value;\n // \u041D\u0430\u0441\u043B\u0435\u0434\u0443\u0435\u0442\u0441\u044F \u0434\u043E\u0447\u0435\u0440\u043D\u0438\u043C \u0434\u0435\u043C\u043E\u043D\u043E\u043C/MCP, \u0447\u0442\u043E\u0431\u044B \u044F\u0437\u044B\u043A \u043D\u0435 \u0440\u0430\u0441\u0445\u043E\u0434\u0438\u043B\u0441\u044F.\n process.env.REVDECK_LANG = value;\n}\n\n/** \u0414\u0432\u0443\u044F\u0437\u044B\u0447\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430: ru \u2014 \u0434\u043B\u044F \u0440\u0443\u0441\u0441\u043A\u043E\u0439 \u043B\u043E\u043A\u0430\u043B\u0438, en \u2014 \u0434\u043B\u044F \u0430\u043D\u0433\u043B\u0438\u0439\u0441\u043A\u043E\u0439. */\nexport function tr(ru: string, en: string): string {\n return current === 'ru' ? ru : en;\n}\n\n/** \u0412\u044B\u0431\u043E\u0440 \u0444\u043E\u0440\u043C\u044B \u043F\u043E \u0447\u0438\u0441\u043B\u0443: \u0440\u0443\u0441\u0441\u043A\u0438\u0435 one/few/many \u0438\u043B\u0438 \u0430\u043D\u0433\u043B\u0438\u0439\u0441\u043A\u0438\u0435 one/other. */\nexport function plural(count: number, ruOne: string, ruFew: string, ruMany: string, enOne: string, enMany: string): string {\n if (current === 'en') return count === 1 ? enOne : enMany;\n const mod10 = count % 10;\n const mod100 = count % 100;\n if (mod10 === 1 && mod100 !== 11) return ruOne;\n if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return ruFew;\n return ruMany;\n}\n\n/** \u042F\u0437\u044B\u043A \u0442\u0435\u043A\u0441\u0442\u0430: \u043A\u0438\u0440\u0438\u043B\u043B\u0438\u0446\u0430 \u0438\u043B\u0438 \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430. \u041D\u0443\u0436\u0435\u043D \u0434\u043B\u044F output.language: auto. */\nexport function detectTextLocale(text: string, fallback: Locale = current): Locale {\n const cyrillic = (text.match(/[\u0410-\u042F\u0430-\u044F\u0401\u0451]/g) ?? []).length;\n const latin = (text.match(/[A-Za-z]/g) ?? []).length;\n if (cyrillic === 0 && latin === 0) return fallback;\n return cyrillic >= latin ? 'ru' : 'en';\n}\n\n/** auto \u2192 \u044F\u0437\u044B\u043A \u0442\u0435\u043A\u0441\u0442\u0430 \u0440\u0435\u0432\u044C\u044E; \u044F\u0432\u043D\u043E\u0435 ru/en \u2014 \u043A\u0430\u043A \u0437\u0430\u0434\u0430\u043D\u043E. */\nexport function resolveOutputLanguage(setting: 'auto' | 'ru' | 'en', texts: string[]): Locale {\n if (setting === 'ru' || setting === 'en') return setting;\n return detectTextLocale(texts.join('\\n'), 'en');\n}\n", "export class MrReviewError extends Error {\n readonly code: string;\n readonly hint: string | undefined;\n\n constructor(message: string, code = 'REVDECK_ERROR', hint?: string) {\n super(message);\n this.name = 'MrReviewError';\n this.code = code;\n this.hint = hint;\n }\n}\n\nexport class ConfigError extends MrReviewError {\n constructor(message: string, hint?: string) {\n super(message, 'CONFIG', hint);\n this.name = 'ConfigError';\n }\n}\n\nexport class ProviderError extends MrReviewError {\n constructor(message: string, hint?: string) {\n super(message, 'PROVIDER', hint);\n this.name = 'ProviderError';\n }\n}\n\nexport class AuthError extends MrReviewError {\n constructor(message: string, hint?: string) {\n super(message, 'AUTH', hint);\n this.name = 'AuthError';\n }\n}\n\nexport class NotFoundError extends MrReviewError {\n constructor(message: string) {\n super(message, 'NOT_FOUND');\n this.name = 'NotFoundError';\n }\n}\n\nexport class ApprovalError extends MrReviewError {\n constructor(message: string) {\n super(message, 'APPROVAL');\n this.name = 'ApprovalError';\n }\n}\n\nexport class PublishError extends MrReviewError {\n constructor(message: string, hint?: string) {\n super(message, 'PUBLISH', hint);\n this.name = 'PublishError';\n }\n}\n\n/** \u041F\u0440\u0438\u0432\u043E\u0434\u0438\u0442 \u043B\u044E\u0431\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043A \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044E, \u043D\u0435 \u0440\u0430\u0441\u043A\u0440\u044B\u0432\u0430\u044F \u0441\u0435\u043A\u0440\u0435\u0442\u043E\u0432 (\u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u2014 \u0441\u043D\u0430\u0440\u0443\u0436\u0438). */\nexport function messageOf(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n", "import type { DiffFile, DiffLine, FileStatus, Hunk } from './types.js';\n\nconst MAX_DIFF_BYTES = 32 * 1024 * 1024;\n\nexport class DiffParseError extends Error {}\n\n/** \u0423\u0431\u0438\u0440\u0430\u0435\u0442 \u043F\u0440\u0435\u0444\u0438\u043A\u0441 a//b/ \u0438 \u043A\u0430\u0432\u044B\u0447\u043A\u0438, \u043E\u0442\u0431\u0440\u0430\u0441\u044B\u0432\u0430\u0435\u0442 \u0442\u0430\u0431\u0443\u043B\u044F\u0446\u0438\u044E \u0441 \u0432\u0440\u0435\u043C\u0435\u043D\u0435\u043C \u0444\u0430\u0439\u043B\u0430. */\nfunction cleanPath(raw: string): string {\n let value = raw.trim();\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.slice(1, -1).replace(/\\\\([\"\\\\])/g, '$1');\n }\n value = value.replace(/\\t.*$/, '');\n return value.replace(/^[ab]\\//, '');\n}\n\nfunction splitGitHeader(line: string): { oldPath: string; newPath: string } {\n // `diff --git a/x b/y`; \u043F\u0443\u0442\u0438 \u043C\u043E\u0433\u0443\u0442 \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043F\u0440\u043E\u0431\u0435\u043B\u044B, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0438\u0449\u0435\u043C \u0440\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C ` b/`.\n const body = line.slice('diff --git '.length).trim();\n const quoted = /^\"(.*)\"\\s+\"(.*)\"$/.exec(body);\n if (quoted) return { oldPath: cleanPath(quoted[1]!), newPath: cleanPath(quoted[2]!) };\n const index = body.lastIndexOf(' b/');\n if (index > 0) {\n return { oldPath: cleanPath(body.slice(0, index)), newPath: cleanPath(body.slice(index + 1)) };\n }\n const [left, right] = body.split(/\\s+/);\n return { oldPath: cleanPath(left ?? ''), newPath: cleanPath(right ?? left ?? '') };\n}\n\nfunction parseHunkHeader(line: string): Hunk {\n const match = /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/.exec(line);\n if (!match) throw new DiffParseError(`invalid hunk header: ${line.slice(0, 120)}`);\n return {\n header: line,\n oldStart: Number(match[1]),\n oldLines: match[2] === undefined ? 1 : Number(match[2]),\n newStart: Number(match[3]),\n newLines: match[4] === undefined ? 1 : Number(match[4]),\n lines: [],\n };\n}\n\n/**\n * \u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 unified diff (\u0444\u043E\u0440\u043C\u0430\u0442 git) \u0432 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 \u0444\u0430\u0439\u043B\u043E\u0432 \u0438 \u0445\u0443\u043D\u043A\u043E\u0432.\n *\n * \u0422\u043E\u043B\u0435\u0440\u0430\u043D\u0442\u0435\u043D \u043A \u043D\u0435\u043F\u043E\u043B\u043D\u044B\u043C \u043F\u0430\u0442\u0447\u0430\u043C (xdiff, `glab mr diff`, `gh pr diff`): \u0438\u043C\u0435\u043D\u0430\n * \u0431\u0435\u0440\u0443\u0442\u0441\u044F \u0438\u0437 `+++`/`---`, \u0435\u0441\u043B\u0438 \u043E\u043D\u0438 \u0435\u0441\u0442\u044C, \u0438\u043D\u0430\u0447\u0435 \u0438\u0437 `diff --git`. \u0421\u0447\u0451\u0442\u0447\u0438\u043A\u0438 \u0445\u0443\u043D\u043A\u0430\n * \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430 \u0438 \u043D\u0435 \u0440\u043E\u043D\u044F\u044E\u0442 \u0440\u0430\u0437\u0431\u043E\u0440 \u043F\u0440\u0438 \u0440\u0430\u0441\u0445\u043E\u0436\u0434\u0435\u043D\u0438\u0438.\n */\nexport function parseUnifiedDiff(patch: string): DiffFile[] {\n if (patch.length > MAX_DIFF_BYTES) {\n throw new DiffParseError(`diff is larger than ${Math.round(MAX_DIFF_BYTES / 1024 / 1024)} MB: open a smaller range`);\n }\n const lines = patch.replace(/\\r\\n/g, '\\n').split('\\n');\n const files: DiffFile[] = [];\n let current: DiffFile | null = null;\n let index = 0;\n\n const start = (oldPath: string, newPath: string): DiffFile => {\n const file: DiffFile = {\n path: newPath || oldPath,\n oldPath: oldPath || newPath,\n status: 'modified',\n binary: false,\n hunks: [],\n };\n files.push(file);\n return file;\n };\n\n while (index < lines.length) {\n const line = lines[index]!;\n if (line.startsWith('diff --git ')) {\n const { oldPath, newPath } = splitGitHeader(line);\n current = start(oldPath, newPath);\n index++;\n continue;\n }\n if (!current && line.startsWith('--- ')) {\n current = start(cleanPath(line.slice(4)), '');\n current.status = 'modified';\n index++;\n continue;\n }\n if (!current) {\n index++;\n continue;\n }\n if (line.startsWith('new file mode')) {\n current.status = 'added';\n index++;\n continue;\n }\n if (line.startsWith('deleted file mode')) {\n current.status = 'deleted';\n index++;\n continue;\n }\n if (line.startsWith('rename from ')) {\n current.oldPath = cleanPath(line.slice('rename from '.length));\n current.status = 'renamed';\n index++;\n continue;\n }\n if (line.startsWith('rename to ')) {\n current.path = cleanPath(line.slice('rename to '.length));\n current.status = 'renamed';\n index++;\n continue;\n }\n if (line.startsWith('Binary files ') || line === 'GIT binary patch') {\n current.binary = true;\n index++;\n continue;\n }\n if (current.hunks.length === 0 && line.startsWith('--- ')) {\n const value = line.slice(4).trim();\n if (value === '/dev/null') {\n current.status = 'added';\n } else {\n current.oldPath = cleanPath(value);\n }\n index++;\n continue;\n }\n if (current.hunks.length === 0 && line.startsWith('+++ ')) {\n const value = line.slice(4).trim();\n if (value === '/dev/null') {\n current.status = 'deleted';\n } else {\n current.path = cleanPath(value);\n }\n index++;\n continue;\n }\n if (line.startsWith('@@')) {\n const hunk = parseHunkHeader(line);\n current.hunks.push(hunk);\n index++;\n let oldLeft = hunk.oldLines;\n let newLeft = hunk.newLines;\n let oldNo = hunk.oldStart;\n let newNo = hunk.newStart;\n while (index < lines.length) {\n const body = lines[index]!;\n // \u0421\u0442\u0440\u043E\u043A\u0438 `--- `/`+++ ` \u0432\u043D\u0443\u0442\u0440\u0438 \u0445\u0443\u043D\u043A\u0430 \u2014 \u044D\u0442\u043E \u0443\u0434\u0430\u043B\u0451\u043D\u043D\u0430\u044F `-- x` \u0438\u043B\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043D\u0430\u044F `++ x`,\n // \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u0433\u0440\u0430\u043D\u0438\u0446\u0435\u0439 \u0441\u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0433\u043E \u0445\u0443\u043D\u043A\u0430 \u0438 \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B.\n if (body.startsWith('diff --git ') || body.startsWith('@@')) break;\n // \u0424\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0439 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u0438 \u043F\u0430\u0442\u0447\u0430 \u0434\u0430\u0451\u0442 \u043F\u0443\u0441\u0442\u043E\u0439 \u044D\u043B\u0435\u043C\u0435\u043D\u0442; \u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430-\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\n // \u0432 git-\u0434\u0438\u0444\u0444\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0441 \u043F\u0440\u043E\u0431\u0435\u043B\u0430.\n if (body === '' && index === lines.length - 1) break;\n if (body.startsWith('\\\\')) {\n index++;\n continue;\n }\n const marker = body[0] ?? '';\n let parsed: DiffLine;\n if (marker === '+') {\n parsed = { kind: '+', text: body.slice(1), oldLine: null, newLine: newNo };\n newNo++;\n newLeft--;\n } else if (marker === '-') {\n parsed = { kind: '-', text: body.slice(1), oldLine: oldNo, newLine: null };\n oldNo++;\n oldLeft--;\n } else {\n // \u041A\u043E\u043D\u0442\u0435\u043A\u0441\u0442: \u0441\u0442\u0440\u043E\u043A\u0430 \u0441 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u043C \u0438\u043B\u0438 \u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 (\u043D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0442\u043E\u0440\u044B \u0442\u0435\u0440\u044F\u044E\u0442 \u043F\u0440\u043E\u0431\u0435\u043B).\n parsed = { kind: ' ', text: marker === ' ' ? body.slice(1) : body, oldLine: oldNo, newLine: newNo };\n oldNo++;\n newNo++;\n oldLeft--;\n newLeft--;\n }\n hunk.lines.push(parsed);\n index++;\n if (oldLeft <= 0 && newLeft <= 0) break;\n }\n continue;\n }\n index++;\n }\n\n return files.filter((file) => file.path && file.path !== '/dev/null');\n}\n\nexport function diffStats(files: DiffFile[]): { files: number; additions: number; deletions: number } {\n let additions = 0;\n let deletions = 0;\n for (const file of files) {\n for (const hunk of file.hunks) {\n for (const line of hunk.lines) {\n if (line.kind === '+') additions++;\n else if (line.kind === '-') deletions++;\n }\n }\n }\n return { files: files.length, additions, deletions };\n}\n\nexport function changedPaths(files: DiffFile[]): string[] {\n return files.map((file) => file.path);\n}\n\nexport function findFile(files: DiffFile[], path: string): DiffFile | undefined {\n return files.find((file) => file.path === path) ?? files.find((file) => file.oldPath === path);\n}\n\n/** \u0421\u0442\u0440\u043E\u043A\u0430 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 (\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0438\u043B\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043D\u0430\u044F), \u043A \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u043C\u043E\u0436\u043D\u043E \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439. */\nexport function findNewLine(files: DiffFile[], path: string, line: number): DiffLine | undefined {\n const file = findFile(files, path);\n if (!file) return undefined;\n for (const hunk of file.hunks) {\n for (const item of hunk.lines) {\n if (item.newLine === line) return item;\n }\n }\n return undefined;\n}\n\nexport function isLineInDiff(files: DiffFile[], path: string, line: number): boolean {\n return findNewLine(files, path, line) !== undefined;\n}\n\nexport interface SnippetLine {\n kind: '+' | '-' | ' ';\n oldLine: number | null;\n newLine: number | null;\n text: string;\n target: boolean;\n}\n\n/** \u0424\u0440\u0430\u0433\u043C\u0435\u043D\u0442 diff \u0432\u043E\u043A\u0440\u0443\u0433 \u0441\u0442\u0440\u043E\u043A\u0438 \u2014 \u0434\u043B\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0439 \u0432 UI. */\nexport function snippetAround(files: DiffFile[], path: string, line: number | null, radius = 6): SnippetLine[] | null {\n const file = findFile(files, path);\n if (!file || line == null) return null;\n const flat: DiffLine[] = file.hunks.flatMap((hunk) => hunk.lines);\n const target = flat.findIndex((item) => item.newLine === line);\n if (target < 0) return null;\n return flat\n .slice(Math.max(0, target - radius), target + radius + 1)\n .map((item) => ({\n kind: item.kind,\n oldLine: item.oldLine,\n newLine: item.newLine,\n text: item.text.length > 400 ? `${item.text.slice(0, 400)}\u2026` : item.text,\n target: item.newLine === line,\n }));\n}\n\n/** \u041F\u043E\u0437\u0438\u0446\u0438\u044F \u0434\u043B\u044F GitLab: \u043D\u0435\u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438 old_line, \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E new_line. */\nexport function linePosition(\n files: DiffFile[],\n path: string,\n line: number,\n): { newPath: string; newLine: number; oldPath: string; oldLine: number | null } | null {\n const file = findFile(files, path);\n const found = findNewLine(files, path, line);\n if (!file || !found) return null;\n return { newPath: file.path, newLine: line, oldPath: file.oldPath, oldLine: found.kind === ' ' ? found.oldLine : null };\n}\n", "import { execFile } from 'node:child_process';\n\nexport interface RunOptions {\n cwd?: string;\n /** \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435; \u0441\u0435\u043A\u0440\u0435\u0442\u044B \u0438\u0437 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u044F \u0432\u044B\u0447\u0438\u0449\u0430\u044E\u0442\u0441\u044F \u0432\u0441\u0435\u0433\u0434\u0430. */\n env?: Record<string, string>;\n timeoutMs?: number;\n maxBuffer?: number;\n /** \u0420\u0430\u0437\u0440\u0435\u0448\u0451\u043D\u043D\u044B\u0435 \u043A\u043E\u0434\u044B \u0432\u043E\u0437\u0432\u0440\u0430\u0442\u0430 \u0441\u0432\u0435\u0440\u0445 \u043D\u0443\u043B\u044F. */\n allowExitCodes?: number[];\n input?: string;\n}\n\nexport interface RunResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\nexport type Runner = (command: string, args: string[], options?: RunOptions) => Promise<RunResult>;\n\n/** \u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u044B \u043F\u043E\u043F\u0430\u0434\u0430\u0442\u044C \u0434\u043E\u0447\u0435\u0440\u043D\u0435\u043C\u0443 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0443: \u0442\u043E\u043A\u0435\u043D\u044B \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0438 \u0430\u0433\u0435\u043D\u0442\u0443. */\nconst SECRET_ENV = [\n 'GITLAB_TOKEN',\n 'GITLAB_PRIVATE_TOKEN',\n 'GLAB_TOKEN',\n 'CI_JOB_TOKEN',\n 'GH_TOKEN',\n 'GITHUB_TOKEN',\n 'GITHUB_ENTERPRISE_TOKEN',\n 'GIT_ASKPASS',\n 'SSH_ASKPASS',\n 'REVDECK_TOKEN',\n];\n\nexport function scrubEnv(extra?: Record<string, string>): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const [key, value] of Object.entries(process.env)) {\n if (SECRET_ENV.includes(key)) continue;\n env[key] = value;\n }\n // \u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u043E\u0435 \u043D\u0435\u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0435 \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u0435 CLI: \u0431\u0435\u0437 \u043F\u0435\u0439\u0434\u0436\u0435\u0440\u0430, \u0446\u0432\u0435\u0442\u0430 \u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043F\u0430\u0440\u043E\u043B\u044F.\n env.PAGER = 'cat';\n env.GIT_PAGER = 'cat';\n env.GIT_TERMINAL_PROMPT = '0';\n env.NO_COLOR = '1';\n env.CLICOLOR = '0';\n env.FORCE_COLOR = '0';\n env.TERM = 'dumb';\n return { ...env, ...extra };\n}\n\nexport const run: Runner = (command, args, options = {}) =>\n new Promise((resolve, reject) => {\n const child = execFile(\n command,\n args,\n {\n cwd: options.cwd,\n env: scrubEnv(options.env),\n timeout: options.timeoutMs ?? 120_000,\n maxBuffer: options.maxBuffer ?? 64 * 1024 * 1024,\n encoding: 'utf8',\n windowsHide: true,\n shell: false,\n },\n (error, stdout, stderr) => {\n const exitCode = (error as { code?: unknown } | null)?.code;\n const code = typeof exitCode === 'number' ? exitCode : error ? 1 : 0;\n if (error && !(options.allowExitCodes ?? []).includes(code)) {\n const reason = (stderr || stdout || error.message).trim();\n reject(Object.assign(new Error(reason.slice(0, 4000)), { command, code, stderr, stdout }));\n return;\n }\n resolve({ stdout, stderr, code });\n },\n );\n if (options.input !== undefined) {\n child.stdin?.end(options.input);\n }\n });\n\n/** \u0415\u0441\u0442\u044C \u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u0435\u043C\u044B\u0439 \u0444\u0430\u0439\u043B \u0432 PATH. */\nexport async function which(command: string): Promise<boolean> {\n try {\n await run(process.platform === 'win32' ? 'where' : 'which', [command], { timeoutMs: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n", "import { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport path from 'node:path';\nimport { AuthError, ProviderError } from '../core/errors.js';\nimport { redact } from '../core/redact.js';\nimport type { Platform } from '../core/types.js';\nimport { tr } from '../core/locale.js';\n\n/** JSON \u0438\u0437 stdout CLI; \u043E\u0448\u0438\u0431\u043A\u0430 \u0440\u0430\u0437\u0431\u043E\u0440\u0430 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u0430 \u043F\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044C\u0441\u044F \u0432 \u00AB\u043F\u0443\u0441\u0442\u043E\u0439 \u043E\u0442\u0432\u0435\u0442\u00BB. */\nexport function parseJson<T>(stdout: string, source: string): T {\n const text = stdout.trim();\n if (!text) throw new ProviderError(tr(`${source}: \u043F\u0443\u0441\u0442\u043E\u0439 \u043E\u0442\u0432\u0435\u0442`, `${source}: empty response`));\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new ProviderError(tr(`${source}: \u043E\u0442\u0432\u0435\u0442 \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F JSON (${redact(text).slice(0, 200)})`, `${source}: response is not JSON (${redact(text).slice(0, 200)})`));\n }\n}\n\n/** \u041E\u0448\u0438\u0431\u043A\u0430 CLI \u2192 \u043F\u043E\u043D\u044F\u0442\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0431\u0435\u0437 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u043E\u0439 \u043F\u0440\u043E \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044E. */\nexport function cliError(error: unknown, platform: Platform, host: string): never {\n const message = redact((error as Error)?.message ?? error).trim();\n const lower = message.toLowerCase();\n if (/(auth|unauthor|401|403|not logged|token|credential|forbidden)/.test(lower)) {\n const hint =\n platform === 'gitlab'\n ? tr(`\u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 glab \u043D\u0430 \u044D\u0442\u043E\u043C \u0445\u043E\u0441\u0442\u0435: glab auth login --hostname ${host}`, `log in to glab for this host: glab auth login --hostname ${host}`)\n : tr(`\u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 gh: GH_HOST=${host} gh auth login`, `log in to gh: GH_HOST=${host} gh auth login`);\n throw new AuthError(`${platform}: ${message || tr('\u043D\u0435\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438', 'not authenticated')}`, hint);\n }\n if (/(not found|404)/.test(lower)) throw new ProviderError(`${platform}: ${message}`, tr('\u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0440\u0435\u0432\u044C\u044E \u0438 \u0434\u043E\u0441\u0442\u0443\u043F \u043A \u043F\u0440\u043E\u0435\u043A\u0442\u0443', 'check the review number and project access'));\n throw new ProviderError(`${platform}: ${message || tr('\u043A\u043E\u043C\u0430\u043D\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u0430\u0441\u044C \u0441 \u043E\u0448\u0438\u0431\u043A\u043E\u0439', 'the command failed')}`);\n}\n\n/** \u0412\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B \u0441 JSON-\u0442\u0435\u043B\u043E\u043C 0600 \u0434\u043B\u044F `--input`; \u0443\u0434\u0430\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u0432\u044B\u0437\u043E\u0432\u0430. */\nexport async function withTempJson<T>(data: unknown, fn: (file: string) => Promise<T>): Promise<T> {\n const dir = await mkdtemp(path.join(tmpdir(), 'revdeck-'));\n const file = path.join(dir, 'payload.json');\n try {\n await writeFile(file, JSON.stringify(data), { mode: 0o600, flag: 'wx' });\n return await fn(file);\n } finally {\n await rm(dir, { recursive: true, force: true });\n }\n}\n\nexport function query(path: string, params: Record<string, string | number | undefined>): string {\n // \u0412\u0435\u0434\u0443\u0449\u0438\u0439 \u0441\u043B\u044D\u0448 \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u0430\u0440\u0441\u0435\u0440\u043E\u043C URL; API glab/gh \u043E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u0443\u0442\u044C \u0431\u0435\u0437 \u043D\u0435\u0433\u043E.\n const url = new URL(path.startsWith('/') ? path : `/${path}`, 'http://local');\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== '') url.searchParams.set(key, String(value));\n }\n return `${url.pathname.replace(/^\\//, '')}${url.search}`;\n}\n", "import { tmpdir } from 'node:os';\nimport type { DiffFile, Note, Platform, ReviewInfo, ReviewRef, Thread, User } from '../core/types.js';\nimport { parseUnifiedDiff } from '../core/diff.js';\nimport { ProviderError } from '../core/errors.js';\nimport { redact } from '../core/redact.js';\nimport { run as realRun, type Runner } from '../core/exec.js';\nimport { parseJson, cliError, query, withTempJson } from './util.js';\nimport { tr } from '../core/locale.js';\nimport type { CreateThreadInput, CreatedThread, ListOptions, Provider, ProviderOptions, ReviewListItem } from './provider.js';\n\ninterface GlUser {\n id: number;\n username: string;\n name: string;\n}\n\ninterface GlNote {\n id: number;\n body: string;\n system: boolean;\n resolvable?: boolean;\n resolved?: boolean;\n created_at: string;\n author?: GlUser;\n position?: {\n new_path?: string | null;\n old_path?: string | null;\n new_line?: number | null;\n old_line?: number | null;\n position_type?: string;\n } | null;\n}\n\ninterface GlDiscussion {\n id: string;\n notes: GlNote[];\n}\n\ninterface GlMergeRequest {\n iid: number;\n title: string;\n description: string | null;\n author?: GlUser;\n state: string;\n draft?: boolean;\n work_in_progress?: boolean;\n source_branch: string;\n target_branch: string;\n web_url: string;\n sha?: string;\n updated_at: string;\n changes_count?: string | null;\n diff_refs?: { base_sha?: string; start_sha?: string; head_sha?: string } | null;\n}\n\ninterface GlDiffFile {\n old_path: string;\n new_path: string;\n new_file: boolean;\n deleted_file: boolean;\n renamed_file: boolean;\n diff: string;\n too_large?: boolean;\n binary?: boolean;\n}\n\nconst EMPTY_SHA = '0000000000000000000000000000000000000000';\n\nexport class GitLabProvider implements Provider {\n readonly platform: Platform = 'gitlab';\n readonly capabilities = { reactions: true, resolve: true, nativeDrafts: true };\n private readonly run: Runner;\n private me: User | null = null;\n private infoCache: ReviewInfo | null = null;\n\n constructor(\n readonly ref: ReviewRef,\n private readonly options: ProviderOptions,\n ) {\n this.run = options.runImpl ?? realRun;\n }\n\n private get projectRef(): string {\n return encodeURIComponent(this.ref.project);\n }\n\n private endpoint(suffix: string): string {\n return `projects/${this.projectRef}/merge_requests/${this.ref.number}${suffix}`;\n }\n\n private async call(args: string[]): Promise<string> {\n const inputIndex = args.indexOf('--input');\n const withHeaders = inputIndex >= 0 && !args.includes('-H')\n ? [...args.slice(0, inputIndex), '-H', 'Content-Type: application/json', ...args.slice(inputIndex)]\n : args;\n try {\n const { stdout } = await this.run('glab', ['api', '--hostname', this.ref.host, ...withHeaders], {\n // \u0412\u043D\u0435 \u0440\u0430\u0431\u043E\u0447\u0435\u0439 \u043A\u043E\u043F\u0438\u0438: `.git/config`, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043C\u043E\u0436\u0435\u0442 \u043C\u0435\u043D\u044F\u0442\u044C \u0430\u0433\u0435\u043D\u0442, \u043D\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442.\n cwd: tmpdir(),\n timeoutMs: 90_000,\n maxBuffer: 64 * 1024 * 1024,\n });\n return stdout;\n } catch (error) {\n cliError(error, 'gitlab', this.ref.host);\n }\n }\n\n private async json<T>(args: string[]): Promise<T> {\n return parseJson<T>(await this.call(args), `GitLab ${this.ref.project}!${this.ref.number}`);\n }\n\n private async paged<T>(endpoint: string, params: Record<string, string | number | undefined> = {}): Promise<T[]> {\n const items: T[] = [];\n for (let page = 1; page <= 50; page++) {\n const chunk = await this.json<T[]>([query(endpoint, { ...params, per_page: 100, page })]);\n if (!Array.isArray(chunk)) throw new ProviderError(tr('GitLab: \u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u043C\u0430\u0441\u0441\u0438\u0432 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0430 \u0441\u043F\u0438\u0441\u043E\u043A', 'GitLab: expected an array in the list response'));\n items.push(...chunk);\n if (chunk.length < 100) break;\n }\n return items;\n }\n\n async info(): Promise<ReviewInfo> {\n if (this.infoCache) return this.infoCache;\n const mr = await this.json<GlMergeRequest>([this.endpoint('')]);\n const refs = mr.diff_refs ?? {};\n const base = refs.base_sha || mr.sha || EMPTY_SHA;\n const start = refs.start_sha || base;\n const head = refs.head_sha || mr.sha || EMPTY_SHA;\n const files = Number.parseInt(String(mr.changes_count ?? '0'), 10);\n const info: ReviewInfo = {\n ref: this.ref,\n title: String(mr.title ?? ''),\n description: String(mr.description ?? ''),\n author: mr.author?.username ?? '',\n authorName: mr.author?.name ?? '',\n state: String(mr.state ?? ''),\n draft: Boolean(mr.draft ?? mr.work_in_progress),\n sourceBranch: String(mr.source_branch ?? ''),\n targetBranch: String(mr.target_branch ?? ''),\n webUrl: String(mr.web_url ?? ''),\n commit: { base, start, head },\n updatedAt: String(mr.updated_at ?? ''),\n stats: { files: Number.isFinite(files) ? files : 0, additions: 0, deletions: 0 },\n };\n this.infoCache = info;\n return info;\n }\n\n async diff(): Promise<DiffFile[]> {\n const items = await this.paged<GlDiffFile>(this.endpoint('/diffs'));\n const chunks: string[] = [];\n for (const file of items) {\n const oldPath = file.old_path;\n const newPath = file.new_path;\n let header = `diff --git a/${oldPath} b/${newPath}\\n`;\n if (file.new_file) header += 'new file mode 100644\\n';\n if (file.deleted_file) header += 'deleted file mode 100644\\n';\n if (file.renamed_file) header += `rename from ${oldPath}\\nrename to ${newPath}\\n`;\n if (file.binary || file.too_large || !file.diff) {\n header += 'Binary files differ\\n';\n chunks.push(header);\n continue;\n }\n header += `--- ${file.new_file ? '/dev/null' : `a/${oldPath}`}\\n+++ ${file.deleted_file ? '/dev/null' : `b/${newPath}`}\\n`;\n chunks.push(header + file.diff);\n }\n return parseUnifiedDiff(chunks.join('\\n'));\n }\n\n async threads(): Promise<Thread[]> {\n const discussions = await this.paged<GlDiscussion>(this.endpoint('/discussions'));\n const threads: Thread[] = [];\n for (const discussion of discussions) {\n const notes = (discussion.notes ?? []).filter((note) => !note.system);\n if (!notes.length) continue;\n const placed = discussion.notes.find((note) => note.position) ?? discussion.notes[0];\n const position = placed?.position ?? null;\n const head = discussion.notes.find((note) => note.resolvable !== undefined) ?? discussion.notes[0];\n threads.push({\n id: String(discussion.id),\n path: position?.new_path ?? position?.old_path ?? null,\n line: position?.new_line ?? position?.old_line ?? null,\n side: position?.new_line ? 'new' : position?.old_line ? 'old' : null,\n resolvable: Boolean(head?.resolvable),\n resolved: Boolean(head?.resolved),\n notes: notes.map((note) => this.mapNote(note)),\n updatedAt: String(notes[notes.length - 1]?.created_at ?? ''),\n });\n }\n return threads;\n }\n\n private mapNote(note: GlNote): Note {\n return {\n id: String(note.id),\n author: note.author?.username ?? '?',\n authorName: note.author?.name ?? '',\n createdAt: String(note.created_at ?? ''),\n body: String(note.body ?? ''),\n system: Boolean(note.system),\n };\n }\n\n async currentUser(): Promise<User> {\n if (this.me) return this.me;\n const user = await this.json<GlUser>(['user']);\n this.me = { username: user.username, name: user.name };\n return this.me;\n }\n\n async list(options: ListOptions = {}): Promise<ReviewListItem[]> {\n const scope = options.scope ?? 'open';\n const limit = Math.min(options.limit ?? 50, 100);\n const params: Record<string, string | number | undefined> = {\n state: 'opened',\n order_by: 'updated_at',\n sort: 'desc',\n per_page: limit,\n };\n if (scope === 'mine') params.scope = 'created_by_me';\n if (scope === 'reviewing') {\n const me = await this.currentUser();\n params.scope = 'all';\n params.reviewer_username = me.username;\n }\n const items = await this.json<GlMergeRequest[]>([query(`projects/${this.projectRef}/merge_requests`, params)]);\n return (Array.isArray(items) ? items : []).map((mr) => ({\n ref: { ...this.ref, number: mr.iid },\n title: String(mr.title ?? ''),\n author: mr.author?.username ?? '',\n updatedAt: String(mr.updated_at ?? ''),\n state: String(mr.state ?? ''),\n draft: Boolean(mr.draft ?? mr.work_in_progress),\n webUrl: String(mr.web_url ?? ''),\n }));\n }\n\n async findByBranch(branch: string): Promise<ReviewRef | null> {\n const items = await this.json<GlMergeRequest[]>([query(`projects/${this.projectRef}/merge_requests`, { state: 'opened', source_branch: branch, per_page: 1 })]);\n const first = Array.isArray(items) ? items[0] : undefined;\n return first ? { ...this.ref, number: first.iid } : null;\n }\n\n async reply(thread: Thread, body: string): Promise<Note> {\n const endpoint = this.endpoint(`/discussions/${encodeURIComponent(thread.id)}/notes`);\n const note = await withTempJson({ body }, async (file) => this.json<GlNote>(['--method', 'POST', endpoint, '--input', file]));\n return this.mapNote(note);\n }\n\n async resolve(threadId: string, resolved: boolean): Promise<void> {\n await withTempJson({ resolved }, async (file) => {\n await this.call(['--method', 'PUT', this.endpoint(`/discussions/${encodeURIComponent(threadId)}`), '--input', file]);\n });\n }\n\n async react(noteId: string, emoji: string): Promise<{ active: boolean }> {\n const base = this.endpoint(`/notes/${encodeURIComponent(noteId)}/award_emoji`);\n const existing = await this.json<{ id: number; name: string; user?: GlUser }[]>([query(base, { per_page: 100 })]);\n const me = await this.currentUser();\n const mine = existing.find((item) => item.name === emoji && item.user?.username === me.username);\n if (mine) {\n await this.call(['--method', 'DELETE', `${base}/${mine.id}`]);\n return { active: false };\n }\n await withTempJson({ name: emoji }, async (file) => {\n await this.call(['--method', 'POST', base, '--input', file]);\n });\n return { active: true };\n }\n\n async createThread(input: CreateThreadInput): Promise<CreatedThread> {\n const info = await this.info();\n if (!info.commit.head || info.commit.head === EMPTY_SHA) {\n throw new ProviderError(tr('GitLab \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B SHA \u0440\u0435\u0432\u0438\u0437\u0438\u0439: \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043A \u0441\u0442\u0440\u043E\u043A\u0435 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D', 'GitLab did not return revision SHAs: a line comment is not possible'));\n }\n const payload =\n input.line === null\n ? { body: input.body }\n : {\n body: input.body,\n position: {\n position_type: 'text',\n base_sha: info.commit.base,\n start_sha: info.commit.start,\n head_sha: info.commit.head,\n new_path: input.file,\n old_path: input.file,\n new_line: input.line,\n ...(input.oldLine !== null ? { old_line: input.oldLine } : {}),\n },\n };\n const created = await withTempJson(payload, async (file) =>\n this.json<GlDiscussion>(['--method', 'POST', this.endpoint('/discussions'), '--input', file]),\n );\n const note = created.notes?.[0];\n if (!note) throw new ProviderError(tr('GitLab \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u043E\u0435 \u043E\u0431\u0441\u0443\u0436\u0434\u0435\u043D\u0438\u0435', 'GitLab did not return the created discussion'));\n return { discussionId: String(created.id), noteId: String(note.id) };\n }\n}\n\nexport function isAuthError(error: unknown): boolean {\n return /auth|401|403|unauthor|forbidden|not logged/i.test(redact(error));\n}\n", "import { tmpdir } from 'node:os';\nimport type { DiffFile, Note, Platform, ReviewInfo, ReviewRef, Thread, User } from '../core/types.js';\nimport { parseUnifiedDiff } from '../core/diff.js';\nimport { ProviderError } from '../core/errors.js';\nimport { run as realRun, type Runner } from '../core/exec.js';\nimport { parseJson, cliError, query, withTempJson } from './util.js';\nimport { tr } from '../core/locale.js';\nimport type { CreateThreadInput, CreatedThread, ListOptions, Provider, ProviderOptions, ReviewListItem } from './provider.js';\n\ninterface GhUser {\n login: string;\n name?: string | null;\n}\n\ninterface GhPull {\n number: number;\n title: string;\n body: string | null;\n user: GhUser | null;\n state: string;\n draft?: boolean;\n merged_at?: string | null;\n html_url: string;\n updated_at: string;\n changed_files?: number;\n additions?: number;\n deletions?: number;\n head: { ref: string; sha: string };\n base: { ref: string; sha: string };\n}\n\ninterface GhFile {\n filename: string;\n previous_filename?: string;\n status: string;\n additions?: number;\n deletions?: number;\n patch?: string;\n}\n\ninterface GhComment {\n id: number;\n body: string;\n user: GhUser | null;\n created_at: string;\n}\n\ninterface GqlComment {\n databaseId: number | null;\n id: string;\n author: { login: string } | null;\n body: string;\n createdAt: string;\n}\n\ninterface GqlThread {\n id: string;\n isResolved: boolean;\n isOutdated: boolean;\n path: string | null;\n line: number | null;\n originalLine: number | null;\n diffSide: 'LEFT' | 'RIGHT' | null;\n comments: { nodes: GqlComment[] };\n}\n\ninterface GqlThreads {\n repository: {\n pullRequest: {\n reviewThreads: {\n pageInfo: { hasNextPage: boolean; endCursor: string | null };\n nodes: GqlThread[];\n };\n } | null;\n } | null;\n}\n\nconst THREADS_QUERY = `query($owner: String!, $name: String!, $number: Int!, $after: String) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $after) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id isResolved isOutdated path line originalLine diffSide\n comments(first: 100) {\n nodes { databaseId id author { login } body createdAt }\n }\n }\n }\n }\n }\n}`;\n\nconst REACTIONS: Record<string, string> = {\n thumbsup: '+1',\n thumbsdown: '-1',\n smile: 'laugh',\n tada: 'hooray',\n confused: 'confused',\n heart: 'heart',\n rocket: 'rocket',\n eyes: 'eyes',\n};\n\nexport class GitHubProvider implements Provider {\n readonly platform: Platform = 'github';\n readonly capabilities = { reactions: true, resolve: true, nativeDrafts: false };\n private readonly run: Runner;\n private readonly owner: string;\n private readonly name: string;\n private me: User | null = null;\n private infoCache: ReviewInfo | null = null;\n\n constructor(\n readonly ref: ReviewRef,\n private readonly options: ProviderOptions,\n ) {\n this.run = options.runImpl ?? realRun;\n const [owner, name, ...rest] = ref.project.split('/');\n if (!owner || !name || rest.length) {\n throw new ProviderError(tr(`GitHub: \u043F\u0440\u043E\u0435\u043A\u0442 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C owner/repo, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E ${ref.project}`, `GitHub: project must be owner/repo, got ${ref.project}`));\n }\n this.owner = owner;\n this.name = name;\n }\n\n private get repo(): string {\n return `${this.owner}/${this.name}`;\n }\n\n private get pullBase(): string {\n return `repos/${this.repo}/pulls/${this.ref.number}`;\n }\n\n private async call(args: string[]): Promise<string> {\n const inputIndex = args.indexOf('--input');\n const withHeaders = inputIndex >= 0 && !args.includes('-H')\n ? [...args.slice(0, inputIndex), '-H', 'Content-Type: application/json', ...args.slice(inputIndex)]\n : args;\n try {\n const { stdout } = await this.run('gh', ['api', ...withHeaders], {\n cwd: tmpdir(),\n env: { GH_HOST: this.ref.host },\n timeoutMs: 90_000,\n maxBuffer: 64 * 1024 * 1024,\n });\n return stdout;\n } catch (error) {\n cliError(error, 'github', this.ref.host);\n }\n }\n\n private async json<T>(args: string[]): Promise<T> {\n return parseJson<T>(await this.call(args), `GitHub ${this.ref.project}#${this.ref.number}`);\n }\n\n private async paged<T>(endpoint: string, params: Record<string, string | number | undefined> = {}): Promise<T[]> {\n const items: T[] = [];\n for (let page = 1; page <= 50; page++) {\n const chunk = await this.json<T[]>([query(endpoint, { ...params, per_page: 100, page })]);\n if (!Array.isArray(chunk)) throw new ProviderError(tr('GitHub: \u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u043C\u0430\u0441\u0441\u0438\u0432 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0430 \u0441\u043F\u0438\u0441\u043E\u043A', 'GitHub: expected an array in the list response'));\n items.push(...chunk);\n if (chunk.length < 100) break;\n }\n return items;\n }\n\n private async graphql<T>(queryText: string, variables: Record<string, string | number | null | undefined>): Promise<T> {\n const args = ['graphql', '-f', `query=${queryText}`];\n for (const [key, value] of Object.entries(variables)) {\n if (value === null || value === undefined) continue;\n args.push(typeof value === 'number' ? '-F' : '-f', `${key}=${value}`);\n }\n const data = await this.json<{ data?: T; errors?: { message: string }[] }>(args);\n if (data.errors?.length) throw new ProviderError(`GitHub GraphQL: ${data.errors.map((item) => item.message).join('; ')}`);\n if (!data.data) throw new ProviderError(tr('GitHub GraphQL: \u043F\u0443\u0441\u0442\u043E\u0439 \u043E\u0442\u0432\u0435\u0442', 'GitHub GraphQL: empty response'));\n return data.data;\n }\n\n async info(): Promise<ReviewInfo> {\n if (this.infoCache) return this.infoCache;\n const pr = await this.json<GhPull>([this.pullBase]);\n const state = pr.merged_at ? 'merged' : String(pr.state ?? '');\n const info: ReviewInfo = {\n ref: this.ref,\n title: String(pr.title ?? ''),\n description: String(pr.body ?? ''),\n author: pr.user?.login ?? '',\n authorName: pr.user?.name ?? '',\n state,\n draft: Boolean(pr.draft),\n sourceBranch: String(pr.head?.ref ?? ''),\n targetBranch: String(pr.base?.ref ?? ''),\n webUrl: String(pr.html_url ?? ''),\n commit: { base: String(pr.base?.sha ?? ''), start: String(pr.base?.sha ?? ''), head: String(pr.head?.sha ?? '') },\n updatedAt: String(pr.updated_at ?? ''),\n stats: {\n files: Number(pr.changed_files ?? 0),\n additions: Number(pr.additions ?? 0),\n deletions: Number(pr.deletions ?? 0),\n },\n };\n this.infoCache = info;\n return info;\n }\n\n async diff(): Promise<DiffFile[]> {\n const files = await this.paged<GhFile>(`${this.pullBase}/files`);\n const chunks: string[] = [];\n for (const file of files) {\n const oldPath = file.previous_filename ?? file.filename;\n const newPath = file.filename;\n let header = `diff --git a/${oldPath} b/${newPath}\\n`;\n if (file.status === 'added') header += 'new file mode 100644\\n--- /dev/null\\n+++ b/';\n else if (file.status === 'removed') header += 'deleted file mode 100644\\n--- a/';\n else if (file.status === 'renamed') header += `rename from ${oldPath}\\nrename to ${newPath}\\n--- a/${oldPath}\\n+++ b/`;\n else header += `--- a/${oldPath}\\n+++ b/`;\n header += file.status === 'removed' ? '/dev/null\\n' : `${newPath}\\n`;\n if (!file.patch) {\n chunks.push(`${header}Binary files differ\\n`);\n continue;\n }\n chunks.push(header + file.patch);\n }\n return parseUnifiedDiff(chunks.join('\\n'));\n }\n\n async threads(): Promise<Thread[]> {\n const nodes: GqlThread[] = [];\n let after: string | null = null;\n for (let page = 0; page < 10; page++) {\n const data: GqlThreads = await this.graphql<GqlThreads>(THREADS_QUERY, {\n owner: this.owner,\n name: this.name,\n number: this.ref.number,\n after,\n });\n const connection = data.repository?.pullRequest?.reviewThreads;\n if (!connection) throw new ProviderError(tr('GitHub: \u0442\u0440\u0435\u0434\u044B \u0440\u0435\u0432\u044C\u044E \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B (\u043D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u0430?)', 'GitHub: review threads not found (no access?)'));\n nodes.push(...connection.nodes);\n if (!connection.pageInfo.hasNextPage) break;\n after = connection.pageInfo.endCursor;\n }\n return nodes\n .filter((node) => node.comments.nodes.length > 0)\n .map((node) => {\n const notes = node.comments.nodes.map((comment) => this.mapGqlNote(comment));\n return {\n id: node.id,\n path: node.path,\n line: node.line ?? node.originalLine,\n side: node.diffSide === 'LEFT' ? ('old' as const) : ('new' as const),\n resolvable: true,\n resolved: node.isResolved,\n notes,\n updatedAt: notes[notes.length - 1]?.createdAt ?? '',\n };\n });\n }\n\n private mapGqlNote(comment: GqlComment): Note {\n return {\n id: String(comment.databaseId ?? comment.id),\n author: comment.author?.login ?? '?',\n authorName: '',\n createdAt: String(comment.createdAt ?? ''),\n body: String(comment.body ?? ''),\n system: false,\n };\n }\n\n async currentUser(): Promise<User> {\n if (this.me) return this.me;\n const user = await this.json<GhUser>(['user']);\n this.me = { username: user.login, name: user.name ?? '' };\n return this.me;\n }\n\n async list(options: ListOptions = {}): Promise<ReviewListItem[]> {\n const limit = Math.min(options.limit ?? 50, 100);\n if (options.scope === 'reviewing') {\n const search = await this.json<{ items: { number: number; title: string; user: GhUser | null; updated_at: string; html_url: string; state: string; draft?: boolean }[] }>([\n query('search/issues', { q: `repo:${this.repo} is:pr is:open review-requested:@me`, per_page: limit }),\n ]);\n return (search.items ?? []).map((item) => ({\n ref: { ...this.ref, number: item.number },\n title: item.title,\n author: item.user?.login ?? '',\n updatedAt: item.updated_at,\n state: item.state,\n draft: Boolean(item.draft),\n webUrl: item.html_url,\n }));\n }\n const pulls = await this.paged<GhPull>(`repos/${this.repo}/pulls`, { state: 'open', sort: 'updated', direction: 'desc' });\n const me = options.scope === 'mine' ? (await this.currentUser()).username : null;\n return pulls\n .filter((pull) => !me || pull.user?.login === me)\n .slice(0, limit)\n .map((pull) => ({\n ref: { ...this.ref, number: pull.number },\n title: pull.title,\n author: pull.user?.login ?? '',\n updatedAt: pull.updated_at,\n state: pull.state,\n draft: Boolean(pull.draft),\n webUrl: pull.html_url,\n }));\n }\n\n async findByBranch(branch: string): Promise<ReviewRef | null> {\n const pulls = await this.json<GhPull[]>([query(`repos/${this.repo}/pulls`, { state: 'open', head: `${this.owner}:${branch}`, per_page: 1 })]);\n const first = Array.isArray(pulls) ? pulls[0] : undefined;\n return first ? { ...this.ref, number: first.number } : null;\n }\n\n async reply(thread: Thread, body: string): Promise<Note> {\n const root = thread.notes[0]?.id;\n if (!root) throw new ProviderError(tr('\u0432 \u0442\u0440\u0435\u0434\u0435 \u043D\u0435\u0442 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043C\u043E\u0436\u043D\u043E \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C', 'the thread has no comment to reply to'));\n const comment = await withTempJson({ body }, async (file) =>\n this.json<GhComment>(['--method', 'POST', `${this.pullBase}/comments/${root}/replies`, '--input', file]),\n );\n return {\n id: String(comment.id),\n author: comment.user?.login ?? '?',\n authorName: '',\n createdAt: comment.created_at,\n body: comment.body,\n system: false,\n };\n }\n\n async resolve(threadId: string, resolved: boolean): Promise<void> {\n const mutation = resolved\n ? 'mutation($id: ID!) { resolveReviewThread(input: { threadId: $id }) { thread { isResolved } } }'\n : 'mutation($id: ID!) { unresolveReviewThread(input: { threadId: $id }) { thread { isResolved } } }';\n await this.graphql<unknown>(mutation, { id: threadId });\n }\n\n async react(noteId: string, emoji: string): Promise<{ active: boolean }> {\n const content = REACTIONS[emoji];\n if (!content) throw new ProviderError(tr(`GitHub \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u0430\u043A\u0446\u0438\u044E ${emoji}`, `GitHub does not support reaction ${emoji}`));\n const base = `repos/${this.repo}/pulls/comments/${noteId}/reactions`;\n const existing = await this.json<{ id: number; content: string; user: GhUser | null }[]>([query(base, { per_page: 100 })]);\n const me = await this.currentUser();\n const mine = existing.find((item) => item.content === content && item.user?.login === me.username);\n if (mine) {\n await this.call(['--method', 'DELETE', `${base}/${mine.id}`]);\n return { active: false };\n }\n await withTempJson({ content }, async (file) => {\n await this.call(['--method', 'POST', base, '--input', file]);\n });\n return { active: true };\n }\n\n async createThread(input: CreateThreadInput): Promise<CreatedThread> {\n if (input.line === null) {\n const comment = await withTempJson({ body: input.body }, async (file) =>\n this.json<GhComment>(['--method', 'POST', `repos/${this.repo}/issues/${this.ref.number}/comments`, '--input', file]),\n );\n return { discussionId: `issue-${comment.id}`, noteId: String(comment.id) };\n }\n const info = await this.info();\n if (!info.commit.head) throw new ProviderError(tr('GitHub \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B head SHA: \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043A \u0441\u0442\u0440\u043E\u043A\u0435 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D', 'GitHub did not return the head SHA: a line comment is not possible'));\n const payload = {\n body: input.body,\n commit_id: info.commit.head,\n path: input.file,\n line: input.line,\n side: 'RIGHT',\n };\n const comment = await withTempJson(payload, async (file) =>\n this.json<GhComment>(['--method', 'POST', `${this.pullBase}/comments`, '--input', file]),\n );\n return { discussionId: `gh-${comment.id}`, noteId: String(comment.id) };\n }\n}\n", "#!/usr/bin/env node\nimport { existsSync, readFileSync } from 'node:fs';\nimport { appendFile, open, readFile, unlink } from 'node:fs/promises';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { parseArgs } from 'node:util';\nimport { daemonInfoPath, ensureDir, databasePath, logPath, runtimeDir, socketPath, stateDir, writeFileAtomic } from '../core/paths.js';\nimport { redactLine } from '../core/redact.js';\nimport { PROTOCOL_VERSION, VERSION } from '../version.js';\nimport { detectLocale, setLocale, tr } from '../core/locale.js';\nimport { Store } from './store.js';\nimport { ReviewService } from './service.js';\nimport { startHttpServer } from './http.js';\nimport { startRpcServer } from './rpc.js';\n\nexport interface DaemonInfo {\n pid: number;\n port: number;\n token: string;\n url: string;\n socket: string;\n startedAt: string;\n version: string;\n protocol: number;\n}\n\nasync function main(): Promise<void> {\n setLocale(detectLocale());\n const { values } = parseArgs({\n options: {\n port: { type: 'string' },\n 'state-dir': { type: 'string' },\n 'runtime-dir': { type: 'string' },\n 'ui-dir': { type: 'string' },\n foreground: { type: 'boolean', default: false },\n 'sync-interval': { type: 'string' },\n },\n allowPositionals: false,\n });\n\n if (values['state-dir']) process.env.REVDECK_STATE_DIR = values['state-dir'];\n if (values['runtime-dir']) process.env.REVDECK_RUNTIME_DIR = values['runtime-dir'];\n\n const foreground = values.foreground === true;\n const log = async (line: string): Promise<void> => {\n const message = `${new Date().toISOString()} ${redactLine(line, 4000)}\\n`;\n if (foreground) process.stderr.write(message);\n try {\n await appendFile(logPath(), message, { mode: 0o600 });\n } catch {\n // \u041B\u043E\u0433 \u043D\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D: \u0434\u0435\u043C\u043E\u043D \u0434\u043E\u043B\u0436\u0435\u043D \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u0438 \u0431\u0435\u0437 \u043D\u0435\u0433\u043E.\n }\n };\n\n const existing = await runningDaemon();\n if (existing) {\n process.stdout.write(`revdeck daemon ${tr('\u0443\u0436\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D', 'is already running')} (pid ${existing.pid}): ${existing.url}/\\n`);\n return;\n }\n\n await ensureDir(stateDir(), 0o700);\n await ensureDir(runtimeDir(), 0o700);\n const lock = await acquireLock();\n if (!lock) {\n process.stdout.write(`revdeck daemon ${tr('\u0443\u0436\u0435 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u0438\u043B\u0438 \u0437\u0430\u043F\u0443\u0449\u0435\u043D', 'is already starting or running')}\\n`);\n return;\n }\n const token = (await import('node:crypto')).randomBytes(32).toString('hex');\n const store = new Store(databasePath());\n const service = new ReviewService({\n store,\n syncIntervalMs: values['sync-interval'] ? Number(values['sync-interval']) : 120_000,\n });\n const socket = socketPath();\n const rpc = await startRpcServer(service, socket);\n const uiDir = values['ui-dir'] ? path.resolve(values['ui-dir']) : path.join(packageRoot(), 'dist', 'ui');\n const http = await startHttpServer({\n service,\n token,\n uiDir,\n ...(values.port ? { port: Number(values.port) } : {}),\n version: VERSION,\n });\n const info: DaemonInfo = {\n pid: process.pid,\n port: http.port,\n token,\n url: http.url,\n socket,\n startedAt: new Date().toISOString(),\n version: VERSION,\n protocol: PROTOCOL_VERSION,\n };\n await writeFileAtomic(daemonInfoPath(), `${JSON.stringify(info, null, 2)}\\n`, 0o600);\n service.startSync();\n\n process.stdout.write(\n [\n `revdeck daemon ${VERSION} (pid ${process.pid})`,\n `UI: ${http.url}/?t=${token}`,\n `${tr('\u0441\u043E\u043A\u0435\u0442', 'socket')}: ${socket}`,\n `${tr('\u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435', 'state')}: ${stateDir()}`,\n '',\n ].join('\\n'),\n );\n await log(`daemon started pid=${process.pid} port=${http.port}`);\n\n let closing = false;\n const shutdown = async (signal: string): Promise<void> => {\n if (closing) return;\n closing = true;\n await log(`daemon stopping (${signal})`);\n try {\n await rpc.close();\n await http.close();\n } finally {\n service.close();\n await unlink(daemonInfoPath()).catch(() => undefined);\n await lock.close().catch(() => undefined);\n await unlink(path.join(stateDir(), 'daemon.lock')).catch(() => undefined);\n process.exit(0);\n }\n };\n for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'] as const) {\n process.on(signal, () => {\n if (signal === 'SIGHUP' && !foreground) return; // \u043E\u0442\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 \u0434\u0435\u043C\u043E\u043D \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0437\u0430\u043A\u0440\u044B\u0442\u0438\u0435 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430\n void shutdown(signal);\n });\n }\n}\n\nfunction packageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n for (;;) {\n const candidate = path.join(dir, 'package.json');\n if (existsSync(candidate)) {\n try {\n const parsed = JSON.parse(readFileSync(candidate, 'utf8')) as { name?: string };\n if (parsed.name === 'revdeck') return dir;\n } catch {\n // \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u043C \u043F\u043E\u0434\u043D\u0438\u043C\u0430\u0442\u044C\u0441\u044F\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) return process.cwd();\n dir = parent;\n }\n}\n\nasync function runningDaemon(): Promise<DaemonInfo | null> {\n const infoPath = daemonInfoPath();\n if (!existsSync(infoPath)) return null;\n let info: DaemonInfo;\n try {\n info = JSON.parse(readFileSync(infoPath, 'utf8')) as DaemonInfo;\n } catch {\n return null;\n }\n if (!info?.pid || !info?.socket) return null;\n try {\n process.kill(info.pid, 0);\n } catch {\n return null;\n }\n const reachable = await new Promise<boolean>((resolve) => {\n const socket = net.connect(info.socket);\n const timer = setTimeout(() => {\n socket.destroy();\n resolve(false);\n }, 500);\n socket.once('connect', () => {\n clearTimeout(timer);\n socket.destroy();\n resolve(true);\n });\n socket.once('error', () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n return reachable ? info : null;\n}\n\nasync function acquireLock(): Promise<Awaited<ReturnType<typeof open>> | null> {\n const file = path.join(stateDir(), 'daemon.lock');\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const handle = await open(file, 'wx', 0o600);\n await handle.writeFile(String(process.pid));\n return handle;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n const pid = Number(await readFile(file, 'utf8').catch(() => ''));\n if (pid) {\n try {\n process.kill(pid, 0);\n return null;\n } catch {\n // \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u043C\u0451\u0440\u0442\u0432 \u2014 \u0437\u0430\u043C\u043E\u043A \u0443\u0441\u0442\u0430\u0440\u0435\u043B\n }\n }\n await unlink(file).catch(() => undefined);\n }\n }\n return null;\n}\n\nvoid main().catch((error) => {\n process.stderr.write(`revdeck: ${redactLine(error instanceof Error ? error.message : error)}\\n`);\n process.exit(1);\n});\n", "import { existsSync } from 'node:fs';\nimport { lstat, mkdir, open, readFile, realpath, rename, unlink } from 'node:fs/promises';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\n/** \u041A\u043E\u0440\u0435\u043D\u044C \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F: \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0438\u0439 \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C \u0441 `.git`; \u0438\u043D\u0430\u0447\u0435 \u0442\u0435\u043A\u0443\u0449\u0438\u0439 \u043A\u0430\u0442\u0430\u043B\u043E\u0433. */\nexport function findRepoRoot(start = process.cwd()): string {\n let dir = path.resolve(start);\n for (;;) {\n if (existsSync(path.join(dir, '.git'))) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return path.resolve(start);\n dir = parent;\n }\n}\n\nexport const CONFIG_FILES = ['.revdeck.yml', '.revdeck.yaml'] as const;\nexport const CACHE_DIR = '.revdeck';\n\nexport function findConfigFile(root: string): string | null {\n for (const name of CONFIG_FILES) {\n const candidate = path.join(root, name);\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/** \u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0434\u0435\u043C\u043E\u043D\u0430: ~/.local/state/revdeck (\u0438\u043B\u0438 $XDG_STATE_HOME). */\nexport function stateDir(): string {\n if (process.env.REVDECK_STATE_DIR) return path.resolve(process.env.REVDECK_STATE_DIR);\n const base = process.env.XDG_STATE_HOME || path.join(os.homedir(), '.local', 'state');\n return path.join(base, 'revdeck');\n}\n\n/** \u0421\u043E\u043A\u0435\u0442 \u0438 pid: $XDG_RUNTIME_DIR/revdeck, \u0438\u043D\u0430\u0447\u0435 \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0439 \u043A\u0430\u0442\u0430\u043B\u043E\u0433 \u0432 tmp. */\nexport function runtimeDir(): string {\n if (process.env.REVDECK_RUNTIME_DIR) return path.resolve(process.env.REVDECK_RUNTIME_DIR);\n const base = process.env.XDG_RUNTIME_DIR || path.join(os.tmpdir(), `revdeck-${process.getuid?.() ?? 'user'}`);\n return path.join(base, 'revdeck');\n}\n\nexport function socketPath(): string {\n return path.join(runtimeDir(), 'daemon.sock');\n}\n\nexport function daemonInfoPath(): string {\n return path.join(stateDir(), 'daemon.json');\n}\n\nexport function logPath(): string {\n return path.join(stateDir(), 'daemon.log');\n}\n\nexport function databasePath(): string {\n return path.join(stateDir(), 'revdeck.sqlite3');\n}\n\nexport async function ensureDir(dir: string, mode = 0o700): Promise<void> {\n await mkdir(dir, { recursive: true, mode });\n const info = await lstat(dir);\n if (!info.isDirectory()) throw new Error(`${dir}: expected a directory`);\n if (process.platform !== 'win32') {\n const { chmod } = await import('node:fs/promises');\n await chmod(dir, mode);\n }\n}\n\n/** \u041F\u0443\u0442\u044C \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u0432\u043D\u0443\u0442\u0440\u0438 root (\u043F\u043E\u0441\u043B\u0435 resolve, \u0431\u0435\u0437 \u0443\u0447\u0451\u0442\u0430 \u0441\u0441\u044B\u043B\u043E\u043A). */\nexport function isInside(root: string, target: string): boolean {\n const relative = path.relative(path.resolve(root), path.resolve(target));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\n/**\n * \u0427\u0438\u0442\u0430\u0435\u0442 \u0442\u0435\u043A\u0441\u0442\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B, \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u044F\u0441\u044C \u0438\u0434\u0442\u0438 \u043F\u043E \u0441\u0438\u043C\u0432\u043E\u043B\u0438\u0447\u0435\u0441\u043A\u0438\u043C \u0441\u0441\u044B\u043B\u043A\u0430\u043C.\n * \u041A\u0430\u0442\u0430\u043B\u043E\u0433 `.revdeck` \u0438 \u0440\u0430\u0431\u043E\u0447\u0438\u0435 \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0438 \u043C\u043E\u0436\u0435\u0442 \u043C\u0435\u043D\u044F\u0442\u044C \u0430\u0433\u0435\u043D\u0442 \u2014 \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u0430\n * \u0443\u0432\u0435\u0441\u0442\u0438 \u0447\u0442\u0435\u043D\u0438\u0435 \u0437\u0430 \u043F\u0440\u0435\u0434\u0435\u043B\u044B \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u043E\u0433\u043E \u043C\u0435\u0441\u0442\u0430.\n */\nexport async function readTextNoFollow(file: string, maxBytes = 4 * 1024 * 1024): Promise<string> {\n const info = await lstat(file);\n if (info.isSymbolicLink()) throw new Error(`${path.basename(file)}: symbolic link, read refused`);\n if (!info.isFile()) throw new Error(`${path.basename(file)}: not a regular file`);\n if (info.size > maxBytes) throw new Error(`${path.basename(file)}: file is larger than ${Math.round(maxBytes / 1024)} KB`);\n const handle = await open(file, 'r');\n try {\n return await handle.readFile({ encoding: 'utf8' });\n } finally {\n await handle.close();\n }\n}\n\n/** \u0410\u0442\u043E\u043C\u0430\u0440\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C: \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B \u0432 \u0442\u043E\u043C \u0436\u0435 \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0435 \u0438 rename. */\nexport async function writeFileAtomic(file: string, data: string, mode = 0o600): Promise<void> {\n await ensureDir(path.dirname(file));\n const tmp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${Date.now().toString(36)}.tmp`);\n let handle;\n try {\n handle = await open(tmp, 'wx', mode);\n await handle.writeFile(data, 'utf8');\n await handle.sync();\n } finally {\n await handle?.close();\n }\n try {\n await rename(tmp, file);\n } catch (error) {\n await unlink(tmp).catch(() => undefined);\n throw error;\n }\n}\n\nexport async function readJsonFile<T>(file: string, fallback: T): Promise<T> {\n try {\n return JSON.parse(await readTextNoFollow(file)) as T;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return fallback;\n throw error;\n }\n}\n\n/** \u041A\u043E\u0440\u0435\u043D\u044C npm-\u043F\u0430\u043A\u0435\u0442\u0430 revdeck: \u043E\u0442 \u043D\u0435\u0433\u043E \u0438\u0449\u0443\u0442\u0441\u044F skills/ \u0438 dist/ui. */\nexport function packageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n for (;;) {\n const candidate = path.join(dir, 'package.json');\n if (existsSync(candidate)) return dir;\n const parent = path.dirname(dir);\n if (parent === dir) return process.cwd();\n dir = parent;\n }\n}\n\nexport async function realDirectory(dir: string): Promise<string> {\n const resolved = await realpath(dir);\n return resolved;\n}\n", "export const VERSION = '0.1.0';\nexport const PROTOCOL_VERSION = 1;\n", "import { DatabaseSync } from 'node:sqlite';\nimport { mkdirSync } from 'node:fs';\nimport path from 'node:path';\nimport type { ReviewConfig } from '../core/config.js';\nimport type {\n Decision,\n DiffFile,\n Finding,\n LineNote,\n ReplyDraft,\n ReviewInfo,\n ReviewSummary,\n Thread,\n} from '../core/types.js';\nimport { reviewId as makeReviewId } from '../core/refs.js';\n\nexport interface ReviewRow {\n id: string;\n platform: string;\n host: string;\n project: string;\n number: number;\n title: string;\n author: string;\n state: string;\n web_url: string;\n updated_at: string;\n synced_at: string;\n root: string;\n}\n\nexport interface ReviewSnapshot {\n diff: DiffFile[];\n threads: Thread[];\n config: ReviewConfig;\n configPath: string | null;\n errors: string[];\n syncedAt: string;\n}\n\nexport interface ReviewListItem {\n id: string;\n platform: string;\n host: string;\n project: string;\n number: number;\n title: string;\n author: string;\n state: string;\n webUrl: string;\n updatedAt: string;\n syncedAt: string;\n root: string;\n}\n\nexport interface ApprovalRecord {\n id: string;\n reviewId: string;\n kind: string;\n hash: string;\n items: unknown[];\n expiresAt: string;\n usedAt: string | null;\n createdAt: string;\n}\n\ntype Row = Record<string, unknown>;\n\nfunction text(row: Row, key: string): string {\n const value = row[key];\n return value === null || value === undefined ? '' : String(value);\n}\n\nfunction json<T>(row: Row, key: string, fallback: T): T {\n const value = row[key];\n if (typeof value !== 'string' || !value) return fallback;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\nexport class Store {\n readonly db: DatabaseSync;\n\n constructor(file: string) {\n if (file !== ':memory:') mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n this.db = new DatabaseSync(file);\n this.db.exec('PRAGMA journal_mode = WAL');\n this.db.exec('PRAGMA foreign_keys = ON');\n this.db.exec('PRAGMA busy_timeout = 5000');\n this.migrate();\n }\n\n close(): void {\n this.db.close();\n }\n\n private migrate(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS reviews (\n id TEXT PRIMARY KEY,\n platform TEXT NOT NULL,\n host TEXT NOT NULL,\n project TEXT NOT NULL,\n number INTEGER NOT NULL,\n title TEXT NOT NULL,\n author TEXT NOT NULL,\n state TEXT NOT NULL,\n web_url TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n synced_at TEXT NOT NULL,\n root TEXT NOT NULL,\n info_json TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS review_data (\n review_id TEXT PRIMARY KEY REFERENCES reviews(id) ON DELETE CASCADE,\n diff_json TEXT NOT NULL,\n threads_json TEXT NOT NULL,\n config_json TEXT NOT NULL,\n config_path TEXT,\n errors_json TEXT NOT NULL,\n synced_at TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS summaries (\n review_id TEXT PRIMARY KEY REFERENCES reviews(id) ON DELETE CASCADE,\n title TEXT NOT NULL,\n scope TEXT NOT NULL,\n summary TEXT NOT NULL,\n changes_json TEXT NOT NULL,\n focus_json TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS findings (\n review_id TEXT NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,\n id TEXT NOT NULL,\n fingerprint TEXT NOT NULL,\n level TEXT NOT NULL,\n file TEXT NOT NULL,\n line INTEGER,\n end_line INTEGER,\n title TEXT NOT NULL,\n body TEXT NOT NULL,\n comment TEXT NOT NULL,\n status TEXT NOT NULL,\n discussion_id TEXT,\n published_at TEXT,\n decision TEXT,\n note TEXT NOT NULL,\n publish_error TEXT NOT NULL DEFAULT '',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (review_id, id)\n );\n CREATE TABLE IF NOT EXISTS drafts (\n review_id TEXT NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,\n thread_id TEXT NOT NULL,\n body TEXT NOT NULL,\n resolve INTEGER NOT NULL,\n note_for_agent TEXT NOT NULL,\n agent_action TEXT NOT NULL,\n posted TEXT NOT NULL,\n replied INTEGER NOT NULL,\n resolved INTEGER NOT NULL,\n error TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (review_id, thread_id)\n );\n CREATE TABLE IF NOT EXISTS notes (\n review_id TEXT NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,\n id TEXT NOT NULL,\n file TEXT NOT NULL,\n line INTEGER NOT NULL,\n side TEXT NOT NULL,\n text TEXT NOT NULL,\n to_agent INTEGER NOT NULL,\n agent_action TEXT NOT NULL,\n agent_reply TEXT NOT NULL,\n posted TEXT NOT NULL,\n discussion_id TEXT NOT NULL,\n note_id TEXT NOT NULL,\n error TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (review_id, id)\n );\n CREATE TABLE IF NOT EXISTS decisions (\n review_id TEXT NOT NULL REFERENCES reviews(id) ON DELETE CASCADE,\n finding_id TEXT NOT NULL,\n decision TEXT,\n note TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (review_id, finding_id)\n );\n CREATE TABLE IF NOT EXISTS approvals (\n id TEXT PRIMARY KEY,\n review_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n hash TEXT NOT NULL,\n items_json TEXT NOT NULL,\n expires_at TEXT NOT NULL,\n used_at TEXT,\n created_at TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS audit (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n at TEXT NOT NULL,\n review_id TEXT,\n action TEXT NOT NULL,\n detail TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS audit_review ON audit(review_id, at);\n `);\n }\n\n saveReview(info: ReviewInfo, root: string, syncedAt = new Date().toISOString()): string {\n const id = makeReviewId(info.ref);\n this.db\n .prepare(\n `INSERT INTO reviews (id, platform, host, project, number, title, author, state, web_url, updated_at, synced_at, root, info_json)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n title = excluded.title, author = excluded.author, state = excluded.state,\n web_url = excluded.web_url, updated_at = excluded.updated_at,\n synced_at = excluded.synced_at, root = excluded.root, info_json = excluded.info_json`,\n )\n .run(\n id,\n info.ref.platform,\n info.ref.host,\n info.ref.project,\n info.ref.number,\n info.title,\n info.author,\n info.state,\n info.webUrl,\n info.updatedAt,\n syncedAt,\n root,\n JSON.stringify(info),\n );\n return id;\n }\n\n saveSnapshot(id: string, snapshot: ReviewSnapshot): void {\n this.db\n .prepare(\n `INSERT INTO review_data (review_id, diff_json, threads_json, config_json, config_path, errors_json, synced_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(review_id) DO UPDATE SET\n diff_json = excluded.diff_json, threads_json = excluded.threads_json,\n config_json = excluded.config_json, config_path = excluded.config_path,\n errors_json = excluded.errors_json, synced_at = excluded.synced_at`,\n )\n .run(\n id,\n JSON.stringify(snapshot.diff),\n JSON.stringify(snapshot.threads),\n JSON.stringify(snapshot.config),\n snapshot.configPath,\n JSON.stringify(snapshot.errors),\n snapshot.syncedAt,\n );\n this.db.prepare('UPDATE reviews SET synced_at = ? WHERE id = ?').run(snapshot.syncedAt, id);\n }\n\n listReviews(): ReviewListItem[] {\n const rows = this.db.prepare('SELECT * FROM reviews ORDER BY synced_at DESC').all() as Row[];\n return rows.map((row) => ({\n id: text(row, 'id'),\n platform: text(row, 'platform'),\n host: text(row, 'host'),\n project: text(row, 'project'),\n number: Number(row.number),\n title: text(row, 'title'),\n author: text(row, 'author'),\n state: text(row, 'state'),\n webUrl: text(row, 'web_url'),\n updatedAt: text(row, 'updated_at'),\n syncedAt: text(row, 'synced_at'),\n root: text(row, 'root'),\n }));\n }\n\n getReview(id: string): { row: ReviewRow; snapshot: ReviewSnapshot } | null {\n const row = this.db.prepare('SELECT * FROM reviews WHERE id = ?').get(id) as Row | undefined;\n if (!row) return null;\n const data = this.db.prepare('SELECT * FROM review_data WHERE review_id = ?').get(id) as Row | undefined;\n if (!data) return null;\n return {\n row: {\n id: text(row, 'id'),\n platform: text(row, 'platform'),\n host: text(row, 'host'),\n project: text(row, 'project'),\n number: Number(row.number),\n title: text(row, 'title'),\n author: text(row, 'author'),\n state: text(row, 'state'),\n web_url: text(row, 'web_url'),\n updated_at: text(row, 'updated_at'),\n synced_at: text(row, 'synced_at'),\n root: text(row, 'root'),\n },\n snapshot: {\n diff: json<DiffFile[]>(data, 'diff_json', []),\n threads: json<Thread[]>(data, 'threads_json', []),\n config: json<ReviewConfig>(data, 'config_json', {} as ReviewConfig),\n configPath: data.config_path ? String(data.config_path) : null,\n errors: json<string[]>(data, 'errors_json', []),\n syncedAt: text(data, 'synced_at'),\n },\n };\n }\n\n info(id: string): ReviewInfo | null {\n const row = this.db.prepare('SELECT info_json FROM reviews WHERE id = ?').get(id) as Row | undefined;\n if (!row) return null;\n return json<ReviewInfo | null>(row, 'info_json', null);\n }\n\n removeReview(id: string): void {\n this.db.prepare('DELETE FROM reviews WHERE id = ?').run(id);\n }\n\n // --- summary ---\n\n getSummary(id: string): ReviewSummary | null {\n const row = this.db.prepare('SELECT * FROM summaries WHERE review_id = ?').get(id) as Row | undefined;\n if (!row) return null;\n return {\n title: text(row, 'title'),\n scope: text(row, 'scope'),\n summary: text(row, 'summary'),\n changes: json<string[]>(row, 'changes_json', []),\n focus: json<string[]>(row, 'focus_json', []),\n };\n }\n\n setSummary(id: string, summary: ReviewSummary): void {\n this.db\n .prepare(\n `INSERT INTO summaries (review_id, title, scope, summary, changes_json, focus_json, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(review_id) DO UPDATE SET\n title = excluded.title, scope = excluded.scope, summary = excluded.summary,\n changes_json = excluded.changes_json, focus_json = excluded.focus_json, updated_at = excluded.updated_at`,\n )\n .run(id, summary.title, summary.scope, summary.summary, JSON.stringify(summary.changes), JSON.stringify(summary.focus), new Date().toISOString());\n }\n\n // --- findings ---\n\n listFindings(id: string): Finding[] {\n const rows = this.db.prepare('SELECT * FROM findings WHERE review_id = ? ORDER BY rowid').all(id) as Row[];\n return rows.map((row) => ({\n id: text(row, 'id'),\n fingerprint: text(row, 'fingerprint'),\n level: text(row, 'level') as Finding['level'],\n file: text(row, 'file'),\n line: row.line === null || row.line === undefined ? null : Number(row.line),\n endLine: row.end_line === null || row.end_line === undefined ? null : Number(row.end_line),\n title: text(row, 'title'),\n body: text(row, 'body'),\n comment: text(row, 'comment'),\n status: text(row, 'status') as Finding['status'],\n discussionId: row.discussion_id ? String(row.discussion_id) : null,\n publishedAt: row.published_at ? String(row.published_at) : null,\n decision: row.decision ? (String(row.decision) as Decision) : null,\n note: text(row, 'note'),\n publishError: text(row, 'publish_error'),\n }));\n }\n\n replaceFindings(id: string, findings: Finding[]): void {\n this.transaction(() => {\n this.db.prepare('DELETE FROM findings WHERE review_id = ?').run(id);\n const insert = this.db.prepare(\n `INSERT INTO findings (review_id, id, fingerprint, level, file, line, end_line, title, body, comment, status, discussion_id, published_at, decision, note, publish_error, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n const now = new Date().toISOString();\n for (const finding of findings) {\n insert.run(\n id,\n finding.id,\n finding.fingerprint,\n finding.level,\n finding.file,\n finding.line,\n finding.endLine,\n finding.title,\n finding.body,\n finding.comment,\n finding.status,\n finding.discussionId,\n finding.publishedAt,\n finding.decision,\n finding.note,\n finding.publishError,\n now,\n );\n }\n });\n }\n\n updateFinding(id: string, finding: Finding): void {\n this.db\n .prepare(\n `UPDATE findings SET level = ?, file = ?, line = ?, end_line = ?, title = ?, body = ?, comment = ?,\n status = ?, discussion_id = ?, published_at = ?, decision = ?, note = ?, publish_error = ?, updated_at = ?\n WHERE review_id = ? AND id = ?`,\n )\n .run(\n finding.level,\n finding.file,\n finding.line,\n finding.endLine,\n finding.title,\n finding.body,\n finding.comment,\n finding.status,\n finding.discussionId,\n finding.publishedAt,\n finding.decision,\n finding.note,\n finding.publishError,\n new Date().toISOString(),\n id,\n finding.id,\n );\n }\n\n // --- drafts ---\n\n listDrafts(id: string): ReplyDraft[] {\n const rows = this.db.prepare('SELECT * FROM drafts WHERE review_id = ? ORDER BY rowid').all(id) as Row[];\n return rows.map((row) => ({\n threadId: text(row, 'thread_id'),\n body: text(row, 'body'),\n resolve: Number(row.resolve) === 1,\n noteForAgent: text(row, 'note_for_agent'),\n agentAction: text(row, 'agent_action') as ReplyDraft['agentAction'],\n posted: text(row, 'posted'),\n replied: Number(row.replied) === 1,\n resolved: Number(row.resolved) === 1,\n error: text(row, 'error'),\n updatedAt: text(row, 'updated_at'),\n }));\n }\n\n getDraft(id: string, threadId: string): ReplyDraft | null {\n return this.listDrafts(id).find((draft) => draft.threadId === threadId) ?? null;\n }\n\n upsertDraft(id: string, draft: ReplyDraft): void {\n this.db\n .prepare(\n `INSERT INTO drafts (review_id, thread_id, body, resolve, note_for_agent, agent_action, posted, replied, resolved, error, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(review_id, thread_id) DO UPDATE SET\n body = excluded.body, resolve = excluded.resolve, note_for_agent = excluded.note_for_agent,\n agent_action = excluded.agent_action, posted = excluded.posted, replied = excluded.replied,\n resolved = excluded.resolved, error = excluded.error, updated_at = excluded.updated_at`,\n )\n .run(\n id,\n draft.threadId,\n draft.body,\n draft.resolve ? 1 : 0,\n draft.noteForAgent,\n draft.agentAction,\n draft.posted,\n draft.replied ? 1 : 0,\n draft.resolved ? 1 : 0,\n draft.error,\n draft.updatedAt,\n );\n }\n\n // --- notes ---\n\n listNotes(id: string): LineNote[] {\n const rows = this.db.prepare('SELECT * FROM notes WHERE review_id = ? ORDER BY created_at').all(id) as Row[];\n return rows.map((row) => ({\n id: text(row, 'id'),\n file: text(row, 'file'),\n line: Number(row.line),\n side: text(row, 'side') as LineNote['side'],\n text: text(row, 'text'),\n toAgent: Number(row.to_agent) === 1,\n agentAction: text(row, 'agent_action') as LineNote['agentAction'],\n agentReply: text(row, 'agent_reply'),\n posted: text(row, 'posted'),\n discussionId: text(row, 'discussion_id'),\n noteId: text(row, 'note_id'),\n error: text(row, 'error'),\n createdAt: text(row, 'created_at'),\n updatedAt: text(row, 'updated_at'),\n }));\n }\n\n upsertNote(id: string, note: LineNote): void {\n this.db\n .prepare(\n `INSERT INTO notes (review_id, id, file, line, side, text, to_agent, agent_action, agent_reply, posted, discussion_id, note_id, error, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(review_id, id) DO UPDATE SET\n file = excluded.file, line = excluded.line, side = excluded.side, text = excluded.text,\n to_agent = excluded.to_agent, agent_action = excluded.agent_action, agent_reply = excluded.agent_reply,\n posted = excluded.posted, discussion_id = excluded.discussion_id, note_id = excluded.note_id,\n error = excluded.error, updated_at = excluded.updated_at`,\n )\n .run(\n id,\n note.id,\n note.file,\n note.line,\n note.side,\n note.text,\n note.toAgent ? 1 : 0,\n note.agentAction,\n note.agentReply,\n note.posted,\n note.discussionId,\n note.noteId,\n note.error,\n note.createdAt,\n note.updatedAt,\n );\n }\n\n deleteNote(id: string, noteId: string): void {\n this.db.prepare('DELETE FROM notes WHERE review_id = ? AND id = ?').run(id, noteId);\n }\n\n // --- decisions ---\n\n listDecisions(id: string): Record<string, { decision: Decision | null; note: string }> {\n const rows = this.db.prepare('SELECT * FROM decisions WHERE review_id = ?').all(id) as Row[];\n const out: Record<string, { decision: Decision | null; note: string }> = {};\n for (const row of rows) {\n out[text(row, 'finding_id')] = {\n decision: row.decision ? (String(row.decision) as Decision) : null,\n note: text(row, 'note'),\n };\n }\n return out;\n }\n\n setDecisions(id: string, patch: Record<string, { decision: Decision | null; note: string }>): void {\n const now = new Date().toISOString();\n this.transaction(() => {\n const stmt = this.db.prepare(\n `INSERT INTO decisions (review_id, finding_id, decision, note, updated_at) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(review_id, finding_id) DO UPDATE SET decision = excluded.decision, note = excluded.note, updated_at = excluded.updated_at`,\n );\n for (const [findingId, value] of Object.entries(patch)) {\n stmt.run(id, findingId, value.decision, value.note, now);\n }\n });\n }\n\n // --- approvals ---\n\n createApproval(record: ApprovalRecord): void {\n this.db\n .prepare('INSERT INTO approvals (id, review_id, kind, hash, items_json, expires_at, used_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)')\n .run(record.id, record.reviewId, record.kind, record.hash, JSON.stringify(record.items), record.expiresAt, record.usedAt, record.createdAt);\n }\n\n getApproval(id: string): ApprovalRecord | null {\n const row = this.db.prepare('SELECT * FROM approvals WHERE id = ?').get(id) as Row | undefined;\n if (!row) return null;\n return {\n id: text(row, 'id'),\n reviewId: text(row, 'review_id'),\n kind: text(row, 'kind'),\n hash: text(row, 'hash'),\n items: json<unknown[]>(row, 'items_json', []),\n expiresAt: text(row, 'expires_at'),\n usedAt: row.used_at ? String(row.used_at) : null,\n createdAt: text(row, 'created_at'),\n };\n }\n\n markApprovalUsed(id: string): void {\n this.db.prepare('UPDATE approvals SET used_at = ? WHERE id = ?').run(new Date().toISOString(), id);\n }\n\n // --- audit ---\n\n audit(reviewId: string | null, action: string, detail: unknown): void {\n this.db\n .prepare('INSERT INTO audit (at, review_id, action, detail) VALUES (?, ?, ?, ?)')\n .run(new Date().toISOString(), reviewId, action, JSON.stringify(detail));\n }\n\n auditTail(limit = 100): { at: string; reviewId: string; action: string; detail: string }[] {\n const rows = this.db.prepare('SELECT * FROM audit ORDER BY id DESC LIMIT ?').all(limit) as Row[];\n return rows.map((row) => ({\n at: text(row, 'at'),\n reviewId: text(row, 'review_id'),\n action: text(row, 'action'),\n detail: text(row, 'detail'),\n }));\n }\n\n transaction(fn: () => void): void {\n this.db.exec('BEGIN');\n try {\n fn();\n this.db.exec('COMMIT');\n } catch (error) {\n this.db.exec('ROLLBACK');\n throw error;\n }\n }\n}\n", "/**\n * \u0414\u043E\u043C\u0435\u043D\u043D\u044B\u0435 \u043C\u043E\u0434\u0435\u043B\u0438 revdeck.\n *\n * \u041E\u0434\u043D\u0430 \u0440\u0435\u0432\u0438\u0437\u0438\u044F (review) \u2014 \u044D\u0442\u043E MR \u0432 GitLab \u0438\u043B\u0438 PR \u0432 GitHub. \u0412\u0441\u0435 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435\u043D\u043D\u044B\u0435\n * \u0440\u0430\u0437\u043B\u0438\u0447\u0438\u044F \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0443\u044E\u0442\u0441\u044F \u0432 \u044D\u0442\u0438 \u0442\u0438\u043F\u044B \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043C\u0438, \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0439 \u043A\u043E\u0434 \u043E \u043D\u0438\u0445 \u043D\u0435 \u0437\u043D\u0430\u0435\u0442.\n */\n\nexport type Platform = 'gitlab' | 'github';\n\nexport const PLATFORMS: readonly Platform[] = ['gitlab', 'github'];\n\nexport const LEVELS = ['blocker', 'major', 'minor', 'question'] as const;\nexport type Level = (typeof LEVELS)[number];\n\nexport const LEVEL_LABELS: Record<Level, string> = {\n blocker: 'blocker',\n major: 'major',\n minor: 'minor',\n question: 'question',\n};\n\nexport type FindingStatus = 'draft' | 'accepted' | 'rejected' | 'published' | 'fixed' | 'stale';\nexport type Decision = 'accept' | 'reject' | 'discuss';\nexport type ReplyAction = 'fix' | 'reply' | 'revise' | 'skip';\nexport type Side = 'new' | 'old';\n\nexport interface ReviewRef {\n platform: Platform;\n /** \u0425\u043E\u0441\u0442 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u044B \u0431\u0435\u0437 \u0441\u0445\u0435\u043C\u044B: gitlab.example.com, github.com. */\n host: string;\n /** GitLab: group/subgroup/project. GitHub: owner/repo. */\n project: string;\n number: number;\n}\n\nexport interface ReviewStats {\n files: number;\n additions: number;\n deletions: number;\n}\n\nexport interface ReviewInfo {\n ref: ReviewRef;\n title: string;\n description: string;\n author: string;\n authorName: string;\n state: string;\n draft: boolean;\n sourceBranch: string;\n targetBranch: string;\n webUrl: string;\n commit: { base: string; start: string; head: string };\n updatedAt: string;\n stats: ReviewStats;\n}\n\n/** \u0421\u0442\u0440\u043E\u043A\u0430 unified diff. oldLine/newLine \u2014 \u043D\u043E\u043C\u0435\u0440\u0430 \u0441\u0442\u0440\u043E\u043A \u0432 \u0441\u0442\u0430\u0440\u043E\u0439 \u0438 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0444\u0430\u0439\u043B\u0430. */\nexport interface DiffLine {\n kind: '+' | '-' | ' ';\n text: string;\n oldLine: number | null;\n newLine: number | null;\n}\n\nexport interface Hunk {\n header: string;\n oldStart: number;\n oldLines: number;\n newStart: number;\n newLines: number;\n lines: DiffLine[];\n}\n\nexport type FileStatus = 'added' | 'modified' | 'deleted' | 'renamed';\n\nexport interface DiffFile {\n path: string;\n oldPath: string;\n status: FileStatus;\n binary: boolean;\n hunks: Hunk[];\n}\n\nexport interface Note {\n id: string;\n author: string;\n authorName: string;\n createdAt: string;\n body: string;\n system: boolean;\n}\n\nexport interface Thread {\n id: string;\n path: string | null;\n line: number | null;\n side: Side | null;\n resolvable: boolean;\n resolved: boolean;\n notes: Note[];\n updatedAt: string;\n}\n\nexport interface User {\n username: string;\n name: string;\n}\n\n/** \u0427\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u043E\u0435 \u043F\u0440\u0435\u0434\u043B\u043E\u0436\u0435\u043D\u0438\u0435/\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u0440\u0435\u0432\u044C\u044E. \u041F\u0443\u0431\u043B\u0438\u043A\u0443\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F. */\nexport interface Finding {\n id: string;\n fingerprint: string;\n level: Level;\n file: string;\n line: number | null;\n endLine: number | null;\n title: string;\n body: string;\n comment: string;\n status: FindingStatus;\n discussionId: string | null;\n publishedAt: string | null;\n decision: Decision | null;\n note: string;\n publishError: string;\n}\n\n/** \u0412\u044B\u0436\u0438\u043C\u043A\u0430 MR, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043F\u0438\u0448\u0435\u0442 \u0430\u0433\u0435\u043D\u0442 \u0432 \u043D\u0430\u0447\u0430\u043B\u0435 \u0440\u0435\u0432\u044C\u044E. */\nexport interface ReviewSummary {\n title: string;\n scope: string;\n summary: string;\n changes: string[];\n focus: string[];\n}\n\n/** \u0427\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u043E\u0442\u0432\u0435\u0442\u0430 \u0432 \u0442\u0440\u0435\u0434. */\nexport interface ReplyDraft {\n threadId: string;\n body: string;\n resolve: boolean;\n noteForAgent: string;\n agentAction: ReplyAction | '';\n posted: string;\n replied: boolean;\n resolved: boolean;\n error: string;\n updatedAt: string;\n}\n\n/** \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043A \u0441\u0442\u0440\u043E\u043A\u0435 diff (\u0438\u0437 UI), \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043C\u043E\u0436\u0435\u0442 \u0443\u0439\u0442\u0438 \u0430\u0433\u0435\u043D\u0442\u0443. */\nexport interface LineNote {\n id: string;\n file: string;\n line: number;\n side: Side;\n text: string;\n toAgent: boolean;\n agentAction: 'fix' | 'reply' | '';\n agentReply: string;\n posted: string;\n discussionId: string;\n noteId: string;\n error: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Review {\n id: string;\n info: ReviewInfo;\n diff: DiffFile[];\n threads: Thread[];\n summary: ReviewSummary | null;\n findings: Finding[];\n drafts: ReplyDraft[];\n notes: LineNote[];\n decisions: Record<string, { decision: Decision | null; note: string }>;\n user: User | null;\n syncedAt: string;\n errors: string[];\n}\n\nexport type PublishKind = 'reply' | 'finding' | 'note';\n\nexport interface PublishItem {\n kind: PublishKind;\n /** threadId \u0434\u043B\u044F reply, finding id \u0434\u043B\u044F finding, note id \u0434\u043B\u044F note. */\n id: string;\n body: string;\n resolve?: boolean;\n file?: string;\n line?: number | null;\n side?: Side;\n}\n\nexport interface PublishPlan {\n reviewId: string;\n kind: PublishKind;\n items: PublishItem[];\n /** sha256 \u043A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u043E\u0433\u043E JSON items; \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442\u0441\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u0437\u0430\u043F\u0438\u0441\u0438. */\n hash: string;\n createdAt: string;\n}\n\nexport interface PublishResultItem {\n kind: PublishKind;\n id: string;\n ok: boolean;\n discussionId?: string;\n noteId?: string;\n error?: string;\n skipped?: boolean;\n}\n\nexport interface PublishResult {\n reviewId: string;\n results: PublishResultItem[];\n startedAt: string;\n finishedAt: string;\n}\n\nexport interface Approval {\n id: string;\n reviewId: string;\n hash: string;\n kind: PublishKind;\n expiresAt: string;\n usedAt: string | null;\n createdAt: string;\n}\n\nexport interface RuleDocument {\n path: string;\n exists: boolean;\n /** \u0417\u0430\u043F\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0435 \u0441\u0435\u043A\u0446\u0438\u0438; \u043F\u0443\u0441\u0442\u043E\u0439 \u043C\u0430\u0441\u0441\u0438\u0432 \u2014 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0446\u0435\u043B\u0438\u043A\u043E\u043C. */\n sections: string[];\n excerpt: string;\n truncated: boolean;\n}\n\nexport interface RuleScope {\n /** \u041F\u0443\u0442\u044C \u0444\u0430\u0439\u043B\u0430 \u0438\u0437 diff \u043B\u0438\u0431\u043E '' \u0434\u043B\u044F \u043E\u0431\u0449\u0438\u0445 \u043F\u0440\u0430\u0432\u0438\u043B. */\n file: string;\n kind: 'app' | 'test' | 'style' | 'config' | 'docs' | 'generated' | 'other';\n documents: RuleDocument[];\n}\n\nexport interface CheckResult {\n id: string;\n name: string;\n argv: string[];\n status: 'passed' | 'failed' | 'error' | 'skipped';\n output: string;\n durationMs: number;\n}\n\nexport interface EffectiveRules {\n configPath: string | null;\n scopes: RuleScope[];\n checks: { id: string; name: string; argv: string[]; consent: boolean; matched: boolean }[];\n /** \u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F: \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D, \u043F\u0443\u0442\u044C \u043D\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D \u0438 \u0442.\u043F. */\n warnings: string[];\n}\n", "import { createHash } from 'node:crypto';\nimport { LEVELS, type Level, type Platform, type ReviewRef } from './types.js';\n\n/** \u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u044B\u0439 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0440\u0435\u0432\u044C\u044E: \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0430, \u0445\u043E\u0441\u0442, \u043F\u0440\u043E\u0435\u043A\u0442 \u0438 \u043D\u043E\u043C\u0435\u0440. */\nexport function reviewId(ref: ReviewRef): string {\n return `${ref.platform}:${ref.host}/${ref.project}!${ref.number}`;\n}\n\nexport function parseReviewId(id: string): ReviewRef {\n const match = /^(gitlab|github):([^/]+)\\/(.+)!(\\d+)$/.exec(id);\n if (!match) throw new Error(`invalid review id: ${id}`);\n return {\n platform: match[1] as Platform,\n host: match[2]!,\n project: match[3]!,\n number: Number(match[4]),\n };\n}\n\n/** \u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u0440\u0435\u0432\u044C\u044E. */\nexport function webUrl(ref: ReviewRef): string {\n const scheme = ref.host.startsWith('localhost') || ref.host.startsWith('127.') ? 'http' : 'https';\n const base = `${scheme}://${ref.host}/${ref.project}`;\n return ref.platform === 'gitlab' ? `${base}/-/merge_requests/${ref.number}` : `${base}/pull/${ref.number}`;\n}\n\nconst GITLAB_URL = /^(?:https?:\\/\\/)?([^/]+)\\/(.+?)\\/-\\/merge_requests\\/(\\d+)(?:[/?#].*)?$/;\nconst GITHUB_URL = /^(?:https?:\\/\\/)?([^/]+)\\/([^/]+\\/[^/]+)\\/pull\\/(\\d+)(?:[/?#].*)?$/;\n\n/**\n * \u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 MR/PR. \u041F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \u043F\u043E\u043B\u043D\u044B\u0435 URL, URL \u0431\u0435\u0437 \u0441\u0445\u0435\u043C\u044B \u0438 `owner/repo#42`\n * (\u0434\u043B\u044F GitHub) / `group/project!42` (\u0434\u043B\u044F GitLab).\n */\nexport function parseReviewUrl(input: string): ReviewRef {\n const value = input.trim();\n const gitlab = GITLAB_URL.exec(value);\n if (gitlab) {\n return { platform: 'gitlab', host: gitlab[1]!, project: gitlab[2]!, number: Number(gitlab[3]) };\n }\n const github = GITHUB_URL.exec(value);\n if (github) {\n return { platform: 'github', host: github[1]!, project: github[2]!, number: Number(github[3]) };\n }\n const short = /^(.+?)([#!])(\\d+)$/.exec(value);\n if (short) {\n return {\n platform: short[2] === '!' ? 'gitlab' : 'github',\n host: short[2] === '!' ? 'gitlab.com' : 'github.com',\n project: short[1]!,\n number: Number(short[3]),\n };\n }\n throw new Error(\n 'could not parse the MR/PR reference: expected https://<host>/<project>/-/merge_requests/<N> ' +\n 'or https://<host>/<owner>/<repo>/pull/<N>, or project!N / owner/repo#N',\n );\n}\n\nexport function isLevel(value: unknown): value is Level {\n return typeof value === 'string' && (LEVELS as readonly string[]).includes(value);\n}\n\nexport function normalizeLevel(value: unknown): Level {\n return isLevel(value) ? value : 'question';\n}\n\n/** \u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F: \u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u043D\u044B\u0439 \u043E\u0442 fingerprint, \u043D\u043E \u043A\u043E\u0440\u043E\u0447\u0435 \u0438 \u0447\u0438\u0442\u0430\u0435\u043C\u044B\u0439. */\nexport function findingId(fingerprint: string, taken: ReadonlySet<string> = new Set()): string {\n for (let length = 8; length <= fingerprint.length; length += 2) {\n const candidate = `f-${fingerprint.slice(0, length)}`;\n if (!taken.has(candidate)) return candidate;\n }\n return `f-${fingerprint}`;\n}\n", "import { EventEmitter } from 'node:events';\nimport { createHash, randomBytes } from 'node:crypto';\nimport { redact } from '../core/redact.js';\nimport { messageOf } from '../core/errors.js';\nimport { findRepoRoot, findConfigFile } from '../core/paths.js';\nimport { loadConfig } from '../core/config.js';\nimport { buildEffectiveRules, renderRules } from '../core/rules.js';\nimport { diffStats, changedPaths, findNewLine, linePosition, snippetAround } from '../core/diff.js';\nimport { sanitizeBody } from '../core/sanitize.js';\nimport { mergeFindings, validateFinding, applyDecisions, fingerprintOf, levelOrder } from '../core/findings.js';\nimport { canonicalJson } from '../core/canonical.js';\nimport { resolveOutputLanguage, tr } from '../core/locale.js';\nimport type { Locale } from '../core/locale.js';\nimport { reviewId as makeReviewId } from '../core/refs.js';\nimport type { ReviewConfig } from '../core/config.js';\nimport type {\n Approval,\n Decision,\n DiffFile,\n Finding,\n Level,\n LineNote,\n Platform,\n PublishItem,\n PublishKind,\n PublishPlan,\n PublishResult,\n PublishResultItem,\n CheckResult,\n ReplyDraft,\n Review,\n ReviewInfo,\n ReviewRef,\n ReviewSummary,\n Side,\n Thread,\n} from '../core/types.js';\nimport type { Provider } from '../providers/provider.js';\nimport { createProvider, projectContext, resolveReviewRef } from '../providers/provider.js';\nimport { run as realRun, type Runner } from '../core/exec.js';\nimport type { ReviewSnapshot, Store } from './store.js';\nimport { toReviewView, type ReviewView } from './view.js';\n\nexport interface ServiceOptions {\n store: Store;\n /** \u0414\u043B\u044F \u0442\u0435\u0441\u0442\u043E\u0432: \u043F\u043E\u0434\u043C\u0435\u043D\u0430 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u043A\u043E\u043C\u0430\u043D\u0434. */\n providerFactory?: (ref: ReviewRef, root: string) => Promise<Provider>;\n runImpl?: Runner;\n now?: () => Date;\n syncIntervalMs?: number;\n refreshTtlMs?: number;\n}\n\nexport interface OpenOptions {\n input?: string;\n platform?: Platform;\n project?: string;\n host?: string;\n branch?: string;\n}\n\nexport interface PublishPreview {\n plan: PublishPlan;\n warnings: string[];\n}\n\nexport interface CommandCheck {\n id: string;\n name: string;\n argv: string[];\n consent: boolean;\n matched: boolean;\n}\n\nconst EMPTY_DRAFT = (threadId: string): ReplyDraft => ({\n threadId,\n body: '',\n resolve: false,\n noteForAgent: '',\n agentAction: '',\n posted: '',\n replied: false,\n resolved: false,\n error: '',\n updatedAt: new Date(0).toISOString(),\n});\n\nconst APPROVAL_TTL_MS = 10 * 60 * 1000;\n\n/**\n * \u041E\u0440\u043A\u0435\u0441\u0442\u0440\u0430\u0442\u043E\u0440: \u0435\u0434\u0438\u043D\u0430\u044F \u0442\u043E\u0447\u043A\u0430 \u043C\u0435\u0436\u0434\u0443 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043C\u0438, \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435\u043C \u0438 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043C\u0438.\n *\n * \u0418\u043D\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B:\n * - \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0443\u0431\u043B\u0438\u043A\u0443\u0435\u0442\u0441\u044F \u0431\u0435\u0437 approval, \u043F\u0440\u0438\u0432\u044F\u0437\u0430\u043D\u043D\u043E\u0433\u043E \u043A \u0445\u0435\u0448\u0443 \u0442\u043E\u0447\u043D\u043E\u0433\u043E \u043D\u0430\u0431\u043E\u0440\u0430\n * \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u0438\u0434\u0435\u043B \u0447\u0435\u043B\u043E\u0432\u0435\u043A;\n * - \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u0430\u044F \u043F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u044F \u0438\u0434\u0435\u043C\u043F\u043E\u0442\u0435\u043D\u0442\u043D\u0430: \u0443\u0436\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442/\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435\n * \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u044E\u0442\u0441\u044F;\n * - \u043E\u0448\u0438\u0431\u043A\u0430 \u043E\u0434\u043D\u043E\u0439 \u0435\u0434\u0438\u043D\u0438\u0446\u044B \u043F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u0438 \u043D\u0435 \u043E\u0442\u043C\u0435\u043D\u044F\u0435\u0442 \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u044B\u0435.\n */\nexport class ReviewService {\n readonly events = new EventEmitter();\n private readonly store: Store;\n private readonly providerFactory: (ref: ReviewRef, root: string) => Promise<Provider>;\n private readonly runImpl: Runner;\n private readonly now: () => Date;\n private readonly refreshTtlMs: number;\n private readonly syncIntervalMs: number;\n private timer: NodeJS.Timeout | null = null;\n private syncing = false;\n\n constructor(options: ServiceOptions) {\n this.store = options.store;\n this.runImpl = options.runImpl ?? realRun;\n this.now = options.now ?? (() => new Date());\n this.refreshTtlMs = options.refreshTtlMs ?? 60_000;\n this.syncIntervalMs = options.syncIntervalMs ?? 120_000;\n this.providerFactory = options.providerFactory ?? (async (ref: ReviewRef, root: string) => createProvider(ref, { root }));\n this.events.setMaxListeners(50);\n }\n\n close(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n this.store.close();\n }\n\n // ---------------------------------------------------------------- reviews\n\n async openReview(rootInput: string, options: OpenOptions = {}): Promise<Review> {\n const root = findRepoRoot(rootInput);\n const loaded = await loadConfig(root);\n const ref = await resolveReviewRef({\n root,\n config: loaded.config,\n ...(options.input ? { input: options.input } : {}),\n ...(options.platform ? { platform: options.platform } : {}),\n ...(options.project ? { project: options.project } : {}),\n ...(options.host ? { host: options.host } : {}),\n ...(options.branch ? { branch: options.branch } : {}),\n });\n const id = makeReviewId(ref);\n const provider = await this.providerFactory(ref, root);\n await this.refresh(id, root, provider, loaded);\n this.store.audit(id, 'review.open', { ref, root });\n return this.getReview(id);\n }\n\n async refreshReview(id: string): Promise<Review> {\n const meta = this.store.getReview(id);\n if (!meta) throw new Error(tr(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E: \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u0435\u0433\u043E`, `review ${id} not found: open it first`));\n const loaded = await loadConfig(meta.row.root).catch((error) => ({\n config: meta.snapshot.config,\n path: meta.snapshot.configPath,\n warnings: [tr(`\u043A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D: ${redact(messageOf(error))}`, `config unavailable: ${redact(messageOf(error))}`)],\n }));\n const provider = await this.providerFactory(\n { platform: meta.row.platform as Platform, host: meta.row.host, project: meta.row.project, number: meta.row.number },\n meta.row.root,\n );\n await this.refresh(id, meta.row.root, provider, loaded);\n return this.getReview(id);\n }\n\n private async refresh(\n id: string,\n root: string,\n provider: Provider,\n loaded: { config: ReviewConfig; path: string | null; warnings: string[] },\n ): Promise<void> {\n const errors: string[] = [...loaded.warnings];\n const previous = this.store.getReview(id)?.snapshot;\n let info: ReviewInfo;\n try {\n info = await provider.info();\n } catch (error) {\n throw new Error(tr(`\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u0440\u0435\u0432\u044C\u044E: ${redact(messageOf(error))}`, `could not read the review: ${redact(messageOf(error))}`));\n }\n const syncedAt = this.now().toISOString();\n // \u0427\u0430\u0441\u0442\u0438\u0447\u043D\u0430\u044F \u0434\u0435\u0433\u0440\u0430\u0434\u0430\u0446\u0438\u044F: \u0435\u0441\u043B\u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C diff \u0438\u043B\u0438 \u0442\u0440\u0435\u0434\u044B, \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u043A\u0435\u0448 \u0438 \u043F\u0440\u0438\u0447\u0438\u043D\u0443.\n let diff: DiffFile[] = previous?.diff ?? [];\n try {\n diff = await provider.diff();\n } catch (error) {\n errors.push(`diff: ${redact(messageOf(error))}`);\n }\n let threads: Thread[] = previous?.threads ?? [];\n try {\n threads = await provider.threads();\n } catch (error) {\n errors.push(`${tr('\u0442\u0440\u0435\u0434\u044B', 'threads')}: ${redact(messageOf(error))}`);\n }\n info.stats = diffStats(diff);\n this.store.saveReview(info, root, syncedAt);\n this.store.saveSnapshot(id, {\n diff,\n threads,\n config: loaded.config,\n configPath: loaded.path,\n errors,\n syncedAt,\n });\n if (diff.length) this.markStaleFindings(id, diff);\n this.emit(id);\n }\n\n private markStaleFindings(id: string, diff: DiffFile[]): void {\n const findings = this.store.listFindings(id);\n if (!findings.length) return;\n let changed = false;\n for (const finding of findings) {\n if (finding.status === 'published' || finding.status === 'stale') continue;\n if (finding.line === null) continue;\n if (!findNewLine(diff, finding.file, finding.line)) {\n this.store.updateFinding(id, { ...finding, status: 'stale' });\n changed = true;\n }\n }\n if (changed) this.emit(id);\n }\n\n getReview(id: string): Review {\n const stored = this.store.getReview(id);\n if (!stored) throw new Error(tr(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `review ${id} not found`));\n const { row, snapshot } = stored;\n const info = this.store.info(id) ?? fallbackInfo(row);\n const draftMap = new Map(this.store.listDrafts(id).map((draft) => [draft.threadId, draft]));\n const threads = snapshot.threads;\n const drafts: ReplyDraft[] = threads.map((thread) => {\n const saved = draftMap.get(thread.id) ?? EMPTY_DRAFT(thread.id);\n // desired != last known state \u2014 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u043B \u00AB\u0437\u0430\u043A\u0440\u044B\u0442\u044C\u00BB \u0438 \u044D\u0442\u043E \u0435\u0449\u0451 \u043D\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D\u043E.\n const desired = saved.resolve !== saved.resolved ? saved.resolve : thread.resolved;\n return {\n ...saved,\n resolved: thread.resolved,\n resolve: desired,\n replied: saved.posted.trim() !== '' && saved.body.trim() === saved.posted.trim(),\n };\n });\n // \u0427\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0438 \u0434\u043B\u044F \u0442\u0440\u0435\u0434\u043E\u0432, \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0443\u0436\u0435 \u043D\u0435\u0442, \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u043C: \u043E\u043D\u0438 \u0432\u0438\u0434\u043D\u044B \u043A\u0430\u043A \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435.\n for (const [threadId, draft] of draftMap) {\n if (!threads.some((thread) => thread.id === threadId)) drafts.push(draft);\n }\n const findings = applyDecisions(this.store.listFindings(id), this.store.listDecisions(id)).sort(\n (a, b) => levelOrder(a.level) - levelOrder(b.level) || a.file.localeCompare(b.file) || (a.line ?? 0) - (b.line ?? 0),\n );\n return {\n id,\n info,\n diff: snapshot.diff,\n threads,\n summary: this.store.getSummary(id),\n findings,\n drafts,\n notes: this.store.listNotes(id),\n decisions: this.store.listDecisions(id),\n user: null,\n syncedAt: snapshot.syncedAt,\n errors: snapshot.errors,\n };\n }\n\n getView(id: string): ReviewView {\n return toReviewView(this.getReview(id), this.now().getTime());\n }\n\n listReviews(): ReturnType<Store['listReviews']> {\n return this.store.listReviews();\n }\n\n async listRemote(\n rootInput: string,\n scope: 'open' | 'mine' | 'reviewing',\n limit = 50,\n ): Promise<{ items: Awaited<ReturnType<Provider['list']>>; platform: Platform; project: string }> {\n const root = findRepoRoot(rootInput);\n const loaded = await loadConfig(root);\n const context = await projectContext(root, loaded.config);\n const provider = await this.providerFactory({ ...context, number: 0 }, root);\n return { items: await provider.list({ scope, limit }), platform: context.platform, project: context.project };\n }\n\n isStale(id: string): boolean {\n const stored = this.store.getReview(id);\n if (!stored) return true;\n return this.now().getTime() - new Date(stored.snapshot.syncedAt).getTime() > this.refreshTtlMs;\n }\n\n async refreshIfStale(id: string): Promise<ReviewView> {\n if (this.isStale(id)) {\n try {\n await this.refreshReview(id);\n } catch {\n // \u041E\u0448\u0438\u0431\u043A\u0430 \u0444\u043E\u043D\u043E\u0432\u043E\u0433\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u0430 \u043B\u043E\u043C\u0430\u0442\u044C \u0447\u0442\u0435\u043D\u0438\u0435 \u043A\u0435\u0448\u0430.\n }\n }\n return this.getView(id);\n }\n\n diffFile(id: string, file: string): { path: string; status: string; binary: boolean; hunks: unknown[] } | null {\n const stored = this.store.getReview(id);\n if (!stored) return null;\n const found = stored.snapshot.diff.find((item) => item.path === file);\n if (!found) return null;\n return { path: found.path, status: found.status, binary: found.binary, hunks: found.hunks };\n }\n\n // ---------------------------------------------------------------- summary\n\n setSummary(id: string, input: unknown): ReviewSummary {\n this.requireReview(id);\n const value = (input ?? {}) as Record<string, unknown>;\n const list = (item: unknown, limit: number): string[] =>\n (Array.isArray(item) ? item : [])\n .map((entry) => String(entry ?? '').trim())\n .filter(Boolean)\n .slice(0, limit)\n .map((entry) => entry.slice(0, 2000));\n const summary: ReviewSummary = {\n title: String(value.title ?? '').slice(0, 500),\n scope: String(value.scope ?? '').slice(0, 1000),\n summary: String(value.summary ?? '').slice(0, 5000),\n changes: list(value.changes, 50),\n focus: list(value.focus, 50),\n };\n this.store.setSummary(id, summary);\n this.emit(id);\n return summary;\n }\n\n // ---------------------------------------------------------------- findings\n\n setFindings(id: string, raw: unknown): Finding[] {\n const review = this.getReview(id);\n if (!Array.isArray(raw)) throw new Error(tr('findings: \u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u043C\u0430\u0441\u0441\u0438\u0432', 'findings: expected an array'));\n const existing = this.store.listFindings(id);\n const knownIds = new Set(existing.map((finding) => finding.id));\n const knownPrints = new Set(existing.map((finding) => finding.fingerprint));\n const drafts: Parameters<typeof mergeFindings>[1] = [];\n const errors: string[] = [];\n for (const [index, item] of raw.entries()) {\n const { value, error } = validateFinding(item);\n if (!value) {\n errors.push(`#${index + 1}: ${error}`);\n continue;\n }\n const known = (value.id ? knownIds.has(value.id) : false) || knownPrints.has(fingerprintOf(value));\n // \u041D\u043E\u0432\u043E\u0435 \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043E\u0431\u044F\u0437\u0430\u043D\u043E \u0441\u0441\u044B\u043B\u0430\u0442\u044C\u0441\u044F \u043D\u0430 \u0441\u0442\u0440\u043E\u043A\u0443 diff. \u0418\u0437\u0432\u0435\u0441\u0442\u043D\u043E\u0435 (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u0441\u0442\u0430\u043B\u043E stale\n // \u043F\u043E\u0441\u043B\u0435 \u043D\u043E\u0432\u044B\u0445 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432) \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u043C, \u0438\u043D\u0430\u0447\u0435 UI \u043D\u0435 \u0441\u043C\u043E\u0433 \u0431\u044B \u043F\u0435\u0440\u0435\u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u0436\u0435 \u043D\u0430\u0431\u043E\u0440.\n if (!known) {\n const file = review.diff.find((entry) => entry.path === value.file);\n if (!file) {\n errors.push(tr(`#${index + 1}: \u0444\u0430\u0439\u043B\u0430 ${value.file} \u043D\u0435\u0442 \u0432 diff`, `#${index + 1}: file ${value.file} is not in the diff`));\n continue;\n }\n if (value.line !== null && !findNewLine(review.diff, value.file, value.line)) {\n errors.push(tr(`#${index + 1}: \u0441\u0442\u0440\u043E\u043A\u0430 ${value.file}:${value.line} \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442 \u0432 diff`, `#${index + 1}: line ${value.file}:${value.line} is not in the diff`));\n continue;\n }\n }\n drafts.push(value);\n }\n if (errors.length) throw new Error(tr(`\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u044B:\\n${errors.join('\\n')}`, `findings rejected:\\n${errors.join('\\n')}`));\n const merged = mergeFindings(this.store.listFindings(id), drafts, { now: this.now().toISOString() });\n this.store.replaceFindings(id, merged);\n this.emit(id);\n return merged;\n }\n\n setDecisions(id: string, raw: unknown): Record<string, { decision: Decision | null; note: string }> {\n this.requireReview(id);\n const patch: Record<string, { decision: Decision | null; note: string }> = {};\n const input = (raw ?? {}) as Record<string, unknown>;\n for (const [findingId, value] of Object.entries(input)) {\n const item = (value ?? {}) as Record<string, unknown>;\n const decision = item.decision;\n patch[findingId] = {\n decision: decision === 'accept' || decision === 'reject' || decision === 'discuss' ? decision : null,\n note: String(item.note ?? '').slice(0, 4000),\n };\n }\n this.store.setDecisions(id, patch);\n this.emit(id);\n return this.store.listDecisions(id);\n }\n\n // ---------------------------------------------------------------- drafts\n\n setDraft(\n id: string,\n threadId: string,\n patch: { body?: string; resolve?: boolean; noteForAgent?: string; agentAction?: string },\n ): ReplyDraft {\n const review = this.getReview(id);\n const thread = review.threads.find((item) => item.id === threadId);\n if (!thread) throw new Error(tr(`\u0442\u0440\u0435\u0434\u0430 ${threadId} \u043D\u0435\u0442 \u0432 \u044D\u0442\u043E\u043C \u0440\u0435\u0432\u044C\u044E`, `thread ${threadId} is not in this review`));\n const previous = this.store.getDraft(id, threadId) ?? EMPTY_DRAFT(threadId);\n const body = patch.body !== undefined ? String(patch.body).slice(0, 64 * 1024) : previous.body;\n const resolve = patch.resolve !== undefined ? Boolean(patch.resolve) : previous.resolve;\n const next: ReplyDraft = {\n ...previous,\n body,\n resolve,\n noteForAgent: patch.noteForAgent !== undefined ? String(patch.noteForAgent).slice(0, 8000) : previous.noteForAgent,\n agentAction: ['fix', 'reply', 'revise', 'skip'].includes(String(patch.agentAction))\n ? (patch.agentAction as ReplyDraft['agentAction'])\n : previous.agentAction,\n resolved: thread.resolved,\n updatedAt: this.now().toISOString(),\n };\n next.replied = next.posted.trim() !== '' && next.body.trim() === next.posted.trim();\n if (body !== previous.body || resolve !== previous.resolve) next.error = '';\n this.store.upsertDraft(id, next);\n this.emit(id);\n return next;\n }\n\n // ---------------------------------------------------------------- notes\n\n addNote(id: string, input: { file: string; line: number; side?: Side; text: string; toAgent?: boolean }): LineNote {\n const review = this.getReview(id);\n if (!findNewLine(review.diff, input.file, input.line)) {\n throw new Error(tr(`\u0441\u0442\u0440\u043E\u043A\u0430 ${input.file}:${input.line} \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442 \u0432 diff`, `line ${input.file}:${input.line} is not in the diff`));\n }\n const timestamp = this.now().toISOString();\n const note: LineNote = {\n id: `u-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`,\n file: input.file,\n line: input.line,\n side: input.side ?? 'new',\n text: String(input.text ?? '').slice(0, 16_000),\n toAgent: input.toAgent ?? true,\n agentAction: '',\n agentReply: '',\n posted: '',\n discussionId: '',\n noteId: '',\n error: '',\n createdAt: timestamp,\n updatedAt: timestamp,\n };\n this.store.upsertNote(id, note);\n this.emit(id);\n return note;\n }\n\n updateNote(\n id: string,\n noteId: string,\n patch: { text?: string; toAgent?: boolean; agentAction?: string; agentReply?: string; posted?: string; discussionId?: string; noteId?: string; error?: string },\n ): LineNote {\n const existing = this.store.listNotes(id).find((note) => note.id === noteId);\n if (!existing) throw new Error(tr(`\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F ${noteId} \u043D\u0435\u0442`, `comment ${noteId} not found`));\n const next: LineNote = {\n ...existing,\n text: patch.text !== undefined ? String(patch.text).slice(0, 16_000) : existing.text,\n toAgent: patch.toAgent !== undefined ? Boolean(patch.toAgent) : existing.toAgent,\n agentAction: ['fix', 'reply', ''].includes(String(patch.agentAction)) ? (patch.agentAction as LineNote['agentAction']) : existing.agentAction,\n agentReply: patch.agentReply !== undefined ? String(patch.agentReply).slice(0, 8000) : existing.agentReply,\n posted: patch.posted !== undefined ? String(patch.posted) : existing.posted,\n discussionId: patch.discussionId ?? existing.discussionId,\n noteId: patch.noteId ?? existing.noteId,\n error: patch.error ?? existing.error,\n updatedAt: this.now().toISOString(),\n };\n // \u041D\u043E\u0432\u044B\u0439 \u0442\u0435\u043A\u0441\u0442 \u0441\u0431\u0440\u0430\u0441\u044B\u0432\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442 \u0430\u0433\u0435\u043D\u0442\u0430: \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u043D \u0437\u0430\u043D\u043E\u0432\u043E.\n if (patch.text !== undefined && patch.text !== existing.text) next.agentReply = patch.agentReply ?? '';\n this.store.upsertNote(id, next);\n this.emit(id);\n return next;\n }\n\n deleteNote(id: string, noteId: string): void {\n const existing = this.store.listNotes(id).find((note) => note.id === noteId);\n if (!existing) return;\n if (existing.posted) throw new Error(tr('\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u0443\u0436\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D: \u0443\u0434\u0430\u043B\u044F\u0442\u044C \u0435\u0433\u043E \u043D\u0443\u0436\u043D\u043E \u0432 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435', 'the comment is already published: delete it in the platform'));\n this.store.deleteNote(id, noteId);\n this.emit(id);\n }\n\n // ---------------------------------------------------------------- publish\n\n previewPublish(id: string, kind: PublishKind, ids: string[]): PublishPreview {\n const review = this.getReview(id);\n const items: PublishItem[] = [];\n const warnings: string[] = [];\n const max = this.configOf(id)?.publish?.maxComments ?? 50;\n for (const itemId of ids) {\n if (items.length >= max) {\n warnings.push(tr(`\u0434\u043E\u0441\u0442\u0438\u0433\u043D\u0443\u0442 \u043B\u0438\u043C\u0438\u0442 ${max} \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0435\u0432 \u0437\u0430 \u0440\u0430\u0437`, `limit of ${max} comments per batch reached`));\n break;\n }\n if (kind === 'reply') {\n const thread = review.threads.find((item) => item.id === itemId);\n const draft = review.drafts.find((item) => item.threadId === itemId);\n if (!thread || !draft) {\n warnings.push(tr(`\u0442\u0440\u0435\u0434 ${itemId} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D`, `thread ${itemId} not found`));\n continue;\n }\n const body = draft.body.trim();\n const alreadyPosted = body !== '' && draft.posted.trim() === body;\n const resolveChanged = draft.resolve !== thread.resolved;\n if (!body && !resolveChanged) {\n warnings.push(tr(`\u0442\u0440\u0435\u0434 ${thread.id.substring(0, 8)}: \u043D\u0435\u0447\u0435\u0433\u043E \u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u0442\u044C`, `thread ${thread.id.substring(0, 8)}: nothing to publish`));\n continue;\n }\n if (body && alreadyPosted && !resolveChanged) {\n warnings.push(tr(`\u0442\u0440\u0435\u0434 ${thread.id.substring(0, 8)}: \u043E\u0442\u0432\u0435\u0442 \u0443\u0436\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D`, `thread ${thread.id.substring(0, 8)}: reply already published`));\n continue;\n }\n if (body) {\n const check = sanitizeBody(body, review.info.ref.platform);\n if (!check.ok) {\n warnings.push(tr(`\u0442\u0440\u0435\u0434 ${thread.id.substring(0, 8)}: ${check.reason}`, `thread ${thread.id.substring(0, 8)}: ${check.reason}`));\n continue;\n }\n }\n items.push({ kind, id: thread.id, body, resolve: draft.resolve });\n continue;\n }\n if (kind === 'finding') {\n const finding = review.findings.find((item) => item.id === itemId);\n if (!finding) {\n warnings.push(tr(`\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 ${itemId} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `finding ${itemId} not found`));\n continue;\n }\n if (finding.status === 'published') {\n warnings.push(tr(`\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 ${finding.id} \u0443\u0436\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D\u043E`, `finding ${finding.id} is already published`));\n continue;\n }\n const body = finding.comment.trim();\n const check = sanitizeBody(body, review.info.ref.platform);\n if (!check.ok) {\n warnings.push(tr(`\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 ${finding.id}: ${check.reason}`, `finding ${finding.id}: ${check.reason}`));\n continue;\n }\n const finalBody = finding.file && finding.line === null ? `\\`${finding.file}\\`: ${body}` : body;\n items.push({\n kind,\n id: finding.id,\n body: finalBody,\n file: finding.file,\n line: finding.line,\n ...(finding.line === null ? {} : { side: 'new' as const }),\n });\n continue;\n }\n const note = review.notes.find((item) => item.id === itemId);\n if (!note) {\n warnings.push(tr(`\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 ${itemId} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D`, `comment ${itemId} not found`));\n continue;\n }\n if (note.posted) {\n warnings.push(tr(`\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 ${note.id} \u0443\u0436\u0435 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D`, `comment ${note.id} is already published`));\n continue;\n }\n const check = sanitizeBody(note.text, review.info.ref.platform);\n if (!check.ok) {\n warnings.push(tr(`\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 ${note.id}: ${check.reason}`, `comment ${note.id}: ${check.reason}`));\n continue;\n }\n items.push({ kind, id: note.id, body: note.text, file: note.file, line: note.line, side: note.side });\n }\n return { plan: this.makePlan(id, kind, items), warnings };\n }\n\n private makePlan(id: string, kind: PublishKind, items: PublishItem[]): PublishPlan {\n const hash = canonicalHash(id, kind, items);\n return { reviewId: id, kind, items, hash, createdAt: this.now().toISOString() };\n }\n\n approve(id: string, kind: PublishKind, ids: string[], expectedHash: string): Approval {\n const preview = this.previewPublish(id, kind, ids);\n if (preview.plan.hash !== expectedHash) {\n throw new Error(tr('\u043D\u0430\u0431\u043E\u0440 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439 \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F: \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u0437\u0430\u043D\u043E\u0432\u043E', 'the plan changed after confirmation: refresh and confirm again'));\n }\n if (!preview.plan.items.length) throw new Error(tr('\u043D\u0435\u0447\u0435\u0433\u043E \u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u0442\u044C: \u0432 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430\u0445 \u043D\u0435\u0442 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439', 'nothing to publish: the selected items have no changes'));\n const approval: Approval = {\n id: randomBytes(16).toString('hex'),\n reviewId: id,\n hash: preview.plan.hash,\n kind,\n expiresAt: new Date(this.now().getTime() + APPROVAL_TTL_MS).toISOString(),\n usedAt: null,\n createdAt: this.now().toISOString(),\n };\n this.store.createApproval({\n id: approval.id,\n reviewId: id,\n kind,\n hash: approval.hash,\n items: preview.plan.items,\n expiresAt: approval.expiresAt,\n usedAt: null,\n createdAt: approval.createdAt,\n });\n this.store.audit(id, 'publish.approve', { approvalId: approval.id, kind, count: preview.plan.items.length });\n return approval;\n }\n\n async publish(id: string, approvalId: string): Promise<PublishResult> {\n const approval = this.store.getApproval(approvalId);\n if (!approval) throw new Error(tr('\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E', 'approval not found'));\n if (approval.reviewId !== id) throw new Error(tr('\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0432\u044B\u0434\u0430\u043D\u043E \u0434\u043B\u044F \u0434\u0440\u0443\u0433\u043E\u0433\u043E \u0440\u0435\u0432\u044C\u044E', 'the approval belongs to another review'));\n if (approval.usedAt) throw new Error(tr('\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0443\u0436\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u043E', 'the approval has already been used'));\n if (new Date(approval.expiresAt).getTime() < this.now().getTime()) throw new Error(tr('\u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0438\u0441\u0442\u0435\u043A\u043B\u043E', 'the approval has expired'));\n this.store.markApprovalUsed(approvalId);\n\n const stored = this.store.getReview(id);\n if (!stored) throw new Error(tr(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `review ${id} not found`));\n const provider = await this.providerFactory(\n { platform: stored.row.platform as Platform, host: stored.row.host, project: stored.row.project, number: stored.row.number },\n stored.row.root,\n );\n const review = this.getReview(id);\n const platform = review.info.ref.platform;\n const results: PublishResultItem[] = [];\n const startedAt = this.now().toISOString();\n\n for (const item of approval.items as PublishItem[]) {\n const result: PublishResultItem = { kind: item.kind, id: item.id, ok: false };\n results.push(result);\n try {\n if (item.kind === 'reply') {\n const thread = review.threads.find((entry) => entry.id === item.id);\n const draft = this.store.getDraft(id, item.id) ?? EMPTY_DRAFT(item.id);\n if (!thread) throw new Error(tr('\u0442\u0440\u0435\u0434 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442', 'the thread no longer exists'));\n const body = String(item.body ?? '').trim();\n if (body && draft.posted.trim() !== body) {\n const check = sanitizeBody(body, platform);\n if (!check.ok) throw new Error(check.reason);\n await provider.reply(thread, body);\n draft.posted = body;\n draft.replied = true;\n result.ok = true;\n }\n if (typeof item.resolve === 'boolean' && item.resolve !== thread.resolved) {\n await provider.resolve(thread.id, item.resolve);\n draft.resolved = item.resolve;\n thread.resolved = item.resolve;\n result.ok = true;\n }\n draft.error = '';\n draft.updatedAt = this.now().toISOString();\n this.store.upsertDraft(id, draft);\n this.saveThreads(id, review.threads);\n result.discussionId = thread.id;\n continue;\n }\n if (item.kind === 'finding') {\n const finding = review.findings.find((entry) => entry.id === item.id);\n if (!finding) throw new Error(tr('\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E', 'finding not found'));\n if (finding.status === 'published') {\n result.ok = true;\n result.skipped = true;\n result.discussionId = finding.discussionId ?? undefined;\n continue;\n }\n const body = String(item.body ?? '').trim();\n const position = finding.line !== null ? linePosition(review.diff, finding.file, finding.line) : null;\n if (finding.line !== null && !position) throw new Error(tr(`\u0441\u0442\u0440\u043E\u043A\u0430 ${finding.file}:${finding.line} \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442 \u0432 diff`, `line ${finding.file}:${finding.line} is not in the diff`));\n const created = await provider.createThread({\n file: finding.file,\n line: finding.line,\n oldLine: position?.oldLine ?? null,\n body,\n });\n finding.status = 'published';\n finding.discussionId = created.discussionId;\n finding.publishedAt = this.now().toISOString();\n this.store.updateFinding(id, finding);\n result.ok = true;\n result.discussionId = created.discussionId;\n result.noteId = created.noteId;\n continue;\n }\n const note = review.notes.find((entry) => entry.id === item.id);\n if (!note) throw new Error(tr('\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D', 'comment not found'));\n if (note.posted) {\n result.ok = true;\n result.skipped = true;\n continue;\n }\n const position = linePosition(review.diff, note.file, note.line);\n if (!position) throw new Error(tr(`\u0441\u0442\u0440\u043E\u043A\u0430 ${note.file}:${note.line} \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442 \u0432 diff`, `line ${note.file}:${note.line} is not in the diff`));\n const created = await provider.createThread({\n file: note.file,\n line: note.line,\n oldLine: position.oldLine,\n body: String(item.body ?? '').trim(),\n });\n note.posted = String(item.body ?? '').trim();\n note.discussionId = created.discussionId;\n note.noteId = created.noteId;\n note.updatedAt = this.now().toISOString();\n this.store.upsertNote(id, note);\n result.ok = true;\n result.discussionId = created.discussionId;\n result.noteId = created.noteId;\n } catch (error) {\n result.error = redact(messageOf(error));\n this.recordPublishError(id, item, result.error);\n }\n }\n\n const finishedAt = this.now().toISOString();\n this.store.audit(id, 'publish.commit', {\n approvalId,\n kind: approval.kind,\n ok: results.filter((item) => item.ok).length,\n failed: results.filter((item) => !item.ok).length,\n });\n this.emit(id);\n // \u0421\u0432\u0435\u0436\u0438\u0435 \u0442\u0440\u0435\u0434\u044B \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u044B \u043F\u043E\u0434\u0442\u044F\u043D\u0443\u0442\u0441\u044F \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435\u043C; UI \u0443\u0436\u0435 \u0432\u0438\u0434\u0438\u0442 posted.\n return { reviewId: id, results, startedAt, finishedAt };\n }\n\n private recordPublishError(id: string, item: PublishItem, error: string): void {\n if (item.kind === 'reply') {\n const draft = this.store.getDraft(id, item.id);\n if (draft) this.store.upsertDraft(id, { ...draft, error, updatedAt: this.now().toISOString() });\n return;\n }\n if (item.kind === 'finding') {\n const finding = this.store.listFindings(id).find((entry) => entry.id === item.id);\n if (finding) this.store.updateFinding(id, { ...finding, publishError: error });\n return;\n }\n const note = this.store.listNotes(id).find((entry) => entry.id === item.id);\n if (note) this.store.upsertNote(id, { ...note, error, updatedAt: this.now().toISOString() });\n }\n\n private saveThreads(id: string, threads: Thread[]): void {\n const stored = this.store.getReview(id);\n if (!stored) return;\n this.store.saveSnapshot(id, { ...stored.snapshot, threads });\n }\n\n // ---------------------------------------------------------------- rules & checks\n\n async rules(id: string): Promise<{ markdown: string; configPath: string | null; warnings: string[]; checks: CommandCheck[]; language: Locale }> {\n const stored = this.store.getReview(id);\n if (!stored) throw new Error(tr(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `review ${id} not found`));\n const info = this.store.info(id);\n const texts = [\n info?.title ?? '',\n info?.description ?? '',\n ...stored.snapshot.threads.flatMap((thread) => thread.notes.map((note) => note.body)),\n ];\n let config = stored.snapshot.config;\n let configPath = stored.snapshot.configPath;\n if (!config?.rules) {\n // \u0421\u043D\u0438\u043C\u043E\u043A \u043C\u043E\u0433 \u0431\u044B\u0442\u044C \u0441\u0434\u0435\u043B\u0430\u043D \u0441\u0442\u0430\u0440\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0431\u0435\u0437 output/rules \u2014 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u043C \u043A\u043E\u043D\u0444\u0438\u0433.\n const loaded = await loadConfig(stored.row.root);\n config = loaded.config;\n configPath = loaded.path;\n }\n const language = resolveOutputLanguage(config.output?.language ?? 'auto', texts);\n const effective = await buildEffectiveRules({\n root: stored.row.root,\n config,\n configPath,\n files: changedPaths(stored.snapshot.diff),\n language,\n });\n return {\n markdown: renderRules(effective, { language }),\n configPath: effective.configPath,\n warnings: effective.warnings,\n checks: effective.checks,\n language,\n };\n }\n\n async runChecks(id: string, options: { allowRun: boolean; ids?: string[] }): Promise<CheckResult[]> {\n const stored = this.store.getReview(id);\n if (!stored) throw new Error(tr(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `review ${id} not found`));\n const { checks } = await this.rules(id);\n const matched = checks.filter((check) => check.matched && (!options.ids?.length || options.ids.includes(check.id)));\n const results: CheckResult[] = [];\n for (const check of matched) {\n if (!options.allowRun) {\n results.push({\n id: check.id,\n name: check.name,\n argv: check.argv,\n status: 'skipped',\n output: tr('\u0437\u0430\u043F\u0443\u0441\u043A \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043D: \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 revdeck checks --run --yes', 'run not confirmed: use revdeck checks --run --yes'),\n durationMs: 0,\n });\n continue;\n }\n const started = Date.now();\n try {\n const { stdout, stderr, code } = await this.runImpl(check.argv[0]!, check.argv.slice(1), {\n cwd: stored.row.root,\n timeoutMs: stored.snapshot.config.checks?.find((item) => item.id === check.id)?.timeoutMs ?? 300_000,\n maxBuffer: 16 * 1024 * 1024,\n });\n results.push({\n id: check.id,\n name: check.name,\n argv: check.argv,\n status: code === 0 ? 'passed' : 'failed',\n output: redact(`${stdout}\\n${stderr}`.trim()).slice(0, 20_000),\n durationMs: Date.now() - started,\n });\n } catch (error) {\n results.push({\n id: check.id,\n name: check.name,\n argv: check.argv,\n status: 'error',\n output: redact(messageOf(error)).slice(0, 20_000),\n durationMs: Date.now() - started,\n });\n }\n }\n this.store.audit(id, 'checks.run', { count: results.length });\n return results;\n }\n\n // ---------------------------------------------------------------- sync\n\n startSync(): void {\n if (this.timer || this.syncIntervalMs <= 0) return;\n this.timer = setInterval(() => {\n void this.syncAll();\n }, this.syncIntervalMs);\n this.timer.unref?.();\n }\n\n async syncAll(): Promise<void> {\n if (this.syncing) return;\n this.syncing = true;\n try {\n const reviews = this.store.listReviews();\n for (let index = 0; index < reviews.length; index += 2) {\n const chunk = reviews.slice(index, index + 2);\n await Promise.allSettled(\n chunk.map(async (item) => {\n const age = this.now().getTime() - new Date(item.syncedAt).getTime();\n if (age < this.syncIntervalMs / 2) return;\n try {\n await this.refreshReview(item.id);\n } catch {\n // \u0424\u043E\u043D\u043E\u0432\u043E\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u043E\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0442\u044C \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u044B\u0435 \u0440\u0435\u0432\u044C\u044E.\n }\n }),\n );\n }\n } finally {\n this.syncing = false;\n }\n }\n\n // ---------------------------------------------------------------- helpers\n\n private emit(id: string): void {\n this.events.emit('review', { reviewId: id, at: this.now().toISOString() });\n }\n\n private requireReview(id: string): void {\n if (!this.store.getReview(id)) throw new Error(`\u0440\u0435\u0432\u044C\u044E ${id} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`);\n }\n\n changedFiles(id: string): string[] {\n const stored = this.store.getReview(id);\n return stored ? changedPaths(stored.snapshot.diff) : [];\n }\n\n diffFor(id: string): DiffFile[] {\n return this.store.getReview(id)?.snapshot.diff ?? [];\n }\n\n threadSnippet(id: string, file: string, line: number | null): ReturnType<typeof snippetAround> {\n if (line === null) return null;\n return snippetAround(this.diffFor(id), file, line, 4);\n }\n\n configOf(id: string): ReviewConfig | null {\n return this.store.getReview(id)?.snapshot.config ?? null;\n }\n\n rootOf(id: string): string | null {\n return this.store.getReview(id)?.row.root ?? null;\n }\n}\n\nexport function canonicalHash(reviewId: string, kind: PublishKind, items: PublishItem[]): string {\n return createHash('sha256').update(canonicalJson({ reviewId, kind, items })).digest('hex');\n}\n\nfunction fallbackInfo(row: {\n platform: string;\n host: string;\n project: string;\n number: number;\n title: string;\n author: string;\n state: string;\n web_url: string;\n updated_at: string;\n}): ReviewInfo {\n return {\n ref: { platform: row.platform as Platform, host: row.host, project: row.project, number: row.number },\n title: row.title,\n description: '',\n author: row.author,\n authorName: '',\n state: row.state,\n draft: false,\n sourceBranch: '',\n targetBranch: '',\n webUrl: row.web_url,\n commit: { base: '', start: '', head: '' },\n updatedAt: row.updated_at,\n stats: { files: 0, additions: 0, deletions: 0 },\n };\n}\n", "import { z } from 'zod';\nimport { readTextNoFollow, findConfigFile, findRepoRoot } from './paths.js';\nimport { ConfigError } from './errors.js';\nimport { parse as parseYaml } from 'yaml';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { globToRegExp } from './glob.js';\nimport { tr } from './locale.js';\n\nconst matchSchema = z.union([z.string().min(1), z.array(z.string().min(1)).min(1)]);\n\nexport const reviewConfigSchema = z.object({\n version: z.literal(1).default(1),\n provider: z\n .object({\n /** auto \u2014 \u043F\u043E git remote; \u0438\u043D\u0430\u0447\u0435 \u044F\u0432\u043D\u0430\u044F \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0430. */\n type: z.enum(['auto', 'gitlab', 'github']).default('auto'),\n host: z.string().min(1).optional(),\n /** GitLab: group/project. GitHub: owner/repo. */\n project: z.string().min(1).optional(),\n /** \u0411\u0430\u0437\u0430 \u0434\u043B\u044F \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E\u0433\u043E diff, \u043A\u043E\u0433\u0434\u0430 \u0440\u0435\u0432\u044C\u044E \u0438\u0434\u0451\u0442 \u043F\u043E \u0432\u0435\u0442\u043A\u0435. */\n base: z.string().min(1).optional(),\n })\n .prefault({}),\n output: z\n .object({\n language: z.enum(['auto', 'ru', 'en']).default('auto'),\n })\n .prefault({}),\n rules: z\n .object({\n /** \u041E\u0431\u0449\u0438\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B, \u0435\u0441\u043B\u0438 \u043D\u0438 \u043E\u0434\u043D\u0430 \u0441\u0442\u0440\u043E\u043A\u0430 map \u043D\u0435 \u043F\u043E\u0434\u043E\u0448\u043B\u0430. \u041F\u0443\u0441\u0442\u043E \u2014 \u0430\u0432\u0442\u043E\u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0438\u0435. */\n sources: z.array(z.string().min(1)).default([]),\n /** \u041F\u0440\u0438\u0432\u044F\u0437\u043A\u0430 \u043F\u0443\u0442\u0435\u0439 \u043A \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u043C: match \u2014 glob, docs \u2014 \u043F\u0443\u0442\u0438 \u0441 \u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0441\u0435\u043A\u0446\u0438\u0435\u0439 `#\u2026`. */\n map: z\n .array(\n z.object({\n match: matchSchema,\n docs: z.array(z.string().min(1)).min(1),\n note: z.string().optional(),\n }),\n )\n .default([]),\n /** \u041F\u0443\u0442\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043D\u0435 \u0440\u0435\u0432\u044C\u044E\u044F\u0442\u0441\u044F (\u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u043A\u043E\u0434 \u0438 \u0442.\u043F.). */\n ignore: z.array(z.string().min(1)).default([]),\n })\n .prefault({}),\n checks: z\n .array(\n z.object({\n id: z.string().min(1),\n name: z.string().optional(),\n /** argv \u0431\u0435\u0437 shell: \u043F\u0435\u0440\u0432\u044B\u043C \u0438\u0434\u0451\u0442 \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u0435\u043C\u044B\u0439 \u0444\u0430\u0439\u043B. */\n argv: z.array(z.string()).min(1),\n /** \u0417\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 diff \u0437\u0430\u0442\u0440\u043E\u043D\u0443\u043B \u044D\u0442\u0438 glob-\u043F\u0443\u0442\u0438. */\n when: z.array(z.string()).default([]),\n consent: z.boolean().default(true),\n timeoutMs: z.number().int().positive().max(3_600_000).default(300_000),\n }),\n )\n .default([]),\n publish: z\n .object({\n requireApproval: z.boolean().default(true),\n maxComments: z.number().int().positive().max(200).default(50),\n })\n .prefault({}),\n});\n\nexport type ReviewConfig = z.infer<typeof reviewConfigSchema>;\n\nexport interface LoadedConfig {\n config: ReviewConfig;\n path: string | null;\n warnings: string[];\n}\n\n/** \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043D\u0430\u0445\u043E\u0434\u044F\u0442\u0441\u044F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438, \u0435\u0441\u043B\u0438 \u043A\u043E\u043D\u0444\u0438\u0433 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0437\u0430\u0434\u0430\u0451\u0442. */\nconst DISCOVERED_SOURCES = [\n 'AGENTS.md',\n 'CLAUDE.md',\n 'CONTRIBUTING.md',\n 'docs/ARCHITECTURE.md',\n 'docs/Architecture.md',\n 'docs/STYLEGUIDE.md',\n 'docs/Styleguide.md',\n 'docs/CONTRIBUTING.md',\n];\n\nexport function parseConfig(text: string, source = '.revdeck.yml'): ReviewConfig {\n let data: unknown;\n try {\n data = parseYaml(text);\n } catch (error) {\n throw new ConfigError(tr(`${source}: \u043D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 YAML: ${(error as Error).message}`, `${source}: invalid YAML: ${(error as Error).message}`));\n }\n if (data === null || data === undefined) data = {};\n const result = reviewConfigSchema.safeParse(data);\n if (!result.success) {\n const issues = result.error.issues\n .slice(0, 10)\n .map((issue) => `${issue.path.join('.') || '<\u043A\u043E\u0440\u0435\u043D\u044C>'}: ${issue.message}`)\n .join('; ');\n throw new ConfigError(`${source}: ${issues}`, tr('\u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u0445\u0435\u043C\u0443 \u0432 docs/configuration.md', 'check the schema in docs/configuration.md'));\n }\n return result.data;\n}\n\nexport async function loadConfig(root = findRepoRoot()): Promise<LoadedConfig> {\n const warnings: string[] = [];\n const file = findConfigFile(root);\n let config: ReviewConfig;\n if (file) {\n config = parseConfig(await readTextNoFollow(file), path.relative(root, file) || file);\n } else {\n config = reviewConfigSchema.parse({});\n warnings.push(tr('\u0444\u0430\u0439\u043B .revdeck.yml \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: \u043F\u0440\u0430\u0432\u0438\u043B\u0430 \u0432\u0437\u044F\u0442\u044B \u0438\u0437 \u0430\u0432\u0442\u043E\u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u043D\u044B\u0445 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u0432', '.revdeck.yml not found: rules come from auto-discovered documents'));\n }\n if (!config.rules.sources.length && !config.rules.map.length) {\n const found = DISCOVERED_SOURCES.filter((item) => existsSync(path.join(root, item)));\n config.rules.sources = found;\n if (!found.length) {\n warnings.push(tr('\u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u0441 \u043F\u0440\u0430\u0432\u0438\u043B\u0430\u043C\u0438 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B: \u0440\u0435\u0432\u044C\u044E \u0431\u0443\u0434\u0435\u0442 \u043E\u043F\u0438\u0440\u0430\u0442\u044C\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 \u043A\u043E\u0434 \u0438 \u0437\u0434\u0440\u0430\u0432\u044B\u0439 \u0441\u043C\u044B\u0441\u043B', 'no rule documents found: the review will rely on the code only'));\n }\n }\n return { config, path: file, warnings };\n}\n\n/** \u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430, \u0447\u0442\u043E \u043F\u0443\u0442\u044C \u0438\u0437 \u043A\u043E\u043D\u0444\u0438\u0433\u0430 \u043D\u0435 \u0432\u044B\u0432\u043E\u0434\u0438\u0442 \u0437\u0430 \u043F\u0440\u0435\u0434\u0435\u043B\u044B \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F. */\nexport function assertConfigPath(root: string, relative: string): string {\n const cleaned = relative.split('#')[0]!;\n const resolved = path.resolve(root, cleaned);\n const rel = path.relative(root, resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new ConfigError(tr(`\u043F\u0443\u0442\u044C ${relative} \u0432\u044B\u0445\u043E\u0434\u0438\u0442 \u0437\u0430 \u043F\u0440\u0435\u0434\u0435\u043B\u044B \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F`, `path ${relative} escapes the repository`));\n }\n return resolved;\n}\n\n/** \u041A\u0430\u043A\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0438\u0437 \u043A\u043E\u043D\u0444\u0438\u0433\u0430 \u043E\u0442\u043D\u043E\u0441\u044F\u0442\u0441\u044F \u043A \u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u044B\u043C \u043F\u0443\u0442\u044F\u043C. */\nexport function checksForPaths(\n config: ReviewConfig,\n paths: string[],\n): { id: string; name: string; argv: string[]; consent: boolean; matched: boolean }[] {\n return config.checks.map((check) => {\n const matched = !check.when.length || paths.some((file) => check.when.some((pattern) => globToRegExp(pattern).test(file)));\n return { id: check.id, name: check.name ?? check.id, argv: check.argv, consent: check.consent, matched };\n });\n}\n", "/** \u041F\u0435\u0440\u0435\u0432\u043E\u0434 glob \u0432 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u0435 \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u0435. \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 `**`, `*`, `?`, `{a,b}`. */\nexport function globToRegExp(glob: string): RegExp {\n let source = '';\n let index = 0;\n const pattern = glob.replace(/^\\.\\//, '').replace(/^\\/+/, '');\n while (index < pattern.length) {\n const char = pattern[index]!;\n if (char === '*') {\n if (pattern[index + 1] === '*') {\n // `**/` \u2014 \u043B\u044E\u0431\u0430\u044F \u0433\u043B\u0443\u0431\u0438\u043D\u0430, `**` \u0432 \u043A\u043E\u043D\u0446\u0435 \u2014 \u0432\u0441\u0451 \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435.\n if (pattern[index + 2] === '/') {\n source += '(?:[^/]+/)*';\n index += 3;\n } else {\n source += '.*';\n index += 2;\n }\n } else {\n source += '[^/]*';\n index += 1;\n }\n continue;\n }\n if (char === '?') {\n source += '[^/]';\n index += 1;\n continue;\n }\n if (char === '{') {\n const end = pattern.indexOf('}', index);\n if (end > index) {\n const options = pattern\n .slice(index + 1, end)\n .split(',')\n .map((item) => escapeRegExp(item.trim()));\n source += `(?:${options.join('|')})`;\n index = end + 1;\n continue;\n }\n }\n source += escapeRegExp(char);\n index += 1;\n }\n return new RegExp(`^${source}$`);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function matchesAny(patterns: readonly string[], value: string): boolean {\n return patterns.some((pattern) => globToRegExp(pattern).test(value));\n}\n\n/** \u041F\u0440\u0438\u0431\u043B\u0438\u0437\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0442\u0438\u043F \u0444\u0430\u0439\u043B\u0430 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0432\u044B\u0431\u043E\u0440\u0430 \u043F\u0440\u0430\u0432\u0438\u043B, \u043D\u0435 \u0434\u043B\u044F \u043E\u0446\u0435\u043D\u043A\u0438 \u043A\u043E\u0434\u0430. */\nexport function classifyFile(path: string): 'app' | 'test' | 'style' | 'config' | 'docs' | 'generated' | 'other' {\n const lower = path.toLowerCase();\n if (/(^|\\/)(node_modules|dist|build|coverage|vendor)\\//.test(lower)) return 'generated';\n if (/\\.(md|mdx|rst|txt|adoc)$/.test(lower) || /(^|\\/)(docs?|adr)\\//.test(lower)) return 'docs';\n if (/(^|\\/)(__tests__|tests?|spec|e2e)\\//.test(lower) || /\\.(test|spec)\\.[cm]?[jt]sx?$/.test(lower) || /_test\\.go$/.test(lower)) return 'test';\n if (/\\.(css|scss|sass|less|styl)$/.test(lower)) return 'style';\n if (/(^|\\/)(package(-lock)?\\.json|pnpm-lock\\.yaml|yarn\\.lock|tsconfig[^/]*\\.json|[^/]*\\.config\\.[cm]?[jt]s|\\.eslintrc[^/]*|\\.prettierrc[^/]*|Dockerfile|Makefile|\\.github\\/workflows\\/|\\.gitlab-ci\\.yml)/.test(lower)) return 'config';\n if (/\\.(generated|g)\\.[cm]?[jt]s$|\\.d\\.ts$|(^|\\/)generated\\//.test(lower)) return 'generated';\n if (/\\.(ts|tsx|js|jsx|mjs|cjs|vue|svelte|py|go|rs|java|kt|rb|php|cs|c|cpp|h|hpp|swift|scala|ex|exs)$/.test(lower)) return 'app';\n return 'other';\n}\n", "import path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { EffectiveRules, RuleDocument, RuleScope } from './types.js';\nimport type { ReviewConfig } from './config.js';\nimport { assertConfigPath, checksForPaths } from './config.js';\nimport { classifyFile, globToRegExp } from './glob.js';\nimport { readTextNoFollow } from './paths.js';\nimport { redactLine } from './redact.js';\nimport type { Locale } from './locale.js';\n\nconst MAX_DOC_BYTES = 96 * 1024;\nconst MAX_TOTAL_BYTES = 320 * 1024;\n\ninterface CachedDoc {\n exists: boolean;\n text: string;\n truncated: boolean;\n}\n\nexport interface BuildRulesOptions {\n root: string;\n config: ReviewConfig;\n configPath: string | null;\n files: string[];\n /** \u042F\u0437\u044B\u043A \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0439 \u0438 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430 \u043F\u0440\u0430\u0432\u0438\u043B. */\n language?: Locale;\n}\n\n/**\n * \u041A\u043E\u043C\u043F\u0438\u043B\u044F\u0442\u043E\u0440 \u043F\u0440\u0430\u0432\u0438\u043B: \u0434\u043B\u044F \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0438\u0437\u043C\u0435\u043D\u0451\u043D\u043D\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0432\u044B\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B\n * \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F \u0438 \u0440\u043E\u0432\u043D\u043E \u0442\u0435 \u0441\u0435\u043A\u0446\u0438\u0438, \u043F\u043E \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0435\u0433\u043E \u043D\u0430\u0434\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C.\n *\n * \u042D\u0442\u043E \u0437\u0430\u043C\u0435\u043D\u0430 \u0440\u0443\u0447\u043D\u043E\u0439 \u0442\u0430\u0431\u043B\u0438\u0446\u0435 \u00AB\u043F\u0443\u0442\u044C \u2192 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u00BB: \u0430\u0433\u0435\u043D\u0442 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442 \u0434\u0435\u0442\u0435\u0440\u043C\u0438\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439\n * \u0438 \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u043D\u044B\u0439 \u043F\u043E \u0440\u0430\u0437\u043C\u0435\u0440\u0443 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0432\u043C\u0435\u0441\u0442\u043E \u0432\u0441\u0435\u0433\u043E docs/.\n */\nexport async function buildEffectiveRules(options: BuildRulesOptions): Promise<EffectiveRules> {\n const { root, config, configPath } = options;\n const language = options.language ?? 'ru';\n const t = (ru: string, en: string): string => (language === 'ru' ? ru : en);\n const warnings: string[] = [];\n const files = options.files.filter((file) => !config.rules.ignore.some((pattern) => globToRegExp(pattern).test(file)));\n const ignored = options.files.length - files.length;\n if (ignored > 0) warnings.push(`${ignored} ${t('\u0444\u0430\u0439\u043B(\u043E\u0432) \u0438\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u044B \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u043E\u0439 rules.ignore', 'file(s) excluded by rules.ignore')}`);\n\n const cache = new Map<string, CachedDoc>();\n let totalBytes = 0;\n\n const readDoc = async (selector: string): Promise<RuleDocument> => {\n const [rawPath] = selector.split('#');\n const relative = rawPath!;\n let resolved: string;\n try {\n resolved = assertConfigPath(root, relative);\n } catch (error) {\n warnings.push(`${relative}: ${(error as Error).message}`);\n return { path: relative, exists: false, sections: [], excerpt: '', truncated: false };\n }\n let cached = cache.get(resolved);\n if (!cached) {\n if (!existsSync(resolved)) {\n cached = { exists: false, text: '', truncated: false };\n warnings.push(`${t('\u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442', 'document')} ${relative} ${t('\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D', 'not found')}`);\n } else {\n try {\n const raw = await readTextNoFollow(resolved, MAX_DOC_BYTES * 2);\n const truncated = raw.length > MAX_DOC_BYTES;\n cached = { exists: true, text: truncated ? raw.slice(0, MAX_DOC_BYTES) : raw, truncated };\n } catch (error) {\n cached = { exists: false, text: '', truncated: false };\n warnings.push(`${relative}: ${redactLine(error)}`);\n }\n }\n cache.set(resolved, cached);\n }\n const selectors = selector.includes('#') ? [selector.slice(selector.indexOf('#') + 1)] : [];\n const excerpt = extractExcerpt(cached.text, selectors, relative, warnings, language);\n totalBytes += excerpt.length;\n return { path: relative, exists: cached.exists, sections: selectors, excerpt, truncated: cached.truncated };\n };\n\n const scopes: RuleScope[] = [];\n for (const file of files) {\n const docs = new Set<string>();\n for (const entry of config.rules.map) {\n const patterns = Array.isArray(entry.match) ? entry.match : [entry.match];\n if (patterns.some((pattern) => globToRegExp(pattern).test(file))) {\n for (const doc of entry.docs) docs.add(doc);\n }\n }\n if (!docs.size) {\n for (const doc of config.rules.sources) docs.add(doc);\n if (!docs.size) {\n warnings.push(`${file}: ${t('\u043D\u0435\u0442 \u043F\u0440\u0430\u0432\u0438\u043B \u2014 \u043F\u0443\u0442\u044C \u043D\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D \u0432 rules.map, \u0430 rules.sources \u043F\u0443\u0441\u0442', 'no rules \u2014 the path is not mapped in rules.map and rules.sources is empty')}`);\n }\n }\n const documents: RuleDocument[] = [];\n for (const doc of docs) {\n if (totalBytes > MAX_TOTAL_BYTES) {\n warnings.push(t('\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u043F\u0440\u0430\u0432\u0438\u043B \u043E\u0431\u0440\u0435\u0437\u0430\u043D: \u043F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u043B\u0438\u043C\u0438\u0442 \u0440\u0430\u0437\u043C\u0435\u0440\u0430', 'rules context truncated: size limit exceeded'));\n break;\n }\n documents.push(await readDoc(doc));\n }\n scopes.push({ file, kind: classifyFile(file), documents });\n }\n\n // \u041E\u0431\u0449\u0438\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 (\u0435\u0441\u043B\u0438 \u0444\u0430\u0439\u043B\u043E\u0432 \u043D\u0435\u0442) \u2014 \u0447\u0442\u043E\u0431\u044B \u0440\u0435\u0432\u044C\u044E \u043F\u043E \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u044E MR \u0442\u043E\u0436\u0435 \u0438\u043C\u0435\u043B\u043E \u043A\u0440\u0438\u0442\u0435\u0440\u0438\u0438.\n if (!files.length) {\n const documents: RuleDocument[] = [];\n for (const doc of config.rules.sources) documents.push(await readDoc(doc));\n if (!documents.length) warnings.push(t('\u043E\u0431\u0449\u0438\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430: rules.sources \u043F\u0443\u0441\u0442, \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B', 'general rules: rules.sources is empty, no documents selected'));\n scopes.push({ file: '', kind: 'other', documents });\n }\n\n return {\n configPath: configPath ? path.relative(root, configPath) : null,\n scopes,\n checks: checksForPaths(config, files),\n warnings: [...new Set(warnings)],\n };\n}\n\n/**\n * \u0412\u044B\u0440\u0435\u0437\u0430\u0435\u0442 \u0437\u0430\u043F\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0435 \u0441\u0435\u043A\u0446\u0438\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430.\n * \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 `#\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A`, `#anchor`, `#L10-L20`, `#10-20`.\n */\nexport function extractExcerpt(text: string, selectors: string[], label: string, warnings: string[], language: Locale = 'ru'): string {\n const t = (ru: string, en: string): string => (language === 'ru' ? ru : en);\n if (!text) return '';\n if (!selectors.length) return text;\n const parts: string[] = [];\n for (const selector of selectors) {\n const range = /^L?(\\d+)(?:-L?(\\d+))?$/.exec(selector.trim());\n if (range) {\n const start = Number(range[1]);\n const end = range[2] ? Number(range[2]) : start;\n const lines = text.split('\\n');\n if (start < 1 || end < start || start > lines.length) {\n warnings.push(`${label}#${selector}: ${t('\u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D \u0441\u0442\u0440\u043E\u043A \u0432\u043D\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430', 'line range is outside the document')}`);\n continue;\n }\n parts.push(lines.slice(start - 1, Math.min(end, lines.length)).join('\\n'));\n continue;\n }\n const section = headingSection(text, selector);\n if (section === null) {\n warnings.push(`${label}#${selector}: ${t('\u0441\u0435\u043A\u0446\u0438\u044F \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430', 'section not found')}`);\n continue;\n }\n parts.push(section);\n }\n return parts.join('\\n\\n');\n}\n\nconst HEADING = /^(#{1,6})\\s+(.+?)\\s*#*\\s*$/;\n\nfunction headingSection(text: string, wanted: string): string | null {\n const lines = text.split('\\n');\n const target = normalizeHeading(wanted);\n let start = -1;\n let level = 0;\n for (let index = 0; index < lines.length; index++) {\n const match = HEADING.exec(lines[index]!);\n if (!match) continue;\n if (normalizeHeading(match[2]!) === target) {\n start = index;\n level = match[1]!.length;\n break;\n }\n }\n if (start < 0) return null;\n let end = lines.length;\n for (let index = start + 1; index < lines.length; index++) {\n const match = HEADING.exec(lines[index]!);\n if (match && match[1]!.length <= level) {\n end = index;\n break;\n }\n }\n return lines.slice(start, end).join('\\n').trimEnd();\n}\n\n/** `#\u0421\u043B\u043E\u0438 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0438` \u0438 `#layers` \u043F\u0440\u0438\u0432\u043E\u0434\u044F\u0442\u0441\u044F \u043A \u043E\u0434\u043D\u043E\u043C\u0443 \u0432\u0438\u0434\u0443. */\nexport function normalizeHeading(value: string): string {\n return value\n .replace(/^#+/, '')\n .replace(/[*_`]/g, '')\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase();\n}\n\n/** \u041A\u043E\u043C\u043F\u0430\u043A\u0442\u043D\u044B\u0439 markdown-\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u043F\u0440\u0430\u0432\u0438\u043B \u0434\u043B\u044F \u0430\u0433\u0435\u043D\u0442\u0430 (MCP/CLI). */\nexport function renderRules(rules: EffectiveRules, options: { withExcerpts?: boolean; maxBytes?: number; language?: Locale } = {}): string {\n const maxBytes = options.maxBytes ?? 200_000;\n const withExcerpts = options.withExcerpts ?? true;\n const language = options.language ?? 'ru';\n const t = (ru: string, en: string): string => (language === 'ru' ? ru : en);\n const out: string[] = [];\n out.push(`# ${t('\u041F\u0440\u0430\u0432\u0438\u043B\u0430 \u0440\u0435\u0432\u044C\u044E', 'Review rules')}${rules.configPath ? ` (${rules.configPath})` : ` (${t('\u0430\u0432\u0442\u043E\u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0438\u0435', 'auto-discovery')})`}`);\n if (rules.warnings.length) out.push(`${t('\u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F', 'Warnings')}:\\n${rules.warnings.map((item) => `- ${item}`).join('\\n')}`);\n const seen = new Set<string>();\n for (const scope of rules.scopes) {\n out.push(`\\n## ${scope.file || `(${t('\u043E\u0431\u0449\u0438\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430', 'general rules')})`} \u2014 ${scope.kind}`);\n for (const doc of scope.documents) {\n const key = `${doc.path}#${doc.sections.join(',')}`;\n const label = `${doc.path}${doc.sections.length ? `#${doc.sections.join(', ')}` : ''}`;\n out.push(`- ${label}${doc.exists ? '' : ` (${t('\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D', 'not found')})`}`);\n if (!withExcerpts || !doc.exists) continue;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(`\\n> ${label}\\n\\n${doc.excerpt}${doc.truncated ? `\\n\\n[${t('\u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043E\u0431\u0440\u0435\u0437\u0430\u043D', 'document truncated')}]` : ''}`);\n if (out.join('\\n').length > maxBytes) {\n out.push(`\\n[${t('\u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u043F\u0440\u0430\u0432\u0438\u043B \u043E\u0431\u0440\u0435\u0437\u0430\u043D \u043F\u043E \u0440\u0430\u0437\u043C\u0435\u0440\u0443', 'rules context truncated by size')}]`);\n return out.join('\\n');\n }\n }\n }\n if (rules.checks.length) {\n out.push(`\\n## ${t('\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430', 'Project checks')}`);\n for (const check of rules.checks) {\n out.push(`- ${check.id}${check.matched ? '' : ` (${t('\u043D\u0435 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043A diff', 'does not match the diff')})`}: \\`${check.argv.join(' ')}\\`${check.consent ? ` \u2014 ${t('\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F', 'requires user consent')}` : ''}`);\n }\n }\n return out.join('\\n');\n}\n", "import type { Platform } from './types.js';\nimport { tr } from './locale.js';\n\n/**\n * \u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0442\u0435\u043A\u0441\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0443\u0439\u0434\u0451\u0442 \u0432 \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u044B\u0439 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439.\n *\n * \u0427\u0430\u0441\u0442\u044C \u0442\u0435\u043A\u0441\u0442\u0430 \u043F\u0438\u0448\u0435\u0442 \u0430\u0433\u0435\u043D\u0442, \u0430 \u0447\u0430\u0441\u0442\u044C \u2014 \u043C\u043E\u0434\u0435\u043B\u044C, \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0432\u0448\u0430\u044F \u043D\u0435\u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0439 MR.\n * \u041F\u043E\u044D\u0442\u043E\u043C\u0443 \u0437\u0430\u043F\u0440\u0435\u0449\u0430\u0435\u043C \u0432\u0441\u0451, \u0447\u0442\u043E \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u0435\u0442\u0441\u044F \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u043E\u0439 \u0438\u043B\u0438 \u043F\u0440\u044F\u0447\u0435\u0442 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0435 \u043E\u0442\n * \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0432 \u043E\u043A\u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F: \u0431\u044B\u0441\u0442\u0440\u044B\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u044B GitLab, HTML, \u0441\u043A\u0440\u044B\u0442\u044B\u0435 \u0438\n * bidi-\u0441\u0438\u043C\u0432\u043E\u043B\u044B, \u043C\u0430\u0441\u0441\u043E\u0432\u044B\u0435 \u0443\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u044F \u0438 \u0432\u043D\u0435\u0448\u043D\u0438\u0435 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438.\n */\n\nconst CONTROL_OR_HIDDEN =\n /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f\\u00ad\\u061c\\u115f\\u1160\\u180e\\u200b-\\u200f\\u2028-\\u202e\\u2060-\\u206f\\u2800\\u3164\\ufeff\\uffa0]/;\n\nconst QUICK_ACTION = /^[\\s\\p{Z}\\p{Cf}]*\\/[a-z_]+(?=[\\s\\p{Z}\\p{Cf}]|$)/imu;\nconst MASS_MENTION = /(^|[^\\w@./-])@(all|here|everyone)(?![\\w-])/i;\nconst MD_IMAGE = /!\\[[^\\]]*\\]\\s*\\(|!\\[[^\\]]*\\]\\s*\\[/;\nconst HTML_TAG = /<(?:img|script|iframe|style|video|audio|object|embed|svg|math)\\b/i;\nconst HTML_COMMENT = /<!--/;\nconst MAX_LENGTH = 64 * 1024;\n\nexport interface SanitizeResult {\n ok: boolean;\n reason: string;\n /** \u0422\u0435\u043A\u0441\u0442 \u043F\u043E\u0441\u043B\u0435 \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u043E\u0432 \u0441\u0442\u0440\u043E\u043A. */\n text: string;\n}\n\nexport interface SanitizeOptions {\n maxLength?: number;\n /** \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0431\u044B\u0441\u0442\u0440\u044B\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u044B GitLab (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F GitLab). */\n quickActions?: boolean;\n}\n\nexport function sanitizeBody(body: string, platform: Platform, options: SanitizeOptions = {}): SanitizeResult {\n const text = String(body ?? '').replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n const maxLength = options.maxLength ?? MAX_LENGTH;\n const checkQuickActions = options.quickActions ?? platform === 'gitlab';\n\n if (text.trim() === '') return { ok: false, reason: tr('\u0442\u0435\u043A\u0441\u0442 \u043F\u0443\u0441\u0442', 'the text is empty'), text };\n if (text.length > maxLength) return { ok: false, reason: tr(`\u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u0438\u043D\u043D\u0435\u0435 ${maxLength} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432`, `the text is longer than ${maxLength} characters`), text };\n if (CONTROL_OR_HIDDEN.test(text)) return { ok: false, reason: tr('\u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u0435\u0441\u0442\u044C \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0438\u043B\u0438 \u043D\u0435\u0432\u0438\u0434\u0438\u043C\u044B\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B', 'the text contains control or invisible characters'), text };\n if (HTML_COMMENT.test(text)) return { ok: false, reason: tr('\u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u0435\u0441\u0442\u044C HTML-\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439', 'the text contains an HTML comment'), text };\n if (HTML_TAG.test(text)) return { ok: false, reason: tr('\u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u0435\u0441\u0442\u044C HTML-\u0442\u0435\u0433', 'the text contains an HTML tag'), text };\n if (MD_IMAGE.test(text)) return { ok: false, reason: tr('\u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u0435\u0441\u0442\u044C \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430: \u0437\u0430\u043C\u0435\u043D\u0438\u0442\u0435 \u0441\u0441\u044B\u043B\u043A\u043E\u0439', 'the text contains an image: replace it with a link'), text };\n if (MASS_MENTION.test(text)) return { ok: false, reason: tr('\u043C\u0430\u0441\u0441\u043E\u0432\u043E\u0435 \u0443\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u0435: \u0443\u043A\u0430\u0436\u0438\u0442\u0435 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u044B\u0445 \u043B\u044E\u0434\u0435\u0439', 'mass mention: name specific people'), text };\n if (checkQuickActions && QUICK_ACTION.test(text)) {\n return { ok: false, reason: tr('\u0441\u0442\u0440\u043E\u043A\u0430-\u043A\u043E\u043C\u0430\u043D\u0434\u0430 GitLab (/approve, /merge \u2026): \u043F\u0435\u0440\u0435\u0444\u0440\u0430\u0437\u0438\u0440\u0443\u0439\u0442\u0435', 'GitLab quick action line (/approve, /merge \u2026): rephrase it'), text };\n }\n return { ok: true, reason: '', text };\n}\n\n/** \u0422\u0435\u043A\u0441\u0442, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0432 GitHub: \u0431\u044B\u0441\u0442\u0440\u044B\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u044E\u0442\u0441\u044F, \u043D\u043E \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u0430\u043A\u0442\u0443\u0430\u043B\u044C\u043D\u043E. */\nexport function sanitizeGithubBody(body: string): SanitizeResult {\n return sanitizeBody(body, 'github', { quickActions: false });\n}\n\nexport function isSafeBody(body: string, platform: Platform): boolean {\n return sanitizeBody(body, platform).ok;\n}\n", "import { createHash } from 'node:crypto';\nimport { LEVELS, type Decision, type Finding, type FindingStatus, type Level } from './types.js';\nimport { normalizeLevel } from './refs.js';\nimport { tr } from './locale.js';\n\nexport interface FindingDraft {\n id?: string;\n level: Level;\n file: string;\n line: number | null;\n endLine?: number | null;\n title: string;\n body: string;\n comment: string;\n}\n\nexport interface FindingValidation {\n value: FindingDraft | null;\n error: string;\n}\n\nconst LEVEL_ORDER: Record<Level, number> = { blocker: 0, major: 1, minor: 2, question: 3 };\n\n/** \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442 \u0438 \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0443\u0435\u0442 \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435, \u043F\u0440\u0438\u0448\u0435\u0434\u0448\u0435\u0435 \u043E\u0442 \u0430\u0433\u0435\u043D\u0442\u0430 (CLI/MCP). */\nexport function validateFinding(raw: unknown): FindingValidation {\n if (!raw || typeof raw !== 'object') return { value: null, error: tr('\u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u043C', 'a finding must be an object') };\n const item = raw as Record<string, unknown>;\n const file = typeof item.file === 'string' ? item.file.trim() : '';\n const title = typeof item.title === 'string' ? item.title.trim() : '';\n const body = typeof item.body === 'string' ? item.body.trim() : '';\n const comment = typeof item.comment === 'string' ? item.comment.trim() : body;\n if (!file) return { value: null, error: tr('\u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D file', 'file is required') };\n if (!title) return { value: null, error: tr('\u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D title', 'title is required') };\n if (!comment) return { value: null, error: tr('\u043F\u0443\u0441\u0442\u043E\u0439 comment', 'comment is empty') };\n const line = item.line === null || item.line === undefined || item.line === '' ? null : Number(item.line);\n if (line !== null && (!Number.isInteger(line) || line < 1)) return { value: null, error: tr(`\u043D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 line: ${String(item.line)}`, `invalid line: ${String(item.line)}`) };\n const endLine = item.endLine === null || item.endLine === undefined ? null : Number(item.endLine);\n if (endLine !== null && (!Number.isInteger(endLine) || line === null || endLine < line)) {\n return { value: null, error: tr('endLine \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 line', 'endLine must be greater than or equal to line') };\n }\n const level = normalizeLevel(item.level);\n if (item.level !== undefined && !(LEVELS as readonly string[]).includes(String(item.level))) {\n return { value: null, error: tr(`\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 level: ${String(item.level)} (\u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F ${LEVELS.join(', ')})`, `unknown level: ${String(item.level)} (expected ${LEVELS.join(', ')})`) };\n }\n return {\n value: {\n ...(typeof item.id === 'string' && item.id ? { id: item.id } : {}),\n level,\n file,\n line,\n endLine,\n title,\n body,\n comment,\n },\n error: '',\n };\n}\n\n/**\n * \u041E\u0442\u043F\u0435\u0447\u0430\u0442\u043E\u043A \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F \u0434\u043B\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0433\u043E \u0440\u0435\u0432\u044C\u044E: \u043D\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043E\u0442 \u043D\u043E\u043C\u0435\u0440\u0430 \u0441\u0442\u0440\u043E\u043A\u0438,\n * \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u043F\u043E\u0441\u043B\u0435 \u043D\u043E\u0432\u044B\u0445 \u043A\u043E\u043C\u043C\u0438\u0442\u043E\u0432 \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0435 \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u0442\u0435\u043C \u0436\u0435.\n */\nexport function fingerprintOf(input: { file: string; level: string; title: string }): string {\n return createHash('sha256')\n .update(`${input.file.trim().toLowerCase()}|${input.level}|${input.title.trim().toLowerCase().replace(/\\s+/g, ' ')}`)\n .digest('hex');\n}\n\nexport interface MergeOptions {\n now?: string;\n}\n\n/**\n * \u0421\u043B\u0438\u0432\u0430\u0435\u0442 \u043D\u043E\u0432\u044B\u0439 \u043D\u0430\u0431\u043E\u0440 \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u0439 \u0441 \u043F\u0440\u0435\u0436\u043D\u0438\u043C, \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u044F \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438\n * \u0441\u0442\u0430\u0442\u0443\u0441 \u043F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u0438. \u0417\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F, \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u0442 \u0432 diff, \u043F\u043E\u043C\u0435\u0447\u0430\u044E\u0442\u0441\u044F stale,\n * \u0430 \u043D\u0435 \u0443\u0434\u0430\u043B\u044F\u044E\u0442\u0441\u044F: \u043E\u0442 \u0438\u0445 id \u0437\u0430\u0432\u0438\u0441\u044F\u0442 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u0438 \u0443\u0436\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438.\n */\nexport function mergeFindings(previous: Finding[], incoming: FindingDraft[], options: MergeOptions = {}): Finding[] {\n const now = options.now ?? new Date().toISOString();\n const byId = new Map(previous.map((item) => [item.id, item]));\n const byFingerprint = new Map(previous.map((item) => [item.fingerprint, item]));\n const byPlace = new Map(previous.filter((item) => item.line !== null).map((item) => [`${item.file}:${item.line}:${item.level}`, item]));\n const used = new Set<string>();\n const result: Finding[] = [];\n\n for (const draft of incoming) {\n const fingerprint = fingerprintOf(draft);\n const match =\n (draft.id ? byId.get(draft.id) : undefined) ??\n byFingerprint.get(fingerprint) ??\n (draft.line !== null ? byPlace.get(`${draft.file}:${draft.line}:${draft.level}`) : undefined);\n\n if (match) {\n used.add(match.id);\n result.push({\n ...match,\n level: draft.level,\n file: draft.file,\n line: draft.line,\n endLine: draft.endLine ?? null,\n title: draft.title,\n body: draft.body,\n // \u041E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0442\u0435\u043A\u0441\u0442 \u043D\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u043C: \u043E\u043D \u0443\u0436\u0435 \u0432\u0438\u0434\u0435\u043D \u0430\u0432\u0442\u043E\u0440\u0443 MR.\n comment: match.status === 'published' ? match.comment : draft.comment,\n status: match.status === 'stale' ? 'draft' : match.status,\n fingerprint,\n });\n continue;\n }\n\n const id = draft.id && !used.has(draft.id) ? draft.id : uniqueId(fingerprint, used, byId);\n used.add(id);\n result.push({\n id,\n fingerprint,\n level: draft.level,\n file: draft.file,\n line: draft.line,\n endLine: draft.endLine ?? null,\n title: draft.title,\n body: draft.body,\n comment: draft.comment,\n status: 'draft',\n discussionId: null,\n publishedAt: null,\n decision: null,\n note: '',\n publishError: '',\n });\n }\n\n for (const old of previous) {\n if (used.has(old.id)) continue;\n result.push({\n ...old,\n status: old.status === 'published' ? 'published' : 'stale',\n });\n }\n\n return result.sort((a, b) => levelOrder(a.level) - levelOrder(b.level) || a.file.localeCompare(b.file) || (a.line ?? 0) - (b.line ?? 0));\n}\n\nfunction uniqueId(fingerprint: string, used: Set<string>, byId: Map<string, Finding>): string {\n for (let length = 8; length <= fingerprint.length; length += 2) {\n const candidate = `f-${fingerprint.slice(0, length)}`;\n if (!used.has(candidate) && !byId.has(candidate)) return candidate;\n }\n return `f-${fingerprint}`;\n}\n\nexport function levelOrder(level: Level): number {\n return LEVEL_ORDER[level];\n}\n\n/** \u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442 \u0440\u0435\u0448\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043A \u0437\u0430\u043C\u0435\u0447\u0430\u043D\u0438\u044F\u043C (accept/reject/discuss). */\nexport function applyDecisions(findings: Finding[], decisions: Record<string, { decision: Decision | null; note: string }>): Finding[] {\n return findings.map((item) => {\n const decision = decisions[item.id];\n if (!decision) return item;\n return { ...item, decision: decision.decision, note: decision.note };\n });\n}\n\nexport function statusLabel(status: FindingStatus): string {\n switch (status) {\n case 'draft':\n return '\u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A';\n case 'accepted':\n return '\u043F\u0440\u0438\u043D\u044F\u0442\u043E';\n case 'rejected':\n return '\u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u043E';\n case 'published':\n return '\u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u043D\u043E';\n case 'fixed':\n return '\u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E';\n case 'stale':\n return '\u0443\u0441\u0442\u0430\u0440\u0435\u043B\u043E';\n }\n}\n", "/**\n * \u041A\u0430\u043D\u043E\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 JSON: \u043A\u043B\u044E\u0447\u0438 \u043E\u0442\u0441\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u044B, \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0431\u0435\u0437 undefined.\n * \u041D\u0443\u0436\u0435\u043D \u0434\u043B\u044F \u0445\u0435\u0448\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A: \u043B\u044E\u0431\u043E\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0442\u0435\u043A\u0441\u0442\u0430\n * \u043C\u0435\u043D\u044F\u0435\u0442 \u0445\u0435\u0448, \u0438 \u043F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u044F \u043F\u043E \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u043C\u0443 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044E \u043E\u0442\u043A\u043B\u043E\u043D\u044F\u0435\u0442\u0441\u044F.\n */\nexport function canonicalJson(value: unknown): string {\n return JSON.stringify(normalize(value));\n}\n\nfunction normalize(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(normalize);\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n const item = (value as Record<string, unknown>)[key];\n if (item !== undefined) out[key] = normalize(item);\n }\n return out;\n }\n return value;\n}\n", "import { run } from './exec.js';\nimport type { Platform } from './types.js';\n\nexport interface RemoteInfo {\n host: string;\n project: string;\n platform: Platform | null;\n url: string;\n}\n\nconst SSH_SCP = /^(?:ssh:\\/\\/)?(?:[^@/]+@)?([^:/]+)(?::(\\d+))?[:/](.+?)(?:\\.git)?\\/?$/;\n\n/** \u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 git remote \u0432 \u0445\u043E\u0441\u0442/\u043F\u0440\u043E\u0435\u043A\u0442. \u041F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 scp-\u043F\u043E\u0434\u043E\u0431\u043D\u044B\u0439 \u0438 URL-\u0432\u0438\u0434\u044B. */\nexport function parseRemote(url: string): RemoteInfo | null {\n const value = url.trim();\n if (!value) return null;\n let host = '';\n let projectPath = '';\n const http = /^(?:https?|git|ssh):\\/\\/(?:[^@/]+@)?([^/:]+)(?::\\d+)?\\/(.+?)(?:\\.git)?\\/?$/.exec(value);\n if (http) {\n host = http[1]!;\n projectPath = http[2]!;\n } else {\n const scp = SSH_SCP.exec(value);\n if (!scp) return null;\n host = scp[1]!;\n projectPath = scp[3]!;\n }\n projectPath = projectPath.replace(/\\/+$/, '').replace(/\\.git$/, '');\n if (!host || !projectPath || !projectPath.includes('/')) return null;\n return { host, project: projectPath, platform: detectPlatform(host), url: value };\n}\n\nexport function detectPlatform(host: string): Platform | null {\n const lower = host.toLowerCase();\n if (lower === 'github.com' || lower.endsWith('.github.com') || lower.includes('github')) return 'github';\n if (lower === 'gitlab.com' || lower.endsWith('.gitlab.com') || lower.includes('gitlab')) return 'gitlab';\n return null;\n}\n\nexport async function gitRemote(root: string, remote = 'origin'): Promise<RemoteInfo | null> {\n try {\n const { stdout } = await run('git', ['config', '--get', `remote.${remote}.url`], { cwd: root, timeoutMs: 10_000 });\n return parseRemote(stdout.trim());\n } catch {\n return null;\n }\n}\n\nexport async function remoteNames(root: string): Promise<string[]> {\n try {\n const { stdout } = await run('git', ['remote'], { cwd: root, timeoutMs: 10_000 });\n return stdout.split('\\n').map((item) => item.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport async function currentBranch(root: string): Promise<string> {\n try {\n const { stdout } = await run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root, timeoutMs: 10_000 });\n return stdout.trim();\n } catch {\n return '';\n }\n}\n\nexport async function headSha(root: string): Promise<string> {\n try {\n const { stdout } = await run('git', ['rev-parse', 'HEAD'], { cwd: root, timeoutMs: 10_000 });\n return stdout.trim();\n } catch {\n return '';\n }\n}\n\n/** \u0412\u0435\u0442\u043A\u0430 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0438\u0437 origin/HEAD, \u0438\u043D\u0430\u0447\u0435 \u043F\u0435\u0440\u0432\u0430\u044F \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445. */\nexport async function defaultBranch(root: string): Promise<string> {\n try {\n const { stdout } = await run('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], { cwd: root, timeoutMs: 10_000 });\n const name = stdout.trim().replace(/^origin\\//, '');\n if (name) return name;\n } catch {\n // fallthrough\n }\n for (const candidate of ['develop', 'main', 'master']) {\n try {\n await run('git', ['rev-parse', '--verify', candidate], { cwd: root, timeoutMs: 10_000 });\n return candidate;\n } catch {\n // next\n }\n }\n return 'main';\n}\n\n/** Diff \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E\u0439 \u0432\u0435\u0442\u043A\u0438 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0431\u0430\u0437\u044B; \u0434\u043B\u044F \u0440\u0435\u0432\u044C\u044E \u0431\u0435\u0437 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u044B. */\nexport async function localDiff(root: string, base: string): Promise<string> {\n const { stdout } = await run('git', ['diff', '--no-color', '--no-ext-diff', '--src-prefix=a/', '--dst-prefix=b/', `${base}...HEAD`], {\n cwd: root,\n timeoutMs: 60_000,\n maxBuffer: 64 * 1024 * 1024,\n });\n return stdout;\n}\n\nexport async function isCleanWorktree(root: string): Promise<boolean> {\n try {\n const { stdout } = await run('git', ['status', '--porcelain'], { cwd: root, timeoutMs: 10_000 });\n return stdout.trim() === '';\n } catch {\n return false;\n }\n}\n\nexport async function commitOf(root: string, ref: string): Promise<string> {\n try {\n const { stdout } = await run('git', ['rev-parse', ref], { cwd: root, timeoutMs: 10_000 });\n return stdout.trim();\n } catch {\n return '';\n }\n}\n", "import type { ReviewConfig } from '../core/config.js';\nimport type { DiffFile, Platform, ReviewInfo, ReviewRef, Thread, User, Note } from '../core/types.js';\nimport type { Runner } from '../core/exec.js';\nimport { currentBranch, gitRemote } from '../core/git.js';\nimport { ProviderError } from '../core/errors.js';\nimport { parseReviewUrl } from '../core/refs.js';\nimport { tr } from '../core/locale.js';\n\nexport interface ProviderOptions {\n root: string;\n /** \u0414\u043B\u044F \u0442\u0435\u0441\u0442\u043E\u0432: \u043F\u043E\u0434\u043C\u0435\u043D\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0430 CLI. */\n runImpl?: Runner;\n}\n\nexport interface ListOptions {\n scope?: 'open' | 'mine' | 'reviewing';\n limit?: number;\n}\n\nexport interface ReviewListItem {\n ref: ReviewRef;\n title: string;\n author: string;\n updatedAt: string;\n state: string;\n draft: boolean;\n webUrl: string;\n}\n\nexport interface CreateThreadInput {\n file: string;\n /** null \u2014 \u043E\u0431\u0449\u0438\u0439 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 \u043A \u0440\u0435\u0432\u044C\u044E, \u0431\u0435\u0437 \u043F\u0440\u0438\u0432\u044F\u0437\u043A\u0438 \u043A \u0441\u0442\u0440\u043E\u043A\u0435. */\n line: number | null;\n oldLine: number | null;\n body: string;\n}\n\nexport interface CreatedThread {\n discussionId: string;\n noteId: string;\n}\n\nexport interface ProviderCapabilities {\n reactions: boolean;\n resolve: boolean;\n nativeDrafts: boolean;\n}\n\n/**\n * \u041F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440. \u0415\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435 \u043C\u0435\u0441\u0442\u043E, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0437\u043D\u0430\u0435\u0442 \u043F\u0440\u043E GitLab/GitHub.\n * \u0412\u0441\u0435 \u043C\u0435\u0442\u043E\u0434\u044B \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u0435, \u0447\u0442\u043E \u043D\u0443\u0436\u043D\u044B \u0440\u0435\u0432\u044C\u044E; \u043D\u0438\u0447\u0435\u0433\u043E \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u044E\u0449\u0435\u0433\u043E \u043A\u043E\u0434 \u043F\u0440\u043E\u0435\u043A\u0442\u0430.\n */\nexport interface Provider {\n readonly ref: ReviewRef;\n readonly platform: Platform;\n readonly capabilities: ProviderCapabilities;\n info(): Promise<ReviewInfo>;\n diff(): Promise<DiffFile[]>;\n threads(): Promise<Thread[]>;\n currentUser(): Promise<User>;\n list(options?: ListOptions): Promise<ReviewListItem[]>;\n findByBranch(branch: string): Promise<ReviewRef | null>;\n reply(thread: Thread, body: string): Promise<Note>;\n resolve(threadId: string, resolved: boolean): Promise<void>;\n react(noteId: string, emoji: string): Promise<{ active: boolean }>;\n createThread(input: CreateThreadInput): Promise<CreatedThread>;\n}\n\nexport interface ProjectContext {\n platform: Platform;\n host: string;\n project: string;\n}\n\n/**\n * \u0412\u044B\u0447\u0438\u0441\u043B\u044F\u0435\u0442 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0443/\u0445\u043E\u0441\u0442/\u043F\u0440\u043E\u0435\u043A\u0442 \u043F\u043E \u044F\u0432\u043D\u044B\u043C \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u0430\u043C, \u043A\u043E\u043D\u0444\u0438\u0433\u0443 \u0438 git remote.\n * \u042F\u0432\u043D\u044B\u0435 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B \u0432\u0430\u0436\u043D\u0435\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0430, \u043A\u043E\u043D\u0444\u0438\u0433 \u0432\u0430\u0436\u043D\u0435\u0435 remote: \u0442\u0430\u043A \u0440\u0435\u0432\u044C\u044E \u043D\u0435\u043B\u044C\u0437\u044F\n * \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u0438\u0442\u044C, \u043F\u043E\u0434\u043C\u0435\u043D\u0438\u0432 `.git/config`.\n */\nexport async function projectContext(root: string, config: ReviewConfig, overrides: Partial<ProjectContext> = {}): Promise<ProjectContext> {\n const remote = await gitRemote(root);\n const platform = overrides.platform ?? (config.provider.type !== 'auto' ? config.provider.type : remote?.platform ?? undefined);\n const host = overrides.host ?? config.provider.host ?? remote?.host;\n const project = overrides.project ?? config.provider.project ?? remote?.project;\n if (!platform) {\n throw new ProviderError(\n tr('\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0443: \u0443\u043A\u0430\u0436\u0438\u0442\u0435 provider.type \u0432 .revdeck.yml \u0438\u043B\u0438 --platform', 'could not determine the platform: set provider.type in .revdeck.yml or pass --platform'),\n tr('git remote \u043D\u0435 \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 GitHub/GitLab (\u0441\u0430\u043C\u043E\u0441\u0442\u043E\u044F\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0445\u043E\u0441\u0442 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u0435 \u044F\u0432\u043D\u043E)', 'git remote does not look like GitHub/GitLab (set a self-hosted platform explicitly)'),\n );\n }\n if (!host || !project) {\n throw new ProviderError(tr('\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u0445\u043E\u0441\u0442 \u0438 \u043F\u0440\u043E\u0435\u043A\u0442', 'could not determine host and project'), tr('\u0443\u043A\u0430\u0436\u0438\u0442\u0435 project \u0438 host \u0432 .revdeck.yml \u0438\u043B\u0438 \u043F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 URL \u0440\u0435\u0432\u044C\u044E', 'set project and host in .revdeck.yml or pass the review URL'));\n }\n return { platform, host, project };\n}\n\nexport async function resolveReviewRef(\n options: { root: string; config: ReviewConfig; input?: string; platform?: Platform; project?: string; host?: string; branch?: string },\n): Promise<ReviewRef> {\n const { root, config, input } = options;\n if (input && /^(https?:)?\\/\\//.test(input.trim())) {\n return parseReviewUrl(input);\n }\n const context = await projectContext(root, config, {\n ...(options.platform ? { platform: options.platform } : {}),\n ...(options.project ? { project: options.project } : {}),\n ...(options.host ? { host: options.host } : {}),\n });\n if (input && /^\\d+$/.test(input.trim())) {\n return { ...context, number: Number(input.trim()) };\n }\n if (input && /^[^#!]+[#!]\\d+$/.test(input.trim())) {\n return parseReviewUrl(input);\n }\n if (input) throw new ProviderError(tr(`\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u0442\u044C \u0440\u0435\u0432\u044C\u044E: ${input}`, `could not parse the review: ${input}`));\n // \u0411\u0435\u0437 \u043D\u043E\u043C\u0435\u0440\u0430 \u0438\u0449\u0435\u043C \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0435 \u0440\u0435\u0432\u044C\u044E \u0442\u0435\u043A\u0443\u0449\u0435\u0439 \u0432\u0435\u0442\u043A\u0438.\n const branch = options.branch ?? (await currentBranch(root));\n if (!branch || branch === 'HEAD') {\n throw new ProviderError(tr('\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u0432\u0435\u0442\u043A\u0443 \u0434\u043B\u044F \u043F\u043E\u0438\u0441\u043A\u0430 \u0440\u0435\u0432\u044C\u044E', 'could not determine the branch to search for a review'), tr('\u043F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0440\u0435\u0432\u044C\u044E \u044F\u0432\u043D\u043E', 'pass the review number explicitly'));\n }\n const probe = await createProvider({ ...context, number: 0 }, { root });\n const found = await probe.findByBranch(branch);\n if (!found) throw new ProviderError(tr(`\u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0435 \u0440\u0435\u0432\u044C\u044E \u0434\u043B\u044F \u0432\u0435\u0442\u043A\u0438 ${branch} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E`, `no open review found for branch ${branch}`), tr('\u043F\u0435\u0440\u0435\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0440\u0435\u0432\u044C\u044E \u044F\u0432\u043D\u043E', 'pass the review number explicitly'));\n return found;\n}\n\nexport async function createProvider(ref: ReviewRef, options: ProviderOptions): Promise<Provider> {\n if (ref.platform === 'gitlab') {\n const { GitLabProvider } = await import('./gitlab.js');\n return new GitLabProvider(ref, options);\n }\n const { GitHubProvider } = await import('./github.js');\n return new GitHubProvider(ref, options);\n}\n", "import { diffStats, snippetAround, type SnippetLine } from '../core/diff.js';\nimport type { DiffFile, Finding, Review, ReviewSummary, Thread } from '../core/types.js';\n\nexport interface ReviewFileSummary {\n path: string;\n oldPath: string;\n status: DiffFile['status'];\n binary: boolean;\n additions: number;\n deletions: number;\n}\n\nexport interface ReviewThreadView extends Thread {\n snippet: SnippetLine[] | null;\n}\n\nexport interface ReviewFindingView extends Finding {\n snippet: SnippetLine[] | null;\n}\n\n/** \u041E\u0442\u0432\u0435\u0442 API/UI: \u0431\u0435\u0437 \u043F\u043E\u043B\u043D\u043E\u0433\u043E diff (\u043E\u043D \u0437\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u043F\u043E \u0444\u0430\u0439\u043B\u0443), \u0441\u043E \u0441\u043D\u0438\u043F\u043F\u0435\u0442\u0430\u043C\u0438. */\nexport interface ReviewView extends Omit<Review, 'diff' | 'threads' | 'findings'> {\n files: ReviewFileSummary[];\n threads: ReviewThreadView[];\n findings: ReviewFindingView[];\n stale: boolean;\n stats: { files: number; additions: number; deletions: number };\n}\n\nexport const STALE_AFTER_MS = 90_000;\n\nexport function fileSummaries(diff: DiffFile[]): ReviewFileSummary[] {\n return diff.map((file) => {\n let additions = 0;\n let deletions = 0;\n for (const hunk of file.hunks) {\n for (const line of hunk.lines) {\n if (line.kind === '+') additions++;\n else if (line.kind === '-') deletions++;\n }\n }\n return { path: file.path, oldPath: file.oldPath, status: file.status, binary: file.binary, additions, deletions };\n });\n}\n\nexport function toReviewView(review: Review, now = Date.now()): ReviewView {\n const { diff, threads, findings, ...rest } = review;\n return {\n ...rest,\n threads: threads.map((thread) => ({\n ...thread,\n snippet: thread.path && thread.line ? snippetAround(diff, thread.path, thread.line, 4) : null,\n })),\n findings: findings.map((finding) => ({\n ...finding,\n snippet: finding.file && finding.line ? snippetAround(diff, finding.file, finding.line, 4) : null,\n })),\n files: fileSummaries(diff),\n stats: diffStats(diff),\n stale: now - new Date(review.syncedAt).getTime() > STALE_AFTER_MS,\n };\n}\n\nexport function summaryOf(review: Review): ReviewSummary | null {\n return review.summary;\n}\n", "import http from 'node:http';\nimport { createReadStream } from 'node:fs';\nimport { readFile, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { timingSafeEqual } from 'node:crypto';\nimport { redact } from '../core/redact.js';\nimport { messageOf } from '../core/errors.js';\nimport type { ReviewService } from './service.js';\nimport type { PublishKind } from '../core/types.js';\nimport { dispatch } from './rpc.js';\n\nexport interface HttpOptions {\n service: ReviewService;\n token: string;\n uiDir: string;\n port?: number;\n host?: string;\n version?: string;\n}\n\nexport interface HttpHandle {\n url: string;\n port: number;\n close(): Promise<void>;\n}\n\nconst MAX_BODY = 4 * 1024 * 1024;\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.woff2': 'font/woff2',\n '.woff': 'font/woff',\n '.ico': 'image/x-icon',\n '.map': 'application/json; charset=utf-8',\n '.txt': 'text/plain; charset=utf-8',\n};\n\nconst SECURITY_HEADERS: Record<string, string> = {\n 'x-content-type-options': 'nosniff',\n 'x-frame-options': 'DENY',\n 'referrer-policy': 'no-referrer',\n 'content-security-policy':\n \"default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'\",\n};\n\nconst COOKIE = 'revdeck_session';\n\nfunction safeEqual(left: string, right: string): boolean {\n const a = Buffer.from(left);\n const b = Buffer.from(right);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n\nfunction cookies(header: string | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n for (const part of (header ?? '').split(';')) {\n const index = part.indexOf('=');\n if (index > 0) out[part.slice(0, index).trim()] = decodeURIComponent(part.slice(index + 1).trim());\n }\n return out;\n}\n\nasync function readBody(req: http.IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n size += (chunk as Buffer).length;\n if (size > MAX_BODY) throw Object.assign(new Error('\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439 \u0437\u0430\u043F\u0440\u043E\u0441'), { status: 413 });\n chunks.push(chunk as Buffer);\n }\n const text = Buffer.concat(chunks).toString('utf8').trim();\n if (!text) return {};\n const parsed: unknown = JSON.parse(text);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw Object.assign(new Error('\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F JSON-\u043E\u0431\u044A\u0435\u043A\u0442'), { status: 400 });\n return parsed as Record<string, unknown>;\n}\n\nfunction reply(res: http.ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n ...SECURITY_HEADERS,\n 'content-type': 'application/json; charset=utf-8',\n 'cache-control': 'no-store',\n });\n res.end(body);\n}\n\nexport async function startHttpServer(options: HttpOptions): Promise<HttpHandle> {\n const { service, token } = options;\n const host = options.host ?? '127.0.0.1';\n\n const server = http.createServer(async (req, res) => {\n const port = (server.address() as { port: number } | null)?.port ?? 0;\n const expectedHosts = new Set([`127.0.0.1:${port}`, `localhost:${port}`, `[::1]:${port}`]);\n if (!expectedHosts.has(String(req.headers.host ?? ''))) {\n reply(res, 403, { ok: false, error: '\u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0439 Host' });\n return;\n }\n if (req.method !== 'GET' && req.headers.origin && !expectedHosts.has(String(req.headers.origin).replace(/^http:\\/\\//, ''))) {\n reply(res, 403, { ok: false, error: '\u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0439 Origin' });\n return;\n }\n const url = new URL(req.url ?? '/', `http://127.0.0.1:${port}`);\n const jar = cookies(req.headers.cookie);\n const authorized = safeEqual(String(jar[COOKIE] ?? ''), token);\n\n try {\n if (req.method === 'GET' && url.pathname === '/') {\n const provided = url.searchParams.get('t');\n if (provided && safeEqual(provided, token)) {\n // \u041E\u0441\u0442\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, review) \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u043C \u043F\u0440\u0438 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0435 \u043D\u0430 \u0447\u0438\u0441\u0442\u044B\u0439 URL.\n const next = new URL('/', url);\n next.searchParams.delete('t');\n res.writeHead(302, {\n ...SECURITY_HEADERS,\n 'set-cookie': `${COOKIE}=${encodeURIComponent(token)}; HttpOnly; SameSite=Strict; Path=/; Max-Age=86400`,\n location: `${next.pathname}${next.search}`,\n });\n res.end();\n return;\n }\n if (!authorized) {\n res.writeHead(401, { ...SECURITY_HEADERS, 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store' });\n res.end('<meta charset=\"utf-8\"><h1>\u041D\u0443\u0436\u043D\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0430</h1><p>\u041E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u0430\u0434\u0440\u0435\u0441 \u0438\u0437 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u043B\u0430: \u043E\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u0442\u043E\u043A\u0435\u043D.</p>');\n return;\n }\n const html = await readFile(path.join(options.uiDir, 'index.html'));\n res.writeHead(200, { ...SECURITY_HEADERS, 'content-type': MIME['.html']!, 'cache-control': 'no-store' });\n res.end(html);\n return;\n }\n\n if (req.method === 'GET' && (url.pathname.startsWith('/assets/') || url.pathname === '/favicon.svg')) {\n const relative = url.pathname === '/favicon.svg' ? 'favicon.svg' : url.pathname.slice('/assets/'.length);\n const target = path.resolve(options.uiDir, url.pathname === '/favicon.svg' ? '' : 'assets', relative);\n if (!target.startsWith(path.resolve(options.uiDir) + path.sep) || relative.includes('..')) {\n reply(res, 404, { ok: false, error: '\u043D\u0435\u0442 \u0444\u0430\u0439\u043B\u0430' });\n return;\n }\n const info = await stat(target).catch(() => null);\n if (!info?.isFile()) {\n reply(res, 404, { ok: false, error: '\u043D\u0435\u0442 \u0444\u0430\u0439\u043B\u0430' });\n return;\n }\n res.writeHead(200, {\n ...SECURITY_HEADERS,\n 'content-type': MIME[path.extname(target)] ?? 'application/octet-stream',\n 'cache-control': 'public, max-age=31536000, immutable',\n });\n createReadStream(target).pipe(res);\n return;\n }\n\n if (!url.pathname.startsWith('/api/')) {\n reply(res, 404, { ok: false, error: '\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E' });\n return;\n }\n if (req.method === 'GET' && url.pathname === '/api/events') {\n if (!authorized) {\n reply(res, 401, { ok: false, error: '\u043D\u0435\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438' });\n return;\n }\n res.writeHead(200, {\n ...SECURITY_HEADERS,\n 'content-type': 'text/event-stream; charset=utf-8',\n 'cache-control': 'no-store',\n connection: 'keep-alive',\n });\n res.write(`event: hello\\ndata: ${JSON.stringify({ at: new Date().toISOString() })}\\n\\n`);\n const listener = (event: { reviewId: string; at: string }) => {\n res.write(`event: review\\ndata: ${JSON.stringify(event)}\\n\\n`);\n };\n service.events.on('review', listener);\n const heartbeat = setInterval(() => res.write(': ping\\n\\n'), 25_000);\n heartbeat.unref?.();\n req.on('close', () => {\n clearInterval(heartbeat);\n service.events.off('review', listener);\n });\n return;\n }\n if (!authorized) {\n reply(res, 401, { ok: false, error: '\u043D\u0435\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438' });\n return;\n }\n\n if (req.method === 'GET' && url.pathname === '/api/health') {\n reply(res, 200, { ok: true, version: options.version ?? 'dev', reviews: service.listReviews().length });\n return;\n }\n if (req.method === 'GET' && url.pathname === '/api/reviews') {\n reply(res, 200, { ok: true, reviews: service.listReviews() });\n return;\n }\n if (req.method === 'GET' && url.pathname === '/api/state') {\n const review = url.searchParams.get('review');\n if (!review) {\n reply(res, 400, { ok: false, error: '\u043D\u0443\u0436\u0435\u043D \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 review' });\n return;\n }\n const view = await service.refreshIfStale(review);\n reply(res, 200, { ok: true, review: view, reviews: service.listReviews() });\n return;\n }\n if (req.method === 'GET' && url.pathname === '/api/diff') {\n const review = url.searchParams.get('review') ?? '';\n const file = url.searchParams.get('file') ?? '';\n const diff = service.diffFile(review, file);\n if (!diff) {\n reply(res, 404, { ok: false, error: '\u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442 \u0432 diff' });\n return;\n }\n reply(res, 200, { ok: true, file: diff });\n return;\n }\n if (req.method === 'GET' && url.pathname === '/api/rules') {\n const review = url.searchParams.get('review') ?? '';\n reply(res, 200, { ok: true, rules: await service.rules(review) });\n return;\n }\n if (req.method === 'POST') {\n const body = await readBody(req);\n const review = String(body.review ?? '');\n switch (url.pathname) {\n case '/api/reviews/open': {\n const root = String(body.root ?? '');\n if (!root) throw Object.assign(new Error('\u043D\u0443\u0436\u0435\u043D root \u0440\u0430\u0431\u043E\u0447\u0435\u0439 \u043A\u043E\u043F\u0438\u0438'), { status: 400 });\n const opened = await service.openReview(root, {\n ...(typeof body.input === 'string' ? { input: body.input } : {}),\n ...(typeof body.platform === 'string' ? { platform: body.platform as 'gitlab' | 'github' } : {}),\n ...(typeof body.project === 'string' ? { project: body.project } : {}),\n ...(typeof body.host === 'string' ? { host: body.host } : {}),\n ...(typeof body.branch === 'string' ? { branch: body.branch } : {}),\n });\n reply(res, 200, { ok: true, review: service.getView(opened.id), reviews: service.listReviews() });\n return;\n }\n case '/api/reviews/refresh': {\n const updated = await service.refreshReview(review);\n reply(res, 200, { ok: true, review: service.getView(updated.id), reviews: service.listReviews() });\n return;\n }\n case '/api/drafts': {\n const draft = service.setDraft(review, String(body.threadId ?? ''), (body.patch ?? {}) as Record<string, never>);\n reply(res, 200, { ok: true, draft });\n return;\n }\n case '/api/findings': {\n const findings = service.setFindings(review, body.findings);\n reply(res, 200, { ok: true, findings });\n return;\n }\n case '/api/summary': {\n const summary = service.setSummary(review, body.summary);\n reply(res, 200, { ok: true, summary });\n return;\n }\n case '/api/decisions': {\n const decisions = service.setDecisions(review, body.decisions);\n reply(res, 200, { ok: true, decisions });\n return;\n }\n case '/api/notes': {\n const action = String(body.action ?? 'add');\n if (action === 'add') {\n const note = service.addNote(review, {\n file: String(body.file ?? ''),\n line: Number(body.line ?? 0),\n side: body.side === 'old' ? 'old' : 'new',\n text: String(body.text ?? ''),\n toAgent: body.toAgent !== false,\n });\n reply(res, 200, { ok: true, note });\n return;\n }\n if (action === 'delete') {\n service.deleteNote(review, String(body.noteId ?? ''));\n reply(res, 200, { ok: true });\n return;\n }\n const note = service.updateNote(review, String(body.noteId ?? ''), (body.patch ?? {}) as Record<string, never>);\n reply(res, 200, { ok: true, note });\n return;\n }\n case '/api/publish/preview': {\n const preview = service.previewPublish(review, String(body.kind ?? 'reply') as PublishKind, Array.isArray(body.ids) ? body.ids.map(String) : []);\n reply(res, 200, { ok: true, preview });\n return;\n }\n case '/api/publish/approve': {\n const approval = service.approve(\n review,\n String(body.kind ?? 'reply') as PublishKind,\n Array.isArray(body.ids) ? body.ids.map(String) : [],\n String(body.hash ?? ''),\n );\n reply(res, 200, { ok: true, approval: { id: approval.id, expiresAt: approval.expiresAt } });\n return;\n }\n case '/api/publish/commit': {\n const result = await service.publish(review, String(body.approvalId ?? ''));\n reply(res, 200, { ok: true, result });\n return;\n }\n case '/api/rpc': {\n const result = await dispatch(service, String(body.method ?? ''), (body.params ?? {}) as Record<string, unknown>);\n reply(res, 200, { ok: true, result });\n return;\n }\n case '/api/checks': {\n const results = await service.runChecks(review, { allowRun: body.run === true, ids: Array.isArray(body.ids) ? body.ids.map(String) : undefined });\n reply(res, 200, { ok: true, results });\n return;\n }\n default:\n reply(res, 404, { ok: false, error: '\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E' });\n return;\n }\n }\n reply(res, 404, { ok: false, error: '\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E' });\n } catch (error) {\n const status = (error as { status?: number }).status ?? 500;\n reply(res, status, { ok: false, error: redact(messageOf(error)) });\n }\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(options.port ?? 0, host, () => resolve());\n });\n const port = (server.address() as { port: number }).port;\n return {\n url: `http://127.0.0.1:${port}`,\n port,\n close: () =>\n new Promise<void>((resolve) => {\n server.close(() => resolve());\n setTimeout(() => resolve(), 1500).unref?.();\n }),\n };\n}\n", "import net from 'node:net';\nimport { chmod, unlink } from 'node:fs/promises';\nimport { ensureDir } from '../core/paths.js';\nimport { redact } from '../core/redact.js';\nimport { messageOf, MrReviewError } from '../core/errors.js';\nimport { PROTOCOL_VERSION, VERSION } from '../version.js';\nimport type { ReviewService } from './service.js';\nimport type { PublishKind } from '../core/types.js';\n\nexport interface RpcServerHandle {\n path: string;\n close(): Promise<void>;\n}\n\ninterface RpcRequest {\n id?: number | string;\n method?: string;\n params?: Record<string, unknown>;\n}\n\nconst MAX_LINE = 4 * 1024 * 1024;\n\nexport async function dispatch(service: ReviewService, method: string, params: Record<string, unknown>): Promise<unknown> {\n switch (method) {\n case 'ping':\n return { ok: true, version: VERSION, protocol: PROTOCOL_VERSION, pid: process.pid };\n case 'reviews.list':\n return { reviews: service.listReviews() };\n case 'reviews.open': {\n const root = String(params.root ?? '');\n if (!root) throw new MrReviewError('\u043D\u0443\u0436\u0435\u043D root \u0440\u0430\u0431\u043E\u0447\u0435\u0439 \u043A\u043E\u043F\u0438\u0438');\n const review = await service.openReview(root, {\n ...(typeof params.input === 'string' ? { input: params.input } : {}),\n ...(typeof params.platform === 'string' ? { platform: params.platform as 'gitlab' | 'github' } : {}),\n ...(typeof params.project === 'string' ? { project: params.project } : {}),\n ...(typeof params.host === 'string' ? { host: params.host } : {}),\n ...(typeof params.branch === 'string' ? { branch: params.branch } : {}),\n });\n return { review: service.getView(review.id), reviews: service.listReviews() };\n }\n case 'reviews.refresh': {\n const review = await service.refreshReview(String(params.review ?? ''));\n return { review: service.getView(review.id), reviews: service.listReviews() };\n }\n case 'reviews.remoteList': {\n const scope = (['open', 'mine', 'reviewing'] as const).includes(params.scope as never)\n ? (params.scope as 'open' | 'mine' | 'reviewing')\n : 'open';\n return service.listRemote(String(params.root ?? process.cwd()), scope, Number(params.limit ?? 50));\n }\n case 'reviews.get': {\n const id = String(params.review ?? '');\n if (params.refresh === true) await service.refreshReview(id);\n return { review: service.getView(id), reviews: service.listReviews() };\n }\n case 'reviews.remove':\n return { ok: true };\n case 'diff.get': {\n const file = service.diffFile(String(params.review ?? ''), String(params.file ?? ''));\n return { file };\n }\n case 'drafts.put':\n return { draft: service.setDraft(String(params.review ?? ''), String(params.threadId ?? ''), (params.patch ?? {}) as Record<string, never>) };\n case 'findings.put':\n return { findings: service.setFindings(String(params.review ?? ''), params.findings) };\n case 'findings.list':\n return { findings: service.getReview(String(params.review ?? '')).findings };\n case 'summary.put':\n return { summary: service.setSummary(String(params.review ?? ''), params.summary) };\n case 'decisions.put':\n return { decisions: service.setDecisions(String(params.review ?? ''), params.decisions) };\n case 'notes.add':\n return {\n note: service.addNote(String(params.review ?? ''), {\n file: String(params.file ?? ''),\n line: Number(params.line ?? 0),\n side: params.side === 'old' ? 'old' : 'new',\n text: String(params.text ?? ''),\n toAgent: params.toAgent !== false,\n }),\n };\n case 'notes.update':\n return { note: service.updateNote(String(params.review ?? ''), String(params.noteId ?? ''), (params.patch ?? {}) as Record<string, never>) };\n case 'notes.delete':\n service.deleteNote(String(params.review ?? ''), String(params.noteId ?? ''));\n return { ok: true };\n case 'publish.preview':\n return {\n preview: service.previewPublish(\n String(params.review ?? ''),\n String(params.kind ?? 'reply') as PublishKind,\n Array.isArray(params.ids) ? params.ids.map(String) : [],\n ),\n };\n case 'publish.approve': {\n const approval = service.approve(\n String(params.review ?? ''),\n String(params.kind ?? 'reply') as PublishKind,\n Array.isArray(params.ids) ? params.ids.map(String) : [],\n String(params.hash ?? ''),\n );\n return { approval: { id: approval.id, expiresAt: approval.expiresAt } };\n }\n case 'publish.commit':\n return { result: await service.publish(String(params.review ?? ''), String(params.approvalId ?? '')) };\n case 'rules.get':\n return { rules: await service.rules(String(params.review ?? '')) };\n case 'checks.run':\n return {\n results: await service.runChecks(String(params.review ?? ''), {\n allowRun: params.allowRun === true,\n ...(Array.isArray(params.ids) ? { ids: params.ids.map(String) } : {}),\n }),\n };\n default:\n throw new MrReviewError(`\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043C\u0435\u0442\u043E\u0434 RPC: ${method}`, 'METHOD', '\u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0435 revdeck: \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0435\u043C\u043E\u043D\u0430 \u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0434\u043E\u043B\u0436\u043D\u044B \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C');\n }\n}\n\nexport async function startRpcServer(service: ReviewService, socketFile: string): Promise<RpcServerHandle> {\n await ensureDir(pathDirname(socketFile), 0o700);\n await unlink(socketFile).catch(() => undefined);\n\n const server = net.createServer((socket) => {\n socket.setEncoding('utf8');\n let buffer = '';\n let queue: Promise<void> = Promise.resolve();\n socket.on('data', (chunk: string) => {\n buffer += chunk;\n if (buffer.length > MAX_LINE) {\n socket.destroy();\n return;\n }\n let index = buffer.indexOf('\\n');\n while (index >= 0) {\n const line = buffer.slice(0, index);\n buffer = buffer.slice(index + 1);\n if (line.trim()) {\n const request = parseRequest(line);\n queue = queue.then(async () => {\n if (!request) return;\n const response = await respond(service, request);\n if (!socket.destroyed) socket.write(`${JSON.stringify(response)}\\n`);\n });\n }\n index = buffer.indexOf('\\n');\n }\n });\n socket.on('error', () => undefined);\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(socketFile, () => resolve());\n });\n await chmod(socketFile, 0o600);\n\n return {\n path: socketFile,\n close: () =>\n new Promise<void>((resolve) => {\n server.close(() => resolve());\n setTimeout(() => resolve(), 1000).unref?.();\n unlink(socketFile).catch(() => undefined);\n }),\n };\n}\n\nfunction pathDirname(file: string): string {\n return file.replace(/[/\\\\][^/\\\\]+$/, '');\n}\n\nfunction parseRequest(line: string): RpcRequest | null {\n try {\n const value = JSON.parse(line) as RpcRequest;\n if (!value || typeof value !== 'object') return null;\n return value;\n } catch {\n return null;\n }\n}\n\nasync function respond(service: ReviewService, request: RpcRequest): Promise<Record<string, unknown>> {\n const id = request.id ?? null;\n if (typeof request.method !== 'string') return { id, error: { message: '\u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D method' } };\n try {\n const result = await dispatch(service, request.method, request.params ?? {});\n return { id, result };\n } catch (error) {\n return {\n id,\n error: {\n message: redact(messageOf(error)),\n ...(error instanceof MrReviewError ? { code: error.code, hint: error.hint } : {}),\n },\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["text", "text", "current", "path", "path", "text", "tmpdir", "tmpdir", "comment", "existsSync", "open", "readFile", "unlink", "net", "path", "chmod", "path", "path", "reviewId", "createHash", "existsSync", "path", "path", "text", "path", "existsSync", "path", "existsSync", "existsSync", "path", "text", "text", "http", "GitLabProvider", "GitHubProvider", "check", "position", "created", "reviewId", "createHash", "readFile", "path", "unlink", "unlink", "text", "port", "readFile", "path", "note", "path", "http", "unlink", "existsSync", "net", "open", "readFile"]
7
+ }