nomadcode/services/core/internal/config/config.go
toki 6d4553bdc9 feat: m-plane-origin-authoring-roundtrip-sync G07-G08 progress and core scheduler improvements
- Add code review and plan logs for cloud G07, G08 subtasks
- Add stale task detection to scheduler
- Update OpenAI client config and tests
- Fix core services Makefile, README, docker-compose, and run script
2026-06-20 18:33:39 +09:00

148 lines
6 KiB
Go

package config
import (
"os"
"strconv"
)
type Config struct {
AppEnv string
HTTPAddr string
DatabaseURL string
RedisURL string
RedisKeyPrefix string
AuthUsername string
AuthPassword string
ModelBaseURL string
ModelAPIKey string
ModelName string
ModelContextSize int
ModelTimeoutSec int
A2AEdgeURL string
A2AAgentURL string
A2AToken string
A2ATimeoutSec int
MattermostBaseURL string
MattermostToken string
MattermostChannelID string
PlaneBaseURL string
PlaneToken string
PlaneWebhookSecret string
PlaneWorkspaceSlug string
PlaneWorkspaceID string
PlaneCreationBacklogStateID string
PlaneAgentAssigneeID string
PlaneSelfActorID string
JiraBaseURL string
JiraEmail string
JiraAPIToken string
WorkflowTaskTimeoutSec int
AuthoringStaleAfterSec int
ProtoSocketPath string
ProtoSocketHeartbeatIntervalSec int
ProtoSocketHeartbeatWaitSec int
GitoProtoSocketURL string
GitoWebhookSecret string
GitoRepoID string
GitoBranch string
GitoDevelopRepoPath string
GitoRemoteName string
RoadmapCreationTodoStateID string
}
// GitoBranchEventsEnabled reports whether the Gito branch event consumer should
// run. It requires an endpoint, a repo id, a local develop checkout path to
// scan against, and a Todo state id to project into. Any missing piece keeps the
// consumer disabled so the rest of the Core server behaves exactly as before.
func (c Config) GitoBranchEventsEnabled() bool {
return c.GitoProtoSocketURL != "" &&
c.GitoRepoID != "" &&
c.GitoDevelopRepoPath != "" &&
c.RoadmapCreationTodoStateID != ""
}
// GitoWebhookConsumerEnabled reports whether the Gito HTTP webhook receiver
// should be wired. Requires secret, repo id, develop repo path, and todo state
// id. Branch defaults to "develop" and is not required.
func (c Config) GitoWebhookConsumerEnabled() bool {
return c.GitoWebhookSecret != "" &&
c.GitoRepoID != "" &&
c.GitoDevelopRepoPath != "" &&
c.RoadmapCreationTodoStateID != ""
}
func Load() Config {
return Config{
AppEnv: getEnv("APP_ENV", "local"),
HTTPAddr: getEnv("HTTP_ADDR", ":8080"),
DatabaseURL: os.Getenv("DATABASE_URL"),
RedisURL: os.Getenv("REDIS_URL"),
RedisKeyPrefix: os.Getenv("REDIS_KEY_PREFIX"),
AuthUsername: getEnv("AUTH_USERNAME", "nomadcode"),
AuthPassword: os.Getenv("AUTH_PASSWORD"),
ModelBaseURL: getEnv("MODEL_BASE_URL", "http://toki-labs.com:18083/v1"),
ModelAPIKey: os.Getenv("MODEL_API_KEY"),
ModelName: getEnv("MODEL_NAME", "codex"),
ModelContextSize: getEnvInt("MODEL_CONTEXT_SIZE", 0),
ModelTimeoutSec: getEnvInt("MODEL_TIMEOUT_SEC", 900),
A2AEdgeURL: firstEnv("A2A_EDGE_URL", "A2A_AGENT_URL"),
A2AAgentURL: firstEnv("A2A_AGENT_URL", "A2A_EDGE_URL"),
A2AToken: os.Getenv("A2A_TOKEN"),
A2ATimeoutSec: getEnvInt("A2A_TIMEOUT_SEC", 300),
MattermostBaseURL: os.Getenv("MATTERMOST_BASE_URL"),
MattermostToken: os.Getenv("MATTERMOST_TOKEN"),
MattermostChannelID: os.Getenv("MATTERMOST_CHANNEL_ID"),
PlaneBaseURL: os.Getenv("PLANE_BASE_URL"),
PlaneToken: os.Getenv("PLANE_TOKEN"),
PlaneWebhookSecret: os.Getenv("PLANE_WEBHOOK_SECRET"),
PlaneWorkspaceSlug: os.Getenv("PLANE_WORKSPACE_SLUG"),
PlaneWorkspaceID: os.Getenv("PLANE_WORKSPACE_ID"),
PlaneCreationBacklogStateID: firstEnv("PLANE_CREATION_BACKLOG_STATE_ID", "PLANE_BACKLOG_STATE_ID"),
PlaneAgentAssigneeID: os.Getenv("PLANE_AGENT_ASSIGNEE_ID"),
PlaneSelfActorID: os.Getenv("PLANE_SELF_ACTOR_ID"),
JiraBaseURL: os.Getenv("JIRA_BASE_URL"),
JiraEmail: os.Getenv("JIRA_EMAIL"),
JiraAPIToken: os.Getenv("JIRA_API_TOKEN"),
WorkflowTaskTimeoutSec: getEnvInt("WORKFLOW_TASK_TIMEOUT_SEC", 300),
AuthoringStaleAfterSec: getEnvInt("AUTHORING_STALE_AFTER_SEC", 1200),
ProtoSocketPath: getEnv("PROTO_SOCKET_PATH", "/proto-socket"),
ProtoSocketHeartbeatIntervalSec: getEnvInt("PROTO_SOCKET_HEARTBEAT_INTERVAL_SEC", 30),
ProtoSocketHeartbeatWaitSec: getEnvInt("PROTO_SOCKET_HEARTBEAT_WAIT_SEC", 10),
GitoProtoSocketURL: os.Getenv("GITO_PROTO_SOCKET_URL"),
GitoWebhookSecret: os.Getenv("GITO_WEBHOOK_SECRET"),
GitoRepoID: os.Getenv("GITO_REPO_ID"),
GitoBranch: getEnv("GITO_BRANCH", "develop"),
GitoDevelopRepoPath: os.Getenv("GITO_DEVELOP_REPO_PATH"),
GitoRemoteName: getEnv("GITO_REMOTE_NAME", "origin"),
RoadmapCreationTodoStateID: firstEnv("ROADMAP_CREATION_TODO_STATE_ID", "PLANE_TODO_STATE_ID"),
}
}
func getEnv(key, fallback string) string {
value := os.Getenv(key)
if value == "" {
return fallback
}
return value
}
func firstEnv(keys ...string) string {
for _, key := range keys {
if value := os.Getenv(key); value != "" {
return value
}
}
return ""
}
func getEnvInt(key string, fallback int) int {
value := os.Getenv(key)
if value == "" {
return fallback
}
parsed, err := strconv.Atoi(value)
if err != nil {
return fallback
}
return parsed
}