mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Handling the status of skills (#23)
* chore: bump version to 0.20.0 [skip ci] * revert: remove automatic skill dependency installation system - Removed dependency installation loading state from SkillSetupWizard - Reverted SkillRuntime dependency checking and installation methods - Cleaned up dependency-related imports and event listeners - Documented complete implementation in skills/todo.md for future work The dependency installation system was causing unwanted loading states when configuring skills. All functionality has been properly reverted while preserving implementation details for future development. * Refactor SkillManagementPanel to conditionally show action buttons based on connection status - Added offline and setup-required states with informative messages - Updated SkillSetupModal to use connection status for setup vs. manage mode - Simplified mode logic for better UX and error handling in setup scenarios * Update CLAUDE.md with new features, state slices, and code quality tools - Document additions: Redux aiSlice, skillsSlice, teamSlice, and architecture updates - Add ESLint, Prettier integrations with Husky hooks and GitHub workflows - Update development commands from npm to yarn for consistency - Expand key user groups and revise target audiences - Include enhanced project structure, build outputs, and CI/CD updates * fix: resolve TypeScript compilation error and enhance skill session synchronization - Fix unused parameter error in SkillManager.getSkillLoadParams() by prefixing with underscore - Add support for session parameter passing in SkillRuntime.load() method - Implement skill reloading capability for post-authentication updates - Ensure proper connection status synchronization between skill setup and UI display 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: change skill button text from 'Configure' to 'Manage' for connected skills - Update SkillsGrid button text to dynamically show based on connection status - Connected skills now show 'Manage' button instead of 'Configure' - Provides clearer user indication of skill state - Improves UX for authenticated skills like Telegram 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: update documentation, download system and code formatting improvements - Update Claude rules with improved project overview and command documentation - Enhance download screen with better architecture detection and formatting - Improve device detection utilities with multi-architecture support - Add skills system troubleshooting documentation - Code formatting improvements with better line breaks and spacing - Optimize GitHub release asset parsing for platform-specific downloads 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Steven Enamakel
github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Claude
parent
9d7472131f
commit
9b3dfd0c2d
@@ -11,59 +11,87 @@ This project is a **crypto-focused communication platform** built with Tauri v2,
|
||||
|
||||
## Target Users
|
||||
|
||||
- Traders, Yield Farmers, Investors
|
||||
- Researchers, KOLs, Developers
|
||||
- General crypto community members
|
||||
- **Crypto Professionals**: Traders, Yield Farmers, Investors
|
||||
- **Researchers & Analysts**: KOLs, Developers, Researchers
|
||||
- **Teams & Organizations**: Collaborative workspaces for crypto projects
|
||||
- **General Community**: Crypto enthusiasts and community members
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Layer | Technology | Version | Purpose |
|
||||
| --------------------- | --------------- | ------- | ----------------------- |
|
||||
| Layer | Technology | Version | Purpose |
|
||||
| --------------------- | --------------- | ------- | ------------------------ |
|
||||
| **Frontend Core** |
|
||||
| UI Framework | React | 19.1.0 | Component-based UI |
|
||||
| Language | TypeScript | 5.8.3 | Type safety |
|
||||
| Build Tool | Vite | 7.0.4 | Fast development |
|
||||
| UI Framework | React | 19.1.0 | Component-based UI |
|
||||
| Language | TypeScript | 5.8.3 | Type safety |
|
||||
| Build Tool | Vite | 7.0.4 | Fast development |
|
||||
| **UI & Styling** |
|
||||
| Styling | Tailwind CSS | Latest | Utility-first CSS |
|
||||
| Components | Headless UI | Latest | Accessible components |
|
||||
| Animation | Framer Motion | Latest | Smooth animations |
|
||||
| Styling | Tailwind CSS | Latest | Utility-first CSS |
|
||||
| Components | Headless UI | Latest | Accessible components |
|
||||
| Animation | Framer Motion | Latest | Smooth animations |
|
||||
| **State & Data** |
|
||||
| State Management | Zustand | Latest | Lightweight state |
|
||||
| Data Fetching | TanStack Query | Latest | Server state management |
|
||||
| Form Handling | React Hook Form | Latest | Form validation |
|
||||
| State Management | Redux Toolkit | Latest | Predictable state mgmt |
|
||||
| State Persistence | Redux Persist | Latest | State rehydration |
|
||||
| Data Fetching | TanStack Query | Latest | Server state management |
|
||||
| Form Handling | React Hook Form | Latest | Form validation |
|
||||
| **AI & Intelligence** |
|
||||
| AI Memory | Custom System | Latest | Context & learning |
|
||||
| Entity Graph | Neo4j | Latest | Knowledge relationships |
|
||||
| Embeddings | OpenAI | Latest | Semantic search |
|
||||
| **Communication** |
|
||||
| Real-time | Socket.io | Latest | Live messaging |
|
||||
| Telegram Integration | MTProto | Latest | Deep Telegram access |
|
||||
| MCP Protocol | JSON-RPC 2.0 | Latest | AI tool execution |
|
||||
| **Team & Skills** |
|
||||
| Skills Platform | GitHub Sync | Latest | Dynamic skill loading |
|
||||
| Team Management | REST API | Latest | Multi-user collaboration |
|
||||
| **Backend Core** |
|
||||
| Language | Rust | 1.93.0 | Performance & safety |
|
||||
| Framework | Tauri | 2.x | Cross-platform apps |
|
||||
| Language | Rust | 1.93.0 | Performance & safety |
|
||||
| Framework | Tauri | 2.x | Cross-platform apps |
|
||||
| **Backend Libraries** |
|
||||
| Async Runtime | Tokio | Latest | Async operations |
|
||||
| JSON Handling | Serde JSON | Latest | Serialization |
|
||||
| Database | SQLx + SQLite | Latest | Local storage |
|
||||
| HTTP Client | Reqwest | Latest | API requests |
|
||||
| WebSocket | WebSocket crate | Latest | Real-time messaging |
|
||||
| Utilities | UUID | Latest | Unique identifiers |
|
||||
| Async Runtime | Tokio | Latest | Async operations |
|
||||
| JSON Handling | Serde JSON | Latest | Serialization |
|
||||
| Database | SQLx + SQLite | Latest | Local storage |
|
||||
| HTTP Client | Reqwest | Latest | API requests |
|
||||
| WebSocket | WebSocket crate | Latest | Real-time messaging |
|
||||
| Utilities | UUID | Latest | Unique identifiers |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
tauri-crossplatform-app/
|
||||
frontend-runner-alphahuman/
|
||||
├── .claude/ # Claude AI configuration
|
||||
│ ├── rules/ # Modular documentation
|
||||
│ └── agents/ # Subagent configurations
|
||||
├── src/ # React frontend source
|
||||
│ ├── lib/ # Core libraries
|
||||
│ │ ├── ai/ # AI system (memory, constitution, entities)
|
||||
│ │ └── mcp/ # Model Context Protocol implementation
|
||||
│ ├── components/ # React components
|
||||
│ │ └── settings/ # Settings modal system
|
||||
│ ├── store/ # Redux state management
|
||||
│ ├── services/ # API clients and services
|
||||
│ └── pages/ # Application pages
|
||||
├── src-tauri/ # Rust backend source
|
||||
│ ├── gen/ # Generated platform code
|
||||
│ │ ├── android/ # Android project
|
||||
│ │ └── apple/ # iOS/macOS project
|
||||
│ ├── icons/ # Application icons
|
||||
│ └── src/ # Rust source code
|
||||
├── skills/ # Skills submodule (GitHub synced)
|
||||
├── public/ # Static assets
|
||||
│ └── lottie/ # Animation files
|
||||
├── .github/workflows/ # CI/CD pipelines
|
||||
└── dist/ # Build output
|
||||
```
|
||||
|
||||
## Key Configuration Files
|
||||
|
||||
- `tauri.conf.json` - Tauri configuration
|
||||
- `Cargo.toml` - Rust dependencies
|
||||
- `package.json` - Node.js dependencies
|
||||
- `vite.config.ts` - Vite build configuration
|
||||
- `tsconfig.json` - TypeScript configuration
|
||||
- `tauri.conf.json` - Tauri configuration (app identifier: com.alphahuman.app)
|
||||
- `Cargo.toml` - Rust dependencies and workspace configuration
|
||||
- `package.json` - Node.js dependencies and scripts
|
||||
- `vite.config.ts` - Vite build configuration with Node.js polyfills
|
||||
- `tsconfig.json` - TypeScript configuration with strict settings
|
||||
- `eslint.config.js` - ESLint configuration with ES modules
|
||||
- `.prettierrc` - Code formatting rules
|
||||
- `.husky/` - Git hooks for pre-commit/pre-push quality checks
|
||||
- `CLAUDE.md` - Main project documentation for Claude Code
|
||||
|
||||
@@ -13,53 +13,75 @@ Before running any commands, ensure you have:
|
||||
### Desktop Development
|
||||
|
||||
```bash
|
||||
# Start development server (hot-reload)
|
||||
npm run tauri dev
|
||||
# Frontend dev server only (port 1420)
|
||||
yarn dev
|
||||
|
||||
# Build for production
|
||||
npm run tauri build
|
||||
# Desktop dev with hot-reload (starts Vite + Tauri)
|
||||
yarn tauri dev
|
||||
|
||||
# Production build (TypeScript compile + Vite build + Tauri bundle)
|
||||
yarn tauri build
|
||||
|
||||
# Debug build with .app bundle (required for deep link testing on macOS)
|
||||
yarn tauri build --debug --bundles app
|
||||
yarn macos:dev
|
||||
```
|
||||
|
||||
### Android Development
|
||||
|
||||
```bash
|
||||
# Initialize Android project (first time)
|
||||
npm run tauri android init
|
||||
yarn tauri android init
|
||||
|
||||
# Start Android development
|
||||
npm run tauri android dev
|
||||
yarn tauri android dev
|
||||
|
||||
# Build Android APK/AAB
|
||||
npm run tauri android build
|
||||
yarn tauri android build
|
||||
```
|
||||
|
||||
### iOS Development
|
||||
|
||||
```bash
|
||||
# Initialize iOS project (first time)
|
||||
npm run tauri ios init
|
||||
yarn tauri ios init
|
||||
|
||||
# Start iOS development
|
||||
npm run tauri ios dev
|
||||
yarn tauri ios dev
|
||||
|
||||
# Build iOS app
|
||||
npm run tauri ios build
|
||||
yarn tauri ios build
|
||||
```
|
||||
|
||||
### Frontend Only
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
yarn install
|
||||
|
||||
# Start Vite dev server only
|
||||
npm run dev
|
||||
yarn dev
|
||||
|
||||
# Build frontend only
|
||||
npm run build
|
||||
yarn build
|
||||
|
||||
# Preview production build
|
||||
npm run preview
|
||||
yarn preview
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
|
||||
```bash
|
||||
# Run linting and formatting checks
|
||||
yarn lint
|
||||
yarn format
|
||||
|
||||
# TypeScript compilation check
|
||||
yarn typecheck
|
||||
|
||||
# Rust checks
|
||||
cargo check --manifest-path src-tauri/Cargo.toml
|
||||
cargo clippy --manifest-path src-tauri/Cargo.toml
|
||||
```
|
||||
|
||||
## Stopping Development Servers
|
||||
@@ -67,7 +89,7 @@ npm run preview
|
||||
### Desktop (Tauri Dev)
|
||||
|
||||
```bash
|
||||
# In the terminal running `npm run tauri dev`:
|
||||
# In the terminal running `yarn tauri dev`:
|
||||
Ctrl + C
|
||||
|
||||
# If process is stuck, force kill:
|
||||
@@ -86,7 +108,7 @@ taskkill /PID <PID> /F # Kill by PID
|
||||
### Android Dev Server
|
||||
|
||||
```bash
|
||||
# In the terminal running `npm run tauri android dev`:
|
||||
# In the terminal running `yarn tauri android dev`:
|
||||
Ctrl + C
|
||||
|
||||
# If emulator/device is stuck:
|
||||
@@ -108,7 +130,7 @@ taskkill /F /IM java.exe # Kills Gradle processes
|
||||
### iOS Dev Server
|
||||
|
||||
```bash
|
||||
# In the terminal running `npm run tauri ios dev`:
|
||||
# In the terminal running `yarn tauri ios dev`:
|
||||
Ctrl + C
|
||||
|
||||
# If simulator is stuck:
|
||||
@@ -129,7 +151,7 @@ pkill -f "cargo"
|
||||
### Frontend Only (Vite)
|
||||
|
||||
```bash
|
||||
# In the terminal running `npm run dev`:
|
||||
# In the terminal running `yarn dev`:
|
||||
Ctrl + C
|
||||
|
||||
# If port 1420 is still occupied:
|
||||
@@ -156,10 +178,10 @@ Get-Process | Where-Object {$_.ProcessName -match "tauri|vite|cargo|node"} | Sto
|
||||
|
||||
## Build Targets
|
||||
|
||||
| Platform | Command | Output |
|
||||
| -------- | ----------------------------- | ------------------- |
|
||||
| Windows | `npm run tauri build` | `.msi`, `.exe` |
|
||||
| macOS | `npm run tauri build` | `.dmg`, `.app` |
|
||||
| Linux | `npm run tauri build` | `.deb`, `.AppImage` |
|
||||
| Android | `npm run tauri android build` | `.apk`, `.aab` |
|
||||
| iOS | `npm run tauri ios build` | `.ipa` |
|
||||
| Platform | Command | Output |
|
||||
| -------- | -------------------------- | ------------------- |
|
||||
| Windows | `yarn tauri build` | `.msi`, `.exe` |
|
||||
| macOS | `yarn tauri build` | `.dmg`, `.app` |
|
||||
| Linux | `yarn tauri build` | `.deb`, `.AppImage` |
|
||||
| Android | `yarn tauri android build` | `.apk`, `.aab` |
|
||||
| iOS | `yarn tauri ios build` | `.ipa` |
|
||||
|
||||
@@ -38,14 +38,24 @@ src/
|
||||
│ ├── authSlice.ts # Authentication state
|
||||
│ ├── socketSlice.ts # Socket connection state
|
||||
│ ├── userSlice.ts # User profile state
|
||||
│ ├── aiSlice.ts # AI system state
|
||||
│ ├── skillsSlice.ts # Skills management state
|
||||
│ ├── teamSlice.ts # Team collaboration state
|
||||
│ └── telegram/ # Telegram state management
|
||||
├── services/ # Service layer (singletons)
|
||||
│ ├── apiClient.ts # HTTP REST client
|
||||
│ ├── socketService.ts # Socket.io client
|
||||
│ └── mtprotoService.ts # Telegram MTProto service
|
||||
├── lib/mcp/ # Model Context Protocol system
|
||||
│ ├── transport.ts # Socket.io JSON-RPC transport
|
||||
│ └── telegram/ # 99 Telegram MCP tools
|
||||
├── lib/ # Core libraries
|
||||
│ ├── ai/ # AI system architecture
|
||||
│ │ ├── memory/ # Memory management with encryption
|
||||
│ │ ├── constitution/ # AI behavior rules
|
||||
│ │ ├── entities/ # Entity graph management
|
||||
│ │ ├── sessions/ # Session capture and transcripts
|
||||
│ │ └── providers/ # AI provider abstractions
|
||||
│ └── mcp/ # Model Context Protocol system
|
||||
│ ├── transport.ts # Socket.io JSON-RPC transport
|
||||
│ └── telegram/ # 99 Telegram MCP tools
|
||||
├── pages/ # Route components
|
||||
│ ├── Welcome.tsx # Landing page
|
||||
│ ├── Login.tsx # Authentication
|
||||
@@ -56,11 +66,18 @@ src/
|
||||
│ ├── ProtectedRoute.tsx # Auth-gated routes
|
||||
│ ├── PublicRoute.tsx # Guest-only routes
|
||||
│ ├── ConnectionIndicator.tsx # Status indicators
|
||||
│ ├── SkillsGrid.tsx # Skills catalog and management
|
||||
│ ├── DownloadScreen.tsx # Multi-platform download system
|
||||
│ └── settings/ # Settings modal system
|
||||
│ ├── SettingsModal.tsx # Main container with routing
|
||||
│ ├── SettingsLayout.tsx # Modal wrapper with portal
|
||||
│ ├── SettingsHome.tsx # Main menu with profile
|
||||
│ ├── panels/ConnectionsPanel.tsx # Connection management
|
||||
│ ├── panels/ # Settings panels
|
||||
│ │ ├── ConnectionsPanel.tsx # Connection management
|
||||
│ │ ├── TeamPanel.tsx # Team management
|
||||
│ │ ├── TeamMembersPanel.tsx # Member roles & permissions
|
||||
│ │ ├── TeamInvitesPanel.tsx # Invitation system
|
||||
│ │ └── BillingPanel.tsx # Premium features and billing
|
||||
│ ├── components/ # Menu items, header, back button
|
||||
│ └── hooks/ # Navigation and animation hooks
|
||||
└── utils/ # Utilities and config
|
||||
@@ -70,15 +87,31 @@ src/
|
||||
|
||||
### Recent Architecture Changes
|
||||
|
||||
- **Settings Modal System**: Complete URL-based modal system with clean white design
|
||||
- Modal routes: `/settings`, `/settings/connections` overlaying existing content
|
||||
- Component structure: SettingsModal, SettingsLayout, ConnectionsPanel, hooks
|
||||
- Redux integration: auth, user, telegram state for profile and connection management
|
||||
- **HashRouter**: Switched from BrowserRouter for better desktop app compatibility
|
||||
- **165+ TypeScript files**: Comprehensive component library with settings modal system
|
||||
- **Provider chain**: Redux → PersistGate → Socket → Telegram → HashRouter → Routes
|
||||
- **MCP Integration**: 99 Telegram tools for AI-driven interactions
|
||||
- **Deep Link Auth**: Web-to-desktop handoff using `alphahuman://` scheme
|
||||
- **Code Quality Infrastructure**: ESLint, Prettier, and Husky hooks for automated quality checks
|
||||
- Pre-commit/pre-push hooks with TypeScript compilation validation
|
||||
- Type-only imports standardization and consolidated import statements
|
||||
- GitHub workflow integration with quality gate checks
|
||||
- **Advanced AI System**: Comprehensive artificial intelligence platform
|
||||
- Memory management with encryption, chunking, and hybrid search capabilities
|
||||
- Constitution-based AI behavior with GitHub integration for rule updates
|
||||
- Entity graph migration to Neo4j backend for knowledge relationships
|
||||
- Session capture, transcript management, and tool compression
|
||||
- **Skills Management Platform**: Dynamic skill loading and management system
|
||||
- SkillsGrid with setup status indicators and management controls
|
||||
- GitHub sync integration for skills catalog updates
|
||||
- Conditional rendering (setup wizard vs management panel)
|
||||
- Skills submodule with background update synchronization
|
||||
- **Team Collaboration Features**: Multi-user workspace management system
|
||||
- TeamPanel, TeamMembersPanel, TeamInvitesPanel for comprehensive team management
|
||||
- Role-based permissions and invitation system with Redux state management
|
||||
- Team API integration with CRUD operations and member management
|
||||
- **Enhanced Settings System**: Expanded modal system with multiple management panels
|
||||
- Team management, billing, privacy, and advanced configuration panels
|
||||
- Enhanced URL routing for deep-linking to specific settings sections
|
||||
- Redux integration across auth, user, telegram, ai, skills, and team slices
|
||||
- **200+ TypeScript files**: Comprehensive component and library ecosystem
|
||||
- **Provider chain**: Redux → PersistGate → Socket → Telegram → AI → Skills → HashRouter → Routes
|
||||
- **Enhanced CI/CD**: Python sidecar support, XGH_TOKEN authentication, GitHub Pages deployment
|
||||
|
||||
## React with Tauri
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# Skills System Troubleshooting Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The Skills System is a Python-based plugin architecture that allows AI agents to have domain-specific knowledge, tools, and automated behaviors. Skills run as isolated Python subprocesses and communicate with the main Tauri application via JSON-RPC.
|
||||
|
||||
## Common Issue: "Setup Failed" with Exit Code 1
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Skills modal shows "Setup Failed" with "Skill process exited with code: 1"
|
||||
- Console shows `ModuleNotFoundError: No module named 'pydantic'`
|
||||
- Error paths like `/Users/cyrus/alphahuman/skills/skills/telegram/`
|
||||
- Python import failures and subprocess stderr messages
|
||||
|
||||
### Root Cause Analysis
|
||||
|
||||
**Primary Issue: Missing Skills Git Submodule**
|
||||
The main cause is that the `skills` Git submodule is not initialized. The system expects skills to be available in the `skills/skills/` directory structure but finds an empty directory.
|
||||
|
||||
**Secondary Issues:**
|
||||
|
||||
1. **Missing Python Virtual Environment**: No `.venv` directory in the skills folder
|
||||
2. **Missing Python Dependencies**: Core packages like `pydantic`, `telethon`, `mcp` not installed
|
||||
3. **Incorrect Python Paths**: PYTHONPATH configuration issues
|
||||
|
||||
### Skills System Architecture
|
||||
|
||||
```
|
||||
skills/ # Git submodule root
|
||||
├── .venv/ # Python virtual environment
|
||||
├── requirements.txt # Shared dependencies
|
||||
├── skills/ # Individual skill packages
|
||||
│ ├── telegram/ # Telegram skill
|
||||
│ │ ├── skill.py # Main skill logic
|
||||
│ │ ├── manifest.json # Skill metadata
|
||||
│ │ ├── requirements.txt # Skill-specific dependencies
|
||||
│ │ └── ...
|
||||
│ ├── browser/ # Browser automation skill
|
||||
│ ├── calendar/ # Calendar integration skill
|
||||
│ └── ... # Other skills
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Solution Steps
|
||||
|
||||
#### 1. Initialize Git Submodule
|
||||
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
This downloads the skills repository from `https://github.com/alphahumanxyz/skills`.
|
||||
|
||||
#### 2. Create Python Virtual Environment
|
||||
|
||||
```bash
|
||||
cd skills
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install --upgrade pip
|
||||
```
|
||||
|
||||
#### 3. Install Dependencies
|
||||
|
||||
```bash
|
||||
.venv/bin/pip install -r requirements.txt
|
||||
```
|
||||
|
||||
This installs:
|
||||
|
||||
- **Core Dependencies**: `mcp>=1.0.0`, `pydantic>=2.0`, `aiosqlite>=0.20.0`
|
||||
- **Skill-Specific Dependencies**: Each skill's requirements.txt (telegram, browser, etc.)
|
||||
|
||||
#### 4. Verify Installation
|
||||
|
||||
```bash
|
||||
# Test core imports
|
||||
.venv/bin/python -c "import pydantic, mcp; print('✅ Core dependencies OK')"
|
||||
|
||||
# Test skill import
|
||||
.venv/bin/python -c "import skills.telegram; print('✅ Telegram skill OK')"
|
||||
```
|
||||
|
||||
### How Skills System Works
|
||||
|
||||
#### Development vs Production Paths
|
||||
|
||||
- **Development**: Skills in git submodule at `./skills/skills/`
|
||||
- **Production**: Skills in `~/.alphahuman/skills/`
|
||||
- **Configuration**: `src/lib/skills/paths.ts` handles path resolution
|
||||
|
||||
#### Skill Execution Process
|
||||
|
||||
1. **Discovery**: `SkillProvider` scans for skill manifests
|
||||
2. **Registration**: Skills registered in Redux store
|
||||
3. **Startup**: Python subprocess spawned with proper environment
|
||||
4. **Communication**: JSON-RPC transport over stdin/stdout
|
||||
5. **Setup**: Interactive setup flow if required
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
The system automatically configures:
|
||||
|
||||
- **PYTHONPATH**: Includes skills directory and virtual environment
|
||||
- **Telegram API**: `TELEGRAM_API_ID`, `TELEGRAM_API_HASH`
|
||||
- **Working Directory**: Skills submodule root
|
||||
|
||||
### Verification Commands
|
||||
|
||||
```bash
|
||||
# Check submodule status
|
||||
git submodule status
|
||||
|
||||
# Verify skills directory structure
|
||||
ls -la skills/skills/telegram/
|
||||
|
||||
# Check virtual environment
|
||||
ls -la skills/.venv/
|
||||
|
||||
# Test Python environment
|
||||
cd skills && .venv/bin/python -c "import sys; print('\\n'.join(sys.path))"
|
||||
```
|
||||
|
||||
### Prevention
|
||||
|
||||
To prevent this issue in fresh checkouts:
|
||||
|
||||
1. **Always initialize submodules**:
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules <repo-url>
|
||||
# or after clone:
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
2. **Setup script**: Consider adding to `package.json`:
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"setup": "git submodule update --init && cd skills && python3 -m venv .venv && .venv/bin/pip install -r requirements.txt"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Related Files
|
||||
|
||||
- **Frontend**: `src/lib/skills/` - Skills management system
|
||||
- **Backend**: `src-tauri/src/commands/skills.rs` - Rust skill commands
|
||||
- **Configuration**: `src/utils/config.ts` - Environment variables
|
||||
- **Providers**: `src/providers/SkillProvider.tsx` - Skills lifecycle
|
||||
|
||||
### Expected Behavior After Fix
|
||||
|
||||
1. Skills modal should show "Connect Telegram" instead of error
|
||||
2. No more Python import errors in console
|
||||
3. Skill setup process should work correctly
|
||||
4. Background GitHub sync should function properly
|
||||
|
||||
This fix resolves the fundamental infrastructure issue preventing skills from loading and running properly.
|
||||
@@ -69,7 +69,7 @@ cargo check --manifest-path src-tauri/Cargo.toml
|
||||
cargo clippy --manifest-path src-tauri/Cargo.toml
|
||||
```
|
||||
|
||||
No test framework is currently configured. No ESLint or Prettier configuration exists in the repo.
|
||||
No test framework is currently configured. **ESLint and Prettier are configured** with Husky pre-commit/pre-push hooks for code quality enforcement.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -85,6 +85,9 @@ State lives in `src/store/` using Redux Toolkit slices:
|
||||
- **userSlice** — user profile
|
||||
- **socketSlice** — connection status, socket ID
|
||||
- **telegramSlice** — connection/auth status, chats, messages, threads (selectively persisted; loading/error states excluded)
|
||||
- **aiSlice** — AI system state, memory management, session tracking
|
||||
- **skillsSlice** — skills catalog, setup status, management state
|
||||
- **teamSlice** — team management, member invites, permissions
|
||||
|
||||
Redux Persist stores auth and telegram state (storage backend is configurable; default uses localStorage). The telegram slice has a complex nested structure in `src/store/telegram/` with separate files for types, reducers, extraReducers, and thunks.
|
||||
|
||||
@@ -165,17 +168,43 @@ Key updates from recent commits:
|
||||
|
||||
### Major Additions
|
||||
|
||||
- **Settings Modal System** (`60054d8`): Complete URL-based settings modal with clean white design
|
||||
- Modal infrastructure with backdrop blur and center positioning
|
||||
- User profile integration with Redux state management
|
||||
- Connection management panel reusing onboarding components
|
||||
- URL routing for `/settings` and `/settings/connections` paths
|
||||
- Mobile responsive design with accessibility features
|
||||
- **Type Casting Helpers**: Added for Telegram MTProto API (`5a0425c`)
|
||||
- **Onboarding Refactor**: Updated connection logic and steps (`bd1d240`)
|
||||
- **MCP Tools Enhancement**: Improved type safety and consistency across Telegram tools (`d0e1191`, `86cc53a`)
|
||||
- **App Structure**: Refactored MCPProvider integration (`d7d848d`)
|
||||
- **Big Integer Support**: Consistent handling across all Telegram MCP tools (`0abed4d`)
|
||||
- **ESLint & Prettier Integration** (`5896966`): Complete code quality toolchain
|
||||
- ES module syntax for ESLint configuration with enhanced TypeScript support
|
||||
- Husky pre-commit/pre-push hooks for automatic formatting and linting
|
||||
- Type-only imports standardization across codebase
|
||||
- Consolidated import statements and improved code organization
|
||||
- GitHub workflows updated with Prettier and ESLint checks
|
||||
- **Advanced Skills System** (`10ec1b3`): Comprehensive skill management platform
|
||||
- Dynamic skills loading from local directory via Rust integration
|
||||
- SkillSetupModal with conditional rendering (wizard vs management panel)
|
||||
- Background GitHub sync for skills catalog updates
|
||||
- Skills table with setup status indicators and management controls
|
||||
- Enhanced skill metadata with setup hooks and descriptions
|
||||
- **Team Management Features** (`10ec1b3`): Multi-user collaboration system
|
||||
- TeamPanel, TeamMembersPanel, and TeamInvitesPanel components
|
||||
- Redux state management for teams, members, and invites
|
||||
- Team API integration with CRUD operations
|
||||
- Settings modal routing for team management paths
|
||||
- Role-based permissions and invitation system
|
||||
- **AI System Enhancements**: Advanced memory and session management
|
||||
- Hybrid search with encryption for AI memory
|
||||
- Constitution-based AI behavior with GitHub integration
|
||||
- Entity graph migration to Neo4j backend
|
||||
- Session capture and transcript management
|
||||
- Memory chunking and context formatting
|
||||
- **Enhanced CI/CD Pipeline** (`b1d7bce`): Production-ready deployment
|
||||
- XGH_TOKEN authentication for alphahumanxyz/alphahuman releases
|
||||
- Python sidecar setup and caching for cross-platform builds
|
||||
- Tauri configuration updates (com.alphahuman.app identifier)
|
||||
- GitHub Pages deployment with optimized workflows
|
||||
- Version tagging and environment variable management
|
||||
- **Device Detection & Download System** (`9d74721`, `b5bccd2`): Enhanced multi-architecture download support
|
||||
- Optimized asset parsing using Maps for unique architecture links per platform
|
||||
- Enhanced DownloadScreen.tsx with architecture-specific download options
|
||||
- Improved device detection for Windows, macOS, Linux, and Android platforms
|
||||
- Added preference logic for more specific filenames in asset parsing
|
||||
- Support for multiple architectures (x64, aarch64) with intelligent sorting
|
||||
- **Version Bump**: Project updated to v0.20.0 (`891517c`)
|
||||
|
||||
### Design System Updates
|
||||
|
||||
@@ -188,16 +217,36 @@ Key updates from recent commits:
|
||||
|
||||
### Component Structure
|
||||
|
||||
- **165+ TypeScript files** across `src/` directory (added settings modal system)
|
||||
- **Settings Modal System**: Complete modal infrastructure in `src/components/settings/`
|
||||
- **200+ TypeScript files** across `src/` directory with comprehensive tooling
|
||||
- **AI System Architecture** (`src/lib/ai/`): Advanced artificial intelligence platform
|
||||
- Memory management with encryption, chunking, and hybrid search
|
||||
- Constitution-based behavior with GitHub integration
|
||||
- Entity graph with Neo4j backend integration
|
||||
- Session capture, transcript management, and tool compression
|
||||
- Provider system with OpenAI integration and custom providers
|
||||
- **Skills Management System**: Dynamic skill platform with Rust integration
|
||||
- SkillsGrid.tsx - Skills catalog with setup status and management
|
||||
- SkillSetupModal.tsx - Conditional wizard/management panel rendering
|
||||
- SkillProvider.tsx - GitHub sync and local directory integration
|
||||
- Skills submodule integration with background updates
|
||||
- **Team Collaboration Features**: Multi-user workspace management
|
||||
- TeamPanel.tsx - Team overview with member management
|
||||
- TeamMembersPanel.tsx - Member roles and permissions
|
||||
- TeamInvitesPanel.tsx - Invitation system with role assignment
|
||||
- Team API integration with Redux state management
|
||||
- **Settings Modal System**: Comprehensive configuration interface
|
||||
- SettingsModal.tsx - Main container with URL routing
|
||||
- SettingsLayout.tsx - Modal wrapper with createPortal
|
||||
- SettingsHome.tsx - Main menu with profile and navigation
|
||||
- ConnectionsPanel.tsx - Connection management with status indicators
|
||||
- Enhanced panels: Billing, Team, Connections, Privacy, Profile
|
||||
- Hooks: useSettingsNavigation.ts, useSettingsAnimation.ts
|
||||
- **Onboarding Flow**: Multi-step process with privacy, analytics, and connection steps
|
||||
- **Authentication**: Web-to-desktop handoff using `alphahuman://` scheme
|
||||
- **Connection Management**: Telegram MTProto and Socket.io integration
|
||||
- **Download System**: Enhanced multi-platform distribution
|
||||
- DownloadScreen.tsx - Platform detection with architecture support
|
||||
- deviceDetection.ts - Comprehensive device/architecture utilities
|
||||
- GitHub API integration for real-time release assets
|
||||
- **Code Quality Infrastructure**: ESLint, Prettier, and Husky integration
|
||||
- Pre-commit/pre-push hooks with TypeScript compilation checks
|
||||
- Standardized type-only imports and consolidated statements
|
||||
- GitHub workflow integration with automated quality checks
|
||||
|
||||
## Git Workflow
|
||||
|
||||
@@ -205,10 +254,17 @@ Key updates from recent commits:
|
||||
|
||||
## Key Patterns
|
||||
|
||||
- **Code Quality**: ESLint and Prettier enforce code standards with Husky hooks. Use type-only imports (`import type`) and consolidate imports from same modules.
|
||||
- **No localStorage**: Avoid `localStorage` and `sessionStorage`; use Redux (and persist) for app state. Remove any direct usage when working on affected code.
|
||||
- **Modal System**: Settings modal uses `createPortal` pattern with URL-based routing. Clean white design (not glass morphism) for system settings. Navigate with `/settings` and `/settings/connections` paths.
|
||||
- **AI System Integration**: Use `src/lib/ai/` for memory management, constitution loading, entity queries, and session capture. AI providers abstracted through interface pattern.
|
||||
- **Skills Management**: Skills loaded dynamically from local directory via Rust. Use `SkillProvider` for GitHub sync and `SkillsGrid` for management interface.
|
||||
- **Team Collaboration**: Team features in `src/components/settings/panels/Team*`. Use Redux `teamSlice` for state management and `teamApi` for backend operations.
|
||||
- **Device Detection**: Use `deviceDetection.ts` utilities for platform/architecture detection. Support multiple architectures per platform (x64, aarch64) with intelligent preference logic.
|
||||
- **GitHub Integration**: Fetch release assets via GitHub API (`fetchLatestRelease()`) and parse by architecture (`parseReleaseAssetsByArchitecture()`). Use Maps for efficient unique architecture tracking.
|
||||
- **Download System**: Platform-specific file type support (.exe/.msi for Windows, .dmg for macOS, .AppImage/.deb/.rpm for Linux, .apk for Android) with fallback links.
|
||||
- **Modal System**: Settings modal uses `createPortal` pattern with URL-based routing. Clean white design (not glass morphism) for system settings. Navigate with `/settings` paths for different panels.
|
||||
- **Component Reuse**: Connection management reuses `connectOptions` array and components from onboarding flow. Maintains consistent UX patterns across features.
|
||||
- **Redux Integration**: Settings modal integrates with existing slices - auth for logout, user for profile display, telegram for connection status. No new state management needed.
|
||||
- **Redux Integration**: Multiple slices (auth, user, telegram, ai, skills, team) with Redux Persist. Use typed hooks and selectors. State functions accept optional `userId` param.
|
||||
- **Node polyfills**: Vite config (`vite.config.ts`) polyfills `buffer`, `process`, `util`, `os`, `crypto`, `stream` for the `telegram` package which requires Node APIs.
|
||||
- **Telegram IDs**: Use `big-integer` library, not native JS numbers (Telegram IDs exceed `Number.MAX_SAFE_INTEGER`).
|
||||
- **MCP tool files**: Each tool in `src/lib/mcp/telegram/tools/` exports a handler conforming to `TelegramMCPToolHandler` interface. Tool names are typed in `src/lib/mcp/telegram/types.ts`.
|
||||
@@ -216,8 +272,7 @@ Key updates from recent commits:
|
||||
- **CORS workaround**: External HTTP requests from the WebView hit CORS. Use Rust `reqwest` via Tauri commands instead of browser `fetch()`.
|
||||
- **Hash Routing**: Uses HashRouter for desktop app compatibility and deep link handling.
|
||||
- **Integration Libraries**: Each integration (Telegram, future Gmail, etc.) lives under `src/lib/<integration>/` with its own `state/`, `services/`, `api/` subdirectories. Domain-specific services belong in the integration folder, not in `src/services/` (which holds only cross-cutting services like socketService, apiClient).
|
||||
- **State Layer**: Each integration dispatches Redux changes through state functions in `src/lib/<integration>/state/` — never import Redux actions directly from services or update handlers. State functions accept an optional `userId` param (falls back to `getCurrentUserId()`).
|
||||
- **Unit Tests**: All unit tests live in `__tests__/` folders co-located with the code they test.
|
||||
- **Unit Tests**: All unit tests live in `__tests__/` folders co-located with the code they test. Use Jest with TypeScript support.
|
||||
|
||||
## Platform Gotchas
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "alphahuman",
|
||||
"private": true,
|
||||
"version": "0.19.0",
|
||||
"version": "0.20.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
type Architecture,
|
||||
type ArchitectureDownloadLink,
|
||||
detectPlatform,
|
||||
fetchLatestRelease,
|
||||
getDownloadLink,
|
||||
getPlatformDisplayName,
|
||||
parseReleaseAssets,
|
||||
parseReleaseAssetsByArchitecture,
|
||||
type Architecture,
|
||||
type ArchitectureDownloadLink,
|
||||
type Platform,
|
||||
type PlatformArchitectureLinks,
|
||||
type PlatformDownloadLinks,
|
||||
@@ -33,7 +33,9 @@ const DownloadScreen = () => {
|
||||
const [selectedPlatform, setSelectedPlatform] = useState<Platform | null>(null);
|
||||
const [selectedArchitecture, setSelectedArchitecture] = useState<Architecture | null>(null);
|
||||
const [releaseLinks, setReleaseLinks] = useState<PlatformDownloadLinks | null>(null);
|
||||
const [architectureLinks, setArchitectureLinks] = useState<PlatformArchitectureLinks | null>(null);
|
||||
const [architectureLinks, setArchitectureLinks] = useState<PlatformArchitectureLinks | null>(
|
||||
null
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -63,7 +65,9 @@ const DownloadScreen = () => {
|
||||
const platformArchLinks = archLinks[detected.platform as keyof PlatformArchitectureLinks];
|
||||
if (platformArchLinks && platformArchLinks.length > 0) {
|
||||
// Prefer detected architecture, otherwise use first available
|
||||
const preferredLink = platformArchLinks.find(link => link.architecture === detected.architecture) || platformArchLinks[0];
|
||||
const preferredLink =
|
||||
platformArchLinks.find(link => link.architecture === detected.architecture) ||
|
||||
platformArchLinks[0];
|
||||
setSelectedArchitecture(preferredLink.architecture);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -88,7 +92,8 @@ const DownloadScreen = () => {
|
||||
return getDownloadLink(selectedPlatform || 'unknown', releaseLinks || undefined);
|
||||
}
|
||||
|
||||
const platformArchLinks = architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks];
|
||||
const platformArchLinks =
|
||||
architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks];
|
||||
if (platformArchLinks && selectedArchitecture) {
|
||||
const link = platformArchLinks.find(l => l.architecture === selectedArchitecture);
|
||||
if (link) {
|
||||
@@ -139,9 +144,7 @@ const DownloadScreen = () => {
|
||||
{error && !isLoading && (
|
||||
<div className="mb-6">
|
||||
<div className="bg-red-500/10 border border-red-500/20 rounded-xl p-4">
|
||||
<p className="text-sm text-red-400">
|
||||
{error}. Using fallback download links.
|
||||
</p>
|
||||
<p className="text-sm text-red-400">{error}. Using fallback download links.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -209,9 +212,12 @@ const DownloadScreen = () => {
|
||||
{downloadOptions
|
||||
.filter(opt => opt.platform !== selectedPlatform)
|
||||
.map(option => {
|
||||
const platformArchLinks = architectureLinks?.[option.platform as keyof PlatformArchitectureLinks];
|
||||
const platformArchLinks =
|
||||
architectureLinks?.[option.platform as keyof PlatformArchitectureLinks];
|
||||
const hasValidLink = platformArchLinks && platformArchLinks.length > 0;
|
||||
const defaultLink = platformArchLinks?.[0]?.url || getDownloadLink(option.platform, releaseLinks || undefined);
|
||||
const defaultLink =
|
||||
platformArchLinks?.[0]?.url ||
|
||||
getDownloadLink(option.platform, releaseLinks || undefined);
|
||||
const hasMultipleArchs = platformArchLinks && platformArchLinks.length > 1;
|
||||
|
||||
return (
|
||||
|
||||
@@ -408,7 +408,7 @@ export default function SkillsGrid() {
|
||||
setSetupModalOpen(true);
|
||||
}}
|
||||
className="px-4 py-1.5 text-xs font-medium text-primary-300 bg-primary-500/10 border border-primary-500/30 rounded-lg hover:bg-primary-500/20 transition-colors flex-shrink-0 ml-3">
|
||||
Configure
|
||||
{connectionStatus === 'connected' ? 'Manage' : 'Configure'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -145,50 +145,59 @@ export default function SkillManagementPanel({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Action buttons — single row */}
|
||||
<div className="pt-1">
|
||||
{!confirmDisconnect ? (
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={handleRestart}
|
||||
disabled={restarting}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-stone-700/60 border border-stone-600/50 rounded-xl hover:bg-stone-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{restarting ? "Restarting..." : "Restart"}
|
||||
</button>
|
||||
{onReconfigure && (
|
||||
{/* Action buttons — only show if skill is actually running */}
|
||||
{connectionStatus !== "offline" && connectionStatus !== "setup_required" ? (
|
||||
<div className="pt-1">
|
||||
{!confirmDisconnect ? (
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={onReconfigure}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-primary-300 bg-primary-500/10 border border-primary-500/30 rounded-xl hover:bg-primary-500/20 transition-colors"
|
||||
onClick={handleRestart}
|
||||
disabled={restarting}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-stone-700/60 border border-stone-600/50 rounded-xl hover:bg-stone-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
Re-run Setup
|
||||
{restarting ? "Restarting..." : "Restart"}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setConfirmDisconnect(true)}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-coral-400 bg-coral-500/10 border border-coral-500/30 rounded-xl hover:bg-coral-500/20 transition-colors"
|
||||
>
|
||||
Disconnect
|
||||
</button>
|
||||
{onReconfigure && (
|
||||
<button
|
||||
onClick={onReconfigure}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-primary-300 bg-primary-500/10 border border-primary-500/30 rounded-xl hover:bg-primary-500/20 transition-colors"
|
||||
>
|
||||
Re-run Setup
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setConfirmDisconnect(true)}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-coral-400 bg-coral-500/10 border border-coral-500/30 rounded-xl hover:bg-coral-500/20 transition-colors"
|
||||
>
|
||||
Disconnect
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={() => setConfirmDisconnect(false)}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-stone-400 bg-stone-800/50 border border-stone-700 rounded-xl hover:bg-stone-800 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDisconnect}
|
||||
disabled={disconnecting}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-coral-500 rounded-xl hover:bg-coral-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{disconnecting ? "Disconnecting..." : "Confirm Disconnect"}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
// Show message for offline skills
|
||||
<div className="pt-1">
|
||||
<div className="text-xs text-stone-500 text-center py-2 px-3 bg-stone-800/30 rounded-xl border border-stone-700/30">
|
||||
Skill is offline. Use "Re-run Setup" to reconnect.
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex space-x-2">
|
||||
<button
|
||||
onClick={() => setConfirmDisconnect(false)}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-stone-400 bg-stone-800/50 border border-stone-700 rounded-xl hover:bg-stone-800 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDisconnect}
|
||||
disabled={disconnecting}
|
||||
className="flex-1 px-3 py-2 text-xs font-medium text-white bg-coral-500 rounded-xl hover:bg-coral-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{disconnecting ? "Disconnecting..." : "Confirm Disconnect"}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { useAppSelector } from "../../store/hooks";
|
||||
import { useSkillConnectionStatus } from "../../lib/skills/hooks";
|
||||
import SkillSetupWizard from "./SkillSetupWizard";
|
||||
import SkillManagementPanel from "./SkillManagementPanel";
|
||||
|
||||
@@ -27,13 +28,20 @@ export default function SkillSetupModal({
|
||||
onClose,
|
||||
}: SkillSetupModalProps) {
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
const setupComplete = useAppSelector(
|
||||
(state) => state.skills.skills[skillId]?.setupComplete,
|
||||
);
|
||||
// Skills without setup hooks always go straight to manage mode.
|
||||
const [mode, setMode] = useState<"manage" | "setup">(
|
||||
!hasSetup || setupComplete ? "manage" : "setup",
|
||||
);
|
||||
const skill = useAppSelector((state) => state.skills.skills[skillId]);
|
||||
const connectionStatus = useSkillConnectionStatus(skillId);
|
||||
|
||||
// Simplified mode logic: Only show manage mode when skill is actually working
|
||||
// Everything else (offline, errors, never connected, etc.) goes to setup mode
|
||||
const [mode, setMode] = useState<"manage" | "setup">(() => {
|
||||
// Only show manage mode when the skill is actually working
|
||||
const isWorking = connectionStatus === "connected" || connectionStatus === "connecting";
|
||||
|
||||
// For skills without setup hooks, still need to check if they're working
|
||||
// Show manage mode only if skill is currently working
|
||||
// Everything else goes to setup mode (first-time setup, errors, offline, disconnected)
|
||||
return isWorking ? "manage" : "setup";
|
||||
});
|
||||
|
||||
// Handle escape key
|
||||
useEffect(() => {
|
||||
@@ -137,7 +145,7 @@ export default function SkillSetupModal({
|
||||
<SkillSetupWizard
|
||||
skillId={skillId}
|
||||
onComplete={onClose}
|
||||
onCancel={setupComplete ? () => setMode("manage") : onClose}
|
||||
onCancel={skill?.setupComplete ? () => setMode("manage") : onClose}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -30,6 +30,7 @@ export default function SkillSetupWizard({
|
||||
}: SkillSetupWizardProps) {
|
||||
const [state, setState] = useState<WizardState>({ phase: "loading" });
|
||||
|
||||
|
||||
// Start the skill (if not running) then start the setup flow on mount
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -162,6 +163,7 @@ export default function SkillSetupWizard({
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
case "step":
|
||||
return (
|
||||
<SetupFormRenderer
|
||||
|
||||
@@ -28,6 +28,17 @@ import { TELEGRAM_API_ID, TELEGRAM_API_HASH } from "../../utils/config";
|
||||
class SkillManager {
|
||||
private runtimes = new Map<string, SkillRuntime>();
|
||||
|
||||
/**
|
||||
* Get skill-specific load parameters (e.g., session data for Telegram)
|
||||
*/
|
||||
private getSkillLoadParams(_skillId: string): Record<string, unknown> {
|
||||
const params: Record<string, unknown> = {};
|
||||
|
||||
// For now, just return empty params - skill-specific session data
|
||||
// will be handled through the skill's own setup process
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a discovered skill manifest to Redux.
|
||||
*/
|
||||
@@ -81,8 +92,9 @@ class SkillManager {
|
||||
|
||||
store.dispatch(setSkillStatus({ skillId, status: "running" }));
|
||||
|
||||
// Load the skill
|
||||
await runtime.load();
|
||||
// Load the skill with additional parameters based on skill type
|
||||
const loadParams = this.getSkillLoadParams(manifest.id);
|
||||
await runtime.load(loadParams);
|
||||
|
||||
// Check if setup is needed
|
||||
const state = store.getState();
|
||||
@@ -302,6 +314,33 @@ class SkillManager {
|
||||
return store.getState().skills.skills[skillId]?.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload a skill with updated parameters (e.g., after authentication).
|
||||
*/
|
||||
async reloadSkill(skillId: string): Promise<void> {
|
||||
const runtime = this.runtimes.get(skillId);
|
||||
if (!runtime || !runtime.isRunning) {
|
||||
return; // Skill not running, nothing to reload
|
||||
}
|
||||
|
||||
try {
|
||||
// Get updated load parameters
|
||||
const loadParams = this.getSkillLoadParams(skillId);
|
||||
|
||||
// Reload the skill with new parameters
|
||||
await runtime.load(loadParams);
|
||||
|
||||
// Check if skill needs activation
|
||||
const state = store.getState();
|
||||
const skillState = state.skills.skills[skillId];
|
||||
if (skillState?.setupComplete) {
|
||||
await this.activateSkill(skillId);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error reloading skill ${skillId}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Reverse RPC handling
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@@ -38,6 +38,7 @@ export class SkillRuntime {
|
||||
this.transport.onReverseRpc(handler);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Spawn the skill subprocess.
|
||||
* Uses absolute cwd from the backend so the sidecar finds the skills package.
|
||||
@@ -94,9 +95,9 @@ export class SkillRuntime {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send skill/load with manifest + data dir.
|
||||
* Send skill/load with manifest + data dir + session data.
|
||||
*/
|
||||
async load(): Promise<void> {
|
||||
async load(additionalParams?: Record<string, unknown>): Promise<void> {
|
||||
// Use absolute path from Rust to avoid cwd-relative ambiguity
|
||||
const dataDir = await invoke<string>("skill_data_dir", {
|
||||
skillId: this.manifest.id,
|
||||
@@ -104,6 +105,7 @@ export class SkillRuntime {
|
||||
await this.transport.request("skill/load", {
|
||||
manifest: this.manifest,
|
||||
dataDir,
|
||||
...additionalParams,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,9 @@ export function detectPlatform(): PlatformInfo {
|
||||
* Fetch the latest release from GitHub
|
||||
*/
|
||||
export async function fetchLatestRelease(): Promise<GitHubRelease> {
|
||||
const response = await fetch('https://api.github.com/repos/alphahumanxyz/alphahuman/releases/latest');
|
||||
const response = await fetch(
|
||||
'https://api.github.com/repos/alphahumanxyz/alphahuman/releases/latest'
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch release: ${response.statusText}`);
|
||||
}
|
||||
@@ -185,7 +187,9 @@ export function getArchitectureDisplayName(arch: Architecture): string {
|
||||
/**
|
||||
* Parse GitHub release assets and map them to platforms with architecture support
|
||||
*/
|
||||
export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]): PlatformArchitectureLinks {
|
||||
export function parseReleaseAssetsByArchitecture(
|
||||
assets: GitHubReleaseAsset[]
|
||||
): PlatformArchitectureLinks {
|
||||
const links: PlatformArchitectureLinks = {};
|
||||
|
||||
// Use Maps to track unique architectures per platform
|
||||
@@ -212,21 +216,39 @@ export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]):
|
||||
};
|
||||
|
||||
// Windows: .exe, .msi, .zip (Windows)
|
||||
if (name.includes('windows') || name.includes('.exe') || name.includes('.msi') || (name.includes('.zip') && !name.includes('macos'))) {
|
||||
if (
|
||||
name.includes('windows') ||
|
||||
name.includes('.exe') ||
|
||||
name.includes('.msi') ||
|
||||
(name.includes('.zip') && !name.includes('macos'))
|
||||
) {
|
||||
// Only add if this architecture doesn't exist yet, or prefer more specific filenames
|
||||
if (!windowsMap.has(architecture) || (name.includes('windows') && !windowsMap.get(architecture)?.fileName.toLowerCase().includes('windows'))) {
|
||||
if (
|
||||
!windowsMap.has(architecture) ||
|
||||
(name.includes('windows') &&
|
||||
!windowsMap.get(architecture)?.fileName.toLowerCase().includes('windows'))
|
||||
) {
|
||||
windowsMap.set(architecture, link);
|
||||
}
|
||||
}
|
||||
// macOS: .dmg
|
||||
else if (name.includes('macos') || name.includes('.dmg') || name.includes('darwin')) {
|
||||
// Only add if this architecture doesn't exist yet, or prefer more specific filenames
|
||||
if (!macosMap.has(architecture) || (name.includes('macos') && !macosMap.get(architecture)?.fileName.toLowerCase().includes('macos'))) {
|
||||
if (
|
||||
!macosMap.has(architecture) ||
|
||||
(name.includes('macos') &&
|
||||
!macosMap.get(architecture)?.fileName.toLowerCase().includes('macos'))
|
||||
) {
|
||||
macosMap.set(architecture, link);
|
||||
}
|
||||
}
|
||||
// Linux: .AppImage, .deb, .rpm
|
||||
else if (name.includes('linux') || name.includes('.appimage') || name.includes('.deb') || name.includes('.rpm')) {
|
||||
else if (
|
||||
name.includes('linux') ||
|
||||
name.includes('.appimage') ||
|
||||
name.includes('.deb') ||
|
||||
name.includes('.rpm')
|
||||
) {
|
||||
// Prefer AppImage, then deb, then rpm for the same architecture
|
||||
const existing = linuxMap.get(architecture);
|
||||
if (!existing) {
|
||||
@@ -267,7 +289,10 @@ export function parseReleaseAssetsByArchitecture(assets: GitHubReleaseAsset[]):
|
||||
}
|
||||
|
||||
// Sort architectures: prefer detected architecture, then x64, then aarch64
|
||||
const sortArchitectures = (archLinks: ArchitectureDownloadLink[], preferredArch?: Architecture) => {
|
||||
const sortArchitectures = (
|
||||
archLinks: ArchitectureDownloadLink[],
|
||||
preferredArch?: Architecture
|
||||
) => {
|
||||
return archLinks.sort((a, b) => {
|
||||
if (preferredArch && a.architecture === preferredArch) return -1;
|
||||
if (preferredArch && b.architecture === preferredArch) return 1;
|
||||
|
||||
Reference in New Issue
Block a user