feat: implement worker core, tests, bot, CI/CD, and Dockerfile#15
Merged
feat: implement worker core, tests, bot, CI/CD, and Dockerfile#15
Conversation
Worker (apps/worker): - Queue poller with atomic claiming, stale recovery, graceful SIGTERM requeue - Dev loop (Ralph Loop): clone → detect → install → Claude loop → test → PR - Claude Agent SDK wrapper for spawning Claude Code sessions - Test runner auto-detection for pytest, jest, vitest, playwright, go, cargo - Git operations: clone, branch, commit, push, create PR - HTTP server with health, drain, cancel endpoints + scale-to-zero - 53 tests across 6 test files, all passing Telegram Bot (apps/bot): - grammY-based bot with /start, /task, /status, /cancel commands - Supabase realtime subscription for streaming job events to chat - Inline keyboard for PR approve/reject actions Infrastructure: - Production multi-stage Dockerfile (Node 22, Python/uv, Go, Rust) - GitHub Actions CI (lint + test + build) and deploy (Fly.io) - Updated shared types (retry fields, DevLoopConfig, DevLoopResult) - Updated SQL migration (attempt, max_attempts, github_token columns) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix command injection in createPullRequest (use execFileSync instead of execSync) - Add try-catch to installDependencies with proper error propagation - Use WORKSPACE_DIR env var instead of hardcoded /tmp path in dev-loop - Add GitHub CLI (gh) to Dockerfile for PR creation - Copy .dockerignore to repo root for proper Docker build context - Add composite: true to shared tsconfig for project references - Fix migration to use gen_random_uuid() instead of uuid_generate_v4() - Add Supabase config files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The @anthropic-ai/claude-agent-sdk spawns a Claude Code subprocess via the query() function. The CLI must be globally installed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update stale OpenAdaptAI/wright URLs to OpenAdaptAI/openadapt-wright in both README.md and dev-loop.ts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test runners emit colored output that broke our regex parsers, causing 0/0 results even when tests were actually passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Vitest uses "Tests 2 passed (2)" format while Jest uses "Tests: 2 failed, 5 passed, 7 total". The parser now handles both formats, fixing the 0/0 results seen in production. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- cloneRepo now accepts an optional branch parameter to checkout the
correct base branch instead of always cloning the default branch
- dev-loop passes job.branch to cloneRepo so auto-detection works
against the right codebase
- parseJest now handles vitest's output format ("Tests 2 passed (2)")
in addition to jest's format ("Tests: 2 failed, 5 passed, 7 total")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fly.io's auto_stop_machines was killing the worker during long Claude sessions because execSync blocks the event loop, preventing health checks from responding. Now the worker manages its own lifecycle via the 5-minute idle timer (process.exit(0)). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 tasks
* fix: security and correctness fixes for worker and bot
- Allowlist env vars passed to Claude subprocess (prevent leaking
SUPABASE_SERVICE_ROLE_KEY, BOT_TOKEN, GITHUB_TOKEN, etc.)
- Wire AbortController from queue-poller through dev-loop to
claude-session for graceful SIGTERM cancellation
- Add github_token to bot insertJob (fixes NOT NULL constraint failure)
- Add Telegram chat ID allowlist middleware (ALLOWED_TELEGRAM_USERS)
- Add @types/node to shared and bot packages (fixes pre-existing
build failures)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add TMPDIR to env allowlist and use once for abort listener
- Add TMPDIR/TMP/TEMP to allowed env vars (git/npm need temp dirs)
- Use { once: true } on abort signal listener to prevent accumulation
across loop iterations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: simplify abortController pass-through and filter NaN from allowlist
- Pass abortController directly instead of conditional spread
- Filter non-finite values from ALLOWED_TELEGRAM_USERS parsing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full implementation of the wright dev automation worker, ported from fastable2's Ralph Loop pattern and generalized for any repo/language.
Worker Core (6 files, ~1400 lines)
Tests (53 passing)
Telegram Bot
Infrastructure
Test plan
🤖 Generated with Claude Code