Skip to content

Commit c5e3b5b

Browse files
authored
Merge pull request #17 from Priyans-hu/feat/improve-claude-md
docs: enhance CLAUDE.md with detailed documentation
2 parents d115bc0 + af7a856 commit c5e3b5b

File tree

10 files changed

+2512
-223
lines changed

10 files changed

+2512
-223
lines changed

CLAUDE.md

Lines changed: 242 additions & 221 deletions
Large diffs are not rendered by default.

internal/analyzer/analyzer.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ func (a *Analyzer) Analyze() (*types.Analysis, error) {
125125
archDetector := detector.NewArchitectureDetector(absPath, files)
126126
analysis.ArchitectureInfo = archDetector.Detect()
127127

128+
// Detect development setup info
129+
devDetector := detector.NewDevelopmentDetector(absPath, files)
130+
analysis.DevelopmentInfo = devDetector.Detect()
131+
132+
// Detect config files
133+
configDetector := detector.NewConfigDetector(absPath, files)
134+
analysis.ConfigFiles = configDetector.Detect()
135+
136+
// Detect CLI info (if applicable)
137+
cliDetector := detector.NewCLIDetector(absPath, files, &analysis.TechStack)
138+
analysis.CLIInfo = cliDetector.Detect()
139+
128140
return analysis, nil
129141
}
130142

@@ -231,7 +243,6 @@ func findSubstring(s, substr string) int {
231243
return -1
232244
}
233245

