Three coupled fixes to the processing UX:
Streaming (providers/*, node-stream.ts):
Native fetch() is blocked by Obsidian's Electron CSP, so every provider
was silently falling back to non-streaming requestUrl. Added a Node https
client (bypasses CSP) and switched all four providers to it. onToken
callbacks now fire per chunk as the model streams.
Cancellation (pipeline.ts, service.ts, commands.ts):
Added AbortController per annotation and plumbed signal through the
provider interface. Cancel now actually tears down in-flight requests
via req.destroy() instead of waiting minutes for the current call to
finish.
Progress modal (progress-modal-state.ts, progress-modal.ts):
Split logic from DOM into a pure ProgressModalStateMachine so the
"Cancelling..." sticky-header and Close-re-triggers-Cancel bugs can't
recur -- Cancel and Close are now structurally distinct buttons,
recreated per render. Added a rotating "while we wait together..."
quote panel (quotes.ts) and a placeholder line in the stream preview
while waiting for the first token. Stream preview is the only element
that scrolls internally; outer log fits its content.
Tests: 451 passing (22 files). New coverage for state machine
transitions, cancellation propagation, and the Node stream client.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use neutral background with red border instead of themed error
background that can make text invisible in some Obsidian themes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Streaming:
- All 4 providers (Anthropic, OpenAI, Google, Ollama) now support
real-time streaming via native fetch + SSE parsing
- Progress modal shows live prose output as the LLM generates it
- onToken callback on CompletionRequest, forwarded through pipeline
File conflicts:
- Fix conflict dialog CSS: use neutral styling instead of error-red
- Add upsertFile() helper that silently overwrites PENNY-managed files
(version files, reviews) instead of showing conflict dialogs
- Version files and reviews are expected to be overwritten on re-runs
- Reserve safeCreateFile conflict dialog for user-created files only
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4-step guided setup modal on first install:
1. Welcome -- explains what PENNY does and the 3-step workflow
2. Provider -- pick Anthropic/OpenAI/Google/Ollama with API key input
3. Project Structure -- auto-detects folders, configures paths
4. Done -- quick start guide with annotation examples
Triggered when setupComplete is false. Can be skipped.
Replaces the old single-line Notice on first load.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Obsidian theme's --text-success variable resolved to green-on-green,
making badge and confirmation text invisible. Use explicit white on
solid green instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Redesign model routing as compact grid with column headers and tighter spacing
- Shorten "Auto (recommended) -> model-id" to "Auto (Model Name)"
- Add Companion Plugins settings section with auto-detection and auto-configure
- Slash Commander: injects all PENNY commands as slash bindings
- Editing Toolbar: adds PENNY submenu with all commands
- Obsidian Git: listed with install link
- Fix requireProvider() to validate routeResearch (audit HIGH-4)
- JSDoc improvements across all provider files and UI modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Research: new "PENNY: Do research" command opens a modal, sends query
to LLM, saves result to research folder organized by topic subfolder.
Appends to existing files if topic already exists.
Error modal: persistent modal with error message, stack trace, and log
path instead of flashing notices. Used in processChapter error handler.
Progress: live elapsed timer, inline spinner, "waiting for response"
text during API calls.
Settings: researchFolder added to project structure paths.
Add real-time elapsed timer (top-right, updates every second) so users
know processing is alive during long API calls. Add inline spinner
animation next to active annotations with "waiting for response..." text.
Timer shows final elapsed on completion ("Done in Xm Ys"). Minimize
button hidden after completion.
Header: gradient background, rounded card, version badge, pill-style
link buttons with hover states.
Model lists: Anthropic shows static catalog with context window sizes.
Ollama auto-fetches installed models on settings load with Refresh
button. Both display in styled panels within their provider sections.
Auto-latest model: "Auto (recommended)" option for each tier, resolves
to best model at runtime (Haiku/Sonnet/Opus per tier). Default for all
new installs.
Detect project structure: button scans vault for standard folder
patterns and auto-fills empty path settings.
Validate paths: button checks all configured paths exist, reports
OK/MISSING/not set for each.
Commands reference: collapsible help section at bottom of settings
with all 11 commands in a styled table.
Ollama refresh models: button fetches installed models from Ollama
endpoint, shows them in a notice.
310 tests passing (8 new router tests for resolveModel).