chore(repo): reinitialize repository

This commit is contained in:
2026-03-18 11:29:54 +08:00
commit 24871e213a
288 changed files with 44369 additions and 0 deletions
+173
View File
@@ -0,0 +1,173 @@
package runtimeconfig
import (
"context"
"encoding/json"
"fmt"
"sort"
"inbox/internal/base/timeutil"
"inbox/internal/domain/role"
"inbox/internal/domain/skill"
)
type Repository interface {
GetRole(ctx context.Context, name string) (role.Definition, error)
GetRoleConfig(ctx context.Context, roleName string) (role.Config, error)
ListRolePrompts(ctx context.Context, roleName string) ([]role.Prompt, error)
ListRoleSkillBindings(ctx context.Context, roleName string) ([]role.SkillBinding, error)
}
type SkillRepository interface {
ListSkillsByIDs(ctx context.Context, ids []string) (map[string]skill.Definition, error)
}
type ResolvedSkill struct {
Binding role.SkillBinding `json:"binding"`
Skill skill.Definition `json:"skill"`
}
type ResolvedRole struct {
Role role.Definition `json:"role"`
WorkspaceID string `json:"workspace_id,omitempty"`
Prompts map[role.PromptKind]role.Prompt `json:"prompts"`
Config role.Config `json:"config"`
Skills []ResolvedSkill `json:"skills"`
ResolvedAt string `json:"resolved_at"`
}
type Service struct {
repo Repository
skills SkillRepository
clock timeutil.Clock
}
func NewService(repo Repository, skills SkillRepository, clock timeutil.Clock) *Service {
if clock == nil {
clock = timeutil.SystemClock{}
}
return &Service{
repo: repo,
skills: skills,
clock: clock,
}
}
func (s *Service) ResolveRole(ctx context.Context, workspaceID, roleName string) (ResolvedRole, error) {
definition, err := s.repo.GetRole(ctx, roleName)
if err != nil {
return ResolvedRole{}, fmt.Errorf("get role %q: %w", roleName, err)
}
prompts, err := s.repo.ListRolePrompts(ctx, roleName)
if err != nil {
return ResolvedRole{}, fmt.Errorf("list role prompts for %q: %w", roleName, err)
}
bindings, err := s.repo.ListRoleSkillBindings(ctx, roleName)
if err != nil {
return ResolvedRole{}, fmt.Errorf("list role skill bindings for %q: %w", roleName, err)
}
resolved := ResolvedRole{
Role: definition,
WorkspaceID: workspaceID,
Prompts: pickPrompts(prompts, workspaceID),
ResolvedAt: timeutil.FormatRFC3339(s.clock.Now()),
}
config, err := s.repo.GetRoleConfig(ctx, roleName)
if err != nil {
return ResolvedRole{}, fmt.Errorf("get role config for %q: %w", roleName, err)
}
resolved.Config = config
resolved.Config.RoleName = roleName
resolvedBindings := pickBindings(bindings, workspaceID)
if len(resolvedBindings) == 0 {
return resolved, nil
}
skillIDs := make([]string, 0, len(resolvedBindings))
for _, binding := range resolvedBindings {
if binding.IsEnabled {
skillIDs = append(skillIDs, binding.SkillID)
}
}
skillsByID, err := s.skills.ListSkillsByIDs(ctx, skillIDs)
if err != nil {
return ResolvedRole{}, fmt.Errorf("list skills for %q: %w", roleName, err)
}
resolved.Skills = make([]ResolvedSkill, 0, len(skillIDs))
for _, binding := range resolvedBindings {
if !binding.IsEnabled {
continue
}
skillDef, ok := skillsByID[binding.SkillID]
if !ok {
return ResolvedRole{}, fmt.Errorf("missing skill %q for role %q", binding.SkillID, roleName)
}
resolved.Skills = append(resolved.Skills, ResolvedSkill{
Binding: binding,
Skill: skillDef,
})
}
sort.Slice(resolved.Skills, func(i, j int) bool {
if resolved.Skills[i].Binding.SortOrder == resolved.Skills[j].Binding.SortOrder {
if resolved.Skills[i].Skill.Name == resolved.Skills[j].Skill.Name {
return resolved.Skills[i].Skill.ID < resolved.Skills[j].Skill.ID
}
return resolved.Skills[i].Skill.Name < resolved.Skills[j].Skill.Name
}
return resolved.Skills[i].Binding.SortOrder < resolved.Skills[j].Binding.SortOrder
})
return resolved, nil
}
func (r ResolvedRole) SnapshotJSON() (string, error) {
data, err := json.Marshal(r)
if err != nil {
return "", fmt.Errorf("marshal runtime config snapshot: %w", err)
}
return string(data), nil
}
func pickPrompts(items []role.Prompt, workspaceID string) map[role.PromptKind]role.Prompt {
out := make(map[role.PromptKind]role.Prompt)
for _, item := range items {
if item.WorkspaceID != "" && item.WorkspaceID != workspaceID {
continue
}
current, exists := out[item.PromptKind]
if !exists {
out[item.PromptKind] = item
continue
}
if current.WorkspaceID == "" && item.WorkspaceID == workspaceID {
out[item.PromptKind] = item
}
}
return out
}
func pickBindings(items []role.SkillBinding, workspaceID string) []role.SkillBinding {
out := make(map[string]role.SkillBinding, len(items))
for _, item := range items {
if item.WorkspaceID != "" && item.WorkspaceID != workspaceID {
continue
}
current, exists := out[item.SkillID]
if !exists {
out[item.SkillID] = item
continue
}
if current.WorkspaceID == "" && item.WorkspaceID == workspaceID {
out[item.SkillID] = item
}
}
result := make([]role.SkillBinding, 0, len(out))
for _, item := range out {
result = append(result, item)
}
return result
}