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:
Cyrus Gray
2026-02-03 05:35:54 +05:30
committed by GitHub
co-authored by Steven Enamakel github-actions[bot] <github-actions[bot]@users.noreply.github.com> Claude
parent 9d7472131f
commit 9b3dfd0c2d
14 changed files with 549 additions and 160 deletions
+56 -28
View File
@@ -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
+47 -25
View File
@@ -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` |
+46 -13
View File
@@ -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
+160
View File
@@ -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.
+78 -23
View File
@@ -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
View File
@@ -1,7 +1,7 @@
{
"name": "alphahuman",
"private": true,
"version": "0.19.0",
"version": "0.20.0",
"type": "module",
"scripts": {
"dev": "vite",
+16 -10
View File
@@ -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 (
+1 -1
View File
@@ -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>
);
+49 -40
View File
@@ -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>
);
}
+16 -8
View File
@@ -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
+41 -2
View File
@@ -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
// -----------------------------------------------------------------------
+4 -2
View File
@@ -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,
});
}
+32 -7
View File
@@ -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;