diff --git a/README.md b/README.md index 2968782..dbe65ed 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ - **🌐 内嵌浏览器**:多开网页 tab,后退 / 前进 / 刷新;内容运行在沙箱 iframe;外链默认按协议分流——HTTP 在侧边栏打开、HTTPS 走系统浏览器(设置页可分别调整) - **💻 真实终端**:xterm.js + node-pty 真实 shell,断线重连回放;可选为模型注入 `terminal_*` 工具 - **📂 模型侧边栏打开(可选)**:全局设置开启后注入 `sidebar_open` 工具——模型可主动在侧边栏打开文件 / 文件夹(树以该目录为根)/ HTTP(S) 网页 -- **🌿 文件变动**:Git 视角(真 diff / 历史 / 暂存·提交·还原 / worktree·子仓库选择)与本轮文件视角(模型读 / 写 / 编辑实时追踪,按文件分组、按类型筛选)**双视角合一**;统一 diff 渲染(改蓝配对 + 行内字符级高亮 + 语法着色(含 mjs/cjs/mts/cts、CSS/SCSS/Less、HTML/XML/SVG/Vue、GraphQL、JSONC/JSON5)+ 上下文折叠),底部可拖拽预览面板,可一键展开为独立 diff tab(默认自由浮窗,可在设置改为面板下半 split);`.md` 操作(读 / 写 / 编辑)预览头部可切换**阅读模式**——经共享 MarkdownText 渲染 GFM 表格 / 任务列表 / 删除线 / 脚注 / 数学公式,本地图片自动改写为 `/sidebar/file` 媒体路由(与编辑器预览同一渲染栈) +- **🌿 文件变动**:Git 视角(真 diff / 历史 / 暂存·提交·还原 / worktree·子仓库选择)与本轮文件视角(模型读 / 写 / 编辑实时追踪,按文件分组、按类型筛选)**双视角合一**;统一 diff 渲染(改蓝配对 + 行内字符级高亮 + 语法着色(含 mjs/cjs/mts/cts、CSS/SCSS/Less、HTML/XML/SVG/Vue、GraphQL、JSONC/JSON5)+ 上下文折叠),底部可拖拽预览面板,可一键展开为独立 diff tab(默认自由浮窗,可在设置改为面板下半 split);`.md` 操作(读 / 写 / 编辑)预览头部可切换**阅读模式**——经共享 MarkdownText 渲染 GFM 表格 / 任务列表 / 删除线 / 脚注 / 数学公式,本地图片自动改写为 `/sidebar/file` 媒体路由;含 ```mermaid 围栏时走编辑器同款懒加载 mermaid 渲染器(图可点击缩放 / 平移) - **🧩 后台任务页**:subagent 拓扑 + 后台任务(退出码 / 实时输出 / 强制终止) - **💬 侧边对话(beta)**:Codex 风格的侧边线程——继承主会话完整上下文(含进行中的回合与工具调用)独立运行,不进入主会话;线程内可持续追问,一键「保存为新会话」提升为顶层会话 - **🪟 双工作台**:右侧栏 + 底部面板;拖 Tab 拆分 / 合并分栏(可跨面板),移动端自动合并全宽抽屉 diff --git a/README_EN.md b/README_EN.md index 52f39fd..75b4c65 100644 --- a/README_EN.md +++ b/README_EN.md @@ -44,7 +44,7 @@ - **🌐 Embedded Browser**: multiple web tabs with back / forward / refresh; content runs in a sandboxed iframe; external links are routed by protocol by default — HTTP opens in the sidebar, HTTPS goes to the system browser (both adjustable in settings) - **💻 Real Terminal**: xterm.js + node-pty real shell, reconnect with transcript replay; optionally injects `terminal_*` tools for the model - **📂 Model-driven sidebar opens (opt-in)**: with the global setting on, the `sidebar_open` tool lets the model actively open files / folders (tree rooted there) / HTTP(S) pages in the sidebar -- **🌿 Changes**: one tab, two lenses — **Git** (real diff / history / stage·commit·revert / worktree & child-repo selection) and **This Session** (live tracking of every file the model reads / writes / edits, grouped by file with kind filters); a unified diff renderer (mod pairing + intra-line character highlights + syntax coloring incl. mjs/cjs/mts/cts, CSS/SCSS/Less, HTML/XML/SVG/Vue, GraphQL, JSONC/JSON5 + context folding), a draggable bottom preview pane, and one-click expansion into a dedicated diff tab; `.md` ops (read / write / edit) offer a **reading-mode** toggle in the preview header — the shared MarkdownText renders GFM tables / task lists / strikethrough / footnotes / math, with local images rewritten through the /sidebar/file media route (the same rendering stack as the editor preview) +- **🌿 Changes**: one tab, two lenses — **Git** (real diff / history / stage·commit·revert / worktree & child-repo selection) and **This Session** (live tracking of every file the model reads / writes / edits, grouped by file with kind filters); a unified diff renderer (mod pairing + intra-line character highlights + syntax coloring incl. mjs/cjs/mts/cts, CSS/SCSS/Less, HTML/XML/SVG/Vue, GraphQL, JSONC/JSON5 + context folding), a draggable bottom preview pane, and one-click expansion into a dedicated diff tab; `.md` ops (read / write / edit) offer a **reading-mode** toggle in the preview header — the shared MarkdownText renders GFM tables / task lists / strikethrough / footnotes / math, with local images rewritten through the /sidebar/file media route; documents with ```mermaid fences render through the editor's lazy mermaid renderer (click-to-zoom / pan diagrams) - **🧩 Background Tasks**: agent topology + background tasks (exit codes / live output / force-kill) - **💬 Side Chat (beta)**: Codex-style side threads — the child inherits the parent's FULL context (completed turns + the pending question + the in-progress turn's assistant output and tool activity, honestly frozen as "interrupted") and runs independently without entering the main conversation; threads support continuous follow-ups (auto-resumed after a DSH restart) and one-click "Save as new session" promotion to a top-level session - **🪟 Dual Workbench**: right sidebar + bottom panel; drag tabs to split / merge panes (cross-panel), mobile auto-merges into a full-width drawer diff --git a/src/client/MarkdownHtml.tsx b/src/client/MarkdownHtml.tsx index 70011ab..ce291bb 100644 --- a/src/client/MarkdownHtml.tsx +++ b/src/client/MarkdownHtml.tsx @@ -31,11 +31,11 @@ import type { SessionScope } from './api.ts' import css from './sidebar.module.css' /** The chunk-resident markdown renderer (mermaid lazy chunk), shared with the - * legacy no-HTML preview path in TextEditor. */ -export const LazyMermaidMarkdown = lazyChunkComponent( - 'mermaid', - (mod) => mod.MermaidMarkdown as ComponentType | undefined, -) + * legacy no-HTML preview path in TextEditor. Defined in mermaid-lazy.tsx (a + * light module) so core-bundle consumers can import the stub without + * dragging DOMPurify along. */ +export { LazyMermaidMarkdown } from './mermaid-lazy.tsx' +import { LazyMermaidMarkdown } from './mermaid-lazy.tsx' /** Everything the sanitizers need to resolve local media + scope the route. */ export interface MarkdownHtmlMedia { diff --git a/src/client/changes/DiffPane.tsx b/src/client/changes/DiffPane.tsx index 939a221..e00bdf3 100644 --- a/src/client/changes/DiffPane.tsx +++ b/src/client/changes/DiffPane.tsx @@ -23,6 +23,8 @@ import { buildDiffSegments, diffLines, diffStats, parseUnifiedDiff, unifiedSegme import { parseReadContent, parseReadLines, type FileOp } from './ops.ts' import { rewriteLocalImageUrls } from '../markdown-images.ts' import { markdownTextProps } from '../markdown-labels.tsx' +import { splitMermaidBlocks } from '../mermaid-blocks.ts' +import { LazyMermaidMarkdown } from '../mermaid-lazy.tsx' import css from './changes.module.css' import diffCss from '../diff/diff.module.css' @@ -183,6 +185,13 @@ export function DiffPane({ target, scope, height, onHeightCommit, onClose, onExp : ''), [mdOp, reading, readingSrc, scope, target], ) + // Mermaid fences render through the same chunk-resident renderer the editor + // preview uses (one MarkdownText pass with the mermaid fences lifted out); + // the plain single-pass path stays byte-for-byte for documents without any. + const readingHasMermaid = useMemo( + () => (readingText !== '' ? splitMermaidBlocks(readingText).some((block) => block.kind === 'mermaid') : false), + [readingText], + ) const codeLabels = { copyLabel: t('copy'), copiedLabel: t('copied') } // Header stats for git targets come off the parsed patch text. @@ -310,7 +319,9 @@ export function DiffPane({ target, scope, height, onHeightCommit, onClose, onExp ? (
- + {readingHasMermaid + ? + : }
) diff --git a/src/client/mermaid-lazy.tsx b/src/client/mermaid-lazy.tsx new file mode 100644 index 0000000..3a56793 --- /dev/null +++ b/src/client/mermaid-lazy.tsx @@ -0,0 +1,16 @@ +/** + * The chunk-resident markdown renderer (mermaid lazy chunk): a light stub + * module so core-bundle consumers (the changes tab's reading mode) can mount + * the mermaid-aware renderer without statically pulling MarkdownHtml's + * DOMPurify/HTML-analysis machinery into the core bundle. The chunk itself + * (src/client/chunks/mermaid) loads on first render via /sidebar/bundle. + */ +import type { ComponentType } from 'react' +import { lazyChunkComponent } from './lazy-chunk.tsx' +import type { MermaidMarkdownProps } from './mermaid-blocks.ts' + +/** Shared with the legacy no-HTML preview path in TextEditor (re-exported). */ +export const LazyMermaidMarkdown = lazyChunkComponent( + 'mermaid', + (mod) => mod.MermaidMarkdown as ComponentType | undefined, +)