cc-transcript-react 0.1.0

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.
package/dist/index.js ADDED
@@ -0,0 +1,690 @@
1
+ import {
2
+ expandEvents,
3
+ extractMessageBlocks,
4
+ extractTextFromContentBlock,
5
+ filterHiddenEvents,
6
+ joinContentText
7
+ } from "./chunk-6AADMKTL.js";
8
+
9
+ // src/react/ClaudeCodeTranscript.tsx
10
+ import { useMemo } from "react";
11
+ import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism";
12
+ import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
13
+
14
+ // src/react/cn.ts
15
+ import { clsx } from "clsx";
16
+ import { extendTailwindMerge } from "tailwind-merge";
17
+ var twMerge = extendTailwindMerge({
18
+ prefix: "cct-"
19
+ });
20
+ function cn(...inputs) {
21
+ return twMerge(clsx(inputs));
22
+ }
23
+
24
+ // src/react/context.ts
25
+ import { createContext, useContext } from "react";
26
+ var TranscriptContext = createContext(null);
27
+ var TranscriptProvider = TranscriptContext.Provider;
28
+ function useTranscriptContext() {
29
+ const ctx = useContext(TranscriptContext);
30
+ if (!ctx) {
31
+ throw new Error("useTranscriptContext must be used within a TranscriptProvider");
32
+ }
33
+ return ctx;
34
+ }
35
+
36
+ // src/react/components/ContentBlockCard.tsx
37
+ import { useState as useState2 } from "react";
38
+ import { ChevronDown, ChevronRight } from "lucide-react";
39
+ import { format } from "date-fns";
40
+
41
+ // src/react/components/block-classification.ts
42
+ var SECONDARY_BLOCK_TYPES = [
43
+ "thinking",
44
+ "tool_use",
45
+ "tool_result",
46
+ "tool_group",
47
+ "skill_group",
48
+ "local_command",
49
+ "local_command_output",
50
+ "local_command_group"
51
+ ];
52
+ function isSecondaryBlock(block) {
53
+ return SECONDARY_BLOCK_TYPES.includes(block.blockType);
54
+ }
55
+ function isTodoTool(toolName) {
56
+ return toolName === "TodoWrite" || toolName === "TodoRead";
57
+ }
58
+ function isAskUserQuestionTool(toolName) {
59
+ return toolName === "AskUserQuestion";
60
+ }
61
+ function shouldExpandByDefault(block) {
62
+ if (!isSecondaryBlock(block)) return true;
63
+ if (block.blockType === "tool_group") {
64
+ const content = block.content;
65
+ const toolName = content?.name;
66
+ if (toolName && (isTodoTool(toolName) || isAskUserQuestionTool(toolName))) return true;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ // src/react/components/block-styles.ts
72
+ import {
73
+ User,
74
+ Bot,
75
+ Wrench,
76
+ Sparkles,
77
+ Terminal
78
+ } from "lucide-react";
79
+ import { createElement } from "react";
80
+ var PROSE_BASE = "cct-prose cct-prose-sm cct-max-w-none";
81
+ var PROSE_CODE_RESET = "prose-code:cct-rounded prose-code:cct-px-1 prose-code:cct-py-0.5 prose-code:before:cct-content-none prose-code:after:cct-content-none";
82
+ var PROSE_COLOR_OVERRIDES = [
83
+ "prose-strong:cct-text-[var(--cct-text-primary)]",
84
+ "prose-a:cct-text-[var(--cct-text-primary)] prose-a:cct-underline",
85
+ "prose-blockquote:cct-text-[var(--cct-text-secondary)] prose-blockquote:cct-border-[var(--cct-border-default)]",
86
+ "prose-hr:cct-border-[var(--cct-border-default)]",
87
+ "prose-th:cct-border-[var(--cct-border-default)] prose-td:cct-border-[var(--cct-border-default)]",
88
+ "prose-figcaption:cct-text-[var(--cct-text-tertiary)]",
89
+ "prose-kbd:cct-text-[var(--cct-text-primary)]"
90
+ ].join(" ");
91
+ var PROSE_TEXT = `${PROSE_BASE} cct-text-[var(--cct-text-body)] prose-headings:cct-text-[var(--cct-text-primary)] ${PROSE_COLOR_OVERRIDES} ${PROSE_CODE_RESET} prose-code:cct-bg-[var(--cct-bg-code)] prose-code:cct-text-[var(--cct-text-primary)] prose-pre:cct-bg-[var(--cct-bg-code)] prose-pre:cct-text-[var(--cct-text-primary)]`;
92
+ var PROSE_THINKING = `${PROSE_BASE} cct-text-[var(--cct-thinking-text)] prose-headings:cct-text-[var(--cct-thinking-text)] prose-strong:cct-text-[var(--cct-thinking-text)] prose-a:cct-text-[var(--cct-thinking-text)] prose-a:cct-underline prose-blockquote:cct-text-[var(--cct-thinking-text)] prose-blockquote:cct-border-[var(--cct-thinking-code-bg)] prose-hr:cct-border-[var(--cct-thinking-code-bg)] prose-kbd:cct-text-[var(--cct-thinking-text)] ${PROSE_CODE_RESET} prose-code:cct-bg-[var(--cct-thinking-code-bg)] prose-code:cct-text-[var(--cct-thinking-code-text)] prose-pre:cct-bg-[var(--cct-thinking-pre-bg)] prose-pre:cct-text-[var(--cct-thinking-text)]`;
93
+ var PROSE_SKILL = `${PROSE_BASE} prose-headings:cct-mt-3 prose-headings:cct-mb-2 prose-p:cct-my-1 prose-ul:cct-my-1 prose-ol:cct-my-1 prose-li:cct-my-0.5 prose-pre:cct-my-2`;
94
+ function getBlockContainerStyle(block) {
95
+ if (isSecondaryBlock(block)) {
96
+ return {
97
+ wrapper: "cct-ml-4",
98
+ container: "cct-border cct-border-[var(--cct-border-default)] cct-bg-[var(--cct-bg-secondary)]",
99
+ header: "cct-px-3 cct-py-2"
100
+ };
101
+ }
102
+ const borderColor = block.eventType === "user" ? "cct-border-[var(--cct-user-border)]" : "cct-border-[var(--cct-assistant-border)]";
103
+ const bgColor = block.eventType === "user" ? "cct-bg-[var(--cct-user-bg)]" : "cct-bg-[var(--cct-assistant-bg)]";
104
+ return {
105
+ wrapper: "",
106
+ container: `cct-border-2 ${borderColor} ${bgColor}`,
107
+ header: "cct-px-4 cct-py-3"
108
+ };
109
+ }
110
+ var ICON_CLASS = "cct-h-4 cct-w-4";
111
+ function icon(component) {
112
+ return createElement(component, { className: ICON_CLASS });
113
+ }
114
+ function getIcon(block) {
115
+ if (block.blockType === "local_command" || block.blockType === "local_command_output" || block.blockType === "local_command_group") {
116
+ return icon(Terminal);
117
+ }
118
+ if (block.blockType === "skill_group") {
119
+ return icon(Sparkles);
120
+ }
121
+ if (block.blockType === "tool_use" || block.blockType === "tool_result" || block.blockType === "tool_group") {
122
+ return icon(Wrench);
123
+ }
124
+ if (block.eventType === "tool_use" || block.eventType === "tool_result") {
125
+ return icon(Wrench);
126
+ }
127
+ if (block.blockType === "thinking") {
128
+ return icon(Sparkles);
129
+ }
130
+ if (block.eventType === "user") {
131
+ return icon(User);
132
+ }
133
+ return icon(Bot);
134
+ }
135
+ function getIconStyle(block) {
136
+ if (isSecondaryBlock(block)) {
137
+ return "cct-bg-[var(--cct-secondary-icon-bg)] cct-text-[var(--cct-text-tertiary)]";
138
+ }
139
+ if (block.eventType === "user") {
140
+ return "cct-bg-[var(--cct-user-icon-bg)] cct-text-[var(--cct-user-icon-text)]";
141
+ }
142
+ return "cct-bg-[var(--cct-assistant-icon-bg)] cct-text-[var(--cct-assistant-icon-text)]";
143
+ }
144
+
145
+ // src/react/components/PermalinkButton.tsx
146
+ import { useState } from "react";
147
+ import { Check, Link2 } from "lucide-react";
148
+ import { jsx } from "react/jsx-runtime";
149
+ function PermalinkButton({ blockId }) {
150
+ const [copied, setCopied] = useState(false);
151
+ const { generatePermalink, copyToClipboard } = useTranscriptContext();
152
+ const handleCopy = async (e) => {
153
+ e.stopPropagation();
154
+ const defaultUrl = typeof window !== "undefined" ? `${window.location.origin}${window.location.pathname}#event-${blockId}` : `#event-${blockId}`;
155
+ const url = generatePermalink ? generatePermalink(blockId) : defaultUrl;
156
+ if (copyToClipboard) {
157
+ await copyToClipboard(url);
158
+ } else if (typeof navigator !== "undefined" && navigator.clipboard) {
159
+ await navigator.clipboard.writeText(url);
160
+ }
161
+ setCopied(true);
162
+ setTimeout(() => setCopied(false), 2e3);
163
+ };
164
+ return /* @__PURE__ */ jsx(
165
+ "button",
166
+ {
167
+ onClick: handleCopy,
168
+ className: "cct-appearance-none cct-border-0 cct-bg-transparent cct-rounded cct-p-1 cct-text-[var(--cct-text-muted)] cct-opacity-0 cct-transition-all hover:cct-bg-[var(--cct-bg-code)] hover:cct-text-[var(--cct-text-secondary)] group-hover:cct-opacity-100",
169
+ title: "Copy link to this block",
170
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "cct-h-3.5 cct-w-3.5 cct-text-[var(--cct-success)]" }) : /* @__PURE__ */ jsx(Link2, { className: "cct-h-3.5 cct-w-3.5" })
171
+ }
172
+ );
173
+ }
174
+
175
+ // src/react/components/MarkdownContent.tsx
176
+ import ReactMarkdown from "react-markdown";
177
+ import remarkGfm from "remark-gfm";
178
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
179
+ import { jsx as jsx2 } from "react/jsx-runtime";
180
+ function MarkdownContent({
181
+ text,
182
+ proseClass
183
+ }) {
184
+ const { codeTheme, codeCustomStyle } = useTranscriptContext();
185
+ const defaultCodeStyle = {
186
+ fontSize: "0.75rem",
187
+ borderRadius: "0.5rem",
188
+ margin: 0,
189
+ ...codeCustomStyle
190
+ };
191
+ return /* @__PURE__ */ jsx2("div", { className: proseClass, children: /* @__PURE__ */ jsx2(
192
+ ReactMarkdown,
193
+ {
194
+ remarkPlugins: [remarkGfm],
195
+ components: {
196
+ code({ className, children, ...props }) {
197
+ const match = /language-(\w+)/.exec(className || "");
198
+ const code = String(children).replace(/\n$/, "");
199
+ if (match) {
200
+ return /* @__PURE__ */ jsx2(
201
+ SyntaxHighlighter,
202
+ {
203
+ language: match[1],
204
+ style: codeTheme,
205
+ customStyle: defaultCodeStyle,
206
+ children: code
207
+ }
208
+ );
209
+ }
210
+ return /* @__PURE__ */ jsx2("code", { className, ...props, children });
211
+ }
212
+ },
213
+ children: text
214
+ }
215
+ ) });
216
+ }
217
+
218
+ // src/react/components/renderers/TextRenderer.tsx
219
+ import { jsx as jsx3 } from "react/jsx-runtime";
220
+ function TextRenderer({ block }) {
221
+ const { classNames } = useTranscriptContext();
222
+ const content = block.content;
223
+ const text = typeof content === "string" ? content : content?.text;
224
+ if (typeof text !== "string") return null;
225
+ return /* @__PURE__ */ jsx3(
226
+ MarkdownContent,
227
+ {
228
+ text,
229
+ proseClass: cn(PROSE_TEXT, classNames?.markdown)
230
+ }
231
+ );
232
+ }
233
+
234
+ // src/react/components/renderers/ThinkingRenderer.tsx
235
+ import { jsx as jsx4 } from "react/jsx-runtime";
236
+ function ThinkingRenderer({ block }) {
237
+ const { classNames } = useTranscriptContext();
238
+ const content = block.content;
239
+ const thinking = content?.thinking;
240
+ return /* @__PURE__ */ jsx4(
241
+ MarkdownContent,
242
+ {
243
+ text: thinking,
244
+ proseClass: cn(PROSE_THINKING, classNames?.markdown)
245
+ }
246
+ );
247
+ }
248
+
249
+ // src/react/components/CodeBlock.tsx
250
+ import { Prism as SyntaxHighlighter2 } from "react-syntax-highlighter";
251
+ import { jsx as jsx5 } from "react/jsx-runtime";
252
+ function CodeBlock({
253
+ children,
254
+ language = "json",
255
+ maxHeight = "300px",
256
+ className
257
+ }) {
258
+ const { codeTheme, codeCustomStyle } = useTranscriptContext();
259
+ return /* @__PURE__ */ jsx5(
260
+ SyntaxHighlighter2,
261
+ {
262
+ language,
263
+ style: codeTheme,
264
+ customStyle: {
265
+ fontSize: "0.75rem",
266
+ borderRadius: "0.5rem",
267
+ margin: 0,
268
+ maxHeight,
269
+ overflow: "auto",
270
+ ...codeCustomStyle
271
+ },
272
+ className: cn(className),
273
+ children
274
+ }
275
+ );
276
+ }
277
+
278
+ // src/react/components/renderers/TodoRenderer.tsx
279
+ import { CheckCircle2, CircleDot, Circle } from "lucide-react";
280
+ import { jsx as jsx6, jsxs } from "react/jsx-runtime";
281
+ function extractTodos(toolName, input, resultContent) {
282
+ if (toolName === "TodoWrite") {
283
+ const inputObj = input;
284
+ if (inputObj?.todos && Array.isArray(inputObj.todos)) {
285
+ return inputObj.todos;
286
+ }
287
+ }
288
+ if (toolName === "TodoRead") {
289
+ if (resultContent) {
290
+ let parsed = resultContent;
291
+ if (typeof resultContent === "string") {
292
+ try {
293
+ parsed = JSON.parse(resultContent);
294
+ } catch {
295
+ return null;
296
+ }
297
+ }
298
+ const resultObj = parsed;
299
+ if (Array.isArray(resultObj)) return resultObj;
300
+ if (resultObj && "todos" in resultObj && Array.isArray(resultObj.todos)) return resultObj.todos;
301
+ }
302
+ }
303
+ return null;
304
+ }
305
+ function TodoListBlock({ todos }) {
306
+ if (todos.length === 0) {
307
+ return /* @__PURE__ */ jsx6("div", { className: "cct-text-sm cct-text-[var(--cct-text-tertiary)] cct-italic", children: "No tasks" });
308
+ }
309
+ return /* @__PURE__ */ jsx6("div", { className: "cct-space-y-1.5", children: todos.map((todo, i) => /* @__PURE__ */ jsxs("div", { className: "cct-flex cct-items-start cct-gap-2", children: [
310
+ todo.status === "completed" && /* @__PURE__ */ jsx6(CheckCircle2, { className: "cct-h-4 cct-w-4 cct-text-[var(--cct-todo-completed)] cct-flex-shrink-0 cct-mt-0.5" }),
311
+ todo.status === "in_progress" && /* @__PURE__ */ jsx6(CircleDot, { className: "cct-h-4 cct-w-4 cct-text-[var(--cct-todo-in-progress)] cct-flex-shrink-0 cct-mt-0.5" }),
312
+ todo.status === "pending" && /* @__PURE__ */ jsx6(Circle, { className: "cct-h-4 cct-w-4 cct-text-[var(--cct-todo-pending)] cct-flex-shrink-0 cct-mt-0.5" }),
313
+ /* @__PURE__ */ jsx6(
314
+ "span",
315
+ {
316
+ className: cn(
317
+ "cct-text-sm",
318
+ todo.status === "completed" && "cct-text-[var(--cct-text-tertiary)] cct-line-through",
319
+ todo.status === "in_progress" && "cct-text-[var(--cct-selected-text)] cct-font-medium",
320
+ todo.status === "pending" && "cct-text-[var(--cct-text-body)]"
321
+ ),
322
+ children: todo.content
323
+ }
324
+ )
325
+ ] }, i)) });
326
+ }
327
+
328
+ // src/react/components/renderers/AskUserQuestionRenderer.tsx
329
+ import { Circle as Circle2, CircleDot as CircleDot2, MessageCircleQuestion, Pencil } from "lucide-react";
330
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
331
+ function extractAskUserQuestions(input) {
332
+ const inputObj = input;
333
+ if (inputObj?.questions && Array.isArray(inputObj.questions)) return inputObj.questions;
334
+ return null;
335
+ }
336
+ function parseUserAnswers(resultContent) {
337
+ const answers = {};
338
+ let contentStr;
339
+ if (typeof resultContent === "string") {
340
+ contentStr = resultContent;
341
+ } else if (Array.isArray(resultContent)) {
342
+ contentStr = resultContent.map((c) => extractTextFromContentBlock(c)).join("");
343
+ } else {
344
+ return answers;
345
+ }
346
+ const regex = /"([^"]+)"="([^"]+)"/g;
347
+ let match;
348
+ while ((match = regex.exec(contentStr)) !== null) {
349
+ answers[match[1]] = match[2];
350
+ }
351
+ return answers;
352
+ }
353
+ function isOptionSelected(answer, options) {
354
+ return options.some((opt) => opt.label === answer);
355
+ }
356
+ function AskUserQuestionBlock({
357
+ questions,
358
+ answers
359
+ }) {
360
+ if (questions.length === 0) {
361
+ return /* @__PURE__ */ jsx7("div", { className: "cct-text-sm cct-text-[var(--cct-text-tertiary)] cct-italic", children: "No questions" });
362
+ }
363
+ return /* @__PURE__ */ jsx7("div", { className: "cct-space-y-4", children: questions.map((q, i) => {
364
+ const answer = answers[q.question];
365
+ const isOtherAnswer = answer && !isOptionSelected(answer, q.options);
366
+ return /* @__PURE__ */ jsxs2("div", { className: "cct-rounded-[var(--cct-border-radius-sm)] cct-border cct-border-[var(--cct-border-default)] cct-bg-[var(--cct-bg-primary)] cct-p-3", children: [
367
+ /* @__PURE__ */ jsxs2("div", { className: "cct-mb-1 cct-flex cct-items-center cct-gap-1.5 cct-text-xs cct-font-medium cct-text-[var(--cct-text-tertiary)]", children: [
368
+ /* @__PURE__ */ jsx7(MessageCircleQuestion, { className: "cct-h-3.5 cct-w-3.5" }),
369
+ q.header
370
+ ] }),
371
+ /* @__PURE__ */ jsx7("div", { className: "cct-mb-3 cct-font-medium cct-text-[var(--cct-text-primary)]", children: q.question }),
372
+ /* @__PURE__ */ jsxs2("div", { className: "cct-space-y-2", children: [
373
+ q.options.map((opt, j) => {
374
+ const isSelected = answer === opt.label;
375
+ return /* @__PURE__ */ jsxs2(
376
+ "div",
377
+ {
378
+ className: cn(
379
+ "cct-flex cct-items-start cct-gap-2 cct-rounded-md cct-p-2 cct-transition-colors",
380
+ isSelected && "cct-bg-[var(--cct-selected-bg)]"
381
+ ),
382
+ children: [
383
+ isSelected ? /* @__PURE__ */ jsx7(CircleDot2, { className: "cct-mt-0.5 cct-h-4 cct-w-4 cct-flex-shrink-0 cct-text-[var(--cct-selected-icon)]" }) : /* @__PURE__ */ jsx7(Circle2, { className: "cct-mt-0.5 cct-h-4 cct-w-4 cct-flex-shrink-0 cct-text-[var(--cct-text-disabled)]" }),
384
+ /* @__PURE__ */ jsxs2("div", { className: "cct-min-w-0 cct-flex-1", children: [
385
+ /* @__PURE__ */ jsx7("span", { className: cn("cct-text-sm", isSelected ? "cct-font-medium cct-text-[var(--cct-selected-text)]" : "cct-text-[var(--cct-text-body)]"), children: opt.label }),
386
+ opt.description && /* @__PURE__ */ jsx7("p", { className: "cct-mt-0.5 cct-text-xs cct-text-[var(--cct-text-tertiary)]", children: opt.description })
387
+ ] })
388
+ ]
389
+ },
390
+ j
391
+ );
392
+ }),
393
+ isOtherAnswer && /* @__PURE__ */ jsxs2("div", { className: "cct-mt-2 cct-flex cct-items-start cct-gap-2 cct-rounded-md cct-border-t cct-border-[var(--cct-border-subtle)] cct-bg-[var(--cct-selected-bg)] cct-p-2 cct-pt-3", children: [
394
+ /* @__PURE__ */ jsx7(Pencil, { className: "cct-mt-0.5 cct-h-4 cct-w-4 cct-flex-shrink-0 cct-text-[var(--cct-selected-icon)]" }),
395
+ /* @__PURE__ */ jsxs2("div", { className: "cct-min-w-0 cct-flex-1", children: [
396
+ /* @__PURE__ */ jsx7("span", { className: "cct-text-xs cct-font-medium cct-text-[var(--cct-text-tertiary)]", children: "Other" }),
397
+ /* @__PURE__ */ jsx7("p", { className: "cct-text-sm cct-font-medium cct-text-[var(--cct-selected-text)]", children: answer })
398
+ ] })
399
+ ] }),
400
+ !answer && /* @__PURE__ */ jsx7("div", { className: "cct-mt-2 cct-text-xs cct-italic cct-text-[var(--cct-text-muted)]", children: "Waiting for answer..." })
401
+ ] })
402
+ ] }, i);
403
+ }) });
404
+ }
405
+
406
+ // src/react/components/renderers/ToolGroupRenderer.tsx
407
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
408
+ function ToolGroupRenderer({ block }) {
409
+ const content = block.content;
410
+ const toolName = content?.name;
411
+ const input = content?.input;
412
+ const resultBlock = block.toolResultBlock;
413
+ const resultContent = resultBlock?.content;
414
+ const resultData = resultContent?.content;
415
+ if (toolName && isTodoTool(toolName)) {
416
+ const todos = extractTodos(toolName, input, resultData);
417
+ if (todos) return /* @__PURE__ */ jsx8(TodoListBlock, { todos });
418
+ }
419
+ if (toolName && isAskUserQuestionTool(toolName)) {
420
+ const questions = extractAskUserQuestions(input);
421
+ if (questions) {
422
+ const answers = parseUserAnswers(resultData);
423
+ return /* @__PURE__ */ jsx8(AskUserQuestionBlock, { questions, answers });
424
+ }
425
+ }
426
+ const displayResult = joinContentText(resultData, {
427
+ fallback: (c) => JSON.stringify(c, null, 2)
428
+ }) || JSON.stringify(resultData, null, 2);
429
+ return /* @__PURE__ */ jsxs3("div", { className: "cct-space-y-3", children: [
430
+ /* @__PURE__ */ jsxs3("div", { children: [
431
+ /* @__PURE__ */ jsx8("div", { className: "cct-mb-1 cct-text-xs cct-font-medium cct-text-[var(--cct-text-muted)]", children: "Input" }),
432
+ /* @__PURE__ */ jsx8(CodeBlock, { children: JSON.stringify(input, null, 2) })
433
+ ] }),
434
+ resultBlock && /* @__PURE__ */ jsxs3("div", { children: [
435
+ /* @__PURE__ */ jsx8("div", { className: "cct-mb-1 cct-text-xs cct-font-medium cct-text-[var(--cct-text-muted)]", children: "Result" }),
436
+ /* @__PURE__ */ jsx8(CodeBlock, { children: displayResult })
437
+ ] })
438
+ ] });
439
+ }
440
+
441
+ // src/react/components/renderers/SkillGroupRenderer.tsx
442
+ import { Check as Check2 } from "lucide-react";
443
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
444
+ function SkillGroupRenderer({ block }) {
445
+ const { classNames } = useTranscriptContext();
446
+ const content = block.content;
447
+ const input = content?.input;
448
+ const resultBlock = block.toolResultBlock;
449
+ const resultContent = resultBlock?.content;
450
+ const resultData = resultContent?.content;
451
+ const skillContentBlock = block.skillContentBlock;
452
+ const skillContent = skillContentBlock?.content;
453
+ const skillText = joinContentText(skillContent);
454
+ return /* @__PURE__ */ jsxs4("div", { className: "cct-space-y-3", children: [
455
+ resultData && /* @__PURE__ */ jsxs4("div", { className: "cct-flex cct-items-center cct-gap-2 cct-text-sm", children: [
456
+ /* @__PURE__ */ jsx9(Check2, { className: "cct-h-4 cct-w-4 cct-text-[var(--cct-success)]" }),
457
+ /* @__PURE__ */ jsx9("span", { className: "cct-text-[var(--cct-text-secondary)]", children: resultData })
458
+ ] }),
459
+ skillText && /* @__PURE__ */ jsxs4("div", { className: "cct-border cct-border-[var(--cct-border-default)] cct-rounded-[var(--cct-border-radius-sm)] cct-p-3 cct-bg-[var(--cct-bg-primary)]", children: [
460
+ /* @__PURE__ */ jsx9("div", { className: "cct-mb-2 cct-text-xs cct-font-medium cct-text-[var(--cct-text-muted)]", children: "Skill Content" }),
461
+ /* @__PURE__ */ jsx9(
462
+ MarkdownContent,
463
+ {
464
+ text: skillText,
465
+ proseClass: cn(PROSE_SKILL, classNames?.markdown)
466
+ }
467
+ )
468
+ ] }),
469
+ !skillText && /* @__PURE__ */ jsxs4("div", { children: [
470
+ /* @__PURE__ */ jsx9("div", { className: "cct-mb-1 cct-text-xs cct-font-medium cct-text-[var(--cct-text-muted)]", children: "Input" }),
471
+ /* @__PURE__ */ jsx9(CodeBlock, { maxHeight: "200px", children: JSON.stringify(input, null, 2) })
472
+ ] })
473
+ ] });
474
+ }
475
+
476
+ // src/react/components/renderers/LocalCommandRenderer.tsx
477
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
478
+ function extractCommandOutput(content) {
479
+ const match = content.match(/<local-command-stdout>([\s\S]*?)<\/local-command-stdout>/);
480
+ return match ? match[1].trim() : content;
481
+ }
482
+ function LocalCommandGroupRenderer({ block }) {
483
+ const { classNames } = useTranscriptContext();
484
+ return /* @__PURE__ */ jsxs5("div", { className: "cct-space-y-3", children: [
485
+ /* @__PURE__ */ jsx10("div", { className: "cct-text-sm cct-text-[var(--cct-text-tertiary)] cct-italic", children: "Command executed" }),
486
+ block.childBlocks && block.childBlocks.length > 0 && /* @__PURE__ */ jsx10("div", { className: "cct-space-y-2 cct-border-l-2 cct-border-[var(--cct-border-default)] cct-pl-3", children: block.childBlocks.map((child) => /* @__PURE__ */ jsxs5("div", { children: [
487
+ /* @__PURE__ */ jsx10("div", { className: "cct-mb-1 cct-text-xs cct-font-medium cct-text-[var(--cct-text-muted)]", children: child.label.text }),
488
+ child.blockType === "local_command_output" ? /* @__PURE__ */ jsx10("pre", { className: "cct-max-h-[200px] cct-overflow-auto cct-whitespace-pre-wrap cct-rounded-[var(--cct-border-radius-sm)] cct-bg-[var(--cct-bg-secondary)] cct-p-2 cct-font-mono cct-text-xs cct-text-[var(--cct-text-secondary)]", children: typeof child.content === "string" ? extractCommandOutput(child.content) : "" }) : child.blockType === "compact_summary" ? /* @__PURE__ */ jsx10("div", { className: "cct-max-h-[300px] cct-overflow-auto cct-rounded-[var(--cct-border-radius-sm)] cct-bg-[var(--cct-summary-bg)] cct-p-3 cct-text-xs cct-text-[var(--cct-text-body)]", children: /* @__PURE__ */ jsx10("pre", { className: "cct-whitespace-pre-wrap cct-font-mono", children: typeof child.content === "string" ? child.content : "" }) }) : /* @__PURE__ */ jsx10("div", { className: cn("cct-prose cct-prose-sm cct-max-w-none cct-text-[var(--cct-text-secondary)]", classNames?.markdown), children: typeof child.content === "string" ? child.content : "" })
489
+ ] }, child.id)) })
490
+ ] });
491
+ }
492
+ function LocalCommandRenderer() {
493
+ return /* @__PURE__ */ jsx10("div", { className: "cct-text-sm cct-text-[var(--cct-text-tertiary)] cct-italic", children: "Command executed" });
494
+ }
495
+ function LocalCommandOutputRenderer({ block }) {
496
+ const output = typeof block.content === "string" ? extractCommandOutput(block.content) : "";
497
+ if (!output) {
498
+ return /* @__PURE__ */ jsx10("div", { className: "cct-text-sm cct-text-[var(--cct-text-muted)] cct-italic", children: "(no output)" });
499
+ }
500
+ return /* @__PURE__ */ jsx10("pre", { className: "cct-max-h-[300px] cct-overflow-auto cct-whitespace-pre-wrap cct-rounded-[var(--cct-border-radius-sm)] cct-bg-[var(--cct-bg-secondary)] cct-p-3 cct-font-mono cct-text-xs cct-text-[var(--cct-text-secondary)]", children: output });
501
+ }
502
+
503
+ // src/react/components/renderers/ToolUseRenderer.tsx
504
+ import { jsx as jsx11 } from "react/jsx-runtime";
505
+ function ToolUseRenderer({ block }) {
506
+ const content = block.content;
507
+ const input = content?.input;
508
+ return /* @__PURE__ */ jsx11(CodeBlock, { maxHeight: "400px", children: JSON.stringify(input, null, 2) });
509
+ }
510
+ function ToolResultRenderer({ block }) {
511
+ const content = block.content;
512
+ const resultContent = content?.content;
513
+ const displayContent = joinContentText(resultContent, {
514
+ fallback: (c) => JSON.stringify(c, null, 2)
515
+ }) || JSON.stringify(resultContent, null, 2);
516
+ return /* @__PURE__ */ jsx11(CodeBlock, { maxHeight: "400px", children: displayContent });
517
+ }
518
+ function StandaloneToolEventRenderer({ block }) {
519
+ const payload = block.content;
520
+ const input = payload?.input || payload?.result || payload;
521
+ return /* @__PURE__ */ jsx11(CodeBlock, { maxHeight: "400px", children: JSON.stringify(input, null, 2) });
522
+ }
523
+
524
+ // src/react/components/renderers/FallbackRenderer.tsx
525
+ import { jsx as jsx12 } from "react/jsx-runtime";
526
+ function FallbackRenderer({ block }) {
527
+ return /* @__PURE__ */ jsx12("pre", { className: "cct-max-h-[300px] cct-overflow-auto cct-whitespace-pre-wrap cct-text-xs cct-text-[var(--cct-text-secondary)]", children: JSON.stringify(block.content, null, 2) });
528
+ }
529
+
530
+ // src/react/components/renderers/index.tsx
531
+ import { Fragment, jsx as jsx13 } from "react/jsx-runtime";
532
+ var DEFAULT_RENDERERS = {
533
+ text: TextRenderer,
534
+ thinking: ThinkingRenderer,
535
+ tool_group: ToolGroupRenderer,
536
+ skill_group: SkillGroupRenderer,
537
+ local_command_group: LocalCommandGroupRenderer,
538
+ local_command: LocalCommandRenderer,
539
+ local_command_output: LocalCommandOutputRenderer,
540
+ tool_use: ToolUseRenderer,
541
+ tool_result: ToolResultRenderer
542
+ };
543
+ function BlockContent({ block }) {
544
+ const { customBlockRenderers } = useTranscriptContext();
545
+ if (customBlockRenderers && block.blockType === "tool_group") {
546
+ const content = block.content;
547
+ const toolName = content?.name;
548
+ if (toolName && customBlockRenderers[toolName]) {
549
+ const result = customBlockRenderers[toolName](block);
550
+ if (result !== null) return /* @__PURE__ */ jsx13(Fragment, { children: result });
551
+ }
552
+ }
553
+ if (customBlockRenderers && customBlockRenderers[block.blockType]) {
554
+ const result = customBlockRenderers[block.blockType](block);
555
+ if (result !== null) return /* @__PURE__ */ jsx13(Fragment, { children: result });
556
+ }
557
+ if (block.eventType === "tool_use" || block.eventType === "tool_result") {
558
+ if (!DEFAULT_RENDERERS[block.blockType]) {
559
+ return /* @__PURE__ */ jsx13(StandaloneToolEventRenderer, { block });
560
+ }
561
+ }
562
+ const Renderer = DEFAULT_RENDERERS[block.blockType];
563
+ if (Renderer) {
564
+ return /* @__PURE__ */ jsx13(Renderer, { block });
565
+ }
566
+ return /* @__PURE__ */ jsx13(FallbackRenderer, { block });
567
+ }
568
+
569
+ // src/react/components/ContentBlockCard.tsx
570
+ import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
571
+ function ContentBlockCard({ block }) {
572
+ const { classNames } = useTranscriptContext();
573
+ const isSecondary = isSecondaryBlock(block);
574
+ const [expanded, setExpanded] = useState2(() => shouldExpandByDefault(block));
575
+ const styles = getBlockContainerStyle(block);
576
+ if (!isSecondary) {
577
+ return /* @__PURE__ */ jsx14("div", { className: cn(styles.wrapper, classNames?.blockWrapper), children: /* @__PURE__ */ jsxs6("div", { className: cn("cct-group cct-overflow-hidden cct-rounded-[var(--cct-border-radius)]", styles.container, classNames?.primaryBlock), children: [
578
+ /* @__PURE__ */ jsxs6("div", { className: cn("cct-flex cct-items-center cct-justify-between", styles.header, classNames?.primaryHeader), children: [
579
+ /* @__PURE__ */ jsxs6("div", { className: "cct-flex cct-items-center cct-gap-2", children: [
580
+ /* @__PURE__ */ jsx14("span", { className: cn("cct-flex cct-h-6 cct-w-6 cct-items-center cct-justify-center cct-rounded-full", getIconStyle(block), classNames?.icon), children: getIcon(block) }),
581
+ /* @__PURE__ */ jsx14("span", { className: cn("cct-font-medium cct-text-[var(--cct-text-primary)]", classNames?.label), children: block.label.text })
582
+ ] }),
583
+ /* @__PURE__ */ jsxs6("div", { className: cn("cct-flex cct-items-center cct-gap-2 cct-text-sm cct-text-[var(--cct-text-tertiary)]", classNames?.timestamp), children: [
584
+ /* @__PURE__ */ jsx14("span", { children: format(new Date(block.timestamp), "HH:mm:ss") }),
585
+ /* @__PURE__ */ jsx14(PermalinkButton, { blockId: block.id })
586
+ ] })
587
+ ] }),
588
+ /* @__PURE__ */ jsx14("div", { className: cn("cct-border-t cct-border-[var(--cct-border-subtle)] cct-px-4 cct-py-3", classNames?.primaryContent), children: /* @__PURE__ */ jsx14(BlockContent, { block }) })
589
+ ] }) });
590
+ }
591
+ return /* @__PURE__ */ jsx14("div", { className: cn(styles.wrapper, classNames?.blockWrapper), children: /* @__PURE__ */ jsxs6("div", { className: cn("cct-group cct-overflow-hidden cct-rounded-[var(--cct-border-radius)]", styles.container, classNames?.secondaryBlock), children: [
592
+ /* @__PURE__ */ jsxs6("div", { className: cn("cct-flex cct-w-full cct-items-center cct-justify-between", styles.header, classNames?.secondaryHeader), children: [
593
+ /* @__PURE__ */ jsxs6(
594
+ "button",
595
+ {
596
+ className: "cct-appearance-none cct-border-0 cct-bg-transparent cct-flex cct-min-w-0 cct-flex-1 cct-items-center cct-gap-2 cct-text-left cct-transition-colors hover:cct-bg-[var(--cct-bg-secondary)]",
597
+ onClick: () => setExpanded(!expanded),
598
+ children: [
599
+ /* @__PURE__ */ jsx14("span", { className: cn("cct-flex cct-h-5 cct-w-5 cct-items-center cct-justify-center cct-rounded-full", getIconStyle(block), classNames?.icon), children: getIcon(block) }),
600
+ /* @__PURE__ */ jsx14("span", { className: cn("cct-text-sm cct-font-medium cct-text-[var(--cct-text-secondary)]", classNames?.label), children: block.label.text }),
601
+ block.label.params && /* @__PURE__ */ jsx14("code", { className: "cct-rounded cct-bg-[var(--cct-bg-code)] cct-px-1 cct-py-0.5 cct-text-xs cct-font-normal cct-text-[var(--cct-text-body)]", children: block.label.params })
602
+ ]
603
+ }
604
+ ),
605
+ /* @__PURE__ */ jsxs6("div", { className: cn("cct-flex cct-items-center cct-gap-2 cct-text-xs cct-text-[var(--cct-text-tertiary)]", classNames?.timestamp), children: [
606
+ /* @__PURE__ */ jsx14("span", { children: format(new Date(block.timestamp), "HH:mm:ss") }),
607
+ /* @__PURE__ */ jsx14(PermalinkButton, { blockId: block.id }),
608
+ /* @__PURE__ */ jsx14(
609
+ "button",
610
+ {
611
+ onClick: () => setExpanded(!expanded),
612
+ className: "cct-appearance-none cct-border-0 cct-bg-transparent cct-p-0.5 hover:cct-bg-[var(--cct-bg-code)] cct-rounded",
613
+ children: expanded ? /* @__PURE__ */ jsx14(ChevronDown, { className: "cct-h-3 cct-w-3" }) : /* @__PURE__ */ jsx14(ChevronRight, { className: "cct-h-3 cct-w-3" })
614
+ }
615
+ )
616
+ ] })
617
+ ] }),
618
+ expanded && /* @__PURE__ */ jsx14("div", { className: cn("cct-border-t cct-border-[var(--cct-border-subtle)] cct-px-3 cct-py-2", classNames?.secondaryContent), children: /* @__PURE__ */ jsx14(BlockContent, { block }) })
619
+ ] }) });
620
+ }
621
+
622
+ // src/react/ClaudeCodeTranscript.tsx
623
+ import { jsx as jsx15 } from "react/jsx-runtime";
624
+ function ClaudeCodeTranscript({
625
+ events,
626
+ projectPath,
627
+ colorScheme = "light",
628
+ className,
629
+ classNames,
630
+ theme,
631
+ customBlockRenderers,
632
+ generatePermalink,
633
+ copyToClipboard
634
+ }) {
635
+ const displayBlocks = useMemo(() => {
636
+ const filtered = filterHiddenEvents(events);
637
+ return expandEvents(filtered, projectPath);
638
+ }, [events, projectPath]);
639
+ const resolvedCodeTheme = useMemo(() => {
640
+ if (theme?.codeTheme) return theme.codeTheme;
641
+ return colorScheme === "dark" ? oneDark : oneLight;
642
+ }, [theme?.codeTheme, colorScheme]);
643
+ const contextValue = useMemo(() => ({
644
+ colorScheme,
645
+ classNames,
646
+ codeTheme: resolvedCodeTheme,
647
+ codeCustomStyle: theme?.codeCustomStyle,
648
+ customBlockRenderers,
649
+ generatePermalink,
650
+ copyToClipboard
651
+ }), [colorScheme, classNames, resolvedCodeTheme, theme?.codeCustomStyle, customBlockRenderers, generatePermalink, copyToClipboard]);
652
+ if (displayBlocks.length === 0) {
653
+ return /* @__PURE__ */ jsx15(TranscriptProvider, { value: contextValue, children: /* @__PURE__ */ jsx15(
654
+ "div",
655
+ {
656
+ "data-cct-root": true,
657
+ "data-cct-theme": colorScheme,
658
+ className: cn(
659
+ "cct-rounded-[var(--cct-border-radius)] cct-border cct-border-dashed cct-border-[var(--cct-border-default)] cct-bg-[var(--cct-bg-primary)] cct-p-8 cct-text-center",
660
+ classNames?.emptyState
661
+ ),
662
+ children: /* @__PURE__ */ jsx15("p", { className: "cct-text-[var(--cct-text-tertiary)]", children: "No events." })
663
+ }
664
+ ) });
665
+ }
666
+ return /* @__PURE__ */ jsx15(TranscriptProvider, { value: contextValue, children: /* @__PURE__ */ jsx15(
667
+ "div",
668
+ {
669
+ "data-cct-root": true,
670
+ "data-cct-theme": colorScheme,
671
+ className: cn("cct-space-y-3", className, classNames?.root),
672
+ children: displayBlocks.map((block) => /* @__PURE__ */ jsx15(
673
+ "div",
674
+ {
675
+ id: `event-${block.id}`,
676
+ className: cn("cct-scroll-mt-20", classNames?.blockWrapper),
677
+ children: /* @__PURE__ */ jsx15(ContentBlockCard, { block })
678
+ },
679
+ block.id
680
+ ))
681
+ }
682
+ ) });
683
+ }
684
+ export {
685
+ ClaudeCodeTranscript,
686
+ expandEvents,
687
+ extractMessageBlocks,
688
+ filterHiddenEvents
689
+ };
690
+ //# sourceMappingURL=index.js.map