@topmindspace/tms-skills 0.3.6 → 0.4.1

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 (184) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.en.md +12 -9
  3. package/README.md +12 -9
  4. package/bin/tms-skills.js +153 -13
  5. package/package.json +1 -1
  6. package/top-ppt-html/README.en.md +2 -2
  7. package/top-ppt-html/README.md +1 -1
  8. package/top-ppt-html/SKILL.md +8 -7
  9. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.html +58 -184
  10. package/top-ppt-html/assets/examples/2026-09-09-architecture-graphite-dark.model.json +13 -3
  11. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.html +58 -337
  12. package/top-ppt-html/assets/examples/2026-09-09-presentation-business-blue.model.json +15 -1
  13. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.html +58 -930
  14. package/top-ppt-html/assets/examples/2026-09-09-research-mckinsey.model.json +15 -1
  15. package/top-ppt-html/assets/examples/2026-09-26-topmind-tms-skills-showcase.html +141 -31
  16. package/top-ppt-html/assets/icons/index.json +557 -0
  17. package/top-ppt-html/assets/icons//344/270/212/344/274/240.png +0 -0
  18. package/top-ppt-html/assets/icons//344/270/212/344/274/240.svg +1 -0
  19. package/top-ppt-html/assets/icons//344/270/213/350/275/275.png +0 -0
  20. package/top-ppt-html/assets/icons//344/270/213/350/275/275.svg +1 -0
  21. package/top-ppt-html/assets/icons//344/270/213/351/231/215.png +0 -0
  22. package/top-ppt-html/assets/icons//344/270/213/351/231/215.svg +1 -0
  23. package/top-ppt-html/assets/icons//344/271/246/347/255/276.png +0 -0
  24. package/top-ppt-html/assets/icons//344/271/246/347/255/276.svg +1 -0
  25. package/top-ppt-html/assets/icons//344/272/221.png +0 -0
  26. package/top-ppt-html/assets/icons//344/272/221.svg +1 -0
  27. package/top-ppt-html/assets/icons//344/275/215/347/275/256.png +0 -0
  28. package/top-ppt-html/assets/icons//344/275/215/347/275/256.svg +1 -0
  29. package/top-ppt-html/assets/icons//344/277/241/346/201/257.png +0 -0
  30. package/top-ppt-html/assets/icons//344/277/241/346/201/257.svg +1 -0
  31. package/top-ppt-html/assets/icons//345/210/206/344/272/253.png +0 -0
  32. package/top-ppt-html/assets/icons//345/210/206/344/272/253.svg +1 -0
  33. package/top-ppt-html/assets/icons//345/213/276/351/200/211.png +0 -0
  34. package/top-ppt-html/assets/icons//345/213/276/351/200/211.svg +1 -0
  35. package/top-ppt-html/assets/icons//345/215/240/346/257/224.png +0 -0
  36. package/top-ppt-html/assets/icons//345/215/240/346/257/224.svg +1 -0
  37. package/top-ppt-html/assets/icons//345/233/242/351/230/237.png +0 -0
  38. package/top-ppt-html/assets/icons//345/233/242/351/230/237.svg +1 -0
  39. package/top-ppt-html/assets/icons//345/233/276/350/241/250.png +0 -0
  40. package/top-ppt-html/assets/icons//345/233/276/350/241/250.svg +1 -0
  41. package/top-ppt-html/assets/icons//345/242/236/351/225/277.png +0 -0
  42. package/top-ppt-html/assets/icons//345/242/236/351/225/277.svg +1 -0
  43. package/top-ppt-html/assets/icons//345/256/211/345/205/250.png +0 -0
  44. package/top-ppt-html/assets/icons//345/256/211/345/205/250.svg +1 -0
  45. package/top-ppt-html/assets/icons//345/257/271/350/257/235.png +0 -0
  46. package/top-ppt-html/assets/icons//345/257/271/350/257/235.svg +1 -0
  47. package/top-ppt-html/assets/icons//345/267/245/345/205/267.png +0 -0
  48. package/top-ppt-html/assets/icons//345/267/245/345/205/267.svg +1 -0
  49. package/top-ppt-html/assets/icons//345/276/252/347/216/257.png +0 -0
  50. package/top-ppt-html/assets/icons//345/276/252/347/216/257.svg +1 -0
  51. package/top-ppt-html/assets/icons//346/210/220/346/236/234.png +0 -0
  52. package/top-ppt-html/assets/icons//346/210/220/346/236/234.svg +1 -0
  53. package/top-ppt-html/assets/icons//346/211/213/346/234/272.png +0 -0
  54. package/top-ppt-html/assets/icons//346/211/213/346/234/272.svg +1 -0
  55. package/top-ppt-html/assets/icons//346/225/210/347/216/207.png +0 -0
  56. package/top-ppt-html/assets/icons//346/225/210/347/216/207.svg +1 -0
  57. package/top-ppt-html/assets/icons//346/225/260/346/215/256.png +0 -0
  58. package/top-ppt-html/assets/icons//346/225/260/346/215/256.svg +1 -0
  59. package/top-ppt-html/assets/icons//346/226/207/344/273/266/345/244/271.png +0 -0
  60. package/top-ppt-html/assets/icons//346/226/207/344/273/266/345/244/271.svg +1 -0
  61. package/top-ppt-html/assets/icons//346/226/207/346/241/243.png +0 -0
  62. package/top-ppt-html/assets/icons//346/226/207/346/241/243.svg +1 -0
  63. package/top-ppt-html/assets/icons//346/227/227/345/270/234.png +0 -0
  64. package/top-ppt-html/assets/icons//346/227/227/345/270/234.svg +1 -0
  65. package/top-ppt-html/assets/icons//346/227/266/351/227/264.png +0 -0
  66. package/top-ppt-html/assets/icons//346/227/266/351/227/264.svg +1 -0
  67. package/top-ppt-html/assets/icons//346/230/237/346/240/207.png +0 -0
  68. package/top-ppt-html/assets/icons//346/230/237/346/240/207.svg +1 -0
  69. package/top-ppt-html/assets/icons//346/231/272/350/203/275.png +0 -0
  70. package/top-ppt-html/assets/icons//346/231/272/350/203/275.svg +1 -0
  71. package/top-ppt-html/assets/icons//346/235/203/351/231/220.png +0 -0
  72. package/top-ppt-html/assets/icons//346/235/203/351/231/220.svg +1 -0
  73. package/top-ppt-html/assets/icons//346/243/200/346/237/245.png +0 -0
  74. package/top-ppt-html/assets/icons//346/243/200/346/237/245.svg +1 -0
  75. package/top-ppt-html/assets/icons//346/264/236/345/257/237.png +0 -0
  76. package/top-ppt-html/assets/icons//346/264/236/345/257/237.svg +1 -0
  77. package/top-ppt-html/assets/icons//346/265/201/347/250/213.png +0 -0
  78. package/top-ppt-html/assets/icons//346/265/201/347/250/213.svg +1 -0
  79. package/top-ppt-html/assets/icons//346/270/205/345/215/225.png +0 -0
  80. package/top-ppt-html/assets/icons//346/270/205/345/215/225.svg +1 -0
  81. package/top-ppt-html/assets/icons//347/201/253/347/256/255.png +0 -0
  82. package/top-ppt-html/assets/icons//347/201/253/347/256/255.svg +1 -0
  83. package/top-ppt-html/assets/icons//347/201/257/346/263/241.png +0 -0
  84. package/top-ppt-html/assets/icons//347/201/257/346/263/241.svg +1 -0
  85. package/top-ppt-html/assets/icons//347/224/250/346/210/267.png +0 -0
  86. package/top-ppt-html/assets/icons//347/224/250/346/210/267.svg +1 -0
  87. package/top-ppt-html/assets/icons//347/233/256/346/240/207.png +0 -0
  88. package/top-ppt-html/assets/icons//347/233/256/346/240/207.svg +1 -0
  89. package/top-ppt-html/assets/icons//347/256/255/345/244/264.png +0 -0
  90. package/top-ppt-html/assets/icons//347/256/255/345/244/264.svg +1 -0
  91. package/top-ppt-html/assets/icons//347/273/204/347/273/207.png +0 -0
  92. package/top-ppt-html/assets/icons//347/273/204/347/273/207.svg +1 -0
  93. package/top-ppt-html/assets/icons//347/275/227/347/233/230.png +0 -0
  94. package/top-ppt-html/assets/icons//347/275/227/347/233/230.svg +1 -0
  95. package/top-ppt-html/assets/icons//350/241/250/346/240/274.png +0 -0
  96. package/top-ppt-html/assets/icons//350/241/250/346/240/274.svg +1 -0
  97. package/top-ppt-html/assets/icons//350/256/241/345/210/222.png +0 -0
  98. package/top-ppt-html/assets/icons//350/256/241/345/210/222.svg +1 -0
  99. package/top-ppt-html/assets/icons//350/256/276/347/275/256.png +0 -0
  100. package/top-ppt-html/assets/icons//350/256/276/347/275/256.svg +1 -0
  101. package/top-ppt-html/assets/icons//350/266/213/345/212/277.png +0 -0
  102. package/top-ppt-html/assets/icons//350/266/213/345/212/277.svg +1 -0
  103. package/top-ppt-html/assets/icons//351/202/256/344/273/266.png +0 -0
  104. package/top-ppt-html/assets/icons//351/202/256/344/273/266.svg +1 -0
  105. package/top-ppt-html/assets/icons//351/207/221/351/222/261.png +0 -0
  106. package/top-ppt-html/assets/icons//351/207/221/351/222/261.svg +1 -0
  107. package/top-ppt-html/assets/icons//351/223/276/346/216/245.png +0 -0
  108. package/top-ppt-html/assets/icons//351/223/276/346/216/245.svg +1 -0
  109. package/top-ppt-html/assets/icons//351/227/252/347/224/265.png +0 -0
  110. package/top-ppt-html/assets/icons//351/227/252/347/224/265.svg +1 -0
  111. package/top-ppt-html/assets/icons//351/243/216/351/231/251.png +0 -0
  112. package/top-ppt-html/assets/icons//351/243/216/351/231/251.svg +1 -0
  113. package/top-ppt-html/assets/pptx-export.js +44 -15
  114. package/top-ppt-html/assets/style-gallery.html +2 -2
  115. package/top-ppt-html/assets/templates/architecture.html +59 -17
  116. package/top-ppt-html/assets/templates/engine.css +12 -0
  117. package/top-ppt-html/assets/templates/presentation.html +59 -17
  118. package/top-ppt-html/assets/templates/research.html +59 -17
  119. package/top-ppt-html/package-lock.json +2 -2
  120. package/top-ppt-html/package.json +2 -2
  121. package/top-ppt-html/references/icons.md +22 -19
  122. package/top-ppt-html/references/layout-variants.md +69 -0
  123. package/top-ppt-html/references/style-pack.md +40 -0
  124. package/top-ppt-html/scripts/audit_css.py +1 -1
  125. package/top-ppt-html/scripts/build_pptx.js +228 -50
  126. package/top-ppt-html/scripts/check_icons.py +119 -0
  127. package/top-ppt-html/scripts/hydrate_charts.py +60 -5
  128. package/top-ppt-html/scripts/icon_lib.js +66 -37
  129. package/top-ppt-html/scripts/layout-constants.json +92 -5
  130. package/top-ppt-html/scripts/make_icon_pack.py +172 -0
  131. package/top-ppt-html/scripts/model-schema.json +4 -1
  132. package/top-ppt-html/scripts/regression.py +3 -3
  133. package/top-ppt-html/scripts/render_compare.py +1 -1
  134. package/top-ppt-html/scripts/render_from_model.py +116 -55
  135. package/top-ppt-html/scripts/scaffold_report.py +1 -1
  136. package/top-ppt-html/scripts/sync_runtime.py +14 -14
  137. package/top-ppt-html/scripts/validate_pptx.py +1 -0
  138. package/top-ppt-html/scripts/validate_report.py +157 -0
  139. package/topmind-cover/README.en.md +4 -4
  140. package/topmind-cover/README.md +4 -4
  141. package/topmind-cover/SKILL.md +36 -16
  142. package/topmind-cover/assets/examples/README.md +13 -7
  143. package/topmind-cover/assets/examples/bg-blur-alt.png +0 -0
  144. package/topmind-cover/assets/examples/bg-blur-wechat.png +0 -0
  145. package/topmind-cover/assets/examples/bg-blur.png +0 -0
  146. package/topmind-cover/assets/examples/big-type-wechat.png +0 -0
  147. package/topmind-cover/assets/examples/big-type.png +0 -0
  148. package/topmind-cover/assets/examples/brand-launch-wechat.png +0 -0
  149. package/topmind-cover/assets/examples/brand-launch.png +0 -0
  150. package/topmind-cover/assets/examples/gan-huo-wechat.png +0 -0
  151. package/topmind-cover/assets/examples/gan-huo.png +0 -0
  152. package/topmind-cover/assets/examples/ip-fun-wechat.png +0 -0
  153. package/topmind-cover/assets/examples/ip-fun.png +0 -0
  154. package/topmind-cover/assets/examples/magazine-wechat.png +0 -0
  155. package/topmind-cover/assets/examples/magazine.png +0 -0
  156. package/topmind-cover/assets/examples/minimal-wechat.png +0 -0
  157. package/topmind-cover/assets/examples/minimal.png +0 -0
  158. package/topmind-cover/assets/examples/news-flash-wechat.png +0 -0
  159. package/topmind-cover/assets/examples/news-flash.png +0 -0
  160. package/topmind-cover/assets/examples/overview.png +0 -0
  161. package/topmind-cover/assets/examples/paper-collage-alt.png +0 -0
  162. package/topmind-cover/assets/examples/paper-collage-wechat.png +0 -0
  163. package/topmind-cover/assets/examples/paper-collage.png +0 -0
  164. package/topmind-cover/assets/examples/tutorial-steps-wechat.png +0 -0
  165. package/topmind-cover/assets/examples/tutorial-steps.png +0 -0
  166. package/topmind-cover/assets/examples/white-clean-alt-wechat.png +0 -0
  167. package/topmind-cover/assets/examples/white-clean-alt.png +0 -0
  168. package/topmind-cover/assets/examples/white-clean-wechat.png +0 -0
  169. package/topmind-cover/assets/examples/white-clean.png +0 -0
  170. package/topmind-cover/package.json +2 -2
  171. package/topmind-cover/references/cover-styles.md +210 -35
  172. package/topmind-cover/references/impact-language.md +43 -2
  173. package/topmind-cover/references/ref-white-clean-1.png +0 -0
  174. package/topmind-cover/references/ref-white-clean-2.png +0 -0
  175. package/topmind-cover/scripts/crop-cover.py +19 -13
  176. package/topmind-wechat-post/README.en.md +2 -2
  177. package/topmind-wechat-post/README.md +2 -2
  178. package/topmind-wechat-post/SKILL.md +1 -1
  179. package/topmind-wechat-post/scripts/md2wechat.py +142 -30
  180. package/topmind-wechat-post/scripts/negative_tests.py +74 -0
  181. package/topmind-x-article/README.en.md +1 -1
  182. package/topmind-x-article/README.md +1 -1
  183. package/topmind-x-article/scripts/md2x.py +25 -5
  184. package/topmind-x-article/scripts/negative_tests.py +17 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,158 @@