234-
235246
// Helper functions to avoid importing strings package multiple times
236247
func splitLines(s string) []string {
237248
var lines []string

internal/detector/cli.go

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
package detector
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"regexp"
7+
"strings"
8+
9+
"github.com/Priyans-hu/argus/pkg/types"
10+
)
11+
12+
// CLIDetector detects CLI-specific information
13+
type CLIDetector struct {
14+
rootPath string
15+
files []types.FileInfo
16+
techStack *types.TechStack
17+
}
18+
19+
// NewCLIDetector creates a new CLI detector
20+
func NewCLIDetector(rootPath string, files []types.FileInfo, techStack *types.TechStack) *CLIDetector {
21+
return &CLIDetector{
22+
rootPath: rootPath,
23+
files: files,
24+
techStack: techStack,
25+
}
26+
}
27+
28+
// Detect extracts CLI-specific information
29+
func (d *CLIDetector) Detect() *types.CLIInfo {
30+
// Only process if this is a CLI project
31+
if !d.isCLIProject() {
32+
return nil
33+
}
34+
35+
info := &types.CLIInfo{}
36+
37+
// Detect flags from source code
38+
info.VerboseFlag, info.DryRunFlag = d.detectFlags()
39+
40+
// Detect output indicators
41+
info.Indicators = d.detectIndicators()
42+
43+
// Return nil if nothing detected
44+
if info.VerboseFlag == "" && info.DryRunFlag == "" && len(info.Indicators) == 0 {
45+
return nil
46+
}
47+
48+
return info
49+
}
50+
51+
// isCLIProject checks if this is a CLI project
52+
func (d *CLIDetector) isCLIProject() bool {
53+
if d.techStack == nil {
54+
return false
55+
}
56+
57+
// Check for CLI frameworks
58+
cliFrameworks := []string{
59+
"cobra", "urfave/cli", "kingpin", "pflag", // Go
60+
"click", "typer", "argparse", // Python
61+
"clap", "structopt", // Rust
62+
"commander", "yargs", "meow", // Node.js
63+
}
64+
65+
for _, fw := range d.techStack.Frameworks {
66+
fwLower := strings.ToLower(fw.Name)
67+
for _, cli := range cliFrameworks {
68+
if strings.Contains(fwLower, cli) {
69+
return true
70+
}
71+
}
72+
}
73+
74+
// Check for cmd/ directory (common Go CLI pattern)
75+
for _, f := range d.files {
76+
if strings.HasPrefix(f.Path, "cmd/") && f.Extension == ".go" {
77+
return true
78+
}
79+
}
80+
81+
return false
82+
}
83+
84+
// detectFlags detects verbose and dry-run flags from source code
85+
func (d *CLIDetector) detectFlags() (verboseFlag, dryRunFlag string) {
86+
// Patterns for flag definitions
87+
verbosePatterns := []string{
88+
`-v.*verbose`,
89+
`--verbose`,
90+
`-verbose`,
91+
`"verbose"`,
92+
`'verbose'`,
93+
}
94+
95+
dryRunPatterns := []string{
96+
`-n.*dry-run`,
97+
`--dry-run`,
98+
`-dry-run`,
99+
`"dry-run"`,
100+
`'dry-run'`,
101+
`"dryRun"`,
102+
}
103+
104+
// Find main.go or cmd/*.go files
105+
mainFiles := d.findMainFiles()
106+
107+
for _, mainFile := range mainFiles {
108+
content, err := os.ReadFile(mainFile)
109+
if err != nil {
110+
continue
111+
}
112+
113+
contentStr := string(content)
114+
115+
// Check for verbose flag
116+
if verboseFlag == "" {
117+
for _, pattern := range verbosePatterns {
118+
if matched, _ := regexp.MatchString(pattern, contentStr); matched {
119+
verboseFlag = "-v, --verbose"
120+
break
121+
}
122+
}
123+
}
124+
125+
// Check for dry-run flag
126+
if dryRunFlag == "" {
127+
for _, pattern := range dryRunPatterns {
128+
if matched, _ := regexp.MatchString(pattern, contentStr); matched {
129+
dryRunFlag = "-n, --dry-run"
130+
break
131+
}
132+
}
133+
}
134+
135+
if verboseFlag != "" && dryRunFlag != "" {
136+
break
137+
}
138+
}
139+
140+
return verboseFlag, dryRunFlag
141+
}
142+
143+
// detectIndicators detects output indicators (emojis or symbols)
144+
func (d *CLIDetector) detectIndicators() []types.Indicator {
145+
var indicators []types.Indicator
146+
147+
// Common CLI indicator patterns
148+
indicatorPatterns := map[string]string{
149+
"✅": "Success",
150+
"❌": "Error",
151+
"⚠️": "Warning",
152+
"🔍": "Scanning/analyzing",
153+
"🔄": "Processing/syncing",
154+
"📊": "Analysis results",
155+
"📄": "File output",
156+
"👁️": "Watch mode",
157+
"✓": "Success",
158+
"✗": "Error",
159+
"→": "Progress indicator",
160+
}
161+
162+
// Find source files
163+
mainFiles := d.findMainFiles()
164+
165+
foundIndicators := make(map[string]bool)
166+
167+
for _, mainFile := range mainFiles {
168+
content, err := os.ReadFile(mainFile)
169+
if err != nil {
170+
continue
171+
}
172+
173+
contentStr := string(content)
174+
175+
for symbol, meaning := range indicatorPatterns {
176+
if strings.Contains(contentStr, symbol) && !foundIndicators[symbol] {
177+
foundIndicators[symbol] = true
178+
indicators = append(indicators, types.Indicator{
179+
Symbol: symbol,
180+
Meaning: meaning,
181+
})
182+
}
183+
}
184+
}
185+
186+
return indicators
187+
}
188+
189+
// findMainFiles finds main.go and cmd/*.go files
190+
func (d *CLIDetector) findMainFiles() []string {
191+
var files []string
192+
193+
// Check main.go
194+
mainPath := filepath.Join(d.rootPath, "main.go")
195+
if _, err := os.Stat(mainPath); err == nil {
196+
files = append(files, mainPath)
197+
}
198+
199+
// Check cmd/ directory
200+
cmdDir := filepath.Join(d.rootPath, "cmd")
201+
if entries, err := os.ReadDir(cmdDir); err == nil {
202+
for _, entry := range entries {
203+
if entry.IsDir() {
204+
// Check for main.go in subdirectory
205+
subMain := filepath.Join(cmdDir, entry.Name(), "main.go")
206+
if _, err := os.Stat(subMain); err == nil {
207+
files = append(files, subMain)
208+
}
209+
} else if strings.HasSuffix(entry.Name(), ".go") {
210+
files = append(files, filepath.Join(cmdDir, entry.Name()))
211+
}
212+
}
213+
}
214+
215+
// Also check internal/generator for output patterns (for this project specifically)
216+
genDir := filepath.Join(d.rootPath, "internal", "generator")
217+
if entries, err := os.ReadDir(genDir); err == nil {
218+
for _, entry := range entries {
219+
if strings.HasSuffix(entry.Name(), ".go") {
220+
files = append(files, filepath.Join(genDir, entry.Name()))
221+
}
222+
}
223+
}
224+
225+
return files
226+
}

0 commit comments

Comments
 (0)