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>
99 lines
3.1 KiB
Go
99 lines
3.1 KiB
Go
// Package domain contains pure domain models with no external dependencies.
|
|
package domain
|
|
|
|
import "time"
|
|
|
|
// SessionID is a strongly-typed identifier for sessions.
|
|
type SessionID string
|
|
|
|
// SessionStatus represents the state of a session.
|
|
type SessionStatus string
|
|
|
|
const (
|
|
// SessionStatusActive indicates the session is currently in use.
|
|
SessionStatusActive SessionStatus = "active"
|
|
|
|
// SessionStatusEnded indicates the session was completed via checkin.
|
|
SessionStatusEnded SessionStatus = "ended"
|
|
|
|
// SessionStatusExpired indicates the session expired without checkin.
|
|
SessionStatusExpired SessionStatus = "expired"
|
|
)
|
|
|
|
// Session represents an interactive remote development session.
|
|
// A session composes a checkout (git token + branch), pod binding, and ephemeral preview URL.
|
|
type Session struct {
|
|
// ID is the unique session identifier.
|
|
ID SessionID
|
|
|
|
// ProjectID is the project this session belongs to.
|
|
ProjectID ProjectID
|
|
|
|
// CheckoutID links to the checkout that provides git access.
|
|
CheckoutID CheckoutID
|
|
|
|
// PodName is the bound project pod for command execution.
|
|
PodName string
|
|
|
|
// PreviewURL is the full HTTPS URL for the ephemeral preview.
|
|
// Format: https://{session-slug}.preview.threesix.ai
|
|
PreviewURL string
|
|
|
|
// PreviewHost is the hostname for the K8s Ingress.
|
|
// Format: {session-slug}.preview.threesix.ai
|
|
PreviewHost string
|
|
|
|
// CreatedBy is the user or API key that created the session.
|
|
CreatedBy string
|
|
|
|
// CreatedAt is when the session was created.
|
|
CreatedAt time.Time
|
|
|
|
// ExpiresAt is when the session will automatically expire.
|
|
ExpiresAt time.Time
|
|
|
|
// Status is the current state of the session.
|
|
Status SessionStatus
|
|
|
|
// LastActivityAt is the most recent command or interaction timestamp.
|
|
LastActivityAt time.Time
|
|
|
|
// EndedAt is when the session was ended (if ended or expired).
|
|
EndedAt *time.Time
|
|
|
|
// ClaudeSessionID is the Claude Code session ID used for --resume in subsequent turns.
|
|
// Set after the first successful claude exec in this session.
|
|
ClaudeSessionID string
|
|
|
|
// ConversationRecordID links this session to its conversation message history.
|
|
// Set on first Claude exec; messages are written to the conversations/messages tables.
|
|
ConversationRecordID string
|
|
|
|
// WebUI indicates whether this session runs claude-code-ui for browser-based interaction.
|
|
// When true, the preview URL routes to the web UI instead of the sidecar port.
|
|
WebUI bool
|
|
}
|
|
|
|
// IsActive returns true if the session can still be used.
|
|
func (s *Session) IsActive() bool {
|
|
return s.Status == SessionStatusActive && time.Now().Before(s.ExpiresAt)
|
|
}
|
|
|
|
// IsExpired returns true if the session has expired.
|
|
func (s *Session) IsExpired() bool {
|
|
return s.Status == SessionStatusActive && time.Now().After(s.ExpiresAt)
|
|
}
|
|
|
|
// IsExpiredWithGrace returns true if the session has expired and the grace period
|
|
// since the last activity has also elapsed. This prevents expiring sessions that
|
|
// are still actively being used.
|
|
func (s *Session) IsExpiredWithGrace(gracePeriod time.Duration) bool {
|
|
if s.Status != SessionStatusActive {
|
|
return false
|
|
}
|
|
if time.Now().Before(s.ExpiresAt) {
|
|
return false
|
|
}
|
|
return time.Since(s.LastActivityAt) > gracePeriod
|
|
}
|