slidemind 0.2.3 → 0.2.4

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidemind",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Connect Claude Code to the slidemind PowerPoint add-in — build and edit native, on-brand PowerPoint decks against the active corporate design, from the terminal.",
5
5
  "author": {
6
6
  "name": "statworx",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slidemind",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Connect Codex to the slidemind PowerPoint add-in — build and edit native, on-brand PowerPoint decks against the active corporate design. Requires the slidemind CLI (npm install -g slidemind); the skills explain the install when it is missing.",
5
5
  "author": {
6
6
  "name": "statworx",
package/AGENTS.md CHANGED
@@ -144,8 +144,9 @@ slidemind/
144
144
  │ │ composition/layouts/authoring/build-export) are READ from the materialized
145
145
  │ │ bundle — owned by the add-in.
146
146
  │ └── search/
147
- │ └── SKILL.md engine-search + slide-reuse skill (installs as slidemind-search): host gate +
148
- │ discover → search → pick → reuse loop + vocabulary→CLI command map. The craft is
147
+ │ └── SKILL.md engine-search + slide-reuse skill (installs as slidemind-search): host gate
148
+ │ (insert-slide + reading an open deck only) + discover → search → pick → reuse
149
+ │ loop + vocabulary→CLI command map. The craft is
149
150
  │ READ from the bundle's workflow/search.md — owned by the add-in.
150
151
  ├── src/ implementation of the slidemind CLI
151
152
  │ ├── bridge/ add-in local-bridge: client.mjs, bundle.mjs (materialize), build-and-push.mjs (server render; native-slide splicing), engine-download.mjs + recolor.mjs (image/icon fetch + recolour),
@@ -166,8 +167,8 @@ We **do not** ship separate slash commands. Earlier versions had a top-level `co
166
167
  ## CLI surface
167
168
 
168
169
  ```bash
169
- slidemind ready [deck] # one-shot session start: connection ladder + design resolution + bundle download + deck bind; --to/--force/--connect-only/--json (HOST REQUIRED)
170
- slidemind doctor # read-only connection diagnostics (ordered next-action ladder; does NOT materialize or bind — `ready` is the preflight)
170
+ slidemind ready [deck] # one-shot session start: connection ladder + design resolution + bundle download + deck bind; --to/--brand/--force/--connect-only/--json (a BOUND deck, an explicit --brand, or a single listed design readies with PowerPoint closed)
171
+ slidemind doctor # read-only diagnostics on TWO independent ladders — backend authoring (session/backend/version/engines) and live PowerPoint (windows/pane); does NOT materialize or bind — `ready` is the preflight
171
172
  slidemind presentations # list PowerPoint windows registered with the add-in
172
173
  slidemind read [presId|file.pptx] # pull an open presentation's content (presId; HOST REQUIRED) OR read a local .pptx on disk (file path; host-free) — same per-slide output (--mode summary|raw)
173
174
  slidemind download-bundle [deck] # materialize the active corporate design's bundle locally
@@ -175,15 +176,16 @@ slidemind new <name> # scaffold ./decks/<name>/ (auto-binds to the
175
176
  slidemind plan <deck> # plan sign-off gate on <deck>/plan.md; markdown editor + live preview + overall feedback, blocks for approve/comments (host-free)
176
177
  slidemind build <deck> # build self-contained HTML preview
177
178
  slidemind review <deck> # spatial preview-review gate; blocks for approve/comments (host-free)
178
- slidemind build-pptx <deck> # render native .pptx via the add-in (HOST REQUIRED)
179
+ slidemind build-pptx <deck> # compose: add-in; template pack: host-free with --pack <dir>
180
+ slidemind inspect-template-deck <deck> # normalized pack model for pack-owned validation; --pack <dir> --json
179
181
  slidemind view-draft <deck> # render the deck's slides to per-slide PNGs so the agent can look before review; no push, no .pptx (host-free once the bundle is materialized)
180
182
  slidemind push <deck> # render + push slides into a running PowerPoint (HOST REQUIRED)
181
- slidemind ls engines # list the live engine catalog (image + slide; --type/--subtype) (HOST REQUIRED)
182
- slidemind search "<query>" # search an engine for imagery or slides (--engine/--intent/--top) (HOST REQUIRED)
183
+ slidemind ls engines # list the live engine catalog (image + slide; --type/--subtype) (pane-free on add-ins with engineRoutes; HOST REQUIRED on older ones)
184
+ slidemind search "<query>" # search an engine for imagery or slides (--engine/--intent/--top/--deck) (pane-free on add-ins with engineRoutes; HOST REQUIRED on older ones)
183
185
  slidemind insert-slide [opts] # reuse found slide(s) live into a window (--search/--pick/--to/--at) (HOST REQUIRED)
184
186
  slidemind imagen "<prompt>" [opts] # generate ONE image via the add-in's image model into <deck>/assets/ (--deck/--out/--size/--quality/--brand-style; connected backend, pane-free)
185
187
  slidemind setup <claim> # one-command onboarding from the add-in's Connect CLI button: redeem the claim + npm install -g + skills + ready (--for/--no-install/--no-ready/--json)
186
- slidemind add-slide [opts] # fold slide(s) into a deck as native .pptx — from an engine (--search/--pick/--deck/--to/--at; HOST REQUIRED) or a local file (--from <file.pptx>/--pick/--deck/--at; host-free, mutually exclusive with --search)
188
+ slidemind add-slide [opts] # fold slide(s) into a deck as native .pptx — from an engine (--search/--pick/--deck/--to/--at/--json; pane-free on add-ins with engineRoutes) or a local file (--from <file.pptx>/--pick/--deck/--at; host-free, mutually exclusive with --search)
187
189
  slidemind whoami # list every connected environment (* = default)
188
190
  slidemind use <url|env> # set the default environment
189
191
  slidemind logout [url|env] # unpair one environment (--all unpairs every one)
@@ -195,7 +197,15 @@ slidemind uninstall --for <target> # remove the skill (also clears the bundle
195
197
 
196
198
  **Multi-environment sessions.** The CLI stores one session **per backend** (`~/.config/slidemind/session.json`, v2 `{version, sessions[], default}`; the legacy single-record v1 shape is migrated on read). Connect once per environment (local / dev / prod) and every command **fans out** across all connected backends, tags each open window with its `env`, and **routes by the presentation's origin backend** automatically — no manual switching. Adding an environment is easiest with `slidemind setup <claim> --no-install --for none` — the claim carries its own backend, so nothing has to be typed or configured. There is no other way in: without a claim the CLI has no backend to talk to. Later commands may scope an existing session with `--backend <url|env>` / `SLIDEMIND_BACKEND`. A normal user connects exactly one backend.
197
199
 
198
- **The design truth lives in the add-in, not the CLI.** The `.pptx` is rendered server-side over the local bridge (no local exporter), the corporate design is fetched as a bundle, brand imagery comes from the add-in's engine, and slide reuse (extract / insert / splice) executes in the add-in too. So `create`/`build-pptx`/`push`/`ls engines`/`search`/`insert-slide`/`add-slide` all hard-require an **open PowerPoint host with the slidemind add-in and an active corporate design**. The engine-search + slide-reuse wire contract is in `docs/slidemind-cli-connect/11-engine-search-slide-reuse.md`; see `docs/slidemind-cli-connect/` for the rest.
200
+ **The design truth lives in the add-in, not the CLI.** The `.pptx` is rendered server-side over the local bridge (no local exporter), the corporate design is fetched as a bundle, brand imagery comes from the add-in's engine, and slide reuse (extract / insert / splice) executes in the add-in too. So `create`/`build-pptx`/`push`/`ls engines`/`search`/`insert-slide`/`add-slide` all need the **slidemind add-in with an active corporate design** behind them. The engine-search + slide-reuse wire contract is in `docs/slidemind-cli-connect/11-engine-search-slide-reuse.md`; see `docs/slidemind-cli-connect/` for the rest.
201
+
202
+ **Engine ops are moving off the task pane.** An add-in that advertises `engineRoutes` in `/api/cli/capabilities` answers discovery, search, download and slide extraction on the CLI session itself (`GET /api/cli/engines`, `POST /api/cli/searches`, `GET /api/cli/searches/:id/results/:sel/{image,thumbnail,slide,source-presentation}`), so those commands need **no PowerPoint window at all** — the searchId is server-owned, `--to` becomes a no-op, and multi-environment routing goes by the deck's bound design (`.bundle-ref.json`), never by an open window's origin. Older add-ins keep relaying every one of them through the pane (`client.resolveEngineBackend()` returns null → `requirePaneHost()`), so **never remove the pane path and never raise `minCliVersion` for this**. Live `insert-slide` and reading an unsaved open deck stay pane-bound — that is Office.js physics, but even there the *extraction* backend is the one that **minted the searchId** (`client.resolveSearchBackend()`), never the target window's origin: with two environments connected those differ, and spending a server-owned id on the wrong one 404s as an "expired search" no re-search can clear.
203
+
204
+ When the backend's permission snapshot ages out, corpus search (only) answers `403 permissions_stale`, rendered through `client.permissionsStaleBlocker(err)` as one user-actionable line — but the snapshot backs the **pane-free path only**, since a live pane signs every request with a browser token that is strictly fresher. So when a pane-ready window is open, `search` **relays through it** instead of blocking (one stderr note; the searchId is then the pane's, and every next step names that window), and the ops that cannot be replayed pane-side — anything bound to an opaque `searchId` — name that open pane as the route to a fresh search rather than telling the user to open an add-in that is already open. `slidemind ls engines` is the exception: `GET /api/cli/engines` is the catalog route on both add-in generations, so there is no second route to retry on and only the message widens. Plan: `docs/slidemind-cli-connect/13-pane-free-authoring.md`.
205
+
206
+ **The two ops that stay pane-bound self-heal a presId churn.** Every pane reconnect mints a NEW presId for the same window, so `push`'s insert and `insert-slide` re-list the registry and re-match the window before giving up: `waitForPaneReady` matches the same presId, then `fileName`+`brandId`, then — when a Save-As renamed the window mid-run — the **design fingerprint alone** (`presFP == brandId`), and only when exactly one connected window carries it (two windows on one design are indistinguishable, and pushing into the wrong one is worse than waiting). `engineOpWithPaneWait` takes that window identity plus an opt-in `retargetOnMissing`, which **only the live insert sets**: for an idempotent engine read a 404 is the search record talking, not the window, so waiting on the registry would just stall the agent (`isMissingPresentationError` keeps a coded 404 like `unknown_search` out of it). Both retries re-send the SAME `operationId`, so the pane-side dedup makes them safe; both retry exactly ONCE and then surface the wake-PowerPoint blocker — `push` by saving the rendered `.pptx` next to the deck rather than throwing the bytes away, `insert-slide` by naming the click and the window-free `add-slide` alternative.
207
+
208
+ **The readiness ladder is two ladders.** `bin/slidemind.mjs` authors them once: `backendBlocker(pub)` (paired → every backend unreachable → CLI below the floor) is what render, bundle and the pane-free engine routes ride on, and `paneBlocker(pub)` (no window → not render-ready → pane suspended) governs only push's insert, `insert-slide` and reading an open presentation. `connectionBlocker = backendBlocker ?? paneBlocker` keeps every pre-existing message byte-identical, `doctor` reports the two separately (`authoring` / `host` in `--json`) so an agent stops reading "pane gone" as "cannot work", and `permissions_stale` is reported as a **degradation** next to the authoring ladder — never a rung, because it must not gate render or bundle. `doctor`'s engine-search line reads the same `capabilities.permissionsStale` flag off `/api/cli/readiness`, so `doctor`, `ls engines` and `search` name ONE cause for that one condition instead of three. `ready`'s ladder for a **bound** deck is session → bundle freshness → (informational) engine + pane reachability: with an empty registry it materializes straight over the brand route instead of sitting out the hydration wait, and when a window IS registered the open add-in stays the design source of truth. An unbound deck with no window resolves through `GET /api/cli/brands` (capability `brandsList`, `client.listBrands()`): one design binds automatically, several stop with `ambiguous_brand` naming `--brand <presFP>`. `client.engineReachability({ backends })` is the engine half of both reports — env labels only, never a URL.
199
209
 
