DeepSeek Harness Plugin Hub

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

探索

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

社区

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

相关链接

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

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

Hook Dsh Normalize Quotes — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins

@playform/hook-dsh-normalize-quotes

Hook Dsh Normalize Quotes

quotes hook:一个 DeepSeek Harness 插件,挂接 llm/stream waterfall——每次流式模型调用都可拦截的包装器——并规范化弯引号系列(U+2018 左单引号、U+2019 右单引号、U+

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

npx -y @deepseek-ai/dsh plugin --profile web add @playform/hook-dsh-normalize-quotes@0.0.1
README兼容性版本

兼容性与来源证明

Hook Dsh Normalize Quotes 以 @playform/hook-dsh-normalize-quotes 发布,当前版本为 0.0.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
any
发布来源
npm
Registry 更新时间
2026/10/17

版本

0.0.1stable
2026/10/9

相关插件

正在加载相关插件…

最新版
0.0.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
38.5 kB
文件数
24
Surface
any
许可证
CC0-1.0
发布源
npm
GitHub
★ 1
周下载
408
安全扫描
✓ v0.0.1 扫描通过
最近提交
2026/10/17
查看源码 ↗项目主页 ↗
README Badge

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

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

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

认领这个 Plugin →
报告问题

相关插件

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

Cc Safety Netcc-safety-net编码代理 CLI 钩子——阻止破坏性命令和访问机密文件Plugin Shopdsh-plugin-shopDeepSeek Harness 插件商店:从可通过 Git 审计的目录中浏览、安装、启用和更新 dsh 插件。Mattpocock Skills Deckdsh-mattpocock-skills-deck安装即自带mattpocock/skills v1.3.1的27个工程与效率技能,无需手动装技能。400亿token打造本插件,在原始技能之上提供10倍的开发效率,也能帮助新手更快上手该技能套件。全力支持GitHub issue;Markdown为预览版;GitLab暂不支持。感谢您的使用和支持💗Bridge@wenbin_wb/dsh-bridgeDSH 远程连接/远程控制插件(remote control):手机扫码即可在移动端/公网继续用 DeepSeek Harness,人不在电脑前也能接着干。一键局域网二维码、Cloudflare 公网隧道、自建隧道与微信 / QQ / 飞书 / Telegram Bot(多工作区/会话持久化/媒体/卡片审批/流式输出),无需自己搭公网服务器。

README

@playform/hook-dsh-normalize-quotes

The DeepSeek Harness Plugin Family for PlayForm.

[!NOTE]

The quote normalizer for model output - a DeepSeek Harness plugin that hooks the llm/stream waterfall (the interceptable wrapper around EVERY streaming model call, bound to the LlmRuntime) and normalizes the curly quote family in model output, live in the transcript: the eight typographic quote code points each map to their ASCII straight counterpart - U+2018/U+2019/U+201A/U+201B to the ASCII apostrophe, and U+201C/U+201D/U+201E/U+201F to the ASCII double quote.

A MAP flavor of the normalize family: the core's Quotes char-to-char table owns the substitution - no replacement config knob.

The @-sentence identity: Hook @ DSH @ Normalize @ Quotes.

The family's raw-write tool (registered by hook-dsh-normalize-dash) bypasses this flavor's transforms too - the exemption is family-wide: the core's Stream/Chunk + Stream/Block pass every raw-write call through by identity, so the tool's explicit normalize parameter (default false = verbatim) is the only normalization it applies.


Where It Fits

Family position (the @-sentence Hook @ DSH @ Normalize @ Quotes): a hook child of the plugin-dsh-factory service and the hook-dsh-core machinery; the second of the six stream normalizer siblings.

One of six siblings in the stream-normalization family, all built on the shared machinery - plugin-dsh-factory for State/Append (and the named Schema helper, shared: false, for the config), hook-dsh-core for the Quotes table and the generic ReplaceMap/Chunk/Block dispatch:

flavortablesubstitution
hook-dsh-normalize-dashcore Dashes class→ replacement (default -)
hook-dsh-normalize-quotes (this bundle)core Quotes MAPcurly → straight
hook-dsh-normalize-ellipsiscore Ellipsis classU+2026 → ...
hook-dsh-normalize-spacescore Spaces classunicode spaces → " "
hook-dsh-normalize-invisiblecore Invisible classremoved (default "")
hook-dsh-normalize-fullwidthcore Fullwidth MAPfull-width → half-width

A non-manifest factory consumer: it injects ["pluginFactory"] and uses State (cell unwrap + shared Ledger/Enabled mappings + its own fields), Append and Journal (the shared P5 record on every N > 0 pass); the config is composed by the factory's standalone Schema helper with shared: false - the minimal block, no fs/observed dead fields.

It touches no files, so fs/write-intent and fs/observed never see it; it wraps the downstream result and always calls next(), so it composes with other llm/stream listeners regardless of registration order.

The DSH plugin family is the DeepSeek Harness plugin layer of the PlayForm ecosystem: TypeScript-first Source/ → Target/, the deterministic @playform build, prepublishOnly-only - the same conventions as every other @playform package.

Install

Terminal (registry)

pnpm add @playform/hook-dsh-normalize-quotes
  1. Remote / dependency install (auto-activation): pnpm add @playform/hook-dsh-normalize-quotes in a profile dir (+ the package name in dsh.profile.bundles, or dsh plugin add) - installed automatically and activated at the next host start.
  2. Local git clone: clone → pnpm install inside the bundle (its pnpm-workspace.yaml pins packages: [.] so the install lands in the bundle, not the workspace root) → build → dsh plugin --profile <name> add <this directory>.
  3. Tarball / npm: dsh plugin --profile <name> add <tarball-or-spec> - the package ships built Target/ (minified, .d.ts twins), so no build runs at install time.

Verify with the hook-dsh-normalize-quotes: activated (...) ledger line.

Usage

The bundle is configured through its cordis.patch.yml row (or the profile's dsh.bundle manifest) - the full config table is in The Config:

- insert:
      - id: hook-dsh-normalize-quotes
        name: "@playform/hook-dsh-normalize-quotes"
        config:
            log: true
            logFile: ~/.dsh/hook-dsh-normalize-quotes.log
            normalizeReasoning: true

The Problem

Smart-quote processors and code editors emit typographic quotes; every parser, shell and diff understands the straight ASCII ones.

Left in model output, a curly quote is a silent correctness hazard - in code blocks, commands and file paths it is simply the wrong character.

This flavor makes the straight form the one that reaches the transcript.


How It Works

The stream pipeline

  llm/stream waterfall (options, next)     the interceptable wrapper around
       │                                   EVERY streaming model call
       ▼  next() called FIRST, always - options never touched
  Normalize(upstream, state)               the async generator
       │   for await (chunk of upstream)
       ▼
  CoreChunk(chunk, transform, reasoning, toolArgs, raw)  the core's per-chunk dispatch
       │
       ├─ text-delta ────────► ReplaceMap(text, Quotes)     rewrite the text field
       ├─ reasoning-delta ───► same, when normalizeReasoning (default ON)
       ├─ block-end ─────────► the assembled block's text fields -
       │                       TextBlock.text / ReasoningBlock.text (plus a
       │                       runtime `thinking` string field) - the deltas
       │                       AND the block must agree, or consumers see
       │                       inconsistencies
       ├─ tool-call-delta ───► ReplaceMap(argumentsDelta, Quotes) when
       │                       normalizeToolArguments (IMPLEMENTED, default
       │                       OFF - execution-critical raw JSON, the user's
       │                       accepted risk; the example patch turns it
       │                       on) - the assembled ToolCallBlock.arguments
       │                       follows the same flag via block-end
       │                       The gate is THREE-WAY with the flag on: a
       │                       delta/block whose `name` is "edit", "raw-write"
       │                       or "normalize-file" passes through BY IDENTITY
       │                       (the edit tool's `old_string` must match the real
       │                       file bytes; the raw-write tool owns its content
       │                       normalization; the normalize-file tool's arguments
       │                       carry a file path - a normalized dash inside a
       │                       filename would corrupt the target),
       │                       and a call whose arguments open with the
       │                       `{"__normalize":false` marker (FIRST key,
       │                       tracked per call id) passes through
       │                       UNNORMALIZED with the marker entry stripped,
       │                       so the executed call carries no unknown key
       └─ block-start / usage / finish
                                ──► PASSTHROUGH BY IDENTITY, ALWAYS
                                    (usage/finish ordering is the
                                     adapter contract)
       │   count === 0 → original chunk BY IDENTITY; rewritten → shallow copy
       ▼
  yield ──► downstream consumers = the live UI + the durable transcript
       │    (order preserved, no buffering; upstream throws propagate)
       ▼  normal loop completion, Count > 0
  Factory.Append ──► `hook-dsh-normalize-quotes: normalized N quote char(s) in one stream`

The transform

Exactly the core's Quotes map (@playform/hook-dsh-core's Normalize/Quotes), applied per text segment through the core's ReplaceMap - eight entries, each typographic quote code point to its ASCII straight counterpart:

Code pointCharacter (by name)ASCII
U+2018left single quotation mark' (U+0027)
U+2019right single quotation mark'
U+201Asingle low-9 quotation mark'
U+201Bsingle high-reversed-9 quotation mark'
U+201Cleft double quotation mark" (U+0022)
U+201Dright double quotation mark"
U+201Edouble low-9 quotation mark"
U+201Fdouble high-reversed-9 quotation mark"
  • No context rules - one character in, its straight counterpart out.
  • Chunk-boundary-safe: single-character substitution, no lookahead - per-chunk application can never disagree with whole-text application.
  • The mapping values are returned through a function replacer, so they are inserted literally (no $-pattern interpretation).
  • Replaced characters are counted per stream for the ledger line.

The Pitfalls

  • A dependency alone is NOT activation - the package must be in dsh.profile.bundles (or the patch row inserted), or no listener registers and no ledger exists.
  • The map is quote-only - the em dash U+2014 and the rest of the dash family are the dashes flavor's class; a quotes-only pass leaves them untouched - run the flavors the session's characters call for.
  • The stream gate rewrites model output only - it never touches disk; files already on disk are the normalize-file tool's job.
  • The count is per replaced code point - N counts matched characters; N = 0 and an upstream throw both write no count line and no journal record.

The Config

FieldTypeDefaultVolatileMeaning
logbooleantrueyeswrite the durable ledger file
logFilestring~/.dsh/hook-dsh-normalize-quotes.logyesthe quotes ledger (separate from the family's logs)
normalizeReasoningbooleantruenonormalize reasoning deltas and the assembled reasoning block too
normalizeToolArgumentsbooleanfalsenoIMPLEMENTED (default OFF): rewrite the tool-call argumentsDelta and the assembled ToolCallBlock.arguments when on (with three exemptions: edit, raw-write and normalize-file calls pass through by identity (the edit tool's old_string must match the real file bytes; the raw-write tool owns its content normalization through its explicit normalize parameter; the normalize-file tool's arguments carry a file path - a normalized dash inside a filename would corrupt the target); and a call whose arguments open with the {"__normalize":false first-key marker passes through unnormalized, the marker entry stripped) - execution-critical raw JSON, the user's accepted risk; the example patch turns it on

There is no replacement field (MAP flavor).

Volatile cells commit without remounting the plugin; the factory's State builder unwraps them defensively.


In Action

One stream, one transformation.

The model emits smart-quoted prose; the live UI and the transcript receive the straight ASCII forms:

text-delta in (what the model wrote):

  ‘She said “let’s ship it” — today’s the day’

text-delta out (what reaches the transcript):

  'She said "let's ship it" — today's the day'

Every typographic quote in the incoming text - the four single forms and the four double forms - becomes its ASCII counterpart; straight quotes that were already there are untouched (the count only counts replacements). The sample carries six of the eight forms; the em dash U+2014 is the dashes flavor's character, not the quotes map's - with only the quotes flavor it passes through untouched.

In code blocks, commands and file paths this is the difference between a command that runs and one that fails for no visible reason.

When a stream finishes normally with replacements made, the ledger gets the count line:

hook-dsh-normalize-quotes: normalized 6 quote char(s) in one stream

(The same pass runs over reasoning deltas when normalizeReasoning is on, and over tool-call arguments when the example patch enables normalizeToolArguments - with the edit, raw-write and normalize-file names exempt and the raw-marker calls passing through unnormalized.)


The Ledger

Two lines, both written through the factory's Append (the hook-dsh-normalize-quotes: prefix is the logger's <State.Module>:; the durable file line is [<ISO>] <message>):

hook-dsh-normalize-quotes: activated (reasoning=on, toolArgs=off, logFile=~/.dsh/hook-dsh-normalize-quotes.log)
hook-dsh-normalize-quotes: normalized N quote char(s) in one stream

The activation line is written by apply(); the count line only follows a normal stream completion and only when N > 0 (a thrown-away stream writes no ledger line).

Every N > 0 pass also journals one normalized record into the shared package_governance v2 domain - event normalized, path = the empty stream-level path, detail byte-identical to the count line - best-effort: with no storage facility the record buffers or drops, and the human ledger stays the complete record.


The two release groups (CLASSIC vs EFFECT-TS)

Two published groups, one contract: this package is the CLASSIC build - plain TypeScript, zero framework dependencies: import ... from "@playform/hook-dsh-normalize-quotes" resolves to Target/. The EFFECT-TS implementation of the same contract is the separate package @playform/ets-hook-dsh-normalize-quotes - effect-backed, built on the shared @playform/ets-base-dsh base with effect v4.0.2 as its runtime dependency. Install the group you run and never mix the groups in one graph (the effect-ts Update returns Effect envelopes, not the classic dispatch envelope).

License 📜

CC0-1.0.