1
+ ## [0.4.1] - 2026-09-29
2
+
3
+ > **本版备发**(tag v0.4.1 待打;npm 待发布;commit = 本轮审计报告落盘时的 `git log` 首条)。
4
+ > 根包 0.4.0 → **0.4.1**(patch);技能版本:top-ppt-html 0.2.0 → **0.2.1**(修技能数据 bug 则 patch)、
5
+ > topmind-cover 保持 0.2.0(仅换样张图+描述文案,无功能变更)、topmind-wechat-post / topmind-x-article 保持 0.1.0。
6
+ > 本轮是第十三轮集成轮(A 文档抛光 + B 示例与描述 + C 新代码复审),改动最小、无新功能。
7
+ > 另含第十四轮集成轮(wechat-post/x-article 真 bug 修复 + installer 测试扩展):**不 bump 版本**,全部并入 0.4.1。
8
+
9
+ ### 安装器 bug 修复(高危 · Worker C 复审发现)
10
+
11
+ - `uninstall`/`install` 的 `assertDestOutsideSource` 守卫被符号链接绕过:`path.resolve` 不解析软链,
12
+ `--to <软链指向包根>` 会跟随链接 `rmSync` 删掉包内技能源目录(已实测验证旧代码确会删源)
13
+ - 修复:`bin/tms-skills.js` 改用 `realpath` 归一化比对(`realOrResolved()`:dest 不存在时向上找最深存在祖先),+25/−4
14
+ - `scripts/test_installer_cli.js` 新增 case11/case12(uninstall/install 经软链指包根 → 拒绝、源目录完好),12 用例全过
15
+
16
+ ### top-ppt-html 0.2.1(Worker C 复审发现 · 低危数据 bug)
17
+
18
+ - `assets/icons/index.json`:「组织」图标关键词含裸「架构」,会把「系统架构」类标题配上人物组织图 → 已收窄为「组织架构」
19
+
20
+ ### 文档抛光(Worker A)
21
+
22
+ - topmind-cover/SKILL.md:冲击力自检清单 10→9(合并逐字正确项)、设计铁律去重
23
+ - impact-language.md:删除与 cover-styles.md 重复的「白色清新」章节(只在 cover-styles 保留,出处回指用户参考图)
24
+ - 根 README 中英:封面技能描述 8 种风格 → 11 种;top-ppt-html README 中英版本口径改为与 `@topmindspace/tms-skills@0.4.1` 同 tag
25
+
26
+ ### 示例与描述(Worker B)
27
+
28
+ - `white-clean-alt.png`(white-clean-2)已重生成:标题「极简收纳全攻略」摆正、逐字正确;配套
29
+ `white-clean-alt-wechat.png`(900×383)新增落盘并纳入 git;示例目录 README 计数同步为 26 张
30
+ - 4 处 description 更新(cover package.json + SKILL frontmatter 加「11 种风格模板」;ppt-html package.json + SKILL frontmatter 加「48 图标 + 弹性版式」);overview alt 文案 8→11
31
+ - cover 安装文案复核:`list` 输出已准确,未动安装器
32
+
33
+ ### 第十四轮集成(Worker A/B/C)——不 bump 版本,全部并入 0.4.1
34
+
35
+ - **topmind-wechat-post 修 6 真 bug**(`scripts/md2wechat.py`,Worker A 专审发现):
36
+ - yaml/diff 代码块高亮正则在分支内误用 `(?m)` → `re.error` 崩溃(编译期统一 `re.M|re.S`,分支内去掉)
37
+ - URL 含平衡括号被截断 → 新增括号嵌套匹配扫描器替代旧正则
38
+ - `[文字](url "title")` 带 title 链接认不出 → 链接解析支持 title
39
+ - 脚注 URL 的 `&` 被转义两次 → 修正转义顺序
40
+ - 坏主题 JSON 的 Traceback → 干净报错;目录当输入的报错文案修正
41
+ - 嵌套围栏被提前闭合 → 围栏匹配支持嵌套
42
+ - `scripts/negative_tests.py` 新增 6 个 case,15/15 绿
43
+ - **topmind-x-article 修嵌套围栏**(`scripts/md2x.py`,Worker A 专审发现);
44
+ `scripts/negative_tests.py` 新增 2 个 case,8/8 绿
45
+ - **installer 回归测试扩展**(Worker C):`scripts/test_installer_cli.js` 新增 case13–22,
46
+ 覆盖 symlink 守卫纵深(realpath 归一化)与 installer 回归,72 断言全绿;`bin/` 未动,无真实绕过
47
+ - **分发体积与性能**(Worker B):无真问题。0.4.1 tarball 解包 29.1MB(0.3.9 18.4MB,
48
+ +10.7MB 系封面示例画廊预期增量);top10 大文件全合法素材;48 图标 PNG 最大 27.4KB 无异常;
49
+ install 耗时 0.3s 不需优化;`sync_npm_files.js --check` 通过
50
+ - 技能版本号保持:wechat-post / x-article 保持 0.1.0(纯 bug 修复按技能版本规则不 bump);
51
+ cover 保持 0.2.0、ppt-html 保持 0.2.1、根包保持 0.4.1
52
+
53
+ ## [0.4.0] - 2026-09-29
54
+
55
+ > **本版备发**(tag v0.4.0 待打;npm 待发布;commit = 本轮审计报告落盘时的 `git log` 首条)。
56
+ > 根包 0.3.9 → **0.4.0**(minor,本轮是功能轮);技能版本:top-ppt-html 0.1.19 → **0.2.0**、topmind-cover 0.1.0 → **0.2.0**、topmind-wechat-post / topmind-x-article 保持 0.1.0。
57
+ > 本轮是"对标业界+浅色封面+图标包版式"的功能轮(第十二轮)。
58
+
59
+ ### 安装器(Worker A)
60
+
61
+ - 新增 `uninstall <id> [--to]` 命令:卸载已安装技能,`--to` 指向文件/缺目录时干净报错 exit 1
62
+ - `install` 已装版本感知:已装同版本拒绝安装并给出三行摘要(当前版本/来源/提示 uninstall 或覆盖),不再静默覆盖
63
+ - `scripts/test_installer_cli.js`:10 用例 38 断言,覆盖 install/uninstall/list/负向输入
64
+ - `--help` 更新、根 README.md/README.en.md 安装章节重写(`github:` 口径、钉版本示例同步 0.4.0)
65
+ - `.github/workflows/ci.yml` 新增 "Installer CLI tests" step
66
+
67
+ ### topmind-cover 0.2.0(Worker B)
68
+
69
+ - 新增 3 个浅色风格:`white-clean`(排第一,标题冲击目标 1/3 字高)、`bg-blur`(背景虚化突出前景)、`paper-collage`(纸拼贴质感)
70
+ - `cover-styles.md` 11 风格重排为浅色优先;`impact-language.md` 补条目;SKILL.md 新增"直出/讨论"决策流
71
+ - 6 张新风格样张 + `overview.png` 重建;`references/ref-white-clean-1/2.png` 新增参考图
72
+
73
+ ### top-ppt-html 0.2.0(Worker C)
74
+
75
+ - 内置原创图标包 `assets/icons/`:48 SVG + 48 PNG + `index.json` 映射,7 个默认图标兜底;`scripts/check_icons.py`(`--strict`)做图标一致性门禁;`references/icons.md` 文档化
76
+ - 3 种 layout variant:bento-grid / timeline / 2-col-feature(`references/layout-variants.md`);`references/style-pack.md` 风格包文档化
77
+ - `validate_report.py` 新增内容覆盖率检查(<95% WARN);随门禁修复 6 个真实丢字 bug
78
+ - `scripts/layout-constants.json` 加 adaptiveText 弹性文本规则;HTML/PPTX 弹性适配减少溢出截断
79
+
80
+ ## [0.3.9] - 2026-09-29
81
+
82
+ > **本版备发**(tag v0.3.9 待打;npm 待发布;commit = 本轮审计报告落盘时的 `git log` 首条)。
83
+ > 注:0.3.7、0.3.8 未发布,全部内容已并入本版。
84
+ > 根包 0.3.8 → **0.3.9**(patch);4 个技能 `version` 保持不动(top-ppt-html 0.1.19,其余 0.1.0)。
85
+ > 本轮是"新鲜眼睛"横扫(第十一轮):只找前十轮没覆盖的盲区,改动最小。
86
+
87
+ ### 代码异味横扫(第十一轮 Worker A)
88
+
89
+ - TODO 注释 6 命中 → 0 真遗留(均为有意为之:文档纪律说明/scaffold 指导注释/校验正则/示例代称)
90
+ - 死代码:全仓 Python + top-ppt-html JS 逐函数交叉 grep,零死函数;12 个 CLI 参数逐个验证全部在用
91
+ - 跨技能一致性修复:19 处错误信息半角冒号 `错误:` → 全角 `错误:`(多数派 47 处);`validate_report.py` 加 `-h/--help` 早退(exit 0),与其他 argparse CLI 一致
92
+ - 重复逻辑(仅记录,不重构):`esc()` HTML 转义三处逐字相同、`read_frontmatter()` 跨技能同构、`load_constants()` 各自实现——均为四技能同构门禁的有意设计
93
+
94
+ ### 对抗输入测试(第十一轮 Worker B:5 真崩溃全部修复)
95
+
96
+ - `bin/tms-skills.js`:`--to` 指向已存在文件时 `mkdirSync` 抛未捕获堆栈 → try/catch 干净报错 exit 1
97
+ - `md2wechat.py`:`resolve_image` 的 `shutil.copy2`/`os.makedirs` 未捕获 OSError(磁盘满/目录当图片)→ 干净报错 exit 1
98
+ - `md2x.py`:输出写入 `mkdir`+`write_text` 未捕获 OSError → 干净报错 exit 1;目录当输入的报错文案修正("找不到输入文件"→"输入是目录不是文件")
99
+ - `crop-cover.py`:`out_dir.mkdir` 与渲染循环 `out.save` 未捕获 OSError(磁盘满→截断 PNG)→ 干净报错 exit 1
100
+ - 对抗矩阵:100KB 单行/emoji+零宽+混合换行/非法 UTF-8/空文件/纯标题/48MB 图片,其余全部干净通过
101
+
102
+ ### 文档一致性(第十一轮 Worker C)
103
+
104
+ - 审计结论抽查 5 处全部为真(architecture 归一化/SKILL.md 13KB 预算/cover 触发词/ip-fun 原位垫色块补丁/footer 移出 content 标记)
105
+ - SKILL.md vs --help 漂移修复 1 处:wechat-post SKILL.md 注释声称 `--workspace` 参数,全仓无此参数 → 改为 `--base`
106
+ - README 示例 10/10 实跑通过(/tmp 干净目录,本地包安装)
107
+
108
+ ## [0.3.8] - 2026-09-29
109
+
110
+ > **本版未发布**(未打 tag、未推 npm;0.3.8 全部内容已并入 0.3.9)。
111
+ > 根包 0.3.6 → **0.3.8**(patch);4 个技能 `version` 保持不动(top-ppt-html 0.1.19,其余 0.1.0)。
112
+ > 本轮只动 top-ppt-html + 文档:渲染产出目检修复(A)+ PPTX 双引擎保真修复 11 bug(B)+ 文档修正(C)。
113
+
114
+ ### 模板 footer 修复(第十轮 Worker A:渲染产出目检)
115
+
116
+ - `top-ppt-html/assets/templates/{presentation,research,architecture}.html`:`<footer>` 移出 `__TOPPPT_CONTENT_START__`/`__TOPPPT_CONTENT_END__` 标记之外——此前自动渲染取 content 区间时会连带删除页脚,目检确认已修复。
117
+
118
+ ### PPTX 双引擎保真修复(第十轮 Worker B:PPTX 实检,11 bug 全部像素复验)
119
+
120
+ - `top-ppt-html/scripts/build_pptx.js` + `assets/pptx-export.js`(双端同规则):
121
+ - 图表数据标签小数位:按模型数值实际小数位(上限 2 位)生成 format code,修复小数标签被截断
122
+ - hbar 条形图:类目轴自下而上绘制,反转数据使首项居顶;单系列颜色按数据点分配(跟随数据归属,与 A 通道一致)
123
+ - streamgraph 退化:相邻 ribbon quad 沿走向微叠 0.02in,消除拼接处抗锯齿发丝缝
124
+ - boxplot:min 标签默认移到须线帽下方,不再被组标签带压住叠印
125
+ - marimekko:单元格归一化兼容裸数值或 `[标签,数值]` 对(裸数值沿用旧行为),修复 NaN 崩坏
126
+ - pyramid:标题列宽按层内宽比例(labelFrac≈0.3)分配,顶层窄时改单框混排,修复窄层标题/说明叠印
127
+ - KPI:第 4 个起的支撑指标不再静默截断——容量按最小允许行高计算、行高按全部指标自适应压缩,超容显式告警
128
+ - donut 图例:百分比列 x(`donut.legendPctX` 5.3 → 10.8)右移,修复图例数值被圆环覆盖
129
+ - table:内容高度逐格预估、超高全表收字号,字号触底仍装不下则显式告警(不再撑高行压脚注)
130
+ - exhibit 徽标:纯编号自动补 `Exhibit ` 前缀(与 HTML 视觉一致),已带前缀的不重复
131
+ - sankey/streamgraph note:note 与 footnote 均参与 `chartBottom` 结算,修复 note 重叠
132
+ - `top-ppt-html/scripts/layout-constants.json`:`donut.legendPctX` 5.3 → 10.8(单源),已由 `sync_runtime.py` 同步至 `pptx-export.js`、画廊、`templates/*.html`、示例的内联副本与 `__TOPPPT_RUNTIME_SHA__` 戳
133
+
134
+ ### 文档修正(第十轮 Worker C)
135
+
136
+ - 根 README(中英):当前线 0.2.x → 0.3.x;`topmind-cover` "17 张双尺寸" → "16 张双尺寸 + 1 张风格总览图"
137
+ - `docs/PUBLISHING.md`:`latest` 指向 0.3.1 → 0.3.6
138
+ - `topmind-wechat-post/README`(中英):二级标题编号示例 `01` → `1`
139
+
140
+ ## [0.3.7] - 2026-09-29
141
+
142
+ > **本版未发布**(未打 tag、未推 npm;0.3.7 全部内容已并入 0.3.8)。
143
+ > 根包 0.3.6 → **0.3.7**(patch);4 个技能 `version` 保持不动(top-ppt-html 0.1.19,其余 0.1.0)。
144
+ > 本轮只动 topmind-cover:文字排印与装饰系统(第九轮)。
145
+
146
+ ### 文字排印与装饰系统(第九轮)
147
+
148
+ - `topmind-cover/references/impact-language.md`:新增第七节"文字装饰系统"(+38 行):6 种可靠装饰(关键词变色/字号对比/色块衬底/轻微阴影立体/手绘划线圈注箭头/小元素旋转≤8°)各给效果/风险/适用风格/提示词写法四列 + 8 风格各 2~3 种必用装饰指定 + 7 条装饰禁令(禁大标题透视/一句话超 3 色/三重叠加/竖排+旋转/色块吞字/装饰压笔画/装饰超量)
149
+ - `topmind-cover/references/cover-styles.md`(316→359 行):8 风格提示词新增"文字特效"段(中英双语,全部含色号与量化参数,如"钩子词放大 1.5 倍""色块高 1.2 倍字高""投影偏移 1/10 字高");各风格"绝不"清单追加装饰禁令;news-flash 单色铁律放宽为"纯黑打底+爆点词朱红点睛"(仍 ≤3 色,与参考图布局/配色/文字结构全错开);brand-launch 品牌词发光描边改为荧光绿块衬底
150
+ - `topmind-cover/SKILL.md`(114→116 行):冲击力自检清单追加第 9/10 条——中文逐字正确(装饰未导致错字/乱码/笔画粘连)、装饰手法 ≤ 该风格指定数量(minimal 只许 1 种);"必过 8 项"同步为"必过 10 项"
151
+ - 16 张样张全部重生成(标题沿用第八轮):三重目检通过——中文逐字正确(装饰是错字重灾区,逐字核对)、每张 ≥2 种装饰生效且不乱(minimal 仅 1 种)、与 7 张参考图无实质相似;返工 1 次(magazine 首版比例错误)
152
+
1
153
  ## [0.3.6] - 2026-09-29
