feat: production readiness improvements

## Error Handling
- Add GlobalErrorBoundary with error classification and recovery
- Add custom error types (SecurityError, ConnectionError, TimeoutError)
- Fix ErrorAlert component syntax errors

## Offline Mode
- Add offlineStore for offline state management
- Implement message queue with localStorage persistence
- Add exponential backoff reconnection (1s→60s)
- Add OfflineIndicator component with status display
- Queue messages when offline, auto-retry on reconnect

## Security Hardening
- Add AES-256-GCM encryption for chat history storage
- Add secure API key storage with OS keychain integration
- Add security audit logging system
- Add XSS prevention and input validation utilities
- Add rate limiting and token generation helpers

## CI/CD (Gitea Actions)
- Add .gitea/workflows/ci.yml for continuous integration
- Add .gitea/workflows/release.yml for release automation
- Support Windows Tauri build and release

## UI Components
- Add LoadingSpinner, LoadingOverlay, LoadingDots components
- Add MessageSkeleton, ConversationListSkeleton skeletons
- Add EmptyMessages, EmptyConversations empty states
- Integrate loading states in ChatArea and ConversationList

## E2E Tests
- Fix WebSocket mock for streaming response tests
- Fix approval endpoint route matching
- Add store state exposure for testing
- All 19 core-features tests now passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-22 00:03:22 +08:00
parent ce562e8bfc
commit 185763868a
27 changed files with 5725 additions and 268 deletions

228
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,228 @@
# ZCLAW Continuous Integration Workflow for Gitea
# Runs on every push to main and all pull requests
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
PNPM_VERSION: '9'
RUST_VERSION: '1.78'
jobs:
# ============================================================================
# Lint and Type Check
# ============================================================================
lint:
name: Lint & TypeCheck
runs-on: ubuntu-latest
container:
image: node:20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install root dependencies
run: pnpm install --frozen-lockfile
- name: Install desktop dependencies
working-directory: desktop
run: pnpm install --frozen-lockfile
- name: Type check desktop
working-directory: desktop
run: pnpm typecheck
- name: Type check root
run: pnpm exec tsc --noEmit
# ============================================================================
# Unit Tests
# ============================================================================
test:
name: Unit Tests
runs-on: ubuntu-latest
container:
image: node:20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install root dependencies
run: pnpm install --frozen-lockfile
- name: Install desktop dependencies
working-directory: desktop
run: pnpm install --frozen-lockfile
- name: Run desktop unit tests
working-directory: desktop
run: pnpm test
- name: Run root unit tests
run: pnpm test
# ============================================================================
# Build Verification (Frontend only - no Tauri)
# ============================================================================
build-frontend:
name: Build Frontend
runs-on: ubuntu-latest
container:
image: node:20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install desktop dependencies
working-directory: desktop
run: pnpm install --frozen-lockfile
- name: Build frontend
working-directory: desktop
run: pnpm build
# ============================================================================
# Rust Backend Check
# ============================================================================
rust-check:
name: Rust Check
runs-on: ubuntu-latest
container:
image: rust:1.78
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust components
run: rustup component add clippy rustfmt
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: |
desktop/src-tauri
- name: Check Rust formatting
working-directory: desktop/src-tauri
run: cargo fmt --all -- --check
- name: Run Clippy
working-directory: desktop/src-tauri
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Check Rust build
working-directory: desktop/src-tauri
run: cargo check --all-targets
# ============================================================================
# Security Scan
# ============================================================================
security:
name: Security Scan
runs-on: ubuntu-latest
container:
image: node:20
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: |
pnpm install --frozen-lockfile
cd desktop && pnpm install --frozen-lockfile
- name: Run npm audit (root)
run: pnpm audit --audit-level=high
continue-on-error: true
- name: Run npm audit (desktop)
working-directory: desktop
run: pnpm audit --audit-level=high
continue-on-error: true
# ============================================================================
# E2E Tests (Optional - requires browser)
# ============================================================================
e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: [lint, test]
container:
image: mcr.microsoft.com/playwright:v1.42.0-jammy
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
working-directory: desktop
run: pnpm install --frozen-lockfile
- name: Install Playwright browsers
working-directory: desktop
run: pnpm exec playwright install chromium
- name: Run E2E tests
working-directory: desktop
run: pnpm test:e2e
continue-on-error: true

View File

@@ -0,0 +1,139 @@
# ZCLAW Release Workflow for Gitea
# Builds Tauri application and creates Gitea Release
# Triggered by pushing version tags (e.g., v0.2.0)
name: Release
on:
push:
tags:
- 'v*'
env:
NODE_VERSION: '20'
PNPM_VERSION: '9'
RUST_VERSION: '1.78'
jobs:
# ============================================================================
# Build Tauri Application for Windows
# ============================================================================
build-windows:
name: Build Windows
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Setup Rust
uses: dtolnay/rust-action@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: |
desktop/src-tauri
- name: Install frontend dependencies
working-directory: desktop
run: pnpm install --frozen-lockfile
- name: Prepare OpenFang Runtime
working-directory: desktop
run: pnpm prepare:openfang-runtime
- name: Build Tauri application
working-directory: desktop
run: pnpm tauri:build:bundled
- name: Find installer
id: find-installer
shell: pwsh
run: |
$installer = Get-ChildItem -Path "desktop/src-tauri/target/release/bundle/nsis" -Filter "*.exe" -Recurse | Select-Object -First 1
echo "INSTALLER_PATH=$($installer.FullName)" >> $env:GITEA_OUTPUT
echo "INSTALLER_NAME=$($installer.Name)" >> $env:GITEA_OUTPUT
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: ${{ steps.find-installer.outputs.INSTALLER_PATH }}
retention-days: 30
# ============================================================================
# Create Gitea Release
# ============================================================================
create-release:
name: Create Release
needs: build-windows
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download Windows artifact
uses: actions/download-artifact@v4
with:
name: windows-installer
path: ./artifacts
- name: Get version from tag
id: get_version
run: echo "VERSION=${GITEA_REF#refs/tags/}" >> $GITEA_OUTPUT
- name: Create Gitea Release
uses: actions/gitea-release@v1
with:
tag_name: ${{ gitea.ref_name }}
name: ZCLAW ${{ steps.get_version.outputs.VERSION }}
body: |
## ZCLAW ${{ steps.get_version.outputs.VERSION }}
### Changes
- See CHANGELOG.md for details
### Downloads
- **Windows**: Download the `.exe` installer below
### System Requirements
- Windows 10/11 (64-bit)
draft: true
prerelease: false
files: |
./artifacts/*.exe
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
# ============================================================================
# Build Summary
# ============================================================================
release-summary:
name: Release Summary
needs: [build-windows, create-release]
runs-on: ubuntu-latest
steps:
- name: Release Summary
run: |
echo "## Release Build Complete"
echo ""
echo "**Tag**: ${{ gitea.ref_name }}"
echo ""
echo "### Artifacts"
echo "- Windows installer uploaded to release"
echo ""
echo "### Next Steps"
echo "1. Review the draft release"
echo "2. Update release notes if needed"
echo "3. Publish the release when ready"