Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
4aa53c1
feat(node): wire up BullMQ worker and Redis adapters
devarshishimpi Sep 21, 2026
42d02f0
feat: add Docker support and self-hosting documentation
devarshishimpi Sep 21, 2026
b3c0f70
feat: integrate BullMQ across node app with improved docker configura…
devarshishimpi Sep 22, 2026
2253315
refactor: extract node adapters to @codraoss/node-adapters package
devarshishimpi Sep 22, 2026
046a178
chore: upgrade dependencies across monorepo
devarshishimpi Sep 22, 2026
e417dd6
chore: strip verbose comments and use workspace dependencies
devarshishimpi Sep 22, 2026
33109a7
chore: update dependencies to specific versions across all packages
devarshishimpi Sep 22, 2026
b3d791a
fix: reorder export fields in package.json for consistency
devarshishimpi Sep 22, 2026
1b1cdcf
chore: update configuration files for improved build process and modu…
devarshishimpi Sep 22, 2026
61fa904
chore: add node-adapters to build:packages script for comprehensive b…
devarshishimpi Sep 22, 2026
f484211
feat: add build coverage check to CI workflow and scripts
devarshishimpi Sep 22, 2026
65fec2b
fix: enhance Docker support and improve error handling in services
devarshishimpi Sep 23, 2026
41ec19f
fix: update Dockerfile and docker-compose for improved security and c…
devarshishimpi Sep 23, 2026
0713e70
fix: update paths and error handling in node services for improved st…
devarshishimpi Sep 23, 2026
fd7b631
fix: update createRuntime type to include DbEnv for improved type safety
devarshishimpi Sep 23, 2026
599b870
fix: update tsconfig to ensure correct rootDir and outDir settings
devarshishimpi Sep 23, 2026
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
33 changes: 0 additions & 33 deletions .changeset/README.md

This file was deleted.

21 changes: 0 additions & 21 deletions .changeset/config.json

This file was deleted.

3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Check build coverage
run: npm run check:builds

- name: Build packages
run: npm run build:packages

Expand Down
81 changes: 0 additions & 81 deletions CHANGELOG.md

This file was deleted.

9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<a href="LICENSE"><img alt="License: AGPL-3.0" src="https://img.shields.io/badge/license-AGPL--3.0-blue.svg"></a>
<a href="https://github.com/sponsors/devarshishimpi"><img alt="Sponsor" src="https://img.shields.io/badge/Sponsor-devarshishimpi-EA4AAA?logo=githubsponsors"></a>
<a href="https://workers.cloudflare.com/"><img alt="Cloudflare Workers" src="https://img.shields.io/badge/runtime-Cloudflare%20Workers-f38020?logo=cloudflare"></a>
<a href="https://nodejs.org/"><img alt="Node.js" src="https://img.shields.io/badge/runtime-Node.js-339933?logo=node.js&logoColor=white"></a>
<a href="https://react.dev/"><img alt="Built with React" src="https://img.shields.io/badge/dashboard-React-61dafb?logo=react&logoColor=111"></a>
<a href="https://www.typescriptlang.org/"><img alt="TypeScript" src="https://img.shields.io/badge/language-TypeScript-3178c6?logo=typescript&logoColor=fff"></a>
</p>
Expand All @@ -19,7 +20,9 @@
|
<a href="https://codra.run/docs">Docs</a>
|
<a href="https://codra.run/docs/installation">Installation</a>
<a href="https://codra.run/docs/installation">Installation (Cloudflare)</a>
|
<a href="./docs/deployment/docker.md">Installation (Docker / Self-Hosted)</a>
|
<a href="https://github.com/devarshishimpi/codra/issues">Issues</a>
|
Expand All @@ -31,11 +34,11 @@

Codra listens to GitHub pull request events, runs AI-powered review jobs, posts inline findings back to the PR, and gives you a dashboard to inspect jobs, repositories, model routing, review history, and failed queue runs.

