DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Rtl Chat Box — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
R

dsh-rtl-chat-box

Rtl Chat Box

dsh 网页 GUI 的从右到左聊天框:在阿拉伯语样式的 RTL 和 LTR 之间切换输入框(以及可选的消息文本),而不影响界面的其他部分

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:Mhmd7-7/dsh-rtl-chat-box#7eb319361e0cbbd9badca3b708c7b29c1d7e7deb
README兼容性版本

兼容性与来源证明

Rtl Chat Box 以 dsh-rtl-chat-box 发布,当前版本为 0.4.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/9/22

版本

0.4.0stable
2026/9/22
0.3.0stable
2026/9/22
0.2.0stable
2026/9/22
查看其余 1 个版本收起版本
0.1.0stable
2026/9/18

相关插件

正在加载相关插件…

最新版
0.4.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/9/22
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 ui-customization 分类下经过校验的插件。

Web App@deepseek-ai/dsh-web-appdsh 浏览器界面捆绑包:位于 dsh-base 之上的 Web 补丁层,加上运行时粘合插件(提供前端 dist、Web 界面提示符、bash 运行时变量和 URL 行)Experimental Agent Team Web Profile@deepseek-ai/dsh-experimental-agent-team-web-profile用于 Agent Teams Remote 和 UI 插件的实验性 Web 配置层Ab Chartdsh-ab-chart带有绘制其调用的浏览器卡片的图表渲染工具,封装在一个可发布的插件包中Whale Widgetdsh-whale-widgetDSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义

README

dsh-rtl-chat-box

Right-to-left chat box for the dsh web GUI — for writing Arabic (or any RTL script) in the composer, and back to English.

It changes only the chat text box, never the page root: the sidebar, columns, and every other surface keep their normal left-to-right layout.

Controls

Settings → General → Chat box direction

ControlEffect
RTLThe chat box becomes right-to-left: caret, alignment, and reading order.
LTRThe chat box is left-to-right again.
AutoEverything follows whatever you type — Arabic reads RTL, English stays LTR. Each list item, paragraph, and typed line follows its own language, in the box and in message text.
Smart bidiMixed Arabic/English inside one message keeps correct ordering (unicode-bidi: plaintext on the box). Forced on in Auto.
Also message textOff (default) = chat box only. On = sent messages and transcript paragraphs follow the direction too. Forced on in Auto, because Auto that stopped at the box would leave every sent Arabic message reading left-to-right.

pre / code / kbd / samp are pinned to LTR in RTL mode so code never scrambles.

The composer is a rich-text editor, not a textarea

The GUI does not put the composer in a textarea. It binds Lexical to a contenteditable host and Lexical writes one block element per line (<p>, and <li> inside a list) as children of that host.

unicode-bidi does not inherit, and the property's own definition is explicit that plaintext on a block box "will not affect any descendant blocks". A rule on the host therefore never reaches a single character that is typed — measured: with only the host rule, a paragraph inside the host stayed left-aligned while the same paragraph matched by a p rule went right-to-left.

So the Auto (and smart) sheet names the host's block descendants as well:

[contenteditable]:not([contenteditable="false"]) :where(p, div, li, …) { unicode-bidi: plaintext; }

This also makes the mode independent of the editor: Lexical happens to write dir="auto" on its top-level blocks today, and the plugin must not depend on that. direction is still never forced in Auto, so English reading order is never touched.

List markers in Auto

Auto decides the marker per item, from that item's own language:

ItemMarker
Arabic (نستكشف المشروع)right edge, next to the text
English (Explore the project)left edge, next to the text

This needs list-style-position: inside, and the reason is subtle.

unicode-bidi: plaintext on the li only changes how the item's content is ordered — it derives the paragraph direction from the first strong character. It does not change the element's direction property.

A ::marker with list-style-position: outside lives in its own box beside the item, and the side it takes is decided by that item's direction property. Because plaintext never touches that property, an outside marker is stuck on one fixed side — which is why the number stayed on the left for Arabic items no matter what else was tried.

With inside, the marker becomes the first inline box of the item's own content, so it is ordered by the same plaintext-derived paragraph direction as the text. That is the only way to get a per-item marker side from CSS. Two consequences of inside then have to be handled, and both were measured in Chromium rather than reasoned about.

