All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Add TimeoutAgentExecution (22m) to handlers for synchronous SDLC
execution, and TimeoutAgent{Default,Medium,Heavy} (12/22/47m) to
workers for tiered agent task execution. Aligns with SDLC action
complexity tiers and prevents inline duration literals.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
2.8 KiB
Go
112 lines
2.8 KiB
Go
// Package main provides the claudebox-sidecar HTTP server.
|
|
// This sidecar runs alongside Claude Code in worker pods, exposing HTTP endpoints
|
|
// for execute, git, and SDLC operations - replacing kubectl exec calls.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/chi/v5/middleware"
|
|
"github.com/orchard9/rdev/internal/claudebox"
|
|
"github.com/orchard9/rdev/internal/envutil"
|
|
"github.com/orchard9/rdev/internal/logging"
|
|
)
|
|
|
|
func main() {
|
|
// Configure logging
|
|
logLevel := logging.LevelInfo
|
|
if envutil.GetEnvBool("DEBUG", false) {
|
|
logLevel = logging.LevelDebug
|
|
}
|
|
log := logging.New(logging.Config{
|
|
Level: logLevel,
|
|
Format: logging.FormatJSON,
|
|
})
|
|
|
|
// Configuration from environment
|
|
port := envutil.GetEnv("PORT", "8080")
|
|
workDir := envutil.GetEnv("WORKSPACE_DIR", "/workspace")
|
|
giteaToken := os.Getenv("GITEA_TOKEN") // Required for git push auth
|
|
gitUser := envutil.GetEnv("GIT_USER", "rdev-worker")
|
|
gitEmail := envutil.GetEnv("GIT_EMAIL", "worker@threesix.ai")
|
|
|
|
// Create server components
|
|
executor := claudebox.NewExecutor(workDir)
|
|
gitOps := claudebox.NewGitOperations(claudebox.GitOperationsConfig{
|
|
WorkDir: workDir,
|
|
GiteaToken: giteaToken,
|
|
GitUser: gitUser,
|
|
GitEmail: gitEmail,
|
|
Logger: log.Slog(),
|
|
})
|
|
sdlcRunner := claudebox.NewSDLCRunner(claudebox.SDLCRunnerConfig{
|
|
WorkDir: workDir,
|
|
Logger: log.Slog(),
|
|
})
|
|
|
|
// Create the server
|
|
server := claudebox.NewServer(claudebox.ServerConfig{
|
|
Executor: executor,
|
|
GitOps: gitOps,
|
|
SDLCRunner: sdlcRunner,
|
|
Logger: log.Slog(),
|
|
})
|
|
|
|
// Create router
|
|
r := chi.NewRouter()
|
|
r.Use(middleware.RequestID)
|
|
r.Use(middleware.RealIP)
|
|
r.Use(logging.Middleware(logging.MiddlewareConfig{
|
|
Logger: log,
|
|
}))
|
|
r.Use(middleware.Recoverer)
|
|
r.Use(middleware.Timeout(50 * time.Minute))
|
|
|
|
// Mount server routes
|
|
server.Mount(r)
|
|
|
|
// Create HTTP server
|
|
addr := fmt.Sprintf(":%s", port)
|
|
httpServer := &http.Server{
|
|
Addr: addr,
|
|
Handler: r,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 55 * time.Minute, // Long timeout for streaming responses
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
// Start server in goroutine
|
|
go func() {
|
|
log.Info("starting claudebox-sidecar", "addr", addr, "workDir", workDir)
|
|
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Error("server error", logging.FieldError, err)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
|
|
// Wait for shutdown signal
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
log.Info("shutting down server")
|
|
|
|
// Graceful shutdown with timeout
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
if err := httpServer.Shutdown(ctx); err != nil {
|
|
log.Error("server shutdown error", logging.FieldError, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
log.Info("server stopped")
|
|
}
|