aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-30 13:03:11 +0000
committerFuwn <[email protected]>2026-01-30 13:03:11 +0000
commit52e13143420cec1dd54d6bae7e763e7186f97634 (patch)
treed062279807e06d03d00d0c6d69e11b30ddb5be54
parentfix(claude:session): Handle empty session index (diff)
downloadfaustus-52e13143420cec1dd54d6bae7e763e7186f97634.tar.xz
faustus-52e13143420cec1dd54d6bae7e763e7186f97634.zip
format: Apply Iku formatting
-rw-r--r--internal/app/model.go11
-rw-r--r--internal/app/preview.go6
-rw-r--r--internal/app/search.go3
-rw-r--r--internal/app/state.go3
-rw-r--r--internal/app/update.go33
-rw-r--r--internal/app/view.go10
-rw-r--r--internal/claude/preview.go5
-rw-r--r--internal/claude/search.go5
-rw-r--r--internal/claude/session.go13
-rw-r--r--main.go4
10 files changed, 12 insertions, 81 deletions
diff --git a/internal/app/model.go b/internal/app/model.go
index 0bfdba0..7a01cd6 100644
--- a/internal/app/model.go
+++ b/internal/app/model.go
@@ -1,12 +1,11 @@
package app
import (
- "time"
-
"github.com/Fuwn/faustus/internal/claude"
"github.com/Fuwn/faustus/internal/ui"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
+ "time"
)
type Tab int
@@ -71,29 +70,21 @@ type Model struct {
func NewModel(sessions []claude.Session) Model {
searchInput := textinput.New()
-
searchInput.Placeholder = "Filter sessions"
searchInput.CharLimit = 100
searchInput.Width = 40
-
renameInput := textinput.New()
-
renameInput.Placeholder = "Enter new name"
renameInput.CharLimit = 200
renameInput.Width = 60
-
deepSearchInput := textinput.New()
-
deepSearchInput.Placeholder = "Search all sessions"
deepSearchInput.CharLimit = 100
deepSearchInput.Width = 50
-
reassignInput := textinput.New()
-
reassignInput.Placeholder = "Enter new project path"
reassignInput.CharLimit = 500
reassignInput.Width = 80
-
model := Model{
sessions: sessions,
keys: ui.DefaultKeyMap(),
diff --git a/internal/app/preview.go b/internal/app/preview.go
index 8578808..95518fe 100644
--- a/internal/app/preview.go
+++ b/internal/app/preview.go
@@ -1,9 +1,8 @@
package app
import (
- "strings"
-
"github.com/Fuwn/faustus/internal/claude"
+ "strings"
)
func (m *Model) invalidatePreviewCache() {
@@ -61,12 +60,9 @@ func (m *Model) calculatePreviewMetrics() previewMetrics {
for _, previewMessage := range preview.Messages {
metrics.messageLines = append(metrics.messageLines, lineCount)
-
lineCount += 1
-
wrapped := wrapText(previewMessage.Content, width)
contentLines := strings.Count(wrapped, "\n") + 1
-
lineCount += contentLines
lineCount += 1
}
diff --git a/internal/app/search.go b/internal/app/search.go
index b4d3833..8f1d327 100644
--- a/internal/app/search.go
+++ b/internal/app/search.go
@@ -1,9 +1,8 @@
package app
import (
- "strings"
-
"github.com/Fuwn/faustus/internal/claude"
+ "strings"
)
func (m *Model) jumpToSearchResult() {
diff --git a/internal/app/state.go b/internal/app/state.go
index cebd672..6b24d80 100644
--- a/internal/app/state.go
+++ b/internal/app/state.go
@@ -1,10 +1,9 @@
package app
import (
+ "github.com/Fuwn/faustus/internal/claude"
"strings"
"time"
-
- "github.com/Fuwn/faustus/internal/claude"
)
func (m *Model) updateFiltered() {
diff --git a/internal/app/update.go b/internal/app/update.go
index eaadef9..752c874 100644
--- a/internal/app/update.go
+++ b/internal/app/update.go
@@ -2,12 +2,11 @@ package app
import (
"fmt"
- "time"
-
"github.com/Fuwn/faustus/internal/claude"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
+ "time"
)
func (m Model) Update(message tea.Msg) (tea.Model, tea.Cmd) {
@@ -17,7 +16,6 @@ func (m Model) Update(message tea.Msg) (tea.Model, tea.Cmd) {
m.height = typedMessage.Height
return m, nil
-
case tea.KeyMsg:
if time.Since(m.messageTime) > 3*time.Second {
m.message = ""
@@ -46,17 +44,14 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
switch {
case key.Matches(keyMessage, m.keys.Quit):
return m, tea.Quit
-
case key.Matches(keyMessage, m.keys.Help):
m.showHelp = !m.showHelp
-
case key.Matches(keyMessage, m.keys.Preview):
m.showPreview = !m.showPreview
m.previewFocus = false
m.previewScroll = 0
m.invalidatePreviewCache()
-
case key.Matches(keyMessage, m.keys.Up):
if m.showPreview && m.previewFocus {
m.previewScroll -= 1
@@ -68,7 +63,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Down):
if m.showPreview && m.previewFocus {
m.previewScroll += 1
@@ -80,7 +74,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.HalfUp):
if m.showPreview && m.previewFocus {
m.previewScroll -= 10
@@ -92,7 +85,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.HalfDown):
if m.showPreview && m.previewFocus {
m.previewScroll += 10
@@ -104,7 +96,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Top):
if m.showPreview && m.previewFocus {
m.previewScroll = 0
@@ -114,7 +105,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Bottom):
if m.showPreview && m.previewFocus {
m.previewScroll = 99999
@@ -126,7 +116,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.ensureVisible()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Tab):
if m.showPreview {
m.previewFocus = !m.previewFocus
@@ -143,7 +132,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.updateFiltered()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Left):
if m.tab != TabSessions {
m.tab = TabSessions
@@ -153,7 +141,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.updateFiltered()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Right):
if m.tab != TabTrash {
m.tab = TabTrash
@@ -163,14 +150,12 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.updateFiltered()
m.invalidatePreviewCache()
}
-
case key.Matches(keyMessage, m.keys.Search):
m.mode = ModeSearch
m.searchInput.Focus()
return m, textinput.Blink
-
case key.Matches(keyMessage, m.keys.Delete):
if len(m.filtered) > 0 {
if m.tab == TabTrash {
@@ -181,13 +166,11 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.mode = ModeConfirm
}
-
case key.Matches(keyMessage, m.keys.Restore):
if len(m.filtered) > 0 && m.tab == TabTrash {
m.confirmAction = ConfirmRestore
m.mode = ModeConfirm
}
-
case key.Matches(keyMessage, m.keys.Rename):
if len(m.filtered) > 0 {
session := &m.filtered[m.cursor]
@@ -199,7 +182,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, textinput.Blink
}
-
case key.Matches(keyMessage, m.keys.Reassign):
if len(m.filtered) > 0 {
session := &m.filtered[m.cursor]
@@ -212,7 +194,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, textinput.Blink
}
-
case key.Matches(keyMessage, m.keys.ReassignAll):
if len(m.filtered) > 0 {
session := &m.filtered[m.cursor]
@@ -225,13 +206,11 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, textinput.Blink
}
-
case key.Matches(keyMessage, m.keys.Clear):
if m.tab == TabTrash {
m.confirmAction = ConfirmEmptyTrash
m.mode = ModeConfirm
}
-
case key.Matches(keyMessage, m.keys.DeepSearch):
m.mode = ModeDeepSearch
@@ -239,7 +218,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.deepSearchInput.Focus()
return m, textinput.Blink
-
case key.Matches(keyMessage, m.keys.NextMatch):
if m.showPreview && m.previewFocus && len(m.previewSearchMatches) > 0 {
m.previewSearchIndex = (m.previewSearchIndex + 1) % len(m.previewSearchMatches)
@@ -250,7 +228,6 @@ func (m Model) handleNormalMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.jumpToSearchResult()
}
-
case key.Matches(keyMessage, m.keys.PrevMatch):
if m.showPreview && m.previewFocus && len(m.previewSearchMatches) > 0 {
m.previewSearchIndex -= 1
@@ -287,7 +264,6 @@ func (m Model) handleSearchMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.previewSearchMatches = nil
return m, nil
-
case key.Matches(keyMessage, m.keys.Enter):
m.mode = ModeNormal
@@ -336,7 +312,6 @@ func (m Model) handleDeepSearchMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd)
m.deepSearchInput.Blur()
return m, nil
-
case key.Matches(keyMessage, m.keys.Enter):
query := m.deepSearchInput.Value()
@@ -375,7 +350,6 @@ func (m Model) handleRenameMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.renameInput.Blur()
return m, nil
-
case key.Matches(keyMessage, m.keys.Enter):
if len(m.filtered) > 0 {
newName := m.renameInput.Value()
@@ -418,7 +392,6 @@ func (m Model) handleReassignMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.reassignInput.Blur()
return m, nil
-
case key.Matches(keyMessage, m.keys.Enter):
if len(m.filtered) > 0 {
newPath := m.reassignInput.Value()
@@ -471,7 +444,6 @@ func (m Model) handleConfirmMode(keyMessage tea.KeyMsg) (tea.Model, tea.Cmd) {
m.confirmAction = ConfirmNone
return m, nil
-
case key.Matches(keyMessage, m.keys.Confirm):
return m.executeConfirmedAction()
}
@@ -489,7 +461,6 @@ func (m Model) executeConfirmedAction() (tea.Model, tea.Cmd) {
m.reloadSessions()
}
}
-
case ConfirmRestore:
if session := m.selectedSession(); session != nil {
if restoreError := claude.RestoreFromTrash(session); restoreError != nil {
@@ -499,7 +470,6 @@ func (m Model) executeConfirmedAction() (tea.Model, tea.Cmd) {
m.reloadSessions()
}
}
-
case ConfirmPermanentDelete:
if session := m.selectedSession(); session != nil {
if deleteError := claude.PermanentlyDelete(session); deleteError != nil {
@@ -509,7 +479,6 @@ func (m Model) executeConfirmedAction() (tea.Model, tea.Cmd) {
m.reloadSessions()
}
}
-
case ConfirmEmptyTrash:
if emptyError := claude.EmptyTrash(); emptyError != nil {
m.setMessage(fmt.Sprintf("Error: %v", emptyError))
diff --git a/internal/app/view.go b/internal/app/view.go
index 1c7be10..1f9fb4b 100644
--- a/internal/app/view.go
+++ b/internal/app/view.go
@@ -2,12 +2,11 @@ package app
import (
"fmt"
- "strings"
- "time"
-
"github.com/Fuwn/faustus/internal/claude"
"github.com/Fuwn/faustus/internal/ui"
"github.com/charmbracelet/lipgloss"
+ "strings"
+ "time"
)
func (m Model) View() string {
@@ -168,7 +167,6 @@ func (m Model) renderSessionCompact(session *claude.Session, isSelected bool, ma
}
maxSummary := maxWidth - 4
-
summary = truncate(summary, maxSummary)
if isSelected {
@@ -194,12 +192,9 @@ func (m Model) renderPreview(width, height int) string {
if m.cursor < len(m.filtered) {
session := &m.filtered[m.cursor]
header := ui.PreviewHeaderStyle.Render(truncate(session.Summary, width-4))
-
lines = append(lines, header)
-
meta := ui.MetaStyle.Render(fmt.Sprintf("%s • %s • %d messages",
session.ProjectName, formatTime(session.Modified), len(preview.Messages)))
-
lines = append(lines, meta)
lines = append(lines, ui.PreviewDividerStyle.Render(strings.Repeat("─", width-4)))
lines = append(lines, "")
@@ -252,7 +247,6 @@ func (m Model) renderPreview(width, height int) string {
}
lines = append(lines, roleStyle.Render(prefix+":")+matchIndicator)
-
content := previewMessage.Content
if m.previewSearchQuery != "" && isMatch {
diff --git a/internal/claude/preview.go b/internal/claude/preview.go
index 1ea08c1..01ab906 100644
--- a/internal/claude/preview.go
+++ b/internal/claude/preview.go
@@ -74,7 +74,6 @@ func LoadSessionPreview(session *Session, maxMessages int) PreviewContent {
}
parsedMessages := parseRawMessage(rawMessage)
-
messages = append(messages, parsedMessages...)
}
@@ -109,7 +108,6 @@ func parseRawMessage(rawMessage RawMessage) []PreviewMessage {
if content != "" {
result = append(result, PreviewMessage{Role: "user", Content: content})
}
-
case "assistant":
var assistantMessage AssistantMessage
@@ -129,7 +127,6 @@ func parseRawMessage(rawMessage RawMessage) []PreviewMessage {
if text != "" {
result = append(result, PreviewMessage{Role: "assistant", Content: text})
}
-
case "tool_use":
toolInfo := contentBlock.Name
@@ -150,7 +147,6 @@ func parseRawMessage(rawMessage RawMessage) []PreviewMessage {
} else if filePath, exists := inputMap["file_path"]; exists {
if filePathString, isString := filePath.(string); isString {
pathParts := strings.Split(filePathString, "/")
-
toolInfo += ": " + pathParts[len(pathParts)-1]
}
}
@@ -158,7 +154,6 @@ func parseRawMessage(rawMessage RawMessage) []PreviewMessage {
result = append(result, PreviewMessage{Role: "tool", Content: toolInfo})
}
-
case "thinking":
thinking := contentBlock.Thinking
diff --git a/internal/claude/search.go b/internal/claude/search.go
index c79f871..7959983 100644
--- a/internal/claude/search.go
+++ b/internal/claude/search.go
@@ -27,7 +27,6 @@ func SearchAllSessions(sessions []Session, query string) []SearchResult {
for sessionIndex := range sessions {
session := &sessions[sessionIndex]
matches := searchSession(session, query)
-
results = append(results, matches...)
}
@@ -66,7 +65,6 @@ func searchSession(session *Session, query string) []SearchResult {
}
matches := searchRawMessage(session, &rawMessage, query, messageIndex)
-
results = append(results, matches...)
if rawMessage.Type == "user" || rawMessage.Type == "assistant" {
@@ -92,7 +90,6 @@ func searchRawMessage(session *Session, rawMessage *RawMessage, query string, me
if matchPosition := strings.Index(contentLowercase, query); matchPosition != -1 {
content := matchContext(userMessage.Content, matchPosition, len(query))
-
results = append(results, SearchResult{
Session: session,
MessageIndex: messageIndex,
@@ -101,7 +98,6 @@ func searchRawMessage(session *Session, rawMessage *RawMessage, query string, me
MatchPosition: matchPosition,
})
}
-
case "assistant":
var assistantMessage AssistantMessage
@@ -115,7 +111,6 @@ func searchRawMessage(session *Session, rawMessage *RawMessage, query string, me
if matchPosition := strings.Index(textLowercase, query); matchPosition != -1 {
content := matchContext(contentBlock.Text, matchPosition, len(query))
-
results = append(results, SearchResult{
Session: session,
MessageIndex: messageIndex,
diff --git a/internal/claude/session.go b/internal/claude/session.go
index c2f191b..4f14cdd 100644
--- a/internal/claude/session.go
+++ b/internal/claude/session.go
@@ -21,9 +21,8 @@ type Session struct {
GitBranch string `json:"gitBranch"`
ProjectPath string `json:"projectPath"`
IsSidechain bool `json:"isSidechain"`
-
- ProjectName string `json:"-"`
- InTrash bool `json:"-"`
+ ProjectName string `json:"-"`
+ InTrash bool `json:"-"`
}
type SessionIndex struct {
@@ -333,7 +332,6 @@ func MoveToTrash(session *Session) error {
if _, statError := os.Stat(sourceAssociatedDirectory); statError == nil {
destinationAssociatedDirectory := filepath.Join(destinationProjectDirectory, session.SessionID)
-
_ = os.Rename(sourceAssociatedDirectory, destinationAssociatedDirectory)
}
@@ -371,7 +369,6 @@ func RestoreFromTrash(session *Session) error {
if _, statError := os.Stat(sourceAssociatedDirectory); statError == nil {
destinationAssociatedDirectory := filepath.Join(destinationProjectDirectory, session.SessionID)
-
_ = os.Rename(sourceAssociatedDirectory, destinationAssociatedDirectory)
}
@@ -393,7 +390,6 @@ func PermanentlyDelete(session *Session) error {
}
associatedDirectory := filepath.Join(projectDirectory, session.SessionID)
-
_ = os.RemoveAll(associatedDirectory)
return removeFromIndex(projectDirectory, session.SessionID)
@@ -555,14 +551,10 @@ func ReassignSessionPath(session *Session, newPath string) error {
}
oldIndexPath := filepath.Join(oldProjectDirectory, "sessions-index.json")
-
_ = removeFromIndex(oldProjectDirectory, session.SessionID)
-
newIndexPath := filepath.Join(newProjectDirectory, "sessions-index.json")
-
session.FullPath = newJsonlPath
session.ProjectPath = newPath
-
_ = addToIndexWithPath(newIndexPath, session, newPath)
if isEmpty, _ := isDirectoryEmpty(oldProjectDirectory); isEmpty {
@@ -769,6 +761,7 @@ func updateJsonlProjectPath(filePath, newPath string) error {
}
lines := strings.Split(string(fileData), "\n")
+
var updatedLines []string
for _, line := range lines {
diff --git a/main.go b/main.go
index 0a50f07..4ed2275 100644
--- a/main.go
+++ b/main.go
@@ -2,15 +2,15 @@ package main
import (
"fmt"
- "os"
-
"github.com/Fuwn/faustus/internal/app"
"github.com/Fuwn/faustus/internal/claude"
tea "github.com/charmbracelet/bubbletea"
+ "os"
)
func main() {
sessions, err := claude.LoadAllSessions()
+
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading sessions: %v\n", err)
os.Exit(1)