A block child strands the marker

Markdown emits <li><p>…</p></li> whenever a list is loose — a blank line between items, which is common in replies. The marker is the item's first inline box, so a block child leaves it alone on a line of its own: the item measured 56px tall with its paragraph starting 32px down, i.e. the number drawn above the text.

The GUI's own stylesheet already works around this for ol nested in a list (:where(ul,ol) ol li p { display: inline }). Auto does it for every list:

li > p:first-child { display: inline; unicode-bidi: normal !important }

unicode-bidi: normal is load-bearing, and leaving it out is a real trap: the shared rule gives every p plaintext, which on an inline box becomes an FSI … PDI isolate. UAX9 rule P2 ignores the characters inside an isolate while looking for the paragraph's first strong character, so the item found no strong character, fell back to LTR, and put the Arabic marker back on the left. Made transparent to the bidi algorithm, the inlined paragraph's text is what the item's own plaintext paragraph reads. Later paragraphs stay blocks, so multi-paragraph items keep their breaks.

!important on that unicode-bidi is what carries it into the composer. The rule above that gives the host's block descendants plaintext is scoped to [contenteditable], so it specificities at (0,2,0) — [contenteditable] plus the :not() argument — while li > p:first-child reaches only (0,1,2). Without the flag the composer's own plaintext wins, the isolate is back, and an Arabic item's number returns to the left. Measured in Chromium, an Arabic <li><p> inside a contenteditable host:

SheetLeft gapRight gapMarker
without !important20px319pxleft
with !important319px20pxright

Transcript text was never affected — nothing there outranks the rule — which is what made the fault read as a marker bug rather than a cascade one. The flag is a declaration-level win over a sibling rule of this same sheet, not another override of the GUI's stylesheet.

A nested list needs its own step in

With every gutter zeroed (padding-inline-*: 0) a nested list lost its indentation entirely — the child item's text landed on the parent's edge. The marker cannot supply it either: inside markers have no gutter column. So the inset comes from the nested block itself:

li > ul, li > ol { padding-inline: 0.9em !important }

It is symmetric on purpose. One list holds Arabic and English items side by side, and only an explicit direction could pick a side — which is exactly what Auto does not have.

In RTL and LTR modes one direction is set for the whole list, so those keep outside markers and the hanging indent — and neither of the two workarounds above is emitted.

Blockquote bars and task-list boxes

