Detailed changes
@@ -655,6 +655,14 @@
"created_at": "2025-09-20T12:37:42Z",
"repoId": 987670088,
"pullRequestNo": 1095
+ },
+ {
+ "name": "Kaneki-x",
+ "id": 6857108,
+ "comment_id": 3338743039,
+ "created_at": "2025-09-26T13:30:16Z",
+ "repoId": 987670088,
+ "pullRequestNo": 1135
}
]
}
@@ -18,6 +18,9 @@ updates:
patterns:
- "*"
ignore:
+ - dependency-name: github.com/charmbracelet/bubbletea/v2
+ versions:
+ - v2.0.0-beta1
- dependency-name: github.com/charmbracelet/lipgloss/v2
versions:
- v2.0.0-beta1
@@ -153,7 +153,7 @@ require (
golang.org/x/text v0.29.0
golang.org/x/time v0.8.0 // indirect
google.golang.org/api v0.211.0 // indirect
- google.golang.org/genai v1.25.0
+ google.golang.org/genai v1.26.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
@@ -427,8 +427,8 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.211.0 h1:IUpLjq09jxBSV1lACO33CGY3jsRcbctfGzhj+ZSE/Bg=
google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0=
-google.golang.org/genai v1.25.0 h1:Cpyh2nmEoOS1eM3mT9XKuA/qWTEDoktfP2gsN3EduPE=
-google.golang.org/genai v1.25.0/go.mod h1:OClfdf+r5aaD+sCd4aUSkPzJItmg2wD/WON9lQnRPaY=
+google.golang.org/genai v1.26.0 h1:r4HGL54kFv/WCRMTAbZg05Ct+vXfhAbTRlXhFyBkEQo=
+google.golang.org/genai v1.26.0/go.mod h1:OClfdf+r5aaD+sCd4aUSkPzJItmg2wD/WON9lQnRPaY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
@@ -9,7 +9,6 @@ import (
"runtime"
"github.com/charmbracelet/crush/internal/version"
- "github.com/denisbrodbeck/machineid"
"github.com/posthog/posthog-go"
)
@@ -39,6 +38,7 @@ func Init() {
slog.Error("Failed to initialize PostHog client", "error", err)
}
client = c
+ distinctId = getDistinctId()
}
// send logs an event to PostHog with the given event name and properties.
@@ -47,7 +47,7 @@ func send(event string, props ...any) {
return
}
err := client.Enqueue(posthog.Capture{
- DistinctId: distinctId(),
+ DistinctId: distinctId,
Event: event,
Properties: pairsToProps(props...).Merge(baseProps),
})
@@ -105,11 +105,3 @@ func pairsToProps(props ...any) posthog.Properties {
func isEven(n int) bool {
return n%2 == 0
}
-
-func distinctId() string {
- id, err := machineid.ProtectedID("charm")
- if err != nil {
- return "crush-cli"
- }
- return id
-}
@@ -0,0 +1,49 @@
+package event
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "net"
+
+ "github.com/denisbrodbeck/machineid"
+)
+
+var distinctId string
+
+const (
+ hashKey = "charm"
+ fallbackId = "unknown"
+)
+
+func getDistinctId() string {
+ if id, err := machineid.ProtectedID(hashKey); err == nil {
+ return id
+ }
+ if macAddr, err := getMacAddr(); err == nil {
+ return hashString(macAddr)
+ }
+ return fallbackId
+}
+
+func getMacAddr() (string, error) {
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ return "", err
+ }
+ for _, iface := range interfaces {
+ if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 && len(iface.HardwareAddr) > 0 {
+ if addrs, err := iface.Addrs(); err == nil && len(addrs) > 0 {
+ return iface.HardwareAddr.String(), nil
+ }
+ }
+ }
+ return "", fmt.Errorf("no active interface with mac address found")
+}
+
+func hashString(str string) string {
+ hash := hmac.New(sha256.New, []byte(str))
+ hash.Write([]byte(hashKey))
+ return hex.EncodeToString(hash.Sum(nil))
+}
@@ -233,9 +233,9 @@ func updateMCPState(name string, state MCPState, err error, client *client.Clien
// CloseMCPClients closes all MCP clients. This should be called during application shutdown.
func CloseMCPClients() error {
var errs []error
- for c := range mcpClients.Seq() {
+ for name, c := range mcpClients.Seq2() {
if err := c.Close(); err != nil {
- errs = append(errs, err)
+ errs = append(errs, fmt.Errorf("close mcp: %s: %w", name, err))
}
}
mcpBroker.Shutdown()
@@ -350,29 +350,6 @@ func (c *Client) NotifyChange(ctx context.Context, filepath string) error {
return c.client.NotifyDidChangeTextDocument(ctx, uri, int(fileInfo.Version), changes)
}
-// CloseFile closes a file in the LSP server.
-//
-// NOTE: this is only ever called on LSP shutdown.
-func (c *Client) CloseFile(ctx context.Context, filepath string) error {
- uri := string(protocol.URIFromPath(filepath))
-
- if _, exists := c.openFiles.Get(uri); !exists {
- return nil // Already closed
- }
-
- if c.cfg.Options.DebugLSP {
- slog.Debug("Closing file", "file", filepath)
- }
-
- if err := c.client.NotifyDidCloseTextDocument(ctx, uri); err != nil {
- return err
- }
-
- c.openFiles.Del(uri)
-
- return nil
-}
-
// IsFileOpen checks if a file is currently open.
func (c *Client) IsFileOpen(filepath string) bool {
uri := string(protocol.URIFromPath(filepath))
@@ -382,29 +359,16 @@ func (c *Client) IsFileOpen(filepath string) bool {
// CloseAllFiles closes all currently open files.
func (c *Client) CloseAllFiles(ctx context.Context) {
- filesToClose := make([]string, 0, c.openFiles.Len())
-
- // First collect all URIs that need to be closed
+ debugLSP := c.cfg != nil && c.cfg.Options.DebugLSP
for uri := range c.openFiles.Seq2() {
- // Convert URI back to file path using proper URI handling
- filePath, err := protocol.DocumentURI(uri).Path()
- if err != nil {
- slog.Error("Failed to convert URI to path for file closing", "uri", uri, "error", err)
- continue
+ if debugLSP {
+ slog.Debug("Closing file", "file", uri)
}
- filesToClose = append(filesToClose, filePath)
- }
-
- // Then close them all
- for _, filePath := range filesToClose {
- err := c.CloseFile(ctx, filePath)
- if err != nil && c.cfg != nil && c.cfg.Options.DebugLSP {
- slog.Warn("Error closing file", "file", filePath, "error", err)
+ if err := c.client.NotifyDidCloseTextDocument(ctx, uri); err != nil {
+ slog.Warn("Error closing rile", "uri", uri, "error", err)
+ continue
}
- }
-
- if c.cfg != nil && c.cfg.Options.DebugLSP {
- slog.Debug("Closed all files", "files", filesToClose)
+ c.openFiles.Del(uri)
}
}