Skip to content
This repository was archived by the owner on Apr 17, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ GIT_PLATFORM=gitlab
# GitLab
GITLAB_URL=https://git.boomstraat.de
GITLAB_TOKEN=your_gitlab_personal_access_token
CI_PROJECT_ID=
CI_MERGE_REQUEST_IID=
CI_PIPELINE_SOURCE=

# GitHub
GITHUB_TOKEN=your_github_token
Expand All @@ -39,4 +36,4 @@ GITHUB_TOKEN=your_github_token
VERBOSE=

# File Processing
IGNORE_LOCK_FILES=
IGNORE_LOCK_FILES=
2 changes: 1 addition & 1 deletion .github/workflows/tiw-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
GITHUB_TOKEN: ${{ github.token }}
LLM_PROVIDER: anthropic
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_MODEL: claude-3-7-sonnet-20250219
ANTHROPIC_MODEL: claude-sonnet-4-20250514
VERBOSE: 'true'
IGNORE_LOCK_FILES: 'true'
MAX_PROMPT_TOKENS: 150000
78 changes: 78 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
stages:
- review

variables:
# GitLab automatically provides CI_PROJECT_ID and CI_MERGE_REQUEST_IID
# in merge request pipelines when CI_PIPELINE_SOURCE=merge_request_event
LLM_PROVIDER: anthropic
ANTHROPIC_MODEL: claude-sonnet-4-20250514
VERBOSE: 'true'
IGNORE_LOCK_FILES: 'true'
MAX_PROMPT_TOKENS: 150000

tiw-code-review:
stage: review
image: node:20-alpine

# Only run on merge request events
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"

# Cache node_modules for faster builds
cache:
key:
files:
- yarn.lock
paths:
- node_modules/
- .yarn/cache/

before_script:
# Install dependencies
- apk add --no-cache git
- yarn install --frozen-lockfile

# Debug environment variables
- echo "🔍 CI Environment Check"
- echo "CI_PROJECT_ID=$CI_PROJECT_ID"
- echo "CI_MERGE_REQUEST_IID=$CI_MERGE_REQUEST_IID"
- echo "CI_PIPELINE_SOURCE=$CI_PIPELINE_SOURCE"
- |
if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "❌ ANTHROPIC_API_KEY is not set or empty"
exit 1
else
echo "✅ ANTHROPIC_API_KEY is set (length: ${#ANTHROPIC_API_KEY})"
echo "✅ First 20 chars: ${ANTHROPIC_API_KEY:0:20}..."
fi
- |
if [ -z "$GITLAB_TOKEN" ]; then
echo "❌ GITLAB_TOKEN is not set or empty"
echo "💡 Please add GITLAB_TOKEN as a CI/CD variable in project settings"
echo "💡 Create a personal access token with 'api' scope at:"
echo " https://gitlab.com/-/profile/personal_access_tokens"
exit 1
else
echo "✅ GITLAB_TOKEN is set (length: ${#GITLAB_TOKEN})"
echo "✅ First 20 chars: ${GITLAB_TOKEN:0:20}..."
fi

script:
# Build the project
- echo "🔨 Building Tiw"
- yarn build

# Run the code review
- echo "🤖 Running Tiw Code Review"
- yarn start ci --platform gitlab --verbose

# Allow the job to fail without failing the entire pipeline
# This prevents blocking MRs if the review service has issues
allow_failure: true

# Only keep artifacts for failed jobs for debugging
artifacts:
when: on_failure
paths:
- reviews/
expire_in: 1 week
96 changes: 70 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ cat > ~/.config/tiw/.env << 'EOF'
# LLM Configuration
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=your_anthropic_api_key
ANTHROPIC_MODEL=claude-3-7-sonnet-20250219
ANTHROPIC_MODEL=claude-sonnet-4-20250514

# Git Platform Configuration
GITLAB_URL=https://gitlab.com
Expand Down Expand Up @@ -95,7 +95,7 @@ DEEPSEEK_API_KEY=your_deepseek_api_key
COPILOT_API_KEY=your_copilot_api_key

# LLM Model Selection
ANTHROPIC_MODEL=claude-3-7-sonnet-20250219
ANTHROPIC_MODEL=claude-sonnet-4-20250514
OPENAI_MODEL=gpt-4
DEEPSEEK_MODEL=deepseek-coder
COPILOT_MODEL=gpt-4
Expand Down Expand Up @@ -205,55 +205,99 @@ Create a `.gitlab-ci.yml` file in your repository:
stages:
- review

