// Package devops defines the rules and composition for the devops agent. package devops import ( "github.com/enmanuel/agents/pkg/decision" "github.com/enmanuel/agents/pkg/tools" ) // Rules returns the decision rules for the devops agent. // These are pure data — no side effects. func Rules() []decision.Rule { return []decision.Rule{ { Name: "help", Match: decision.MatchCommand("help"), Actions: []decision.Action{{ Kind: decision.ActionKindReply, Reply: &decision.ReplyAction{ Content: "**DevOps Agent** — comandos disponibles:\n" + "- `!status ` — estado del target\n" + "- `!deploy ` — deployment en el environment\n" + "- `!rollback ` — rollback del último deploy\n" + "- `!logs ` — últimas líneas de log\n" + "- `!healthcheck` — health check de producción", }, }}, }, { Name: "healthcheck", Match: decision.MatchCommand("healthcheck"), Actions: []decision.Action{{ Kind: decision.ActionKindSSH, SSH: &tools.SSHCommandSpec{ Target: "production", Command: "/opt/scripts/healthcheck.sh", Timeout: "30s", }, }}, }, { Name: "status", Match: decision.MatchCommand("status"), Actions: []decision.Action{{ Kind: decision.ActionKindSSH, SSH: &tools.SSHCommandSpec{ Target: "monitoring", Command: "systemctl status --no-pager", Timeout: "15s", }, }}, }, { Name: "deploy-staging", Match: decision.And(decision.MatchCommand("deploy"), func(ctx decision.MessageContext) bool { return len(ctx.Args) > 0 && ctx.Args[0] == "staging" }), Actions: []decision.Action{{ Kind: decision.ActionKindSSH, SSH: &tools.SSHCommandSpec{ Target: "staging", Command: "cd /app && git pull origin main && systemctl restart app", Timeout: "60s", }, }}, }, { Name: "deploy-production", Match: decision.And( decision.MatchCommand("deploy"), decision.MatchMinPowerLevel(50), func(ctx decision.MessageContext) bool { return len(ctx.Args) > 0 && ctx.Args[0] == "production" }, ), Actions: []decision.Action{{ Kind: decision.ActionKindSSH, SSH: &tools.SSHCommandSpec{ Target: "production", Command: "cd /app && git pull origin main && systemctl restart app", Timeout: "120s", }, }}, }, { Name: "logs", Match: decision.MatchCommand("logs"), Actions: []decision.Action{{ Kind: decision.ActionKindSSH, SSH: &tools.SSHCommandSpec{ Target: "production", Command: "journalctl -u app -n 50 --no-pager", Timeout: "15s", }, }}, }, // Fallback: anything else goes to LLM { Name: "llm-fallback", Match: decision.And( decision.MatchAny(), func(ctx decision.MessageContext) bool { return ctx.Command == "" && (ctx.IsMention || ctx.IsDirectMsg) }, ), Actions: []decision.Action{{ Kind: decision.ActionKindLLM, LLM: &decision.LLMAction{}, }}, }, } }