doctorCommand wires the `cam doctor` subcommand. Output is layered so that existing assertion-based tests keep passing: the legacy "Providers: N" summary header appears first, followed by the new structured check sections.
(state *globalState)
| 16 | // existing assertion-based tests keep passing: the legacy "Providers: N" |
| 17 | // summary header appears first, followed by the new structured check sections. |
| 18 | func (a *App) doctorCommand(state *globalState) *cobra.Command { |
| 19 | var verbose bool |
| 20 | cmd := &cobra.Command{ |
| 21 | Use: "doctor", |
| 22 | Aliases: []string{"d"}, |
| 23 | Short: "Run diagnostic checks on environment and API keys", |
| 24 | Args: cobra.NoArgs, |
| 25 | RunE: func(cmd *cobra.Command, args []string) error { |
| 26 | out := cmd.OutOrStdout() |
| 27 | printer := ui.New(out, cmd.ErrOrStderr()) |
| 28 | |
| 29 | // --- legacy summary header (preserves existing test assertions). |
| 30 | file, providersErr := makeProviderAPI(state).File(context.Background()) |
| 31 | if providersErr == nil { |
| 32 | names := file.SortedNames() |
| 33 | fmt.Fprintf(out, "Providers: %d\n", len(names)) |
| 34 | for _, name := range names { |
| 35 | ep := file.Endpoints[name] |
| 36 | fmt.Fprintf(out, "- %s: %s\n", name, ep.Endpoint) |
| 37 | if ep.APIKeyEnv != "" { |
| 38 | status := "missing" |
| 39 | if os.Getenv(ep.APIKeyEnv) != "" { |
| 40 | status = "set" |
| 41 | } |
| 42 | fmt.Fprintf(out, " Environment: %s %s\n", ep.APIKeyEnv, status) |
| 43 | } |
| 44 | if verbose && ep.SupportedClient != "" { |
| 45 | clients := ep.Clients() |
| 46 | sort.Strings(clients) |
| 47 | fmt.Fprintf(out, " Supported clients: %s\n", joinComma(clients)) |
| 48 | } |
| 49 | } |
| 50 | fmt.Fprintln(out) |
| 51 | } else { |
| 52 | fmt.Fprintf(out, "Providers config could not be loaded: %v\n\n", providersErr) |
| 53 | } |
| 54 | |
| 55 | // --- structured doctor checks (new in sub-project #1). |
| 56 | checks := []doctor.Check{ |
| 57 | doctor.InstallationCheck{Version: a.version}, |
| 58 | doctor.ConfigCheck{Path: state.storePath}, |
| 59 | doctor.EnvCheck{}, |
| 60 | doctor.EndpointFormatCheck{File: file}, |
| 61 | doctor.CacheCheck{}, |
| 62 | doctor.GeminiAuthCheck{}, |
| 63 | doctor.CopilotAuthCheck{}, |
| 64 | doctor.ToolsAvailableCheck{}, |
| 65 | } |
| 66 | doctor.Run(context.Background(), printer, checks) |
| 67 | return nil |
| 68 | }, |
| 69 | } |
| 70 | cmd.Flags().BoolVar(&verbose, "verbose", false, "Show verbose diagnostics") |
| 71 | return cmd |
| 72 | } |
no test coverage detected