diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 5f15b9d3..00000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(npm run *)" - ] - } -} diff --git a/.github/workflows/manual-cross-platform-release.yml b/.github/workflows/manual-cross-platform-release.yml index a4325bfb..13680d72 100644 --- a/.github/workflows/manual-cross-platform-release.yml +++ b/.github/workflows/manual-cross-platform-release.yml @@ -18,10 +18,8 @@ jobs: include: - os: windows-latest platform: win - build_command: npx electron-builder --win --x64 --publish never - os: macos-latest platform: mac - build_command: npx electron-builder --mac --publish never runs-on: ${{ matrix.os }} permissions: contents: write @@ -29,42 +27,40 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 11 + - name: Setup Node uses: actions/setup-node@v4 with: node-version: 22 - cache: npm + cache: pnpm - - name: Install dependencies - run: npm ci + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable - - name: Build Electron main process - run: npm run electron:build-main + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + with: + workspaces: src-tauri - - name: Build renderer assets - run: npm run build + - name: Install dependencies + run: pnpm install --frozen-lockfile - - name: Build release packages - env: - CSC_IDENTITY_AUTO_DISCOVERY: "false" - run: ${{ matrix.build_command }} - shell: bash + - name: Build Tauri bundle + run: pnpm tauri:build - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: release-${{ matrix.platform }} - path: | - release/*.exe - release/*.dmg - release/*.zip - release/*.yml - release/*.yaml - release/*.blockmap + path: src-tauri/target/release/bundle/**/* if-no-files-found: error publish: - if: ${{ inputs.publish }} + if: inputs.publish name: Publish GitHub Release needs: build runs-on: ubuntu-latest @@ -74,35 +70,44 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 11 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Download artifacts uses: actions/download-artifact@v4 with: path: release-artifacts - - name: Prepare release metadata + - name: Read version id: meta run: | VERSION=$(node -p "require('./package.json').version") - TAG="v${VERSION}" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT" - - name: Create or update release + - name: Create or update GitHub release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | TAG="${{ steps.meta.outputs.tag }}" - TITLE="Release ${TAG}" if gh release view "$TAG" >/dev/null 2>&1; then echo "Release $TAG already exists; uploading artifacts." else - gh release create "$TAG" --title "$TITLE" --notes "Manual cross-platform build artifacts." + gh release create "$TAG" \ + --title "Release $TAG" \ + --notes "Manual cross-platform Tauri build." fi while IFS= read -r -d '' file; do echo "Uploading $(basename "$file")" gh release upload "$TAG" "$file" --clobber - done < <( - find release-artifacts -type f \ - \( -name '*.exe' -o -name '*.dmg' -o -name '*.zip' -o -name '*.yml' -o -name '*.yaml' -o -name '*.blockmap' \) \ - -print0 - ) + done < <(find release-artifacts -type f \( \ + -name '*.exe' -o -name '*.msi' -o \ + -name '*.dmg' -o -name '*.tar.gz' -o -name '*.zip' \ + \) -print0) diff --git a/.gitignore b/.gitignore index 81a3c688..14d9a31b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,55 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -# Environment variables -.env -.env.local -.env.*.local -.env.production - -node_modules -dist -dist-ssr -electron-dist -release -*.local - -# Claude Code -.claude - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? +# ── Logs ────────────────────────────────────────────────────────────────────── +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# ── Environment variables ────────────────────────────────────────────────────── +.env +.env.local +.env.*.local +.env.production + +# ── Node.js ─────────────────────────────────────────────────────────────────── +node_modules/ + +# ── Frontend build output ────────────────────────────────────────────────────── +dist/ +dist-ssr/ + +# ── Tauri ───────────────────────────────────────────────────────────────────── +# Rust build artifacts — can be several GiB, always regenerated by cargo +src-tauri/target/ + +# Tauri-generated mobile/desktop scaffolding (tauri android/ios init) +src-tauri/gen/ + +# Wix toolchain downloaded by tauri-plugin-bundler for Windows NSIS/MSI +src-tauri/WixTools/ + +# Tauri CLI local cache +.tauri/ + + +# ── Editor ──────────────────────────────────────────────────────────────────── +.vscode/* +!.vscode/extensions.json +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# ── OS ──────────────────────────────────────────────────────────────────────── +.DS_Store +Thumbs.db + +# ── Misc ────────────────────────────────────────────────────────────────────── +*.local + +# ── Claude Code ─────────────────────────────────────────────────────────────── +.claude/ diff --git a/CLAUDE.md b/CLAUDE.md index 5f9efbb0..33bfae09 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,75 +1,64 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This repository is a **Tauri desktop application** for Windows and macOS. ## Commands ```bash -# Development -npm run dev # Vite renderer dev server only -npm run electron:dev-hide # Electron + renderer dev (hidden window) -npm run electron:dev-show # Electron + renderer dev (visible window) -npm start # Alias for electron:dev-hide - -# Build -npm run build # tsc + vite build (renderer) -npm run electron:build-main # Build Electron main process -npm run electron:build # Full Electron distribution build - -# Code quality -npm run lint # ESLint check -npm run format # Prettier + ESLint auto-fix +pnpm dev +pnpm tauri:dev +pnpm build +pnpm tauri:build +pnpm lint +pnpm format ``` ## Architecture -This is an **Electron desktop application** - an AI-powered live interview assistant that provides real-time transcription and AI suggestions during job interviews. +The app is built as a Tauri desktop client with a React frontend. -**Stack:** React 19 + TypeScript + Tailwind CSS + shadcn/ui (renderer), Electron 40 (main), Vite (build). +### Frontend -### Process Split +- `src/` — React, Tailwind, hooks, components, pages. +- `src/lib/tauri-bridge.ts` exposes the IPC compatibility API used by renderer hooks. -``` -src/main/ ← Electron main process (Node.js) -src/renderer/ ← React/Vite frontend -``` - -The path alias `@/*` resolves to `./renderer/*`. - -**Main process** handles: audio capture, WebSocket connections to backend, IPC with renderer, Electron Store persistence, global hotkeys, auto-updates. +### Native Backend -**Renderer** handles: UI, routing, state display. It never calls backend APIs directly - all backend communication goes through IPC to main. +- `src-tauri/src/` — Tauri command handlers, services, state, and native utilities. +- `src-tauri/tauri.conf.json` — macOS and Windows bundle settings. +- `src-tauri/Cargo.toml` — Rust dependency manifest. ### IPC Bridge -[src/main/preload.cts](src/main/preload.cts) exposes `window.electronAPI` to the renderer with namespaced APIs: `config`, `auth`, `payment`, `llm`, `appState`, `transcription`, `liveSuggestion`, `actionSuggestion`, `tools`, `window`, `autoUpdater`, `external`. - -IPC handlers live in [src/main/ipc/](src/main/ipc/) (one file per domain). Services in [src/main/services/](src/main/services/) contain the business logic called by handlers. - -### State Management (Renderer) - -Two distinct stores: - -1. **AppState** ([src/renderer/hooks/use-app-state.tsx](src/renderer/hooks/use-app-state.tsx)) - React Context, synced from main via IPC. Holds real-time interview state: running status, transcripts, AI suggestions, credits, backend health. Read-only in renderer; mutated by main process pushing updates. +- Tauri `invoke()` is exposed through `tauriApi` and assigned to `window.electronAPI` for compatibility. +- Transcription, permissions, payment, config, and window control are handled through Tauri commands. -2. **ConfigStore** ([src/renderer/hooks/use-config-store.ts](src/renderer/hooks/use-config-store.ts)) - Zustand store backed by Electron Store. Holds user settings, auth tokens, audio/video device selection, interview configuration (CV, job description). Persisted to disk. +## Key Implementation Notes -### API Layer (Main Process) +- Electron has been removed from the repository. +- The build flows are now Tauri-first. +- Native audio loopback is implemented in `src-tauri/src/commands/transcription.rs`. +- macOS screen recording permission is validated natively. +- The GitHub Actions workflow builds Tauri bundles for Windows and macOS. -[src/main/api/client.ts](src/main/api/client.ts) - `ApiClient` class: fetch-based, Bearer token auth, streaming support. Wrapped by domain-specific clients: `AuthApi`, `LLMApi`, `PaymentApi`, `HealthCheckApi` in [src/main/api/](src/main/api/). +## Build and Release Workflow -Backend URL is defined in [src/main/consts.ts](src/main/consts.ts). +The workflow at `.github/workflows/manual-cross-platform-release.yml`: -### Routing (Renderer) +- builds on Windows and macOS in parallel +- installs pnpm dependencies +- runs `pnpm tauri:build` (which builds the frontend via `beforeBuildCommand` automatically) +- uploads bundle artifacts +- publishes a GitHub release when the `publish` input is enabled -Hash-based router (required for Electron): `/` → auth flow → `/main` (interview UI) → `/payment`. +## Platform Support -Router defined in [src/renderer/router.tsx](src/renderer/router.tsx). +- Windows 11+ +- macOS 14.4+ -### Key Features +## Notes for Developers -- **Transcription:** Dual-channel (speaker + interviewer mic) via WebSocket streaming - [src/main/services/transcript-service.ts](src/main/services/transcript-service.ts) -- **Live Suggestions:** Real-time AI responses based on CV + job description - [src/main/services/live-suggestion-service.ts](src/main/services/live-suggestion-service.ts) -- **Action Suggestions:** Screenshot-based problem solving (up to 3 images) - [src/main/services/action-suggestion-service.ts](src/main/services/action-suggestion-service.ts) -- **Credits:** Purchase and usage tracking via payment API -- **Auto-Updates:** electron-updater publishing to GitHub releases +- There is no `src/main/` Electron host code in this repo anymore. +- Use the Tauri app as the single desktop implementation. +- Update native dependencies in `src-tauri/Cargo.toml` and frontend dependencies in `package.json`. +- Package manager is pnpm — do not use npm or yarn. diff --git a/README.md b/README.md index 898c4114..b53a1631 100644 --- a/README.md +++ b/README.md @@ -1,193 +1,109 @@ -# Power Interview AI - Privacy-First AI Interview Assistant - -