> **Beta** - Codra is under active development. Expect rough edges, missing features, and breaking changes between releases. Feedback and bug reports are welcome via [GitHub Issues](https://github.com/devarshishimpi/codra/issues).
> **Beta** - Codra is under active development. Cloudflare Worker is stable for self-hosted use; Node standalone is newer and still being hardened. Expect rough edges. Bugs and feedback welcome via [GitHub Issues](https://github.com/devarshishimpi/codra/issues).

## Why Codra

- **Own the whole review loop**: Run the GitHub App, Cloudflare Worker, queue, database, model credentials, and dashboard under your own control.
- **Own the whole review loop**: Run the GitHub App, web server, queue, database, model credentials, and dashboard under your own control (deploy on Cloudflare Workers or your own VPS via Docker).
- **Review with repository context**: Codra checks pull request diffs for correctness, security, performance, maintainability, and repo-specific patterns.
- **Configure each repository**: Tune triggers, skipped paths, draft handling, mention reviews, labels, custom rules, and review budgets from the dashboard.
- **Route models deliberately**: Use global defaults, per-repo model chains, fallbacks, and size-based overrides for larger pull requests.
Expand Down
67 changes: 67 additions & 0 deletions apps/node/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
FROM node:20-alpine3.24 AS builder
WORKDIR /app

# Install build dependencies if needed
RUN apk add --no-cache python3 make g++

# Copy workspace and lock file
COPY package.json package-lock.json tsconfig.base.json ./
COPY apps/node/package.json ./apps/node/
COPY packages/api/package.json ./packages/api/
COPY packages/core/package.json ./packages/core/
COPY packages/db/package.json ./packages/db/
COPY packages/models/package.json ./packages/models/
COPY packages/provider-github/package.json ./packages/provider-github/
COPY packages/schema/package.json ./packages/schema/

# Install all dependencies (with devDependencies for build)
RUN npm ci

# Copy source code
COPY apps/node ./apps/node
COPY packages ./packages

# Build the node server and its dependencies
RUN npm run build --workspace=@codraoss/node-server

# Prune development dependencies before copying to runner stage
RUN npm prune --omit=dev

# Build runner stage
FROM node:20-alpine3.24 AS runner
WORKDIR /app

ENV NODE_ENV=production

# Copy built artifacts and necessary files
COPY --from=builder /app/node_modules ./node_modules

COPY --from=builder /app/apps/node/package.json ./apps/node/package.json
COPY --from=builder /app/apps/node/dist ./apps/node/dist

# Selectively copy only workspace packages' dist folders and package.json files
COPY --from=builder /app/packages/api/package.json ./packages/api/
COPY --from=builder /app/packages/api/dist ./packages/api/dist

COPY --from=builder /app/packages/core/package.json ./packages/core/
COPY --from=builder /app/packages/core/dist ./packages/core/dist

COPY --from=builder /app/packages/db/package.json ./packages/db/
COPY --from=builder /app/packages/db/dist ./packages/db/dist

COPY --from=builder /app/packages/models/package.json ./packages/models/
COPY --from=builder /app/packages/models/dist ./packages/models/dist

COPY --from=builder /app/packages/provider-github/package.json ./packages/provider-github/
COPY --from=builder /app/packages/provider-github/dist ./packages/provider-github/dist

COPY --from=builder /app/packages/schema/package.json ./packages/schema/
COPY --from=builder /app/packages/schema/dist ./packages/schema/dist

USER node

EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "apps/node/dist/index.js"]
23 changes: 12 additions & 11 deletions apps/node/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codraoss/node-server",
"version": "0.9.6",
"version": "0.9.13",
"private": true,
"type": "module",
"scripts": {
Expand All @@ -10,20 +10,21 @@
"typecheck": "tsc -p tsconfig.json"
},
"dependencies": {
"@codraoss/api": "*",
"@codraoss/core": "*",
"@codraoss/db": "*",
"@codraoss/models": "*",
"@codraoss/provider-github": "*",
"@codraoss/schema": "*",
"@hono/node-server": "^1.11.1",
"@codraoss/api": "^0.9.13",
"@codraoss/core": "^0.9.13",
"@codraoss/db": "^0.9.13",
"@codraoss/models": "^0.9.13",
"@codraoss/node-adapters": "^0.9.13",
"@codraoss/provider-github": "^0.9.13",
"@codraoss/schema": "^0.9.13",
"@hono/node-server": "^1.11.5",
"bullmq": "^6.3.8",
"dotenv": "^16.4.5",
"hono": "^4.6.0",
"dotenv": "^16.4.7",
"hono": "^4.6.20",
"ioredis": "^6.0.0"
},
"devDependencies": {
"@types/node": "^20.12.12",
"@types/node": "^20.12.14",
"tsup": "^8.0.2"
}
}
14 changes: 0 additions & 14 deletions apps/node/src/adapters/redis-queue.ts

