Skip to content
Open
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
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
verify:
name: Verify Stability
Expand Down Expand Up @@ -46,10 +49,10 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: 'npm'
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 1'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write

strategy:
matrix:
language: ['javascript-typescript']

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3.36.3
with:
languages: ${{ matrix.language }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3.36.3
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Changelog

## v0.9.2

### What's New

- **UI Redesign:** Full visual overhaul of the dashboard, landing page, and auth flows with an updated color system, improved dark mode, and a cleaner layout overall.
- **Code Splitting:** All pages now use `React.lazy` for async loading, reducing initial bundle size and improving load times.
- **Custom LLM Providers:** Manage custom OpenAI-compatible API providers directly from the dashboard. Rate limits are optional. No more hardcoded keys in wrangler config.
- **Cloudflare Setup Script:** A new Node.js script automates the full Cloudflare deployment setup, making self-hosting significantly easier.
- **Increased Review Capacity:** Max files processed per review raised from 15 to 100.

### Improvements

- Review jobs are now resumable and lease-aware, stalled reviews can recover automatically.
- Added retry logic for transient model provider failures.
- Optimized job polling with ETag caching and adaptive delays.
- Improved settings UI, error reporting, and API robustness across the board.
- Added GitHub Actions CI with a disposable test environment for the full test suite.

### Bug Fixes

- Fixed `APP_PRIVATE_KEY` parsing for single-line strings with literal `\n` sequences.
- Fixed database migration failures on existing deployments.
- Fixed duplicate `/api/auth/updates-email` calls on page load.
- Fixed file review status bar rendering on the dashboard.

**Full Changelog**: https://github.com/devarshishimpi/codra/commits/v0.9.2
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ Codra listens to GitHub pull request events, runs AI-powered review jobs, posts
- Mention-triggered reviews for on-demand analysis
- Inline GitHub review comments plus summary reviews and check run updates
- Queue-backed processing through Cloudflare Queues
- Dead letter queue inspection, replay, and purge workflows
- GitHub OAuth dashboard authentication
- External PostgreSQL storage through Cloudflare Hyperdrive
- Dashboard-managed LLM providers for OpenAI, OpenRouter, Anthropic, Google, and Cloudflare models
Expand All @@ -66,7 +65,7 @@ Codra listens to GitHub pull request events, runs AI-powered review jobs, posts
- **Worker**: Cloudflare Workers, Hono, Wrangler
- **Dashboard**: React, Vite, Tailwind CSS, Radix UI, Recharts
- **Data**: PostgreSQL, Cloudflare Hyperdrive, Cloudflare KV
- **Queues**: Cloudflare Queues with DLQ workflows
- **Queues**: Cloudflare Queues and Workflows
- **Models**: OpenAI, OpenRouter, Anthropic, Google, and Cloudflare providers
- **GitHub**: GitHub App webhooks, checks, reviews, and OAuth
- **Quality**: TypeScript, Zod, Vitest, Playwright browser tests
Expand Down
4 changes: 4 additions & 0 deletions db/migrations/004_review_performance_settings.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
INSERT INTO global_settings (key, value) VALUES
('review_concurrency_level', 'medium'),
('review_max_comments', '10')
ON CONFLICT (key) DO NOTHING;
3 changes: 3 additions & 0 deletions db/migrations/005_drop_model_rate_limits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE model_configs DROP COLUMN IF EXISTS rpm;
ALTER TABLE model_configs DROP COLUMN IF EXISTS tpm;
ALTER TABLE model_configs DROP COLUMN IF EXISTS rpd;
5 changes: 5 additions & 0 deletions db/migrations/006_job_continuation_count.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- Tracks how many times a job has rescheduled the *same* phase without completing any
-- file review (a "no-progress continuation"). Reset to 0 whenever a chunk makes progress.
-- A hard ceiling on this counter (see MAX_JOB_CONTINUATIONS in review.ts) stops a job that
-- can never make headway from churning indefinitely on transient/budget deferrals.
ALTER TABLE jobs ADD COLUMN IF NOT EXISTS continuation_count INT NOT NULL DEFAULT 0;
7 changes: 7 additions & 0 deletions db/migrations/007_file_review_async_batch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Supports the Workers AI asynchronous Batch API path (see submitCloudflareBatch/pollCloudflareBatch).
-- A file review submitted to the async queue is persisted with file_status = 'pending' plus the
-- queue request_id, so a later review-phase invocation can poll for the result across invocations
-- (decoupling long/reasoning-model inference from any single invocation's timeout & subrequest cap).
-- Both columns are cleared once the batch completes and the review is persisted as 'done'/'failed'.
ALTER TABLE file_reviews ADD COLUMN IF NOT EXISTS async_request_id TEXT;
ALTER TABLE file_reviews ADD COLUMN IF NOT EXISTS async_model TEXT;
6 changes: 6 additions & 0 deletions db/migrations/008_job_cancelled_status.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Adds a terminal 'cancelled' status for jobs that a user explicitly stops (see the /stop
-- endpoint). Distinct from 'failed' (nothing went wrong) and 'superseded' (replaced by a newer
-- job). The status column is TEXT + CHECK (not the native enum), so we just widen the CHECK.
ALTER TABLE jobs DROP CONSTRAINT IF EXISTS jobs_status_check;
ALTER TABLE jobs ADD CONSTRAINT jobs_status_check
CHECK (status IN ('queued', 'running', 'done', 'failed', 'superseded', 'cancelled'));
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"clsx": "^2.1.1",
"hono": "^4.12.12",
"jsonrepair": "^3.13.3",
"lenis": "^1.3.25",
"lucide-react": "^1.8.0",
"motion": "^12.42.2",
"picomatch": "^4.0.4",
Expand Down
31 changes: 8 additions & 23 deletions scripts/migrate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -271,15 +271,6 @@ async function ensureModelCatalog() {
await query('ALTER TABLE model_configs ADD COLUMN IF NOT EXISTS provider_id UUID');
await query('ALTER TABLE model_configs ADD COLUMN IF NOT EXISTS model_name TEXT');

await query('ALTER TABLE model_configs ALTER COLUMN rpm DROP NOT NULL');
await query('ALTER TABLE model_configs ALTER COLUMN tpm DROP NOT NULL');
await query('ALTER TABLE model_configs ALTER COLUMN rpd DROP NOT NULL');
await query(`
UPDATE model_configs
SET rpm = NULL, tpm = NULL, rpd = NULL, updated_at = now()
WHERE rpm = 1 AND tpm = 1 AND rpd = 1
`);

await query(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 Potential database constraint violation in migration

The migration removes the commands that make 'rpm', 'tpm', and 'rpd' columns nullable (DROP NOT NULL), while simultaneously removing those columns from the subsequent INSERT statements. If these columns remain in the schema as NOT NULL and lack default values, the INSERT queries will fail with a constraint violation error. If these fields are deprecated, they should be explicitly dropped from the table using 'ALTER TABLE model_configs DROP COLUMN ...' to ensure schema consistency across environments.

Suggested change
await query(
// If the columns are no longer needed:
await query('ALTER TABLE model_configs DROP COLUMN IF EXISTS rpm');
await query('ALTER TABLE model_configs DROP COLUMN IF EXISTS tpm');
await query('ALTER TABLE model_configs DROP COLUMN IF EXISTS rpd');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Data inconsistency in schema migration

The migration removes rpm, tpm, and rpd from the INSERT and UPSERT operations. If the model_configs table columns rpm, tpm, and rpd have a NOT NULL constraint, these inserts will fail. The removal of the previous code block which dropped the NOT NULL constraints (lines 274-276) suggests that the columns are still expected to be non-nullable or were not correctly altered to allow NULLs.

Suggested change
await query(
Ensure the database schema has been updated to allow NULL values in rpm, tpm, and rpd columns before removing them from the INSERT statements, or provide default values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Data inconsistency in schema migration

The migration removes rpm, tpm, and rpd from the INSERT and UPSERT operations. If the model_configs table columns rpm, tpm, and rpd have a NOT NULL constraint, these inserts will fail. The removal of the previous code block which dropped the NOT NULL constraints (lines 274-276) suggests that the columns are still expected to be non-nullable or were not correctly altered to allow NULLs.

Suggested change
await query(
Ensure the database schema has been updated to allow NULL values in rpm, tpm, and rpd columns before removing them from the INSERT statements, or provide default values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Data inconsistency in schema migration

The migration removes rpm, tpm, and rpd from the INSERT and UPSERT operations. If the model_configs table columns rpm, tpm, and rpd have a NOT NULL constraint, these inserts will fail. The removal of the previous code block which dropped the NOT NULL constraints (lines 274-276) suggests that the columns are still expected to be non-nullable or were not correctly altered to allow NULLs.

Suggested change
await query(
Ensure the database schema has been updated to allow NULL values in rpm, tpm, and rpd columns before removing them from the INSERT statements, or provide default values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Data inconsistency in schema migration

The migration removes rpm, tpm, and rpd from the INSERT and UPSERT operations. If the model_configs table columns rpm, tpm, and rpd have a NOT NULL constraint, these inserts will fail. The removal of the previous code block which dropped the NOT NULL constraints (lines 274-276) suggests that the columns are still expected to be non-nullable or were not correctly altered to allow NULLs.

Suggested change
await query(
Ensure the database schema has been updated to allow NULL values in rpm, tpm, and rpd columns before removing them from the INSERT statements, or provide default values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Data inconsistency in schema migration

The migration removes rpm, tpm, and rpd from the INSERT and UPSERT operations. If the model_configs table columns rpm, tpm, and rpd have a NOT NULL constraint, these inserts will fail. The removal of the previous code block which dropped the NOT NULL constraints (lines 274-276) suggests that the columns are still expected to be non-nullable or were not correctly altered to allow NULLs.

Suggested change
await query(
Ensure the database schema has been updated to allow NULL values in rpm, tpm, and rpd columns before removing them from the INSERT statements, or provide default values.

`
UPDATE model_configs mc
Expand Down Expand Up @@ -317,14 +308,11 @@ async function ensureModelCatalog() {

await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT $1, 10, 131072, 300, 'cloudflare', p.id, $1, now()
INSERT INTO model_configs (model_id, provider, provider_id, model_name, updated_at)
SELECT $1, 'cloudflare', p.id, $1, now()
FROM llm_providers p
WHERE p.name = 'Cloudflare'
ON CONFLICT (model_id) DO UPDATE SET
rpm = EXCLUDED.rpm,
tpm = EXCLUDED.tpm,
rpd = EXCLUDED.rpd,
provider = EXCLUDED.provider,
provider_id = EXCLUDED.provider_id,
model_name = EXCLUDED.model_name,
Expand All @@ -335,14 +323,11 @@ async function ensureModelCatalog() {

await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT '@cf/zai-org/glm-4.7-flash', 20, 131072, 600, 'cloudflare', p.id, '@cf/zai-org/glm-4.7-flash', now()
INSERT INTO model_configs (model_id, provider, provider_id, model_name, updated_at)
SELECT '@cf/zai-org/glm-4.7-flash', 'cloudflare', p.id, '@cf/zai-org/glm-4.7-flash', now()
FROM llm_providers p
WHERE p.name = 'Cloudflare'
ON CONFLICT (model_id) DO UPDATE SET
rpm = EXCLUDED.rpm,
tpm = EXCLUDED.tpm,
rpd = EXCLUDED.rpd,
provider = EXCLUDED.provider,
provider_id = EXCLUDED.provider_id,
model_name = EXCLUDED.model_name,
Expand All @@ -352,8 +337,8 @@ async function ensureModelCatalog() {

await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT 'gemma-4-31b-it', 15, 1000000, 1500, 'gemini', p.id, 'gemma-4-31b-it', now()
INSERT INTO model_configs (model_id, provider, provider_id, model_name, updated_at)
SELECT 'gemma-4-31b-it', 'gemini', p.id, 'gemma-4-31b-it', now()
FROM llm_providers p
WHERE p.name = 'Google'
ON CONFLICT (model_id) DO UPDATE SET
Expand All @@ -366,8 +351,8 @@ async function ensureModelCatalog() {

await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT 'gemma-4-26b-a4b-it', 30, 1000000, 1500, 'gemini', p.id, 'gemma-4-26b-a4b-it', now()
INSERT INTO model_configs (model_id, provider, provider_id, model_name, updated_at)
SELECT 'gemma-4-26b-a4b-it', 'gemini', p.id, 'gemma-4-26b-a4b-it', now()
FROM llm_providers p
WHERE p.name = 'Google'
ON CONFLICT (model_id) DO UPDATE SET
Expand Down
82 changes: 8 additions & 74 deletions src/client/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -903,8 +903,7 @@
gap: 0.625rem !important;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Excessive use of !important

The CSS relies heavily on !important for almost every property (e.g., lines 906, 917, 924, 994). This creates extreme specificity that makes the styles nearly impossible to override or extend without further !important declarations, leading to a 'specificity war' and making the codebase difficult to maintain.

Suggested change
gap: 0.625rem !important;
Remove !important and instead increase selector specificity or reorganize the CSS cascade to ensure styles are applied correctly.

padding: 0.75rem 0.875rem !important;
border-radius: 0.625rem !important;
border-width: 1px !important;
border-style: solid !important;
border: none !important;
font-family: var(--font-sans) !important;
font-size: 0.8125rem !important;
line-height: 1.45 !important;
Expand All @@ -915,7 +914,6 @@

/* light defaults (overridden per-variant below) */
background: oklch(99.5% 0.004 115) !important;
border-color: oklch(88% 0.008 115) !important;
color: oklch(15% 0.02 115) !important;

/* smooth entrance */
Expand All @@ -924,7 +922,6 @@

.dark .codra-toast {
background: oklch(13% 0.018 115) !important;
border-color: oklch(22% 0.022 115) !important;
color: oklch(94% 0.006 115) !important;
box-shadow:
0 6px 24px oklch(0% 0 0 / 0.5),
Expand Down Expand Up @@ -983,64 +980,9 @@
background: oklch(28% 0.022 115) !important;
}

/* ── SUCCESS ─────────────────────────────────────── */
.codra-toast-success {
background: oklch(98.5% 0.045 115) !important;
border-color: oklch(82% 0.16 115) !important;
color: oklch(28% 0.10 115) !important;
}

.dark .codra-toast-success {
background: oklch(16% 0.08 115) !important;
border-color: oklch(32% 0.14 115) !important;
color: oklch(90% 0.18 115) !important;
}

.codra-toast-success .codra-toast-description {
color: oklch(38% 0.10 115) !important;
opacity: 0.85 !important;
}

.dark .codra-toast-success .codra-toast-description {
color: oklch(72% 0.12 115) !important;
opacity: 0.9 !important;
}

/* ── ERROR ───────────────────────────────────────── */
.codra-toast-error {
background: oklch(98.5% 0.03 25) !important;
border-color: oklch(80% 0.14 25) !important;
color: oklch(32% 0.14 25) !important;
}

.dark .codra-toast-error {
background: oklch(15% 0.07 25) !important;
border-color: oklch(35% 0.14 25) !important;
color: oklch(85% 0.08 25) !important;
}

.codra-toast-error .codra-toast-description {
color: oklch(42% 0.12 25) !important;
opacity: 0.85 !important;
}

.dark .codra-toast-error .codra-toast-description {
color: oklch(68% 0.10 25) !important;
opacity: 0.9 !important;
}

/* ── LOADING ─────────────────────────────────────── */
.codra-toast-loading {
background: oklch(98% 0.004 115) !important;
border-color: oklch(86% 0.010 115) !important;
color: oklch(20% 0.020 115) !important;
}

.dark .codra-toast-loading {
background: oklch(14% 0.020 115) !important;
border-color: oklch(24% 0.025 115) !important;
color: oklch(88% 0.008 115) !important;
}
/* ── SUCCESS / ERROR / LOADING ─────────────────────

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loss of visual status differentiation

By removing the background colors for success, error, and loading toast variants, you lose critical UI feedback. While you mentioned that icons provide status, accessibility standards often require color or redundant cues to ensure users with varying vision capabilities can distinguish between a success notification and an error. Relying solely on icons significantly reduces the scannability of the toast system.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Re-introduce subtle background tints for status variants to maintain accessibility and visual hierarchy, even if they are more muted than previous versions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loss of visual status differentiation

By removing the background colors for success, error, and loading toast variants, you lose critical UI feedback. While you mentioned that icons provide status, accessibility standards often require color or redundant cues to ensure users with varying vision capabilities can distinguish between a success notification and an error. Relying solely on icons significantly reduces the scannability of the toast system.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Re-introduce subtle background tints for status variants to maintain accessibility and visual hierarchy, even if they are more muted than previous versions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loss of visual status differentiation

By removing the background colors for success, error, and loading toast variants, you lose critical UI feedback. While you mentioned that icons provide status, accessibility standards often require color or redundant cues to ensure users with varying vision capabilities can distinguish between a success notification and an error. Relying solely on icons significantly reduces the scannability of the toast system.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Re-introduce subtle background tints for status variants to maintain accessibility and visual hierarchy, even if they are more muted than previous versions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loss of visual status differentiation

By removing the background colors for success, error, and loading toast variants, you lose critical UI feedback. While you mentioned that icons provide status, accessibility standards often require color or redundant cues to ensure users with varying vision capabilities can distinguish between a success notification and an error. Relying solely on icons significantly reduces the scannability of the toast system.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Re-introduce subtle background tints for status variants to maintain accessibility and visual hierarchy, even if they are more muted than previous versions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Loss of visual status differentiation

By removing the background colors for success, error, and loading toast variants, you lose critical UI feedback. While you mentioned that icons provide status, accessibility standards often require color or redundant cues to ensure users with varying vision capabilities can distinguish between a success notification and an error. Relying solely on icons significantly reduces the scannability of the toast system.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Re-introduce subtle background tints for status variants to maintain accessibility and visual hierarchy, even if they are more muted than previous versions.

Use the default toast text color instead of a
status tint (icon color already conveys status). */

/* spinner inherits accent color */
.codra-toast-loader svg {
Expand All @@ -1049,26 +991,18 @@

/* ── WARNING ─────────────────────────────────────── */
.codra-toast-warning {
background: oklch(98.5% 0.04 65) !important;
border-color: oklch(82% 0.13 65) !important;
color: oklch(35% 0.12 65) !important;
color: oklch(35% 0.12 65) !important;
}

.dark .codra-toast-warning {
background: oklch(16% 0.08 65) !important;
border-color: oklch(35% 0.14 65) !important;
color: oklch(82% 0.14 65) !important;
color: oklch(82% 0.14 65) !important;
}

/* ── INFO ────────────────────────────────────────── */
.codra-toast-info {
background: oklch(98.5% 0.03 250) !important;
border-color: oklch(80% 0.12 250) !important;
color: oklch(30% 0.12 250) !important;
color: oklch(30% 0.12 250) !important;
}

.dark .codra-toast-info {
background: oklch(15% 0.07 250) !important;
border-color: oklch(33% 0.12 250) !important;
color: oklch(80% 0.12 250) !important;
color: oklch(80% 0.12 250) !important;
}
Loading
Loading