|
| 1 | +// Package ask provides the AI assistant command powered by OpenCode. |
| 2 | +package ask |
| 3 | + |
| 4 | +import ( |
| 5 | + "context" |
| 6 | + _ "embed" |
| 7 | + "fmt" |
| 8 | + "os" |
| 9 | + "os/exec" |
| 10 | + "path/filepath" |
| 11 | + "strings" |
| 12 | + |
| 13 | + "github.com/urfave/cli/v2" |
| 14 | +) |
| 15 | + |
| 16 | +//go:embed agent.md |
| 17 | +var agentMarkdown []byte |
| 18 | + |
| 19 | +const agentName = "createos" |
| 20 | + |
| 21 | +// installAgent writes the embedded agent markdown to ~/.opencode/agents/createos.md. |
| 22 | +func installAgent() error { |
| 23 | + home, err := os.UserHomeDir() |
| 24 | + if err != nil { |
| 25 | + return fmt.Errorf("could not determine home directory: %w", err) |
| 26 | + } |
| 27 | + |
| 28 | + agentsDir := filepath.Join(home, ".opencode", "agents") |
| 29 | + if err := os.MkdirAll(agentsDir, 0750); err != nil { //nolint:gosec // user-owned directory |
| 30 | + return fmt.Errorf("could not create agents directory: %w", err) |
| 31 | + } |
| 32 | + |
| 33 | + agentPath := filepath.Join(agentsDir, agentName+".md") |
| 34 | + if err := os.WriteFile(agentPath, agentMarkdown, 0600); err != nil { |
| 35 | + return fmt.Errorf("could not write agent file: %w", err) |
| 36 | + } |
| 37 | + return nil |
| 38 | +} |
| 39 | + |
| 40 | +// NewAskCommand returns the ask AI assistant command. |
| 41 | +func NewAskCommand() *cli.Command { |
| 42 | + return &cli.Command{ |
| 43 | + Name: "ask", |
| 44 | + Usage: "Ask the AI assistant to help manage your infrastructure", |
| 45 | + ArgsUsage: "[message]", |
| 46 | + Description: "Opens the OpenCode AI assistant pre-configured to use the createos CLI.\n\n" + |
| 47 | + " Interactive mode (TUI):\n" + |
| 48 | + " createos ask\n\n" + |
| 49 | + " Non-interactive mode:\n" + |
| 50 | + " createos ask \"list my VMs\"\n" + |
| 51 | + " createos ask \"deploy a VM in nyc3\"\n\n" + |
| 52 | + " Requires opencode to be installed: https://opencode.ai", |
| 53 | + Action: func(c *cli.Context) error { |
| 54 | + opencodeBin, err := exec.LookPath("opencode") |
| 55 | + if err != nil { |
| 56 | + return fmt.Errorf("opencode is not installed or not in PATH\n\n Install it from: https://opencode.ai") |
| 57 | + } |
| 58 | + |
| 59 | + if err := installAgent(); err != nil { |
| 60 | + return fmt.Errorf("could not install CreateOS agent: %w", err) |
| 61 | + } |
| 62 | + |
| 63 | + message := strings.Join(c.Args().Slice(), " ") |
| 64 | + |
| 65 | + var args []string |
| 66 | + if message != "" { |
| 67 | + args = []string{"run", message, "--agent", agentName} |
| 68 | + } else { |
| 69 | + args = []string{"--agent", agentName} |
| 70 | + } |
| 71 | + |
| 72 | + cmd := exec.CommandContext(context.Background(), opencodeBin, args...) //nolint:gosec |
| 73 | + cmd.Stdin = os.Stdin |
| 74 | + cmd.Stdout = os.Stdout |
| 75 | + cmd.Stderr = os.Stderr |
| 76 | + |
| 77 | + return cmd.Run() |
| 78 | + }, |
| 79 | + } |
| 80 | +} |
0 commit comments