@tanagram/cli 0.1.4 → 0.1.5
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/bin/tanagram +0 -0
- package/commands/run.go +77 -20
- package/commands/sync.go +78 -21
- package/package.json +1 -1
package/bin/tanagram
CHANGED
|
Binary file
|
package/commands/run.go
CHANGED
|
@@ -5,11 +5,13 @@ import (
|
|
|
5
5
|
"fmt"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"sync"
|
|
8
9
|
"time"
|
|
9
10
|
|
|
10
11
|
"github.com/tanagram/cli/checker"
|
|
11
12
|
"github.com/tanagram/cli/extractor"
|
|
12
13
|
"github.com/tanagram/cli/git"
|
|
14
|
+
"github.com/tanagram/cli/parser"
|
|
13
15
|
"github.com/tanagram/cli/storage"
|
|
14
16
|
)
|
|
15
17
|
|
|
@@ -69,38 +71,93 @@ func Run() error {
|
|
|
69
71
|
|
|
70
72
|
// Auto-sync if any files changed
|
|
71
73
|
if needsSync {
|
|
72
|
-
fmt.Printf("\nSyncing policies with LLM...\n")
|
|
74
|
+
fmt.Printf("\nSyncing policies with LLM (processing %d files in parallel)...\n", len(instructionFiles))
|
|
73
75
|
|
|
74
|
-
totalPolicies := 0
|
|
75
76
|
ctx := context.Background()
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
// Result type for collecting sync results
|
|
79
|
+
type syncResult struct {
|
|
80
|
+
file string
|
|
81
|
+
relPath string
|
|
82
|
+
policies []parser.Policy
|
|
83
|
+
err error
|
|
84
|
+
}
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
// Channel to collect results
|
|
87
|
+
results := make(chan syncResult, len(instructionFiles))
|
|
88
|
+
var wg sync.WaitGroup
|
|
89
|
+
|
|
90
|
+
// Start spinner
|
|
91
|
+
stop := make(chan bool)
|
|
92
|
+
var completed int
|
|
93
|
+
var mu sync.Mutex
|
|
94
|
+
go func() {
|
|
95
|
+
chars := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
|
96
|
+
i := 0
|
|
97
|
+
for {
|
|
98
|
+
select {
|
|
99
|
+
case <-stop:
|
|
100
|
+
fmt.Print("\r")
|
|
101
|
+
return
|
|
102
|
+
default:
|
|
103
|
+
mu.Lock()
|
|
104
|
+
c := completed
|
|
105
|
+
mu.Unlock()
|
|
106
|
+
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(instructionFiles))
|
|
107
|
+
i++
|
|
108
|
+
time.Sleep(100 * time.Millisecond)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}()
|
|
112
|
+
|
|
113
|
+
// Launch goroutines for each file
|
|
114
|
+
for _, file := range instructionFiles {
|
|
115
|
+
wg.Add(1)
|
|
116
|
+
go func(file string) {
|
|
117
|
+
defer wg.Done()
|
|
118
|
+
relPath, _ := filepath.Rel(gitRoot, file)
|
|
119
|
+
policies, err := extractor.ExtractPoliciesFromFile(ctx, file)
|
|
120
|
+
results <- syncResult{file, relPath, policies, err}
|
|
121
|
+
}(file)
|
|
122
|
+
}
|
|
85
123
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
// Close results channel when all goroutines complete
|
|
125
|
+
go func() {
|
|
126
|
+
wg.Wait()
|
|
127
|
+
close(results)
|
|
128
|
+
}()
|
|
90
129
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
130
|
+
// Collect results
|
|
131
|
+
totalPolicies := 0
|
|
132
|
+
for result := range results {
|
|
133
|
+
mu.Lock()
|
|
134
|
+
completed++
|
|
135
|
+
mu.Unlock()
|
|
136
|
+
|
|
137
|
+
if result.err != nil {
|
|
138
|
+
stop <- true
|
|
139
|
+
close(stop)
|
|
140
|
+
time.Sleep(50 * time.Millisecond)
|
|
141
|
+
fmt.Printf("\r✗ Failed to process %s\n", result.relPath)
|
|
142
|
+
return fmt.Errorf("failed to extract policies from %s: %w", result.file, result.err)
|
|
94
143
|
}
|
|
95
144
|
|
|
96
|
-
if err := cache.UpdateFile(file, policies); err != nil {
|
|
97
|
-
|
|
145
|
+
if err := cache.UpdateFile(result.file, result.policies); err != nil {
|
|
146
|
+
stop <- true
|
|
147
|
+
close(stop)
|
|
148
|
+
time.Sleep(50 * time.Millisecond)
|
|
149
|
+
return fmt.Errorf("failed to update cache for %s: %w", result.file, err)
|
|
98
150
|
}
|
|
99
151
|
|
|
100
|
-
|
|
101
|
-
|
|
152
|
+
totalPolicies += len(result.policies)
|
|
153
|
+
fmt.Printf("\r✓ %s - %d policies\n", result.relPath, len(result.policies))
|
|
102
154
|
}
|
|
103
155
|
|
|
156
|
+
// Stop spinner
|
|
157
|
+
stop <- true
|
|
158
|
+
close(stop)
|
|
159
|
+
time.Sleep(50 * time.Millisecond)
|
|
160
|
+
|
|
104
161
|
if err := cache.Save(); err != nil {
|
|
105
162
|
return fmt.Errorf("failed to save cache: %w", err)
|
|
106
163
|
}
|
package/commands/sync.go
CHANGED
|
@@ -5,9 +5,11 @@ import (
|
|
|
5
5
|
"fmt"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"sync"
|
|
8
9
|
"time"
|
|
9
10
|
|
|
10
11
|
"github.com/tanagram/cli/extractor"
|
|
12
|
+
"github.com/tanagram/cli/parser"
|
|
11
13
|
"github.com/tanagram/cli/storage"
|
|
12
14
|
)
|
|
13
15
|
|
|
@@ -37,39 +39,94 @@ func Sync() error {
|
|
|
37
39
|
return fmt.Errorf("failed to load cache: %w", err)
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
// Parse and sync each file using LLM
|
|
41
|
-
fmt.Printf("\nSyncing policies with LLM...\n")
|
|
42
|
+
// Parse and sync each file using LLM in parallel
|
|
43
|
+
fmt.Printf("\nSyncing policies with LLM (processing %d files in parallel)...\n", len(instructionFiles))
|
|
42
44
|
|
|
43
|
-
totalPolicies := 0
|
|
44
45
|
ctx := context.Background()
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
// Result type for collecting sync results
|
|
48
|
+
type syncResult struct {
|
|
49
|
+
file string
|
|
50
|
+
relPath string
|
|
51
|
+
policies []parser.Policy
|
|
52
|
+
err error
|
|
53
|
+
}
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
// Channel to collect results
|
|
56
|
+
results := make(chan syncResult, len(instructionFiles))
|
|
57
|
+
var wg sync.WaitGroup
|
|
58
|
+
|
|
59
|
+
// Start spinner
|
|
60
|
+
stop := make(chan bool)
|
|
61
|
+
var completed int
|
|
62
|
+
var mu sync.Mutex
|
|
63
|
+
go func() {
|
|
64
|
+
chars := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
|
|
65
|
+
i := 0
|
|
66
|
+
for {
|
|
67
|
+
select {
|
|
68
|
+
case <-stop:
|
|
69
|
+
fmt.Print("\r")
|
|
70
|
+
return
|
|
71
|
+
default:
|
|
72
|
+
mu.Lock()
|
|
73
|
+
c := completed
|
|
74
|
+
mu.Unlock()
|
|
75
|
+
fmt.Printf("\r%s Processing files... (%d/%d completed)", chars[i%len(chars)], c, len(instructionFiles))
|
|
76
|
+
i++
|
|
77
|
+
time.Sleep(100 * time.Millisecond)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}()
|
|
81
|
+
|
|
82
|
+
// Launch goroutines for each file
|
|
83
|
+
for _, file := range instructionFiles {
|
|
84
|
+
wg.Add(1)
|
|
85
|
+
go func(file string) {
|
|
86
|
+
defer wg.Done()
|
|
87
|
+
relPath, _ := filepath.Rel(gitRoot, file)
|
|
88
|
+
policies, err := extractor.ExtractPoliciesFromFile(ctx, file)
|
|
89
|
+
results <- syncResult{file, relPath, policies, err}
|
|
90
|
+
}(file)
|
|
91
|
+
}
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
93
|
+
// Close results channel when all goroutines complete
|
|
94
|
+
go func() {
|
|
95
|
+
wg.Wait()
|
|
96
|
+
close(results)
|
|
97
|
+
}()
|
|
59
98
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
99
|
+
// Collect results
|
|
100
|
+
totalPolicies := 0
|
|
101
|
+
for result := range results {
|
|
102
|
+
mu.Lock()
|
|
103
|
+
completed++
|
|
104
|
+
mu.Unlock()
|
|
105
|
+
|
|
106
|
+
if result.err != nil {
|
|
107
|
+
stop <- true
|
|
108
|
+
close(stop)
|
|
109
|
+
time.Sleep(50 * time.Millisecond)
|
|
110
|
+
fmt.Printf("\r✗ Failed to process %s\n", result.relPath)
|
|
111
|
+
return fmt.Errorf("failed to extract policies from %s: %w", result.file, result.err)
|
|
63
112
|
}
|
|
64
113
|
|
|
65
|
-
if err := cache.UpdateFile(file, policies); err != nil {
|
|
66
|
-
|
|
114
|
+
if err := cache.UpdateFile(result.file, result.policies); err != nil {
|
|
115
|
+
stop <- true
|
|
116
|
+
close(stop)
|
|
117
|
+
time.Sleep(50 * time.Millisecond)
|
|
118
|
+
return fmt.Errorf("failed to update cache for %s: %w", result.file, err)
|
|
67
119
|
}
|
|
68
120
|
|
|
69
|
-
|
|
70
|
-
|
|
121
|
+
totalPolicies += len(result.policies)
|
|
122
|
+
fmt.Printf("\r✓ %s - %d policies\n", result.relPath, len(result.policies))
|
|
71
123
|
}
|
|
72
124
|
|
|
125
|
+
// Stop spinner
|
|
126
|
+
stop <- true
|
|
127
|
+
close(stop)
|
|
128
|
+
time.Sleep(50 * time.Millisecond)
|
|
129
|
+
|
|
73
130
|
// Save cache
|
|
74
131
|
if err := cache.Save(); err != nil {
|
|
75
132
|
return fmt.Errorf("failed to save cache: %w", err)
|