package main import ( "os" "github.com/bdw/ship/internal/output" "github.com/spf13/cobra" ) // This file defines the v2 CLI structure. // The primary command is: ship [PATH] [FLAGS] // All output is JSON by default. var rootV2Cmd = &cobra.Command{ Use: "ship [PATH]", Short: "Deploy code to a VPS. JSON output for agents.", Long: `Ship deploys code to a VPS. Point it at a directory or binary, get a URL back. ship ./myproject # auto-detect and deploy ship ./site --name docs # deploy with specific name ship ./api --health /healthz # deploy with health check ship ./preview --ttl 24h # deploy with auto-expiry All output is JSON. Use --pretty for human-readable output.`, Args: cobra.MaximumNArgs(1), RunE: runDeployV2, SilenceUsage: true, SilenceErrors: true, DisableAutoGenTag: true, } func initV2() { // Global flags rootV2Cmd.PersistentFlags().StringVar(&hostFlag, "host", "", "VPS host (SSH config alias or user@host)") rootV2Cmd.PersistentFlags().BoolVar(&output.Pretty, "pretty", false, "Human-readable output") // Deploy flags rootV2Cmd.Flags().String("name", "", "Deploy name (becomes subdomain)") rootV2Cmd.Flags().String("health", "", "Health check endpoint (e.g., /healthz)") rootV2Cmd.Flags().String("ttl", "", "Auto-delete after duration (e.g., 1h, 7d)") rootV2Cmd.Flags().StringArray("env", nil, "Environment variable (KEY=VALUE)") rootV2Cmd.Flags().String("env-file", "", "Path to .env file") // Check for SHIP_PRETTY env var if os.Getenv("SHIP_PRETTY") == "1" { output.Pretty = true } // Add subcommands rootV2Cmd.AddCommand(listV2Cmd) rootV2Cmd.AddCommand(statusV2Cmd) rootV2Cmd.AddCommand(logsV2Cmd) rootV2Cmd.AddCommand(removeV2Cmd) rootV2Cmd.AddCommand(hostV2Cmd) } func runDeployV2(cmd *cobra.Command, args []string) error { path := "." if len(args) > 0 { path = args[0] } opts := deployV2Options{ Host: hostFlag, Pretty: output.Pretty, } // Get flag values opts.Name, _ = cmd.Flags().GetString("name") opts.Health, _ = cmd.Flags().GetString("health") opts.TTL, _ = cmd.Flags().GetString("ttl") opts.Env, _ = cmd.Flags().GetStringArray("env") opts.EnvFile, _ = cmd.Flags().GetString("env-file") // deployV2 handles all output and exits deployV2(path, opts) // Should not reach here (deployV2 calls os.Exit) return nil } // Placeholder subcommands - to be implemented var listV2Cmd = &cobra.Command{ Use: "list", Short: "List all deployments", RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement output.PrintAndExit(&output.ListResponse{ Status: "ok", Deploys: []output.DeployInfo{}, }) return nil }, } var statusV2Cmd = &cobra.Command{ Use: "status NAME", Short: "Check status of a deployment", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement output.PrintAndExit(output.Err(output.ErrNotFound, "not implemented")) return nil }, } var logsV2Cmd = &cobra.Command{ Use: "logs NAME", Short: "View logs for a deployment", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement output.PrintAndExit(output.Err(output.ErrNotFound, "not implemented")) return nil }, } var removeV2Cmd = &cobra.Command{ Use: "remove NAME", Short: "Remove a deployment", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement output.PrintAndExit(output.Err(output.ErrNotFound, "not implemented")) return nil }, } var hostV2Cmd = &cobra.Command{ Use: "host", Short: "Manage VPS host", } func init() { hostV2Cmd.AddCommand(hostInitV2Cmd) hostV2Cmd.AddCommand(hostStatusV2Cmd) } var hostInitV2Cmd = &cobra.Command{ Use: "init USER@HOST --domain DOMAIN", Short: "Initialize a VPS for deployments", RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement - this is critical functionality to preserve output.PrintAndExit(output.Err(output.ErrNotFound, "not implemented")) return nil }, } var hostStatusV2Cmd = &cobra.Command{ Use: "status", Short: "Check host status", RunE: func(cmd *cobra.Command, args []string) error { // TODO: implement output.PrintAndExit(output.Err(output.ErrNotFound, "not implemented")) return nil }, }