@bahulam/code 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +6 -6
  3. package/README.md +10 -17
  4. package/package.json +9 -9
  5. package/src/agents/loader.mjs +1 -1
  6. package/src/agents/workflow_loader.mjs +2 -2
  7. package/src/auth/tarang-auth.mjs +3 -2
  8. package/src/config/model-catalog-default.json +4 -3
  9. package/src/config/model-catalog.mjs +2 -0
  10. package/src/context/prose-chunker.mjs +162 -5
  11. package/src/core/attachments.mjs +65 -3
  12. package/src/core/bundled-runtime.mjs +1 -1
  13. package/src/core/headless.mjs +14 -0
  14. package/src/core/jsonl-writer.mjs +3 -3
  15. package/src/core/lint-resolver.mjs +472 -0
  16. package/src/core/local-agent.mjs +15 -4
  17. package/src/core/local-store.mjs +4 -0
  18. package/src/core/output-filter.mjs +21 -25
  19. package/src/core/pricing.mjs +10 -3
  20. package/src/core/stream-client.mjs +9 -4
  21. package/src/core/tool-executor.mjs +105 -29
  22. package/src/daemon/http-dashboard.mjs +400 -0
  23. package/src/daemon/session-core.mjs +1 -0
  24. package/src/local-service/agent-relay.mjs +868 -0
  25. package/src/local-service/approval-bridge.mjs +222 -0
  26. package/src/local-service/browser.mjs +24 -0
  27. package/src/local-service/command.mjs +155 -0
  28. package/src/local-service/file-access.mjs +393 -0
  29. package/src/local-service/machine.mjs +86 -0
  30. package/src/local-service/paths.mjs +29 -0
  31. package/src/local-service/preview-converters.mjs +260 -0
  32. package/src/local-service/server.mjs +2644 -0
  33. package/src/local-service/session-store.mjs +221 -0
  34. package/src/onboarding/preflight.mjs +1 -1
  35. package/src/terminal/analytics.mjs +2 -6
  36. package/src/terminal/ansi.mjs +11 -3
  37. package/src/terminal/main.mjs +37 -11
  38. package/src/terminal/model-catalog-display.mjs +111 -0
  39. package/src/terminal/repl-format.mjs +4 -1
  40. package/src/terminal/repl-model-form.mjs +81 -14
  41. package/src/terminal/repl-render.mjs +35 -5
  42. package/src/terminal/repl-state.mjs +12 -0
  43. package/src/terminal/repl.mjs +231 -53
  44. package/src/terminal/tool-display.mjs +32 -0
  45. package/src/terminal/watch-state.mjs +118 -0
  46. package/src/tools/analyze-image.mjs +158 -0
  47. package/src/tools/bash.mjs +11 -9
  48. package/src/tools/generate-image.mjs +411 -0
  49. package/src/tools/lint.mjs +24 -43
  50. package/src/tools/registry.mjs +4 -0
  51. package/src/ui/icons.mjs +2 -0
  52. package/src/ui/palette.mjs +1 -1
  53. package/src/ui/slash-commands.mjs +4 -6
  54. package/src/ui/tool-card.mjs +7 -3
  55. package/pulse/app/activity/page.tsx +0 -190
  56. package/pulse/app/api/activity/route.ts +0 -138
  57. package/pulse/app/api/benchmark/route.ts +0 -113
  58. package/pulse/app/api/benchmarks/route.ts +0 -195
  59. package/pulse/app/api/costs/route.ts +0 -88
  60. package/pulse/app/api/export/route.ts +0 -77
  61. package/pulse/app/api/history/route.ts +0 -11
  62. package/pulse/app/api/import/route.ts +0 -31
  63. package/pulse/app/api/memory/route.ts +0 -50
  64. package/pulse/app/api/plans/route.ts +0 -9
  65. package/pulse/app/api/projects/[slug]/route.ts +0 -96
  66. package/pulse/app/api/projects/route.ts +0 -121
  67. package/pulse/app/api/sessions/[id]/replay/route.ts +0 -20
  68. package/pulse/app/api/sessions/[id]/route.ts +0 -31
  69. package/pulse/app/api/sessions/route.ts +0 -112
  70. package/pulse/app/api/settings/route.ts +0 -14
  71. package/pulse/app/api/stats/route.ts +0 -143
  72. package/pulse/app/api/todos/route.ts +0 -9
  73. package/pulse/app/api/tools/route.ts +0 -160
  74. package/pulse/app/benchmarks/page.tsx +0 -224
  75. package/pulse/app/costs/page.tsx +0 -179
  76. package/pulse/app/export/page.tsx +0 -465
  77. package/pulse/app/favicon.ico +0 -0
  78. package/pulse/app/globals.css +0 -263
  79. package/pulse/app/help/page.tsx +0 -143
  80. package/pulse/app/history/page.tsx +0 -157
  81. package/pulse/app/layout.tsx +0 -46
  82. package/pulse/app/memory/page.tsx +0 -365
  83. package/pulse/app/overview-client.tsx +0 -393
  84. package/pulse/app/page.tsx +0 -14
  85. package/pulse/app/plans/page.tsx +0 -308
  86. package/pulse/app/projects/[slug]/page.tsx +0 -390
  87. package/pulse/app/projects/page.tsx +0 -110
  88. package/pulse/app/sessions/[id]/page.tsx +0 -243
  89. package/pulse/app/sessions/page.tsx +0 -39
  90. package/pulse/app/settings/page.tsx +0 -188
  91. package/pulse/app/todos/page.tsx +0 -211
  92. package/pulse/app/tools/page.tsx +0 -249
  93. package/pulse/cli.js +0 -164
  94. package/pulse/components/activity/day-of-week-chart.tsx +0 -35
  95. package/pulse/components/activity/streak-card.tsx +0 -36
  96. package/pulse/components/costs/cache-efficiency-panel.tsx +0 -76
  97. package/pulse/components/costs/cost-by-project-chart.tsx +0 -48
  98. package/pulse/components/costs/cost-over-time-chart.tsx +0 -95
  99. package/pulse/components/costs/model-token-table.tsx +0 -60
  100. package/pulse/components/global-search.tsx +0 -193
  101. package/pulse/components/keyboard-nav-provider.tsx +0 -23
  102. package/pulse/components/layout/bottom-nav.tsx +0 -53
  103. package/pulse/components/layout/client-layout.tsx +0 -31
  104. package/pulse/components/layout/sidebar-context.tsx +0 -50
  105. package/pulse/components/layout/sidebar.tsx +0 -183
  106. package/pulse/components/layout/top-bar.tsx +0 -121
  107. package/pulse/components/overview/activity-heatmap.tsx +0 -107
  108. package/pulse/components/overview/conversation-table.tsx +0 -148
  109. package/pulse/components/overview/model-breakdown-donut.tsx +0 -95
  110. package/pulse/components/overview/peak-hours-chart.tsx +0 -87
  111. package/pulse/components/overview/project-activity-donut.tsx +0 -96
  112. package/pulse/components/overview/stat-card.tsx +0 -102
  113. package/pulse/components/overview/usage-over-time-chart.tsx +0 -166
  114. package/pulse/components/projects/project-card.tsx +0 -175
  115. package/pulse/components/sessions/replay/assistant-markdown.tsx +0 -94
  116. package/pulse/components/sessions/replay/compaction-card.tsx +0 -25
  117. package/pulse/components/sessions/replay/session-sidebar.tsx +0 -231
  118. package/pulse/components/sessions/replay/token-accumulation-chart.tsx +0 -98
  119. package/pulse/components/sessions/replay/tool-call-badge.tsx +0 -127
  120. package/pulse/components/sessions/replay/turn-cards.tsx +0 -220
  121. package/pulse/components/sessions/replay/user-tool-result.tsx +0 -158
  122. package/pulse/components/sessions/session-badges.tsx +0 -49
  123. package/pulse/components/sessions/session-table.tsx +0 -299
  124. package/pulse/components/theme-provider.tsx +0 -44
  125. package/pulse/components/tools/feature-adoption-table.tsx +0 -58
  126. package/pulse/components/tools/mcp-server-panel.tsx +0 -45
  127. package/pulse/components/tools/tool-ranking-chart.tsx +0 -57
  128. package/pulse/components/tools/version-history-table.tsx +0 -32
  129. package/pulse/components/ui/alert.tsx +0 -66
  130. package/pulse/components/ui/badge.tsx +0 -48
  131. package/pulse/components/ui/breadcrumb.tsx +0 -109
  132. package/pulse/components/ui/button.tsx +0 -64
  133. package/pulse/components/ui/calendar.tsx +0 -220
  134. package/pulse/components/ui/card.tsx +0 -92
  135. package/pulse/components/ui/command.tsx +0 -158
  136. package/pulse/components/ui/dialog.tsx +0 -158
  137. package/pulse/components/ui/input.tsx +0 -21
  138. package/pulse/components/ui/popover.tsx +0 -89
  139. package/pulse/components/ui/progress.tsx +0 -31
  140. package/pulse/components/ui/select.tsx +0 -190
  141. package/pulse/components/ui/separator.tsx +0 -28
  142. package/pulse/components/ui/sheet.tsx +0 -143
  143. package/pulse/components/ui/skeleton.tsx +0 -13
  144. package/pulse/components/ui/table.tsx +0 -116
  145. package/pulse/components/ui/tabs.tsx +0 -91
  146. package/pulse/components/ui/tooltip.tsx +0 -57
  147. package/pulse/components/use-global-keyboard-nav.ts +0 -79
  148. package/pulse/components.json +0 -23
  149. package/pulse/eslint.config.mjs +0 -18
  150. package/pulse/lib/bahulam-paths.ts +0 -23
  151. package/pulse/lib/claude-reader.ts +0 -592
  152. package/pulse/lib/decode.ts +0 -129
  153. package/pulse/lib/pricing.ts +0 -102
  154. package/pulse/lib/replay-parser.ts +0 -165
  155. package/pulse/lib/tool-categories.ts +0 -140
  156. package/pulse/lib/utils.ts +0 -6
  157. package/pulse/next-env.d.ts +0 -6
  158. package/pulse/next.config.ts +0 -16
  159. package/pulse/package.json +0 -45
  160. package/pulse/postcss.config.mjs +0 -7
  161. package/pulse/public/activity.png +0 -0
  162. package/pulse/public/cc-lens.png +0 -0
  163. package/pulse/public/command-k.png +0 -0
  164. package/pulse/public/costs.png +0 -0
  165. package/pulse/public/dashboard-dark.png +0 -0
  166. package/pulse/public/dashboard-white.png +0 -0
  167. package/pulse/public/export.png +0 -0
  168. package/pulse/public/file.svg +0 -1
  169. package/pulse/public/globe.svg +0 -1
  170. package/pulse/public/next.svg +0 -1
  171. package/pulse/public/projects.png +0 -0
  172. package/pulse/public/session-chat.png +0 -0
  173. package/pulse/public/todos.png +0 -0
  174. package/pulse/public/tools.png +0 -0
  175. package/pulse/public/vercel.svg +0 -1
  176. package/pulse/public/window.svg +0 -1
  177. package/pulse/tsconfig.json +0 -34
  178. package/pulse/types/claude.ts +0 -294
