@tanagram/cli 0.2.2 → 0.3.1

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.
@@ -180,7 +180,7 @@ func ConfigList() error {
180
180
  projectStatus := checkHookStatus(projectSettingsPath)
181
181
 
182
182
  // Print results
183
- fmt.Println("Claude Code Hook Status:\n")
183
+ fmt.Println("Claude Code Hook Status:")
184
184
 
185
185
  fmt.Printf("User Settings (~/.claude/settings.json):\n")
186
186
  printHookStatus(userStatus, userSettingsPath)
@@ -350,3 +350,35 @@ func printHookStatus(status HookStatus, path string) {
350
350
  }
351
351
  }
352
352
 
353
+ // EnsureClaudeConfigured checks if Claude Code hooks are configured,
354
+ // and automatically sets them up if not. This is called on first run
355
+ // of commands that need Claude Code integration.
356
+ func EnsureClaudeConfigured() error {
357
+ home, err := os.UserHomeDir()
358
+ if err != nil {
359
+ // Silently skip if we can't get home dir - not critical
360
+ return nil
361
+ }
362
+
363
+ settingsPath := filepath.Join(home, ".claude", "settings.json")
364
+ status := checkHookStatus(settingsPath)
365
+
366
+ // If hooks are already configured, we're done
367
+ if status.IsUpToDate {
368
+ return nil
369
+ }
370
+
371
+ // If file doesn't exist or hooks aren't configured, set them up
372
+ if !status.FileExists || !status.PreHookExists || !status.PostHookExists {
373
+ fmt.Println("Setting up Claude Code integration...")
374
+ if err := ConfigClaude(); err != nil {
375
+ // Don't fail the command if hook setup fails - just warn
376
+ fmt.Fprintf(os.Stderr, "Warning: Failed to setup Claude Code hooks: %v\n", err)
377
+ fmt.Fprintf(os.Stderr, "You can manually setup hooks later with: tanagram config claude\n\n")
378
+ return nil
379
+ }
380
+ fmt.Println() // Add blank line after setup message
381
+ }
382
+
383
+ return nil
384
+ }
package/commands/run.go CHANGED
@@ -16,6 +16,7 @@ import (
16
16
  "github.com/tanagram/cli/parser"
17
17
  "github.com/tanagram/cli/snapshot"
18
18
  "github.com/tanagram/cli/storage"
19
+ "github.com/tanagram/cli/utils"
19
20
  )
20
21
 
21
22
  // spinner shows a simple spinner animation
