@tanagram/cli 0.1.10 → 0.1.12
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 +1 -1
- package/bin/tanagram +0 -0
- package/commands/run.go +12 -13
- package/commands/sync.go +28 -10
- package/main.go +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,7 +123,7 @@ If you have existing hooks, you can merge this hook into your existing config.
|
|
|
123
123
|
|
|
124
124
|
## How It Works
|
|
125
125
|
|
|
126
|
-
1. **Finds instruction files** - Searches for `AGENTS.md`, `POLICIES.md`, `CLAUDE.md`, and `.cursor/rules/*.mdc` in your git repository
|
|
126
|
+
1. **Finds instruction files** - Searches for `AGENTS.md`, `POLICIES.md`, `CLAUDE.md`, `BUGBOT.md`, and `.cursor/rules/*.mdc` in your git repository
|
|
127
127
|
2. **Checks cache** - Loads cached policies and MD5 hashes from `.tanagram/`
|
|
128
128
|
3. **Auto-syncs** - Detects file changes via MD5 and automatically resyncs if needed
|
|
129
129
|
4. **LLM extraction** - Uses Claude AI to extract ALL policies from instruction files
|
package/bin/tanagram
CHANGED
|
Binary file
|
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, CLAUDE.md, .cursor/rules/*.mdc)")
|
|
50
|
+
return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, CLAUDE.md, BUGBOT.md, .cursor/rules/*.mdc)")
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// Load cache
|
|
@@ -56,22 +56,21 @@ func Run() error {
|
|
|
56
56
|
return fmt.Errorf("failed to load cache: %w", err)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
// Check each file for changes and
|
|
60
|
-
|
|
59
|
+
// Check each file for changes and collect which files need syncing
|
|
60
|
+
var filesToSync []string
|
|
61
61
|
for _, file := range instructionFiles {
|
|
62
62
|
changed, err := cache.HasChanged(file)
|
|
63
63
|
if err != nil {
|
|
64
64
|
return fmt.Errorf("failed to check if %s changed: %w", file, err)
|
|
65
65
|
}
|
|
66
66
|
if changed {
|
|
67
|
-
|
|
68
|
-
break
|
|
67
|
+
filesToSync = append(filesToSync, file)
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
// Auto-sync
|
|
73
|
-
if
|
|
74
|
-
fmt.Printf("\nSyncing policies with LLM (processing %d
|
|
71
|
+
// Auto-sync only the files that changed
|
|
72
|
+
if len(filesToSync) > 0 {
|
|
73
|
+
fmt.Printf("\nSyncing policies with LLM (processing %d changed file(s) in parallel)...\n", len(filesToSync))
|
|
75
74
|
|
|
76
75
|
ctx := context.Background()
|
|
77
76
|
|
|
@@ -84,7 +83,7 @@ func Run() error {
|
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
// Channel to collect results
|
|
87
|
-
results := make(chan syncResult, len(
|
|
86
|
+
results := make(chan syncResult, len(filesToSync))
|
|
88
87
|
var wg sync.WaitGroup
|
|
89
88
|
|
|
90
89
|
// Start spinner
|
|
@@ -103,15 +102,15 @@ func Run() error {
|
|
|
103
102
|
mu.Lock()
|
|
104
103
|
c := completed
|
|
105
104
|
mu.Unlock()
|
|
106
|
-
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(
|
|
105
|
+
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(filesToSync))
|
|
107
106
|
i++
|
|
108
107
|
time.Sleep(100 * time.Millisecond)
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
}()
|
|
112
111
|
|
|
113
|
-
// Launch goroutines for
|
|
114
|
-
for _, file := range
|
|
112
|
+
// Launch goroutines only for changed files
|
|
113
|
+
for _, file := range filesToSync {
|
|
115
114
|
wg.Add(1)
|
|
116
115
|
go func(file string) {
|
|
117
116
|
defer wg.Done()
|
|
@@ -162,7 +161,7 @@ func Run() error {
|
|
|
162
161
|
return fmt.Errorf("failed to save cache: %w", err)
|
|
163
162
|
}
|
|
164
163
|
|
|
165
|
-
fmt.Printf("\n✓ Synced %d policies from %d file(s)\n", totalPolicies, len(
|
|
164
|
+
fmt.Printf("\n✓ Synced %d policies from %d changed file(s)\n", totalPolicies, len(filesToSync))
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
// Load all policies from 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, CLAUDE.md, .cursor/rules/*.mdc)")
|
|
31
|
+
return fmt.Errorf("no instruction files found (looking for AGENTS.md, POLICIES.md, CLAUDE.md, BUGBOT.md, .cursor/rules/*.mdc)")
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
fmt.Printf("Found %d instruction file(s)\n", len(instructionFiles))
|
|
@@ -39,8 +39,26 @@ func Sync() error {
|
|
|
39
39
|
return fmt.Errorf("failed to load cache: %w", err)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
//
|
|
43
|
-
|
|
42
|
+
// Check which files have changed and need syncing
|
|
43
|
+
var filesToSync []string
|
|
44
|
+
for _, file := range instructionFiles {
|
|
45
|
+
changed, err := cache.HasChanged(file)
|
|
46
|
+
if err != nil {
|
|
47
|
+
return fmt.Errorf("failed to check if %s changed: %w", file, err)
|
|
48
|
+
}
|
|
49
|
+
if changed {
|
|
50
|
+
filesToSync = append(filesToSync, file)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// If no files changed, nothing to sync
|
|
55
|
+
if len(filesToSync) == 0 {
|
|
56
|
+
fmt.Println("✓ All instruction files are up to date")
|
|
57
|
+
return nil
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Parse and sync only changed files using LLM in parallel
|
|
61
|
+
fmt.Printf("\nSyncing policies with LLM (processing %d changed file(s) in parallel)...\n", len(filesToSync))
|
|
44
62
|
|
|
45
63
|
ctx := context.Background()
|
|
46
64
|
|
|
@@ -53,7 +71,7 @@ func Sync() error {
|
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
// Channel to collect results
|
|
56
|
-
results := make(chan syncResult, len(
|
|
74
|
+
results := make(chan syncResult, len(filesToSync))
|
|
57
75
|
var wg sync.WaitGroup
|
|
58
76
|
|
|
59
77
|
// Start spinner
|
|
@@ -72,15 +90,15 @@ func Sync() error {
|
|
|
72
90
|
mu.Lock()
|
|
73
91
|
c := completed
|
|
74
92
|
mu.Unlock()
|
|
75
|
-
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(
|
|
93
|
+
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(filesToSync))
|
|
76
94
|
i++
|
|
77
95
|
time.Sleep(100 * time.Millisecond)
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
}()
|
|
81
99
|
|
|
82
|
-
// Launch goroutines for
|
|
83
|
-
for _, file := range
|
|
100
|
+
// Launch goroutines only for changed files
|
|
101
|
+
for _, file := range filesToSync {
|
|
84
102
|
wg.Add(1)
|
|
85
103
|
go func(file string) {
|
|
86
104
|
defer wg.Done()
|
|
@@ -132,17 +150,17 @@ func Sync() error {
|
|
|
132
150
|
return fmt.Errorf("failed to save cache: %w", err)
|
|
133
151
|
}
|
|
134
152
|
|
|
135
|
-
fmt.Printf("\n✓ Synced %d policies from %d file(s)\n", totalPolicies, len(
|
|
153
|
+
fmt.Printf("\n✓ Synced %d policies from %d changed file(s)\n", totalPolicies, len(filesToSync))
|
|
136
154
|
return nil
|
|
137
155
|
}
|
|
138
156
|
|
|
139
157
|
// FindInstructionFiles searches for instruction files in the git repository
|
|
140
|
-
// Looks for: AGENTS.md, POLICIES.md, CLAUDE.md, and .cursor/rules/*.mdc
|
|
158
|
+
// Looks for: AGENTS.md, POLICIES.md, CLAUDE.md, BUGBOT.md, and .cursor/rules/*.mdc
|
|
141
159
|
func FindInstructionFiles(gitRoot string) ([]string, error) {
|
|
142
160
|
var files []string
|
|
143
161
|
|
|
144
162
|
// Common instruction file names to look for
|
|
145
|
-
commonNames := []string{"AGENTS.md", "POLICIES.md", "CLAUDE.md"}
|
|
163
|
+
commonNames := []string{"AGENTS.md", "POLICIES.md", "CLAUDE.md", "BUGBOT.md"}
|
|
146
164
|
|
|
147
165
|
// Directories to skip
|
|
148
166
|
skipDirs := map[string]bool{
|
package/main.go
CHANGED
|
@@ -57,7 +57,7 @@ EXAMPLES:
|
|
|
57
57
|
|
|
58
58
|
INSTRUCTION FILES:
|
|
59
59
|
Tanagram looks for instruction files in your git repository:
|
|
60
|
-
- AGENTS.md, POLICIES.md, CLAUDE.md
|
|
60
|
+
- AGENTS.md, POLICIES.md, CLAUDE.md, BUGBOT.md
|
|
61
61
|
- Cursor rules: .cursor/rules/*.mdc
|
|
62
62
|
|
|
63
63
|
Policies are cached and automatically resynced when files change.
|