Two things depend on the item's direction property, which plaintext never changes and one list cannot vary per item, so Auto leaves them at their physical defaults:

  • a blockquote keeps its bar on the left even when its Arabic text aligns right (the GUI's markdown sheet sets border-left / padding-left physically);
  • a task-list input[type=checkbox] keeps the GUI's margin: 0 8px 0 0, so the gap sits on the checkbox's outer side for an Arabic item rather than between the box and its text.

RTL sets one direction for the whole surface, so it can — and does — mirror both: the bar moves to the right (border-right + padding-right) and the checkbox gap flips to the left (margin: 0 0 0 8px). LTR needs neither, because the GUI is already left-to-right.

Why the GUI's own list CSS must be overridden

The markdown stylesheet in dsh-web-frontend does this:

._markdown_ :where(ul,ol)    { padding-left: 18px }
._markdown_ :where(ul,ol) ol { list-style-position: inside; padding-left: 0 }

padding-left is physical. In a right-to-left list the marker needs its gutter on the right, so a left-only inset leaves the number with nowhere to go.

That selector — a class plus :where() — has specificity (0,1,0), so a plain ul, ol rule loses to it. Every rule the plugin uses to correct list layout is therefore marked !important.

The choice is stored in localStorage under dsh-rtl-chat-box, so it survives a page reload.

Layout

PathRole
package.jsonBundle manifest — dsh.bundle.patch and the dsh.client entry (platform: web).
cordis.patch.ymlInserts the ui-rtl-chat-box row into the web plugin roster.
lib/index.jsHost loader entry. Deliberately a no-op: nothing host-side.
lib/client.jsThe browser half — the direction stylesheet plus the General settings row.
CHANGELOG.mdRelease history, starting at 0.1.0.
LICENSEMIT.
.gitignoreNode/JS ignores, plus the local probe/ scratch space used when measuring layout.

Requirements

RequirementVersionNotes
dsh0.1.5-rc.2The only release this plugin has been checked against. Declared per release in dsh.compatibility.dshReleases; other versions are unverified.
@deepseek-ai/cordis^4.0.1Peer dependency, resolved from the profile's own installation.
ProfilewebThe plugin has a browser half and registers a settings.general.item slot.
Node.jsany version the installed dsh itself supportsThe package is plain ESM with no build step, so it adds no Node version requirement of its own.

dsh-rtl-chat-box has no runtime npm dependencies. lib/index.js and lib/client.js ship prebuilt in the repository, so there is no prepare/build step for pnpm to approve: installing straight from GitHub does not need an allowBuilds entry in the profile's pnpm-workspace.yaml.

Install

dsh plugin --profile web add "github:Mhmd7-7/dsh-rtl-chat-box"

To install a local checkout instead of the GitHub source, pass its path in place of the spec:

dsh plugin --profile web add "C:\path\to\dsh-rtl-chat-box"

Then restart the web profile — the client bundle is built when the server starts, so a running GUI will not pick this up until it restarts.

A restart really is required, and a page refresh is not enough: the host caches each /plugins/<id>/client.js response with an immutable-cache header, keyed by the content revision baked into window.__DSH_BOOT__ — and that revision is computed when the plugin graph is composed, which happens at server start. The client-hmr row that would recompose on change is idle until a rebuild watcher (pnpm run dev:web from a source checkout) rewrites bundles, so an edited lib/client.js stays invisible to a server that started before the edit.

Uninstall

dsh plugin --profile web remove dsh-rtl-chat-box

Checking a change

The stylesheet is generated by cssFor(), so it can be rendered and measured without the GUI. The probe that produced every number in this file loads the plugin's own lib/client.js in Node (with window/document stubs), writes a page per preference state next to a copy of the GUI's markdown stylesheet, and reads geometry back from headless Chromium:

chrome --headless=new --dump-dom --virtual-time-budget=3000 file:///…/page.html

Per element it reports the text's ink gaps against the content box, which is what distinguishes a marker on the right from one on the left, and li height plus first-child offset, which is what catches a marker stranded on its own line.

Notes

The direction is applied through a single <style> element appended to document.head and removed when the plugin's fiber is disposed.

The box is matched as textarea or a live contenteditable surface. Message text — only when "also message text" is on — is scoped under the transcript column, [data-chat-flow], so the sidebar, settings, and every other surface keep their normal layout. Direction is set on that container (it inherits) rather than per paragraph, which is also what reaches the user-message bubble: a plain div with no stable class of its own, so it could not be matched directly. In Auto / smart modes that same bubble follows its own language via unicode-bidi: plaintext on div.

Permissions and scope

A dsh plugin runs with the permissions of the dsh process that loads it. This one is a browser-side plugin, and what it touches is bounded:

SurfaceAccess
Host files, network, child processes, credentialsnone — lib/index.js exports an empty apply() and nothing else.
Browser DOMappends one <style> element to document.head, removed when the plugin's fiber is disposed.
Browser storageone localStorage key, dsh-rtl-chat-box, holding the direction preference. A blocked storage backend only costs persistence, never the live effect.
Settings UIregisters one row at settings.general.item.

The package declares no file, network, command, or credential access and has no runtime dependencies. It also has no preinstall, install, postinstall, or prepare script — installing it runs nothing.

Being listed in a plugin catalogue is not a security review, so read the source: the whole plugin is lib/client.js plus a no-op host entry.

Contributing

Issues and pull requests are welcome at https://github.com/Mhmd7-7/dsh-rtl-chat-box.

  • Open an issue for a bug or a behaviour question. Include the direction mode (RTL / LTR / Auto), what you expected, and what the box did instead.
  • Keep a pull request focused on one change. Please do not refactor the direction logic (cssFor() in lib/client.js) as a side effect: the comments there record why each rule is shaped the way it is, and most of those details were measured in Chromium rather than reasoned about.
  • Any layout claim should arrive with the measurement that supports it, in the form described under Checking a change.
  • Add your entry to CHANGELOG.md under ## [Unreleased], and bump version in package.json if the release is part of the pull request.

License

MIT © 2026 Mhmd7-7