2
154
 
155
+ > **本版已发布**(commit 5dc0bb8,tag v0.3.6,GitHub Release + npm @0.3.6,latest 已切换)。
3
156
  > 根包 0.3.5 → **0.3.6**(patch);4 个技能 `version` 保持不动(top-ppt-html 0.1.19,其余 0.1.0)。
4
157
  > 本轮只动 topmind-cover:冲击力升级(第八轮)。
5
158
 
package/README.en.md CHANGED
@@ -39,14 +39,14 @@ npx @topmindspace/tms-skills install topmind-x-article
39
39
 
40
40
  ### topmind-cover · Cover art generation
41
41
 
42
- Shared cover art for X long-form and WeChat: striking, eye-catching, theme-focused. **Pick a style → check the example → compose the prompt from the recipe**, then one-click crop to both platform sizes with `crop-cover.py` (X 1200×675, WeChat 900×383). 8-style index and recipes: [`references/cover-styles.md`](./topmind-cover/references/cover-styles.md).
42
+ Shared cover art for X long-form and WeChat: striking, eye-catching, theme-focused. **Pick a style → check the example → compose the prompt from the recipe**, then one-click crop to both platform sizes with `crop-cover.py` (X 1200×675, WeChat 900×383). 11-style index and recipes: [`references/cover-styles.md`](./topmind-cover/references/cover-styles.md).
43
43
 
