Skip to content

Commit 0b947ce

Browse files
brtkwrclaude
andcommitted
feat: improved search and preview
- Search now includes session ID, timestamps, full cwd path - Preview shows First/Last activity timestamps with highlighting - Added --dump flag for debugging search lines - Positional arg pre-populates search (ccs buyer) - Args after -- passed to claude (ccs buyer -- --plan) - Use --exact and --no-sort for better result ordering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fcc2432 commit 0b947ce

3 files changed

Lines changed: 115 additions & 15 deletions

File tree

go.mod

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
11
module github.com/brtkwr/ccs
22

3-
go 1.21
3+
go 1.24.0
4+
5+
require (
6+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
7+
github.com/charmbracelet/bubbles v0.21.0 // indirect
8+
github.com/charmbracelet/bubbletea v1.3.10 // indirect
9+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
10+
github.com/charmbracelet/lipgloss v1.1.0 // indirect
11+
github.com/charmbracelet/x/ansi v0.10.1 // indirect
12+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
13+
github.com/charmbracelet/x/term v0.2.1 // indirect
14+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
15+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
16+
github.com/mattn/go-isatty v0.0.20 // indirect
17+
github.com/mattn/go-localereader v0.0.1 // indirect
18+
github.com/mattn/go-runewidth v0.0.16 // indirect
19+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
20+
github.com/muesli/cancelreader v0.2.2 // indirect
21+
github.com/muesli/termenv v0.16.0 // indirect
22+
github.com/rivo/uniseg v0.4.7 // indirect
23+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
24+
golang.org/x/sys v0.36.0 // indirect
25+
golang.org/x/text v0.3.8 // indirect
26+
)

go.sum

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
2+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3+
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
4+
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
5+
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
6+
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
7+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
8+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
9+
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
10+
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
11+
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
12+
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
13+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
14+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
15+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
16+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
17+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
18+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
19+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
20+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
21+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
22+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
23+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
24+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
25+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
26+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
27+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
28+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
29+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
30+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
31+
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
32+
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
33+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
34+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
35+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
36+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
37+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
38+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
41+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
42+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
43+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=

main.go

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
"time"
1616
)
1717

18-
const version = "0.3.1"
18+
const version = "0.4.0"
1919

2020
// Message represents a conversation message
2121
type Message struct {
@@ -270,15 +270,18 @@ func buildSearchLines(conversations []Conversation) ([]string, map[string]Conver
270270
}
271271

272272
displayText := truncate(firstUserMsg.Text, 100)
273-
searchText := strings.Join(strings.Fields(strings.Join(allUserText, " ")), " ")
274-
ts := formatTimestamp(conv.LastTimestamp)
273+
firstTs := formatTimestamp(conv.FirstTimestamp)
274+
lastTs := formatTimestamp(conv.LastTimestamp)
275+
// Include session ID, timestamps, project/cwd, and all user messages in search text
276+
allSearchText := append([]string{conv.SessionID, firstTs, lastTs, conv.Cwd, project}, allUserText...)
277+
searchText := strings.Join(strings.Fields(strings.Join(allSearchText, " ")), " ")
275278
projectPad := padOrTruncate(project, 25)
276279

277280
// Format: id \t date \t project \t display_message \t search_text
281+
// search_text hidden with zero-width or minimal display
278282
// Colors: date=dim, project=yellow/bold, message=white
279-
// search_text is hidden (column 5) but used for matching
280283
line := fmt.Sprintf("%s\t\033[90m%s\033[0m\t\033[1;33m%s\033[0m\t%s\t%s",
281-
conv.SessionID, ts, projectPad, displayText, searchText)
284+
conv.SessionID, lastTs, projectPad, displayText, searchText)
282285
lines = append(lines, line)
283286
}
284287

@@ -368,8 +371,10 @@ func showPreview(line, query string) {
368371
return
369372
}
370373

371-
fmt.Printf("\033[1;33mProject:\033[0m %s\n", conv.Cwd)
372-
fmt.Printf("\033[1;33mSession:\033[0m %s\n", sessionID)
374+
fmt.Printf("\033[1;33mProject:\033[0m %s\n", highlight(conv.Cwd, query))
375+
fmt.Printf("\033[1;33mSession:\033[0m %s\n", highlight(sessionID, query))
376+
fmt.Printf("\033[1;33mFirst activity:\033[0m %s\n", highlight(formatTimestamp(conv.FirstTimestamp), query))
377+
fmt.Printf("\033[1;33mLast activity:\033[0m %s\n", highlight(formatTimestamp(conv.LastTimestamp), query))
373378
fmt.Printf("\033[1;33mTotal messages:\033[0m %d\n\n", len(conv.Messages))
374379

375380
// Find all messages containing the query
@@ -507,10 +512,36 @@ func main() {
507512
return
508513
}
509514

515+
// Debug mode - dump search lines with optional filter highlight
516+
for i, arg := range args {
517+
if arg == "--dump" {
518+
filter := ""
519+
if i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
520+
filter = args[i+1]
521+
}
522+
conversations, _ := getConversations()
523+
lines, _ := buildSearchLines(conversations)
524+
for _, line := range lines {
525+
if filter != "" {
526+
line = highlight(line, filter)
527+
}
528+
fmt.Println(line)
529+
}
530+
return
531+
}
532+
}
533+
534+
// Parse ccs args: positional arg is filter, args after -- go to claude
535+
// Usage: ccs [filter] [-- claude-args...]
510536
var claudeFlags []string
511-
for _, arg := range args {
512-
if strings.HasPrefix(arg, "-") {
513-
claudeFlags = append(claudeFlags, arg)
537+
var filterQuery string
538+
for i, arg := range args {
539+
if arg == "--" {
540+
claudeFlags = args[i+1:]
541+
break
542+
}
543+
if !strings.HasPrefix(arg, "-") && filterQuery == "" {
544+
filterQuery = arg
514545
}
515546
}
516547

@@ -552,11 +583,10 @@ func main() {
552583

553584
self, _ := os.Executable()
554585

555-
cmd := exec.Command("fzf",
586+
fzfArgs := []string{
556587
"--ansi",
557588
"--delimiter=\t",
558-
"--with-nth=2,3,4",
559-
"--nth=2..",
589+
"--exact",
560590
"--no-sort",
561591
"--tabstop=4",
562592
"--preview", fmt.Sprintf("%s --preview {} {q}", self),
@@ -567,8 +597,12 @@ func main() {
567597
"--layout=reverse",
568598
"--border=rounded",
569599
"--info=inline",
570-
)
600+
}
601+
if filterQuery != "" {
602+
fzfArgs = append(fzfArgs, "--query", filterQuery)
603+
}
571604

605+
cmd := exec.Command("fzf", fzfArgs...)
572606
cmd.Stdin = strings.NewReader(strings.Join(lines, "\n"))
573607
cmd.Stderr = os.Stderr
574608

0 commit comments

Comments
 (0)