Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"gitdiff-parser": "^0.3.1",
"js-md5": "^0.8.3",
"js-yaml": "^4.1.1",
"katex": "^0.16.28",
"lucide-react": "^0.561.0",
"motion": "^12.23.24",
"nanoid": "^5.1.6",
Expand Down
1 change: 1 addition & 0 deletions web/src/bootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import "katex/dist/katex.min.css";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Declare katex as a direct web dependency

Importing katex/dist/katex.min.css here relies on katex being hoisted from streamdown’s transitive dependencies, but web/package.json does not declare katex itself. This can break the web build in environments that don't hoist transitive packages (or after future dependency graph changes), where Vite will fail to resolve the import at startup; adding katex as a direct dependency avoids that fragility.

Useful? React with 👍 / 👎.

import App from "./App.tsx";
import { ErrorBoundary } from "./components/error-boundary";

Expand Down
13 changes: 8 additions & 5 deletions web/src/components/ai-elements/streamdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ export const safeRehypePlugins: StreamdownProps["rehypePlugins"] = [
* 2. Escapes both < and > in HTML-like tags elsewhere
*/
export const escapeHtmlOutsideCodeBlocks = (text: string): string => {
// Match ONLY valid fenced code blocks (``` at line start) and inline code.
// Mid-line ``` is a syntax error and should be treated as plain text.
// Fenced code blocks: ``` at line start, optional language, content, then \n```
// Also match inline code: `..` (single backticks, no newlines inside)
const codeBlockRegex = /(^|\n)```[a-z]*\n[\s\S]*?\n```|`[^`\n]+`/g;
// Match regions that should NOT be escaped:
// 1. Fenced code blocks: ``` at line start, optional language, content, then \n```
// 2. Inline code: `..` (single backticks, no newlines inside)
// 3. Display math: $$...$$ (can span multiple lines)
// 4. Inline math: $...$ (no newlines, non-empty, no leading/trailing space)
// Math delimiters must be preserved because KaTeX needs raw < and > for expressions like $x < y$.
const codeBlockRegex =
/(^|\n)```[a-z]*\n[\s\S]*?\n```|`[^`\n]+`|\$\$[\s\S]*?\$\$|\$(?!\s)[^$\n]+(?<!\s)\$/g;
const codeBlocks: { start: number; end: number }[] = [];

// Find all valid code blocks
Expand Down