44
44
  ```bash
45
45
  npx @topmindspace/tms-skills install topmind-cover
46
46
  ```
47
47
 
48
48
  <p align="center">
49
- <img src="https://github.com/topmindspace/tms-skills/raw/main/topmind-cover/assets/examples/overview.png" alt="topmind-cover · 8 cover-style overview" width="960" />
49
+ <img src="https://github.com/topmindspace/tms-skills/raw/main/topmind-cover/assets/examples/overview.png" alt="topmind-cover · 11 cover-style overview" width="960" />
50
50
  </p>
51
51
 
52
52
  > Let ideas fly — make good thinking visible.
@@ -55,18 +55,18 @@ npx @topmindspace/tms-skills install topmind-cover
55
55
  <img src="docs/assets/tms-skills-banner.png" alt="tms-skills · top-ppt-html — formal business presentations" width="960" />
56
56
  </p>
57
57
 
58
- > **Warning**: do not install `@topmindspace/tms-skills@^2` (2.0.0–2.1.1 deprecated). Current line is **0.2.x** (`latest`).
58
+ > **Warning**: do not install `@topmindspace/tms-skills@^2` (2.0.0–2.1.1 deprecated). Current line is **0.3.x** (`latest`).
59
59
 
60
60
  ## Skills
61
61
 
