dsh-output-styles 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.zh.md CHANGED
@@ -2,66 +2,60 @@
2
2
 
3
3
  # 🎨 dsh-output-styles
4
4
 
5
- **DeepSeek Harness 版的 Claude Code `outputStyles`** —— 在运行时、按会话、持久地切换模型输出风格。
5
+ **DeepSeek Harness 的 Claude Code `outputStyles` 等价实现** —— 在运行时、按会话、持久地切换模型输出风格。
6
6
 
7
- [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
8
- [![CI](https://github.com/PerryLink/dsh-output-styles/actions/workflows/ci.yml/badge.svg)](https://github.com/PerryLink/dsh-output-styles/actions/workflows/ci.yml)
7
+ *`/style concise` —— 从此每条回复都简洁。`/style off` —— 回到项目默认。*
8
+
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-output-styles/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-output-styles/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-output-styles?label=version)](https://github.com/PerryLink/dsh-output-styles/releases)
9
14
  [![npm version](https://img.shields.io/npm/v/dsh-output-styles)](https://www.npmjs.com/package/dsh-output-styles)
10
15
  [![npm downloads](https://img.shields.io/npm/dm/dsh-output-styles)](https://www.npmjs.com/package/dsh-output-styles)
11
- [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
- [![DSH](https://img.shields.io/badge/deepseek--harness-0.1.0--rc.6-4d6bfe.svg)](#)
13
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg)](#)
14
16
 
15
- 🌐 [English](README.md) · [中文](README.zh.md) · [日本語](README.ja.md) · [한국어](README.ko.md) · [Español](README.es.md)
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
16
18
 
17
19
  </div>
18
20
 
19
21
  ---
20
22
 
21
- `/style concise` —— 从此之后每条回复都简洁。`/style step-by-step` —— 模型按编号步骤叙述推理。`/style off` —— 回到项目默认。每会话一条命令、重启后依然生效、零 agent-loop 改动。
23
+ ## Compatibility
22
24
 
23
- ## ✨ 特性
24
-
25
- | | |
25
+ | Surface | Status |
26
26
  |---|---|
27
- | 🗂️ **风格库** | 每个风格一个 Markdown 文件(`styles/*.md`);frontmatter 存元数据,正文即模型指令。`name` 缺省继承文件名,且可含空格(如 `Diagrams first`)。内置六种风格,含与 Claude Code 对齐的 `proactive` 与 `learning`。 |
28
- | ⌨️ **`/style` 命令** | 无参列出全部风格(含描述)与当前选择;`/style <name>` 切换;`/style off` 恢复项目默认。`/style` 之后的整段文本即风格名。 |
29
- | 💾 **会话级持久化** | 选择保存在 `output_style` 存储域,按 sessionId 隔离——会话互不干扰,重启后保留。 |
30
- | 🧩 **系统提示注入** | `systemPrompt.section()` 贡献(order 90)在每次组装时注入当前会话的风格正文;正文按可配置预算截断。 |
31
- | 🎭 **Claude Code `keep-coding-instructions`** | `keep-coding-instructions: false`(缺省,与 Claude Code 一致)的风格**替换整个系统提示**——适合彻底离开软件工程的风格。 |
32
- | 📌 **强制风格** | Claude Code 的 `force-for-plugin`(别名 `force`)无条件生效,覆盖任何会话选择;两个强制风格会在加载期报错。 |
33
- | 🔁 **Claude Code 兼容** | 加载 `outputStyles` JSON 集合(`{ name, description, prompt }`),支持单对象与 `settings.json` 式数组;坏条目逐个跳过并警告。 |
34
- | 📚 **目录分层** | `stylesDir` 是目录列表,后者覆盖前者(内置 `styles/` 是最低层,`includeBuiltins: false` 可排除)。 |
35
- | 🔄 **热加载** | 风格文件改动即时生效,无需重启(`watchStyles: false` 可关闭)。 |
36
- | ⚙️ **settings 项目默认** | 从未选择过的会话依次回落到 settings 的 `output-style.style`、再回落 `defaultStyle`。 |
37
- | 🖱️ **Web 选择器** | `dsh.client` 入口(`dsh-output-styles/client`)把宿主 `/style` 命令装饰成投影驱动的弹窗选择器。 |
38
- | 📊 **会话投影** | `style` 投影(`{ options, currentValue }`)供 Web UI 使用,按会话日志中**已成功落定**的命令折叠。 |
39
- | 🧯 **失效即响、坏件干净跳过** | 配置错误加载期抛错;坏风格文件跳过并警告,绝不拖垮 profile。 |
40
- | 🌐 **五语文档** | EN · 中文 · 日本語 · 한국어 · Español。 |
41
-
42
- ## 🚀 快速开始
27
+ | Harness | DeepSeek Harness `0.1.0-rc.8` |
28
+ | Node | `^22.19.0 || >=24.0.0` |
29
+ | Platforms | 全部(host + Web 客户端) |
30
+ | Model | 任意(系统提示注入) |
31
+
32
+ ## What you get
33
+
34
+ `dsh-output-styles` 是 DeepSeek Harness 的 Claude Code `outputStyles` 等价实现:一个 `/style` 命令,在运行时切换模型输出风格,按会话持久化,并在每次提示组装时注入。
35
+
36
+ - **风格库** —— 每种风格一个 Markdown 文件(`styles/*.md`);frontmatter 存元数据,正文即模型指令。内置六种(`concise`、`explanatory`、`formal`、`learning`、`proactive`、`step-by-step`),含与 Claude Code 对齐的 `proactive` 与 `learning`。
37
+ - **`/style` 命令** —— 无参数时列出风格(含描述)与当前选择;`/style <name>` 切换;`/style off` 恢复项目默认。
38
+ - **会话级持久化** —— 选择存于 `output_style` 存储域,按 sessionId 隔离,重启后仍保留。
39
+ - **系统提示注入** —— `systemPrompt.section()` 贡献(顺序 `sectionOrder`)在每次组装时注入当前会话的风格正文,按可配置预算截断。
40
+ - **Claude Code 对齐** —— `keep-coding-instructions`、`force-for-plugin`(别名 `force`)、`outputStyles` JSON 兼容、分层 `stylesDir` 目录、热重载,以及通过 DSH settings 接缝的项目默认回退。
41
+ - **渲染器注册表(`output.render.*`)** —— `ctx.outputRenderers` 允许任意插件注册纯 presenter,经 `output.render/before` waterfall 应用;内置渲染器 `concise` 与 `step-by-step`。
42
+ - **按会话/按工具规则** —— `rules: [{ match: { tool: 'bash' }, style: 'concise' }]` 为匹配请求指定渲染器;可通过 `output-style-rules` 设置区编辑。
43
+ - **`/export`** —— 经渲染管线把当前会话导出为 Markdown 或净化 HTML;每次渲染都保留原文与渲染结果并列。
44
+
45
+ ## Quick start
43
46
 
44
47
  ```sh
45
- # 1. 安装——本包是 bundle 补丁层,一条命令即组合好
46
- # storage + storage-json + storage-domain + 插件行:
47
- dsh plugin --profile <name> add dsh-output-styles
48
-
49
- # 2. 启动并切换
50
- dsh --profile <name>
51
- /style # → 当前状态 + 每风格一行
52
- /style concise # → switched to concise
53
- /style Diagrams first # → 含空格的名字同样可用
54
- /style off # → 回到项目默认
55
- ```
48
+ # 1. install the bundle into your profile
49
+ dsh plugin --profile web add "github:PerryLink/dsh-output-styles#main"
56
50
 
57
- 该补丁层对 web profile 幂等(按 id 插入会替换同 id 行),web profile 本就内建 storage 三行。使用 Web 选择器时,向 profile 添加客户端行:
51
+ # or from npm (published releases)
52
+ dsh plugin --profile web add dsh-output-styles
58
53
 
59
- ```yaml
60
- - id: output-styles-client
61
- name: 'dsh-output-styles/client'
54
+ # 2. restart and verify the row
55
+ dsh --profile web --dump-config | grep -A3 'id: output-styles'
62
56
  ```
63
57
 
64
- ## 🎬 演示
58
+ ## Demo
65
59
 
66
60
  ```
67
61
  You > /style
@@ -80,160 +74,173 @@ You > 请只用一句话介绍你自己。
80
74
  AI > 我是运行在 DeepSeek Harness 插件化平台上、基于 deepseek-v4-pro 模型的 AI 编码代理。
81
75
  ```
82
76
 
83
- ## 🧠 工作原理
77
+ ## How it works
84
78
 
85
79
  ```mermaid
86
80
  flowchart LR
87
- U[输入 /style concise] --> C[命令注册表]
88
- C -->|记录 command/run| L[(会话日志)]
89
- C -->|写入 {style, source}| D[(output_style 域)]
81
+ U[You type /style concise] --> C[command registry]
82
+ C -->|command/run logged| L[(session log)]
83
+ C -->|put {style, source}| D[(output_style domain)]
90
84
  D --> R[OutputStyleRuntime]
91
- R -->|每次组装注入正文| S[systemPrompt 节 order 90]
92
- S --> M[模型请求]
93
- M -->|完整系统提示| H[记录 request/header]
85
+ R -->|body at every assembly| S[systemPrompt section order 90]
86
+ S --> M[Model request]
87
+ M -->|full system prompt| H[request/header logged]
94
88
  ```
95
89
 
96
- 模型所见的一切都能从会话日志重建——无需新增会话事件类型、不改 agent-loop。风格名来自 `command/run`,注入的确切文本来自 `request/header`,来源标记 `{ kind: 'plugin', plugin: 'dsh-output-styles' }` 随域记录存储。风格只作用于主会话;子代理会话保持各自的提示(与 Claude Code 一致)。
90
+ 模型所见的一切都能从会话日志重建 —— 无新增会话事件类型、无 agent-loop 改动。风格名来自 `command/run`,精确注入文本来自 `request/header`,来源标记 `{ kind: 'plugin', plugin: 'dsh-output-styles' }` 随域记录携带。风格只作用于主会话;子代理会话保留各自提示(与 Claude Code 一致)。
97
91
 
98
- ## ⚙️ 配置
92
+ ## Install & uninstall
99
93
 
100
- 所有可调项都是带校验的 Schemastery `Config` 字段(非法值加载即失败):
94
+ - **git channel**(最新 `main`):`dsh plugin --profile web add "github:PerryLink/dsh-output-styles#main"` —— `prepare` 脚本仅用生产依赖构建。
95
+ - **npm channel**(发布版本):`dsh plugin --profile web add dsh-output-styles`。
96
+ - **tarball channel**:在本仓库执行 `pnpm pack`,然后 `dsh plugin --profile web add ./dsh-output-styles-<version>.tgz`。
97
+ - **uninstall**:`dsh plugin --profile web remove dsh-output-styles`。
101
98
 
102
- | 字段 | 默认 | 含义 |
99
+ ## Configuration
100
+
101
+ 所有可调项均为 Schemastery `Config` 字段(可在 cordis.yml 中修改)。非法值在加载期失败。
102
+
103
+ | Key | Default | Meaning |
103
104
  |---|---|---|
104
- | `stylesDir` | `[]` | 风格库目录列表,相对 cwd 解析;后者覆盖前者。`[]` = 仅内置 `styles/`。裸字符串视为单目录列表。 |
105
- | `maxStyleChars` | `4000` | 风格正文预算(码点,≥ 1);超长正文截断并加标记。 |
106
- | `defaultStyle` | `''` | 从未选择过的会话(且无 settings 默认)使用的风格;`''` = 不注入。 |
107
- | `compatJson` | `true` | 加载 Claude Code `outputStyles` JSON 条目(单对象或数组)。 |
108
- | `sectionOrder` | `90` | 注入节顺序(0 = persona,100–199 = 工具指引)。 |
109
- | `truncationMarker` | `"\n\n[style truncated]"` | 截断点追加的标记。 |
110
- | `includeBuiltins` | `true` | 将包内置 `styles/` 作为最低优先级层纳入。 |
111
- | `watchStyles` | `true` | 风格文件在磁盘上变化时重载风格库。 |
112
- | `rules` | `[]` | 按会话/按工具的渲染规则:`[{ match: { tool?, contentType?, session? }, style, priority? }]`——`style` 指定渲染器 id(内置与风格同名)。 |
113
- | `enableExport` | `true` | 注册 `/export` 命令(Markdown/HTML 会话导出,渲染器感知)。 |
114
-
115
- ## 🎨 渲染器协议
116
-
117
- `output.render.*` 协议把呈现层变成扩展点。渲染器是**纯 presenter**——`presenter(text, context)` 把参数映射为展示数据、绝不碰 DOM——按工具名与内容类型匹配、按优先级排序:第三方插件经 `ctx.outputRenderers.register({ id, match, priority, presenter })` 注册(register 返回 disposer,归调用方 ctx.effect)。每次渲染先过 `output.render/before` waterfall(监听器必须 `next()`),再走规则表(按会话/按工具:`rules: [{ match: { tool: 'bash' }, style: 'concise' }]`,设置页 `output-style-rules` 可编辑)。内置渲染器 `concise`(空白折叠 + 预算截断)与 `step-by-step`(步骤统一编号)。可审计:每个结果携带 `{ original, rendered, rendererId, changed }`,原始文本即会话日志、渲染确定可重建。`/export [markdown|html] [--renderer=<id>]` 经同一流水线导出当前会话。完整协议:docs/renderer-protocol.md(英文)/ docs/renderer-protocol.zh.md。
118
- ## 📚 风格库
119
-
120
- <details>
121
- <summary><code>styles/concise.md</code></summary>
122
-
123
- ```markdown
124
- ---
125
- name: concise
126
- description: Terse, direct answers — minimal prose, no preamble.
127
- whenToUse: Daily coding work, tool-heavy sessions, or when prompt length matters.
128
- keep-coding-instructions: true
129
- ---
105
+ | `stylesDir` | `[]` | 风格库目录,相对 cwd 解析;后者覆盖前者。`[]` = 仅内置 `styles/` |
106
+ | `maxStyleChars` | `4000` | 风格正文预算(≥ 1);超长正文带标记截断 |
107
+ | `defaultStyle` | `''` | 从未选择过风格的会话所用风格(且无 settings 默认);`''` = 无风格 |
108
+ | `compatJson` | `true` | 加载 Claude Code `outputStyles` JSON 条目(单对象或数组) |
109
+ | `sectionOrder` | `90` | 注入段的顺序(0 = persona,100–199 = 工具指引) |
110
+ | `truncationMarker` | `"\n\n[style truncated]"` | 追加在截断点的标记 |
111
+ | `includeBuiltins` | `true` | 将包内置 `styles/` 作为最低优先级层 |
112
+ | `watchStyles` | `true` | 风格文件在磁盘上变化时重载库 |
113
+ | `rules` | `[]` | 按会话/按工具渲染规则:`[{ match: { tool?, contentType?, session? }, style, priority? }]` |
114
+ | `enableExport` | `true` | 注册 `/export` 命令(Markdown/HTML 会话导出,感知渲染器) |
115
+
116
+ ## Tools & surfaces
117
+
118
+ | Surface | Kind | Notes |
119
+ |---|---|---|
120
+ | `/style` | command | 列出风格、切换或恢复项目默认 |
121
+ | `/export` | command | 把当前会话渲染为 Markdown 或净化 HTML |
122
+ | `output_style` | storage domain | 按 sessionId 隔离的会话级风格选择 |
123
+ | `systemPrompt.section()` | contribution | 在每次组装时注入当前风格正文 |
124
+ | `output.render.*` | renderer registry | `ctx.outputRenderers` + `output.render/before` waterfall |
125
+ | `style` | projection | 从已落定命令折叠出的 `{ options, currentValue }` |
126
+ | Web picker | client entry | `dsh-output-styles/client` 用弹出选择器装饰 `/style` |
130
127
 
131
- You are in the concise output style for this conversation.
132
- - Lead with the direct answer; skip preamble, restatements, and filler.
133
- - 回答语言跟随用户语言:中文提问用中文回答,英文提问用英文回答。
134
- ```
128
+ ## Command reference
135
129
 
136
- </details>
130
+ | Input | Outcome |
131
+ |---|---|
132
+ | `/style` | 列出当前选择 + 每个风格一行(名称 — 描述) |
133
+ | `/style concise` | 切换(持久写入),`switched to concise` |
134
+ | `/style Diagrams first` | 多词名称取整个余下部分 |
135
+ | `/style off` | 恢复项目默认(settings 默认,其次 `defaultStyle`) |
136
+ | `/style nope` | `error: unknown output style "nope" (available: …)` |
137
+ | `/export` | 经渲染管线把当前会话渲染为 Markdown |
138
+ | `/export html` | 渲染为净化 HTML |
139
+ | `/export --renderer=concise` | 强制指定一个渲染器渲染(跳过规则) |
137
140
 
138
- frontmatter 字段:
141
+ ## Style library
139
142
 
140
- | 字段 | 默认 | 含义 |
143
+ 每种风格一个 Markdown 文件;frontmatter 存元数据,正文即模型指令。`name` 默认取文件名,可含空格(`Diagrams first`)。
144
+
145
+ | Field | Default | Meaning |
141
146
  |---|---|---|
142
- | `name` | 文件名 | 切换目标;字母、数字、空格、连字符(首尾无空白;`off` 为保留字)。 |
143
- | `description` | ——(必填) | 列表与选择器里展示的一句话。 |
144
- | `whenToUse` | —— | 可选适用场景说明,追加到列表。 |
145
- | `keep-coding-instructions` | `false` | `true` 保留宿主提示(身份、persona、工具指引);`false` 整体替换(Claude Code 语义)。 |
146
- | `force-for-plugin` | `false` | Claude Code 官方字段:无条件生效,覆盖会话选择;`force` 为其别名,最多一个风格可设置。 |
147
+ | `name` | 文件名 | 切换目标;字母、数字、空格与连字符(`off` 为保留字) |
148
+ | `description` | —(必填) | 列表与选择器中显示的一句话 |
149
+ | `whenToUse` | — | 追加到列表的可选指引 |
150
+ | `keep-coding-instructions` | `false` | 为 `true` 时保留 harness 提示;为 `false` 时整体替换(Claude Code 语义) |
151
+ | `force-for-plugin` | `false` | 无条件应用,覆盖任何会话选择;`force` 为别名,至多一种风格可设置 |
147
152
 
148
- <details>
149
- <summary>Claude Code <code>outputStyles</code> JSON(<code>compatJson: true</code>)</summary>
153
+ 启用 `compatJson: true` 后,Claude Code `outputStyles` JSON 条目(`{ name, description, prompt }`)与 Markdown 风格并列加载;无法解析的条目带警告跳过。
150
154
 
151
- ```json
152
- { "name": "explain", "description": "Explain like a teacher.", "prompt": "Teach in small steps." }
153
- ```
155
+ ## Renderer protocol
154
156
 
155
- 条目按 Claude Code 原样接受 `keep-coding-instructions` 与 `force-for-plugin` 字段。旧版 `settings.json` 的数组形式(`[{ … }, { … }]`)原样加载;坏条目逐个跳过并警告。
157
+ `output.render.*` 协议把呈现层变为扩展点。渲染器是**纯 presenter** —— `presenter(text, context)` 把参数映射为展示数据、绝不触碰 DOM —— 按工具名与内容类型匹配,按优先级排序。
156
158
 
157
- </details>
159
+ - **Waterfall first**:每个渲染请求先经 `output.render/before`(`{ text, context }`);监听器必须调用 `next()`。
160
+ - **Rules**:`rules: [{ match: { tool: 'bash' }, style: 'concise' }]` 为匹配请求指定渲染器;冲突按 `priority` 再按规则顺序裁决。
161
+ - **Built-ins**:`concise`(空白压缩 + 预算截断)与 `step-by-step`(一致的步骤编号)。
162
+ - **Auditability**:每次渲染结果携带 `{ original, rendered, rendererId, changed }`;渲染文本是展示内容,原文始终可从会话日志重建。
158
163
 
159
- ## ⌨️ 命令参考
164
+ ## Web picker
160
165
 
161
- | 输入 | 结果 |
162
- |---|---|
163
- | `/style` | 列出当前选择 + 每风格一行(名称 — 描述) |
164
- | `/style concise` | 切换(持久写入),`switched to concise` |
165
- | `/style Diagrams first` | 含空格的风格名 = `/style` 后的整段文本 |
166
- | `/style off` | 恢复项目默认(先 settings 默认,后 `defaultStyle`) |
167
- | `/style nope` | `error: unknown output style "nope" (available: …)` |
166
+ `dsh.client` 条目装饰 host `/style` 命令的裸调用,弹出一个选择器:一个 "off" 行 + 每个库风格一行(`description · whenToUse`),当前行高亮。选择通过命令 Remote 提交 `/style <name>`,因此每次切换都保留 host 的持久命令生命周期。选择器跟随 Web UI 自带的 `zh`/`en` 语言对。
168
167
 
169
- ## 🖱️ Web 选择器
168
+ ## Differences from Claude Code
170
169
 
171
- `dsh.client` 入口把宿主 `/style` 命令的裸调用装饰成弹窗选择器:「off」行 + 每风格一行(`描述 · 适用场景`),当前行高亮。选中即通过命令 Remote 提交 `/style <name>`,因此每次切换都保留宿主的持久命令生命周期,`style` 投影始终是唯一展示事实。选择器文案跟随 Web UI 内置的 `zh`/`en` 语言对。
170
+ | | Claude Code | dsh-output-styles |
171
+ |---|---|---|
172
+ | 风格文件 | 用户/项目/受管层的 `.claude/output-styles` | `stylesDir` 目录 + 内置 `styles/`,后者目录优先 |
173
+ | 自定义风格 | Markdown,frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 相同字段(`force-for-plugin` 原样接受,`force` 为别名)+ `whenToUse` |
174
+ | 旧版 JSON | `settings.json` 中的 `outputStyles` 数组 | 原样加载(`compatJson: true`) |
175
+ | 生效时机 | `/clear` 之后或新会话 | 立即——系统提示按请求重新组装 |
176
+ | 子代理 | 风格不适用 | 相同——子代理会话保留各自提示 |
177
+ | 切换 | `/config` 菜单或 `outputStyle` 设置(`/output-style` 命令已在 v2.1.91 移除) | `/style` 命令 + Web picker + settings `output-style.style` |
172
178
 
173
- ## 🔍 生态冲突检查
179
+ ## Conflict check
174
180
 
175
- 开发前对 DSH 生态做了筛查(2026-08 快照):[topic:dsh-plugin](https://github.com/topics/dsh-plugin) 下没有 `style`/`output-style` 仓库,四大 [awesome 列表](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 没有 output-style 分类,[dsh-hub 目录](https://github.com/omdsh-dev/dsh-hub-workshop) 亦无条目。最接近的邻居——[dsh-soul-md](https://github.com/Scorp1o117/dsh-soul-md)(persona)与 [dsh-claude-marketplace](https://github.com/ben7am1n/dsh-claude-marketplace)(明确将输出风格推迟到 v0.2+)——相邻而不冲突。
181
+ 开发前已对照 DSH 生态排查(2026-08 快照):[topic:dsh-plugin](https://github.com/topics/dsh-plugin) 下无 `style`/`output-style` 仓库,四个主要 [awesome lists](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) 中无 output-style 分类,[dsh-hub catalog](https://github.com/omdsh-dev/dsh-hub-workshop) 中无条目。最接近的邻居——[dsh-soul-md](https://github.com/Scorp1o117/dsh-soul-md)(persona)与 [dsh-claude-marketplace](https://github.com/ben7am1n/dsh-claude-marketplace)(输出风格明确推迟到 v0.2+)——是相邻而非冲突。
176
182
 
177
- ## 🆚 与 Claude Code 的差异
183
+ ## Permissions & data
178
184
 
179
- | | Claude Code | dsh-output-styles |
180
- |---|---|---|
181
- | 风格文件 | 用户/项目/托管层级的 `.claude/output-styles` | `stylesDir` 目录 + 内置 `styles/`,后目录胜出 |
182
- | 自定义风格 | Markdown,frontmatter `name`/`description`/`keep-coding-instructions`/`force-for-plugin` | 同字段(`force-for-plugin` 原样接受,`force` 为别名)+ `whenToUse` |
183
- | 旧版 JSON | `settings.json` 里的 `outputStyles` 数组 | 原样加载(`compatJson: true`) |
184
- | 生效时机 | `/clear` 或新会话后 | 立即生效——系统提示每次请求重组 |
185
- | 子代理 | 风格不适用 | 一致——子代理会话保持各自提示 |
186
- | 切换方式 | `/config` 菜单或 `outputStyle` 设置(`/output-style` 命令已在 v2.1.91 移除) | `/style` 命令 + Web 选择器 + settings `output-style.style` |
185
+ - **Permissions**:workshop 清单声明 `fs:read`、`fs:watch`、`storage:read`、`storage:write` 与 `settings:read`。
186
+ - **Data**:风格选择存于 `output_style` 存储域(按 sessionId 隔离);不持久化其他状态,无网络请求。
187
+ - **Session log**:风格名来自 `command/run`,精确注入文本来自 `request/header`;来源标记 `{ kind: 'plugin', plugin: 'dsh-output-styles' }` 随域记录携带。
187
188
 
188
- ## 🧪 开发
189
+ ## Security boundaries
190
+
191
+ - **仅公开服务。** 贡献 `systemPrompt`、命令、存储与 settings;不改 engine / agent-loop / apiproxy / 官方 UI。
192
+ - **模型可见 ⟺ 已记录。** 模型所见的一切都能从会话日志重建 —— 无新增会话事件类型、无 agent-loop 改动。
193
+ - **始终保留原文。** 每次渲染(含 `/export`)都保留原文与渲染结果并列;HTML 导出使用净化 HTML。
194
+
195
+ ## Known limitations
196
+
197
+ - **仅主会话。** 风格只作用于主会话;子代理会话保留各自提示(与 Claude Code 一致)。
198
+ - **截断。** 超过 `maxStyleChars` 的风格正文带标记截断。
199
+ - **跳过坏文件。** 损坏的风格文件带警告跳过,绝不破坏 profile。
200
+
201
+ ## Development
189
202
 
190
203
  ```sh
191
204
  pnpm install
192
- pnpm run typecheck # 两个 tsc 工程
193
- pnpm test # vitest —— 93 个测试
194
- pnpm run verify # typecheck + 测试 + 自包含检查(prepublishOnly 闸门)
195
- pnpm run build # lib/ 产物(宿主 + 客户端两个 bundle)
196
- pnpm pack # 供 dsh plugin add 使用的 tarball
205
+ pnpm run typecheck # 两个 tsc 项目
206
+ pnpm test # vitest —— 107 个测试
207
+ pnpm run verify # typecheck + tests + self-contained(prepublishOnly 门禁)
208
+ pnpm run build # lib/ 产物(host + client 包)
209
+ pnpm pack # 供 dsh plugin add 的 tarball
197
210
  ```
198
211
 
199
- 发布:推送后缀与 `package.json` 版本一致的 `v*` tag 会触发 Publish 工作流——完整验证后发布到 npm(含 provenance)。任何 `npm publish` 也会通过 `prepublishOnly` 执行 `verify` 闸门。
212
+ 发布:推送后缀与 `package.json` 版本一致的 `v*` 标签会触发 Publish workflow —— 完整验证后带 provenance 发布到 npm。
200
213
 
201
- 结构遵循 [omdsh-dev/plugin-template](https://github.com/omdsh-dev/plugin-template):`src/index.ts`(插件元数据)、`src/config.ts`(schema)、`src/runtime.ts`(运行时服务与激活)、`src/invariant.ts`(不变量)、`src/client/`(Web 选择器)、`styles/`(内置风格)。
214
+ ## Topics
202
215
 
203
- ## 👥 贡献者
216
+ `deepseek-harness`, `dsh`, `dsh-plugin`, `output-style`, `output-styles`, `claude-code`
204
217
 
205
- 感谢每一位为本项目做出贡献的人:
218
+ ## Contributors
206
219
 
207
- - [@PerryLink](https://github.com/PerryLink) — 作者与维护者:插件架构、风格库、bundle 安装、Web 选择器、五语文档与 CI/发布工具链。
220
+ - [@PerryLink](https://github.com/PerryLink) —— 作者与维护者:插件架构、风格库、bundle 安装、Web picker、五语文档与 CI/发布工具链。
208
221
 
209
- 发现 bug 或有想法?欢迎提交 [issue](https://github.com/PerryLink/dsh-output-styles/issues) 或 [pull request](https://github.com/PerryLink/dsh-output-styles/pulls),任何语言的贡献都欢迎。
222
+ ## PerryLink DSH Plugin Family
210
223
 
211
- ## PerryLink DSH 插件家族
224
+ 本项目是 [PerryLink](https://github.com/PerryLink) 维护的 [15 个 DeepSeek Harness 插件](https://github.com/PerryLink) 之一。如果这个对你有用,其他插件多半也有用:
212
225
 
213
- 本项目是 [PerryLink](https://github.com/PerryLink) 维护的 [15 个 DeepSeek Harness 插件](https://github.com/PerryLink)之一。如果你觉得这个插件有用,其余的很可能同样有用:
214
-
215
- | 插件 | 一句话说明 |
226
+ | Plugin | One-liner |
216
227
  |---|---|
217
- | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | 只读 MCP 运行时面板:/mcp 命令 + 设置页,状态/工具/错误一览 |
218
- | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | 工程纪律守门:需求审讯、测试证据门、对抗评审 |
219
- | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | 持久化后台子代理:Web 侧边栏进度、随时留言与打断 |
220
- | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | 基于语言服务器的诊断/格式化/补全/代码动作/重命名 |
221
- | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | 对标 Claude Code outputStyles 的运行时风格切换 |
222
- | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | 对标 Claude Code /rewind:快照、会话 fork、一键回退 |
223
- | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code 风格声明式 allow/deny/ask 权限规则,带审计 |
224
- | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | 审批链上的第二模型自动审查,默认 fail-closed |
225
- | [dsh-memento](https://github.com/PerryLink/dsh-memento) | 带审批门的跨会话记忆:ctx.memory + SQLite + memory 工具 |
226
- | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | 安全审计技能包:密钥扫描、依赖与供应链审查 |
227
- | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | 在 Web 侧边栏置顶会话,持久排序 |
228
- | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Web 作曲器终端式输入历史:方向键、Ctrl+R 搜索 |
229
- | [dsh-github](https://github.com/PerryLink/dsh-github) | DSH 的 GitHub PR/issue 集成,所有写操作经审批门 |
230
- | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | 插件开发知识库,随 bundle 安装的按需 agent 技能 |
231
- | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | 把 Claude Code 会话、记忆、技能和 CLAUDE.md 迁入 DSH |
232
-
233
- ## 📄 License
234
-
235
- [Apache-2.0](LICENSE) © 2026 dsh-output-styles contributors
236
-
237
- ---
238
-
239
- <sub>Topics: `dsh` · `dsh-plugin` · `deepseek-harness` · `output-styles` · `claude-code`</sub>
228
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
229
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
230
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
231
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
232
+ | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching |
233
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
234
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code-style declarative allow/deny/ask permission rules with audit |
235
+ | [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
236
+ | [dsh-memento](https://github.com/PerryLink/dsh-memento) | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
237
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
238
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
239
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
240
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | GitHub PR/issues integration for DSH, every write gated by approval |
241
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
242
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
243
+
244
+ ## License
245
+
246
+ [Apache License 2.0](LICENSE) © 2026 dsh-output-styles contributors
package/lib/client.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/client/locales.ts
1
+ //#region lib/types/client/locales.js
2
2
  /**
3
3
  * Simplified Chinese dictionary (the key-set source of truth).
4
4
  *
@@ -17,7 +17,17 @@ const en = {
17
17
  "option.offDetail": "Restore the project default output style"
18
18
  };
19
19
  //#endregion
20
- //#region src/client/index.ts
20
+ //#region lib/types/client/index.js
21
+ /**
22
+ * Browser half of `dsh-output-styles`: a popup picker decorating the HOST
23
+ * `/style` command. The picker reads the `style` session projection
24
+ * (`{ options, currentValue }`), which the host plugin keeps fresh, and
25
+ * submits the completed `/style <name>` / `/style off` line back through the
26
+ * command Remote — so every switch keeps the host's durable command
27
+ * lifecycle (`command/run`/`command/done`) and the projection stays the
28
+ * single displayed fact.
29
+ * @module dsh-output-styles/client
30
+ */
21
31
  /** Client plugin name; keep stable after publishing. */
22
32
  const name = "dsh-output-styles-client";
23
33
  /** Required client services: the command surface, the sessions face, the command Remote, and locale. */
@@ -78,7 +88,7 @@ function apply(ctx) {
78
88
  },
79
89
  onSelect: async (option, session) => {
80
90
  const line = option.id === OFF_ID ? "/style off" : `/style ${option.id}`;
81
- const result = await remote.commands.execute(session.sessionId, line);
91
+ const result = await remote.commands.execute(session.sessionId, line, []);
82
92
  if (!result.ok) throw new Error(`command.execute failed: ${result.error.code}: ${result.error.message}`);
83
93
  if (result.value === void 0) throw new Error(`unknown or malformed command: ${line}`);
84
94
  }
package/lib/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { _ as styleSelectionSchema, c as loadStyleLibrary, d as STYLE_COMMAND, f as applyStyleEvent, g as STYLE_SOURCE, h as OUTPUT_STYLE_DOMAIN, i as installInvariant, l as truncateStyle, m as OFF, o as STYLE_NAME_RE, p as parseStyleInput, s as isValidStyleName, t as PACKAGE_NAME, u as EMPTY_STYLE_STATE, v as styleSelectionViewSchema } from "./invariant-B9LpUViP.js";
1
+ import { _ as styleSelectionSchema, c as loadStyleLibrary, d as STYLE_COMMAND, f as applyStyleEvent, g as STYLE_SOURCE, h as OUTPUT_STYLE_DOMAIN, i as installInvariant, l as truncateStyle, m as OFF, o as STYLE_NAME_RE, p as parseStyleInput, s as isValidStyleName, t as PACKAGE_NAME, u as EMPTY_STYLE_STATE, v as styleSelectionViewSchema } from "./invariant-CEWlfnrw.js";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { watch } from "node:fs";
6
6
  import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
7
7
  import { deriveEventMessage, foldSurface } from "@deepseek-ai/dsh-session/surface";
8
- //#region src/config.ts
8
+ //#region lib/types/config.js
9
9
  /**
10
10
  * Serializable configuration, schema, and direct-call defaults.
11
11
  *
@@ -79,7 +79,20 @@ function resolveConfig(config, defaultStylesDir) {
79
79
  };
80
80
  }
81
81
  //#endregion
82
- //#region src/renderers.ts
82
+ //#region lib/types/renderers.js
83
+ /**
84
+ * The `output.render.*` protocol: a presenter registry that turns raw
85
+ * model-visible text into display text. A renderer is a pure function —
86
+ * `presenter(text, meta)` maps args to presentation data and never touches
87
+ * the DOM — matched by tool name and content type, ordered by priority.
88
+ * Every rendered result carries its original text alongside, so any consumer
89
+ * (this plugin's `/export`, third-party panels) can log both and keep the
90
+ * "model-visible ⟺ reconstructable" invariant.
91
+ *
92
+ * This module is dependency-free (no DOM, no node: imports, no DSH imports)
93
+ * so the protocol vocabulary itself is portable and unit-testable anywhere.
94
+ * @module dsh-output-styles/renderers
95
+ */
83
96
  /**
84
97
  * Validates a renderer before registration: id grammar, name, description,
85
98
  * match shape, priority, presenter function. Throws on the first violation
@@ -232,7 +245,7 @@ const BUILTIN_RENDERERS = [{
232
245
  presenter: (text) => enumerate(text)
233
246
  }];
234
247
  //#endregion
235
- //#region src/export.ts
248
+ //#region lib/types/export.js
236
249
  /**
237
250
  * Session export: a pure projection of the current session's message surface
238
251
  * into Markdown or sanitized HTML, with renderer application on top. The
@@ -396,7 +409,7 @@ function renderExport(registry, lines, format, rules, now = /* @__PURE__ */ new
396
409
  };
397
410
  }
398
411
  //#endregion
399
- //#region src/runtime.ts
412
+ //#region lib/types/runtime.js
400
413
  /**
401
414
  * Runtime boundary and Cordis activation: style resolution over the durable
402
415
  * selection domain, the model-visible system-prompt section, the `/style`
@@ -729,10 +742,11 @@ async function apply(ctx, config) {
729
742
  ctx.inject(["invariants"], (invariantCtx) => {
730
743
  const registry = invariantCtx.get("invariants");
731
744
  if (registry === void 0) return;
732
- registry.register(PACKAGE_NAME, installInvariant({
745
+ const facts = {
733
746
  knownStyles: () => new Set(runtime.names),
734
747
  selectionFor: (sessionId) => runtime.selectionFor(sessionId)
735
- }));
748
+ };
749
+ invariantCtx.effect(() => registry.register(PACKAGE_NAME, installInvariant(facts)), "dsh-output-styles: invariant companion");
736
750
  });
737
751
  const renderers = new RendererRegistry();
738
752
  for (const renderer of BUILTIN_RENDERERS) ctx.effect(() => renderers.register(renderer), `dsh-output-styles: renderer ${renderer.id}`);
@@ -823,7 +837,7 @@ function parseExportInput(rawInput) {
823
837
  };
824
838
  }
825
839
  //#endregion
826
- //#region src/index.ts
840
+ //#region lib/types/index.js
827
841
  /**
828
842
  * `dsh-output-styles`: Claude Code `outputStyles`-equivalent runtime output
829
843
  * styles for DeepSeek Harness. The plugin registers a model-visible system
@@ -3,7 +3,16 @@ import { readFileSync, readdirSync } from "node:fs";
3
3
  import { z } from "zod";
4
4
  import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
5
5
  import { parse } from "yaml";
6
- //#region src/types.ts
6
+ //#region lib/types/types.js
7
+ /**
8
+ * Durable domain vocabulary and type-table merges owned by this package.
9
+ *
10
+ * The selection domain is the single source of the per-session style choice;
11
+ * its record schema doubles as the durable validation boundary. The `style`
12
+ * projection key is declared here (its one home) and re-exported from the
13
+ * package root so consumers receive the `SessionProjectionMap` merge.
14
+ * @module dsh-output-styles/types
15
+ */
7
16
  /** The reserved switch target that removes a session's selection. */
8
17
  const OFF = "off";
9
18
  /**
@@ -45,7 +54,16 @@ const styleSelectionViewSchema = z.object({
45
54
  currentValue: z.string().min(1).nullable()
46
55
  });
47
56
  //#endregion
48
- //#region src/style-command.ts
57
+ //#region lib/types/style-command.js
58
+ /**
59
+ * Strict parsing of the `/style` command input and the pure projection fold
60
+ * over its logged lifecycle events.
61
+ *
62
+ * The handler and the session-projection unit share {@link parseStyleInput}:
63
+ * the projection folds exactly the inputs the handler accepts, so the
64
+ * displayed selection can never diverge from what the command did.
65
+ * @module dsh-output-styles/style-command
66
+ */
49
67
  /** Command name registered on `ctx.commands`; also the log's `command/run` name. */
50
68
  const STYLE_COMMAND = "style";
51
69
  /**
@@ -112,7 +130,7 @@ function applyStyleEvent(state, event) {
112
130
  };
113
131
  }
114
132
  //#endregion
115
- //#region src/style-library.ts
133
+ //#region lib/types/style-library.js
116
134
  /**
117
135
  * Style-library loading: one style per `*.md` file (frontmatter + body),
118
136
  * with optional Claude Code `outputStyles` JSON compatibility (single entry
@@ -386,7 +404,27 @@ function truncateStyle(body, maxChars, marker) {
386
404
  return chars.slice(0, maxChars).join("") + marker;
387
405
  }
388
406
  //#endregion
389
- //#region src/invariant.ts
407
+ //#region lib/types/invariant.js
408
+ /**
409
+ * Package-owned invariant companion for `dsh-output-styles`.
410
+ *
411
+ * Two post-commit diagnostic checks over the events this plugin's write path
412
+ * produces (both target events are committed before dispatch, so a violation
413
+ * is reported — via the host registry's `fail` — rather than vetoed):
414
+ *
415
+ * 1. Every `output_style`/`selection` durable write carries this plugin's own
416
+ * source marker and a legal style name; when the library is known,
417
+ * the name must be a library member.
418
+ * 2. A successful `/style <name>` command has a matching selection record on
419
+ * its session by the time its `command/done` settles, and `/style off`
420
+ * leaves no record. The standalone companion (no library/domain handle)
421
+ * skips this check.
422
+ *
423
+ * The main plugin registers a facts-bearing installer from its own context;
424
+ * the `./invariant` export is the standalone companion usable through a
425
+ * separate profile row.
426
+ * @module dsh-output-styles/invariant
427
+ */
390
428
  /** Full npm package name owning the reported failures. */
391
429
  const PACKAGE_NAME = "dsh-output-styles";
392
430
  /** Cordis companion plugin name. */
package/lib/invariant.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as name, i as installInvariant, n as apply, r as inject, t as PACKAGE_NAME } from "./invariant-B9LpUViP.js";
1
+ import { a as name, i as installInvariant, n as apply, r as inject, t as PACKAGE_NAME } from "./invariant-CEWlfnrw.js";
2
2
  export { PACKAGE_NAME, apply, inject, installInvariant, name };
@@ -9,7 +9,7 @@
9
9
  * @module dsh-output-styles/client
10
10
  */
11
11
  import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
12
- import { type StyleKey } from './locales.ts';
12
+ import { type StyleKey } from './locales.js';
13
13
  declare module '@deepseek-ai/dsh-client-ui-slots' {
14
14
  interface LocaleNamespaceMap {
15
15
  /** The style picker's copy. */