Merge branch 'main' into ui

Ayman Bagabas created

Change summary

.github/cla-signatures.json                   |  8 ++++
.github/workflows/nightly.yml                 |  2 
.github/workflows/schema-update.yml           |  4 +-
crush.json                                    | 36 ++++++++++++++++++++
internal/agent/tools/edit.go                  |  8 ++--
internal/agent/tools/multiedit.go             |  6 +-
internal/agent/tools/write.go                 |  4 +-
internal/lsp/client.go                        |  2 
internal/tui/components/core/status/status.go |  6 ++
internal/tui/tui.go                           |  4 +-
internal/tui/util/util.go                     |  1 
11 files changed, 64 insertions(+), 17 deletions(-)

Detailed changes

.github/cla-signatures.json 🔗

@@ -871,6 +871,14 @@
       "created_at": "2025-11-19T15:59:07Z",
       "repoId": 987670088,
       "pullRequestNo": 1478
+    },
+    {
+      "name": "heimoshuiyu",
+      "id": 22657774,
+      "comment_id": 3565689668,
+      "created_at": "2025-11-22T05:23:17Z",
+      "repoId": 987670088,
+      "pullRequestNo": 1496
     }
   ]
 }

.github/workflows/nightly.yml 🔗

@@ -11,7 +11,7 @@ jobs:
     outputs:
       should_run: ${{ steps.check.outputs.should_run }}
     steps:
-      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
         with:
           fetch-depth: 1
       - id: check

.github/workflows/schema-update.yml 🔗

@@ -10,10 +10,10 @@ jobs:
   update-schema:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
         with:
           token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
-      - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
+      - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
         with:
           go-version-file: go.mod
       - run: go run . schema > ./schema.json

crush.json 🔗

@@ -1,6 +1,40 @@
 {
   "$schema": "https://charm.land/crush.json",
   "lsp": {
-    "gopls": {}
+    "gopls": {
+      "options": {
+        "gofumpt": true,
+        "codelenses": {
+          "gc_details": true,
+          "generate": true,
+          "run_govulncheck": true,
+          "test": true,
+          "tidy": true,
+          "upgrade_dependency": true
+        },
+        "hints": {
+          "assignVariableTypes": true,
+          "compositeLiteralFields": true,
+          "compositeLiteralTypes": true,
+          "constantValues": true,
+          "functionTypeParameters": true,
+          "parameterNames": true,
+          "rangeVariableTypes": true
+        },
+        "analyses": {
+          "nilness": true,
+          "unusedparams": true,
+          "unusedvariable": true,
+          "unusedwrite": true,
+          "useany": true
+        },
+        "staticcheck": true,
+        "directoryFilters": [
+          "-.git",
+          "-node_modules"
+        ],
+        "semanticTokens": true
+      }
+    }
   }
 }

internal/agent/tools/edit.go 🔗

@@ -163,7 +163,7 @@ func createNewFile(edit editContext, filePath, content string, call fantasy.Tool
 	_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, content)
 	if err != nil {
 		// Log error but don't fail the operation
-		slog.Debug("Error creating file history version", "error", err)
+		slog.Error("Error creating file history version", "error", err)
 	}
 
 	recordFileWrite(filePath)
@@ -290,13 +290,13 @@ func deleteContent(edit editContext, filePath, oldString string, replaceAll bool
 		// User Manually changed the content store an intermediate version
 		_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, oldContent)
 		if err != nil {
-			slog.Debug("Error creating file history version", "error", err)
+			slog.Error("Error creating file history version", "error", err)
 		}
 	}
 	// Store the new version
 	_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, "")
 	if err != nil {
-		slog.Debug("Error creating file history version", "error", err)
+		slog.Error("Error creating file history version", "error", err)
 	}
 
 	recordFileWrite(filePath)
@@ -431,7 +431,7 @@ func replaceContent(edit editContext, filePath, oldString, newString string, rep
 	// Store the new version
 	_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, newContent)
 	if err != nil {
-		slog.Debug("Error creating file history version", "error", err)
+		slog.Error("Error creating file history version", "error", err)
 	}
 
 	recordFileWrite(filePath)

internal/agent/tools/multiedit.go 🔗

