Skip to content

Add Tauri v2 + Svelte 5 desktop UI for helixsh#8

Merged
musicofthings merged 14 commits into
mainfrom
claude/tauri-ui
May 1, 2026
Merged

Add Tauri v2 + Svelte 5 desktop UI for helixsh#8
musicofthings merged 14 commits into
mainfrom
claude/tauri-ui

Conversation

@musicofthings

@musicofthings musicofthings commented May 1, 2026

Copy link
Copy Markdown
Owner

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

    • Custom frameless titlebar with macOS-style traffic-light buttons
    • Window management (minimize, maximize, close, drag)
    • Cross-platform support (Linux, macOS, Windows)
  • Command Execution & Streaming

    • run_helixsh command spawns helixsh processes with real-time stdout/stderr streaming via Tauri events
    • query_helixsh for lightweight synchronous queries (doctor, nf-list, etc.)
    • Automatic helixsh resolution: bundled sidecar → PATH → python -m helixsh
  • UI Components

    • CommandBar: Input with autocomplete (50+ commands), command history (arrow keys), intent mode toggle (⚡), strict mode lock (🔒)
    • CommandBlock: Collapsible per-command output blocks with streaming lines, status badges, timestamps
    • Sidebar: Three tabs—tools (environment doctor output), pipelines (nf-core list), history
    • StatusBar: Role indicator (auditor/analyst/admin with color coding), strict mode, running status, helixsh path
    • TitleBar: Custom frameless titlebar with logo and window controls
  • State Management

    • Svelte stores for blocks, role, strictMode, helixshPath, sidebarTab, doctorData, pipelineList
    • Real-time block updates from streaming events
  • RBAC & Modes

    • Role selector (auditor/analyst/admin) injected as --role flag
    • Strict mode toggle appends --strict to all invocations
    • Intent mode sends natural language to helixsh intent command
  • Build & Development

    • Vite dev server with HMR for rapid iteration
    • GitHub Actions CI/CD for cross-platform builds (Linux, macOS, Windows)
    • Development dependencies: Tauri CLI, Svelte, Vite, @tauri-apps/api

Notable Implementation Details

  • Shell-like argument parsing with regex for quoted strings
  • Async streaming via tokio with separate stdout/stderr readers
  • CSS variables for dark theme (GitHub-inspired palette)
  • Responsive layout: titlebar (36px) + sidebar (220px) + main area + statusbar (28px)
  • Auto-scroll to latest command block on new output
  • Welcome screen with command hints when no blocks exist

https://claude.ai/code/session_01E7C1r4saaKwguu88r6sqt4


Open in Devin Review

claude added 2 commits May 1, 2026 14:03
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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread ui/src-tauri/src/lib.rs Outdated

fn which_helixsh() -> Option<String> {
std::env::var("PATH").ok().and_then(|path| {
path.split(':').find_map(|dir| {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment thread ui/src-tauri/src/lib.rs Outdated
return ("helixsh".to_string(), vec![]);
}
// Last resort: python -m helixsh
("python3".to_string(), vec!["-m".to_string(), "helixsh".to_string()])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +32 to +37
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

devin-ai-integration[bot]

This comment was marked as resolved.

claude added 2 commits May 1, 2026 15:22
… 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
devin-ai-integration[bot]

This comment was marked as resolved.

claude added 4 commits May 1, 2026 15:29
- 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
devin-ai-integration[bot]

This comment was marked as resolved.

claude added 5 commits May 1, 2026 15:51
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
devin-ai-integration[bot]

This comment was marked as resolved.

…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
@musicofthings
musicofthings merged commit 4aa3633 into main May 1, 2026
6 checks passed
@musicofthings
musicofthings deleted the claude/tauri-ui branch May 1, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants