**English** | [简体中文](README.md)
dsh-ppt-master-plus
# dsh-ppt-master-plus **Faithfully wraps the upstream [ppt-master](https://github.com/hugohe3/ppt-master) skill set as a [DeepSeek Harness](https://github.com/deepseek-ai) (DSH) plugin** — byte-for-byte vendored, zero rewriting, zero runtime dependencies, one-command upstream sync. The upstream skill set is a complete AI presentation workflow (generate / reconstruct / beautify PPTX, Brand·Style·Layout·Deck workspaces, native template filling). This wrapper rewrites none of it — it only **mounts it reliably into DSH**: registers the skills, exposes lifecycle tools, and adds venv interpreter isolation, a graphical configuration card and tool-visibility scoping. - **Zero rewriting**: the vendored `skills/ppt-master/` is **byte-identical** to the upstream release, passing upstream's `attribution_guard.py` integrity gate by construction; - **Zero runtime npm dependencies**: pure Node built-ins; the skill's Python dependencies are installed on demand by a lifecycle tool; - **Updatable**: `scripts/sync-upstream.mjs` syncs a new upstream release in one command (download → integrity gate → verify → replace → commit/tag/push); - **Isolatable interpreter**: optional venv mode gives upstream scripts a dedicated interpreter, landable on persistent volumes in containers; - **Graphical configuration**: ships its own client half — a configuration card on DSH's Plugins page (bilingual), saving **takes effect without a restart**. ## Architecture ```mermaid %%{init: {"flowchart": {"wrappingWidth": 320}}}%% flowchart TB UP["Upstream ppt-master
GitHub · MIT"]:::up SYNC["scripts/sync-upstream.mjs
download → integrity gate → replace"]:::tool VENDOR["skills/ppt-master/
byte-for-byte vendor"]:::artifact HOST["index.js
ctx.skills · ctx.tools.register"]:::code CARD["lib/client.js
Plugins-page config card"]:::code DSH["DeepSeek Harness
2 skills · 3 tools
+ config card"]:::host UP --> SYNC --> VENDOR --> HOST --> DSH CARD --> DSH classDef up fill:#d9a52122,stroke:#b8860b,stroke-width:1.5px,rx:6,ry:6 classDef tool fill:#4f6ef722,stroke:#4f6ef7,stroke-width:1.5px,rx:6,ry:6 classDef artifact fill:#2f9e7822,stroke:#2f9e78,stroke-width:1.5px,rx:6,ry:6 classDef code fill:#4f6ef722,stroke:#4f6ef7,stroke-width:1.5px,rx:6,ry:6 classDef host fill:#8c959f22,stroke:#8c959f,stroke-width:1.5px,rx:6,ry:6 ``` The skill surface is registered by `index.js` through `ctx.skills`: the vendored `ppt-master` skill plus an **in-memory, never-on-disk** entry skill `ppt-master-env` (interpreter routing entry). DSH injects the skill directory's absolute path via `resourceBase`, which the executing agent substitutes for upstream's `${SKILL_DIR}` convention — mechanically satisfying the hard rule in upstream's `SKILL.md`. ## Installation ### Prerequisites | Dependency | Purpose | Notes | |---|---|---| | **DeepSeek Harness** | Host runtime | The config card needs **DSH ≥ 0.2.0-rc.2**; older hosts degrade quietly to "no card" with no other impact | | **Node.js ≥ 20** | Plugin & tool runtime | Pure built-ins, no npm dependencies | | **Python ≥ 3.10** | Upstream scripts & integrity gate | POSIX uses `python3`; Windows tries `python3` → `py -3` → `python`. A working venv is recommended (venv mode needs its ensurepip) | | **pip** | Installing upstream Python deps | Always `python -m pip`; venv mode uses `/Scripts/pip.exe` (Windows) or `/bin/pip3` (POSIX), unaffected by PEP 668 | | **git** / **tar** | Sync script | Only needed when syncing upstream | ### Windows support - **Interpreter resolution**: `python3` → `py -3` → `python`, each probed and required to be ≥ 3.10. The Microsoft Store `python3.exe` stub (exit 49 / `WindowsApps` / `Microsoft Store`) is detected and gets install guidance instead of a misleading "no Python". - **venv layout**: `Scripts\python.exe` / `Scripts\pip.exe` on Windows, `bin/python3` / `bin/pip3` on POSIX; probing, creation, installation and diagnostics share one platform module (`lib/platform.js`). - **Install command**: always `python -m pip` (with the candidate prefix preserved, e.g. `py -3 -m pip …`); `pip3` is never assumed to be on PATH. - **`.env` path**: `ppt_master_check_env` reports the file that actually wins (session cwd → `SKILL_DIR` → package root → `~/.ppt-master`). - **Symlinks**: tests that need symlink creation are explicitly skipped on Windows; the product does not rely on symlinks. - **tar**: `verify-plugin` diagnostics and `sync-upstream` reports normalise paths; extraction works around GNU tar's drive-letter parsing (Git Bash) and still works with Windows' bundled bsdtar. ### Install into DSH ```bash # Option 1: install from GitHub (recommended) dsh plugin --profile add https://github.com/AlbertZJ/dsh-ppt-master-plus.git # Option 2: local path link (development machines) dsh plugin --profile add link:/path/to/dsh-ppt-master-plus ``` Restart the session after installing and the `ppt-master` skill becomes visible to agents; the client half (config card) is loaded by the host **once after a restart** — afterwards saving configuration **takes effect without restarts**. > Install size is about **65 MB**, almost entirely the byte-for-byte vendored upstream skill tree (templates and references), not runtime dependencies; the plugin itself has zero npm dependencies. ### First run 1. **Environment check**: call `ppt_master_check_env` — confirms interpreter readiness (including the Windows candidate fallback and Store-alias diagnosis), the integrity gate, installed Python dependencies, and the effective `.env` path. 2. **Install Python dependencies**: call `ppt_master_setup_deps` (idempotent), or run `python -m pip install -r skills/ppt-master/requirements.txt` manually. 3. **Configure `.env` (as needed)**: upstream image-generation scripts need an image backend. In your **session working directory** (position 1 of upstream's `.env` lookup order; the package root is the position-3 fallback) run `cp skills/ppt-master/.env.example .env` and fill in `IMAGE_BACKEND` plus the provider key/model per the comments inside (process environment variables work too). `.env` is gitignored; plugin tools never read or echo its contents. ## Lifecycle tools | Tool | Parameters | Behaviour | |---|---|---| | `ppt_master_info` | none | Plugin version, upstream version, absolute `SKILL_DIR`, upstream repo link. Read-only. | | `ppt_master_check_env` | none | Environment check: interpreter readiness (including Windows candidate fallback and Store-alias diagnosis), runs `attribution_guard.py`, probes Python dependency state, reports the effective `.env` path. Read-only. | | `ppt_master_setup_deps` | `user?`, `breakSystemPackages?` | Idempotent `requirements.txt` install, re-runs the check afterwards. **The only tool with side effects**; venv creation/removal happens only here. | All three tools are **venv-aware** (payloads carry a `venv` section; with `venv.enabled=true` the tool descriptions gain an interpreter hint). `user` / `breakSystemPackages` are **effective in system mode only** — ignored in venv mode, noted in the response. ## Configuration The plugin declares a native cordis Config — two key groups, every leaf `.volatile()`. Saving through the **Plugins-page card** takes the host's volatile fast path and **takes effect without a restart** (all three tools re-read the configuration on every call, `venv.*` exactly like `scope.*`; the one exception is the synthesized entry skill `ppt-master-env`, whose body is a registration-time snapshot and whose own footnote points at the two live tools); hand-editing the profile `cordis.patch.yml` **requires restarting DSH**. The two channels are equivalent — whichever writes first wins. ### The Plugins-page card (preferred entry) GUI sidebar **Plugins → Installed → `dsh-ppt-master-plus`** → the card on the package detail page: three venv fields (`enabled` / `path` / `oldPathPolicy`), a "Tool visibility scope" section, and a version block — copy bilingual, following the interface language. In memory-mode sessions the card states explicitly that nothing will be written to the host configuration. ### venv isolation | Key | Values | Default | |---|---|---| | `venv.enabled` | enable venv interpreter isolation | `false` | | `venv.path` | venv directory (absolute or `~`-prefixed; relative paths are invalid) | `~/.ppt-master/venv` | | `venv.oldPathPolicy` | what happens to the old venv after a path change: `keep` / `delete` | `keep` | - **Lazy creation**: changing configuration has zero side effects; creation/removal happens only in `ppt_master_setup_deps`. - **Container advice**: point `venv.path` at a persistent volume (e.g. `/dsh-home/.ppt-master/venv`) — a venv's internal symlinks reference absolute container paths, so whether it survives an image change depends on the image staying the same. - **Damage recovery**: delete and recreate (`rm -rf `, then re-run `setup_deps`); a half-built venv (missing `Scriptspip.exe` / `bin/pip3`) likewise — install `python3-venv` first if ensurepip is missing (python.org's Windows installer ships ensurepip). - **Deletion safety**: automatic deletion only touches old venvs that carry an **ownership marker** and satisfy the safety conditions; `enabled=false` deletes nothing; **do not store user data inside the venv directory**. Both kinds of orphan directories (unmarked / marked-but-unregistered) need manual `rm -rf`. - **Configuration hot reload**: all three tools re-read `venv.*` on every call, so a card save applies immediately (no restart). The body of the synthesized entry skill `ppt-master-env` is a **registration-time snapshot** — after changing `venv.*` it still shows the old routing guidance; defer to `ppt_master_info` / `ppt_master_check_env`, which its footnote names (restarting DSH refreshes the body too). - Full decision criteria and implementation details: [AGENTS.md](AGENTS.md) §6. ### Tool visibility scope (global / selected workspaces) The three `ppt_master_*` tools are registered **globally** by default. If most of your workspaces have nothing to do with PPT, the scope keys remove them from those workspaces' tool tables **for real** (the host's assembly-layer `tools.restrict`, not a front-end filter): | Key | Values | Default | |---|---|---| | `scope.mode` | `global` (every workspace) / `selected` (only the listed ones) | `global` | | `scope.workspaceIds` | array of workspace id strings | `[]` | Under `selected`: a session's ownership is resolved by "workspace `sessionIds` membership → canonical path of the session `cwd`"; visible only when resolved **and** listed — **sessions belonging to no workspace stay invisible**. Degradation (an explicit narrowing intent is never silently widened): missing judgement services → deny under the strictest reading plus one `console.warn`; a transient registry read failure keeps the previous round's judgement; a host without `tools.restrict` degrades to execution-layer denial only. Configure via the card's mode radio + workspace checklist (fed by the host `workspaces` service); saving takes effect immediately. Host floor: besides the config card, `scope.mode=selected` also depends on the host injecting the `agents` / `workspaceRegistry` services and the `tools.restrict` / `tools.guard` capabilities; when any is missing the scope falls back or denies under the readings above (never silently widened), with no impact on `global` mode or the rest of the plugin. Known limitations: only **tools** are narrowed, not the skill entry; judgement uses the `cwd` at session creation; ids of deleted workspaces are ignored; a restriction layer may linger if the host throws during release (a restart clears it); the marketplace screenshot `assets/screenshot-1-config-card.png` awaits regeneration (the card gained the scope section). ### Profile patch (the equivalent channel) Edit the profile's `cordis.patch.yml` and append (**write every field** — a patch `config` replaces wholesale; **restart DSH afterwards**): ```yaml - id: dsh-ppt-master-plus config: venv: enabled: true path: /dsh-home/.ppt-master/venv oldPathPolicy: keep scope: mode: selected workspaceIds: - b6ef89f7-74a6-4e4f-84eb-07581e390020 ``` After a plugin upgrade adds new configuration fields, compare and complete existing patch entries (or simply re-save once on the card) — otherwise the new fields fall back to defaults. ## Restart boundaries and diagnostics **What needs a restart**: - Saving configuration on the card — **no** (volatile fast path; the tool side applies immediately, `venv.*` included). The **body** of the synthesized entry skill `ppt-master-env` is a registration-time snapshot and does not rewrite itself — its own footnote defers live state to `ppt_master_info` / `ppt_master_check_env`; - Editing only `lib/client.js` — **no** (host hot-updates via stat polling, ~500 ms); - Editing `package.json`'s `dsh.client` / `exports["./client"]` declarations, or the profile patch by hand — **yes**. **Card missing / unavailable** — check in order: ① just edited the `package.json` declaration surface? restart DSH (most common); ② does the host Plugins page provide the `plugins.bundle.config` slot; ③ the card shows "configuration channel not connected" = host lacks the `configForms` service (optional wiring, everything else unaffected); ④ old hosts that ignore `dsh.client` degrade quietly — plugin functionality is unaffected, configure via profile patch or upgrade the host. **Other**: a failed plugin load that takes the skill surface down with it is usually `@deepseek-ai/schemastery` controlled-resolution failure — confirm the package exists in the host profile's `node_modules` and that `DSH_NODE_MODULES` / `DSH_PROFILE_DIR` / `DSH_HOME` point at it (details in [AGENTS.md](AGENTS.md) §3). **Missing entry skill**: if the host rejects the synthetic candidate without `resourceBase`, only the entry skill is absent — the vendored skill and the tools are unaffected. ## Syncing a new upstream release ```bash node scripts/sync-upstream.mjs [options] ``` | Option | Meaning | |---|---| | `--ref ` | Upstream ref (default: latest semver release tag) | | `--repo ` | Upstream repository URL (default `https://github.com/hugohe3/ppt-master.git`) | | `--refresh` | Ignore the `.upstream/` cache and re-download | | `--confirm-structural` | Structural changes confirmed by a human; force the automatic path | | `--skip-guard` | Skip running `attribution_guard.py` (must combine with `--no-push` or `--dry-run`) | | `--no-push` | Local commit + tag only, no push | | `--dry-run` | Print what would happen | Flow: resolve the latest tag → download (or reuse cache) → integrity gate → structural-change detection → automatic path: verification precedes replacement → replace `skills/` → bump the version (auto-rewriting the `lib/client.js` version constants) → commit + tag `v` → push. **Structural changes 🔴** (skill dirs added/removed, renamed, `metadata.version` missing …) stop the run with a report (exit code 2, written to `sync-report.txt` at the repo root); assess manually and re-run with `--confirm-structural`. **Push credentials**: prefer a git credential helper that `git credential fill` can resolve (GitHub and GitLab alike); `DSH_PPT_GITLAB_PAT` remains available for GitLab mirrors. If missing, the push step fails with exit code 6 and prints guidance. **Versioning**: `package.json` mirrors the upstream version (e.g. `6.7.1`); wrapper-only changes append an `-rN` suffix. Exit codes: `0` ok/up-to-date · `1` usage · `2` structural change awaiting a human · `3` integrity gate · `4` verification · `5` network/source · `6` push/tag conflict · `7` missing toolchain. ## Repository layout ``` dsh-ppt-master-plus/ ├── package.json / cordis.patch.yml # DSH plugin manifest & bundle-layer patch ├── index.js # plugin entry ├── lib/ # client half / tools / venv / skill provider / scope ├── skills/ppt-master/ # ★ upstream vendor tree (byte-for-byte) ├── scripts/ # sync-upstream / verify-plugin / check-dsh-compat ├── tests/ # full node:test suite (727 cases) ├── docs/superpowers/ # design & plan documents (development history) ├── .github/ # CI and issue/PR templates └── README / AGENTS.md / CONTRIBUTING.md / NOTICE / LICENSE ``` ## Development flow (GitHub Flow) `main` is protected — **no direct pushes**. Every change goes **Issue → branch → PR → squash merge**; commit messages use conventional prefixes. Details in [CONTRIBUTING.md](CONTRIBUTING.md); agent-facing mechanism notes, the test map and version bookkeeping live in [AGENTS.md](AGENTS.md). ## Local verification (development) ```bash node scripts/check-dsh-compat.mjs # contract check: spec §7.7 six (+⑦) design-precondition probes node --test tests/*.test.mjs # full suite (727/715/12 skipped in the stub-SDK environment) node scripts/verify-plugin.mjs --upstream .upstream/refs/tags/@ # integrity check (needs the cache dir) ``` Machines without the host SDK (CI included): build the default stub tree with `node tests/helpers/stub-sdk.mjs .ci-stub`, then run the first two commands with `DSH_NODE_MODULES=$PWD/.ci-stub/node_modules` (expected: 727/715/12 skipped — skips are declared explicitly, e.g. symlink creation is unavailable on default Windows); mechanisms and red-light signatures in [AGENTS.md](AGENTS.md) §4, CI in `.github/workflows/ci.yml`. ## Version history | Version (tag) | Notes | |---|---| | `v6.7.0` | Initial delivery: vendored upstream v6.7.0 + skill provider + three lifecycle tools + three scripts | | `v6.7.0-r1` … `r2` | Wrapper revisions (review-fix waves: sync-script robustness) | | `v6.7.0-r3` | venv interpreter isolation + Plugins-page config card + GitHub release surface | | `v6.7.1` | Upstream sync: vendored v6.7.1 (byte-for-byte) | | `v6.7.1-r1` | Tool visibility scope (two scope keys + assembly-layer removal + guard backstop) | | `v6.7.1-r2` | Review-fix wave: scope runtime hardening (`safeString` / injection watchdog / disposed cleanup / single refresh per round) + card checkbox disabled-on-missing-baseline and read-only styling + stronger contract probes + single-pass strict resolution criterion | | `v6.7.1-r3` | venv configuration is now **re-read live**: a card save applies to all three tools immediately instead of an apply-time snapshot (design R8 / issue #16); an invalid path warns at save time | | `v6.7.3-r1` | Wrapper revision (starting point of this repository): **Windows runtime support** (`python3` → `py -3` → `python`, `Scriptspython.exe` / `Scriptspip.exe`, `python -m pip`, Microsoft Store alias diagnosis), effective `.env` path in `check_env`, normalised diagnostics/reports in `verify-plugin` and `sync-upstream`, GNU tar drive-letter workaround; suite grows to 727 tests | | `v6.7.3` | Upstream sync: vendored v6.7.3 (byte-for-byte). Carries the v6.7.2 "stop losing or overwriting content silently" batch (skill-only installs place projects in the working folder again, PDF tables no longer rewritten against one sample paper, HTML/`.txt` decoded by declared charset, same-titled batches no longer overwrite each other, whole-word image search, native-chart part-name collisions, formula MCE fallback so WPS/LibreOffice are not blank) and the v6.7.3 Edit Native round-trip fixes; also fixes `verify-plugin`'s `baseName` for backslash paths (no more false failure of check ⑥ on Windows) | > Versioning: the `base` mirrors upstream releases; wrapper revisions append `-rN`. Itemized details in [AGENTS.md](AGENTS.md) §5. ## Acknowledgements and licence - Upstream project: [hugohe3/ppt-master](https://github.com/hugohe3/ppt-master) (MIT, © 2025-2026 Hugo He) — every capability of this wrapper comes from the upstream skill set; many thanks to the author. - Wrapper source: [SAXEM1997/dsh-ppt-master-wrapper](https://github.com/SAXEM1997/dsh-ppt-master-wrapper) (MIT, © 2026 dsh-ppt-master-wrapper contributors) — this repository is derived from it and adds Windows support plus the revisions above. - **Dual LICENSE attribution**: the root [`LICENSE`](LICENSE) is this project's own MIT licence; the vendored `skills/ppt-master/LICENSE` is the **upstream original, preserved byte-for-byte** (guarded by the integrity gate — do not modify). The full upstream copyright notice is in [`NOTICE`](NOTICE); the vendored `SPONSORS*.md` files are preserved likewise — consider sponsoring the original author. MIT, see [LICENSE](LICENSE).