@tanagram/cli 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,7 +99,7 @@ tanagram help
99
99
 
100
100
  ## How It Works
101
101
 
102
- 1. **Finds instruction files** - Searches for `AGENTS.md`, `POLICIES.md` in your git repository
102
+ 1. **Finds instruction files** - Searches for `AGENTS.md`, `POLICIES.md`, `CLAUDE.md` in your git repository
103
103
  2. **Checks cache** - Loads cached policies and MD5 hashes from `.tanagram/`
104
104
  3. **Auto-syncs** - Detects file changes via MD5 and automatically resyncs if needed
105
105
  4. **LLM extraction** - Uses Claude AI to extract ALL policies from instruction files
package/bin/tanagram CHANGED
Binary file
@@ -81,7 +81,7 @@ func checkFileWithLLM(ctx context.Context, file string, changes []git.ChangedLin
81
81
  File: file,
82
82
  LineNumber: firstLine.LineNumber,
83
83
  PolicyName: policy.Name,
84
- Message: fmt.Sprintf("%s\n\nLLM Analysis: %s", policy.Message, check.Reason),
84
+ Message: check.Reason,
85
85
  Code: formatChangesForDisplay(changes),
86
86
  })
87
87
  }
@@ -100,20 +100,10 @@ func formatChangesForLLM(changes []git.ChangedLine) string {
100
100
 
101
101
  // formatChangesForDisplay creates a compact display of changed lines
102
102
  func formatChangesForDisplay(changes []git.ChangedLine) string {
103
- if len(changes) == 1 {
103
+ // Just return the first line's content, trimmed
104
+ // Line numbers will be shown in the formatted output
105
+ if len(changes) > 0 {
104
106
  return strings.TrimSpace(changes[0].Content)
105
107
  }
106
-
107
- var builder strings.Builder
108
- for i, change := range changes {
109
- if i > 0 {
110
- builder.WriteString("\n")
111
- }
112
- builder.WriteString(fmt.Sprintf("L%d: %s", change.LineNumber, strings.TrimSpace(change.Content)))
113
- if i >= 2 { // Limit to first 3 lines
114
- builder.WriteString("\n...")
115
- break
116
- }
117
- }
118
- return builder.String()
108
+ return ""
119
109
  }
@@ -3,6 +3,7 @@ package checker
3
3
  import (
4
4
  "context"
5
5
  "fmt"
6
+ "sort"
6
7
  "strings"
7
8
 
8
9
  "github.com/tanagram/cli/git"
@@ -44,12 +45,46 @@ func FormatViolations(result *CheckResult) string {
44
45
  return "✓ No policy violations found"
45
46
  }
46
47
 
48
+ // ANSI color codes
49
+ const (
50
+ colorReset = "\033[0m"
51
+ colorGray = "\033[90m"
52
+ )
53
+
54
+ // Group violations by file
55
+ violationsByFile := make(map[string][]Violation)
56
+ for _, v := range result.Violations {
57
+ violationsByFile[v.File] = append(violationsByFile[v.File], v)
58
+ }
59
+
60
+ // Sort files for consistent output
61
+ files := make([]string, 0, len(violationsByFile))
62
+ for file := range violationsByFile {
63
+ files = append(files, file)
64
+ }
65
+ sort.Strings(files)
66
+
47
67
  var output strings.Builder
48
68
  output.WriteString(fmt.Sprintf("✗ Found %d policy violation(s):\n\n", len(result.Violations)))
49
69
 
50
- for _, v := range result.Violations {
51
- output.WriteString(fmt.Sprintf("%s:%d - [%s] %s\n", v.File, v.LineNumber, v.PolicyName, v.Message))
52
- output.WriteString(fmt.Sprintf(" > %s\n\n", v.Code))
70
+ for _, file := range files {
71
+ violations := violationsByFile[file]
72
+
73
+ // Sort violations by line number
74
+ sort.Slice(violations, func(i, j int) bool {
75
+ return violations[i].LineNumber < violations[j].LineNumber
76
+ })
77
+
78
+ output.WriteString(fmt.Sprintf("- %s\n\n", file))
79
+
80
+ for _, v := range violations {
81
+ // Print the code line in gray
82
+ output.WriteString(fmt.Sprintf(" %s%d: %s%s\n", colorGray, v.LineNumber, v.Code, colorReset))
83
+
84
+ // Print the violation message indented with arrow
85
+ output.WriteString(fmt.Sprintf(" ^ %s\n", v.Message))
86
+ }
87
+ output.WriteString("\n")
53
88
  }
54
89
 
55
90
  return output.String()
package/commands/run.go CHANGED
@@ -47,7 +47,7 @@ func Run() error {
47
47
  }
48
48
 
49
49
  if len(instructionFiles) == 0 {
50
- return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, etc.)")
50
+ return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, CLAUDE.md)")
51
51
  }
52
52
 
53
53
  // Load cache
package/commands/sync.go CHANGED
@@ -28,7 +28,7 @@ func Sync() error {
28
28
  }
29
29
 
30
30
  if len(instructionFiles) == 0 {
31
- return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, etc.)")
31
+ return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, CLAUDE.md)")
32
32
  }
33
33
 
34
34
  fmt.Printf("Found %d instruction file(s)\n", len(instructionFiles))
@@ -137,12 +137,12 @@ func Sync() error {
137
137
  }
138
138
 
139
139
  // FindInstructionFiles searches for instruction files in the git repository
140
- // Looks for: AGENTS.md, POLICIES.md, and .md files in .tanagram/policies/
140
+ // Looks for: AGENTS.md, POLICIES.md, CLAUDE.md
141
141
  func FindInstructionFiles(gitRoot string) ([]string, error) {
142
142
  var files []string
143
143
 
144
144
  // Common instruction file names to look for
145
- commonNames := []string{"AGENTS.md", "POLICIES.md"}
145
+ commonNames := []string{"AGENTS.md", "POLICIES.md", "CLAUDE.md"}
146
146
 
147
147
  // Directories to skip
148
148
  skipDirs := map[string]bool{
package/main.go CHANGED
@@ -56,7 +56,7 @@ EXAMPLES:
56
56
  tanagram list # View all cached policies
57
57
 
58
58
  INSTRUCTION FILES:
59
- Tanagram looks for instruction files like AGENTS.md or POLICIES.md
59
+ Tanagram looks for instruction files like AGENTS.md, POLICIES.md, or CLAUDE.md
60
60
  in your git repository. Policies are cached and automatically resynced
61
61
  when files change.
62
62
  `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanagram/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Tanagram - Catch sloppy code before it ships",
5
5
  "main": "index.js",
6
6
  "bin": {