This file was deleted.

40 changes: 40 additions & 0 deletions apps/node/src/adapters/services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { GitProviderFactory, ModelErrorClassifier, ReviewFormatter, ReviewGitProvider, ReviewModel } from '@codraoss/core/ports';
import type { TokenTracker } from '@codraoss/core/token-tracker';
import type { NodeAppBindings } from '../env';
import { GitHubService } from '@codraoss/provider-github';
import { isRetryableModelError, ModelRunner, nextChainIndexOf } from '@codraoss/models';
import { FormatterService } from '@codraoss/core/formatter';
import { getResolvedModelConfig } from '@codraoss/db/model-configs';

export function makeGitHubFactory(env: NodeAppBindings) {
return (installationId: string, tracker: TokenTracker): ReviewGitProvider => new GitHubService(env, installationId, tracker);
}

export function makeModelFactory(env: NodeAppBindings) {
return (jobId: string, tracker: TokenTracker): ReviewModel => new ModelRunner({
kv: env.APP_KV as any,
secretStore: {
getSecret: async (key) => (env[key as keyof NodeAppBindings] as string | undefined | null) ?? process.env[key] ?? null,
},
getConfig: (modelId) => getResolvedModelConfig({ HYPERDRIVE: env.DATABASE_CONFIG, APP_KV: env.APP_KV }, modelId),
aiBinding: undefined,
tracker,
jobId,
});
}

export function makeFormatterFactory(env: NodeAppBindings) {
return (): ReviewFormatter => new FormatterService(env.APP_URL);
}

export function makeGitHubClientFactory(env: NodeAppBindings): GitProviderFactory {
return {
forInstallation(installationId: string, tracker?: TokenTracker): ReviewGitProvider {
return new GitHubService(env, installationId, tracker);
},
};
}

export function makeModelErrorClassifier(): ModelErrorClassifier {
return { isRetryableModelError, nextChainIndexOf };
}
10 changes: 10 additions & 0 deletions apps/node/src/adapters/telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { TelemetrySink } from '@codraoss/core/ports';
import type { NodeAppBindings } from '../env';

export function makeTelemetrySink(_env: NodeAppBindings): TelemetrySink {
return {
send: async (_event) => {
// Telemetry stubbed in Node open-source.
}
};
}
23 changes: 16 additions & 7 deletions apps/node/src/api-deps.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import { createSharedApiDeps } from '@codraoss/api';
import type { NodeAppBindings } from './env';
import { logger } from '@codraoss/api/logger';
import { createReviewRuntime } from './runtime';

export function createNodeApiDeps(env: NodeAppBindings) {
return createSharedApiDeps({
sessionStore: env.SESSION_STORE,
kv: env.APP_KV,
db: { HYPERDRIVE: env.HYPERDRIVE, APP_KV: env.APP_KV, workerMode: false },
db: { HYPERDRIVE: env.DATABASE_CONFIG, APP_KV: env.APP_KV, workerMode: false },
identityProvider: env.IDENTITY_PROVIDER,

enqueueReviewJob: async (input) => {
await env.REVIEW_QUEUE.send(input);
},
terminateJobWorkflow: async (_job) => {
logger.warn('[STUB] terminateJobWorkflow called');
terminateJobWorkflow: async (job) => {
if (env.REVIEW_QUEUE.deleteJob) {
try {
await env.REVIEW_QUEUE.deleteJob(job.id);
logger.info(`[API Deps] Terminated job workflow for job ${job.id}`);
} catch (error) {
logger.error(`[API Deps] Failed to terminate job workflow for job ${job.id}: ${error}`);
throw error;
}
} else {
logger.warn(`[API Deps] QueueAdapter does not support deleteJob. Cannot terminate ${job.id}`);
}
},
scheduleBestEffortJobMaintenance: () => {
// In node, this is a long running process, we can just spawn a promise.
},
createReviewRuntime: () => {
throw new Error('Review runtime not implemented for Node yet.');

},
createReviewRuntime: () => createReviewRuntime(env),
getOrFetchRawDiffForCompletedJob: async () => '',
logger,
getSecret: async (key) => process.env[key] ?? null,
Expand Down
Loading
Loading