@@ -1,220 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import { ToolCallBadge } from './tool-call-badge'
5
- import { CompactionCard } from './compaction-card'
6
- import { AssistantMarkdown } from './assistant-markdown'
7
- import { UserToolResult } from './user-tool-result'
8
- import { formatCost, formatTokens, formatDurationMs } from '@/lib/decode'
9
- import type { ReplayTurn, CompactionEvent } from '@/types/claude'
10
- import { Badge } from '@/components/ui/badge'
11
- import { Button } from '@/components/ui/button'
12
- import { cn } from '@/lib/utils'
13
- import { ChevronDown, ChevronUp, Brain, Clock, Coins } from 'lucide-react'
14
-
15
- /** Show “Show more” when assistant text exceeds this length (markdown; avoid slicing mid-block). */
16
- const ASSISTANT_COLLAPSE_THRESHOLD = 900
17
-
18
- interface TurnCardProps {
19
- turn: ReplayTurn
20
- turnNumber: number
21
- compactionBefore?: CompactionEvent
22
- toolResults: Map<string, { content: string; is_error: boolean }>
23
- }
24
-
25
- function TokenBreakdown({ turn }: { turn: ReplayTurn }) {
26
- if (!turn.usage) return null
27
- const u = turn.usage
28
- const items = [
29
- u.input_tokens ? { label: 'In', value: u.input_tokens, color: 'var(--viz-sky)' } : null,
30
- u.output_tokens ? { label: 'Out', value: u.output_tokens, color: '#d97706' } : null,
31
- u.cache_creation_input_tokens ? { label: 'cW', value: u.cache_creation_input_tokens, color: '#a78bfa' } : null,
32
- u.cache_read_input_tokens ? { label: 'cR', value: u.cache_read_input_tokens, color: '#34d399' } : null,
33
- ].filter(Boolean) as { label: string; value: number; color: string }[]
34
-
35
- if (items.length === 0) return null
36
-
37
- return (
38
- <div className="flex items-center gap-1 flex-wrap">
39
- <Coins className="w-3 h-3 text-muted-foreground/50 shrink-0" />
40
- {items.map(({ label, value, color }) => (
41
- <span
42
- key={label}
43
- className="text-[11px] font-mono px-1.5 py-0.5 rounded border border-border/50 bg-muted/50"
44
- style={{ color }}
45
- >
46
- {label}:{formatTokens(value)}
47
- </span>
48
- ))}
49
- {turn.estimated_cost ? (
50
- <span className="text-[11px] font-mono text-[#d97706] px-1 py-0.5">
51
- {formatCost(turn.estimated_cost)}
52
- </span>
53
- ) : null}
54
- </div>
55
- )
56
- }
57
-
58
- export function UserTurnCard({ turn, compactionBefore, toolResults }: TurnCardProps) {
59
- return (
60
- <div>
61
- {compactionBefore && <CompactionCard event={compactionBefore} />}
62
-
63
- <div className="mb-5 flex flex-col items-end gap-1.5">
64
- {/* Timestamp label */}
65
- <span className="text-[11px] text-muted-foreground/40 pr-1">
66
- {new Date(turn.timestamp).toLocaleTimeString()}
67
- </span>
68
-
69
- {/* User bubble (right-aligned) */}
70
- {turn.text && (
71
- <div className="max-w-[85%] bg-primary/10 border border-primary/20 rounded-2xl rounded-tr-sm px-4 py-3">
72
- <p className="text-sm text-foreground/90 whitespace-pre-wrap leading-relaxed">
73
- {turn.text}
74
- </p>
75
- </div>
76
- )}
77
-
78
- {/* Tool results (user feedback) */}
79
- {turn.tool_results && turn.tool_results.length > 0 && (
80
- <div className="flex w-full max-w-[90%] flex-col gap-2">
81
- {turn.tool_results.map(r => (
82
- <UserToolResult key={r.tool_use_id} content={r.content} isError={r.is_error} />
83
- ))}
84
- </div>
85
- )}
86
- </div>
87
- </div>
88
- )
89
- }
90
-
91
- export function AssistantTurnCard({ turn, turnNumber, toolResults }: TurnCardProps) {
92
- const [thinkingOpen, setThinkingOpen] = useState(false)
93
- const [expanded, setExpanded] = useState(false)
94
-
95
- const modelShort = turn.model?.includes('opus-4-6') ? 'Opus 4.6'
96
- : turn.model?.includes('opus-4-5') ? 'Opus 4.5'
97
- : turn.model?.includes('opus-4') ? 'Opus 4'
98
- : turn.model?.includes('sonnet-4-6') ? 'Sonnet 4.6'
99
- : turn.model?.includes('sonnet-4-5') ? 'Sonnet 4.5'
100
- : turn.model?.includes('sonnet') ? 'Sonnet'
101
- : turn.model?.includes('haiku') ? 'Haiku'
102
- : turn.model ?? 'Claude'
103
-
104
- const textToShow = turn.text ?? ''
105
- const needsExpandToggle = textToShow.length > ASSISTANT_COLLAPSE_THRESHOLD
106
-
107
- return (
108
- <div className="mb-6 flex flex-col gap-1.5">
109
- {/* Header row */}
110
- <div className="flex items-center gap-2 flex-wrap">
111
- <div className="flex items-center gap-1.5">
112
- <div className="w-6 h-6 rounded-full bg-primary/20 border border-primary/30 flex items-center justify-center shrink-0">
113
- <span className="text-[10px] font-bold text-primary">C</span>
114
- </div>
115
- <span className="text-xs font-semibold text-primary/80">Claude</span>
116
- </div>
117
- <Badge variant="outline" className="text-[11px] px-1.5 py-0 h-5 font-mono">
118
- {modelShort}
119
- </Badge>
120
- <span className="text-[11px] text-muted-foreground/30">#{turnNumber}</span>
121
- {turn.turn_duration_ms && (
122
- <span className="text-[11px] text-muted-foreground/40 flex items-center gap-1">
123
- <Clock className="w-3 h-3" />
124
- {formatDurationMs(turn.turn_duration_ms)}
125
- </span>
126
- )}
127
- </div>
128
-
129
- {/* Thinking block */}
130
- {turn.has_thinking && (
131
- <div className="ml-8">
132
- <Button
133
- type="button"
134
- variant="ghost"
135
- size="sm"
136
- className="h-auto gap-1.5 px-2 py-1.5 text-xs font-medium text-indigo-700 hover:bg-indigo-500/10 hover:text-indigo-900 dark:text-indigo-400/90 dark:hover:text-indigo-300"
137
- onClick={() => setThinkingOpen(o => !o)}
138
- >
139
- <Brain className="h-3.5 w-3.5 shrink-0" />
140
- Extended thinking
141
- <ChevronDown
142
- className={cn('h-3.5 w-3.5 shrink-0 transition-transform duration-200', thinkingOpen && 'rotate-180')}
143
- />
144
- </Button>
145
- {thinkingOpen && turn.thinking_text && (
146
- <div className="mt-1 bg-indigo-50 border border-indigo-200/80 rounded-xl px-4 py-3 dark:bg-indigo-950/20 dark:border-indigo-800/25">
147
- <pre className="text-xs text-indigo-950/90 whitespace-pre-wrap max-h-56 overflow-auto leading-relaxed dark:text-indigo-200/50">
148
- {turn.thinking_text.slice(0, 3000)}
149
- {turn.thinking_text.length > 3000 && (
150
- <span className="text-indigo-400/40"> …[{(turn.thinking_text.length - 3000).toLocaleString()} more chars]</span>
151
- )}
152
- </pre>
153
- </div>
154
- )}
155
- </div>
156
- )}
157
-
158
- {/* Tool calls */}
159
- {turn.tool_calls && turn.tool_calls.length > 0 && (
160
- <div className="ml-8 space-y-1">
161
- {turn.tool_calls.map(tc => (
162
- <ToolCallBadge
163
- key={tc.id}
164
- tool={tc}
165
- result={toolResults.get(tc.id)}
166
- />
167
- ))}
168
- </div>
169
- )}
170
-
171
- {/* Response text bubble */}
172
- {textToShow && (
173
- <div className="ml-8">
174
- <div className="rounded-2xl rounded-tl-sm border border-border/60 bg-card px-4 py-3">
175
- <div
176
- className={cn(
177
- 'relative',
178
- needsExpandToggle && !expanded && 'max-h-112 overflow-hidden'
179
- )}
180
- >
181
- <AssistantMarkdown content={textToShow} />
182
- {needsExpandToggle && !expanded && (
183
- <div
184
- className="pointer-events-none absolute inset-x-0 bottom-0 h-14 bg-linear-to-t from-card to-transparent"
185
- aria-hidden
186
- />
187
- )}
188
- </div>
189
- {needsExpandToggle && (
190
- <Button
191
- type="button"
192
- variant="ghost"
193
- size="sm"
194
- className="mt-2 h-7 gap-1 px-2 text-xs text-muted-foreground hover:text-foreground"
195
- onClick={() => setExpanded(e => !e)}
196
- >
197
- {expanded ? (
198
- <>
199
- <ChevronUp className="h-3 w-3" /> Show less
200
- </>
201
- ) : (
202
- <>
203
- <ChevronDown className="h-3 w-3" /> Show full response
204
- </>
205
- )}
206
- </Button>
207
- )}
208
- </div>
209
- </div>
210
- )}
211
-
212
- {/* Token breakdown */}
213
- {turn.usage && (
214
- <div className="ml-8 mt-0.5">
215
- <TokenBreakdown turn={turn} />
216
- </div>
217
- )}
218
- </div>
219
- )
220
- }
@@ -1,158 +0,0 @@
1
- 'use client'
2
-
3
- import { cn } from '@/lib/utils'
4
- import { AlertCircle, CheckCircle2, FileEdit, FileText, Info } from 'lucide-react'
5
-
6
- export type ParsedToolResult =
7
- | { kind: 'file_updated'; path: string; note?: string }
8
- | { kind: 'file_written'; path: string; note?: string }
9
- | { kind: 'file_read'; path: string; note?: string }
10
- | { kind: 'plain'; text: string }
11
-
12
- function restAfterAction(s: string, idx: number, needleLen: number): string | undefined {
13
- let rest = s.slice(idx + needleLen).trim()
14
- rest = rest.replace(/^\.\s*/, '').trim()
15
- if (rest.startsWith('(') && rest.endsWith(')')) {
16
- rest = rest.slice(1, -1).trim()
17
- }
18
- return rest || undefined
19
- }
20
-
21
- /**
22
- * Best-effort parse of common Kepler / tool sandbox result strings.
23
- */
24
- export function parseToolResultMessage(raw: string): ParsedToolResult {
25
- const s = raw.trim()
26
- if (!s) return { kind: 'plain', text: raw }
27
-
28
- const prefix = 'The file '
29
-
30
- const needles: Array<{ needle: string; kind: 'file_updated' | 'file_written' | 'file_read' }> = [
31
- { needle: ' has been updated successfully', kind: 'file_updated' },
32
- { needle: ' has been written successfully', kind: 'file_written' },
33
- { needle: ' has been written.', kind: 'file_written' },
34
- { needle: ' was read successfully', kind: 'file_read' },
35
- { needle: ' has been read.', kind: 'file_read' },
36
- ]
37
-
38
- if (s.startsWith(prefix)) {
39
- for (const { needle, kind } of needles) {
40
- const i = s.indexOf(needle)
41
- if (i <= prefix.length) continue
42
- const path = s.slice(prefix.length, i).trim()
43
- if (!path) continue
44
- const note = restAfterAction(s, i, needle.length)
45
- if (kind === 'file_updated') return { kind: 'file_updated', path, note }
46
- if (kind === 'file_written') return { kind: 'file_written', path, note }
47
- return { kind: 'file_read', path, note }
48
- }
49
- }
50
-
51
- return { kind: 'plain', text: s }
52
- }
53
-
54
- function formatPathForUi(path: string, max = 100): string {
55
- if (path.length <= max) return path
56
- const parts = path.split('/')
57
- if (parts.length <= 2) return path.slice(0, max - 1) + '…'
58
- const file = parts[parts.length - 1] ?? path
59
- const start = parts.slice(0, 2).join('/')
60
- return `${start}/…/${file}`
61
- }
62
-
63
- interface Props {
64
- content: string
65
- isError: boolean
66
- }
67
-
68
- export function UserToolResult({ content, isError }: Props) {
69
- const parsed = parseToolResultMessage(content)
70
-
71
- if (isError) {
72
- return (
73
- <div className="flex gap-2.5 rounded-xl border border-red-500/25 bg-red-950/25 px-3 py-2.5 text-left">
74
- <AlertCircle className="mt-0.5 h-4 w-4 shrink-0 text-red-400" />
75
- <div className="min-w-0 flex-1">
76
- <p className="text-[11px] font-semibold uppercase tracking-wide text-red-400/90">Tool error</p>
77
- <pre className="mt-1 whitespace-pre-wrap wrap-break-word font-mono text-[12px] leading-relaxed text-red-200/90">
78
- {content}
79
- </pre>
80
- </div>
81
- </div>
82
- )
83
- }
84
-
85
- if (parsed.kind === 'file_updated') {
86
- return (
87
- <div className="flex gap-2.5 rounded-xl border border-emerald-500/20 bg-emerald-500/6 px-3 py-2.5 text-left">
88
- <FileEdit className="mt-0.5 h-4 w-4 shrink-0 text-emerald-500" />
89
- <div className="min-w-0 flex-1 space-y-1">
90
- <div className="flex flex-wrap items-center gap-1.5">
91
- <span className="text-[13px] font-medium text-foreground">File updated</span>
92
- <CheckCircle2 className="h-3.5 w-3.5 text-emerald-500/90" aria-hidden />
93
- </div>
94
- <p
95
- className="break-all font-mono text-[12px] leading-snug text-foreground/85"
96
- title={parsed.path}
97
- >
98
- {formatPathForUi(parsed.path)}
99
- </p>
100
- {parsed.note ? (
101
- <p className="flex gap-1.5 text-[11px] leading-relaxed text-muted-foreground">
102
- <Info className="mt-0.5 h-3 w-3 shrink-0 text-muted-foreground/50" />
103
- <span>{parsed.note}</span>
104
- </p>
105
- ) : null}
106
- </div>
107
- </div>
108
- )
109
- }
110
-
111
- if (parsed.kind === 'file_written') {
112
- return (
113
- <div className="flex gap-2.5 rounded-xl border border-blue-700/20 bg-blue-700/[0.07] dark:border-sky-500/20 dark:bg-sky-500/6 px-3 py-2.5 text-left">
114
- <FileText className="mt-0.5 h-4 w-4 shrink-0 text-blue-700 dark:text-sky-500" />
115
- <div className="min-w-0 flex-1 space-y-1">
116
- <span className="text-[13px] font-medium text-foreground">File written</span>
117
- <p className="break-all font-mono text-[12px] leading-snug text-foreground/85" title={parsed.path}>
118
- {formatPathForUi(parsed.path)}
119
- </p>
120
- {parsed.note ? <p className="text-[11px] text-muted-foreground">{parsed.note}</p> : null}
121
- </div>
122
- </div>
123
- )
124
- }
125
-
126
- if (parsed.kind === 'file_read') {
127
- return (
128
- <div className="flex gap-2.5 rounded-xl border border-border/60 bg-muted/30 px-3 py-2.5 text-left">
129
- <FileText className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
130
- <div className="min-w-0 flex-1 space-y-1">
131
- <span className="text-[13px] font-medium text-foreground/90">File read</span>
132
- <p className="break-all font-mono text-[12px] leading-snug text-muted-foreground" title={parsed.path}>
133
- {formatPathForUi(parsed.path)}
134
- </p>
135
- {parsed.note ? <p className="text-[11px] text-muted-foreground/80">{parsed.note}</p> : null}
136
- </div>
137
- </div>
138
- )
139
- }
140
-
141
- const text = parsed.text
142
- const long = text.length > 320
143
-
144
- return (
145
- <div
146
- className={cn(
147
- 'rounded-xl border border-border/50 bg-muted/35 px-3 py-2.5 text-left',
148
- 'text-[13px] leading-relaxed text-foreground/85'
149
- )}
150
- >
151
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground/70">Result</p>
152
- <p className={cn('mt-1.5 whitespace-pre-wrap wrap-break-word', long && 'line-clamp-6')}>{text}</p>
153
- {long && (
154
- <p className="mt-2 text-[11px] text-muted-foreground/50">… {text.length.toLocaleString()} characters total</p>
155
- )}
156
- </div>
157
- )
158
- }
@@ -1,49 +0,0 @@
1
- 'use client'
2
-
3
- interface BadgeProps {
4
- has_compaction?: boolean
5
- uses_task_agent?: boolean
6
- uses_mcp?: boolean
7
- uses_web_search?: boolean
8
- uses_web_fetch?: boolean
9
- has_thinking?: boolean
10
- }
11
-
12
- export function SessionBadges({
13
- has_compaction,
14
- uses_task_agent,
15
- uses_mcp,
16
- uses_web_search,
17
- uses_web_fetch,
18
- has_thinking,
19
- }: BadgeProps) {
20
- return (
21
- <div className="flex flex-wrap gap-1">
22
- {has_compaction && (
23
- <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[12px] font-medium bg-amber-500/20 text-amber-400 border border-amber-500/30">
24
- ⚡ compacted
25
- </span>
26
- )}
27
- {uses_task_agent && (
28
- <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[12px] font-medium bg-purple-500/20 text-purple-400 border border-purple-500/30">
29
- 🤖 agent
30
- </span>
31
- )}
32
- {uses_mcp && (
33
- <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[12px] font-medium bg-blue-500/20 text-blue-700 dark:text-blue-400 border border-blue-500/30">
34
- 🔌 mcp
35
- </span>
36
- )}
37
- {(uses_web_search || uses_web_fetch) && (
38
- <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[12px] font-medium bg-green-500/20 text-green-400 border border-green-500/30">
39
- 🔍 web
40
- </span>
41
- )}
42
- {has_thinking && (
43
- <span className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[12px] font-medium bg-indigo-500/20 text-indigo-400 border border-indigo-500/30">
44
- 🧠 thinking
45
- </span>
46
- )}
47
- </div>
48
- )
49
- }