dsh-fishpai 1.0.3 → 1.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ 本项目的更改记录在此文件。
4
+
5
+ All notable changes to this project are documented in this file.
6
+
7
+ 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/);
8
+ 版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
9
+
10
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
11
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
12
+
13
+ ## [1.1.0] - 2026-10-09
14
+
15
+ ### 变更
16
+
17
+ - 客户端挂载改为只走 DSH **官方右侧栏**:标签页与引导列表经 `sidebarRightTabs.register` 加两个 `sidebar.right.pane.tab` 槽位注册,打开走 `sidebarRight.openTab`。此前与之并存的 `dsh-better-sidebar` 回退通道移除。
18
+ - 宿主依赖下限抬到 `>=0.2.0-rc.2 <0.3.0-0`:`peerDependencies` 的七个 `@deepseek-ai/dsh-*` 包与新增的 `engines.dsh` 一条同口径。此前声明的下限是 0.1.5-rc.2。
19
+ - 内置图标名改用宿主当前导出的拼写(`*Regular` 字重后缀),去掉两代拼写的对照表:下限抬高后只需服务一条线;某个名字取不到时仍降级成纯文字。
20
+
21
+ ### Changed
22
+
23
+ - The client now mounts only through the DSH **official right sidebar**: the tab and the guide entry are registered via `sidebarRightTabs.register` plus the two `sidebar.right.pane.tab` slots, and opening goes through `sidebarRight.openTab`. The parallel `dsh-better-sidebar` fallback channel that previously accompanied it is removed.
24
+ - Raised the host floor to `>=0.2.0-rc.2 <0.3.0-0`, applied uniformly to the seven `@deepseek-ai/dsh-*` packages in `peerDependencies` and to a new `engines.dsh` entry. The previous floor was 0.1.5-rc.2.
25
+ - Built-in icon names now use the host's current export spelling (the `*Regular` weight suffix), dropping the two-generation alias table; with the floor raised there is only one line to serve. A name that cannot be resolved still degrades to plain text.
26
+
27
+ ## [1.0.4] - 2026-10-04
28
+
29
+ ### 新增
30
+
31
+ - 插件有了自己的图标:包根 `icon.svg`(36×36,渐变描边的侧视鱼),由 `package.json` 顶层 `icon` 字段声明并列入 `files`。插件列表里不再显示 DSH 的默认图形。
32
+ - 插件列表里的显示名与描述有了中英两份(`locale/en.json`、`locale/zh.json` 的 `meta.title` 与 `meta.description`),中文名定为「鱼排编辑器」;`package.json` 的 `exports` 与 `files` 相应放行 `locale/*.json`。此前该处回退成包名与英文 `description`,在中文界面里中英混排。
33
+
34
+ ### 变更
35
+
36
+ - 右侧栏标签页、引导列表、回退标签页的那条鱼改用包根 `icon.svg` 的**同一份图**(36 画板内联渲染,放大 1.3 倍取景)。插件列表的磁贴与侧边栏不再各画一套。
37
+ - 面板内部(空白页的品牌行)仍用 16 画板的 `FishGlyph`,颜色走 `currentColor`;它与 `icon.svg` 同轮廓,按 36 ÷ 16 = 2.25 折算(描边 0.89,眼睛 0.72)。
38
+
39
+ ### Added
40
+
41
+ - The plugin now ships its own icon: `icon.svg` at the package root (36×36, a gradient-outlined side-view fish), declared through the top-level `icon` field in `package.json` and listed in `files`. The plugin list no longer falls back to the default DSH artwork.
42
+ - The plugin's display name and description in the plugin list now ship in both languages (`meta.title` and `meta.description` in `locale/en.json` and `locale/zh.json`), with the Chinese name settled as 鱼排编辑器; `exports` and `files` in `package.json` admit `locale/*.json` accordingly. The list previously fell back to the package name and the English `description`, mixing languages inside a Chinese interface.
43
+
44
+ ### Changed
45
+
46
+ - The fish in the sidebar tab, the guide list, and the fallback tab now renders the **same artwork** as the package-root `icon.svg` (inlined on the 36-canvas, scaled 1.3× to take up the frame). The plugin-list tile and the sidebar no longer carry two separate drawings.
47
+ - Inside the panel (the blank page's brand row) the 16-canvas `FishGlyph` stays, coloured through `currentColor`; it shares its contour with `icon.svg`, derived by 36 ÷ 16 = 2.25 (stroke 0.89, eye radius 0.72).
48
+
49
+ ## [1.0.3] - 2026-09-28
50
+
51
+ ### 变更
52
+
53
+ - 声明宿主依赖区间 `>=0.1.5-rc.2 <0.3.0-0`(`peerDependencies`,覆盖本插件注入与运行时依赖的七个 `@deepseek-ai/dsh-*` 包)。DSH 0.1.7-rc.1 起的兼容闸按该字段逐条判定插件能否在宿主上加载;本插件在 DSH 0.2.0-rc.1 上安装与加载正常。
54
+
55
+ ### Changed
56
+
57
+ - Declared the host range `>=0.1.5-rc.2 <0.3.0-0` in `peerDependencies`, covering the seven `@deepseek-ai/dsh-*` packages this plugin injects or requires at runtime. The compatibility gate in dsh 0.1.7-rc.1 and later checks this field entry by entry to decide whether the plugin may load on the host; this plugin installs and loads normally on dsh 0.2.0-rc.1.
58
+
59
+ ## [1.0.2] - 2026-09-25
60
+
61
+ ### 安全
62
+
63
+ - **复制回退路径**(没有 `ClipboardItem` 的环境)不再把渲染产物直接写进 WebUI 主文档:改为先解析、剥掉脚本类容器与事件属性、再插入。那个容器与宿主同源,事件属性会在挂载那一刻执行。
64
+ - **自定义主题的样式值不再放行双引号**:样式值会被原样拼进 `style="…"`,一个双引号即可闭合属性并注入任意属性;单引号仍可用。主题色与正文字号改为同一套形态校验,`POST /render` 与文档保存两条写入口共用这份规则。
65
+ - **复制与导出产物在清理阶段剥掉危险标签与事件属性**:`<script>`、`<style>`、`<iframe>`、`<object>`、`<embed>`、`<link>`、`<meta>`、事件属性与危险协议 URL 一律移除,导出的 `.html` 双击打开时稿件里的裸 HTML 不再执行。
66
+ - **外链判定改为「归一化 + 协议白名单」**:`JavaScript:`、`java\tscript:`、实体编码等变体不再被当成正常外链。
67
+ - 代码块的围栏语言串、语言标签与提示卡片标题改为转义后再拼入产物,畸形语言串不再产出第二个 `style` 属性或注入元素。
68
+
69
+ ### 变更
70
+
71
+ - 「参考资料」脚注的判定改为协议白名单(`http`/`https`/`mailto`):相对路径(如 `./notes.md`)与 `ftp:`、`tel:` 等不再计入脚注,但仍原样保留在产物里。
72
+
73
+ ### Security
74
+
75
+ - **The copy fallback path** (environments without `ClipboardItem`) no longer writes the rendered output straight into the WebUI main document: it now parses the output first, strips script-like containers and event attributes, and only then inserts it. That container is same-origin with the host, so an event attribute would execute the moment it is mounted.
76
+ - **Custom theme style values no longer allow double quotes**: a style value is concatenated verbatim into `style="…"`, so a single double quote can close the attribute and inject arbitrary attributes; single quotes are still allowed. Theme colors and body font size now share the same shape validation, and the two write entry points — `POST /render` and document saving — use this same rule.
77
+ - **Copy and export output strips dangerous tags and event attributes during the cleanup stage**: `<script>`, `<style>`, `<iframe>`, `<object>`, `<embed>`, `<link>`, `<meta>`, event attributes and dangerous-protocol URLs are all removed, so bare HTML in the manuscript no longer executes when the exported `.html` is opened by double-clicking.
78
+ - **External link detection now uses normalization plus a protocol whitelist**: variants such as `JavaScript:` and `java\tscript:` and entity-encoded forms are no longer treated as ordinary external links.
79
+ - Code block fence language strings, language labels and prompt card titles are escaped before being concatenated into the output, so a malformed language string no longer produces a second `style` attribute or injects elements.
80
+
81
+ ### Changed
82
+
83
+ - The "References" footnote check now uses a protocol whitelist (`http`/`https`/`mailto`): relative paths (such as `./notes.md`) and `ftp:`, `tel:` and the like are no longer counted as footnotes, but they are still kept verbatim in the output.
84
+
85
+ ## [1.0.1] - 2026-09-23
86
+
87
+ ### 修复
88
+
89
+ - 适配 DSH 0.1.7 的 ui-primitives 图标改名(0.1.7 起导出名去尺寸后缀、改字重后缀,旧拼写在 0.1.7 的导出表里已消失):主题图标、下拉箭头与选中勾按「0.1.7 名 → 0.1.5 名」运行时探测解析,两代宿主共用一份产物(此前 0.1.7 上解析不到导出、按纯文字降级)。
90
+ - 适配 DSH 0.1.7 客户端「Session 多实例」后的当前会话解析:会话列表快照不再携带当前选中,改为读右侧栏座位的挂载会话(0.1.5 线仍走快照);轮询在两代宿主上都定位得到会话(此前 0.1.7 读不到当前会话、整轮空转)。
91
+ - 右侧栏引导页的鱼排入口补上条目 id(0.1.7 起引导条目按 id 标识)。
package/NOTICE.md CHANGED
@@ -10,15 +10,14 @@
10
10
  | 上游仓库 | https://github.com/ye4wzp/mopai-markdown |
11
11
  | 上游作者 | [@ye4wzp](https://github.com/ye4wzp) |
12
12
  | 许可 | MIT |
13
- | 本仓库 fork 自 | `main`(fork 时的上游 HEAD) |
14
- | 上游原样保留位置 | `legacy-site/`(去掉 `screenshots/`,其余原样:`index.html`、`css/`、`js/`、`docs/`、`DESIGN.md`、`README*.md`、`tests/` 等) |
13
+ | 本仓库 fork 自 | `main` @ `c91487abfc5848f5b78e9fcec3b62d58033c61dc`(2026-08-19) |
15
14
 
16
15
  鱼排直接复用了上游两项核心资产,均为 MIT:
17
16
 
18
17
  1. **主题定义** —— 上游 `js/themes.js` 复制为本仓库 `plugin/vendor/themes.js`(换行符归一为 LF;
19
18
  另外**有意删除了两套主题**:「金融时报(ft)」与「Medium」——前者靠整页异色底立身、公众号文章不要
20
- 整页底色,后者与「纽约时报」只剩字号与字体栈的差别)。上游那 13 套的原版文件仍在 `legacy-site/js/`,
21
- 需要逐字节比对时看那边。
19
+ 整页底色,后者与「纽约时报」只剩字号与字体栈的差别)。上游原版 `js/themes.js` 的 blob SHA 为
20
+ `dfa0ea47287fb16969aabe75163f9049c10c82e8`,需要逐字节比对时按此锚点取上游文件核对。
22
21
  2. **渲染管线设计** —— 「先渲染 HTML,再给每个标签内联主题样式」「复制到公众号时把代码块内
23
22
  span 的计算样式内联」「h4–h6 套 h3 样式」「外链转文末参考资料」等行为与验收标准。
24
23
 
package/README.md CHANGED
@@ -1,23 +1,23 @@
1
1
  <div align="center">
2
- <img src="https://raw.githubusercontent.com/OMSociety/dsh-fishpai/main/logo.png" alt="鱼排 FishPai" width="190">
3
- <h1>鱼排 FishPai</h1>
2
+ <img src="https://raw.githubusercontent.com/OMSociety/dsh-fishpai/main/docs/logo.png" alt="鱼排 FishPai" width="190">
3
+ <h1>鱼排编辑器 FishPai</h1>
4
4
  <p>公众号排版工作台,长在 DeepSeek Harness 的右侧栏里。</p>
5
5
  <p>人在侧栏改字、加批注与占位;模型用<strong>块级 diff</strong> 看懂你改了什么、想要什么;成品仍由你复制粘贴进公众号编辑器。</p>
6
6
 
7
7
  <p>
8
- <a href="https://github.com/OMSociety/dsh-fishpai/releases"><img src="https://img.shields.io/github/v/tag/OMSociety/dsh-fishpai?color=4f6ef7&label=version" alt="Version"></a>
9
- <a href="https://github.com/deepseek-ai/dsh"><img src="https://img.shields.io/badge/DSH-%3E%3D0.1.5--rc.2-4f6ef7" alt="DSH"></a>
8
+ <a href="https://www.npmjs.com/package/dsh-fishpai"><img src="https://img.shields.io/npm/v/dsh-fishpai?color=4f6ef7&label=version" alt="Version"></a>
9
+ <a href="https://github.com/deepseek-ai/dsh"><img src="https://img.shields.io/badge/DSH-%3E%3D0.2.0--rc.2_%3C0.3.0--0-4f6ef7" alt="DSH"></a>
10
10
  <a href="LICENSE"><img src="https://img.shields.io/github/license/OMSociety/dsh-fishpai?color=4f6ef7" alt="License"></a>
11
11
  <a href="https://github.com/OMSociety/dsh-fishpai/stargazers"><img src="https://img.shields.io/github/stars/OMSociety/dsh-fishpai?color=4f6ef7" alt="Stars"></a>
12
12
  <a href="https://github.com/OMSociety/dsh-fishpai/issues"><img src="https://img.shields.io/github/issues/OMSociety/dsh-fishpai?color=4f6ef7" alt="Issues"></a>
13
13
  </p>
14
14
 
15
- <a href="#这是什么">这是什么</a> • <a href="#核心特性">核心特性</a> • <a href="#效果">效果</a> • <a href="#快速开始">快速开始</a> • <a href="#模型工具">模型工具</a> • <a href="#面板快捷键">面板快捷键</a> • <a href="#开发">开发</a> • <a href="#许可证与作者">许可证与作者</a>
15
+ <a href="#这是什么">这是什么</a> • <a href="#核心特性">核心特性</a> • <a href="#效果">效果</a> • <a href="#安装方式">安装方式</a> • <a href="#模型工具">模型工具</a> • <a href="#面板快捷键">面板快捷键</a> • <a href="#开发">开发</a> • <a href="#许可证与作者">许可证与作者</a>
16
16
  </div>
17
17
 
18
18
  ## 这是什么
19
19
 
20
- **鱼排**把 Markdown 排成**内联样式 HTML**:整段粘进微信公众号编辑器就得到成品排版。
20
+ **鱼排编辑器**把 Markdown 排成**内联样式 HTML**:整段粘进微信公众号编辑器就得到成品排版。
21
21
 
22
22
  它同时是一个**人在回路里的改稿台**——面板与模型看的是同一篇文档,谁改了什么一目了然。
23
23
 
@@ -53,25 +53,17 @@
53
53
 
54
54
  同一份 HTML 用「导出 HTML」存成文件、在浏览器里打开,看到的就是面板右侧那个样子。
55
55
 
56
- ## 快速开始
56
+ ## 安装方式
57
57
 
58
- **方式一:从 GitHub 装(推荐)**
58
+ **从 npm 安装**
59
59
 
60
60
  ```powershell
61
- # 1) 先停掉 dsh web(运行中的服务会锁住依赖,装完再起)
62
- dsh plugin --profile web add "github:OMSociety/dsh-fishpai#v1.0.2"
63
- # 2) 重新启动 dsh web
61
+ # 先停掉正在运行的 DSH(运行中的服务会锁住依赖,装完再起)
62
+ dsh plugin --profile <profile> add "dsh-fishpai"
64
63
  ```
65
64
 
66
- **方式二:clone 到本地再装**
67
-
68
- ```powershell
69
- git clone https://github.com/OMSociety/dsh-fishpai D:\WorkSpace\dsh-fishpai
70
- dsh plugin --profile web add "github:OMSociety/dsh-fishpai"
71
- ```
72
-
73
- > 装好后**刷新一下浏览器页面**,右侧栏就会多出「鱼排编辑器」入口(官方右侧栏的 `+` 菜单 / 引导页里也能找到)——只重启宿主不够,客户端产物是页面加载时取的。
74
- > 本插件零运行时依赖,不受 `minimumReleaseAge` 影响;客户端产物 `lib/client.js` 已入库,不需要本地构建。
65
+ > 装好后**刷新一下浏览器页面**,「鱼排编辑器」从右侧栏的引导页打开——只重启宿主不够,客户端产物是页面加载时取的;入口与布局按会话记忆,新会话第一次要点一次(模型调 `fishpai_open` 时也会自动打开)。
66
+ > 本插件零运行时依赖,不受 `minimumReleaseAge` 影响。
75
67
 
76
68
  **装完怎么用**
77
69
 
@@ -142,7 +134,6 @@ plugin/vendor/ 上游 themes.js + markdown-it 14.1.0 + highlight.js 11.
142
134
  client/ 客户端源码(TSX → esbuild 打成 lib/client.js)
143
135
  lib/client.js 客户端 bundle(入库;dsh plugin add 不做构建)
144
136
  skills/fishpai/ 鱼排技能:教模型怎么选主题、怎么按块改稿
145
- legacy-site/ 上游 SPA 原样留存,便于复核渲染一致性
146
137
  test/ golden、站点对照、块/diff/批注/补丁、宿主红线、微信兼容层、主题规格、图标双版本对照、bundle 形态、快捷键、真实 Cordis 挂载、客户端 store 时序
147
138
  ```
148
139
 
package/icon.svg ADDED
@@ -0,0 +1,10 @@
1
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="paint0_linear_fishpai" x1="7" y1="10" x2="29" y2="26" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#7FA0FF"/>
5
+ <stop offset="1" stop-color="#3B54C9"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <path d="M7.5 18C9.348 13.56 13.044 10.785 17.748 10.785C20.94 10.785 23.292 12.45 24.804 14.67L28.5 11.34L26.316 18L28.5 24.66L24.804 21.33C23.292 23.55 20.94 25.215 17.748 25.215C13.044 25.215 9.348 22.44 7.5 18Z" stroke="url(#paint0_linear_fishpai)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"/>
9
+ <circle cx="12.2" cy="16.5" r="1.3" fill="url(#paint0_linear_fishpai)"/>
10
+ </svg>
package/lib/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 自动生成,请勿手改 —— 源码在 client/,用 `npm run build` 重新生成。
3
- * 改完记得把本文件一起提交:`dsh plugin add github:` 只安装、不构建。
3
+ * 改完记得把本文件一起提交:`dsh plugin add dsh-fishpai` 只安装、不构建。
4
4
  */
5
5
  window.__ModuleLoader__.load({
6
6
  id: "dsh-fishpai",
@@ -1002,43 +1002,18 @@ window.__ModuleLoader__.load({
1002
1002
  }
1003
1003
 
1004
1004
  // client/icon-names.ts
1005
- var ICON_EXPORT_ALIASES = {
1006
- // 主题图标(THEME_GLYPH 引用的就是这些稳定名)
1007
- IconAgentPresetOutline16: ["IconAgentPresetOutlineRegular", "IconAgentPresetOutline16"],
1008
- IconBranchOutline16: ["IconBranchOutlineRegular", "IconBranchOutline16"],
1009
- IconBrowseOutline16: ["IconBrowseOutlineRegular", "IconBrowseOutline16"],
1010
- IconCodeOutline16: ["IconCodeOutlineRegular", "IconCodeOutline16"],
1011
- IconDarkOutline16: ["IconDarkOutlineRegular", "IconDarkOutline16"],
1012
- IconEditOutline16: ["IconEditOutlineRegular", "IconEditOutline16"],
1013
- IconEnhanceOutline16: ["IconEnhanceOutlineRegular", "IconEnhanceOutline16"],
1014
- IconLightOutline16: ["IconLightOutlineRegular", "IconLightOutline16"],
1015
- IconListPenOutline16: ["IconListPenOutlineRegular", "IconListPenOutline16"],
1016
- IconPersonalizationOutline16: ["IconPersonalizationOutlineRegular", "IconPersonalizationOutline16"],
1017
- IconSparkle16: ["IconSparkleRegular", "IconSparkle16"],
1018
- IconThinkOutline16: ["IconThinkOutlineRegular", "IconThinkOutline16"],
1019
- // 面板控件(下拉箭头 / 选中勾)
1020
- IconChevronDownOutline14: ["IconChevronDownOutlineRegular", "IconChevronDownOutline14"],
1021
- IconCheckOutline14: ["IconCheckOutlineRegular", "IconCheckOutline14"]
1022
- };
1023
- function iconExportCandidates(stable) {
1024
- const aliases = ICON_EXPORT_ALIASES[stable];
1025
- return aliases ? [aliases[0], aliases[1]] : [stable];
1026
- }
1027
1005
  function isIconComponent(value) {
1028
1006
  if (typeof value === "function") return true;
1029
1007
  return !!value && typeof value === "object" && !!value.$$typeof;
1030
1008
  }
1031
- function resolveIconExport(primitives, stable) {
1032
- for (const name2 of iconExportCandidates(stable)) {
1033
- let value;
1034
- try {
1035
- value = primitives ? primitives[name2] : void 0;
1036
- } catch {
1037
- continue;
1038
- }
1039
- if (isIconComponent(value)) return value;
1009
+ function resolveIconExport(primitives, name2) {
1010
+ let value;
1011
+ try {
1012
+ value = primitives ? primitives[name2] : void 0;
1013
+ } catch {
1014
+ return null;
1040
1015
  }
1041
- return null;
1016
+ return isIconComponent(value) ? value : null;
1042
1017
  }
1043
1018
 
1044
1019
  // client/icons.tsx
@@ -1056,57 +1031,63 @@ window.__ModuleLoader__.load({
1056
1031
  if (!Icon) return null;
1057
1032
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { size: props.size ?? fallbackSize, className: props.className });
1058
1033
  }
1059
- function FishGlyph({ size = 16, className }) {
1060
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", className, children: [
1061
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1062
- "path",
1063
- {
1064
- d: "M2.1 8C3.2 5.6 5.4 4.1 8.2 4.1C10.1 4.1 11.5 5 12.4 6.2L14.6 4.4L13.3 8L14.6 11.6L12.4 9.8C11.5 11 10.1 11.9 8.2 11.9C5.4 11.9 3.2 10.4 2.1 8Z",
1065
- stroke: "currentColor",
1066
- strokeWidth: "1.05",
1067
- strokeLinejoin: "round",
1068
- strokeLinecap: "round"
1069
- }
1070
- ),
1071
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "4.9", cy: "7.2", r: "0.75", fill: "currentColor" })
1034
+ function FishMark({ size = 16, className }) {
1035
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: size, height: size, viewBox: "0 0 36 36", fill: "none", "aria-hidden": "true", className, children: [
1036
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("linearGradient", { id: "dsh-fishpai-mark", x1: "7", y1: "10", x2: "29", y2: "26", gradientUnits: "userSpaceOnUse", children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { stopColor: "#7FA0FF" }),
1038
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("stop", { offset: "1", stopColor: "#3B54C9" })
1039
+ ] }) }),
1040
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { transform: "translate(18 18) scale(1.3) translate(-18 -18)", children: [
1041
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1042
+ "path",
1043
+ {
1044
+ d: "M7.5 18C9.348 13.56 13.044 10.785 17.748 10.785C20.94 10.785 23.292 12.45 24.804 14.67L28.5 11.34L26.316 18L28.5 24.66L24.804 21.33C23.292 23.55 20.94 25.215 17.748 25.215C13.044 25.215 9.348 22.44 7.5 18Z",
1045
+ stroke: "url(#dsh-fishpai-mark)",
1046
+ strokeWidth: "2",
1047
+ strokeLinejoin: "round",
1048
+ strokeLinecap: "round"
1049
+ }
1050
+ ),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12.2", cy: "16.5", r: "1.3", fill: "url(#dsh-fishpai-mark)" })
1052
+ ] })
1072
1053
  ] });
1073
1054
  }
1074
1055
  var THEME_GLYPH = {
1075
- default: "IconListPenOutline16",
1056
+ default: "IconListPenOutlineRegular",
1076
1057
  // 排版:默认公众号就是给微信做的那套
1077
- elegant: "IconSparkle16",
1058
+ elegant: "IconSparkleRegular",
1078
1059
  // 优雅简约
1079
- deep_read: "IconThinkOutline16",
1060
+ deep_read: "IconThinkOutlineRegular",
1080
1061
  // 深度阅读
1081
- nyt: "IconBrowseOutline16",
1062
+ nyt: "IconBrowseOutlineRegular",
1082
1063
  // 纽约时报(版面)
1083
- apple: "IconLightOutline16",
1064
+ apple: "IconLightOutlineRegular",
1084
1065
  // Apple 极简(明亮、留白)
1085
- claude: "IconAgentPresetOutline16",
1066
+ claude: "IconAgentPresetOutlineRegular",
1086
1067
  // Claude(对话助手)
1087
- sspai: "IconPersonalizationOutline16",
1068
+ sspai: "IconPersonalizationOutlineRegular",
1088
1069
  // 少数派(个性)
1089
- bamboo: "IconBranchOutline16",
1070
+ bamboo: "IconBranchOutlineRegular",
1090
1071
  // 竹林(枝叶)
1091
- tech: "IconCodeOutline16",
1072
+ tech: "IconCodeOutlineRegular",
1092
1073
  // 技术风格(代码)
1093
- dark_night: "IconDarkOutline16",
1074
+ dark_night: "IconDarkOutlineRegular",
1094
1075
  // 暗夜模式
1095
- gradient: "IconEnhanceOutline16",
1076
+ gradient: "IconEnhanceOutlineRegular",
1096
1077
  // 渐变彩虹(增色)
1097
1078
  // 「自定义主题」:工作目录里那**一套**模型生成的主题,图标固定这一个。
1098
- // 为什么不让模型挑:合法图标名的名单只在浏览器这半(`icon-names.ts` 的对照表),而校验器在宿主那半——
1079
+ // 为什么不让模型挑:图标名是客户端这半的事,宿主那半的校验器看不到候选名单——
1099
1080
  // 让模型选就得在宿主再抄一份、跟着 DSH 升级维护,抄漏一个的后果是"图标静默消失且不报错"。
1100
- custom: "IconEditOutline16"
1081
+ custom: "IconEditOutlineRegular"
1101
1082
  };
1102
1083
  function ThemeGlyph({ themeKey, size = 16, className }) {
1103
1084
  return builtin(THEME_GLYPH[themeKey] || "", { size, className }, 16);
1104
1085
  }
1105
1086
  function CaretGlyph({ size = 14, className }) {
1106
- return builtin("IconChevronDownOutline14", { size, className }, 14) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className, children: "▾" });
1087
+ return builtin("IconChevronDownOutlineRegular", { size, className }, 14) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className, children: "▾" });
1107
1088
  }
1108
1089
  function TickGlyph({ size = 14, className }) {
1109
- return builtin("IconCheckOutline14", { size, className }, 14) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className, children: "✓" });
1090
+ return builtin("IconCheckOutlineRegular", { size, className }, 14) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className, children: "✓" });
1110
1091
  }
1111
1092
 
1112
1093
  // client/panel.tsx
@@ -1216,7 +1197,7 @@ window.__ModuleLoader__.load({
1216
1197
  }
1217
1198
  function BlankMark() {
1218
1199
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fp-blank-mark", children: [
1219
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fp-blank-glyph", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FishGlyph, { size: 15 }) }),
1200
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "fp-blank-glyph", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FishMark, { size: 15 }) }),
1220
1201
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "鱼排编辑器" })
1221
1202
  ] });
1222
1203
  }
@@ -2425,7 +2406,8 @@ window.__ModuleLoader__.load({
2425
2406
  border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);
2426
2407
  }
2427
2408
  .fp-blank-mark{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-primary)}
2428
- /* 品牌标:鱼形图标放在一块小方瓦里(图标本身用 currentColor,深浅色通吃) */
2409
+ /* 品牌标:鱼形图标放在一块小方瓦里。标自带渐变(与侧边栏、插件列表磁贴同一份图),
2410
+ 方瓦的底色与描边只用令牌,深浅色通吃 */
2429
2411
  .fp-blank-glyph{
2430
2412
  width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;
2431
2413
  background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);
@@ -2515,7 +2497,6 @@ window.__ModuleLoader__.load({
2515
2497
  var inject = ["slots", "sessions"];
2516
2498
  var TAB_ID = "dsh-fishpai";
2517
2499
  var TAB_KIND = "fishpai";
2518
- var FALLBACK_TAB_ID = `${TAB_ID}:editor`;
2519
2500
  var POLL_MS = 3e3;
2520
2501
  function pick(injected, key) {
2521
2502
  if (!injected) return void 0;
@@ -2580,16 +2561,14 @@ window.__ModuleLoader__.load({
2580
2561
  return React2.createElement(
2581
2562
  "span",
2582
2563
  { className: "fp-title-label" },
2583
- React2.createElement(FishGlyph, { size: 14, className: "fp-title-glyph" }),
2564
+ React2.createElement(FishMark, { size: 14, className: "fp-title-glyph" }),
2584
2565
  "鱼排编辑器"
2585
2566
  );
2586
2567
  }
2587
2568
  let openOfficial = null;
2588
- let openFallback = null;
2589
2569
  const openPanel = () => {
2590
- const open = openOfficial || openFallback;
2591
- if (!open) throw new Error("右侧栏通道尚未就绪");
2592
- open();
2570
+ if (!openOfficial) throw new Error("官方右侧栏尚未就绪");
2571
+ openOfficial();
2593
2572
  };
2594
2573
  const openIfRequested = (sessionId, docKey) => {
2595
2574
  try {
@@ -2603,8 +2582,6 @@ window.__ModuleLoader__.load({
2603
2582
  });
2604
2583
  return true;
2605
2584
  };
2606
- let officialReady = false;
2607
- let disposeFallbackTab = null;
2608
2585
  let seatHandle = null;
2609
2586
  try {
2610
2587
  seatHandle = ctx.inject(["sidebarRightTabs", "sidebarRight"], (injected) => {
@@ -2634,7 +2611,7 @@ window.__ModuleLoader__.load({
2634
2611
  title: () => "鱼排编辑器",
2635
2612
  description: () => "公众号排版:Markdown + 实时预览 + 与模型来回改稿",
2636
2613
  // 不给 icon 的话,新标签页的引导列表画一个默认的立方体占位(就是"看着像缺图标"的那个)
2637
- icon: FishGlyph
2614
+ icon: FishMark
2638
2615
  }
2639
2616
  ]
2640
2617
  })
@@ -2657,15 +2634,6 @@ window.__ModuleLoader__.load({
2657
2634
  if (sidebarRight && typeof sidebarRight.openTab === "function") {
2658
2635
  openOfficial = () => sidebarRight.openTab(TAB_KIND);
2659
2636
  }
2660
- officialReady = true;
2661
- if (disposeFallbackTab) {
2662
- try {
2663
- disposeFallbackTab();
2664
- } catch {
2665
- }
2666
- disposeFallbackTab = null;
2667
- openFallback = null;
2668
- }
2669
2637
  const dispose = () => {
2670
2638
  for (const off of disposers.reverse()) {
2671
2639
  try {
@@ -2673,7 +2641,6 @@ window.__ModuleLoader__.load({
2673
2641
  } catch {
2674
2642
  }
2675
2643
  }
2676
- officialReady = false;
2677
2644
  openOfficial = null;
2678
2645
  getMountedSession = null;
2679
2646
  };
@@ -2682,33 +2649,6 @@ window.__ModuleLoader__.load({
2682
2649
  } catch (error) {
2683
2650
  console.warn("[dsh-fishpai] 官方右侧栏席位注入失败:", error);
2684
2651
  }
2685
- let fallbackHandle = null;
2686
- try {
2687
- fallbackHandle = ctx.inject(["betterSidebar"], (injected) => {
2688
- if (officialReady) return;
2689
- const bs = pick(injected, "betterSidebar");
2690
- if (!bs || typeof bs.registerTab !== "function") return;
2691
- const off = bs.registerTab({
2692
- id: FALLBACK_TAB_ID,
2693
- title: () => "鱼排编辑器",
2694
- // better-sidebar 的 TabDescriptor 支持 icon(它把它转交给原生右侧栏的引导页)
2695
- icon: (size) => React2.createElement(FishGlyph, { size: size || 16 }),
2696
- order: 40,
2697
- single: true,
2698
- component: (props) => React2.createElement(PanelHost, props)
2699
- });
2700
- openFallback = () => bs.openTab({ type: FALLBACK_TAB_ID });
2701
- disposeFallbackTab = () => {
2702
- try {
2703
- off();
2704
- } catch {
2705
- }
2706
- };
2707
- return off;
2708
- });
2709
- } catch (error) {
2710
- console.warn("[dsh-fishpai] better-sidebar 回退注入失败:", error);
2711
- }
2712
2652
  ctx.effect(() => {
2713
2653
  let stopped = false;
2714
2654
  let warned = false;
@@ -2757,8 +2697,6 @@ window.__ModuleLoader__.load({
2757
2697
  stopped = true;
2758
2698
  clearInterval(timer);
2759
2699
  seatHandle?.dispose?.();
2760
- fallbackHandle?.dispose?.();
2761
- disposeFallbackTab?.();
2762
2700
  for (const store of stores.values()) store.dispose();
2763
2701
  stores.clear();
2764
2702
  };
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "FishPai Editor",
4
+ "description": "Typeset WeChat Official Account Markdown in the right sidebar: you edit and annotate, the model reads block-level diffs."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "鱼排编辑器",
4
+ "description": "在右侧栏把 Markdown 排成公众号成品:人改字加批注,模型读块级 diff。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-fishpai",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "DeepSeek Harness plugin: 鱼排 FishPai — a WeChat Official Account typesetting workbench in the DSH right sidebar, with block-level diffs and annotations a model can read. Rendering core derived from the MIT mopai-markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,13 +22,18 @@
22
22
  "skill"
23
23
  ],
24
24
  "main": "./plugin/index.mjs",
25
+ "icon": "./icon.svg",
25
26
  "exports": {
26
27
  ".": "./plugin/index.mjs",
28
+ "./locale/*.json": "./locale/*.json",
27
29
  "./client": "./lib/client.js",
28
30
  "./cordis.patch.yml": "./cordis.patch.yml",
29
31
  "./package.json": "./package.json"
30
32
  },
31
33
  "files": [
34
+ "CHANGELOG.md",
35
+ "icon.svg",
36
+ "locale/*.json",
32
37
  "plugin",
33
38
  "lib",
34
39
  "skills",
@@ -38,13 +43,13 @@
38
43
  "LICENSE"
39
44
  ],
40
45
  "peerDependencies": {
41
- "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.5-rc.2 <0.3.0-0",
42
- "@deepseek-ai/dsh-client-ui-sidebar-right": ">=0.1.5-rc.2 <0.3.0-0",
43
- "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.2 <0.3.0-0",
44
- "@deepseek-ai/dsh-host-webserver": ">=0.1.5-rc.2 <0.3.0-0",
45
- "@deepseek-ai/dsh-session": ">=0.1.5-rc.2 <0.3.0-0",
46
- "@deepseek-ai/dsh-skill": ">=0.1.5-rc.2 <0.3.0-0",
47
- "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.3.0-0"
46
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.2.0-rc.2 <0.3.0-0",
47
+ "@deepseek-ai/dsh-client-ui-sidebar-right": ">=0.2.0-rc.2 <0.3.0-0",
48
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.2.0-rc.2 <0.3.0-0",
49
+ "@deepseek-ai/dsh-host-webserver": ">=0.2.0-rc.2 <0.3.0-0",
50
+ "@deepseek-ai/dsh-session": ">=0.2.0-rc.2 <0.3.0-0",
51
+ "@deepseek-ai/dsh-skill": ">=0.2.0-rc.2 <0.3.0-0",
52
+ "@deepseek-ai/dsh-tools": ">=0.2.0-rc.2 <0.3.0-0"
48
53
  },
49
54
  "dsh": {
50
55
  "bundle": {
@@ -55,7 +60,8 @@
55
60
  }
56
61
  },
57
62
  "engines": {
58
- "node": ">=20"
63
+ "node": ">=20",
64
+ "dsh": ">=0.2.0-rc.2 <0.3.0-0"
59
65
  },
60
66
  "scripts": {
61
67
  "build": "node scripts/build-client.mjs",
@@ -149,7 +149,7 @@ const themes = {
149
149
  // · ft 的特点就是整页粉橙异色底(background: #fff1e5),而公众号文章不适合整页底色;
150
150
  // 去掉底之后它与相邻的衬线主题几乎一样,没有单独存在的价值。
151
151
  // · medium 与 nyt 的差别只剩字号与字体栈,实际观感重合。
152
- // 上游原版 themes.js 仍完整保留在 legacy-site/ 里,需要逐字节比对时看那边。
152
+ // 上游原版 themes.js 的逐字节比对锚点见 NOTICE.md。
153
153
 
154
154
  // ─── 现代数字系列 ─────────────────────
155
155
  apple: {