On macOS 12 (Monterey), the app launches but no main window appears.
The root cause is WebKit bug #242740: Safari 15's WKWebView has a race
condition with top-level await in ES modules, causing silent JS failure
that prevents `getCurrentWindow().show()` from ever being called.
Three complementary fixes:
1. Change Vite build target from `esnext` to `safari14` (Tauri recommended)
and add `vite-plugin-top-level-await` to transform TLA into compatible
Promise chains, avoiding the WebKit bug entirely.
2. Replace top-level `await import("./App")` in main.tsx with a `.then()`
chain, removing TLA dependency at the source level.
3. Add a Rust-side 8-second timeout safety net in `setup()` that
force-shows the main window if the frontend JS fails to do so,
preventing permanently hidden windows regardless of the failure cause.
Closes#95
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three related environment issues are addressed:
1. Linux ICU version mismatch (#91):
The Linux build used pkg-config to dynamically link against the host's
ICU (libicuuc.so.70 on Ubuntu 22.04). Users on newer distros (e.g.
Ubuntu 25.10 with ICU 76) get "cannot open shared object" errors.
Switch to vcpkg static linking, mirroring the macOS fix (commit 9566956).
2. MCP servers fail on macOS GUI app (#87):
macOS GUI apps inherit a minimal PATH (/usr/bin:/bin) that lacks
/opt/homebrew/bin, so MCP server commands like `uv` silently fail.
Prepend common tool directories (~/.local/bin, ~/.cargo/bin,
/opt/homebrew/bin, NVM paths, etc.) to the child process PATH in
create_command().
3. Existing NVM-installed Claude Code ignored (#90):
find_claude_binary() relied on `which` which fails in GUI apps without
NVM in PATH. Add NVM_BIN env var check and login shell fallback
(`$SHELL -l -c "which claude"`) to discover claude through the user's
actual shell configuration.
Closes#87, closes#90, closes#91
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract shared is_essential_env_var() with case-insensitive matching
- Replace duplicated inline env var lists in install_claude_cli, login_claude, and install_uv
- Add 16 Windows-essential env vars (USERPROFILE, APPDATA, SYSTEMROOT, etc.)
- Use eq_ignore_ascii_case for PATH checks
Without these variables, PowerShell/npm cannot function correctly,
causing the "Installing CLI" step to fail on Windows.
Closes#88
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file hardcodes /opt/homebrew paths (Apple Silicon only) for local
development. It should not be tracked — each developer sets up their
own local paths. Added to .gitignore to prevent re-committing.
Relates to #77 (crash on start due to dynamically linked ICU).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add build-macos-intel job using macos-15-intel runner with
x86_64-apple-darwin target. Includes code signing, notarization,
and updater support (darwin-x86_64 platform key in latest.json).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Isolate tectonic compilation in subprocess to prevent font cache
assertion crash on retry (fixes#67)
- Fix unreachable pattern warning in lib.rs by merging duplicate
WindowEvent::Focused match arms
- Add editor shortcuts: Cmd+B (bold), Cmd+I (italic), Cmd+/ (comment)
- Add Tab/Shift-Tab indent support in CodeMirror editor
- Fix WebKit rendering artifacts with translateZ(0) on .cm-scroller
- Force recompile on button click and Cmd+Enter (skip generation check)
- Add minimum 500ms compile spinner for visual feedback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add sanitize_appimage_env() to restore original LD_LIBRARY_PATH/PATH
when spawning child processes from AppImage (fixes xdg-open, curl)
- Pass DISPLAY, WAYLAND_DISPLAY, XDG_*, DBUS_SESSION_BUS_ADDRESS to
child processes for Linux desktop integration
- Add stdin(Stdio::null()) to install_claude_cli to prevent interactive
prompt hangs
- Add 120s timeout to login_claude to prevent indefinite hang when
browser fails to open
- Show "Setup Guide" link to code.claude.com/docs/quickstart on login
failure
- Keep releases as draft in CI workflow for manual publish
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add dual workaround for WKWebView failing to repaint after returning
from background (1px resize nudge + DOM reflow)
- Use version-free download links in landing page
- Resolve app version dynamically from Tauri in sidebar
- Bump version to 1.0.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix echo loop: only debug window listens for debug-log-entry events
- Gate emit on _debugWindowConnected flag (no IPC when debug window closed)
- Simplify bulk sync: replace buffer on open instead of timestamp dedup
- Auto-scroll: use instant behavior, only scroll when already at bottom
- Fix systemInfo useEffect to run once ([] deps instead of [systemInfo])
- Debug panel is now a separate Tauri window (survives main window
black screen) opened via Cmd+Shift+D or open_debug_window command
- Cross-window log bridging via Tauri events: main window emits
entries, debug window receives them + bulk sync on open
- Log store uses mutable ring buffer + version counter instead of
array spread per log; caches localStorage debug flag
- Debounce app-visibility-restored (200ms) to coalesce duplicate
visibilitychange + Tauri Focused events
- Single getImageData(2x2) call in isCanvasBlank instead of 3x 1x1
- Extract shared getGpuRenderer (cached), SystemInfo type,
getVisibilityLogs into log-store.ts
- Event name constants (APP_VISIBILITY_RESTORED)
- Remove debug UI from error-fallback.tsx and App.tsx
- Fix misplaced import in document-store.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add visibility/focus recovery to prevent black screen when returning
from another app. When macOS reclaims GPU/WebView resources during app
switching, canvas contexts are silently invalidated. This adds:
- visibilitychange + Tauri Focused event listeners in main.tsx
- Canvas blank detection and auto-re-render in mupdf-page.tsx
- IntersectionObserver reconnection via focusGen in pdf-viewer.tsx
- MuPDF worker error recovery and resetMupdfClient() in mupdf-client.ts
- Cmd+Shift+D debug panel keyboard shortcut
- lib.rs: #[allow(unused_mut)] on builder (mut only needed on macOS)
- claude.rs: move CommandExt import to module level with #[cfg(windows)]
- claude.rs: #[allow(unused_variables)] on home (used only on Unix)
- claude.rs: add #[cfg(not(windows))] to Unix-only dir helper functions
- uv.rs: move CommandExt import to module level with #[cfg(windows)]
- skills.rs: fix unreachable Ok(()) after #[cfg] return branches
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename build artifacts to fixed names (ClaudePrism-macOS.dmg, etc.)
- Update latest.json URLs to use fixed filenames
- Update README download links to /releases/latest
- Inline update UI on home screen with version badge
- Gitignore Tauri gen/schemas
- Bump to v1.0.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace toast-based updater with inline version badge on home screen
- Show version + check/update/progress states directly in ProjectPicker
- Move Toaster to App level for workspace toast support
- Remove auto-generated Tauri schemas from git tracking
- Bump to v1.0.2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Toaster was only in WorkspaceWithClaude so update toasts didn't show
on the home screen. Moved to App level. Also shows version on home.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previous key generated with --ci had unusable password. Regenerated
with explicit password and updated pubkey + workflow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add tauri-plugin-updater with signed update artifacts
- Add backgroundThrottling: disabled to prevent WKWebView black screen
- Add update check UI with toast notifications (sonner)
- Update build scripts to generate latest.json for GitHub Releases
- Add multi-platform CI workflow (macOS/Linux/Windows) with draft releases
- Bump version to 1.0.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reduce from 32px to 12px — 32px was too much padding, pushing content
too far from the top edge.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
projectRoot.split("/") didn't handle Windows backslash paths, causing
the full path (C:\Users\...\project) to display in the sidebar header.
Now splits on both / and \ so only the folder name is shown.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changes missed from PR #37 squash merge:
- Set --titlebar-height to 32px on Windows (was 0px, content hidden
behind native overlay titlebar)
- Add ExecutionPolicy Bypass to PowerShell installers (uv + Claude Code)
- Add ~/.local/bin/uv.exe to Windows uv binary search paths
- PDF toolbar: Export/History as icon-only buttons, Capture & Ask text
hidden on narrow panels via container query
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Setting the dock icon in setup() caused SIGBUS on first launch from
signed release binaries due to Gatekeeper App Translocation interfering
with ImageIO plugin initialization.
Moved set_macos_app_icon() to RunEvent::Ready, which fires after the
app is fully initialized — matching Tauri's own approach for dev icons.
Closes#38
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Windows users without Git for Windows see "Install Claude Code" loop
because Claude Code requires git-bash but the app never checks for it.
Now check_claude_status reports missing_git on Windows, and the setup UI
shows a dedicated "Git for Windows Required" screen with a download link
and re-check button.
Also adds Windows-essential env vars to uv installer and improves the
CI workflow to support manual release_tag input.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add CREATE_NO_WINDOW flag to all child process spawns on Windows to
prevent blank console windows from flashing (claude.rs: 4 sites,
uv.rs: 5 sites)
- Fix claude.exe detection: native installer path check now uses .exe
extension on Windows (~/.local/bin/claude.exe)
- Fix PATH separator in install_claude_cli: use ";" on Windows instead
of hardcoded ":"
- Add strip_ansi() to filter terminal escape sequences ([?2026h] etc.)
from install/login output streamed to the frontend UI
- Fix slash_commands.rs path splitting to handle Windows backslashes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vcpkg root was not available, causing build failures for freetype2,
graphite2, and ICU. System pkg-config resolves these reliably.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update IGNORED_EXTENSIONS comment from "LaTeX build artifacts" to reflect
that it now includes general non-editable/binary files
- Update getFileType comment to match the broader scope of ignored extensions
- Add test coverage for representative binary extensions (.docx, .xlsx, .hwp,
.accdb, .zip, .exe, .mp3, .mp4, .psd, .sqlite, .dll, .pptx)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 40+ binary extensions (.hwp, .docx, .xlsx, .accdb, .zip, .exe,
media files, etc.) to IGNORED_EXTENSIONS so they are filtered out
during directory scanning. These files cannot be meaningfully edited
in the text editor and would only cause unnecessary I/O and memory
usage when present in a project folder.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Resolve git merge conflict markers in latex-editor.tsx compileRef
- Use setTimeout for pending recompile to prevent unbounded call stack recursion
- Add clearPdfBytesCache() in test beforeEach for proper test isolation
- Use existing `state` variable instead of redundant getState() calls
- Log when strip_nul actually strips nul bytes for diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three interconnected issues caused degraded UX:
1. **White-screen crash**: Large PDF `Uint8Array` buffers (often 5-20MB) stored
directly in Zustand state caused React to diff them on every render. This
triggered excessive memory pressure and eventual WebView white-screen crashes,
especially with multi-root projects keeping a `pdfCache` Map in state.
2. **"nul byte found in provided data" spawn error**: Clipboard artifacts or
encoding issues could introduce interior nul bytes into Claude CLI arguments,
causing `Command::spawn()` to fail on macOS/Linux (which use C strings
internally).
3. **Silently dropped recompiles**: When a compile was requested while another
was already running (`isCompiling === true`), the request was silently
discarded. This meant edits made during compilation never triggered a
follow-up compile.
- Replaced `pdfData: Uint8Array | null` and `pdfCache: Map<string, Uint8Array>`
in Zustand with an external module-level `_pdfBytesCache` Map.
- Added a `pdfRevision` counter in state that increments whenever PDF bytes
change, triggering React re-renders without diffing the actual buffer.
- Exposed `getPdfBytes()`, `getCurrentPdfBytes()`, `hasPdfData()`, and
`clearPdfBytesCache()` as direct accessors for components.
- Added `migratePdfBytesKey()` helper to deduplicate cache re-keying logic
used by `renameFile` and `moveFile`.
- Conditional `pdfRevision` bumping in `setActiveFile` — only bumps when the
PDF root actually changes, avoiding unnecessary re-renders on tab switches
within the same root.
- `setPdfData(null)` no longer copies `compileErrorCache`/`lastCompiledGenerations`
Maps since it doesn't need to modify them.
- Added `strip_nul()` using `Cow<str>` for zero-allocation fast path when no
nul bytes are present (the common case).
- Applied to program, args, cwd, and inherited PATH in `create_command()`.
- Added structured error logging on spawn failure with tab ID for debugging.
- Added `pendingRecompile` boolean to document store.
- When `isCompiling` is true and a compile is requested, sets
`pendingRecompile = true` instead of silently returning.
- After compilation finishes (in `finally` block), checks `pendingRecompile`
and triggers a follow-up compile if queued.
- Applied consistently in latex-editor, pdf-preview, and use-claude-events.
- Added `js_log` IPC command for frontend → stderr logging that survives
white-screen crashes.
- Added PDF size logging in `compile_latex` for monitoring.
- Updated test state shape (`pdfRevision` instead of `pdfData`, added
`pendingRecompile`).
- Fixed `setActiveFile` test: cursor position is preserved (editor manages
per-file cursor cache), not reset to 0.
- Updated `setPdfData` test to use `getCurrentPdfBytes()` accessor.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only call stat() for image/other file types during project scan to avoid
unnecessary I/O overhead on tex/bib/style/pdf files. Use convertFileSrc
(asset URL) as fallback in ImagePreview when dataUrl is not available,
so large images are viewable without loading them entirely into memory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, claude.cmd is an npm wrapper that breaks when arguments
contain special characters (quotes, &, |, etc.) because cmd.exe
interprets them. Instead, resolve the .cmd to the underlying
node_modules/@anthropic-ai/claude-code/cli.js and invoke node directly.
This fixes "batch file arguments are invalid" errors on Windows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Skip auto-loading files > 1 MB during project open. Large non-essential
files (e.g., .jsonl training data) show a VS Code-style "Open Anyway"
prompt instead of being read into memory immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>