mr-review:
variables:
LLM_PROVIDER: anthropic
ANTHROPIC_MODEL: claude-sonnet-4-20250514
VERBOSE: 'true'
IGNORE_LOCK_FILES: 'true'
MAX_PROMPT_TOKENS: 150000

tiw-code-review:
stage: review
image: node:latest
image: node:20-alpine

# Only run on merge request events
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"

# Cache node_modules for faster builds
cache:
key:
files:
- yarn.lock
paths:
- node_modules/

before_script:
- apk add --no-cache git
- yarn install --frozen-lockfile
- yarn build

script:
- npm install -g tiw
- tiw ci
only:
- merge_requests
variables:
LLM_PROVIDER: anthropic
IGNORE_LOCK_FILES: 'true'
VERBOSE: 'true'
- yarn start ci --platform gitlab --verbose

# Allow failure to prevent blocking MRs
allow_failure: true
```

**Important:** Configure these secure variables in GitLab CI/CD settings:

- `GITLAB_TOKEN`: Your GitLab personal access token
- `ANTHROPIC_API_KEY` (or other LLM provider API key)
- `GITLAB_TOKEN`: Your GitLab personal access token with `api` scope
- `ANTHROPIC_API_KEY`: Your Anthropic API key (or other LLM provider API key)

#### GitHub Actions

Create a `.github/workflows/review.yml` file:
Create a `.github/workflows/tiw-review.yml` file:

```yaml
name: Code Review
name: Tiw Code Review

on:
pull_request:
types: [opened, synchronize]
types: [opened, synchronize, reopened]

jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- uses: actions/checkout@v3
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v3

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- run: npm install -g tiw
- name: Run Tiw
run: tiw ci --platform github
node-version: '20'
cache: 'yarn'

- name: Install dependencies
run: yarn install

- name: Build Tiw
run: yarn build

- name: Run Tiw Review
run: yarn start ci --platform github --verbose
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
LLM_PROVIDER: anthropic
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_MODEL: claude-sonnet-4-20250514
VERBOSE: 'true'
IGNORE_LOCK_FILES: 'true'
MAX_PROMPT_TOKENS: 150000
```

**Important:** Configure these secrets in GitHub repository settings:

- `ANTHROPIC_API_KEY`: Your Anthropic API key (or other LLM provider API key)
- The `GITHUB_TOKEN` is automatically provided by GitHub Actions

### Common Options

The following options are available for all commands:
Expand Down Expand Up @@ -303,11 +347,11 @@ tiw url --help

```sh
# Use Anthropic Claude
tiw local --provider anthropic --model claude-3-7-sonnet-20250219
tiw local --provider anthropic --model claude-sonnet-4-20250514
# OR using environment variables
export LLM_PROVIDER=anthropic
export ANTHROPIC_API_KEY=your_api_key
export ANTHROPIC_MODEL=claude-3-7-sonnet-20250219
export ANTHROPIC_MODEL=claude-sonnet-4-20250514
tiw local
```

Expand Down
12 changes: 6 additions & 6 deletions USAGE_EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ tiw local
# Production environment
export LLM_PROVIDER=anthropic
export ANTHROPIC_API_KEY=your-prod-key
export ANTHROPIC_MODEL=claude-3-7-sonnet-20250219 # Best quality
export ANTHROPIC_MODEL=claude-sonnet-4-20250514 # Best quality
export MAX_PROMPT_TOKENS=150000
tiw local
```
Expand Down Expand Up @@ -104,7 +104,7 @@ tiw url https://github.com/owner/repo/pull/123
# GitHub PR with custom configuration
tiw url https://github.com/company/project/pull/456 \
--provider anthropic \
--model claude-3-7-sonnet-20250219 \
--model claude-sonnet-4-20250514 \
--debug

