Session WebUI: - Add `web_ui` flag to session create — launches claude-code-ui in pod on port 3001 - Install @siteboon/claude-code-ui in claudebox Dockerfile, expose port 3001 - Migration 027: add web_ui column to sessions table - startWebUI/stopWebUI fire-and-forget helpers in SessionsHandler - Service selects preview port 3001 (web UI) vs 8080 (sidecar) based on flag Aeries Daeya cookbook: - Add cookbooks/trees/aeries-daeya.yaml: privacy-first avatar social platform (infra → avatar data model → AI generation pipeline → studio UI) - Add cookbooks/scripts/aeries-daeya-test.sh: run/status/diagnose/teardown harness - Fix race condition in common.sh wait_for_pipeline: detect already-running pipelines at startup and track directly instead of waiting for a newer one Docs/tooling: - Add SDK Update Workflow section to CLAUDE.md - Add `make sdk` and `make sdk-check` targets for OpenAPI spec management Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/orchard9/rdev/internal/domain"
|
|
"github.com/orchard9/rdev/internal/logging"
|
|
"github.com/orchard9/rdev/internal/service"
|
|
)
|
|
|
|
// startWebUI launches claude-code-ui as a background process in the session pod.
|
|
// This is fire-and-forget — UI startup failure does not block session creation.
|
|
func (h *SessionsHandler) startWebUI(ctx context.Context, session *domain.Session) {
|
|
log := logging.FromContext(ctx).WithService("SessionsHandler")
|
|
|
|
bgCtx := context.WithoutCancel(ctx)
|
|
go func() {
|
|
startCtx, cancel := context.WithTimeout(bgCtx, TimeoutStandard)
|
|
defer cancel()
|
|
|
|
cmd := &domain.Command{
|
|
ID: domain.CommandID(fmt.Sprintf("webui-%s", session.ID)),
|
|
ProjectID: session.ProjectID,
|
|
Type: domain.CommandTypeShell,
|
|
Args: []string{fmt.Sprintf("nohup claude-code-ui --port %d > /tmp/claude-code-ui.log 2>&1 &", service.WebUIPort)},
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
if _, err := h.executor.Execute(startCtx, cmd, session.PodName, func(_ domain.OutputLine) {}); err != nil {
|
|
log.Error("failed to start claude-code-ui",
|
|
logging.FieldError, err,
|
|
"session_id", session.ID,
|
|
logging.FieldProjectID, session.ProjectID,
|
|
)
|
|
} else {
|
|
log.Info("claude-code-ui started",
|
|
"session_id", session.ID,
|
|
"port", service.WebUIPort,
|
|
)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// stopWebUI kills the claude-code-ui process in the session pod.
|
|
// Best-effort — failure is logged but does not block session teardown.
|
|
func (h *SessionsHandler) stopWebUI(ctx context.Context, session *domain.Session) {
|
|
log := logging.FromContext(ctx).WithService("SessionsHandler")
|
|
|
|
killCtx, cancel := context.WithTimeout(ctx, TimeoutFastLookup)
|
|
defer cancel()
|
|
|
|
cmd := &domain.Command{
|
|
ID: domain.CommandID(fmt.Sprintf("webui-stop-%s", session.ID)),
|
|
ProjectID: session.ProjectID,
|
|
Type: domain.CommandTypeShell,
|
|
Args: []string{"pkill -f claude-code-ui || true"},
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
if _, err := h.executor.Execute(killCtx, cmd, session.PodName, func(_ domain.OutputLine) {}); err != nil {
|
|
log.Warn("failed to stop claude-code-ui",
|
|
logging.FieldError, err,
|
|
"session_id", session.ID,
|
|
logging.FieldProjectID, session.ProjectID,
|
|
)
|
|
}
|
|
}
|