62
62
  | Skill | Version | What it does |
63
63
  |-------|---------|--------------|
64
- | [`top-ppt-html`](./top-ppt-html/) | **0.1.19** | Formal business decks: paginated HTML + editable 16:9 PPTX; dual delivery · MD3-inspired density; 3 modes × 9 styles; strict 0/0 |
64
+ | [`top-ppt-html`](./top-ppt-html/) | **0.2.1** | Formal business decks: paginated HTML + editable 16:9 PPTX; dual delivery · MD3-inspired density; 3 modes × 9 styles; strict 0/0 |
65
65
  | [`topmind-wechat-post`](./topmind-wechat-post/) | **0.1.0** | WeChat article lifecycle: package, review, 3 quality gates, inline typography & publish checklist |
66
66
  | [`topmind-x-article`](./topmind-x-article/) | **0.1.0** | X long-form one-click publish: Markdown → paste-ready plain text + cover + checklist |
67
- | [`topmind-cover`](./topmind-cover/) | **0.1.0** | Cover art for X / WeChat: striking, theme-focused; 8-style cover style library + 17 dual-size example images |
67
+ | [`topmind-cover`](./topmind-cover/) | **0.2.0** | Cover art for X / WeChat: striking, theme-focused; 11-style cover style library + 26 example images (incl. 3 alt samples) + 1 style overview |
68
68
 
69
- Installer [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) is **0.3.6** (whole-repo same-tag releases).
69
+ Installer [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) is **0.4.1** (whole-repo same-tag releases).
70
70
 
71
71
  ## Install
72
72
 
