Why: An A4 page is wider than the preview column, and the page background followed the app theme, so body text disappeared in dark mode.
Evidence: npm test (17 files, 81 tests) and npx tsc -b passed in modules/frontend.
Impact: Docx pages stay on --paper with their own styles and shrink to fit the column. A column wider than the page, including fullscreen, keeps them at 100%. Before: section background var(--bg) and color var(--text). After: var(--paper) and var(--paper-ink).
Refs: feature/docx-paper-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The conversation and office fallbacks wrote marked output straight into the page, including converted docx HTML.
Evidence: html-sinks ratchet forbids new innerHTML writes outside @ui safeHtml.
Impact: Conversation keeps line-break rendering. Unsafe links are stripped after docx and pptx preview. dompurify is deduped with the UI package.
Refs: feature/sillytavern-review
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Process output folded on every text delta, successful tool
results disappeared after refresh, and generated files stayed plain
text instead of a card that opens a closable preview.
Evidence: npx tsc -b --noEmit (clean); npx vitest run (51 passed).
Impact: Live work stays expanded until the run ends, then folds to
one worked-time line. File cards open a per-conversation preview pane.
docx renders page by page, with mammoth if that fails.
Refs: feature/chat-timeline-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: docx preview already sniffs ZIP magic so a text file renamed to
.docx stays readable. xlsx and pptx loaders still fed those bytes to
the parser and surfaced a raw library error.
Evidence: npx tsc --noEmit and npx vitest run (40 tests) on this branch
after merging origin/main. Legacy .xls/.ppt skip the sniff because they
are not OOXML.
Impact: pseudo xlsx/pptx render as text with a short note. Real ZIP
workbooks and decks still use the existing parsers.
Refs: Dev PR #96, task feature/preview-sniff-fallback
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: agent-generated ".docx" artifacts were historically plain text bytes
written via string-only write tools; the docx preview loader fed them
straight to mammoth/JSZip, which threw "Can't find end of central directory"
on the meeting-notes docx from the review session.
Evidence: docxLoader now checks the PK\x03\x04 (or empty-archive PK\x05\x06)
magic before mammoth; non-ZIP bytes render as markdown with a readable note
instead of an error. vitest 33/33 pass, tsc --noEmit clean.
Impact: stock fake-docx artifacts become readable immediately; real docx
previews unchanged. Rendering only, no API/contract change.
Refs: .task/feature-preview-sniff-fallback.md
Why: the adjudicated plan (D1-D4) calls for office/link previews with
loaders injected from the host, right-rail light preview alongside the
overlay viewer, and artifact deletion kept as an API capability with no
UI entry.
Evidence: previewsetup.ts injects docx (mammoth), xlsx (SheetJS, sheet
tabs, 200-row cap), pptx (pptx-preview full-fidelity; pptx2html was
dropped for a broken module entry — tXml case mismatch breaks Linux
builds — per the D2 fallback clause), and the /api/url-preview fetcher,
all via dynamic import: the main entry grows ~12KB while xlsx (430KB),
pptx (1.2MB) and jszip (98KB) load on first preview. DocViewer becomes a
FilePreview container (keeps text-family editing); Workbench gains a
preview tab with rail-preview state (store.railPreview); artifact chips
and panel rows gain a rail-preview action; the panel delete button is
removed while api.deleteArtifact and DELETE /api/artifacts/{id} remain.
tsc clean; vitest 33 passed; production build succeeds.
Impact: previews work end to end for the whole format matrix; deletion
stays plugin-reachable only.
Refs: task feature/file-preview-caps; ui fb76239; core 4d29301; backend
6d4ccfd.