Conversation
WalkthroughReplaces Streamdown usage in frontend/app/aipanel/aimessage.tsx with a new WaveStreamdown component and supplies it a codeBlockMaxWidth atom from WaveAIModel. Adds frontend/app/element/streamdown.tsx implementing WaveStreamdown plus Code, CodeBlock, Collapsible, and async Shiki-based highlighting with copy/execute controls. Imports Streamdown stylesheet in frontend/tailwindsetup.css and adds Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧬 Code graph analysis (1)frontend/app/element/streamdown.tsx (3)
🪛 ast-grep (0.39.5)frontend/app/element/streamdown.tsx[warning] 102-102: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks. (react-unsafe-html-injection) 🪛 Biome (2.1.2)frontend/app/element/streamdown.tsx[error] 103-103: Avoid passing content using the dangerouslySetInnerHTML prop. Setting content using code can expose users to cross-site scripting (XSS) attacks (lint/security/noDangerouslySetInnerHtml) [error] 216-216: Avoid passing children using a prop The canonical way to pass children in React is to use JSX elements (lint/correctness/noChildrenProp) ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (5)
frontend/app/aipanel/aimessage.tsx(3 hunks)frontend/app/element/streamdown.tsx(1 hunks)frontend/tailwindsetup.css(1 hunks)package.json(1 hunks)tsconfig.json(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/app/element/streamdown.tsx (1)
frontend/app/element/iconbutton.tsx (1)
IconButton(12-34)
frontend/app/aipanel/aimessage.tsx (1)
frontend/app/element/streamdown.tsx (1)
WaveStreamdown(170-274)
🪛 ast-grep (0.39.5)
frontend/app/element/streamdown.tsx
[warning] 56-56: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
frontend/app/element/streamdown.tsx
[error] 57-57: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 192-192: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Analyze (go)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Build for TestDriver.ai
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/app/element/streamdown.tsx (1)
223-225: Use JSX children instead of thechildrenprop.Passing
{props.children}via thechildrenprop violates our React lint rule and is unnecessary—wrap<CodeBlock>and place{props.children}between the tags instead.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/app/element/streamdown.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/app/element/streamdown.tsx (3)
emain/updater.ts (1)
start(124-132)frontend/app/element/copybutton.tsx (1)
CopyButton(59-59)frontend/app/element/iconbutton.tsx (1)
IconButton(12-34)
🪛 ast-grep (0.39.5)
frontend/app/element/streamdown.tsx
[warning] 93-93: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
frontend/app/element/streamdown.tsx
[error] 94-94: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 224-224: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build for TestDriver.ai
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
frontend/app/element/streamdown.tsx
Outdated
| defaultOrigin="http://localhost" | ||
| components={{ | ||
| code: Code, | ||
| pre: (props: React.HTMLAttributes<HTMLPreElement>) => ( | ||
| <CodeBlock children={props.children} onClickExecute={onClickExecute} /> | ||
| ), |
There was a problem hiding this comment.
Avoid forcing defaultOrigin to localhost.
Hard-coding defaultOrigin="http://localhost" rewrites every relative link in streamed markdown to point at localhost, so production users land on dead URLs. Drop the override (let Streamdown infer the current origin) or plumb the real host in from the caller.
🧰 Tools
🪛 Biome (2.1.2)
[error] 224-224: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
🤖 Prompt for AI Agents
In frontend/app/element/streamdown.tsx around lines 220–225, the component is
forcing defaultOrigin="http://localhost" which rewrites relative links to
localhost; remove that hard-coded defaultOrigin prop so Streamdown uses the
current window origin, or change the call site to pass a real origin prop (e.g.,
read from window.location.origin or a forwarded prop from the server/env) and
pass it through instead of the literal "http://localhost".
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
frontend/app/element/streamdown.tsx (4)
13-15: Fix getTextContent to handle all React node types.This implementation only extracts text from bare strings. During streaming, markdown children frequently arrive as arrays, fragments, numbers, or nested React elements, causing
getTextContentto return""and leaving code blocks blank.Based on past review feedback, replace with a recursive extractor:
-function getTextContent(node: React.ReactNode): string { - return typeof node === "string" ? node : ""; -} +function extractText(node: React.ReactNode): string { + if (node == null) return ""; + if (typeof node === "string" || typeof node === "number") return String(node); + if (Array.isArray(node)) return node.map(extractText).join(""); + if (React.isValidElement(node)) return extractText(node.props?.children); + return ""; +}Also update the import on line 7:
-import { useEffect, useRef, useState } from "react"; +import { isValidElement, useEffect, useRef, useState } from "react";Then use
extractTextinstead ofgetTextContentthroughout the file (lines 111, 146, 152).
50-80: Extract text from children prop, not stale DOM.After the first highlight pass,
codeRef.current?.textContentreturns the previously highlighted HTML markup instead of the raw source. On subsequent renders during streaming, this causes the effect to re-highlight stale content, so code blocks never update with new text.Based on past review feedback, extract the raw text from the current
childrenprop (using the recursiveextractTextfunction suggested above) instead of reading from the DOM:useEffect(() => { let disposed = false; - if (!text) { + const raw = extractText(text) || codeRef.current?.textContent || ""; + if (!raw) { setHtml(""); return; } (async () => { try { - const full = await codeToHtml(text, { lang, theme: ShikiTheme }); + const full = await codeToHtml(raw, { lang, theme: ShikiTheme }); const start = full.indexOf("<code"); const open = full.indexOf(">", start); const end = full.lastIndexOf("</code>"); const inner = start !== -1 && open !== -1 && end !== -1 ? full.slice(open + 1, end) : ""; if (!disposed) { setHtml(inner); setHasError(false); } } catch (e) { if (!disposed) { setHasError(true); } console.warn(`Shiki highlight failed for ${lang}`, e); } })(); return () => { disposed = true; }; - }, [text, lang]); + }, [raw, lang]);
126-135: Remove duplicate getTextContent implementation.
CodeBlockreimplementsgetTextContentwith a more complete recursive version, but the top-level helper (lines 13-15) is too simplistic. Once you replace the top-level version with the recursiveextractTexthelper (per the earlier comment), remove this duplicate and use the shared implementation.const CodeBlock = ({ children, onClickExecute }: CodeBlockProps) => { - const getTextContent = (children: any): string => { - if (typeof children === "string") { - return children; - } else if (Array.isArray(children)) { - return children.map(getTextContent).join(""); - } else if (children.props && children.props.children) { - return getTextContent(children.props.children); - } - return ""; - }; - const getLanguage = (children: any): string => { if (children?.props?.className) { const match = children.props.className.match(/language-([\w+-]+)/i); if (match) return match[1]; } return "text"; }; const handleCopy = async (e: React.MouseEvent) => { - let textToCopy = getTextContent(children); + let textToCopy = extractText(children); textToCopy = textToCopy.replace(/\n$/, ""); await navigator.clipboard.writeText(textToCopy); }; const handleExecute = (e: React.MouseEvent) => { - let textToCopy = getTextContent(children); + let textToCopy = extractText(children); textToCopy = textToCopy.replace(/\n$/, ""); if (onClickExecute) { onClickExecute(textToCopy); return; } };
228-228: Remove hardcoded localhost origin.
defaultOrigin="http://localhost"forces all relative links in streamed markdown to point at localhost, breaking them for production users. Drop this prop so Streamdown uses the currentwindow.location.origin, or pass the real origin from the environment.Based on past review feedback:
- defaultOrigin="http://localhost"
🧹 Nitpick comments (1)
frontend/app/element/streamdown.tsx (1)
102-102: Document XSS safety of dangerouslySetInnerHTML usage.Static analysis flags
dangerouslySetInnerHTML, but this usage is acceptable because the HTML comes from Shiki (a trusted syntax highlighter library) rather than user input. Consider adding a brief comment explaining the safety:return ( <code ref={codeRef} className={cn("font-mono text-[12px]", className)} + // Safe: HTML generated by trusted Shiki highlighter dangerouslySetInnerHTML={{ __html: html }} /> );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/app/aipanel/aipanel.tsx(1 hunks)frontend/app/aipanel/aipanelmessages.tsx(3 hunks)frontend/app/aipanel/waveai-model.tsx(2 hunks)frontend/app/element/streamdown.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/app/aipanel/aipanelmessages.tsx (1)
frontend/app/aipanel/waveai-model.tsx (2)
WaveAIModel(24-213)scrollToBottom(148-150)
frontend/app/element/streamdown.tsx (2)
frontend/app/element/copybutton.tsx (1)
CopyButton(59-59)frontend/app/element/iconbutton.tsx (1)
IconButton(12-34)
🪛 ast-grep (0.39.5)
frontend/app/element/streamdown.tsx
[warning] 101-101: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
frontend/app/element/streamdown.tsx
[error] 102-102: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 232-232: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Analyze (go)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Build for TestDriver.ai
🔇 Additional comments (2)
frontend/app/aipanel/waveai-model.tsx (1)
27-27: LGTM! Clean callback pattern for scroll coordination.The scrollToBottom callback mechanism is well-implemented. The nullable callback provides flexibility, and the simple synchronous methods are appropriate for coordinating scroll behavior across components.
Also applies to: 144-150
frontend/app/aipanel/aipanelmessages.tsx (1)
8-8: LGTM! Proper callback registration.The integration with
WaveAIModelis correctly implemented. TheuseEffectwithmodelas a dependency ensures the scroll callback is properly wired whenever the model instance changes, and thescrollToBottomfunction reference is stable.Also applies to: 29-29, 42-44
| setTimeout(() => { | ||
| model.scrollToBottom(); | ||
| }, 100); |
There was a problem hiding this comment.
Clean up setTimeout on unmount.
If the component unmounts during the 100ms delay, the timeout will still fire and attempt to call model.scrollToBottom(). Store the timeout ID and clear it in the cleanup function:
useEffect(() => {
const loadMessages = async () => {
const messages = await model.loadChat();
setMessages(messages as any);
setIsLoadingChat(false);
- setTimeout(() => {
+ const timeoutId = setTimeout(() => {
model.scrollToBottom();
}, 100);
+ return () => clearTimeout(timeoutId);
};
loadMessages();
}, [model, setMessages]);Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In frontend/app/aipanel/aipanel.tsx around lines 107 to 109, the setTimeout used
to call model.scrollToBottom() is not cleaned up on unmount; store the timeout
ID (e.g., in a ref or local variable captured by the effect) when calling
setTimeout and in the effect's cleanup call clearTimeout(timeoutId) so the
callback won't run after unmount; ensure the timeoutId type is compatible with
TS (number | NodeJS.Timeout depending on environment) and clear it in the
returned cleanup function.
…ll. have code block scroll instead. (keeps copy button / controls visible as well)
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
frontend/app/element/streamdown.tsx (2)
1-16: Text extraction still needs fixing per previous reviews.The
getTextContenthelper at lines 14-16 only handles bare strings. During streaming, markdown often arrives as fragments/arrays, causing the extractor to return""and breaking both highlighting and toolbar actions (copy/execute). This issue was flagged in previous reviews and remains unresolved.Per the previous review comment on lines 8-145: Replace this helper with a recursive extractor that handles strings, numbers, arrays, and React elements, then use it consistently in both
CodeandCodeBlock.
225-225: Hard-coded localhost origin breaks production links.This issue was flagged in a previous review and remains unresolved. Setting
defaultOrigin="http://localhost"rewrites all relative links to localhost, breaking them for production users.Per the previous review comment on lines 225-234: Remove this hard-coded prop and let Streamdown infer the current origin, or pass
window.location.originfrom the caller.frontend/app/aipanel/aipanel.tsx (1)
108-110: Timeout cleanup still missing.The
setTimeouthere was flagged in a previous review but remains unfixed. If the component unmounts during the 100ms delay, the callback will still attempt to invokemodel.scrollToBottom().Per the previous review comment on lines 108-110: Store the timeout ID and clear it in the effect's cleanup function:
const loadMessages = async () => { const messages = await model.loadChat(); setMessages(messages as any); setIsLoadingChat(false); - setTimeout(() => { + const timeoutId = setTimeout(() => { model.scrollToBottom(); }, 100); }; loadMessages(); + return () => { + if (timeoutId !== undefined) clearTimeout(timeoutId); + };
🧹 Nitpick comments (1)
frontend/app/element/streamdown.tsx (1)
228-234: Avoid passingchildrenas a prop.React's canonical pattern uses JSX element children, not
children={...}props. While functional, this violates React conventions and triggers linter warnings.Refactor to use JSX element syntax:
- pre: (props: React.HTMLAttributes<HTMLPreElement>) => ( - <CodeBlock - children={props.children} - onClickExecute={onClickExecute} - codeBlockMaxWidthAtom={codeBlockMaxWidthAtom} - /> - ), + pre: (props: React.HTMLAttributes<HTMLPreElement>) => ( + <CodeBlock + onClickExecute={onClickExecute} + codeBlockMaxWidthAtom={codeBlockMaxWidthAtom} + > + {props.children} + </CodeBlock> + ),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/app/aipanel/aimessage.tsx(3 hunks)frontend/app/aipanel/aipanel.tsx(3 hunks)frontend/app/aipanel/waveai-model.tsx(3 hunks)frontend/app/element/streamdown.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/app/aipanel/aimessage.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/app/element/streamdown.tsx (3)
frontend/util/util.ts (1)
useAtomValueSafe(425-425)frontend/app/element/copybutton.tsx (1)
CopyButton(59-59)frontend/app/element/iconbutton.tsx (1)
IconButton(12-34)
🪛 ast-grep (0.39.5)
frontend/app/element/streamdown.tsx
[warning] 86-86: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
frontend/app/element/streamdown.tsx
[error] 87-87: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 230-230: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build for TestDriver.ai
- GitHub Check: Analyze (go)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
frontend/app/element/streamdown.tsx (1)
30-90: Shiki HTML insertion is safe here.The static analysis tools flag
dangerouslySetInnerHTMLat line 87, but this is a false positive. Shiki is a trusted syntax highlighter that generates sanitized HTML. The string manipulation (lines 46-49) extracts only the inner<code>content, which is already safe.frontend/app/aipanel/aipanel.tsx (1)
115-132: LGTM! Width tracking with ResizeObserver.The ResizeObserver implementation correctly tracks the panel's width, persists it to
globalStore, and properly cleans up on unmount. This integrates well with the model'scontainerWidthatom for responsive code block sizing.frontend/app/aipanel/waveai-model.tsx (1)
27-27: LGTM! Width management and scroll callback additions.The new width-tracking atoms (
containerWidth,codeBlockMaxWidth) and scroll callback registration cleanly extend the model's capabilities:
containerWidthis updated by the panel's ResizeObservercodeBlockMaxWidthderives a responsive max-width (container width - 35px padding)- The callback pattern for
scrollToBottomis simple and correctThese changes integrate well with the panel's width tracking and enable responsive code block rendering in the Streamdown component.
Also applies to: 34-35, 65-68, 151-157
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
frontend/app/element/streamdown.tsx (2)
8-8: Unify robust text extraction for streamed children (fix highlight/copy/execute).Current getTextContent only handles bare strings; streamed nodes often arrive as arrays/fragments/elements, causing empty text in Code and drift with CodeBlock’s local extractor. Replace with a single recursive extractor and reuse it everywhere.
- import { useCallback, useEffect, useMemo, useRef, useState } from "react"; + import { isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -function getTextContent(node: React.ReactNode): string { - return typeof node === "string" ? node : ""; -} +function extractText(node: React.ReactNode): string { + if (node == null) return ""; + if (typeof node === "string" || typeof node === "number") return String(node); + if (Array.isArray(node)) return node.map(extractText).join(""); + if (isValidElement(node)) return extractText(node.props?.children); + return ""; +} @@ - const text = getTextContent(children); + const text = extractText(children); @@ - const getTextContent = (children: any): string => { - if (typeof children === "string") { - return children; - } else if (Array.isArray(children)) { - return children.map(getTextContent).join(""); - } else if (children.props && children.props.children) { - return getTextContent(children.props.children); - } - return ""; - }; + // use shared extractText @@ - let textToCopy = getTextContent(children); + let textToCopy = extractText(children); textToCopy = textToCopy.replace(/\n$/, ""); await navigator.clipboard.writeText(textToCopy); @@ - let textToCopy = getTextContent(children); + let textToCopy = extractText(children); textToCopy = textToCopy.replace(/\n$/, ""); if (onClickExecute) { onClickExecute(textToCopy); return; }Also applies to: 15-17, 103-114, 124-134, 144-147, 150-156
319-321: Remove hard-coded defaultOrigin=localhost.This rewrites relative links to localhost in production. Let Streamdown infer origin or pass the real origin.
- defaultOrigin="http://localhost"
🧹 Nitpick comments (2)
frontend/app/element/streamdown.tsx (2)
94-101: dangerouslySetInnerHTML: confirm Shiki escaping or sanitize.Shiki typically escapes user content, but this bypasses React XSS guards. Sanitize or document why it’s safe (e.g., DOMPurify) to satisfy linters and harden.
Example:
- dangerouslySetInnerHTML={{ __html: html }} + dangerouslySetInnerHTML={{ __html: html /* already sanitized by Shiki */ }}Or sanitize before setHtml:
// import DOMPurify from "dompurify"; // setHtml(DOMPurify.sanitize(inner, { ALLOWED_ATTR: ["class"] }));
222-228: Pass children via JSX, not children prop.Avoid anti-pattern flagged by linters; keeps React idiomatic.
- pre: (props: React.HTMLAttributes<HTMLPreElement>) => ( - <CodeBlock - children={props.children} - onClickExecute={onClickExecute} - codeBlockMaxWidthAtom={codeBlockMaxWidthAtom} - /> - ), + pre: ({ children }: React.HTMLAttributes<HTMLPreElement>) => ( + <CodeBlock onClickExecute={onClickExecute} codeBlockMaxWidthAtom={codeBlockMaxWidthAtom}> + {children} + </CodeBlock> + ),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/app/element/streamdown.tsx(1 hunks)pkg/aiusechat/usechat.go(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/app/element/streamdown.tsx (3)
frontend/util/util.ts (1)
useAtomValueSafe(425-425)frontend/app/element/copybutton.tsx (1)
CopyButton(59-59)frontend/app/element/iconbutton.tsx (1)
IconButton(12-34)
🪛 ast-grep (0.39.5)
frontend/app/element/streamdown.tsx
[warning] 97-97: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
frontend/app/element/streamdown.tsx
[error] 98-98: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
[error] 224-224: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build for TestDriver.ai
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (go)
🔇 Additional comments (1)
pkg/aiusechat/usechat.go (1)
71-71: Prompt tweak LGTM.Clear, actionable guidance for code/command width. No functional impact.
No description provided.