@@ -76,7 +76,8 @@ Installer [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspa
76
76
  npx @topmindspace/tms-skills list
77
77
  npx @topmindspace/tms-skills install top-ppt-html
78
78
  npx @topmindspace/tms-skills install top-ppt-html --to ./.claude/skills
79
- npx @topmindspace/tms-skills@0.3.6 install top-ppt-html # pin
79
+ npx @topmindspace/tms-skills@0.4.1 install top-ppt-html # pin
80
+ npx @topmindspace/tms-skills uninstall top-ppt-html --to ./.claude/skills
80
81
  ```
81
82
 
82
83
  ```bash
@@ -84,7 +85,9 @@ npx @topmindspace/tms-skills@0.3.6 install top-ppt-html # pin
84
85
  npx github:topmindspace/tms-skills install top-ppt-html
85
86
  ```
86
87
 
87
- Default probe order: `./.agents` → `./.claude` → `./.cursor` → `./.codex` → `./.mimocode`, then user-level `~/.claude`, etc. Or pass `--to`. Do not `npm install top-ppt-html` (skill id is not a standalone package).
88
+ Default probe order: `./.agents` → `./.claude` → `./.cursor` → `./.codex` → `./.mimocode`, then user-level `~/.claude`, etc. Or pass `--to`. When `--to` is omitted, the install summary explicitly prints the auto-detected target directory. Do not `npm install top-ppt-html` (skill id is not a standalone package).
89
+
90
+ `install` details: if a same-named skill already exists, the installed version is reported and overwriting is refused — pass `--force` to replace (or `uninstall` first). On success, a three-line summary is printed: where it was installed / installed skill version and installer version / next steps.
88
91
 
89
92
  PPTX export needs `npm install` in the skill folder (pptxgenjs). HTML generation uses Python stdlib only.
90
93
 
@@ -93,7 +96,7 @@ PPTX export needs `npm install` in the skill folder (pptxgenjs). HTML generation
93
96
  ```
94
97
  tms-skills/
95
98
  ├─ top-ppt-html/ # skill (SKILL.md + assets + references + scripts)
96
- ├─ bin/tms-skills.js # CLI: list / install
99
+ ├─ bin/tms-skills.js # CLI: list / install / uninstall
97
100
  ├─ docs/ # publishing · showcase shots · banner · Pages source
98
101
  ├─ scripts/ # repo gates / privacy scan
99
102
  ├─ package.json # @topmindspace/tms-skills
package/README.md CHANGED
@@ -37,14 +37,14 @@ npx @topmindspace/tms-skills install topmind-x-article
37
37
 
38
38
  ### topmind-cover · 封面配图生成
39
39
 
40
- X 长文与公众号共用的封面图:震撼、醒目、主题突出。**选风格 → 看示例 → 按配方组 prompt** 三步出图,`crop-cover.py` 一键裁出双平台尺寸(X 1200×675、公众号 900×383)。8 种风格索引与配方见 [`references/cover-styles.md`](./topmind-cover/references/cover-styles.md)。
40
+ X 长文与公众号共用的封面图:震撼、醒目、主题突出。**选风格 → 看示例 → 按配方组 prompt** 三步出图,`crop-cover.py` 一键裁出双平台尺寸(X 1200×675、公众号 900×383)。11 种风格索引与配方见 [`references/cover-styles.md`](./topmind-cover/references/cover-styles.md)。
41
41
 
42
42
  ```bash
43
43
  npx @topmindspace/tms-skills install topmind-cover
44
44
  ```
45
45
 
46
46
  <p align="center">
47
- <img src="https://github.com/topmindspace/tms-skills/raw/main/topmind-cover/assets/examples/overview.png" alt="topmind-cover · 8 封面风格总览" width="960" />
47
+ <img src="https://github.com/topmindspace/tms-skills/raw/main/topmind-cover/assets/examples/overview.png" alt="topmind-cover · 11 封面风格总览" width="960" />
48
48
  </p>
49
49
 
50
50
  > 让 idea 飞,好想法被看见。
@@ -53,18 +53,18 @@ npx @topmindspace/tms-skills install topmind-cover
53
53
  <img src="docs/assets/tms-skills-banner.png" alt="tms-skills · top-ppt-html — formal business presentations" width="960" />
54
54
  </p>
55
55
 
56
- > **警告**:不要安装 `@topmindspace/tms-skills@^2`(2.0.0–2.1.1 已弃用)。当前线 **0.2.x**(`latest`)。
56
+ > **警告**:不要安装 `@topmindspace/tms-skills@^2`(2.0.0–2.1.1 已弃用)。当前线 **0.3.x**(`latest`)。
57
57
 
58
58
  ## 技能一览
59
59
 
60
60
  | 技能 | 版本 | 做什么 |
61
61
  |------|------|--------|
62
- | [`top-ppt-html`](./top-ppt-html/) | **0.1.19** | 正式商务演示:HTML 可翻页 + 16:9 可编辑 PPTX;双交付 · MD3 密度克制;三模式 × 九风格;strict 0/0 |
62
+ | [`top-ppt-html`](./top-ppt-html/) | **0.2.1** | 正式商务演示:HTML 可翻页 + 16:9 可编辑 PPTX;双交付 · MD3 密度克制;三模式 × 九风格;strict 0/0 |
63
63
  | [`topmind-wechat-post`](./topmind-wechat-post/) | **0.1.0** | 公众号文章全生命周期:交付包、审校改写、质量三关、微信内联排版与发布清单 |
64
64
  | [`topmind-x-article`](./topmind-x-article/) | **0.1.0** | X 长文一键发布:Markdown 原稿转可直接粘贴的纯文本 + 封面图 + 发布清单 |
65
- | [`topmind-cover`](./topmind-cover/) | **0.1.0** | 文章封面配图(X / 公众号共用):震撼醒目主题突出;8 风格封面风格库 + 17 张双尺寸示例图 |
65
+ | [`topmind-cover`](./topmind-cover/) | **0.2.0** | 文章封面配图(X / 公众号共用):震撼醒目主题突出;11 风格封面风格库 + 26 张示例图(含 3 张 alt 样张) + 1 张风格总览图 |
66
66
 
67
- 安装器 [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) 为 **0.3.6**(整仓同 tag 发版)。
67
+ 安装器 [`@topmindspace/tms-skills`](https://www.npmjs.com/package/@topmindspace/tms-skills) 为 **0.4.1**(整仓同 tag 发版)。
68
68
 
69
69
  > SKILL.md frontmatter 除标准 `name`/`description` 外,本仓库扩展了 `action_category` / `triggers` / `triggers_cn` / `updated` 字段供安装器与路由使用。
70
70
 
@@ -76,7 +76,8 @@ npx @topmindspace/tms-skills install topmind-cover
76
76
  npx @topmindspace/tms-skills list
77
77
  npx @topmindspace/tms-skills install top-ppt-html
78
78
  npx @topmindspace/tms-skills install top-ppt-html --to ./.claude/skills
79
- npx @topmindspace/tms-skills@0.3.6 install top-ppt-html # 钉版本
79
+ npx @topmindspace/tms-skills@0.4.1 install top-ppt-html # 钉版本
80
+ npx @topmindspace/tms-skills uninstall top-ppt-html --to ./.claude/skills
80
81
  ```
81
82
 
82
83
  ```bash
@@ -84,7 +85,9 @@ npx @topmindspace/tms-skills@0.3.6 install top-ppt-html # 钉版本
84
85
  npx github:topmindspace/tms-skills install top-ppt-html
85
86
  ```
86
87
 
87
- 默认探测:`./.agents` → `./.claude` → `./.cursor` → `./.codex` → `./.mimocode`,再用户级 `~/.claude` 等;也可用 `--to`。不要 `npm install top-ppt-html`(技能 id 不是独立包)。
88
+ 默认探测:`./.agents` → `./.claude` → `./.cursor` → `./.codex` → `./.mimocode`,再用户级 `~/.claude` 等;也可用 `--to`。未给 `--to` 时安装摘要会明确打印探测到的目标目录。不要 `npm install top-ppt-html`(技能 id 不是独立包)。
89
+
90
+ `install` 细节:若同名技能已存在,会报出已装版本并拒绝覆盖,需加 `--force` 才替换(或先 `uninstall` 再装)。安装成功后打印三行摘要:装到哪里 / 装的技能版本与安装器版本 / 下一步。
88
91
 
89
92
  PPTX 精导需在技能目录 `npm install`(pptxgenjs)。HTML 生成仅 Python 标准库。
90
93
 
@@ -93,7 +96,7 @@ PPTX 精导需在技能目录 `npm install`(pptxgenjs)。HTML 生成仅 Pyth
93
96
  ```
94
97
  tms-skills/
95
98
  ├─ top-ppt-html/ # 技能(SKILL.md + assets + references + scripts)
96
- ├─ bin/tms-skills.js # CLI:list / install
99
+ ├─ bin/tms-skills.js # CLI:list / install / uninstall
97
100
  ├─ docs/ # 发布规范 · showcase 截图 · banner · Pages 源
98
101
  ├─ scripts/ # 仓库级门禁 / 隐私扫描
99
102
  ├─ package.json # @topmindspace/tms-skills
package/bin/tms-skills.js CHANGED
@@ -10,6 +10,7 @@
10
10
  * npx @topmindspace/tms-skills install top-ppt-html
11
11
  * npx @topmindspace/tms-skills install top-ppt-html --to ./skills-out
12
12
  * npx @topmindspace/tms-skills install top-ppt-html --force
13
+ * npx @topmindspace/tms-skills uninstall top-ppt-html --to ./skills-out
13
14
  * npx github:topmindspace/tms-skills install top-ppt-html # follow repo HEAD
14
15
  */
15
16
  'use strict';
@@ -69,6 +70,30 @@ function readSkillMeta(skillId) {
69
70
  return { id: skillId, description: String(desc).slice(0, 120) };
70
71
  }
71
72
 
73
+ /** 读技能目录下 SKILL.md frontmatter 的 version 字段(读不到返回 '',调用方兜底)。 */
74
+ function readSkillVersion(skillPath) {
75
+ try {
76
+ const p = path.join(skillPath, 'SKILL.md');
77
+ if (!fs.existsSync(p)) return '';
78
+ const text = fs.readFileSync(p, 'utf8');
79
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
80
+ if (!m) return '';
81
+ const v = m[1].match(/^version:\s*(.+?)\s*$/m);
82
+ return v ? v[1] : '';
83
+ } catch {
84
+ return '';
85
+ }
86
+ }
87
+
88
+ function installerVersion() {
89
+ try {
90
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
91
+ return pkg.version || 'unknown';
92
+ } catch {
93
+ return 'unknown';
94
+ }
95
+ }
96
+
72
97
  function resolveDefaultTarget() {
73
98
  const home = process.env.HOME || process.env.USERPROFILE || '';
74
99
  const candidates = [
@@ -112,15 +137,34 @@ function normPath(p) {
112
137
  return process.platform === 'win32' ? s.toLowerCase() : s;
113
138
  }
114
139
 
140
+ /** realpath 能解析就解析(跟符号链接),失败回退 path.resolve。
141
+ * dest 可能还不存在(install 流程):往上找最深存在的祖先解析后再拼回。
142
+ * 否则 --to 经符号链接指向包内时,词法比对会被绕过(rmSync 会跟链接删掉源)。 */
143
+ function realOrResolved(p) {
144
+ let cur = path.resolve(p);
145
+ const tail = [];
146
+ for (;;) {
147
+ try {
148
+ return path.join(fs.realpathSync(cur), ...tail);
149
+ } catch {
150
+ const parent = path.dirname(cur);
151
+ if (parent === cur) return path.join(cur, ...tail);
152
+ tail.unshift(path.basename(cur));
153
+ cur = parent;
154
+ }
155
+ }
156
+ }
157
+
115
158
  /** 安装目标守卫(审计 严重-2):
116
159
  * dest == 技能源目录 → --force 会先 rmSync 删掉源目录,再"成功"装出空目录(数据丢失 + 虚假成功);
117
160
  * dest 在源目录内部 → copyDir 无限递归复制直至 ENAMETOOLONG,并留下垃圾目录树。
118
- * path.resolve 归一化后比对(dest === src,或 dest 以 src + 路径分隔符开头),
161
+ * realpath 归一化后比对(dest === src,或 dest 以 src + 路径分隔符开头),
162
+ * 防止 --to 经符号链接指向包内绕过词法比对;
119
163
  * Windows 下额外做大小写归一。无论是否 --force,一律拒绝。
120
164
  */
121
165
  function assertDestOutsideSource(src, dest) {
122
- const absSrc = normPath(src);
123
- const absDest = normPath(dest);
166
+ const absSrc = normPath(realOrResolved(src));
167
+ const absDest = normPath(realOrResolved(dest));
124
168
  if (absDest === absSrc || absDest.startsWith(absSrc + path.sep)) {
125
169
  die(
126
170
  `Refusing to install into the skill's own directory tree.\n` +
@@ -132,7 +176,7 @@ function assertDestOutsideSource(src, dest) {
132
176
  }
133
177
  }
134
178
 
135
- function install(skillId, targetRoot, { force = false } = {}) {
179
+ function install(skillId, targetRoot, { force = false, defaultTarget = false } = {}) {
136
180
  assertSkillId(skillId);
137
181
  const src = skillDir(skillId);
138
182
  if (!fs.existsSync(path.join(src, 'SKILL.md'))) {
@@ -140,25 +184,85 @@ function install(skillId, targetRoot, { force = false } = {}) {
140
184
  }
141
185
  const dest = path.join(targetRoot, skillId);
142
186
  assertDestOutsideSource(src, dest);
143
- fs.mkdirSync(targetRoot, { recursive: true });
187
+ try {
188
+ fs.mkdirSync(targetRoot, { recursive: true });
189
+ } catch (e) {
190
+ die(
191
+ `Cannot create install directory: ${targetRoot}\n` +
192
+ ` reason: ${e.message}\n` +
193
+ 'Choose a --to directory that can be created (not a file, not unwritable).'
194
+ );
195
+ }
144
196
  if (fs.existsSync(dest)) {
145
197
  if (!force) {
198
+ // 已装过:报出已装版本,要求 --force 才覆盖(不静默覆盖)。
199
+ const installedVer = readSkillVersion(dest) || 'unknown';
200
+ const packageVer = readSkillVersion(src) || 'unknown';
146
201
  die(
147
- `Destination already exists: ${dest}\n` +
148
- 'Refusing to overwrite. Pass --force (or -f) to replace.'
202
+ `Already installed: ${dest}\n` +
203
+ ` installed version: ${installedVer} (this package ships ${packageVer})\n` +
204
+ 'Refusing to overwrite. Pass --force (or -f) to replace, or remove it first:\n' +
205
+ ` tms-skills uninstall ${skillId} --to ${targetRoot}`
149
206
  );
150
207
  }
151
208
  fs.rmSync(dest, { recursive: true, force: true });
152
209
  }
153
210
  copyDir(src, dest);
211
+ // 安装摘要三行:装到哪里 / 装了什么版本 / 下一步。
212
+ const toNote = defaultTarget ? ' (default, auto-detected — no --to given)' : '';
213
+ const skillVer = readSkillVersion(dest) || 'unknown';
154
214
  console.log(`Installed ${skillId}`);
155
- console.log(` from ${src}`);
156
- console.log(` to ${dest}`);
215
+ console.log(` to: ${dest}${toNote}`);
216
+ console.log(` version: skill ${skillVer} (installer ${installerVersion()})`);
217
+ console.log(` next: ${nextStep(skillId, dest)}`);
218
+ }
219
+
220
+ function nextStep(skillId, dest) {
157
221
  if (skillId === 'top-ppt-html') {
158
- console.log('');
159
- console.log('Optional (PPTX export only):');
160
- console.log(` cd "${dest}" && npm install`);
222
+ return `optional (PPTX export only): cd "${dest}" && npm install — then restart your agent so it picks up the skill`;
223
+ }
224
+ return 'restart your agent so it picks up the skill';
225
+ }
226
+
227
+ /** 列出目标根目录下已安装的技能(有 SKILL.md 的子目录)。 */
228
+ function listInstalledIds(targetRoot) {
229
+ try {
230
+ return fs
231
+ .readdirSync(targetRoot, { withFileTypes: true })
232
+ .filter((d) => d.isDirectory() && fs.existsSync(path.join(targetRoot, d.name, 'SKILL.md')))
233
+ .map((d) => d.name)
234
+ .sort();
235
+ } catch {
236
+ return [];
237
+ }
238
+ }
239
+
240
+ function uninstall(skillId, targetRoot) {
241
+ assertSkillId(skillId);
242
+ const src = skillDir(skillId);
243
+ const dest = path.join(targetRoot, skillId);
244
+ // 守卫:--to 指到包内时,dest 会命中安装器自带的技能源目录 → 一律拒绝,
245
+ // 防止把仓库自身的技能目录删掉(同 install 的 assertDestOutsideSource)。
246
+ if (fs.existsSync(path.join(src, 'SKILL.md'))) {
247
+ assertDestOutsideSource(src, dest);
248
+ }
249
+ if (!fs.existsSync(dest)) {
250
+ const installed = listInstalledIds(targetRoot);
251
+ die(
252
+ `Nothing to uninstall: ${dest}\n` +
253
+ ` skill '${skillId}' is not installed under ${targetRoot}.` +
254
+ (installed.length ? `\n installed here: ${installed.join(', ')}` : '')
255
+ );
161
256
  }
257
+ if (!fs.existsSync(path.join(dest, 'SKILL.md'))) {
258
+ die(
259
+ `Refusing to uninstall: ${dest}\n` +
260
+ ` not a skill directory (missing SKILL.md) — will not delete arbitrary folders.`
261
+ );
262
+ }
263
+ fs.rmSync(dest, { recursive: true, force: true });
264
+ console.log(`Uninstalled ${skillId}`);
265
+ console.log(` from ${dest}`);
162
266
  }
163
267
 
164
268
  function usageText() {
@@ -167,16 +271,33 @@ function usageText() {
167
271
  Usage:
168
272
  tms-skills list|ls
169
273
  tms-skills install <skill-id> [--to|-t <dir>] [--force|-f]
274
+ tms-skills uninstall <skill-id> [--to|-t <dir>]
170
275
  tms-skills help
171
276
 
277
+ Behavior:
278
+ install copies <skill-id>/ into <dir>/<skill-id>/. If the skill is already
279
+ installed, the installed version is reported and --force is required
280
+ to overwrite. Prints where/what-version/next-steps when done.
281
+ uninstall removes <dir>/<skill-id>/ (refuses: not installed, not a skill
282
+ directory, or the package's own skill source).
283
+ No --to: the target directory is auto-detected (probe order below) and
284
+ printed explicitly in the install summary.
285
+
286
+ Target probe order (no --to): ./.agents/skills, ./.claude/skills,
287
+ ./.cursor/skills, ./.codex/skills, ./.mimocode/skills, then
288
+ ~/.claude/skills, ~/.agents/skills, ~/.cursor/skills, ~/.codex/skills.
289
+
172
290
  Examples (npm recommended when published):
173
291
  npx @topmindspace/tms-skills list
174
292
  npx @topmindspace/tms-skills install top-ppt-html
175
293
  npx @topmindspace/tms-skills install top-ppt-html --to ./.agents/skills
176
294
  npx @topmindspace/tms-skills install top-ppt-html --force
295
+ npx @topmindspace/tms-skills uninstall top-ppt-html --to ./.agents/skills
177
296
 
178
297
  # Follow repo HEAD:
179
298
  npx github:topmindspace/tms-skills install top-ppt-html
299
+
300
+ Privacy: the installer is fully local — it never collects or uploads anything.
180
301
  `;
181
302
  }
182
303
 
@@ -225,7 +346,26 @@ function main(argv) {
225
346
  }
226
347
  }
227
348
  const targetRoot = to ? path.resolve(to) : resolveDefaultTarget();
228
- install(skillId, targetRoot, { force });
349
+ install(skillId, targetRoot, { force, defaultTarget: !to });
350
+ return;
351
+ }
352
+
353
+ if (cmd === 'uninstall') {
354
+ const skillId = args[1];
355
+ if (!skillId || skillId.startsWith('-')) {
356
+ die('Missing skill id.\n\n' + usageText());
357
+ }
358
+ let to = null;
359
+ for (let i = 2; i < args.length; i++) {
360
+ if (args[i] === '--to' || args[i] === '-t') {
361
+ to = args[++i];
362
+ if (!to) die('Option --to requires a directory path.');
363
+ } else {
364
+ die(`Unknown option: ${args[i]}\n\n` + usageText());
365
+ }
366
+ }
367
+ const targetRoot = to ? path.resolve(to) : resolveDefaultTarget();
368
+ uninstall(skillId, targetRoot);
229
369
  return;
230
370
  }
231
371
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topmindspace/tms-skills",
3
- "version": "0.3.6",
3
+ "version": "0.4.1",
4
4
  "description": "TopMindspace 智能体技能 monorepo — 通过 npm / GitHub npx 安装技能(top-ppt-html:HTML+PPT 双交付,正式商务演示文稿)。",
5
5
  "license": "MIT",
6
6
  "author": "TopMindspace",
@@ -10,7 +10,7 @@
10
10
  **Let ideas fly — make good thinking visible.** A high-craft skill for **demo reports / formal business presentations**: **HTML + PPT dual delivery** — day-to-day, present with paginated HTML like slides; export **layout-faithful editable PPTX** when needed. **MD3-inspired**: fitting information density, restrained type / shapes / color. Core craft is layout, typography, color, and content structure — not gadget soup.
11
11
 
12
12
  - Skill id: `top-ppt-html`; brand: **TopPPT HTML**
13
- - Version: **v0.1.19** (same tag as `@topmindspace/tms-skills@0.3.6`)
13
+ - Version: **v0.2.1** (same tag as `@topmindspace/tms-skills@0.4.1`)
14
14
  - **Agent entry**: `SKILL.md` → `references/playbook.md` (L1) → L2 on demand
15
15
  - **Human maintainers**: this README (install / commands / layout); do not treat it as the generation spec
16
16
 
@@ -55,7 +55,7 @@ Also: arrow-key paging; **Esc** closes modals. After style/theme change, re-run
55
55
 
56
56
  ```bash
57
57
  npx @topmindspace/tms-skills install top-ppt-html
58
- npx @topmindspace/tms-skills@0.3.6 install top-ppt-html
58
+ npx @topmindspace/tms-skills@0.4.1 install top-ppt-html
59
59
  npx github:topmindspace/tms-skills install top-ppt-html
60
60
  ```
61
61
 
@@ -10,7 +10,7 @@
10
10
  **让 idea 飞,好想法被看见。** 为**演示报告 / 正式商务演示**而生的高品质演示文稿技能:**HTML + PPT 双交付**——日常用可翻页 HTML 等同幻灯片;需要时再导出**版式保真可编辑 PPTX**。参考 **MD3**:合适信息密度、克制文字/图形/颜色。核心工艺是版式、排版、色彩与内容组织——不是 gadget 堆砌。
11
11
 
12
12
  - 技能标识:`top-ppt-html`;品牌名:**TopPPT HTML**
13
- - 版本:**v0.1.19**(与 `@topmindspace/tms-skills@0.3.6` 同 tag)
13
+ - 版本:**v0.2.1**(与 `@topmindspace/tms-skills@0.4.1` 同 tag)
14
14
  - **智能体入口**:`SKILL.md` → `references/playbook.md`(L1)→ L2 按需
15
15
  - **人类维护者**:本 README(安装 / 命令 / 目录);勿把本文件当生成规范
16
16