@@ -275,26 +276,31 @@ func Run() error {
275
276
 
276
277
  // Track policy check results (similar to policy.execute.result in github-app)
277
278
  metrics.Track("cli.policy.check.result", map[string]interface{}{
278
- "policies_checked": len(policies),
279
- "changes_checked": len(changesToCheck),
280
- "violations_found": len(result.Violations),
281
- "has_violations": len(result.Violations) > 0,
282
- "duration_seconds": checkDuration.Seconds(),
283
- "used_snapshot": useSnapshot,
279
+ "policies_checked": len(policies),
280
+ "changes_checked": len(changesToCheck),
281
+ "violations_found": len(result.Violations),
282
+ "has_violations": len(result.Violations) > 0,
283
+ "duration_seconds": checkDuration.Seconds(),
284
+ "used_snapshot": useSnapshot,
284
285
  })
285
286
 
286
287
  // Handle results based on whether violations were found
287
288
  if len(result.Violations) > 0 {
288
- // Format and output violations to stderr
289
- violationOutput := checker.FormatViolations(result)
290
- fmt.Fprint(os.Stderr, violationOutput)
289
+ // Determine parent process to decide output format
290
+ parentProcess := utils.GetParentProcess()
291
291
 
292
- // Format and output Claude-friendly instructions to stderr
293
- claudeInstructions := checker.FormatClaudeInstructions(result)
294
- fmt.Fprint(os.Stderr, claudeInstructions)
292
+ if parentProcess == "claude" {
293
+ // Format and output Claude-friendly instructions to stderr
294
+ claudeInstructions := checker.FormatClaudeInstructions(result)
295
+ fmt.Fprint(os.Stderr, claudeInstructions)
295
296
 
296
- // Exit with code 2 to trigger Claude Code hook behavior
297
- os.Exit(2)
297
+ // Exit with code 2 to trigger Claude Code hook behavior
298
+ os.Exit(2)
299
+ } else {
300
+ // Format and output violations to stderr
301
+ violationOutput := checker.FormatViolations(result)
302
+ fmt.Fprint(os.Stderr, violationOutput)
303
+ }
298
304
  }
299
305
 
300
306
  // No violations found - output success message
package/go.mod CHANGED
@@ -2,33 +2,42 @@ module github.com/tanagram/cli
2
2
 
3
3
  go 1.24.0
4
4
 
5
- require github.com/anthropics/anthropic-sdk-go v1.17.0
5
+ require (
6
+ github.com/anthropics/anthropic-sdk-go v1.17.0
7
+ github.com/charmbracelet/bubbletea v1.3.10
8
+ github.com/charmbracelet/lipgloss v1.1.0
9
+ github.com/posthog/posthog-go v1.6.12
10
+ github.com/shirou/gopsutil/v3 v3.24.5
11
+ )
6
12
 
7
13
  require (
8
14
  github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
9
- github.com/charmbracelet/bubbletea v1.3.10 // indirect
10
15
  github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
11
- github.com/charmbracelet/lipgloss v1.1.0 // indirect
12
16
  github.com/charmbracelet/x/ansi v0.10.1 // indirect
13
17
  github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
14
18
  github.com/charmbracelet/x/term v0.2.1 // indirect
15
19
  github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
20
+ github.com/go-ole/go-ole v1.2.6 // indirect
16
21
  github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
17
22
  github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
23
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
18
24
  github.com/mattn/go-isatty v0.0.20 // indirect
19
25
  github.com/mattn/go-localereader v0.0.1 // indirect
20
26
  github.com/mattn/go-runewidth v0.0.16 // indirect
21
27
  github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
22
28
  github.com/muesli/cancelreader v0.2.2 // indirect
23
29
  github.com/muesli/termenv v0.16.0 // indirect
24
- github.com/posthog/posthog-go v1.6.12 // indirect
30
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
25
31
  github.com/rivo/uniseg v0.4.7 // indirect
26
- github.com/stretchr/testify v1.10.0 // indirect
32
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
27
33
  github.com/tidwall/gjson v1.18.0 // indirect
28
34
  github.com/tidwall/match v1.1.1 // indirect
29
35
  github.com/tidwall/pretty v1.2.1 // indirect
30
36
  github.com/tidwall/sjson v1.2.5 // indirect
37
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
38
+ github.com/tklauser/numcpus v0.6.1 // indirect
31
39
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
40
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
32
41
  golang.org/x/sys v0.36.0 // indirect
33
42
  golang.org/x/text v0.27.0 // indirect
34
43
  )
package/go.sum CHANGED
@@ -18,10 +18,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
18
18
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19
19
  github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
20
20
  github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
21
+ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
22
+ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
23
+ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
24
+ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
25
+ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
21
26
  github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
22
27
  github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
23
28
  github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
24
29
  github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
30
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
31
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
25
32
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
26
33
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
27
34
  github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
@@ -38,11 +45,17 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
38
45
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
39
46
  github.com/posthog/posthog-go v1.6.12 h1:rsOBL/YdMfLJtOVjKJLgdzYmvaL3aIW6IVbAteSe+aI=
40
47
  github.com/posthog/posthog-go v1.6.12/go.mod h1:LcC1Nu4AgvV22EndTtrMXTy+7RGVC0MhChSw7Qk5XkY=
48
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
49
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
41
50
  github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
42
51
  github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
43
52
  github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
44
- github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
45
- github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
53
+ github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
54
+ github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
55
+ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
56
+ github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
57
+ github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
58
+ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
46
59
  github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
47
60
  github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
48
61
  github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -55,13 +68,26 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
55
68
  github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
56
69
  github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
57
70
  github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
71
+ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
72
+ github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
73
+ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
74
+ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
58
75
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
59
76
  github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
77
+ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
78
+ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
79
+ golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
80
+ golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
81
+ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
82
+ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
60
83
  golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
61
84
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
85
+ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
86
+ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
62
87
  golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
63
88
  golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
64
89
  golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
65
90
  golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
91
+ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
66
92
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
67
93
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
package/main.go CHANGED
@@ -43,6 +43,12 @@ func main() {
43
43
  metrics.Track("cli.command.execute", map[string]interface{}{
44
44
  "command": "run",
45
45
  })
46
+ // Auto-setup Claude Code hooks on first run
47
+ if err := commands.EnsureClaudeConfigured(); err != nil {
48
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
49
+ exitCode = 1
50
+ return
51
+ }
46
52
  err = commands.Run()
47
53
  case "snapshot":
48
54
  metrics.Track("cli.command.execute", map[string]interface{}{
@@ -53,11 +59,23 @@ func main() {
53
59
  metrics.Track("cli.command.execute", map[string]interface{}{
54
60
  "command": "sync",
55
61
  })
62
+ // Auto-setup Claude Code hooks on first run
63
+ if err := commands.EnsureClaudeConfigured(); err != nil {
64
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
65
+ exitCode = 1
66
+ return
67
+ }
56
68
  err = commands.Sync()
57
69
  case "list":
58
70
  metrics.Track("cli.command.execute", map[string]interface{}{
59
71
  "command": "list",
60
72
  })
73
+ // Auto-setup Claude Code hooks on first run
74
+ if err := commands.EnsureClaudeConfigured(); err != nil {
75
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
76
+ exitCode = 1
77
+ return
78
+ }
61
79
  err = commands.List()
62
80
  case "config":
63
81
  // Handle config subcommands
@@ -7,6 +7,7 @@ import (
7
7
  "time"
8
8
 
9
9
  "github.com/posthog/posthog-go"
10
+ "github.com/tanagram/cli/utils"
10
11
  )
11
12
 
12
13
  var (
@@ -84,6 +85,7 @@ func Track(event string, properties map[string]interface{}) {
84
85
  properties["os_user"] = getUser()
85
86
  properties["hostname"] = getHostname()
86
87
  properties["cwd"] = getCwd()
88
+ properties["parent_process"] = utils.GetParentProcess()
87
89
 
88
90
  // Build properties - include all custom properties from the caller
89
91
  props := posthog.NewProperties()
@@ -141,3 +143,5 @@ func getCwd() string {
141
143
  func getVersion() string {
142
144
  return version
143
145
  }
146
+
147
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanagram/cli",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Tanagram - Catch sloppy code before it ships",
5
5
  "main": "index.js",
6
6
  "bin": {