跳到正文
dsh-market 浏览插件 GitHub EN

drscrewdriver/dsh-pptx-sidebar

dsh-better-sidebar 的 .pptx 阅读视图:按演示顺序列出幻灯片,还原项目符号层级、演讲者备注与内嵌图片。归档体积、单部件解压字节与幻灯片数量均有上限,演示文稿不会卡死标签页。

Star 数 ★ 0 分类 文档与渲染 收录于 2026-09-25 npm dsh-pptx-sidebar

安装

在 DeepSeek Harness 里通过 dsh-market 安装

dsh plugin --profile web add dshmarket

或使用命令行

dsh plugin --profile web add dsh-pptx-sidebar

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 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:sldIdLst lists 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.xml carries MASTER 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 Zweigen compat/0.1.7 / compat/0.1.5 (npm-Tags dsh-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ées compat/0.1.7 / compat/0.1.5 (tags npm dsh-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 congeladas compat/0.1.7 / compat/0.1.5 (etiquetas npm dsh-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 congelati compat/0.1.7 / compat/0.1.5 (tag npm dsh-0.1.7 / dsh-0.1.5).

License

MIT

内容来自项目 README(GitHub)↗

评论

评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。