200
210
  ## External skill packs (this repo ships none)
201
211
 
@@ -211,7 +221,18 @@ Some decks build from a **template pack** (`mode: "fill-template"` in the pack's
211
221
 
212
222
  A pack that declares no `components.canonical` fails loudly in `layoutNumber()` — returning null instead would silently demote every master-backed slide to freeform and build a deck that quietly lost its template.
213
223
 
214
- Packs resolve through `locateSkillDir()` (`src/builders/resolve-skill.mjs`): `$SLIDEMIND_SKILLS_DIR/<name>` → `~/.config/slidemind/skills/<name>` → `<package>/skills/<name>` → the **harness** skill and plugin dirs (`~/.claude`, `~/.codex`, opencode; both `<name>` and `slidemind-<name>`). That last tier is what makes every distribution channel work — a plugin or admin upload lands the pack in a harness directory, never in ours — and it ranks *after* the package so this CLI's own skills are never shadowed by a stale copy.
224
+ The preferred integration is explicit: `slidemind build-pptx <deck> --pack <exact-directory>`.
225
+ The pack directory is resolved by its owning plugin, so the CLI does not need to
226
+ know the plugin name or any harness cache layout. Pack-owned validation can use
227
+ `slidemind inspect-template-deck <deck> --pack <exact-directory> --json`, which
228
+ returns a normalized sequence without running domain-specific rules.
229
+
230
+ For compatibility, direct builds still resolve through `locateSkillDir()`
231
+ (`src/builders/resolve-skill.mjs`): `$SLIDEMIND_SKILLS_DIR/<name>` →
232
+ `~/.config/slidemind/skills/<name>` → `<package>/skills/<name>` → the **harness**
233
+ skill and plugin dirs (`~/.claude`, `~/.codex`, opencode; both `<name>` and
234
+ `slidemind-<name>`). This fallback remains until external packs migrate to
235
+ explicit paths.
215
236
 
216
237
  Pack-dependent integration tests belong in the pack's own repo, not here.
217
238
 
package/README.md CHANGED
@@ -238,6 +238,7 @@ slidemind new my-deck # scaffold ./decks/my-deck/ (auto-binds to the
238
238
  slidemind build my-deck # build a self-contained HTML preview (offline)
239
239
  slidemind review my-deck # spatial preview review: leave comments / approve in the browser (offline)
240
240
  slidemind build-pptx my-deck # render a native .pptx via the add-in (host required)
241
+ # template packs may pass --pack <exact-pack-directory>
241
242
  slidemind push my-deck # stream slides straight into an open PowerPoint (host required)
242
243
  slidemind read <presId|file.pptx> # read an open presentation (host required) or a local .pptx on disk (host-free)
243
244
  slidemind ls engines # list the active design's image + slide engines (host required)
@@ -279,6 +280,9 @@ slidemind plan <deck> Plan sign-off gate on <deck>/plan.md; blocks fo
279
280
  slidemind build <deck> Build a self-contained HTML preview (offline)
280
281
  slidemind review <deck> Spatial preview review; blocks for approve/comments (offline)
281
282
  slidemind build-pptx <deck> Render a native .pptx via the add-in (host required)
283
+ --pack <dir> for an explicit fill-template pack
284
+ slidemind inspect-template-deck <deck> Emit a normalized template-deck model for pack validation
285
+ --pack <dir> --json [--allow-unrendered-freeform]
282
286
  slidemind view-draft <deck> Render slides to per-slide PNGs, no push — look before review (offline once cached)
283
287
  --to <presId> --out <dir> --open
284
288
  slidemind push <deck> Build + push slides into an open PowerPoint (host required)