Skills Plugins MCP Prompt Model 导航 博客 资讯 我的中心
工具与能力 #dsh-plugin

dsh-plugin-quote

Select text in the DeepSeek Harness Web conversation and append it to the composer as a markdown blockquote.

xieweikang123 @xieweikang123 ⬇ 1 ★ 0 main

安装

dsh plugin --profile web add github:xieweikang123/dsh-plugin-quote
下载安装清单

需要可复现安装时,可在仓库后追加 #commit 固定提交。

Select text in the DeepSeek Harness Web conversation and append it to the composer as a markdown blockquote.

该插件未提供要点说明,请参考仓库 README。

dsh-plugin
  1. 安装并启动 DeepSeek Harness:npx @deepseek-ai/dsh web
  2. 在终端执行上面的安装命令(CLI 会解析插件并核验来源)
  3. 用 dsh plugins list 确认已安装,必要时重启 Harness 生效

插件以当前 dsh 进程的权限运行,安装时可能执行代码。请先通读仓库源码与许可证,确认无破坏性命令与越权访问;本站只做索引,不对第三方插件安全性作担保。

代码仓库github.com/xieweikang123/dsh-plugin-quote
许可证MIT
主要语言main
下载量1
GitHub 星标0
最近推送2026-09-11
收录日期2026-09-19
分类工具与能力

事实信息来自公开插件目录快照(2026-10-01),介绍文案由本站再加工。

以下为插件仓库 README 全文(原始内容,由公开目录抓取整理)。

# dsh-plugin-quote

A DeepSeek Harness Web plugin. Select text in the conversation, click the button that appears, and the selection lands in the composer as a markdown blockquote.

```
my question

> the paragraphs you selected
> keep their line breaks

```

Nothing new reaches the model: the quote is ordinary user text, exactly as if you had typed it.

## Requirements

