package module import ( "fmt" "strings" "time" "ops-assistant/internal/core/policy" "ops-assistant/internal/core/runbook" ) type CommandTemplate struct { RunbookName string Gate Gate InputsFn func(text string, parts []string) (map[string]string, error) MetaFn func(userID int64, confirmToken string, inputs map[string]string) runbook.RunMeta DryRunMsg string SuccessMsg func(jobID uint) string } type CommandSpec struct { Prefixes []string Template CommandTemplate ErrPrefix string ErrHint string } func ExecTemplate(runner *Runner, userID int64, raw string, tpl CommandTemplate) (uint, string, error) { dryRun, confirmToken := policy.ParseCommonFlags(raw) parts := strings.Fields(strings.TrimSpace(raw)) inputs := map[string]string{} if tpl.InputsFn != nil { out, err := tpl.InputsFn(raw, parts) if err != nil { return 0, "", err } inputs = out } meta := runbook.NewMeta() if tpl.MetaFn != nil { meta = tpl.MetaFn(userID, confirmToken, inputs) } if meta.RequestID == "" { meta.RequestID = fmt.Sprintf("ops-u%d-%d", userID, time.Now().Unix()) } req := Request{ RunbookName: tpl.RunbookName, Inputs: inputs, Meta: meta, Gate: tpl.Gate, DryRun: dryRun, ConfirmToken: confirmToken, } jobID, out, err := runner.Run(raw, userID, req) return jobID, out, err } func FormatDryRunMessage(tpl CommandTemplate) string { if tpl.DryRunMsg != "" { return tpl.DryRunMsg } return fmt.Sprintf("🧪 dry-run: 将执行 %s(未实际执行)", tpl.RunbookName) } func FormatSuccessMessage(tpl CommandTemplate, jobID uint) string { if tpl.SuccessMsg != nil { return tpl.SuccessMsg(jobID) } return fmt.Sprintf("✅ %s 已执行,job=%d", tpl.RunbookName, jobID) } func MatchAnyPrefix(text string, prefixes []string) bool { text = strings.TrimSpace(text) for _, p := range prefixes { if strings.HasPrefix(text, p) { return true } } return false } func MatchCommand(text string, specs []CommandSpec) (CommandSpec, bool) { for _, sp := range specs { if MatchAnyPrefix(text, sp.Prefixes) { return sp, true } } return CommandSpec{}, false } func FormatExecError(sp CommandSpec, err error) string { msg := sp.ErrPrefix + err.Error() if sp.ErrHint != "" { msg += "(示例:" + sp.ErrHint + ")" } return msg }