feat: Introduce analyze Command for Deep Educational Codebase Analysis
#6
@ -14,8 +14,8 @@ import (
|
||||
"gmgauthier.com/grokkit/internal/git"
|
||||
"gmgauthier.com/grokkit/internal/grok"
|
||||
"gmgauthier.com/grokkit/internal/linter"
|
||||
"gmgauthier.com/grokkit/internal/logger"
|
||||
"gmgauthier.com/grokkit/internal/prompts" // new package (see below)
|
||||
"gmgauthier.com/grokkit/internal/logger" // note: we use package-level funcs
|
||||
"gmgauthier.com/grokkit/internal/prompts"
|
||||
)
|
||||
|
||||
var analyzeCmd = &cobra.Command{
|
||||
@ -32,20 +32,20 @@ Uses language-specific prompts discovered in .grokkit/prompts/ or ~/.config/grok
|
||||
if output == "" {
|
||||
output = "analyze.md"
|
||||
}
|
||||
model := config.GetModel(viper.GetString("model"))
|
||||
// Fixed: config.GetModel takes (commandName, flagModel)
|
||||
model := config.GetModel("analyze", viper.GetString("model"))
|
||||
yes := viper.GetBool("yes")
|
||||
|
||||
log := logger.Get()
|
||||
|
||||
// Safety: note if not in git repo
|
||||
if !git.IsRepo(dir) {
|
||||
log.Warn("Not inside a git repository. Git metadata in report will be limited.")
|
||||
// Fixed: use package-level logger funcs (no .Get())
|
||||
// Safety: note if not in git repo (IsRepo takes no args)
|
||||
if !git.IsRepo() {
|
||||
logger.Warn("Not inside a git repository. Git metadata in report will be limited.")
|
||||
}
|
||||
|
||||
// 1. Discover source files
|
||||
files, err := discoverSourceFiles(dir)
|
||||
if err != nil {
|
||||
log.Error("Failed to discover source files", "dir", dir, "error", err)
|
||||
logger.Error("Failed to discover source files", "dir", dir, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(files) == 0 {
|
||||
@ -53,7 +53,7 @@ Uses language-specific prompts discovered in .grokkit/prompts/ or ~/.config/grok
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 2. Detect primary language (extend linter as needed)
|
||||
// 2. Detect primary language
|
||||
lang := linter.DetectPrimaryLanguage(files)
|
||||
if lang == "" {
|
||||
lang = "unknown"
|
||||
@ -70,22 +70,20 @@ Uses language-specific prompts discovered in .grokkit/prompts/ or ~/.config/grok
|
||||
fmt.Println(`You are an expert ` + lang + ` educator...`)
|
||||
os.Exit(1)
|
||||
}
|
||||
log.Info("Loaded analysis prompt", "language", lang, "path", promptPath)
|
||||
logger.Info("Loaded analysis prompt", "language", lang, "path", promptPath)
|
||||
|
||||
// 4. Build rich project context (tree, key files, git info, etc.)
|
||||
// 4. Build rich project context
|
||||
context := buildProjectContext(dir, files)
|
||||
|
||||
// 5. Call Grok (silent stream for full report)
|
||||
// 5. Call Grok — use the exact working pattern you provided
|
||||
messages := []map[string]string{
|
||||
{"role": "system", "content": promptContent},
|
||||
{"role": "user", "content": "Analyze the following project and generate the full educational Markdown report:\n\n" + context},
|
||||
}
|
||||
|
||||
report, err := grok.GetClient().StreamSilent(messages, model)
|
||||
if err != nil {
|
||||
log.Error("Grok analysis failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// Fixed: NewClient() + Stream() (or StreamSilent if you prefer no live output)
|
||||
// For a long report, StreamSilent is usually better (no live printing)
|
||||
report := grok.NewClient().StreamSilent(messages, model)
|
||||
|
||||
// 6. Transactional preview + confirmation
|
||||
if !yes {
|
||||
@ -93,7 +91,10 @@ Uses language-specific prompts discovered in .grokkit/prompts/ or ~/.config/grok
|
||||
previewLines(report, 60)
|
||||
fmt.Printf("\nWrite report to %s? (y/N): ", output)
|
||||
var confirm string
|
||||
fmt.Scanln(&confirm)
|
||||
_, err := fmt.Scanln(&confirm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !strings.HasPrefix(strings.ToLower(confirm), "y") {
|
||||
fmt.Println("Analysis cancelled by user.")
|
||||
return
|
||||
@ -107,7 +108,7 @@ Uses language-specific prompts discovered in .grokkit/prompts/ or ~/.config/grok
|
||||
}
|
||||
|
||||
if err := os.WriteFile(output, []byte(report), 0644); err != nil {
|
||||
log.Error("Failed to write report", "file", output, "error", err)
|
||||
logger.Error("Failed to write report", "file", output, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@ -120,7 +121,6 @@ func init() {
|
||||
analyzeCmd.Flags().String("dir", ".", "Repository root to analyze")
|
||||
analyzeCmd.Flags().StringP("output", "o", "analyze.md", "Output file (use - for stdout)")
|
||||
analyzeCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
|
||||
// model flag is handled globally via config.GetModel
|
||||
|
||||
rootCmd.AddCommand(analyzeCmd)
|
||||
}
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
package linter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
import "strings"
|
||||
|
||||
// DetectPrimaryLanguage returns the dominant language in the given list of files.
|
||||
// It counts occurrences of each detected language and returns the most frequent one.
|
||||
// DetectPrimaryLanguage returns the dominant language from the list of files.
|
||||
// It counts detected languages and returns the most frequent one.
|
||||
// Falls back to "go" (common default) or "unknown".
|
||||
func DetectPrimaryLanguage(files []string) string {
|
||||
if len(files) == 0 {
|
||||
@ -26,7 +23,7 @@ func DetectPrimaryLanguage(files []string) string {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Find the language with the highest count
|
||||
// Find most common language
|
||||
var bestLang string
|
||||
maxCount := -1
|
||||
for lang, count := range counts {
|
||||
@ -36,7 +33,7 @@ func DetectPrimaryLanguage(files []string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Friendly bias toward Go in mixed repos (common case)
|
||||
// Bias toward Go in mixed repos
|
||||
if counts["go"] > 0 && counts["go"] >= maxCount/2 {
|
||||
return "go"
|
||||
}
|
||||
@ -44,8 +41,7 @@ func DetectPrimaryLanguage(files []string) string {
|
||||
return bestLang
|
||||
}
|
||||
|
||||
// SupportedLanguages returns a list of all languages known to the linter.
|
||||
// Useful for error messages or future prompt discovery.
|
||||
// SupportedLanguages returns all known languages (for future use or error messages).
|
||||
func SupportedLanguages() []string {
|
||||
var langs []string
|
||||
for _, l := range languages {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user