feat(background+pdf): subfolder context, per-file selection, PDF extraction, and multimodal improvements #21

Closed
casper-stevens wants to merge 0 commits from development_link_pdf_extracted_markdown_v2 into development
Member

Warning

This branch requires lhumina_code/hero_lib#125 to compile.
generator.rs uses AiClient::image_request(), which was introduced in that PR.
Do not merge until hero_lib#125 has landed.


Summary

This PR covers the full scope of the background-panel and PDF-extraction feature cycle. An earlier PR (#20) was closed as stale — it described only the initial background subfolder work while the branch had grown to include PDF extraction, link support, and context sync fixes. This replacement covers everything at the current commit.

Changes

Background panel

  • Recursive subfolder support — nested folders render in a tree; the root section appears even when there are no subfolders
  • Per-file context selection in the create-slide modal and instruct panel — expand any folder to pick individual files
  • Select-all / deselect-all checkbox in both context sections
  • Background context is kept in sync when switching decks so the generate-slide context menu always has a valid selection even before the modal is opened (_bgSelectionDeckPath guard in dashboard.js)

PDF extraction

  • discovery.rs: detect AI-auto-extracted .md companions for PDFs via the <!-- Auto-extracted from marker; expose has_extracted_md / is_extracted flags on BackgroundFile; exclude extracted companions from folder file counts
  • types.rs: add has_extracted_md and is_extracted fields to BackgroundFile
  • rpc.rs / routes.rs: new endpoints wired for PDF extraction

Multimodal image improvements

  • Images are normalised to PNG before sending to AI (fixes silent drops with some providers on JPEG/WebP)
  • Smarter image directive: model is told to reproduce verbatim, extract data, or use as style reference depending on slide intent
  • Native passthrough for small PNG/JPEG files within dimension limits to avoid unnecessary re-encoding

Rhai / generator

  • deck_module.rs / slide_module.rs: new bindings for link and PDF extraction features
  • generate_slide.rhai: updated image directive handling
  • generate_job.rs / agent.rs: per-file selection threaded through both create and instruct pipelines

Known shortcomings (see ADR 0003)

  • The two files previously in merge-conflict state (discovery.rs, dashboard.js) had their conflicts resolved in the working tree but were left unstaged — they were staged and committed in a single broad commit rather than as a focused resolution commit.
  • The branch name (development_link_pdf_extracted_markdown_v2) understates the scope of changes.
  • Ephemeral test directories (test/, test2/, examples/dasd/) are present but untracked; .gitignore should be updated.

PRD: Background Context Transparency & UX

docs/prd/0001-background-context-transparency.md — Status: draft

The background context system works correctly under the hood but is opaque to users. This PRD addresses seven distinct failure modes to make the system legible and trustworthy.

Goals

  • A new user uploading a PDF understands immediately that extraction is required before it contributes to generation.
  • A user who configures a context selection can always see what is active without opening a modal.
  • Silent failures (multimodal fallback, image resizing) surface as visible feedback.
  • "Generate All Slides" respects the user's context selection.

Functional Requirements (selected)

ID Requirement Priority
FR1 PDF files without an extracted .md companion show a distinct visual state (muted icon + warning badge) in the background panel. Must
FR2 Hovering an unextracted PDF shows a tooltip: "Not yet contributing to generation. Right-click → Extract .md to activate." Must
FR3 On first upload of a PDF, an inline toast informs the user that extraction is required. Must
FR5 "Generate All Slides" uses the same active context selection as individual slide generation. Must
FR6 A compact context summary indicator is shown in the slides toolbar when the active deck has background content. Must
FR7 Clicking the context indicator opens the context selection UI as a persistent popover. Must
FR8 The context selection is persisted to localStorage keyed by deck path. Must
FR16 If the multimodal image generation call fails and the system falls back to text-only, a persistent warning badge is shown on the affected slide card. Must

Full requirement list in docs/prd/0001-background-context-transparency.md.

Open questions

  • FR15 (preprocessing metadata): requires a signature change to encode_image_for_model. Separate PR or bundle?
  • FR7 (context popover): replace or sit alongside the existing modal context sections?

ADR-0001: Generate All Slides respects the active context selection

docs/adr/0001-generate-all-uses-active-selection.md — Status: accepted

Problem: "Generate All Slides" bypassed the context selection and sent all background folders to every job. Individual slide generation respected the selection. This asymmetry silently overrode explicit user configuration.

Decision: Single button, respects selection (Option A). "Generate All Slides" uses the same active selection as individual generation. A context summary in the toolbar (FR6) makes the active selection visible before clicking.

Option B (two explicit buttons) was rejected — adds UI complexity for an advanced workflow most users never need. Option C (do nothing) perpetuates a silent override.


ADR-0002: Context selection persists to localStorage per deck path

docs/adr/0002-context-selection-localStorage-persistence.md — Status: accepted

Problem: The active context selection lived only in JavaScript memory — lost on reload, lost on tab close, reset on deck change.

Decision: localStorage per deck path with 24-hour expiry (Option A). Covers same-session reload friction without risking stale selections from previous days. Fails silently if storage is unavailable.

Storage key: hero_slides_context_selection_v1__{base64(deck_path)}


ADR-0003: PR process shortcomings on this feature branch

docs/adr/0003-pr-process-shortcomings-background-pdf-feature-branch.md — Status: accepted

Five process mistakes made during this cycle, recorded so they are not repeated:

  1. Stale PR left open while branch diverged — PR #20 was opened for background subfolder work; branch grew to include PDF extraction without replacing the PR.
  2. Merge conflicts left unstageddiscovery.rs and dashboard.js had conflicts resolved in the working tree but git add was never run; index remained broken.
  3. Broad catch-up commit — all pending changes bundled into one 685-insertion commit, conflating conflict resolution with new feature work.
  4. Branch name understated scopedevelopment_link_pdf_extracted_markdown_v2 implies only PDF/link work; actual scope included background subfolders, context sync, select-all UI, and more.
  5. Untracked work directories not gitignoredtest/, test2/, examples/dasd/ left as noise in every git status.

Closes #7


Warning

Do not merge until lhumina_code/hero_lib#125 has landed.
The multimodal render path in generator.rs depends on AiClient::image_request() from that PR.
Merging against an older hero_lib will break the build.

> [!WARNING] > **This branch requires [lhumina_code/hero_lib#125](https://forge.ourworld.tf/lhumina_code/hero_lib/pulls/125) to compile.** > `generator.rs` uses `AiClient::image_request()`, which was introduced in that PR. > Do not merge until hero_lib#125 has landed. --- ## Summary This PR covers the full scope of the background-panel and PDF-extraction feature cycle. An earlier PR (#20) was closed as stale — it described only the initial background subfolder work while the branch had grown to include PDF extraction, link support, and context sync fixes. This replacement covers everything at the current commit. ## Changes ### Background panel - Recursive subfolder support — nested folders render in a tree; the root section appears even when there are no subfolders - Per-file context selection in the create-slide modal and instruct panel — expand any folder to pick individual files - Select-all / deselect-all checkbox in both context sections - Background context is kept in sync when switching decks so the generate-slide context menu always has a valid selection even before the modal is opened (`_bgSelectionDeckPath` guard in `dashboard.js`) ### PDF extraction - `discovery.rs`: detect AI-auto-extracted `.md` companions for PDFs via the `<!-- Auto-extracted from` marker; expose `has_extracted_md` / `is_extracted` flags on `BackgroundFile`; exclude extracted companions from folder file counts - `types.rs`: add `has_extracted_md` and `is_extracted` fields to `BackgroundFile` - `rpc.rs` / `routes.rs`: new endpoints wired for PDF extraction ### Multimodal image improvements - Images are normalised to PNG before sending to AI (fixes silent drops with some providers on JPEG/WebP) - Smarter image directive: model is told to reproduce verbatim, extract data, or use as style reference depending on slide intent - Native passthrough for small PNG/JPEG files within dimension limits to avoid unnecessary re-encoding ### Rhai / generator - `deck_module.rs` / `slide_module.rs`: new bindings for link and PDF extraction features - `generate_slide.rhai`: updated image directive handling - `generate_job.rs` / `agent.rs`: per-file selection threaded through both create and instruct pipelines ## Known shortcomings (see ADR 0003) - The two files previously in merge-conflict state (`discovery.rs`, `dashboard.js`) had their conflicts resolved in the working tree but were left unstaged — they were staged and committed in a single broad commit rather than as a focused resolution commit. - The branch name (`development_link_pdf_extracted_markdown_v2`) understates the scope of changes. - Ephemeral test directories (`test/`, `test2/`, `examples/dasd/`) are present but untracked; `.gitignore` should be updated. --- ## PRD: Background Context Transparency & UX > `docs/prd/0001-background-context-transparency.md` — Status: draft The background context system works correctly under the hood but is opaque to users. This PRD addresses seven distinct failure modes to make the system legible and trustworthy. **Goals** - A new user uploading a PDF understands immediately that extraction is required before it contributes to generation. - A user who configures a context selection can always see what is active without opening a modal. - Silent failures (multimodal fallback, image resizing) surface as visible feedback. - "Generate All Slides" respects the user's context selection. **Functional Requirements (selected)** | ID | Requirement | Priority | |----|-------------|----------| | FR1 | PDF files without an extracted `.md` companion show a distinct visual state (muted icon + warning badge) in the background panel. | Must | | FR2 | Hovering an unextracted PDF shows a tooltip: "Not yet contributing to generation. Right-click → Extract .md to activate." | Must | | FR3 | On first upload of a PDF, an inline toast informs the user that extraction is required. | Must | | FR5 | "Generate All Slides" uses the same active context selection as individual slide generation. | Must | | FR6 | A compact context summary indicator is shown in the slides toolbar when the active deck has background content. | Must | | FR7 | Clicking the context indicator opens the context selection UI as a persistent popover. | Must | | FR8 | The context selection is persisted to `localStorage` keyed by deck path. | Must | | FR16 | If the multimodal image generation call fails and the system falls back to text-only, a persistent warning badge is shown on the affected slide card. | Must | Full requirement list in [`docs/prd/0001-background-context-transparency.md`](docs/prd/0001-background-context-transparency.md). **Open questions** - FR15 (preprocessing metadata): requires a signature change to `encode_image_for_model`. Separate PR or bundle? - FR7 (context popover): replace or sit alongside the existing modal context sections? --- ## ADR-0001: Generate All Slides respects the active context selection > `docs/adr/0001-generate-all-uses-active-selection.md` — Status: accepted **Problem:** "Generate All Slides" bypassed the context selection and sent all background folders to every job. Individual slide generation respected the selection. This asymmetry silently overrode explicit user configuration. **Decision:** Single button, respects selection (Option A). "Generate All Slides" uses the same active selection as individual generation. A context summary in the toolbar (FR6) makes the active selection visible before clicking. Option B (two explicit buttons) was rejected — adds UI complexity for an advanced workflow most users never need. Option C (do nothing) perpetuates a silent override. --- ## ADR-0002: Context selection persists to localStorage per deck path > `docs/adr/0002-context-selection-localStorage-persistence.md` — Status: accepted **Problem:** The active context selection lived only in JavaScript memory — lost on reload, lost on tab close, reset on deck change. **Decision:** `localStorage` per deck path with 24-hour expiry (Option A). Covers same-session reload friction without risking stale selections from previous days. Fails silently if storage is unavailable. Storage key: `hero_slides_context_selection_v1__{base64(deck_path)}` --- ## ADR-0003: PR process shortcomings on this feature branch > `docs/adr/0003-pr-process-shortcomings-background-pdf-feature-branch.md` — Status: accepted Five process mistakes made during this cycle, recorded so they are not repeated: 1. **Stale PR left open while branch diverged** — PR #20 was opened for background subfolder work; branch grew to include PDF extraction without replacing the PR. 2. **Merge conflicts left unstaged** — `discovery.rs` and `dashboard.js` had conflicts resolved in the working tree but `git add` was never run; index remained broken. 3. **Broad catch-up commit** — all pending changes bundled into one 685-insertion commit, conflating conflict resolution with new feature work. 4. **Branch name understated scope** — `development_link_pdf_extracted_markdown_v2` implies only PDF/link work; actual scope included background subfolders, context sync, select-all UI, and more. 5. **Untracked work directories not gitignored** — `test/`, `test2/`, `examples/dasd/` left as noise in every `git status`. --- ## Related Issue Closes https://forge.ourworld.tf/lhumina_code/hero_slides/issues/7 --- > [!WARNING] > **Do not merge until [lhumina_code/hero_lib#125](https://forge.ourworld.tf/lhumina_code/hero_lib/pulls/125) has landed.** > The multimodal render path in `generator.rs` depends on `AiClient::image_request()` from that PR. > Merging against an older `hero_lib` will break the build.
feat(background): improve panel UX, image upload, root file support, and multimodal AI
Some checks failed
Test / test (push) Failing after 1m5s
Test / test (pull_request) Failing after 1m23s
121e9120bf
- Allow PNG/JPG/JPEG/WEBP/GIF uploads to background panel (was text-only)
- Collapse background panel by default; auto-open when content exists
- Support files directly at content/background/ root (no subfolder needed)
- Include root text files and images in AI generation context
- Pass background images as multimodal input to AI content and image generation
- Add framing prompt so background images inform style/mood, not literal output
- Normalize all images to PNG before passing to AI (fixes JPEG handling)
- Add per-root-file selection checkboxes in create-slide modal
- Fix root file selection key bug in background tree UI

#7
fix(generator): remove framing note that blocked literal image reproduction
Some checks failed
Test / test (pull_request) Failing after 1m5s
Test / test (push) Failing after 1m6s
b64a60677f
The framing prompt told the model never to reproduce background images
literally. This broke the core use case of getting an exact image on a
slide. Per-file selection checkboxes already let users exclude unwanted
images, so the restriction is no longer needed.

#7
feat(background): subfolder support, per-file selection, and instruct context control
Some checks failed
Test / test (pull_request) Failing after 1m7s
Test / test (push) Failing after 1m25s
bcf0bba61c
Background panel:
- Recursive folder discovery — subfolders like "company/team" now visible
- Nested tree rendering with indentation and per-folder expand/collapse
- "Add subfolder" button on every folder node
- Top upload button always targets root (was incorrectly targeting first folder)
- Drag files to root by dropping on the root files section
- Drag files between any folder depth (fixed lastIndexOf parsing for nested paths)
- Context menu "Move to Root" option added

Create-slide modal:
- Per-folder file checkboxes — expand any folder to pick individual files
- Root files still selectable individually as before
- Only selected files passed to AI generation

Instruct panel (slide editor):
- Background context section now shows root files + folders + per-file selection
- Root files individually selectable with checkboxes
- Each folder expandable to pick specific files
- Selected background_root_files and background_folder_files passed through
  the full job pipeline (RPC → generate_job → rhai → deck_module)
- JPEG/WebP images normalized to PNG before passing to AI (consistent with create flow)

#7
fix(background): show context selection when only root files exist
Some checks failed
Test / test (pull_request) Failing after 1m4s
Test / test (push) Failing after 1m10s
ef02d5ca6e
handle_deck_get was only checking find_background_folders (directories)
to set has_background. If a deck had files directly at content/background/
but no subfolders, has_background was false and the context section never
appeared in the create-slide modal or instruct panel.
feat(background): add select all / deselect all toggle to context sections
Some checks failed
Test / test (push) Failing after 1m4s
Test / test (pull_request) Failing after 1m29s
8c068d7443
Adds an 'All'/'None' toggle button to both the create-slide modal and the
instruct panel background context sections. Button label reflects current
state: shows 'None' when everything is selected, 'All' when deselected.
feat(background): add checkmark icon to select-all toggle button
Some checks failed
Test / test (push) Failing after 1m50s
Test / test (pull_request) Failing after 1m51s
8cf5b3cbaf
fix(background): replace toggle button with actual checkbox for select-all
Some checks failed
Test / test (pull_request) Failing after 1m4s
Test / test (push) Failing after 1m7s
c4b7439262
fix(generator): smarter image directive for multimodal slide generation
Some checks failed
Test / test (pull_request) Failing after 1m6s
Test / test (push) Failing after 1m6s
6a40512172
Replaces the blanket "style-reference only" framing with a three-rule
directive that tells the model to read the slide content first and decide:
1. reproduce the image verbatim if the slide calls for it
2. extract information from it if the slide asks for data/text
3. use it as style reference only if the slide doesn't reference it

Also includes discovery and CSS tweaks from the parallel work session.

#7
feat(pdf): add PDF extraction, link support, and background context sync
Some checks failed
Test / test (push) Failing after 1s
Test / test (pull_request) Failing after 1s
91cf510ffa
- Discovery: detect auto-extracted .md companions for PDFs, expose has_extracted_md / is_extracted flags, filter them from counts
- Types: add BackgroundFile fields for PDF ↔ extracted-md pairing
- Generator / agent / generate_job: thread per-file selection through context collection for background images and text
- Deck module / slide module: expose new Rhai bindings for link and PDF extraction features
- Voice: minor cleanup
- RPC / routes: wire up new endpoints for PDF extraction and background context
- dashboard.js: sync selectedBackground* on deck change so generate-slide context menu has valid context before modal is opened; resolve merge conflict
- Rhai generate_slide script: smarter image directive handling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs(adr): record PR process shortcomings for background/pdf feature branch
Some checks failed
Test / test (push) Failing after 2s
Test / test (pull_request) Failing after 1s
f8ca4c8a82
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(generator): migrate multimodal path to image_request() builder (requires hero_lib#125)
Some checks failed
Test / test (push) Failing after 2s
Test / test (pull_request) Failing after 1s
c02830c0c5
`generate_image_with_messages` was removed in lhumina_code/hero_lib#125 and
replaced by the `AiClient::image_request()` builder API.  The multimodal
render path now decodes each base64 background image to raw bytes and attaches
them via `add_image_data()`, then reads the first `GeneratedImage` from the
`ImageGenerationResult`.  A top-of-file comment marks the hard dependency on
hero_lib#125 so the requirement is visible at a glance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
refactor(ui): rename admin Templates tab to Prompts
Some checks failed
Test / test (push) Failing after 1s
Test / test (pull_request) Failing after 2s
eca2050faa
Closes lhumina_code/hero_slides#28
feat(generator): route background images through ImageRef pipeline
Some checks failed
Test / test (pull_request) Failing after 1s
Test / test (push) Failing after 2s
0251648251
Replaces the base64 round-trip in the slide background image pipeline
with `herolib_ai::ImageRef`. `discovery::image_file_to_ref` now returns
an `ImageRef::Bytes` for images that fit the pass-through budget
(<=1568px, <=4 MiB, native mime) and an `ImageRef::Path` otherwise; the
resize/encode work moves into `herolib_ai`'s `image_io` pipeline via
`add_image_ref_with` (image_request) and `ImageRef::load` (chat
multimodal). The predicted resize target dimensions are recorded up
front so the output directory still gets an accurate resize marker.

The `collect_background_images` / `collect_selected_background_images[_with_meta]`
API changes shape from `Vec<(String, String)>` to `Vec<ImageRef>`; all
internal callers (deck, generator, rhai module, agent) compile cleanly
because they pass the slice through unchanged.

Requires hero_lib#128 (`ImageRef`, `add_image_ref_with`, `load_image_from_bytes`).

Refs lhumina_code/hero_slides#25 (phase 1 — removes the discovery
base64 round-trip and hero_lib-duplicated resize logic; the slide-
markdown image-ref parsing piece lands in a follow-up).
Author
Member

Two commits landed since PR open:

  • eca2050closes #28 (rename admin Templates tab → Prompts)
  • 0251648 — phase 1 of #25 (route background images through ImageRef). Requires hero_lib PR 129 which depends on #125. Current local workspace builds green via the ../hero_lib path-patch pointing at PR 129's head.

Phase 2 of #25 (markdown ![alt](url) parsing, label assignment, per-image intent) is the next thing to land on this branch.

🤖 via Claude

Two commits landed since PR open: - `eca2050` — closes #28 (rename admin Templates tab → Prompts) - `0251648` — phase 1 of #25 (route background images through `ImageRef`). **Requires [hero_lib PR 129](https://forge.ourworld.tf/lhumina_code/hero_lib/pulls/129) which depends on #125**. Current local workspace builds green via the `../hero_lib` path-patch pointing at PR 129's head. Phase 2 of #25 (markdown `![alt](url)` parsing, label assignment, per-image intent) is the next thing to land on this branch. 🤖 via Claude
Track preprocessing events from the multimodal path on disk (via the existing
fallback_marker_path / resize_marker_path helpers in the generator) and expose
them through slide.list, slide.preview, slide.generate, and a new one-shot
slide.consumeResizeNotification method. Adds ImageResizeInfo to the lib types,
threads the fallback flag onto SlideFile, and renames/moves the markers along
with slide renames/deletes so the indicators stay attached to the right slide.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a fallback state badge for slides that fell back to text-only, a
warning dot on unextracted PDFs in the background file list, an active-
context indicator + popover next to Generate All, and instruct-pane
status/last-applied hints. All reads are optional so older server
responses continue to render correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Collapses two `if let Some { if ... }` nests into `if let Some && ...` in
discovery and slide_ops, replaces a manual splitn(2, ...) with split_once,
silences the unused rpc_discover spec in the basic_usage example, and
allows too_many_arguments on four fns that legitimately exceed the 7-arg
default (generate_slide, generate_slide_content, rhai slide_instruct_content,
server submit_instruct_content_job).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds SlideImageRef on SlideContent populated by parser::extract_image_refs,
which walks the slide body line by line, skips fenced code blocks, and
assigns a stable label to each ref (slugified alt, falling back to the
src filename stem, then image_<N>; collisions get a numeric suffix).

The generator resolves each ref to an ImageRef — HTTP(S) URLs become
ImageRef::Url (fetched sync in herolib_ai), other srcs are resolved
against the deck root as paths. Missing paths and data: URLs are logged
and dropped rather than aborting the render. Resolved inline refs are
attached FIRST in the multimodal request so their order matches the new
LABELED INLINE IMAGES inventory prepended to the slide-content section;
the framing prompt tells the model to use that inventory to map
`![label](src)` occurrences to the correct attachment, using the
surrounding slide text as per-image intent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace untyped `Theme { raw_content }` with a typed record: name, kind,
description, tags, the prompt-facing `style` prose, reference images, and
a `source` provenance marker. Add `parse_theme_toml(dir)` for the new
`themes/<name>/theme.toml` format; `parse_theme(path)` keeps parsing the
legacy `theme.md` into `Theme { source: LegacyMd(..), style: contents }`
so existing decks round-trip without migration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`list_themes(deck)` scans `<deck>/themes/<name>/theme.toml` and returns
parsed themes sorted by name; malformed entries are logged and skipped so a
single broken theme doesn't hide the rest from a picker. Slide front matter
now understands `theme: <name>` — `resolve_slide_theme` looks the name up
against the deck's `themes/` directory and falls back to the deck's default
theme when the selector is absent or points at a missing/malformed file.
`deck_generate` and `slide_generate_with_selection` call the resolver per
slide so each slide can render against its own theme.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`resolve_theme_refs` turns a theme's `refs` entries into multimodal
attachments (prefixed `theme_<stem>` labels, `theme_<stem>_<N>` on
collision; missing files are logged and dropped). `generate_slide` now
adds them to the `image_request()` builder after inline refs and before
background images, using the same `bg_image_opts` budget so theme images
honour the 1568px / 4 MiB limits that apply to backgrounds. The prompt
gains a `LABELED THEME REFERENCES` section that tells the model how to
use each ref by kind (example / palette / mood / other) and surfaces the
optional per-ref note.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a JSON-RPC endpoint that wraps hero_slides_lib::list_themes, so
clients (UI, agents) can enumerate typed themes under <deck>/themes/
without reading the filesystem directly. Each entry exposes name, kind,
description, tags, refs (absolute paths), and a source variant so the
UI can distinguish TOML themes from the legacy theme.md fallback.

Updates the openrpc.json schema and refreshes the committed
openrpc.client.generated.rs inspection snapshot to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a "Themes" tab to the dashboard that lists typed themes for the
selected deck via the new deck.listThemes RPC. Each entry shows name,
kind, description, tags, resolved reference images (kind, filename,
optional note), and a provenance marker (theme.toml / theme.md /
built-in). No write path — editing themes stays on disk for this pass,
matching the phase-2 read-only UI scope.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat(themes): deck_list_themes Rhai binding (#26 C6)
Some checks failed
Test / test (push) Failing after 1s
Test / test (pull_request) Failing after 2s
9cf674c38e
Exposes hero_slides_lib::list_themes to Rhai scripts so automation can
discover typed themes under <deck>/themes/ and inspect their metadata
(name, kind, description, tags, refs, source) without parsing theme.toml
files directly. Adds an integration test covering the empty and
populated cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The UI dashboard was showing "Disconnected" because the /rpc proxy
route was missing from routes.rs. The AppState socket_path field was
set but never wired up to a handler.

Adds a POST /rpc handler that proxies JSON-RPC requests to the backend
unix socket (hero_slides/rpc.sock), handling both Content-Length and
chunked Transfer-Encoding responses.
fix(ui): add /rpc proxy route to connect dashboard to backend
Some checks failed
Test / test (push) Failing after 1m0s
025823a6cb
The UI dashboard was showing "Disconnected" because the /rpc proxy
route was missing from routes.rs. The AppState socket_path field was
set but never wired up to a handler.

Adds a POST /rpc handler that proxies JSON-RPC requests to the backend
unix socket (hero_slides/rpc.sock), handling both Content-Length and
chunked Transfer-Encoding responses.
Merge branch 'main' into development_link_pdf_extracted_markdown_v2
Some checks failed
Test / test (pull_request) Failing after 2s
Test / test (push) Failing after 2s
c31a539886
* main:
  cargo
  fix(ui): add /rpc proxy route to connect dashboard to backend
casper-stevens closed this pull request 2026-04-17 07:38:01 +00:00
Some checks failed
Test / test (pull_request) Failing after 2s
Test / test (push) Failing after 2s

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_slides!21
No description provided.