dsh-better-sidebar 的 .pptx 阅读视图:按演示顺序列出幻灯片,还原项目符号层级、演讲者备注与内嵌图片。归档体积、单部件解压字节与幻灯片数量均有上限,演示文稿不会卡死标签页。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-pptx-sidebar
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:drscrewdriver/dsh-pptx-sidebar
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
简体中文 | Français | Deutsch | Italiano | Русский | Español
⛔ 本项目已停止维护(2026-10-01)。 DSH 宿主较新版本已内置 office 演示文稿的侧栏预览,本插件不再单独维护、不再发版,也不参与后续宿主版本线适配。已发布版本仍可安装使用;0.1.x 宿主请使用冻结分支
compat/0.1.7/compat/0.1.5的对应版本。
Read .pptx / .pptm decks in the DSH sidebar — the slides in presentation
order, with their text, bullet levels, speaker notes and inline pictures.
This is a reading view, not a slide reproduction. No absolute positioning, no theme fonts, no placeholder inheritance, no animation. The viewer says so in its header, because a layout difference that looks like a rendering bug is worse than a plainly-labelled limitation.
It is a dsh-better-sidebar consumer: it registers a file previewer and renders inside the Side card's preview area. Without that plugin it loads, warns once, and does nothing.
Install
dsh plugin --profile <profile> add github:drscrewdriver/dsh-pptx-sidebar#<sha>
dsh plugin --profile <profile> add dsh-pptx-sidebar@0.1.0 # once published
Then restart the DSH host — a browser refresh is not enough for a new loader row. Verify without starting anything:
dsh --profile <profile> --dump-config | Select-String dsh-pptx-sidebar
Manual installation is three steps, not one — see cordis.patch.yml. Doing only
steps 1 and 3 produces a profile where the package is present, the patch row is
present, and nothing loads, silently.
What it does / does not do
| Done | Not done |
|---|---|
Slide list in p:sldIdLst order |
Visual layout, absolute positioning |
| Text paragraphs, per-paragraph bullet levels | Theme/master font resolution |
| Title detection from placeholder type | Placeholder inheritance (see below) |
Speaker notes from notesSlide parts |
Charts re-rendered as charts |
| Inline pictures as blob URLs | Animation, transitions, timings |
Real tables (a:tbl) |
Comments, revision marks |
| Bold / italic runs | Editing, writing back |
| Seven circuit-breaker ceilings | Legacy .ppt (BIFF/OLE2), WPS formats |
The placeholder inheritance line (deliberate)
A slide often shows text it does not contain: numbers, footers, and title text
that live in slideLayout / slideMaster, referenced through a p:ph
placeholder. Resolving that means re-implementing PowerPoint's inheritance chain
— including lstStyle level overrides and which layout the slide actually uses.
v1 does not do it. Only the slide's own part is read. The consequence is stated rather than hidden: a slide whose text is entirely inherited renders with no text. That is a visible omission, not a corruption — the opposite trade (inheriting wrongly) would show text that is not on the slide.
Width adaptation
The sidebar pane is resizable, so the reading view adapts to it — within bounds, because "adaptive" is not a licence to keep growing or shrinking:
| Knob | Value | Why |
|---|---|---|
| Base width | 360 px | The factor is exactly 1 here, so the usual pane width renders the layout 0.1.0 shipped |
| Floor | 0.9× | A narrow pane still gets readable type |
| Ceiling | 1.15× | A wide pane gets comfortable type, not enormous type |
| Quantisation | 2 decimals | A drag re-lays-out on 0.01 steps, not on every pixel |
The factor is derived from the pane width and written to the --reader-scale
custom property; the root font-size becomes 13px × scale and the slide content
is expressed in em, so text reflows at the new size instead of being
transform-scaled (which would blur glyphs).
Only the document scales. Titles, bullets, paragraphs, notes, tables and image captions follow the factor; the header strip, the slide strip, the breaker banner and the loading/empty states keep their fixed size. Chrome that changes size while you drag a divider reads as a glitch rather than as responsiveness.
Two related decisions:
- An unmeasurable width falls back to 1, not to a bound. Before the first measurement the width is 0, and rendering that as "as narrow as possible" would flash tiny type every time a deck is opened.
- Pictures do not scale. They render at the size the shape transform states and are only capped by the pane; magnifying a bitmap past its natural size to track the text would make it softer, not more faithful.
The pipeline
archive bytes (host /sidebar/file, custom loader)
→ archive-size gate refuse before any unpacking
→ central directory (declared-size gate) refuse a lying part before inflating
→ streaming inflate + total budget the zip-bomb gate
→ ppt/presentation.xml p:sldIdLst — slide ORDER
→ ppt/_rels/presentation.xml.rels rId → slides/slideN.xml
→ ppt/slides/slideN.xml p:spTree → p:sp / p:pic / p:graphicFrame
│ p:txBody → a:p → a:pPr@lvl (level), a:r → a:rPr(b/i) + a:t
│ p:pic → a:blip@r:embed → slide rels → ppt/media/*
│ p:grpSp → recursed, never flattened away
├→ ppt/slides/_rels/slideN.xml.rels .../notesSlide → notesSlides/notesSlideN.xml
└→ rules: a slide too long loses only its own tail; notes absent is silence
Pictures are pulled out of the zip and turned into object URLs. An embedded image lives inside the archive, so there is no host route to point at — this is not "reading files ourselves", it is using the bytes the host already handed over.
Seven circuit-breaker ceilings
| Dimension | Default | Over it |
|---|---|---|
| Archive size | 8 MB | BLOCKED — refused before any unpacking |
| Total inflate | 64 MB | BLOCKED — the zip-bomb gate |
| One part | 32 MB | BLOCKED — a single oversized XML part |
| Slides | 300 | TRUNCATED — the reader stops walking the deck |
| Slide text | 20 000 chars | that slide's remaining text elided |
| Images | 200 | further pictures skipped |
| One image | 8 MB | that picture skipped (not even inflated) |
At most one warning per dimension, structurally — warnings live in a
Map<reason, warning>, so a dimension that trips on every slide produces one
line, not sixty.
The per-slide text ceiling elides only the offending slide. A per-block ceiling would shave every slide equally and lose information the deck had budget for; the failure mode we accept instead is "slide 12 is cut short".
Tests
npm install
npm run verify # build (bundle load gate) + tests
npm test # 19 checks
The fixture is a real pptx-shaped zip built in the test file, with a genuine tiny PNG. It is hostile where the format is:
p:sldIdLstlists slide2 before slide1, so sorting parts by filename would pass every other assertion and still be wrong;- one slide relationship uses an absolute target, another is External;
ppt/slideLayouts/slideLayout1.xmlcarriesMASTER TEXT MUST NOT APPEAR, which must never surface — that is what "no placeholder inheritance" means here.
Layout
| File | Role |
|---|---|
pptx.ts |
The reader: parts, relationships, shape tree, notes, pictures |
circuit-breaker.ts |
The seven ceilings and the single-warning-per-dimension rule |
zip.ts / xml.ts |
Container reading; targeted XML scanning with depth counting |
PptxViewer.tsx |
Slide strip, current-slide rendering, object-URL lifetime |
locales.ts |
zh / en dictionaries, including every warning template |
seams.ts |
Structural mirrors of the client services we consume |
The zip and XML code is copied from the sibling document plugin rather than shared. Two users of this code is not yet the threshold for extracting a package — that would add a third thing to publish and version-lock.
Compatibility
| Plugin version | DSH host range | Notes |
|---|---|---|
| 0.3.0 | >=0.2.0-rc.1 <0.2.1-0 |
The 0.2.0 line (main, promoted from compat/0.2.0). Metadata-only adaptation: the consumption surface is pure ctx.get(...) calls, 0.2.0-rc.1 keeps the 0.1.7 plugin API intact |
| 0.2.0 | >=0.1.5-rc.1 <0.2.0-0 |
Served by the frozen branches compat/0.1.7 / compat/0.1.5 |
engines.dsh, the @deepseek-ai/dsh-client-locale peer in package.json, and
dsh.plugin.json's engines.dsh all carry the same range (kept in lockstep).
Languages / Sprachen / Langues / Языки / Idiomas / Lingue
This README is written in English. Compatibility and install quick reference (this line requires DSH 0.2.0: >=0.2.0-rc.1 <0.2.1-0; install: dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0):
- Deutsch — benötigt DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0). Installation:dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0. Die 0.1.x-Wirtslinie wird von den eingefrorenen Zweigencompat/0.1.7/compat/0.1.5(npm-Tagsdsh-0.1.7/dsh-0.1.5) versorgt. - Français — nécessite DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0). Installation :dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0. La lignée d'hôtes 0.1.x est assurée par les branches figéescompat/0.1.7/compat/0.1.5(tags npmdsh-0.1.7/dsh-0.1.5). - Русский — требуется DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0). Установка:dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0. Линия хостов 0.1.x обслуживается замороженными веткамиcompat/0.1.7/compat/0.1.5(npm-тегиdsh-0.1.7/dsh-0.1.5). - Español — requiere DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0). Instalación:dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0. La línea de anfitriones 0.1.x la atienden las ramas congeladascompat/0.1.7/compat/0.1.5(etiquetas npmdsh-0.1.7/dsh-0.1.5). - Italiano — richiede DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0). Installazione:dsh plugin --profile <profile> add dsh-pptx-sidebar@dsh-0.2.0. La linea di host 0.1.x è servita dai rami congelaticompat/0.1.7/compat/0.1.5(tag npmdsh-0.1.7/dsh-0.1.5).
License
MIT
链接
同类插件
tt-a1i/archify#integrations/deepseek-harness★ 92724
从仓库或系统描述生成经过校验的自包含交互式架构图、流程图、时序图、数据流图和生命周期图。
dream-num/dsh-univer-office★ 657
为 DeepSeek Harness 打造一个真正的办公环境。Univer Office 插件将电子表格、文档、幻灯片、画布、多维表格等汇聚到同一个运行时——数据互联、修改经过校验、变更按版本管理,并以隔离工作树支持多 Agent 协作。
ECNU/EduWork#dsh-knowledge-studio★ 275
基于工作区资料的 Studio,复用 DSH 模型与共享成果服务,制作报告、演示文稿、表格、思维导图、测验、闪卡及音视频。Office 生成需 Python 3.12+ 及相关依赖,并配置 DSH_OFFICE_PYTHON;媒体渲染需 Chromium;本地语音转写另需 whisper.cpp 和模型。
PerryLink/dsh-industry-research★ 215
面向 DeepSeek Harness 的确定性行业研究报告:公司与行业研究流程基于分阶段证据产出结构化、可核验的报告。
HuanLinOTO/dsh-plugin-mineru★ 51
向模型暴露 MineRU 文档解析工具。
PolinniZhong/dsh-knit★ 48
把会话工作区里已有的 Markdown 文档、源码、图片与视频列进 DSH 侧边栏,按与当前对话的相关性排序。默认的词法模式用最近几条消息在本地与标题、摘要、正文做带 IDF 加权的匹配(BM25)—— 不调用模型、没有网络出口,内容不出本机。列表来自工作区扫描,而不是「最近打开记录」,所以重启 DSH 或新开会话都不会变空。排序结果组织成主要 / 辅助 / 相关三层的阅读顺序,每一条都写明可核验的理由(命中了哪个字段、被哪一篇引用),点一行即可就地预览:Markdown 按渲染后的样子显示、相对路径图片真实渲染、源码走宿主自带的语法高亮、视频走 HTTP Range 流式播放。同一份 Context Pack 也作为 knit_docs 工具交给 agent。后续版本陆续补上读取证据与生命周期(归因在读那一刻冻结)、固定 / 排除(排除先于检索生效,且可恢复)、关系证据(引用 / 导入 / 测试,带行号)与增量索引(重启后复用)。v0.23 起还多一条可选的混合检索:默认关闭,只有你自己配好 Ollama 或 OpenAI 兼容的 embedding 服务才会生效。它生效时,发出去的是你这句查询原话加上每篇候选文件的标题与摘要 —— Markdown 的摘要取自正文首段(不超过 60 字),代码的摘要是它所在的工作区相对目录,图片 / 视频贡献的是文件名;完整正文与绝对路径都不发送,指向本机服务(loopback)时内容不出这台机器。v0.24 起还能做变更关联:用一条只读的 git status(固定 argv、不走 shell、子进程环境白名单),配合同一套引用 / 导入 / 测试 / 提及证据,指出这次改动大概率该一起看哪些文件 —— 默认关闭。语义检索的收益仍待真 provider 实测,因此不承诺召回提升。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。