@kb-labs/review-contracts 2.66.0 → 2.67.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.
package/dist/index.d.ts CHANGED
@@ -160,6 +160,8 @@ interface LLMAnalyzer {
160
160
  interface InputFile {
161
161
  path: string;
162
162
  content: string;
163
+ /** Whether this is a newly created (untracked) file */
164
+ isNewFile?: boolean;
163
165
  }
164
166
  /**
165
167
  * Review request
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AA0fO,IAAe,kBAAf,MAAsD;AAAA;AAAA;AAAA;AAAA,EASjD,gBAAA,CAAiB,MAAkB,MAAA,EAAwB;AACnE,IAAA,OAAO,UAAU,IAAA,CAAK,EAAE,IAAI,IAAA,CAAK,WAAW,IAAI,MAAM,CAAA,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKU,cAAA,CAAe,IAAA,EAAkB,IAAA,EAAc,IAAA,EAAsB;AAC7E,IAAA,OAAO,CAAA,EAAG,KAAK,EAAE,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAAA,EAChD;AACF","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/review-contracts/types\n * Core type definitions for AI Review plugin\n */\n\n/**\n * Engine types (not specific tools!)\n * Used for deduplication priority\n */\nexport type EngineType =\n | 'compiler' // TypeScript compiler, rustc, go build\n | 'linter' // ESLint, Ruff, golangci-lint, Clippy, RuboCop\n | 'sast' // Semgrep, CodeQL, Bandit\n | 'ast' // tree-sitter (read-only AST analysis)\n | 'llm'; // LLM-based analysis\n\n/**\n * Engine registry entry\n * Maps concrete tools to engine types\n */\nexport interface HeuristicEngine {\n id: string; // 'eslint', 'ruff', 'golangci', 'clippy'\n name: string;\n language: string[]; // ['typescript', 'javascript']\n type: EngineType; // Maps to priority tier\n}\n\n/**\n * Rule categories\n */\nexport type RuleCategory =\n | 'style'\n | 'correctness'\n | 'security'\n | 'architecture'\n | 'maintainability';\n\n/**\n * Finding severity levels\n */\nexport type FindingSeverity =\n | 'blocker'\n | 'high'\n | 'medium'\n | 'low'\n | 'info';\n\n/**\n * Confidence levels for findings\n * Critical for agent gating!\n */\nexport type FindingConfidence =\n | 'certain' // Deterministic, can be auto-fixed\n | 'likely' // High confidence but needs human review\n | 'heuristic'; // Pattern-based, might have false positives\n\n/**\n * Review modes\n */\nexport type ReviewMode =\n | 'heuristic' // Fast, deterministic (default in CI)\n | 'llm' // LLM-only (for complex analysis)\n | 'full'; // Heuristic + LLM (local development)\n\n/**\n * Unified rule contract\n * All rules (heuristic/LLM) follow same contract\n */\nexport interface ReviewRule {\n id: string; // Stable ID (e.g., \"eslint:no-unused-vars\")\n title: string;\n category: RuleCategory;\n severity: FindingSeverity;\n engine: string; // Engine ID (e.g., 'eslint', 'ruff')\n confidence: FindingConfidence;\n\n rationale?: string; // Why this rule exists\n references?: string[]; // ADR/doc links\n quickFix?: FixTemplate[]; // Concrete fix (if available)\n}\n\n/**\n * Fix template for auto-fixing\n */\nexport interface FixTemplate {\n type: 'replace' | 'insert' | 'delete';\n pattern?: string; // Regex pattern to match\n replacement?: string; // Replacement text\n position?: {\n line: number;\n column: number;\n };\n}\n\n/**\n * Review finding\n */\nexport interface ReviewFinding {\n id: string; // Unique finding ID\n ruleId: string; // Rule that generated this finding\n type: string; // Finding type (e.g., 'security', 'style')\n severity: FindingSeverity;\n confidence: FindingConfidence;\n \n file: string; // File path\n line: number; // Line number\n column?: number; // Column number (optional)\n endLine?: number; // End line for multi-line findings\n \n message: string; // Human-readable message\n snippet?: string; // Code snippet showing the issue\n suggestion?: string; // Suggested fix\n rationale?: string; // Why this is an issue\n \n engine: string; // Which engine found this\n source: string; // Source identifier (e.g., 'eslint', 'llm-architecture')\n \n fix?: FixTemplate[]; // Auto-fix instructions\n \n // For agent mode gating\n scope?: 'local' | 'global'; // 1-2 files (local) vs architecture redesign (global)\n automated?: boolean; // Can be auto-applied?\n}\n\n/**\n * Finding fingerprint for deduplication\n */\nexport interface FindingFingerprint {\n key: string; // sha1(ruleId|file|bucket|snippetHash)\n bucket: {\n file: string;\n lineStart: number; // line - 2\n lineEnd: number; // line + 2\n };\n snippetHash: string; // normalizeWhitespace(snippet).slice(0, 100) + hash\n}\n\n/**\n * Parsed file for analysis\n */\nexport interface ParsedFile {\n path: string;\n content: string;\n contentHash: string; // For deterministic caching\n language: string; // Detected language\n ast?: unknown; // Optional AST (if available)\n}\n\n/**\n * Review context for LLM analyzers\n */\nexport interface ReviewContext {\n preset: string; // Preset ID\n file: string; // Current file being analyzed\n\n // TASK CONTEXT: What is being reviewed and why\n taskContext?: string; // Description of the task (e.g., \"Add multi-tenancy support\")\n repoScope?: string[]; // Which repos are part of this task\n\n // PRIMARY: Static documents from preset (always available)\n documents: Document[];\n\n // OPTIONAL: Dynamic examples via Mind RAG (when available)\n examples: Example[];\n\n // OPTIONAL: Related ADRs (when Mind RAG available)\n relatedADRs: ADR[];\n\n // PRIMARY: Project conventions from atomic rules\n // Key = category name (e.g., 'naming', 'architecture', 'consistency')\n // Value = composed markdown content from all rules in category\n conventions: Record<string, string>;\n}\n\n/**\n * Static document (from preset config)\n */\nexport interface Document {\n id: string;\n title: string;\n content: string;\n type: 'rule' | 'convention' | 'guide';\n}\n\n/**\n * Example from codebase (via Mind RAG)\n */\nexport interface Example {\n file: string;\n snippet: string;\n description: string;\n}\n\n/**\n * Architecture Decision Record\n */\nexport interface ADR {\n id: string;\n title: string;\n path: string;\n summary: string;\n}\n\n\n/**\n * LLM Analyzer interface\n */\nexport interface LLMAnalyzer {\n readonly id: string;\n readonly name: string;\n\n analyze(files: ParsedFile[], context: ReviewContext): Promise<ReviewFinding[]>;\n}\n\n/**\n * Input file (from CLI layer)\n * Simple file representation before orchestrator parsing\n */\nexport interface InputFile {\n path: string;\n content: string;\n}\n\n/**\n * Review request\n */\nexport interface ReviewRequest {\n files: InputFile[]; // Simple files - orchestrator will parse to ParsedFile\n mode: ReviewMode;\n presetId: string;\n\n // Additional context\n cwd?: string; // Working directory\n\n // Task context for LLM (what are we trying to achieve?)\n taskContext?: string; // Description of the task being reviewed\n\n // Scope for diff-based review (submodule names)\n // When provided, system collects git diff from these repos\n repoScope?: string[]; // ['kb-labs-core', 'kb-labs-cli']\n\n config?: { // Engine-specific configuration\n eslintConfig?: string; // Path to ESLint config\n ruffConfig?: string; // Path to Ruff config (future)\n golangciConfig?: string; // Path to golangci-lint config (future)\n clippyConfig?: string; // Path to Clippy config (future)\n };\n}\n\n/**\n * Review preset configuration\n */\nexport interface ReviewPreset {\n id: string;\n name: string;\n description?: string;\n\n rules: string[]; // Rule IDs to enable\n excludeRules?: string[]; // Rule IDs to disable\n\n llm?: {\n enabled: boolean; // Enable LLM analysis?\n analyzers: string[]; // Which LLM analyzers to run\n };\n\n severity?: {\n failOn?: FindingSeverity; // Exit with error if severity >= this\n };\n\n // LLM context (for LLM analyzers)\n documents?: Document[]; // Static documents (guides, rules)\n}\n\n/**\n * Engine configuration within a preset\n */\nexport interface PresetEngineConfig {\n enabled: boolean;\n rules?: string[]; // Override which rules to enable\n config?: Record<string, unknown>; // Engine-specific config\n}\n\n/**\n * LLM analyzer context - passed to LLM analyzers for guidance\n */\nexport interface LLMAnalyzerContext {\n projectType?: string; // 'monorepo' | 'library' | 'application'\n framework?: string; // 'nodejs' | 'react' | 'next.js'\n language?: string; // 'typescript' | 'javascript' | 'python'\n\n // Dynamic conventions - any category name is valid\n // Categories map to .kb/ai-review/rules/{category}/ directories\n // Common categories: naming, architecture, security, testing, performance, errorHandling, consistency\n conventions?: Record<string, string>;\n\n adrs?: string[]; // ADR references for context\n}\n\n/**\n * Detailed preset configuration with engine-specific settings\n */\nexport interface PresetDefinition extends ReviewPreset {\n // Preset inheritance\n extends?: string; // Inherit from another preset (e.g., 'kb-labs', 'default')\n\n // Engine-specific configuration\n engines?: {\n eslint?: PresetEngineConfig;\n ruff?: PresetEngineConfig;\n golangci?: PresetEngineConfig;\n clippy?: PresetEngineConfig;\n };\n\n // File patterns\n include?: string[]; // Patterns to include\n exclude?: string[]; // Patterns to exclude\n\n // Performance tuning\n maxConcurrent?: number; // Max concurrent engine runs\n timeout?: number; // Timeout per file (ms)\n\n // LLM Analyzer context (guides LLM analyzers)\n context?: LLMAnalyzerContext;\n\n // Atomic rules composition (ESLint-style)\n // Dynamic categories - any category name is valid\n // Categories are defined by directory structure in .kb/ai-review/rules/{category}/\n atomicRules?: Record<string, {\n include?: string[]; // Include specific rules (e.g., ['pyramid-rule', 'typescript-naming'])\n exclude?: string[]; // Exclude specific rules\n }>;\n}\n\n/**\n * Review result\n */\nexport interface ReviewResult {\n findings: ReviewFinding[];\n summary: ReviewSummary;\n metadata: ReviewMetadata;\n}\n\n/**\n * Review summary statistics\n */\nexport interface ReviewSummary {\n total: number;\n bySeverity: {\n error: number;\n warning: number;\n info: number;\n };\n byType: Record<string, number>;\n}\n\n/**\n * Review metadata\n */\nexport interface ReviewMetadata {\n preset: string;\n mode: ReviewMode;\n filesReviewed: number;\n analyzedFiles: number; // Alias for filesReviewed (for backward compat)\n heuristicFindings: number;\n llmFindings: number;\n totalFindings: number;\n durationMs: number;\n engines: string[]; // List of engines used (e.g., ['eslint', 'ruff'])\n\n // LLM-Lite specific metadata (v2)\n llmLite?: LLMLiteMetadata;\n\n // Incremental review metadata\n incremental?: IncrementalMetadata;\n}\n\n/**\n * Incremental review metadata\n * Tracks cached files and new vs known findings\n */\nexport interface IncrementalMetadata {\n /** Files skipped (unchanged, used cache) */\n cachedFiles: number;\n /** Files analyzed fresh */\n analyzedFiles: number;\n /** New findings (not seen before) */\n newFindings: number;\n /** Known findings (seen in previous review) */\n knownFindings: number;\n /** Findings from cached files */\n cachedFindings: number;\n}\n\n/**\n * LLM-Lite analysis metadata (v2)\n * Detailed stats for batch tool-based review\n */\nexport interface LLMLiteMetadata {\n /** Number of LLM API calls */\n llmCalls: number;\n\n /** Tool call counts */\n toolCalls: {\n get_diffs: number;\n get_file_chunks: number;\n report_findings: number;\n };\n\n /** Token usage */\n tokens: {\n input: number;\n output: number;\n total: number;\n };\n\n /** Estimated cost in USD */\n estimatedCost: number;\n\n /** Verification stats */\n verification: {\n /** Raw findings before verification */\n rawFindings: number;\n /** Findings that passed verification */\n verified: number;\n /** Findings downgraded due to uncertainty */\n downgraded: number;\n /** Findings discarded as hallucinations */\n discarded: number;\n /** Hallucination rate (0.0-1.0) */\n hallucinationRate: number;\n };\n\n /** Timing breakdown */\n timing: {\n /** Total analysis time (ms) */\n totalMs: number;\n /** Time spent on LLM calls (ms) */\n llmMs: number;\n /** Time spent on verification (ms) */\n verifyMs: number;\n };\n}\n\n\n/**\n * Review configuration in kb.config.json\n */\nexport interface ReviewConfig {\n // Default preset to use\n defaultPreset?: string;\n\n // Presets directory (relative to .kb/)\n presetsDir?: string;\n\n // Custom presets (inline definitions or file paths)\n presets?: Array<PresetDefinition | string>;\n\n // Engine configurations\n engines?: {\n eslint?: {\n configPath?: string; // Path to ESLint config\n enabled?: boolean;\n };\n ruff?: {\n configPath?: string;\n enabled?: boolean;\n };\n golangci?: {\n configPath?: string;\n enabled?: boolean;\n };\n clippy?: {\n enabled?: boolean;\n };\n };\n\n // File patterns to include/exclude globally\n include?: string[];\n exclude?: string[];\n\n // Custom analyzers directory (default: .kb/review/analyzers)\n analyzersDir?: string;\n\n // Rules directory (relative to .kb/, default: ai-review/rules)\n rulesDir?: string;\n\n // Prompts directory (relative to .kb/, default: ai-review/prompts)\n promptsDir?: string;\n\n // LLM configuration for llm-lite mode\n llm?: {\n // Minimum turns for LLM conversation (default: 3)\n minTurns?: number;\n // Maximum turns for LLM conversation (default: 25)\n maxTurns?: number;\n // Files per turn for adaptive calculation (default: 10)\n filesPerTurn?: number;\n // Lines per turn for adaptive calculation (default: 500)\n linesPerTurn?: number;\n };\n}\n\n/**\n * Base LLM analyzer class\n * Extend this to create custom analyzers\n */\nexport abstract class BaseLLMAnalyzer implements LLMAnalyzer {\n abstract readonly id: string;\n abstract readonly name: string;\n\n abstract analyze(files: ParsedFile[], context: ReviewContext): Promise<ReviewFinding[]>;\n\n /**\n * Generate cache key for file + preset combination\n */\n protected generateCacheKey(file: ParsedFile, preset: string): string {\n return `review:${this.id}:${file.contentHash}:${preset}`;\n }\n\n /**\n * Build finding ID\n */\n protected buildFindingId(file: ParsedFile, line: number, type: string): string {\n return `${this.id}-${file.path}-${line}-${type}`;\n }\n}\n\n// =============================================================================\n// Diff Provider Types (for LLM-Lite mode)\n// =============================================================================\n\n/**\n * Parsed diff hunk with line information\n */\nexport interface DiffHunk {\n /** Starting line in new file (1-indexed) */\n newStart: number;\n /** Number of lines in new file */\n newLines: number;\n /** Starting line in old file (1-indexed) */\n oldStart: number;\n /** Number of lines in old file */\n oldLines: number;\n /** Raw hunk content (unified diff format) */\n content: string;\n /** Lines that were added */\n addedLines: number[];\n /** Lines that were deleted (relative to old file) */\n deletedLines: number[];\n}\n\n/**\n * File diff with parsed hunks\n */\nexport interface FileDiff {\n /** File path (relative to repo root) */\n file: string;\n /** Raw unified diff */\n diff: string;\n /** Number of lines added */\n additions: number;\n /** Number of lines deleted */\n deletions: number;\n /** Whether this is a new file */\n isNewFile: boolean;\n /** Whether this is a deleted file */\n isDeleted: boolean;\n /** Whether this is a renamed file */\n isRenamed: boolean;\n /** Parsed hunks */\n hunks: DiffHunk[];\n /** Set of changed line numbers (in new file) */\n changedLines: Set<number>;\n}\n\n/**\n * Batch diff request\n */\nexport interface BatchDiffRequest {\n /** Directory containing .git */\n cwd: string;\n /** Files to get diffs for */\n files: string[];\n /** Include staged changes */\n staged?: boolean;\n /** Include unstaged changes */\n unstaged?: boolean;\n /** Max lines per file diff (truncate large diffs) */\n maxLinesPerFile?: number;\n}\n\n/**\n * Batch diff result\n */\nexport interface BatchDiffResult {\n /** Successfully fetched diffs */\n diffs: FileDiff[];\n /** Files that failed to fetch */\n errors: Array<{ file: string; error: string }>;\n /** Total lines in all diffs */\n totalLines: number;\n}\n\n/**\n * DiffProvider interface (implementation in review-core)\n */\nexport interface IDiffProvider {\n getDiffs(request: BatchDiffRequest): Promise<BatchDiffResult>;\n getFileDiff(file: string, staged?: boolean, unstaged?: boolean, maxLines?: number): Promise<FileDiff | null>;\n isLineInDiff(fileDiff: FileDiff, lineNumber: number): boolean;\n getLineContext(file: string, lineNumber: number, contextLines?: number): Promise<{ lines: string[]; startLine: number } | null>;\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AA4fO,IAAe,kBAAf,MAAsD;AAAA;AAAA;AAAA;AAAA,EASjD,gBAAA,CAAiB,MAAkB,MAAA,EAAwB;AACnE,IAAA,OAAO,UAAU,IAAA,CAAK,EAAE,IAAI,IAAA,CAAK,WAAW,IAAI,MAAM,CAAA,CAAA;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKU,cAAA,CAAe,IAAA,EAAkB,IAAA,EAAc,IAAA,EAAsB;AAC7E,IAAA,OAAO,CAAA,EAAG,KAAK,EAAE,CAAA,CAAA,EAAI,KAAK,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAAA,EAChD;AACF","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/review-contracts/types\n * Core type definitions for AI Review plugin\n */\n\n/**\n * Engine types (not specific tools!)\n * Used for deduplication priority\n */\nexport type EngineType =\n | 'compiler' // TypeScript compiler, rustc, go build\n | 'linter' // ESLint, Ruff, golangci-lint, Clippy, RuboCop\n | 'sast' // Semgrep, CodeQL, Bandit\n | 'ast' // tree-sitter (read-only AST analysis)\n | 'llm'; // LLM-based analysis\n\n/**\n * Engine registry entry\n * Maps concrete tools to engine types\n */\nexport interface HeuristicEngine {\n id: string; // 'eslint', 'ruff', 'golangci', 'clippy'\n name: string;\n language: string[]; // ['typescript', 'javascript']\n type: EngineType; // Maps to priority tier\n}\n\n/**\n * Rule categories\n */\nexport type RuleCategory =\n | 'style'\n | 'correctness'\n | 'security'\n | 'architecture'\n | 'maintainability';\n\n/**\n * Finding severity levels\n */\nexport type FindingSeverity =\n | 'blocker'\n | 'high'\n | 'medium'\n | 'low'\n | 'info';\n\n/**\n * Confidence levels for findings\n * Critical for agent gating!\n */\nexport type FindingConfidence =\n | 'certain' // Deterministic, can be auto-fixed\n | 'likely' // High confidence but needs human review\n | 'heuristic'; // Pattern-based, might have false positives\n\n/**\n * Review modes\n */\nexport type ReviewMode =\n | 'heuristic' // Fast, deterministic (default in CI)\n | 'llm' // LLM-only (for complex analysis)\n | 'full'; // Heuristic + LLM (local development)\n\n/**\n * Unified rule contract\n * All rules (heuristic/LLM) follow same contract\n */\nexport interface ReviewRule {\n id: string; // Stable ID (e.g., \"eslint:no-unused-vars\")\n title: string;\n category: RuleCategory;\n severity: FindingSeverity;\n engine: string; // Engine ID (e.g., 'eslint', 'ruff')\n confidence: FindingConfidence;\n\n rationale?: string; // Why this rule exists\n references?: string[]; // ADR/doc links\n quickFix?: FixTemplate[]; // Concrete fix (if available)\n}\n\n/**\n * Fix template for auto-fixing\n */\nexport interface FixTemplate {\n type: 'replace' | 'insert' | 'delete';\n pattern?: string; // Regex pattern to match\n replacement?: string; // Replacement text\n position?: {\n line: number;\n column: number;\n };\n}\n\n/**\n * Review finding\n */\nexport interface ReviewFinding {\n id: string; // Unique finding ID\n ruleId: string; // Rule that generated this finding\n type: string; // Finding type (e.g., 'security', 'style')\n severity: FindingSeverity;\n confidence: FindingConfidence;\n \n file: string; // File path\n line: number; // Line number\n column?: number; // Column number (optional)\n endLine?: number; // End line for multi-line findings\n \n message: string; // Human-readable message\n snippet?: string; // Code snippet showing the issue\n suggestion?: string; // Suggested fix\n rationale?: string; // Why this is an issue\n \n engine: string; // Which engine found this\n source: string; // Source identifier (e.g., 'eslint', 'llm-architecture')\n \n fix?: FixTemplate[]; // Auto-fix instructions\n \n // For agent mode gating\n scope?: 'local' | 'global'; // 1-2 files (local) vs architecture redesign (global)\n automated?: boolean; // Can be auto-applied?\n}\n\n/**\n * Finding fingerprint for deduplication\n */\nexport interface FindingFingerprint {\n key: string; // sha1(ruleId|file|bucket|snippetHash)\n bucket: {\n file: string;\n lineStart: number; // line - 2\n lineEnd: number; // line + 2\n };\n snippetHash: string; // normalizeWhitespace(snippet).slice(0, 100) + hash\n}\n\n/**\n * Parsed file for analysis\n */\nexport interface ParsedFile {\n path: string;\n content: string;\n contentHash: string; // For deterministic caching\n language: string; // Detected language\n ast?: unknown; // Optional AST (if available)\n}\n\n/**\n * Review context for LLM analyzers\n */\nexport interface ReviewContext {\n preset: string; // Preset ID\n file: string; // Current file being analyzed\n\n // TASK CONTEXT: What is being reviewed and why\n taskContext?: string; // Description of the task (e.g., \"Add multi-tenancy support\")\n repoScope?: string[]; // Which repos are part of this task\n\n // PRIMARY: Static documents from preset (always available)\n documents: Document[];\n\n // OPTIONAL: Dynamic examples via Mind RAG (when available)\n examples: Example[];\n\n // OPTIONAL: Related ADRs (when Mind RAG available)\n relatedADRs: ADR[];\n\n // PRIMARY: Project conventions from atomic rules\n // Key = category name (e.g., 'naming', 'architecture', 'consistency')\n // Value = composed markdown content from all rules in category\n conventions: Record<string, string>;\n}\n\n/**\n * Static document (from preset config)\n */\nexport interface Document {\n id: string;\n title: string;\n content: string;\n type: 'rule' | 'convention' | 'guide';\n}\n\n/**\n * Example from codebase (via Mind RAG)\n */\nexport interface Example {\n file: string;\n snippet: string;\n description: string;\n}\n\n/**\n * Architecture Decision Record\n */\nexport interface ADR {\n id: string;\n title: string;\n path: string;\n summary: string;\n}\n\n\n/**\n * LLM Analyzer interface\n */\nexport interface LLMAnalyzer {\n readonly id: string;\n readonly name: string;\n\n analyze(files: ParsedFile[], context: ReviewContext): Promise<ReviewFinding[]>;\n}\n\n/**\n * Input file (from CLI layer)\n * Simple file representation before orchestrator parsing\n */\nexport interface InputFile {\n path: string;\n content: string;\n /** Whether this is a newly created (untracked) file */\n isNewFile?: boolean;\n}\n\n/**\n * Review request\n */\nexport interface ReviewRequest {\n files: InputFile[]; // Simple files - orchestrator will parse to ParsedFile\n mode: ReviewMode;\n presetId: string;\n\n // Additional context\n cwd?: string; // Working directory\n\n // Task context for LLM (what are we trying to achieve?)\n taskContext?: string; // Description of the task being reviewed\n\n // Scope for diff-based review (submodule names)\n // When provided, system collects git diff from these repos\n repoScope?: string[]; // ['kb-labs-core', 'kb-labs-cli']\n\n config?: { // Engine-specific configuration\n eslintConfig?: string; // Path to ESLint config\n ruffConfig?: string; // Path to Ruff config (future)\n golangciConfig?: string; // Path to golangci-lint config (future)\n clippyConfig?: string; // Path to Clippy config (future)\n };\n}\n\n/**\n * Review preset configuration\n */\nexport interface ReviewPreset {\n id: string;\n name: string;\n description?: string;\n\n rules: string[]; // Rule IDs to enable\n excludeRules?: string[]; // Rule IDs to disable\n\n llm?: {\n enabled: boolean; // Enable LLM analysis?\n analyzers: string[]; // Which LLM analyzers to run\n };\n\n severity?: {\n failOn?: FindingSeverity; // Exit with error if severity >= this\n };\n\n // LLM context (for LLM analyzers)\n documents?: Document[]; // Static documents (guides, rules)\n}\n\n/**\n * Engine configuration within a preset\n */\nexport interface PresetEngineConfig {\n enabled: boolean;\n rules?: string[]; // Override which rules to enable\n config?: Record<string, unknown>; // Engine-specific config\n}\n\n/**\n * LLM analyzer context - passed to LLM analyzers for guidance\n */\nexport interface LLMAnalyzerContext {\n projectType?: string; // 'monorepo' | 'library' | 'application'\n framework?: string; // 'nodejs' | 'react' | 'next.js'\n language?: string; // 'typescript' | 'javascript' | 'python'\n\n // Dynamic conventions - any category name is valid\n // Categories map to .kb/ai-review/rules/{category}/ directories\n // Common categories: naming, architecture, security, testing, performance, errorHandling, consistency\n conventions?: Record<string, string>;\n\n adrs?: string[]; // ADR references for context\n}\n\n/**\n * Detailed preset configuration with engine-specific settings\n */\nexport interface PresetDefinition extends ReviewPreset {\n // Preset inheritance\n extends?: string; // Inherit from another preset (e.g., 'kb-labs', 'default')\n\n // Engine-specific configuration\n engines?: {\n eslint?: PresetEngineConfig;\n ruff?: PresetEngineConfig;\n golangci?: PresetEngineConfig;\n clippy?: PresetEngineConfig;\n };\n\n // File patterns\n include?: string[]; // Patterns to include\n exclude?: string[]; // Patterns to exclude\n\n // Performance tuning\n maxConcurrent?: number; // Max concurrent engine runs\n timeout?: number; // Timeout per file (ms)\n\n // LLM Analyzer context (guides LLM analyzers)\n context?: LLMAnalyzerContext;\n\n // Atomic rules composition (ESLint-style)\n // Dynamic categories - any category name is valid\n // Categories are defined by directory structure in .kb/ai-review/rules/{category}/\n atomicRules?: Record<string, {\n include?: string[]; // Include specific rules (e.g., ['pyramid-rule', 'typescript-naming'])\n exclude?: string[]; // Exclude specific rules\n }>;\n}\n\n/**\n * Review result\n */\nexport interface ReviewResult {\n findings: ReviewFinding[];\n summary: ReviewSummary;\n metadata: ReviewMetadata;\n}\n\n/**\n * Review summary statistics\n */\nexport interface ReviewSummary {\n total: number;\n bySeverity: {\n error: number;\n warning: number;\n info: number;\n };\n byType: Record<string, number>;\n}\n\n/**\n * Review metadata\n */\nexport interface ReviewMetadata {\n preset: string;\n mode: ReviewMode;\n filesReviewed: number;\n analyzedFiles: number; // Alias for filesReviewed (for backward compat)\n heuristicFindings: number;\n llmFindings: number;\n totalFindings: number;\n durationMs: number;\n engines: string[]; // List of engines used (e.g., ['eslint', 'ruff'])\n\n // LLM-Lite specific metadata (v2)\n llmLite?: LLMLiteMetadata;\n\n // Incremental review metadata\n incremental?: IncrementalMetadata;\n}\n\n/**\n * Incremental review metadata\n * Tracks cached files and new vs known findings\n */\nexport interface IncrementalMetadata {\n /** Files skipped (unchanged, used cache) */\n cachedFiles: number;\n /** Files analyzed fresh */\n analyzedFiles: number;\n /** New findings (not seen before) */\n newFindings: number;\n /** Known findings (seen in previous review) */\n knownFindings: number;\n /** Findings from cached files */\n cachedFindings: number;\n}\n\n/**\n * LLM-Lite analysis metadata (v2)\n * Detailed stats for batch tool-based review\n */\nexport interface LLMLiteMetadata {\n /** Number of LLM API calls */\n llmCalls: number;\n\n /** Tool call counts */\n toolCalls: {\n get_diffs: number;\n get_file_chunks: number;\n report_findings: number;\n };\n\n /** Token usage */\n tokens: {\n input: number;\n output: number;\n total: number;\n };\n\n /** Estimated cost in USD */\n estimatedCost: number;\n\n /** Verification stats */\n verification: {\n /** Raw findings before verification */\n rawFindings: number;\n /** Findings that passed verification */\n verified: number;\n /** Findings downgraded due to uncertainty */\n downgraded: number;\n /** Findings discarded as hallucinations */\n discarded: number;\n /** Hallucination rate (0.0-1.0) */\n hallucinationRate: number;\n };\n\n /** Timing breakdown */\n timing: {\n /** Total analysis time (ms) */\n totalMs: number;\n /** Time spent on LLM calls (ms) */\n llmMs: number;\n /** Time spent on verification (ms) */\n verifyMs: number;\n };\n}\n\n\n/**\n * Review configuration in kb.config.json\n */\nexport interface ReviewConfig {\n // Default preset to use\n defaultPreset?: string;\n\n // Presets directory (relative to .kb/)\n presetsDir?: string;\n\n // Custom presets (inline definitions or file paths)\n presets?: Array<PresetDefinition | string>;\n\n // Engine configurations\n engines?: {\n eslint?: {\n configPath?: string; // Path to ESLint config\n enabled?: boolean;\n };\n ruff?: {\n configPath?: string;\n enabled?: boolean;\n };\n golangci?: {\n configPath?: string;\n enabled?: boolean;\n };\n clippy?: {\n enabled?: boolean;\n };\n };\n\n // File patterns to include/exclude globally\n include?: string[];\n exclude?: string[];\n\n // Custom analyzers directory (default: .kb/review/analyzers)\n analyzersDir?: string;\n\n // Rules directory (relative to .kb/, default: ai-review/rules)\n rulesDir?: string;\n\n // Prompts directory (relative to .kb/, default: ai-review/prompts)\n promptsDir?: string;\n\n // LLM configuration for llm-lite mode\n llm?: {\n // Minimum turns for LLM conversation (default: 3)\n minTurns?: number;\n // Maximum turns for LLM conversation (default: 25)\n maxTurns?: number;\n // Files per turn for adaptive calculation (default: 10)\n filesPerTurn?: number;\n // Lines per turn for adaptive calculation (default: 500)\n linesPerTurn?: number;\n };\n}\n\n/**\n * Base LLM analyzer class\n * Extend this to create custom analyzers\n */\nexport abstract class BaseLLMAnalyzer implements LLMAnalyzer {\n abstract readonly id: string;\n abstract readonly name: string;\n\n abstract analyze(files: ParsedFile[], context: ReviewContext): Promise<ReviewFinding[]>;\n\n /**\n * Generate cache key for file + preset combination\n */\n protected generateCacheKey(file: ParsedFile, preset: string): string {\n return `review:${this.id}:${file.contentHash}:${preset}`;\n }\n\n /**\n * Build finding ID\n */\n protected buildFindingId(file: ParsedFile, line: number, type: string): string {\n return `${this.id}-${file.path}-${line}-${type}`;\n }\n}\n\n// =============================================================================\n// Diff Provider Types (for LLM-Lite mode)\n// =============================================================================\n\n/**\n * Parsed diff hunk with line information\n */\nexport interface DiffHunk {\n /** Starting line in new file (1-indexed) */\n newStart: number;\n /** Number of lines in new file */\n newLines: number;\n /** Starting line in old file (1-indexed) */\n oldStart: number;\n /** Number of lines in old file */\n oldLines: number;\n /** Raw hunk content (unified diff format) */\n content: string;\n /** Lines that were added */\n addedLines: number[];\n /** Lines that were deleted (relative to old file) */\n deletedLines: number[];\n}\n\n/**\n * File diff with parsed hunks\n */\nexport interface FileDiff {\n /** File path (relative to repo root) */\n file: string;\n /** Raw unified diff */\n diff: string;\n /** Number of lines added */\n additions: number;\n /** Number of lines deleted */\n deletions: number;\n /** Whether this is a new file */\n isNewFile: boolean;\n /** Whether this is a deleted file */\n isDeleted: boolean;\n /** Whether this is a renamed file */\n isRenamed: boolean;\n /** Parsed hunks */\n hunks: DiffHunk[];\n /** Set of changed line numbers (in new file) */\n changedLines: Set<number>;\n}\n\n/**\n * Batch diff request\n */\nexport interface BatchDiffRequest {\n /** Directory containing .git */\n cwd: string;\n /** Files to get diffs for */\n files: string[];\n /** Include staged changes */\n staged?: boolean;\n /** Include unstaged changes */\n unstaged?: boolean;\n /** Max lines per file diff (truncate large diffs) */\n maxLinesPerFile?: number;\n}\n\n/**\n * Batch diff result\n */\nexport interface BatchDiffResult {\n /** Successfully fetched diffs */\n diffs: FileDiff[];\n /** Files that failed to fetch */\n errors: Array<{ file: string; error: string }>;\n /** Total lines in all diffs */\n totalLines: number;\n}\n\n/**\n * DiffProvider interface (implementation in review-core)\n */\nexport interface IDiffProvider {\n getDiffs(request: BatchDiffRequest): Promise<BatchDiffResult>;\n getFileDiff(file: string, staged?: boolean, unstaged?: boolean, maxLines?: number): Promise<FileDiff | null>;\n isLineInDiff(fileDiff: FileDiff, lineNumber: number): boolean;\n getLineContext(file: string, lineNumber: number, contextLines?: number): Promise<{ lines: string[]; startLine: number } | null>;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kb-labs/review-contracts",
3
3
  "description": "Type definitions and contracts for AI Review plugin",
4
- "version": "2.66.0",
4
+ "version": "2.67.0",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
@@ -19,7 +19,7 @@
19
19
  "tsup": "^8.5.0",
20
20
  "typescript": "^5.6.3",
21
21
  "vitest": "^3.2.4",
22
- "@kb-labs/devkit": "2.66.0"
22
+ "@kb-labs/devkit": "2.67.0"
23
23
  },
24
24
  "engines": {
25
25
  "node": ">=20.0.0",