Skip to content

Commit 1e8521e

Browse files
GordonBeemingclaudegitbutler-client
authored
Clean up search results UI (#4)
Remove verbose diagnostic output (session counts, search patterns), filter system tags from session descriptions in the display layer, and split the selection prompt into a summary block (with descriptions and AI reasons) plus single-line selectable items so only the title line gets highlighted. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: GitButler <gitbutler@gitbutler.com>
1 parent 1c595ed commit 1e8521e

3 files changed

Lines changed: 57 additions & 32 deletions

File tree

claude-recall.sln

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.5.2.0
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
6+
EndProject
7+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClaudeRecall", "src\ClaudeRecall\ClaudeRecall.csproj", "{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2}"
8+
EndProject
9+
Global
10+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
11+
Debug|Any CPU = Debug|Any CPU
12+
Release|Any CPU = Release|Any CPU
13+
EndGlobalSection
14+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
15+
{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
16+
{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
17+
{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
18+
{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2}.Release|Any CPU.Build.0 = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(SolutionProperties) = preSolution
21+
HideSolutionNode = FALSE
22+
EndGlobalSection
23+
GlobalSection(NestedProjects) = preSolution
24+
{0F51B8F7-1C04-DE3D-A7F1-4B810CEA38E2} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
25+
EndGlobalSection
26+
GlobalSection(ExtensibilityGlobals) = postSolution
27+
SolutionGuid = {F0AA3B70-DD43-47B5-BD8A-9744B0C52E8A}
28+
EndGlobalSection
29+
EndGlobal

src/ClaudeRecall/Program.cs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -98,37 +98,22 @@ await AnsiConsole.Status()
9898
.Where(s => (s.LastTimestamp ?? s.FirstTimestamp ?? DateTimeOffset.MinValue) >= cutoff)
9999
.ToList();
100100

101-
if (verbose)
102-
{
103-
AnsiConsole.MarkupLine($"[grey]Found {sessions.Count} sessions across {sessions.Select(s => s.ProjectDir).Distinct().Count()} projects (last {days} days)[/]");
104-
}
105-
106101
// Step 2: Build chains
107102
var chains = ChainBuilder.Build(sessions);
108103

109-
if (verbose)
110-
{
111-
AnsiConsole.MarkupLine($"[grey]{chains.Count} session chains[/]");
112-
}
113-
114104
// Step 3: Generate search patterns
115105
List<string> patterns;
116106

117107
if (regexMode || noAi)
118108
{
119109
patterns = [query];
120-
if (verbose)
121-
AnsiConsole.MarkupLine($"[grey]Regex mode: searching for \"{Markup.Escape(query)}\"[/]");
122110
}
123111
else
124112
{
125113
patterns = await AnsiConsole.Status()
126114
.Spinner(Spinner.Known.Dots)
127115
.StartAsync("[blue]Generating search terms...[/]", async _ =>
128116
await ClaudeAiService.GenerateSearchTerms(query));
129-
130-
if (verbose)
131-
AnsiConsole.MarkupLine($"[grey]Search patterns: {string.Join(", ", patterns.Select(p => Markup.Escape(p)))}[/]");
132117
}
133118

134119
// Step 4: Search
@@ -142,11 +127,6 @@ await AnsiConsole.Status()
142127
results = SearchEngine.Search(chains, patterns);
143128
});
144129

145-
if (verbose)
146-
{
147-
AnsiConsole.MarkupLine($"[grey]{results.Count} matching chains[/]");
148-
}
149-
150130
// Step 5: AI validation (if enabled and we have results to narrow down)
151131
if (!regexMode && !noAi && results.Count > 3)
152132
{
@@ -234,6 +214,7 @@ await AnsiConsole.Status()
234214

235215
// Step 7: Display results
236216
SearchView.RenderResults(results, query, verbose);
217+
SearchView.RenderResultsSummary(results);
237218

238219
// Step 8: Interactive selection
239220
while (true)

src/ClaudeRecall/Tui/SearchView.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,8 @@ private static void RenderChainTree(SearchResult result, int index)
8383
AnsiConsole.Write(tree);
8484
}
8585

86-
public static int? PromptForAction(List<SearchResult> results)
86+
public static void RenderResultsSummary(List<SearchResult> results)
8787
{
88-
var choiceMap = new Dictionary<string, int>();
89-
var choiceList = new List<string>();
90-
9188
for (int i = 0; i < results.Count; i++)
9289
{
9390
var r = results[i];
@@ -99,18 +96,36 @@ private static void RenderChainTree(SearchResult result, int index)
9996
? first
10097
: $"{first} - {last}";
10198

102-
var line1 = $"#{i + 1} {Markup.Escape(title)} [grey]{dateInfo} ({chain.TotalMessages} msgs)[/]";
99+
AnsiConsole.MarkupLine($"[blue bold]#{i + 1}[/] [bold]{Markup.Escape(title)}[/] [grey]{dateInfo} ({chain.TotalMessages} msgs)[/]");
103100

104101
var description = GetChainDescription(chain, 200);
105-
var line2 = description is not null ? $" [grey]{Markup.Escape(description)}[/]" : "";
102+
if (description is not null)
103+
AnsiConsole.MarkupLine($" [grey]{Markup.Escape(description)}[/]");
104+
105+
if (r.AiReason is { Length: > 0 })
106+
AnsiConsole.MarkupLine($" [mediumpurple1]AI: {Markup.Escape(r.AiReason)}[/]");
107+
}
106108

107-
var aiReason = r.AiReason is { Length: > 0 } ? $" [mediumpurple1]AI: {Markup.Escape(r.AiReason)}[/]" : "";
109+
AnsiConsole.WriteLine();
110+
}
111+
112+
public static int? PromptForAction(List<SearchResult> results)
113+
{
114+
var choiceMap = new Dictionary<string, int>();
115+
var choiceList = new List<string>();
108116

109-
var parts = new List<string> { line1 };
110-
if (line2.Length > 0) parts.Add(line2);
111-
if (aiReason.Length > 0) parts.Add(aiReason);
117+
for (int i = 0; i < results.Count; i++)
118+
{
119+
var r = results[i];
120+
var chain = r.Chain;
121+
var title = GetSessionTitle(chain);
122+
var first = FormatFriendlyDate(chain.FirstTimestamp);
123+
var last = FormatFriendlyDate(chain.LastTimestamp);
124+
var dateInfo = chain.FirstTimestamp?.Date == chain.LastTimestamp?.Date
125+
? first
126+
: $"{first} - {last}";
112127

113-
var label = string.Join("\n", parts);
128+
var label = $"#{i + 1} {Markup.Escape(title)} [grey]{dateInfo} ({chain.TotalMessages} msgs)[/]";
114129
choiceList.Add(label);
115130
choiceMap[label] = i;
116131
}
@@ -143,7 +158,7 @@ private static string GetSessionTitle(SessionChain chain)
143158
{
144159
var firstMsg = chain.Sessions
145160
.Select(s => s.FirstUserMessage)
146-
.FirstOrDefault(m => m is not null);
161+
.FirstOrDefault(m => m is not null && !m.TrimStart().StartsWith('<'));
147162

148163
if (firstMsg is null) return null;
149164

0 commit comments

Comments
 (0)