- DeepSeek Harness with the **Web** profile (`dsh web`). There is no composer in the `headless`, `sdk`, or `acp` profiles, so the plugin is inert there.
- Built and tested against **dsh `0.1.5-rc.1`**. Harness plugin APIs are pre-stable — see [Compatibility](#compatibility).

## Install

```sh
npm install @walkerxie/dsh-plugin-quote
```

Then add one row to your Web profile's patch file (`~/.dsh/profiles/web/cordis.patch.yml`), pointing at the installed package:

```yaml
- insert:
    - id: ui-quote
      name: '@walkerxie/dsh-plugin-quote'
```

To run from a checkout instead — useful while developing the plugin itself — build it and point the row at the file:

```sh
git clone https://github.com/Xieweikang123/dsh-plugin-quote.git
cd dsh-plugin-quote
npm install
npm run build
```

```yaml
- insert:
    - id: ui-quote
      name: 'file:///absolute/path/to/dsh-plugin-quote/lib/index.js'
```

The profile reloads its patch live, so a page refresh is enough. If the button does not appear, restart `dsh web` once so the loader picks the new row up from boot.

## Uninstall

Delete the `- insert:` block — or set `disabled: true` on the row — and refresh. The plugin owns nothing else: no config, no session data, no files of its own.

## Usage

1. Select text inside a message. Selections inside the composer itself never offer the button, because that is you editing your own draft.
2. Click **引用选中文字** / **Quote selection**. It appears below the selection, right-aligned to the last selected line.
3. The selection is appended to the draft as a blockquote, the control disappears, and focus moves to the composer with the caret at the end of the draft. Keep typing.

Escape dismisses the control without touching your selection.

## How it works

- **One entry, no host behavior.** The plugin registers a single `conversation.input.overlay` entry and its host half is an empty `apply()`. It adds no tool, no prompt section, and no session event.
- **Selection tracking.** One document-level source listens for `selectionchange`, pointer and key gestures, scroll, and resize, and publishes only what changed. A selection is quotable only inside the conversation transcript. The anchor is the last line's box with a non-zero area: engines emit a zero-size rect for a trailing line break, and anchoring to it would pin the control to the viewport's top-left corner.
- **The plugin owns its coordinate frame.** The control renders into a zero-size host the plugin creates as a direct child of `` and pins to the viewport origin with `position: fixed`. The button inside it is `position: absolute`, so its coordinates are true viewport coordinates — the same space `getBoundingClientRect()` reports the selection in. Nothing above the host can reinterpret them: `position`, `transform`, `filter`, `perspective`, and `contain` on any ancestor all change what `fixed` resolves against, and the document element has no ancestor to do that. The host is created during the first render rather than in an effect, so the very first paint is already in the right space.
- **The draft write.** The control calls the composer's own public `inputActions.setDraft()`. It reads and writes no state of its own — the draft stays where it already lives.
- **Focus hand-off.** `setDraft` leaves the editor's selection at the end of the draft but moves no DOM focus, so the control focuses the composer's editor itself and collapses the caret at the end. The card to focus is read from the control's own slot seat, not by searching the document, because the button now lives outside it and a settled message's editor would otherwise be found first.
- **Fixed contrast, not themed.** The control's fill and text are hard-coded black on white rather than drawn from theme tokens. It floats over conversation text it does not own, so it must stay legible over whatever is behind it; a themed pair would flip with the host theme and could land light-on-light or dark-on-dark. The border and shadow are still themed, because they only soften the edge. This is also why the control stays readable without the harness defining any particular token.

## Compatibility

DeepSeek Harness plugin APIs are **pre-stable**: nothing below is a compatibility promise, and a harness update can break this plugin silently — the quote still lands, or the button simply stops appearing.

This plugin depends on:

| Dependency | Kind |
| --- | --- |
| The `conversation.input.overlay` slot, declared by `@deepseek-ai/dsh-client-ui-conversation` | slot name |
| The `useInput` and `inputActions` props that every session-scope slot receives | framework contract |
| `ctx.slots` and `ctx.locale` services | framework contract |
| `[data-conversation-scroll]`, `[data-composer-card]`, and `[data-composer-input]` DOM markers | **not a contract** — internal markers |
| `react-dom`'s `createPortal` and a document root to portal into | framework contract |

The first three failing is loud. The DOM markers failing is silent, and the focus hand-off is a documented workaround rather than an API.

## Known limits

- **The control covers the line below the selection.** Placement is a fixed offset below the selection's last line, so the button sits over whatever follows it. Reserving layout space instead would reflow the transcript on every selection.
- **Append only.** The public composer API exposes whole-draft replacement and no insert-at-caret verb, so a quote always lands at the end of the draft.
- **Plain text only.** Quoting a fenced code block drops its fences and quoting a table drops its cell separators, because the browser's text serialization returns rendered text.
- **Transcript only.** Selections in the trajectory or waterfall views offer nothing; they are separate surfaces.
- **One action.** This is a quote button, not a selection toolbar. Copy, search, and annotation belong to whichever surface owns those decisions.

## Development

```sh
npm install
npm test          # unit + real-cordis registration tests
npm run typecheck
npm run build     # lib/index.js (host half) + lib/client.js (browser half)
```

`lib/client.js` is not a plain bundle: the Web shell mounts plugins through a closure-factory contract, so the build wraps the browser half in `window.__ModuleLoader__.load({ id, factory })` and resolves React and the other platform modules through the injected `require` instead of inlining them. `scripts/build.mjs` is that whole build, with a small CSS Modules compiler in front of it.

### The CSS Modules compiler

Two details of that compiler are load-bearing, and both fail silently when wrong:

- **The class map must hold plain strings.** lightningcss reports each export as `{ name, composes, isReferenced }`, and handing that object to `className` renders `[object Object]`, which no selector matches — every rule in the file is dropped. The build flattens the records to names.
- **The style tag is keyed by a content hash.** HMR re-runs the module factory in the live page, so a path-only key would find the previous sheet still tagged and skip injecting the new one.

`tests/build.client.spec.ts` asserts both against the built bundle, because neither is visible in the sources.

## License

MIT

数据来源:公开的 DeepSeek Harness 插件目录与各插件 GitHub 仓库。本站为独立第三方目录,与 DeepSeek、幻方(High-Flyer)及插件作者均无隶属或背书关系。

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。