Skip to content

Commit bde8122

Browse files
mannnrachmanCopilotclaude
authored
feat: migrate from electron to tauri (#37)
* feat: add Tauri 2.0 POC project structure (Electron → Tauri migration Fase 1) - Add src-tauri/ with Cargo.toml, Rust entry points, and shell detection commands - Add tauri.conf.json with frameless window, CSP, and capabilities config - Add TauriTerminal component (xterm.js + tauri-plugin-pty + WebGL) - Add TauriTitleBar with Tauri window API (minimize/maximize/close/drag) - Add TauriApp entry point with show-on-ready pattern - Add vite.config.tauri.ts for dual-build (Electron + Tauri side-by-side) - Add tauri-index.html as separate entry for Tauri build - Add Tauri npm deps (@tauri-apps/api, tauri-pty, @tauri-apps/plugin-os) - Add dev:tauri and build:tauri scripts to package.json - Update .gitignore for dist-tauri/ and src-tauri/target/ - All 653 existing tests pass, both typechecks pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: resolve code review findings in Tauri POC (F1-F5) - F1 [HIGH]: Store PTY event handler disposables, unlisten on cleanup - F2 [MEDIUM]: Track WebGL addon in ref, dispose explicitly, check disposed flag - F3 [MEDIUM]: Fix race condition in TauriTitleBar resize listener with mounted flag - F4 [MEDIUM]: Add disposedRef guard to ResizeObserver, fix cleanup order - F5 [MEDIUM]: Validate PATH-based shells on Windows using 'where' command Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add url config to tauri window for production build Tauri defaults to loading index.html but our entry is tauri-index.html. Without explicit url config, the frontend never loads and window stays hidden. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: add gitignore for agent files * chore: untrack docs folder and add to gitignore * feat(pty): add Rust PTY manager with multi-terminal support * feat(trackers): add Rust CWD, Git, and exit code trackers * feat(commands): register Tauri IPC commands and wire Rust backend modules * feat(terminal-api): add Tauri terminal IPC adapter layer * fix(types): add index signature to TerminalSpawnOptions for Tauri invoke * feat(terminal): migrate ConnectedTerminal to Tauri terminal API * refactor(hooks): migrate terminal tracking hooks to Tauri API * build(deps): add Tauri plugin dependencies for persistence, fs, dialog, clipboard * feat(persistence): add Tauri persistence and filesystem adapter * feat(adapters): add Tauri dialog, clipboard, and window adapter * feat(api): add unified API bridge and barrel exports * refactor(hooks): migrate persistence and filesystem hooks to Tauri adapter * refactor(stores): migrate Zustand stores to Tauri adapter * refactor(components): migrate UI components to Tauri adapter * refactor(app): migrate pages, layout, and TauriApp to full Tauri UI * test: add Tauri mock infrastructure and adapter unit tests * fix: correct IPC argument mapping, event shapes, window controls, and shell detection * fix: resolve shell default, filesystem timeout, and window state edge cases * build(deps): add Tauri updater and process plugin dependencies * feat(updater-api): add Tauri updater adapter with safe update and version skip * refactor(updater): migrate updater store and hooks to Tauri plugin * ci: add Tauri release workflow and update PR validation * test: add updater adapter tests and update existing test suites * feat(tauri): complete Fase 4 - add backup/rollback adapters and NSIS config AC-10: Implement backup and rollback Tauri adapters - Add tauri-backup-api.ts with createBackup, listBackups, restoreBackup, cleanupOldBackups - Add tauri-rollback-api.ts with keepPreviousVersion, availableRollbacks, installRollback - Use @tauri-apps/plugin-fs and @tauri-apps/plugin-store instead of Electron APIs - Add 13 tests covering API structure and error handling AC-12: Update README with Tauri build instructions - Add Tauri 2.0 badge and dual backend support description - Document Rust toolchain and platform-specific prerequisites - Add Tauri development and build commands - Include migration status link AC-14: Create benchmark documentation - Add docs/benchmark-electron-vs-tauri.md with comparison tables - Document bundle size, RAM usage, startup time targets - Include methodology and measurement procedures AC-15: Enhance NSIS installer configuration - Add windows.nsis config with installMode, languages, shortcuts - Configure publisher, copyright, and category metadata - Set up WebView2 bootstrapper for Windows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: spam terminal * fix: add isTauriContext guards to prevent browser crash Without these guards, getCurrentWindow() throws TypeError in plain browser because window.__TAURI_INTERNALS__ is undefined. This crashed the entire React app via error boundary when TitleBar.tsx called windowApi.onMaximizeChange() in a useEffect. - tauri-window-api.ts: add isTauriContext() helper, guard all methods (minimize, toggleMaximize, close, onMaximizeChange, onCloseRequested, respondToClose) to return early/noop when not in Tauri context - TauriApp.tsx: guard showWindow() call with isTauriContext check - TitleBar.tsx: related cleanup from guard addition * fix: defer initial fitAddon.fit() to requestAnimationFrame WebglAddon.activate() is async internally. Calling fitAddon.fit() synchronously right after loadWebglAddon() caused an uncaught: TypeError: Cannot read properties of undefined (reading 'dimensions') 5 times on startup (once per terminal), sourced from xterm's RenderService.get dimensions() -> this._renderer.value.dimensions where _renderer.value is undefined until WebGL finishes initializing. Fix: wrap initial fit() call in requestAnimationFrame() so the WebGL renderer has one frame tick to complete initialization. Also fixes debounce test regression: add mockClear() after spawn assertion to account for the needsResizeOnReadyRef immediate-resize path that fires before the xterm onResize debounce under test. * perf: reduce PTY kill timeout from 2000ms to 300ms Reduces perceived lag when closing a terminal tab. The kill operation should be near-instant for graceful shutdown; 300ms is a sufficient safety margin for the race to avoid hanging the close flow. * refactor(tauri): consolidate GitStatus type to shared IPC contract - Re-export GitStatus from @shared/types/ipc.types in project.ts - Update use-git-status.ts to import from shared types - Ensures type consistency between Rust backend and renderer - Eliminates duplicate GitStatus definition This aligns the renderer domain model with the Tauri IPC contract, ensuring the GitStatus interface matches the Rust tracker's serialized output (camelCase, same fields). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(shared): add canonical Migration API contract Define canonical MigrationApi interface with 6 methods: - getVersion, getSchemaInfo, getHistory, getRegistered, runMigration, rollback - Add IpcResult<T> type definitions for error handling - Document Rust command naming mapping (snake_case) This contract is used by both renderer adapters and Rust backend. * feat(rust): implement data migration backend with store plugin - Add MigrationManager with Tauri store plugin integration - Implement data_migration_get_registered: return actual migrations - Implement data_migration_run_migrations: process pending migrations - Implement data_migration_rollback: execute rollback to version - Register MigrationManager in app state Replaces placeholder implementations with working backend. * fix(rust): fix CWD and Git tracker polling not starting - Fix ensure_polling_started() implementation (was empty) - Add interior mutability pattern (Arc<RwLock<Option<JoinHandle>>>) - Add is_polling_started atomic flag for proper one-time initialization - Add poll_count indicator for testability - Fix shutdown() to properly abort tasks Closes: CWD changes were never detected, terminal-cwd-changed event never fired * feat(renderer): add Tauri adapters for Session and Data Migration - Implement SessionApi interface using @tauri-apps/plugin-store - Implement MigrationApi interface with canonical contract - Map invoke calls to Rust commands (snake_case) - Handle IpcResult<T> success/error responses These adapters complete the Tauri implementation for Session and Data Migration domains. * refactor(renderer): make facade Tauri-first with Electron compatibility - Add isTauriContext() guard using window.__TAURI_INTERNALS__ - Export sessionApi from Tauri adapter on Tauri runtime - Export dataMigrationApi from Tauri adapter on Tauri runtime - Mark session-api.ts and data-migration-api.ts as deprecated (Electron only) - Add explicit error boundaries for wrong context usage BREAKING-CHANGE: Session and Data Migration APIs now route to Tauri by default. Electron fallback available via compatibility modules. * docs(renderer): document keyboard and system event fallback mode - Document Fallback Mode decision for keyboard events (WebView2 limitation) - Document Heartbeat approach for system power-resume (chosen, not workaround) - Add TODO for what would be needed for Backend Event Mode - Reference decision document from keyboard/system APIs Decision: Fallback Mode over Backend Event Mode due to technical limitations. See: docs/decisions/keyboard-system-event-mode-final.md * feat(renderer): implement bootstrap context detection and visibility integration - Add isTauriContext() detection in main.tsx bootstrap - Route to TauriApp component when Tauri context detected - Integrate visibility state with backend terminal_set_visibility command - Ensure visibility-aware polling works end-to-end Enables CPU-saving pause/resume behavior for trackers when app hidden. * test(renderer): add test suite for Session, Data Migration, and parity - Add 18 automated parity checks (Implemented/Wired/Verified per domain) - Test Session adapter with all 5 methods (save, restore, clear, flush, hasSession) - Test Data Migration adapter with canonical contract (rollback payload shape) - Test facade routing uses Tauri adapters on Tauri runtime - Add visibility transition and recovery scenarios Covers regression prevention for Tauri-first facade pattern. * test(main): add Electron IPC compatibility tests - Test session:save, session:restore, session:clear, session:flush, session:hasSession - Test dataMigration:runMigrations, dataMigration:rollback, etc. - Verify IpcResult pattern compatibility between Electron and Tauri - Validate legacy vs canonical method name mappings Ensures Electron compatibility path continues working during coexistence. * chore: update supporting types and preload interfaces - Sync preload TypeScript definitions with Tauri API changes - Update project types for new migration domain types - Minor main process adjustments for compatibility No functional changes, type sync only. * feat: add logging support for terminal events and improve PTY management * feat: enhance PTY management with dedicated writer and improve error handling in IPC tests * feat: add various icon assets for Tauri application including adaptive icons and SVG * feat: update Tauri configuration and dependencies, add MCP bridge plugin * feat: add Git Bash path candidates and improve shell resolution on Windows * feat(tauri): eliminate cmd.exe spawn for shell detection - add resolve_executable_from_path() to search PATH without spawning cmd - add is_builtin_windows_shell() to allow known shells without PATH resolution - cache shell detection results with OnceLock to avoid repeated lookups - add debug logging for shell availability checks * feat(tauri): improve pty manager spawn and orphan detection - replace CommandExt CREATE_NO_WINDOW with resolve_executable_from_path - refactor orphan detection loop to use tokio interval - extract reader/writer setup into cleaner patterns * feat(tauri): stabilize git tracker polling and spawn-less git detection - replace git binary detection via cmd spawn with resolve_command_candidates_from_path - use RwLock + AtomicBool for thread-safe polling state - apply rustfmt formatting to cwd_tracker and exit_code_tracker * chore(tauri): apply rustfmt to migrations.rs * feat(renderer): async terminal restore with pty spawn on startup - make restoreFromLayout and createDefaultTerminal async - spawn PTY via terminalApi.spawn() before creating terminal store entry - link terminal to ptyId via setTerminalPtyId after spawn - add PROJECT_RESTORE_LOCKS to prevent concurrent restore for same project - add normalizeShellForStartup() to skip cmd.exe on Windows Tauri - guard setTerminalPtyId against ptyId conflicts and double-assignment - cache detectShells IPC result on frontend to deduplicate startup calls * feat(renderer): explicit pty spawn in workspace and autoSpawn control - add autoSpawn prop to ConnectedTerminal to skip implicit PTY spawn - integrate addRendererRef/removeRendererRef for PTY ref counting - update onCloseTerminal signature to include tabId - spawn PTY explicitly before adding terminal in WorkspaceLayout - refactor close-confirm state to track both terminalId and tabId * test: add/update tests for terminal restore and store - add tests for autoSpawn=false in ConnectedTerminal - add tests for setTerminalPtyId conflict guard in terminal-store - add use-terminal-restore.test.ts covering normalizeShellForStartup and restore lock * chore(tauri-platform): tighten desktop integration plumbing * fix(migrations): execute handlers and rollback safely * fix(terminal-runtime): harden Windows PTY and restore flow * fix(windows-env): preserve PATH case-insensitively for PTY shells * chore(electron-cleanup): remove legacy main and preload runtime * chore(tooling): finalize Tauri-only build and release config * refactor(runtime): harden Tauri renderer adapters and window state * feat(desktop): wire native menu and recovery-aware updater flow * feat(shortcuts): switch defaults to Tauri-safe tab navigation * docs(repo): refresh credits and Tauri contributor metadata * chore(types): simplify rollback request compatibility alias * test(tauri): realign regression coverage with Tauri-only runtime * feat(window-api): add global Window interface with API definitions * chore(release): prepare 0.3.0 beta packaging * ci(release): run tauri-action through npm * chore(release): bump beta package version to 0.3.0-2 * chore(ci-docs): fix safe workflow and documentation findings * fix(tauri-windows): harden shell test and conpty utilities * fix(git-tracker): refresh cwd and branch polling safely * chore(rustfmt): normalize pending Rust formatting * fix(ci): use tauri-action@v0 and bump version to 0.3.0-3 * fix(release): restore cross-platform Rust dependencies * fix(pty-manager): simplify default shell resolution for non-Windows environments * docs(readme): fix linux dependency code fence * ci(release): harden workflow and validation matrix * fix(tauri): harden runtime and migration startup * fix(capabilities): allow process relaunch * ci: stabilize tauri release workflow reruns * docs: add missing linux tauri dependency * fix: harden migration registration and persistence * fix: harden terminal and git tracker runtime * ci(fork): add push-based monitoring workflow * fix(rust): resolve clippy warnings blocking fork CI --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7fd4dfa commit bde8122

File tree

245 files changed

+30045
-23749
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

245 files changed

+30045
-23749
lines changed

.github/workflows/fork-monitor.yml

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
name: Fork Monitor
2+
3+
on:
4+
push:
5+
branches:
6+
- feat/**
7+
- fix/**
8+
- refactor/**
9+
- perf/**
10+
- test/**
11+
- chore/**
12+
- ci/**
13+
- build/**
14+
workflow_dispatch:
15+
16+
permissions:
17+
contents: read
18+
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
cancel-in-progress: true
22+
23+
jobs:
24+
validate:
25+
if: github.repository == 'mannnrachman/termul'
26+
name: Lint, Typecheck & Test
27+
runs-on: ubuntu-latest
28+
timeout-minutes: 15
29+
steps:
30+
- name: Checkout
31+
uses: actions/checkout@v4
32+
33+
- name: Setup Node.js
34+
uses: actions/setup-node@v4
35+
with:
36+
node-version: 20
37+
cache: npm
38+
39+
- name: Install npm dependencies
40+
run: npm ci
41+
42+
- name: Lint
43+
run: npm run lint
44+
45+
- name: Typecheck
46+
run: npm run typecheck
47+
48+
- name: Test
49+
run: npm run test
50+
51+
rust-checks:
52+
if: github.repository == 'mannnrachman/termul'
53+
name: Rust Checks
54+
runs-on: ubuntu-22.04
55+
timeout-minutes: 20
56+
steps:
57+
- name: Checkout
58+
uses: actions/checkout@v4
59+
60+
- name: Install Linux dependencies
61+
run: |
62+
sudo apt-get update
63+
sudo apt-get install -y \
64+
libwebkit2gtk-4.1-dev \
65+
libappindicator3-dev \
66+
librsvg2-dev \
67+
patchelf
68+
69+
- name: Setup Rust
70+
uses: dtolnay/rust-toolchain@stable
71+
with:
72+
components: clippy
73+
74+
- name: Cache Rust
75+
uses: swatinem/rust-cache@v2
76+
with:
77+
workspaces: src-tauri
78+
cache-on-failure: true
79+
80+
- name: Cargo check
81+
working-directory: src-tauri
82+
run: cargo check --all-targets
83+
84+
- name: Cargo test
85+
working-directory: src-tauri
86+
run: cargo test
87+
88+
- name: Cargo clippy
89+
working-directory: src-tauri
90+
run: cargo clippy --all-targets -- -D warnings
91+
92+
rust-windows-check:
93+
if: github.repository == 'mannnrachman/termul'
94+
name: Rust Windows Smoke Check
95+
runs-on: windows-latest
96+
timeout-minutes: 15
97+
steps:
98+
- name: Checkout
99+
uses: actions/checkout@v4
100+
101+
- name: Setup Rust
102+
uses: dtolnay/rust-toolchain@stable
103+
with:
104+
components: clippy
105+
106+
- name: Cache Rust
107+
uses: swatinem/rust-cache@v2
108+
with:
109+
workspaces: src-tauri
110+
cache-on-failure: true
111+
112+
- name: Cargo check
113+
working-directory: src-tauri
114+
run: cargo check --all-targets
115+
116+
build-check:
117+
if: github.repository == 'mannnrachman/termul'
118+
name: Verify Tauri Frontend Build
119+
needs: [validate, rust-checks, rust-windows-check]
120+
runs-on: ubuntu-latest
121+
timeout-minutes: 15
122+
steps:
123+
- name: Checkout
124+
uses: actions/checkout@v4
125+
126+
- name: Setup Node.js
127+
uses: actions/setup-node@v4
128+
with:
129+
node-version: 20
130+
cache: npm
131+
132+
- name: Install npm dependencies
133+
run: npm ci
134+
135+
- name: Build Tauri frontend assets
136+
run: npm run build:frontend:tauri

.github/workflows/pr-validation.yml

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,49 +45,104 @@ jobs:
4545
- name: Checkout
4646
uses: actions/checkout@v4
4747

48-
- name: Setup Bun
49-
uses: oven-sh/setup-bun@v2
50-
with:
51-
bun-version: latest
52-
5348
- name: Setup Node.js
5449
uses: actions/setup-node@v4
5550
with:
5651
node-version: 20
52+
cache: npm
5753

58-
- name: Install dependencies
59-
run: bun install --frozen-lockfile
54+
- name: Install npm dependencies
55+
run: npm ci
6056

6157
- name: Lint
62-
run: bun run lint
58+
run: npm run lint
6359

6460
- name: Typecheck
65-
run: bun run typecheck
61+
run: npm run typecheck
6662

6763
- name: Test
68-
run: bun run test
64+
run: npm run test
6965

70-
build-check:
71-
name: Verify Build
72-
needs: validate
73-
runs-on: ubuntu-latest
66+
rust-checks:
67+
name: Rust Checks
68+
runs-on: ubuntu-22.04
69+
timeout-minutes: 20
70+
steps:
71+
- name: Checkout
72+
uses: actions/checkout@v4
73+
74+
- name: Install Linux dependencies
75+
run: |
76+
sudo apt-get update
77+
sudo apt-get install -y \
78+
libwebkit2gtk-4.1-dev \
79+
libappindicator3-dev \
80+
librsvg2-dev \
81+
patchelf
82+
83+
- name: Setup Rust
84+
uses: dtolnay/rust-toolchain@stable
85+
with:
86+
components: clippy
87+
88+
- name: Cache Rust
89+
uses: swatinem/rust-cache@v2
90+
with:
91+
workspaces: src-tauri
92+
cache-on-failure: true
93+
94+
- name: Cargo check
95+
working-directory: src-tauri
96+
run: cargo check --all-targets
97+
98+
- name: Cargo test
99+
working-directory: src-tauri
100+
run: cargo test
101+
102+
- name: Cargo clippy
103+
working-directory: src-tauri
104+
run: cargo clippy --all-targets -- -D warnings
105+
106+
rust-windows-check:
107+
name: Rust Windows Smoke Check
108+
runs-on: windows-latest
74109
timeout-minutes: 15
75110
steps:
76111
- name: Checkout
77112
uses: actions/checkout@v4
78113

79-
- name: Setup Bun
80-
uses: oven-sh/setup-bun@v2
114+
- name: Setup Rust
115+
uses: dtolnay/rust-toolchain@stable
81116
with:
82-
bun-version: latest
117+
components: clippy
118+
119+
- name: Cache Rust
120+
uses: swatinem/rust-cache@v2
121+
with:
122+
workspaces: src-tauri
123+
cache-on-failure: true
124+
125+
- name: Cargo check
126+
working-directory: src-tauri
127+
run: cargo check --all-targets
128+
129+
build-check:
130+
name: Verify Tauri Frontend Build
131+
needs: [validate, rust-checks, rust-windows-check]
132+
runs-on: ubuntu-latest
133+
timeout-minutes: 15
134+
steps:
135+
- name: Checkout
136+
uses: actions/checkout@v4
83137

84138
- name: Setup Node.js
85139
uses: actions/setup-node@v4
86140
with:
87141
node-version: 20
142+
cache: npm
88143

89-
- name: Install dependencies
90-
run: bun install --frozen-lockfile
144+
- name: Install npm dependencies
145+
run: npm ci
91146

92-
- name: Build (verify compilation)
93-
run: bun run build
147+
- name: Build Tauri frontend assets
148+
run: npm run build:frontend:tauri

0 commit comments

Comments
 (0)