# Private GitHub repository
Expand Down Expand Up @@ -185,7 +185,7 @@ mr-review-anthropic:
- tiw ci --provider anthropic --verbose
variables:
LLM_PROVIDER: anthropic
ANTHROPIC_MODEL: claude-3-7-sonnet-20250219
ANTHROPIC_MODEL: claude-sonnet-4-20250514
MAX_PROMPT_TOKENS: 150000
only:
- merge_requests
Expand Down Expand Up @@ -283,7 +283,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
LLM_PROVIDER: anthropic
ANTHROPIC_MODEL: claude-3-7-sonnet-20250219
ANTHROPIC_MODEL: claude-sonnet-4-20250514
MAX_PROMPT_TOKENS: 150000
IGNORE_LOCK_FILES: 'true'
```
Expand Down Expand Up @@ -445,7 +445,7 @@ REVIEWS_DIR=./dev-reviews
# .env.production
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-api03-your-prod-key
ANTHROPIC_MODEL=claude-3-7-sonnet-20250219 # Best quality
ANTHROPIC_MODEL=claude-sonnet-4-20250514 # Best quality

GIT_PLATFORM=gitlab
GITLAB_URL=https://gitlab.company.com
Expand All @@ -469,7 +469,7 @@ DEEPSEEK_API_KEY=your-deepseek-key
COPILOT_API_KEY=your-copilot-key

# Provider-specific models
ANTHROPIC_MODEL=claude-3-7-sonnet-20250219
ANTHROPIC_MODEL=claude-sonnet-4-20250514
OPENAI_MODEL=gpt-4
DEEPSEEK_MODEL=deepseek-coder
COPILOT_MODEL=gpt-4
Expand Down
6 changes: 3 additions & 3 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class Config {
return {
// LLM provider configuration
llmProvider: (this.getEnvVar('LLM_PROVIDER') as LLMProvider) || 'anthropic',
anthropicModel: this.getEnvVar('ANTHROPIC_MODEL') || 'claude-3-7-sonnet-20250219',
anthropicModel: this.getEnvVar('ANTHROPIC_MODEL') || 'claude-sonnet-4-20250514',
openaiModel: this.getEnvVar('OPENAI_MODEL') || 'gpt-4',
deepseekModel: this.getEnvVar('DEEPSEEK_MODEL') || 'deepseek-coder',
copilotModel: this.getEnvVar('COPILOT_MODEL') || 'gpt-4',
Expand Down Expand Up @@ -339,8 +339,8 @@ export class Config {

if (this.options['templates'] && !this.options.formatterTemplate) {
const templatesDir = this.options['templates'] as string;
updatedConfig.formatterTemplate = path.join(templatesDir, 'formatter.txt');
updatedConfig.promptDir = templatesDir;
updatedConfig.formatterTemplate = path.join(templatesDir, 'formatters', 'markdown_format.md');
updatedConfig.promptDir = path.join(templatesDir, 'prompts');
}

return updatedConfig;
Expand Down
28 changes: 28 additions & 0 deletions src/core/MRReviewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,34 @@ export class MRReviewer {
this.logger.debug(`Prompt length: ${prompt.length} characters`);
}

// Debug mode: skip API call and return mock response
if (process.env['DEBUG_MODE'] === 'true' || process.env['SKIP_API'] === 'true') {
this.logger.info('🚧 DEBUG MODE: Skipping LLM API call');
this.logger.debug('Generated prompt:');
this.logger.debug('='.repeat(50));
this.logger.debug(prompt);
this.logger.debug('='.repeat(50));

return JSON.stringify({
overview: {
summary: "DEBUG MODE: Mock review response",
riskLevel: "low",
recommendedAction: "comment"
},
fileReviews: [],
testReview: {
compliance: "unknown",
missingTests: ["Debug mode - no actual analysis performed"],
testQualityIssues: []
},
generalFeedback: {
strengths: ["Template system is working"],
concerns: ["This is a mock response for debugging"],
suggestions: ["Set DEBUG_MODE=false to use real LLM analysis"]
}
}, null, 2);
}

return await this.llmAdapter.analyzeCode(prompt);
} catch (error) {
this.logger.error('Error analyzing diff with LLM:', error as Error);
Expand Down
2 changes: 1 addition & 1 deletion src/core/ReviewFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FileUtils } from '../utils/fileUtils';
export interface ReviewComment {
line: number;
type: string;
severity: string;
priority: string;
comment: string;
suggestion?: string;
}
Expand Down
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,11 @@ function buildConfigOptions(command: Command): Record<string, any> {
llmProvider: mergedOptions.provider as LLMProvider,
model: mergedOptions.model,
gitPlatform: mergedOptions.platform as GitPlatform | undefined,
promptDir: mergedOptions.templates,
promptDir: mergedOptions.templates
? path.join(mergedOptions.templates, 'prompts')
: undefined,
formatterTemplate: mergedOptions.templates
? path.join(mergedOptions.templates, 'formatter.txt')
? path.join(mergedOptions.templates, 'formatters', 'markdown_format.md')
: undefined,
mrMode: mergedOptions.mrMode as MRMode,
gitMrUrl: mergedOptions.gitMrUrl,
Expand Down
2 changes: 1 addition & 1 deletion src/templates/default-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Use this exact JSON structure:
{
"line": 42,
"type": "issue|suggestion|praise",
"severity": "critical|high|medium|low",
"priority": "blocking|major|minor|suggestion",
"comment": "Detailed comment about the code",
"suggestion": "Optional code suggestion"
}
Expand Down
Loading
Loading