From 871eb5c10fbd973f567a1e57713b6f8330122dda Mon Sep 17 00:00:00 2001 From: brandonkachen Date: Tue, 16 Sep 2025 18:24:56 -0700 Subject: [PATCH 1/4] =?UTF-8?q?feat(agent/version):=20improve=20UX=20by=20?= =?UTF-8?q?surfacing=20per-version=20usage=20with=20a=20badge=20and=20metr?= =?UTF-8?q?ics;=20refine=20Run/Save=20button=20icons=20and=20prompts=20for?= =?UTF-8?q?=20clarity.\n\n=F0=9F=A4=96=20Generated=20with=20Codebuff\nCo-A?= =?UTF-8?q?uthored-By:=20Codebuff=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lock | 2 +- npm-app/src/index.ts | 12 +++++++-- .../[id]/agents/[agentId]/[version]/page.tsx | 26 ++++++++++++------- .../[agentId]/[version]/run-agent-button.tsx | 6 ++--- .../[agentId]/[version]/save-agent-button.tsx | 6 ++--- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/bun.lock b/bun.lock index c1e281bee7..d2c4cac144 100644 --- a/bun.lock +++ b/bun.lock @@ -236,7 +236,7 @@ }, "sdk": { "name": "@codebuff/sdk", - "version": "0.1.30", + "version": "0.1.31", "dependencies": { "@vscode/ripgrep": "1.15.14", "@vscode/tree-sitter-wasm": "0.1.4", diff --git a/npm-app/src/index.ts b/npm-app/src/index.ts index 8dd2505a1d..19ef1d2e46 100644 --- a/npm-app/src/index.ts +++ b/npm-app/src/index.ts @@ -240,13 +240,21 @@ For all commands and options, run 'codebuff' and then type 'help'. ) const initialInput = isCommand ? '' : filteredArgs.join(' ') + // Handle --agent flag by prefilling user input instead of directly invoking + let finalInitialInput = initialInput + if (options.agent && !initialInput) { + finalInitialInput = `@${options.agent}` + } else if (options.agent && initialInput) { + finalInitialInput = `@${options.agent} ${initialInput}` + } + codebuff({ - initialInput, + initialInput: finalInitialInput, git, costMode, runInitFlow: options.init, model: options.model, - agent: options.agent, + agent: undefined, // Don't pass agent to CLI - use prefilled input instead params: parsedAgentParams, print: options.print, cwd: options.cwd, diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx index a8da631167..569949e54f 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx @@ -16,6 +16,7 @@ import { AgentUsageMetrics } from './agent-usage-metrics' import { RunAgentButton } from './run-agent-button' import { CopyIdButton } from './copy-id-button' import { SaveAgentButton } from './save-agent-button' +import { VersionUsageBadge } from './version-usage-badge' import { Button } from '@/components/ui/button' interface AgentDetailPageProps { @@ -200,12 +201,6 @@ const AgentDetailPage = async ({ params }: AgentDetailPageProps) => { - {/* Usage Metrics */} -
{/* Version Navigation */}
@@ -236,9 +231,16 @@ const AgentDetailPage = async ({ params }: AgentDetailPageProps) => { className="w-full justify-start group transition-colors" >
- - v{version.version} - +
+ + v{version.version} + + +
{index === 0 && ( { {/* Agent Definition */}
+ {/* Usage Metrics */} + Agent Definition diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/run-agent-button.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/run-agent-button.tsx index 51278e688e..2c28409948 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/run-agent-button.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/run-agent-button.tsx @@ -1,6 +1,6 @@ 'use client' -import { Copy } from 'lucide-react' +import { Play } from 'lucide-react' import { Button } from '@/components/ui/button' import { toast } from '@/components/ui/use-toast' @@ -12,7 +12,7 @@ export function RunAgentButton({ agentId }: RunAgentButtonProps) { const handleCopy = () => { navigator.clipboard.writeText(`codebuff --agent ${agentId}`) toast({ - description: `Command copied to clipboard: "codebuff --agent ${agentId}"`, + description: `Command copied! Go to your terminal and paste to run this agent.`, }) } @@ -23,7 +23,7 @@ export function RunAgentButton({ agentId }: RunAgentButtonProps) { onClick={handleCopy} className="flex items-center gap-2" > - + Run this agent ) diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/save-agent-button.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/save-agent-button.tsx index 27a490ef5a..a00781a741 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/save-agent-button.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/save-agent-button.tsx @@ -1,6 +1,6 @@ 'use client' -import { Copy } from 'lucide-react' +import { Bookmark } from 'lucide-react' import { Button } from '@/components/ui/button' import { toast } from '@/components/ui/use-toast' @@ -12,7 +12,7 @@ export function SaveAgentButton({ agentId }: SaveAgentButtonProps) { const handleCopy = () => { navigator.clipboard.writeText(`codebuff save-agent ${agentId}`) toast({ - description: `Command copied to clipboard: "codebuff save-agent ${agentId}"`, + description: `Command copied! Go to your terminal and paste to save this agent to your project.`, }) } @@ -23,7 +23,7 @@ export function SaveAgentButton({ agentId }: SaveAgentButtonProps) { onClick={handleCopy} className="flex items-center gap-2" > - + Save this agent ) From d5e635ab5dc1ebb9711d25f977b3226646f60071 Mon Sep 17 00:00:00 2001 From: brandonkachen Date: Tue, 16 Sep 2025 18:27:15 -0700 Subject: [PATCH 2/4] feat(agent/version): surface per-version usage metrics in agent detail view to improve visibility. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with Codebuff Co-Authored-By: Codebuff --- .../[version]/version-usage-badge.tsx | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 web/src/app/publishers/[id]/agents/[agentId]/[version]/version-usage-badge.tsx diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/version-usage-badge.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/version-usage-badge.tsx new file mode 100644 index 0000000000..5c7256819b --- /dev/null +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/version-usage-badge.tsx @@ -0,0 +1,68 @@ +'use client' + +import { useQuery } from '@tanstack/react-query' +import { Badge } from '@/components/ui/badge' +import { Skeleton } from '@/components/ui/skeleton' + +interface VersionUsageBadgeProps { + publisherId: string + agentId: string + version: string +} + +interface AgentData { + id: string + publisher: { + id: string + } + version_stats?: Record< + string, + { + total_invocations: number + } + > +} + +const formatUsageCount = (count?: number) => { + if (!count) return '0' + if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M` + if (count >= 1000) return `${(count / 1000).toFixed(1)}K` + return count.toString() +} + +export const VersionUsageBadge = ({ + publisherId, + agentId, + version, +}: VersionUsageBadgeProps) => { + const { data: agents, isLoading } = useQuery({ + queryKey: ['agents'], + queryFn: async () => { + const response = await fetch('/api/agents') + if (!response.ok) { + throw new Error('Failed to fetch agents') + } + return await response.json() + }, + }) + + const agent = agents?.find( + (agent) => agent.id === agentId && agent.publisher.id === publisherId + ) + + const totalRuns = agent?.version_stats?.[version]?.total_invocations || 0 + + if (isLoading) { + return + } + + if (totalRuns === 0) { + return null + } + + return ( + + {formatUsageCount(totalRuns)} runs + + ) +} From 73fcf751740b42630ef7891b5981c23021b3baed Mon Sep 17 00:00:00 2001 From: brandonkachen Date: Tue, 16 Sep 2025 19:03:20 -0700 Subject: [PATCH 3/4] fix: make store page nicer --- .../[version]/agent-usage-metrics.tsx | 129 ++++--- .../[id]/agents/[agentId]/[version]/page.tsx | 37 +- web/src/app/store/page.tsx | 319 +++++++++--------- 3 files changed, 238 insertions(+), 247 deletions(-) diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/agent-usage-metrics.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/agent-usage-metrics.tsx index b83c470f95..3bb7fd2714 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/agent-usage-metrics.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/agent-usage-metrics.tsx @@ -2,7 +2,6 @@ import { useQuery } from '@tanstack/react-query' import { TrendingUp, Users, DollarSign, Play, Calendar } from 'lucide-react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' interface AgentUsageMetricsProps { @@ -89,21 +88,14 @@ export const AgentUsageMetrics = ({ if (isLoading) { return ( - - - Usage Metrics - - -
- {Array.from({ length: 4 }).map((_, i) => ( -
- - -
- ))} +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ +
- - + ))} +
) } @@ -112,68 +104,63 @@ export const AgentUsageMetrics = ({ } return ( - - - Usage Metrics - - -
-
-
- - - {formatCurrency(usageMetrics.weekly_spent)} - -
- Weekly Usage +
+
+
+
+ + + {formatCurrency(usageMetrics.weekly_spent)} +
-
-
- - {formatUsageCount(usageMetrics.usage_count)} -
- Total Runs + Weekly Usage +
+
+
+ + {formatUsageCount(usageMetrics.usage_count)}
-
-
- - {usageMetrics.unique_users || 0} -
- Unique Users + Total Runs +
+
+
+ + {usageMetrics.unique_users || 0}
-
-
- - - {formatCurrency(usageMetrics.avg_cost_per_invocation).replace( - '$', - '' - )} - -
- - Avg Cost per Run + Unique Users +
+
+
+ + + {formatCurrency(usageMetrics.avg_cost_per_invocation).replace( + '$', + '' + )}
+ + Avg Cost per Run +
- {usageMetrics.last_used && ( -
-
- - - Last used:{' '} - {new Date(usageMetrics.last_used).toLocaleDateString('en-US', { - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - })} - -
+
+ {usageMetrics.last_used && ( +
+
+ + + Last used:{' '} + {new Date(usageMetrics.last_used).toLocaleDateString('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + })} +
- )} - - +
+ )} +
) } diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx index 569949e54f..a2eadffbf4 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx @@ -262,23 +262,30 @@ const AgentDetailPage = async ({ params }: AgentDetailPageProps) => {
- {/* Agent Definition */} + {/* Agent Definition and Usage Stats Combined */}
- {/* Usage Metrics */} - - - Agent Definition -

- Complete agent data in TypeScript format -

-
- - + + {/* Usage Metrics for this version */} +
+

+ Usage Statistics + + v{params.version} + +

+ +
+ + {/* Agent Definition */} +
+

Definition

+ +
diff --git a/web/src/app/store/page.tsx b/web/src/app/store/page.tsx index a96c8ac505..de5c24105d 100644 --- a/web/src/app/store/page.tsx +++ b/web/src/app/store/page.tsx @@ -197,14 +197,6 @@ const AgentStorePage = () => { return count.toString() } - const isRecentlyUpdated = (createdAt: string) => { - const now = new Date() - const created = new Date(createdAt) - const timeDiff = now.getTime() - created.getTime() - const hoursDiff = timeDiff / (1000 * 3600) - return hoursDiff <= 24 - } - const AgentCard = ({ agent, isEditorsChoice = false, @@ -212,176 +204,181 @@ const AgentStorePage = () => { agent: AgentData isEditorsChoice?: boolean }) => ( - - + - {/* Header - Agent ID and Publisher */} - -
-
-
- - {agent.id} - - - v{agent.version} - -
e.preventDefault()}> - -
-
-
-
-
- -
-
-
-
-
- + {/* Editor's Choice Badge - Positioned absolutely for better visual hierarchy */} + {isEditorsChoice && ( +
+ - - - - {agent.publisher.name[0]?.toUpperCase() || - agent.publisher.id[0]?.toUpperCase()} - - - - @{agent.publisher.id} - - - {agent.publisher.verified && ( - - ✓ - - )} + + Editor's Choice +
-
- {agent.last_used && ( - - {formatRelativeTime(agent.last_used)} - - )} -
- {isRecentlyUpdated(agent.created_at) && ( + )} + + + {/* Header Section - Improved spacing and hierarchy */} +
+ {/* Agent Name and Version */} +
+
+

+ {agent.id} +

- Updated + v{agent.version} - )} - {isEditorsChoice && ( - + {/* Action buttons */} +
+
e.preventDefault()}> + { + navigator.clipboard.writeText( + `codebuff --agent ${agent.publisher.id}/${agent.id}@${agent.version}` + ) + toast({ + description: `Agent run command copied to clipboard!`, + }) + }} + className="p-2 hover:bg-muted/50 rounded-lg transition-all duration-200 opacity-60 group-hover:opacity-100" + title={`Copy: codebuff --agent ${agent.publisher.id}/${agent.id}@${agent.version}`} + > + + +
+ +
+
+ + {/* Publisher Info */} +
+ e.stopPropagation()} + > + + + + {agent.publisher.name[0]?.toUpperCase() || + agent.publisher.id[0]?.toUpperCase()} + + + + @{agent.publisher.id} + + {agent.publisher.verified && ( + + ✓ + + )} + + {agent.last_used && ( + - - Editor's Choice - + Used {formatRelativeTime(agent.last_used)} + )}
-
- - - {/* Single Row Metrics with Labels */} -
-
-
- - - {formatCurrency(agent.weekly_spent)} - + {/* Metrics Grid - Redesigned for better readability */} +
+
+
+ + + {formatCurrency(agent.weekly_spent)} + +
+

Weekly spend

- - Weekly spend - -
-
-
- - {formatUsageCount(agent.usage_count)} + +
+
+ + + {formatUsageCount(agent.usage_count)} + +
+

Weekly runs

- Weekly runs -
-
-
- - - {formatCurrency(agent.avg_cost_per_invocation).replace( - '$', - '' - )} - + +
+
+ + + {formatCurrency(agent.avg_cost_per_invocation)} + +
+

Per run

- Per run -
-
-
- - {agent.unique_users || 0} + +
+
+ + + {agent.unique_users || 0} + +
+

Users

- Users
-
- {/* Tags */} - {agent.tags && agent.tags.length > 0 && ( -
- {agent.tags.slice(0, 3).map((tag) => ( - - {tag} - - ))} - {agent.tags.length > 3 && ( - - +{agent.tags.length - 3} - - )} -
- )} - - - + {/* Tags - Improved design and spacing */} + {agent.tags && agent.tags.length > 0 && ( +
+
+ {agent.tags.slice(0, 4).map((tag) => ( + + {tag} + + ))} + {agent.tags.length > 4 && ( + + +{agent.tags.length - 4} + + )} +
+
+ )} + + + +
) return ( From fcef1a7c82b1367a99e5701de91101f07cf5c9cf Mon Sep 17 00:00:00 2001 From: brandonkachen Date: Wed, 17 Sep 2025 13:29:23 -0700 Subject: [PATCH 4/4] Update page.tsx --- .../[id]/agents/[agentId]/[version]/page.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx index a2eadffbf4..2ca0408b49 100644 --- a/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx +++ b/web/src/app/publishers/[id]/agents/[agentId]/[version]/page.tsx @@ -235,11 +235,13 @@ const AgentDetailPage = async ({ params }: AgentDetailPageProps) => { v{version.version} - + {index !== 0 && ( + + )}
{index === 0 && (