dsh-ppt-master
Verifieddsh-ppt-master · v1.0.8 · MIT
PPT Master for DeepSeek Harness — agent preset 形式提供全套 ppt_* 工具(源文档→逐页手写 SVG→质检→导出可编辑 PPTX),只在选中该预设的会话里生效,不占用其他会话的上下文。
Install
dsh plugin add dsh-ppt-master Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Readme
dsh-ppt-master
把 PPT Master 装成 DSH agent preset 的插件包:
选中「PPT Master」预设的会话里,直接多出 32 个 ppt_* 工具 + 2 个 skill,
走 源文档 → 八项确认 → 逐页手写 SVG → 质检 → 视觉闸门 → 导出可编辑 PPTX 这条流水线。
没选这个预设的会话完全不受影响 —— 工具不会出现,也不占任何上下文。
dsh plugin add [email protected] # 建议写死版本
npm view dsh-ppt-master versions # 查有哪些版本
为什么要写死版本号。 pnpm 有一个「新版本隔离期」(
minimumReleaseAge, 默认约 24 小时):发布不足隔离期的版本不参与版本解析。而所有版本都还在 隔离期内时,pnpm 在 loose 模式下会退回最旧的那个版本。 实测本包刚发 1.0.4 时,dsh plugin add dsh-ppt-master与@latest都装到了 1.0.0 —— 而 1.0.0 的预设是坏的(见下方 「构造期必需 config」,卡片会显示「加载失败」)。写死版本号即可绕过解析。 这不是本包特有的问题,任何频繁发版的包都会这样。
装完之后新建会话,在预设选择器里选 PPT Master。
为什么做成预设,而不是常驻插件
DSH 的工具是进程级注册的:插件一旦启用,工具就出现在所有会话里。
这对通用插件是对的,对一个 32 个工具的专业流水线是错的 —— 每次聊别的,
ppt_render、ppt_svg_metrics、ppt_watermark_remove… 全都躺在工具表里,
每轮都在烧上下文、都在干扰模型选工具。
agent preset 正好解决这件事:预设是会话级的能力组装。本包的
cordis.patch.yml 里挂的是一行声明(官方 @deepseek-ai/dsh-agent-preset),
它描述「PPT Master 这个预设 = 这些插件」;工具行本身写在声明内部的 plugins:
列表里。于是装载动作、工具注册、系统提示词,全部发生在选中该预设的会话里。
顺带一提:这也让提示词可以随预设走。本包在预设里塞了 PPT 专用的 persona (八项确认是硬停、SVG 必须手写、视觉闸门必须看图),而不是把纪律硬编码进工具。
32 个工具
工具与 skill 是互补关系,不是替代:skill 负责流程纪律(哪一步必须停下、 什么不许做),工具负责原子操作(真的去跑那个脚本)。
| 阶段 | 工具 | 干什么 |
|---|---|---|
| 体检 | ppt_env |
探测 Python 解释器与 14 组依赖,报告缺什么 |
| ① 素材 | ppt_convert |
pdf/doc/excel/ppt/网页 → Markdown |
ppt_intake |
素材入仓、登记来源 | |
ppt_pptx_to_svg |
已有 PPTX → SVG(改造既有稿) | |
| ② 项目 | ppt_project |
init / import-sources / validate / info |
ppt_template_import ppt_template_register ppt_icons |
模板与图标库 | |
| ③ 计划 | ppt_spec_update |
改 spec_lock.md(配色/字体/页序) |
ppt_fill |
模板填充:analyze/scaffold/check-plan/apply |
|
ppt_images_analyze ppt_image_gen ppt_image_search ppt_latex |
配图与公式 | |
ppt_images_rotate ppt_watermark_remove |
图片预处理 | |
| ④ 逐页 | ppt_svg_quality ppt_svg_metrics |
单页质检、文字宽度/排版度量 |
ppt_svg_position |
坐标/图表几何计算 | |
ppt_svg_finalize ppt_svg_extract_assets |
后处理(每步单独跑) | |
| ⑤ 收口 | ppt_notes_split ppt_batch_validate |
讲稿拆分、全量校验 |
| ⑥ 闸门 | ppt_render ppt_contact_sheet ppt_visual_review ppt_check_annotations |
渲染 → 拼图 → 逐页看图 |
| ⑦ 导出 | ppt_export |
SVG → 可编辑 PPTX |
| 附加 | ppt_animation ppt_narration |
动画配置、AI 配音 |
ppt_beautify_identity ppt_beautify_inventory |
美化既有设计 |
所有工具都支持两个通用参数:
extra_args—— 透传工具没建模的旗标,上游脚本加参数时不用等插件更新;cwd—— 指定工作目录。
返回统一是 { ok, exitCode, timedOut, output },output 是合并后的 stdout+stderr。
两个 skill
| Skill | 内容 |
|---|---|
ppt-master-dsh |
精简入口(6.7 KB)。流程纪律 + 每步该调哪个工具 + 卡住时看哪里 |
ppt-master |
上游原文(71 KB,未作修改)。references/ 与 workflows/ 是细节的唯一权威 |
为什么需要一个插件,而不是把目录丢进 ~/.agents/skills?
因为 DSH 不展开 ${SKILL_DIR}。
DSH 自带的 @deepseek-ai/dsh-skill-filesystem 只做发现与解析:扫磁盘上的 SKILL.md,
把 frontmatter 解析成目录条目,正文原样返回,不做任何变量替换。
而 PPT Master 的 SKILL.md 里有 53 处 ${SKILL_DIR}:
python3 ${SKILL_DIR}/scripts/project_manager.py init <project_name>
在 Claude Code 里 SKILL_DIR 由宿主展开;在 DSH 里没有任何东西展开它。直接拷目录
进去,agent 拿到的就是字面量 ${SKILL_DIR} —— 好在 filesystem provider 会同时告诉
它「Base directory for this skill」在哪,所以它猜得出来,只是文档与事实不符、要来回试错。
本插件在加载正文时把 ${SKILL_DIR} 替换成装好之后的真实绝对路径,
于是文档里的命令行可以原样复制执行:
python3 C:/Users/<you>/.dsh/profiles/desktop/node_modules/dsh-ppt-master/skills/ppt-master/scripts/project_manager.py init demo
同一机制还提供了 ${PAYLOAD_DIR}:指向上游载荷根目录,供精简 skill 做
「细节看原文」的跳转。展开是运行时做的,skills/ 下的文件一个字节都没改。
只展开这两个,不动 ${TEMPLATE_DIR}
${TEMPLATE_DIR} 是运行时由用户或 agent 自己赋值的模板来源路径
(SKILL.md 里写的是 TEMPLATE_DIR=<user-supplied path>),不是包能预先知道的值。
替换它会破坏语义,所以原样保留。
与手工安装的 skill 如何共存
skill 注册表按 rank 合并同名 skill,数字小的赢:
| Rank | 来源 | 路径 |
|---|---|---|
| 400 | user-dsh |
~/.dsh/skills |
| 500 | user-agents |
~/.agents/skills |
| 600 | 本插件(默认) | 包内 skills/ppt-master/ |
所以机器上有 ~/.agents/skills/ppt-master 时,那份优先,本插件静默让位,
不会出现两条同名 skill。这是刻意的:手工副本通常是你正在调试的版本。
实测(本机,两种配置各跑一次真实 registry):
| 配置 | 胜出者 | 展开后残留 ${SKILL_DIR} |
|---|---|---|
| 默认(rank 600) | filesystem(手工副本) |
53 处未展开 |
rank: 100 |
ppt-master(本插件) |
0 |
想让插件压过手工副本:patch 只能按顶层 id 匹配,预设内部的插件行
(ppt-master-tools)不在索引里 —— 按嵌套 id 覆盖会报
patch: entry "ppt-master-tools" not found。必须整块替换预设的 config,
把自己要保留的行原样带上(patch 语义是整块替换,不是深合并):
- id: preset-ppt-master
config:
id: ppt-master
name: PPT Master
order: 10
plugins:
# …把你想要的插件行照抄过来…
- id: ppt-master-tools
name: dsh-ppt-master
config:
rank: 100 # 小于 400,压过 ~/.dsh/skills 与 ~/.agents/skills
Python 依赖
插件永远不会自己跑 pip install —— 那是有副作用的系统改动,必须你点头。
开工先调 ppt_env,它会报告解释器、版本,以及 14 组依赖各缺什么:
| 组 | 模块 / 命令 | 用在哪 |
|---|---|---|
| 核心(必需) | pptx docx openpyxl |
几乎所有环节 |
| 核心(原生扩展) | PIL lxml numpy |
图像、XML、数值 |
| SVG/PDF 转换 | reportlab svglib |
渲染与 PDF 处理 |
| PDF 解析 | fitz |
PDF 素材 |
| 文档转换 | mammoth markdownify bs4 ebooklib |
源文档转换 |
文档转换(.ipynb) |
nbconvert |
笔记本转幻灯片 ⚠️ Android 不可用 |
| 网页抓取 | requests |
抓网页素材 |
| 网页抓取(强反爬) | curl_cffi |
微信等站点 ⚠️ Android 不可用 |
| YAML 配置 | yaml |
配置读写 |
| 视觉质检 | playwright |
视觉闸门首选 ⚠️ Android 不可用 |
| 渲染回退 | rsvg-convert(apt 包 librsvg) |
Android 上的唯一渲染后端 |
| 确认页 / 实时预览 | flask |
SVG 编辑器 |
| AI 生图 | google.genai |
Gemini 图片后端 ⚠️ Android 不可用 |
| 语音旁白 | edge_tts |
AI 配音 |
Android 上 4 组永远装不上(
nbconvert/curl_cffi/playwright/google.genai,都缺android_arm64轮子)。这是平台事实,不是缺漏:ppt_env会把它们单独标成「Android 不可用」,且不计入ok判定 —— 否则任何一台手机上ok都恒为 false,模型会误以为环境没准备好而反复重试。⚠️
pip是原子的:同一条命令里只要有一个包构建失败,整条命令一个包都不装。 所以ppt_env给出的 pip 命令已经把这 4 组排除掉了,照抄即可,不要自己补。
缺哪组装哪个,ppt_env 会给出可直接复制的 pip 命令。完整清单:
pip install -r "<PAYLOAD_DIR>/requirements.txt"
用哪个 Python
按顺序探测:环境变量 DSH_PPT_PYTHON → python → python3 → py -3,
并且真的运行一次打印版本才算数(光看 where 可能撞上 Windows 的
Microsoft Store 别名占位符)。
$env:DSH_PPT_PYTHON = "C:\path\to\python.exe"
不想污染系统解释器就用 venv,把 DSH_PPT_PYTHON 指过去。
包结构
dsh-ppt-master/
├── package.json # dsh.bundle.patch 指向 cordis.patch.yml
├── cordis.patch.yml # 声明 agent preset「PPT Master」及其插件组成
├── lib/
│ ├── index.js # 两个 skill 的 provider + 展开 ${SKILL_DIR}/${PAYLOAD_DIR}
│ ├── tools.js # 32 个工具定义(参数 schema / 输出渲染 / argv 组装)
│ └── runner.js # Python 探测、依赖体检、子进程执行
├── skills/ppt-master/ # 上游载荷原文(SKILL.md + scripts/references/templates/workflows)
├── skills/ppt-master-dsh/ # 精简入口 skill
├── verify.mjs # 自检 81 项,零依赖
├── probe-load.mjs # 真实 Cordis 装载冒烟测试
├── LICENSE # 本包 MIT
└── LICENSE.ppt-master # 上游 skill 的 MIT 许可(Hugo He)
为什么零 peerDependencies
一旦把 @deepseek-ai/dsh-* 写进 peerDependencies,安装时的
evaluatePluginCompatibility 就会拿它去卡运行时版本。而 DSH 的预发布版本号
(如 0.1.6-alpha.1)只匹配同 major.minor.patch 且带预发布段的区间 ——
^0.1.6 在 0.1.6-alpha.1 上判否,必然 incompatible-version。
本包因此零依赖:工具用 ctx.tools.register() 收的普通对象(不 import
dsh-tools)、rank 常量 600 硬编码、frontmatter 用 40 行自带解析器。
代价是那点重复代码,换来的是在任何 DSH 运行时上都能装。
为什么用 spawn 而不是 shell
工具直接 spawn(python, [脚本绝对路径, ...argv]),不经 shell。
PPT 的路径充满中文、空格、引号、#、%、$。拼成命令行字符串再交给 shell,
任何一个字符都可能变成注入或截断。传 argv 数组则完全绕开转义问题。
代价是不参与 DSH 的 sandbox/审批链 —— 可接受,因为这些命令是 skill 自带的
Python 脚本,不是模型现编的任意命令。
自检
node verify.mjs # 81 项静态契约 + 载荷 + 发布卫生,零依赖
node probe-load.mjs <profile>/node_modules # 真实 Cordis 装载 + 真跑一次工具
verify.mjs 覆盖:插件契约(patch 在 files 里、声明行是 agent-preset、
预设内引用了本包、每个 group 都有 isolate 域、零 peer、构造期必需 config)、
载荷(两个 skill 的 frontmatter / 占位符展开 / 精简版确实更短)、工具定义
(32 个、名字不重复、required 不点幽灵键、未占保留名)、移动端适配
(渲染回退器在场且可被 DSH_PPT_RSVG 覆盖、Python 探测覆盖 Termux 前缀、
Android 有可执行安装指引、pip 命令可整条粘贴)、发布卫生(无本机路径
/ 无凭据 / 无 .pyc)。
probe-load.mjs 在真实 Context 上装一遍,断言工具全部注册、ppt_env 能跑出
解释器版本、ppt_project 能跑通完整 spawn 链路并如实返回非零。
为什么校验「构造期必需 config」
预设里的某一行如果在构造函数里校验 config(而不是用 Config schema),漏字段
的后果不是「该项被忽略」,而是构造抛错 → 整行挂载失败 → 整份预设被 registry
标记 broken:卡片显示红色「加载失败」,且该预设无法被选入会话。
1.0.0 就踩了这个坑:plan-mode 行没带 config.section,
@deepseek-ai/dsh-plan-mode 的构造函数抛
PlanModeConfig needs a string section``,整套工具随之报废。1.0.1 修好,
并在 verify.mjs 里加了针对这类「构造期必需 config」的回归断言
(去掉 section 立刻报 FAIL)。
判断某个包属于这一类:看它的 lib/index.js 里有没有
XxxConfig needs a ... / XxxConfig: ... must be ... 这种在构造路径上直接
读 config 的断言。用 Config schema 校验的包不在其列 —— 它们缺字段时会被
schema 补默认值或在加载期报清晰的 schema 错误。
移动端(Android / Termux)适配
这些能力来自一次真实手机会话的复盘(100.7 分钟、271 步、359 次工具调用):
ppt_render自动回退到rsvg-convert。 上游渲染闸门只走 playwright, 拿不到就退出码 3;而 playwright 在 Android 上没有发行版 (pip install playwright→ No matching distribution)。现在ppt_render检测到 playwright 路径不可用(退出码 3/127,或输出里含Executable doesn't exist/playwright install等特征)时,自动用rsvg-convert渲染到同一个inspection/目录,并在输出里标明[回退]。可用DSH_PPT_RSVG指定转换器路径。回退只在确认是 playwright 缺失时触发 —— 别的非零退出码不会被它掩盖。- Python 探测覆盖 Termux。 实测手机宿主进程没有
PREFIX环境变量, 只有 PATH 里带着…/termux/usr/bin。所以候选表既从PREFIX/TERMUX_PREFIX/ PATH 反推前缀,也直接拼已知的com.dsh.android/com.dsharnessmobile.shell私有目录。 - 平台专属的安装指引。 找不到 Python 时,Android 上给出可直接抄的
apt-get install -y --no-install-recommends python python-pip(而不是对手机说 「安装 Python 3.10+」这种无法执行的话)。缺依赖时给出按 apt / pip 分开的两条 命令,并说明哪些组在 Android 上本就没有轮子、不必反复重试。⚠️
--no-install-recommends不能省。python-pip的Recommends里写着 clang / make / pkg-config,apt 默认会一起把整个 LLVM(llvm/lld/libllvm)拖进来。 真机实测同一条命令 139 秒 → 16 秒,且那堆东西对装依赖毫无用处。⚠️ 原生扩展必须走 apt。
pip install lxml(或 Pillow / numpy / PyMuPDF)在 Android 上必然失败 —— PyPI 没有android_arm64轮子。Termux 仓库里有预编译包,ppt_env会直接给出对应的apt-get install命令。 rsvg-convert是 Android 上唯一的渲染后端。playwright没有 Android 发行版, 所以ppt_render必然走 rsvg 回退。它是可执行文件而不是 Python 模块, 原先的体检只查 Python 模块、从不提示装它 —— 于是全新环境里两个后端都缺, 视觉闸门整条断掉。现在ppt_env会探测rsvg-convert是否存在, 并在 Android 上把它列入 apt 命令(包名librsvg)。ppt_svg_metrics支持texts: [...]批量度量。 单条调用一次要 起一个 Python 进程;实测被单条调用了 22 次。批量走一个进程内联脚本。- 精简 skill 内建省 token 纪律。 实测 47% 的输出花在反复
bash cat上游 skill 文件上,而read工具一次未用。精简版 SKILL.md 直接写明 用read、每个文件只读一次、不要job_output长等、批量度量、 不要手写渲染循环。
许可
本插件包:MIT(见 LICENSE)。
随包分发的 PPT Master skill:MIT,Copyright (c) 2025-2026 Hugo He
(见 LICENSE.ppt-master)。skill 载荷未作修改,路径展开发生在运行时。