dsh-ppt-studio 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.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +480 -0
  3. package/agent-presets/ppt/agent.cordis.yml +308 -0
  4. package/agent-presets/ppt/preset.yml +3 -0
  5. package/cordis.patch.yml +29 -0
  6. package/docs/00-/350/256/276/350/256/241/346/272/220.md +537 -0
  7. package/docs/01-/351/234/200/346/261/202/344/270/216/347/233/256/346/240/207.md +136 -0
  8. package/docs/02-/346/212/200/346/234/257/346/212/245/345/221/212.md +483 -0
  9. package/docs/03-/346/233/264/346/226/260/346/227/245/345/277/227.md +2898 -0
  10. package/docs/04-/350/267/257/347/272/277/345/233/276/344/270/216/351/207/214/347/250/213/347/242/221.md +113 -0
  11. package/docs/05-/350/277/255/344/273/243/346/265/201/347/250/213.md +210 -0
  12. package/docs/06-/350/257/204/345/256/241/344/270/216/346/265/213/350/257/225.md +296 -0
  13. package/docs/fidelity-report.md +225 -0
  14. package/examples/fx/fx-mini/deck.yaml +39 -0
  15. package/examples/fx/fx-mini/pages/01.yaml +6 -0
  16. package/examples/fx/fx-mini/pages/02.yaml +2 -0
  17. package/examples/fx/fx-mini/pages/03.yaml +6 -0
  18. package/examples/fx/fx-pro/deck.yaml +48 -0
  19. package/examples/fx/fx-pro/pages/01_cover.yaml +40 -0
  20. package/examples/fx/fx-pro/pages/02_arch.yaml +55 -0
  21. package/examples/fx/fx-pro/pages/03_table.yaml +20 -0
  22. package/examples/fx/fx-pro/pages/04_chart.yaml +40 -0
  23. package/examples/fx/fx-pro/pages/05_timeline.yaml +71 -0
  24. package/examples/fx/fx-pro/pages/06_longtext.yaml +13 -0
  25. package/examples/fx/fx-pro/pages/07_safearea.yaml +33 -0
  26. package/examples/fx/fx-pro/pages/08_contrast.yaml +22 -0
  27. package/examples/fx/fx-pro/pages/09_custgeom.yaml +32 -0
  28. package/examples/fx/fx-pro/pages/10_numbers.yaml +25 -0
  29. package/examples/fx/fx-pro/pages/11_section.yaml +20 -0
  30. package/examples/fx/fx-pro/pages/12_summary.yaml +57 -0
  31. package/examples/fx/fx-pro/preview/01_pages_01_cover.html +1 -0
  32. package/examples/fx/fx-pro/preview/02_pages_02_arch.html +3 -0
  33. package/examples/fx/fx-pro/preview/03_pages_03_table.html +1 -0
  34. package/examples/fx/fx-pro/preview/04_pages_04_chart.html +3 -0
  35. package/examples/fx/fx-pro/preview/05_pages_05_timeline.html +2 -0
  36. package/examples/fx/fx-pro/preview/06_pages_06_longtext.html +4 -0
  37. package/examples/fx/fx-pro/preview/07_pages_07_safearea.html +2 -0
  38. package/examples/fx/fx-pro/preview/08_pages_08_contrast.html +1 -0
  39. package/examples/fx/fx-pro/preview/09_pages_09_custgeom.html +1 -0
  40. package/examples/fx/fx-pro/preview/10_pages_10_numbers.html +1 -0
  41. package/examples/fx/fx-pro/preview/11_pages_11_section.html +1 -0
  42. package/examples/fx/fx-pro/preview/12_pages_12_summary.html +1 -0
  43. package/examples/fx/fx-pro/preview/deck.html +10 -0
  44. package/examples/fx/fx-pro/preview/layout.json +2325 -0
  45. package/examples/fx/fx-pro/preview/measured.json +814 -0
  46. package/examples/fx/fx-pro.pptx +0 -0
  47. package/examples/fx/ren-single/01.png +0 -0
  48. package/examples/fx/ren-spliced/01.png +0 -0
  49. package/examples/fx/ren-spliced/03.png +0 -0
  50. package/examples/fx/seed.pptx +0 -0
  51. package/examples/fx/single.pptx +0 -0
  52. package/examples/fx/spliced.pptx +0 -0
  53. package/examples/smoke/deck.yaml +26 -0
  54. package/examples/smoke/imported/deck.yaml +30 -0
  55. package/examples/smoke/imported/import-styles.json +126 -0
  56. package/examples/smoke/imported/pages/slide_01.yaml +31 -0
  57. package/examples/smoke/imported/pages/slide_02.yaml +38 -0
  58. package/examples/smoke/imported/pages/slide_03.yaml +55 -0
  59. package/examples/smoke/imported/preview-rt/01_pages_slide_01.html +1 -0
  60. package/examples/smoke/imported/preview-rt/02_pages_slide_02.html +1 -0
  61. package/examples/smoke/imported/preview-rt/03_pages_slide_03.html +1 -0
  62. package/examples/smoke/imported/preview-rt/deck.html +1 -0
  63. package/examples/smoke/imported/preview-rt/layout.json +434 -0
  64. package/examples/smoke/imported/reference/previews/01.png +0 -0
  65. package/examples/smoke/imported/reference/previews/02.png +0 -0
  66. package/examples/smoke/imported/reference/previews/03.png +0 -0
  67. package/examples/smoke/imported/source.pptx +0 -0
  68. package/examples/smoke/media-test.png +0 -0
  69. package/examples/smoke/out-smoke.pptx +0 -0
  70. package/examples/smoke/pages/01_cover.yaml +27 -0
  71. package/examples/smoke/pages/02_content.yaml +42 -0
  72. package/examples/smoke/pages/03_chart.yaml +35 -0
  73. package/examples/smoke/preview/01_pages_01_cover.html +1 -0
  74. package/examples/smoke/preview/02_pages_02_content.html +1 -0
  75. package/examples/smoke/preview/03_pages_03_chart.html +1 -0
  76. package/examples/smoke/preview/deck.html +1 -0
  77. package/examples/smoke/preview/layout.json +378 -0
  78. package/lib/autodeclare.js +40 -0
  79. package/lib/commands.js +161 -0
  80. package/lib/crosscheck.js +300 -0
  81. package/lib/imgmeta.js +55 -0
  82. package/lib/index.js +239 -0
  83. package/lib/measurement.js +209 -0
  84. package/lib/msrender.js +123 -0
  85. package/lib/pptd/export-pptx.js +686 -0
  86. package/lib/pptd/import-pptx.js +774 -0
  87. package/lib/pptd/layout.js +209 -0
  88. package/lib/pptd/render-html.js +254 -0
  89. package/lib/pptd/schema.js +518 -0
  90. package/lib/pptd/svgCharts.js +147 -0
  91. package/lib/pptxPy.js +205 -0
  92. package/lib/preset-delivery.js +195 -0
  93. package/lib/preview-server.js +164 -0
  94. package/lib/router.js +165 -0
  95. package/lib/scaffold.js +315 -0
  96. package/lib/skill.js +174 -0
  97. package/lib/splice.js +219 -0
  98. package/lib/state.js +88 -0
  99. package/lib/surgical.js +369 -0
  100. package/lib/templates.js +400 -0
  101. package/lib/tools.js +955 -0
  102. package/lib/verify.js +828 -0
  103. package/lib/xmljs.js +112 -0
  104. package/lib/zips.js +117 -0
  105. package/package.json +81 -0
  106. package/scripts/audit-manual-facts.mjs +294 -0
  107. package/scripts/audit-template-fidelity.mjs +162 -0
  108. package/scripts/bench-m2.mjs +48 -0
  109. package/scripts/build-templates.mjs +63 -0
  110. package/scripts/build.mjs +14 -0
  111. package/scripts/build.sh +7 -0
  112. package/scripts/check-lib-freshness.mjs +70 -0
  113. package/scripts/check-preset.mjs +189 -0
  114. package/scripts/check-tracked-lf.mjs +84 -0
  115. package/scripts/dbg-import.mjs +13 -0
  116. package/scripts/dbg-media.mjs +10 -0
  117. package/scripts/dbg-tpl-inventory.mjs +23 -0
  118. package/scripts/dump-workflow-baseline.mjs +38 -0
  119. package/scripts/e2e-1.0.mjs +129 -0
  120. package/scripts/eval-skills-blind.mjs +91 -0
  121. package/scripts/eval-skills-score.mjs +129 -0
  122. package/scripts/export-orig-templates.ps1 +17 -0
  123. package/scripts/fixtures/workflow-baseline.json +300 -0
  124. package/scripts/fixtures.mjs +501 -0
  125. package/scripts/import-user-templates.mjs +60 -0
  126. package/scripts/install-desktop.mjs +312 -0
  127. package/scripts/install.mjs +209 -0
  128. package/scripts/migrate-templates-dualtrack.mjs +71 -0
  129. package/scripts/preflight-1.0.mjs +198 -0
  130. package/scripts/probe-asset-freshness.mjs +57 -0
  131. package/scripts/probe-effect-semantics.mjs +69 -0
  132. package/scripts/probe-reparse-safety.mjs +32 -0
  133. package/scripts/rebuild-templates-c11.mjs +69 -0
  134. package/scripts/regression-real.mjs +84 -0
  135. package/scripts/release-sync.mjs +425 -0
  136. package/scripts/shot-templates.mjs +49 -0
  137. package/scripts/smoke.mjs +2512 -0
  138. package/scripts/verify-bundle-install.mjs +281 -0
  139. package/scripts/verify-fresh-install.mjs +260 -0
  140. package/skills/ppt-studio-copy/SKILL.md +139 -0
  141. package/skills/ppt-studio-craft/SKILL.md +171 -0
  142. package/skills/ppt-studio-data/SKILL.md +173 -0
  143. package/skills/ppt-studio-manual/SKILL.md +104 -0
  144. package/templates/academic-white/deck.yaml +24 -0
  145. package/templates/academic-white/pages/_chart.yaml +43 -0
  146. package/templates/academic-white/pages/_compare.yaml +37 -0
  147. package/templates/academic-white/pages/_content.yaml +35 -0
  148. package/templates/academic-white/pages/_cover.yaml +28 -0
  149. package/templates/academic-white/pages/_ending.yaml +28 -0
  150. package/templates/academic-white/pages/_flow.yaml +61 -0
  151. package/templates/academic-white/preview.png +0 -0
  152. package/templates/academic-white/template.yaml +14 -0
  153. package/templates/business-blue/deck.yaml +28 -0
  154. package/templates/business-blue/pages/_chart.yaml +36 -0
  155. package/templates/business-blue/pages/_compare.yaml +45 -0
  156. package/templates/business-blue/pages/_content.yaml +80 -0
  157. package/templates/business-blue/pages/_cover.yaml +39 -0
  158. package/templates/business-blue/pages/_ending.yaml +32 -0
  159. package/templates/business-blue/pages/_flow.yaml +87 -0
  160. package/templates/business-blue/preview.png +0 -0
  161. package/templates/business-blue/template.yaml +14 -0
  162. package/templates/pitch-bold/deck.yaml +23 -0
  163. package/templates/pitch-bold/pages/_chart.yaml +32 -0
  164. package/templates/pitch-bold/pages/_compare.yaml +36 -0
  165. package/templates/pitch-bold/pages/_content.yaml +58 -0
  166. package/templates/pitch-bold/pages/_cover.yaml +31 -0
  167. package/templates/pitch-bold/pages/_ending.yaml +27 -0
  168. package/templates/pitch-bold/pages/_flow.yaml +46 -0
  169. package/templates/pitch-bold/preview.png +0 -0
  170. package/templates/pitch-bold/template.yaml +14 -0
  171. package/templates/tech-dark/deck.yaml +24 -0
  172. package/templates/tech-dark/pages/_chart.yaml +27 -0
  173. package/templates/tech-dark/pages/_compare.yaml +38 -0
  174. package/templates/tech-dark/pages/_content.yaml +51 -0
  175. package/templates/tech-dark/pages/_cover.yaml +30 -0
  176. package/templates/tech-dark/pages/_ending.yaml +25 -0
  177. package/templates/tech-dark/pages/_flow.yaml +80 -0
  178. package/templates/tech-dark/preview.png +0 -0
  179. package/templates/tech-dark/template.yaml +14 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zbsph
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,480 @@
1
+ # PPT 工作室(dsh-ppt-studio)
2
+
3
+ 在 DeepSeek Harness 里说需求,它把 PPT 做出来:先定大纲和版式,再逐页制作,每页过一遍自动检查,最后交付一个能用 PowerPoint 打开、继续改的 `.pptx`。
4
+
5
+ 当前版本 **1.0.4**,安装包 **866 kB**(1.0.3 及更早的版本是 35 MB,因为随包带着 4 套没人用过的导入模板,1.0.4 把它们删了)。
6
+
7
+ 装上之后,**这个 profile 的所有会话都能用**,不需要专门切到某个预设。预设「PPT 工作室」提供的是人格和身份,不是"开关"。
8
+
9
+ ---
10
+
11
+ ## 1. 装上
12
+
13
+ ### 1.1 需要什么
14
+
15
+ 一台能跑 `dsh web` 的机器,或者 **DeepSeek Harness 桌面端**(桌面端见 §1.7,装法不同)。宿主版本要求 **DSH `>= 0.1.7-rc.1`**(本包 1.0.7 起;`0.1.7-rc.1` 命令行版验过,`0.1.7-rc.2` 命令行版与**桌面端**都验过)。Office、Edge/Chrome、python-pptx 都是**可选增强**:没有它们插件照常工作,只是真渲染、截图、兜底引擎这些能力自动降级,交付说明里会写明。
16
+
17
+ ### 1.2 一条命令
18
+
19
+ 从 [Releases 页面](https://github.com/zbsph/dsh-ppt-studio/releases) 复制**最新那条** `.tgz` 资产的完整链接,然后:
20
+
21
+ ```powershell
22
+ dsh plugin --profile web add <粘贴那条资产 URL>
23
+ # 装完重启 dsh web
24
+ ```
25
+
26
+ 本插件声明了 `dsh.bundle.patch`(仓库根的 `cordis.patch.yml`),所以**装完就挂上了**:不用手工建链接,不用跑安装器,也不用 npm 账号(资产是公开的,装的人不需要账号)。
27
+
28
+ 资产名形如 `dsh-ppt-studio-1.1.0-20260926-0238-72517e53.tgz`:版本、构建时间、构建内容的前 8 位哈希。页面会保留历次构建,所以**按上传时间取最新那条**。懒得翻页面就用这行拿名字:
29
+
30
+ ```powershell
31
+ gh release view v1.1.0 --json assets --jq '.assets | sort_by(.createdAt) | last | .name'
32
+ ```
33
+
34
+ > **npm 上还没有这个包**。包名 `dsh-ppt-studio` 已经占好(未被别人使用),首次发布被 npm 的 2FA 写入策略挡下
35
+ > (`E403 … Two-factor authentication or granular access token with bypass 2fa enabled is required`),需要账号持有人提供验证码或建一个可绕过 2FA 的 token。
36
+ > **在发布成功之前,别用 `dsh plugin add dsh-ppt-studio` —— 那会 404。** 等上架后这里会换成 npm 命令,两条通道的内容是同一份字节。
37
+
38
+ 也可以直接装仓库地址,产物和 tgz 一样(`lib/` 已入库):
39
+
40
+ ```powershell
41
+ dsh plugin --profile web add https://github.com/zbsph/dsh-ppt-studio
42
+ ```
43
+
44
+ > 为什么资产名不固定:同一个 URL 用 `--clobber` 覆盖内容后,pnpm 会复用本地旧副本,`dsh plugin add <同一 URL>` 不会重新下载(2026-09-15 实测,`--force` 也绕不过)。把构建哈希写进文件名,URL 必变,升级才真的换字节。
45
+
46
+ ### 1.3 装完怎么确认
47
+
48
+ ```powershell
49
+ dsh --profile web --dump-config # 组合树里应出现 ppt-studio 插件行
50
+ ```
51
+
52
+ 看到这行就说明挂上了,重启 `dsh web` 后生效。
53
+
54
+ ### 1.4 升级 / 卸载
55
+
56
+ ```powershell
57
+ # 升级:拿新的资产 URL 再跑一次 add,不需要先卸载
58
+ dsh plugin --profile web add <新的资产 URL>
59
+
60
+ # 卸载
61
+ dsh plugin --profile web remove dsh-ppt-studio
62
+ ```
63
+
64
+ 从 v1.0.2 或更早升上来的注意一件事:那时的包名是 `@dsh-external/dsh-ppt-studio`。旧包会作为独立依赖留在 profile 里,和新包一起被挂载两次。先摘掉它:
65
+
66
+ ```powershell
67
+ dsh plugin --profile web remove @dsh-external/dsh-ppt-studio
68
+ ```
69
+
70
+ 同时装不会崩(插件里有防重),但没必要。安装器检测到旧包残留时会提醒你。
71
+
72
+ ### 1.5 没有 pnpm,或者想离线装
73
+
74
+ 下载 `.tgz`,解压到任意目录,然后跑安装器:
75
+
76
+ ```powershell
77
+ tar -xzf dsh-ppt-studio-<版本>-<构建时间>-<构建戳>.tgz -C D:\plugins
78
+ node D:\plugins\package\scripts\install.mjs
79
+ # 自定义 DSH_HOME:加 --prefix <你的 .dsh 目录>
80
+ # 指定安装规格:--spec <URL|目录>;跳过预设资产校验:--no-preset
81
+ ```
82
+
83
+ 安装器是幂等的,重复跑会跳过已经存在的项。装完一样要重启 `dsh web`。
84
+
85
+ 如果你已经在用 dsh-super-injector,在注入器环境里对解压目录(或源码目录)跑 `dev_inject_plugin` 也行,注入器负责建链接和重启恢复。
86
+
87
+ ### 1.6 想让工具只在「PPT 工作室」里出现
88
+
89
+ **本版本(DSH 0.1.7 及以后)不支持这种隔离**,安装器的 `--isolate` 会直接拒绝并说明原因,而不是写出一个永远不会被读到的预设。
90
+
91
+ 原因是宿主换了机制:0.1.6 及以前,预设是"磁盘上的一个目录"(`~/.dsh/.agent-presets/ppt/`),
92
+ 所以隔离可以靠"预设目录里放一个链接 + 预设里写一行相对路径"实现;**0.1.7 把目录发现整个删掉了**
93
+ (上游原文:*the harness discovers no preset on disk*),预设改为向 `agentPresets` 注册表**声明**,
94
+ 而预设里的每一行都要在**注册表所在那一层**的路径下解析——那里既不是你的 profile,也不是预设目录,
95
+ 所以相对路径和包名都解析不到,预设会被判 `broken`,选择器里根本不会列出它。
96
+
97
+ 于是本版本只有一条受支持的装法:**默认的全局装法**(`dsh plugin add` / `install.mjs` 不带 `--isolate`),
98
+ 这个 profile 的所有会话都能用 ppt_* 工具与手册。预设「PPT 工作室」仍然存在、仍可选,它提供的是**人格与身份**(见 §1.1)。
99
+
100
+ > 想要"只在某个预设里生效"需要把插件行写进**预设声明本身**,并给它一个安装期算出的绝对 `file://` 名字。
101
+ > 这块还没做——宁可明确拒绝,也不静默失败。
102
+
103
+ ### 1.7 桌面端(DeepSeek Harness 应用)
104
+
105
+ 桌面版把 harness 打在自己的应用目录里,**profile 是独立的 `desktop`**(`~/.dsh/profiles/desktop`),
106
+ 所以你之前给 `web` profile 装的那份不会自动出现在桌面端。
107
+
108
+ 装法不同,因为桌面端有两条限制:
109
+
110
+ - **命令行不让你碰 `desktop` profile**。`dsh plugin --profile desktop ...` 会直接报
111
+ `profile "desktop" is managed exclusively by the Electron application`,
112
+ 启动和插件管理都是这样,没有绕过开关。
113
+ - **桌面端自带的 pnpm 装不了 tarball 网址**。它内置 pnpm 11.7.0,而桌面 profile 用的是
114
+ `nodeLinker: hoisted`;这个组合下 `pnpm add <https…tgz>` 会报
115
+ `ERR_PNPM_MISSING_TARBALL_INTEGRITY`。同样的 URL 换成 pnpm 11.21 或去掉 `nodeLinker` 都能装上。
116
+
117
+ 所以桌面端用专门的安装器(它只调用**应用自带的** pnpm 和 Node,不会用系统 Node 去重编 profile 里的原生模块):
118
+
119
+ ```powershell
120
+ # 从发布包解压后(或直接对源码目录)
121
+ node D:\plugins\package\scripts\install-desktop.mjs
122
+ # 自定义:--prefix <你的 .dsh 目录> / --app-dir <应用目录> / --spec <URL|tgz|目录>
123
+ # 先看看它会做什么、不动盘:--dry-run
124
+ # 卸载:--uninstall
125
+ ```
126
+
127
+ 它会:把本包打成一个 tgz 放进 `<profile>/.dsh-plugins/`,以相对 `file:` 规格装进 profile
128
+ (这样不会因为外部目录被删而让桌面端下次装依赖时失败),再把包名补进 `dsh.profile.bundles`
129
+ (桌面端启动只认这个列表)。装完**必须重启桌面端**——bundle 层在启动时组合,不热更。
130
+
131
+ > 显式给 `--spec <https…tgz>` 时,安装器会先按原样试;撞上上面那个缺陷就自动回退
132
+ > (有可用的系统 pnpm 就用它,否则下载到 profile 内走 `file:`)。
133
+ > 两条路都实测过。安装失败时它会**把 profile 文件还原回原样**,不会留半个状态给你。
134
+
135
+ 重启后确认:新建会话的预设选择器里能看到「PPT 工作室」;在会话里调一次 `ppt_state`,
136
+ `presetDelivery` 字段会写明预设声明成功与否。
137
+
138
+ ---
139
+
140
+ ## 2. 用起来
141
+
142
+ ### 2.1 三步
143
+
144
+ 1. 进入「PPT 工作室」,直接说需求,比如"帮我做一个 10 页的年度总结 PPT"。它会按题材定风格;你也可以点名用内置模板("用内置模板"),或者把它自己的 ppt 丢给它参考。
145
+ 2. 跟着工作流走:澄清需求 → 定大纲 → 定版式 → 逐页制作 → 页审 → 整体审 → 导出。每页做完会自动跑一遍渲染和检查。
146
+ 3. 拿交付物:`.pptx` + 中间层工程 + 一份说明(素材来源、没做视觉审阅的部分、怎么改)。对话里会给你一个预览链接,点开就能看。
147
+
148
+ ```text
149
+ /ppt quick # 快速模式:省 token,页数≤8、文本精简、跳过视觉审阅(交付说明会标注)
150
+ /ppt normal # 完整模式(默认)
151
+ /ppt quality audit # 从严档:禁止一键声明、强制逐页视觉审阅、导出后回读断言 + 真渲染复核
152
+ /ppt template <id> # 记本会话默认模板
153
+ /ppt help
154
+ ```
155
+
156
+ 还不熟 DSL 的话,让它先 `ppt_new(dir=D:\demo)` 生成一个能跑通的示例工程,改那个比从空文件写快。
157
+
158
+ ### 2.2 四类任务
159
+
160
+ | 任务 | 怎么说 | 它怎么做 | 你拿到什么 |
161
+ |---|---|---|---|
162
+ | 从头做 | "做一个 XX 主题的 PPT" | 按题材定风格(你指定用内置模板、或某个模板明显适配时才用现成的),逐页做 | 完整工程 + pptx |
163
+ | 补完 | "补两页 / 加个章节" | 复制母版当参考,新增页注册进页表 | 追加后的工程 + pptx |
164
+ | 修改 | "改第 15 页 / 美化这页" | 导入原稿读真身 → 只改这页 → 替换回原稿 | 整册只变一页(其余页逐字节不动)+ 可选单页版 |
165
+ | 总结 | "把这 50 页总结成 10 页" | 导入全稿,提炼重排 | 新工程 + pptx |
166
+
167
+ 任务是按语义识别的:说清楚是 PPT 需求才进入工作流,随便提一句"我昨天做了个 PPT"不会误触发。
168
+
169
+ ### 2.3 自带 4 本手册
170
+
171
+ 插件里内置了 4 本手册,模型按需加载,不用你管:
172
+
173
+ | 手册 | 什么时候用 |
174
+ |---|---|
175
+ | `ppt-studio-manual` | 你**提问**时用("这插件怎么用 / XX 怎么写 / 为什么报错")。制作过程中不加载 |
176
+ | `ppt-studio-craft` | 定大纲、定版式,"这页怎么排 / 太挤 / 太像模板了" |
177
+ | `ppt-studio-data` | 页面要放数字或图表 |
178
+ | `ppt-studio-copy` | 写标题要点,"太 AI 了 / 像机器写的" |
179
+
180
+ 这 4 本是纯增量:只给启发式和反例,不改规则、也不定义任何检查数值。没有 `dsh-skill` 服务的极简装配下也能用,只是手册不以目录形式出现。
181
+
182
+ ---
183
+
184
+ ## 3. 模板
185
+
186
+ 自带 4 套自研风格,每套含主题和 6 张版式母版:`business-blue`(商务蓝)、`academic-white`(学术会议)、`tech-dark`(科技深色)、`pitch-bold`(路演大字)。
187
+
188
+ **什么时候会用它们**:你明确要求用内置模板时(它把清单和预览图给你挑),或者某个模板明显贴合你的题材时。**你没提模板的话,它默认按题材自己设计风格**,不会拿现成模板凑——历史题材那种明显不适配的,硬套只会更差。**如果你给它自己的 PPT,或让它改你已有的稿,它只参考你那份**,内置模板完全不参与。
189
+
190
+ ```text
191
+ ppt_templates # 看清单和预览图
192
+ /ppt template business-blue # 记本会话默认
193
+ ppt_new(dir=D:\demo, template=business-blue) # 物化成工作区
194
+ ```
195
+
196
+ 物化出来的工作区里,`pages/_*.yaml` 是**参考母版**(不进检查),`01_opening.yaml` 是正式页。第一件事是跑 `ppt_verify autoDeclare=true` 把模板自带的有意叠层声明掉;剩下的错误都是模板原文案残留,替换掉就干净了。
197
+
198
+ 想用自己的模板:**把 .pptx 直接交给它**,一句话就行("把这个模板加进模板库")。它会保留你那份原始 pptx 当真相层,存到**你自己的模板库**里:
199
+
200
+ ```text
201
+ ppt_template_add pptx=D:\我的模板.pptx # 入库(可给多份,逐个来)
202
+ ppt_template_remove id=我的模板 # 删掉(只能删你自己加的)
203
+ ppt_templates # 看清单:你的 + 随包的分别列出
204
+ ```
205
+
206
+ 你的模板库在 `~/.dsh/ppt-studio/templates/`(Windows:`C:\Users\<你>\.dsh\ppt-studio\templates`)。它**不在插件包里**,所以升级插件不会丢;随包那 4 套是只读的,删不掉(删了升级也会回来,不如不删)。入库之后,你自己的模板和随包模板在清单里同等可选,而且按上面的政策,**你给的模板优先级最高**——要用它就直接说。
207
+
208
+ > **1.0.4 变更**:随包不再带 4 套"从真实 PPT 导入"的重型模板(实用毕业设计论文答辩、极简实用部门工作总结、深蓝质感论文答辩、简约商务)。它们合计 46.2 MB,占安装包 96%,实际从未被用过。想找回来:从 [v1.0.3 的资产](https://github.com/zbsph/dsh-ppt-studio/releases/tag/v1.0.3) 里取 `package/templates/<id>/`,或从 git 历史取 `git show v1.0.3:templates/<id>/...`(注意 `previews/` 是 Office 渲染产物,没进 git,只在资产里)。放回 `templates/` 就能用。
209
+
210
+ ---
211
+
212
+ ## 4. 保真与改稿(三条通道)
213
+
214
+ | 你的目标 | 用什么 | 保真到什么程度 |
215
+ |---|---|---|
216
+ | 想"像"某个模板或原稿 | `ppt_import` 导入 → 看 `reference/previews/*.png` 真身 → 自己创作 | 风格级,版式由你掌控 |
217
+ | 要"看起来就是模板原样" | `ppt_patch`(只替换文字和表格内容,样式几何图片原样保留) | 结构级,模板 XML 不动 |
218
+ | 改既有精美 PPT 的**某一页** | `ppt_splice` 替换一页;要单页文件再用 `ppt_slice` | 逐字节级,其余页 SHA256 自证没动 |
219
+
220
+ 改一页的标准流程:
221
+
222
+ ```text
223
+ ppt_import(<源.pptx>, D:\work) # 导入,顺带拿到参考层
224
+ # 先看 reference/previews 里的整页真身,再改 D:\work\pages\slide_15.yaml
225
+ ppt_render → ppt_verify # 检查清零
226
+ ppt_splice(dir=D:\work, source=<源.pptx>, page=15) # 整册副本,只变第 15 页
227
+ ppt_visual(pptx=<spliced 产物>, pages="15") # 抽查这页真实观感
228
+ ```
229
+
230
+ 改一页别用"整册重新导出":近似稿重渲会顺手改坏其他页的观感。`ppt_splice` 只替换目标页,其余条目逐字节不变,它会自己打印 SHA256 校验结果。
231
+
232
+ ---
233
+
234
+ ## 5. 常见问题
235
+
236
+ **装了但好像没生效?**
237
+ 按顺序查:`dsh plugin --profile web list` 看包装上没 → `dsh --profile web --dump-config` 看组合树里有没有 `ppt-studio` 行 → **重启 dsh web**。第二步看不到通常是版本太老(v1.0.0 之前没有 `dsh.bundle` 声明,装了不挂载),升级后重装一次。
238
+
239
+ **为什么 verify 报重叠,可我就是想让它重叠?**
240
+ 把这对元素写进该页 `expectedOverlaps` 再重验,命中就显示 ✓ 预期重叠。嵌套的卡片只要声明**相邻层**(面板→框→文字),隔层自动通过。但文字压文字、表格压图表这种**内容互压永远不放过**,那是真冲突,得改布局。
241
+
242
+ **样式写了没生效。**
243
+ 样式键必须写在 `content` 里面。元素级写 `fontSize: 14` 无效,`ppt_check` 会直接报错。
244
+
245
+ **字号能到 11pt 吗?**
246
+ 能。字号下限**只由你的指令决定**:你说"不得小于 14 号",它就写进 `theme.minFontSize` 并严格遵守;你没说,就没有强制下限(导出自动缩字最多到原字号的 60%,不会往上抬)。表格单元格另有 11pt 的底。
247
+
248
+ **导出总在缩字。**
249
+ 先看 verify 是不是已经报了溢出。溢出清零后导出就不会再缩。只有个别页有存量问题(导入的近似稿常见),用 `ppt_splice` 改那一页,别整册重渲。
250
+
251
+ **中文长句被误报溢出。**
252
+ 度量偏保守,宁可误报不可漏报。按提示加宽容器、精简文案,或在语义断点显式 `\n` 换行。想确认到底溢没溢,跑 `ppt_measure` 用浏览器实测复核(实测是终审)。
253
+
254
+ **预览链接 404。**
255
+ 路由由「PPT 工作室」会话挂载时注册。确认当前会话是 PPT 工作室;进去之后链接就有了。
256
+
257
+ **没有 Edge / 没有 Office 还能用吗?**
258
+ 能。截图、实测、真渲染会自动降级并标注,HTML 预览和结构检查照常。交付说明里会写"未经视觉审阅"。
259
+
260
+ **图表支持哪些?**
261
+ bar / line / pie,矢量拼绘,导出的图在 PowerPoint 里可编辑。用 python-pptx 兜底引擎时会降级成表格(报告里会标注)。复杂图表建议用图片,或者直接用形状拼。
262
+
263
+ **讲稿能进 pptx 吗?**
264
+ 能。页面写 `notes:`(多行用 `|` 块标量),导出就成了 PowerPoint 备注页,`ppt_import` 也能读回来改。没写 `notes:` 的页不会产生备注部件,老工程导出结果不变。翻页和计时属于放映设置,不在插件范围内。
265
+
266
+ **导入后文字里出现 `&amp;` `&lt;`?**
267
+ 不该出现(2026-09-14 修)。旧版本导入的工程重新 `ppt_import` 一次即可。
268
+
269
+ **报告里出现"质量档降级"?**
270
+ 你的工程状态文件(`state.json`)损坏或读不出来,插件按 standard 继续跑,audit 档的额外检查这一轮没生效。修好文件或重跑 `/ppt quality audit`。2026-09-18 起这类回落会明说,之前是静默的。
271
+
272
+ **装的时候下载超时?**
273
+ 网络抖动时在 `~/.dsh/profiles/web/.npmrc` 里加这几行,然后重跑:
274
+
275
+ ```ini
276
+ fetch-timeout=600000
277
+ fetch-retries=5
278
+ fetch-retry-maxtimeout=120000
279
+ ```
280
+
281
+ 失败不会破坏已有安装,直接重试。
282
+
283
+ **表格在 PowerPoint 里不见了 / 一片空白?**
284
+ v1.0.0 修订前旧引擎的结构 bug(graphicFrame 里嵌了 `<a:xfrm>`,PowerPoint 会静默丢帧)。已修复,导出报告现在带 parity 回读自证(表 N/N、图 M/M、线方向 N/N)。旧产物重新 `ppt_export`。
285
+
286
+ **网页预览是对的,打开 pptx 斜线方向反了 / 叉号少一笔 / 水平线变斜了?**
287
+ 同一个家族的三个旧引擎编码 bug,都已修复:连线方向丢 `flipH/flipV`、箭头 `<a:tailEnd>` 写在 `<a:ln>` 外面、水平线包围盒被 `max(1,…)` 抬成 1pt 高。导出报告的 parity 行会逐条从 OOXML 反推端点自证。**修复前导出的产物请重新 `ppt_export`**。
288
+
289
+ **真渲染图上怎么有水印?**
290
+ 那是比例标注("1px=1pt · 960×540" 加细边框),防止人工读图时把坐标看错。脚本参数 `noWatermark` 可以关。
291
+
292
+ **PowerShell 解压 .pptx 报 "not a supported archive format"?**
293
+ `Expand-Archive` 只认 `.zip`。先复制成 `.zip` 再解,或者用 `tar -xzf <file> -C <out>`。
294
+
295
+ **Office 渲染时窗口闪一下?**
296
+ 正常,PowerPoint COM 需要。只读打开,结束自动释放。
297
+
298
+ **升级 DSH 之后「PPT 工作室」选不出来,或者切过去就报错?**
299
+ 先分清是"预设漂移"还是"宿主换了预设机制",两者的修法不同:
300
+
301
+ - **内容漂移**:本插件的预设是随包 standard 预设的副本,只加了一处有意差异(persona 人格,理由写在 `agent-presets/ppt/agent.cordis.yml` 顶部,白名单在 `scripts/check-preset.mjs`)。上游改预设(改配置、加行、停用行)而副本没跟,会话行为就会不一致。发生过两次:`0.1.5-rc.2` 把 persona 从 `text` 改成必填的 `prefix`;`0.1.6-alpha.2` 删掉了 `dsh-workflow-worker-thread`、把 `tool-ralph` 改成默认停用、新增 `tool-plugin-manager`。修法是拿到修好的版本后重跑安装,或者单独跑 `node scripts/check-preset.mjs` 看漂移。
302
+ - **机制变更**:`0.1.7` 换了预设的交付方式(磁盘目录 → 注册表声明,见 §1.6),参照物文件也从 `dsh-agent-presets/presets/standard/agent.cordis.yml` 换成了 `dsh-web-app/presets/standard.patch.yml`。本包 1.0.7 起已适配;`check-preset.mjs` 两种格式都认,认到哪种会在输出第一屏写明。
303
+ - **完全看不到这个预设**:调一次 `ppt_state`,看 `presetDelivery` 字段——它会写明是否已声明、以及失败原因(例如宿主没装配 `agentPresets` 注册表)。这比翻日志可靠。
304
+
305
+ **插件对外只交付三样东西**:`ppt_*` 工具面 + `/ppt` 命令面、工作流提示段、内置手册。都挂在插件实例上,卸载即净。想确认手册通道:调一次 `ppt_state`,`manualSkill` 会报注册与可见状态。
306
+
307
+ ---
308
+
309
+ ## 6. 环境要求与已知边界
310
+
311
+ **环境**:DSH web `0.1.7-rc.2`(Windows 主机实测;COM/Edge 探测路径按 Windows 写的,macOS/Linux 未验证)。路径与中间层一律 UTF-8,也兼容 WPS 导出的 UTF-16 文件。
312
+
313
+ **支持的元素**:text / shape / line / image / table / chart。
314
+
315
+ - shape 支持 rect、roundRect、ellipse、triangle,常见的 prst 自选图形(箭头、菱形、五边形、流程图等),以及 custGeom 自定义路径,带旋转、纯色/渐变/透明度填充。
316
+ - line 只有两个点,多点折线要拆成首尾相接的多条。
317
+ - chart 支持 bar/line/pie;图表里的分类名、数值、单位、图例需要你自己用文本元素补上(DSL 里没有这些字段)。
318
+ - 背景支持 hex、主题引用、纯色、图片(cover/contain/fill)。
319
+
320
+ **这些不做,都有替代路径**:
321
+
322
+ - 文本度量是估算档加实测档。实测依赖浏览器;和 Office 原生排版之间存在字体级系统差异(加粗中文已按 1.06 倍补偿)。
323
+ - 导入不支持阴影、动画、超链接、母版继承;渐变归一到主色(原始 stops 存在 `import-styles.json`);chart 降级成占位;EMF 媒体和 WPS 跨实现打开未验证。
324
+ - pptxgenjs 第三引擎没做,`/ppt engine pptxgenjs` 会被明确拒绝,不会静默换成别的引擎。python-pptx 只在兜底或显式指定时用,且里头的透明度和渐变按纯色近似。
325
+ - dsh 网页里的内嵌预览面板没做,对话内用 `ppt_preview` 和整览截图已经够用。
326
+ - **模板的整页真身预览需要本机装 Microsoft Office**。没有 Office 时,参考层只注入 `source: reference/template.pptx`,原件还在,可以自己打开对照。这一条有机器断言钉着:smoke 分别断言"有预览就必须注入并拷贝"和"没有预览就只能注入 source,且不得出现 previews 引用"。
327
+
328
+ ---
329
+
330
+ ## 7. 参考:中间层 DSL
331
+
332
+ 整个工程就是 `deck.yaml` + `pages/*.yaml` + `media/`。渲染、检查、导出都读这一份,1px = 1pt,原点在左上,默认 960×540。
333
+
334
+ ```yaml
335
+ version: 1
336
+ title: 我的演示
337
+ size: [960, 540] # 也可写 {width, height}
338
+ theme: # 样式统一在 theme 定义,元素只引用 token
339
+ colors: {primary: "#2563EB", ink: "#1F2937"}
340
+ textStyles:
341
+ title: {fontSize: 32, color: "$ink", bold: true}
342
+ body: {fontSize: 16, color: "$ink"}
343
+ safeArea: {top: 20, bottom: 20} # 可选:模板页眉页脚带这类非内容区
344
+ minFontSize: 14 # 可选:你给了字号下限时才写
345
+ pages:
346
+ - pages/01_cover.yaml
347
+ ```
348
+
349
+ 页面文件:
350
+
351
+ ```yaml
352
+ pageType: cover
353
+ background: "#F5F6F7" # hex / $themeRef / {type: solid,color} / {type: image,src,fit}
354
+ notes: | # 可选:讲稿,导出成 pptx 备注页
355
+ 开场先给结论。
356
+ 第二行给证据。
357
+ elements:
358
+ - elementId: t1 # 页内唯一,必填
359
+ elementType: text # text|shape|line|image|table|chart
360
+ bounds: [60, 60, 400, 50] # 必填(line 可省,由 points 推导)
361
+ content:
362
+ text: "正文,长句在语义断点显式 \n 换行"
363
+ style: "$body" # 引用 theme.textStyles,或直接写样式字段(必须写在 content 内)
364
+ - elementId: bar
365
+ elementType: chart
366
+ bounds: [60, 300, 400, 200]
367
+ chart:
368
+ type: bar
369
+ data: {cols: [分类, 值], rows: [[甲, 10], [乙, 20]]} # 只认 cols + rows;多系列加 series
370
+ - elementId: card
371
+ elementType: shape
372
+ kind: roundRect # 也可以是 rightArrow / diamond / flowchartProcess / custGeom …
373
+ bounds: [60, 60, 400, 200]
374
+ fill: "$colors.primary" # 或 {color, alpha}、{type: gradient, stops: [...], angle}
375
+ line: {color: "#FFFFFF", width: 1}
376
+ ```
377
+
378
+ 几个容易踩的点:
379
+
380
+ - 样式键必须在 `content` 里面。
381
+ - `expectedOverlaps` 两种写法等价:`[{pair: [a,b]}]` 和 `- pair: [a,b]`,每对一行。
382
+ - 声明里的 id 必须是本页真实存在的元素,写错会被防呆拦住。
383
+ - 更全的写法直接问模型(`ppt_schema`),或者看 `examples/smoke` 里的样例工程。
384
+
385
+ ---
386
+
387
+ ## 8. 参考:质量检查体系
388
+
389
+ 核心思路:**重叠合不合法,由设计意图决定,不由元素类型决定**。设计时声明,审阅时对照。
390
+
391
+ **重叠**。有意重叠写进该页 `expectedOverlaps`,检查时逐对对照,命中就是 ✓,没命中就是错误(要么改布局,要么确认有意后补声明)。嵌套承载只需声明相邻层。内容互压永远不放过。`role: decoration` 只豁免重叠,不豁免出界。批量声明用 `ppt_verify autoDeclare=true`(audit 档禁用)。
392
+
393
+ **出界**分两级。超页面边界是 `out-of-page`,永远错误,不可声明(放映时看不到)。超安全区是 `out-of-safe-area`,可以声明:把有意落在页眉页脚带上的 logo、角标写进该页 `expectedOutOfSafeArea`。这两个码分开是因为处置完全不同:一个补声明就行,另一个必须改布局。
394
+
395
+ **文本**。估算偏保守,渲染、检查、导出用同一套度量。字号下限由你的指令决定。表格单元格按列宽换行后超出表格高度会报 `table-overflow`,修法是扩大表格高度、加宽列或精简单元格文案。
396
+
397
+ **主题一致性**。`theme-conformance` 默认 strict:页面颜色必须来自 `theme.colors` 或中性灰,出板就报错。要加新颜色先加进 theme。字号字体是建议级。导入的工程会自动带上原稿全量色板,不会误报原稿色。
398
+
399
+ **审阅三层**:
400
+
401
+ ```text
402
+ ppt_render + ppt_verify # 数字检查,快,错误必须清零
403
+ ppt_shot + 读图 # 视觉审阅,慢,但构图失衡这类问题只有看图才发现
404
+ ppt_visual # Office 真渲染复核(有 Office 时;audit 档导出后自动跑)
405
+ ```
406
+
407
+ `[·]` 开头的建议(美学、对比度、孤字、密度)永远不是门禁,但值得逐条看。
408
+
409
+ **实测档**。`ppt_measure` 用浏览器真实排版测量,`ppt_verify measured=true` 拿它和估算交叉:实测发现溢出而估算没发现,算新错误;估算报了而实测没事,降为警告(字体差异,人工确认)。两个文件每页都带 1 基的 `pageNo` 用来配对,对不上会报 `measured-unpaired` 而不是静默跳过。看到这个错,基本都是 `measured.json` 是旧产物,或者在测量之后又动过页面,重跑 `ppt_render` + `ppt_measure` 即可。
410
+
411
+ ---
412
+
413
+ ## 9. 参考:工具一览
414
+
415
+ **创作链**:`ppt_schema`(语法速查)、`ppt_new`(生成示例工程)、`ppt_check`(结构校验)、`ppt_render`(渲染 HTML + `layout.json`)、`ppt_verify`(布局检查,支持 `autoDeclare` / `measured` / `pages` 局部审阅)、`ppt_shot`(截图,`overview=true` 出整览)、`ppt_measure`(浏览器实测)、`ppt_crosscheck`(内容审阅材料包)、`ppt_preview`(对话内预览链接)。
416
+
417
+ **输入链**:`ppt_import`(pptx → 工程 + 参考层)、`ppt_visual`(Office 逐页真渲染)、`ppt_media`(图片尺寸格式)。
418
+
419
+ **交付链**:`ppt_export`(导出 pptx,默认 pptd 引擎)、`ppt_patch`(贴模板手术)、`ppt_splice`(替换进原稿)、`ppt_slice`(裁单页)。
420
+
421
+ **模板链**:`ppt_templates`(清单与预览)、`ppt_template_add`(收纳自己的模板)、`ppt_template_styleaudit`(写/看模板的视觉审计缓存)。
422
+
423
+ **状态链**:`ppt_status`、`ppt_state`。
424
+
425
+ `ppt_crosscheck` 值得单独说一句:它**不做判断**,只把材料摆上桌(全页正文按阅读顺序、工作区里实际有哪些素材、一份审阅协议)。判定由审阅者给,默认用独立子代理(你说"不要用子代理"时它自己审并标注);没有外部素材时只能判"无法核实",不会报绿。它不进任何门禁,输出里也没有可"变绿"的东西。
426
+
427
+ ---
428
+
429
+ ## 10. 开发与维护
430
+
431
+ ```bash
432
+ node scripts/build.mjs # 免 tsc:src → lib 复制(纯 ESM JS,源码即产物)
433
+ npm test # build + LF 守卫 + smoke(262 断言)+ 预设漂移自检
434
+ npm run check:eol # 发行字节守卫:跟踪的文本文件必须全 LF(--fix 就地修)
435
+ npm run fresh # 用户视角终验:干净克隆 npm test + 真装一遍
436
+ npm run test:bundle # 安装路径自证:隔离 DSH_HOME + 真 dsh plugin add + dump-config
437
+ npm run test:preset # 预设自检:本预设 vs 随包 standard 逐行比对(DSH 升级后必跑)
438
+ npm run check:lib # lib/ 必须逐字节等于 src/
439
+ node scripts/preflight-1.0.mjs # 发布前预检(11 断言)
440
+ node scripts/e2e-1.0.mjs # 端到端(13 断言:真浏览器测量 + 真 Office 渲染 + splice/slice)
441
+ node scripts/audit-manual-facts.mjs # 手册事实审计:逐条核对"手册 vs 源码"(39 条)
442
+ ```
443
+
444
+ **"干净检出"才算验收**。`.github/workflows/ci.yml` 在 ubuntu 和 windows 上各自干净检出后跑 `npm test`,并在 windows 上真跑一遍用户会敲的那条命令。这条规矩来自两次真实事故:Windows 干净克隆是 CRLF(Git for Windows 默认 `core.autocrlf=true`),按 `\n` 做的文本手术会**静默失效**;没有 Office 的机器上,整页预览断言必红,而预览本来就是 PowerPoint COM 渲染出来的。现在 `.gitattributes` 把检出字节钉成 LF,`normalizeText()` 兜住手改过的 CRLF/BOM 文件,Office 和浏览器相关的断言一律显式降级为跳过、且保持断言总数恒定。
445
+
446
+ **改完代码让本机跑上新版**(都要重启 `dsh web`,profile bundle 不热更):
447
+
448
+ ```bash
449
+ npm run sync -- --local # 日常迭代:不发 GitHub,本机跑刚构建的字节
450
+ npm run sync # 发版:上传资产 + 本机与 GitHub 拉齐 + 用户视角终验
451
+ ```
452
+
453
+ **发版四步,顺序不能换**。`npm run sync` 在"本地有未推送提交"或"tag 不指向 HEAD"时会拒绝继续。
454
+
455
+ ```bash
456
+ git push origin main # ① 推提交
457
+ gh release create v<版本> --target "$(git rev-parse HEAD)" --title ... --notes-file ... # ② tag 显式指到这一提交
458
+ npm run sync # ③ 构建 → 上传资产 → git 前置检查 + 用户视角终验
459
+ npm publish "<③ 产出的那个 tgz>" # ④ 发 npm(用同一个 tgz,保证两条通道同一份字节)
460
+ ```
461
+
462
+ `gh release create` 不指定 `--target` 时会按默认分支 HEAD 建 tag,本地没推就把 tag 建在旧提交上。v1.0.1 第一次发布就是这么错的:资产哈希全绿,而 GitHub 上的 tag 指向 v1.0.0 的代码。所以加了机器判据。`--skip-fresh` 能跳过终验,但状态文件里会留 `freshInstall: null`,不把"没验"伪装成"验过"。
463
+
464
+ **npm 通道的现状(2026-09-26)**:包名是**无 scope** 的 `dsh-ppt-studio`(`private` 已去掉,`publishConfig.access=public`),**但还没有发布成功**:
465
+ - ✅ 账号已注册、`npm login` 已通(`npm whoami` = `zbsph`);
466
+ - ✅ 包名未被占用(`npm view dsh-ppt-studio` → 404),构件已备好(就是第 ③ 步产出的那个 tgz,sha 与 Release 资产一致);
467
+ - ❌ 首次 `npm publish` 返回 **E403**:`Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages` —— 账号开了 2FA,而 `npm login` 的普通凭据不能写。需要发布时给 `--otp=<6 位码>`,或建一个勾了 **Bypass 2FA** 的 granular token。
468
+
469
+ 所以**现在不要**用 `dsh plugin --profile web add dsh-ppt-studio`(会 404);先用 §1.2 的资产 URL。发布成功后,这里会改成 npm 命令。
470
+ > 最早那次卡点是 npm **网站**对这个出口 IP 返回 403(注册/建 token 走不通,registry API 一直正常);2026-09-26 换出口后网站这关过了,卡点才转到 2FA 写入策略。
471
+
472
+ **`lib/` 为什么提交**:`dsh plugin add <仓库 URL>` 只能拿到 git 里已提交的内容,而 `exports` 指向 `./lib/index.js`。lib 不入库,git 装出来的包就缺入口文件、挂不上。代价是"改了 src 忘了 build 就提交"会静默发旧代码,所以配了守卫:`npm run check:lib` 加 smoke 里一条同义断言(lib 必须逐字节等于 src,且不能被 `.gitignore` 忽略、必须被 git 跟踪)。改码流程就是改 `src/` → `node scripts/build.mjs` → 连 `lib/` 一起提交。
473
+
474
+ **包名是单一事实源**:改名要同步 `package.json`、`cordis.patch.yml` 的插件行,以及 `scripts/install.mjs` 里的落点路径。漏一处就是"装了不生效",smoke 有断言盯着。
475
+
476
+ **OOXML 产物必须用真消费者验**。加备注页时先写的 `notesMasterIdLst`,python-pptx 照读不误,真 PowerPoint 却报"文件或目录损坏"。第三方库能读不等于能打开。凡改导出编码,至少走一次真 PowerPoint(`ppt_visual`)或真浏览器。
477
+
478
+ **文档链**(每次改动同步):`docs/01-需求与目标.md`(需求与决策)、`docs/02-技术报告.md`(实现)、`docs/03-更新日志.md`(版本记录)、`docs/04-路线图与里程碑.md`(验收)、`docs/05-迭代流程.md`(检查单)、`docs/06-评审与测试.md`(发布前评审与测试矩阵)。
479
+
480
+ **版本规则**:semver。破坏中间层或接口兼容是 major,新特性是 minor,修复和文档是 patch。v1.0.0 是三轮真实端到端测试通过后的稳定基线。