为 Web 界面提供希伯来语 RTL 渲染:按主导文字判定每个块的方向,输入框的 bidi 处理,以及在 RTL 行上方向正确的 Cmd+左/右 行内跳转。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:kfirsch/dsh-hebrew-rtl
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
English | עברית
Correct Hebrew RTL rendering for the DeepSeek Harness web GUI: per-block direction by dominant script, bidi-safe input fields, and RTL-aware Cmd+←/→ line navigation.
The problem
The GUI renders every block left-to-right. For Hebrew that produces three distinct failures:
- Whole paragraphs read backwards. A Hebrew sentence is laid out as an LTR paragraph, so its lines start on the wrong side and punctuation lands at the wrong end.
- Typing into a field runs the wrong way. The
ask_user_questioncustom-answer field inherits the page direction, so Hebrew typed into it flows left-to-right. Cmd+←/→feel inverted. These shortcuts are logical in every browser:←goes to the line's logical start, which on an RTL line sits at the visual right edge. Pressing←jumps the caret to the far right.
The obvious CSS answer — unicode-bidi: plaintext — fixes only the easy half. It picks a block's direction from its first strong directional character, so a Hebrew sentence that opens with a Latin product name, a list number, or an emoji is still rendered LTR and still reads garbled.
What this plugin does
Per-block direction by dominant script
For each block element (p, ul/ol, h1–h6, blockquote, table) it drops code-like tokens from the block's text, then counts Hebrew-majority words against Latin-majority words in what remains:
| Content | Result |
|---|---|
| No Hebrew prose | No override — unicode-bidi: plaintext stays in charge |
| Hebrew words > Latin words | direction: rtl + text-align: right |
| Latin words > Hebrew words | direction: ltr + text-align: left |
| Equal (both present) | direction: rtl — a block with as much Hebrew as Latin is Hebrew text quoting English |
Forced blocks get unicode-bidi: isolate, so the Unicode Bidi algorithm still lays out the minority-script runs correctly inside the chosen paragraph direction:
היום בדקנו את הפלאגין החדש עם DSH והכול עבד מצוין.
→ RTL, and "DSH" stays in place, unreversed
This is a test sentence with שלום in the middle.
→ LTR, and "שלום" stays in place, mid-sentence
Dominance is the rule because both simpler alternatives fail in an obvious way. First-strong alone mis-renders any Hebrew paragraph that does not begin in Hebrew. "Any Hebrew character forces RTL" over-corrects in the other direction: an English sentence carrying one Hebrew word flips to RTL and its English runs come out reversed.
Why words, and why code tokens are excluded. Counting raw letters breaks on technical Hebrew prose. A single identifier can outweigh a whole paragraph — git+https://git@github.com:kfirsch/...#<sha> contributes 44 Latin letters by itself, and a commit sha another 40 — so a Hebrew sentence that merely cites a URL was rendered LTR. Identifiers, URLs, paths, shas and 15/15-style ratios are therefore stripped before counting; they are still laid out normally, they just no longer vote on the paragraph's direction. Counting whole words rather than letters follows from the same reasoning: a three-letter Hebrew word says as much about the sentence's language as credential does. The stripping is deliberately conservative — an ordinary Latin word standing alone is never treated as code, so genuine English prose still counts in full.
The heuristic is not infallible on a block that is genuinely half-and-half after stripping (a short line of mostly commit hashes with two Hebrew words, say). Those fall back to first-strong rather than guessing.
Composite elements are judged whole, never by their parts. This one rule was learned three times over:
- Tables. Judging each
tdseparately gave a six-row status table three different verdicts — Hebrew label cells went RTL while theHEADandCommitscells beside them stayed LTR — so the label column changed edges from row to row. Column order is a property of the table rather than the cell, so per-cell directions also fight the column order itself. - Lists. The same failure one level down. In a Hebrew numbered list, a short all-Latin item such as
pushhas no Hebrew to weigh, so it got no verdict at all, fell back to the page's LTR, and jumped to the opposite margin from its RTL siblings — breaking the numbering column. - Formulas. KaTeX renders a formula as hundreds of nested
<span>s whose horizontal positions it computes itself. Letting each one pick its own direction tore formulas apart:(idle + rightsizing)and$870/monthcame out reordered into nonsense..katexand its whole subtree are excluded — KaTeX handles bidi itself.
So the direction is decided once per composite, from its whole text, and every part inherits it. unicode-bidi: isolate still lays out each part's own content correctly within that direction.
Blocks are re-evaluated through a MutationObserver as text streams in, coalesced with requestAnimationFrame so streaming does not trigger a scan per character.
Bidi-safe input fields
The composer and the ask_user_question custom-answer field are each a two-layer stack: a visible or measuring mirror layer plus a real <textarea> sharing one grid cell. Both layers must carry identical bidi metrics, or their computed heights and wrapping diverge and the field mis-sizes or the caret drifts away from the glyphs.
Both layers therefore receive unicode-bidi: plaintext together — never the textarea alone — so each line's direction follows what is actually typed into it.
RTL-aware line navigation
A capture-phase keydown listener intercepts Cmd+←/→ only when the caret's current line is RTL, and swaps them so each arrow points where the caret visually goes. Lines that are not RTL are left completely untouched. Shift-extension and selection direction are preserved.
Install
dsh plugin --profile web add github:kfirsch/dsh-hebrew-rtl
Then restart dsh web and hard-refresh the browser tab.
To pin an exact commit (recommended — a later push then cannot silently change what runs):
dsh plugin --profile web add github:kfirsch/dsh-hebrew-rtl#<commit-sha>
The package ships plain hand-written JavaScript in lib/ with no build step, so installing from GitHub needs no allowBuilds approval.
Uninstall
dsh plugin --profile web remove dsh-hebrew-rtl
Scope: Hebrew only, deliberately
The direction rule generalises cleanly to every RTL script — Arabic and its languages, Syriac, Thaana, N'Ko, Adlam — and that version was written and passed a 16-case script matrix. It was then reverted on purpose: neither the author nor a reviewer can proof-read those scripts, and shipping text-direction handling that nobody involved can verify is worse than not shipping it. The package name says what it actually supports.
A pull request adding another script is welcome from someone who reads it and can confirm the rendering by eye.
Compatibility
- Surface: the
webprofile (dsh web). No host service, no configuration, no network access. - What it never touches:
contenteditableregions and code blocks — code stays LTR regardless of its content. - Tested against dsh
0.1.1-rc.2.
License
MIT © Kfir Schneider
For reviewers: why there is no build step
lib/ is not build output — it is the hand-written source, in the exact wire
format the DSH client module system loads. There is deliberately no src/, no
scripts.build and no scripts.prepack, so a clean checkout is already the
artifact and a GitHub install needs no allowBuilds approval.
plugin_check flags all three of those as warnings on the assumption that a
plugin is compiled; they are inapplicable here rather than unaddressed. The
package passes with no errors.
Run the checks yourself:
npm test # smoke-tests the direction rule and the caret swap
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-task-board★ 8759
侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
zhu1090093659/dsh-web#packages/dsh-web-all★ 8759
DSH Web UI 插件与皮肤合集:任务看板、git 图、右侧面板、远程移动端 UI、桌宠、实时 token 统计与皮肤中心。
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 4819
右下角常驻的小鲸鱼挂件:余额、今日已用与每轮对话消耗(含峰谷价),余额预警与今日预算的泡泡内容都可编辑;泡泡点击序列模块化自定义,支持并列加权 A/B、随机台词与随机图片;内置 30+ 厂商模板(OpenAI / OpenRouter / Kimi / 硅基流动 / 方舟 / 智谱 / MiniMax 等),按模型查余额与订阅额度;另有任务结束音效、导入音频、自定义角色与资源管理。数据全在本机,无遥测。
ccch1mneyyy/dsh-TUI★ 4602
Claude Code 风格全屏终端 UI:像素鲸鱼顶栏、实时工作状态行、思考流式展开。
omdsh-dev/DSH-better-sidebar★ 4181
侧边栏完整工作台:内置文件渲染编辑、终端、Git 与子代理,支持三方插件注册新 Tab。
Devin-AXIS/deepseek-design#deepseek-idesign★ 1461
可视化设计工作室,支持网站、App 原型、海报、信息卡、报告和杂志的模板创建、元素编辑、选区级 AI 草稿衔接与导出。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。