ai-agent/internal/command/registry.go
admin 8dc496b626
Some checks failed
CI / test (push) Has been cancelled
Release / release (push) Failing after 4m36s
first commit
2026-03-08 15:40:34 +07:00

130 lines
4.0 KiB
Go

package command
import (
"fmt"
"sort"
"strings"
)
// Command represents a slash command.
type Command struct {
Name string
Aliases []string
Description string
Usage string
Handler func(ctx *Context, args []string) Result
}
// Context provides commands with read access to application state.
type Context struct {
Model string
ModelList []string
AgentProfile string
AgentList []string
ToolCount int
ServerCount int
ServerNames []string
Skills []SkillInfo
LoadedFile string
ICEEnabled bool
ICEConversations int
ICESessionID string
// Token stats
SessionEvalTotal int
SessionPromptTotal int
SessionTurnCount int
NumCtx int
CurrentModel string
// File changes
FileChanges map[string]int // path → modification count
}
// SkillInfo is a read-only view of a skill for command display.
type SkillInfo struct {
Name string
Description string
Active bool
}
// Result is returned by command handlers to describe what to do.
type Result struct {
Text string // Display text (shown as system message)
Action Action // Side effect for the TUI to execute
Data string // Optional payload (e.g. file path, model name)
Error string // Error text (takes priority over Text)
}
// Action describes a side effect the TUI should perform.
type Action int
const (
ActionNone Action = iota
ActionShowHelp // Show help overlay
ActionClear // Clear conversation history
ActionQuit // Exit the application
ActionLoadContext // Load markdown context (Data = path)
ActionUnloadContext // Remove loaded context
ActionActivateSkill // Activate skill (Data = name)
ActionDeactivateSkill // Deactivate skill (Data = name)
ActionSwitchModel // Switch model (Data = model name)
ActionSwitchAgent // Switch agent profile (Data = agent name)
ActionShowSessions // Open sessions picker
ActionShowModelPicker // Open model picker overlay
ActionCommit // Generate commit message and commit
ActionSendPrompt // Send Data as a message to the agent
ActionExport // Export conversation (Data = path)
ActionImport // Import conversation (Data = path)
)
// Registry holds all registered slash commands.
type Registry struct {
commands map[string]*Command // name/alias → command
all []*Command // ordered list
}
// NewRegistry creates an empty command registry.
func NewRegistry() *Registry {
return &Registry{
commands: make(map[string]*Command),
}
}
// Register adds a command to the registry.
func (r *Registry) Register(cmd *Command) {
r.all = append(r.all, cmd)
r.commands[cmd.Name] = cmd
for _, alias := range cmd.Aliases {
r.commands[alias] = cmd
}
}
// Execute dispatches a slash command by name and returns the result.
func (r *Registry) Execute(ctx *Context, name string, args []string) Result {
cmd, ok := r.commands[name]
if !ok {
return Result{Error: fmt.Sprintf("unknown command: /%s — type /help for available commands", name)}
}
return cmd.Handler(ctx, args)
}
// All returns all registered commands in registration order.
func (r *Registry) All() []*Command {
return r.all
}
// Match returns commands whose name starts with the given prefix.
func (r *Registry) Match(prefix string) []*Command {
var matches []*Command
seen := make(map[string]bool)
for _, cmd := range r.all {
if strings.HasPrefix(cmd.Name, prefix) && !seen[cmd.Name] {
matches = append(matches, cmd)
seen[cmd.Name] = true
}
}
sort.Slice(matches, func(i, j int) bool {
return matches[i].Name < matches[j].Name
})
return matches
}