@@ -196,7 +196,7 @@ func processMultiEditWithCreation(edit editContext, params MultiEditParams, call
 
 	_, err = edit.files.CreateVersion(edit.ctx, sessionID, params.FilePath, currentContent)
 	if err != nil {
-		slog.Debug("Error creating file history version", "error", err)
+		slog.Error("Error creating file history version", "error", err)
 	}
 
 	recordFileWrite(params.FilePath)
@@ -338,14 +338,14 @@ func processMultiEditExistingFile(edit editContext, params MultiEditParams, call
 		// User manually changed the content, store an intermediate version
 		_, err = edit.files.CreateVersion(edit.ctx, sessionID, params.FilePath, oldContent)
 		if err != nil {
-			slog.Debug("Error creating file history version", "error", err)
+			slog.Error("Error creating file history version", "error", err)
 		}
 	}
 
 	// Store the new version
 	_, err = edit.files.CreateVersion(edit.ctx, sessionID, params.FilePath, currentContent)
 	if err != nil {
-		slog.Debug("Error creating file history version", "error", err)
+		slog.Error("Error creating file history version", "error", err)
 	}
 
 	recordFileWrite(params.FilePath)

internal/agent/tools/write.go 🔗

@@ -147,13 +147,13 @@ func NewWriteTool(lspClients *csync.Map[string, *lsp.Client], permissions permis
 				// User Manually changed the content store an intermediate version
 				_, err = files.CreateVersion(ctx, sessionID, filePath, oldContent)
 				if err != nil {
-					slog.Debug("Error creating file history version", "error", err)
+					slog.Error("Error creating file history version", "error", err)
 				}
 			}
 			// Store the new version
 			_, err = files.CreateVersion(ctx, sessionID, filePath, params.Content)
 			if err != nil {
-				slog.Debug("Error creating file history version", "error", err)
+				slog.Error("Error creating file history version", "error", err)
 			}
 
 			recordFileWrite(filePath)

internal/lsp/client.go 🔗

@@ -417,7 +417,7 @@ func (c *Client) openKeyConfigFiles(ctx context.Context) {
 		if _, err := os.Stat(file); err == nil {
 			// File exists, try to open it
 			if err := c.OpenFile(ctx, file); err != nil {
-				slog.Debug("Failed to open key config file", "file", file, "error", err)
+				slog.Error("Failed to open key config file", "file", file, "error", err)
 			} else {
 				slog.Debug("Opened key config file for initialization", "file", file)
 			}

internal/tui/components/core/status/status.go 🔗

@@ -82,7 +82,11 @@ func (m *statusCmp) infoMsg() string {
 		info := ansi.Truncate(m.info.Msg, widthLeft, "…")
 		message = t.S().Base.Foreground(t.BgOverlay).Width(widthLeft+2).Background(t.Warning).Padding(0, 1).Render(info)
 	default:
-		infoType = t.S().Base.Foreground(t.BgSubtle).Background(t.Green).Padding(0, 1).Bold(true).Render("HEY!")
+		note := "OKAY!"
+		if m.info.Type == util.InfoTypeUpdate {
+			note = "HEY!"
+		}
+		infoType = t.S().Base.Foreground(t.BgSubtle).Background(t.Green).Padding(0, 1).Bold(true).Render(note)
 		widthLeft := m.width - (lipgloss.Width(infoType) + 2)
 		info := ansi.Truncate(m.info.Msg, widthLeft, "…")
 		message = t.S().Base.Background(t.GreenDark).Width(widthLeft+2).Foreground(t.BgSubtle).Padding(0, 1).Render(info)

internal/tui/tui.go 🔗

@@ -380,9 +380,9 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			statusMsg = fmt.Sprintf("This is a development version of Crush. The latest version is v%s.", msg.LatestVersion)
 		}
 		s, statusCmd := a.status.Update(util.InfoMsg{
-			Type: util.InfoTypeInfo,
+			Type: util.InfoTypeUpdate,
 			Msg:  statusMsg,
-			TTL:  30 * time.Second,
+			TTL:  10 * time.Second,
 		})
 		a.status = s.(status.StatusCmp)
 		return a, statusCmd

internal/tui/util/util.go 🔗

@@ -38,6 +38,7 @@ const (
 	InfoTypeSuccess
 	InfoTypeWarn
 	InfoTypeError
+	InfoTypeUpdate
 )
 
 func ReportInfo(info string) tea.Cmd {