Add Tauri v2 + Svelte 5 desktop UI for helixsh#8
Conversation
Adds ui/ — a frameless Warp-inspired desktop app that wraps the helixsh CLI with a rich, dark-themed terminal UI. Frontend (Svelte 5 + Vite): - TitleBar: custom frameless window with traffic-light controls - Sidebar: doctor tool status, nf-core pipeline list, RBAC role selector - CommandBlock: collapsible per-command output block with streaming stdout/stderr (green/red), status badge, timestamp, and collapse toggle - CommandBar: Warp-style input with tab-autocomplete (50+ commands), intent mode toggle, command history, strict-mode lock, submit button - StatusBar: live RBAC role, strict mode, running indicator, helixsh path - Store: Svelte stores for blocks, role, strictMode, doctorData, pipelineList Rust backend (Tauri v2): - run_helixsh: streams stdout/stderr as Tauri events (helixsh://output, helixsh://done) for real-time block updates - query_helixsh: synchronous capture for doctor/nf-list sidebar queries - get_helixsh_path: resolves sidecar .pyz → PATH → python -m helixsh - window_action / start_drag: custom titlebar window controls CI: GitHub Actions workflow builds on ubuntu-24.04, macos-latest, windows-latest and uploads binary artifacts. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
npm ci in CI environments fails without --legacy-peer-deps because @sveltejs/vite-plugin-svelte 4 and Svelte 5 have an unresolved peer dep declaration. Adding .npmrc makes both local and CI installs consistent. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 44d7331e8d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| fn which_helixsh() -> Option<String> { | ||
| std::env::var("PATH").ok().and_then(|path| { | ||
| path.split(':').find_map(|dir| { |
There was a problem hiding this comment.
Use OS-native PATH parsing for helixsh lookup
which_helixsh splits PATH with ':', which is Unix-specific; on Windows the separator is ';' and drive letters also contain :, so entries are parsed incorrectly and helixsh detection fails. In the Windows build context introduced by this commit, that forces the app onto fallback execution paths even when helixsh is installed, causing command runs to fail or use the wrong interpreter.
Useful? React with 👍 / 👎.
| return ("helixsh".to_string(), vec![]); | ||
| } | ||
| // Last resort: python -m helixsh | ||
| ("python3".to_string(), vec!["-m".to_string(), "helixsh".to_string()]) |
There was a problem hiding this comment.
Replace hardcoded
python3 with cross-platform interpreter resolution
The executable resolver hardcodes python3 for both sidecar launch and -m helixsh fallback, but standard Windows installs typically expose python/py instead. When helixsh is not found on PATH (or when using the sidecar), run_helixsh/query_helixsh will fail to spawn on Windows, making the desktop UI unable to execute commands there.
Useful? React with 👍 / 👎.
| "icon": [ | ||
| "icons/32x32.png", | ||
| "icons/128x128.png", | ||
| "icons/128x128@2x.png", | ||
| "icons/icon.icns", | ||
| "icons/icon.ico" |
There was a problem hiding this comment.
Add bundled icon assets or disable bundle icon references
tauri.conf.json enables bundling and references five icon files under src-tauri/icons/, but this commit does not add that directory or any of those files. As a result, documented production builds (npm run tauri build) are expected to fail during bundling because required icon resources are missing.
Useful? React with 👍 / 👎.
… icons
- lib.rs: replace path.split(':') with std::env::split_paths() so PATH
is parsed correctly on Windows (uses ';' separator and drive letters)
- lib.rs: add python_exe() helper that probes 'py' -> 'python' -> 'python3'
on Windows (vs hard-coded 'python3' which doesn't exist on Windows by default)
- lib.rs: look for 'helixsh.exe' (not 'helixsh') when on Windows
- src-tauri/icons/: add placeholder PNG/ICO/ICNS icons so tauri.conf.json
bundle references resolve; generated as solid #58a6ff blue placeholder images
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
…ilure protocol-asset is not used — helixsh commands are invoked via subprocess IPC (run_helixsh/query_helixsh), not the asset:// protocol. Removing the feature resolves the Tauri compile error on all platforms. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
- lib.rs: use tauri::WebviewWindow (not tauri::Window) for window_action
command — Tauri v2 webview-backed windows require WebviewWindow
- lib.rs: remove start_drag command — CSS -webkit-app-region: drag handles
window dragging without needing a Rust IPC round-trip
- lib.rs: remove tauri-plugin-shell (unused; subprocess execution is via
custom run_helixsh/query_helixsh commands)
- lib.rs: simplify python_exe() to compile-time cfg check, eliminating
blocking std::process::Command probes in async context
- Cargo.toml: remove tauri-plugin-shell dependency
- capabilities/default.json: remove shell:allow-* permissions (no longer needed)
- TitleBar.svelte: remove invoke("start_drag") call; drag handled by CSS
- CommandBar.svelte: append error to existing lines on catch instead of
replacing them (Devin review: avoids wiping streamed output on late errors)
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
- Remove "plugins": {"shell": ...} — tauri-plugin-shell was removed from
Cargo.toml but config remained, causing generate_context! macro failure
- Set "bundle": {"active": false} — prevents bundler from running during
plain 'tauri build', which requires platform-specific packaging tools
(codesign on macOS, WiX/NSIS on Windows) not available in CI
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
Replace AppHandle+Emitter event broadcasting with Channel<HelixEvent>
so output lines and exit codes are streamed directly to the invoking
frontend tab without any shared global listeners. Removes all usage of
tauri::Emitter, tauri::Manager, and the listen() API on the JS side.
- lib.rs: accept Channel<HelixEvent> in run_helixsh; spawn stdout/stderr
reader tasks that send Output events; send Done on exit
- App.svelte: drop listen("helixsh://output/done") calls from onMount
- CommandBar.svelte: create Channel per invocation, set onmessage handler
for Output/Done events, pass onEvent channel to invoke("run_helixsh")
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
Two compile errors on all platforms: - Channel<T>::send takes T by value, not &T; remove & from all three send() calls (Output stdout, Output stderr, Done) - tauri::Window does not implement CommandArg in Tauri v2; use tauri::WebviewWindow for window injection in window_action command https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
parseDoctor: helixsh doctor uses fixed-width space-separated columns (name, state, details), not colon-delimited. Rewrite to split on whitespace and check state === 'ok'. loadPipelines: helixsh nf-list outputs a JSON array; parse with JSON.parse and extract .name instead of splitting raw text by newlines. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
…lict Tauri v2's #[tauri::command] macro generates __tauri_command_name_<fn> macro_rules items in the module where the attribute appears. When generate_handler! is called in the same module, it tries to import those same names, triggering E0255: cannot import more than once. Fix: extract all #[tauri::command] functions into commands.rs so the generated macros live in the commands module. lib.rs then references them via qualified paths (commands::run_helixsh etc.) and generate_handler! imports from crate::commands without any name collision. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
tauri::generate_context!() panics at compile time if icon PNGs are not RGBA. The icons were RGB (no alpha channel), causing the error: "icon .../32x32.png is not RGBA". Converted all three PNG icons to RGBA. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
tauri_build::build() generates gen/schemas/ with JSON schemas for ACL and capability validation (IDE support). Adding these to the repo makes the schemas available without requiring a local build step. https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
…as exitCode
Serde's rename_all on an enum only renames variant names (Output→output,
Done→done), not fields inside struct variants. Without rename_all_fields,
Done { exit_code } serializes as "exit_code" in JSON, but the frontend
reads msg.data.exitCode — always undefined — making every command block
show status "error" regardless of the real exit code.
Fix: add rename_all_fields = "camelCase" at the container level (serde
≥1.0.185, we use 1.0.228) so exit_code → exitCode in the Done variant.
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4
Summary
This PR introduces a complete desktop application for helixsh using Tauri v2 and Svelte 5. The UI provides a modern, Warp-inspired shell interface with streaming command output, intent mode for natural language queries, and integrated environment/pipeline management.
Key Changes
Desktop Application Framework: Full Tauri v2 setup with Svelte 5 frontend and Rust backend
Command Execution & Streaming
run_helixshcommand spawns helixsh processes with real-time stdout/stderr streaming via Tauri eventsquery_helixshfor lightweight synchronous queries (doctor, nf-list, etc.)python -m helixshUI Components
State Management
RBAC & Modes
--roleflag--strictto all invocationshelixsh intentcommandBuild & Development
Notable Implementation Details
https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4