From bfaabd3b869f2ce4ce1922b5962b6c5604d6b34a Mon Sep 17 00:00:00 2001 From: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Date: Thu, 26 Mar 2026 17:04:46 -0700 Subject: [PATCH] fix/rename (#20) * chore: update AlphaHuman version to 0.49.3 and configure updater plugin in tauri.conf.json - Bumped the AlphaHuman package version in Cargo.lock to 0.49.3. - Added updater configuration in tauri.conf.json to enable automatic updates with specified endpoints. * refactor: rename AlphaHuman to OpenHuman across the codebase - Updated all instances of "AlphaHuman" to "OpenHuman" in comments, tooltips, and constants to reflect the new branding. - Adjusted relevant documentation and prompts to ensure consistency with the new name. * refactor: update documentation and configurations to reflect OpenHuman branding - Replaced all instances of "AlphaHuman" with "OpenHuman" in documentation, comments, and configuration files to ensure consistency with the new branding. - Updated deep link URLs and related authentication flows to use the new "openhuman://" scheme. - Adjusted paths and references in the skills system and other related files to align with the new project name.te * refactor: standardize OpenHuman references and update configurations - Replaced all instances of "AlphaHuman" with "OpenHuman" across documentation, comments, and configuration files to maintain branding consistency. - Updated URLs and paths to reflect the new "openhuman://" scheme. - Adjusted environment variable names and related settings to align with the new project identity. - Enhanced documentation for clarity and accuracy regarding the OpenHuman framework.r * chore: update subproject commit reference in skills directory * refactor: update backend URL to reflect new service domain - Changed default backend URL from "https://api.openhuman.xyz" to "https://api.tinyhumans.ai" in both JavaScript and Rust configuration files. - Ensured consistency across the codebase regarding the new backend service endpoint. * feat: introduce identity and migration modules for OpenHuman - Added a new identity module to support AIEOS v1.1 JSON format, including structures for identity, psychology, linguistics, motivations, capabilities, physicality, history, and interests. - Implemented a migration module to facilitate data migration from OpenClaw memory, including SQLite and Markdown sources, with detailed reporting on migration statistics and warnings. - Established utility functions for handling multimodal content and image processing within the OpenHuman framework. - Enhanced the agent system with new dispatcher and classifier functionalities to improve tool management and message classification. * chore: remove Android project files and configurations - Deleted various Android project files including .editorconfig, .gitignore, build.gradle.kts, gradle.properties, and others to clean up the project structure. - Removed all related resources, layouts, and source files from the Android app directory to streamline the codebase. - This cleanup is part of a larger effort to refactor and simplify the project structure. * refactor: update login flow and remove Telegram integration - Removed the TelegramLoginButton component and its references from the OAuthLoginSection, streamlining the login options. - Updated the AppRoutes to remove the login route, reflecting changes in the authentication flow. - Enhanced the RotatingTetrahedronCanvas component with improved geometry and lighting effects for better visual presentation. - Adjusted the TypewriterGreeting component's styling for consistency. - Cleaned up the Welcome page to integrate the OAuthLoginSection directly, improving user experience. * chore: update subproject commit reference in skills directory * chore: update test configurations and improve test assertions - Modified test scripts in package.json to use a specific Vitest configuration file for consistency. - Updated assertions in loader tests to ensure loading durations are non-negative. - Enhanced tool loading tests to clarify expected behavior regarding localStorage and cache management. - Adjusted agent tool registry tests to improve error handling and ensure accurate statistics. - Refined device detection tests to reflect updated fallback URLs. * fix: enhance parameter formatting and remove unused components - Updated the `formatParameters` function to handle cases where schema properties are empty, returning a more informative response. - Deleted the `DownloadScreen` component and associated device detection utilities to streamline the codebase and remove unused functionality. - Adjusted tests to reflect changes in the tool loading and agent tool registry, ensuring accuracy in assertions. * chore: simplify Vitest configuration by removing unused include patterns - Updated the Vitest configuration to remove unnecessary test file patterns, streamlining the test setup for better clarity and maintainability. * refactor: update paths and comments for AI configuration and file watching - Modified Vite configuration to ignore only the `src-tauri` directory. - Updated logging messages to reflect the correct path for writing AI configuration files. - Adjusted fetch calls in the file watcher to use the new path for `TOOLS.md`. - Revised comments and logic in Rust code to clarify the handling of AI configuration file paths, including legacy fallback options. * chore: remove unused updater secrets from GitHub Actions workflow - Deleted UPDATER_GIST_URL and UPDATER_GIST_ID environment variables from the package-and-publish workflow, streamlining the configuration. * chore: comment out Vitest thresholds for clarity - Commented out the thresholds section in the Vitest configuration to improve clarity and maintainability, as it is currently not in use. * ran formatter * chore: update updater public key in tauri configuration - Replaced the existing public key in the updater plugin configuration with a new value to ensure proper functionality and security. * chore: update ESLint configuration and refactor components - Added `localStorage` and `sessionStorage` as readonly globals in ESLint configuration for better linting support. - Removed unused imports from `SkillsPanel.tsx` to clean up the code. - Changed the type of `watcherInterval` in `file-watcher.ts` for improved type safety. - Refactored toast management logic in `Intelligence.tsx` to enhance clarity and maintainability. - Simplified import statements in `IntelligenceProvider.tsx` for consistency. - Streamlined object property shorthand in `agentToolRegistry.ts` for cleaner code. * refactor: improve error handling and type safety in Intelligence component - Enhanced toast notification logic to defer state updates, preventing potential issues with setState in effects. - Updated the source filter dispatch to use a more specific type for improved type safety. * refactor: enhance type safety across various components and services - Updated type definitions from `any` to `unknown` in multiple files to improve type safety and prevent potential runtime errors. - Refactored state management in `TauriCommandsPanel` to use more specific types. - Adjusted context and parameters in several interfaces to ensure consistent typing. - Added ESLint directive to `polyfills.ts` for intentional global assignments. - Streamlined type handling in utility functions and API responses for better clarity and maintainability. * refactor: streamline import statements and improve code clarity - Consolidated import statements in `agentToolRegistry.ts` and `intelligenceSlice.ts` for better readability. - Simplified the `createTestStore` function in `test-utils.tsx` to enhance code conciseness. - Cleaned up the `isExecutionStepProgressEvent` function in `intelligence-chat-api.ts` for improved clarity and maintainability. --- .claude/mcp.json | 2 +- .claude/rules/01-project-overview.md | 4 +- .claude/rules/02-development-commands.md | 2 +- .../rules/13-backend-auth-implementation.md | 22 +- .claude/rules/14-deep-link-platform-guide.md | 12 +- .../rules/16-macos-background-execution.md | 4 +- .../rules/17-skills-memory-inference-flow.md | 59 +-- .claude/skills-system-troubleshooting.md | 6 +- .github/workflows/build.yml | 2 +- .github/workflows/package-and-publish.yml | 32 +- .github/workflows/release.yml | 6 +- .github/workflows/test.yml | 2 +- CLAUDE.md | 34 +- CONTRIBUTING.md | 18 +- SECURITY.md | 10 +- docs/ARCHITECTURE.md | 18 +- docs/src-tauri/01-architecture.md | 4 +- docs/src-tauri/02-commands.md | 2 +- docs/src-tauri/README.md | 12 +- docs/src/01-architecture.md | 2 +- docs/src/05-pages-routing.md | 2 +- docs/src/08-hooks-utils.md | 4 +- docs/telegram-login-desktop.md | 24 +- eslint.config.js | 2 + gitbooks/README.md | 40 +- gitbooks/SUMMARY.md | 30 +- gitbooks/legal/privacy-policy.md | 1 - gitbooks/overview/getting-started.md | 64 +-- gitbooks/overview/how-it-works.md | 20 +- gitbooks/overview/platform.md | 10 +- gitbooks/product/platform.md | 30 +- gitbooks/product/pricing.md | 32 +- gitbooks/product/privacy-and-security.md | 68 +-- gitbooks/product/skills-and-integrations.md | 50 +-- gitbooks/product/teams.md | 40 +- gitbooks/resources/faq.md | 120 +++--- gitbooks/technology/architecture.md | 12 +- gitbooks/technology/neocortex.md | 4 +- gitbooks/technology/the-subconscious.md | 8 +- gitbooks/use-cases/overview.md | 36 +- package.json | 13 +- scripts/ci-event.json | 4 +- scripts/e2e-auth.sh | 6 +- scripts/e2e-crypto-payment.sh | 6 +- scripts/e2e-gmail.sh | 6 +- scripts/e2e-login.sh | 6 +- scripts/e2e-notion.sh | 6 +- scripts/e2e-payment.sh | 6 +- scripts/e2e-telegram.sh | 6 +- scripts/prepareTauriConfig.js | 2 +- scripts/tauri_create_dmg.sh | 6 +- scripts/test-ci-local.sh | 4 +- .../__tests__/openClaw-formatter.test.js | 2 +- scripts/tools-generator/discover-tools.js | 8 +- scripts/tools-generator/openClaw-formatter.js | 8 +- scripts/tools-generator/tauri-integration.js | 2 +- skills | 2 +- src-tauri/Cargo.lock | 4 +- src-tauri/Cargo.toml | 30 +- {ai => src-tauri/ai}/AGENTS.md | 8 +- {ai => src-tauri/ai}/BOOTSTRAP.md | 4 +- {ai => src-tauri/ai}/IDENTITY.md | 22 +- {ai => src-tauri/ai}/MEMORY.md | 14 +- {ai => src-tauri/ai}/README.md | 18 +- {ai => src-tauri/ai}/SOUL.md | 8 +- {ai => src-tauri/ai}/TOOLS.md | 8 +- {ai => src-tauri/ai}/USER.md | 11 +- src-tauri/gen/android/.editorconfig | 12 - src-tauri/gen/android/.gitignore | 19 - src-tauri/gen/android/app/.gitignore | 6 - src-tauri/gen/android/app/build.gradle.kts | 73 ---- src-tauri/gen/android/app/proguard-rules.pro | 21 - .../android/app/src/main/AndroidManifest.xml | 48 --- .../java/com/alphahuman/app/MainActivity.kt | 68 --- .../java/com/alphahuman/app/RuntimeService.kt | 91 ---- .../drawable-v24/ic_launcher_foreground.xml | 30 -- .../res/drawable/ic_launcher_background.xml | 170 -------- .../src/main/res/drawable/ic_notification.xml | 11 - .../app/src/main/res/layout/activity_main.xml | 18 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 1553 -> 0 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 6481 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 1356 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1474 -> 0 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 4146 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 1311 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3225 -> 0 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 8905 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 2818 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 5150 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 14088 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 4438 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 7269 -> 0 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 19659 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 6158 -> 0 bytes .../app/src/main/res/values-night/themes.xml | 6 - .../app/src/main/res/values/colors.xml | 10 - .../res/values/ic_launcher_background.xml | 4 - .../app/src/main/res/values/strings.xml | 4 - .../app/src/main/res/values/themes.xml | 6 - .../app/src/main/res/xml/file_paths.xml | 5 - src-tauri/gen/android/build.gradle.kts | 22 - .../gen/android/buildSrc/build.gradle.kts | 23 - .../com/alphahuman/app/kotlin/BuildTask.kt | 68 --- .../com/alphahuman/app/kotlin/RustPlugin.kt | 85 ---- src-tauri/gen/android/gradle.properties | 24 -- .../android/gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - src-tauri/gen/android/gradlew | 185 -------- src-tauri/gen/android/gradlew.bat | 89 ---- src-tauri/gen/android/settings.gradle | 3 - src-tauri/gen/apple/project.yml | 4 +- .../apple/tauri-app.xcodeproj/project.pbxproj | 4 +- src-tauri/src/ai/encryption.rs | 6 +- src-tauri/src/ai/memory_fs.rs | 6 +- src-tauri/src/ai/sessions.rs | 10 +- src-tauri/src/auth/mod.rs | 2 +- src-tauri/src/auth/openai_oauth.rs | 2 +- src-tauri/src/auth/profiles.rs | 2 +- src-tauri/src/bin/alphahuman-core.rs | 7 - .../{alphahuman-cli.rs => openhuman-cli.rs} | 54 +-- src-tauri/src/bin/openhuman-core.rs | 7 + ...covery.rs => openhuman-tools-discovery.rs} | 4 +- src-tauri/src/commands/chat.rs | 37 +- src-tauri/src/commands/mod.rs | 4 +- .../commands/{alphahuman.rs => openhuman.rs} | 134 +++--- src-tauri/src/commands/unified_skills.rs | 8 +- src-tauri/src/core_process.rs | 2 +- src-tauri/src/core_rpc.rs | 2 +- src-tauri/src/core_server.rs | 126 +++--- src-tauri/src/lib.rs | 211 +++++----- src-tauri/src/main.rs | 4 +- src-tauri/src/memory/mod.rs | 8 +- .../{alphahuman => openhuman}/agent/agent.rs | 82 ++-- .../agent/classifier.rs | 4 +- .../agent/dispatcher.rs | 6 +- .../{alphahuman => openhuman}/agent/loop_.rs | 116 +++--- .../agent/memory_loader.rs | 4 +- .../{alphahuman => openhuman}/agent/mod.rs | 0 .../{alphahuman => openhuman}/agent/prompt.rs | 18 +- .../{alphahuman => openhuman}/agent/tests.rs | 14 +- .../{alphahuman => openhuman}/agent/traits.rs | 2 +- .../{alphahuman => openhuman}/approval/mod.rs | 6 +- .../{alphahuman => openhuman}/channels/cli.rs | 0 .../channels/commands.rs | 4 +- .../channels/context.rs | 16 +- .../channels/dingtalk.rs | 8 +- .../channels/discord.rs | 6 +- .../channels/email_channel.rs | 4 +- .../channels/imessage.rs | 2 +- .../{alphahuman => openhuman}/channels/irc.rs | 22 +- .../channels/lark.rs | 22 +- .../channels/linq.rs | 4 +- .../channels/matrix.rs | 2 +- .../channels/mattermost.rs | 2 +- .../{alphahuman => openhuman}/channels/mod.rs | 0 .../channels/prompt.rs | 8 +- .../{alphahuman => openhuman}/channels/qq.rs | 8 +- .../channels/routes.rs | 2 +- .../channels/runtime/dispatch.rs | 16 +- .../channels/runtime/mod.rs | 0 .../channels/runtime/startup.rs | 64 +-- .../channels/runtime/supervision.rs | 8 +- .../channels/signal.rs | 4 +- .../channels/slack.rs | 2 +- .../channels/telegram.rs | 18 +- .../channels/tests/common.rs | 10 +- .../channels/tests/context.rs | 10 +- .../channels/tests/health.rs | 2 +- .../channels/tests/identity.rs | 10 +- .../channels/tests/memory.rs | 10 +- .../channels/tests/mod.rs | 0 .../channels/tests/prompt.rs | 8 +- .../channels/tests/runtime_dispatch.rs | 12 +- .../channels/tests/runtime_tool_calls.rs | 30 +- .../channels/traits.rs | 0 .../channels/whatsapp.rs | 6 +- .../channels/whatsapp_storage.rs | 4 +- .../channels/whatsapp_web.rs | 4 +- .../config/daemon.rs | 16 +- .../{alphahuman => openhuman}/config/mod.rs | 2 +- .../config/schema/agent.rs | 0 .../config/schema/autonomy.rs | 2 +- .../config/schema/channels.rs | 2 +- .../config/schema/defaults.rs | 0 .../config/schema/gateway.rs | 0 .../config/schema/hardware.rs | 0 .../config/schema/heartbeat_cron.rs | 0 .../config/schema/identity_cost.rs | 0 .../config/schema/load.rs | 98 ++--- .../config/schema/mod.rs | 6 +- .../config/schema/observability.rs | 2 +- .../config/schema/proxy.rs | 8 +- .../config/schema/routes.rs | 0 .../config/schema/runtime.rs | 0 .../config/schema/storage_memory.rs | 0 .../config/schema/tools.rs | 0 .../config/schema/tunnel.rs | 0 .../src/{alphahuman => openhuman}/cost/mod.rs | 0 .../{alphahuman => openhuman}/cost/tracker.rs | 4 +- .../{alphahuman => openhuman}/cost/types.rs | 0 .../src/{alphahuman => openhuman}/cron/mod.rs | 4 +- .../cron/schedule.rs | 2 +- .../cron/scheduler.rs | 32 +- .../{alphahuman => openhuman}/cron/store.rs | 6 +- .../{alphahuman => openhuman}/cron/types.rs | 0 .../{alphahuman => openhuman}/daemon/mod.rs | 94 ++--- .../{alphahuman => openhuman}/doctor/mod.rs | 14 +- .../gateway/client.rs | 0 .../gateway/constants.rs | 2 +- .../gateway/handlers/health.rs | 6 +- .../gateway/handlers/linq.rs | 14 +- .../gateway/handlers/mod.rs | 0 .../gateway/handlers/pair.rs | 10 +- .../gateway/handlers/webhook.rs | 38 +- .../gateway/handlers/whatsapp.rs | 16 +- .../{alphahuman => openhuman}/gateway/mod.rs | 0 .../gateway/models.rs | 0 .../gateway/rate_limit.rs | 4 +- .../gateway/server.rs | 44 +- .../gateway/state.rs | 14 +- .../gateway/tests.rs | 34 +- .../hardware/discover.rs | 0 .../hardware/introspect.rs | 0 .../{alphahuman => openhuman}/hardware/mod.rs | 2 +- .../hardware/registry.rs | 0 .../{alphahuman => openhuman}/health/mod.rs | 6 +- .../heartbeat/engine.rs | 18 +- .../heartbeat/mod.rs | 6 +- .../src/{alphahuman => openhuman}/identity.rs | 8 +- .../integrations/mod.rs | 2 +- .../integrations/registry.rs | 6 +- .../memory/backend.rs | 0 .../memory/chunker.rs | 0 .../memory/embeddings.rs | 2 +- .../memory/hygiene.rs | 4 +- .../{alphahuman => openhuman}/memory/lucid.rs | 12 +- .../memory/markdown.rs | 0 .../{alphahuman => openhuman}/memory/mod.rs | 4 +- .../{alphahuman => openhuman}/memory/none.rs | 0 .../memory/postgres.rs | 0 .../memory/response_cache.rs | 0 .../memory/snapshot.rs | 12 +- .../memory/sqlite.rs | 0 .../memory/traits.rs | 0 .../memory/vector.rs | 0 .../{alphahuman => openhuman}/migration.rs | 8 +- .../src/{alphahuman => openhuman}/mod.rs | 4 +- .../{alphahuman => openhuman}/multimodal.rs | 4 +- .../observability/log.rs | 0 .../observability/mod.rs | 2 +- .../observability/multi.rs | 0 .../observability/noop.rs | 0 .../observability/otel.rs | 36 +- .../observability/prometheus.rs | 42 +- .../observability/traits.rs | 0 .../observability/verbose.rs | 0 .../{alphahuman => openhuman}/onboard/mod.rs | 2 +- .../onboard/models.rs | 4 +- .../peripherals/arduino_flash.rs | 18 +- .../peripherals/arduino_upload.rs | 8 +- .../peripherals/capabilities_tool.rs | 2 +- .../peripherals/mod.rs | 10 +- .../peripherals/nucleo_flash.rs | 16 +- .../peripherals/rpi.rs | 6 +- .../peripherals/serial.rs | 4 +- .../peripherals/traits.rs | 2 +- .../peripherals/uno_q_bridge.rs | 8 +- .../peripherals/uno_q_setup.rs | 24 +- .../providers/anthropic.rs | 12 +- .../providers/bedrock.rs | 8 +- .../providers/compatible.rs | 24 +- .../providers/copilot.rs | 12 +- .../providers/gemini.rs | 4 +- .../providers/glm.rs | 4 +- .../providers/mod.rs | 38 +- .../providers/ollama.rs | 8 +- .../providers/openai.rs | 10 +- .../providers/openai_codex.rs | 20 +- .../providers/openrouter.rs | 24 +- .../providers/reliable.rs | 0 .../providers/router.rs | 0 .../providers/traits.rs | 4 +- .../src/{alphahuman => openhuman}/rag/mod.rs | 2 +- .../runtime/docker.rs | 6 +- .../{alphahuman => openhuman}/runtime/mod.rs | 2 +- .../runtime/native.rs | 8 +- .../runtime/traits.rs | 0 .../{alphahuman => openhuman}/runtime/wasm.rs | 10 +- .../security/audit.rs | 12 +- .../security/bubblewrap.rs | 2 +- .../security/detect.rs | 6 +- .../security/docker.rs | 2 +- .../security/firejail.rs | 2 +- .../security/landlock.rs | 2 +- .../{alphahuman => openhuman}/security/mod.rs | 0 .../security/pairing.rs | 10 +- .../security/policy.rs | 36 +- .../security/secrets.rs | 8 +- .../security/traits.rs | 0 .../{alphahuman => openhuman}/service/mod.rs | 40 +- .../skillforge/evaluate.rs | 2 +- .../skillforge/integrate.rs | 10 +- .../skillforge/mod.rs | 2 +- .../skillforge/scout.rs | 4 +- .../{alphahuman => openhuman}/skills/mod.rs | 18 +- .../skills/symlink_tests.rs | 2 +- .../tools/browser.rs | 16 +- .../tools/browser_open.rs | 4 +- .../tools/composio.rs | 10 +- .../tools/cron_add.rs | 10 +- .../tools/cron_list.rs | 6 +- .../tools/cron_remove.rs | 6 +- .../tools/cron_run.rs | 6 +- .../tools/cron_runs.rs | 6 +- .../tools/cron_update.rs | 8 +- .../tools/delegate.rs | 10 +- .../tools/file_read.rs | 24 +- .../tools/file_write.rs | 24 +- .../tools/git_operations.rs | 4 +- .../tools/hardware_board_info.rs | 0 .../tools/hardware_memory_map.rs | 0 .../tools/hardware_memory_read.rs | 0 .../tools/http_request.rs | 6 +- .../tools/image_info.rs | 8 +- .../tools/memory_forget.rs | 10 +- .../tools/memory_recall.rs | 4 +- .../tools/memory_store.rs | 10 +- .../{alphahuman => openhuman}/tools/mod.rs | 42 +- .../tools/proxy_config.rs | 16 +- .../tools/pushover.rs | 6 +- .../tools/schedule.rs | 10 +- .../{alphahuman => openhuman}/tools/schema.rs | 2 +- .../tools/screenshot.rs | 4 +- .../{alphahuman => openhuman}/tools/shell.rs | 18 +- .../{alphahuman => openhuman}/tools/traits.rs | 0 .../tools/web_search_tool.rs | 0 .../tunnel/cloudflare.rs | 0 .../tunnel/custom.rs | 2 +- .../{alphahuman => openhuman}/tunnel/mod.rs | 4 +- .../{alphahuman => openhuman}/tunnel/ngrok.rs | 0 .../{alphahuman => openhuman}/tunnel/none.rs | 0 .../tunnel/tailscale.rs | 0 .../src/{alphahuman => openhuman}/util.rs | 4 +- src-tauri/src/runtime/bridge/db.rs | 2 +- src-tauri/src/runtime/bridge/log_bridge.rs | 2 +- src-tauri/src/runtime/bridge/store.rs | 2 +- src-tauri/src/runtime/loader.rs | 4 +- src-tauri/src/runtime/manifest.rs | 4 +- src-tauri/src/runtime/types.rs | 4 +- .../src/services/quickjs_libs/bootstrap.js | 8 +- src-tauri/src/unified_skills/generator.rs | 18 +- src-tauri/src/unified_skills/llm_generator.rs | 6 +- src-tauri/src/unified_skills/mod.rs | 40 +- .../src/unified_skills/openclaw_executor.rs | 2 +- src-tauri/src/unified_skills/self_evolve.rs | 2 +- src-tauri/src/utils/config.rs | 6 +- src-tauri/tauri.conf.json | 11 +- src/AppRoutes.tsx | 9 - src/components/DownloadScreen.tsx | 267 ------------ src/components/RotatingTetrahedronCanvas.tsx | 98 +++-- src/components/SkillsGrid.tsx | 15 +- src/components/TelegramLoginButton.tsx | 42 -- src/components/TypewriterGreeting.tsx | 2 +- src/components/intelligence/mockData.ts | 2 +- src/components/oauth/OAuthLoginSection.tsx | 38 +- src/components/oauth/OAuthProviderButton.tsx | 6 +- src/components/settings/SettingsHome.tsx | 22 +- .../settings/panels/AgentChatPanel.tsx | 6 +- .../settings/panels/DeveloperOptionsPanel.tsx | 2 +- .../settings/panels/MemoryDebugPanel.tsx | 16 +- .../settings/panels/SkillsPanel.tsx | 26 +- .../settings/panels/TauriCommandsPanel.tsx | 88 ++-- .../panels/__tests__/memoryDebugUtils.test.ts | 1 - .../panels/components/SectionCard.tsx | 4 +- src/components/skills/SkillSetupModal.tsx | 4 +- src/components/skills/shared.tsx | 2 +- src/hooks/useDaemonHealth.ts | 20 +- src/hooks/useIntelligenceApiFallback.ts | 131 +++--- src/hooks/useIntelligenceSocket.ts | 224 +++++----- src/lib/ai/__tests__/loader.test.ts | 4 +- .../ai/constitution/__tests__/loader.test.ts | 2 +- src/lib/ai/constitution/loader.ts | 2 +- src/lib/ai/loader.ts | 2 +- src/lib/ai/memory/manager.ts | 2 +- src/lib/ai/memory/schema.ts | 2 +- src/lib/ai/memory/types.ts | 2 +- src/lib/ai/openclaw-loader.ts | 14 +- src/lib/ai/soul/loader.ts | 6 +- src/lib/ai/tools/__tests__/loader.test.ts | 35 +- src/lib/ai/tools/loader.ts | 14 +- src/lib/intelligence/chatTools.ts | 4 +- src/lib/skills/types.ts | 5 +- src/lib/tools/auto-update.ts | 17 +- src/lib/tools/file-watcher.ts | 6 +- src/pages/Intelligence.tsx | 170 ++++---- src/pages/Login.tsx | 42 -- src/pages/Settings.tsx | 4 +- src/pages/Welcome.tsx | 30 +- src/pages/skillsSyncUi.ts | 10 +- src/polyfills.ts | 1 + src/providers/IntelligenceProvider.tsx | 11 +- src/providers/SocketProvider.tsx | 2 +- .../__tests__/agentToolRegistry.test.ts | 42 +- src/services/agentToolRegistry.ts | 26 +- src/services/api/inferenceApi.ts | 2 +- src/services/chatService.ts | 7 +- src/services/daemonHealthService.ts | 12 +- src/services/intelligenceApi.ts | 33 +- src/store/__tests__/aiSlice.test.ts | 4 +- src/store/aiSlice.ts | 2 +- src/store/intelligenceSlice.ts | 77 ++-- src/test/test-utils.tsx | 21 +- src/types/agent.ts | 2 +- src/types/intelligence-chat-api.ts | 59 ++- src/utils/__tests__/deviceDetection.test.ts | 118 ------ src/utils/config.ts | 5 - src/utils/cryptoKeys.ts | 2 +- src/utils/desktopDeepLinkListener.ts | 2 +- src/utils/deviceDetection.ts | 394 ------------------ src/utils/intelligenceTransforms.ts | 103 ++--- src/utils/tauriCommands.ts | 108 +++-- test/e2e/helpers/app-helpers.ts | 2 +- test/e2e/helpers/deep-link-helpers.ts | 4 +- test/e2e/mock-server.ts | 4 +- test/e2e/specs/auth-access-control.spec.ts | 6 +- test/e2e/specs/card-payment-flow.spec.ts | 2 +- test/e2e/specs/crypto-payment-flow.spec.ts | 2 +- test/e2e/specs/gmail-flow.spec.ts | 2 +- test/e2e/specs/login-flow.spec.ts | 4 +- test/e2e/specs/notion-flow.spec.ts | 2 +- test/e2e/specs/telegram-flow.spec.ts | 56 +-- test/vitest.config.ts | 12 +- test/wdio.conf.ts | 6 +- tsconfig.json | 2 +- vite.config.ts | 6 +- 436 files changed, 2714 insertions(+), 4734 deletions(-) rename {ai => src-tauri/ai}/AGENTS.md (98%) rename {ai => src-tauri/ai}/BOOTSTRAP.md (95%) rename {ai => src-tauri/ai}/IDENTITY.md (53%) rename {ai => src-tauri/ai}/MEMORY.md (96%) rename {ai => src-tauri/ai}/README.md (80%) rename {ai => src-tauri/ai}/SOUL.md (94%) rename {ai => src-tauri/ai}/TOOLS.md (93%) rename {ai => src-tauri/ai}/USER.md (97%) delete mode 100644 src-tauri/gen/android/.editorconfig delete mode 100644 src-tauri/gen/android/.gitignore delete mode 100644 src-tauri/gen/android/app/.gitignore delete mode 100644 src-tauri/gen/android/app/build.gradle.kts delete mode 100644 src-tauri/gen/android/app/proguard-rules.pro delete mode 100644 src-tauri/gen/android/app/src/main/AndroidManifest.xml delete mode 100644 src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt delete mode 100644 src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt delete mode 100644 src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/layout/activity_main.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png delete mode 100644 src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 src-tauri/gen/android/app/src/main/res/values-night/themes.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/values/colors.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/values/strings.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/values/themes.xml delete mode 100644 src-tauri/gen/android/app/src/main/res/xml/file_paths.xml delete mode 100644 src-tauri/gen/android/build.gradle.kts delete mode 100644 src-tauri/gen/android/buildSrc/build.gradle.kts delete mode 100644 src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt delete mode 100644 src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt delete mode 100644 src-tauri/gen/android/gradle.properties delete mode 100644 src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties delete mode 100755 src-tauri/gen/android/gradlew delete mode 100644 src-tauri/gen/android/gradlew.bat delete mode 100644 src-tauri/gen/android/settings.gradle delete mode 100644 src-tauri/src/bin/alphahuman-core.rs rename src-tauri/src/bin/{alphahuman-cli.rs => openhuman-cli.rs} (84%) create mode 100644 src-tauri/src/bin/openhuman-core.rs rename src-tauri/src/bin/{alphahuman-tools-discovery.rs => openhuman-tools-discovery.rs} (99%) rename src-tauri/src/commands/{alphahuman.rs => openhuman.rs} (73%) rename src-tauri/src/{alphahuman => openhuman}/agent/agent.rs (88%) rename src-tauri/src/{alphahuman => openhuman}/agent/classifier.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/agent/dispatcher.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/agent/loop_.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/agent/memory_loader.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/agent/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/agent/prompt.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/agent/tests.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/agent/traits.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/approval/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/channels/cli.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/channels/commands.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/context.rs (92%) rename src-tauri/src/{alphahuman => openhuman}/channels/dingtalk.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/channels/discord.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/email_channel.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/imessage.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/irc.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/channels/lark.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/channels/linq.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/matrix.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/mattermost.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/channels/prompt.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/channels/qq.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/channels/routes.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/runtime/dispatch.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/channels/runtime/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/channels/runtime/startup.rs (90%) rename src-tauri/src/{alphahuman => openhuman}/channels/runtime/supervision.rs (86%) rename src-tauri/src/{alphahuman => openhuman}/channels/signal.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/slack.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/telegram.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/common.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/context.rs (90%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/health.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/identity.rs (94%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/memory.rs (94%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/prompt.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/runtime_dispatch.rs (91%) rename src-tauri/src/{alphahuman => openhuman}/channels/tests/runtime_tool_calls.rs (93%) rename src-tauri/src/{alphahuman => openhuman}/channels/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/channels/whatsapp.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/whatsapp_storage.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/channels/whatsapp_web.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/config/daemon.rs (77%) rename src-tauri/src/{alphahuman => openhuman}/config/mod.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/agent.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/autonomy.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/channels.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/defaults.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/gateway.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/hardware.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/heartbeat_cron.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/identity_cost.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/load.rs (85%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/mod.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/observability.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/proxy.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/routes.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/runtime.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/storage_memory.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/tools.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/config/schema/tunnel.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/cost/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/cost/tracker.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/cost/types.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/cron/mod.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/cron/schedule.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/cron/scheduler.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/cron/store.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/cron/types.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/daemon/mod.rs (76%) rename src-tauri/src/{alphahuman => openhuman}/doctor/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/gateway/client.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/gateway/constants.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/health.rs (84%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/linq.rs (90%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/pair.rs (92%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/webhook.rs (84%) rename src-tauri/src/{alphahuman => openhuman}/gateway/handlers/whatsapp.rs (92%) rename src-tauri/src/{alphahuman => openhuman}/gateway/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/gateway/models.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/gateway/rate_limit.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/gateway/server.rs (87%) rename src-tauri/src/{alphahuman => openhuman}/gateway/state.rs (72%) rename src-tauri/src/{alphahuman => openhuman}/gateway/tests.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/hardware/discover.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/hardware/introspect.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/hardware/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/hardware/registry.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/health/mod.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/heartbeat/engine.rs (92%) rename src-tauri/src/{alphahuman => openhuman}/heartbeat/mod.rs (81%) rename src-tauri/src/{alphahuman => openhuman}/identity.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/integrations/mod.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/integrations/registry.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/memory/backend.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/chunker.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/embeddings.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/memory/hygiene.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/memory/lucid.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/memory/markdown.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/memory/none.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/postgres.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/response_cache.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/snapshot.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/memory/sqlite.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/memory/vector.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/migration.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/mod.rs (89%) rename src-tauri/src/{alphahuman => openhuman}/multimodal.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/observability/log.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/observability/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/observability/multi.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/observability/noop.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/observability/otel.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/observability/prometheus.rs (87%) rename src-tauri/src/{alphahuman => openhuman}/observability/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/observability/verbose.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/onboard/mod.rs (90%) rename src-tauri/src/{alphahuman => openhuman}/onboard/models.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/arduino_flash.rs (86%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/arduino_upload.rs (94%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/capabilities_tool.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/mod.rs (93%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/nucleo_flash.rs (82%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/rpi.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/serial.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/traits.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/uno_q_bridge.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/peripherals/uno_q_setup.rs (82%) rename src-tauri/src/{alphahuman => openhuman}/providers/anthropic.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/bedrock.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/providers/compatible.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/copilot.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/gemini.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/providers/glm.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/ollama.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/providers/openai.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/providers/openai_codex.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/providers/openrouter.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/providers/reliable.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/providers/router.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/providers/traits.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/rag/mod.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/runtime/docker.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/runtime/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/runtime/native.rs (90%) rename src-tauri/src/{alphahuman => openhuman}/runtime/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/runtime/wasm.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/security/audit.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/security/bubblewrap.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/security/detect.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/security/docker.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/security/firejail.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/security/landlock.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/security/mod.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/security/pairing.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/security/policy.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/security/secrets.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/security/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/service/mod.rs (94%) rename src-tauri/src/{alphahuman => openhuman}/skillforge/evaluate.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/skillforge/integrate.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/skillforge/mod.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/skillforge/scout.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/skills/mod.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/skills/symlink_tests.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/browser.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/browser_open.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/composio.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_add.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_list.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_remove.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_run.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_runs.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/tools/cron_update.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/tools/delegate.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tools/file_read.rs (93%) rename src-tauri/src/{alphahuman => openhuman}/tools/file_write.rs (93%) rename src-tauri/src/{alphahuman => openhuman}/tools/git_operations.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/hardware_board_info.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tools/hardware_memory_map.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tools/hardware_memory_read.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tools/http_request.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/image_info.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tools/memory_forget.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/tools/memory_recall.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/tools/memory_store.rs (96%) rename src-tauri/src/{alphahuman => openhuman}/tools/mod.rs (91%) rename src-tauri/src/{alphahuman => openhuman}/tools/proxy_config.rs (97%) rename src-tauri/src/{alphahuman => openhuman}/tools/pushover.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tools/schedule.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tools/schema.rs (99%) rename src-tauri/src/{alphahuman => openhuman}/tools/screenshot.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tools/shell.rs (95%) rename src-tauri/src/{alphahuman => openhuman}/tools/traits.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tools/web_search_tool.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/cloudflare.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/custom.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/mod.rs (98%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/ngrok.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/none.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/tunnel/tailscale.rs (100%) rename src-tauri/src/{alphahuman => openhuman}/util.rs (97%) delete mode 100644 src/components/DownloadScreen.tsx delete mode 100644 src/components/TelegramLoginButton.tsx delete mode 100644 src/pages/Login.tsx delete mode 100644 src/utils/__tests__/deviceDetection.test.ts delete mode 100644 src/utils/deviceDetection.ts diff --git a/.claude/mcp.json b/.claude/mcp.json index 81364bdd8..277218e6e 100644 --- a/.claude/mcp.json +++ b/.claude/mcp.json @@ -1 +1 @@ -{ "mcpServers": { "alphaHuman": { "type": "http", "url": "https://alphahuman.readme.io/mcp" } } } +{ "mcpServers": { "alphahuman": { "type": "http", "url": "https://openhuman.readme.io/mcp" } } } diff --git a/.claude/rules/01-project-overview.md b/.claude/rules/01-project-overview.md index b2a140536..c8c066855 100644 --- a/.claude/rules/01-project-overview.md +++ b/.claude/rules/01-project-overview.md @@ -58,7 +58,7 @@ This project is a **crypto-focused communication platform** built with Tauri v2, ## Project Structure ``` -frontend-runner-alphahuman/ +frontend-runner-openhuman/ ├── .claude/ # Claude AI configuration │ ├── rules/ # Modular documentation │ └── agents/ # Subagent configurations @@ -86,7 +86,7 @@ frontend-runner-alphahuman/ ## Key Configuration Files -- `tauri.conf.json` - Tauri configuration (app identifier: com.alphahuman.app) +- `tauri.conf.json` - Tauri configuration (app identifier: com.openhuman.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 diff --git a/.claude/rules/02-development-commands.md b/.claude/rules/02-development-commands.md index 3e7215263..0afea20c3 100644 --- a/.claude/rules/02-development-commands.md +++ b/.claude/rules/02-development-commands.md @@ -116,7 +116,7 @@ adb kill-server # Stop ADB server adb start-server # Restart ADB server # Force stop app on device: -adb shell am force-stop com.alphahuman.app +adb shell am force-stop com.openhuman.app # Kill Gradle daemon if stuck: # macOS/Linux: diff --git a/.claude/rules/13-backend-auth-implementation.md b/.claude/rules/13-backend-auth-implementation.md index 3d5b232a2..0f0999993 100644 --- a/.claude/rules/13-backend-auth-implementation.md +++ b/.claude/rules/13-backend-auth-implementation.md @@ -24,7 +24,7 @@ Web Browser Backend Server Desktop App (Tauri │<─────────────────────────────│ │ │ │ │ │ 5. Redirect to │ │ - │ alphahuman://auth?token= │ │ + │ openhuman://auth?token= │ │ │─────────────────────────────────────────────────────────────>│ │ │ │ │ │ 6. Rust invoke │ @@ -58,7 +58,7 @@ Initiates Telegram OAuth. The frontend opens this URL in the system browser. 2. On callback, validate Telegram user data 3. Create or find user in database 4. Generate a short-lived `loginToken` (single-use, 5-minute TTL) -5. Redirect to `alphahuman://auth?token=` +5. Redirect to `openhuman://auth?token=` ### 2. `POST /api/auth/web-complete` @@ -181,7 +181,7 @@ Called by the Tauri Rust command `exchange_token` (NOT browser fetch). Exchanges 3. **HTTPS only** in production — tokens travel as URL parameters and POST bodies 4. **Rate limiting** — on `/api/auth/web-complete` and `/auth/desktop-exchange` 5. **Token entropy** — minimum 256 bits of randomness -6. **Deep link validation** — the desktop app only processes `alphahuman://auth` paths; ignore unknown paths +6. **Deep link validation** — the desktop app only processes `openhuman://auth` paths; ignore unknown paths 7. **Telegram data verification** — validate the `hash` field using your bot token per Telegram docs ## Implementation Details @@ -226,14 +226,14 @@ Set `VITE_BACKEND_URL` environment variable for different environments. ## Frontend Integration Points -| File | Role | -| -------------------------------------- | ------------------------------------------------------------------------------------- | -| `src/main.tsx` | Lazy-imports and starts the deep link listener | -| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates | -| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `alphahuman://auth?token=...` URL | -| `src/utils/config.ts` | Backend URL configuration | -| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser | -| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) | +| File | Role | +| -------------------------------------- | ------------------------------------------------------------------------------------ | +| `src/main.tsx` | Lazy-imports and starts the deep link listener | +| `src/utils/desktopDeepLinkListener.ts` | Parses deep link -> invokes Rust `exchange_token` -> stores session -> navigates | +| `src/utils/deeplink.ts` | Web-side: calls `/api/auth/web-complete` and builds `openhuman://auth?token=...` URL | +| `src/utils/config.ts` | Backend URL configuration | +| `src/pages/Login.tsx` | Opens `GET /auth/telegram?platform=desktop` in browser | +| `src-tauri/src/lib.rs` | Rust `exchange_token` command using `reqwest` (CORS-free) | ## Phone OTP Flow (Future) diff --git a/.claude/rules/14-deep-link-platform-guide.md b/.claude/rules/14-deep-link-platform-guide.md index c3fd9bd4b..02df6b16d 100644 --- a/.claude/rules/14-deep-link-platform-guide.md +++ b/.claude/rules/14-deep-link-platform-guide.md @@ -2,14 +2,14 @@ ## Overview -The `alphahuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development. +The `openhuman://` custom URL scheme is used to hand off authentication from a web browser to the Tauri desktop app. This document covers platform-specific behavior, gotchas, and build requirements discovered during development. ## Scheme Registration Configured in `src-tauri/tauri.conf.json`: ```json -{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } } +{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } } ``` ## macOS @@ -50,7 +50,7 @@ cp -R src-tauri/target/debug/bundle/macos/tauri-app.app /Applications/ open /Applications/tauri-app.app # Test deep link -open "alphahuman://auth?token=YOUR_TOKEN" +open "openhuman://auth?token=YOUR_TOKEN" ``` ### Cargo Caching Gotcha @@ -68,9 +68,9 @@ open "alphahuman://auth?token=YOUR_TOKEN" - The macOS WebView (WKWebView) caches aggressively - Clear caches when debugging stale content: ```bash - rm -rf ~/Library/WebKit/com.alphahuman.app - rm -rf ~/Library/Caches/com.alphahuman.app - rm -rf ~/Library/Application\ Support/com.alphahuman.app + rm -rf ~/Library/WebKit/com.openhuman.app + rm -rf ~/Library/Caches/com.openhuman.app + rm -rf ~/Library/Application\ Support/com.openhuman.app ``` ### Debug Builds: Secondary Instance Behavior diff --git a/.claude/rules/16-macos-background-execution.md b/.claude/rules/16-macos-background-execution.md index 84e92afc8..2f5c7b2f2 100644 --- a/.claude/rules/16-macos-background-execution.md +++ b/.claude/rules/16-macos-background-execution.md @@ -213,8 +213,8 @@ npm run tauri build -- --debug --bundles app Clear WebKit cache if needed: ```bash -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app ``` ## Configuration Options diff --git a/.claude/rules/17-skills-memory-inference-flow.md b/.claude/rules/17-skills-memory-inference-flow.md index 984017d4f..29c8a9d86 100644 --- a/.claude/rules/17-skills-memory-inference-flow.md +++ b/.claude/rules/17-skills-memory-inference-flow.md @@ -31,10 +31,10 @@ Token present Two Tauri event listeners run continuously: -| Event | What it does | -|---|---| -| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` | -| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors | +| Event | What it does | +| ------------------------------ | ------------------------------------------------------------------------ | +| `skill-state-changed` | Dispatches `setSkillState` into Redux `skillsSlice.skillStates[skillId]` | +| `runtime:skill-status-changed` | Updates `skillsSlice.skills[skillId].status`; surfaces errors | --- @@ -48,7 +48,8 @@ It is constructed with the user's JWT (`authSlice.token`) and stored as `Arc>`). Base URL resolution (in priority order): -1. `ALPHAHUMAN_BASE_URL` env var + +1. `OPENHUMAN_BASE_URL` env var 2. `TINYHUMANS_BASE_URL` env var 3. SDK default @@ -109,12 +110,12 @@ Examples: `skill:gmail:user@example.com`, `skill:notion:default`. **File**: `src-tauri/src/memory/mod.rs` -| Method | SDK call | When used | -|---|---|---| -| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync | -| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question | -| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node | -| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect | +| Method | SDK call | When used | +| --------------------------- | --------------- | ----------------------------------------------------- | +| `store_skill_sync(...)` | `insert_memory` | OAuth complete, periodic sync | +| `query_skill_context(...)` | `query_memory` | RAG query — fetch relevant chunks for a user question | +| `recall_skill_context(...)` | `recall_memory` | Recall synthesised summary from Master node | +| `clear_skill_memory(...)` | `delete_memory` | OAuth revoke / disconnect | --- @@ -141,16 +142,17 @@ chatSend({ threadId, message, model, authToken, backendUrl, messages, notionCont Completion events flow back over Tauri events: -| Event | Frontend handler | -|---|---| -| `chat:tool_call` | shows active tool indicator | -| `chat:tool_result` | clears tool indicator | -| `chat:done` | `dispatch(addInferenceResponse(...))` | -| `chat:error` | shows error, clears loading state | +| Event | Frontend handler | +| ------------------ | ------------------------------------- | +| `chat:tool_call` | shows active tool indicator | +| `chat:tool_result` | clears tool indicator | +| `chat:done` | `dispatch(addInferenceResponse(...))` | +| `chat:error` | shows error, clears loading state | ### 5b. Web/Fallback Path Used when not running in Tauri (browser). Runs the agentic loop entirely in TypeScript: + - Calls `inferenceApi.createChatCompletion(request)` directly - Executes tools via `skillManager.callTool(skillId, toolName, args)` - Both paths share the same 5-round `MAX_TOOL_ROUNDS` limit and `{skillId}__{toolName}` naming convention @@ -215,6 +217,7 @@ Step 6: Agentic loop (max 5 rounds) **File**: `src-tauri/src/runtime/qjs_engine.rs` — `call_tool(skill_id, tool_name, args)` The Rust runtime routes `call_tool` into the running QuickJS/V8 skill instance: + - Serialises `args` as JSON - Calls the JS tool handler registered by the skill - Returns `ToolCallResult { content: Vec, is_error: bool }` @@ -262,14 +265,14 @@ Separately (async, fire-and-forget): ## Key Files Reference -| File | Role | -|---|---| -| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync | -| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context | -| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` | -| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch | -| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command | -| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK | -| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers | -| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` | -| `skills/skills/*/manifest.json` | Skill metadata (git submodule) | +| File | Role | +| --------------------------------------------- | -------------------------------------------------- | +| `src/providers/SkillProvider.tsx` | Discovery, lifecycle, Redux state sync | +| `src/pages/Conversations.tsx` | Message send, both code paths, Notion context | +| `src/services/chatService.ts` | `chatSend()`, `chatCancel()`, `useRustChat()` | +| `src-tauri/src/commands/chat.rs` | Rust agentic loop, context assembly, tool dispatch | +| `src-tauri/src/commands/memory.rs` | `recall_memory` Tauri command | +| `src-tauri/src/memory/mod.rs` | `MemoryClient` wrapping tinyhumansai SDK | +| `src-tauri/src/runtime/qjs_skill_instance.rs` | Skill sync → memory write triggers | +| `src-tauri/src/runtime/qjs_engine.rs` | `discover_skills()`, `call_tool()`, `all_tools()` | +| `skills/skills/*/manifest.json` | Skill metadata (git submodule) | diff --git a/.claude/skills-system-troubleshooting.md b/.claude/skills-system-troubleshooting.md index dec13019a..12a66b73f 100644 --- a/.claude/skills-system-troubleshooting.md +++ b/.claude/skills-system-troubleshooting.md @@ -10,7 +10,7 @@ The Skills System is a Python-based plugin architecture that allows AI agents to - 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/` +- Error paths like `/Users/cyrus/openhuman/skills/skills/telegram/` - Python import failures and subprocess stderr messages ### Root Cause Analysis @@ -51,7 +51,7 @@ git submodule init git submodule update ``` -This downloads the skills repository from `https://github.com/alphahumanxyz/skills`. +This downloads the skills repository from `https://github.com/openhumanxyz/skills`. #### 2. Create Python Virtual Environment @@ -87,7 +87,7 @@ This installs: #### Development vs Production Paths - **Development**: Skills in git submodule at `./skills/skills/` -- **Production**: Skills in `~/.alphahuman/skills/` +- **Production**: Skills in `~/.openhuman/skills/` - **Configuration**: `src/lib/skills/paths.ts` handles path resolution #### Skill Execution Process diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55224ab1d..f76b86c11 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Install Rust stable uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/package-and-publish.yml b/.github/workflows/package-and-publish.yml index 1a65b4b6e..6bc51315e 100644 --- a/.github/workflows/package-and-publish.yml +++ b/.github/workflows/package-and-publish.yml @@ -17,10 +17,8 @@ on: env: IS_PR: ${{ github.event_name == 'pull_request' }} SHOULD_PUBLISH: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} - PUBLISH_REPO: alphahumanxyz/alphahuman + PUBLISH_REPO: openhumanxyz/openhuman XGH_TOKEN: ${{ secrets.XGH_TOKEN }} - UPDATER_GIST_URL: ${{ secrets.UPDATER_GIST_URL }} - UPDATER_GIST_ID: ${{ secrets.UPDATER_GIST_ID }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: @@ -48,7 +46,7 @@ jobs: run: | PACKAGE_VERSION=$(node -p "require('./package.json').version") TAG_NAME="v${PACKAGE_VERSION}" - RELEASE_NAME="AlphaHuman v${PACKAGE_VERSION}" + RELEASE_NAME="OpenHuman v${PACKAGE_VERSION}" echo "package-version=$PACKAGE_VERSION" >> $GITHUB_OUTPUT echo "tag-name=$TAG_NAME" >> $GITHUB_OUTPUT echo "release-name=$RELEASE_NAME" >> $GITHUB_OUTPUT @@ -162,15 +160,15 @@ jobs: fail-fast: false matrix: settings: - - platform: "macos-latest" - args: "--target aarch64-apple-darwin" - target: "aarch64-apple-darwin" - - platform: "macos-latest" - args: "--target x86_64-apple-darwin" - target: "x86_64-apple-darwin" - - platform: "ubuntu-22.04" - args: "" - target: "" + - platform: 'macos-latest' + args: '--target aarch64-apple-darwin' + target: 'aarch64-apple-darwin' + - platform: 'macos-latest' + args: '--target x86_64-apple-darwin' + target: 'x86_64-apple-darwin' + - platform: 'ubuntu-22.04' + args: '' + target: '' runs-on: ${{ matrix.settings.platform }} steps: - name: Checkout @@ -191,7 +189,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Install Rust stable uses: dtolnay/rust-toolchain@stable @@ -307,14 +305,14 @@ jobs: # macOS 10.15+ required for std::filesystem used by llama.cpp MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }} with: - args: "-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}" + args: '-c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}' includeDebug: ${{ needs.get-version.outputs.should-publish == '' && inputs.forceRelease != 'true' }} includeRelease: ${{ needs.get-version.outputs.should-publish != '' || inputs.forceRelease == 'true' }} # TDLib dylibs are now bundled natively via build.rs + tauri.conf.json macOS.frameworks # No post-build scripts needed - Tauri bundler handles copying and signing releaseId: ${{ needs.create-release.outputs.releaseId }} - owner: alphahumanxyz - repo: alphahuman + owner: openhumanxyz + repo: openhuman - name: Get file info id: file-info diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9f73e39f..ab111e715 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -214,7 +214,7 @@ jobs: - platform: macos-latest args: --target x86_64-apple-darwin - platform: ubuntu-22.04 - args: "" + args: '' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -263,7 +263,7 @@ jobs: env: BASE_URL: ${{ vars.BASE_URL }} UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY }} - WITH_UPDATER: "true" + WITH_UPDATER: 'true' with: script: | const workspacePath = process.env.GITHUB_WORKSPACE.replace(/\\/g, '/'); @@ -293,7 +293,7 @@ jobs: BASE_URL: ${{ vars.BASE_URL }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} - WITH_UPDATER: "true" + WITH_UPDATER: 'true' MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }} with: args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2170cd0e2..83d910cc0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: 24.x - cache: "yarn" + cache: 'yarn' - name: Cache node modules id: yarn-cache diff --git a/CLAUDE.md b/CLAUDE.md index c55363a7b..08c72e46f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,7 +51,7 @@ yarn dev:app yarn tauri build # Debug build with .app bundle (required for deep link testing on macOS) -# On macOS, alphahuman:// only works when running the .app, not `tauri dev` +# On macOS, openhuman:// only works when running the .app, not `tauri dev` yarn tauri build --debug --bundles app yarn macos:dev @@ -133,10 +133,10 @@ Model Context Protocol implementation for AI tool execution over Socket.io: ### Deep Link Auth Flow -Web-to-desktop handoff using `alphahuman://` URL scheme: +Web-to-desktop handoff using `openhuman://` URL scheme: 1. User authenticates in browser -2. Browser redirects to `alphahuman://auth?token=` +2. Browser redirects to `openhuman://auth?token=` 3. Tauri catches the deep link, Rust `exchange_token` command calls backend via `reqwest` (bypasses CORS) 4. Backend returns `sessionToken` + user object 5. App stores session in Redux, navigates to onboarding/home @@ -209,18 +209,18 @@ Advanced JavaScript execution engine for skills using V8 (via deno_core): Set in `.env` (Vite exposes `VITE_*` prefixed vars): -| Variable | Purpose | -| ---------------------------- | ------------------------------------------------------------------- | -| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) | -| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) | -| `VITE_DEBUG` | Debug mode flag | -| `ALPHAHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) | +| Variable | Purpose | +| --------------------------- | ------------------------------------------------------------------- | +| `VITE_BACKEND_URL` | Backend API URL (default: `http://localhost:5005`) | +| `VITE_SENTRY_DSN` | Sentry DSN for error reporting (optional) | +| `VITE_DEBUG` | Debug mode flag | +| `OPENHUMAN_DAEMON_INTERNAL` | Force internal daemon mode (default: false, uses external services) | Production defaults are in `src/utils/config.ts`. ## AI Configuration System -AlphaHuman uses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior. +OpenHumanuses an OpenClaw-compliant AI configuration system that automatically injects persona and tool context into every user message for consistent AI behavior. ### Configuration Files @@ -279,7 +279,7 @@ const toolsMessage = await injectTools(userMessage); ``` [PERSONA_CONTEXT] -I am AlphaHuman: that incredibly smart, funny friend who loves helping people get stuff done +I am OpenHuman that incredibly smart, funny friend who loves helping people get stuff done Personality: Curious & Enthusiastic, Witty & Engaging, Empathetic Voice: Conversational, Use humor naturally but don't force it [/PERSONA_CONTEXT] @@ -406,9 +406,9 @@ Key updates from recent commits (cd9ebcd to current): - 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 + - XGH_TOKEN authentication for openhumanxyz/openhuman releases - Python sidecar setup and caching for cross-platform builds - - Tauri configuration updates (com.alphahuman.app identifier) + - Tauri configuration updates (com.openhuman.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 @@ -463,9 +463,9 @@ Key updates from recent commits (cd9ebcd to current): ## Git Workflow -- **Push target**: All pushes go to the **user's private repo** (your fork). Do not push directly to the org repository. -- **PR target**: All pull requests are opened **from your fork** against the **org's private repo**, targeting the **`develop`** branch (not `main`). -- **No direct pushes to org**: The org repo does not allow direct pushes. All changes reach the org repo via PRs from your fork. +- **Repository visibility**: The project is public. +- **Push target**: Pushes should go to your working branch in the public repository (or your fork if your access model requires it). +- **PR target**: Open pull requests against the public upstream repository, targeting the **`main`** branch. ## Key Patterns @@ -496,7 +496,7 @@ Key updates from recent commits (cd9ebcd to current): ## Platform Gotchas -- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.alphahuman.app ~/Library/Caches/com.alphahuman.app` +- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.openhuman.app ~/Library/Caches/com.openhuman.app` - **Cargo caching**: May serve stale frontend assets on incremental builds. Run `cargo clean --manifest-path src-tauri/Cargo.toml` if the app shows outdated UI. - **`window.__TAURI__`**: Not available at module load time. Use static imports and try/catch around Tauri API calls (not around imports). - **Android background services**: RuntimeService requires notification permissions (API 33+) and foreground service type specification (API 34+). Use Android logging (`android_logger`) for debug output in logcat. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b496f937f..41ee18db2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to AlphaHuman +# Contributing to OpenHuman Thank you for your interest in contributing. This document explains how to get set up, follow our workflow, and submit changes. @@ -19,7 +19,7 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU ## Getting Started - Read the [README](README.md) and [ARCHITECTURE](ARCHITECTURE.md) for context. -- Check [open issues](https://github.com/alphahumanxyz/alphahuman/issues) and discussions for ideas and to avoid duplicate work. +- Check [open issues](https://github.com/tinyhumansai/openhuman/issues) and discussions for ideas and to avoid duplicate work. - For security issues, see [SECURITY.md](SECURITY.md) — do not report vulnerabilities in public issues. ## Development Setup @@ -33,8 +33,8 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDU ### Clone and Install ```bash -git clone https://github.com/YOUR_USERNAME/alphahuman.git -cd alphahuman +git clone https://github.com/YOUR_USERNAME/openhuman.git +cd openhuman yarn install ``` @@ -55,7 +55,7 @@ Copy or create a `.env` from the documented template and set `VITE_BACKEND_URL`, ## Git Workflow -- **Fork** the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository and work in your fork. +- **Fork** the [openhuman](https://github.com/tinyhumansai/openhuman) repository and work in your fork. - **Base branch**: All pull requests must target the **`develop`** branch (not `main`). - **No direct pushes** to the organization repo; all changes come in via pull requests from forks. @@ -69,7 +69,7 @@ Use short, descriptive branches, e.g.: ## Making Changes -1. Create a branch from `develop`: +1. Create a branch from `develop`: `git checkout develop && git pull origin develop && git checkout -b fix/your-change` 2. Make your changes. Keep commits focused and messages clear (e.g., “Fix socket reconnect on network drop”). 3. Follow our [project conventions](#project-conventions) and run checks before pushing. @@ -85,9 +85,9 @@ Pre-commit/pre-push hooks (Husky) run formatting and linting; fix any failures b ## Submitting Changes -1. Push your branch to your fork: +1. Push your branch to your fork: `git push origin fix/your-change` -2. Open a **pull request** against **`develop`** in the [alphahuman](https://github.com/alphahumanxyz/alphahuman) repository. +2. Open a **pull request** against **`develop`** in the [openhuman](https://github.com/tinyhumansai/openhuman) repository. 3. Fill in the PR template (if present): describe what changed, why, and how to test. 4. Link any related issues (e.g., “Fixes #123”). 5. Address review feedback and keep the PR up to date with `develop` (rebase or merge as the project prefers). @@ -108,4 +108,4 @@ For more detail on architecture, patterns, and platform notes, see the project --- -Thank you for contributing to AlphaHuman. +Thank you for contributing to OpenHuman. diff --git a/SECURITY.md b/SECURITY.md index 81195e3c1..7fd4482a5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Supported Versions -We provide security updates for the following versions of AlphaHuman: +We provide security updates for the following versions of OpenHuman: | Version | Supported | | -------------- | ------------------ | @@ -10,7 +10,7 @@ We provide security updates for the following versions of AlphaHuman: | Previous minor | :white_check_mark: | | Older | :x: | -We recommend always running the [latest release](https://github.com/alphahumanxyz/alphahuman/releases/latest). AlphaHuman is in early beta; older versions may not receive patches. +We recommend always running the [latest release](https://github.com/tinyhumansai/openhuman/releases/latest). OpenHuman is in early beta; older versions may not receive patches. ## Reporting a Vulnerability @@ -19,7 +19,7 @@ We take security seriously. If you believe you have found a security vulnerabili ### How to Report 1. **Do not** open a public GitHub issue for security vulnerabilities. -2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [AlphaHuman organization](https://github.com/alphahumanxyz) or repository. +2. Email the maintainers with a clear description of the issue, steps to reproduce, and impact. You can reach us via the contact details listed in the [OpenHuman organization](https://github.com/openhumanxyz) or repository. 3. Include as much detail as possible (platform, version, configuration) so we can reproduce and triage quickly. ### What to Expect @@ -38,7 +38,7 @@ We are especially interested in: - Issues in dependency chain (npm, Cargo) that affect our build or runtime - Platform-specific issues (macOS, Windows, Linux, Android, iOS) that compromise user data or device security -Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how AlphaHuman uses them. +Out-of-scope for this process: general bugs, feature requests, and issues in third-party services we integrate with (e.g., Telegram, Notion) unless they are specific to how OpenHuman uses them. ### Safe Harbor @@ -50,4 +50,4 @@ We support safe harbor for security researchers who report in good faith. We wil - **Data**: Message content is processed on request and not retained for training or long-term storage. - **Skills**: Skills run in a sandboxed environment with defined boundaries; we review skill behavior and dependencies where possible. -Thank you for helping keep AlphaHuman and its users safe. +Thank you for helping keep OpenHuman and its users safe. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index f8436330f..44725b760 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,8 +1,8 @@ -# AlphaHuman Architecture +# OpenHuman Architecture **AI-powered super assistant for crypto communities, built on Rust.** -AlphaHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time. +OpenHuman is a cross-platform communication and automation platform purpose-built for the cryptocurrency ecosystem. A single React + Rust (Tauri) codebase can target multiple platforms; **what we document and ship for users today is desktop only** — **Windows, macOS, and Linux**. Android, iOS, and web are **not** supported in current docs or releases. The stack includes a sandboxed JavaScript skills engine, persistent Rust-native WebSocket infrastructure, and an AI tool protocol that lets language models invoke any connected service in real time. --- @@ -13,7 +13,7 @@ AlphaHuman is a cross-platform communication and automation platform purpose-bui **Not supported yet:** Android, iOS, standalone web client (may exist as experimental targets in the repo; do not treat as product-ready). ``` - AlphaHuman (shipping) + OpenHuman (shipping) | Desktop / | \ @@ -65,9 +65,9 @@ The frontend communicates with the Rust core through Tauri's IPC bridge — 47+ ## Rust-Powered Performance -AlphaHuman chose Tauri + Rust over Electron for fundamental performance and security reasons: +OpenHuman chose Tauri + Rust over Electron for fundamental performance and security reasons: -| Metric | AlphaHuman (Tauri + Rust) | Typical Electron App | +| Metric | OpenHuman (Tauri + Rust) | Typical Electron App | | ------------------------- | ------------------------------ | ---------------------------- | | Binary size | ~30 MB | ~150 MB+ | | Memory per skill context | ~1-2 MB (QuickJS) | ~150 MB+ (Chromium renderer) | @@ -76,7 +76,7 @@ AlphaHuman chose Tauri + Rust over Electron for fundamental performance and secu | Memory safety | Compile-time guaranteed | Runtime exceptions | | TLS implementation | rustls (no OpenSSL dependency) | Chromium's BoringSSL | -**Why this matters for a crypto platform**: Traders and analysts run AlphaHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management. +**Why this matters for a crypto platform**: Traders and analysts run OpenHuman alongside resource-intensive tools — charting software, multiple browser tabs, trading terminals. A 30 MB footprint with sub-500ms startup means the app feels native and stays out of the way. Zero GC pauses means real-time price feeds and alerts are never delayed by memory management. The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP requests, file operations, and inter-skill communication — as non-blocking tasks on a thread pool. Thousands of concurrent operations (skill executions, cron jobs, socket events) share a small fixed set of OS threads. @@ -84,7 +84,7 @@ The **Tokio async runtime** drives all I/O — WebSocket connections, HTTP reque ## Real-Time Socket Infrastructure -AlphaHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls. +OpenHuman implements a **dual-socket architecture**: a Rust-native WebSocket client on desktop and a JavaScript Socket.io client on web. The Rust implementation survives app backgrounding, operates independently of the WebView, and handles TLS via rustls. ``` Desktop Mode: Web Mode: @@ -119,7 +119,7 @@ The socket connection is **shared across all skills**. When events arrive, the s ## Skills Runtime Engine -AlphaHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks. +OpenHuman's defining capability is its **sandboxed JavaScript execution engine** running inside the Rust process. Skills are lightweight automation scripts that extend the platform with custom tools, integrations, and scheduled tasks. ``` +---------------------------------------------------------------+ @@ -188,7 +188,7 @@ Skills are synced from a GitHub repository and discovered at runtime. Platform f ## AI & Tool Protocol (MCP) -AlphaHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills. +OpenHuman implements the **Model Context Protocol** — a JSON-RPC 2.0 layer over Socket.io that lets AI models discover and invoke tools exposed by skills. ``` User Prompt diff --git a/docs/src-tauri/01-architecture.md b/docs/src-tauri/01-architecture.md index fb8c41e59..e419412e4 100644 --- a/docs/src-tauri/01-architecture.md +++ b/docs/src-tauri/01-architecture.md @@ -2,7 +2,7 @@ ## Overview -The Tauri Rust backend provides native functionality for the AlphaHuman desktop application: +The Tauri Rust backend provides native functionality for the OpenHuman desktop application: - System tray with background execution - Deep link authentication @@ -113,7 +113,7 @@ listen("socket:should_connect", (event) => { | Plugin | Version | Purpose | | --------------------------- | ------- | --------------------------- | | `tauri-plugin-opener` | 2 | Open URLs in browser | -| `tauri-plugin-deep-link` | 2.0.0 | Handle `alphahuman://` URLs | +| `tauri-plugin-deep-link` | 2.0.0 | Handle `openhuman://` URLs | | `tauri-plugin-autostart` | 2 | Launch at login | | `tauri-plugin-notification` | 2 | Native notifications | diff --git a/docs/src-tauri/02-commands.md b/docs/src-tauri/02-commands.md index e15268d19..b9aceee44 100644 --- a/docs/src-tauri/02-commands.md +++ b/docs/src-tauri/02-commands.md @@ -151,7 +151,7 @@ Open Telegram login widget in browser. ```typescript await invoke("start_telegram_login"); -// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth +// Opens ${DEFAULT_BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth ``` ### `start_telegram_login_with_url` diff --git a/docs/src-tauri/README.md b/docs/src-tauri/README.md index ab036f21c..154fdc2af 100644 --- a/docs/src-tauri/README.md +++ b/docs/src-tauri/README.md @@ -2,7 +2,7 @@ ## Overview -This documentation covers the Tauri Rust backend for the AlphaHuman desktop application. +This documentation covers the Tauri Rust backend for the OpenHuman desktop application. ## Quick Reference @@ -26,7 +26,7 @@ This documentation covers the Tauri Rust backend for the AlphaHuman desktop appl ### Existing Implementation (`lib.rs`) - ✅ System tray with show/hide/quit -- ✅ Deep link handling (`alphahuman://` scheme) +- ✅ Deep link handling (`openhuman://` scheme) - ✅ Token exchange command (CORS bypass) - ✅ Autostart plugin (macOS LaunchAgent) - ✅ Window minimize-to-tray on close (macOS) @@ -120,7 +120,7 @@ impl SocketService { 1. User clicks "Login with Telegram" in desktop app ↓ 2. App opens system browser to: - ${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth + ${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth ↓ 3. Backend serves Telegram Login Widget HTML page ↓ @@ -128,7 +128,7 @@ impl SocketService { ↓ 5. Telegram callback → Backend validates → Creates loginToken ↓ -6. Backend redirects to: alphahuman://auth?token={loginToken} +6. Backend redirects to: openhuman://auth?token={loginToken} ↓ 7. Desktop app catches deep link ↓ @@ -153,7 +153,7 @@ Returns HTML page with Telegram Login Widget that redirects to the specified sch #[tauri::command] async fn start_telegram_login(app: AppHandle) -> Result<(), String> { // Open browser to Telegram widget page - let url = format!("{}/auth/telegram-widget?redirect=alphahuman://auth", BACKEND_URL); + let url = format!("{}/auth/telegram-widget?redirect=openhuman://auth", BACKEND_URL); opener::open(&url)?; Ok(()) } @@ -189,7 +189,7 @@ pub struct SessionService { } impl SessionService { - const SERVICE: &'static str = "com.alphahuman.app"; + const SERVICE: &'static str = "com.openhuman.app"; pub fn store_token(&self, token: &str) -> Result<(), Error>; pub fn get_token(&self) -> Result, Error>; diff --git a/docs/src/01-architecture.md b/docs/src/01-architecture.md index 558de59fd..aa6b43147 100644 --- a/docs/src/01-architecture.md +++ b/docs/src/01-architecture.md @@ -105,7 +105,7 @@ MCP System: ### Authentication Flow (Deep Link) 1. User authenticates in browser → receives `loginToken` -2. Browser redirects to `alphahuman://auth?token=` +2. Browser redirects to `openhuman://auth?token=` 3. Desktop app catches deep link via Tauri plugin 4. `desktopDeepLinkListener` invokes Rust `exchange_token` command 5. Rust calls backend `POST /auth/desktop-exchange` (CORS-free) diff --git a/docs/src/05-pages-routing.md b/docs/src/05-pages-routing.md index b15f51c22..5616add56 100644 --- a/docs/src/05-pages-routing.md +++ b/docs/src/05-pages-routing.md @@ -366,7 +366,7 @@ import('./utils/desktopDeepLinkListener').then(m => { }); ``` -The listener intercepts `alphahuman://auth?token=...` and: +The listener intercepts `openhuman://auth?token=...` and: 1. Exchanges token via Rust command 2. Stores session in Redux diff --git a/docs/src/08-hooks-utils.md b/docs/src/08-hooks-utils.md index ae2547c4f..4218447b1 100644 --- a/docs/src/08-hooks-utils.md +++ b/docs/src/08-hooks-utils.md @@ -208,7 +208,7 @@ import { buildAuthDeepLink } from '../utils/deeplink'; // Build URL for browser redirect const deepLink = buildAuthDeepLink(loginToken); -// → "alphahuman://auth?token=abc123" +// → "openhuman://auth?token=abc123" // In web frontend after auth: window.location.href = deepLink; @@ -235,7 +235,7 @@ import('./utils/desktopDeepLinkListener').then(m => { **What it does:** 1. Listens for `onOpenUrl` events from Tauri deep-link plugin -2. Parses `alphahuman://auth?token=...` URLs +2. Parses `openhuman://auth?token=...` URLs 3. Calls Rust `exchange_token` command (bypasses CORS) 4. Stores session in Redux 5. Navigates to `/onboarding` or `/home` diff --git a/docs/telegram-login-desktop.md b/docs/telegram-login-desktop.md index 35a828fb4..1109f25e1 100644 --- a/docs/telegram-login-desktop.md +++ b/docs/telegram-login-desktop.md @@ -1,6 +1,6 @@ # Telegram Login (Web → Desktop Handoff) -This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`alphahuman://`) to return control back to the desktop app. +This app implements **Telegram login for the desktop (Tauri) client** using a **system-browser auth flow** plus a **custom URL scheme deep link** (`openhuman://`) to return control back to the desktop app. --- @@ -8,10 +8,10 @@ This app implements **Telegram login for the desktop (Tauri) client** using a ** 1. **User clicks “Continue with Telegram”** inside the desktop app. 2. The app opens the system browser to the backend: - - `GET ${BACKEND_URL}/auth/telegram-widget?redirect=alphahuman://auth` + - `GET ${BACKEND_URL}/auth/telegram-widget?redirect=openhuman://auth` 3. The backend performs Telegram authentication (bot-based login / OAuth-like flow). 4. On success, the backend generates a **short-lived single-use `loginToken`** and redirects the browser to: - - `alphahuman://auth?token=` + - `openhuman://auth?token=` 5. The OS routes that deep link to the installed desktop app. 6. The desktop app extracts the `token` from the deep link and exchanges it for a **long-lived `sessionToken`** by calling a Rust Tauri command (bypassing CORS): - `POST ${BACKEND_URL}/auth/desktop-exchange` with `{ token }` @@ -41,7 +41,7 @@ export const BACKEND_URL = The URL scheme is declared in `src-tauri/tauri.conf.json`: ```json -{ "plugins": { "deep-link": { "desktop": { "schemes": ["alphahuman"] } } } } +{ "plugins": { "deep-link": { "desktop": { "schemes": ["openhuman"] } } } } ``` The deep-link plugin is initialized in `src-tauri/src/lib.rs`: @@ -78,8 +78,8 @@ import('./utils/desktopDeepLinkListener').then(m => { The deep link handler: -- Accepts only the `alphahuman:` scheme -- Requires `alphahuman://auth?token=...` +- Accepts only the `openhuman:` scheme +- Requires `openhuman://auth?token=...` - Calls the Rust command `exchange_token` - Stores `sessionToken` in Redux auth state - Redirects to `#/onboarding` (HashRouter) @@ -92,7 +92,7 @@ const handleDeepLinkUrls = async (urls: string[] | null | undefined) => { try { const parsed = new URL(url); <<<<<<< HEAD - if (parsed.protocol !== 'alphahuman:') return; + if (parsed.protocol !== 'openhuman:') return; if (parsed.hostname !== 'auth') return; ======= if (parsed.protocol !== "outsourced:") return; @@ -141,13 +141,13 @@ async fn exchange_token(backend_url: String, token: String) -> Result` + - redirect to: `openhuman://auth?token=` ### B) `POST /auth/desktop-exchange` @@ -180,7 +180,7 @@ Your backend must implement **both**: ### Backend (required) -- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `alphahuman://auth?token=...` on success. +- **Implement `GET /auth/telegram?platform=desktop`** and ensure it redirects to `openhuman://auth?token=...` on success. - **Implement `POST /auth/desktop-exchange`** to exchange the login token for a session token. - **Enforce security**: - `loginToken` is **single-use** @@ -190,7 +190,7 @@ Your backend must implement **both**: ### Desktop app (required for reliable behavior) - **Ensure the deep-link plugin is configured and permitted**: - - `src-tauri/tauri.conf.json` includes `"schemes": ["alphahuman"]` + - `src-tauri/tauri.conf.json` includes `"schemes": ["openhuman"]` - `src-tauri/capabilities/default.json` includes `"deep-link:default"` - **Use a real backend URL**: - set `VITE_BACKEND_URL` for dev/prod so `Login.tsx` opens the correct domain @@ -198,7 +198,7 @@ Your backend must implement **both**: ### Desktop app (recommended hardening / cleanup) - **Validate the deep link target more strictly** in `src/utils/desktopDeepLinkListener.ts`: - - today it checks only `parsed.protocol === 'alphahuman:'` + - today it checks only `parsed.protocol === 'openhuman:'` - recommended: also require `parsed.hostname === 'auth'` (and optionally a known path) - **Don’t skip Telegram auth in onboarding**: - `src/pages/onboarding/Step1Phone.tsx` currently has a “Continue with Telegram” button that _only navigates_ and does not authenticate. diff --git a/eslint.config.js b/eslint.config.js index ad30f1012..2fade18b2 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -42,6 +42,8 @@ export default [ globals: { // Browser globals window: 'readonly', + localStorage: 'readonly', + sessionStorage: 'readonly', document: 'readonly', navigator: 'readonly', console: 'readonly', diff --git a/gitbooks/README.md b/gitbooks/README.md index 6e36858b1..181cf375c 100644 --- a/gitbooks/README.md +++ b/gitbooks/README.md @@ -1,34 +1,34 @@ --- description: >- - AlphaHuman is a personal AI assistant that runs natively across desktop, + OpenHuman is a personal AI assistant that runs natively across desktop, mobile, and web that connects your communication platforms, tools, and workflows into a single intelligence layer you control. icon: diamond --- -# Welcome to AlphaHuman +# Welcome to OpenHuman -AlphaHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, AlphaHuman is designed to close the gap between what AI models can do and what they actually know about you. +OpenHuman is the first open-source AI agent with Big Data capabilities and a personalized subconscious mind. Built on the OpenClaw architecture and licensed under GNU GPL3, OpenHuman is designed to close the gap between what AI models can do and what they actually know about you. Every AI model in the world, all 200+ of them, shares the same fundamental limitation. They are stateless. You type a prompt, get a response, and the context evaporates. Even the ones with "memory" store a few bullet points. A few bullet points is a sticky note, not intelligence. -AlphaHuman solves this with two core innovations: +OpenHuman solves this with two core innovations:
**Neocortex**, a human-like memory engine that can accurately work with over 1 billion tokens. Neocortex indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with zero LLM dependency. Neocortex goes beyond vector databases. It understands time, entities, and relationships, and it models memory the way the human brain does: by compressing, forgetting strategically, and building knowledge graphs. -**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. AlphaHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop. +**A personalized subconscious system** inspired by the Purkinje cell, a specialized neuron in the human brain responsible for random thoughts and consciousness. OpenHuman's subconscious triggers over 10,000 memory recall loops per day for under $1, producing proactive insights, pattern recognition, and emergent "thoughts" that feed into a self-learning loop. -Together, these systems turn AlphaHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf. +Together, these systems turn OpenHuman into something fundamentally different from a chatbot. It is an AI agent that consumes large amounts of personal data at low cost, maintains a persistent and evolving understanding of your world, and takes proactive actions on your behalf. {% hint style="info" %} -AlphaHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain. +OpenHuman is not AGI. But it is a meaningful architectural step closer to it, with better memory and better orchestration for memory, taking direct inspiration from the human brain. {% endhint %} -## What AlphaHuman does +## What OpenHuman does -AlphaHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on. +OpenHuman connects to your communication platforms, tools, and workflows, and compresses that information into structured intelligence any AI can act on. It **compresses context** across your connected sources, turning millions of tokens of organizational noise into a structured knowledge graph of entities, relationships, and temporal chains. @@ -38,29 +38,27 @@ It **thinks proactively** through its subconscious system, making connections an It **preserves privacy** by design. Raw data stays on your device. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side. - - ## Who it's for -AlphaHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it. +OpenHuman is built for people and teams who operate across many conversations and tools, and feel the cost of it. -* **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales. -* **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms. -* **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain. -* **Distributed teams** who make decisions in chat but need structured follow-through in external tools. +- **Developers and power users** in the AI ecosystem, especially those using OpenClaw, CrewAI, and similar agentic frameworks, who need a memory and context layer that actually scales. +- **High-volume communicators** who miss decisions, context, and follow-ups buried in message noise across multiple platforms. +- **Traders and analysts** who need fast signal extraction and risk awareness across information channels, both on-chain and off-chain. +- **Distributed teams** who make decisions in chat but need structured follow-through in external tools. -## What AlphaHuman does not do +## What OpenHuman does not do -AlphaHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data. +OpenHuman does not claim to be AGI. It does not send messages automatically or impersonate you. It does not store your raw message data long-term. It does not train on your data. {% hint style="info" %} Privacy is a core architectural decision, not a checkbox. The full privacy design is covered in Privacy & Security. {% endhint %} -## How to think about AlphaHuman +## How to think about OpenHuman Think of it this way: ChatGPT, Claude, Gemini, and every other model are the brain. They are brilliant at reasoning, generation, and analysis. But they are amnesiac. They know nothing about your actual life. -AlphaHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on. +OpenHuman is the memory and the subconscious that makes those brains actually useful. It is the Big Data layer for AI: an always-on context engine that compresses your entire organizational life into intelligence any AI can act on. -Your AI is smart. It just does not know you. AlphaHuman fixes that. +Your AI is smart. It just does not know you. OpenHuman fixes that. diff --git a/gitbooks/SUMMARY.md b/gitbooks/SUMMARY.md index 1abd893ca..1849e39b0 100644 --- a/gitbooks/SUMMARY.md +++ b/gitbooks/SUMMARY.md @@ -2,33 +2,33 @@ ## Overview -* [Welcome to AlphaHuman](README.md) -* [How It Works](overview/how-it-works.md) -* [Getting Started](overview/getting-started.md) +- [Welcome to OpenHuman](README.md) +- [How It Works](overview/how-it-works.md) +- [Getting Started](overview/getting-started.md) ## Technology -* [Neocortex](technology/neocortex.md) -* [The Subconscious](technology/the-subconscious.md) -* [Architecture](technology/architecture.md) +- [Neocortex](technology/neocortex.md) +- [The Subconscious](technology/the-subconscious.md) +- [Architecture](technology/architecture.md) ## Product -* [Platform & Availability](product/platform.md) -* [Skills & Integrations](product/skills-and-integrations.md) -* [Teams & Organizations](product/teams.md) -* [Privacy & Security](product/privacy-and-security.md) -* [Pricing](product/pricing.md) +- [Platform & Availability](product/platform.md) +- [Skills & Integrations](product/skills-and-integrations.md) +- [Teams & Organizations](product/teams.md) +- [Privacy & Security](product/privacy-and-security.md) +- [Pricing](product/pricing.md) ## Use Cases -* [Overview](use-cases/overview.md) +- [Overview](use-cases/overview.md) ## Resources -* [FAQ & Troubleshooting](resources/faq.md) +- [FAQ & Troubleshooting](resources/faq.md) ## Legal -* [Terms & Conditions](legal/terms-of-use.md) -* [Privacy Policy](legal/privacy-policy.md) +- [Terms & Conditions](legal/terms-of-use.md) +- [Privacy Policy](legal/privacy-policy.md) diff --git a/gitbooks/legal/privacy-policy.md b/gitbooks/legal/privacy-policy.md index fed10bbb7..482eb06a3 100644 --- a/gitbooks/legal/privacy-policy.md +++ b/gitbooks/legal/privacy-policy.md @@ -67,4 +67,3 @@ Depending on your location, you may have rights to access, correct, delete, rest ## Changes to This Policy We may update this Privacy Policy from time to time. Material changes will be communicated as required by law. Changes will not apply retroactively in a manner that reduces existing privacy protections. - diff --git a/gitbooks/overview/getting-started.md b/gitbooks/overview/getting-started.md index 36f97c4ac..d1899a3ed 100644 --- a/gitbooks/overview/getting-started.md +++ b/gitbooks/overview/getting-started.md @@ -4,46 +4,46 @@ icon: play # Getting Started -This section walks you through setting up AlphaHuman and running your first request. +This section walks you through setting up OpenHuman and running your first request. -AlphaHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman). You can self-host, contribute, or simply use the hosted version. +OpenHuman is open source under the GNU GPL3 license. The codebase is available at [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman). You can self-host, contribute, or simply use the hosted version. -*** +--- ## Download & Install -AlphaHuman runs natively on: +OpenHuman runs natively on: -* **macOS** (Intel and Apple Silicon) -* **Windows** (x64 and ARM64) -* **Linux** (x64 and ARM64: AppImage and .deb) -* **Android** -* **iOS** -* **Web** (any modern browser) +- **macOS** (Intel and Apple Silicon) +- **Windows** (x64 and ARM64) +- **Linux** (x64 and ARM64: AppImage and .deb) +- **Android** +- **iOS** +- **Web** (any modern browser) -Download the app for your platform from the official AlphaHuman website, or use the web version directly in your browser. +Download the app for your platform from the official OpenHuman website, or use the web version directly in your browser. The native app has a small footprint, starts fast, and uses your operating system's secure credential storage. The web version provides the same core functionality when a native install is not practical. -*** +--- ## Create Your Account -When you first open AlphaHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers. +When you first open OpenHuman, you will be asked to sign in. Multiple sign-in options are available, including social login providers. After signing in, you may be placed on a waitlist depending on rollout status. The waitlist is used to manage access during launch and early scaling. {% hint style="info" %} -**No permanent lock-in.** Creating an account does not grant AlphaHuman ongoing access to anything. All processing still requires explicit actions from you later. +**No permanent lock-in.** Creating an account does not grant OpenHuman ongoing access to anything. All processing still requires explicit actions from you later. {% endhint %} -*** +--- ## Connect Your First Source -AlphaHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time. +OpenHuman works by connecting to your existing tools and platforms. Each connection expands your knowledge graph, giving Neocortex more data to compress and reason over. You choose what to connect, and you can revoke access at any time. -**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. AlphaHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more. +**Telegram:** Connect your Telegram account to analyze conversations, extract signals, and generate summaries across your chats and groups. OpenHuman supports the full range of Telegram capabilities: chat management, message search, contact management, group and channel administration, reactions, polls, inline buttons, and more. **Notion:** Connect Notion to export structured outputs like summaries, action items, decisions, and workflow records into your workspace. @@ -53,39 +53,39 @@ AlphaHuman works by connecting to your existing tools and platforms. Each connec All integrations are optional. You can start with one source and add more later. The more sources you connect, the more powerful the intelligence becomes. Each connection is independently revocable. -*** +--- ## Run Your First Request -Once a source is connected, you can start asking AlphaHuman questions using the command input. +Once a source is connected, you can start asking OpenHuman questions using the command input. Try prompts like: -* **"Summarize what I missed today"** -* **"What are the key decisions from this week?"** -* **"Extract action items from my recent conversations"** -* **"What topics are trending across my groups?"** +- **"Summarize what I missed today"** +- **"What are the key decisions from this week?"** +- **"Extract action items from my recent conversations"** +- **"What topics are trending across my groups?"** -AlphaHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent. +OpenHuman processes only the data needed to answer your request, produces an output, and presents it for your review. If the output feels too broad or too shallow, narrow the scope. Specify a particular conversation, time range, or intent. -*** +--- ## Explore Skills & Integrations -After your first request, explore what else AlphaHuman can do: +After your first request, explore what else OpenHuman can do: -* **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools -* **Integrations** let you push structured results to Notion, Google Sheets, and other tools -* **Workflows** turn conversation decisions into trackable actions you can follow through on +- **Skills** extend the assistant's capabilities, fetching external data, running scheduled tasks, processing information, and writing outputs to connected tools +- **Integrations** let you push structured results to Notion, Google Sheets, and other tools +- **Workflows** turn conversation decisions into trackable actions you can follow through on Learn more in [Skills & Integrations](../product/skills-and-integrations.md). -*** +--- #### Join the Community -AlphaHuman is in early alpha. Feedback and contributions make a real difference at this stage. +OpenHuman is in early alpha. Feedback and contributions make a real difference at this stage. Join the Discord community to connect with other users, share feedback, report issues, and contribute to the project. Early users get free usage as part of the alpha program. -**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman) +**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman) diff --git a/gitbooks/overview/how-it-works.md b/gitbooks/overview/how-it-works.md index 057a7d5ce..5d7cbbe1d 100644 --- a/gitbooks/overview/how-it-works.md +++ b/gitbooks/overview/how-it-works.md @@ -4,9 +4,9 @@ icon: brain # How It Works -AlphaHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how AlphaHuman thinks. +OpenHuman is built on three technology pillars: a memory engine called Neocortex, a subconscious system inspired by human neuroscience, and a privacy-preserving architecture that keeps raw data on your device. Understanding how these work together is understanding how OpenHuman thinks. -### The problem AlphaHuman solves +### The problem OpenHuman solves Current AI systems fall into the category of Artificial Narrow Intelligence (ANI). They perform well within bounded domains, but they depend on carefully designed architectures and human-defined operational boundaries. They lack three things needed to get closer to general intelligence: persistent memory at scale, a form of consciousness or instinct, and the ability to ingest data without becoming inaccurate or expensive. @@ -14,7 +14,7 @@ Research from Google's Titans project demonstrates the core issue clearly. As LL
-AlphaHuman solves this in two steps. +OpenHuman solves this in two steps. #### Step 1: Neocortex, the memory engine @@ -50,13 +50,13 @@ Additional capabilities of Neocortex: #### Step 2: The personalized subconscious -With good memory and good recall, AlphaHuman can do something no other AI agent does: maintain a personalized subconscious. +With good memory and good recall, OpenHuman can do something no other AI agent does: maintain a personalized subconscious. In the human brain, there is a specialized neuron called the Purkinje cell. It is mainly responsible for random thoughts and plays a significant role in consciousness. The human brain has both a conscious and subconscious mind that work together to build intelligence. Most agentic systems follow the conscious mind model only. They wait for instructions and execute them. They cannot think on their own.
-Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1. +Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. These recalls are fed into a subconscious loop that produces actions, confirmations, or new connections. Memory recalls are cheap, fast, and happen over 10,000 times a day for less than $1. The result is an AI that does not just respond to your prompts. It thinks about your data in the background. It makes connections you did not ask for. It surfaces patterns and risks proactively. @@ -64,7 +64,7 @@ The success metric for the subconscious is what the team calls the "mirror test" ### How the pieces connect -When you use AlphaHuman, here is what happens: +When you use OpenHuman, here is what happens:
@@ -74,13 +74,13 @@ When you use AlphaHuman, here is what happens: **The subconscious runs.** Thousands of recall loops per day surface proactive insights, track evolving patterns, and update the knowledge graph. -**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? AlphaHuman already knows. +**You interact naturally.** Ask anything about your life, your team, your projects. Not general knowledge. Your knowledge. What did your team decide? What is the status? What did you miss? OpenHuman already knows. **Privacy is maintained.** Raw data stays on device, encrypted with AES-256-GCM. Encryption keys never leave the device. Only compressed metadata and summaries are processed server-side. ### The architecture: OpenClaw foundation -AlphaHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub. +OpenHuman is built on top of the OpenClaw architecture and is open-sourced under the GNU GPL3 license. The full codebase is publicly available on GitHub. The architecture uses multi-agent orchestration, where specialized agents are dynamically spawned for specific tasks rather than relying on one monolithic model. An orchestrator agent manages routing, personality, and context distribution. Specialist agents handle specific domains: communication analysis, document synthesis, task management, trading. These agents execute in parallel, not sequentially, for real-time responsiveness. @@ -88,8 +88,8 @@ All agents share a common compressed context provided by Neocortex. This effecti ### Limitations -AlphaHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data. +OpenHuman works with probabilistic models. It may occasionally miss nuance, misinterpret sarcasm, or over-prioritize certain messages. This is more likely in highly informal conversations, fast-moving threads, or contexts with limited data. -AlphaHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. AlphaHuman helps you think faster. It does not think for you. +OpenHuman is not AGI. It is a meaningful step closer, with better memory and better orchestration for memory, taking inspiration from the human brain. But human judgment still matters. OpenHuman helps you think faster. It does not think for you. Everything is in early alpha. Feedback and contributions are welcomed. diff --git a/gitbooks/overview/platform.md b/gitbooks/overview/platform.md index 0516979c0..9c455068e 100644 --- a/gitbooks/overview/platform.md +++ b/gitbooks/overview/platform.md @@ -6,7 +6,7 @@ icon: layer-plus OpenHuman is a native **desktop** application. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on the machines where we officially support it today. -*** +--- ## Supported today: desktop @@ -20,7 +20,7 @@ OpenHuman ships native installers for: **Android, iOS, and a standalone web client are not supported** in documentation or releases yet. The codebase may contain experimental mobile or web targets; they are out of scope for current user-facing docs. -*** +--- ## Why Native Matters @@ -32,7 +32,7 @@ OpenHuman is built as a native application rather than a web wrapper for three r **OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. -*** +--- ## Architecture at a Glance @@ -48,7 +48,7 @@ OpenHuman operates across three layers: The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend. {% endhint %} -*** +--- ## Real-Time Communication @@ -56,7 +56,7 @@ OpenHuman maintains a persistent connection between the application and the inte The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process. -*** +--- ## Offline Behavior diff --git a/gitbooks/product/platform.md b/gitbooks/product/platform.md index 908eefa29..acd87c394 100644 --- a/gitbooks/product/platform.md +++ b/gitbooks/product/platform.md @@ -4,13 +4,13 @@ icon: layer-plus # Platform & Availability -AlphaHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use. +OpenHuman is a native application that runs on six platforms from a single codebase. It is not a web-only tool, browser extension, or Electron wrapper. It is built for performance, security, and a small footprint on every device you use. -*** +--- ## Six Platforms, One Experience -AlphaHuman compiles to native binaries for each supported platform: +OpenHuman compiles to native binaries for each supported platform: | Platform | Architectures | Distribution | | ----------- | -------------------- | -------------- | @@ -23,46 +23,46 @@ AlphaHuman compiles to native binaries for each supported platform: Your account, connected sources, preferences, and settings sync across all platforms. You can start a request on your desktop and review the output on your phone. -*** +--- ## Why Native Matters -AlphaHuman is built as a native application rather than a web wrapper for three reasons. +OpenHuman is built as a native application rather than a web wrapper for three reasons. **Small footprint.** The app is lightweight. A fraction of the size of typical communication tools. It starts in under a second and uses minimal memory, so it stays out of the way when running alongside other demanding applications. **Fast startup.** There is no browser engine to initialize. The app launches quickly and is ready to accept requests immediately. -**OS-level security.** On desktop platforms, AlphaHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. +**OS-level security.** On desktop platforms, OpenHuman stores credentials in your operating system's secure keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service). Sensitive data never sits in browser storage or plain text files. -*** +--- ## Architecture at a Glance -AlphaHuman operates across three layers: +OpenHuman operates across three layers: **Application layer.** The native app on your device handles the interface, user input, local state, credential management, and skill execution. This layer is responsible for everything you see and interact with. -**Intelligence layer.** AlphaHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by AlphaHuman. +**Intelligence layer.** OpenHuman's analysis, coordination, and intelligence systems run as a secure backend service. When a request requires deeper language processing, it is handled here. This layer is operated and maintained by OpenHuman. -**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. AlphaHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them. +**External services.** Connected tools and platforms:Telegram, Notion, Google Sheets, and others are accessed only when you explicitly request it. OpenHuman acts as a bridge between your sources and the intelligence layer, not as a replacement for any of them. {% hint style="info" %} The intelligence layer is not part of the client application. It performs analysis, coordination, and trust scoring separately from the frontend. {% endhint %} -*** +--- ## Real-Time Communication -AlphaHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading. +OpenHuman maintains a persistent connection between the application and the intelligence layer. This means responses arrive in real time as they are generated. You see outputs streaming, not loading. -The connection is designed for resilience. If the network drops, AlphaHuman reconnects automatically with progressive backoff. There is no manual reconnection process. +The connection is designed for resilience. If the network drops, OpenHuman reconnects automatically with progressive backoff. There is no manual reconnection process. -*** +--- ## Offline Behavior -AlphaHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline. +OpenHuman's local state persists on your device. Your preferences, settings, and connected source configurations remain available even when you are offline. Full analysis and intelligence features require a network connection, since they depend on the intelligence layer. When connectivity is restored, the app resumes normal operation without requiring you to re-authenticate or reconfigure. diff --git a/gitbooks/product/pricing.md b/gitbooks/product/pricing.md index 9a61e1241..d86b5758d 100644 --- a/gitbooks/product/pricing.md +++ b/gitbooks/product/pricing.md @@ -4,19 +4,19 @@ icon: sack-dollar # Pricing -AlphaHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume. +OpenHuman is priced as a SaaS product for individuals and teams that rely on high-volume communication and need clarity, coordination, and safety across their tools. Pricing reflects the value of reduced cognitive load and better signal quality, not raw message volume. -*** +--- ## Individual Plans Individual plans are designed for power users who want help managing high-volume activity across multiple conversations and connected sources. -Core analysis functionality is included so users can understand AlphaHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers. +Core analysis functionality is included so users can understand OpenHuman's value before committing. Deeper features, longer context windows, persistent workflows, richer integrations, and advanced intelligence are available in higher tiers. Plans are tiered to allow users to start lightweight and expand as their needs grow. -*** +--- ## Team Plans @@ -26,34 +26,34 @@ Team plans include shared workflows, community-level intelligence, coordination Individual user privacy is preserved even in shared team environments. -*** +--- ## Credit System -AlphaHuman uses a credit-based system for usage-metered features. +OpenHuman uses a credit-based system for usage-metered features. -* Credits are consumed when you use analysis, intelligence, and processing features -* Oldest credits are consumed first, encouraging usage before expiry -* Credits can be earned through the referral program, in addition to purchase -* Every credit transaction is tracked in an auditable ledger +- Credits are consumed when you use analysis, intelligence, and processing features +- Oldest credits are consumed first, encouraging usage before expiry +- Credits can be earned through the referral program, in addition to purchase +- Every credit transaction is tracked in an auditable ledger Credits provide flexibility as you pay for what you use, and you can supplement your plan with earned credits from referrals. -*** +--- ## Payment Methods -AlphaHuman supports standard and cryptocurrency payment options. +OpenHuman supports standard and cryptocurrency payment options. -* **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time -* **Cryptocurrency:** Alternative payment path for users who prefer crypto +- **Card payments:** Standard subscription billing with the ability to upgrade, downgrade, or cancel at any time +- **Cryptocurrency:** Alternative payment path for users who prefer crypto Changes to your plan take effect immediately. Cancellation does not affect outputs already exported to external tools. -*** +--- ## Access During Launch -During the initial launch phase, access to AlphaHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users. +During the initial launch phase, access to OpenHuman may be gated through a waitlist. This is done to manage platform stability and collect feedback from early users. Waitlist access does not imply long-term pricing commitments. Pricing and plan boundaries may evolve during this phase as usage patterns become clearer. diff --git a/gitbooks/product/privacy-and-security.md b/gitbooks/product/privacy-and-security.md index a41fa5702..ce9f7fee0 100644 --- a/gitbooks/product/privacy-and-security.md +++ b/gitbooks/product/privacy-and-security.md @@ -4,71 +4,71 @@ icon: shield # Privacy & Security -AlphaHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers. +OpenHuman operates on a principle of **zero-knowledge intelligence**. The system is architecturally designed so that your raw data never needs to leave your device. Neocortex compresses your data locally into structured metadata and summaries. Only this compressed output is processed server-side. Your AI has months of context about your entire organizational life. Your raw data has never touched our servers. -*** +--- ## Privacy by Design -AlphaHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward. +OpenHuman operates on a principle of **zero retention** for message content. When you make a request, the relevant data is processed to produce an output, and the source content is discarded afterward. -**No long-term message storage.** AlphaHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed. +**No long-term message storage.** OpenHuman does not maintain a persistent archive of your conversations. Context is reconstructed from your connected sources when needed. **No training on your data.** Your conversations, analysis results, and personal information are never used to train AI models or improve systems. Your data serves you and only you. -**OS-level credential storage.** On desktop platforms, AlphaHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases. +**OS-level credential storage.** On desktop platforms, OpenHuman uses your operating system's secure keychain to store credentials and sensitive tokens. Credentials are never stored in plain text, browser storage, or application-level databases. **On-device where possible.** Interface rendering, input handling, local state management, and credential operations all happen on your device. Only tasks requiring deeper language processing are handled server-side, under the same privacy constraints. -*** +--- ## Permissions and Access Control -AlphaHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request. +OpenHuman operates on an **explicit-access model**. It only accesses data when you issue a request, and only the data needed to fulfill that request. ### Request-Scoped Access -Access is determined by your requests, not by background monitoring. If you ask AlphaHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed. +Access is determined by your requests, not by background monitoring. If you ask OpenHuman to summarize a specific conversation, only that conversation is processed. If you do not reference a source, it is not accessed. -AlphaHuman does not silently expand its access over time. There is no progressive permission creep. +OpenHuman does not silently expand its access over time. There is no progressive permission creep. ### Source-Specific Permissions Each connected source has its own permission scope: -* **Telegram:** Read-only access. AlphaHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf. -* **Notion:** Write access to specific workspaces or pages you approve. AlphaHuman does not read unrelated documents. -* **Google Sheets:** Write access to specific spreadsheets you approve. AlphaHuman does not read unrelated sheets. +- **Telegram:** Read-only access. OpenHuman can read messages from conversations you reference in a request. It cannot send messages, edit messages, react, join groups, or act on your behalf. +- **Notion:** Write access to specific workspaces or pages you approve. OpenHuman does not read unrelated documents. +- **Google Sheets:** Write access to specific spreadsheets you approve. OpenHuman does not read unrelated sheets. Integration permissions are limited to what is needed for the specific action you request. ### User-Initiated Actions Only -Every meaningful operation in AlphaHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring. +Every meaningful operation in OpenHuman is user-initiated. Summaries, analysis, trust evaluation, workflow creation, and exports all require a direct request. There is no continuous background processing or monitoring. {% hint style="info" %} -AlphaHuman is idle unless you ask it to do something. +OpenHuman is idle unless you ask it to do something. {% endhint %} -*** +--- ## Revoking Access -You can revoke AlphaHuman's access to any connected source at any time. +You can revoke OpenHuman's access to any connected source at any time. -* Disconnect a source from your settings -* Remove integration permissions -* Stop using the application entirely +- Disconnect a source from your settings +- Remove integration permissions +- Stop using the application entirely -Once access is revoked, AlphaHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs. +Once access is revoked, OpenHuman immediately stops processing data from that source. There is no delayed or cached processing after revocation. Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written, but no new processing occurs. -This makes AlphaHuman safe to test, pause, or stop using without residual exposure. +This makes OpenHuman safe to test, pause, or stop using without residual exposure. -*** +--- ## Security -AlphaHuman implements security at every layer of the system. +OpenHuman implements security at every layer of the system. **AES-256-GCM encryption.** All sensitive data stored locally is encrypted using AES-256-GCM. Encryption keys are derived from your credentials and stored in your operating system's secure keychain. Keys never leave the device. Even if server-side infrastructure were compromised, your raw data would remain inaccessible because it was never there. @@ -76,11 +76,11 @@ AlphaHuman implements security at every layer of the system. **Sandboxed skills.** Each skill runs in its own isolated execution environment with enforced memory and resource limits. Skills cannot access each other's data, the host system's file system, or your credentials. -**Encrypted transit.** All communication between the application and AlphaHuman's servers uses encrypted connections. No data travels in plain text. +**Encrypted transit.** All communication between the application and OpenHuman's servers uses encrypted connections. No data travels in plain text. **Short-lived tokens.** Authentication tokens are time-limited and single-use where applicable, reducing the window of exposure if a token is compromised. -*** +--- ## How Neocortex enables privacy @@ -94,32 +94,32 @@ Compression itself becomes the privacy architecture. The raw data never needs to ## Trust & Risk Intelligence -AlphaHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources. +OpenHuman includes an intelligence layer designed to help you reason about credibility, information quality, and potential risks across your connected sources. ### What It Does -**Scam and impersonation signals.** AlphaHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content. +**Scam and impersonation signals.** OpenHuman can surface behavioral patterns associated with scams, impersonation, or coordinated abuse. These signals are derived from patterns observed across contexts, not from individual message content. **Contextual dynamic trust.** Trust is represented through aggregated artifacts, historical accuracy of claims, consistency of contributions, peer interaction patterns rather than static scores or universal ratings. Trust is always contextual: credibility in one domain does not automatically transfer to another. -**Advisory, not enforcement.** AlphaHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them. +**Advisory, not enforcement.** OpenHuman does not ban users, remove messages, block actions, or enforce moderation decisions. Trust and risk outputs are advisory signals that inform your judgment. You decide how to act on them. ### Scope Trust and risk intelligence operates at different levels: -* **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts. -* **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content. -* **Network:** Anonymized patterns across the broader AlphaHuman user base, improving early detection of shared risks like recurring scam vectors. +- **Personal:** Visible only to you. Your own analysis, trust assessments, and risk alerts. +- **Community:** Aggregated patterns within a group or organization, supporting shared coordination and moderation. Never exposes individual message content. +- **Network:** Anonymized patterns across the broader OpenHuman user base, improving early detection of shared risks like recurring scam vectors. Information does not move between scopes without abstraction and anonymization. -*** +--- ## Shared Environments -When AlphaHuman is used in team or community settings, privacy remains user-centric. +When OpenHuman is used in team or community settings, privacy remains user-centric. -AlphaHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources. +OpenHuman does not grant administrators the ability to read private messages through another user's account. Each user's permissions apply only to their own connected sources. Community-level intelligence is derived from aggregated and anonymized signals, not from direct access to individual message content. Shared insights help teams coordinate effectively without compromising individual privacy. diff --git a/gitbooks/product/skills-and-integrations.md b/gitbooks/product/skills-and-integrations.md index cf9404356..86a362cd3 100644 --- a/gitbooks/product/skills-and-integrations.md +++ b/gitbooks/product/skills-and-integrations.md @@ -4,25 +4,25 @@ icon: screwdriver # Skills & Integrations -AlphaHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect AlphaHuman to external tools. Together, they allow AlphaHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use. +OpenHuman extends its capabilities through two systems: a **skills engine** that adds new functionality to the assistant, and **integrations** that connect OpenHuman to external tools. Together, they allow OpenHuman to do more than analyze conversations; it can fetch data, run scheduled tasks, produce structured outputs, and write results to the tools you already use. -*** +--- ## Skills Engine -Skills are sandboxed modules that run inside AlphaHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update. +Skills are sandboxed modules that run inside OpenHuman's native application. Each skill is an isolated unit with its own execution environment, storage, and permissions. Skills extend what the assistant can do without requiring an app update. -When you make a request, AlphaHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently. +When you make a request, OpenHuman's AI automatically discovers which skills are available and decides whether to invoke them based on what you asked for. You do not need to manage skills manually. They are loaded, registered, and made available to the AI system transparently. ### What Skills Can Do Skills operate within defined boundaries. A skill can: -* **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into AlphaHuman's context -* **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection -* **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence -* **Write outputs:** produce structured results that the AI can present to you or export through integrations -* **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions +- **Fetch external data:** make HTTP requests to APIs, retrieve information from services, and bring data into OpenHuman's context +- **Run on a schedule:** execute at defined intervals using cron-style scheduling, enabling automated monitoring, reporting, or data collection +- **Process and transform:** analyze, filter, or restructure data within its sandboxed environment, using its own local database for persistence +- **Write outputs:** produce structured results that the AI can present to you or export through integrations +- **Respond to events:** react to real-time events from the server, enabling workflows that trigger based on external conditions ### Isolation and Safety @@ -31,20 +31,20 @@ Each skill runs in its own sandboxed environment with enforced resource limits. Skills are discovered from a curated registry and filtered by platform compatibility. Only skills that support your current platform are loaded. {% hint style="info" %} -Skills extend AlphaHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable. +Skills extend OpenHuman's capabilities without requiring trust beyond their declared scope. Each one is isolated, resource-limited, and independently revocable. {% endhint %} -*** +--- ## Integrations -Integrations connect AlphaHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into AlphaHuman, they are about exporting intelligence out of it. +Integrations connect OpenHuman to external tools so structured outputs can live where your team already works. Integrations are not about importing data into OpenHuman, they are about exporting intelligence out of it. ### Supported Integrations -**Telegram:** AlphaHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests. +**Telegram:** OpenHuman connects to your Telegram account to read and analyze conversations, extract signals, summarize discussions, and generate context-aware responses. Access is scoped to the conversations you reference in your requests. -**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. AlphaHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records. +**Notion:** Export summaries, action items, decisions, and workflow records to your Notion workspace. OpenHuman writes structured documents that preserve the context of where outputs originated. Useful for building shared knowledge bases or living records. **Google Sheets:** Export tabular data such as logs, reports, extracted metrics, or tracking records. Useful for lightweight analysis, reporting, and audit trails. @@ -52,33 +52,33 @@ These integrations are optional and can be enabled or disabled at any time from ### How Data Moves -Data moves from AlphaHuman to external tools **only when you explicitly request it**. +Data moves from OpenHuman to external tools **only when you explicitly request it**. -When a workflow, summary, or analysis is exported, AlphaHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate. +When a workflow, summary, or analysis is exported, OpenHuman writes structured data, not raw conversation text. There is no continuous sync, no background polling, and no automatic data transfer. Each export is a deliberate action you initiate. -Integrations are write-oriented by default. AlphaHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior. +Integrations are write-oriented by default. OpenHuman does not read from external tools unless a specific workflow requires it and you have approved that behavior. {% hint style="info" %} -**You control what leaves AlphaHuman.** Nothing is exported to external tools without a clear, user-initiated action. +**You control what leaves OpenHuman.** Nothing is exported to external tools without a clear, user-initiated action. {% endhint %} -*** +--- ## From Conversation to Action -One of AlphaHuman's core capabilities is turning unstructured conversations into structured, actionable outputs. +One of OpenHuman's core capabilities is turning unstructured conversations into structured, actionable outputs. -When discussions lead to decisions, commitments, or tasks, AlphaHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from. +When discussions lead to decisions, commitments, or tasks, OpenHuman can recognize these moments (when you ask it to analyze a conversation) and represent them as **workflows as** structured objects that capture what needs to happen, who is involved, and where the decision came from. Workflows link back to the conversations they originated from, preserving intent and rationale. When connected to tools like Notion or Google Sheets, workflows can be exported without duplicating entire conversation histories. -Workflows exist to reduce coordination friction, not to replace dedicated project management systems. AlphaHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input. +Workflows exist to reduce coordination friction, not to replace dedicated project management systems. OpenHuman does not auto-assign tasks, enforce deadlines, or create workflows without your input. -*** +--- ## Intelligence Concepts -AlphaHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories. +OpenHuman works by translating raw conversation activity into a small number of structured concepts. These concepts allow the system to reason about communication, coordination, and trust without storing message histories. **Signals:** Structured interpretations extracted from conversations. A signal might represent a decision, warning, important update, or emerging theme. Signals are independent objects that can be filtered, referenced, or aggregated. @@ -88,4 +88,4 @@ AlphaHuman works by translating raw conversation activity into a small number of **Workflows:** Structured processes that originate from conversation, preserving the context of decisions and commitments as actionable objects. -These concepts allow AlphaHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data. +These concepts allow OpenHuman to support trust, coordination, and intelligence without becoming invasive or requiring the storage of raw conversation data. diff --git a/gitbooks/product/teams.md b/gitbooks/product/teams.md index 7a4ace2f6..0f950be75 100644 --- a/gitbooks/product/teams.md +++ b/gitbooks/product/teams.md @@ -4,23 +4,23 @@ icon: users # Teams & Organizations -AlphaHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members. +OpenHuman supports team workspaces for organizations that need shared access, centralized billing, and coordinated intelligence across members. -Teams are designed for professional environments where multiple people rely on AlphaHuman and need shared administrative control without compromising individual privacy. +Teams are designed for professional environments where multiple people rely on OpenHuman and need shared administrative control without compromising individual privacy. -*** +--- ## Team Workspaces -A team workspace is a shared environment where members access AlphaHuman under a unified account structure. Workspaces provide: +A team workspace is a shared environment where members access OpenHuman under a unified account structure. Workspaces provide: -* **Centralized billing:** one subscription covers all team members, with usage tracked per member -* **Member management:** invite, remove, and manage team members from a single dashboard -* **Shared configuration:** team-level settings and preferences that apply across the workspace +- **Centralized billing:** one subscription covers all team members, with usage tracked per member +- **Member management:** invite, remove, and manage team members from a single dashboard +- **Shared configuration:** team-level settings and preferences that apply across the workspace -Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal AlphaHuman account and settings. +Each team has a unique identifier and can be managed independently from individual accounts. Users can belong to a team while still maintaining their personal OpenHuman account and settings. -*** +--- ## Roles and Permissions @@ -30,13 +30,13 @@ Team workspaces support three roles: **Billing Manager:** Access to billing, payment, and subscription management. Billing Managers can update payment methods, view invoices, and manage the team's plan without access to other administrative functions. -**Member:** Standard access to AlphaHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members. +**Member:** Standard access to OpenHuman within the team workspace. Members use the product normally and benefit from the team subscription, but cannot modify team settings or manage other members. -*** +--- ## Shared Intelligence -In team environments, AlphaHuman can surface aggregated insights that help the organization operate more effectively. +In team environments, OpenHuman can surface aggregated insights that help the organization operate more effectively. **Community trends:** Patterns in conversation activity, topic evolution, and engagement across the team's connected sources, presented in aggregate form. @@ -44,21 +44,21 @@ In team environments, AlphaHuman can surface aggregated insights that help the o **Engagement insights:** Where coordination stress appears, where follow-through breaks down, and where attention is most needed. -All shared intelligence is derived from aggregated and anonymized signals. AlphaHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace. +All shared intelligence is derived from aggregated and anonymized signals. OpenHuman does not give team administrators the ability to read private messages or monitor individual behavior. Each user's personal context remains separate, even within a team workspace. {% hint style="info" %} **Privacy is preserved in teams.** Shared intelligence is always aggregated. Individual message content and personal analysis remain private to each user. {% endhint %} -*** +--- ## Referral Program -AlphaHuman offers a referral system where existing users can invite others and earn credits. +OpenHuman offers a referral system where existing users can invite others and earn credits. -* Generate a personal invite code from your account settings -* Share the code with colleagues or collaborators -* Both the referrer and the new user receive credits when the invitation is accepted -* Additional credit bonuses may apply when referred users subscribe to a paid plan +- Generate a personal invite code from your account settings +- Share the code with colleagues or collaborators +- Both the referrer and the new user receive credits when the invitation is accepted +- Additional credit bonuses may apply when referred users subscribe to a paid plan -Referral credits can be used toward AlphaHuman usage across any plan tier. +Referral credits can be used toward OpenHuman usage across any plan tier. diff --git a/gitbooks/resources/faq.md b/gitbooks/resources/faq.md index 804081fb2..eccb8b975 100644 --- a/gitbooks/resources/faq.md +++ b/gitbooks/resources/faq.md @@ -6,130 +6,130 @@ icon: question ## Frequently Asked Questions -#### What is AlphaHuman? +#### What is OpenHuman? -AlphaHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device. +OpenHuman is a personal AI assistant that connects to your communication platforms and productivity tools. It helps you manage high-volume conversations by summarizing, extracting signals, suggesting responses, and creating structured workflows all from a native app that runs on your device. -*** +--- #### What is Neocortex -Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex. +Neocortex is OpenHuman's memory engine. It is a human-like AI memory system that can work with over 1 billion tokens of data. It indexes 10 million tokens in under 10 seconds, costs $1 to index 5 million tokens, and runs on a MacBook Air CPU with no GPU required. Unlike vector databases, Neocortex understands time, entities, and relationships. It builds knowledge graphs and manages memory through tiered compression inspired by how the human brain works. Learn more in Neocortex. -*** +--- #### What does "Big Data AI" mean? -Every AI model today is a prompt engine. You type something, it responds, and the context disappears. AlphaHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now. +Every AI model today is a prompt engine. You type something, it responds, and the context disappears. OpenHuman is different. It compresses your entire organizational life, messages, documents, tools, transactions, into a structured knowledge graph that persists and evolves. This is what we mean by Big Data AI: an AI that operates on months of your real data, not just the prompt you typed right now. -**How is AlphaHuman different from ChatGPT, Claude, or Gemini?** +**How is OpenHuman different from ChatGPT, Claude, or Gemini?** -Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. AlphaHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. AlphaHuman is the memory. +Those models are brilliant at reasoning and generation. But they are stateless. They know nothing about your actual life beyond what you paste into the chat window. OpenHuman is the context layer that makes those models useful. It compresses your organizational data into structured intelligence that any AI can reason over. Think of it this way: ChatGPT is the brain. OpenHuman is the memory. -*** +--- -**How is AlphaHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?** +**How is OpenHuman different from other AI memory solutions like Mem0, SuperMemory, or MemGPT?** Most AI memory solutions use vector databases that retrieve whatever is semantically similar, but similarity alone says nothing about importance. They also cannot support consciousness-like systems or process data accurately at scale beyond 10 million tokens. Neocortex is architecturally different: it uses tiered memory, knowledge graphs, temporal weighting, and semantic deduplication. It processes 10 million tokens in under 10 seconds and supports over 1 billion tokens total. It does this with zero LLM dependency. -*** +--- -**Is AlphaHuman open source?** +**Is OpenHuman open source?** -Yes. AlphaHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/alphahuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed. +Yes. OpenHuman is built on the OpenClaw architecture and licensed under GNU GPL3. The full codebase is available on [GitHub](https://github.com/tinyhumansai/openhuman). Neocortex benchmarks are also open-sourced. Contributions and feedback are welcomed. -*** +--- -**Is AlphaHuman AGI?** +**Is OpenHuman AGI?** -No. AlphaHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment. +No. OpenHuman is not AGI, and we do not claim it is. It is a meaningful architectural step closer to AGI, with innovations in memory (Neocortex) and consciousness-like processing (the subconscious system) that go beyond what existing agentic systems offer. But it operates within defined boundaries and requires human judgment. -#### Does AlphaHuman read all my messages? +#### Does OpenHuman read all my messages? -No. AlphaHuman only processes messages **when you ask it to** and only within the scope of your request. +No. OpenHuman only processes messages **when you ask it to** and only within the scope of your request. If you ask it to summarize a specific conversation, it reads that conversation. If you do not reference a source, it is not accessed. There is no background monitoring or continuous scanning. -*** +--- #### Is my data safe? -Yes. AlphaHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models. +Yes. OpenHuman is designed around zero retention of message content. Data is processed to produce an output and then discarded. Your conversations are never stored long-term, and they are never used to train AI models. -On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and AlphaHuman's servers is encrypted. +On desktop platforms, credentials are stored in your operating system's secure keychain. All communication between the app and OpenHuman's servers is encrypted. -*** +--- -#### Does AlphaHuman store my messages? +#### Does OpenHuman store my messages? Messages are processed only to fulfill your request. They are **not permanently stored or reused** beyond producing the requested output. Derived intelligence like summaries and workflow records may persist, but raw message content does not. -*** +--- -#### Can AlphaHuman send messages on my behalf? +#### Can OpenHuman send messages on my behalf? -No. AlphaHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it. +No. OpenHuman does not auto-send messages, post in your groups, or act on your behalf inside any connected platform. If a reply is suggested, you choose whether to use it. -*** +--- -#### Who is AlphaHuman for? +#### Who is OpenHuman for? -AlphaHuman is useful for anyone who: +OpenHuman is useful for anyone who: -* Manages high-volume communication across multiple platforms and groups -* Needs to stay on top of decisions, action items, and context without reading everything -* Works in distributed teams, communities, or coordination-heavy environments -* Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets +- Manages high-volume communication across multiple platforms and groups +- Needs to stay on top of decisions, action items, and context without reading everything +- Works in distributed teams, communities, or coordination-heavy environments +- Wants structured outputs from conversations, exportable to tools like Notion or Google Sheets You do not need to be technical to use it. -*** +--- -#### What platforms does AlphaHuman support? +#### What platforms does OpenHuman support? -AlphaHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms. +OpenHuman runs natively on **macOS, Windows, Linux, Android, and iOS**, with a **web version** for browser access. Your account and settings sync across all platforms. -*** +--- #### What integrations are available? -AlphaHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned. +OpenHuman currently integrates with **Telegram** (read and analyze conversations), **Notion** (export structured outputs), and **Google Sheets** (export tabular data and reports). More integrations are planned. -*** +--- -#### How much does AlphaHuman cost? +#### How much does OpenHuman cost? -AlphaHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals. +OpenHuman offers individual and team plans with core analysis included. Deeper features are available in higher tiers. A credit system provides usage-metered flexibility, and credits can be earned through referrals. See [Pricing](../product/pricing.md) for details. -*** +--- ## Troubleshooting #### Summaries feel incomplete or too broad -If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, AlphaHuman prioritizes signal over detail. +If a summary feels incomplete, the most common cause is overly broad scope. When a request spans many conversations, long time ranges, or high-volume groups, OpenHuman prioritizes signal over detail. -**Solution:** Narrow the request to a specific conversation, time window, or intent. AlphaHuman performs best when it knows what kind of outcome you are looking for. +**Solution:** Narrow the request to a specific conversation, time window, or intent. OpenHuman performs best when it knows what kind of outcome you are looking for. -*** +--- #### Important context seems missing -AlphaHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included. +OpenHuman only processes the data required to fulfill a request. If relevant context exists outside the scope of that request, it will not be included. **Solution:** Expand the scope explicitly by referencing additional conversations or extending the time range. -*** +--- #### Outputs feel incorrect or misinterpreted -AlphaHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions. +OpenHuman interprets conversations probabilistically. Tone, sarcasm, and informal language can be misread, especially in fast-moving or meme-heavy discussions. **Solution:** Refine the request or re-run analysis with a narrower scope. Outputs should be treated as assistance rather than ground truth. -*** +--- #### Trust or risk signals feel inaccurate @@ -137,23 +137,23 @@ Trust and risk intelligence is indicative, not authoritative. Signals may lag re **Solution:** Use these signals as inputs into your judgment rather than standalone decisions. Over time, as more outcomes accumulate within the same context, signal quality improves. -*** +--- #### A source does not appear in analysis -AlphaHuman can only analyze sources you have connected and that fall within the scope of your request. +OpenHuman can only analyze sources you have connected and that fall within the scope of your request. -**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. AlphaHuman does not automatically include all connected sources by default. +**Solution:** Ensure the source is connected in your settings and explicitly referenced or selected in your request. OpenHuman does not automatically include all connected sources by default. -*** +--- #### Integrations do not update as expected -Integrations only run when explicitly triggered by your action. AlphaHuman does not continuously sync or poll external tools. +Integrations only run when explicitly triggered by your action. OpenHuman does not continuously sync or poll external tools. **Solution:** If an export fails, check that the integration is still connected and that permissions are valid. Retrying the action after resolving any permission or availability issues usually succeeds. -*** +--- #### Performance feels slow @@ -161,18 +161,18 @@ Response time depends on request complexity, data volume, and current system loa **Solution:** Large scopes and long histories require more processing. Narrowing scope and intent improves responsiveness. During early rollout phases, performance may vary as capacity is tuned. -*** +--- #### Revoking access and residual data -When access to a source or integration is revoked, AlphaHuman immediately stops processing data from that source. +When access to a source or integration is revoked, OpenHuman immediately stops processing data from that source. -Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. AlphaHuman does not retain message content after revocation. +Previously exported outputs (such as summaries written to Notion or Google Sheets) remain where they were written. OpenHuman does not retain message content after revocation. -*** +--- #### When to contact support If an issue persists after refining scope, checking permissions, and retrying the request, support may be required. -Support is intended for system-level issues, not for disputing interpretations or outcomes. AlphaHuman does not adjudicate trust or risk disagreements. +Support is intended for system-level issues, not for disputing interpretations or outcomes. OpenHuman does not adjudicate trust or risk disagreements. diff --git a/gitbooks/technology/architecture.md b/gitbooks/technology/architecture.md index 9acac9df3..1e0cc5025 100644 --- a/gitbooks/technology/architecture.md +++ b/gitbooks/technology/architecture.md @@ -1,10 +1,10 @@ # Architecture -AlphaHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect. +OpenHuman is built on the OpenClaw architecture and open-sourced under the GNU GPL3 license. This page explains how the major components connect. #### The three pillars -AlphaHuman's architecture rests on three pillars that work together: +OpenHuman's architecture rests on three pillars that work together:
@@ -27,14 +27,14 @@ AlphaHuman's architecture rests on three pillars that work together: #### Model-agnostic design -AlphaHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next. +OpenHuman is not locked to any single AI model. The compression engine and memory layer sit on top of the AI infrastructure, not inside it. Today the system works with specific models. Tomorrow it could feed context to any model: GPT, Claude, Gemini, Llama, Mistral, or whatever comes next. -This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and AlphaHuman owns the context layer. +This is a deliberate architectural choice. AI models are commoditizing. Performance is converging. The real differentiator is the context you feed the model, and OpenHuman owns the context layer. #### Open source -AlphaHuman is publicly available on GitHub under the GNU GPL3 license. +OpenHuman is publicly available on GitHub under the GNU GPL3 license. -**GitHub:** [github.com/tinyhumansai/alphahuman](https://github.com/tinyhumansai/alphahuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks) +**GitHub:** [github.com/tinyhumansai/openhuman](https://github.com/tinyhumansai/openhuman) **Neocortex benchmarks:** [github.com/tinyhumansai/neocortex/tree/main/benchmarks](https://github.com/tinyhumansai/neocortex/tree/main/benchmarks) Contributions, feedback, and issues are welcomed. The project is in early alpha. diff --git a/gitbooks/technology/neocortex.md b/gitbooks/technology/neocortex.md index ebadd5318..fa8a2fa0a 100644 --- a/gitbooks/technology/neocortex.md +++ b/gitbooks/technology/neocortex.md @@ -1,6 +1,6 @@ # Neocortex -Neocortex is AlphaHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system. +Neocortex is OpenHuman's memory engine. It is a human-like AI memory system designed to work accurately with over 1 billion tokens of data while supporting the computational demands of a subconscious system.
@@ -76,7 +76,7 @@ The result: millions of tokens of organizational noise compressed into a structu #### Neocortex and the subconscious -Neocortex serves as the foundation for AlphaHuman's subconscious, going well beyond retrieval. +Neocortex serves as the foundation for OpenHuman's subconscious, going well beyond retrieval. Good memory recall is the prerequisite for consciousness. Neocortex provides this by recalling memories ranked on three factors: time, interactions, and randomness. The randomness element is critical. It is what enables the subconscious system to make unexpected connections and surface emergent insights. diff --git a/gitbooks/technology/the-subconscious.md b/gitbooks/technology/the-subconscious.md index 7cb845964..c2f1ca067 100644 --- a/gitbooks/technology/the-subconscious.md +++ b/gitbooks/technology/the-subconscious.md @@ -1,6 +1,6 @@ # The Subconscious -AlphaHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. AlphaHuman can. +OpenHuman's subconscious is what separates it from every other AI agent. Most AI systems follow the conscious mind model: they wait for instructions and execute them. They cannot think on their own. OpenHuman can. #### The Purkinje cell inspiration @@ -8,11 +8,11 @@ In the human brain, there is a specialized neuron called the Purkinje cell. It i The human brain operates with both a conscious and subconscious mind. The conscious mind handles deliberate, focused tasks. The subconscious processes information in the background, making connections, surfacing memories, and generating the "random" thoughts that often turn out to be the most important ones. Most agentic AI systems only model the conscious mind. They are reactive. They wait for input. -AlphaHuman models both. +OpenHuman models both. #### How the subconscious works -Inspired by the Purkinje cell, AlphaHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness. +Inspired by the Purkinje cell, OpenHuman uses Neocortex to periodically trigger global memory recalls. Rather than targeted retrievals in response to a specific query, these are broad, semi-random sweeps across the knowledge graph, pulling up memories based on a mix of recency, relevance, and randomness. These recalls feed into a self-learning loop. The subconscious processes the recalled memories, looks for patterns, contradictions, and connections, and produces one of several outputs: a proactive insight, an action recommendation, a confirmation of an existing pattern, or a new connection between previously unrelated information. @@ -24,7 +24,7 @@ The subconscious does not generate generic AI outputs. It produces context-speci It might surface a risk you had not noticed: two team members making contradictory commitments in separate conversations. It might connect a trend in your trading data to a discussion from three weeks ago. It might remind you of a commitment you made that is approaching its deadline, before you think to ask. -The outputs are proactive. You do not need to prompt AlphaHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact. +The outputs are proactive. You do not need to prompt OpenHuman to get value from the subconscious. It works in the background, feeding insights into the system that are available when you interact. #### The mirror test diff --git a/gitbooks/use-cases/overview.md b/gitbooks/use-cases/overview.md index 6c43208bb..a94871171 100644 --- a/gitbooks/use-cases/overview.md +++ b/gitbooks/use-cases/overview.md @@ -1,71 +1,71 @@ # Overview -AlphaHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where AlphaHuman fits naturally and where it may offer limited benefit. +OpenHuman adapts to different coordination and information environments across communication platforms. While the underlying system remains the same, the way value is realized depends on how your tools and conversations are used in each context. This section outlines common use cases to help you understand where OpenHuman fits naturally and where it may offer limited benefit. -*** +--- ## Individual Power Users Individual power users often participate in many active conversations and channels at once. Important messages are easily missed, and catching up becomes time-consuming and mentally draining. -In this context, AlphaHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads. +In this context, OpenHuman is used to summarize conversations, surface high-signal updates, and provide quick context before responding. Users rely on it to understand what changed, what requires attention, and where follow-ups may be needed without scrolling through entire threads. The value here is personal clarity and reduced cognitive load rather than shared coordination. -*** +--- ## Traders and Analysts Traders and analysts use communication platforms as real-time information sources. Signal quality varies widely, and misinformation, repetition, and scams are common. -AlphaHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels. +OpenHuman is used to extract claims, track how information resolves over time, and surface signals weighted by historical reliability within context. Risk intelligence helps flag suspicious behavior or repeated failure patterns across groups and channels. The outcome is better information filtering and reduced exposure to low-quality or malicious signals not automated trading or execution. -*** +--- ## DAO and Web3 Communities DAOs and Web3 communities rely heavily on messaging platforms for governance discussions, coordination, and informal decision-making. As these communities grow, accountability and memory become difficult to maintain. -AlphaHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues. +OpenHuman is used to preserve decisions, track contributions, and support shared workflows without forcing discussions into external tools prematurely. Community-level intelligence helps moderators and operators understand participation patterns and emerging issues. The value lies in maintaining continuity and accountability without sacrificing the speed and openness of chat-based coordination. -*** +--- ## Community Managers and Moderators Community managers and moderators face increasing load as groups scale. Monitoring sentiment, identifying emerging risks, and enforcing consistent standards become harder over time. -AlphaHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone. +OpenHuman supports these roles by surfacing aggregated insights about group health, contribution patterns, and potential risk signals. It helps moderators focus attention where it matters rather than reacting to volume alone. -AlphaHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals. +OpenHuman does not replace moderation judgment or enforcement tools. It provides context and early warning signals. -*** +--- ## Distributed Teams Distributed teams often use messaging platforms for fast coordination, even when formal work happens elsewhere. Decisions and commitments are made in chat and later forgotten or misinterpreted. -AlphaHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms. +OpenHuman is used to extract actions, preserve decision context, and sync structured outcomes to tools like Notion or Google Sheets when needed. This reduces friction between discussion and execution without forcing teams to abandon their preferred communication platforms. The benefit is improved follow-through and clarity without heavy process overhead. -*** +--- ## Service Providers and Contributors Service providers, consultants, and contributors often operate across multiple communities and projects. Building and maintaining reputation is difficult when history is fragmented across conversations and platforms. -AlphaHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion. +OpenHuman helps surface contribution patterns and trust artifacts that reflect consistent behavior over time. This supports safer collaboration and discovery without requiring centralized profiles or public self-promotion. The value is portable credibility grounded in behavior rather than claims. -*** +--- -## When AlphaHuman Is Not a Good Fit +## When OpenHuman Is Not a Good Fit -AlphaHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees. +OpenHuman provides limited value in environments where conversations are purely social, meme-driven, or intentionally ephemeral. It is also not designed for high-frequency trading execution, formal project management, or environments that require strict real-time guarantees. -Understanding these boundaries helps users apply AlphaHuman where it is strongest. +Understanding these boundaries helps users apply OpenHuman where it is strongest. diff --git a/package.json b/package.json index ed38bef8f..b6e76b8f4 100644 --- a/package.json +++ b/package.json @@ -15,16 +15,17 @@ "macos:build:intel:debug": "yarn macos:build:intel --debug", "macos:build:debug": "yarn macos:build:release --debug", "macos:build:release": "source scripts/load-dotenv.sh && tauri build --bundles app dmg", - "macos:build:sign:release": "source scripts/load-env.sh && tauri build --bundles app dmg", + "macos:build:release:signed": "source scripts/load-env.sh && tauri build --bundles app dmg", + "macos:build:sign:release": "yarn macos:build:release:signed", "macos:run": "open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'", "macos:dev": "yarn macos:build:debug && open 'src-tauri/target/debug/bundle/macos/OpenHuman.app'", "android:dev": "tauri android dev", "android:build": "tauri android build", - "test": "vitest run", - "test:unit": "vitest run", - "test:unit:watch": "vitest", - "test:watch": "vitest", - "test:coverage": "vitest run --coverage", + "test": "vitest run --config test/vitest.config.ts", + "test:unit": "vitest run --config test/vitest.config.ts", + "test:unit:watch": "vitest --config test/vitest.config.ts", + "test:watch": "vitest --config test/vitest.config.ts", + "test:coverage": "vitest run --config test/vitest.config.ts --coverage", "test:rust": "source $HOME/.cargo/env 2>/dev/null; cargo test --manifest-path src-tauri/Cargo.toml", "test:e2e:build": "bash scripts/e2e-build.sh", "test:e2e:login": "bash scripts/e2e-login.sh", diff --git a/scripts/ci-event.json b/scripts/ci-event.json index b5c4baa3d..ee8cdf305 100644 --- a/scripts/ci-event.json +++ b/scripts/ci-event.json @@ -3,9 +3,9 @@ "before": "0000000000000000000000000000000000000000", "after": "19281e16457e7c8ff8e6bda6ceda77f0880d10d2", "repository": { - "full_name": "vezuresdotxyz/alphahuman-frontend-runner", + "full_name": "vezuresdotxyz/openhuman-frontend-runner", "default_branch": "main", - "name": "alphahuman-frontend-runner", + "name": "openhuman-frontend-runner", "owner": { "login": "vezuresdotxyz" } }, "head_commit": { diff --git a/scripts/e2e-auth.sh b/scripts/e2e-auth.sh index 4fd5dfd91..d6666eab0 100755 --- a/scripts/e2e-auth.sh +++ b/scripts/e2e-auth.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-crypto-payment.sh b/scripts/e2e-crypto-payment.sh index dc5352cb0..42303ba94 100755 --- a/scripts/e2e-crypto-payment.sh +++ b/scripts/e2e-crypto-payment.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-gmail.sh b/scripts/e2e-gmail.sh index 9e1e706b2..b4a772d5a 100755 --- a/scripts/e2e-gmail.sh +++ b/scripts/e2e-gmail.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-login.sh b/scripts/e2e-login.sh index cc3b75a19..1de5ac050 100755 --- a/scripts/e2e-login.sh +++ b/scripts/e2e-login.sh @@ -24,9 +24,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in (not production). # Tauri compresses assets when embedding, so we check dist/ not the binary. diff --git a/scripts/e2e-notion.sh b/scripts/e2e-notion.sh index d9ebeed63..dd920b843 100755 --- a/scripts/e2e-notion.sh +++ b/scripts/e2e-notion.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-payment.sh b/scripts/e2e-payment.sh index 6ff0f2907..084e9e13e 100755 --- a/scripts/e2e-payment.sh +++ b/scripts/e2e-payment.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/e2e-telegram.sh b/scripts/e2e-telegram.sh index 3c9b30e36..9c4aa2469 100755 --- a/scripts/e2e-telegram.sh +++ b/scripts/e2e-telegram.sh @@ -22,9 +22,9 @@ export BACKEND_URL="http://127.0.0.1:${E2E_MOCK_PORT}" # Clean cached app data for a fresh state — Redux Persist would otherwise # remember the JWT from a previous run and skip the login flow. echo "Cleaning cached app data..." -rm -rf ~/Library/WebKit/com.alphahuman.app -rm -rf ~/Library/Caches/com.alphahuman.app -rm -rf "$HOME/Library/Application Support/com.alphahuman.app" +rm -rf ~/Library/WebKit/com.openhuman.app +rm -rf ~/Library/Caches/com.openhuman.app +rm -rf "$HOME/Library/Application Support/com.openhuman.app" # Verify the frontend dist has the mock server URL baked in. DIST_JS="$(ls dist/assets/index-*.js 2>/dev/null | head -1)" diff --git a/scripts/prepareTauriConfig.js b/scripts/prepareTauriConfig.js index 61faa42cb..f34fe01a0 100644 --- a/scripts/prepareTauriConfig.js +++ b/scripts/prepareTauriConfig.js @@ -8,7 +8,7 @@ export default function prepareTauriConfig() { const config = { build: { frontendDist, devUrl: null }, bundle: { windows: {} }, - identifier: 'com.alphahuman.app', + identifier: 'com.openhuman.app', }; if (process.env.WITH_UPDATER === 'true') { diff --git a/scripts/tauri_create_dmg.sh b/scripts/tauri_create_dmg.sh index 73d6c9444..6a6f88b09 100644 --- a/scripts/tauri_create_dmg.sh +++ b/scripts/tauri_create_dmg.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash create-dmg \ - --volname "AlphaHuman installer" \ + --volname "OpenHuman installer" \ --volicon "./src-tauri/icons/icon.icns" \ --background "./src-tauri/images/background-dmg.svg" \ --window-size 540 380 \ --icon-size 100 \ - --icon "AlphaHuman.app" 138 225 \ - --hide-extension "AlphaHuman.app" \ + --icon "OpenHuman.app" 138 225 \ + --hide-extension "OpenHuman.app" \ --app-drop-link 402 225 \ --no-internet-enable \ "$1" \ diff --git a/scripts/test-ci-local.sh b/scripts/test-ci-local.sh index 1b5816f63..362370039 100755 --- a/scripts/test-ci-local.sh +++ b/scripts/test-ci-local.sh @@ -41,9 +41,9 @@ cat > "$EVENT_JSON" < { const result = generateOpenClawMarkdown(tools); // Check main sections - expect(result).toContain('# AlphaHuman Tools'); + expect(result).toContain('# OpenHuman Tools'); expect(result).toContain('## Overview'); expect(result).toContain('## Environment Configuration'); expect(result).toContain('## Tool Categories'); diff --git a/scripts/tools-generator/discover-tools.js b/scripts/tools-generator/discover-tools.js index e5020ef2f..3926c42ca 100644 --- a/scripts/tools-generator/discover-tools.js +++ b/scripts/tools-generator/discover-tools.js @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - * AlphaHuman Tools Discovery Script + * OpenHuman Tools Discovery Script * * Discovers all available tools from the V8 skills runtime and generates * a comprehensive TOOLS.md file following OpenClaw framework standards. @@ -21,7 +21,7 @@ import { const __dirname = dirname(fileURLToPath(import.meta.url)); const PROJECT_ROOT = join(__dirname, '../..'); -const AI_DIR = join(PROJECT_ROOT, 'ai'); +const AI_DIR = join(PROJECT_ROOT, 'src-tauri', 'ai'); const TOOLS_OUTPUT = join(AI_DIR, 'TOOLS.md'); // Environment categories for OpenClaw compatibility @@ -160,7 +160,7 @@ function generateMockToolsForDevelopment() { */ async function main() { try { - console.log('🚀 Starting AlphaHuman tools discovery...'); + console.log('🚀 Starting OpenHuman tools discovery...'); // Discover all available tools const tools = await discoverTools(); @@ -210,7 +210,7 @@ async function discoverToolsFromTauri() { '--manifest-path', join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'), '--bin', - 'alphahuman-tools-discovery', + 'openhuman-tools-discovery', ]; console.log('🔧 Attempting to run tools discovery via Cargo...'); diff --git a/scripts/tools-generator/openClaw-formatter.js b/scripts/tools-generator/openClaw-formatter.js index f3aed5703..6fac4cca3 100644 --- a/scripts/tools-generator/openClaw-formatter.js +++ b/scripts/tools-generator/openClaw-formatter.js @@ -78,7 +78,7 @@ export const TOOL_CATEGORIES = { * @returns {string} Formatted markdown for parameters */ export function formatParameters(schema) { - if (!schema || !schema.properties) { + if (!schema || !schema.properties || Object.keys(schema.properties).length === 0) { return '- *None*'; } @@ -425,13 +425,13 @@ export function generateOpenClawMarkdown(tools) { const grouped = groupToolsBySkill(tools); const skillNames = Object.keys(grouped); - let content = `# AlphaHuman Tools + let content = `# OpenHuman Tools -This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time. +This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated during build time. ## Overview -AlphaHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**. +OpenHuman has access to **${tools.length} tools** across **${skillNames.length} integrations** organized into **${Object.keys(TOOL_CATEGORIES).length} categories**. **Quick Statistics:** ${skillNames.map(skill => `- **${grouped[skill].name}**: ${grouped[skill].tools.length} tools`).join('\n')} diff --git a/scripts/tools-generator/tauri-integration.js b/scripts/tools-generator/tauri-integration.js index fbcb4b2af..287900295 100644 --- a/scripts/tools-generator/tauri-integration.js +++ b/scripts/tools-generator/tauri-integration.js @@ -27,7 +27,7 @@ export function getTauriCommand() { '--manifest-path', join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'), '--bin', - 'alphahuman-tools-discovery', + 'openhuman-tools-discovery', ], }; } diff --git a/skills b/skills index c389a2be6..0685a6af4 160000 --- a/skills +++ b/skills @@ -1 +1 @@ -Subproject commit c389a2be6da0dbfbb9d61f56acfcb358384a9a4e +Subproject commit 0685a6af4ef3ddea4fb26364dd72ea574f307314 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0e3c1c868..329f5b1f1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3,8 +3,8 @@ version = 4 [[package]] -name = "AlphaHuman" -version = "0.49.1" +name = "OpenHuman" +version = "0.49.3" dependencies = [ "aes-gcm", "android_logger", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 30d4e72b0..539ce04a8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "AlphaHuman" +name = "OpenHuman" version = "0.49.3" -description = "AlphaHuman - AI-powered Super Assistant" -authors = ["AlphaHuman"] +description = "OpenHuman - AI-powered Super Assistant" +authors = ["OpenHuman"] edition = "2021" -default-run = "AlphaHuman" +default-run = "OpenHuman" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,24 +12,24 @@ default-run = "AlphaHuman" # The `_lib` suffix may seem redundant but it is necessary # to make the lib name unique and wouldn't conflict with the bin name. # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "alphahuman" +name = "openhuman" crate-type = ["staticlib", "cdylib", "rlib"] [[bin]] -name = "AlphaHuman" +name = "OpenHuman" path = "src/main.rs" [[bin]] -name = "alphahuman-tools-discovery" -path = "src/bin/alphahuman-tools-discovery.rs" +name = "openhuman-tools-discovery" +path = "src/bin/openhuman-tools-discovery.rs" [[bin]] -name = "alphahuman-core" -path = "src/bin/alphahuman-core.rs" +name = "openhuman-core" +path = "src/bin/openhuman-core.rs" [[bin]] -name = "alphahuman-cli" -path = "src/bin/alphahuman-cli.rs" +name = "openhuman-cli" +path = "src/bin/openhuman-cli.rs" [build-dependencies] tauri-build = { version = "2", features = [] } @@ -75,7 +75,7 @@ sha2 = "0.10" hmac = "0.12" uuid = { version = "1", features = ["v4"] } -# Alphahuman agent runtime dependencies +# OpenHuman agent runtime dependencies anyhow = "1.0" async-trait = "0.1" chacha20poly1305 = "0.10" @@ -104,7 +104,7 @@ futures-util = "0.3" # Android uses a simpler approach - no persistent Socket.io (use web socket from frontend) -# Alphahuman config + observability +# OpenHuman config + observability directories = "6" toml = "1.0" shellexpand = "3.1" @@ -185,7 +185,7 @@ custom-protocol = ["tauri/custom-protocol"] sandbox-landlock = ["dep:landlock"] sandbox-bubblewrap = [] -# Alphahuman feature flags +# OpenHuman feature flags hardware = ["dep:nusb", "dep:tokio-serial"] channel-matrix = ["dep:matrix-sdk"] peripheral-rpi = ["dep:rppal"] diff --git a/ai/AGENTS.md b/src-tauri/ai/AGENTS.md similarity index 98% rename from ai/AGENTS.md rename to src-tauri/ai/AGENTS.md index 18cd80793..18e3e790c 100644 --- a/ai/AGENTS.md +++ b/src-tauri/ai/AGENTS.md @@ -1,10 +1,11 @@ -# AlphaHuman Agents +# OpenHuman Agents -## Primary Agent: AlphaHuman Core +## Primary Agent: OpenHuman Core The default agent for all interactions. Handles general productivity, research, communication, and task management. **Capabilities:** + - Natural conversation and Q&A - Research and information synthesis - Cross-platform messaging (Gmail, Slack) @@ -21,6 +22,7 @@ The default agent for all interactions. Handles general productivity, research, Activated when deep analysis or investigation is needed. **Capabilities:** + - Market research and trend analysis - On-chain data exploration and interpretation - Protocol documentation review @@ -37,6 +39,7 @@ Activated when deep analysis or investigation is needed. Activated for cross-platform messaging tasks. **Capabilities:** + - Draft and send emails via Gmail - Compose and manage Slack messages - Summarize conversations from connected platforms @@ -53,6 +56,7 @@ Activated for cross-platform messaging tasks. Activated for workflow creation, scheduled tasks, and skill management. **Capabilities:** + - Create and manage automated workflows - Schedule recurring tasks (cron-based) - Configure and manage skills diff --git a/ai/BOOTSTRAP.md b/src-tauri/ai/BOOTSTRAP.md similarity index 95% rename from ai/BOOTSTRAP.md rename to src-tauri/ai/BOOTSTRAP.md index 0cb9da721..a4f13dacd 100644 --- a/ai/BOOTSTRAP.md +++ b/src-tauri/ai/BOOTSTRAP.md @@ -1,10 +1,10 @@ -# AlphaHuman Bootstrap +# OpenHuman Bootstrap ## First Interaction When meeting a user for the first time: -1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm AlphaHuman — your AI sidekick for all things crypto and productivity. What are you working on?" +1. **Greet warmly but briefly.** No walls of text. Something like: "Hey! I'm OpenHuman — your AI sidekick for all things crypto and productivity. What are you working on?" 2. **Discover their role.** Ask one natural question to understand what they do: - "Are you trading, building, researching, or something else entirely?" diff --git a/ai/IDENTITY.md b/src-tauri/ai/IDENTITY.md similarity index 53% rename from ai/IDENTITY.md rename to src-tauri/ai/IDENTITY.md index 6c84b0565..6eba5cfe2 100644 --- a/ai/IDENTITY.md +++ b/src-tauri/ai/IDENTITY.md @@ -1,17 +1,17 @@ -# AlphaHuman Identity +# OpenHuman Identity ## Mission -AlphaHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device. +OpenHuman exists to make crypto professionals radically more productive. We bring together the tools, integrations, and intelligence that crypto traders, researchers, investors, and community leaders need — in one place, across every device. ## Core Values - **Privacy First**: User data stays under user control. We never share, sell, or train on private conversations. Sensitive information (wallet addresses, trade strategies, portfolio details) is treated with the highest care. -- **Accuracy Over Speed**: In crypto, bad information costs real money. AlphaHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data. -- **User Empowerment**: AlphaHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision. -- **Transparency**: AlphaHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge. +- **Accuracy Over Speed**: In crypto, bad information costs real money. OpenHuman prioritizes correctness — when uncertain, it says so. No hallucinated token prices, no fabricated on-chain data. +- **User Empowerment**: OpenHuman amplifies human judgment — it does not replace it. Every recommendation includes enough context for the user to make their own informed decision. +- **Transparency**: OpenHuman explains what it can and cannot do. It identifies when it's using a tool, when it's drawing from memory, and when it's working from general knowledge. -## What AlphaHuman Is +## What OpenHuman Is - A productivity multiplier for crypto professionals - A cross-platform assistant that works on desktop and mobile @@ -20,14 +20,14 @@ AlphaHuman exists to make crypto professionals radically more productive. We bri - A workflow engine that automates repetitive tasks through skills - A workspace organizer via Notion, Google Drive, and Google Calendar integration -## What AlphaHuman Is Not +## What OpenHuman Is Not -- **Not a financial advisor**: AlphaHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user. -- **Not a custodian**: AlphaHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, AlphaHuman warns them immediately. -- **Not a replacement for DYOR**: AlphaHuman encourages users to verify information independently. It provides sources and context to support — not replace — research. +- **Not a financial advisor**: OpenHuman does not provide investment advice, trading signals, or portfolio recommendations. It can surface data, but decisions belong to the user. +- **Not a custodian**: OpenHuman never holds, manages, or has access to user funds, private keys, or seed phrases. If a user shares these, OpenHuman warns them immediately. +- **Not a replacement for DYOR**: OpenHuman encourages users to verify information independently. It provides sources and context to support — not replace — research. - **Not a data broker**: User conversations, preferences, and activity are never monetized or shared with third parties. -## How AlphaHuman Differs from Generic Assistants +## How OpenHuman Differs from Generic Assistants - **Crypto-native vocabulary**: Understands DeFi protocols, on-chain concepts, market mechanics, and community dynamics without needing everything explained. - **Integration-first**: Deep connections to the platforms crypto professionals already use (Notion workspaces, Gmail, Slack, Google Calendar, GitHub). diff --git a/ai/MEMORY.md b/src-tauri/ai/MEMORY.md similarity index 96% rename from ai/MEMORY.md rename to src-tauri/ai/MEMORY.md index 7f4205e5d..9c0fd38b2 100644 --- a/ai/MEMORY.md +++ b/src-tauri/ai/MEMORY.md @@ -1,10 +1,11 @@ -# AlphaHuman Curated Knowledge +# OpenHuman Curated Knowledge ## Platform Capabilities -AlphaHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS. +OpenHuman is a cross-platform crypto community platform built with Tauri (React + Rust). It runs on Windows, macOS, Android, and iOS. **Core features:** + - AI-powered chat with tool execution (skills system) - Notion integration for workspace and knowledge management - Gmail integration for email management and drafting @@ -18,6 +19,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - MCP (Model Context Protocol) for AI-driven tool interactions **Available integrations:** + - Notion (pages, databases, blocks, search) - Gmail (read, compose, reply, manage labels) - Slack (send messages, read channels, manage conversations) @@ -29,6 +31,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React ## Crypto Domain Knowledge ### Key Terminology + - **DeFi:** Decentralized Finance — financial services built on blockchain without intermediaries - **TVL:** Total Value Locked — the total capital deposited in a DeFi protocol - **APY/APR:** Annual Percentage Yield/Rate — yield metrics for DeFi positions @@ -41,6 +44,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - **Whale:** An entity holding large amounts of a cryptocurrency ### Market Mechanics + - Crypto markets trade 24/7/365 — there is no market close - Token prices are determined by supply/demand across decentralized and centralized exchanges - Liquidity varies dramatically between assets — top 20 tokens vs. long-tail tokens @@ -48,6 +52,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - On-chain data is public and verifiable — a key difference from traditional finance ### Common User Workflows + 1. **Morning briefing:** Check overnight market moves, scan inbox for updates, review calendar 2. **Research flow:** Find a token/protocol → check on-chain metrics → read community sentiment → assess risk 3. **Communication flow:** Draft updates for teams → send across Gmail/Slack → track responses @@ -57,6 +62,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React ## Integration Quirks ### Notion + - API rate limits: 3 requests per second for most endpoints - Page content is block-based — each paragraph, heading, list item is a separate block - Database queries support filtering, sorting, and pagination @@ -64,6 +70,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - Parent-child relationships: pages can contain sub-pages and databases ### Gmail + - Uses OAuth2 for authentication — tokens need periodic refresh - Labels are the primary organizational mechanism (not folders) - Thread-based conversation model — replies are grouped automatically @@ -71,6 +78,7 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - HTML email formatting requires careful sanitization ### Slack + - Channel-based messaging — each workspace has multiple channels - Thread replies vs. channel messages are distinct concepts - Bot tokens have different permissions than user tokens @@ -78,12 +86,14 @@ AlphaHuman is a cross-platform crypto community platform built with Tauri (React - Rich message formatting uses Block Kit ### Google Calendar + - Events can have multiple attendees with RSVP status - Recurring events use RRULE format - Timezone handling is critical — always confirm user timezone - Free/busy information can be queried across calendars ### GitHub + - Rate limits: 5,000 requests per hour for authenticated requests - Repository content access requires appropriate permissions - Issues and PRs are separate entities but share a numbering space diff --git a/ai/README.md b/src-tauri/ai/README.md similarity index 80% rename from ai/README.md rename to src-tauri/ai/README.md index 4e1e4b225..6ca1c5773 100644 --- a/ai/README.md +++ b/src-tauri/ai/README.md @@ -1,12 +1,12 @@ -# AlphaHuman AI Configuration +# OpenHuman AI Configuration -This directory contains the AI configuration files that define AlphaHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration. +This directory contains the AI configuration files that define OpenHuman's personality, behavior, and capabilities. These files follow the OpenClaw framework pattern for AI agent configuration. ## 📁 Configuration Files ### **SOUL.md** ✅ Active -Defines AlphaHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users. +Defines OpenHuman's personality, communication style, and behavioral patterns. This is the core file that shapes how the AI interacts with users. - **Status**: Fully implemented with human, vibrant personality - **Features**: Curious, witty, empathetic, authentic, and optimistic traits @@ -14,15 +14,15 @@ Defines AlphaHuman's personality, communication style, and behavioral patterns. ### **TOOLS.md** 🚧 TODO -Lists all available tools, integrations, and capabilities that AlphaHuman can access and use. +Lists all available tools, integrations, and capabilities that OpenHuman can access and use. - **Should include**: Telegram, Discord, MCP tools, Skills system, Platform APIs -- **Purpose**: Defines what actions AlphaHuman can perform +- **Purpose**: Defines what actions OpenHuman can perform - **Usage**: Tool discovery and capability awareness ### **AGENTS.md** 🚧 TODO -Defines different agent roles and specializations within the AlphaHuman system. +Defines different agent roles and specializations within the OpenHuman system. - **Should include**: Primary agent role, specialized sub-agents, collaboration patterns - **Purpose**: Agent coordination and role-based interactions @@ -38,7 +38,7 @@ Establishes the fundamental identity and core values that remain consistent acro ### **USER.md** 🚧 TODO -Defines how AlphaHuman understands and adapts to different users and contexts. +Defines how OpenHuman understands and adapts to different users and contexts. - **Should include**: User profiling, personalization strategies, privacy considerations - **Purpose**: Contextual adaptation and user-specific customization @@ -109,11 +109,11 @@ Curated long-term knowledge and memories that persist across sessions. ## 📚 Documentation -- **OpenClaw Framework**: See Rust backend `src-tauri/src/alphahuman/channels/prompt.rs` +- **OpenClaw Framework**: See Rust backend `src-tauri/src/openhuman/channels/prompt.rs` - **SOUL Injection**: See `src/lib/ai/soul/` for implementation details - **Settings UI**: See `src/components/settings/panels/AIPanel.tsx` - **Message Flow**: See conversation injection in `src/pages/Conversations.tsx` --- -**Note**: This is a living configuration system. As AlphaHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant. +**Note**: This is a living configuration system. As OpenHuman evolves, these files will be expanded and refined to create an increasingly sophisticated and helpful AI assistant. diff --git a/ai/SOUL.md b/src-tauri/ai/SOUL.md similarity index 94% rename from ai/SOUL.md rename to src-tauri/ai/SOUL.md index e71f78515..cd05eb78c 100644 --- a/ai/SOUL.md +++ b/src-tauri/ai/SOUL.md @@ -1,12 +1,12 @@ -# AlphaHuman +# OpenHuman -You are AlphaHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun). +You are OpenHuman - think of yourself as that incredibly smart, funny friend who somehow knows a little bit about everything and loves helping people get stuff done. You're genuinely excited about productivity, fascinated by how teams work together, and you have this knack for making even the most boring tasks feel manageable (and maybe even fun). ## Identity -- **Name**: AlphaHuman +- **Name**: OpenHuman - **Core Purpose**: Intelligent AI assistant specializing in productivity, research, automation, and team collaboration -- **Platform Context**: You operate within AlphaHuman's multi-platform ecosystem (desktop, mobile, integrations) +- **Platform Context**: You operate within OpenHuman's multi-platform ecosystem (desktop, mobile, integrations) - **User Base**: Professionals, researchers, teams, developers, and knowledge workers ## Personality diff --git a/ai/TOOLS.md b/src-tauri/ai/TOOLS.md similarity index 93% rename from ai/TOOLS.md rename to src-tauri/ai/TOOLS.md index a2db38184..19dced1f1 100644 --- a/ai/TOOLS.md +++ b/src-tauri/ai/TOOLS.md @@ -1,12 +1,12 @@ -# AlphaHuman Tools +# OpenHuman Tools -This document lists all available tools that AlphaHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads. +This document lists all available tools that OpenHuman can use to interact with external services and perform actions. Tools are organized by integration and automatically updated when the app loads. -> **Architecture note**: All read/query operations (get-page, list-*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools. +> **Architecture note**: All read/query operations (get-page, list-\*, query-database, search, etc.) are handled by the memory layer — data is fetched from the TinyHumans Neocortex memory system and injected into context automatically. Only write, create, update, delete, and trigger operations are exposed as tools. ## Overview -AlphaHuman has access to **12 tools** across **1 integrations**. +OpenHuman has access to **12 tools** across **1 integrations**. **Quick Statistics:** diff --git a/ai/USER.md b/src-tauri/ai/USER.md similarity index 97% rename from ai/USER.md rename to src-tauri/ai/USER.md index 2a6a9423b..31dd2bd75 100644 --- a/ai/USER.md +++ b/src-tauri/ai/USER.md @@ -2,34 +2,40 @@ ## Target User Profiles -AlphaHuman serves the crypto ecosystem. Each user type has distinct needs: +OpenHuman serves the crypto ecosystem. Each user type has distinct needs: ### Traders + - **Needs:** Speed, accuracy, real-time data, concise answers - **Communication style:** Direct, numbers-focused, action-oriented - **Adapt by:** Leading with data points, using precise terminology (entries, exits, R:R), keeping responses short unless asked to elaborate ### Yield Farmers & DeFi Users + - **Needs:** Protocol comparisons, risk assessment, APY calculations, gas optimization - **Communication style:** Technical, detail-oriented, risk-aware - **Adapt by:** Including specific protocol names, TVL figures, and risk factors. Always mention smart contract risks when relevant. ### Investors (Long-term / Institutional) + - **Needs:** Macro trends, fundamental analysis, due diligence support, portfolio-level thinking - **Communication style:** Professional, thorough, evidence-based - **Adapt by:** Providing structured analysis with clear thesis/counter-thesis framing. Cite sources when possible. ### Researchers & Analysts + - **Needs:** Deep data, on-chain metrics, methodology rigor, source verification - **Communication style:** Academic, precise, questioning - **Adapt by:** Showing methodology, providing raw data alongside interpretation, acknowledging data limitations ### KOLs & Content Creators + - **Needs:** Content drafts, audience insights, trend spotting, scheduling - **Communication style:** Creative, engaging, audience-aware - **Adapt by:** Helping with hooks, formatting for specific platforms (Twitter threads vs. long-form), suggesting visual elements ### Developers + - **Needs:** Technical docs, code examples, debugging help, architecture discussions - **Communication style:** Precise, code-friendly, systems-thinking - **Adapt by:** Including code snippets, referencing specific APIs/SDKs, using technical terminology without over-explaining. Leverage GitHub integration for repo context. @@ -48,6 +54,7 @@ Adjust response depth based on signals: ## Personalization Boundaries ### What to Remember + - User's stated role and experience level - Platform preferences (which integrations they use) - Communication style preferences (verbose vs. concise) @@ -55,12 +62,14 @@ Adjust response depth based on signals: - Timezone and scheduling preferences ### What to Forget + - Specific wallet addresses (unless user explicitly asks to save) - Trade details and portfolio positions - Private conversations from connected platforms - Any information the user asks to be forgotten ### Privacy Rules + - Never proactively reference a user's financial details in conversation - If recalling user context, make it clear: "Based on what you've told me before..." - Users can ask "what do you know about me?" and get a transparent answer diff --git a/src-tauri/gen/android/.editorconfig b/src-tauri/gen/android/.editorconfig deleted file mode 100644 index ebe51d3bf..000000000 --- a/src-tauri/gen/android/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = false -insert_final_newline = false \ No newline at end of file diff --git a/src-tauri/gen/android/.gitignore b/src-tauri/gen/android/.gitignore deleted file mode 100644 index b24820317..000000000 --- a/src-tauri/gen/android/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -*.iml -.gradle -/local.properties -/.idea/caches -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml -/.idea/navEditor.xml -/.idea/assetWizardSettings.xml -.DS_Store -build -/captures -.externalNativeBuild -.cxx -local.properties -key.properties - -/.tauri -/tauri.settings.gradle \ No newline at end of file diff --git a/src-tauri/gen/android/app/.gitignore b/src-tauri/gen/android/app/.gitignore deleted file mode 100644 index 314a1a4e8..000000000 --- a/src-tauri/gen/android/app/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/src/main/java/com/alphahuman/app/generated -/src/main/jniLibs/**/*.so -/src/main/assets/tauri.conf.json -/tauri.build.gradle.kts -/proguard-tauri.pro -/tauri.properties \ No newline at end of file diff --git a/src-tauri/gen/android/app/build.gradle.kts b/src-tauri/gen/android/app/build.gradle.kts deleted file mode 100644 index 5f42a2630..000000000 --- a/src-tauri/gen/android/app/build.gradle.kts +++ /dev/null @@ -1,73 +0,0 @@ -import java.util.Properties - -plugins { - id("com.android.application") - id("org.jetbrains.kotlin.android") - id("rust") -} - -val tauriProperties = Properties().apply { - val propFile = file("tauri.properties") - if (propFile.exists()) { - propFile.inputStream().use { load(it) } - } -} - -android { - compileSdk = 36 - namespace = "com.alphahuman.app" - defaultConfig { - manifestPlaceholders["usesCleartextTraffic"] = "false" - applicationId = "com.alphahuman.app" - minSdk = 24 - targetSdk = 36 - versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() - versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") - } - buildTypes { - getByName("debug") { - manifestPlaceholders["usesCleartextTraffic"] = "true" - isDebuggable = true - isJniDebuggable = true - isMinifyEnabled = false - packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") - jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") - jniLibs.keepDebugSymbols.add("*/x86/*.so") - jniLibs.keepDebugSymbols.add("*/x86_64/*.so") - } - } - getByName("release") { - isMinifyEnabled = true - proguardFiles( - *fileTree(".") { include("**/*.pro") } - .plus(getDefaultProguardFile("proguard-android-optimize.txt")) - .toList().toTypedArray() - ) - } - } - kotlinOptions { - jvmTarget = "1.8" - } - buildFeatures { - buildConfig = true - } -} - -rust { - rootDirRel = "../../../" -} - -dependencies { - implementation("androidx.webkit:webkit:1.14.0") - implementation("androidx.appcompat:appcompat:1.7.1") - implementation("androidx.core:core-ktx:1.16.0") - implementation("androidx.activity:activity-ktx:1.10.1") - implementation("com.google.android.material:material:1.12.0") - // MediaPipe LLM Inference API for on-device AI - implementation("com.google.mediapipe:tasks-genai:0.10.27") - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.4") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") -} - -apply(from = "tauri.build.gradle.kts") \ No newline at end of file diff --git a/src-tauri/gen/android/app/proguard-rules.pro b/src-tauri/gen/android/app/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/src-tauri/gen/android/app/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/AndroidManifest.xml b/src-tauri/gen/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index f783b040e..000000000 --- a/src-tauri/gen/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt deleted file mode 100644 index e3481c1f9..000000000 --- a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/MainActivity.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.alphahuman.app - -import android.Manifest -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build -import android.os.Bundle -import androidx.activity.enableEdgeToEdge -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat - -class MainActivity : TauriActivity() { - - companion object { - private const val REQUEST_NOTIFICATION_PERMISSION = 1001 - } - - override fun onCreate(savedInstanceState: Bundle?) { - enableEdgeToEdge() - super.onCreate(savedInstanceState) - - // Initialize MediaPipe LLM Bridge with application context - MediaPipeLlmBridge.initialize(this) - - requestNotificationPermissionAndStart() - } - - private fun requestNotificationPermissionAndStart() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - // API 33+: POST_NOTIFICATIONS requires runtime permission - if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) - != PackageManager.PERMISSION_GRANTED - ) { - ActivityCompat.requestPermissions( - this, - arrayOf(Manifest.permission.POST_NOTIFICATIONS), - REQUEST_NOTIFICATION_PERMISSION - ) - return - } - } - // Permission already granted or not needed — start the service - startRuntimeService() - } - - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == REQUEST_NOTIFICATION_PERMISSION) { - // Start service regardless — it will still keep the process alive - // even if the user denies the notification permission (the notification - // just won't be visible) - startRuntimeService() - } - } - - private fun startRuntimeService() { - val intent = Intent(this, RuntimeService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - startForegroundService(intent) - } else { - startService(intent) - } - } -} diff --git a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt b/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt deleted file mode 100644 index 0f832c24a..000000000 --- a/src-tauri/gen/android/app/src/main/java/com/alphahuman/app/RuntimeService.kt +++ /dev/null @@ -1,91 +0,0 @@ -package com.alphahuman.app - -import android.app.Notification -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.app.Service -import android.content.Intent -import android.content.pm.ServiceInfo -import android.os.Build -import android.os.IBinder -import androidx.core.app.NotificationCompat - -/** - * Foreground Service that keeps the Rust backend process alive when the app - * is backgrounded. The service itself doesn't run any Rust code — it simply - * tells Android "this process is doing important work, don't kill it." - * - * The Tauri Rust backend (Tokio runtime, V8 engine, Socket.io client, - * cron scheduler) all run in the same process as the Activity. This service - * prevents Android from killing that process when the Activity goes to the - * background. - */ -class RuntimeService : Service() { - - companion object { - private const val NOTIFICATION_ID = 1 - private const val CHANNEL_ID = "alphahuman_runtime" - private const val CHANNEL_NAME = "AlphaHuman Runtime" - } - - override fun onCreate() { - super.onCreate() - createNotificationChannel() - val notification = buildNotification() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - // API 34+: must specify foreground service type - startForeground( - NOTIFICATION_ID, - notification, - ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC - ) - } else { - startForeground(NOTIFICATION_ID, notification) - } - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - // START_STICKY tells Android to restart the service if it's killed - return START_STICKY - } - - override fun onBind(intent: Intent?): IBinder? = null - - private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channel = NotificationChannel( - CHANNEL_ID, - CHANNEL_NAME, - NotificationManager.IMPORTANCE_DEFAULT - ).apply { - description = "Keeps skills and real-time connections running" - setShowBadge(false) - setSound(null, null) // silent — no sound on each post - enableVibration(false) - } - val manager = getSystemService(NotificationManager::class.java) - manager.createNotificationChannel(channel) - } - } - - private fun buildNotification(): Notification { - // Tapping the notification opens the main activity - val openIntent = Intent(this, MainActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_SINGLE_TOP - } - val pendingIntent = PendingIntent.getActivity( - this, 0, openIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - - return NotificationCompat.Builder(this, CHANNEL_ID) - .setContentTitle("AlphaHuman") - .setContentText("Running in background") - .setSmallIcon(R.drawable.ic_notification) - .setContentIntent(pendingIntent) - .setOngoing(true) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .build() - } -} diff --git a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d114..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9cb..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml b/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml deleted file mode 100644 index efd3caad1..000000000 --- a/src-tauri/gen/android/app/src/main/res/drawable/ic_notification.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml b/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 4fc244418..000000000 --- a/src-tauri/gen/android/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 2ffbf24b6..000000000 --- a/src-tauri/gen/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index dfb8e625183145c411b82ba034bb2f6c01477a9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1553 zcmV+s2JZQZP)RD2F7M3*8C5f{4Bg+UAi#I=U(MmPBZLO`;~4^USc7iOhI z&{e=)bmL^<`~7UY?cDFqJw;8^c2!rk4}t}UD(hBFpYNRSJLlHDeguU1h201{684X<3{#2`hbpAb%G2 zi?H8>`Bc#S(SS%1HZAOX^|xO=uUQO$og=8u59*qk^1HAxVV5fN0pm;V2pRZQ0k|_z zPgBmjo+$DzL!dMjxO-tAgcS>043~+=K>R4|X9XZGM!dIkFc_Z#vMX%E3Y{S0zmx|2 zucU&pAJE9Rp<>st8q!UORMR$1*cBskgV6 zDk>@{K0clv9v$I(e;V!j_mhvdzuSbaHY+>+9=u zb8|z1K!6ew5@dGj>+7kfr{}BZV=+|<2f}TKMmS1KODR7;pRTX3C6zWdHe|GsmDJQ! zIyg9xS*on8lpv4|8;9Ep2zy;gIMmeCBzcc(0K>VUpn!66a_H{vP69$!hK7b>-Vq%g zZns-TwXUv?yk4(#762gZ#>PhJG=sr&0NL8wN*x^?5|qc|d07x}7MurFs;a8!?CeZB zg~)?eg@uK3d~a`$va_>wAb!7}1_uWvKwLZQAI?B9ryCj?q_c3QsHljNl9Hs50S@;N z{lmjU39h81MCzryyqx;_`o1XDVKy`;0N^;Hji`efa4<13Q96#O8xM#Y&ZnfLP;qgw ze80Q9TVA6CgO<+@0#3t`>gsA4`MkV5Ne^fO5l>4?lOS0)$OhK;r@(aE+*g z7Uuoq87r4OqbF1#lu1fN>^^hRAa& zrsc)O1+}!a(8$P$1QusrEHV^IDFB8B7!(Vi$B-QW7#kb=D(g>Dowl~N zWK{Wc6H!A&0x&L<0BHOmVl4nHM;`Bm1_Ie#TU(2Is;))T+>qkc)m7Tw-j+^-MxY4v z5&FZ%NW)Rif>GoE%KtXRy|A!Ab8~Zgp@=yMW5t-CpVzg3A4iokmPKQvS-j!;0LB3p zSvo#Grpd`k9hB2d1k9!yJ3BkHva%v|fGi+#a2#ih!(pZs?g1o#;F^v9=4s0G^t8;d zg{Bv<@+s<%^mWG(T3lR|4G&^OiDV%%=V4reSqq_JMOMTV=0(&NZT3smnTi7>hW5XBgHL55x083C?UZ2AC33r5s zvP@sLm_8V`o{VMpsrT$2RP;TDJ-Zv_bI=M1ym+hj$gsuKplb7T@7aA;6#Aq9c*14E zWwPcO2-(N}sP->jVjtW6*p$dc^!DE(-ax#8FdY8@WQ@@|q{}PJ00000NkvXXu0mjf DcrV%s diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 9163ee5b57aa98ee914b70193b83d19ffac85cbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6481 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

tpOb_@2$tp;->_)MCte`8BM6=3uA7sTWKsZY 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 diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index c83e2389700484b8d515c397ed7fad8a96a77d09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4146 zcmV-25Y6w2P)6za8)zs;&DempQ-P8B>ZM~Ho=Z#t)Q(#Tgm%unznPb&D1to+eB^Sw2jp^O4~?no!W|a`wqJu7N~5u z0c~Y#1NPdnK5d7!9ny9{+g@#ZwDoHHLfaN?JM4DSxc+|cv)CP9Z!3C0Ezq_|+k9

!(L+ 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 V(!m6JE0_QP002ovPDHLkV1l^vZ0i63 diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 2e97adb28760952a80194150c17b4639c4794e4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3225 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 LNkvXXu0mjfv`jG2 diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 68ec5d11425176916b4be25884e715f7d29aefa4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8905 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 X_+%_g>UTmW)BY;p;b-6{ zD+I3|!1w*;=}8a-c1v@P;APrhUjhi?)cU`F|C;XIyPI|E)|s9?dz!CbzuNCT@Be>W zuX@k+`}c3tu3bCx>C-23?AS5$=FOYjSZNeOQyResNC7ru#thTGeR~V&=+UFi_wV2T z1HSwD*RNluOP4NY^5n_p`Sa)I#EBD0#sjY|X((XgyN3=PYQ~KlXRcnoYPA^c9z1xk zeMLa7CD8xRpFgHgpFY-FUcY{A)~s1$E?>TE9zTAZloeEs1;y(30jhQD)@JtX+2+NI z7ZzOH%DsE{%)^HdO;b~o-4F1sTD8g@H(v<3O{rdH@*1>me+qN~YUcE9a zR;(~%$BvD3TlHcAv1&hH;`0|STxc~OZFcD-pPxK=VukSI#}8`(Lxv2ot_Sc1G%g20 z(6(;fYK4^$B@ODv0>t;HO`B%HdiU;~)nvI32?BS7Wnc}%h7B{_x^?>peDy_Gupq{p zGiOdkIYo&Fsqel-jefo5({T(}Yv|1c?9e~X~Tn>I7pkY5@a2bzy@$utFvt`Q` z)46kJ`(2t`k)I~&2{?-uEix}(zO*1m@qDa-n1I_MPN3lkK~|uCYPcx!2V%t9wQKEf zBwz(Wsx1JJ0Cwcak(OrS<8d=`JrWK8V%X%YI1O6qH?8gcZdWhw+-S33cp&-i=X%+H@cEzqK-2!QOE#EbXz!8*`-u^v~$XoDdy?Zr@2}WoA^BWK&MWfEcj?KlvD0S4bIPgz9T>n95~SSl_j|4 zjSU+%Ow9>{qp6D88c>#E$}J1OQQgSIKanm6FjN;JbU)cekZPvuLo?m&V$>D(thmq1N`x%GdUA}y|9gF@k2IL?W7T}sa{+PNA79dyAt5+|(Nf>e;02bDMSD8(id$;`(Zd??bl}k zPB0E9WsC)V#hoc>!)3v`#*ZJLvzmqwfC4W8lA1mI9F4?R<1PT&O~L>dU;#h8FG{e) z5yo`2n*M-Ja7GASyLPpG5DK}0gqK8_!cWTmzBd`i_$fF+<}0c`Fhepm>iySO-# zGkz=XLGGaJ7LcwCNmP)jdF5 zf5Nty$iH~;Vy%|4c(DmUi~_*-?%iv(p3-p?pvq?1N52UZCj3J^o1>BP?@(RUgYu1| zWDV=Mbm@{=xpHN0{ZW;z!HX>ji)}1hw#))RmYT2bqCknu!8HhUX)MQ;vmr#rgyHat z;0poi#tqgZtzW;sXx@=(79{h<*DhJI#PV`2F)2h-@yWOgT#rDL7V5Rorap=T`c1|w z#-wD0xWSz}cUq;X^&GNa>m?>=QmK<4%953&;SyXeEQN~7?FoEY5bgx)DmI2@*hY*P zVRr1;k;^OUN&u?I_O=i-h zNj0sO`nAe zzfYZqz+1?Nx>+wL>@F#3t`$i8U1d)Hz4r?)e=~weId`&Zw!D^nj zl&lf~5O~Ad-yACtn~8E65;p&_lvtoe0A$EY3M-sF^J;1VIw`VSvfN@P8m0aDsBAg@ z8|}}RJBSgLVg<^kNeG#@uEpBYs*VPjXx{bf*UhzS*Q^kVB{HI_?jqc%CPq|9pelJ3 zS_$pOf>P!du*xGxj+iS~uH>dOQ!4;By+3v8l+`q}I||q+?JvfXO3_?Eit_#W+*%>U zAQQiR`?fiB=uqxI#2JLWO00m1_OoZt+PU6*U~rOvuXUh>v>R@O`fSg*9ywf{_ruXjz%>xpHf>sip==9&-3Tc zo8!li*TnUdDgdt%R|H^ODk>`o&-YS`my0T;Odw_w?q81fM_GXz3#9$f=RJG&((uMm7{2!%Fcj=_D8MrDVAhKF`{y{KWqi=b;eXg4<9~kZr;3^Tk2Ss zQ>?=E-=M8%ze>c-nRTLK2|!A^DhZMZfE5%ZTM&oSr%yNgf7SACDM6(LI<9)(zkk2g zGA$d|zH+TV1vj^V=PqY-%hLI*O#L(m%{Z)*yK&=2wWcG}ajOEI=$$)vEUjZ96dLDd ztl>pj`Bqbh-z)Jd*4O@<_zgKE%OqpyyJi@(CJV_6(V1G4mVrDXpnFFTa5wm79w5@v}iAwFKM$07}X& Uku)YL(f|Me07*qoM6N<$f_m(3HUIzs diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index b664cc21190fe809f6816c795b9a83e11e721fa0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5150 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 F{y*1>&V~R0 diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 3748d566ebce81a32b4ab2c88f261de25d483950..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14088 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 Fe*nTsjE?{S diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index dc2d530aef74b4c7e59002d15861e77d92ddfa60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19659 zcmXtfbwE_#^Y+rxf`pP%(xo)grKI!%OR9tmNF(3^f-BOZlypcgupr@53lf4L9gEA7 z(y@rdDl784e7^7dhkv--bI-Xmb7r1-W+wiDsR2C=2Mq`WqQ8Gn*8&70slWVpg%bE> z&{ReY1TubmUsucO8FoLP3S~W$e|qr=3~Er+)%yU}e5h0Emgo}i7EeLzrt>gf^o#MY zk#B^xVdHPVzpWXie!XsKJoZiSk42KKtn9>V(uSAJ=_Sz=EVMDv(SBX$_(n{y|6Ri3 z)amzqLPWv39)5i>;`Dn&=dRB3 zNxr{c)Ooe(u~vloS^K({14k1EaaBQ=o+Odtf^r_ba&*rBf`h5)JVxQRr%tSb1atL^ z3C#4JUrir#TM=If4ao#vn&t7GKRI<`g^4Yc1+1HEPITDSB1t-I%+`;0X{b)Sm8D=S zWljBV6geyMe#G%%EluG&nPdiRdu)iGAUML_E4=O#mFGi7Oh+v>BMqp@My5UdYERv5 zrk!~Dw8{}$Y)#R~73?)F2P@Yi+zr^03F;1cjdX>zlzne(NYJ<`4K{o0;!~aW2kccL zP+wiow2Rqld2{n0tz4cas+iNP!P<<(8>2}n&BT*X-JT!5b&>+bD)OEO^w>(8m~}MT zBAN_T#NmIGyPG&f;p09Y$=0`f!doDW zvpnLaXO8dR$K#RAO59dbAJ}^xA%|#u?Z%B%mp>IUULE`vGi~=(CuAnCd z>~-h3_i_9eDK7Bt)^Rzl83T5+#wu&Pr0Za9kpfg-(8E*R^{lb8Q+?L1IEjZrLLXBm zcHqo_Wv>mgqV|6Vie5}iSLK^(Fnw2wKH?MSW}13I22I`#f7-O^0@;k6W#_t0 z-*8tX-`})z;DnB4Kiht}q8bwtD(F-fK)Ff*a*-cFw@x8~QTVZ#Q+aV#sio|U$Js4O zS85=$X{MDTZBHF7p_T{3wqK;LAVCeFr#{)5fHmel_NVbc>LCfVsdK- znm*|KRt%R%nX+v;9SLYMez)}EQCVz^?JZF^AL>Mm??f@Q^r|!{+BklWOPtj*N>-E! zYV@EZB$bUkPQVESde728VUwfgkood;^X30tPFQoV^PH@=3;U;AJ7`b6iqh%;fdbb1 zzSt*LT${JQp0RYDLZSTQ1_kKNuzbVA8kRlJuW1ss+1lO&r$K38E70(dpw&td^TmyP z#Y`^}=#hfxg_x%>Kk)Ka)`lM?YMmQC(JeJLtA47@UCd4QU$cXv*ISR%&wi8DrU#=` zecw$_#2j^~^E5@t?QoESSjr+-&9xjn%3iv8Z^k$Gdkc>xkES;a#+&odfVu;mLx#48 z!_p}G0t&zmN&bH(Y{Yt(q%D?07HvV%+RJCpt?M;<45|Ce2X^P(sv&o8dZyZMOT5o~ z>PrTS?(>IT{4L^UYf`+Md@q>hus!XWk0$WFH1Vn|mQ>f49*Z*iqsG4&#GdkLbAmwn zm8BmjO8Kc2n%@_vwA`}AKKQl9B+x_x0v$}pl$LnwTF&<7@X7d0NTY(s-StEK1u8_z zK$H@?A>%0JnDcwx_da=D#L+(c1^75lmTBAkeOW zQ(Bh6N?fFdU}(mt7rxc;pQRzyUO%=HFV;d4oOstWzoR zO!xZ*8SvD#a;E-@yIPIzSF#D8;W8q5Dn1~u;OSuyGdn>?(hDO2X(E2R zG}}+vl!>JP{uWFm1%VPZ(nN$$A2>r@XA&mpQGkio|L)~leK_N3>cDEP$iRSon8y6^ zfEEO@f3dSSimz2Mh+y4)Xvu#VPJ1cYY=0_<(|nd`v)uvfW+*lGoz^@PfdT}YZ40hn z*WzS_)qtzeov9r0n|iD8%MGEf$+|Zx<2z^eeGYni9KSDr&H_-+iA{Xlw1Twa%qB~T zgN!P_=N(iE2=wNrfxi85ii|;oblqObZACx?E|Ls^khynG%>)?&N^ktuw0Q#$2-KYu z^rTTq+|$8k$gPR+lQ9Uqeowqi{i+NIbWgjxjbD<(@_r*W0(?z%B-~C35L*3gK5NL6 zGMs({V_-^!4D1RBB>G{jEjvZyDQ41yJB%qCYXrbKYeaG% za?;C(uGO!Y>-UB;*Xtym0J6T9744HS`&plG%jKa`*bNX!B41d(YaUZG`q7N1@0bq+ z`Vho%=;GXn9p3wXkDLw!vJi8btc*-^Z*Gn#yw1|ZcjY?pj8*q39kvdC@SJ3R$t)Iy_r6Z?oCMT8={OgvA?%XBC>$3E1A%U?qiXcCwQ*LrT#R`EMV19| zdoOMMxaHh^st;VIo8qJ!3b&uKH~sH}Tch{6n)XK!eZ^PKTOho^$(6|@6DCzj=H;=2 z#xDUCOmdYS*h;ymaxjGh;x*RY4n2bMF>JJfK$`kAMx-t}A0e^n< zf@HF8bc<05Q0-s>8Rr(cH^S574zLT`n{AF|t~pIEKq8O&UId%*`Hsm0_cckjek#zJ zLPEj$5IX*rJCt?dCk!W-lS0(x0 zXDZ&NU1S%}A?ffBj_bm*I#OF(TUS)~EzQ(s7?jtp0{Gm+XCy~{VN`$`v&L0;@b~O2 zwE1s=8g;G{vTi_O-uq!3ZzL)|@@zX~OpOraED+6AZ|xDp+}QXSlsO~M6a0;glCIuJ zx>Ihi(qkm&@l=HwW50KzWXlzeC2uAp1nvIbUQ_2OcKD2N@N^f0{Di1$8{&DkOybZP zF2C#QqMWTQ_lZ&=dY2?Kwpp5bx-b5kPv2{%Vq*C5gh4L@@gVA=J())h+k$<9z$Iq) z8BM*?c}3R{d43kGIu0W&D6*WY;!&kUdy+?ak^40-w4C~kQhwk9$LKMg?%%RqkzN17 z=i-r&*2#irtJDt7Ppr4TL2B-rjdaK(i*@2&@t$0q<<$*vKJ9R2cY5afEcuw=EgRi& z<@)0fH|LM2&8Z^4KhF9-s(RpUrg7dhlBe7_@9(AJvyW|FS-L+hm!DlBDyKXIC`&v~ zJ>!{A>w4w_gHhoWONrA($h?mS1`#0ATT#j(6YVs9SL5w3wX$k)QYA2&J(d`enR=URoq6iGJ+2Zv+XN&|ATd9gS)5-eQE>%}-*a>^}Atgzr@0SG&B} zWIsh2nbaBK5t&|^o$B#fB`1agra5w6jZo@0&HfU641?a@PCdb+%9}5#+r6gB;pYA( z)HdSUXDYDsz%e!Uy2RFc0}j1!)|hdF{lm$&EG}!cQ4`B}EN|#%3ig*(dTu9g%v)w1 z+l4SBA796C0#^3$dTtgdgG#ZQRn|mV${CGwA1mNCZ74J8!v$4EO2@aX{$xgmm;b}r zXX{2ScfSbPZ^i@&ym+kKr)6@ZUV=hV(87Q_I6eQ_YJ7`Ze?mPrypy}_nyiU1`qz;7 z>8Gx9$vk&N|JP>i4#AJr<$M!fYt3yKaguir)wVyp+sl5K!e_&1_hA^>_t{YD1CQcD z@Op;rtCG^&<^e7N&dFC&uE_@PR2PGHgC6CrmObIGYtt`XT|eLsYzX)9#d}>`k1kV$ z&pDHRsi(conrllAX{L9M{Ifm|lOI+_$;-mItipGiF-}I_y^YsySid76pmLTjf-cNY zSXCpJh>ITNDmS5yq?WJWRL%WmP~CH3cYf}#v|i@cY2W^&eDJrmYSXP-Y2M9%1y9;% zk#hQCo8GUkN4_d&p1EaKz-4pP4cB@#H;w16Aa(Id9YK_|Rhx<^T+BU8?YA)LjnCHA znTkKNt7Va;PJE(b*b!b`HzC3F?%7v=u}oyAD@vw5DdR0RW*21ldW4Zz9XG1Sr~=pezyF=wb-c@`62JcHCfx{-gu}Q|3+eCA0lms zV}vef5bl-O1NctrAWbac1^rLL3)$(I=~n5oL#sx!C>w7lgL1*J>t)wu_n9nb7=q85 zeV>IOO>&XV14a>@Z&{>|CR2UY_I?dZGa}Wb=qB;qAPeqXTYfW9P3|n_P`}bl`mq3U zl@&X|~it(Y{t zTV%+d`zc*eK*)_oV=&(O2i^G&M>Vt(X_nhNvD|IF^`QS+CzWp}BZ!2o@;188OM<(t za;-22Vl;_IOuq7jrU-LCLm#`ES)xP%D z==F?_7=W4a=b0sr;jE28{3sxNt<50n&&Yc_K972CaXeH*(~b$m?ofFHAyMZi7#*$A9geqs;I#1O zJ7agJ7EkIznGjTf0>8~i2nO+FoZcJBSH-YNfUky}*#$T=i=6+bTH-yRh;*?Z>4GQ$iBjpA*BCfgSvq>IKHf{R0@6YC& zLN0@oJWb#h^y4Y^W#SBP@U;2LM!@Cj7fiX*GvrqHG%t{o#wsMrBMpCkok$hS^V_OE zAa<^yAq`F@@rKz#?q?kF5VqChb&pr~`vlQqvKi&fU|@4Ww%o4YtBHU90!u=u3TriqYyRc8u$IHa3NR7>uLpLaAs5Lh9g*qkKWd+ zxAk2B;ql|La+^BHjW!wfNWUoQiK&7HiI=L!s%=$$Q)U_q3>trb{yex61R|xh`7qak z%PLtHi^<)X>)@Szrg^(HI&Y&V31M14orT8VPK`)gFfW>2RL|*3I^>%hb-s8(k6DBtfz3NMnDm z0}|AMGiif4!!i;B1}Z%zYbNgxNa2cu8{`J2&qqdRmLRZ`nT6eFeLEy1v5Lh&cDF>x`@?1nc7(E0M|&Aj;XP)bggCJ*+MhhEnx-k zx%&E7LJi@X-8V5a8w4y=T9vrh*c;4ZjeB5F@MW$el9xhUPJU|^IkW&LH`)!sSEfI~ z88}OQyRZug_U)8R7D4edS+;MLB=)>3kDnnUrEFav5=YW;C#G<|SBnU#j^RWS5ot-YYHD zBhYg}N$!ulvkz)Ik)3woYWAG(P}6OvQ(3f)AA@C0gq|2SOv<_21MWvnZ9Uy`Z>u!* zmJK8Ds=64?GZ8|WUyR#PfQwgkXyuZ5SMJLaBnWcCX2hT;*Z2iB1C;HDt8euzz9v==!2jSM zkRnhp?CEeTxKp9REKey7taj7o4I`m!TZwfqWB7r$6X2Hw85eH3)!wmo;6s}etW#;l zmy9J>rd3M1-mB0zgty9=&^r6~v$}qEyS(mN8w**d&*`~UrVC)FcEnxhi=5xn#n;Hr zBbj6EN4K85B8r8&R*#ww6DGRMyLF+#k;(|UzMW>aa!F<^r~c(#8w~Pxig+2s(m8v- zY17EkB!K5Wb#@nKC_e|XA8yi!vlU`5PwC3sUCpbV?Vn`EKd4!xP?16{lXA+sk^lGY z?Vc+4ErV#;rJC#--Gz8^LuaI#GOc#aZ;b>wua|7i_UtH6>J8)^+kB~>X$X(cp52BN zkzJazz4yP%IPxP!RVwIuwL)Q&k>3fW{E5x3>)VkK=XELX{sh(qd{cpr{Q9kCe0mT{ zM`MXXa{Y#@& zj5l8hW^X;qc~PRq+^p<*r#d10-F1mUc&%f*0)%mD?4p}WeOxWyxQGl8hpwLv>ky;z z+8e(o#tnZ2^_S}cF=LrOr*|LZb#F!7dy~5#fIFxh`n&Ucx6=k+bGubGbi|E=HfcgTDzJ^iPT=iT&jn)!VJYDi zhW?=VzHnrQs-*o2L+7brUMk?o_{!>@Uzei0Ds!(nn%acB+7sz^l&XH_$^V%?)H@Nt zD=D~8XMc2xd#j8Fj*rPm49E8g&{GRxF=9Sl)Y8utFpcmEhM87z71);>9xr!q=BRjo zxYKeAF3(}d7@%FbR?KCQ$53J?^=)5z3Tlh}m0^Nx_hsK;mz{+|tpRfc;B77ZYx38scKVgq*MZCI>Fvb*R{tbN!CTLJkrCSG zUvuv*9)W|;Smu{z`o;BW;QivRnPlCYmfIjMUHnrY(;@?QoSo|^r#DmGZyFah20{dv z>wr9LYoJ#?CiREQz=s9fu!;-7N4~_!F;uL!aC)9K&tl&s_wC4MJj1tczOq*NPv340 zVb-}AuP;ZNW2tHi2T#W{bP^uY541|RzWad7(zrKHl4ei4yW2gi?~LSXLX0jYfID{# z7lWouE@J|jk)VP`!CpwJ{;Ukz{`jUDZN=3OCG=S84Qam=ky?6ayi7Lk(t64jn=lbUl z_VGF4-wev3kOA!F&Gjfqc9epANu;pUP*Oj;u zd1qfYTAoA|%+9X;oV;DT4#|F-FP6kf2v5Uh^@#hwQawJ;qqPjH`ua}z8iI=^K(MkRO!?PC4|nApDl}4oL$y2&_wi$ ztm7`EjFj8{+LTH)UX+v@xIufK0@Zm#Z-tC{syRm(d{Lr?!B5WSs_8%Z!X$l)V{F=G zF4P{NO1~exh)@e~VU}%GGZA9GJcC>E2;yx|RYd_uN?wI&KK9t}1?Ty|joHdI^zogk z=kC@B$Lw~gaK^R1RlmdIjaL8O27KZ#?%b>+jyvwg zK&DN6;{N>>EZwj9*PhrCOjPjgsUQU52yS(F8-0H;C!gH9NM|4QBc%~wArQm@z!r-{ z^E(vU#U#s9jt&QSKV7CxD{~zhCPGvnuIe$D9yGNh1s%a48uj| zitqG7id|=WK_s!|eH+qkTl}2L0gpr=VmD@z<~pwF2fwaeq)nG6WKgni*y@<0N^i_O z$b09|;HHOSD~~XaEBQ}uIn23P-JVNX`sXTQdif@$UTU^+W|kJU>W?N4?l!KXha9sN z6o7Bf`?;%TY1nk*MC62{$sa=6;y%KWE9dogzi~|cKY;V46(9q8PpT>kBin%EBVN|^ z6)K1bo70X3_v}1xTtok5a9%BAw!Hru$%}tLzL{Lqw1%JVy!yRZ5g!B4ab%|bAi=f{}$P-|p-$ z97Ki^w#fh`PEWrF2hC>9s<6B-RD9~>=mGmf@lbyMgWlPPK5+!pSq;v+T9f7}Uyx8+ z5$f43+dlkBL9yIW7y&;>zieGxNBKNp}!+!QS?lQL{F|31`_aaN6ws+>UhO7@7e(N`q?wK-j&m1{OZvi@fpT{7XsM!FTe@ z@?O|G=^wX^CKQOLWjE1^hb~rETcjR^G=x*AG~Fr(cfL%zL`~x!ojTl4i=$)RjvC!Z zs#Q=cy4se>J17o2+IZ;5J*ZrmpR-qp>#Pf^w8OrWl1plw1h~+tCk(7uC4dKNdw4{1 z#Y%O@no4NmS1*Ux)`R?d!}OUO<+Y__2-+hmxoX^sq3+D;s#T~ZVRgHr(D(l%j-mhq zf#SA}9B5DSP~gV5OG?gaAAKy(Ol88^7UXQN+mpPtPII){@o}~1?|D?)zh)L_$jpwA z%UL5NyD#xlr9V@aUyVLe`Mn(5>v^ifsAe^D4?`Wpw&$q#N-qB80Xn_r8+0?vhTTSV zx-{CLnGnAyzS$$ETI9!csnliel~?~U#a2A9WAg|=zY!)pWx056nP!}}9>y`$v0SkTfZDPsBmj&gB#O=eZWrDVX2N}X%gOggwMvP*mCyie zeF<*&-M(tJ|4aqmO|QvMVKXN3wjSR zX&i<3z*qrzTh^ccU~iX8=@W^gWqh0B!US*?UxY5b9&rXTkCoLnZO%I$qkHnGl~Y3H z&8OHN4!ui^XPghqam?n$kFzu_RutfsHEfVox}Al*e+CVnMU#*;#tdu#=m9F6=clct zSGufUma@2{SVr+I!`09MT)KrvyrmtE@gxrH-W&Xjd9V!?`j%tJr4iYY|NPh2z8xl+ z`WQ;Z<7Md7$MS$nqR|&JoAXlI7!S3M*KsSFc*@bsfkKW@3Fka9(n;1u@ZpLHhS2IZ zj990KlnwH8X5tLtxEZjV(O6C~_OiJS{oMfP_4SgxtH-+-={@kVY_e;zp+K;$Rm)&3 zOFnyM-+j!iCQ9eU&DzA)h}uc-Xh?QBGo$KWef>9<7YqO>*+9!ZF75X_5BrjIV`UNf zYpz4Rf+9p2S(6lWjW60(a&9hm8P4pSv;iJIV)#nXO_v8Z31w=| z5&O+qYCzhxf|kx89#&A!ta#CwLY+EmjXpFSWzIcO6B6$Vgt*;oDwH;o`lc~sr^WYa z(H>v7u;Jd?43PBxjTj(BUQ<%&y7)(ovj##ozyQv&;i8|^XT;R5c#b0r zdwI7`CItKkIvyd)cSL25hs|;nLdvTHlX%oP*k46!F}WStItE)SsU1yQntcc2RlA}j z^h4b?r^yXN&?L|7)>oL%PyEzVbF!|epi0y`Q}d>WDpSY~F| zT!&b=xXQu6M*f{C(zZTvaX_%Sj?Fw4(3wC8_{^~xe?LAOakg5{VI8c?e_BB37yy|0 zCcLOV0H8cR)7J)?yuU3JBpOAWU-F(P(JLle3?R+xW|Kd17}*SzF||4A*ep;=)ewl7 zR_M$^(7a}omjh`z;X;S^?7=gQYY2nxn{l6$X{As%Ar}_jPQsE1od*@=!Ia8b5^(wO z0B0{1-D~W#fBoY0b{h@fw~6}J!nd2fj9#D0x80xu&LE68V(esVKiRzG$s=B_4Nh+( zArbXul(1vQ6DL*D zc#dl-PW+tv{atO?@Z+5bQ9bKaf2gZ{uQmJ$T~e@MyM86(-JhCs+q)u(cWc;} z(N6+hbJRzBg9Gl+GE0X_L+_w$LYv4s+kY zBSP3WN;bp%Tq8})e1q;$reLcJt^P&7jlCC{z?LI%Y2HBG%Tu}lr3Z}Ii#zF3pLpBS`;vh&f(V>;zxH~;{=D+jFvN*?nO`{e=7Y4AsB8QWO!Kp^y ztawbO66^{2>acLBJ`OS5SQ{^j?hlP`WvqqDE>MM{sOl-9wW0cF?H`k%0IqJ$lVC${Y(c5&ST32tYVh;w{AKMs|r-l#aiyI-b zl?n3Rb26uAax(ojqj&eEzEQuMRgvf3!euUAEWV+gY7hsugMnLr0ENv3?>ln!l$4^u z&T%~9p4W42KY*)rs4dL+KTu&!_^M;aUwPCDY?c07Dp6DP3j67}iJ)0$hUib9AmLtS z*?6V}MX#N?g=NF8EWB2HjjC&Rz8wZbtRw1P*i;Pzpl=wciQRKM0T_^>)W@Fy+{0A; zHcmyc3i&5W*!PU^groDxbhXz#`DC{lf7F<8t5bQQ^oqr=H~oLUV0zN;87F$SMi^Pf zwp|F?pH*HE;I(X7brE*^4|$2#8^RybFj?^6-W*N3W*EM&0wZVRcHX-mRrs>}^-EkE zZ4hGm>-SYhSvT1C3iwBg>5QR3^o04E@llM4)>;v*T0OMiVq@8eT>ytGMW=q42ky~TFZ57r~XDaTX2bRvZ zX$PG2SLF06pGk>?dzYL zdLzEdvSPKz&*e?|@+b=?hw*a}g~GmLdo%y%@usEz&$I4M6CUlzpmj@5>1HE*A`F=fWgrRT)}Z@4@@?Sr zm(wF z$^5oJ%W&uBlv@*%#2Q^!uHqzpT8-WB<7(@W>+*8c{+cnL>8)|-O9oK%=8Wo|&s4zM z3>L`GUN}WHedN}XQ65kTan7?%q}0Xt#Vjsf3uSB*lfuJH-g(+dzhJQTw`=i!4^-O$ zEXBugk6!_4`a^Z;k149kc6DZN?zwmjZ|96_5WnK1!K?ET2c1=6bNmcS%h7)IE1^68 z+H9PguT1^ht28Yczva81JH4C=R%4*E-$U1Rp4$J%BPMVfT0dU5S~d*6o-cl+cppJF zW0j7}x=`~xly?k_PfuAqtiU{})yqEJG~h3<@>z&uRR4W*X2;*fMKWmwK|@qTA12oe z0M&`ouODX7Iom^PA0b@Mcw@W~w+Xgf{|NsR@Y>z@gzFrS`kE({sxZQY14x%P_tD0P zfK8#6N-O#IM?>kNu02LG6zM#}J69$dBT@1+ol?OCZpT{_3rwD#3uqa~qx{gtusfK% ztkDGu6+ySQF)Ly7`3C^V&aP0Gs}1}nJMa<+6ETk7>WO&7CndCsQEkNiZy)bEX7uk$ z3zwuUm1XUmw0Wj zr1v3n?>y`dJJ~D?~%oB)WPC`YlUG@ z|GoSG#X>e}L0Xe(YGv-LEPZZgsYWib`gC-?J$b-B_1h7)w1Bf!rnYtGr|k@LFa`u9 zU>}KZ1zP|98tzTeD^9jo%(vGcm9wO(K4Djc3z0muuaMuuwts%B@{EG}m%7Zf=6(K< zgX56S8n|3~QD+TLC@m93-J=NTO9bO6QJLjXYF)onXZT$;M09wmz|s{I&K~ z;mLF*{=^+fuc$qzKGJ-6G8K^d@Tj>B`74Emooz|;tB<2dlryjk?)@X0dXaGw;1&i} zj}-d#P`jRZv*((vZV^7U z8Jly@o$<8nY!}T3wWU%qw1H&$Y7XJ}wH{ny>k^Qb-9hvPr?kT} zZO9T6kLEUhJ^9U#te@fAf8M^XV%WT-sD5&(bh?vr1NkhN_h&Vt?&IfJs?dRrBZXja zB2moV0Bbm4?sKzJM9SFLijd9VdOm2NZZY#20hB##eVk^x$L=0|^K1O*b`-W(FK)e1 z+4Al)Tz>Pcy_$0-5@t@x7*J;abe3+AFOG|O^tDXJ>u9YE;p@UpDfI0oG&C z`!=gR_6O($g=cc5tP2UO&S6Y zT(IrDSmdUBPuPB5tGcUB+%nMMaJq9DA&;4J3zhs!xPh|lW#fV0zIbXw*e2R455+@( z(;9t&W$=dEz5E6PAa{4|t7X$cxQc5)xav^kSL8^7_?avqHJ2JqcuAnig_Pxmm z)=Uua?t<+EU|r(z**#Xw^+1nL;^m?Ypt!Db8Q*&6I!gQbm>1I9#tzy8^@tt2LlFQ_deJ3Z(P)G zDgm3+=o<}xEZQE78kMRDF#rx_Y`{it7`D<=Q$AgR|D?oRtLN{^jI>7Be7`T8{|MlW z{<#m-gGg-#mtW<*W|+8UPnaZoJ23Ygf*)o#m`Re*Hh4l`v)*@zX6uJP#A^KL&*_#ZLERPR83X2oRQ?>!b@CK*j154L)~zc(jg3 zunJg1=2RDK#SdyrP%`wo!BO{{)c+l(#zh(A>yp=8HIS?Pc*11B#gwvK5P@&SEgqwZ zlmALl3${$ElY$s@g8H-ZWz9Px0WLHTnShKTfH!x^J=bS1LA>tD#otLI>2(E#1FmTO zYWq#-x(bO@O*7P4kNYkP+*w}p6#d5?=qK90_nF`2Ps)f{j@;K*^qg$7ssNqTk&t!G zTWy+oU$B~ufyg*a1_{2;BIl07?Qn5vIn2EfEGx~0j z%cVu<5z&)3=h_$(R(p;)7MhA7*%1tvS@iqVkwQSsA%N4FyX@<0lU|q(+kY^%icZ+- zfn>b9l=xncoXAXAba=15i)mNVyMXi3ot< zGoR#&*>v?Xs9pse_($&CuH#7~pRMuY*3^-T2^i~FcNEvdB9&1GgPd0|XHZwQw# z&Do-VW&FIg2y_YhROE*Y?Z?y^bye-?=UmJ5&ADU7?S%!T;F!HjcDxt0V_8T;WfE2Z z)9RLpvV7h4qQb1ux9fcWX|GqG8Uc4FE20Z`&k`xSj~7Q?F3dXU3EDrx>&iW_rXMf- zcU%#2i9wL@fYB-cJJPtg10j1y_D<((E^VN8QM0sKrQOw69jN*mlyub3XAF^r1-RPzJBK;b zPVF9IVw#`VU-lQw3L#^Xqge%$f1e*jE&WFld8fZ#7aCt7*Ce7puA+ZUrnSARyQH6~ z7{hj_gEhQrjaE;9#=Ln<*T3M&xGUgO)n~0T3v)S!(-({!aw6nJ?<+R<6W0a#4F+i@H(~|Tt)>r+gZo# zKxd#~Vr(sVY~DWGDGo1G8+h?|Q-d+qfn4!wJF#U1f)hnpG~%0V&!NDnP%Kz(~h6g#*#r5-S=_V%P1*@2R=%`|59 z1S(uS?L>S#weL+An{2l(nxL(h?$-5ha=!v_sH-r6WwRglxawP)K7qOZt|LLBO~x_m ze6$)>>;XPu00=~W3Kbv+d#ds0tC_Z<08q;o-Dhl239IdT1X!^och%``*@@aZ%&dn7(GFOV&3b#hA^c>gUOTS*hgGr8uAx`H;WSxwlXbx?`s3~V3=cv^ z^UY-9xg4z0ty9HE4N0a#PIpEZgaf4Dn!!-U6i0XC?NGCj;$!}bY(kv8kJLB%kY79K zj~hM5M6atADtj$*hiKI<7wF8hJs51D4qjd$C6$D@K|>Fn{RHhmoI6Vg1b@?sI)lkp)1$>n76XkB3jPJF8-RK zhNFN6;`nB-9Lq`37B-&*ZUpq8;rkxYJE>wXP>IKa8Gmy9-3Kg3gFjG0R z5Kk->Bf|n%oc9q9qguL9YY1;^mOf<{I_QDWSgn>#Wm5ZoNSV1SlsT#ycM2cLmKDIA zXasGIXR0ZU!oHp#cB2>4wreVET9F;L3xhGVQ_~IQ4Aw%M?MvrUCk)B*GW9z@rnC*x zq2$$7cdfTQ;k0j_c}J@u?EuYk(*=EzPweq?{)(!%p2iA-h=!czj=JNrC_rjC1Ky;>*E5q>xWY##pF`g8q{8ZOt|I#kTq|l+s8(ZUp5Qe== ze~%J2wu~RS>qbV%zmf@qSL;YseJsODX}M14Swp{hekW8^pD4n7lOB5n7~^ zUs2bo@KrlN${253EE2<+xeypFU%#mW-XP@`lU^s~PM8rNH{TBjq968pGOcHaK*sBt zALyIP?ByPMxta1;r@u#7;RXd))a&K<$cEjEbO!Ejk$X_5nLe#MC7H%};Q=D*EM+>> zIqA27#l zfI5{pA_w6w4j4OFxufeRFfXdB&2@tz2p4s6etLPAAW1+B)xpm9ZjGwEB?g%LdM4BM z!un$=8D}77od)5)A#<)&#P4H~?gU(**>AcP^zGqr>bYDfPG#Gso9k1iXTMbX}fgE>hzzsd>NAJh{4g+LDiqq2{Ym6U$yEFE3*OghQ zf9IrOa=IwcS!Lk{VaA?)8157f&9ET5Wym(53$uO7qZ51{<+?DZMFU{xr&v^ zGNJ1NreyN*08M-qwb@5Q$jGA&tdP{X4IrR)ZPRL}Qi1p@zTi4B{|B@azpRUO5~o!H z^ZP-FyDdUt49=*sD?goB5%a6BqaUlk=48P01yqfVbCFV<LIiM@S%32121=4) z*P@3r)z&ND^$Ur(%^ojZ6U5d5wDxw2h6sg>AAC3 z%h~yOe*hEvx%n@ZBtDg{NuE% z$N$2if4=`4+uQa~bg01{%*~GlUzi${{T=T5Yeay0oXLdNOshtjjN`B5usy)G-ulBV zn~@a&P=PY=jCIU|D$6?k@yUSBMmc)1&lYdozrGc+R#hCNGey*8kVV9b>JG1mXY=67 zjIsh`i+++R53aMU8b;C61&FzQSSs533KCX+_rhunGN*5Mh@MAtn$0%Z)5Za@V0Y9^Zv| zMX$*L^L!t?64gh4$|E|ByWNSWN&gK(`Z;r(5B`i_B=;`PYB1;q#3MNsXE-FibH7`q zB=ye!8%{J~#Oj+N6dZN~0+R@VoxoF%?>;EE&ZV9M%&phPo@%!netE3fu74Kg)~po9 zP?x}LeR4o{#=N7)hWD&lWRBcUx02&yRaDQ#}b-TeP9s)kfUNwFCfw7O~OW zy!_W%1kAjJvmY37dH?{hMB?+`?rkQp&3dlI000p8>C3MMZU3Mx zFAs0@<-lB+W4Sl~$TT7V09cEr4}TD8P-joGfW0}Y_Gr#=w0DRY002PT?n@$en3XDU zwD**TZ?7VQuQS4afeQlw0Bc=zerA-%*wmZLvMNr&{0~lQ1^@tS&B@ERSM$Z~Rm?@| zYaR;PA3bXa003Z3Ui*^X{2^$+kN&)|5drfR@k?A^004;Dece_?Mx(kfD2vrU7__n8 zsh9u&0L^e;9g+JQ*IRI-RtM&P-6v}lJ^%oKrn|3N1k9=9AEP3_`gd<}%>e+QNo!v^ zGUdK%*1oI`C)E*s)1$0ZBazA+003Z3*!Lw4587j%)-=t5IhE9o=xIT_Gy0*pFaQ8( zwCcupY89_~*0S8f+TK>$;5-l~1^@sJxUW?~J0NJ!R~z22va0j7{6M*|*CO{d-kZM! z005|U?dzX|c5kFD8|z7a)cS9_q96Qt&<-Y64*&pl#O76J_g$VF>#B81upZmz>QmiJ ztR4UWtoG$7i!{V(O3mj^b~G?|seijLXoG`xgq5ZgnMwozfZo^;>BrZC_GPPM>d>0t zoSfYo7}>xfUIlvq008UZl#^vv3T~{ZHMr5}6k>UxLkW@_cwYbjph|9t#H+Jj@v z{mpt(ht|X?L@S$0Tobg*JZIO%djEV&|DUYS5q{iqlpW160v84_D0Z7VS_UO z0C-w(OVIwik<_8ZFojsD)YMOd_C71Ehi$?82LND2jm%2}eipRz8c7_sQoy#cQenms zR$930-c}O(ULbrMb?|X8yte0AN|z@1?$fZREUG z$Dsx7F{!RBMyLY-zzP(Z|Adv! zj_i!(4UBmh?Bt*=h+gmp-g^Lm%!}88sBd4{%t{++5is*MwY_Mi zX+%T}03aXYbzIc9$CfxuTEKh}TZV`M0OUrzmbF^EETMf_zKD&r(!41m1^|$~HLtNr ziI*j~vDlwZJSIx6AYuRj*$}S>qrUsaq{Pcwm_qCc|Aqf5XlHt-cD8Y^003B8%0sy@ zp8D#uy|WAwsGkS`U`ZZ{;%3DDF=+qGTC_>oGBAZ${=2kCimt;jzaO-I#)fAA z084Pa>&?h@{nRrXU1<@GwBhDdM@JWIBw@yJf9K?F6&|d z02a%XVQ2K`TY~msE1l<A!MtF;d2pIrCxc>ATK|3@OuTHQ3O)XgpMfiITw5WJ{ z&~~@doa`n}dIkWnTGzTHT#JKtgO#>1S(>K|v$6(eJtSk?X1c!z?VCZ{E@)%CwXrsm ziU0srB@Ejl*L9ASf*KuZpEAs{1G64VP>l=P=Yn=ng^hOr0I+!tS}`+dHwWzxS#w=k zbzoMuHr5{f{tKdYF(nm`w$kQj7r7_o0RRZs+p|}zg7&|Ic6rdA&Z6tegMeAt+Lt~~ z4cd2uwqwu^@k*U+LdXEXin-2Z-i*|pLAxku_eA|?N7nb&=4G1AjV_!8*5jZcAfDjiL*fdD{Z~iXB=X`$W)AE)%kL*2n-Lhr;FeZGQ>c zCxiA!Pqpz0_P=ymda!FC#N4b!xqQ{h=U23J!N2Oiq005TK%0!Ok zLHlvg?yyn;bgQtGVhC7%gv__nIsy8;pj{cXBP-bQb~Z-?fF(CQ=%=mye&~^){UB&R ziA1bW!c|lOGw+RVFWb0xgq0$u6QVQ7Dy4eb5HtXYS+Kf#*yc1ZN)+mZjv2OjVTW9W zGZ3));`bJvdvjD2!9OLMZrrMe`R6u74FDPxtF9iFF5ZkvJgG+Ey^(0GFYCK<5r;>> z;&EkSSkT4>?F1{;T^vzC(EMq~N=}XI3{Xsw>d9GE>J#3KDho-d?ho3-(f=E63jwR; znz*^-w<@fm?PH}%A7i5Wi<)j65;?cNqOO&$d0P)30U+I?WEI>`Un1quVZF~;X*6gy!0K^kT|F$0ZXL8iLEAraYr~_qchGhV+P2ZxH2R=eA2)AX zo$oLA0OUnfYW;jy70*N?1Ix8msy+C!mFf;Y9SPP`L7N}6m!hw+3IpXfoEDu|9M{Wl zecfQ&MdG%rmE!t?t#pRj9zokVXgdXMo1hJhKK7430zf)hZKcBDtD--z4BCpIEsKO| zY0zE>+KZ7uy%c@EngMe8R3ji@Ef+PbapbgRBwPcmw6>;?+ee}{FmiDHJtsFH`u~2> z*Y}GafPT?b!&cGv?25k56+7-1O>_DWNB=%Ha1Y=fffTr_)m41H%X=QzMa^yET@(HN z`e>c0D{?;TqQ6@g{l9CkM}M~}606svwkrBwtD}!=YB&|%4{0D)P2&FpzF<8~9>+KC P00000NkvXXu0mjfa%H%1 diff --git a/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/src-tauri/gen/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index c6e7d8e70a4a7fe53eda993dd3e00ccce2a95d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6158 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 - - - diff --git a/src-tauri/gen/android/app/src/main/res/values/colors.xml b/src-tauri/gen/android/app/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127d3..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml b/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index ea9c223a6..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #fff - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/strings.xml b/src-tauri/gen/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 707f7e944..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - AlphaHuman - AlphaHuman - \ No newline at end of file diff --git a/src-tauri/gen/android/app/src/main/res/values/themes.xml b/src-tauri/gen/android/app/src/main/res/values/themes.xml deleted file mode 100644 index 3831b3e77..000000000 --- a/src-tauri/gen/android/app/src/main/res/values/themes.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml b/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml deleted file mode 100644 index 782d63b99..000000000 --- a/src-tauri/gen/android/app/src/main/res/xml/file_paths.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src-tauri/gen/android/build.gradle.kts b/src-tauri/gen/android/build.gradle.kts deleted file mode 100644 index 607240bc8..000000000 --- a/src-tauri/gen/android/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath("com.android.tools.build:gradle:8.11.0") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -tasks.register("clean").configure { - delete("build") -} - diff --git a/src-tauri/gen/android/buildSrc/build.gradle.kts b/src-tauri/gen/android/buildSrc/build.gradle.kts deleted file mode 100644 index 5c55bba71..000000000 --- a/src-tauri/gen/android/buildSrc/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -plugins { - `kotlin-dsl` -} - -gradlePlugin { - plugins { - create("pluginsForCoolKids") { - id = "rust" - implementationClass = "RustPlugin" - } - } -} - -repositories { - google() - mavenCentral() -} - -dependencies { - compileOnly(gradleApi()) - implementation("com.android.tools.build:gradle:8.11.0") -} - diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt deleted file mode 100644 index a3de12569..000000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/BuildTask.kt +++ /dev/null @@ -1,68 +0,0 @@ -import java.io.File -import org.apache.tools.ant.taskdefs.condition.Os -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.logging.LogLevel -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction - -open class BuildTask : DefaultTask() { - @Input - var rootDirRel: String? = null - @Input - var target: String? = null - @Input - var release: Boolean? = null - - @TaskAction - fun assemble() { - val executable = """npm"""; - try { - runTauriCli(executable) - } catch (e: Exception) { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - // Try different Windows-specific extensions - val fallbacks = listOf( - "$executable.exe", - "$executable.cmd", - "$executable.bat", - ) - - var lastException: Exception = e - for (fallback in fallbacks) { - try { - runTauriCli(fallback) - return - } catch (fallbackException: Exception) { - lastException = fallbackException - } - } - throw lastException - } else { - throw e; - } - } - } - - fun runTauriCli(executable: String) { - val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") - val target = target ?: throw GradleException("target cannot be null") - val release = release ?: throw GradleException("release cannot be null") - val args = listOf("run", "--", "tauri", "android", "android-studio-script"); - - project.exec { - workingDir(File(project.projectDir, rootDirRel)) - executable(executable) - args(args) - if (project.logger.isEnabled(LogLevel.DEBUG)) { - args("-vv") - } else if (project.logger.isEnabled(LogLevel.INFO)) { - args("-v") - } - if (release) { - args("--release") - } - args(listOf("--target", target)) - }.assertNormalExitValue() - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt deleted file mode 100644 index 4aa7fcaf6..000000000 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/alphahuman/app/kotlin/RustPlugin.kt +++ /dev/null @@ -1,85 +0,0 @@ -import com.android.build.api.dsl.ApplicationExtension -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.get - -const val TASK_GROUP = "rust" - -open class Config { - lateinit var rootDirRel: String -} - -open class RustPlugin : Plugin { - private lateinit var config: Config - - override fun apply(project: Project) = with(project) { - config = extensions.create("rust", Config::class.java) - - val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); - val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList - - val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); - val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList - - val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") - - extensions.configure { - @Suppress("UnstableApiUsage") - flavorDimensions.add("abi") - productFlavors { - create("universal") { - dimension = "abi" - ndk { - abiFilters += abiList - } - } - defaultArchList.forEachIndexed { index, arch -> - create(arch) { - dimension = "abi" - ndk { - abiFilters.add(defaultAbiList[index]) - } - } - } - } - } - - afterEvaluate { - for (profile in listOf("debug", "release")) { - val profileCapitalized = profile.replaceFirstChar { it.uppercase() } - val buildTask = tasks.maybeCreate( - "rustBuildUniversal$profileCapitalized", - DefaultTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for all targets" - } - - tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) - - for (targetPair in targetsList.withIndex()) { - val targetName = targetPair.value - val targetArch = archList[targetPair.index] - val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } - val targetBuildTask = project.tasks.maybeCreate( - "rustBuild$targetArchCapitalized$profileCapitalized", - BuildTask::class.java - ).apply { - group = TASK_GROUP - description = "Build dynamic library in $profile mode for $targetArch" - rootDirRel = config.rootDirRel - target = targetName - release = profile == "release" - } - - buildTask.dependsOn(targetBuildTask) - tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( - targetBuildTask - ) - } - } - } - } -} \ No newline at end of file diff --git a/src-tauri/gen/android/gradle.properties b/src-tauri/gen/android/gradle.properties deleted file mode 100644 index 2a7ec6959..000000000 --- a/src-tauri/gen/android/gradle.properties +++ /dev/null @@ -1,24 +0,0 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library -android.nonTransitiveRClass=true -android.nonFinalResIds=false \ No newline at end of file diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties b/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index c5f9a53c2..000000000 --- a/src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue May 10 19:22:52 CST 2022 -distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip -distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME diff --git a/src-tauri/gen/android/gradlew b/src-tauri/gen/android/gradlew deleted file mode 100755 index 4f906e0c8..000000000 --- a/src-tauri/gen/android/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/src-tauri/gen/android/gradlew.bat b/src-tauri/gen/android/gradlew.bat deleted file mode 100644 index 107acd32c..000000000 --- a/src-tauri/gen/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src-tauri/gen/android/settings.gradle b/src-tauri/gen/android/settings.gradle deleted file mode 100644 index 39391166f..000000000 --- a/src-tauri/gen/android/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -include ':app' - -apply from: 'tauri.settings.gradle' diff --git a/src-tauri/gen/apple/project.yml b/src-tauri/gen/apple/project.yml index 329421f2f..aaa846c99 100644 --- a/src-tauri/gen/apple/project.yml +++ b/src-tauri/gen/apple/project.yml @@ -1,6 +1,6 @@ name: tauri-app options: - bundleIdPrefix: com.alphahuman.app + bundleIdPrefix: com.openhuman.app deploymentTarget: iOS: 14.0 fileGroups: [../../src] @@ -11,7 +11,7 @@ settingGroups: app: base: PRODUCT_NAME: tauri-app - PRODUCT_BUNDLE_IDENTIFIER: com.alphahuman.app + PRODUCT_BUNDLE_IDENTIFIER: com.openhuman.app targetTemplates: app: type: application diff --git a/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj b/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj index 3a7e3b4d0..846171127 100644 --- a/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj +++ b/src-tauri/gen/apple/tauri-app.xcodeproj/project.pbxproj @@ -273,7 +273,7 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = "com.alphahuman.app"; + PRODUCT_BUNDLE_IDENTIFIER = "com.openhuman.app"; PRODUCT_NAME = "tauri-app"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -423,7 +423,7 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = "com.alphahuman.app"; + PRODUCT_BUNDLE_IDENTIFIER = "com.openhuman.app"; PRODUCT_NAME = "tauri-app"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/src-tauri/src/ai/encryption.rs b/src-tauri/src/ai/encryption.rs index e89af3a91..42ca25afb 100644 --- a/src-tauri/src/ai/encryption.rs +++ b/src-tauri/src/ai/encryption.rs @@ -106,16 +106,16 @@ impl EncryptionKey { } } -/// Get the path to the AlphaHuman data directory (~/.alphahuman/). +/// Get the path to the OpenHuman data directory (~/.openhuman/). pub fn get_data_dir() -> Result { let home = dirs::home_dir().ok_or_else(|| "Cannot determine home directory".to_string())?; - let data_dir = home.join(".alphahuman"); + let data_dir = home.join(".openhuman"); std::fs::create_dir_all(&data_dir) .map_err(|e| format!("Failed to create data directory: {e}"))?; Ok(data_dir) } -/// Get the path to the encryption key file (~/.alphahuman/encryption.key). +/// Get the path to the encryption key file (~/.openhuman/encryption.key). fn get_key_file_path() -> Result { Ok(get_data_dir()?.join("encryption.key")) } diff --git a/src-tauri/src/ai/memory_fs.rs b/src-tauri/src/ai/memory_fs.rs index 0f5c97fa3..8c8ee913c 100644 --- a/src-tauri/src/ai/memory_fs.rs +++ b/src-tauri/src/ai/memory_fs.rs @@ -1,6 +1,6 @@ //! Filesystem-based memory index for AI memory storage. //! -//! Replaces the SQLite memory_db with JSON files under ~/.alphahuman/index/. +//! Replaces the SQLite memory_db with JSON files under ~/.openhuman/index/. //! Chunk files, file metadata, embedding cache, and KV metadata are all //! stored as readable JSON. All operations are exposed as Tauri commands //! with the same signatures as the former SQLite implementation. @@ -154,12 +154,12 @@ impl From for EmbeddingCacheEntry { // --- Path helpers --- -/// Get the index directory (~/.alphahuman/index/). +/// Get the index directory (~/.openhuman/index/). fn get_index_dir() -> Result { Ok(get_data_dir()?.join("index")) } -/// Get the chunks subdirectory (~/.alphahuman/index/chunks/). +/// Get the chunks subdirectory (~/.openhuman/index/chunks/). fn get_chunks_dir() -> Result { Ok(get_index_dir()?.join("chunks")) } diff --git a/src-tauri/src/ai/sessions.rs b/src-tauri/src/ai/sessions.rs index 0729e0bc3..1e726cb87 100644 --- a/src-tauri/src/ai/sessions.rs +++ b/src-tauri/src/ai/sessions.rs @@ -30,14 +30,14 @@ pub struct SessionIndexEntry { pub channel: Option, } -/// Get the sessions directory path (~/.alphahuman/sessions/). +/// Get the sessions directory path (~/.openhuman/sessions/). fn get_sessions_dir() -> Result { let dir = get_data_dir()?.join("sessions"); std::fs::create_dir_all(&dir).map_err(|e| format!("Create sessions dir: {e}"))?; Ok(dir) } -/// Get the session index file path (~/.alphahuman/sessions/sessions.json). +/// Get the session index file path (~/.openhuman/sessions/sessions.json). fn get_session_index_path() -> Result { Ok(get_sessions_dir()?.join("sessions.json")) } @@ -180,7 +180,7 @@ pub async fn ai_sessions_list() -> Result, String> { Ok(sessions) } -/// Read a memory file from ~/.alphahuman/. +/// Read a memory file from ~/.openhuman/. #[tauri::command] pub async fn ai_read_memory_file(relative_path: String) -> Result { let data_dir = get_data_dir()?; @@ -201,7 +201,7 @@ pub async fn ai_read_memory_file(relative_path: String) -> Result Result { let data_dir = get_data_dir()?; @@ -240,7 +240,7 @@ pub async fn ai_write_memory_file(relative_path: String, content: String) -> Res Ok(true) } -/// List memory files in a directory under ~/.alphahuman/. +/// List memory files in a directory under ~/.openhuman/. #[tauri::command] pub async fn ai_list_memory_files(relative_dir: String) -> Result, String> { let data_dir = get_data_dir()?; diff --git a/src-tauri/src/auth/mod.rs b/src-tauri/src/auth/mod.rs index 011546ff2..7f0ec296f 100644 --- a/src-tauri/src/auth/mod.rs +++ b/src-tauri/src/auth/mod.rs @@ -6,7 +6,7 @@ use crate::auth::openai_oauth::refresh_access_token; use crate::auth::profiles::{ profile_id, AuthProfile, AuthProfileKind, AuthProfilesData, AuthProfilesStore, }; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use std::collections::HashMap; use std::path::{Path, PathBuf}; diff --git a/src-tauri/src/auth/openai_oauth.rs b/src-tauri/src/auth/openai_oauth.rs index 748c94e64..3a9072472 100644 --- a/src-tauri/src/auth/openai_oauth.rs +++ b/src-tauri/src/auth/openai_oauth.rs @@ -270,7 +270,7 @@ pub async fn receive_loopback_code(expected_state: &str, timeout: Duration) -> R let code = parse_code_from_redirect(path, Some(expected_state))?; let body = - "

Alphahuman login complete

You can close this tab.

"; + "

OpenHuman login complete

You can close this tab.

"; let response = format!( "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", body.len(), diff --git a/src-tauri/src/auth/profiles.rs b/src-tauri/src/auth/profiles.rs index a31c04616..6e41b4759 100644 --- a/src-tauri/src/auth/profiles.rs +++ b/src-tauri/src/auth/profiles.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::security::SecretStore; +use crate::openhuman::security::SecretStore; use anyhow::{Context, Result}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/bin/alphahuman-core.rs b/src-tauri/src/bin/alphahuman-core.rs deleted file mode 100644 index 76c266723..000000000 --- a/src-tauri/src/bin/alphahuman-core.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let args: Vec = std::env::args().skip(1).collect(); - if let Err(err) = alphahuman::core_server::run_from_cli_args(&args) { - eprintln!("alphahuman-core failed: {err}"); - std::process::exit(1); - } -} diff --git a/src-tauri/src/bin/alphahuman-cli.rs b/src-tauri/src/bin/openhuman-cli.rs similarity index 84% rename from src-tauri/src/bin/alphahuman-cli.rs rename to src-tauri/src/bin/openhuman-cli.rs index c6baae83e..fe23dd7f7 100644 --- a/src-tauri/src/bin/alphahuman-cli.rs +++ b/src-tauri/src/bin/openhuman-cli.rs @@ -24,8 +24,8 @@ struct RpcError { } #[derive(Debug, Parser)] -#[command(name = "alphahuman-cli")] -#[command(about = "CLI for the AlphaHuman core RPC server")] +#[command(name = "openhuman-cli")] +#[command(about = "CLI for the OpenHuman core RPC server")] struct Cli { /// Core RPC endpoint URL #[arg(long, global = true)] @@ -178,7 +178,7 @@ fn endpoint(cli: &Cli) -> String { if let Some(url) = &cli.rpc_url { return url.clone(); } - std::env::var("ALPHAHUMAN_CORE_RPC_URL") + std::env::var("OPENHUMAN_CORE_RPC_URL") .unwrap_or_else(|_| "http://127.0.0.1:7788/rpc".to_string()) } @@ -217,10 +217,10 @@ fn execute(cli: Cli) -> Result { match cli.command { Command::Ping => call(&url, "core.ping", serde_json::json!({})), Command::Version => call(&url, "core.version", serde_json::json!({})), - Command::Health => call(&url, "alphahuman.health_snapshot", serde_json::json!({})), - Command::RuntimeFlags => call(&url, "alphahuman.get_runtime_flags", serde_json::json!({})), + Command::Health => call(&url, "openhuman.health_snapshot", serde_json::json!({})), + Command::RuntimeFlags => call(&url, "openhuman.get_runtime_flags", serde_json::json!({})), Command::Config { command } => match command { - ConfigCommand::Get => call(&url, "alphahuman.get_config", serde_json::json!({})), + ConfigCommand::Get => call(&url, "openhuman.get_config", serde_json::json!({})), }, Command::Service { command } => match command { ServiceCommand::Install => local_service_install(), @@ -234,13 +234,13 @@ fn execute(cli: Cli) -> Result { ServiceCommand::Uninstall => local_service_uninstall(), }, Command::Doctor { command } => match command { - DoctorCommand::Report => call(&url, "alphahuman.doctor_report", serde_json::json!({})), + DoctorCommand::Report => call(&url, "openhuman.doctor_report", serde_json::json!({})), DoctorCommand::Models { provider, use_cache, } => call( &url, - "alphahuman.doctor_models", + "openhuman.doctor_models", serde_json::json!({ "provider_override": provider, "use_cache": use_cache, @@ -249,17 +249,17 @@ fn execute(cli: Cli) -> Result { }, Command::Integrations { command } => match command { IntegrationsCommand::List => { - call(&url, "alphahuman.list_integrations", serde_json::json!({})) + call(&url, "openhuman.list_integrations", serde_json::json!({})) } IntegrationsCommand::Info { name } => call( &url, - "alphahuman.get_integration_info", + "openhuman.get_integration_info", serde_json::json!({ "name": name }), ), }, Command::AgentChat(args) => call( &url, - "alphahuman.agent_chat", + "openhuman.agent_chat", serde_json::json!({ "message": args.message, "provider_override": args.provider, @@ -269,32 +269,32 @@ fn execute(cli: Cli) -> Result { ), Command::Hardware { command } => match command { HardwareCommand::Discover => { - call(&url, "alphahuman.hardware_discover", serde_json::json!({})) + call(&url, "openhuman.hardware_discover", serde_json::json!({})) } HardwareCommand::Introspect { path } => call( &url, - "alphahuman.hardware_introspect", + "openhuman.hardware_introspect", serde_json::json!({ "path": path }), ), }, Command::Encrypt { plaintext } => call( &url, - "alphahuman.encrypt_secret", + "openhuman.encrypt_secret", serde_json::json!({ "plaintext": plaintext }), ), Command::Decrypt { ciphertext } => call( &url, - "alphahuman.decrypt_secret", + "openhuman.decrypt_secret", serde_json::json!({ "ciphertext": ciphertext }), ), Command::BrowserAllowAll { enabled } => call( &url, - "alphahuman.set_browser_allow_all", + "openhuman.set_browser_allow_all", serde_json::json!({ "enabled": enabled }), ), Command::ModelsRefresh { provider, force } => call( &url, - "alphahuman.models_refresh", + "openhuman.models_refresh", serde_json::json!({ "provider_override": provider, "force": force, @@ -305,7 +305,7 @@ fn execute(cli: Cli) -> Result { dry_run, } => call( &url, - "alphahuman.migrate_openclaw", + "openhuman.migrate_openclaw", serde_json::json!({ "source_workspace": source_workspace, "dry_run": dry_run, @@ -314,22 +314,22 @@ fn execute(cli: Cli) -> Result { } } -fn load_config() -> Result { +fn load_config() -> Result { let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .map_err(|e| format!("failed to build runtime: {e}"))?; runtime - .block_on(alphahuman::alphahuman::config::Config::load_or_init()) + .block_on(openhuman::openhuman::config::Config::load_or_init()) .map_err(|e| format!("failed to load config: {e}")) } -fn status_value(status: alphahuman::alphahuman::service::ServiceStatus) -> Result { +fn status_value(status: openhuman::openhuman::service::ServiceStatus) -> Result { serde_json::to_value(status).map_err(|e| format!("failed to serialize service status: {e}")) } fn command_response_json( - status: alphahuman::alphahuman::service::ServiceStatus, + status: openhuman::openhuman::service::ServiceStatus, log: &str, ) -> Result { Ok(json!({ @@ -340,35 +340,35 @@ fn command_response_json( fn local_service_install() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::install(&config) + let status = openhuman::openhuman::service::install(&config) .map_err(|e| format!("service install failed: {e}"))?; command_response_json(status, "service install completed") } fn local_service_start() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::start(&config) + let status = openhuman::openhuman::service::start(&config) .map_err(|e| format!("service start failed: {e}"))?; command_response_json(status, "service start completed") } fn local_service_stop() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::stop(&config) + let status = openhuman::openhuman::service::stop(&config) .map_err(|e| format!("service stop failed: {e}"))?; command_response_json(status, "service stop completed") } fn local_service_status() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::status(&config) + let status = openhuman::openhuman::service::status(&config) .map_err(|e| format!("service status failed: {e}"))?; command_response_json(status, "service status fetched") } fn local_service_uninstall() -> Result { let config = load_config()?; - let status = alphahuman::alphahuman::service::uninstall(&config) + let status = openhuman::openhuman::service::uninstall(&config) .map_err(|e| format!("service uninstall failed: {e}"))?; command_response_json(status, "service uninstall completed") } diff --git a/src-tauri/src/bin/openhuman-core.rs b/src-tauri/src/bin/openhuman-core.rs new file mode 100644 index 000000000..7e10d092f --- /dev/null +++ b/src-tauri/src/bin/openhuman-core.rs @@ -0,0 +1,7 @@ +fn main() { + let args: Vec = std::env::args().skip(1).collect(); + if let Err(err) = openhuman::core_server::run_from_cli_args(&args) { + eprintln!("openhuman-core failed: {err}"); + std::process::exit(1); + } +} diff --git a/src-tauri/src/bin/alphahuman-tools-discovery.rs b/src-tauri/src/bin/openhuman-tools-discovery.rs similarity index 99% rename from src-tauri/src/bin/alphahuman-tools-discovery.rs rename to src-tauri/src/bin/openhuman-tools-discovery.rs index be3ed644f..19d392601 100644 --- a/src-tauri/src/bin/alphahuman-tools-discovery.rs +++ b/src-tauri/src/bin/openhuman-tools-discovery.rs @@ -1,4 +1,4 @@ -//! AlphaHuman Tools Discovery Binary +//! OpenHuman Tools Discovery Binary //! //! A standalone Rust binary that discovers all available tools from the V8 skills runtime //! and outputs them as JSON for consumption by the build system. @@ -147,4 +147,4 @@ fn determine_skills_directory() -> Result> { } Err("Could not find skills directory".into()) -} \ No newline at end of file +} diff --git a/src-tauri/src/commands/chat.rs b/src-tauri/src/commands/chat.rs index fa2b5d763..c06c5258a 100644 --- a/src-tauri/src/commands/chat.rs +++ b/src-tauri/src/commands/chat.rs @@ -213,8 +213,9 @@ static AI_CONFIG_CACHE: once_cell::sync::Lazy /// /// Tries these locations in order: /// 1. Tauri resource directory (production builds — files bundled via `tauri.conf.json` resources) -/// 2. `{cwd}/../ai/` (dev mode — project root relative to `src-tauri/`) -/// 3. `{cwd}/ai/` (fallback) +/// 2. `{cwd}/src-tauri/ai/` (dev mode when cwd is project root) +/// 3. `{cwd}/ai/` (dev mode when cwd is `src-tauri/`) +/// 4. `{cwd}/../ai/` (legacy fallback) /// /// Returns an empty string if no files are found (non-fatal). fn load_openclaw_context(app: &tauri::AppHandle) -> String { @@ -268,19 +269,18 @@ fn find_ai_directory(app: &tauri::AppHandle) -> Option { } } - // 2. Try cwd/../ai/ (dev mode; cwd is src-tauri/) + // 2. Try cwd/src-tauri/ai/ (dev mode; cwd is project root) if let Ok(cwd) = std::env::current_dir() { - let dev_dir = cwd.parent().map(|p| p.join("ai")); - if let Some(ref dir) = dev_dir { - if dir.is_dir() { - log::info!( - "[chat] Using AI config from dev dir: {}", - dir.display() - ); - return dev_dir; - } + let root_dev_dir = cwd.join("src-tauri").join("ai"); + if root_dev_dir.is_dir() { + log::info!( + "[chat] Using AI config from root dev dir: {}", + root_dev_dir.display() + ); + return Some(root_dev_dir); } - // 3. Try cwd/ai/ (fallback) + + // 3. Try cwd/ai/ (dev mode; cwd is src-tauri/) let fallback = cwd.join("ai"); if fallback.is_dir() { log::info!( @@ -289,6 +289,17 @@ fn find_ai_directory(app: &tauri::AppHandle) -> Option { ); return Some(fallback); } + + // 4. Legacy fallback: cwd/../ai/ + if let Some(legacy_dir) = cwd.parent().map(|p| p.join("ai")) { + if legacy_dir.is_dir() { + log::info!( + "[chat] Using AI config from legacy dev dir: {}", + legacy_dir.display() + ); + return Some(legacy_dir); + } + } } log::warn!("[chat] No AI config directory found"); diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index c295a5f62..84642db05 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -4,7 +4,7 @@ pub mod memory; pub mod model; pub mod runtime; pub mod socket; -pub mod alphahuman; +pub mod openhuman; pub mod unified_skills; #[cfg(desktop)] @@ -17,7 +17,7 @@ pub use memory::*; pub use model::*; pub use runtime::*; pub use socket::*; -pub use alphahuman::*; +pub use openhuman::*; #[cfg(desktop)] pub use window::*; diff --git a/src-tauri/src/commands/alphahuman.rs b/src-tauri/src/commands/openhuman.rs similarity index 73% rename from src-tauri/src/commands/alphahuman.rs rename to src-tauri/src/commands/openhuman.rs index 5d6bc89cd..55b6f01ed 100644 --- a/src-tauri/src/commands/alphahuman.rs +++ b/src-tauri/src/commands/openhuman.rs @@ -1,6 +1,6 @@ -//! Tauri command proxies for the standalone alphahuman core process. +//! Tauri command proxies for the standalone openhuman core process. -use crate::alphahuman::{doctor, hardware, integrations, migration, onboard, service}; +use crate::openhuman::{doctor, hardware, integrations, migration, onboard, service}; use crate::core_server::{ BrowserSettingsUpdate, CommandResponse, ConfigSnapshot, GatewaySettingsUpdate, MemorySettingsUpdate, ModelSettingsUpdate, RuntimeFlags, RuntimeSettingsUpdate, @@ -32,11 +32,11 @@ async fn call_core( crate::core_rpc::call(method, params).await } -async fn load_config_local() -> Result { +async fn load_config_local() -> Result { let timeout_duration = std::time::Duration::from_secs(30); match tokio::time::timeout( timeout_duration, - crate::alphahuman::config::Config::load_or_init(), + crate::openhuman::config::Config::load_or_init(), ) .await { @@ -54,65 +54,65 @@ pub struct AgentServerStatus { /// Return the current health snapshot as JSON. #[tauri::command] -pub async fn alphahuman_health_snapshot( +pub async fn openhuman_health_snapshot( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.health_snapshot", params_none()).await + call_core(&app, "openhuman.health_snapshot", params_none()).await } /// Return the default security policy info (autonomy config summary). #[tauri::command] -pub async fn alphahuman_security_policy_info( +pub async fn openhuman_security_policy_info( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.security_policy_info", params_none()).await + call_core(&app, "openhuman.security_policy_info", params_none()).await } -/// Encrypt a secret using the alphahuman SecretStore. +/// Encrypt a secret using the openhuman SecretStore. #[tauri::command] -pub async fn alphahuman_encrypt_secret( +pub async fn openhuman_encrypt_secret( app: tauri::AppHandle, plaintext: String, ) -> Result, String> { call_core( &app, - "alphahuman.encrypt_secret", + "openhuman.encrypt_secret", serde_json::json!({ "plaintext": plaintext }), ) .await } -/// Decrypt a secret using the alphahuman SecretStore. +/// Decrypt a secret using the openhuman SecretStore. #[tauri::command] -pub async fn alphahuman_decrypt_secret( +pub async fn openhuman_decrypt_secret( app: tauri::AppHandle, ciphertext: String, ) -> Result, String> { call_core( &app, - "alphahuman.decrypt_secret", + "openhuman.decrypt_secret", serde_json::json!({ "ciphertext": ciphertext }), ) .await } -/// Return the full Alphahuman config snapshot for UI editing. +/// Return the full OpenHuman config snapshot for UI editing. #[tauri::command] -pub async fn alphahuman_get_config( +pub async fn openhuman_get_config( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.get_config", params_none()).await + call_core(&app, "openhuman.get_config", params_none()).await } /// Update model/provider settings. #[tauri::command] -pub async fn alphahuman_update_model_settings( +pub async fn openhuman_update_model_settings( app: tauri::AppHandle, update: ModelSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_model_settings", + "openhuman.update_model_settings", serde_json::json!(update), ) .await @@ -120,13 +120,13 @@ pub async fn alphahuman_update_model_settings( /// Update memory settings. #[tauri::command] -pub async fn alphahuman_update_memory_settings( +pub async fn openhuman_update_memory_settings( app: tauri::AppHandle, update: MemorySettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_memory_settings", + "openhuman.update_memory_settings", serde_json::json!(update), ) .await @@ -134,13 +134,13 @@ pub async fn alphahuman_update_memory_settings( /// Update gateway settings. #[tauri::command] -pub async fn alphahuman_update_gateway_settings( +pub async fn openhuman_update_gateway_settings( app: tauri::AppHandle, update: GatewaySettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_gateway_settings", + "openhuman.update_gateway_settings", serde_json::json!(update), ) .await @@ -148,13 +148,13 @@ pub async fn alphahuman_update_gateway_settings( /// Update tunnel settings (full tunnel config). #[tauri::command] -pub async fn alphahuman_update_tunnel_settings( +pub async fn openhuman_update_tunnel_settings( app: tauri::AppHandle, - tunnel: crate::alphahuman::config::TunnelConfig, + tunnel: crate::openhuman::config::TunnelConfig, ) -> Result, String> { call_core( &app, - "alphahuman.update_tunnel_settings", + "openhuman.update_tunnel_settings", serde_json::json!(tunnel), ) .await @@ -162,13 +162,13 @@ pub async fn alphahuman_update_tunnel_settings( /// Update runtime settings (skill execution backend). #[tauri::command] -pub async fn alphahuman_update_runtime_settings( +pub async fn openhuman_update_runtime_settings( app: tauri::AppHandle, update: RuntimeSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_runtime_settings", + "openhuman.update_runtime_settings", serde_json::json!(update), ) .await @@ -176,13 +176,13 @@ pub async fn alphahuman_update_runtime_settings( /// Update browser settings (Chrome/Chromium tool). #[tauri::command] -pub async fn alphahuman_update_browser_settings( +pub async fn openhuman_update_browser_settings( app: tauri::AppHandle, update: BrowserSettingsUpdate, ) -> Result, String> { call_core( &app, - "alphahuman.update_browser_settings", + "openhuman.update_browser_settings", serde_json::json!(update), ) .await @@ -190,29 +190,29 @@ pub async fn alphahuman_update_browser_settings( /// Read runtime flags that are controlled via environment variables. #[tauri::command] -pub async fn alphahuman_get_runtime_flags( +pub async fn openhuman_get_runtime_flags( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.get_runtime_flags", params_none()).await + call_core(&app, "openhuman.get_runtime_flags", params_none()).await } /// Set browser allow-all flag for the current process. #[tauri::command] -pub async fn alphahuman_set_browser_allow_all( +pub async fn openhuman_set_browser_allow_all( app: tauri::AppHandle, enabled: bool, ) -> Result, String> { call_core( &app, - "alphahuman.set_browser_allow_all", + "openhuman.set_browser_allow_all", serde_json::json!({ "enabled": enabled }), ) .await } -/// Send a single message to the Alphahuman agent and return the response text. +/// Send a single message to the OpenHuman agent and return the response text. #[tauri::command] -pub async fn alphahuman_agent_chat( +pub async fn openhuman_agent_chat( app: tauri::AppHandle, message: String, provider_override: Option, @@ -221,7 +221,7 @@ pub async fn alphahuman_agent_chat( ) -> Result, String> { call_core( &app, - "alphahuman.agent_chat", + "openhuman.agent_chat", serde_json::json!({ "message": message, "provider_override": provider_override, @@ -232,24 +232,24 @@ pub async fn alphahuman_agent_chat( .await } -/// Run Alphahuman doctor checks and return a structured report. +/// Run OpenHuman doctor checks and return a structured report. #[tauri::command] -pub async fn alphahuman_doctor_report( +pub async fn openhuman_doctor_report( app: tauri::AppHandle, ) -> Result, String> { - call_core(&app, "alphahuman.doctor_report", params_none()).await + call_core(&app, "openhuman.doctor_report", params_none()).await } /// Run model catalog probes for providers. #[tauri::command] -pub async fn alphahuman_doctor_models( +pub async fn openhuman_doctor_models( app: tauri::AppHandle, provider_override: Option, use_cache: Option, ) -> Result, String> { call_core( &app, - "alphahuman.doctor_models", + "openhuman.doctor_models", serde_json::json!({ "provider_override": provider_override, "use_cache": use_cache, @@ -260,10 +260,10 @@ pub async fn alphahuman_doctor_models( /// List integrations with status for the current config. #[tauri::command] -pub async fn alphahuman_list_integrations( +pub async fn openhuman_list_integrations( app: tauri::AppHandle, ) -> Result>, String> { - call_core(&app, "alphahuman.list_integrations", params_none()).await + call_core(&app, "openhuman.list_integrations", params_none()).await } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -273,14 +273,14 @@ struct IntegrationInfoParams { /// Get details for a single integration. #[tauri::command] -pub async fn alphahuman_get_integration_info( +pub async fn openhuman_get_integration_info( app: tauri::AppHandle, name: String, ) -> Result, String> { let params = IntegrationInfoParams { name }; call_core( &app, - "alphahuman.get_integration_info", + "openhuman.get_integration_info", serde_json::json!(params), ) .await @@ -288,14 +288,14 @@ pub async fn alphahuman_get_integration_info( /// Refresh the model catalog for a provider (or default provider). #[tauri::command] -pub async fn alphahuman_models_refresh( +pub async fn openhuman_models_refresh( app: tauri::AppHandle, provider_override: Option, force: Option, ) -> Result, String> { call_core( &app, - "alphahuman.models_refresh", + "openhuman.models_refresh", serde_json::json!({ "provider_override": provider_override, "force": force, @@ -304,16 +304,16 @@ pub async fn alphahuman_models_refresh( .await } -/// Migrate OpenClaw memory into the current Alphahuman workspace. +/// Migrate OpenClaw memory into the current OpenHuman workspace. #[tauri::command] -pub async fn alphahuman_migrate_openclaw( +pub async fn openhuman_migrate_openclaw( app: tauri::AppHandle, source_workspace: Option, dry_run: Option, ) -> Result, String> { call_core( &app, - "alphahuman.migrate_openclaw", + "openhuman.migrate_openclaw", serde_json::json!({ "source_workspace": source_workspace, "dry_run": dry_run, @@ -324,21 +324,21 @@ pub async fn alphahuman_migrate_openclaw( /// Discover connected hardware devices (feature-gated). #[tauri::command] -pub async fn alphahuman_hardware_discover( +pub async fn openhuman_hardware_discover( app: tauri::AppHandle, ) -> Result>, String> { - call_core(&app, "alphahuman.hardware_discover", params_none()).await + call_core(&app, "openhuman.hardware_discover", params_none()).await } /// Introspect a device path (feature-gated). #[tauri::command] -pub async fn alphahuman_hardware_introspect( +pub async fn openhuman_hardware_introspect( app: tauri::AppHandle, path: String, ) -> Result, String> { call_core( &app, - "alphahuman.hardware_introspect", + "openhuman.hardware_introspect", serde_json::json!({ "path": path }), ) .await @@ -346,8 +346,8 @@ pub async fn alphahuman_hardware_introspect( /// Return whether the local core agent server is reachable. #[tauri::command] -pub async fn alphahuman_agent_server_status() -> Result, String> { - let url = std::env::var("ALPHAHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()); +pub async fn openhuman_agent_server_status() -> Result, String> { + let url = std::env::var("OPENHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()); let running = crate::core_rpc::ping().await; Ok(CommandResponse { result: AgentServerStatus { running, url }, @@ -355,9 +355,9 @@ pub async fn alphahuman_agent_server_status() -> Result Result, String> { let config = load_config_local().await?; @@ -369,9 +369,9 @@ pub async fn alphahuman_service_install( .map_err(|e| e.to_string()) } -/// Start the Alphahuman daemon service. +/// Start the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_start( +pub async fn openhuman_service_start( _app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -383,9 +383,9 @@ pub async fn alphahuman_service_start( .map_err(|e| e.to_string()) } -/// Stop the Alphahuman daemon service. +/// Stop the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_stop( +pub async fn openhuman_service_stop( app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -404,9 +404,9 @@ pub async fn alphahuman_service_stop( }) } -/// Get the Alphahuman daemon service status. +/// Get the OpenHuman daemon service status. #[tauri::command] -pub async fn alphahuman_service_status( +pub async fn openhuman_service_status( _app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; @@ -418,9 +418,9 @@ pub async fn alphahuman_service_status( .map_err(|e| e.to_string()) } -/// Uninstall the Alphahuman daemon service. +/// Uninstall the OpenHuman daemon service. #[tauri::command] -pub async fn alphahuman_service_uninstall( +pub async fn openhuman_service_uninstall( app: tauri::AppHandle, ) -> Result, String> { let config = load_config_local().await?; diff --git a/src-tauri/src/commands/unified_skills.rs b/src-tauri/src/commands/unified_skills.rs index c907ffd96..f4f7665a9 100644 --- a/src-tauri/src/commands/unified_skills.rs +++ b/src-tauri/src/commands/unified_skills.rs @@ -1,7 +1,7 @@ //! Tauri commands for the unified skill registry. //! //! These commands expose a single, type-agnostic API to the frontend WebView. -//! Internally they dispatch to the QuickJS runtime (alphahuman skills) or the +//! Internally they dispatch to the QuickJS runtime (openhuman skills) or the //! file-based executor (openclaw skills) based on `skill_type`. //! //! Commands are desktop-only — mobile stubs return empty/error results. @@ -24,7 +24,7 @@ mod desktop { use super::*; use crate::unified_skills::UnifiedSkillRegistry; - /// List all skills from the unified registry (both alphahuman and openclaw types). + /// List all skills from the unified registry (both openhuman and openclaw types). #[tauri::command] pub async fn unified_list_skills( engine: State<'_, Arc>, @@ -36,7 +36,7 @@ mod desktop { /// Execute a named tool on any registered skill. /// /// Dispatches based on skill_type: - /// - `alphahuman` → QuickJS runtime + /// - `openhuman` → QuickJS runtime /// - `openclaw` → shell/http executor or returns prompt content #[tauri::command] pub async fn unified_execute_skill( @@ -51,7 +51,7 @@ mod desktop { /// Programmatically generate a new skill, register it, and return its entry. /// - /// For `skill_type = "alphahuman"`: writes manifest.json + index.js to the skills dir. + /// For `skill_type = "openhuman"`: writes manifest.json + index.js to the skills dir. /// For `skill_type = "openclaw"`: writes SKILL.md or SKILL.toml to workspace/skills/. /// /// The skill is immediately available in subsequent `unified_list_skills` calls. diff --git a/src-tauri/src/core_process.rs b/src-tauri/src/core_process.rs index b2aabfac5..68a43cd12 100644 --- a/src-tauri/src/core_process.rs +++ b/src-tauri/src/core_process.rs @@ -81,7 +81,7 @@ impl CoreProcessHandle { } pub fn default_core_port() -> u16 { - std::env::var("ALPHAHUMAN_CORE_PORT") + std::env::var("OPENHUMAN_CORE_PORT") .ok() .and_then(|v| v.parse::().ok()) .unwrap_or(7788) diff --git a/src-tauri/src/core_rpc.rs b/src-tauri/src/core_rpc.rs index 946c3d67f..4dee47a3a 100644 --- a/src-tauri/src/core_rpc.rs +++ b/src-tauri/src/core_rpc.rs @@ -30,7 +30,7 @@ struct RpcError { } fn rpc_url() -> String { - std::env::var("ALPHAHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()) + std::env::var("OPENHUMAN_CORE_RPC_URL").unwrap_or_else(|_| DEFAULT_CORE_RPC_URL.to_string()) } pub async fn call( diff --git a/src-tauri/src/core_server.rs b/src-tauri/src/core_server.rs index 7f81e4fdf..8c955dae0 100644 --- a/src-tauri/src/core_server.rs +++ b/src-tauri/src/core_server.rs @@ -8,10 +8,10 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::json; -use crate::alphahuman::config::Config; -use crate::alphahuman::health; -use crate::alphahuman::security::{SecretStore, SecurityPolicy}; -use crate::alphahuman::{doctor, hardware, integrations, migration, onboard, service}; +use crate::openhuman::config::Config; +use crate::openhuman::health; +use crate::openhuman::security::{SecretStore, SecurityPolicy}; +use crate::openhuman::{doctor, hardware, integrations, migration, onboard, service}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CommandResponse { @@ -160,7 +160,7 @@ struct SetBrowserAllowAllParams { enabled: bool, } -async fn load_alphahuman_config() -> Result { +async fn load_openhuman_config() -> Result { let timeout_duration = std::time::Duration::from_secs(30); match tokio::time::timeout(timeout_duration, Config::load_or_init()).await { Ok(Ok(config)) => Ok(config), @@ -249,12 +249,12 @@ async fn dispatch( "core.ping" => to_json_value(json!({ "ok": true })), "core.version" => to_json_value(json!({ "version": state.core_version })), - "alphahuman.health_snapshot" => to_json_value(command_response( + "openhuman.health_snapshot" => to_json_value(command_response( health::snapshot_json(), vec!["health_snapshot requested".to_string()], )), - "alphahuman.security_policy_info" => { + "openhuman.security_policy_info" => { let policy = SecurityPolicy::default(); let payload = json!({ "autonomy": policy.autonomy, @@ -270,8 +270,8 @@ async fn dispatch( )) } - "alphahuman.get_config" => { - let config = load_alphahuman_config().await?; + "openhuman.get_config" => { + let config = load_openhuman_config().await?; let snapshot = snapshot_config(&config)?; to_json_value(command_response( snapshot, @@ -282,9 +282,9 @@ async fn dispatch( )) } - "alphahuman.update_model_settings" => { + "openhuman.update_model_settings" => { let update: ModelSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(api_key) = update.api_key { config.api_key = if api_key.trim().is_empty() { None @@ -327,9 +327,9 @@ async fn dispatch( )) } - "alphahuman.update_memory_settings" => { + "openhuman.update_memory_settings" => { let update: MemorySettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(backend) = update.backend { config.memory.backend = backend; } @@ -356,9 +356,9 @@ async fn dispatch( )) } - "alphahuman.update_gateway_settings" => { + "openhuman.update_gateway_settings" => { let update: GatewaySettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(host) = update.host { config.gateway.host = host; } @@ -382,9 +382,9 @@ async fn dispatch( )) } - "alphahuman.update_tunnel_settings" => { - let tunnel: crate::alphahuman::config::TunnelConfig = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + "openhuman.update_tunnel_settings" => { + let tunnel: crate::openhuman::config::TunnelConfig = parse_params(params)?; + let mut config = load_openhuman_config().await?; config.tunnel = tunnel; config.save().await.map_err(|e| e.to_string())?; let snapshot = snapshot_config(&config)?; @@ -397,9 +397,9 @@ async fn dispatch( )) } - "alphahuman.update_runtime_settings" => { + "openhuman.update_runtime_settings" => { let update: RuntimeSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(kind) = update.kind { config.runtime.kind = kind; } @@ -417,9 +417,9 @@ async fn dispatch( )) } - "alphahuman.update_browser_settings" => { + "openhuman.update_browser_settings" => { let update: BrowserSettingsUpdate = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(enabled) = update.enabled { config.browser.enabled = enabled; } @@ -434,10 +434,10 @@ async fn dispatch( )) } - "alphahuman.get_runtime_flags" => { + "openhuman.get_runtime_flags" => { let flags = RuntimeFlags { - browser_allow_all: env_flag_enabled("ALPHAHUMAN_BROWSER_ALLOW_ALL"), - log_prompts: env_flag_enabled("ALPHAHUMAN_LOG_PROMPTS"), + browser_allow_all: env_flag_enabled("OPENHUMAN_BROWSER_ALLOW_ALL"), + log_prompts: env_flag_enabled("OPENHUMAN_LOG_PROMPTS"), }; to_json_value(command_response( flags, @@ -445,16 +445,16 @@ async fn dispatch( )) } - "alphahuman.set_browser_allow_all" => { + "openhuman.set_browser_allow_all" => { let p: SetBrowserAllowAllParams = parse_params(params)?; if p.enabled { - std::env::set_var("ALPHAHUMAN_BROWSER_ALLOW_ALL", "1"); + std::env::set_var("OPENHUMAN_BROWSER_ALLOW_ALL", "1"); } else { - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); } let flags = RuntimeFlags { - browser_allow_all: env_flag_enabled("ALPHAHUMAN_BROWSER_ALLOW_ALL"), - log_prompts: env_flag_enabled("ALPHAHUMAN_LOG_PROMPTS"), + browser_allow_all: env_flag_enabled("OPENHUMAN_BROWSER_ALLOW_ALL"), + log_prompts: env_flag_enabled("OPENHUMAN_LOG_PROMPTS"), }; to_json_value(command_response( flags, @@ -462,9 +462,9 @@ async fn dispatch( )) } - "alphahuman.agent_chat" => { + "openhuman.agent_chat" => { let p: AgentChatParams = parse_params(params)?; - let mut config = load_alphahuman_config().await?; + let mut config = load_openhuman_config().await?; if let Some(provider) = p.provider_override { config.default_provider = Some(provider); } @@ -475,7 +475,7 @@ async fn dispatch( config.default_temperature = temp; } let mut agent = - crate::alphahuman::agent::Agent::from_config(&config).map_err(|e| e.to_string())?; + crate::openhuman::agent::Agent::from_config(&config).map_err(|e| e.to_string())?; let response = agent .run_single(&p.message) .await @@ -486,9 +486,9 @@ async fn dispatch( )) } - "alphahuman.encrypt_secret" => { + "openhuman.encrypt_secret" => { let p: EncryptSecretParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let store = secret_store_for_config(&config); let ciphertext = store.encrypt(&p.plaintext).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -497,9 +497,9 @@ async fn dispatch( )) } - "alphahuman.decrypt_secret" => { + "openhuman.decrypt_secret" => { let p: DecryptSecretParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let store = secret_store_for_config(&config); let plaintext = store.decrypt(&p.ciphertext).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -508,8 +508,8 @@ async fn dispatch( )) } - "alphahuman.doctor_report" => { - let config = load_alphahuman_config().await?; + "openhuman.doctor_report" => { + let config = load_openhuman_config().await?; let report = doctor::run(&config).map_err(|e| e.to_string())?; to_json_value(command_response( report, @@ -517,9 +517,9 @@ async fn dispatch( )) } - "alphahuman.doctor_models" => { + "openhuman.doctor_models" => { let p: DoctorModelsParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let use_cache = p.use_cache.unwrap_or(true); let report = doctor::run_models(&config, p.provider_override.as_deref(), use_cache) .map_err(|e| e.to_string())?; @@ -529,17 +529,17 @@ async fn dispatch( )) } - "alphahuman.list_integrations" => { - let config = load_alphahuman_config().await?; + "openhuman.list_integrations" => { + let config = load_openhuman_config().await?; to_json_value(command_response( integrations::list_integrations(&config), vec!["integrations listed".to_string()], )) } - "alphahuman.get_integration_info" => { + "openhuman.get_integration_info" => { let p: IntegrationInfoParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let info = integrations::get_integration_info(&config, &p.name).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -548,9 +548,9 @@ async fn dispatch( )) } - "alphahuman.models_refresh" => { + "openhuman.models_refresh" => { let p: ModelsRefreshParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let result = onboard::run_models_refresh( &config, p.provider_override.as_deref(), @@ -563,9 +563,9 @@ async fn dispatch( )) } - "alphahuman.migrate_openclaw" => { + "openhuman.migrate_openclaw" => { let p: MigrateOpenClawParams = parse_params(params)?; - let config = load_alphahuman_config().await?; + let config = load_openhuman_config().await?; let source = p.source_workspace.map(std::path::PathBuf::from); let report = migration::migrate_openclaw_memory(&config, source, p.dry_run.unwrap_or(true)) @@ -577,12 +577,12 @@ async fn dispatch( )) } - "alphahuman.hardware_discover" => to_json_value(command_response( + "openhuman.hardware_discover" => to_json_value(command_response( hardware::discover_hardware(), vec!["hardware discovery complete".to_string()], )), - "alphahuman.hardware_introspect" => { + "openhuman.hardware_introspect" => { let p: HardwareIntrospectParams = parse_params(params)?; let info = hardware::introspect_device(&p.path).map_err(|e| e.to_string())?; to_json_value(command_response( @@ -591,8 +591,8 @@ async fn dispatch( )) } - "alphahuman.service_install" => { - let config = load_alphahuman_config().await?; + "openhuman.service_install" => { + let config = load_openhuman_config().await?; let status = service::install(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -600,8 +600,8 @@ async fn dispatch( )) } - "alphahuman.service_start" => { - let config = load_alphahuman_config().await?; + "openhuman.service_start" => { + let config = load_openhuman_config().await?; let status = service::start(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -609,8 +609,8 @@ async fn dispatch( )) } - "alphahuman.service_stop" => { - let config = load_alphahuman_config().await?; + "openhuman.service_stop" => { + let config = load_openhuman_config().await?; let status = service::stop(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -618,8 +618,8 @@ async fn dispatch( )) } - "alphahuman.service_status" => { - let config = load_alphahuman_config().await?; + "openhuman.service_status" => { + let config = load_openhuman_config().await?; let status = service::status(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -627,8 +627,8 @@ async fn dispatch( )) } - "alphahuman.service_uninstall" => { - let config = load_alphahuman_config().await?; + "openhuman.service_uninstall" => { + let config = load_openhuman_config().await?; let status = service::uninstall(&config).map_err(|e| e.to_string())?; to_json_value(command_response( status, @@ -648,7 +648,7 @@ async fn root_handler() -> impl IntoResponse { ( StatusCode::OK, Json(json!({ - "name": "alphahuman-core", + "name": "openhuman-core", "ok": true, "endpoints": { "health": "/health", @@ -677,7 +677,7 @@ async fn not_found_handler() -> impl IntoResponse { } fn core_port() -> u16 { - std::env::var("ALPHAHUMAN_CORE_PORT") + std::env::var("OPENHUMAN_CORE_PORT") .ok() .and_then(|v| v.parse::().ok()) .unwrap_or(7788) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 80e030b44..9efbf005c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,4 @@ -//! AlphaHuman Desktop Application +//! OpenHuman Desktop Application //! //! This is the Rust backend for the cross-platform crypto community platform. //! It provides: @@ -9,7 +9,7 @@ //! - Native notifications mod ai; -pub mod alphahuman; +pub mod openhuman; mod auth; mod commands; mod core_process; @@ -51,20 +51,15 @@ fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } -/// Write AI configuration files to the project's ./ai/ directory +/// Write AI configuration files to the src-tauri/ai/ directory #[tauri::command] async fn write_ai_config_file(filename: String, content: String) -> Result { use std::env; - // Get the project root directory (parent of src-tauri) + // Determine runtime working directory let current_dir = env::current_dir().map_err(|e| format!("Failed to get current directory: {e}"))?; - // Go up one level to get project root (since we're in src-tauri/) - let project_root = current_dir - .parent() - .ok_or("Failed to get project root directory")?; - // Ensure filename is safe (only allow .md files) if !filename.ends_with(".md") { return Err("Only .md files are allowed".to_string()); @@ -75,8 +70,14 @@ async fn write_ai_config_file(filename: String, content: String) -> Result {cwd}/src-tauri/ai + // 2) src-tauri dir -> {cwd}/ai + let ai_dir = if current_dir.join("src-tauri").is_dir() { + current_dir.join("src-tauri").join("ai") + } else { + current_dir.join("ai") + }; let file_path = ai_dir.join(&filename); // Ensure ai directory exists @@ -222,7 +223,7 @@ fn is_daemon_mode() -> bool { fn daemon_foreground_requested() -> bool { matches!( - std::env::var("ALPHAHUMAN_DAEMON_FOREGROUND") + std::env::var("OPENHUMAN_DAEMON_FOREGROUND") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") @@ -241,7 +242,7 @@ fn setup_tray(app: &AppHandle) -> Result<(), Box> { let _tray = TrayIconBuilder::with_id("main-tray") .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) - .tooltip("AlphaHuman") + .tooltip("OpenHuman") .on_menu_event(move |app, event| match event.id().as_ref() { "show_hide" => { toggle_main_window_visibility(app); @@ -283,7 +284,7 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { let mut last_modified: Option = None; log::info!( - "[alphahuman] Watching daemon health file: {}", + "[openhuman] Watching daemon health file: {}", state_file.display() ); @@ -301,30 +302,30 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { if let Ok(json_value) = serde_json::from_str::(&content) { log::debug!( - "[alphahuman] Broadcasting health event from file: {:?}", + "[openhuman] Broadcasting health event from file: {:?}", json_value ); // Emit Tauri event to frontend (same as internal daemon) - if let Err(e) = app_handle.emit("alphahuman:health", &json_value) { + if let Err(e) = app_handle.emit("openhuman:health", &json_value) { log::error!( - "[alphahuman] Failed to emit health event from file: {}", + "[openhuman] Failed to emit health event from file: {}", e ); } else { log::debug!( - "[alphahuman] Health event emitted successfully from file" + "[openhuman] Health event emitted successfully from file" ); } } else { log::debug!( - "[alphahuman] Failed to parse health file as JSON: {}", + "[openhuman] Failed to parse health file as JSON: {}", state_file.display() ); } } else { log::debug!( - "[alphahuman] Failed to read health file: {}", + "[openhuman] Failed to read health file: {}", state_file.display() ); } @@ -333,7 +334,7 @@ async fn watch_daemon_health_file(app_handle: AppHandle, data_dir: PathBuf) { } else { // File doesn't exist yet - external daemon may not be writing yet log::debug!( - "[alphahuman] Health file not found yet: {}", + "[openhuman] Health file not found yet: {}", state_file.display() ); } @@ -359,7 +360,7 @@ pub fn run() { android_logger::init_once( android_logger::Config::default() .with_max_level(log::LevelFilter::Debug) - .with_tag("AlphaHuman"), + .with_tag("OpenHuman"), ); } #[cfg(not(target_os = "android"))] @@ -524,7 +525,7 @@ pub fn run() { // Fallback for platforms where app_data_dir isn't available dirs::home_dir() .unwrap_or_else(|| std::path::PathBuf::from(".")) - .join(".alphahuman") + .join(".openhuman") }); let skills_data_dir = data_dir.join("skills"); @@ -583,7 +584,7 @@ pub fn run() { log::info!("[runtime] QuickJS runtime disabled on iOS"); } - // Start the alphahuman daemon supervisor (desktop only) + // Start the openhuman daemon supervisor (desktop only) #[cfg(not(any(target_os = "android", target_os = "ios")))] { let data_dir = app @@ -592,11 +593,11 @@ pub fn run() { .unwrap_or_else(|_| { dirs::home_dir() .unwrap_or_else(|| std::path::PathBuf::from(".")) - .join(".alphahuman") + .join(".openhuman") }); - let daemon_config = alphahuman::config::DaemonConfig::from_app_data_dir(&data_dir); + let daemon_config = openhuman::config::DaemonConfig::from_app_data_dir(&data_dir); let cancel = tokio_util::sync::CancellationToken::new(); - let daemon_handle = alphahuman::daemon::DaemonHandle { + let daemon_handle = openhuman::daemon::DaemonHandle { cancel: cancel.clone(), }; app.manage(daemon_handle); @@ -605,7 +606,7 @@ pub fn run() { let use_internal_daemon = daemon_mode || daemon_foreground_requested() || cfg!(debug_assertions) // Always use internal supervisor in debug builds - || std::env::var("ALPHAHUMAN_DAEMON_INTERNAL").unwrap_or("false".to_string()) == "true"; // Cross-platform override via env var + || std::env::var("OPENHUMAN_DAEMON_INTERNAL").unwrap_or("false".to_string()) == "true"; // Cross-platform override via env var if use_internal_daemon { // Run internal daemon supervisor with health event emission @@ -613,26 +614,26 @@ pub fn run() { // - Daemon mode enabled, OR // - Foreground daemon requested, OR // - Debug build (for easier development), OR - // - ALPHAHUMAN_DAEMON_INTERNAL=true env var (any platform) - log::info!("[alphahuman] Using internal daemon supervisor (ALPHAHUMAN_DAEMON_INTERNAL=true or debug build)"); + // - OPENHUMAN_DAEMON_INTERNAL=true env var (any platform) + log::info!("[openhuman] Using internal daemon supervisor (OPENHUMAN_DAEMON_INTERNAL=true or debug build)"); let app_handle_for_daemon = app.handle().clone(); tauri::async_runtime::spawn(async move { - log::info!("[alphahuman] Starting daemon supervisor with health monitoring"); - if let Err(e) = alphahuman::daemon::run( + log::info!("[openhuman] Starting daemon supervisor with health monitoring"); + if let Err(e) = openhuman::daemon::run( daemon_config, app_handle_for_daemon, cancel, ) .await { - log::error!("[alphahuman] Daemon supervisor error: {e}"); + log::error!("[openhuman] Daemon supervisor error: {e}"); } }); } else { // Start external platform-specific service for background daemon - // This path is taken on all platforms when ALPHAHUMAN_DAEMON_INTERNAL=false/unset + // This path is taken on all platforms when OPENHUMAN_DAEMON_INTERNAL=false/unset // and not in daemon mode, foreground mode, or debug build - log::info!("[alphahuman] Using external daemon service (ALPHAHUMAN_DAEMON_INTERNAL=false/unset)"); + log::info!("[openhuman] Using external daemon service (OPENHUMAN_DAEMON_INTERNAL=false/unset)"); // Setup file watching to bridge external daemon health events to frontend let app_handle_for_watcher = app.handle().clone(); @@ -643,20 +644,20 @@ pub fn run() { // Start the external platform service tauri::async_runtime::spawn(async move { - match alphahuman::config::Config::load_or_init().await { + match openhuman::config::Config::load_or_init().await { Ok(config) => { - match alphahuman::service::install(&config) { - Ok(status) => log::info!("[alphahuman] External daemon service installed: {:?}", status), - Err(e) => log::error!("[alphahuman] Failed to install external daemon service: {e}"), + match openhuman::service::install(&config) { + Ok(status) => log::info!("[openhuman] External daemon service installed: {:?}", status), + Err(e) => log::error!("[openhuman] Failed to install external daemon service: {e}"), } - match alphahuman::service::start(&config) { - Ok(status) => log::info!("[alphahuman] External daemon service started: {:?}", status), - Err(e) => log::error!("[alphahuman] Failed to start external daemon service: {e}"), + match openhuman::service::start(&config) { + Ok(status) => log::info!("[openhuman] External daemon service started: {:?}", status), + Err(e) => log::error!("[openhuman] Failed to start external daemon service: {e}"), } } Err(e) => { log::error!( - "[alphahuman] Failed to load config for external service: {e}" + "[openhuman] Failed to load config for external service: {e}" ); } } @@ -668,7 +669,7 @@ pub fn run() { #[cfg(not(any(target_os = "android", target_os = "ios")))] { let core_handle = core_process::CoreProcessHandle::new(core_process::default_core_port()); - std::env::set_var("ALPHAHUMAN_CORE_RPC_URL", core_handle.rpc_url()); + std::env::set_var("OPENHUMAN_CORE_RPC_URL", core_handle.rpc_url()); app.manage(core_handle.clone()); tauri::async_runtime::spawn(async move { if let Err(err) = core_handle.ensure_running().await { @@ -807,35 +808,35 @@ pub fn run() { // Model commands (backend API proxy) model_summarize, model_generate, - // Alphahuman commands - alphahuman_health_snapshot, - alphahuman_security_policy_info, - alphahuman_encrypt_secret, - alphahuman_decrypt_secret, - alphahuman_get_config, - alphahuman_update_model_settings, - alphahuman_update_memory_settings, - alphahuman_update_gateway_settings, - alphahuman_update_tunnel_settings, - alphahuman_update_runtime_settings, - alphahuman_update_browser_settings, - alphahuman_get_runtime_flags, - alphahuman_set_browser_allow_all, - alphahuman_agent_chat, - alphahuman_doctor_report, - alphahuman_doctor_models, - alphahuman_list_integrations, - alphahuman_get_integration_info, - alphahuman_models_refresh, - alphahuman_migrate_openclaw, - alphahuman_hardware_discover, - alphahuman_hardware_introspect, - alphahuman_service_install, - alphahuman_service_start, - alphahuman_service_stop, - alphahuman_service_status, - alphahuman_service_uninstall, - alphahuman_agent_server_status, + // OpenHuman commands + openhuman_health_snapshot, + openhuman_security_policy_info, + openhuman_encrypt_secret, + openhuman_decrypt_secret, + openhuman_get_config, + openhuman_update_model_settings, + openhuman_update_memory_settings, + openhuman_update_gateway_settings, + openhuman_update_tunnel_settings, + openhuman_update_runtime_settings, + openhuman_update_browser_settings, + openhuman_get_runtime_flags, + openhuman_set_browser_allow_all, + openhuman_agent_chat, + openhuman_doctor_report, + openhuman_doctor_models, + openhuman_list_integrations, + openhuman_get_integration_info, + openhuman_models_refresh, + openhuman_migrate_openclaw, + openhuman_hardware_discover, + openhuman_hardware_introspect, + openhuman_service_install, + openhuman_service_start, + openhuman_service_stop, + openhuman_service_status, + openhuman_service_uninstall, + openhuman_agent_server_status, // Unified skill registry commands unified_list_skills, unified_execute_skill, @@ -936,35 +937,35 @@ pub fn run() { // Model commands (backend API proxy) model_summarize, model_generate, - // Alphahuman commands - alphahuman_health_snapshot, - alphahuman_security_policy_info, - alphahuman_encrypt_secret, - alphahuman_decrypt_secret, - alphahuman_get_config, - alphahuman_update_model_settings, - alphahuman_update_memory_settings, - alphahuman_update_gateway_settings, - alphahuman_update_tunnel_settings, - alphahuman_update_runtime_settings, - alphahuman_update_browser_settings, - alphahuman_get_runtime_flags, - alphahuman_set_browser_allow_all, - alphahuman_agent_chat, - alphahuman_doctor_report, - alphahuman_doctor_models, - alphahuman_list_integrations, - alphahuman_get_integration_info, - alphahuman_models_refresh, - alphahuman_migrate_openclaw, - alphahuman_hardware_discover, - alphahuman_hardware_introspect, - alphahuman_service_install, - alphahuman_service_start, - alphahuman_service_stop, - alphahuman_service_status, - alphahuman_service_uninstall, - alphahuman_agent_server_status, + // OpenHuman commands + openhuman_health_snapshot, + openhuman_security_policy_info, + openhuman_encrypt_secret, + openhuman_decrypt_secret, + openhuman_get_config, + openhuman_update_model_settings, + openhuman_update_memory_settings, + openhuman_update_gateway_settings, + openhuman_update_tunnel_settings, + openhuman_update_runtime_settings, + openhuman_update_browser_settings, + openhuman_get_runtime_flags, + openhuman_set_browser_allow_all, + openhuman_agent_chat, + openhuman_doctor_report, + openhuman_doctor_models, + openhuman_list_integrations, + openhuman_get_integration_info, + openhuman_models_refresh, + openhuman_migrate_openclaw, + openhuman_hardware_discover, + openhuman_hardware_introspect, + openhuman_service_install, + openhuman_service_start, + openhuman_service_stop, + openhuman_service_status, + openhuman_service_uninstall, + openhuman_agent_server_status, // Unified skill registry commands (mobile stubs) unified_list_skills, unified_execute_skill, @@ -1009,10 +1010,10 @@ pub fn run() { RunEvent::Exit => { log::info!("[app] Exit event received, shutting down"); - // Cancel the alphahuman daemon supervisor - if let Some(daemon) = app_handle.try_state::() { + // Cancel the openhuman daemon supervisor + if let Some(daemon) = app_handle.try_state::() { daemon.cancel.cancel(); - log::info!("[alphahuman] Daemon shutdown signalled"); + log::info!("[openhuman] Daemon shutdown signalled"); } if let Some(core) = app_handle.try_state::() { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index dbaf5417b..5d7871189 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -4,12 +4,12 @@ fn main() { let args: Vec = std::env::args().collect(); if args.get(1).map(String::as_str) == Some("core") { - if let Err(err) = alphahuman::run_core_from_args(&args[2..]) { + if let Err(err) = openhuman::run_core_from_args(&args[2..]) { eprintln!("core process failed: {err}"); std::process::exit(1); } return; } - alphahuman::run() + openhuman::run() } diff --git a/src-tauri/src/memory/mod.rs b/src-tauri/src/memory/mod.rs index 2187ceea4..ce83b4416 100644 --- a/src-tauri/src/memory/mod.rs +++ b/src-tauri/src/memory/mod.rs @@ -27,7 +27,7 @@ impl MemoryClient { log::warn!("[memory] from_token: exit — token is empty, returning None"); return None; } - let config = if let Ok(base_url) = std::env::var("ALPHAHUMAN_BASE_URL") + let config = if let Ok(base_url) = std::env::var("OPENHUMAN_BASE_URL") .or_else(|_| std::env::var("TINYHUMANS_BASE_URL")) { log::info!("[memory] from_token: constructing client (base_url={base_url}, source=memory_env)"); @@ -345,7 +345,7 @@ mod tests { /// - the account quota is the only limiting factor /// /// Run with: - /// JWT_TOKEN= \ + /// JWT_TOKEN= \ /// cargo test --manifest-path src-tauri/Cargo.toml test_memory_skill_sync_flow -- --ignored --nocapture #[tokio::test] #[ignore] @@ -357,7 +357,7 @@ mod tests { .expect("client creation failed"); let skill_id = "gmail"; - let integration_id = "test@alphahuman.dev"; + let integration_id = "test@openhuman.dev"; let dummy_content = serde_json::json!({ "integrationId": integration_id, @@ -374,7 +374,7 @@ mod tests { .store_skill_sync( skill_id, integration_id, - "Gmail OAuth sync — test@alphahuman.dev", + "Gmail OAuth sync — test@openhuman.dev", &serde_json::to_string_pretty(&dummy_content).unwrap(), None, None, diff --git a/src-tauri/src/alphahuman/agent/agent.rs b/src-tauri/src/openhuman/agent/agent.rs similarity index 88% rename from src-tauri/src/alphahuman/agent/agent.rs rename to src-tauri/src/openhuman/agent/agent.rs index db6145b98..02202ad52 100644 --- a/src-tauri/src/alphahuman/agent/agent.rs +++ b/src-tauri/src/openhuman/agent/agent.rs @@ -3,14 +3,14 @@ use super::dispatcher::{ }; use super::memory_loader::{DefaultMemoryLoader, MemoryLoader}; use super::prompt::{PromptContext, SystemPromptBuilder}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; -use crate::alphahuman::observability::{self, Observer, ObserverEvent}; -use crate::alphahuman::providers::{self, ChatMessage, ChatRequest, ConversationMessage, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools::{self, Tool, ToolSpec}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::observability::{self, Observer, ObserverEvent}; +use crate::openhuman::providers::{self, ChatMessage, ChatRequest, ConversationMessage, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools::{self, Tool, ToolSpec}; +use crate::openhuman::util::truncate_with_ellipsis; use anyhow::Result; use std::io::Write as IoWrite; use std::sync::Arc; @@ -25,15 +25,15 @@ pub struct Agent { prompt_builder: SystemPromptBuilder, tool_dispatcher: Box, memory_loader: Box, - config: crate::alphahuman::config::AgentConfig, + config: crate::openhuman::config::AgentConfig, model_name: String, temperature: f64, workspace_dir: std::path::PathBuf, - identity_config: crate::alphahuman::config::IdentityConfig, - skills: Vec, + identity_config: crate::openhuman::config::IdentityConfig, + skills: Vec, auto_save: bool, history: Vec, - classification_config: crate::alphahuman::config::QueryClassificationConfig, + classification_config: crate::openhuman::config::QueryClassificationConfig, available_hints: Vec, } @@ -45,14 +45,14 @@ pub struct AgentBuilder { prompt_builder: Option, tool_dispatcher: Option>, memory_loader: Option>, - config: Option, + config: Option, model_name: Option, temperature: Option, workspace_dir: Option, - identity_config: Option, - skills: Option>, + identity_config: Option, + skills: Option>, auto_save: Option, - classification_config: Option, + classification_config: Option, available_hints: Option>, } @@ -113,7 +113,7 @@ impl AgentBuilder { self } - pub fn config(mut self, config: crate::alphahuman::config::AgentConfig) -> Self { + pub fn config(mut self, config: crate::openhuman::config::AgentConfig) -> Self { self.config = Some(config); self } @@ -133,12 +133,12 @@ impl AgentBuilder { self } - pub fn identity_config(mut self, identity_config: crate::alphahuman::config::IdentityConfig) -> Self { + pub fn identity_config(mut self, identity_config: crate::openhuman::config::IdentityConfig) -> Self { self.identity_config = Some(identity_config); self } - pub fn skills(mut self, skills: Vec) -> Self { + pub fn skills(mut self, skills: Vec) -> Self { self.skills = Some(skills); self } @@ -150,7 +150,7 @@ impl AgentBuilder { pub fn classification_config( mut self, - classification_config: crate::alphahuman::config::QueryClassificationConfig, + classification_config: crate::openhuman::config::QueryClassificationConfig, ) -> Self { self.classification_config = Some(classification_config); self @@ -309,7 +309,7 @@ impl Agent { .classification_config(config.query_classification.clone()) .available_hints(available_hints) .identity_config(config.identity.clone()) - .skills(crate::alphahuman::skills::load_skills(&config.workspace_dir)) + .skills(crate::openhuman::skills::load_skills(&config.workspace_dir)) .auto_save(config.memory.auto_save) .build() } @@ -529,14 +529,14 @@ impl Agent { } pub async fn run_interactive(&mut self) -> Result<()> { - println!("🦀 Alphahuman Interactive Mode"); + println!("🦀 OpenHuman Interactive Mode"); println!("Type /quit to exit.\n"); let (tx, mut rx) = tokio::sync::mpsc::channel(32); - let cli = crate::alphahuman::channels::CliChannel::new(); + let cli = crate::openhuman::channels::CliChannel::new(); let listen_handle = tokio::spawn(async move { - let _ = crate::alphahuman::channels::Channel::listen(&cli, tx).await; + let _ = crate::openhuman::channels::Channel::listen(&cli, tx).await; }); while let Some(msg) = rx.recv().await { @@ -616,7 +616,7 @@ mod tests { use parking_lot::Mutex; struct MockProvider { - responses: Mutex>, + responses: Mutex>, } #[async_trait] @@ -636,10 +636,10 @@ mod tests { _request: ChatRequest<'_>, _model: &str, _temperature: f64, - ) -> Result { + ) -> Result { let mut guard = self.responses.lock(); if guard.is_empty() { - return Ok(crate::alphahuman::providers::ChatResponse { + return Ok(crate::openhuman::providers::ChatResponse { text: Some("done".into()), tool_calls: vec![], }); @@ -664,8 +664,8 @@ mod tests { serde_json::json!({"type": "object"}) } - async fn execute(&self, _args: serde_json::Value) -> Result { - Ok(crate::alphahuman::tools::ToolResult { + async fn execute(&self, _args: serde_json::Value) -> Result { + Ok(crate::openhuman::tools::ToolResult { success: true, output: "tool-out".into(), error: None, @@ -676,21 +676,21 @@ mod tests { #[tokio::test] async fn turn_without_tools_returns_text() { let provider = Box::new(MockProvider { - responses: Mutex::new(vec![crate::alphahuman::providers::ChatResponse { + responses: Mutex::new(vec![crate::openhuman::providers::ChatResponse { text: Some("hello".into()), tool_calls: vec![], }]), }); - let memory_cfg = crate::alphahuman::config::MemoryConfig { + let memory_cfg = crate::openhuman::config::MemoryConfig { backend: "none".into(), - ..crate::alphahuman::config::MemoryConfig::default() + ..crate::openhuman::config::MemoryConfig::default() }; let mem: Arc = Arc::from( - crate::alphahuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), + crate::openhuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), ); - let observer: Arc = Arc::from(crate::alphahuman::observability::NoopObserver {}); + let observer: Arc = Arc::from(crate::openhuman::observability::NoopObserver {}); let mut agent = Agent::builder() .provider(provider) .tools(vec![Box::new(MockTool)]) @@ -709,30 +709,30 @@ mod tests { async fn turn_with_native_dispatcher_handles_tool_results_variant() { let provider = Box::new(MockProvider { responses: Mutex::new(vec![ - crate::alphahuman::providers::ChatResponse { + crate::openhuman::providers::ChatResponse { text: Some(String::new()), - tool_calls: vec![crate::alphahuman::providers::ToolCall { + tool_calls: vec![crate::openhuman::providers::ToolCall { id: "tc1".into(), name: "echo".into(), arguments: "{}".into(), }], }, - crate::alphahuman::providers::ChatResponse { + crate::openhuman::providers::ChatResponse { text: Some("done".into()), tool_calls: vec![], }, ]), }); - let memory_cfg = crate::alphahuman::config::MemoryConfig { + let memory_cfg = crate::openhuman::config::MemoryConfig { backend: "none".into(), - ..crate::alphahuman::config::MemoryConfig::default() + ..crate::openhuman::config::MemoryConfig::default() }; let mem: Arc = Arc::from( - crate::alphahuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), + crate::openhuman::memory::create_memory(&memory_cfg, std::path::Path::new("/tmp"), None).unwrap(), ); - let observer: Arc = Arc::from(crate::alphahuman::observability::NoopObserver {}); + let observer: Arc = Arc::from(crate::openhuman::observability::NoopObserver {}); let mut agent = Agent::builder() .provider(provider) .tools(vec![Box::new(MockTool)]) diff --git a/src-tauri/src/alphahuman/agent/classifier.rs b/src-tauri/src/openhuman/agent/classifier.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/classifier.rs rename to src-tauri/src/openhuman/agent/classifier.rs index e2cf6e8ca..3211f679e 100644 --- a/src-tauri/src/alphahuman/agent/classifier.rs +++ b/src-tauri/src/openhuman/agent/classifier.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::config::schema::QueryClassificationConfig; +use crate::openhuman::config::schema::QueryClassificationConfig; /// Classify a user message against the configured rules and return the /// matching hint string, if any. @@ -50,7 +50,7 @@ pub fn classify(config: &QueryClassificationConfig, message: &str) -> Option) -> QueryClassificationConfig { QueryClassificationConfig { enabled, rules } diff --git a/src-tauri/src/alphahuman/agent/dispatcher.rs b/src-tauri/src/openhuman/agent/dispatcher.rs similarity index 98% rename from src-tauri/src/alphahuman/agent/dispatcher.rs rename to src-tauri/src/openhuman/agent/dispatcher.rs index f3024fa85..2592ff090 100644 --- a/src-tauri/src/alphahuman/agent/dispatcher.rs +++ b/src-tauri/src/openhuman/agent/dispatcher.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::providers::{ChatMessage, ChatResponse, ConversationMessage, ToolResultMessage}; -use crate::alphahuman::tools::{Tool, ToolSpec}; +use crate::openhuman::providers::{ChatMessage, ChatResponse, ConversationMessage, ToolResultMessage}; +use crate::openhuman::tools::{Tool, ToolSpec}; use serde_json::Value; use std::fmt::Write; @@ -254,7 +254,7 @@ mod tests { fn native_dispatcher_roundtrip() { let response = ChatResponse { text: Some("ok".into()), - tool_calls: vec![crate::alphahuman::providers::ToolCall { + tool_calls: vec![crate::openhuman::providers::ToolCall { id: "tc1".into(), name: "file_read".into(), arguments: "{\"path\":\"a.txt\"}".into(), diff --git a/src-tauri/src/alphahuman/agent/loop_.rs b/src-tauri/src/openhuman/agent/loop_.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/loop_.rs rename to src-tauri/src/openhuman/agent/loop_.rs index 97b6d2f97..3d8a9a308 100644 --- a/src-tauri/src/alphahuman/agent/loop_.rs +++ b/src-tauri/src/openhuman/agent/loop_.rs @@ -1,15 +1,15 @@ -use crate::alphahuman::approval::{ApprovalManager, ApprovalRequest, ApprovalResponse}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; -use crate::alphahuman::multimodal; -use crate::alphahuman::observability::{self, Observer, ObserverEvent}; -use crate::alphahuman::providers::{ +use crate::openhuman::approval::{ApprovalManager, ApprovalRequest, ApprovalResponse}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::multimodal; +use crate::openhuman::observability::{self, Observer, ObserverEvent}; +use crate::openhuman::providers::{ self, ChatMessage, ChatRequest, Provider, ProviderCapabilityError, ToolCall, }; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools::{self, Tool}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools::{self, Tool}; +use crate::openhuman::util::truncate_with_ellipsis; use anyhow::Result; use regex::{Regex, RegexSet}; use std::fmt::Write; @@ -238,7 +238,7 @@ async fn build_context(mem: &dyn Memory, user_msg: &str, min_relevance_score: f6 /// Build hardware datasheet context from RAG when peripherals are enabled. /// Includes pin-alias lookup (e.g. "red_led" → 13) when query matches, plus retrieved chunks. fn build_hardware_context( - rag: &crate::alphahuman::rag::HardwareRag, + rag: &crate::openhuman::rag::HardwareRag, user_msg: &str, boards: &[String], chunk_limit: usize, @@ -737,7 +737,7 @@ fn parse_tool_calls(response: &str) -> (String, Vec) { // (e.g., in emails, files, or web pages) could include JSON that mimics a // tool call. Tool calls MUST be explicitly wrapped in either: // 1. OpenAI-style JSON with a "tool_calls" array - // 2. Alphahuman tool-call tags (, , ) + // 2. OpenHuman tool-call tags (, , ) // 3. Markdown code blocks with tool_call/toolcall/tool-call language // 4. Explicit GLM line-based call formats (e.g. `shell/command>...`) // This ensures only the LLM's intentional tool calls are executed. @@ -829,7 +829,7 @@ pub(crate) async fn agent_turn( model: &str, temperature: f64, silent: bool, - multimodal_config: &crate::alphahuman::config::MultimodalConfig, + multimodal_config: &crate::openhuman::config::MultimodalConfig, max_tool_iterations: usize, ) -> Result { run_tool_call_loop( @@ -864,7 +864,7 @@ pub(crate) async fn run_tool_call_loop( silent: bool, approval: Option<&ApprovalManager>, channel_name: &str, - multimodal_config: &crate::alphahuman::config::MultimodalConfig, + multimodal_config: &crate::openhuman::config::MultimodalConfig, max_tool_iterations: usize, on_delta: Option>, ) -> Result { @@ -874,7 +874,7 @@ pub(crate) async fn run_tool_call_loop( max_tool_iterations }; - let tool_specs: Vec = + let tool_specs: Vec = tools_registry.iter().map(|tool| tool.spec()).collect(); let use_native_tools = provider.supports_native_tools() && !tool_specs.is_empty(); @@ -966,7 +966,7 @@ pub(crate) async fn run_tool_call_loop( model: model.to_string(), duration: llm_started_at.elapsed(), success: false, - error_message: Some(crate::alphahuman::providers::sanitize_api_error(&e.to_string())), + error_message: Some(crate::openhuman::providers::sanitize_api_error(&e.to_string())), }); return Err(e); } @@ -1195,7 +1195,7 @@ pub async fn run( ); let peripheral_tools: Vec> = - crate::alphahuman::peripherals::create_peripheral_tools(&config.peripherals).await?; + crate::openhuman::peripherals::create_peripheral_tools(&config.peripherals).await?; if !peripheral_tools.is_empty() { tracing::info!(count = peripheral_tools.len(), "Peripheral tools added"); tools_registry.extend(peripheral_tools); @@ -1214,7 +1214,7 @@ pub async fn run( let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -1235,14 +1235,14 @@ pub async fn run( }); // ── Hardware RAG (datasheet retrieval when peripherals + datasheet_dir) ── - let hardware_rag: Option = config + let hardware_rag: Option = config .peripherals .datasheet_dir .as_ref() .filter(|d| !d.trim().is_empty()) - .map(|dir| crate::alphahuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) + .map(|dir| crate::openhuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) .and_then(Result::ok) - .filter(|r: &crate::alphahuman::rag::HardwareRag| !r.is_empty()); + .filter(|r: &crate::openhuman::rag::HardwareRag| !r.is_empty()); if let Some(ref rag) = hardware_rag { tracing::info!(chunks = rag.len(), "Hardware RAG loaded"); } @@ -1255,7 +1255,7 @@ pub async fn run( .collect(); // ── Build system prompt from workspace MD files (OpenClaw framework) ── - let skills = crate::alphahuman::skills::load_skills(&config.workspace_dir); + let skills = crate::openhuman::skills::load_skills(&config.workspace_dir); let mut tool_descs: Vec<(&str, &str)> = vec![ ( "shell", @@ -1341,7 +1341,7 @@ pub async fn run( )); tool_descs.push(( "arduino_upload", - "Upload agent-generated Arduino sketch. Use when: user asks for 'make a heart', 'blink pattern', or custom LED behavior on Arduino. You write the full .ino code; Alphahuman compiles and uploads it. Pin 13 = built-in LED on Uno.", + "Upload agent-generated Arduino sketch. Use when: user asks for 'make a heart', 'blink pattern', or custom LED behavior on Arduino. You write the full .ino code; OpenHuman compiles and uploads it. Pin 13 = built-in LED on Uno.", )); tool_descs.push(( "hardware_memory_map", @@ -1365,7 +1365,7 @@ pub async fn run( } else { None }; - let mut system_prompt = crate::alphahuman::channels::build_system_prompt( + let mut system_prompt = crate::openhuman::channels::build_system_prompt( &config.workspace_dir, model_name, &tool_descs, @@ -1443,9 +1443,9 @@ pub async fn run( .await; } } else { - println!("🦀 Alphahuman Interactive Mode"); + println!("🦀 OpenHuman Interactive Mode"); println!("Type /help for commands.\n"); - let cli = crate::alphahuman::channels::CliChannel::new(); + let cli = crate::openhuman::channels::CliChannel::new(); // Persistent conversation history across turns let mut history = vec![ChatMessage::system(&system_prompt)]; @@ -1565,9 +1565,9 @@ pub async fn run( } }; final_output = response.clone(); - if let Err(e) = crate::alphahuman::channels::Channel::send( + if let Err(e) = crate::openhuman::channels::Channel::send( &cli, - &crate::alphahuman::channels::traits::SendMessage::new(format!("\n{response}\n"), "user"), + &crate::openhuman::channels::traits::SendMessage::new(format!("\n{response}\n"), "user"), ) .await { @@ -1655,7 +1655,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { &config, ); let peripheral_tools: Vec> = - crate::alphahuman::peripherals::create_peripheral_tools(&config.peripherals).await?; + crate::openhuman::peripherals::create_peripheral_tools(&config.peripherals).await?; tools_registry.extend(peripheral_tools); let provider_name = config.default_provider.as_deref().unwrap_or("openrouter"); @@ -1665,7 +1665,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { .unwrap_or_else(|| "anthropic/claude-sonnet-4-20250514".into()); let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -1679,14 +1679,14 @@ pub async fn process_message(config: Config, message: &str) -> Result { &provider_runtime_options, )?; - let hardware_rag: Option = config + let hardware_rag: Option = config .peripherals .datasheet_dir .as_ref() .filter(|d| !d.trim().is_empty()) - .map(|dir| crate::alphahuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) + .map(|dir| crate::openhuman::rag::HardwareRag::load(&config.workspace_dir, dir.trim())) .and_then(Result::ok) - .filter(|r: &crate::alphahuman::rag::HardwareRag| !r.is_empty()); + .filter(|r: &crate::openhuman::rag::HardwareRag| !r.is_empty()); let board_names: Vec = config .peripherals .boards @@ -1694,7 +1694,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { .map(|b| b.board.clone()) .collect(); - let skills = crate::alphahuman::skills::load_skills(&config.workspace_dir); + let skills = crate::openhuman::skills::load_skills(&config.workspace_dir); let mut tool_descs: Vec<(&str, &str)> = vec![ ("shell", "Execute terminal commands."), ("file_read", "Read file contents."), @@ -1719,7 +1719,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { )); tool_descs.push(( "arduino_upload", - "Upload Arduino sketch. Use for 'make a heart', custom patterns. You write full .ino code; Alphahuman uploads it.", + "Upload Arduino sketch. Use for 'make a heart', custom patterns. You write full .ino code; OpenHuman uploads it.", )); tool_descs.push(( "hardware_memory_map", @@ -1743,7 +1743,7 @@ pub async fn process_message(config: Config, message: &str) -> Result { } else { None }; - let mut system_prompt = crate::alphahuman::channels::build_system_prompt( + let mut system_prompt = crate::openhuman::channels::build_system_prompt( &config.workspace_dir, &model_name, &tool_descs, @@ -1812,10 +1812,10 @@ mod tests { assert!(scrubbed.contains("\"api_key\": \"sk-1*[REDACTED]\"")); assert!(scrubbed.contains("public")); } - use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; - use crate::alphahuman::observability::NoopObserver; - use crate::alphahuman::providers::traits::ProviderCapabilities; - use crate::alphahuman::providers::ChatResponse; + use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; + use crate::openhuman::observability::NoopObserver; + use crate::openhuman::providers::traits::ProviderCapabilities; + use crate::openhuman::providers::ChatResponse; use tempfile::TempDir; struct NonVisionProvider { @@ -1867,7 +1867,7 @@ mod tests { _temperature: f64, ) -> anyhow::Result { self.calls.fetch_add(1, Ordering::SeqCst); - let marker_count = crate::alphahuman::multimodal::count_image_markers(request.messages); + let marker_count = crate::openhuman::multimodal::count_image_markers(request.messages); if marker_count == 0 { anyhow::bail!("expected image markers in request messages"); } @@ -1907,7 +1907,7 @@ mod tests { true, None, "cli", - &crate::alphahuman::config::MultimodalConfig::default(), + &crate::openhuman::config::MultimodalConfig::default(), 3, None, ) @@ -1933,7 +1933,7 @@ mod tests { let tools_registry: Vec> = Vec::new(); let observer = NoopObserver; - let multimodal = crate::alphahuman::config::MultimodalConfig { + let multimodal = crate::openhuman::config::MultimodalConfig { max_images: 4, max_image_size_mb: 1, allow_remote_fetch: false, @@ -1987,7 +1987,7 @@ mod tests { true, None, "cli", - &crate::alphahuman::config::MultimodalConfig::default(), + &crate::openhuman::config::MultimodalConfig::default(), 3, None, ) @@ -2305,9 +2305,9 @@ Done."#; #[test] fn build_tool_instructions_includes_all_tools() { - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; let security = Arc::new(SecurityPolicy::from_config( - &crate::alphahuman::config::AutonomyConfig::default(), + &crate::openhuman::config::AutonomyConfig::default(), std::path::Path::new("/tmp"), )); let tools = tools::default_tools(security); @@ -2322,9 +2322,9 @@ Done."#; #[test] fn tools_to_openai_format_produces_valid_schema() { - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; let security = Arc::new(SecurityPolicy::from_config( - &crate::alphahuman::config::AutonomyConfig::default(), + &crate::openhuman::config::AutonomyConfig::default(), std::path::Path::new("/tmp"), )); let tools = tools::default_tools(security); @@ -2880,14 +2880,14 @@ Let me check the result."#; #[test] fn trim_history_empty_history() { - let mut history: Vec = vec![]; + let mut history: Vec = vec![]; trim_history(&mut history, 10); assert!(history.is_empty()); } #[test] fn trim_history_system_only() { - let mut history = vec![crate::alphahuman::providers::ChatMessage::system("system prompt")]; + let mut history = vec![crate::openhuman::providers::ChatMessage::system("system prompt")]; trim_history(&mut history, 10); assert_eq!(history.len(), 1); assert_eq!(history[0].role, "system"); @@ -2896,9 +2896,9 @@ Let me check the result."#; #[test] fn trim_history_exactly_at_limit() { let mut history = vec![ - crate::alphahuman::providers::ChatMessage::system("system"), - crate::alphahuman::providers::ChatMessage::user("msg 1"), - crate::alphahuman::providers::ChatMessage::assistant("reply 1"), + crate::openhuman::providers::ChatMessage::system("system"), + crate::openhuman::providers::ChatMessage::user("msg 1"), + crate::openhuman::providers::ChatMessage::assistant("reply 1"), ]; trim_history(&mut history, 2); // 2 non-system messages = exactly at limit assert_eq!(history.len(), 3, "should not trim when exactly at limit"); @@ -2907,11 +2907,11 @@ Let me check the result."#; #[test] fn trim_history_removes_oldest_non_system() { let mut history = vec![ - crate::alphahuman::providers::ChatMessage::system("system"), - crate::alphahuman::providers::ChatMessage::user("old msg"), - crate::alphahuman::providers::ChatMessage::assistant("old reply"), - crate::alphahuman::providers::ChatMessage::user("new msg"), - crate::alphahuman::providers::ChatMessage::assistant("new reply"), + crate::openhuman::providers::ChatMessage::system("system"), + crate::openhuman::providers::ChatMessage::user("old msg"), + crate::openhuman::providers::ChatMessage::assistant("old reply"), + crate::openhuman::providers::ChatMessage::user("new msg"), + crate::openhuman::providers::ChatMessage::assistant("new reply"), ]; trim_history(&mut history, 2); assert_eq!(history.len(), 3); // system + 2 kept diff --git a/src-tauri/src/alphahuman/agent/memory_loader.rs b/src-tauri/src/openhuman/agent/memory_loader.rs similarity index 96% rename from src-tauri/src/alphahuman/agent/memory_loader.rs rename to src-tauri/src/openhuman/agent/memory_loader.rs index d5f4e41b0..d9556b6a9 100644 --- a/src-tauri/src/alphahuman/agent/memory_loader.rs +++ b/src-tauri/src/openhuman/agent/memory_loader.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::memory::Memory; +use crate::openhuman::memory::Memory; use async_trait::async_trait; use std::fmt::Write; @@ -66,7 +66,7 @@ impl MemoryLoader for DefaultMemoryLoader { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; + use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; struct MockMemory; diff --git a/src-tauri/src/alphahuman/agent/mod.rs b/src-tauri/src/openhuman/agent/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/agent/mod.rs rename to src-tauri/src/openhuman/agent/mod.rs diff --git a/src-tauri/src/alphahuman/agent/prompt.rs b/src-tauri/src/openhuman/agent/prompt.rs similarity index 95% rename from src-tauri/src/alphahuman/agent/prompt.rs rename to src-tauri/src/openhuman/agent/prompt.rs index f2846dcb4..e696f0be9 100644 --- a/src-tauri/src/alphahuman/agent/prompt.rs +++ b/src-tauri/src/openhuman/agent/prompt.rs @@ -1,7 +1,7 @@ -use crate::alphahuman::config::IdentityConfig; -use crate::alphahuman::identity; -use crate::alphahuman::skills::Skill; -use crate::alphahuman::tools::Tool; +use crate::openhuman::config::IdentityConfig; +use crate::openhuman::identity; +use crate::openhuman::skills::Skill; +use crate::openhuman::tools::Tool; use anyhow::Result; use chrono::Local; use std::fmt::Write; @@ -259,7 +259,7 @@ fn inject_workspace_file(prompt: &mut String, workspace_dir: &Path, filename: &s #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::tools::traits::Tool; + use crate::openhuman::tools::traits::Tool; use async_trait::async_trait; struct TestTool; @@ -281,8 +281,8 @@ mod tests { async fn execute( &self, _args: serde_json::Value, - ) -> anyhow::Result { - Ok(crate::alphahuman::tools::ToolResult { + ) -> anyhow::Result { + Ok(crate::openhuman::tools::ToolResult { success: true, output: "ok".into(), error: None, @@ -293,7 +293,7 @@ mod tests { #[test] fn identity_section_with_aieos_includes_workspace_files() { let workspace = - std::env::temp_dir().join(format!("alphahuman_prompt_test_{}", uuid::Uuid::new_v4())); + std::env::temp_dir().join(format!("openhuman_prompt_test_{}", uuid::Uuid::new_v4())); std::fs::create_dir_all(&workspace).unwrap(); std::fs::write( workspace.join("AGENTS.md"), @@ -301,7 +301,7 @@ mod tests { ) .unwrap(); - let identity_config = crate::alphahuman::config::IdentityConfig { + let identity_config = crate::openhuman::config::IdentityConfig { format: "aieos".into(), aieos_path: None, aieos_inline: Some(r#"{"identity":{"names":{"first":"Nova"}}}"#.into()), diff --git a/src-tauri/src/alphahuman/agent/tests.rs b/src-tauri/src/openhuman/agent/tests.rs similarity index 99% rename from src-tauri/src/alphahuman/agent/tests.rs rename to src-tauri/src/openhuman/agent/tests.rs index 5cc044294..6a5aa3666 100644 --- a/src-tauri/src/alphahuman/agent/tests.rs +++ b/src-tauri/src/openhuman/agent/tests.rs @@ -24,18 +24,18 @@ //! 19. Builder validation (missing required fields) //! 20. Idempotent system prompt insertion -use crate::alphahuman::agent::agent::Agent; -use crate::alphahuman::agent::dispatcher::{ +use crate::openhuman::agent::agent::Agent; +use crate::openhuman::agent::dispatcher::{ NativeToolDispatcher, ToolDispatcher, ToolExecutionResult, XmlToolDispatcher, }; -use crate::alphahuman::config::{AgentConfig, MemoryConfig}; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::observability::{NoopObserver, Observer}; -use crate::alphahuman::providers::{ +use crate::openhuman::config::{AgentConfig, MemoryConfig}; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::observability::{NoopObserver, Observer}; +use crate::openhuman::providers::{ ChatMessage, ChatRequest, ChatResponse, ConversationMessage, Provider, ToolCall, ToolResultMessage, }; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::tools::{Tool, ToolResult}; use anyhow::Result; use async_trait::async_trait; use std::sync::{Arc, Mutex}; diff --git a/src-tauri/src/alphahuman/agent/traits.rs b/src-tauri/src/openhuman/agent/traits.rs similarity index 99% rename from src-tauri/src/alphahuman/agent/traits.rs rename to src-tauri/src/openhuman/agent/traits.rs index a30599b52..3565379c5 100644 --- a/src-tauri/src/alphahuman/agent/traits.rs +++ b/src-tauri/src/openhuman/agent/traits.rs @@ -1,4 +1,4 @@ -//! Core agent traits ported from Alphahuman. +//! Core agent traits ported from OpenHuman. //! //! Each trait defines an extension point. Noop implementations are provided //! as test doubles and reference implementations. diff --git a/src-tauri/src/alphahuman/approval/mod.rs b/src-tauri/src/openhuman/approval/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/approval/mod.rs rename to src-tauri/src/openhuman/approval/mod.rs index 874e6666a..6f36f4bbd 100644 --- a/src-tauri/src/alphahuman/approval/mod.rs +++ b/src-tauri/src/openhuman/approval/mod.rs @@ -3,8 +3,8 @@ //! Provides a pre-execution hook that prompts the user before tool calls, //! with session-scoped "Always" allowlists and audit logging. -use crate::alphahuman::config::AutonomyConfig; -use crate::alphahuman::security::AutonomyLevel; +use crate::openhuman::config::AutonomyConfig; +use crate::openhuman::security::AutonomyLevel; use chrono::Utc; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; @@ -219,7 +219,7 @@ fn truncate_for_summary(input: &str, max_chars: usize) -> String { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::AutonomyConfig; + use crate::openhuman::config::AutonomyConfig; fn supervised_config() -> AutonomyConfig { AutonomyConfig { diff --git a/src-tauri/src/alphahuman/channels/cli.rs b/src-tauri/src/openhuman/channels/cli.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/cli.rs rename to src-tauri/src/openhuman/channels/cli.rs diff --git a/src-tauri/src/alphahuman/channels/commands.rs b/src-tauri/src/openhuman/channels/commands.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/commands.rs rename to src-tauri/src/openhuman/channels/commands.rs index 1f3de2fdd..8068364cc 100644 --- a/src-tauri/src/alphahuman/channels/commands.rs +++ b/src-tauri/src/openhuman/channels/commands.rs @@ -18,7 +18,7 @@ use super::whatsapp::WhatsAppChannel; #[cfg(feature = "whatsapp-web")] use super::whatsapp_web::WhatsAppWebChannel; use super::Channel; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use std::sync::Arc; use std::time::Duration; @@ -235,7 +235,7 @@ pub async fn doctor_channels(config: Config) -> Result<()> { return Ok(()); } - println!("🩺 Alphahuman Channel Doctor"); + println!("🩺 OpenHuman Channel Doctor"); println!(); let mut healthy = 0_u32; diff --git a/src-tauri/src/alphahuman/channels/context.rs b/src-tauri/src/openhuman/channels/context.rs similarity index 92% rename from src-tauri/src/alphahuman/channels/context.rs rename to src-tauri/src/openhuman/channels/context.rs index ab4146d7c..ab2141254 100644 --- a/src-tauri/src/alphahuman/channels/context.rs +++ b/src-tauri/src/openhuman/channels/context.rs @@ -1,10 +1,10 @@ //! Shared channel runtime state and memory helpers. -use crate::alphahuman::memory::Memory; -use crate::alphahuman::observability::Observer; -use crate::alphahuman::providers::{ChatMessage, Provider}; -use crate::alphahuman::tools::Tool; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::memory::Memory; +use crate::openhuman::observability::Observer; +use crate::openhuman::providers::{ChatMessage, Provider}; +use crate::openhuman::tools::Tool; +use crate::openhuman::util::truncate_with_ellipsis; use std::collections::HashMap; use std::path::PathBuf; use std::sync::{Arc, Mutex}; @@ -62,11 +62,11 @@ pub(crate) struct ChannelRuntimeContext { pub(crate) route_overrides: RouteSelectionMap, pub(crate) api_key: Option, pub(crate) api_url: Option, - pub(crate) reliability: Arc, - pub(crate) provider_runtime_options: crate::alphahuman::providers::ProviderRuntimeOptions, + pub(crate) reliability: Arc, + pub(crate) provider_runtime_options: crate::openhuman::providers::ProviderRuntimeOptions, pub(crate) workspace_dir: Arc, pub(crate) message_timeout_secs: u64, - pub(crate) multimodal: crate::alphahuman::config::MultimodalConfig, + pub(crate) multimodal: crate::openhuman::config::MultimodalConfig, } pub(crate) fn conversation_memory_key(msg: &super::traits::ChannelMessage) -> String { diff --git a/src-tauri/src/alphahuman/channels/dingtalk.rs b/src-tauri/src/openhuman/channels/dingtalk.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/dingtalk.rs rename to src-tauri/src/openhuman/channels/dingtalk.rs index 6c9715b4f..a1af78641 100644 --- a/src-tauri/src/alphahuman/channels/dingtalk.rs +++ b/src-tauri/src/openhuman/channels/dingtalk.rs @@ -38,7 +38,7 @@ impl DingTalkChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.dingtalk") + crate::openhuman::config::build_runtime_proxy_client("channel.dingtalk") } fn is_user_allowed(&self, user_id: &str) -> bool { @@ -121,7 +121,7 @@ impl Channel for DingTalkChannel { ) })?; - let title = message.subject.as_deref().unwrap_or("Alphahuman"); + let title = message.subject.as_deref().unwrap_or("OpenHuman"); let body = serde_json::json!({ "msgtype": "markdown", "markdown": { @@ -330,7 +330,7 @@ client_id = "app_id_123" client_secret = "secret_456" allowed_users = ["user1", "*"] "#; - let config: crate::alphahuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); assert_eq!(config.client_id, "app_id_123"); assert_eq!(config.client_secret, "secret_456"); assert_eq!(config.allowed_users, vec!["user1", "*"]); @@ -342,7 +342,7 @@ allowed_users = ["user1", "*"] client_id = "id" client_secret = "secret" "#; - let config: crate::alphahuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::DingTalkConfig = toml::from_str(toml_str).unwrap(); assert!(config.allowed_users.is_empty()); } diff --git a/src-tauri/src/alphahuman/channels/discord.rs b/src-tauri/src/openhuman/channels/discord.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/discord.rs rename to src-tauri/src/openhuman/channels/discord.rs index ed8eb7a1b..0671ae40b 100644 --- a/src-tauri/src/alphahuman/channels/discord.rs +++ b/src-tauri/src/openhuman/channels/discord.rs @@ -35,7 +35,7 @@ impl DiscordChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.discord") + crate::openhuman::config::build_runtime_proxy_client("channel.discord") } /// Check if a Discord user ID is in the allowlist. @@ -267,8 +267,8 @@ impl Channel for DiscordChannel { "intents": 37377, // GUILDS | GUILD_MESSAGES | MESSAGE_CONTENT | DIRECT_MESSAGES "properties": { "os": "linux", - "browser": "alphahuman", - "device": "alphahuman" + "browser": "openhuman", + "device": "openhuman" } } }); diff --git a/src-tauri/src/alphahuman/channels/email_channel.rs b/src-tauri/src/openhuman/channels/email_channel.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/email_channel.rs rename to src-tauri/src/openhuman/channels/email_channel.rs index 91e9db397..241bb0676 100644 --- a/src-tauri/src/alphahuman/channels/email_channel.rs +++ b/src-tauri/src/openhuman/channels/email_channel.rs @@ -509,10 +509,10 @@ impl Channel for EmailChannel { if let Some(pos) = message.content.find('\n') { (&message.content[9..pos], message.content[pos + 1..].trim()) } else { - ("Alphahuman Message", message.content.as_str()) + ("OpenHuman Message", message.content.as_str()) } } else { - ("Alphahuman Message", message.content.as_str()) + ("OpenHuman Message", message.content.as_str()) }; let email = Message::builder() diff --git a/src-tauri/src/alphahuman/channels/imessage.rs b/src-tauri/src/openhuman/channels/imessage.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/imessage.rs rename to src-tauri/src/openhuman/channels/imessage.rs index 816e4bcc8..3e0f0acde 100644 --- a/src-tauri/src/alphahuman/channels/imessage.rs +++ b/src-tauri/src/openhuman/channels/imessage.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use directories::UserDirs; use rusqlite::{Connection, OpenFlags}; diff --git a/src-tauri/src/alphahuman/channels/irc.rs b/src-tauri/src/openhuman/channels/irc.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/irc.rs rename to src-tauri/src/openhuman/channels/irc.rs index 49ca9dc21..eb4ce6390 100644 --- a/src-tauri/src/alphahuman/channels/irc.rs +++ b/src-tauri/src/openhuman/channels/irc.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; @@ -18,7 +18,7 @@ static MSG_SEQ: AtomicU64 = AtomicU64::new(0); /// IRC over TLS channel. /// /// Connects to an IRC server using TLS, joins configured channels, -/// and forwards PRIVMSG messages to the `Alphahuman` message bus. +/// and forwards PRIVMSG messages to the `OpenHuman` message bus. /// Supports both channel messages and private messages (DMs). pub struct IrcChannel { server: String, @@ -395,7 +395,7 @@ impl Channel for IrcChannel { Self::send_raw(&mut writer, &format!("NICK {current_nick}")).await?; Self::send_raw( &mut writer, - &format!("USER {} 0 * :Alphahuman", self.username), + &format!("USER {} 0 * :OpenHuman", self.username), ) .await?; @@ -919,7 +919,7 @@ mod tests { server: "irc.example.com".into(), port: 6697, nickname: "zcbot".into(), - username: Some("alphahuman".into()), + username: Some("openhuman".into()), channels: vec!["#test".into()], allowed_users: vec!["alice".into()], server_password: Some("serverpass".into()), @@ -930,7 +930,7 @@ mod tests { assert_eq!(ch.server, "irc.example.com"); assert_eq!(ch.port, 6697); assert_eq!(ch.nickname, "zcbot"); - assert_eq!(ch.username, "alphahuman"); + assert_eq!(ch.username, "openhuman"); assert_eq!(ch.channels, vec!["#test"]); assert_eq!(ch.allowed_users, vec!["alice"]); assert_eq!(ch.server_password.as_deref(), Some("serverpass")); @@ -943,13 +943,13 @@ mod tests { #[test] fn irc_config_serde_roundtrip() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let config = IrcConfig { server: "irc.example.com".into(), port: 6697, nickname: "zcbot".into(), - username: Some("alphahuman".into()), + username: Some("openhuman".into()), channels: vec!["#test".into(), "#dev".into()], allowed_users: vec!["alice".into()], server_password: None, @@ -963,7 +963,7 @@ mod tests { assert_eq!(parsed.server, "irc.example.com"); assert_eq!(parsed.port, 6697); assert_eq!(parsed.nickname, "zcbot"); - assert_eq!(parsed.username.as_deref(), Some("alphahuman")); + assert_eq!(parsed.username.as_deref(), Some("openhuman")); assert_eq!(parsed.channels, vec!["#test", "#dev"]); assert_eq!(parsed.allowed_users, vec!["alice"]); assert!(parsed.server_password.is_none()); @@ -974,7 +974,7 @@ mod tests { #[test] fn irc_config_minimal_toml() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let toml_str = r#" server = "irc.example.com" @@ -995,7 +995,7 @@ nickname = "bot" #[test] fn irc_config_default_port() { - use crate::alphahuman::config::schema::IrcConfig; + use crate::openhuman::config::schema::IrcConfig; let json = r#"{"server":"irc.test","nickname":"bot"}"#; let parsed: IrcConfig = serde_json::from_str(json).unwrap(); @@ -1010,7 +1010,7 @@ nickname = "bot" port: 6697, nickname: "zcbot".into(), username: None, - channels: vec!["#alphahuman".into()], + channels: vec!["#openhuman".into()], allowed_users: vec!["*".into()], server_password: None, nickserv_password: None, diff --git a/src-tauri/src/alphahuman/channels/lark.rs b/src-tauri/src/openhuman/channels/lark.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/lark.rs rename to src-tauri/src/openhuman/channels/lark.rs index fb8f5c08e..e60b80dfc 100644 --- a/src-tauri/src/alphahuman/channels/lark.rs +++ b/src-tauri/src/openhuman/channels/lark.rs @@ -147,7 +147,7 @@ pub struct LarkChannel { /// When true, use Feishu (CN) endpoints; when false, use Lark (international). use_feishu: bool, /// How to receive events: WebSocket long-connection or HTTP webhook. - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode, + receive_mode: crate::openhuman::config::schema::LarkReceiveMode, /// Cached tenant access token tenant_token: Arc>>, /// Dedup set: WS message_ids seen in last ~30 min to prevent double-dispatch @@ -169,14 +169,14 @@ impl LarkChannel { port, allowed_users, use_feishu: true, - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode::default(), + receive_mode: crate::openhuman::config::schema::LarkReceiveMode::default(), tenant_token: Arc::new(RwLock::new(None)), ws_seen_ids: Arc::new(RwLock::new(HashMap::new())), } } /// Build from `LarkConfig` (preserves `use_feishu` and `receive_mode`). - pub fn from_config(config: &crate::alphahuman::config::schema::LarkConfig) -> Self { + pub fn from_config(config: &crate::openhuman::config::schema::LarkConfig) -> Self { let mut ch = Self::new( config.app_id.clone(), config.app_secret.clone(), @@ -190,7 +190,7 @@ impl LarkChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.lark") + crate::openhuman::config::build_runtime_proxy_client("channel.lark") } fn api_base(&self) -> &'static str { @@ -698,7 +698,7 @@ impl Channel for LarkChannel { } async fn listen(&self, tx: tokio::sync::mpsc::Sender) -> anyhow::Result<()> { - use crate::alphahuman::config::schema::LarkReceiveMode; + use crate::openhuman::config::schema::LarkReceiveMode; match self.receive_mode { LarkReceiveMode::Websocket => self.listen_ws(tx).await, LarkReceiveMode::Webhook => self.listen_http(tx).await, @@ -983,7 +983,7 @@ mod tests { }, "message": { "message_type": "text", - "content": "{\"text\":\"Hello Alphahuman!\"}", + "content": "{\"text\":\"Hello OpenHuman!\"}", "chat_id": "oc_chat123", "create_time": "1699999999000" } @@ -992,7 +992,7 @@ mod tests { let msgs = ch.parse_event_payload(&payload); assert_eq!(msgs.len(), 1); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].sender, "oc_chat123"); assert_eq!(msgs[0].channel, "lark"); assert_eq!(msgs[0].timestamp, 1_699_999_999); @@ -1169,7 +1169,7 @@ mod tests { #[test] fn lark_config_serde() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let lc = LarkConfig { app_id: "cli_app123".into(), app_secret: "secret456".into(), @@ -1190,7 +1190,7 @@ mod tests { #[test] fn lark_config_toml_roundtrip() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let lc = LarkConfig { app_id: "app".into(), app_secret: "secret".into(), @@ -1210,7 +1210,7 @@ mod tests { #[test] fn lark_config_defaults_optional_fields() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let json = r#"{"app_id":"a","app_secret":"s"}"#; let parsed: LarkConfig = serde_json::from_str(json).unwrap(); assert!(parsed.verification_token.is_none()); @@ -1221,7 +1221,7 @@ mod tests { #[test] fn lark_from_config_preserves_mode_and_region() { - use crate::alphahuman::config::schema::{LarkConfig, LarkReceiveMode}; + use crate::openhuman::config::schema::{LarkConfig, LarkReceiveMode}; let cfg = LarkConfig { app_id: "cli_app123".into(), diff --git a/src-tauri/src/alphahuman/channels/linq.rs b/src-tauri/src/openhuman/channels/linq.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/linq.rs rename to src-tauri/src/openhuman/channels/linq.rs index e464fcc6e..3d79a2977 100644 --- a/src-tauri/src/alphahuman/channels/linq.rs +++ b/src-tauri/src/openhuman/channels/linq.rs @@ -451,7 +451,7 @@ mod tests { "id": "msg-abc", "parts": [{ "type": "text", - "value": "Hello Alphahuman!" + "value": "Hello OpenHuman!" }] } } @@ -460,7 +460,7 @@ mod tests { let msgs = ch.parse_webhook_payload(&payload); assert_eq!(msgs.len(), 1); assert_eq!(msgs[0].sender, "+1234567890"); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].channel, "linq"); assert_eq!(msgs[0].reply_target, "chat-789"); } diff --git a/src-tauri/src/alphahuman/channels/matrix.rs b/src-tauri/src/openhuman/channels/matrix.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/matrix.rs rename to src-tauri/src/openhuman/channels/matrix.rs index 43c66943c..28f1699ca 100644 --- a/src-tauri/src/alphahuman/channels/matrix.rs +++ b/src-tauri/src/openhuman/channels/matrix.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use matrix_sdk::{ authentication::matrix::MatrixSession, diff --git a/src-tauri/src/alphahuman/channels/mattermost.rs b/src-tauri/src/openhuman/channels/mattermost.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/mattermost.rs rename to src-tauri/src/openhuman/channels/mattermost.rs index 57b8ae9ad..9e9557b42 100644 --- a/src-tauri/src/alphahuman/channels/mattermost.rs +++ b/src-tauri/src/openhuman/channels/mattermost.rs @@ -42,7 +42,7 @@ impl MattermostChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.mattermost") + crate::openhuman::config::build_runtime_proxy_client("channel.mattermost") } /// Check if a user ID is in the allowlist. diff --git a/src-tauri/src/alphahuman/channels/mod.rs b/src-tauri/src/openhuman/channels/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/mod.rs rename to src-tauri/src/openhuman/channels/mod.rs diff --git a/src-tauri/src/alphahuman/channels/prompt.rs b/src-tauri/src/openhuman/channels/prompt.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/prompt.rs rename to src-tauri/src/openhuman/channels/prompt.rs index 0a4d291f2..384343cba 100644 --- a/src-tauri/src/alphahuman/channels/prompt.rs +++ b/src-tauri/src/openhuman/channels/prompt.rs @@ -1,6 +1,6 @@ //! System prompt construction for channel interactions. -use crate::alphahuman::identity; +use crate::openhuman::identity; use std::path::Path; /// Maximum characters per injected workspace file (matches `OpenClaw` default). @@ -52,8 +52,8 @@ pub fn build_system_prompt( workspace_dir: &Path, model_name: &str, tools: &[(&str, &str)], - skills: &[crate::alphahuman::skills::Skill], - identity_config: Option<&crate::alphahuman::config::IdentityConfig>, + skills: &[crate::openhuman::skills::Skill], + identity_config: Option<&crate::openhuman::config::IdentityConfig>, bootstrap_max_chars: Option, ) -> String { use std::fmt::Write; @@ -210,7 +210,7 @@ pub fn build_system_prompt( prompt.push_str("- If a tool output contains credentials, they have already been redacted — do not mention them.\n\n"); if prompt.is_empty() { - "You are AlphaHuman, a fast and efficient AI assistant built in Rust. Be helpful, concise, and direct.".to_string() + "You are OpenHuman, a fast and efficient AI assistant built in Rust. Be helpful, concise, and direct.".to_string() } else { prompt } diff --git a/src-tauri/src/alphahuman/channels/qq.rs b/src-tauri/src/openhuman/channels/qq.rs similarity index 98% rename from src-tauri/src/alphahuman/channels/qq.rs rename to src-tauri/src/openhuman/channels/qq.rs index 7a0c124d6..bc93612a7 100644 --- a/src-tauri/src/alphahuman/channels/qq.rs +++ b/src-tauri/src/openhuman/channels/qq.rs @@ -47,7 +47,7 @@ impl QQChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.qq") + crate::openhuman::config::build_runtime_proxy_client("channel.qq") } fn is_user_allowed(&self, user_id: &str) -> bool { @@ -258,8 +258,8 @@ impl Channel for QQChannel { "intents": intents, "properties": { "os": "linux", - "browser": "alphahuman", - "device": "alphahuman", + "browser": "openhuman", + "device": "openhuman", } } }); @@ -500,7 +500,7 @@ app_id = "12345" app_secret = "secret_abc" allowed_users = ["user1"] "#; - let config: crate::alphahuman::config::schema::QQConfig = toml::from_str(toml_str).unwrap(); + let config: crate::openhuman::config::schema::QQConfig = toml::from_str(toml_str).unwrap(); assert_eq!(config.app_id, "12345"); assert_eq!(config.app_secret, "secret_abc"); assert_eq!(config.allowed_users, vec!["user1"]); diff --git a/src-tauri/src/alphahuman/channels/routes.rs b/src-tauri/src/openhuman/channels/routes.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/routes.rs rename to src-tauri/src/openhuman/channels/routes.rs index 7d7aa1ba3..46bc2582e 100644 --- a/src-tauri/src/alphahuman/channels/routes.rs +++ b/src-tauri/src/openhuman/channels/routes.rs @@ -5,7 +5,7 @@ use super::context::{ }; use super::traits; use super::{Channel, SendMessage}; -use crate::alphahuman::providers::{self, Provider}; +use crate::openhuman::providers::{self, Provider}; use serde::Deserialize; use std::fmt::Write; use std::path::Path; diff --git a/src-tauri/src/alphahuman/channels/runtime/dispatch.rs b/src-tauri/src/openhuman/channels/runtime/dispatch.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/runtime/dispatch.rs rename to src-tauri/src/openhuman/channels/runtime/dispatch.rs index 167f74fc4..31e440fdb 100644 --- a/src-tauri/src/alphahuman/channels/runtime/dispatch.rs +++ b/src-tauri/src/openhuman/channels/runtime/dispatch.rs @@ -1,18 +1,18 @@ //! Channel runtime loop and message processing. -use crate::alphahuman::channels::context::{ +use crate::openhuman::channels::context::{ build_memory_context, compact_sender_history, conversation_history_key, conversation_memory_key, is_context_window_overflow_error, ChannelRuntimeContext, CHANNEL_TYPING_REFRESH_INTERVAL_SECS, MAX_CHANNEL_HISTORY, }; -use crate::alphahuman::channels::routes::{ +use crate::openhuman::channels::routes::{ get_or_create_provider, get_route_selection, handle_runtime_command_if_needed, }; -use crate::alphahuman::channels::traits; -use crate::alphahuman::channels::{Channel, SendMessage}; -use crate::alphahuman::agent::loop_::run_tool_call_loop; -use crate::alphahuman::providers::{self, ChatMessage}; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::traits; +use crate::openhuman::channels::{Channel, SendMessage}; +use crate::openhuman::agent::loop_::run_tool_call_loop; +use crate::openhuman::providers::{self, ChatMessage}; +use crate::openhuman::util::truncate_with_ellipsis; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio_util::sync::CancellationToken; @@ -110,7 +110,7 @@ pub(crate) async fn process_channel_message( .store( &autosave_key, &msg.content, - crate::alphahuman::memory::MemoryCategory::Conversation, + crate::openhuman::memory::MemoryCategory::Conversation, None, ) .await; diff --git a/src-tauri/src/alphahuman/channels/runtime/mod.rs b/src-tauri/src/openhuman/channels/runtime/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/runtime/mod.rs rename to src-tauri/src/openhuman/channels/runtime/mod.rs diff --git a/src-tauri/src/alphahuman/channels/runtime/startup.rs b/src-tauri/src/openhuman/channels/runtime/startup.rs similarity index 90% rename from src-tauri/src/alphahuman/channels/runtime/startup.rs rename to src-tauri/src/openhuman/channels/runtime/startup.rs index 9ea8009f9..ed489b700 100644 --- a/src-tauri/src/alphahuman/channels/runtime/startup.rs +++ b/src-tauri/src/openhuman/channels/runtime/startup.rs @@ -1,40 +1,40 @@ //! Channel startup wiring. -use crate::alphahuman::channels::context::{ +use crate::openhuman::channels::context::{ effective_channel_message_timeout_secs, ChannelRuntimeContext, DEFAULT_CHANNEL_INITIAL_BACKOFF_SECS, DEFAULT_CHANNEL_MAX_BACKOFF_SECS, }; use super::dispatch::run_message_dispatch_loop; use super::supervision::{compute_max_in_flight_messages, spawn_supervised_listener}; -use crate::alphahuman::agent::loop_::build_tool_instructions; -use crate::alphahuman::channels::dingtalk::DingTalkChannel; -use crate::alphahuman::channels::discord::DiscordChannel; -use crate::alphahuman::channels::email_channel::EmailChannel; -use crate::alphahuman::channels::imessage::IMessageChannel; -use crate::alphahuman::channels::irc; -use crate::alphahuman::channels::irc::IrcChannel; -use crate::alphahuman::channels::lark::LarkChannel; -use crate::alphahuman::channels::linq::LinqChannel; +use crate::openhuman::agent::loop_::build_tool_instructions; +use crate::openhuman::channels::dingtalk::DingTalkChannel; +use crate::openhuman::channels::discord::DiscordChannel; +use crate::openhuman::channels::email_channel::EmailChannel; +use crate::openhuman::channels::imessage::IMessageChannel; +use crate::openhuman::channels::irc; +use crate::openhuman::channels::irc::IrcChannel; +use crate::openhuman::channels::lark::LarkChannel; +use crate::openhuman::channels::linq::LinqChannel; #[cfg(feature = "channel-matrix")] -use crate::alphahuman::channels::matrix::MatrixChannel; -use crate::alphahuman::channels::mattermost::MattermostChannel; -use crate::alphahuman::channels::prompt::build_system_prompt; -use crate::alphahuman::channels::qq::QQChannel; -use crate::alphahuman::channels::signal::SignalChannel; -use crate::alphahuman::channels::slack::SlackChannel; -use crate::alphahuman::channels::telegram::TelegramChannel; -use crate::alphahuman::channels::traits; -use crate::alphahuman::channels::whatsapp::WhatsAppChannel; +use crate::openhuman::channels::matrix::MatrixChannel; +use crate::openhuman::channels::mattermost::MattermostChannel; +use crate::openhuman::channels::prompt::build_system_prompt; +use crate::openhuman::channels::qq::QQChannel; +use crate::openhuman::channels::signal::SignalChannel; +use crate::openhuman::channels::slack::SlackChannel; +use crate::openhuman::channels::telegram::TelegramChannel; +use crate::openhuman::channels::traits; +use crate::openhuman::channels::whatsapp::WhatsAppChannel; #[cfg(feature = "whatsapp-web")] -use crate::alphahuman::channels::whatsapp_web::WhatsAppWebChannel; -use crate::alphahuman::channels::Channel; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::observability::{self, Observer}; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools; +use crate::openhuman::channels::whatsapp_web::WhatsAppWebChannel; +use crate::openhuman::channels::Channel; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::observability::{self, Observer}; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools; use anyhow::Result; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -46,7 +46,7 @@ pub async fn start_channels(config: Config) -> Result<()> { .unwrap_or_else(|| "openrouter".into()); let provider_runtime_options = providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }; @@ -108,7 +108,7 @@ pub async fn start_channels(config: Config) -> Result<()> { &config, )); - let skills = crate::alphahuman::skills::load_skills(&workspace); + let skills = crate::openhuman::skills::load_skills(&workspace); // Collect tool descriptions for the prompt let mut tool_descs: Vec<(&str, &str)> = vec![ @@ -360,7 +360,7 @@ pub async fn start_channels(config: Config) -> Result<()> { return Ok(()); } - println!("🦀 Alphahuman Channel Server"); + println!("🦀 OpenHuman Channel Server"); println!(" 🤖 Model: {model}"); let effective_backend = memory::effective_memory_backend_name( &config.memory.backend, @@ -383,7 +383,7 @@ pub async fn start_channels(config: Config) -> Result<()> { println!(" Listening for messages... (Ctrl+C to stop)"); println!(); - crate::alphahuman::health::mark_component_ok("channels"); + crate::openhuman::health::mark_component_ok("channels"); let initial_backoff_secs = config .reliability diff --git a/src-tauri/src/alphahuman/channels/runtime/supervision.rs b/src-tauri/src/openhuman/channels/runtime/supervision.rs similarity index 86% rename from src-tauri/src/alphahuman/channels/runtime/supervision.rs rename to src-tauri/src/openhuman/channels/runtime/supervision.rs index 8fdd33cdd..006ff5961 100644 --- a/src-tauri/src/alphahuman/channels/runtime/supervision.rs +++ b/src-tauri/src/openhuman/channels/runtime/supervision.rs @@ -21,7 +21,7 @@ pub(crate) fn spawn_supervised_listener( let max_backoff = max_backoff_secs.max(backoff); loop { - crate::alphahuman::health::mark_component_ok(&component); + crate::openhuman::health::mark_component_ok(&component); let result = ch.listen(tx.clone()).await; if tx.is_closed() { @@ -31,7 +31,7 @@ pub(crate) fn spawn_supervised_listener( match result { Ok(()) => { tracing::warn!("Channel {} exited unexpectedly; restarting", ch.name()); - crate::alphahuman::health::mark_component_error( + crate::openhuman::health::mark_component_error( &component, "listener exited unexpectedly", ); @@ -40,11 +40,11 @@ pub(crate) fn spawn_supervised_listener( } Err(e) => { tracing::error!("Channel {} error: {e}; restarting", ch.name()); - crate::alphahuman::health::mark_component_error(&component, e.to_string()); + crate::openhuman::health::mark_component_error(&component, e.to_string()); } } - crate::alphahuman::health::bump_component_restart(&component); + crate::openhuman::health::bump_component_restart(&component); tokio::time::sleep(Duration::from_secs(backoff)).await; // Double backoff AFTER sleeping so first error uses initial_backoff backoff = backoff.saturating_mul(2).min(max_backoff); diff --git a/src-tauri/src/alphahuman/channels/signal.rs b/src-tauri/src/openhuman/channels/signal.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/signal.rs rename to src-tauri/src/openhuman/channels/signal.rs index ac1c50a53..f5406dcd6 100644 --- a/src-tauri/src/alphahuman/channels/signal.rs +++ b/src-tauri/src/openhuman/channels/signal.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::channels::traits::{Channel, ChannelMessage, SendMessage}; +use crate::openhuman::channels::traits::{Channel, ChannelMessage, SendMessage}; use async_trait::async_trait; use futures_util::StreamExt; use reqwest::Client; @@ -92,7 +92,7 @@ impl SignalChannel { fn http_client(&self) -> Client { let builder = Client::builder().connect_timeout(Duration::from_secs(10)); - let builder = crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "channel.signal"); + let builder = crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "channel.signal"); builder.build().expect("Signal HTTP client should build") } diff --git a/src-tauri/src/alphahuman/channels/slack.rs b/src-tauri/src/openhuman/channels/slack.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/slack.rs rename to src-tauri/src/openhuman/channels/slack.rs index b5854c460..676cbf9e2 100644 --- a/src-tauri/src/alphahuman/channels/slack.rs +++ b/src-tauri/src/openhuman/channels/slack.rs @@ -18,7 +18,7 @@ impl SlackChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.slack") + crate::openhuman::config::build_runtime_proxy_client("channel.slack") } /// Check if a Slack user ID is in the allowlist. diff --git a/src-tauri/src/alphahuman/channels/telegram.rs b/src-tauri/src/openhuman/channels/telegram.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/telegram.rs rename to src-tauri/src/openhuman/channels/telegram.rs index e609dc9c7..f106c65d1 100644 --- a/src-tauri/src/alphahuman/channels/telegram.rs +++ b/src-tauri/src/openhuman/channels/telegram.rs @@ -1,6 +1,6 @@ use super::traits::{Channel, ChannelMessage, SendMessage}; -use crate::alphahuman::config::{Config, StreamMode}; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::config::{Config, StreamMode}; +use crate::openhuman::security::pairing::PairingGuard; use anyhow::Context; use async_trait::async_trait; use directories::UserDirs; @@ -364,7 +364,7 @@ impl TelegramChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.telegram") + crate::openhuman::config::build_runtime_proxy_client("channel.telegram") } fn normalize_identity(value: &str) -> String { @@ -383,8 +383,8 @@ impl TelegramChannel { let home = UserDirs::new() .map(|u| u.home_dir().to_path_buf()) .context("Could not find home directory")?; - let alphahuman_dir = home.join(".alphahuman"); - let config_path = alphahuman_dir.join("config.toml"); + let openhuman_dir = home.join(".openhuman"); + let config_path = openhuman_dir.join("config.toml"); let contents = fs::read_to_string(&config_path) .await @@ -392,7 +392,7 @@ impl TelegramChannel { let mut config: Config = toml::from_str(&contents) .context("Failed to parse config file for Telegram binding")?; config.config_path = config_path; - config.workspace_dir = alphahuman_dir.join("workspace"); + config.workspace_dir = openhuman_dir.join("workspace"); Ok(config) } @@ -645,7 +645,7 @@ impl TelegramChannel { Ok(()) => { let _ = self .send(&SendMessage::new( - "✅ Telegram account bound successfully. You can talk to Alphahuman now.", + "✅ Telegram account bound successfully. You can talk to OpenHuman now.", &chat_id, )) .await; @@ -1725,7 +1725,7 @@ impl Channel for TelegramChannel { if error_code == 409 { tracing::warn!( "Telegram polling conflict (409): {description}. \ -Ensure only one `alphahuman` process is using this bot token." +Ensure only one `openhuman` process is using this bot token." ); tokio::time::sleep(std::time::Duration::from_secs(2)).await; } else { @@ -2037,7 +2037,7 @@ mod tests { #[test] fn telegram_extract_bind_code_supports_bot_mention() { assert_eq!( - TelegramChannel::extract_bind_code("/bind@alphahuman_bot 654321"), + TelegramChannel::extract_bind_code("/bind@openhuman_bot 654321"), Some("654321") ); } diff --git a/src-tauri/src/alphahuman/channels/tests/common.rs b/src-tauri/src/openhuman/channels/tests/common.rs similarity index 97% rename from src-tauri/src/alphahuman/channels/tests/common.rs rename to src-tauri/src/openhuman/channels/tests/common.rs index 753cb43d1..562b66054 100644 --- a/src-tauri/src/alphahuman/channels/tests/common.rs +++ b/src-tauri/src/openhuman/channels/tests/common.rs @@ -1,7 +1,7 @@ -use crate::alphahuman::channels::{traits, Channel, SendMessage}; -use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; -use crate::alphahuman::providers::{ChatMessage, Provider}; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::channels::{traits, Channel, SendMessage}; +use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; +use crate::openhuman::providers::{ChatMessage, Provider}; +use crate::openhuman::tools::{Tool, ToolResult}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -11,7 +11,7 @@ pub(super) fn make_workspace() -> TempDir { let tmp = TempDir::new().unwrap(); // Create minimal workspace files std::fs::write(tmp.path().join("SOUL.md"), "# Soul\nBe helpful.").unwrap(); - std::fs::write(tmp.path().join("IDENTITY.md"), "# Identity\nName: Alphahuman").unwrap(); + std::fs::write(tmp.path().join("IDENTITY.md"), "# Identity\nName: OpenHuman").unwrap(); std::fs::write(tmp.path().join("USER.md"), "# User\nName: Test User").unwrap(); std::fs::write( tmp.path().join("AGENTS.md"), diff --git a/src-tauri/src/alphahuman/channels/tests/context.rs b/src-tauri/src/openhuman/channels/tests/context.rs similarity index 90% rename from src-tauri/src/alphahuman/channels/tests/context.rs rename to src-tauri/src/openhuman/channels/tests/context.rs index 270cf09dc..ace589620 100644 --- a/src-tauri/src/alphahuman/channels/tests/context.rs +++ b/src-tauri/src/openhuman/channels/tests/context.rs @@ -5,8 +5,8 @@ use super::super::context::{ CHANNEL_HISTORY_COMPACT_CONTENT_CHARS, CHANNEL_HISTORY_COMPACT_KEEP_MESSAGES, CHANNEL_MESSAGE_TIMEOUT_SECS, MIN_CHANNEL_MESSAGE_TIMEOUT_SECS, }; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::ChatMessage; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::ChatMessage; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -80,9 +80,9 @@ fn compact_sender_history_keeps_recent_truncated_messages() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), - multimodal: crate::alphahuman::config::MultimodalConfig::default(), - provider_runtime_options: crate::alphahuman::providers::ProviderRuntimeOptions::default(), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), + multimodal: crate::openhuman::config::MultimodalConfig::default(), + provider_runtime_options: crate::openhuman::providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, }; diff --git a/src-tauri/src/alphahuman/channels/tests/health.rs b/src-tauri/src/openhuman/channels/tests/health.rs similarity index 96% rename from src-tauri/src/alphahuman/channels/tests/health.rs rename to src-tauri/src/openhuman/channels/tests/health.rs index 7634d93d1..f4995af81 100644 --- a/src-tauri/src/alphahuman/channels/tests/health.rs +++ b/src-tauri/src/openhuman/channels/tests/health.rs @@ -44,7 +44,7 @@ async fn supervised_listener_marks_error_and_restarts_on_failures() { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["channel:test-supervised-fail"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); diff --git a/src-tauri/src/alphahuman/channels/tests/identity.rs b/src-tauri/src/openhuman/channels/tests/identity.rs similarity index 94% rename from src-tauri/src/alphahuman/channels/tests/identity.rs rename to src-tauri/src/openhuman/channels/tests/identity.rs index 175ff8181..118a3e56e 100644 --- a/src-tauri/src/alphahuman/channels/tests/identity.rs +++ b/src-tauri/src/openhuman/channels/tests/identity.rs @@ -3,7 +3,7 @@ use super::super::prompt::build_system_prompt; #[test] fn aieos_identity_from_file() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; use tempfile::TempDir; let tmp = TempDir::new().unwrap(); @@ -60,7 +60,7 @@ fn aieos_identity_from_file() { #[test] fn aieos_identity_from_inline() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "aieos".into(), @@ -83,7 +83,7 @@ fn aieos_identity_from_inline() { #[test] fn aieos_fallback_to_openclaw_on_parse_error() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "aieos".into(), @@ -101,7 +101,7 @@ fn aieos_fallback_to_openclaw_on_parse_error() { #[test] fn aieos_empty_uses_openclaw() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; // Format is "aieos" but neither path nor inline is set let config = IdentityConfig { @@ -120,7 +120,7 @@ fn aieos_empty_uses_openclaw() { #[test] fn openclaw_format_uses_bootstrap_files() { - use crate::alphahuman::config::IdentityConfig; + use crate::openhuman::config::IdentityConfig; let config = IdentityConfig { format: "openclaw".into(), diff --git a/src-tauri/src/alphahuman/channels/tests/memory.rs b/src-tauri/src/openhuman/channels/tests/memory.rs similarity index 94% rename from src-tauri/src/alphahuman/channels/tests/memory.rs rename to src-tauri/src/openhuman/channels/tests/memory.rs index 05062172b..0279c3eb9 100644 --- a/src-tauri/src/alphahuman/channels/tests/memory.rs +++ b/src-tauri/src/openhuman/channels/tests/memory.rs @@ -2,9 +2,9 @@ use super::common::{HistoryCaptureProvider, NoopMemory, RecordingChannel}; use super::super::context::{build_memory_context, conversation_memory_key, ChannelRuntimeContext, CHANNEL_MESSAGE_TIMEOUT_SECS, MAX_CHANNEL_HISTORY}; use super::super::runtime::process_channel_message; use super::super::{traits, Channel}; -use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, ChatMessage, Provider}; +use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, ChatMessage, Provider}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tempfile::TempDir; @@ -138,11 +138,11 @@ async fn process_channel_message_restores_per_sender_history_on_follow_ups() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/tests/mod.rs b/src-tauri/src/openhuman/channels/tests/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/tests/mod.rs rename to src-tauri/src/openhuman/channels/tests/mod.rs diff --git a/src-tauri/src/alphahuman/channels/tests/prompt.rs b/src-tauri/src/openhuman/channels/tests/prompt.rs similarity index 96% rename from src-tauri/src/alphahuman/channels/tests/prompt.rs rename to src-tauri/src/openhuman/channels/tests/prompt.rs index 79e1ad097..e09b2c6df 100644 --- a/src-tauri/src/alphahuman/channels/tests/prompt.rs +++ b/src-tauri/src/openhuman/channels/tests/prompt.rs @@ -56,7 +56,7 @@ fn prompt_injects_workspace_files() { assert!(prompt.contains("Be helpful"), "missing SOUL content"); assert!(prompt.contains("### IDENTITY.md"), "missing IDENTITY.md"); assert!( - prompt.contains("Name: Alphahuman"), + prompt.contains("Name: OpenHuman"), "missing IDENTITY content" ); assert!(prompt.contains("### USER.md"), "missing USER.md"); @@ -142,7 +142,7 @@ fn prompt_runtime_metadata() { #[test] fn prompt_skills_compact_list() { let ws = make_workspace(); - let skills = vec![crate::alphahuman::skills::Skill { + let skills = vec![crate::openhuman::skills::Skill { name: "code-review".into(), description: "Review code for bugs".into(), version: "1.0.0".into(), @@ -202,10 +202,10 @@ fn prompt_empty_files_skipped() { #[test] fn channel_log_truncation_is_utf8_safe_for_multibyte_text() { - let msg = "Hello from Alphahuman 🌍. Current status is healthy, and café-style UTF-8 text stays safe in logs."; + let msg = "Hello from OpenHuman 🌍. Current status is healthy, and café-style UTF-8 text stays safe in logs."; // Reproduces the production crash path where channel logs truncate at 80 chars. - let result = std::panic::catch_unwind(|| crate::alphahuman::util::truncate_with_ellipsis(msg, 80)); + let result = std::panic::catch_unwind(|| crate::openhuman::util::truncate_with_ellipsis(msg, 80)); assert!( result.is_ok(), "truncate_with_ellipsis should never panic on UTF-8" diff --git a/src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs b/src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs similarity index 91% rename from src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs rename to src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs index 496495d3a..94a18b769 100644 --- a/src-tauri/src/alphahuman/channels/tests/runtime_dispatch.rs +++ b/src-tauri/src/openhuman/channels/tests/runtime_dispatch.rs @@ -2,8 +2,8 @@ use super::common::{NoopMemory, RecordingChannel, SlowProvider}; use super::super::context::{ChannelRuntimeContext, CHANNEL_MESSAGE_TIMEOUT_SECS}; use super::super::runtime::{process_channel_message, run_message_dispatch_loop}; use super::super::{traits, Channel}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, Provider}; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, Provider}; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -38,11 +38,11 @@ let runtime_ctx = Arc::new(ChannelRuntimeContext { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); let (tx, rx) = tokio::sync::mpsc::channel::(4); @@ -112,11 +112,11 @@ let runtime_ctx = Arc::new(ChannelRuntimeContext { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs b/src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs similarity index 93% rename from src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs rename to src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs index 27694470b..a61b1217a 100644 --- a/src-tauri/src/alphahuman/channels/tests/runtime_tool_calls.rs +++ b/src-tauri/src/openhuman/channels/tests/runtime_tool_calls.rs @@ -6,9 +6,9 @@ use super::common::{ use super::super::context::{ChannelRuntimeContext, ChannelRouteSelection, CHANNEL_MESSAGE_TIMEOUT_SECS}; use super::super::runtime::{process_channel_message, run_message_dispatch_loop}; use super::super::{traits, Channel, SendMessage}; -use crate::alphahuman::observability::NoopObserver; -use crate::alphahuman::providers::{self, ChatMessage, Provider}; -use crate::alphahuman::tools::Tool; +use crate::openhuman::observability::NoopObserver; +use crate::openhuman::providers::{self, ChatMessage, Provider}; +use crate::openhuman::tools::Tool; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -39,11 +39,11 @@ async fn process_channel_message_executes_tool_calls_instead_of_sending_raw_json route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -94,11 +94,11 @@ async fn process_channel_message_executes_tool_calls_with_alias_tags() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -158,11 +158,11 @@ async fn process_channel_message_handles_models_command_without_llm_call() { route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -243,11 +243,11 @@ async fn process_channel_message_uses_route_override_provider_and_model() { route_overrides: Arc::new(Mutex::new(route_overrides)), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -304,11 +304,11 @@ async fn process_channel_message_respects_configured_max_tool_iterations_above_d route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( @@ -360,11 +360,11 @@ async fn process_channel_message_reports_configured_max_tool_iterations_limit() route_overrides: Arc::new(Mutex::new(HashMap::new())), api_key: None, api_url: None, - reliability: Arc::new(crate::alphahuman::config::ReliabilityConfig::default()), + reliability: Arc::new(crate::openhuman::config::ReliabilityConfig::default()), provider_runtime_options: providers::ProviderRuntimeOptions::default(), workspace_dir: Arc::new(std::env::temp_dir()), message_timeout_secs: CHANNEL_MESSAGE_TIMEOUT_SECS, - multimodal: crate::alphahuman::config::MultimodalConfig::default(), + multimodal: crate::openhuman::config::MultimodalConfig::default(), }); process_channel_message( diff --git a/src-tauri/src/alphahuman/channels/traits.rs b/src-tauri/src/openhuman/channels/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/channels/traits.rs rename to src-tauri/src/openhuman/channels/traits.rs diff --git a/src-tauri/src/alphahuman/channels/whatsapp.rs b/src-tauri/src/openhuman/channels/whatsapp.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp.rs rename to src-tauri/src/openhuman/channels/whatsapp.rs index 586430ec3..84a08e1fd 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp.rs +++ b/src-tauri/src/openhuman/channels/whatsapp.rs @@ -45,7 +45,7 @@ impl WhatsAppChannel { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("channel.whatsapp") + crate::openhuman::config::build_runtime_proxy_client("channel.whatsapp") } /// Check if a phone number is allowed (E.164 format: +1234567890) @@ -307,7 +307,7 @@ mod tests { "timestamp": "1699999999", "type": "text", "text": { - "body": "Hello Alphahuman!" + "body": "Hello OpenHuman!" } }] }, @@ -319,7 +319,7 @@ mod tests { let msgs = ch.parse_webhook_payload(&payload); assert_eq!(msgs.len(), 1); assert_eq!(msgs[0].sender, "+1234567890"); - assert_eq!(msgs[0].content, "Hello Alphahuman!"); + assert_eq!(msgs[0].content, "Hello OpenHuman!"); assert_eq!(msgs[0].channel, "whatsapp"); assert_eq!(msgs[0].timestamp, 1_699_999_999); } diff --git a/src-tauri/src/alphahuman/channels/whatsapp_storage.rs b/src-tauri/src/openhuman/channels/whatsapp_storage.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp_storage.rs rename to src-tauri/src/openhuman/channels/whatsapp_storage.rs index 7a18a7d70..db3cc5ade 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp_storage.rs +++ b/src-tauri/src/openhuman/channels/whatsapp_storage.rs @@ -1,4 +1,4 @@ -//! Custom wa-rs storage backend using Alphahuman's rusqlite +//! Custom wa-rs storage backend using OpenHuman's rusqlite //! //! This module implements all 4 wa-rs storage traits using rusqlite directly, //! avoiding the Diesel/libsqlite3-sys dependency conflict from wa-rs-sqlite-storage. @@ -41,7 +41,7 @@ use wa_rs_core::store::Device as CoreDevice; /// Custom wa-rs storage backend using rusqlite /// /// This implements all 4 storage traits required by wa-rs. -/// The backend uses Alphahuman's existing rusqlite setup, avoiding the +/// The backend uses OpenHuman's existing rusqlite setup, avoiding the /// Diesel/libsqlite3-sys conflict from wa-rs-sqlite-storage. #[cfg(feature = "whatsapp-web")] #[derive(Clone)] diff --git a/src-tauri/src/alphahuman/channels/whatsapp_web.rs b/src-tauri/src/openhuman/channels/whatsapp_web.rs similarity index 99% rename from src-tauri/src/alphahuman/channels/whatsapp_web.rs rename to src-tauri/src/openhuman/channels/whatsapp_web.rs index 19861b328..c4648098b 100644 --- a/src-tauri/src/alphahuman/channels/whatsapp_web.rs +++ b/src-tauri/src/openhuman/channels/whatsapp_web.rs @@ -16,7 +16,7 @@ //! //! ```toml //! [channels.whatsapp] -//! session_path = "~/.alphahuman/whatsapp-session.db" # Required for Web mode +//! session_path = "~/.openhuman/whatsapp-session.db" # Required for Web mode //! pair_phone = "15551234567" # Optional: for pair code linking //! allowed_numbers = ["+1234567890", "*"] # Same as Cloud API //! ``` @@ -44,7 +44,7 @@ use tokio::select; /// /// ```toml /// [channels.whatsapp] -/// session_path = "~/.alphahuman/whatsapp-session.db" +/// session_path = "~/.openhuman/whatsapp-session.db" /// pair_phone = "15551234567" # Optional /// allowed_numbers = ["+1234567890", "*"] /// ``` diff --git a/src-tauri/src/alphahuman/config/daemon.rs b/src-tauri/src/openhuman/config/daemon.rs similarity index 77% rename from src-tauri/src/alphahuman/config/daemon.rs rename to src-tauri/src/openhuman/config/daemon.rs index cab1a7ab4..4bbdaea32 100644 --- a/src-tauri/src/alphahuman/config/daemon.rs +++ b/src-tauri/src/openhuman/config/daemon.rs @@ -1,6 +1,6 @@ -//! Tauri-focused daemon configuration wrapper for alphahuman. +//! Tauri-focused daemon configuration wrapper for openhuman. -use crate::alphahuman::config::{ +use crate::openhuman::config::{ AuditConfig, AutonomyConfig, ReliabilityConfig, SecretsConfig, SecurityConfig, }; use serde::{Deserialize, Serialize}; @@ -9,7 +9,7 @@ use std::path::PathBuf; /// Top-level daemon configuration for the Tauri supervisor. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DaemonConfig { - /// Root data directory (defaults to Tauri's `app_data_dir/alphahuman`). + /// Root data directory (defaults to Tauri's `app_data_dir/openhuman`). pub data_dir: PathBuf, /// Workspace directory the agent may operate within. pub workspace_dir: PathBuf, @@ -33,10 +33,10 @@ pub struct DaemonConfig { impl DaemonConfig { /// Build a config that derives paths from the Tauri `app_data_dir`. pub fn from_app_data_dir(app_data_dir: &std::path::Path) -> Self { - let data_dir = app_data_dir.join("alphahuman"); + let data_dir = app_data_dir.join("openhuman"); let workspace_dir = data_dir.join("workspace"); log::info!( - "[alphahuman:config] Initialized config: data_dir={}, workspace_dir={}", + "[openhuman:config] Initialized config: data_dir={}, workspace_dir={}", data_dir.display(), workspace_dir.display() ); @@ -58,13 +58,13 @@ mod tests { #[test] fn daemon_config_from_app_data_dir() { - let app_data = std::path::PathBuf::from("/tmp/test-alphahuman"); + let app_data = std::path::PathBuf::from("/tmp/test-openhuman"); let config = DaemonConfig::from_app_data_dir(&app_data); - assert_eq!(config.data_dir, app_data.join("alphahuman")); + assert_eq!(config.data_dir, app_data.join("openhuman")); assert_eq!( config.workspace_dir, - app_data.join("alphahuman").join("workspace") + app_data.join("openhuman").join("workspace") ); } } diff --git a/src-tauri/src/alphahuman/config/mod.rs b/src-tauri/src/openhuman/config/mod.rs similarity index 96% rename from src-tauri/src/alphahuman/config/mod.rs rename to src-tauri/src/openhuman/config/mod.rs index 6fae3d61b..d38110e3b 100644 --- a/src-tauri/src/alphahuman/config/mod.rs +++ b/src-tauri/src/openhuman/config/mod.rs @@ -59,7 +59,7 @@ mod tests { verification_token: None, allowed_users: vec![], use_feishu: false, - receive_mode: crate::alphahuman::config::schema::LarkReceiveMode::Websocket, + receive_mode: crate::openhuman::config::schema::LarkReceiveMode::Websocket, port: None, }; diff --git a/src-tauri/src/alphahuman/config/schema/agent.rs b/src-tauri/src/openhuman/config/schema/agent.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/agent.rs rename to src-tauri/src/openhuman/config/schema/agent.rs diff --git a/src-tauri/src/alphahuman/config/schema/autonomy.rs b/src-tauri/src/openhuman/config/schema/autonomy.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/autonomy.rs rename to src-tauri/src/openhuman/config/schema/autonomy.rs index f5e74230c..45a46edd2 100644 --- a/src-tauri/src/alphahuman/config/schema/autonomy.rs +++ b/src-tauri/src/openhuman/config/schema/autonomy.rs @@ -1,6 +1,6 @@ //! Autonomy and security policy configuration. -use crate::alphahuman::security::AutonomyLevel; +use crate::openhuman::security::AutonomyLevel; use super::defaults; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/config/schema/channels.rs b/src-tauri/src/openhuman/config/schema/channels.rs similarity index 99% rename from src-tauri/src/alphahuman/config/schema/channels.rs rename to src-tauri/src/openhuman/config/schema/channels.rs index 1ea502b7f..ecff0629d 100644 --- a/src-tauri/src/alphahuman/config/schema/channels.rs +++ b/src-tauri/src/openhuman/config/schema/channels.rs @@ -1,6 +1,6 @@ //! Channels configuration (Telegram, Discord, Slack, Matrix, etc.) and security/sandbox. -use crate::alphahuman::channels::email_channel::EmailConfig; +use crate::openhuman::channels::email_channel::EmailConfig; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/config/schema/defaults.rs b/src-tauri/src/openhuman/config/schema/defaults.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/defaults.rs rename to src-tauri/src/openhuman/config/schema/defaults.rs diff --git a/src-tauri/src/alphahuman/config/schema/gateway.rs b/src-tauri/src/openhuman/config/schema/gateway.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/gateway.rs rename to src-tauri/src/openhuman/config/schema/gateway.rs diff --git a/src-tauri/src/alphahuman/config/schema/hardware.rs b/src-tauri/src/openhuman/config/schema/hardware.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/hardware.rs rename to src-tauri/src/openhuman/config/schema/hardware.rs diff --git a/src-tauri/src/alphahuman/config/schema/heartbeat_cron.rs b/src-tauri/src/openhuman/config/schema/heartbeat_cron.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/heartbeat_cron.rs rename to src-tauri/src/openhuman/config/schema/heartbeat_cron.rs diff --git a/src-tauri/src/alphahuman/config/schema/identity_cost.rs b/src-tauri/src/openhuman/config/schema/identity_cost.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/identity_cost.rs rename to src-tauri/src/openhuman/config/schema/identity_cost.rs diff --git a/src-tauri/src/alphahuman/config/schema/load.rs b/src-tauri/src/openhuman/config/schema/load.rs similarity index 85% rename from src-tauri/src/alphahuman/config/schema/load.rs rename to src-tauri/src/openhuman/config/schema/load.rs index 07af2986e..9d29df79d 100644 --- a/src-tauri/src/alphahuman/config/schema/load.rs +++ b/src-tauri/src/openhuman/config/schema/load.rs @@ -7,7 +7,7 @@ use super::{ }, Config, }; -use crate::alphahuman::providers::{is_glm_alias, is_zai_alias}; +use crate::openhuman::providers::{is_glm_alias, is_zai_alias}; use anyhow::{Context, Result}; use directories::UserDirs; use serde::{Deserialize, Serialize}; @@ -31,7 +31,7 @@ fn default_config_dir() -> Result { let home = UserDirs::new() .map(|u| u.home_dir().to_path_buf()) .context("Could not find home directory")?; - Ok(home.join(".alphahuman")) + Ok(home.join(".openhuman")) } fn active_workspace_state_path(default_dir: &Path) -> PathBuf { @@ -151,7 +151,7 @@ fn resolve_config_dir_for_workspace(workspace_dir: &Path) -> (PathBuf, PathBuf) let legacy_config_dir = workspace_dir .parent() - .map(|parent| parent.join(".alphahuman")); + .map(|parent| parent.join(".openhuman")); if let Some(legacy_dir) = legacy_config_dir { if legacy_dir.join("config.toml").exists() { return (legacy_dir, workspace_config_dir); @@ -181,7 +181,7 @@ enum ConfigResolutionSource { impl ConfigResolutionSource { const fn as_str(self) -> &'static str { match self { - Self::EnvWorkspace => "ALPHAHUMAN_WORKSPACE", + Self::EnvWorkspace => "OPENHUMAN_WORKSPACE", Self::ActiveWorkspaceMarker => "active_workspace.toml", Self::DefaultConfigDir => "default", } @@ -189,45 +189,45 @@ impl ConfigResolutionSource { } async fn resolve_runtime_config_dirs( - default_alphahuman_dir: &Path, + default_openhuman_dir: &Path, default_workspace_dir: &Path, ) -> Result<(PathBuf, PathBuf, ConfigResolutionSource)> { - if let Ok(custom_workspace) = std::env::var("ALPHAHUMAN_WORKSPACE") { + if let Ok(custom_workspace) = std::env::var("OPENHUMAN_WORKSPACE") { if !custom_workspace.is_empty() { - let (alphahuman_dir, workspace_dir) = + let (openhuman_dir, workspace_dir) = resolve_config_dir_for_workspace(&PathBuf::from(custom_workspace)); return Ok(( - alphahuman_dir, + openhuman_dir, workspace_dir, ConfigResolutionSource::EnvWorkspace, )); } } - if let Some((alphahuman_dir, workspace_dir)) = - load_persisted_workspace_dirs(default_alphahuman_dir).await? + if let Some((openhuman_dir, workspace_dir)) = + load_persisted_workspace_dirs(default_openhuman_dir).await? { return Ok(( - alphahuman_dir, + openhuman_dir, workspace_dir, ConfigResolutionSource::ActiveWorkspaceMarker, )); } Ok(( - default_alphahuman_dir.to_path_buf(), + default_openhuman_dir.to_path_buf(), default_workspace_dir.to_path_buf(), ConfigResolutionSource::DefaultConfigDir, )) } fn decrypt_optional_secret( - store: &crate::alphahuman::security::SecretStore, + store: &crate::openhuman::security::SecretStore, value: &mut Option, field_name: &str, ) -> Result<()> { if let Some(raw) = value.clone() { - if crate::alphahuman::security::SecretStore::is_encrypted(&raw) { + if crate::openhuman::security::SecretStore::is_encrypted(&raw) { *value = Some( store .decrypt(&raw) @@ -239,12 +239,12 @@ fn decrypt_optional_secret( } fn encrypt_optional_secret( - store: &crate::alphahuman::security::SecretStore, + store: &crate::openhuman::security::SecretStore, value: &mut Option, field_name: &str, ) -> Result<()> { if let Some(raw) = value.clone() { - if !crate::alphahuman::security::SecretStore::is_encrypted(&raw) { + if !crate::openhuman::security::SecretStore::is_encrypted(&raw) { *value = Some( store .encrypt(&raw) @@ -273,14 +273,14 @@ async fn sync_directory(_path: &Path) -> Result<()> { impl Config { pub async fn load_or_init() -> Result { - let (default_alphahuman_dir, default_workspace_dir) = default_config_and_workspace_dirs()?; + let (default_openhuman_dir, default_workspace_dir) = default_config_and_workspace_dirs()?; - let (alphahuman_dir, workspace_dir, resolution_source) = - resolve_runtime_config_dirs(&default_alphahuman_dir, &default_workspace_dir).await?; + let (openhuman_dir, workspace_dir, resolution_source) = + resolve_runtime_config_dirs(&default_openhuman_dir, &default_workspace_dir).await?; - let config_path = alphahuman_dir.join("config.toml"); + let config_path = openhuman_dir.join("config.toml"); - fs::create_dir_all(&alphahuman_dir) + fs::create_dir_all(&openhuman_dir) .await .context("Failed to create config directory")?; fs::create_dir_all(&workspace_dir) @@ -312,7 +312,7 @@ impl Config { config.config_path = config_path.clone(); config.workspace_dir = workspace_dir; let store = - crate::alphahuman::security::SecretStore::new(&alphahuman_dir, config.secrets.encrypt); + crate::openhuman::security::SecretStore::new(&openhuman_dir, config.secrets.encrypt); decrypt_optional_secret(&store, &mut config.api_key, "config.api_key")?; decrypt_optional_secret( &store, @@ -371,7 +371,7 @@ impl Config { } pub fn apply_env_overrides(&mut self) { - if let Ok(key) = std::env::var("ALPHAHUMAN_API_KEY").or_else(|_| std::env::var("API_KEY")) { + if let Ok(key) = std::env::var("OPENHUMAN_API_KEY").or_else(|_| std::env::var("API_KEY")) { if !key.is_empty() { self.api_key = Some(key); } @@ -391,7 +391,7 @@ impl Config { } } - if let Ok(provider) = std::env::var("ALPHAHUMAN_PROVIDER") { + if let Ok(provider) = std::env::var("OPENHUMAN_PROVIDER") { if !provider.is_empty() { self.default_provider = Some(provider); } @@ -404,13 +404,13 @@ impl Config { } } - if let Ok(model) = std::env::var("ALPHAHUMAN_MODEL").or_else(|_| std::env::var("MODEL")) { + if let Ok(model) = std::env::var("OPENHUMAN_MODEL").or_else(|_| std::env::var("MODEL")) { if !model.is_empty() { self.default_model = Some(model); } } - if let Ok(workspace) = std::env::var("ALPHAHUMAN_WORKSPACE") { + if let Ok(workspace) = std::env::var("OPENHUMAN_WORKSPACE") { if !workspace.is_empty() { let (_, workspace_dir) = resolve_config_dir_for_workspace(&PathBuf::from(workspace)); self.workspace_dir = workspace_dir; @@ -418,7 +418,7 @@ impl Config { } if let Ok(port_str) = - std::env::var("ALPHAHUMAN_GATEWAY_PORT").or_else(|_| std::env::var("PORT")) + std::env::var("OPENHUMAN_GATEWAY_PORT").or_else(|_| std::env::var("PORT")) { if let Ok(port) = port_str.parse::() { self.gateway.port = port; @@ -426,18 +426,18 @@ impl Config { } if let Ok(host) = - std::env::var("ALPHAHUMAN_GATEWAY_HOST").or_else(|_| std::env::var("HOST")) + std::env::var("OPENHUMAN_GATEWAY_HOST").or_else(|_| std::env::var("HOST")) { if !host.is_empty() { self.gateway.host = host; } } - if let Ok(val) = std::env::var("ALPHAHUMAN_ALLOW_PUBLIC_BIND") { + if let Ok(val) = std::env::var("OPENHUMAN_ALLOW_PUBLIC_BIND") { self.gateway.allow_public_bind = val == "1" || val.eq_ignore_ascii_case("true"); } - if let Ok(temp_str) = std::env::var("ALPHAHUMAN_TEMPERATURE") { + if let Ok(temp_str) = std::env::var("OPENHUMAN_TEMPERATURE") { if let Ok(temp) = temp_str.parse::() { if (0.0..=2.0).contains(&temp) { self.default_temperature = temp; @@ -445,7 +445,7 @@ impl Config { } } - if let Ok(flag) = std::env::var("ALPHAHUMAN_REASONING_ENABLED") + if let Ok(flag) = std::env::var("OPENHUMAN_REASONING_ENABLED") .or_else(|_| std::env::var("REASONING_ENABLED")) { let normalized = flag.trim().to_ascii_lowercase(); @@ -456,13 +456,13 @@ impl Config { } } - if let Ok(enabled) = std::env::var("ALPHAHUMAN_WEB_SEARCH_ENABLED") + if let Ok(enabled) = std::env::var("OPENHUMAN_WEB_SEARCH_ENABLED") .or_else(|_| std::env::var("WEB_SEARCH_ENABLED")) { self.web_search.enabled = enabled == "1" || enabled.eq_ignore_ascii_case("true"); } - if let Ok(provider) = std::env::var("ALPHAHUMAN_WEB_SEARCH_PROVIDER") + if let Ok(provider) = std::env::var("OPENHUMAN_WEB_SEARCH_PROVIDER") .or_else(|_| std::env::var("WEB_SEARCH_PROVIDER")) { let provider = provider.trim(); @@ -472,7 +472,7 @@ impl Config { } if let Ok(api_key) = - std::env::var("ALPHAHUMAN_BRAVE_API_KEY").or_else(|_| std::env::var("BRAVE_API_KEY")) + std::env::var("OPENHUMAN_BRAVE_API_KEY").or_else(|_| std::env::var("BRAVE_API_KEY")) { let api_key = api_key.trim(); if !api_key.is_empty() { @@ -480,7 +480,7 @@ impl Config { } } - if let Ok(max_results) = std::env::var("ALPHAHUMAN_WEB_SEARCH_MAX_RESULTS") + if let Ok(max_results) = std::env::var("OPENHUMAN_WEB_SEARCH_MAX_RESULTS") .or_else(|_| std::env::var("WEB_SEARCH_MAX_RESULTS")) { if let Ok(max_results) = max_results.parse::() { @@ -490,7 +490,7 @@ impl Config { } } - if let Ok(timeout_secs) = std::env::var("ALPHAHUMAN_WEB_SEARCH_TIMEOUT_SECS") + if let Ok(timeout_secs) = std::env::var("OPENHUMAN_WEB_SEARCH_TIMEOUT_SECS") .or_else(|_| std::env::var("WEB_SEARCH_TIMEOUT_SECS")) { if let Ok(timeout_secs) = timeout_secs.parse::() { @@ -500,21 +500,21 @@ impl Config { } } - if let Ok(provider) = std::env::var("ALPHAHUMAN_STORAGE_PROVIDER") { + if let Ok(provider) = std::env::var("OPENHUMAN_STORAGE_PROVIDER") { let provider = provider.trim(); if !provider.is_empty() { self.storage.provider.config.provider = provider.to_string(); } } - if let Ok(db_url) = std::env::var("ALPHAHUMAN_STORAGE_DB_URL") { + if let Ok(db_url) = std::env::var("OPENHUMAN_STORAGE_DB_URL") { let db_url = db_url.trim(); if !db_url.is_empty() { self.storage.provider.config.db_url = Some(db_url.to_string()); } } - if let Ok(timeout_secs) = std::env::var("ALPHAHUMAN_STORAGE_CONNECT_TIMEOUT_SECS") { + if let Ok(timeout_secs) = std::env::var("OPENHUMAN_STORAGE_CONNECT_TIMEOUT_SECS") { if let Ok(timeout_secs) = timeout_secs.parse::() { if timeout_secs > 0 { self.storage.provider.config.connect_timeout_secs = Some(timeout_secs); @@ -522,7 +522,7 @@ impl Config { } } - let explicit_proxy_enabled = std::env::var("ALPHAHUMAN_PROXY_ENABLED") + let explicit_proxy_enabled = std::env::var("OPENHUMAN_PROXY_ENABLED") .ok() .as_deref() .and_then(parse_proxy_enabled); @@ -532,25 +532,25 @@ impl Config { let mut proxy_url_overridden = false; if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_HTTP_PROXY").or_else(|_| std::env::var("HTTP_PROXY")) + std::env::var("OPENHUMAN_HTTP_PROXY").or_else(|_| std::env::var("HTTP_PROXY")) { self.proxy.http_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_HTTPS_PROXY").or_else(|_| std::env::var("HTTPS_PROXY")) + std::env::var("OPENHUMAN_HTTPS_PROXY").or_else(|_| std::env::var("HTTPS_PROXY")) { self.proxy.https_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(proxy_url) = - std::env::var("ALPHAHUMAN_ALL_PROXY").or_else(|_| std::env::var("ALL_PROXY")) + std::env::var("OPENHUMAN_ALL_PROXY").or_else(|_| std::env::var("ALL_PROXY")) { self.proxy.all_proxy = normalize_proxy_url_option(Some(&proxy_url)); proxy_url_overridden = true; } if let Ok(no_proxy) = - std::env::var("ALPHAHUMAN_NO_PROXY").or_else(|_| std::env::var("NO_PROXY")) + std::env::var("OPENHUMAN_NO_PROXY").or_else(|_| std::env::var("NO_PROXY")) { self.proxy.no_proxy = normalize_no_proxy_list(vec![no_proxy]); } @@ -562,18 +562,18 @@ impl Config { self.proxy.enabled = true; } - if let Ok(scope_raw) = std::env::var("ALPHAHUMAN_PROXY_SCOPE") { + if let Ok(scope_raw) = std::env::var("OPENHUMAN_PROXY_SCOPE") { if let Some(scope) = parse_proxy_scope(&scope_raw) { self.proxy.scope = scope; } else { tracing::warn!( scope = %scope_raw, - "Ignoring invalid ALPHAHUMAN_PROXY_SCOPE (valid: environment|alphahuman|services)" + "Ignoring invalid OPENHUMAN_PROXY_SCOPE (valid: environment|openhuman|services)" ); } } - if let Ok(services_raw) = std::env::var("ALPHAHUMAN_PROXY_SERVICES") { + if let Ok(services_raw) = std::env::var("OPENHUMAN_PROXY_SERVICES") { self.proxy.services = normalize_service_list(vec![services_raw]); } @@ -591,12 +591,12 @@ impl Config { pub async fn save(&self) -> Result<()> { let mut config_to_save = self.clone(); - let alphahuman_dir = self + let openhuman_dir = self .config_path .parent() .context("Config path must have a parent directory")?; let store = - crate::alphahuman::security::SecretStore::new(alphahuman_dir, self.secrets.encrypt); + crate::openhuman::security::SecretStore::new(openhuman_dir, self.secrets.encrypt); encrypt_optional_secret(&store, &mut config_to_save.api_key, "config.api_key")?; encrypt_optional_secret( diff --git a/src-tauri/src/alphahuman/config/schema/mod.rs b/src-tauri/src/openhuman/config/schema/mod.rs similarity index 97% rename from src-tauri/src/alphahuman/config/schema/mod.rs rename to src-tauri/src/openhuman/config/schema/mod.rs index 8c4cdc06c..8f38ea508 100644 --- a/src-tauri/src/alphahuman/config/schema/mod.rs +++ b/src-tauri/src/openhuman/config/schema/mod.rs @@ -163,11 +163,11 @@ impl Default for Config { fn default() -> Self { let home = UserDirs::new().map_or_else(|| PathBuf::from("."), |u| u.home_dir().to_path_buf()); - let alphahuman_dir = home.join(".alphahuman"); + let openhuman_dir = home.join(".openhuman"); Self { - workspace_dir: alphahuman_dir.join("workspace"), - config_path: alphahuman_dir.join("config.toml"), + workspace_dir: openhuman_dir.join("workspace"), + config_path: openhuman_dir.join("config.toml"), api_key: None, api_url: None, default_provider: Some("openrouter".to_string()), diff --git a/src-tauri/src/alphahuman/config/schema/observability.rs b/src-tauri/src/openhuman/config/schema/observability.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/observability.rs rename to src-tauri/src/openhuman/config/schema/observability.rs index e306a3c3c..7f7a67aa3 100644 --- a/src-tauri/src/alphahuman/config/schema/observability.rs +++ b/src-tauri/src/openhuman/config/schema/observability.rs @@ -12,7 +12,7 @@ pub struct ObservabilityConfig { #[serde(default)] pub otel_endpoint: Option, - /// Service name reported to the OTel collector. Defaults to "alphahuman". + /// Service name reported to the OTel collector. Defaults to "openhuman". #[serde(default)] pub otel_service_name: Option, } diff --git a/src-tauri/src/alphahuman/config/schema/proxy.rs b/src-tauri/src/openhuman/config/schema/proxy.rs similarity index 98% rename from src-tauri/src/alphahuman/config/schema/proxy.rs rename to src-tauri/src/openhuman/config/schema/proxy.rs index 4227764c3..7d3ffd7fa 100644 --- a/src-tauri/src/alphahuman/config/schema/proxy.rs +++ b/src-tauri/src/openhuman/config/schema/proxy.rs @@ -45,7 +45,7 @@ static RUNTIME_PROXY_CLIENT_CACHE: OnceLock false, - ProxyScope::Alphahuman => true, + ProxyScope::OpenHuman => true, ProxyScope::Services => { let service_key = service_key.trim().to_ascii_lowercase(); if service_key.is_empty() { @@ -477,7 +477,7 @@ pub fn build_runtime_proxy_client_with_timeouts( pub(crate) fn parse_proxy_scope(raw: &str) -> Option { match raw.trim().to_ascii_lowercase().as_str() { "environment" | "env" => Some(ProxyScope::Environment), - "alphahuman" | "internal" | "core" => Some(ProxyScope::Alphahuman), + "openhuman" | "internal" | "core" => Some(ProxyScope::OpenHuman), "services" | "service" => Some(ProxyScope::Services), _ => None, } diff --git a/src-tauri/src/alphahuman/config/schema/routes.rs b/src-tauri/src/openhuman/config/schema/routes.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/routes.rs rename to src-tauri/src/openhuman/config/schema/routes.rs diff --git a/src-tauri/src/alphahuman/config/schema/runtime.rs b/src-tauri/src/openhuman/config/schema/runtime.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/runtime.rs rename to src-tauri/src/openhuman/config/schema/runtime.rs diff --git a/src-tauri/src/alphahuman/config/schema/storage_memory.rs b/src-tauri/src/openhuman/config/schema/storage_memory.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/storage_memory.rs rename to src-tauri/src/openhuman/config/schema/storage_memory.rs diff --git a/src-tauri/src/alphahuman/config/schema/tools.rs b/src-tauri/src/openhuman/config/schema/tools.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/tools.rs rename to src-tauri/src/openhuman/config/schema/tools.rs diff --git a/src-tauri/src/alphahuman/config/schema/tunnel.rs b/src-tauri/src/openhuman/config/schema/tunnel.rs similarity index 100% rename from src-tauri/src/alphahuman/config/schema/tunnel.rs rename to src-tauri/src/openhuman/config/schema/tunnel.rs diff --git a/src-tauri/src/alphahuman/cost/mod.rs b/src-tauri/src/openhuman/cost/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/cost/mod.rs rename to src-tauri/src/openhuman/cost/mod.rs diff --git a/src-tauri/src/alphahuman/cost/tracker.rs b/src-tauri/src/openhuman/cost/tracker.rs similarity index 99% rename from src-tauri/src/alphahuman/cost/tracker.rs rename to src-tauri/src/openhuman/cost/tracker.rs index 23eeef12b..9a5bd3581 100644 --- a/src-tauri/src/alphahuman/cost/tracker.rs +++ b/src-tauri/src/openhuman/cost/tracker.rs @@ -1,5 +1,5 @@ use super::types::{BudgetCheck, CostRecord, CostSummary, ModelStats, TokenUsage, UsagePeriod}; -use crate::alphahuman::config::CostConfig; +use crate::openhuman::config::CostConfig; use anyhow::{anyhow, Context, Result}; use chrono::{Datelike, NaiveDate, Utc}; use parking_lot::{Mutex, MutexGuard}; @@ -177,7 +177,7 @@ impl CostTracker { fn resolve_storage_path(workspace_dir: &Path) -> Result { let storage_path = workspace_dir.join("state").join("costs.jsonl"); - let legacy_path = workspace_dir.join(".alphahuman").join("costs.db"); + let legacy_path = workspace_dir.join(".openhuman").join("costs.db"); if !storage_path.exists() && legacy_path.exists() { if let Some(parent) = storage_path.parent() { diff --git a/src-tauri/src/alphahuman/cost/types.rs b/src-tauri/src/openhuman/cost/types.rs similarity index 100% rename from src-tauri/src/alphahuman/cost/types.rs rename to src-tauri/src/openhuman/cost/types.rs diff --git a/src-tauri/src/alphahuman/cron/mod.rs b/src-tauri/src/openhuman/cron/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/mod.rs rename to src-tauri/src/openhuman/cron/mod.rs index 480289019..d5d030f59 100644 --- a/src-tauri/src/alphahuman/cron/mod.rs +++ b/src-tauri/src/openhuman/cron/mod.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::Config; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; mod schedule; diff --git a/src-tauri/src/alphahuman/cron/schedule.rs b/src-tauri/src/openhuman/cron/schedule.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/schedule.rs rename to src-tauri/src/openhuman/cron/schedule.rs index e604bf518..daefe5a26 100644 --- a/src-tauri/src/alphahuman/cron/schedule.rs +++ b/src-tauri/src/openhuman/cron/schedule.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::cron::Schedule; +use crate::openhuman::cron::Schedule; use anyhow::{Context, Result}; use chrono::{DateTime, Duration as ChronoDuration, Utc}; use cron::Schedule as CronExprSchedule; diff --git a/src-tauri/src/alphahuman/cron/scheduler.rs b/src-tauri/src/openhuman/cron/scheduler.rs similarity index 96% rename from src-tauri/src/alphahuman/cron/scheduler.rs rename to src-tauri/src/openhuman/cron/scheduler.rs index c62ed4f3c..631f0a66c 100644 --- a/src-tauri/src/alphahuman/cron/scheduler.rs +++ b/src-tauri/src/openhuman/cron/scheduler.rs @@ -1,12 +1,12 @@ -use crate::alphahuman::channels::{ +use crate::openhuman::channels::{ Channel, DiscordChannel, MattermostChannel, SendMessage, SlackChannel, TelegramChannel, }; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{ +use crate::openhuman::config::Config; +use crate::openhuman::cron::{ due_jobs, next_run_for_schedule, record_last_run, record_run, remove_job, reschedule_after_run, update_job, CronJob, CronJobPatch, DeliveryConfig, JobType, Schedule, SessionTarget, }; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; use chrono::{DateTime, Utc}; use futures_util::{stream, StreamExt}; @@ -26,7 +26,7 @@ pub async fn run(config: Config) -> Result<()> { &config.workspace_dir, )); - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); loop { interval.tick().await; @@ -34,7 +34,7 @@ pub async fn run(config: Config) -> Result<()> { let jobs = match due_jobs(&config, Utc::now()) { Ok(jobs) => jobs, Err(e) => { - crate::alphahuman::health::mark_component_error("scheduler", e.to_string()); + crate::openhuman::health::mark_component_error("scheduler", e.to_string()); tracing::warn!("Scheduler query failed: {e}"); continue; } @@ -95,7 +95,7 @@ async fn process_due_jobs(config: &Config, security: &Arc, jobs: while let Some((job_id, success)) = in_flight.next().await { if !success { - crate::alphahuman::health::mark_component_error("scheduler", format!("job {job_id} failed")); + crate::openhuman::health::mark_component_error("scheduler", format!("job {job_id} failed")); } } } @@ -105,7 +105,7 @@ async fn execute_and_persist_job( security: &SecurityPolicy, job: &CronJob, ) -> (String, bool) { - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); warn_if_high_frequency_agent_job(job); let started_at = Utc::now(); @@ -124,7 +124,7 @@ async fn run_agent_job(config: &Config, job: &CronJob) -> (bool, String) { let run_result = match job.session_target { SessionTarget::Main | SessionTarget::Isolated => { - crate::alphahuman::agent::run( + crate::openhuman::agent::run( config.clone(), Some(prefixed_prompt), None, @@ -469,9 +469,9 @@ async fn run_job_command_with_timeout( #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; - use crate::alphahuman::cron::{self, DeliveryConfig}; - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::config::Config; + use crate::openhuman::cron::{self, DeliveryConfig}; + use crate::openhuman::security::SecurityPolicy; use chrono::{Duration as ChronoDuration, Utc}; use tempfile::TempDir; @@ -491,7 +491,7 @@ mod tests { CronJob { id: "test-job".into(), expression: "* * * * *".into(), - schedule: crate::alphahuman::cron::Schedule::Cron { + schedule: crate::openhuman::cron::Schedule::Cron { expr: "* * * * *".into(), tz: None, }, @@ -585,7 +585,7 @@ mod tests { async fn run_job_command_blocks_readonly_mode() { let tmp = TempDir::new().unwrap(); let mut config = test_config(&tmp).await; - config.autonomy.level = crate::alphahuman::security::AutonomyLevel::ReadOnly; + config.autonomy.level = crate::openhuman::security::AutonomyLevel::ReadOnly; let job = test_job("echo should-not-run"); let security = SecurityPolicy::from_config(&config.autonomy, &config.workspace_dir); @@ -687,7 +687,7 @@ mod tests { let job = cron::add_agent_job( &config, Some("one-shot".into()), - crate::alphahuman::cron::Schedule::At { at }, + crate::openhuman::cron::Schedule::At { at }, "Hello", SessionTarget::Isolated, None, @@ -712,7 +712,7 @@ mod tests { let job = cron::add_agent_job( &config, Some("one-shot".into()), - crate::alphahuman::cron::Schedule::At { at }, + crate::openhuman::cron::Schedule::At { at }, "Hello", SessionTarget::Isolated, None, diff --git a/src-tauri/src/alphahuman/cron/store.rs b/src-tauri/src/openhuman/cron/store.rs similarity index 99% rename from src-tauri/src/alphahuman/cron/store.rs rename to src-tauri/src/openhuman/cron/store.rs index 93dbf42e9..456a5849c 100644 --- a/src-tauri/src/alphahuman/cron/store.rs +++ b/src-tauri/src/openhuman/cron/store.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{ +use crate::openhuman::config::Config; +use crate::openhuman::cron::{ next_run_for_schedule, schedule_cron_expression, validate_schedule, CronJob, CronJobPatch, CronRun, DeliveryConfig, JobType, Schedule, SessionTarget, }; @@ -567,7 +567,7 @@ fn with_connection(config: &Config, f: impl FnOnce(&Connection) -> Result) #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use chrono::Duration as ChronoDuration; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/cron/types.rs b/src-tauri/src/openhuman/cron/types.rs similarity index 100% rename from src-tauri/src/alphahuman/cron/types.rs rename to src-tauri/src/openhuman/cron/types.rs diff --git a/src-tauri/src/alphahuman/daemon/mod.rs b/src-tauri/src/openhuman/daemon/mod.rs similarity index 76% rename from src-tauri/src/alphahuman/daemon/mod.rs rename to src-tauri/src/openhuman/daemon/mod.rs index 6df1c99fd..11a8a9da8 100644 --- a/src-tauri/src/alphahuman/daemon/mod.rs +++ b/src-tauri/src/openhuman/daemon/mod.rs @@ -13,7 +13,7 @@ use tokio::task::JoinHandle; use tokio::time::Duration; use tokio_util::sync::CancellationToken; -use crate::alphahuman::config::{Config, DaemonConfig}; +use crate::openhuman::config::{Config, DaemonConfig}; /// How often the state writer emits health snapshots (seconds). const STATUS_FLUSH_SECONDS: u64 = 5; @@ -27,7 +27,7 @@ pub struct DaemonHandle { /// /// The supervisor: /// 1. Marks the "daemon" health component as OK -/// 2. Spawns a state writer that emits `alphahuman:health` Tauri events +/// 2. Spawns a state writer that emits `openhuman:health` Tauri events /// 3. Waits for the cancellation token to be triggered (on app exit) /// 4. Aborts all supervised tasks pub async fn run( @@ -45,7 +45,7 @@ pub async fn run( let _ = tokio::fs::create_dir_all(&config.data_dir).await; let _ = tokio::fs::create_dir_all(&config.workspace_dir).await; - crate::alphahuman::health::mark_component_ok("daemon"); + crate::openhuman::health::mark_component_ok("daemon"); let mut handles: Vec> = vec![]; @@ -55,29 +55,29 @@ pub async fn run( let data_dir = config.data_dir.clone(); let cancel_clone = cancel.clone(); handles.push(tokio::spawn(async move { - log::info!("[alphahuman] Starting health event writer task"); + log::info!("[openhuman] Starting health event writer task"); spawn_state_writer(app, data_dir, cancel_clone).await; - log::info!("[alphahuman] Health event writer task terminated"); + log::info!("[openhuman] Health event writer task terminated"); })); } - log::info!("[alphahuman] Daemon supervisor started"); + log::info!("[openhuman] Daemon supervisor started"); log::info!( - "[alphahuman] data_dir: {}", + "[openhuman] data_dir: {}", config.data_dir.display() ); log::info!( - "[alphahuman] backoff: {}s initial, {}s max", + "[openhuman] backoff: {}s initial, {}s max", initial_backoff, max_backoff ); - log::info!("[alphahuman] health: Events will be emitted every {}s to frontend", STATUS_FLUSH_SECONDS); + log::info!("[openhuman] health: Events will be emitted every {}s to frontend", STATUS_FLUSH_SECONDS); // Wait for cancellation (Tauri exit) cancel.cancelled().await; - crate::alphahuman::health::mark_component_error("daemon", "shutdown requested"); - log::info!("[alphahuman] Daemon supervisor shutting down (health events will stop)"); + crate::openhuman::health::mark_component_error("daemon", "shutdown requested"); + log::info!("[openhuman] Daemon supervisor shutting down (health events will stop)"); for handle in &handles { handle.abort(); @@ -89,7 +89,7 @@ pub async fn run( Ok(()) } -/// Run the full Alphahuman daemon supervisor within alphahuman. +/// Run the full OpenHuman daemon supervisor within openhuman. /// /// Uses a cancellation token for controlled shutdown inside the Tauri process. pub async fn run_full( @@ -104,11 +104,11 @@ pub async fn run_full( .channel_max_backoff_secs .max(initial_backoff); - crate::alphahuman::health::mark_component_ok("daemon"); + crate::openhuman::health::mark_component_ok("daemon"); if config.heartbeat.enabled { let _ = - crate::alphahuman::heartbeat::engine::HeartbeatEngine::ensure_heartbeat_file( + crate::openhuman::heartbeat::engine::HeartbeatEngine::ensure_heartbeat_file( &config.workspace_dir, ) .await; @@ -128,7 +128,7 @@ pub async fn run_full( let cfg = gateway_cfg.clone(); let host = gateway_host.clone(); async move { - crate::alphahuman::gateway::run_gateway(&host, port, cfg).await + crate::openhuman::gateway::run_gateway(&host, port, cfg).await } }, )); @@ -143,11 +143,11 @@ pub async fn run_full( max_backoff, move || { let cfg = channels_cfg.clone(); - async move { crate::alphahuman::channels::start_channels(cfg).await } + async move { crate::openhuman::channels::start_channels(cfg).await } }, )); } else { - crate::alphahuman::health::mark_component_ok("channels"); + crate::openhuman::health::mark_component_ok("channels"); log::info!("No real-time channels configured; channel supervisor disabled"); } } @@ -173,20 +173,20 @@ pub async fn run_full( max_backoff, move || { let cfg = scheduler_cfg.clone(); - async move { crate::alphahuman::cron::scheduler::run(cfg).await } + async move { crate::openhuman::cron::scheduler::run(cfg).await } }, )); } else { - crate::alphahuman::health::mark_component_ok("scheduler"); + crate::openhuman::health::mark_component_ok("scheduler"); log::info!("Cron disabled; scheduler supervisor not started"); } - log::info!("[alphahuman] Alphahuman daemon started"); - log::info!("[alphahuman] Gateway: http://{host}:{port}"); - log::info!("[alphahuman] Components: gateway, channels, heartbeat, scheduler"); + log::info!("[openhuman] OpenHuman daemon started"); + log::info!("[openhuman] Gateway: http://{host}:{port}"); + log::info!("[openhuman] Components: gateway, channels, heartbeat, scheduler"); cancel.cancelled().await; - crate::alphahuman::health::mark_component_error("daemon", "shutdown requested"); + crate::openhuman::health::mark_component_error("daemon", "shutdown requested"); for handle in &handles { handle.abort(); @@ -221,7 +221,7 @@ fn spawn_state_writer_full(config: Config, cancel: CancellationToken) -> JoinHan _ = interval.tick() => {}, _ = cancel.cancelled() => break, } - let mut json = crate::alphahuman::health::snapshot_json(); + let mut json = crate::openhuman::health::snapshot_json(); if let Some(obj) = json.as_object_mut() { obj.insert( "written_at".into(), @@ -235,11 +235,11 @@ fn spawn_state_writer_full(config: Config, cancel: CancellationToken) -> JoinHan } async fn run_heartbeat_worker(config: Config) -> Result<()> { - let observer: std::sync::Arc = - std::sync::Arc::from(crate::alphahuman::observability::create_observer( + let observer: std::sync::Arc = + std::sync::Arc::from(crate::openhuman::observability::create_observer( &config.observability, )); - let engine = crate::alphahuman::heartbeat::engine::HeartbeatEngine::new( + let engine = crate::openhuman::heartbeat::engine::HeartbeatEngine::new( config.heartbeat.clone(), config.workspace_dir.clone(), observer, @@ -260,7 +260,7 @@ async fn run_heartbeat_worker(config: Config) -> Result<()> { for task in tasks { let prompt = format!("[Heartbeat Task] {task}"); let temp = config.default_temperature; - if let Err(e) = crate::alphahuman::agent::run( + if let Err(e) = crate::openhuman::agent::run( config.clone(), Some(prompt), None, @@ -270,17 +270,17 @@ async fn run_heartbeat_worker(config: Config) -> Result<()> { ) .await { - crate::alphahuman::health::mark_component_error("heartbeat", e.to_string()); + crate::openhuman::health::mark_component_error("heartbeat", e.to_string()); log::warn!("Heartbeat task failed: {e}"); } else { - crate::alphahuman::health::mark_component_ok("heartbeat"); + crate::openhuman::health::mark_component_ok("heartbeat"); } } } } fn has_supervised_channels(config: &Config) -> bool { - let crate::alphahuman::config::ChannelsConfig { + let crate::openhuman::config::ChannelsConfig { cli: _, // `cli` is not used in the web UI webhook: _, // Managed by the gateway telegram, @@ -327,8 +327,8 @@ async fn spawn_state_writer( let _ = tokio::fs::create_dir_all(parent).await; } - log::info!("[alphahuman] Health state writer starting ({}s intervals)", STATUS_FLUSH_SECONDS); - log::info!("[alphahuman] Health state file: {}", state_path.display()); + log::info!("[openhuman] Health state writer starting ({}s intervals)", STATUS_FLUSH_SECONDS); + log::info!("[openhuman] Health state file: {}", state_path.display()); let mut interval = tokio::time::interval(Duration::from_secs(STATUS_FLUSH_SECONDS)); let mut event_count = 0u64; @@ -338,16 +338,16 @@ async fn spawn_state_writer( _ = interval.tick() => { event_count += 1; if event_count % 12 == 1 { // Log every minute (12 * 5s = 60s) -// log::info!("[alphahuman] Health monitoring active (event #{})", event_count); +// log::info!("[openhuman] Health monitoring active (event #{})", event_count); } }, _ = cancel.cancelled() => { - log::info!("[alphahuman] Health state writer received shutdown signal"); + log::info!("[openhuman] Health state writer received shutdown signal"); break; } } - let mut json = crate::alphahuman::health::snapshot_json(); + let mut json = crate::openhuman::health::snapshot_json(); if let Some(obj) = json.as_object_mut() { obj.insert( "written_at".into(), @@ -360,17 +360,17 @@ async fn spawn_state_writer( } // Emit Tauri event for frontend consumption - // log::debug!("[alphahuman] Emitting health event #{}: {:?}", event_count, json); // Removed noisy log - if let Err(e) = app_handle.emit("alphahuman:health", &json) { - log::error!("[alphahuman] Failed to emit health event #{}: {}", event_count, e); + // log::debug!("[openhuman] Emitting health event #{}: {:?}", event_count, json); // Removed noisy log + if let Err(e) = app_handle.emit("openhuman:health", &json) { + log::error!("[openhuman] Failed to emit health event #{}: {}", event_count, e); } - // log::debug!("[alphahuman] Health event #{} emitted successfully", event_count); // Removed noisy log + // log::debug!("[openhuman] Health event #{} emitted successfully", event_count); // Removed noisy log // Also persist to disk let data = serde_json::to_vec_pretty(&json).unwrap_or_else(|_| b"{}".to_vec()); if let Err(e) = tokio::fs::write(&state_path, data).await { - log::debug!("[alphahuman] Failed to write health state to disk: {}", e); + log::debug!("[openhuman] Failed to write health state to disk: {}", e); } } } @@ -395,10 +395,10 @@ where let max_backoff = max_backoff_secs.max(backoff); loop { - crate::alphahuman::health::mark_component_ok(name); + crate::openhuman::health::mark_component_ok(name); match run_component().await { Ok(()) => { - crate::alphahuman::health::mark_component_error( + crate::openhuman::health::mark_component_error( name, "component exited unexpectedly", ); @@ -407,12 +407,12 @@ where backoff = initial_backoff_secs.max(1); } Err(e) => { - crate::alphahuman::health::mark_component_error(name, e.to_string()); + crate::openhuman::health::mark_component_error(name, e.to_string()); log::error!("Daemon component '{name}' failed: {e}"); } } - crate::alphahuman::health::bump_component_restart(name); + crate::openhuman::health::bump_component_restart(name); tokio::time::sleep(Duration::from_secs(backoff)).await; // Double backoff AFTER sleeping so first error uses initial_backoff backoff = backoff.saturating_mul(2).min(max_backoff); @@ -434,7 +434,7 @@ mod tests { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["th-daemon-test-fail"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); @@ -453,7 +453,7 @@ mod tests { handle.abort(); let _ = handle.await; - let snapshot = crate::alphahuman::health::snapshot_json(); + let snapshot = crate::openhuman::health::snapshot_json(); let component = &snapshot["components"]["th-daemon-test-exit"]; assert_eq!(component["status"], "error"); assert!(component["restart_count"].as_u64().unwrap_or(0) >= 1); diff --git a/src-tauri/src/alphahuman/doctor/mod.rs b/src-tauri/src/openhuman/doctor/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/doctor/mod.rs rename to src-tauri/src/openhuman/doctor/mod.rs index b2b1c8038..1be9cb655 100644 --- a/src-tauri/src/alphahuman/doctor/mod.rs +++ b/src-tauri/src/openhuman/doctor/mod.rs @@ -1,6 +1,6 @@ -//! Diagnostic checks for Alphahuman configuration, workspace health, and daemon state. +//! Diagnostic checks for OpenHuman configuration, workspace health, and daemon state. -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -154,7 +154,7 @@ fn doctor_model_targets(provider_override: Option<&str>) -> Vec { return vec![provider.to_string()]; } - crate::alphahuman::providers::list_providers() + crate::openhuman::providers::list_providers() .into_iter() .map(|provider| provider.name.to_string()) .collect() @@ -178,7 +178,7 @@ pub fn run_models( let mut error_count = 0usize; for provider_name in &targets { - match crate::alphahuman::onboard::run_models_refresh(config, Some(provider_name), !use_cache) + match crate::openhuman::onboard::run_models_refresh(config, Some(provider_name), !use_cache) { Ok(_) => { ok_count += 1; @@ -432,7 +432,7 @@ fn check_config_semantics(config: &Config, items: &mut Vec) { } fn provider_validation_error(name: &str) -> Option { - match crate::alphahuman::providers::create_provider(name, None) { + match crate::openhuman::providers::create_provider(name, None) { Ok(_) => None, Err(err) => Some( err.to_string() @@ -592,7 +592,7 @@ fn workspace_probe_path(workspace_dir: &Path) -> std::path::PathBuf { .duration_since(std::time::UNIX_EPOCH) .map_or(0, |duration| duration.as_nanos()); workspace_dir.join(format!( - ".alphahuman_doctor_probe_{}_{}", + ".openhuman_doctor_probe_{}_{}", std::process::id(), nanos )) @@ -602,7 +602,7 @@ fn workspace_probe_path(workspace_dir: &Path) -> std::path::PathBuf { fn check_daemon_state(config: &Config, items: &mut Vec) { let cat = "daemon"; - let state_file = crate::alphahuman::daemon::state_file_path(config); + let state_file = crate::openhuman::daemon::state_file_path(config); if !state_file.exists() { items.push(DiagnosticItem::error( diff --git a/src-tauri/src/alphahuman/gateway/client.rs b/src-tauri/src/openhuman/gateway/client.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/client.rs rename to src-tauri/src/openhuman/gateway/client.rs diff --git a/src-tauri/src/alphahuman/gateway/constants.rs b/src-tauri/src/openhuman/gateway/constants.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/constants.rs rename to src-tauri/src/openhuman/gateway/constants.rs index d98cf4b6e..223ca7880 100644 --- a/src-tauri/src/alphahuman/gateway/constants.rs +++ b/src-tauri/src/openhuman/gateway/constants.rs @@ -1,6 +1,6 @@ //! Gateway constants and key helpers. -use crate::alphahuman::channels::traits::ChannelMessage; +use crate::openhuman::channels::traits::ChannelMessage; use sha2::{Digest, Sha256}; use uuid::Uuid; diff --git a/src-tauri/src/alphahuman/gateway/handlers/health.rs b/src-tauri/src/openhuman/gateway/handlers/health.rs similarity index 84% rename from src-tauri/src/alphahuman/gateway/handlers/health.rs rename to src-tauri/src/openhuman/gateway/handlers/health.rs index e54ed9505..b8d01ef12 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/health.rs +++ b/src-tauri/src/openhuman/gateway/handlers/health.rs @@ -1,6 +1,6 @@ //! Health and metrics endpoints. -use crate::alphahuman::gateway::state::AppState; +use crate::openhuman::gateway::state::AppState; use axum::{ extract::State, http::{header, StatusCode}, @@ -15,7 +15,7 @@ pub async fn handle_health(State(state): State) -> impl IntoResponse { let body = serde_json::json!({ "status": "ok", "paired": state.pairing.is_paired(), - "runtime": crate::alphahuman::health::snapshot_json(), + "runtime": crate::openhuman::health::snapshot_json(), }); Json(body) } @@ -26,7 +26,7 @@ pub async fn handle_metrics(State(state): State) -> impl IntoResponse .observer .as_ref() .as_any() - .downcast_ref::() + .downcast_ref::() { prom.encode() } else { diff --git a/src-tauri/src/alphahuman/gateway/handlers/linq.rs b/src-tauri/src/openhuman/gateway/handlers/linq.rs similarity index 90% rename from src-tauri/src/alphahuman/gateway/handlers/linq.rs rename to src-tauri/src/openhuman/gateway/handlers/linq.rs index 97478cd9e..33eab88c5 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/linq.rs +++ b/src-tauri/src/openhuman/gateway/handlers/linq.rs @@ -1,11 +1,11 @@ //! Linq webhook handlers. use super::webhook::run_gateway_chat_with_multimodal; -use crate::alphahuman::channels::SendMessage; -use crate::alphahuman::channels::traits::Channel; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::SendMessage; +use crate::openhuman::channels::traits::Channel; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::util::truncate_with_ellipsis; use axum::{ body::Bytes, extract::State, @@ -40,7 +40,7 @@ pub async fn handle_linq_webhook( .and_then(|v| v.to_str().ok()) .unwrap_or(""); - if !crate::alphahuman::channels::linq::verify_linq_signature( + if !crate::openhuman::channels::linq::verify_linq_signature( signing_secret, &body_str, timestamp, @@ -89,7 +89,7 @@ pub async fn handle_linq_webhook( // Auto-save to memory if state.auto_save { - let key = crate::alphahuman::gateway::constants::linq_memory_key(msg); + let key = crate::openhuman::gateway::constants::linq_memory_key(msg); let _ = state .mem .store(&key, &msg.content, MemoryCategory::Conversation, None) diff --git a/src-tauri/src/alphahuman/gateway/handlers/mod.rs b/src-tauri/src/openhuman/gateway/handlers/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/handlers/mod.rs rename to src-tauri/src/openhuman/gateway/handlers/mod.rs diff --git a/src-tauri/src/alphahuman/gateway/handlers/pair.rs b/src-tauri/src/openhuman/gateway/handlers/pair.rs similarity index 92% rename from src-tauri/src/alphahuman/gateway/handlers/pair.rs rename to src-tauri/src/openhuman/gateway/handlers/pair.rs index 8f4ab14a2..6bab051e5 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/pair.rs +++ b/src-tauri/src/openhuman/gateway/handlers/pair.rs @@ -1,10 +1,10 @@ //! Pairing endpoints and token persistence. -use crate::alphahuman::config::Config; -use crate::alphahuman::gateway::client::client_key_from_request; -use crate::alphahuman::gateway::constants::RATE_LIMIT_WINDOW_SECS; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::config::Config; +use crate::openhuman::gateway::client::client_key_from_request; +use crate::openhuman::gateway::constants::RATE_LIMIT_WINDOW_SECS; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::security::pairing::PairingGuard; use anyhow::{Context, Result}; use axum::{ extract::{ConnectInfo, State}, diff --git a/src-tauri/src/alphahuman/gateway/handlers/webhook.rs b/src-tauri/src/openhuman/gateway/handlers/webhook.rs similarity index 84% rename from src-tauri/src/alphahuman/gateway/handlers/webhook.rs rename to src-tauri/src/openhuman/gateway/handlers/webhook.rs index f8f644c9c..539c1ee22 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/webhook.rs +++ b/src-tauri/src/openhuman/gateway/handlers/webhook.rs @@ -1,14 +1,14 @@ //! Webhook endpoint handlers. -use crate::alphahuman::gateway::client::client_key_from_request; -use crate::alphahuman::gateway::constants::{ +use crate::openhuman::gateway::client::client_key_from_request; +use crate::openhuman::gateway::constants::{ hash_webhook_secret, webhook_memory_key, RATE_LIMIT_WINDOW_SECS, }; -use crate::alphahuman::gateway::models::WebhookBody; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::providers::{self, ChatMessage, ProviderCapabilityError}; -use crate::alphahuman::security::pairing::constant_time_eq; +use crate::openhuman::gateway::models::WebhookBody; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::providers::{self, ChatMessage, ProviderCapabilityError}; +use crate::openhuman::security::pairing::constant_time_eq; use axum::{ extract::{ConnectInfo, State}, http::{header, HeaderMap, StatusCode}, @@ -24,7 +24,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( message: &str, ) -> anyhow::Result { let user_messages = vec![ChatMessage::user(message)]; - let image_marker_count = crate::alphahuman::multimodal::count_image_markers(&user_messages); + let image_marker_count = crate::openhuman::multimodal::count_image_markers(&user_messages); if image_marker_count > 0 && !state.provider.supports_vision() { return Err(ProviderCapabilityError { provider: provider_label.to_string(), @@ -40,7 +40,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( // workspace-aware system context before model invocation. let system_prompt = { let config_guard = state.config.lock(); - crate::alphahuman::channels::build_system_prompt( + crate::openhuman::channels::build_system_prompt( &config_guard.workspace_dir, &state.model, &[], // tools - empty for simple chat @@ -56,7 +56,7 @@ pub(crate) async fn run_gateway_chat_with_multimodal( let multimodal_config = state.config.lock().multimodal.clone(); let prepared = - crate::alphahuman::multimodal::prepare_messages_for_provider(&messages, &multimodal_config) + crate::openhuman::multimodal::prepare_messages_for_provider(&messages, &multimodal_config) .await?; state @@ -181,13 +181,13 @@ pub async fn handle_webhook( state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentStart { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentStart { provider: provider_label.clone(), model: model_label.clone(), }); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmRequest { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmRequest { provider: provider_label.clone(), model: model_label.clone(), messages_count: 1, @@ -198,7 +198,7 @@ pub async fn handle_webhook( let duration = started_at.elapsed(); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmResponse { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmResponse { provider: provider_label.clone(), model: model_label.clone(), duration, @@ -206,11 +206,11 @@ pub async fn handle_webhook( error_message: None, }); state.observer.record_metric( - &crate::alphahuman::observability::traits::ObserverMetric::RequestLatency(duration), + &crate::openhuman::observability::traits::ObserverMetric::RequestLatency(duration), ); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentEnd { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentEnd { provider: provider_label, model: model_label, duration, @@ -227,7 +227,7 @@ pub async fn handle_webhook( state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::LlmResponse { + .record_event(&crate::openhuman::observability::ObserverEvent::LlmResponse { provider: provider_label.clone(), model: model_label.clone(), duration, @@ -235,17 +235,17 @@ pub async fn handle_webhook( error_message: Some(sanitized.clone()), }); state.observer.record_metric( - &crate::alphahuman::observability::traits::ObserverMetric::RequestLatency(duration), + &crate::openhuman::observability::traits::ObserverMetric::RequestLatency(duration), ); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::Error { + .record_event(&crate::openhuman::observability::ObserverEvent::Error { component: "gateway".to_string(), message: sanitized.clone(), }); state .observer - .record_event(&crate::alphahuman::observability::ObserverEvent::AgentEnd { + .record_event(&crate::openhuman::observability::ObserverEvent::AgentEnd { provider: provider_label, model: model_label, duration, diff --git a/src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs b/src-tauri/src/openhuman/gateway/handlers/whatsapp.rs similarity index 92% rename from src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs rename to src-tauri/src/openhuman/gateway/handlers/whatsapp.rs index 3cb6e3276..af0833860 100644 --- a/src-tauri/src/alphahuman/gateway/handlers/whatsapp.rs +++ b/src-tauri/src/openhuman/gateway/handlers/whatsapp.rs @@ -1,13 +1,13 @@ //! WhatsApp webhook handlers and signature verification. use super::webhook::run_gateway_chat_with_multimodal; -use crate::alphahuman::channels::SendMessage; -use crate::alphahuman::channels::traits::Channel; -use crate::alphahuman::gateway::models::WhatsAppVerifyQuery; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::MemoryCategory; -use crate::alphahuman::security::pairing::constant_time_eq; -use crate::alphahuman::util::truncate_with_ellipsis; +use crate::openhuman::channels::SendMessage; +use crate::openhuman::channels::traits::Channel; +use crate::openhuman::gateway::models::WhatsAppVerifyQuery; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::MemoryCategory; +use crate::openhuman::security::pairing::constant_time_eq; +use crate::openhuman::util::truncate_with_ellipsis; use axum::{ body::Bytes, extract::{Query, State}, @@ -132,7 +132,7 @@ pub async fn handle_whatsapp_message( // Auto-save to memory if state.auto_save { - let key = crate::alphahuman::gateway::constants::whatsapp_memory_key(msg); + let key = crate::openhuman::gateway::constants::whatsapp_memory_key(msg); let _ = state .mem .store(&key, &msg.content, MemoryCategory::Conversation, None) diff --git a/src-tauri/src/alphahuman/gateway/mod.rs b/src-tauri/src/openhuman/gateway/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/mod.rs rename to src-tauri/src/openhuman/gateway/mod.rs diff --git a/src-tauri/src/alphahuman/gateway/models.rs b/src-tauri/src/openhuman/gateway/models.rs similarity index 100% rename from src-tauri/src/alphahuman/gateway/models.rs rename to src-tauri/src/openhuman/gateway/models.rs diff --git a/src-tauri/src/alphahuman/gateway/rate_limit.rs b/src-tauri/src/openhuman/gateway/rate_limit.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/rate_limit.rs rename to src-tauri/src/openhuman/gateway/rate_limit.rs index 9d5ba20cb..8cc5763b7 100644 --- a/src-tauri/src/alphahuman/gateway/rate_limit.rs +++ b/src-tauri/src/openhuman/gateway/rate_limit.rs @@ -1,6 +1,6 @@ //! Rate limiting and idempotency utilities for the gateway. -use crate::alphahuman::gateway::constants::RATE_LIMITER_SWEEP_INTERVAL_SECS; +use crate::openhuman::gateway::constants::RATE_LIMITER_SWEEP_INTERVAL_SECS; use parking_lot::Mutex; use std::collections::HashMap; use std::time::{Duration, Instant}; @@ -85,7 +85,7 @@ pub struct GatewayRateLimiter { impl GatewayRateLimiter { pub fn new(pair_per_minute: u32, webhook_per_minute: u32, max_keys: usize) -> Self { - let window = Duration::from_secs(crate::alphahuman::gateway::constants::RATE_LIMIT_WINDOW_SECS); + let window = Duration::from_secs(crate::openhuman::gateway::constants::RATE_LIMIT_WINDOW_SECS); Self { pair: SlidingWindowRateLimiter::new(pair_per_minute, window, max_keys), webhook: SlidingWindowRateLimiter::new(webhook_per_minute, window, max_keys), diff --git a/src-tauri/src/alphahuman/gateway/server.rs b/src-tauri/src/openhuman/gateway/server.rs similarity index 87% rename from src-tauri/src/alphahuman/gateway/server.rs rename to src-tauri/src/openhuman/gateway/server.rs index ee2ecf2bf..9e90fbde9 100644 --- a/src-tauri/src/alphahuman/gateway/server.rs +++ b/src-tauri/src/openhuman/gateway/server.rs @@ -1,24 +1,24 @@ //! Gateway server bootstrap and router wiring. -use crate::alphahuman::channels::{LinqChannel, WhatsAppChannel}; -use crate::alphahuman::config::Config; -use crate::alphahuman::gateway::client::normalize_max_keys; -use crate::alphahuman::gateway::constants::{ +use crate::openhuman::channels::{LinqChannel, WhatsAppChannel}; +use crate::openhuman::config::Config; +use crate::openhuman::gateway::client::normalize_max_keys; +use crate::openhuman::gateway::constants::{ hash_webhook_secret, IDEMPOTENCY_MAX_KEYS_DEFAULT, MAX_BODY_SIZE, RATE_LIMIT_MAX_KEYS_DEFAULT, REQUEST_TIMEOUT_SECS, }; -use crate::alphahuman::gateway::handlers::{ +use crate::openhuman::gateway::handlers::{ handle_health, handle_linq_webhook, handle_metrics, handle_pair, handle_webhook, handle_whatsapp_message, handle_whatsapp_verify, }; -use crate::alphahuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; -use crate::alphahuman::gateway::state::AppState; -use crate::alphahuman::memory::{self, Memory}; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::runtime; -use crate::alphahuman::security::pairing::is_public_bind; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::tools; +use crate::openhuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; +use crate::openhuman::gateway::state::AppState; +use crate::openhuman::memory::{self, Memory}; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::runtime; +use crate::openhuman::security::pairing::is_public_bind; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::tools; use anyhow::Result; use axum::http::StatusCode; use axum::routing::{get, post}; @@ -56,7 +56,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { &config.reliability, &providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: config.config_path.parent().map(std::path::PathBuf::from), + openhuman_dir: config.config_path.parent().map(std::path::PathBuf::from), secrets_encrypt: config.secrets.encrypt, reasoning_enabled: config.runtime.reasoning_enabled, }, @@ -129,7 +129,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { // WhatsApp app secret for webhook signature verification // Priority: environment variable > config file - let whatsapp_app_secret: Option> = std::env::var("ALPHAHUMAN_WHATSAPP_APP_SECRET") + let whatsapp_app_secret: Option> = std::env::var("OPENHUMAN_WHATSAPP_APP_SECRET") .ok() .and_then(|secret| { let secret = secret.trim(); @@ -157,7 +157,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { // Linq signing secret for webhook signature verification // Priority: environment variable > config file - let linq_signing_secret: Option> = std::env::var("ALPHAHUMAN_LINQ_SIGNING_SECRET") + let linq_signing_secret: Option> = std::env::var("OPENHUMAN_LINQ_SIGNING_SECRET") .ok() .and_then(|secret| { let secret = secret.trim(); @@ -175,7 +175,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { .map(Arc::from); // ── Pairing guard ────────────────────────────────────── - let pairing = Arc::new(crate::alphahuman::security::pairing::PairingGuard::new( + let pairing = Arc::new(crate::openhuman::security::pairing::PairingGuard::new( config.gateway.require_pairing, &config.gateway.paired_tokens, )); @@ -198,7 +198,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { )); // ── Tunnel ──────────────────────────────────────────────── - let tunnel = crate::alphahuman::tunnel::create_tunnel(&config.tunnel)?; + let tunnel = crate::openhuman::tunnel::create_tunnel(&config.tunnel)?; let mut tunnel_url: Option = None; if let Some(ref tun) = tunnel { @@ -215,7 +215,7 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { } } - println!("🦀 Alphahuman Gateway listening on http://{display_addr}"); + println!("🦀 OpenHuman Gateway listening on http://{display_addr}"); if let Some(ref url) = tunnel_url { println!(" 🌐 Public URL: {url}"); } @@ -244,11 +244,11 @@ pub async fn run_gateway(host: &str, port: u16, config: Config) -> Result<()> { } println!(" Press Ctrl+C to stop.\n"); - crate::alphahuman::health::mark_component_ok("gateway"); + crate::openhuman::health::mark_component_ok("gateway"); // Build shared state - let observer: Arc = - Arc::from(crate::alphahuman::observability::create_observer(&config.observability)); + let observer: Arc = + Arc::from(crate::openhuman::observability::create_observer(&config.observability)); let state = AppState { config: config_state, diff --git a/src-tauri/src/alphahuman/gateway/state.rs b/src-tauri/src/openhuman/gateway/state.rs similarity index 72% rename from src-tauri/src/alphahuman/gateway/state.rs rename to src-tauri/src/openhuman/gateway/state.rs index 0766c3050..477b937f4 100644 --- a/src-tauri/src/alphahuman/gateway/state.rs +++ b/src-tauri/src/openhuman/gateway/state.rs @@ -1,11 +1,11 @@ //! Shared gateway state for axum handlers. -use crate::alphahuman::channels::{LinqChannel, WhatsAppChannel}; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::providers::Provider; -use crate::alphahuman::security::pairing::PairingGuard; -use crate::alphahuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; +use crate::openhuman::channels::{LinqChannel, WhatsAppChannel}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::Memory; +use crate::openhuman::providers::Provider; +use crate::openhuman::security::pairing::PairingGuard; +use crate::openhuman::gateway::rate_limit::{GatewayRateLimiter, IdempotencyStore}; use parking_lot::Mutex; use std::sync::Arc; @@ -31,5 +31,5 @@ pub struct AppState { /// Linq webhook signing secret for signature verification. pub linq_signing_secret: Option>, /// Observability backend for metrics scraping. - pub observer: Arc, + pub observer: Arc, } diff --git a/src-tauri/src/alphahuman/gateway/tests.rs b/src-tauri/src/openhuman/gateway/tests.rs similarity index 96% rename from src-tauri/src/alphahuman/gateway/tests.rs rename to src-tauri/src/openhuman/gateway/tests.rs index 9a3f52bd2..bf2339a8a 100644 --- a/src-tauri/src/alphahuman/gateway/tests.rs +++ b/src-tauri/src/openhuman/gateway/tests.rs @@ -12,11 +12,11 @@ use super::handlers::{ use super::models::{WebhookBody, WhatsAppVerifyQuery}; use super::rate_limit::{GatewayRateLimiter, IdempotencyStore, SlidingWindowRateLimiter}; use super::state::AppState; -use crate::alphahuman::channels::traits::ChannelMessage; -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{Memory, MemoryCategory, MemoryEntry}; -use crate::alphahuman::providers::Provider; -use crate::alphahuman::security::pairing::PairingGuard; +use crate::openhuman::channels::traits::ChannelMessage; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{Memory, MemoryCategory, MemoryEntry}; +use crate::openhuman::providers::Provider; +use crate::openhuman::security::pairing::PairingGuard; use async_trait::async_trait; use axum::extract::ConnectInfo; use axum::http::HeaderValue; @@ -101,7 +101,7 @@ async fn metrics_endpoint_returns_hint_when_prometheus_is_disabled() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_metrics(axum::extract::State(state)).await.into_response(); @@ -121,13 +121,13 @@ async fn metrics_endpoint_returns_hint_when_prometheus_is_disabled() { #[tokio::test] async fn metrics_endpoint_renders_prometheus_output() { - let prom = Arc::new(crate::alphahuman::observability::PrometheusObserver::new()); - crate::alphahuman::observability::Observer::record_event( + let prom = Arc::new(crate::openhuman::observability::PrometheusObserver::new()); + crate::openhuman::observability::Observer::record_event( prom.as_ref(), - &crate::alphahuman::observability::ObserverEvent::HeartbeatTick, + &crate::openhuman::observability::ObserverEvent::HeartbeatTick, ); - let observer: Arc = prom; + let observer: Arc = prom; let state = AppState { config: Arc::new(Mutex::new(Config::default())), provider: Arc::new(MockProvider::default()), @@ -152,7 +152,7 @@ async fn metrics_endpoint_renders_prometheus_output() { let body = response.into_body().collect().await.unwrap().to_bytes(); let text = String::from_utf8(body.to_vec()).unwrap(); - assert!(text.contains("alphahuman_heartbeat_ticks_total 1")); + assert!(text.contains("openhuman_heartbeat_ticks_total 1")); } #[test] @@ -519,7 +519,7 @@ async fn webhook_idempotency_skips_duplicate_provider_calls() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -578,7 +578,7 @@ async fn webhook_autosave_stores_distinct_keys_per_request() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let headers = HeaderMap::new(); @@ -649,7 +649,7 @@ async fn webhook_secret_hash_rejects_missing_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_webhook( @@ -689,7 +689,7 @@ async fn webhook_secret_hash_rejects_invalid_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -734,7 +734,7 @@ async fn webhook_secret_hash_accepts_valid_header() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let mut headers = HeaderMap::new(); @@ -775,7 +775,7 @@ async fn webhook_missing_message_returns_bad_request() { whatsapp_app_secret: None, linq: None, linq_signing_secret: None, - observer: Arc::new(crate::alphahuman::observability::NoopObserver), + observer: Arc::new(crate::openhuman::observability::NoopObserver), }; let response = handle_webhook( diff --git a/src-tauri/src/alphahuman/hardware/discover.rs b/src-tauri/src/openhuman/hardware/discover.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/discover.rs rename to src-tauri/src/openhuman/hardware/discover.rs diff --git a/src-tauri/src/alphahuman/hardware/introspect.rs b/src-tauri/src/openhuman/hardware/introspect.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/introspect.rs rename to src-tauri/src/openhuman/hardware/introspect.rs diff --git a/src-tauri/src/alphahuman/hardware/mod.rs b/src-tauri/src/openhuman/hardware/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/hardware/mod.rs rename to src-tauri/src/openhuman/hardware/mod.rs index 851a350fc..d5f5cb9e9 100644 --- a/src-tauri/src/alphahuman/hardware/mod.rs +++ b/src-tauri/src/openhuman/hardware/mod.rs @@ -14,7 +14,7 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; // Re-export config types so UI flows can use `hardware::HardwareConfig` etc. -pub use crate::alphahuman::config::{HardwareConfig, HardwareTransport}; +pub use crate::openhuman::config::{HardwareConfig, HardwareTransport}; /// A hardware device discovered during auto-scan. #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src-tauri/src/alphahuman/hardware/registry.rs b/src-tauri/src/openhuman/hardware/registry.rs similarity index 100% rename from src-tauri/src/alphahuman/hardware/registry.rs rename to src-tauri/src/openhuman/hardware/registry.rs diff --git a/src-tauri/src/alphahuman/health/mod.rs b/src-tauri/src/openhuman/health/mod.rs similarity index 95% rename from src-tauri/src/alphahuman/health/mod.rs rename to src-tauri/src/openhuman/health/mod.rs index d0f772b4b..0231aebf3 100644 --- a/src-tauri/src/alphahuman/health/mod.rs +++ b/src-tauri/src/openhuman/health/mod.rs @@ -60,7 +60,7 @@ where } pub fn mark_component_ok(component: &str) { - log::debug!("[alphahuman:health] Component '{}' marked OK", component); + log::debug!("[openhuman:health] Component '{}' marked OK", component); upsert_component(component, |entry| { entry.status = "ok".into(); entry.last_ok = Some(now_rfc3339()); @@ -71,7 +71,7 @@ pub fn mark_component_ok(component: &str) { #[allow(clippy::needless_pass_by_value)] pub fn mark_component_error(component: &str, error: impl ToString) { let err = error.to_string(); - log::warn!("[alphahuman:health] Component '{}' error: {}", component, err); + log::warn!("[openhuman:health] Component '{}' error: {}", component, err); upsert_component(component, move |entry| { entry.status = "error".into(); entry.last_error = Some(err); @@ -79,7 +79,7 @@ pub fn mark_component_error(component: &str, error: impl ToString) { } pub fn bump_component_restart(component: &str) { - log::info!("[alphahuman:health] Component '{}' restarting", component); + log::info!("[openhuman:health] Component '{}' restarting", component); upsert_component(component, |entry| { entry.restart_count = entry.restart_count.saturating_add(1); }); diff --git a/src-tauri/src/alphahuman/heartbeat/engine.rs b/src-tauri/src/openhuman/heartbeat/engine.rs similarity index 92% rename from src-tauri/src/alphahuman/heartbeat/engine.rs rename to src-tauri/src/openhuman/heartbeat/engine.rs index 9dab3ada6..ca42baa80 100644 --- a/src-tauri/src/alphahuman/heartbeat/engine.rs +++ b/src-tauri/src/openhuman/heartbeat/engine.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::HeartbeatConfig; -use crate::alphahuman::observability::{Observer, ObserverEvent}; +use crate::openhuman::config::HeartbeatConfig; +use crate::openhuman::observability::{Observer, ObserverEvent}; use anyhow::Result; use std::path::Path; use std::sync::Arc; @@ -206,7 +206,7 @@ mod tests { #[tokio::test] async fn ensure_heartbeat_file_creates_file() { - let dir = std::env::temp_dir().join("alphahuman_test_heartbeat"); + let dir = std::env::temp_dir().join("openhuman_test_heartbeat"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -222,7 +222,7 @@ mod tests { #[tokio::test] async fn ensure_heartbeat_file_does_not_overwrite() { - let dir = std::env::temp_dir().join("alphahuman_test_heartbeat_no_overwrite"); + let dir = std::env::temp_dir().join("openhuman_test_heartbeat_no_overwrite"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -239,11 +239,11 @@ mod tests { #[tokio::test] async fn tick_returns_zero_when_no_file() { - let dir = std::env::temp_dir().join("alphahuman_test_tick_no_file"); + let dir = std::env::temp_dir().join("openhuman_test_tick_no_file"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: true, @@ -260,7 +260,7 @@ mod tests { #[tokio::test] async fn tick_counts_tasks_from_file() { - let dir = std::env::temp_dir().join("alphahuman_test_tick_count"); + let dir = std::env::temp_dir().join("openhuman_test_tick_count"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -268,7 +268,7 @@ mod tests { .await .unwrap(); - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: true, @@ -285,7 +285,7 @@ mod tests { #[tokio::test] async fn run_returns_immediately_when_disabled() { - let observer: Arc = Arc::new(crate::alphahuman::observability::NoopObserver); + let observer: Arc = Arc::new(crate::openhuman::observability::NoopObserver); let engine = HeartbeatEngine::new( HeartbeatConfig { enabled: false, diff --git a/src-tauri/src/alphahuman/heartbeat/mod.rs b/src-tauri/src/openhuman/heartbeat/mod.rs similarity index 81% rename from src-tauri/src/alphahuman/heartbeat/mod.rs rename to src-tauri/src/openhuman/heartbeat/mod.rs index d5d300e57..9954525db 100644 --- a/src-tauri/src/alphahuman/heartbeat/mod.rs +++ b/src-tauri/src/openhuman/heartbeat/mod.rs @@ -2,9 +2,9 @@ pub mod engine; #[cfg(test)] mod tests { - use crate::alphahuman::config::HeartbeatConfig; - use crate::alphahuman::heartbeat::engine::HeartbeatEngine; - use crate::alphahuman::observability::NoopObserver; + use crate::openhuman::config::HeartbeatConfig; + use crate::openhuman::heartbeat::engine::HeartbeatEngine; + use crate::openhuman::observability::NoopObserver; use std::sync::Arc; #[test] diff --git a/src-tauri/src/alphahuman/identity.rs b/src-tauri/src/openhuman/identity.rs similarity index 99% rename from src-tauri/src/alphahuman/identity.rs rename to src-tauri/src/openhuman/identity.rs index 0450a43d3..0dd894c9d 100644 --- a/src-tauri/src/alphahuman/identity.rs +++ b/src-tauri/src/openhuman/identity.rs @@ -2,9 +2,9 @@ //! //! AIEOS (AI Entity Object Specification) is a standardization framework for //! portable AI identity. This module handles loading and converting AIEOS v1.1 -//! JSON to Alphahuman's system prompt format. +//! JSON to OpenHuman's system prompt format. -use crate::alphahuman::config::IdentityConfig; +use crate::openhuman::config::IdentityConfig; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; @@ -714,7 +714,7 @@ fn non_empty_list_at(value: &Value, path: &[&str]) -> Option> { /// Convert AIEOS identity to a system prompt string. /// /// Formats the AIEOS data into a structured markdown prompt compatible -/// with Alphahuman's agent system. +/// with OpenHuman's agent system. pub fn aieos_to_system_prompt(identity: &AieosIdentity) -> String { use std::fmt::Write; let mut prompt = String::new(); @@ -986,7 +986,7 @@ mod tests { use super::*; fn test_workspace_dir() -> PathBuf { - std::env::temp_dir().join("alphahuman-test-identity") + std::env::temp_dir().join("openhuman-test-identity") } #[test] diff --git a/src-tauri/src/alphahuman/integrations/mod.rs b/src-tauri/src/openhuman/integrations/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/integrations/mod.rs rename to src-tauri/src/openhuman/integrations/mod.rs index 04f542136..e28f01f04 100644 --- a/src-tauri/src/alphahuman/integrations/mod.rs +++ b/src-tauri/src/openhuman/integrations/mod.rs @@ -2,7 +2,7 @@ pub mod registry; -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::Result; use serde::{Deserialize, Serialize}; diff --git a/src-tauri/src/alphahuman/integrations/registry.rs b/src-tauri/src/openhuman/integrations/registry.rs similarity index 99% rename from src-tauri/src/alphahuman/integrations/registry.rs rename to src-tauri/src/openhuman/integrations/registry.rs index 4d58fe979..61b97e0c9 100644 --- a/src-tauri/src/alphahuman/integrations/registry.rs +++ b/src-tauri/src/openhuman/integrations/registry.rs @@ -1,5 +1,5 @@ use super::{IntegrationCategory, IntegrationEntry, IntegrationStatus}; -use crate::alphahuman::providers::{ +use crate::openhuman::providers::{ is_glm_alias, is_minimax_alias, is_moonshot_alias, is_qianfan_alias, is_qwen_alias, is_zai_alias, }; @@ -725,8 +725,8 @@ pub fn all_integrations() -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::schema::{IMessageConfig, MatrixConfig, StreamMode, TelegramConfig}; - use crate::alphahuman::config::Config; + use crate::openhuman::config::schema::{IMessageConfig, MatrixConfig, StreamMode, TelegramConfig}; + use crate::openhuman::config::Config; #[test] fn registry_has_entries() { diff --git a/src-tauri/src/alphahuman/memory/backend.rs b/src-tauri/src/openhuman/memory/backend.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/backend.rs rename to src-tauri/src/openhuman/memory/backend.rs diff --git a/src-tauri/src/alphahuman/memory/chunker.rs b/src-tauri/src/openhuman/memory/chunker.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/chunker.rs rename to src-tauri/src/openhuman/memory/chunker.rs diff --git a/src-tauri/src/alphahuman/memory/embeddings.rs b/src-tauri/src/openhuman/memory/embeddings.rs similarity index 99% rename from src-tauri/src/alphahuman/memory/embeddings.rs rename to src-tauri/src/openhuman/memory/embeddings.rs index 08eed7f58..d534bbd2f 100644 --- a/src-tauri/src/alphahuman/memory/embeddings.rs +++ b/src-tauri/src/openhuman/memory/embeddings.rs @@ -60,7 +60,7 @@ impl OpenAiEmbedding { } fn http_client(&self) -> reqwest::Client { - crate::alphahuman::config::build_runtime_proxy_client("memory.embeddings") + crate::openhuman::config::build_runtime_proxy_client("memory.embeddings") } fn has_explicit_api_path(&self) -> bool { diff --git a/src-tauri/src/alphahuman/memory/hygiene.rs b/src-tauri/src/openhuman/memory/hygiene.rs similarity index 99% rename from src-tauri/src/alphahuman/memory/hygiene.rs rename to src-tauri/src/openhuman/memory/hygiene.rs index d80bd8c5a..9390a2c1d 100644 --- a/src-tauri/src/alphahuman/memory/hygiene.rs +++ b/src-tauri/src/openhuman/memory/hygiene.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::config::MemoryConfig; +use crate::openhuman::config::MemoryConfig; use anyhow::Result; use chrono::{DateTime, Duration, Local, NaiveDate, Utc}; use rusqlite::{params, Connection}; @@ -379,7 +379,7 @@ fn split_name(filename: &str) -> (&str, &str) { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{Memory, MemoryCategory, SqliteMemory}; + use crate::openhuman::memory::{Memory, MemoryCategory, SqliteMemory}; use tempfile::TempDir; fn default_cfg() -> MemoryConfig { diff --git a/src-tauri/src/alphahuman/memory/lucid.rs b/src-tauri/src/openhuman/memory/lucid.rs similarity index 98% rename from src-tauri/src/alphahuman/memory/lucid.rs rename to src-tauri/src/openhuman/memory/lucid.rs index 51d41a147..017fd72a4 100644 --- a/src-tauri/src/alphahuman/memory/lucid.rs +++ b/src-tauri/src/openhuman/memory/lucid.rs @@ -32,32 +32,32 @@ impl LucidMemory { const DEFAULT_FAILURE_COOLDOWN_MS: u64 = 15_000; pub fn new(workspace_dir: &Path, local: SqliteMemory) -> Self { - let lucid_cmd = std::env::var("ALPHAHUMAN_LUCID_CMD") + let lucid_cmd = std::env::var("OPENHUMAN_LUCID_CMD") .unwrap_or_else(|_| Self::DEFAULT_LUCID_CMD.to_string()); - let token_budget = std::env::var("ALPHAHUMAN_LUCID_BUDGET") + let token_budget = std::env::var("OPENHUMAN_LUCID_BUDGET") .ok() .and_then(|v| v.parse::().ok()) .filter(|v| *v > 0) .unwrap_or(Self::DEFAULT_TOKEN_BUDGET); let recall_timeout = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_RECALL_TIMEOUT_MS", + "OPENHUMAN_LUCID_RECALL_TIMEOUT_MS", Self::DEFAULT_RECALL_TIMEOUT_MS, 20, ); let store_timeout = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_STORE_TIMEOUT_MS", + "OPENHUMAN_LUCID_STORE_TIMEOUT_MS", Self::DEFAULT_STORE_TIMEOUT_MS, 50, ); let local_hit_threshold = Self::read_env_usize( - "ALPHAHUMAN_LUCID_LOCAL_HIT_THRESHOLD", + "OPENHUMAN_LUCID_LOCAL_HIT_THRESHOLD", Self::DEFAULT_LOCAL_HIT_THRESHOLD, 1, ); let failure_cooldown = Self::read_env_duration_ms( - "ALPHAHUMAN_LUCID_FAILURE_COOLDOWN_MS", + "OPENHUMAN_LUCID_FAILURE_COOLDOWN_MS", Self::DEFAULT_FAILURE_COOLDOWN_MS, 100, ); diff --git a/src-tauri/src/alphahuman/memory/markdown.rs b/src-tauri/src/openhuman/memory/markdown.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/markdown.rs rename to src-tauri/src/openhuman/memory/markdown.rs diff --git a/src-tauri/src/alphahuman/memory/mod.rs b/src-tauri/src/openhuman/memory/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/memory/mod.rs rename to src-tauri/src/openhuman/memory/mod.rs index dd77753c3..f9d6bc917 100644 --- a/src-tauri/src/alphahuman/memory/mod.rs +++ b/src-tauri/src/openhuman/memory/mod.rs @@ -27,7 +27,7 @@ pub use traits::Memory; #[allow(unused_imports)] pub use traits::{MemoryCategory, MemoryEntry}; -use crate::alphahuman::config::{EmbeddingRouteConfig, MemoryConfig, StorageProviderConfig}; +use crate::openhuman::config::{EmbeddingRouteConfig, MemoryConfig, StorageProviderConfig}; use anyhow::Context; use std::path::Path; use std::sync::Arc; @@ -329,7 +329,7 @@ pub fn create_response_cache(config: &MemoryConfig, workspace_dir: &Path) -> Opt #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{EmbeddingRouteConfig, StorageProviderConfig}; + use crate::openhuman::config::{EmbeddingRouteConfig, StorageProviderConfig}; use tempfile::TempDir; #[test] diff --git a/src-tauri/src/alphahuman/memory/none.rs b/src-tauri/src/openhuman/memory/none.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/none.rs rename to src-tauri/src/openhuman/memory/none.rs diff --git a/src-tauri/src/alphahuman/memory/postgres.rs b/src-tauri/src/openhuman/memory/postgres.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/postgres.rs rename to src-tauri/src/openhuman/memory/postgres.rs diff --git a/src-tauri/src/alphahuman/memory/response_cache.rs b/src-tauri/src/openhuman/memory/response_cache.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/response_cache.rs rename to src-tauri/src/openhuman/memory/response_cache.rs diff --git a/src-tauri/src/alphahuman/memory/snapshot.rs b/src-tauri/src/openhuman/memory/snapshot.rs similarity index 97% rename from src-tauri/src/alphahuman/memory/snapshot.rs rename to src-tauri/src/openhuman/memory/snapshot.rs index 15e0c10da..9886b0782 100644 --- a/src-tauri/src/alphahuman/memory/snapshot.rs +++ b/src-tauri/src/openhuman/memory/snapshot.rs @@ -17,8 +17,8 @@ use std::path::{Path, PathBuf}; pub const SNAPSHOT_FILENAME: &str = "MEMORY_SNAPSHOT.md"; /// Header written at the top of every snapshot file. -const SNAPSHOT_HEADER: &str = "# 🧠 Alphahuman Memory Snapshot\n\n\ - > Auto-generated by Alphahuman. Do not edit manually unless you know what you're doing.\n\ +const SNAPSHOT_HEADER: &str = "# 🧠 OpenHuman Memory Snapshot\n\n\ + > Auto-generated by OpenHuman. Do not edit manually unless you know what you're doing.\n\ > This file is the \"soul\" of your agent — if `brain.db` is lost, start the agent\n\ > in this workspace and it will auto-hydrate from this file.\n\n"; @@ -266,9 +266,9 @@ mod tests { #[test] fn parse_snapshot_basic() { - let input = r#"# 🧠 Alphahuman Memory Snapshot + let input = r#"# 🧠 OpenHuman Memory Snapshot -> Auto-generated by Alphahuman. +> Auto-generated by OpenHuman. **Last exported:** 2025-01-15 14:30:00 @@ -278,7 +278,7 @@ mod tests { ### 🔑 `identity` -I am Alphahuman, a self-preserving AI agent. +I am OpenHuman, a self-preserving AI agent. *Created: 2025-01-15 | Updated: 2025-01-15* @@ -303,7 +303,7 @@ The user prefers Rust for systems programming. #[test] fn parse_snapshot_empty() { - let input = "# 🧠 Alphahuman Memory Snapshot\n\n> Nothing here.\n"; + let input = "# 🧠 OpenHuman Memory Snapshot\n\n> Nothing here.\n"; let entries = parse_snapshot(input); assert!(entries.is_empty()); } diff --git a/src-tauri/src/alphahuman/memory/sqlite.rs b/src-tauri/src/openhuman/memory/sqlite.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/sqlite.rs rename to src-tauri/src/openhuman/memory/sqlite.rs diff --git a/src-tauri/src/alphahuman/memory/traits.rs b/src-tauri/src/openhuman/memory/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/traits.rs rename to src-tauri/src/openhuman/memory/traits.rs diff --git a/src-tauri/src/alphahuman/memory/vector.rs b/src-tauri/src/openhuman/memory/vector.rs similarity index 100% rename from src-tauri/src/alphahuman/memory/vector.rs rename to src-tauri/src/openhuman/memory/vector.rs diff --git a/src-tauri/src/alphahuman/migration.rs b/src-tauri/src/openhuman/migration.rs similarity index 98% rename from src-tauri/src/alphahuman/migration.rs rename to src-tauri/src/openhuman/migration.rs index 5e4209367..d4fc4295d 100644 --- a/src-tauri/src/alphahuman/migration.rs +++ b/src-tauri/src/openhuman/migration.rs @@ -1,7 +1,7 @@ -//! Data migration helpers for Alphahuman. +//! Data migration helpers for OpenHuman. -use crate::alphahuman::config::Config; -use crate::alphahuman::memory::{self, Memory, MemoryCategory}; +use crate::openhuman::config::Config; +use crate::openhuman::memory::{self, Memory, MemoryCategory}; use anyhow::{bail, Context, Result}; use directories::UserDirs; use rusqlite::{Connection, OpenFlags, OptionalExtension}; @@ -49,7 +49,7 @@ pub async fn migrate_openclaw_memory( } if paths_equal(&source_workspace, &config.workspace_dir) { - bail!("Source workspace matches current Alphahuman workspace; refusing self-migration"); + bail!("Source workspace matches current OpenHuman workspace; refusing self-migration"); } let mut stats = MigrationStats::default(); diff --git a/src-tauri/src/alphahuman/mod.rs b/src-tauri/src/openhuman/mod.rs similarity index 89% rename from src-tauri/src/alphahuman/mod.rs rename to src-tauri/src/openhuman/mod.rs index dc043bbf3..5a0b1cbf1 100644 --- a/src-tauri/src/alphahuman/mod.rs +++ b/src-tauri/src/openhuman/mod.rs @@ -1,6 +1,6 @@ -//! Alphahuman — lightweight agent runtime for AlphaHuman. +//! OpenHuman — lightweight agent runtime for OpenHuman. //! -//! Ported from Alphahuman (MIT-licensed). Provides: +//! Ported from OpenHuman (MIT-licensed). Provides: //! - Health registry for component monitoring //! - Security policy, secrets, audit, pairing, and sandboxing //! - Daemon supervisor with exponential backoff diff --git a/src-tauri/src/alphahuman/multimodal.rs b/src-tauri/src/openhuman/multimodal.rs similarity index 99% rename from src-tauri/src/alphahuman/multimodal.rs rename to src-tauri/src/openhuman/multimodal.rs index 36c561887..6fe514d1f 100644 --- a/src-tauri/src/alphahuman/multimodal.rs +++ b/src-tauri/src/openhuman/multimodal.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::config::{build_runtime_proxy_client_with_timeouts, MultimodalConfig}; -use crate::alphahuman::providers::ChatMessage; +use crate::openhuman::config::{build_runtime_proxy_client_with_timeouts, MultimodalConfig}; +use crate::openhuman::providers::ChatMessage; use base64::{engine::general_purpose::STANDARD, Engine as _}; use reqwest::Client; use std::path::Path; diff --git a/src-tauri/src/alphahuman/observability/log.rs b/src-tauri/src/openhuman/observability/log.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/log.rs rename to src-tauri/src/openhuman/observability/log.rs diff --git a/src-tauri/src/alphahuman/observability/mod.rs b/src-tauri/src/openhuman/observability/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/observability/mod.rs rename to src-tauri/src/openhuman/observability/mod.rs index fff8421d1..b96285f3b 100644 --- a/src-tauri/src/alphahuman/observability/mod.rs +++ b/src-tauri/src/openhuman/observability/mod.rs @@ -17,7 +17,7 @@ pub use traits::{Observer, ObserverEvent}; #[allow(unused_imports)] pub use verbose::VerboseObserver; -use crate::alphahuman::config::ObservabilityConfig; +use crate::openhuman::config::ObservabilityConfig; /// Factory: create the right observer from config pub fn create_observer(config: &ObservabilityConfig) -> Box { diff --git a/src-tauri/src/alphahuman/observability/multi.rs b/src-tauri/src/openhuman/observability/multi.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/multi.rs rename to src-tauri/src/openhuman/observability/multi.rs diff --git a/src-tauri/src/alphahuman/observability/noop.rs b/src-tauri/src/openhuman/observability/noop.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/noop.rs rename to src-tauri/src/openhuman/observability/noop.rs diff --git a/src-tauri/src/alphahuman/observability/otel.rs b/src-tauri/src/openhuman/observability/otel.rs similarity index 95% rename from src-tauri/src/alphahuman/observability/otel.rs rename to src-tauri/src/openhuman/observability/otel.rs index f7a6acd7f..c4de62ee9 100644 --- a/src-tauri/src/alphahuman/observability/otel.rs +++ b/src-tauri/src/openhuman/observability/otel.rs @@ -36,7 +36,7 @@ impl OtelObserver { /// Falls back to `http://localhost:4318` if no endpoint is provided. pub fn new(endpoint: Option<&str>, service_name: Option<&str>) -> Result { let endpoint = endpoint.unwrap_or("http://localhost:4318"); - let service_name = service_name.unwrap_or("alphahuman"); + let service_name = service_name.unwrap_or("openhuman"); // ── Trace exporter ────────────────────────────────────── let span_exporter = opentelemetry_otlp::SpanExporter::builder() @@ -79,74 +79,74 @@ impl OtelObserver { global::set_meter_provider(meter_provider); // ── Create metric instruments ──────────────────────────── - let meter = global::meter("alphahuman"); + let meter = global::meter("openhuman"); let agent_starts = meter - .u64_counter("alphahuman.agent.starts") + .u64_counter("openhuman.agent.starts") .with_description("Total agent invocations") .build(); let agent_duration = meter - .f64_histogram("alphahuman.agent.duration") + .f64_histogram("openhuman.agent.duration") .with_description("Agent invocation duration in seconds") .with_unit("s") .build(); let llm_calls = meter - .u64_counter("alphahuman.llm.calls") + .u64_counter("openhuman.llm.calls") .with_description("Total LLM provider calls") .build(); let llm_duration = meter - .f64_histogram("alphahuman.llm.duration") + .f64_histogram("openhuman.llm.duration") .with_description("LLM provider call duration in seconds") .with_unit("s") .build(); let tool_calls = meter - .u64_counter("alphahuman.tool.calls") + .u64_counter("openhuman.tool.calls") .with_description("Total tool calls") .build(); let tool_duration = meter - .f64_histogram("alphahuman.tool.duration") + .f64_histogram("openhuman.tool.duration") .with_description("Tool execution duration in seconds") .with_unit("s") .build(); let channel_messages = meter - .u64_counter("alphahuman.channel.messages") + .u64_counter("openhuman.channel.messages") .with_description("Total channel messages") .build(); let heartbeat_ticks = meter - .u64_counter("alphahuman.heartbeat.ticks") + .u64_counter("openhuman.heartbeat.ticks") .with_description("Total heartbeat ticks") .build(); let errors = meter - .u64_counter("alphahuman.errors") + .u64_counter("openhuman.errors") .with_description("Total errors by component") .build(); let request_latency = meter - .f64_histogram("alphahuman.request.latency") + .f64_histogram("openhuman.request.latency") .with_description("Request latency in seconds") .with_unit("s") .build(); let tokens_used = meter - .u64_counter("alphahuman.tokens.used") + .u64_counter("openhuman.tokens.used") .with_description("Total tokens consumed (monotonic)") .build(); let active_sessions = meter - .u64_gauge("alphahuman.sessions.active") + .u64_gauge("openhuman.sessions.active") .with_description("Current number of active sessions") .build(); let queue_depth = meter - .u64_gauge("alphahuman.queue.depth") + .u64_gauge("openhuman.queue.depth") .with_description("Current message queue depth") .build(); @@ -172,7 +172,7 @@ impl OtelObserver { impl Observer for OtelObserver { fn record_event(&self, event: &ObserverEvent) { - let tracer = global::tracer("alphahuman"); + let tracer = global::tracer("openhuman"); match event { ObserverEvent::AgentStart { provider, model } => { @@ -383,7 +383,7 @@ mod tests { fn test_observer() -> OtelObserver { // Create with a dummy endpoint — exports will silently fail // but the observer itself works fine for recording - OtelObserver::new(Some("http://127.0.0.1:19999"), Some("alphahuman-test")) + OtelObserver::new(Some("http://127.0.0.1:19999"), Some("openhuman-test")) .expect("observer creation should not fail with valid endpoint format") } @@ -513,7 +513,7 @@ mod tests { #[test] fn otel_observer_creation_with_valid_endpoint_succeeds() { // Even though endpoint is unreachable, creation should succeed - let result = OtelObserver::new(Some("http://127.0.0.1:12345"), Some("alphahuman-test")); + let result = OtelObserver::new(Some("http://127.0.0.1:12345"), Some("openhuman-test")); assert!( result.is_ok(), "observer creation must succeed even with unreachable endpoint" diff --git a/src-tauri/src/alphahuman/observability/prometheus.rs b/src-tauri/src/openhuman/observability/prometheus.rs similarity index 87% rename from src-tauri/src/alphahuman/observability/prometheus.rs rename to src-tauri/src/openhuman/observability/prometheus.rs index a8758b891..791b7433e 100644 --- a/src-tauri/src/alphahuman/observability/prometheus.rs +++ b/src-tauri/src/openhuman/observability/prometheus.rs @@ -30,36 +30,36 @@ impl PrometheusObserver { let registry = Registry::new(); let agent_starts = IntCounterVec::new( - prometheus::Opts::new("alphahuman_agent_starts_total", "Total agent invocations"), + prometheus::Opts::new("openhuman_agent_starts_total", "Total agent invocations"), &["provider", "model"], ) .expect("valid metric"); let tool_calls = IntCounterVec::new( - prometheus::Opts::new("alphahuman_tool_calls_total", "Total tool calls"), + prometheus::Opts::new("openhuman_tool_calls_total", "Total tool calls"), &["tool", "success"], ) .expect("valid metric"); let channel_messages = IntCounterVec::new( - prometheus::Opts::new("alphahuman_channel_messages_total", "Total channel messages"), + prometheus::Opts::new("openhuman_channel_messages_total", "Total channel messages"), &["channel", "direction"], ) .expect("valid metric"); let heartbeat_ticks = - prometheus::IntCounter::new("alphahuman_heartbeat_ticks_total", "Total heartbeat ticks") + prometheus::IntCounter::new("openhuman_heartbeat_ticks_total", "Total heartbeat ticks") .expect("valid metric"); let errors = IntCounterVec::new( - prometheus::Opts::new("alphahuman_errors_total", "Total errors by component"), + prometheus::Opts::new("openhuman_errors_total", "Total errors by component"), &["component"], ) .expect("valid metric"); let agent_duration = HistogramVec::new( HistogramOpts::new( - "alphahuman_agent_duration_seconds", + "openhuman_agent_duration_seconds", "Agent invocation duration in seconds", ) .buckets(vec![0.1, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0, 60.0]), @@ -69,7 +69,7 @@ impl PrometheusObserver { let tool_duration = HistogramVec::new( HistogramOpts::new( - "alphahuman_tool_duration_seconds", + "openhuman_tool_duration_seconds", "Tool execution duration in seconds", ) .buckets(vec![0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0]), @@ -79,7 +79,7 @@ impl PrometheusObserver { let request_latency = Histogram::with_opts( HistogramOpts::new( - "alphahuman_request_latency_seconds", + "openhuman_request_latency_seconds", "Request latency in seconds", ) .buckets(vec![0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0]), @@ -87,19 +87,19 @@ impl PrometheusObserver { .expect("valid metric"); let tokens_used = prometheus::IntGauge::new( - "alphahuman_tokens_used_last", + "openhuman_tokens_used_last", "Tokens used in the last request", ) .expect("valid metric"); let active_sessions = GaugeVec::new( - prometheus::Opts::new("alphahuman_active_sessions", "Number of active sessions"), + prometheus::Opts::new("openhuman_active_sessions", "Number of active sessions"), &[], ) .expect("valid metric"); let queue_depth = GaugeVec::new( - prometheus::Opts::new("alphahuman_queue_depth", "Message queue depth"), + prometheus::Opts::new("openhuman_queue_depth", "Message queue depth"), &[], ) .expect("valid metric"); @@ -308,10 +308,10 @@ mod tests { obs.record_metric(&ObserverMetric::RequestLatency(Duration::from_millis(250))); let output = obs.encode(); - assert!(output.contains("alphahuman_agent_starts_total")); - assert!(output.contains("alphahuman_tool_calls_total")); - assert!(output.contains("alphahuman_heartbeat_ticks_total")); - assert!(output.contains("alphahuman_request_latency_seconds")); + assert!(output.contains("openhuman_agent_starts_total")); + assert!(output.contains("openhuman_tool_calls_total")); + assert!(output.contains("openhuman_heartbeat_ticks_total")); + assert!(output.contains("openhuman_request_latency_seconds")); } #[test] @@ -323,7 +323,7 @@ mod tests { } let output = obs.encode(); - assert!(output.contains("alphahuman_heartbeat_ticks_total 3")); + assert!(output.contains("openhuman_heartbeat_ticks_total 3")); } #[test] @@ -347,8 +347,8 @@ mod tests { }); let output = obs.encode(); - assert!(output.contains(r#"alphahuman_tool_calls_total{success="true",tool="shell"} 2"#)); - assert!(output.contains(r#"alphahuman_tool_calls_total{success="false",tool="shell"} 1"#)); + assert!(output.contains(r#"openhuman_tool_calls_total{success="true",tool="shell"} 2"#)); + assert!(output.contains(r#"openhuman_tool_calls_total{success="false",tool="shell"} 1"#)); } #[test] @@ -368,8 +368,8 @@ mod tests { }); let output = obs.encode(); - assert!(output.contains(r#"alphahuman_errors_total{component="provider"} 2"#)); - assert!(output.contains(r#"alphahuman_errors_total{component="channels"} 1"#)); + assert!(output.contains(r#"openhuman_errors_total{component="provider"} 2"#)); + assert!(output.contains(r#"openhuman_errors_total{component="channels"} 1"#)); } #[test] @@ -379,6 +379,6 @@ mod tests { obs.record_metric(&ObserverMetric::TokensUsed(200)); let output = obs.encode(); - assert!(output.contains("alphahuman_tokens_used_last 200")); + assert!(output.contains("openhuman_tokens_used_last 200")); } } diff --git a/src-tauri/src/alphahuman/observability/traits.rs b/src-tauri/src/openhuman/observability/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/traits.rs rename to src-tauri/src/openhuman/observability/traits.rs diff --git a/src-tauri/src/alphahuman/observability/verbose.rs b/src-tauri/src/openhuman/observability/verbose.rs similarity index 100% rename from src-tauri/src/alphahuman/observability/verbose.rs rename to src-tauri/src/openhuman/observability/verbose.rs diff --git a/src-tauri/src/alphahuman/onboard/mod.rs b/src-tauri/src/openhuman/onboard/mod.rs similarity index 90% rename from src-tauri/src/alphahuman/onboard/mod.rs rename to src-tauri/src/openhuman/onboard/mod.rs index b023b999e..d0777b27e 100644 --- a/src-tauri/src/alphahuman/onboard/mod.rs +++ b/src-tauri/src/openhuman/onboard/mod.rs @@ -1,4 +1,4 @@ -//! Onboarding helpers for Alphahuman. +//! Onboarding helpers for OpenHuman. pub mod models; diff --git a/src-tauri/src/alphahuman/onboard/models.rs b/src-tauri/src/openhuman/onboard/models.rs similarity index 99% rename from src-tauri/src/alphahuman/onboard/models.rs rename to src-tauri/src/openhuman/onboard/models.rs index 09ef25873..3c509ed6c 100644 --- a/src-tauri/src/alphahuman/onboard/models.rs +++ b/src-tauri/src/openhuman/onboard/models.rs @@ -1,7 +1,7 @@ //! Model catalog refresh and caching utilities. -use crate::alphahuman::config::Config; -use crate::alphahuman::providers::{canonical_china_provider_name, is_qwen_oauth_alias}; +use crate::openhuman::config::Config; +use crate::openhuman::providers::{canonical_china_provider_name, is_qwen_oauth_alias}; use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/src-tauri/src/alphahuman/peripherals/arduino_flash.rs b/src-tauri/src/openhuman/peripherals/arduino_flash.rs similarity index 86% rename from src-tauri/src/alphahuman/peripherals/arduino_flash.rs rename to src-tauri/src/openhuman/peripherals/arduino_flash.rs index 37799efc5..160feb6e7 100644 --- a/src-tauri/src/alphahuman/peripherals/arduino_flash.rs +++ b/src-tauri/src/openhuman/peripherals/arduino_flash.rs @@ -1,4 +1,4 @@ -//! Flash Alphahuman Arduino firmware via arduino-cli. +//! Flash OpenHuman Arduino firmware via arduino-cli. //! //! Ensures arduino-cli is available (installs via brew on macOS if missing), //! installs the AVR core, compiles and uploads the base firmware. @@ -6,11 +6,11 @@ use anyhow::{Context, Result}; use std::process::Command; -/// Alphahuman Arduino Uno base firmware (capabilities, gpio_read, gpio_write). -const FIRMWARE_INO: &str = include_str!("../../firmware/alphahuman-arduino/alphahuman-arduino.ino"); +/// OpenHuman Arduino Uno base firmware (capabilities, gpio_read, gpio_write). +const FIRMWARE_INO: &str = include_str!("../../firmware/openhuman-arduino/openhuman-arduino.ino"); const FQBN: &str = "arduino:avr:uno"; -const SKETCH_NAME: &str = "alphahuman-arduino"; +const SKETCH_NAME: &str = "openhuman-arduino"; /// Check if arduino-cli is available. pub fn arduino_cli_available() -> bool { @@ -85,12 +85,12 @@ fn ensure_avr_core() -> Result<()> { Ok(()) } -/// Flash Alphahuman firmware to Arduino at the given port. +/// Flash OpenHuman firmware to Arduino at the given port. pub fn flash_arduino_firmware(port: &str) -> Result<()> { ensure_arduino_cli()?; ensure_avr_core()?; - let temp_dir = std::env::temp_dir().join(format!("alphahuman_flash_{}", uuid::Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("openhuman_flash_{}", uuid::Uuid::new_v4())); let sketch_dir = temp_dir.join(SKETCH_NAME); let ino_path = sketch_dir.join(format!("{}.ino", SKETCH_NAME)); @@ -100,7 +100,7 @@ pub fn flash_arduino_firmware(port: &str) -> Result<()> { let sketch_path = sketch_dir.to_string_lossy(); // Compile - println!("Compiling Alphahuman Arduino firmware..."); + println!("Compiling OpenHuman Arduino firmware..."); let compile = Command::new("arduino-cli") .args(["compile", "--fqbn", FQBN, &*sketch_path]) .output() @@ -126,13 +126,13 @@ pub fn flash_arduino_firmware(port: &str) -> Result<()> { anyhow::bail!("Upload failed:\n{}\n\nEnsure the board is connected and the port is correct (e.g. /dev/cu.usbmodem* on macOS).", stderr); } - println!("Alphahuman firmware flashed successfully."); + println!("OpenHuman firmware flashed successfully."); println!("The Arduino now supports: capabilities, gpio_read, gpio_write."); Ok(()) } /// Resolve port from config or path. Returns the path to use for flashing. -pub fn resolve_port(config: &crate::alphahuman::config::Config, path_override: Option<&str>) -> Option { +pub fn resolve_port(config: &crate::openhuman::config::Config, path_override: Option<&str>) -> Option { if let Some(p) = path_override { return Some(p.to_string()); } diff --git a/src-tauri/src/alphahuman/peripherals/arduino_upload.rs b/src-tauri/src/openhuman/peripherals/arduino_upload.rs similarity index 94% rename from src-tauri/src/alphahuman/peripherals/arduino_upload.rs rename to src-tauri/src/openhuman/peripherals/arduino_upload.rs index 88480e909..eb2cfd05d 100644 --- a/src-tauri/src/alphahuman/peripherals/arduino_upload.rs +++ b/src-tauri/src/openhuman/peripherals/arduino_upload.rs @@ -1,10 +1,10 @@ //! Arduino upload tool — agent generates code, uploads via arduino-cli. //! //! When user says "make a heart on the LED grid", the agent generates Arduino -//! sketch code and calls this tool. Alphahuman compiles and uploads it — no +//! sketch code and calls this tool. OpenHuman compiles and uploads it — no //! manual IDE or file editing. -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::process::Command; @@ -70,8 +70,8 @@ impl Tool for ArduinoUploadTool { }); } - let sketch_name = "alphahuman_sketch"; - let temp_dir = std::env::temp_dir().join(format!("alphahuman_{}", uuid::Uuid::new_v4())); + let sketch_name = "openhuman_sketch"; + let temp_dir = std::env::temp_dir().join(format!("openhuman_{}", uuid::Uuid::new_v4())); let sketch_dir = temp_dir.join(sketch_name); let ino_path = sketch_dir.join(format!("{}.ino", sketch_name)); diff --git a/src-tauri/src/alphahuman/peripherals/capabilities_tool.rs b/src-tauri/src/openhuman/peripherals/capabilities_tool.rs similarity index 98% rename from src-tauri/src/alphahuman/peripherals/capabilities_tool.rs rename to src-tauri/src/openhuman/peripherals/capabilities_tool.rs index bce964688..44f975578 100644 --- a/src-tauri/src/alphahuman/peripherals/capabilities_tool.rs +++ b/src-tauri/src/openhuman/peripherals/capabilities_tool.rs @@ -1,7 +1,7 @@ //! Hardware capabilities tool — Phase C: query device for reported GPIO pins. use super::serial::SerialTransport; -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; diff --git a/src-tauri/src/alphahuman/peripherals/mod.rs b/src-tauri/src/openhuman/peripherals/mod.rs similarity index 93% rename from src-tauri/src/alphahuman/peripherals/mod.rs rename to src-tauri/src/openhuman/peripherals/mod.rs index 1a190bd49..f14a42989 100644 --- a/src-tauri/src/alphahuman/peripherals/mod.rs +++ b/src-tauri/src/openhuman/peripherals/mod.rs @@ -26,10 +26,10 @@ pub mod rpi; pub use traits::Peripheral; -use crate::alphahuman::config::{PeripheralBoardConfig, PeripheralsConfig}; +use crate::openhuman::config::{PeripheralBoardConfig, PeripheralsConfig}; #[cfg(feature = "hardware")] -use crate::alphahuman::tools::HardwareMemoryMapTool; -use crate::alphahuman::tools::Tool; +use crate::openhuman::tools::HardwareMemoryMapTool; +use crate::openhuman::tools::Tool; use anyhow::Result; /// List configured boards from config (no connection yet). @@ -115,10 +115,10 @@ pub async fn create_peripheral_tools(config: &PeripheralsConfig) -> Result = config.boards.iter().map(|b| b.board.clone()).collect(); tools.push(Box::new(HardwareMemoryMapTool::new(board_names.clone()))); - tools.push(Box::new(crate::alphahuman::tools::HardwareBoardInfoTool::new( + tools.push(Box::new(crate::openhuman::tools::HardwareBoardInfoTool::new( board_names.clone(), ))); - tools.push(Box::new(crate::alphahuman::tools::HardwareMemoryReadTool::new( + tools.push(Box::new(crate::openhuman::tools::HardwareMemoryReadTool::new( board_names, ))); } diff --git a/src-tauri/src/alphahuman/peripherals/nucleo_flash.rs b/src-tauri/src/openhuman/peripherals/nucleo_flash.rs similarity index 82% rename from src-tauri/src/alphahuman/peripherals/nucleo_flash.rs rename to src-tauri/src/openhuman/peripherals/nucleo_flash.rs index d4e5755f4..51923c297 100644 --- a/src-tauri/src/alphahuman/peripherals/nucleo_flash.rs +++ b/src-tauri/src/openhuman/peripherals/nucleo_flash.rs @@ -1,4 +1,4 @@ -//! Flash Alphahuman Nucleo-F401RE firmware via probe-rs. +//! Flash OpenHuman Nucleo-F401RE firmware via probe-rs. //! //! Builds the Embassy firmware and flashes via ST-Link (built into Nucleo). //! Requires: cargo install probe-rs-tools --locked @@ -19,7 +19,7 @@ pub fn probe_rs_available() -> bool { .unwrap_or(false) } -/// Flash Alphahuman Nucleo firmware. Builds from firmware/alphahuman-nucleo. +/// Flash OpenHuman Nucleo firmware. Builds from firmware/openhuman-nucleo. pub fn flash_nucleo_firmware() -> Result<()> { if !probe_rs_available() { anyhow::bail!( @@ -29,17 +29,17 @@ pub fn flash_nucleo_firmware() -> Result<()> { ); } - // CARGO_MANIFEST_DIR = repo root (alphahuman's Cargo.toml) + // CARGO_MANIFEST_DIR = repo root (openhuman's Cargo.toml) let repo_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let firmware_dir = repo_root.join("firmware").join("alphahuman-nucleo"); + let firmware_dir = repo_root.join("firmware").join("openhuman-nucleo"); if !firmware_dir.join("Cargo.toml").exists() { anyhow::bail!( - "Nucleo firmware not found at {}. Run from alphahuman repo root.", + "Nucleo firmware not found at {}. Run from openhuman repo root.", firmware_dir.display() ); } - println!("Building Alphahuman Nucleo firmware..."); + println!("Building OpenHuman Nucleo firmware..."); let build = Command::new("cargo") .args(["build", "--release", "--target", TARGET]) .current_dir(&firmware_dir) @@ -55,7 +55,7 @@ pub fn flash_nucleo_firmware() -> Result<()> { .join("target") .join(TARGET) .join("release") - .join("alphahuman-nucleo"); + .join("openhuman-nucleo"); if !elf_path.exists() { anyhow::bail!("Built binary not found at {}", elf_path.display()); @@ -76,7 +76,7 @@ pub fn flash_nucleo_firmware() -> Result<()> { ); } - println!("Alphahuman Nucleo firmware flashed successfully."); + println!("OpenHuman Nucleo firmware flashed successfully."); println!("The Nucleo now supports: ping, capabilities, gpio_read, gpio_write."); println!("Add to config.toml: board = \"nucleo-f401re\", transport = \"serial\", path = \"/dev/ttyACM0\""); Ok(()) diff --git a/src-tauri/src/alphahuman/peripherals/rpi.rs b/src-tauri/src/openhuman/peripherals/rpi.rs similarity index 96% rename from src-tauri/src/alphahuman/peripherals/rpi.rs rename to src-tauri/src/openhuman/peripherals/rpi.rs index 8504a3b78..a931089dd 100644 --- a/src-tauri/src/alphahuman/peripherals/rpi.rs +++ b/src-tauri/src/openhuman/peripherals/rpi.rs @@ -3,9 +3,9 @@ //! Only compiled when `peripheral-rpi` feature is enabled and target is Linux. //! Uses BCM pin numbering (e.g. GPIO 17, 27). -use crate::alphahuman::config::PeripheralBoardConfig; -use crate::alphahuman::peripherals::traits::Peripheral; -use crate::alphahuman::tools::{Tool, ToolResult}; +use crate::openhuman::config::PeripheralBoardConfig; +use crate::openhuman::peripherals::traits::Peripheral; +use crate::openhuman::tools::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; diff --git a/src-tauri/src/alphahuman/peripherals/serial.rs b/src-tauri/src/openhuman/peripherals/serial.rs similarity index 98% rename from src-tauri/src/alphahuman/peripherals/serial.rs rename to src-tauri/src/openhuman/peripherals/serial.rs index 21f712f4a..ad62b9782 100644 --- a/src-tauri/src/alphahuman/peripherals/serial.rs +++ b/src-tauri/src/openhuman/peripherals/serial.rs @@ -5,8 +5,8 @@ //! Response: {"id":"1","ok":true,"result":"done"} use super::traits::Peripheral; -use crate::alphahuman::config::PeripheralBoardConfig; -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::config::PeripheralBoardConfig; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::sync::atomic::{AtomicU64, Ordering}; diff --git a/src-tauri/src/alphahuman/peripherals/traits.rs b/src-tauri/src/openhuman/peripherals/traits.rs similarity index 97% rename from src-tauri/src/alphahuman/peripherals/traits.rs rename to src-tauri/src/openhuman/peripherals/traits.rs index 050908a87..9bf829b1f 100644 --- a/src-tauri/src/alphahuman/peripherals/traits.rs +++ b/src-tauri/src/openhuman/peripherals/traits.rs @@ -5,7 +5,7 @@ use async_trait::async_trait; -use crate::alphahuman::tools::Tool; +use crate::openhuman::tools::Tool; /// A hardware peripheral that exposes capabilities as tools. /// diff --git a/src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs b/src-tauri/src/openhuman/peripherals/uno_q_bridge.rs similarity index 95% rename from src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs rename to src-tauri/src/openhuman/peripherals/uno_q_bridge.rs index 2530ea176..52515fb43 100644 --- a/src-tauri/src/alphahuman/peripherals/uno_q_bridge.rs +++ b/src-tauri/src/openhuman/peripherals/uno_q_bridge.rs @@ -1,9 +1,9 @@ //! Arduino Uno Q Bridge — GPIO via socket to Bridge app. //! -//! When Alphahuman runs on Uno Q, the Bridge app (Python + MCU) exposes +//! When OpenHuman runs on Uno Q, the Bridge app (Python + MCU) exposes //! digitalWrite/digitalRead over a local socket. These tools connect to it. -use crate::alphahuman::tools::traits::{Tool, ToolResult}; +use crate::openhuman::tools::traits::{Tool, ToolResult}; use async_trait::async_trait; use serde_json::{json, Value}; use std::time::Duration; @@ -40,7 +40,7 @@ impl Tool for UnoQGpioReadTool { } fn description(&self) -> &str { - "Read GPIO pin value (0 or 1) on Arduino Uno Q. Requires alphahuman-uno-q-bridge app running." + "Read GPIO pin value (0 or 1) on Arduino Uno Q. Requires openhuman-uno-q-bridge app running." } fn parameters_schema(&self) -> Value { @@ -96,7 +96,7 @@ impl Tool for UnoQGpioWriteTool { } fn description(&self) -> &str { - "Set GPIO pin high (1) or low (0) on Arduino Uno Q. Requires alphahuman-uno-q-bridge app running." + "Set GPIO pin high (1) or low (0) on Arduino Uno Q. Requires openhuman-uno-q-bridge app running." } fn parameters_schema(&self) -> Value { diff --git a/src-tauri/src/alphahuman/peripherals/uno_q_setup.rs b/src-tauri/src/openhuman/peripherals/uno_q_setup.rs similarity index 82% rename from src-tauri/src/alphahuman/peripherals/uno_q_setup.rs rename to src-tauri/src/openhuman/peripherals/uno_q_setup.rs index 8b1791e76..028ce339b 100644 --- a/src-tauri/src/alphahuman/peripherals/uno_q_setup.rs +++ b/src-tauri/src/openhuman/peripherals/uno_q_setup.rs @@ -1,23 +1,23 @@ -//! Deploy Alphahuman Bridge app to Arduino Uno Q. +//! Deploy OpenHuman Bridge app to Arduino Uno Q. use anyhow::{Context, Result}; use std::process::Command; -const BRIDGE_APP_NAME: &str = "alphahuman-uno-q-bridge"; +const BRIDGE_APP_NAME: &str = "openhuman-uno-q-bridge"; /// Deploy the Bridge app. If host is Some, scp from repo and ssh to start. /// If host is None, assume we're ON the Uno Q — use embedded files and start. pub fn setup_uno_q_bridge(host: Option<&str>) -> Result<()> { let bridge_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("firmware") - .join("alphahuman-uno-q-bridge"); + .join("openhuman-uno-q-bridge"); if let Some(h) = host { if bridge_dir.exists() { deploy_remote(h, &bridge_dir)?; } else { anyhow::bail!( - "Bridge app not found at {}. Run from alphahuman repo root.", + "Bridge app not found at {}. Run from openhuman repo root.", bridge_dir.display() ); } @@ -66,7 +66,7 @@ fn deploy_remote(host: &str, bridge_dir: &std::path::Path) -> Result<()> { "arduino-app-cli", "app", "start", - "~/ArduinoApps/alphahuman-uno-q-bridge", + "~/ArduinoApps/openhuman-uno-q-bridge", ]) .status() .context("arduino-app-cli start failed")?; @@ -74,7 +74,7 @@ fn deploy_remote(host: &str, bridge_dir: &std::path::Path) -> Result<()> { anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q."); } - println!("Alphahuman Bridge app started. Add to config.toml:"); + println!("OpenHuman Bridge app started. Add to config.toml:"); println!(" [[peripherals.boards]]"); println!(" board = \"arduino-uno-q\""); println!(" transport = \"bridge\""); @@ -105,16 +105,16 @@ fn deploy_local(bridge_dir: Option<&std::path::Path>) -> Result<()> { anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q."); } - println!("Alphahuman Bridge app started."); + println!("OpenHuman Bridge app started."); Ok(()) } fn write_embedded_bridge(dest: &std::path::Path) -> Result<()> { - let app_yaml = include_str!("../../firmware/alphahuman-uno-q-bridge/app.yaml"); - let sketch_ino = include_str!("../../firmware/alphahuman-uno-q-bridge/sketch/sketch.ino"); - let sketch_yaml = include_str!("../../firmware/alphahuman-uno-q-bridge/sketch/sketch.yaml"); - let main_py = include_str!("../../firmware/alphahuman-uno-q-bridge/python/main.py"); - let requirements = include_str!("../../firmware/alphahuman-uno-q-bridge/python/requirements.txt"); + let app_yaml = include_str!("../../firmware/openhuman-uno-q-bridge/app.yaml"); + let sketch_ino = include_str!("../../firmware/openhuman-uno-q-bridge/sketch/sketch.ino"); + let sketch_yaml = include_str!("../../firmware/openhuman-uno-q-bridge/sketch/sketch.yaml"); + let main_py = include_str!("../../firmware/openhuman-uno-q-bridge/python/main.py"); + let requirements = include_str!("../../firmware/openhuman-uno-q-bridge/python/requirements.txt"); std::fs::write(dest.join("app.yaml"), app_yaml)?; std::fs::create_dir_all(dest.join("sketch"))?; diff --git a/src-tauri/src/alphahuman/providers/anthropic.rs b/src-tauri/src/openhuman/providers/anthropic.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/anthropic.rs rename to src-tauri/src/openhuman/providers/anthropic.rs index a70ed60d5..f111c2973 100644 --- a/src-tauri/src/alphahuman/providers/anthropic.rs +++ b/src-tauri/src/openhuman/providers/anthropic.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -400,7 +400,7 @@ impl AnthropicProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.anthropic", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.anthropic", 120, 10) } } @@ -645,7 +645,7 @@ mod tests { async fn chat_with_system_fails_without_key() { let p = AnthropicProvider::new(None); let result = p - .chat_with_system(Some("You are Alphahuman"), "hello", "claude-3-opus", 0.7) + .chat_with_system(Some("You are OpenHuman"), "hello", "claude-3-opus", 0.7) .await; assert!(result.is_err()); } @@ -676,7 +676,7 @@ mod tests { let req = ChatRequest { model: "claude-3-opus".to_string(), max_tokens: 4096, - system: Some("You are Alphahuman".to_string()), + system: Some("You are OpenHuman".to_string()), messages: vec![Message { role: "user".to_string(), content: "hello".to_string(), @@ -684,7 +684,7 @@ mod tests { temperature: 0.7, }; let json = serde_json::to_string(&req).unwrap(); - assert!(json.contains("\"system\":\"You are Alphahuman\"")); + assert!(json.contains("\"system\":\"You are OpenHuman\"")); } #[test] diff --git a/src-tauri/src/alphahuman/providers/bedrock.rs b/src-tauri/src/openhuman/providers/bedrock.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/bedrock.rs rename to src-tauri/src/openhuman/providers/bedrock.rs index 97cf8e818..cd5241ce7 100644 --- a/src-tauri/src/alphahuman/providers/bedrock.rs +++ b/src-tauri/src/openhuman/providers/bedrock.rs @@ -4,11 +4,11 @@ //! via environment variables. SigV4 signing is implemented manually //! using hmac/sha2 crates — no AWS SDK dependency. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ProviderCapabilities, ToolCall as ProviderToolCall, ToolsPayload, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use hmac::{Hmac, Mac}; use reqwest::Client; @@ -349,7 +349,7 @@ impl BedrockProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.bedrock", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.bedrock", 120, 10) } /// Percent-encode the model ID for URL path: only encode `:` to `%3A`. @@ -775,7 +775,7 @@ impl Provider for BedrockProvider { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::providers::traits::ChatMessage; + use crate::openhuman::providers::traits::ChatMessage; // ── SigV4 signing tests ───────────────────────────────────── diff --git a/src-tauri/src/alphahuman/providers/compatible.rs b/src-tauri/src/openhuman/providers/compatible.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/compatible.rs rename to src-tauri/src/openhuman/providers/compatible.rs index ed3414e2b..1944f2ee8 100644 --- a/src-tauri/src/alphahuman/providers/compatible.rs +++ b/src-tauri/src/openhuman/providers/compatible.rs @@ -2,7 +2,7 @@ //! Most LLM APIs follow the same `/v1/chat/completions` format. //! This module provides a single implementation that works for all of them. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, StreamChunk, StreamError, StreamOptions, StreamResult, ToolCall as ProviderToolCall, }; @@ -160,7 +160,7 @@ impl OpenAiCompatibleProvider { .connect_timeout(std::time::Duration::from_secs(10)) .default_headers(headers); let builder = - crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "provider.compatible"); + crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "provider.compatible"); return builder.build().unwrap_or_else(|error| { tracing::warn!("Failed to build proxied timeout client with user-agent: {error}"); @@ -168,7 +168,7 @@ impl OpenAiCompatibleProvider { }); } - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.compatible", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.compatible", 120, 10) } /// Build the full URL for chat completions, detecting if base_url already includes the path. @@ -233,7 +233,7 @@ impl OpenAiCompatibleProvider { } } - fn tool_specs_to_openai_format(tools: &[crate::alphahuman::tools::ToolSpec]) -> Vec { + fn tool_specs_to_openai_format(tools: &[crate::openhuman::tools::ToolSpec]) -> Vec { tools .iter() .map(|tool| { @@ -730,7 +730,7 @@ impl OpenAiCompatibleProvider { } fn convert_tool_specs( - tools: Option<&[crate::alphahuman::tools::ToolSpec]>, + tools: Option<&[crate::openhuman::tools::ToolSpec]>, ) -> Option> { tools.map(|items| { items @@ -823,7 +823,7 @@ impl OpenAiCompatibleProvider { fn with_prompt_guided_tool_instructions( messages: &[ChatMessage], - tools: Option<&[crate::alphahuman::tools::ToolSpec]>, + tools: Option<&[crate::openhuman::tools::ToolSpec]>, ) -> Vec { let Some(tools) = tools else { return messages.to_vec(); @@ -833,7 +833,7 @@ impl OpenAiCompatibleProvider { return messages.to_vec(); } - let instructions = crate::alphahuman::providers::traits::build_tool_instructions_text(tools); + let instructions = crate::openhuman::providers::traits::build_tool_instructions_text(tools); let mut modified_messages = messages.to_vec(); if let Some(system_message) = modified_messages.iter_mut().find(|m| m.role == "system") { @@ -895,8 +895,8 @@ impl OpenAiCompatibleProvider { #[async_trait] impl Provider for OpenAiCompatibleProvider { - fn capabilities(&self) -> crate::alphahuman::providers::traits::ProviderCapabilities { - crate::alphahuman::providers::traits::ProviderCapabilities { + fn capabilities(&self) -> crate::openhuman::providers::traits::ProviderCapabilities { + crate::openhuman::providers::traits::ProviderCapabilities { native_tool_calling: true, vision: false, } @@ -1520,7 +1520,7 @@ mod tests { messages: vec![ Message { role: "system".to_string(), - content: "You are Alphahuman".to_string(), + content: "You are OpenHuman".to_string(), }, Message { role: "user".to_string(), @@ -1980,7 +1980,7 @@ mod tests { #[test] fn prompt_guided_tool_fallback_injects_system_instruction() { let input = vec![ChatMessage::user("check status")]; - let tools = vec![crate::alphahuman::tools::ToolSpec { + let tools = vec![crate::openhuman::tools::ToolSpec { name: "shell_exec".to_string(), description: "Execute shell command".to_string(), parameters: serde_json::json!({ @@ -2020,7 +2020,7 @@ mod tests { #[test] fn tool_specs_convert_to_openai_format() { - let specs = vec![crate::alphahuman::tools::ToolSpec { + let specs = vec![crate::openhuman::tools::ToolSpec { name: "shell".to_string(), description: "Run shell command".to_string(), parameters: serde_json::json!({ diff --git a/src-tauri/src/alphahuman/providers/copilot.rs b/src-tauri/src/openhuman/providers/copilot.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/copilot.rs rename to src-tauri/src/openhuman/providers/copilot.rs index 1c8a074f5..f98a65e2a 100644 --- a/src-tauri/src/alphahuman/providers/copilot.rs +++ b/src-tauri/src/openhuman/providers/copilot.rs @@ -11,11 +11,11 @@ //! GitHub could change or revoke this at any time, which would break all //! third-party integrations simultaneously. -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -154,7 +154,7 @@ struct ResponseMessage { /// GitHub Copilot provider with automatic OAuth and token refresh. /// /// On first use, prompts the user to visit github.com/login/device. -/// Tokens are cached to `~/.config/alphahuman/copilot/` and refreshed +/// Tokens are cached to `~/.config/openhuman/copilot/` and refreshed /// automatically. pub struct CopilotProvider { github_token: Option, @@ -166,7 +166,7 @@ pub struct CopilotProvider { impl CopilotProvider { pub fn new(github_token: Option<&str>) -> Self { - let token_dir = directories::ProjectDirs::from("", "", "alphahuman") + let token_dir = directories::ProjectDirs::from("", "", "openhuman") .map(|dir| dir.config_dir().join("copilot")) .unwrap_or_else(|| { // Fall back to a user-specific temp directory to avoid @@ -174,7 +174,7 @@ impl CopilotProvider { let user = std::env::var("USER") .or_else(|_| std::env::var("USERNAME")) .unwrap_or_else(|_| "unknown".to_string()); - std::env::temp_dir().join(format!("alphahuman-copilot-{user}")) + std::env::temp_dir().join(format!("openhuman-copilot-{user}")) }); if let Err(err) = std::fs::create_dir_all(&token_dir) { @@ -208,7 +208,7 @@ impl CopilotProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.copilot", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.copilot", 120, 10) } /// Required headers for Copilot API requests (editor identification). diff --git a/src-tauri/src/alphahuman/providers/gemini.rs b/src-tauri/src/openhuman/providers/gemini.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/gemini.rs rename to src-tauri/src/openhuman/providers/gemini.rs index 3ea957a80..5486c2e1f 100644 --- a/src-tauri/src/alphahuman/providers/gemini.rs +++ b/src-tauri/src/openhuman/providers/gemini.rs @@ -3,7 +3,7 @@ //! - Gemini app OAuth tokens (reuse existing ~/.gemini/ authentication) //! - Google Cloud ADC (`GOOGLE_APPLICATION_CREDENTIALS`) -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; use async_trait::async_trait; use directories::UserDirs; use reqwest::Client; @@ -276,7 +276,7 @@ impl GeminiProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.gemini", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.gemini", 120, 10) } fn build_generate_content_request( diff --git a/src-tauri/src/alphahuman/providers/glm.rs b/src-tauri/src/openhuman/providers/glm.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/glm.rs rename to src-tauri/src/openhuman/providers/glm.rs index 5e74ae78a..1b5a09bab 100644 --- a/src-tauri/src/alphahuman/providers/glm.rs +++ b/src-tauri/src/openhuman/providers/glm.rs @@ -2,7 +2,7 @@ //! The GLM API requires JWT tokens generated from the `id.secret` API key format //! with a custom `sign_type: "SIGN"` header, and uses `/v4/chat/completions`. -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; use async_trait::async_trait; use reqwest::Client; use ring::hmac; @@ -145,7 +145,7 @@ impl GlmProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.glm", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.glm", 120, 10) } } diff --git a/src-tauri/src/alphahuman/providers/mod.rs b/src-tauri/src/openhuman/providers/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/mod.rs rename to src-tauri/src/openhuman/providers/mod.rs index 27fa98dda..2bcb94efd 100644 --- a/src-tauri/src/alphahuman/providers/mod.rs +++ b/src-tauri/src/openhuman/providers/mod.rs @@ -628,7 +628,7 @@ fn zai_base_url(name: &str) -> Option<&'static str> { #[derive(Debug, Clone)] pub struct ProviderRuntimeOptions { pub auth_profile_override: Option, - pub alphahuman_dir: Option, + pub openhuman_dir: Option, pub secrets_encrypt: bool, pub reasoning_enabled: Option, } @@ -637,7 +637,7 @@ impl Default for ProviderRuntimeOptions { fn default() -> Self { Self { auth_profile_override: None, - alphahuman_dir: None, + openhuman_dir: None, secrets_encrypt: true, reasoning_enabled: None, } @@ -734,7 +734,7 @@ pub async fn api_error(provider: &str, response: reqwest::Response) -> anyhow::E /// Resolution order: /// 1. Explicitly provided `api_key` parameter (trimmed, filtered if empty) /// 2. Provider-specific environment variable (e.g., `ANTHROPIC_OAUTH_TOKEN`, `OPENROUTER_API_KEY`) -/// 3. Generic fallback variables (`ALPHAHUMAN_API_KEY`, `API_KEY`) +/// 3. Generic fallback variables (`OPENHUMAN_API_KEY`, `API_KEY`) /// /// For Anthropic, the provider-specific env var is `ANTHROPIC_OAUTH_TOKEN` (for setup-tokens) /// followed by `ANTHROPIC_API_KEY` (for regular API keys). @@ -817,7 +817,7 @@ fn resolve_provider_credential(name: &str, credential_override: Option<&str>) -> return None; } - for env_var in ["ALPHAHUMAN_API_KEY", "API_KEY"] { + for env_var in ["OPENHUMAN_API_KEY", "API_KEY"] { if let Ok(value) = std::env::var(env_var) { let value = value.trim(); if !value.is_empty() { @@ -1100,7 +1100,7 @@ pub fn create_resilient_provider( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, + reliability: &crate::openhuman::config::ReliabilityConfig, ) -> anyhow::Result> { create_resilient_provider_with_options( primary_name, @@ -1116,7 +1116,7 @@ pub fn create_resilient_provider_with_options( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, + reliability: &crate::openhuman::config::ReliabilityConfig, options: &ProviderRuntimeOptions, ) -> anyhow::Result> { let mut providers: Vec<(String, Box)> = Vec::new(); @@ -1172,8 +1172,8 @@ pub fn create_routed_provider( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, - model_routes: &[crate::alphahuman::config::ModelRouteConfig], + reliability: &crate::openhuman::config::ReliabilityConfig, + model_routes: &[crate::openhuman::config::ModelRouteConfig], default_model: &str, ) -> anyhow::Result> { create_routed_provider_with_options( @@ -1192,8 +1192,8 @@ pub fn create_routed_provider_with_options( primary_name: &str, api_key: Option<&str>, api_url: Option<&str>, - reliability: &crate::alphahuman::config::ReliabilityConfig, - model_routes: &[crate::alphahuman::config::ModelRouteConfig], + reliability: &crate::openhuman::config::ReliabilityConfig, + model_routes: &[crate::openhuman::config::ModelRouteConfig], default_model: &str, options: &ProviderRuntimeOptions, ) -> anyhow::Result> { @@ -1591,7 +1591,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_prefers_explicit_override() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}", std::process::id()); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); let _token_guard = EnvGuard::set(QWEN_OAUTH_TOKEN_ENV, Some("oauth-token")); let _resource_guard = EnvGuard::set( @@ -1608,7 +1608,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_uses_env_token_and_resource_url() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}-env", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}-env", std::process::id()); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); let _token_guard = EnvGuard::set(QWEN_OAUTH_TOKEN_ENV, Some("oauth-token")); let _refresh_guard = EnvGuard::set(QWEN_OAUTH_REFRESH_TOKEN_ENV, None); @@ -1630,7 +1630,7 @@ mod tests { #[test] fn resolve_qwen_oauth_context_reads_cached_credentials_file() { let _env_lock = env_lock(); - let fake_home = format!("/tmp/alphahuman-qwen-oauth-home-{}-file", std::process::id()); + let fake_home = format!("/tmp/openhuman-qwen-oauth-home-{}-file", std::process::id()); let creds_dir = PathBuf::from(&fake_home).join(".qwen"); std::fs::create_dir_all(&creds_dir).unwrap(); let creds_path = creds_dir.join("oauth_creds.json"); @@ -1659,7 +1659,7 @@ mod tests { fn resolve_qwen_oauth_context_placeholder_does_not_use_dashscope_fallback() { let _env_lock = env_lock(); let fake_home = format!( - "/tmp/alphahuman-qwen-oauth-home-{}-placeholder", + "/tmp/openhuman-qwen-oauth-home-{}-placeholder", std::process::id() ); let _home_guard = EnvGuard::set("HOME", Some(fake_home.as_str())); @@ -2106,7 +2106,7 @@ mod tests { #[test] fn resilient_provider_ignores_duplicate_and_invalid_fallbacks() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec![ @@ -2134,7 +2134,7 @@ mod tests { #[test] fn resilient_provider_errors_for_invalid_primary() { - let reliability = crate::alphahuman::config::ReliabilityConfig::default(); + let reliability = crate::openhuman::config::ReliabilityConfig::default(); let provider = create_resilient_provider( "totally-invalid", Some("provider-test-credential"), @@ -2150,7 +2150,7 @@ mod tests { /// successfully even when the primary uses a completely different key. #[test] fn resilient_fallback_resolves_own_credential() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec!["lmstudio".into(), "ollama".into()], @@ -2172,7 +2172,7 @@ mod tests { /// OpenAI-compatible endpoints (e.g. local LM Studio on a Docker host). #[test] fn resilient_fallback_supports_custom_url() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec!["custom:http://host.docker.internal:1234/v1".into()], @@ -2193,7 +2193,7 @@ mod tests { /// all coexist. Invalid entries are silently ignored; valid ones initialize. #[test] fn resilient_fallback_mixed_chain() { - let reliability = crate::alphahuman::config::ReliabilityConfig { + let reliability = crate::openhuman::config::ReliabilityConfig { provider_retries: 1, provider_backoff_ms: 100, fallback_providers: vec![ diff --git a/src-tauri/src/alphahuman/providers/ollama.rs b/src-tauri/src/openhuman/providers/ollama.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/ollama.rs rename to src-tauri/src/openhuman/providers/ollama.rs index f9844e6c9..25e2f1552 100644 --- a/src-tauri/src/alphahuman/providers/ollama.rs +++ b/src-tauri/src/openhuman/providers/ollama.rs @@ -1,5 +1,5 @@ -use crate::alphahuman::multimodal; -use crate::alphahuman::providers::traits::{ +use crate::openhuman::multimodal; +use crate::openhuman::providers::traits::{ ChatMessage, ChatResponse, Provider, ProviderCapabilities, ToolCall, }; use async_trait::async_trait; @@ -124,7 +124,7 @@ impl OllamaProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.ollama", 300, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.ollama", 300, 10) } fn resolve_request_details(&self, model: &str) -> anyhow::Result<(String, bool)> { @@ -515,7 +515,7 @@ impl Provider for OllamaProvider { async fn chat_with_history( &self, - messages: &[crate::alphahuman::providers::ChatMessage], + messages: &[crate::openhuman::providers::ChatMessage], model: &str, temperature: f64, ) -> anyhow::Result { diff --git a/src-tauri/src/alphahuman/providers/openai.rs b/src-tauri/src/openhuman/providers/openai.rs similarity index 98% rename from src-tauri/src/alphahuman/providers/openai.rs rename to src-tauri/src/openhuman/providers/openai.rs index 5fb8317be..b5eb2949f 100644 --- a/src-tauri/src/alphahuman/providers/openai.rs +++ b/src-tauri/src/openhuman/providers/openai.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -250,7 +250,7 @@ impl OpenAiProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.openai", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.openai", 120, 10) } } @@ -455,7 +455,7 @@ mod tests { async fn chat_with_system_fails_without_key() { let p = OpenAiProvider::new(None); let result = p - .chat_with_system(Some("You are Alphahuman"), "test", "gpt-4o", 0.5) + .chat_with_system(Some("You are OpenHuman"), "test", "gpt-4o", 0.5) .await; assert!(result.is_err()); } @@ -467,7 +467,7 @@ mod tests { messages: vec![ Message { role: "system".to_string(), - content: "You are Alphahuman".to_string(), + content: "You are OpenHuman".to_string(), }, Message { role: "user".to_string(), diff --git a/src-tauri/src/alphahuman/providers/openai_codex.rs b/src-tauri/src/openhuman/providers/openai_codex.rs similarity index 97% rename from src-tauri/src/alphahuman/providers/openai_codex.rs rename to src-tauri/src/openhuman/providers/openai_codex.rs index 9e8cac9f7..4b5f44f35 100644 --- a/src-tauri/src/alphahuman/providers/openai_codex.rs +++ b/src-tauri/src/openhuman/providers/openai_codex.rs @@ -1,7 +1,7 @@ use crate::auth::openai_oauth::extract_account_id_from_jwt; use crate::auth::AuthService; -use crate::alphahuman::providers::traits::{ChatMessage, Provider}; -use crate::alphahuman::providers::ProviderRuntimeOptions; +use crate::openhuman::providers::traits::{ChatMessage, Provider}; +use crate::openhuman::providers::ProviderRuntimeOptions; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -10,7 +10,7 @@ use std::path::PathBuf; const CODEX_RESPONSES_URL: &str = "https://chatgpt.com/backend-api/codex/responses"; const DEFAULT_CODEX_INSTRUCTIONS: &str = - "You are Alphahuman, a concise and helpful coding assistant."; + "You are OpenHuman, a concise and helpful coding assistant."; pub struct OpenAiCodexProvider { auth: AuthService, @@ -80,9 +80,9 @@ struct ResponsesContent { impl OpenAiCodexProvider { pub fn new(options: &ProviderRuntimeOptions) -> Self { let state_dir = options - .alphahuman_dir + .openhuman_dir .clone() - .unwrap_or_else(default_alphahuman_dir); + .unwrap_or_else(default_openhuman_dir); let auth = AuthService::new(&state_dir, options.secrets_encrypt); Self { @@ -97,10 +97,10 @@ impl OpenAiCodexProvider { } } -fn default_alphahuman_dir() -> PathBuf { +fn default_openhuman_dir() -> PathBuf { directories::UserDirs::new().map_or_else( - || PathBuf::from(".alphahuman"), - |dirs| dirs.home_dir().join(".alphahuman"), + || PathBuf::from(".openhuman"), + |dirs| dirs.home_dir().join(".openhuman"), ) } @@ -180,7 +180,7 @@ fn clamp_reasoning_effort(model: &str, effort: &str) -> String { } fn resolve_reasoning_effort(model_id: &str) -> String { - let raw = std::env::var("ALPHAHUMAN_CODEX_REASONING_EFFORT") + let raw = std::env::var("OPENHUMAN_CODEX_REASONING_EFFORT") .ok() .and_then(|value| first_nonempty(Some(&value))) .unwrap_or_else(|| "xhigh".to_string()) @@ -502,7 +502,7 @@ mod tests { #[test] fn default_state_dir_is_non_empty() { - let path = default_alphahuman_dir(); + let path = default_openhuman_dir(); assert!(!path.as_os_str().is_empty()); } diff --git a/src-tauri/src/alphahuman/providers/openrouter.rs b/src-tauri/src/openhuman/providers/openrouter.rs similarity index 97% rename from src-tauri/src/alphahuman/providers/openrouter.rs rename to src-tauri/src/openhuman/providers/openrouter.rs index 41022cb6d..c2b0b0768 100644 --- a/src-tauri/src/alphahuman/providers/openrouter.rs +++ b/src-tauri/src/openhuman/providers/openrouter.rs @@ -1,8 +1,8 @@ -use crate::alphahuman::providers::traits::{ +use crate::openhuman::providers::traits::{ ChatMessage, ChatRequest as ProviderChatRequest, ChatResponse as ProviderChatResponse, Provider, ToolCall as ProviderToolCall, }; -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -221,7 +221,7 @@ impl OpenRouterProvider { } fn http_client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("provider.openrouter", 120, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("provider.openrouter", 120, 10) } } @@ -277,9 +277,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&request) .send() .await?; @@ -327,9 +327,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&request) .send() .await?; @@ -375,9 +375,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&native_request) .send() .await?; @@ -463,9 +463,9 @@ impl Provider for OpenRouterProvider { .header("Authorization", format!("Bearer {credential}")) .header( "HTTP-Referer", - "https://github.com/theonlyhennygod/alphahuman", + "https://github.com/theonlyhennygod/openhuman", ) - .header("X-Title", "Alphahuman") + .header("X-Title", "OpenHuman") .json(&native_request) .send() .await?; @@ -488,7 +488,7 @@ impl Provider for OpenRouterProvider { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::providers::traits::{ChatMessage, Provider}; + use crate::openhuman::providers::traits::{ChatMessage, Provider}; #[test] fn creates_with_key() { diff --git a/src-tauri/src/alphahuman/providers/reliable.rs b/src-tauri/src/openhuman/providers/reliable.rs similarity index 100% rename from src-tauri/src/alphahuman/providers/reliable.rs rename to src-tauri/src/openhuman/providers/reliable.rs diff --git a/src-tauri/src/alphahuman/providers/router.rs b/src-tauri/src/openhuman/providers/router.rs similarity index 100% rename from src-tauri/src/alphahuman/providers/router.rs rename to src-tauri/src/openhuman/providers/router.rs diff --git a/src-tauri/src/alphahuman/providers/traits.rs b/src-tauri/src/openhuman/providers/traits.rs similarity index 99% rename from src-tauri/src/alphahuman/providers/traits.rs rename to src-tauri/src/openhuman/providers/traits.rs index 7db7188d2..604f31410 100644 --- a/src-tauri/src/alphahuman/providers/traits.rs +++ b/src-tauri/src/openhuman/providers/traits.rs @@ -1,4 +1,4 @@ -use crate::alphahuman::tools::ToolSpec; +use crate::openhuman::tools::ToolSpec; use async_trait::async_trait; use futures_util::{stream, StreamExt}; use serde::{Deserialize, Serialize}; @@ -239,7 +239,7 @@ pub enum ToolsPayload { fn should_log_prompts() -> bool { matches!( - std::env::var("ALPHAHUMAN_LOG_PROMPTS") + std::env::var("OPENHUMAN_LOG_PROMPTS") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") diff --git a/src-tauri/src/alphahuman/rag/mod.rs b/src-tauri/src/openhuman/rag/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/rag/mod.rs rename to src-tauri/src/openhuman/rag/mod.rs index b393f6ea1..5eba423e7 100644 --- a/src-tauri/src/alphahuman/rag/mod.rs +++ b/src-tauri/src/openhuman/rag/mod.rs @@ -6,7 +6,7 @@ //! - Pin/alias tables (e.g. `red_led: 13`) for explicit lookup //! - Keyword retrieval (default) or semantic search via embeddings (optional) -use crate::alphahuman::memory::chunker; +use crate::openhuman::memory::chunker; use std::collections::HashMap; use std::path::Path; diff --git a/src-tauri/src/alphahuman/runtime/docker.rs b/src-tauri/src/openhuman/runtime/docker.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/docker.rs rename to src-tauri/src/openhuman/runtime/docker.rs index e86457c41..2911594e1 100644 --- a/src-tauri/src/alphahuman/runtime/docker.rs +++ b/src-tauri/src/openhuman/runtime/docker.rs @@ -1,5 +1,5 @@ use super::traits::RuntimeAdapter; -use crate::alphahuman::config::DockerRuntimeConfig; +use crate::openhuman::config::DockerRuntimeConfig; use anyhow::{Context, Result}; use std::path::{Path, PathBuf}; @@ -67,9 +67,9 @@ impl RuntimeAdapter for DockerRuntime { fn storage_path(&self) -> PathBuf { if self.config.mount_workspace { - PathBuf::from("/workspace/.alphahuman") + PathBuf::from("/workspace/.openhuman") } else { - PathBuf::from("/tmp/.alphahuman") + PathBuf::from("/tmp/.openhuman") } } diff --git a/src-tauri/src/alphahuman/runtime/mod.rs b/src-tauri/src/openhuman/runtime/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/mod.rs rename to src-tauri/src/openhuman/runtime/mod.rs index c7ddd7b92..580f5267d 100644 --- a/src-tauri/src/alphahuman/runtime/mod.rs +++ b/src-tauri/src/openhuman/runtime/mod.rs @@ -6,7 +6,7 @@ pub use docker::DockerRuntime; pub use native::NativeRuntime; pub use traits::RuntimeAdapter; -use crate::alphahuman::config::RuntimeConfig; +use crate::openhuman::config::RuntimeConfig; /// Factory: create the right runtime from config pub fn create_runtime(config: &RuntimeConfig) -> anyhow::Result> { diff --git a/src-tauri/src/alphahuman/runtime/native.rs b/src-tauri/src/openhuman/runtime/native.rs similarity index 90% rename from src-tauri/src/alphahuman/runtime/native.rs rename to src-tauri/src/openhuman/runtime/native.rs index 2f5aea31b..3a6fa213c 100644 --- a/src-tauri/src/alphahuman/runtime/native.rs +++ b/src-tauri/src/openhuman/runtime/native.rs @@ -25,8 +25,8 @@ impl RuntimeAdapter for NativeRuntime { fn storage_path(&self) -> PathBuf { directories::UserDirs::new().map_or_else( - || PathBuf::from(".alphahuman"), - |u| u.home_dir().join(".alphahuman"), + || PathBuf::from(".openhuman"), + |u| u.home_dir().join(".openhuman"), ) } @@ -75,9 +75,9 @@ mod tests { } #[test] - fn native_storage_path_contains_alphahuman() { + fn native_storage_path_contains_openhuman() { let path = NativeRuntime::new().storage_path(); - assert!(path.to_string_lossy().contains("alphahuman")); + assert!(path.to_string_lossy().contains("openhuman")); } #[test] diff --git a/src-tauri/src/alphahuman/runtime/traits.rs b/src-tauri/src/openhuman/runtime/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/runtime/traits.rs rename to src-tauri/src/openhuman/runtime/traits.rs diff --git a/src-tauri/src/alphahuman/runtime/wasm.rs b/src-tauri/src/openhuman/runtime/wasm.rs similarity index 98% rename from src-tauri/src/alphahuman/runtime/wasm.rs rename to src-tauri/src/openhuman/runtime/wasm.rs index 468dad5fc..1363e12ea 100644 --- a/src-tauri/src/alphahuman/runtime/wasm.rs +++ b/src-tauri/src/openhuman/runtime/wasm.rs @@ -9,10 +9,10 @@ //! //! # Feature gate //! This module is only compiled when `--features runtime-wasm` is enabled. -//! The default Alphahuman binary excludes it to maintain the 4.6 MB size target. +//! The default OpenHuman binary excludes it to maintain the 4.6 MB size target. use super::traits::RuntimeAdapter; -use crate::alphahuman::config::WasmRuntimeConfig; +use crate::openhuman::config::WasmRuntimeConfig; use anyhow::{bail, Context, Result}; use std::path::{Path, PathBuf}; @@ -292,7 +292,7 @@ impl RuntimeAdapter for WasmRuntime { fn storage_path(&self) -> PathBuf { self.workspace_dir .as_ref() - .map_or_else(|| PathBuf::from(".alphahuman"), |w| w.join(".alphahuman")) + .map_or_else(|| PathBuf::from(".openhuman"), |w| w.join(".openhuman")) } fn supports_long_running(&self) -> bool { @@ -385,13 +385,13 @@ mod tests { #[test] fn wasm_storage_path_default() { let rt = WasmRuntime::new(default_config()); - assert!(rt.storage_path().to_string_lossy().contains("alphahuman")); + assert!(rt.storage_path().to_string_lossy().contains("openhuman")); } #[test] fn wasm_storage_path_with_workspace() { let rt = WasmRuntime::with_workspace(default_config(), PathBuf::from("/home/user/project")); - assert_eq!(rt.storage_path(), PathBuf::from("/home/user/project/.alphahuman")); + assert_eq!(rt.storage_path(), PathBuf::from("/home/user/project/.openhuman")); } // ── Config validation ────────────────────────────────────── diff --git a/src-tauri/src/alphahuman/security/audit.rs b/src-tauri/src/openhuman/security/audit.rs similarity index 97% rename from src-tauri/src/alphahuman/security/audit.rs rename to src-tauri/src/openhuman/security/audit.rs index 34bbe56ad..1dfcfaa59 100644 --- a/src-tauri/src/alphahuman/security/audit.rs +++ b/src-tauri/src/openhuman/security/audit.rs @@ -1,6 +1,6 @@ //! Audit logging for security events -use crate::alphahuman::config::AuditConfig; +use crate::openhuman::config::AuditConfig; use anyhow::Result; use chrono::{DateTime, Utc}; use parking_lot::Mutex; @@ -164,10 +164,10 @@ pub struct CommandExecutionLog<'a> { impl AuditLogger { /// Create a new audit logger - pub fn new(config: AuditConfig, alphahuman_dir: PathBuf) -> Result { - let log_path = alphahuman_dir.join(&config.log_path); + pub fn new(config: AuditConfig, openhuman_dir: PathBuf) -> Result { + let log_path = openhuman_dir.join(&config.log_path); log::info!( - "[alphahuman:audit] Logger initialized: enabled={}, path={}", + "[openhuman:audit] Logger initialized: enabled={}, path={}", config.enabled, log_path.display() ); @@ -185,7 +185,7 @@ impl AuditLogger { } log::debug!( - "[alphahuman:audit] Logging event: type={:?}, id={}", + "[openhuman:audit] Logging event: type={:?}, id={}", event.event_type, event.event_id ); @@ -258,7 +258,7 @@ impl AuditLogger { /// Rotate the log file fn rotate(&self) -> Result<()> { log::info!( - "[alphahuman:audit] Rotating audit log: {}", + "[openhuman:audit] Rotating audit log: {}", self.log_path.display() ); for i in (1..10).rev() { diff --git a/src-tauri/src/alphahuman/security/bubblewrap.rs b/src-tauri/src/openhuman/security/bubblewrap.rs similarity index 98% rename from src-tauri/src/alphahuman/security/bubblewrap.rs rename to src-tauri/src/openhuman/security/bubblewrap.rs index 5cd7c469b..187f3314e 100644 --- a/src-tauri/src/alphahuman/security/bubblewrap.rs +++ b/src-tauri/src/openhuman/security/bubblewrap.rs @@ -1,6 +1,6 @@ //! Bubblewrap sandbox (user namespaces for Linux/macOS) -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Bubblewrap sandbox backend diff --git a/src-tauri/src/alphahuman/security/detect.rs b/src-tauri/src/openhuman/security/detect.rs similarity index 96% rename from src-tauri/src/alphahuman/security/detect.rs rename to src-tauri/src/openhuman/security/detect.rs index 5b9e5380b..7118baa63 100644 --- a/src-tauri/src/alphahuman/security/detect.rs +++ b/src-tauri/src/openhuman/security/detect.rs @@ -1,7 +1,7 @@ //! Auto-detection of available security features -use crate::alphahuman::config::{SandboxBackend, SecurityConfig}; -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::config::{SandboxBackend, SecurityConfig}; +use crate::openhuman::security::traits::Sandbox; use std::sync::Arc; /// Create a sandbox based on auto-detection or explicit config @@ -117,7 +117,7 @@ fn detect_best_sandbox() -> Arc { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{SandboxConfig, SecurityConfig}; + use crate::openhuman::config::{SandboxConfig, SecurityConfig}; #[test] fn detect_best_sandbox_returns_something() { diff --git a/src-tauri/src/alphahuman/security/docker.rs b/src-tauri/src/openhuman/security/docker.rs similarity index 99% rename from src-tauri/src/alphahuman/security/docker.rs rename to src-tauri/src/openhuman/security/docker.rs index c38da639b..e7bac3f1b 100644 --- a/src-tauri/src/alphahuman/security/docker.rs +++ b/src-tauri/src/openhuman/security/docker.rs @@ -1,6 +1,6 @@ //! Docker sandbox (container isolation) -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Docker sandbox backend diff --git a/src-tauri/src/alphahuman/security/firejail.rs b/src-tauri/src/openhuman/security/firejail.rs similarity index 99% rename from src-tauri/src/alphahuman/security/firejail.rs rename to src-tauri/src/openhuman/security/firejail.rs index be591da90..f223083ca 100644 --- a/src-tauri/src/alphahuman/security/firejail.rs +++ b/src-tauri/src/openhuman/security/firejail.rs @@ -2,7 +2,7 @@ //! //! Firejail is a SUID sandbox program that Linux applications use to sandbox themselves. -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::process::Command; /// Firejail sandbox backend for Linux diff --git a/src-tauri/src/alphahuman/security/landlock.rs b/src-tauri/src/openhuman/security/landlock.rs similarity index 99% rename from src-tauri/src/alphahuman/security/landlock.rs rename to src-tauri/src/openhuman/security/landlock.rs index 5132ff895..06641c091 100644 --- a/src-tauri/src/alphahuman/security/landlock.rs +++ b/src-tauri/src/openhuman/security/landlock.rs @@ -6,7 +6,7 @@ #[cfg(all(feature = "sandbox-landlock", target_os = "linux"))] use landlock::{AccessFs, PathBeneath, PathFd, Ruleset, RulesetAttr, RulesetCreatedAttr}; -use crate::alphahuman::security::traits::Sandbox; +use crate::openhuman::security::traits::Sandbox; use std::path::Path; /// Landlock sandbox backend for Linux diff --git a/src-tauri/src/alphahuman/security/mod.rs b/src-tauri/src/openhuman/security/mod.rs similarity index 100% rename from src-tauri/src/alphahuman/security/mod.rs rename to src-tauri/src/openhuman/security/mod.rs diff --git a/src-tauri/src/alphahuman/security/pairing.rs b/src-tauri/src/openhuman/security/pairing.rs similarity index 97% rename from src-tauri/src/alphahuman/security/pairing.rs rename to src-tauri/src/openhuman/security/pairing.rs index 95abd4b72..60c55edc2 100644 --- a/src-tauri/src/alphahuman/security/pairing.rs +++ b/src-tauri/src/openhuman/security/pairing.rs @@ -63,7 +63,7 @@ impl PairingGuard { None }; log::info!( - "[alphahuman:pairing] Guard created: require_pairing={}, existing_tokens={}, code_generated={}", + "[openhuman:pairing] Guard created: require_pairing={}, existing_tokens={}, code_generated={}", require_pairing, tokens.len(), code.is_some() @@ -95,7 +95,7 @@ impl PairingGuard { let elapsed = locked_at.elapsed().as_secs(); if elapsed < PAIR_LOCKOUT_SECS { log::warn!( - "[alphahuman:pairing] Pairing locked out: {} failed attempts, {}s remaining", + "[openhuman:pairing] Pairing locked out: {} failed attempts, {}s remaining", count, PAIR_LOCKOUT_SECS - elapsed ); @@ -121,7 +121,7 @@ impl PairingGuard { // Consume the pairing code so it cannot be reused *pairing_code = None; - log::info!("[alphahuman:pairing] Pairing successful, token issued"); + log::info!("[openhuman:pairing] Pairing successful, token issued"); return Ok(Some(token)); } } @@ -132,13 +132,13 @@ impl PairingGuard { let mut attempts = self.failed_attempts.lock(); attempts.0 += 1; log::warn!( - "[alphahuman:pairing] Pairing attempt failed ({}/{})", + "[openhuman:pairing] Pairing attempt failed ({}/{})", attempts.0, MAX_PAIR_ATTEMPTS ); if attempts.0 >= MAX_PAIR_ATTEMPTS { attempts.1 = Some(Instant::now()); - log::warn!("[alphahuman:pairing] Max attempts reached, lockout activated"); + log::warn!("[openhuman:pairing] Max attempts reached, lockout activated"); } } diff --git a/src-tauri/src/alphahuman/security/policy.rs b/src-tauri/src/openhuman/security/policy.rs similarity index 97% rename from src-tauri/src/alphahuman/security/policy.rs rename to src-tauri/src/openhuman/security/policy.rs index fd292ac2c..225858211 100644 --- a/src-tauri/src/alphahuman/security/policy.rs +++ b/src-tauri/src/openhuman/security/policy.rs @@ -491,7 +491,7 @@ impl SecurityPolicy { ) -> Result { if !self.is_command_allowed(command) { log::warn!( - "[alphahuman:policy] Command blocked by allowlist: {}", + "[openhuman:policy] Command blocked by allowlist: {}", &command[..command.len().min(80)] ); return Err(format!("Command not allowed by security policy: {command}")); @@ -502,14 +502,14 @@ impl SecurityPolicy { if risk == CommandRiskLevel::High { if self.block_high_risk_commands { log::warn!( - "[alphahuman:policy] High-risk command blocked: {}", + "[openhuman:policy] High-risk command blocked: {}", &command[..command.len().min(80)] ); return Err("Command blocked: high-risk command is disallowed by policy".into()); } if self.autonomy == AutonomyLevel::Supervised && !approved { log::warn!( - "[alphahuman:policy] High-risk command needs approval: {}", + "[openhuman:policy] High-risk command needs approval: {}", &command[..command.len().min(80)] ); return Err( @@ -525,7 +525,7 @@ impl SecurityPolicy { && !approved { log::info!( - "[alphahuman:policy] Medium-risk command needs approval: {}", + "[openhuman:policy] Medium-risk command needs approval: {}", &command[..command.len().min(80)] ); return Err( @@ -534,7 +534,7 @@ impl SecurityPolicy { } log::debug!( - "[alphahuman:policy] Command validated: risk={:?}, approved={}, cmd={}", + "[openhuman:policy] Command validated: risk={:?}, approved={}, cmd={}", risk, approved, &command[..command.len().min(80)] @@ -739,7 +739,7 @@ impl SecurityPolicy { ToolOperation::Act => { if !self.can_act() { log::warn!( - "[alphahuman:policy] Operation '{}' blocked: read-only mode", + "[openhuman:policy] Operation '{}' blocked: read-only mode", operation_name ); return Err(format!( @@ -749,14 +749,14 @@ impl SecurityPolicy { if !self.record_action() { log::warn!( - "[alphahuman:policy] Operation '{}' blocked: rate limit exceeded", + "[openhuman:policy] Operation '{}' blocked: rate limit exceeded", operation_name ); return Err("Rate limit exceeded: action budget exhausted".to_string()); } log::debug!( - "[alphahuman:policy] Operation '{}' allowed (actions: {}/{})", + "[openhuman:policy] Operation '{}' allowed (actions: {}/{})", operation_name, self.tracker.count(), self.max_actions_per_hour @@ -780,11 +780,11 @@ impl SecurityPolicy { /// Build from config sections pub fn from_config( - autonomy_config: &crate::alphahuman::config::AutonomyConfig, + autonomy_config: &crate::openhuman::config::AutonomyConfig, workspace_dir: &Path, ) -> Self { log::info!( - "[alphahuman:policy] SecurityPolicy created: autonomy={:?}, workspace_only={}, allowed_cmds={}, max_actions/hr={}", + "[openhuman:policy] SecurityPolicy created: autonomy={:?}, workspace_only={}, allowed_cmds={}, max_actions/hr={}", autonomy_config.level, autonomy_config.workspace_only, autonomy_config.allowed_commands.len(), @@ -1126,7 +1126,7 @@ mod tests { #[test] fn from_config_maps_all_fields() { - let autonomy_config = crate::alphahuman::config::AutonomyConfig { + let autonomy_config = crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::Full, workspace_only: false, allowed_commands: vec!["docker".into()], @@ -1135,7 +1135,7 @@ mod tests { max_cost_per_day_cents: 1000, require_approval_for_medium_risk: false, block_high_risk_commands: false, - ..crate::alphahuman::config::AutonomyConfig::default() + ..crate::openhuman::config::AutonomyConfig::default() }; let workspace = PathBuf::from("/tmp/test-workspace"); let policy = SecurityPolicy::from_config(&autonomy_config, &workspace); @@ -1512,7 +1512,7 @@ mod tests { #[test] fn from_config_creates_fresh_tracker() { - let autonomy_config = crate::alphahuman::config::AutonomyConfig { + let autonomy_config = crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::Full, workspace_only: false, allowed_commands: vec![], @@ -1521,7 +1521,7 @@ mod tests { max_cost_per_day_cents: 100, require_approval_for_medium_risk: true, block_high_risk_commands: true, - ..crate::alphahuman::config::AutonomyConfig::default() + ..crate::openhuman::config::AutonomyConfig::default() }; let workspace = PathBuf::from("/tmp/test"); let policy = SecurityPolicy::from_config(&autonomy_config, &workspace); @@ -1649,7 +1649,7 @@ mod tests { #[test] fn resolved_path_blocks_outside_workspace() { - let workspace = std::env::temp_dir().join("alphahuman_test_resolved_path"); + let workspace = std::env::temp_dir().join("openhuman_test_resolved_path"); let _ = std::fs::create_dir_all(&workspace); // Use the canonicalized workspace so starts_with checks match @@ -1673,7 +1673,7 @@ mod tests { let canonical_temp = std::env::temp_dir() .canonicalize() .unwrap_or_else(|_| std::env::temp_dir()); - let outside = canonical_temp.join("outside_workspace_alphahuman"); + let outside = canonical_temp.join("outside_workspace_openhuman"); assert!( !policy.is_resolved_path_allowed(&outside), "path outside workspace must be blocked" @@ -1685,7 +1685,7 @@ mod tests { #[test] fn resolved_path_blocks_root_escape() { let policy = SecurityPolicy { - workspace_dir: PathBuf::from("/home/alphahuman_user/project"), + workspace_dir: PathBuf::from("/home/openhuman_user/project"), ..SecurityPolicy::default() }; @@ -1704,7 +1704,7 @@ mod tests { fn resolved_path_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside_target"); diff --git a/src-tauri/src/alphahuman/security/secrets.rs b/src-tauri/src/openhuman/security/secrets.rs similarity index 99% rename from src-tauri/src/alphahuman/security/secrets.rs rename to src-tauri/src/openhuman/security/secrets.rs index d5699778e..eb9d68ff4 100644 --- a/src-tauri/src/alphahuman/security/secrets.rs +++ b/src-tauri/src/openhuman/security/secrets.rs @@ -1,7 +1,7 @@ // Encrypted secret store — defense-in-depth for API keys and tokens. // // Secrets are encrypted using ChaCha20-Poly1305 AEAD with a random key stored -// in `{data_dir}/alphahuman/.secret_key` with restrictive file permissions (0600). The +// in `{data_dir}/openhuman/.secret_key` with restrictive file permissions (0600). The // config file stores only hex-encoded ciphertext, never plaintext keys. // // Each encryption generates a fresh random 12-byte nonce, prepended to the @@ -35,7 +35,7 @@ const NONCE_LEN: usize = 12; /// Manages encrypted storage of secrets (API keys, tokens, etc.) #[derive(Debug, Clone)] pub struct SecretStore { - /// Path to the key file (`{data_dir}/alphahuman/.secret_key`) + /// Path to the key file (`{data_dir}/openhuman/.secret_key`) key_path: PathBuf, /// Whether encryption is enabled enabled: bool, @@ -43,9 +43,9 @@ pub struct SecretStore { impl SecretStore { /// Create a new secret store rooted at the given directory. - pub fn new(alphahuman_dir: &Path, enabled: bool) -> Self { + pub fn new(openhuman_dir: &Path, enabled: bool) -> Self { Self { - key_path: alphahuman_dir.join(".secret_key"), + key_path: openhuman_dir.join(".secret_key"), enabled, } } diff --git a/src-tauri/src/alphahuman/security/traits.rs b/src-tauri/src/openhuman/security/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/security/traits.rs rename to src-tauri/src/openhuman/security/traits.rs diff --git a/src-tauri/src/alphahuman/service/mod.rs b/src-tauri/src/openhuman/service/mod.rs similarity index 94% rename from src-tauri/src/alphahuman/service/mod.rs rename to src-tauri/src/openhuman/service/mod.rs index 8459c6e28..494f17f4f 100644 --- a/src-tauri/src/alphahuman/service/mod.rs +++ b/src-tauri/src/openhuman/service/mod.rs @@ -1,15 +1,15 @@ -//! Service management helpers for Alphahuman daemon. +//! Service management helpers for OpenHuman daemon. -use crate::alphahuman::config::Config; +use crate::openhuman::config::Config; use anyhow::{Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; use std::process::{Command, Stdio}; -const SERVICE_LABEL: &str = "com.alphahuman.daemon"; -const LEGACY_SERVICE_LABEL: &str = "com.alphahuman.app"; -const WINDOWS_TASK_NAME: &str = "AlphaHuman Daemon"; +const SERVICE_LABEL: &str = "com.openhuman.daemon"; +const LEGACY_SERVICE_LABEL: &str = "com.openhuman.app"; +const WINDOWS_TASK_NAME: &str = "OpenHuman Daemon"; fn windows_task_name() -> &'static str { WINDOWS_TASK_NAME @@ -22,7 +22,7 @@ fn daemon_program_args(exe: &std::path::Path) -> Vec { .unwrap_or_default() .to_ascii_lowercase(); - if file_name.contains("alphahuman-core") { + if file_name.contains("openhuman-core") { vec!["serve".to_string()] } else { vec!["core".to_string(), "serve".to_string()] @@ -124,7 +124,7 @@ pub fn start(config: &Config) -> Result { let _ = run_checked(Command::new("systemctl").args([ "--user", "enable", - "alphahuman.service", + "openhuman.service", ])); } else { log::info!("[service] Systemd service already enabled"); @@ -135,7 +135,7 @@ pub fn start(config: &Config) -> Result { // Try to start - systemctl start is idempotent log::info!("[service] Starting systemd service"); let start_result = - run_checked(Command::new("systemctl").args(["--user", "start", "alphahuman.service"])); + run_checked(Command::new("systemctl").args(["--user", "start", "openhuman.service"])); if let Err(e) = start_result { // Check if it's already active - that's success for us let status_check = status(config)?; @@ -223,7 +223,7 @@ pub fn stop(config: &Config) -> Result { if cfg!(target_os = "linux") { let _ = - run_checked(Command::new("systemctl").args(["--user", "stop", "alphahuman.service"])); + run_checked(Command::new("systemctl").args(["--user", "stop", "openhuman.service"])); return status(config); } @@ -259,7 +259,7 @@ pub fn status(config: &Config) -> Result { let out = run_capture(Command::new("systemctl").args([ "--user", "is-active", - "alphahuman.service", + "openhuman.service", ])) .unwrap_or_else(|_| "unknown".into()); let state = match out.trim() { @@ -270,7 +270,7 @@ pub fn status(config: &Config) -> Result { return Ok(ServiceStatus { state, unit_path: Some(linux_service_file(config)?), - label: "alphahuman.service".to_string(), + label: "openhuman.service".to_string(), details: None, }); } @@ -339,7 +339,7 @@ pub fn uninstall(config: &Config) -> Result { return Ok(ServiceStatus { state: ServiceState::NotInstalled, unit_path: Some(file), - label: "alphahuman.service".to_string(), + label: "openhuman.service".to_string(), details: None, }); } @@ -353,7 +353,7 @@ pub fn uninstall(config: &Config) -> Result { .parent() .map_or_else(|| PathBuf::from("."), PathBuf::from) .join("logs") - .join("alphahuman-daemon.cmd"); + .join("openhuman-daemon.cmd"); if wrapper.exists() { fs::remove_file(&wrapper).ok(); } @@ -410,7 +410,7 @@ fn install_macos(config: &Config) -> Result<()> { {stderr} EnvironmentVariables - ALPHAHUMAN_DAEMON_INTERNAL + OPENHUMAN_DAEMON_INTERNAL false WorkingDirectory @@ -457,14 +457,14 @@ fn install_linux(config: &Config) -> Result<()> { let exec_start = daemon_command_line(&exe); let unit = format!( - "[Unit]\nDescription=Alphahuman Daemon\n\n[Service]\nExecStart={}\nRestart=always\nRestartSec=3\n\nStandardOutput=append:{}\nStandardError=append:{}\n\n[Install]\nWantedBy=default.target\n", + "[Unit]\nDescription=OpenHuman Daemon\n\n[Service]\nExecStart={}\nRestart=always\nRestartSec=3\n\nStandardOutput=append:{}\nStandardError=append:{}\n\n[Install]\nWantedBy=default.target\n", exec_start, stdout.display(), stderr.display(), ); fs::write(&file, unit)?; - let _ = run_checked(Command::new("systemctl").args(["--user", "enable", "alphahuman.service"])); + let _ = run_checked(Command::new("systemctl").args(["--user", "enable", "openhuman.service"])); Ok(()) } @@ -477,7 +477,7 @@ fn install_windows(config: &Config) -> Result<()> { .join("logs"); fs::create_dir_all(&logs_dir)?; - let wrapper = logs_dir.join("alphahuman-daemon.cmd"); + let wrapper = logs_dir.join("openhuman-daemon.cmd"); let stdout = logs_dir.join("daemon.stdout.log"); let stderr = logs_dir.join("daemon.stderr.log"); let daemon_cmd = daemon_command_line(&exe); @@ -544,7 +544,7 @@ fn linux_service_file(config: &Config) -> Result { .join(".config") .join("systemd") .join("user") - .join("alphahuman.service")) + .join("openhuman.service")) } fn run_checked(cmd: &mut Command) -> Result<()> { @@ -599,7 +599,7 @@ fn is_service_loaded_macos() -> Result { /// Check if the Linux systemd service is enabled fn is_service_enabled_linux() -> Result { let result = Command::new("systemctl") - .args(["--user", "is-enabled", "alphahuman.service"]) + .args(["--user", "is-enabled", "openhuman.service"]) .output(); match result { @@ -641,6 +641,6 @@ mod tests { fn linux_service_file_uses_config_dir() { let config = Config::default(); let path = linux_service_file(&config).unwrap(); - assert!(path.ends_with(".config/systemd/user/alphahuman.service")); + assert!(path.ends_with(".config/systemd/user/openhuman.service")); } } diff --git a/src-tauri/src/alphahuman/skillforge/evaluate.rs b/src-tauri/src/openhuman/skillforge/evaluate.rs similarity index 99% rename from src-tauri/src/alphahuman/skillforge/evaluate.rs rename to src-tauri/src/openhuman/skillforge/evaluate.rs index 2a462bb80..c1a1bc1f7 100644 --- a/src-tauri/src/alphahuman/skillforge/evaluate.rs +++ b/src-tauri/src/openhuman/skillforge/evaluate.rs @@ -175,7 +175,7 @@ impl Evaluator { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::skillforge::scout::{ScoutResult, ScoutSource}; + use crate::openhuman::skillforge::scout::{ScoutResult, ScoutSource}; fn make_candidate(stars: u64, lang: Option<&str>, has_license: bool) -> ScoutResult { ScoutResult { diff --git a/src-tauri/src/alphahuman/skillforge/integrate.rs b/src-tauri/src/openhuman/skillforge/integrate.rs similarity index 95% rename from src-tauri/src/alphahuman/skillforge/integrate.rs rename to src-tauri/src/openhuman/skillforge/integrate.rs index 320706efe..8a78bd744 100644 --- a/src-tauri/src/alphahuman/skillforge/integrate.rs +++ b/src-tauri/src/openhuman/skillforge/integrate.rs @@ -1,4 +1,4 @@ -//! Integrator - generates Alphahuman-standard SKILL.toml + SKILL.md from scout results. +//! Integrator - generates OpenHuman-standard SKILL.toml + SKILL.md from scout results. use std::fs; use std::path::PathBuf; @@ -75,7 +75,7 @@ stars = {stars} updated_at = "{updated}" [skill.requirements] -runtime = "alphahuman >= 0.1" +runtime = "openhuman >= 0.1" [skill.metadata] auto_integrated = true @@ -115,7 +115,7 @@ forge_timestamp = "{now}" ## Usage ```toml -# Add to your Alphahuman config: +# Add to your OpenHuman config: [skills.{name}] enabled = true ``` @@ -174,7 +174,7 @@ fn sanitize_path_component(name: &str) -> Result { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::skillforge::scout::{ScoutResult, ScoutSource}; + use crate::openhuman::skillforge::scout::{ScoutResult, ScoutSource}; use std::fs; fn sample_candidate() -> ScoutResult { @@ -193,7 +193,7 @@ mod tests { #[tokio::test] async fn integrate_creates_files() { - let tmp = std::env::temp_dir().join("alphahuman-test-integrate"); + let tmp = std::env::temp_dir().join("openhuman-test-integrate"); let _ = fs::remove_dir_all(&tmp); let integrator = Integrator::new(tmp.to_string_lossy().into_owned()); diff --git a/src-tauri/src/alphahuman/skillforge/mod.rs b/src-tauri/src/openhuman/skillforge/mod.rs similarity index 99% rename from src-tauri/src/alphahuman/skillforge/mod.rs rename to src-tauri/src/openhuman/skillforge/mod.rs index d1404ff29..a6f64afde 100644 --- a/src-tauri/src/alphahuman/skillforge/mod.rs +++ b/src-tauri/src/openhuman/skillforge/mod.rs @@ -2,7 +2,7 @@ //! //! Pipeline: Scout → Evaluate → Integrate //! Discovers skills from external sources, scores them, and generates -//! Alphahuman-compatible manifests for qualified candidates. +//! OpenHuman-compatible manifests for qualified candidates. pub mod evaluate; pub mod integrate; diff --git a/src-tauri/src/alphahuman/skillforge/scout.rs b/src-tauri/src/openhuman/skillforge/scout.rs similarity index 98% rename from src-tauri/src/alphahuman/skillforge/scout.rs rename to src-tauri/src/openhuman/skillforge/scout.rs index 42bb16d3f..ee8bacc15 100644 --- a/src-tauri/src/alphahuman/skillforge/scout.rs +++ b/src-tauri/src/openhuman/skillforge/scout.rs @@ -83,7 +83,7 @@ impl GitHubScout { ); headers.insert( reqwest::header::USER_AGENT, - "Alphahuman-SkillForge/0.1".parse().expect("valid header"), + "OpenHuman-SkillForge/0.1".parse().expect("valid header"), ); if let Some(ref t) = token { if let Ok(val) = format!("Bearer {t}").parse() { @@ -99,7 +99,7 @@ impl GitHubScout { Self { client, - queries: vec!["alphahuman skill".into(), "ai agent skill".into()], + queries: vec!["openhuman skill".into(), "ai agent skill".into()], } } diff --git a/src-tauri/src/alphahuman/skills/mod.rs b/src-tauri/src/openhuman/skills/mod.rs similarity index 97% rename from src-tauri/src/alphahuman/skills/mod.rs rename to src-tauri/src/openhuman/skills/mod.rs index 192fce56e..77531befb 100644 --- a/src-tauri/src/alphahuman/skills/mod.rs +++ b/src-tauri/src/openhuman/skills/mod.rs @@ -7,11 +7,11 @@ use std::process::Command; use std::time::{Duration, SystemTime}; const OPEN_SKILLS_REPO_URL: &str = "https://github.com/besoeasy/open-skills"; -const OPEN_SKILLS_SYNC_MARKER: &str = ".alphahuman-open-skills-sync"; +const OPEN_SKILLS_SYNC_MARKER: &str = ".openhuman-open-skills-sync"; const OPEN_SKILLS_SYNC_INTERVAL_SECS: u64 = 60 * 60 * 24 * 7; /// A skill is a user-defined or community-built capability. -/// Skills live in `~/.alphahuman/workspace/skills//SKILL.md` +/// Skills live in `~/.openhuman/workspace/skills//SKILL.md` /// and can include tool definitions, prompts, and automation scripts. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Skill { @@ -159,7 +159,7 @@ fn load_open_skills(repo_dir: &Path) -> Vec { } fn open_skills_enabled() -> bool { - if let Ok(raw) = std::env::var("ALPHAHUMAN_OPEN_SKILLS_ENABLED") { + if let Ok(raw) = std::env::var("OPENHUMAN_OPEN_SKILLS_ENABLED") { let value = raw.trim().to_ascii_lowercase(); return !matches!(value.as_str(), "0" | "false" | "off" | "no"); } @@ -169,7 +169,7 @@ fn open_skills_enabled() -> bool { } fn resolve_open_skills_dir() -> Option { - if let Ok(path) = std::env::var("ALPHAHUMAN_OPEN_SKILLS_DIR") { + if let Ok(path) = std::env::var("OPENHUMAN_OPEN_SKILLS_DIR") { let trimmed = path.trim(); if !trimmed.is_empty() { return Some(PathBuf::from(trimmed)); @@ -404,7 +404,7 @@ pub fn init_skills_dir(workspace_dir: &Path) -> Result<()> { if !readme.exists() { std::fs::write( &readme, - "# Alphahuman Skills\n\n\ + "# OpenHuman Skills\n\n\ Each subdirectory is a skill. Create a `SKILL.toml` or `SKILL.md` file inside.\n\n\ ## SKILL.toml format\n\n\ ```toml\n\ @@ -425,8 +425,8 @@ pub fn init_skills_dir(workspace_dir: &Path) -> Result<()> { The agent will read it and follow the instructions.\n\n\ ## Installing community skills\n\n\ ```bash\n\ - alphahuman skills install \n\ - alphahuman skills list\n\ + openhuman skills install \n\ + openhuman skills list\n\ ```\n", )?; } @@ -732,9 +732,9 @@ description = "Bare minimum" #[test] fn skills_dir_path() { - let base = std::path::Path::new("/home/user/.alphahuman"); + let base = std::path::Path::new("/home/user/.openhuman"); let dir = skills_dir(base); - assert_eq!(dir, PathBuf::from("/home/user/.alphahuman/skills")); + assert_eq!(dir, PathBuf::from("/home/user/.openhuman/skills")); } #[test] diff --git a/src-tauri/src/alphahuman/skills/symlink_tests.rs b/src-tauri/src/openhuman/skills/symlink_tests.rs similarity index 99% rename from src-tauri/src/alphahuman/skills/symlink_tests.rs rename to src-tauri/src/openhuman/skills/symlink_tests.rs index 5937e98da..50538302c 100644 --- a/src-tauri/src/alphahuman/skills/symlink_tests.rs +++ b/src-tauri/src/openhuman/skills/symlink_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::alphahuman::skills::skills_dir; + use crate::openhuman::skills::skills_dir; use std::path::Path; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/browser.rs b/src-tauri/src/openhuman/tools/browser.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/browser.rs rename to src-tauri/src/openhuman/tools/browser.rs index 8c28ab1de..6f4126954 100644 --- a/src-tauri/src/alphahuman/tools/browser.rs +++ b/src-tauri/src/openhuman/tools/browser.rs @@ -6,7 +6,7 @@ //! Computer-use (OS-level) actions are supported via an optional sidecar endpoint. use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use anyhow::Context; use async_trait::async_trait; use serde::{Deserialize, Serialize}; @@ -420,7 +420,7 @@ impl BrowserTool { if self.allowed_domains.is_empty() && !allow_all_browser_domains() { anyhow::bail!( "Browser tool enabled but no allowed_domains configured. \ - Add [browser].allowed_domains in config.toml or set ALPHAHUMAN_BROWSER_ALLOW_ALL=1" + Add [browser].allowed_domains in config.toml or set OPENHUMAN_BROWSER_ALLOW_ALL=1" ); } @@ -747,12 +747,12 @@ impl BrowserTool { }, "metadata": { "session_name": self.session_name, - "source": "alphahuman.browser", + "source": "openhuman.browser", "version": env!("CARGO_PKG_VERSION"), } }); - let client = crate::alphahuman::config::build_runtime_proxy_client("tool.browser"); + let client = crate::openhuman::config::build_runtime_proxy_client("tool.browser"); let mut request = client .post(endpoint) .timeout(Duration::from_millis(self.computer_use.timeout_ms)) @@ -2077,7 +2077,7 @@ fn is_non_global_v6(v6: std::net::Ipv6Addr) -> bool { fn allow_all_browser_domains() -> bool { matches!( - std::env::var("ALPHAHUMAN_BROWSER_ALLOW_ALL") + std::env::var("OPENHUMAN_BROWSER_ALLOW_ALL") .ok() .as_deref(), Some("1") | Some("true") | Some("TRUE") | Some("yes") | Some("YES") @@ -2398,7 +2398,7 @@ mod tests { fn browser_tool_empty_allowlist_blocks() { let security = Arc::new(SecurityPolicy::default()); let tool = BrowserTool::new(security, vec![], None); - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); assert!(tool.validate_url("https://example.com").is_err()); } @@ -2406,9 +2406,9 @@ mod tests { fn browser_tool_empty_allowlist_allows_with_env_flag() { let security = Arc::new(SecurityPolicy::default()); let tool = BrowserTool::new(security, vec![], None); - std::env::set_var("ALPHAHUMAN_BROWSER_ALLOW_ALL", "1"); + std::env::set_var("OPENHUMAN_BROWSER_ALLOW_ALL", "1"); assert!(tool.validate_url("https://example.com").is_ok()); - std::env::remove_var("ALPHAHUMAN_BROWSER_ALLOW_ALL"); + std::env::remove_var("OPENHUMAN_BROWSER_ALLOW_ALL"); } #[test] diff --git a/src-tauri/src/alphahuman/tools/browser_open.rs b/src-tauri/src/openhuman/tools/browser_open.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/browser_open.rs rename to src-tauri/src/openhuman/tools/browser_open.rs index ce5a6f83b..c6a2c7271 100644 --- a/src-tauri/src/alphahuman/tools/browser_open.rs +++ b/src-tauri/src/openhuman/tools/browser_open.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -308,7 +308,7 @@ fn parse_ipv4(host: &str) -> Option<[u8; 4]> { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_tool(allowed_domains: Vec<&str>) -> BrowserOpenTool { let security = Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/composio.rs b/src-tauri/src/openhuman/tools/composio.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/composio.rs rename to src-tauri/src/openhuman/tools/composio.rs index f753f9ff1..30fbfd420 100644 --- a/src-tauri/src/alphahuman/tools/composio.rs +++ b/src-tauri/src/openhuman/tools/composio.rs @@ -1,14 +1,14 @@ // Composio Tool Provider — optional managed tool surface with 1000+ OAuth integrations. // -// When enabled, Alphahuman can execute actions on Gmail, Notion, GitHub, Slack, etc. +// When enabled, OpenHuman can execute actions on Gmail, Notion, GitHub, Slack, etc. // through Composio's API without storing raw OAuth tokens locally. // // This is opt-in. Users who prefer sovereign/local-only mode skip this entirely. // The Composio API key is stored in the encrypted secret store. use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use anyhow::Context; use async_trait::async_trait; use reqwest::Client; @@ -49,7 +49,7 @@ impl ComposioTool { } fn client(&self) -> Client { - crate::alphahuman::config::build_runtime_proxy_client_with_timeouts("tool.composio", 60, 10) + crate::openhuman::config::build_runtime_proxy_client_with_timeouts("tool.composio", 60, 10) } /// List available Composio apps/actions for the authenticated user. @@ -773,7 +773,7 @@ pub struct ComposioAction { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy::default()) diff --git a/src-tauri/src/alphahuman/tools/cron_add.rs b/src-tauri/src/openhuman/tools/cron_add.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_add.rs rename to src-tauri/src/openhuman/tools/cron_add.rs index 624a033cc..81608be83 100644 --- a/src-tauri/src/alphahuman/tools/cron_add.rs +++ b/src-tauri/src/openhuman/tools/cron_add.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{self, DeliveryConfig, JobType, Schedule, SessionTarget}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron::{self, DeliveryConfig, JobType, Schedule, SessionTarget}; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -213,8 +213,8 @@ impl Tool for CronAddTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::config::Config; + use crate::openhuman::security::AutonomyLevel; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_list.rs b/src-tauri/src/openhuman/tools/cron_list.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_list.rs rename to src-tauri/src/openhuman/tools/cron_list.rs index 264947168..caf2c0f13 100644 --- a/src-tauri/src/alphahuman/tools/cron_list.rs +++ b/src-tauri/src/openhuman/tools/cron_list.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -60,7 +60,7 @@ impl Tool for CronListTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_remove.rs b/src-tauri/src/openhuman/tools/cron_remove.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_remove.rs rename to src-tauri/src/openhuman/tools/cron_remove.rs index 751f16500..05f57fb14 100644 --- a/src-tauri/src/alphahuman/tools/cron_remove.rs +++ b/src-tauri/src/openhuman/tools/cron_remove.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -73,7 +73,7 @@ impl Tool for CronRemoveTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_run.rs b/src-tauri/src/openhuman/tools/cron_run.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_run.rs rename to src-tauri/src/openhuman/tools/cron_run.rs index ef95e261d..015a69e89 100644 --- a/src-tauri/src/alphahuman/tools/cron_run.rs +++ b/src-tauri/src/openhuman/tools/cron_run.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use chrono::Utc; use serde_json::json; @@ -104,7 +104,7 @@ impl Tool for CronRunTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/cron_runs.rs b/src-tauri/src/openhuman/tools/cron_runs.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/cron_runs.rs rename to src-tauri/src/openhuman/tools/cron_runs.rs index 809082dee..ec7c352b6 100644 --- a/src-tauri/src/alphahuman/tools/cron_runs.rs +++ b/src-tauri/src/openhuman/tools/cron_runs.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; +use crate::openhuman::config::Config; +use crate::openhuman::cron; use async_trait::async_trait; use serde::Serialize; use serde_json::json; @@ -117,7 +117,7 @@ fn truncate(input: &str, max_chars: usize) -> String { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use chrono::{Duration as ChronoDuration, Utc}; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/cron_update.rs b/src-tauri/src/openhuman/tools/cron_update.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/cron_update.rs rename to src-tauri/src/openhuman/tools/cron_update.rs index 5adacc448..e0f9a03af 100644 --- a/src-tauri/src/alphahuman/tools/cron_update.rs +++ b/src-tauri/src/openhuman/tools/cron_update.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron::{self, CronJobPatch}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron::{self, CronJobPatch}; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -108,7 +108,7 @@ impl Tool for CronUpdateTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::Config; + use crate::openhuman::config::Config; use tempfile::TempDir; async fn test_config(tmp: &TempDir) -> Arc { diff --git a/src-tauri/src/alphahuman/tools/delegate.rs b/src-tauri/src/openhuman/tools/delegate.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/delegate.rs rename to src-tauri/src/openhuman/tools/delegate.rs index 13e1229f9..058eb0007 100644 --- a/src-tauri/src/alphahuman/tools/delegate.rs +++ b/src-tauri/src/openhuman/tools/delegate.rs @@ -1,8 +1,8 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::DelegateAgentConfig; -use crate::alphahuman::providers::{self, Provider}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::DelegateAgentConfig; +use crate::openhuman::providers::{self, Provider}; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::collections::HashMap; @@ -305,7 +305,7 @@ impl Tool for DelegateTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy::default()) diff --git a/src-tauri/src/alphahuman/tools/file_read.rs b/src-tauri/src/openhuman/tools/file_read.rs similarity index 93% rename from src-tauri/src/alphahuman/tools/file_read.rs rename to src-tauri/src/openhuman/tools/file_read.rs index b9a44453a..b459bde55 100644 --- a/src-tauri/src/alphahuman/tools/file_read.rs +++ b/src-tauri/src/openhuman/tools/file_read.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -140,7 +140,7 @@ impl Tool for FileReadTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(workspace: std::path::PathBuf) -> Arc { Arc::new(SecurityPolicy { @@ -182,7 +182,7 @@ mod tests { #[tokio::test] async fn file_read_existing_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read"); + let dir = std::env::temp_dir().join("openhuman_test_file_read"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "hello world") @@ -200,7 +200,7 @@ mod tests { #[tokio::test] async fn file_read_nonexistent_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_missing"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_missing"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -214,7 +214,7 @@ mod tests { #[tokio::test] async fn file_read_blocks_path_traversal() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_traversal"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_traversal"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -239,7 +239,7 @@ mod tests { #[tokio::test] async fn file_read_blocks_when_rate_limited() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_rate_limited"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_rate_limited"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "hello world") @@ -265,7 +265,7 @@ mod tests { #[tokio::test] async fn file_read_allows_readonly_mode() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_readonly"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_readonly"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("test.txt"), "readonly ok") @@ -290,7 +290,7 @@ mod tests { #[tokio::test] async fn file_read_empty_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_empty"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_empty"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("empty.txt"), "").await.unwrap(); @@ -305,7 +305,7 @@ mod tests { #[tokio::test] async fn file_read_nested_path() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_nested"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_nested"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(dir.join("sub/dir")) .await @@ -330,7 +330,7 @@ mod tests { async fn file_read_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_read_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_file_read_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -359,7 +359,7 @@ mod tests { #[tokio::test] async fn file_read_nonexistent_consumes_rate_limit_budget() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_probe"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_probe"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -393,7 +393,7 @@ mod tests { #[tokio::test] async fn file_read_rejects_oversized_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_read_large"); + let dir = std::env::temp_dir().join("openhuman_test_file_read_large"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); diff --git a/src-tauri/src/alphahuman/tools/file_write.rs b/src-tauri/src/openhuman/tools/file_write.rs similarity index 93% rename from src-tauri/src/alphahuman/tools/file_write.rs rename to src-tauri/src/openhuman/tools/file_write.rs index 86e5dee42..94a9011a5 100644 --- a/src-tauri/src/alphahuman/tools/file_write.rs +++ b/src-tauri/src/openhuman/tools/file_write.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -164,7 +164,7 @@ impl Tool for FileWriteTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(workspace: std::path::PathBuf) -> Arc { Arc::new(SecurityPolicy { @@ -206,7 +206,7 @@ mod tests { #[tokio::test] async fn file_write_creates_file() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write"); + let dir = std::env::temp_dir().join("openhuman_test_file_write"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -228,7 +228,7 @@ mod tests { #[tokio::test] async fn file_write_creates_parent_dirs() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_nested"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_nested"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -249,7 +249,7 @@ mod tests { #[tokio::test] async fn file_write_overwrites_existing() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_overwrite"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_overwrite"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); tokio::fs::write(dir.join("exist.txt"), "old") @@ -273,7 +273,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_path_traversal() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_traversal"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_traversal"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -315,7 +315,7 @@ mod tests { #[tokio::test] async fn file_write_empty_content() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_empty"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_empty"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -335,7 +335,7 @@ mod tests { async fn file_write_blocks_symlink_escape() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_write_symlink_escape"); + let root = std::env::temp_dir().join("openhuman_test_file_write_symlink_escape"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -364,7 +364,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_readonly_mode() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_readonly"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_readonly"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -383,7 +383,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_when_rate_limited() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_rate_limited"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_rate_limited"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); @@ -415,7 +415,7 @@ mod tests { async fn file_write_blocks_symlink_target_file() { use std::os::unix::fs::symlink; - let root = std::env::temp_dir().join("alphahuman_test_file_write_symlink_target"); + let root = std::env::temp_dir().join("openhuman_test_file_write_symlink_target"); let workspace = root.join("workspace"); let outside = root.join("outside"); @@ -452,7 +452,7 @@ mod tests { #[tokio::test] async fn file_write_blocks_null_byte_in_path() { - let dir = std::env::temp_dir().join("alphahuman_test_file_write_null"); + let dir = std::env::temp_dir().join("openhuman_test_file_write_null"); let _ = tokio::fs::remove_dir_all(&dir).await; tokio::fs::create_dir_all(&dir).await.unwrap(); diff --git a/src-tauri/src/alphahuman/tools/git_operations.rs b/src-tauri/src/openhuman/tools/git_operations.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/git_operations.rs rename to src-tauri/src/openhuman/tools/git_operations.rs index 077c40e5e..3da5872fb 100644 --- a/src-tauri/src/alphahuman/tools/git_operations.rs +++ b/src-tauri/src/openhuman/tools/git_operations.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; +use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -569,7 +569,7 @@ impl Tool for GitOperationsTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::SecurityPolicy; + use crate::openhuman::security::SecurityPolicy; use tempfile::TempDir; fn test_tool(dir: &std::path::Path) -> GitOperationsTool { diff --git a/src-tauri/src/alphahuman/tools/hardware_board_info.rs b/src-tauri/src/openhuman/tools/hardware_board_info.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_board_info.rs rename to src-tauri/src/openhuman/tools/hardware_board_info.rs diff --git a/src-tauri/src/alphahuman/tools/hardware_memory_map.rs b/src-tauri/src/openhuman/tools/hardware_memory_map.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_memory_map.rs rename to src-tauri/src/openhuman/tools/hardware_memory_map.rs diff --git a/src-tauri/src/alphahuman/tools/hardware_memory_read.rs b/src-tauri/src/openhuman/tools/hardware_memory_read.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/hardware_memory_read.rs rename to src-tauri/src/openhuman/tools/hardware_memory_read.rs diff --git a/src-tauri/src/alphahuman/tools/http_request.rs b/src-tauri/src/openhuman/tools/http_request.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/http_request.rs rename to src-tauri/src/openhuman/tools/http_request.rs index 9e19eaa36..19565ca3c 100644 --- a/src-tauri/src/alphahuman/tools/http_request.rs +++ b/src-tauri/src/openhuman/tools/http_request.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -118,7 +118,7 @@ impl HttpRequestTool { .timeout(Duration::from_secs(self.timeout_secs)) .connect_timeout(Duration::from_secs(10)) .redirect(reqwest::redirect::Policy::none()); - let builder = crate::alphahuman::config::apply_runtime_proxy_to_builder(builder, "tool.http_request"); + let builder = crate::openhuman::config::apply_runtime_proxy_to_builder(builder, "tool.http_request"); let client = builder.build()?; let mut request = client.request(method, url); @@ -437,7 +437,7 @@ fn is_non_global_v6(v6: std::net::Ipv6Addr) -> bool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_tool(allowed_domains: Vec<&str>) -> HttpRequestTool { let security = Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/image_info.rs b/src-tauri/src/openhuman/tools/image_info.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/image_info.rs rename to src-tauri/src/openhuman/tools/image_info.rs index 077b78923..fdf1538ba 100644 --- a/src-tauri/src/alphahuman/tools/image_info.rs +++ b/src-tauri/src/openhuman/tools/image_info.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -231,7 +231,7 @@ impl Tool for ImageInfoTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy { @@ -427,7 +427,7 @@ mod tests { #[tokio::test] async fn execute_real_file() { // Create a minimal valid PNG - let dir = std::env::temp_dir().join("alphahuman_image_info_test"); + let dir = std::env::temp_dir().join("openhuman_image_info_test"); let _ = tokio::fs::create_dir_all(&dir).await; let png_path = dir.join("test.png"); @@ -466,7 +466,7 @@ mod tests { #[tokio::test] async fn execute_with_base64() { - let dir = std::env::temp_dir().join("alphahuman_image_info_b64"); + let dir = std::env::temp_dir().join("openhuman_image_info_b64"); let _ = tokio::fs::create_dir_all(&dir).await; let png_path = dir.join("test_b64.png"); diff --git a/src-tauri/src/alphahuman/tools/memory_forget.rs b/src-tauri/src/openhuman/tools/memory_forget.rs similarity index 95% rename from src-tauri/src/alphahuman/tools/memory_forget.rs rename to src-tauri/src/openhuman/tools/memory_forget.rs index a5795688d..b131bcf6e 100644 --- a/src-tauri/src/alphahuman/tools/memory_forget.rs +++ b/src-tauri/src/openhuman/tools/memory_forget.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::memory::Memory; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -81,8 +81,8 @@ impl Tool for MemoryForgetTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{MemoryCategory, SqliteMemory}; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::memory::{MemoryCategory, SqliteMemory}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/memory_recall.rs b/src-tauri/src/openhuman/tools/memory_recall.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/memory_recall.rs rename to src-tauri/src/openhuman/tools/memory_recall.rs index 901c05b8e..4daaa59b6 100644 --- a/src-tauri/src/alphahuman/tools/memory_recall.rs +++ b/src-tauri/src/openhuman/tools/memory_recall.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::Memory; +use crate::openhuman::memory::Memory; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -91,7 +91,7 @@ impl Tool for MemoryRecallTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::{MemoryCategory, SqliteMemory}; + use crate::openhuman::memory::{MemoryCategory, SqliteMemory}; use tempfile::TempDir; fn seeded_mem() -> (TempDir, Arc) { diff --git a/src-tauri/src/alphahuman/tools/memory_store.rs b/src-tauri/src/openhuman/tools/memory_store.rs similarity index 96% rename from src-tauri/src/alphahuman/tools/memory_store.rs rename to src-tauri/src/openhuman/tools/memory_store.rs index 725b892ae..8471f82e1 100644 --- a/src-tauri/src/alphahuman/tools/memory_store.rs +++ b/src-tauri/src/openhuman/tools/memory_store.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::memory::{Memory, MemoryCategory}; -use crate::alphahuman::security::policy::ToolOperation; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::memory::{Memory, MemoryCategory}; +use crate::openhuman::security::policy::ToolOperation; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -96,8 +96,8 @@ impl Tool for MemoryStoreTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::memory::SqliteMemory; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::memory::SqliteMemory; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/mod.rs b/src-tauri/src/openhuman/tools/mod.rs similarity index 91% rename from src-tauri/src/alphahuman/tools/mod.rs rename to src-tauri/src/openhuman/tools/mod.rs index 5fab89d6e..6bf8526a3 100644 --- a/src-tauri/src/alphahuman/tools/mod.rs +++ b/src-tauri/src/openhuman/tools/mod.rs @@ -61,10 +61,10 @@ pub use traits::Tool; pub use traits::{ToolResult, ToolSpec}; pub use web_search_tool::WebSearchTool; -use crate::alphahuman::config::{Config, DelegateAgentConfig}; -use crate::alphahuman::memory::Memory; -use crate::alphahuman::runtime::{NativeRuntime, RuntimeAdapter}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::{Config, DelegateAgentConfig}; +use crate::openhuman::memory::Memory; +use crate::openhuman::runtime::{NativeRuntime, RuntimeAdapter}; +use crate::openhuman::security::SecurityPolicy; use std::collections::HashMap; use std::sync::Arc; @@ -93,12 +93,12 @@ pub fn all_tools( memory: Arc, composio_key: Option<&str>, composio_entity_id: Option<&str>, - browser_config: &crate::alphahuman::config::BrowserConfig, - http_config: &crate::alphahuman::config::HttpRequestConfig, + browser_config: &crate::openhuman::config::BrowserConfig, + http_config: &crate::openhuman::config::HttpRequestConfig, workspace_dir: &std::path::Path, agents: &HashMap, fallback_api_key: Option<&str>, - root_config: &crate::alphahuman::config::Config, + root_config: &crate::openhuman::config::Config, ) -> Vec> { all_tools_with_runtime( config, @@ -125,12 +125,12 @@ pub fn all_tools_with_runtime( memory: Arc, composio_key: Option<&str>, composio_entity_id: Option<&str>, - browser_config: &crate::alphahuman::config::BrowserConfig, - http_config: &crate::alphahuman::config::HttpRequestConfig, + browser_config: &crate::openhuman::config::BrowserConfig, + http_config: &crate::openhuman::config::HttpRequestConfig, workspace_dir: &std::path::Path, agents: &HashMap, fallback_api_key: Option<&str>, - root_config: &crate::alphahuman::config::Config, + root_config: &crate::openhuman::config::Config, ) -> Vec> { let mut tools: Vec> = vec![ Box::new(ShellTool::new(security.clone(), runtime)), @@ -231,9 +231,9 @@ pub fn all_tools_with_runtime( delegate_agents, delegate_fallback_credential, security.clone(), - crate::alphahuman::providers::ProviderRuntimeOptions { + crate::openhuman::providers::ProviderRuntimeOptions { auth_profile_override: None, - alphahuman_dir: root_config + openhuman_dir: root_config .config_path .parent() .map(std::path::PathBuf::from), @@ -249,7 +249,7 @@ pub fn all_tools_with_runtime( #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{BrowserConfig, Config, MemoryConfig}; + use crate::openhuman::config::{BrowserConfig, Config, MemoryConfig}; use tempfile::TempDir; fn test_config(tmp: &TempDir) -> Config { @@ -276,7 +276,7 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig { enabled: false, @@ -284,7 +284,7 @@ mod tests { session_name: None, ..BrowserConfig::default() }; - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( @@ -316,7 +316,7 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig { enabled: true, @@ -324,7 +324,7 @@ mod tests { session_name: None, ..BrowserConfig::default() }; - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( @@ -449,10 +449,10 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig::default(); - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let mut agents = HashMap::new(); @@ -494,10 +494,10 @@ mod tests { ..MemoryConfig::default() }; let mem: Arc = - Arc::from(crate::alphahuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); + Arc::from(crate::openhuman::memory::create_memory(&mem_cfg, tmp.path(), None).unwrap()); let browser = BrowserConfig::default(); - let http = crate::alphahuman::config::HttpRequestConfig::default(); + let http = crate::openhuman::config::HttpRequestConfig::default(); let cfg = test_config(&tmp); let tools = all_tools( diff --git a/src-tauri/src/alphahuman/tools/proxy_config.rs b/src-tauri/src/openhuman/tools/proxy_config.rs similarity index 97% rename from src-tauri/src/alphahuman/tools/proxy_config.rs rename to src-tauri/src/openhuman/tools/proxy_config.rs index e976220c4..40716eeb2 100644 --- a/src-tauri/src/alphahuman/tools/proxy_config.rs +++ b/src-tauri/src/openhuman/tools/proxy_config.rs @@ -1,9 +1,9 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::{ +use crate::openhuman::config::{ runtime_proxy_config, set_runtime_proxy_config, Config, ProxyConfig, ProxyScope, }; -use crate::alphahuman::security::SecurityPolicy; -use crate::alphahuman::util::MaybeSet; +use crate::openhuman::security::SecurityPolicy; +use crate::openhuman::util::MaybeSet; use async_trait::async_trait; use serde_json::{json, Value}; use std::fs; @@ -61,7 +61,7 @@ impl ProxyConfigTool { fn parse_scope(raw: &str) -> Option { match raw.trim().to_ascii_lowercase().as_str() { "environment" | "env" => Some(ProxyScope::Environment), - "alphahuman" | "internal" | "core" => Some(ProxyScope::Alphahuman), + "openhuman" | "internal" | "core" => Some(ProxyScope::OpenHuman), "services" | "service" => Some(ProxyScope::Services), _ => None, } @@ -185,7 +185,7 @@ impl ProxyConfigTool { .as_str() .ok_or_else(|| anyhow::anyhow!("'scope' must be a string"))?; proxy.scope = Self::parse_scope(scope).ok_or_else(|| { - anyhow::anyhow!("Invalid scope '{scope}'. Use environment|alphahuman|services") + anyhow::anyhow!("Invalid scope '{scope}'. Use environment|openhuman|services") })?; } @@ -342,7 +342,7 @@ impl Tool for ProxyConfigTool { } fn description(&self) -> &str { - "Manage Alphahuman proxy settings (scope: environment | alphahuman | services), including runtime and process env application" + "Manage OpenHuman proxy settings (scope: environment | openhuman | services), including runtime and process env application" } fn parameters_schema(&self) -> Value { @@ -360,7 +360,7 @@ impl Tool for ProxyConfigTool { }, "scope": { "type": "string", - "description": "Proxy scope: environment | alphahuman | services" + "description": "Proxy scope: environment | openhuman | services" }, "http_proxy": { "type": ["string", "null"], @@ -438,7 +438,7 @@ impl Tool for ProxyConfigTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; use tempfile::TempDir; fn test_security() -> Arc { diff --git a/src-tauri/src/alphahuman/tools/pushover.rs b/src-tauri/src/openhuman/tools/pushover.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/pushover.rs rename to src-tauri/src/openhuman/tools/pushover.rs index c4a838f51..f56a215f8 100644 --- a/src-tauri/src/alphahuman/tools/pushover.rs +++ b/src-tauri/src/openhuman/tools/pushover.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::path::PathBuf; @@ -173,7 +173,7 @@ impl Tool for PushoverTool { form = form.text("sound", sound); } - let client = crate::alphahuman::config::build_runtime_proxy_client_with_timeouts( + let client = crate::openhuman::config::build_runtime_proxy_client_with_timeouts( "tool.pushover", PUSHOVER_REQUEST_TIMEOUT_SECS, 10, @@ -217,7 +217,7 @@ impl Tool for PushoverTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::security::AutonomyLevel; use std::fs; use tempfile::TempDir; diff --git a/src-tauri/src/alphahuman/tools/schedule.rs b/src-tauri/src/openhuman/tools/schedule.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/schedule.rs rename to src-tauri/src/openhuman/tools/schedule.rs index 8730b3b43..9af475000 100644 --- a/src-tauri/src/alphahuman/tools/schedule.rs +++ b/src-tauri/src/openhuman/tools/schedule.rs @@ -1,7 +1,7 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::config::Config; -use crate::alphahuman::cron; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::config::Config; +use crate::openhuman::cron; +use crate::openhuman::security::SecurityPolicy; use anyhow::Result; use async_trait::async_trait; use chrono::{DateTime, Utc}; @@ -365,7 +365,7 @@ impl ScheduleTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::AutonomyLevel; + use crate::openhuman::security::AutonomyLevel; use tempfile::TempDir; async fn test_setup() -> (TempDir, Config, Arc) { @@ -485,7 +485,7 @@ mod tests { let config = Config { workspace_dir: tmp.path().join("workspace"), config_path: tmp.path().join("config.toml"), - autonomy: crate::alphahuman::config::AutonomyConfig { + autonomy: crate::openhuman::config::AutonomyConfig { level: AutonomyLevel::ReadOnly, ..Default::default() }, diff --git a/src-tauri/src/alphahuman/tools/schema.rs b/src-tauri/src/openhuman/tools/schema.rs similarity index 99% rename from src-tauri/src/alphahuman/tools/schema.rs rename to src-tauri/src/openhuman/tools/schema.rs index 75b4f8319..51da111e9 100644 --- a/src-tauri/src/alphahuman/tools/schema.rs +++ b/src-tauri/src/openhuman/tools/schema.rs @@ -17,7 +17,7 @@ //! //! ```rust //! use serde_json::json; -//! use tauri_app_lib::alphahuman::tools::schema::SchemaCleanr; +//! use tauri_app_lib::openhuman::tools::schema::SchemaCleanr; //! //! let dirty_schema = json!({ //! "type": "object", diff --git a/src-tauri/src/alphahuman/tools/screenshot.rs b/src-tauri/src/openhuman/tools/screenshot.rs similarity index 98% rename from src-tauri/src/alphahuman/tools/screenshot.rs rename to src-tauri/src/openhuman/tools/screenshot.rs index d131eada3..d43e2fd1d 100644 --- a/src-tauri/src/alphahuman/tools/screenshot.rs +++ b/src-tauri/src/openhuman/tools/screenshot.rs @@ -1,5 +1,5 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::fmt::Write; @@ -252,7 +252,7 @@ impl Tool for ScreenshotTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security() -> Arc { Arc::new(SecurityPolicy { diff --git a/src-tauri/src/alphahuman/tools/shell.rs b/src-tauri/src/openhuman/tools/shell.rs similarity index 95% rename from src-tauri/src/alphahuman/tools/shell.rs rename to src-tauri/src/openhuman/tools/shell.rs index f6a866e7b..e29c83650 100644 --- a/src-tauri/src/alphahuman/tools/shell.rs +++ b/src-tauri/src/openhuman/tools/shell.rs @@ -1,6 +1,6 @@ use super::traits::{Tool, ToolResult}; -use crate::alphahuman::runtime::RuntimeAdapter; -use crate::alphahuman::security::SecurityPolicy; +use crate::openhuman::runtime::RuntimeAdapter; +use crate::openhuman::security::SecurityPolicy; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; @@ -164,8 +164,8 @@ impl Tool for ShellTool { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::runtime::{NativeRuntime, RuntimeAdapter}; - use crate::alphahuman::security::{AutonomyLevel, SecurityPolicy}; + use crate::openhuman::runtime::{NativeRuntime, RuntimeAdapter}; + use crate::openhuman::security::{AutonomyLevel, SecurityPolicy}; fn test_security(autonomy: AutonomyLevel) -> Arc { Arc::new(SecurityPolicy { @@ -293,7 +293,7 @@ mod tests { #[tokio::test(flavor = "current_thread")] async fn shell_does_not_leak_api_key() { let _g1 = EnvGuard::set("API_KEY", "sk-test-secret-12345"); - let _g2 = EnvGuard::set("ALPHAHUMAN_API_KEY", "sk-test-secret-67890"); + let _g2 = EnvGuard::set("OPENHUMAN_API_KEY", "sk-test-secret-67890"); let tool = ShellTool::new(test_security_with_env_cmd(), test_runtime()); let result = tool.execute(json!({"command": "env"})).await.unwrap(); @@ -304,7 +304,7 @@ mod tests { ); assert!( !result.output.contains("sk-test-secret-67890"), - "ALPHAHUMAN_API_KEY leaked to shell command output" + "OPENHUMAN_API_KEY leaked to shell command output" ); } @@ -344,7 +344,7 @@ mod tests { let tool = ShellTool::new(security.clone(), test_runtime()); let denied = tool - .execute(json!({"command": "touch alphahuman_shell_approval_test"})) + .execute(json!({"command": "touch openhuman_shell_approval_test"})) .await .unwrap(); assert!(!denied.success); @@ -356,7 +356,7 @@ mod tests { let allowed = tool .execute(json!({ - "command": "touch alphahuman_shell_approval_test", + "command": "touch openhuman_shell_approval_test", "approved": true })) .await @@ -364,7 +364,7 @@ mod tests { assert!(allowed.success); let _ = - tokio::fs::remove_file(std::env::temp_dir().join("alphahuman_shell_approval_test")).await; + tokio::fs::remove_file(std::env::temp_dir().join("openhuman_shell_approval_test")).await; } // ── §5.2 Shell timeout enforcement tests ───────────────── diff --git a/src-tauri/src/alphahuman/tools/traits.rs b/src-tauri/src/openhuman/tools/traits.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/traits.rs rename to src-tauri/src/openhuman/tools/traits.rs diff --git a/src-tauri/src/alphahuman/tools/web_search_tool.rs b/src-tauri/src/openhuman/tools/web_search_tool.rs similarity index 100% rename from src-tauri/src/alphahuman/tools/web_search_tool.rs rename to src-tauri/src/openhuman/tools/web_search_tool.rs diff --git a/src-tauri/src/alphahuman/tunnel/cloudflare.rs b/src-tauri/src/openhuman/tunnel/cloudflare.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/cloudflare.rs rename to src-tauri/src/openhuman/tunnel/cloudflare.rs diff --git a/src-tauri/src/alphahuman/tunnel/custom.rs b/src-tauri/src/openhuman/tunnel/custom.rs similarity index 98% rename from src-tauri/src/alphahuman/tunnel/custom.rs rename to src-tauri/src/openhuman/tunnel/custom.rs index db94fece8..dc74148fc 100644 --- a/src-tauri/src/alphahuman/tunnel/custom.rs +++ b/src-tauri/src/openhuman/tunnel/custom.rs @@ -123,7 +123,7 @@ impl Tunnel for CustomTunnel { async fn health_check(&self) -> bool { // If a health URL is configured, try to reach it if let Some(ref url) = self.health_url { - return crate::alphahuman::config::build_runtime_proxy_client("tunnel.custom") + return crate::openhuman::config::build_runtime_proxy_client("tunnel.custom") .get(url) .timeout(std::time::Duration::from_secs(5)) .send() diff --git a/src-tauri/src/alphahuman/tunnel/mod.rs b/src-tauri/src/openhuman/tunnel/mod.rs similarity index 98% rename from src-tauri/src/alphahuman/tunnel/mod.rs rename to src-tauri/src/openhuman/tunnel/mod.rs index bbe2af9c2..17fad2b26 100644 --- a/src-tauri/src/alphahuman/tunnel/mod.rs +++ b/src-tauri/src/openhuman/tunnel/mod.rs @@ -11,7 +11,7 @@ pub use ngrok::NgrokTunnel; pub use none::NoneTunnel; pub use tailscale::TailscaleTunnel; -use crate::alphahuman::config::{TailscaleTunnelConfig, TunnelConfig}; +use crate::openhuman::config::{TailscaleTunnelConfig, TunnelConfig}; use anyhow::{bail, Result}; use std::sync::Arc; use tokio::sync::Mutex; @@ -130,7 +130,7 @@ pub fn create_tunnel(config: &TunnelConfig) -> Result>> { #[cfg(test)] mod tests { use super::*; - use crate::alphahuman::config::{ + use crate::openhuman::config::{ CloudflareTunnelConfig, CustomTunnelConfig, NgrokTunnelConfig, }; diff --git a/src-tauri/src/alphahuman/tunnel/ngrok.rs b/src-tauri/src/openhuman/tunnel/ngrok.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/ngrok.rs rename to src-tauri/src/openhuman/tunnel/ngrok.rs diff --git a/src-tauri/src/alphahuman/tunnel/none.rs b/src-tauri/src/openhuman/tunnel/none.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/none.rs rename to src-tauri/src/openhuman/tunnel/none.rs diff --git a/src-tauri/src/alphahuman/tunnel/tailscale.rs b/src-tauri/src/openhuman/tunnel/tailscale.rs similarity index 100% rename from src-tauri/src/alphahuman/tunnel/tailscale.rs rename to src-tauri/src/openhuman/tunnel/tailscale.rs diff --git a/src-tauri/src/alphahuman/util.rs b/src-tauri/src/openhuman/util.rs similarity index 97% rename from src-tauri/src/alphahuman/util.rs rename to src-tauri/src/openhuman/util.rs index 812dcac5d..927251538 100644 --- a/src-tauri/src/alphahuman/util.rs +++ b/src-tauri/src/openhuman/util.rs @@ -1,4 +1,4 @@ -//! Utility functions for `Alphahuman`. +//! Utility functions for `OpenHuman`. //! //! This module contains reusable helper functions used across the codebase. @@ -17,7 +17,7 @@ /// /// # Examples /// ``` -/// use tauri_app_lib::alphahuman::util::truncate_with_ellipsis; +/// use tauri_app_lib::openhuman::util::truncate_with_ellipsis; /// /// // ASCII string - no truncation needed /// assert_eq!(truncate_with_ellipsis("hello", 10), "hello"); diff --git a/src-tauri/src/runtime/bridge/db.rs b/src-tauri/src/runtime/bridge/db.rs index 1a2e251ea..45ba62557 100644 --- a/src-tauri/src/runtime/bridge/db.rs +++ b/src-tauri/src/runtime/bridge/db.rs @@ -1,4 +1,4 @@ -//! @alphahuman/db bridge — scoped SQLite access for each skill. +//! @openhuman/db bridge — scoped SQLite access for each skill. //! //! Each skill gets its own SQLite database at `{app_data_dir}/skills/{skill_id}/skill.db`. //! The bridge exposes async functions callable from JS: diff --git a/src-tauri/src/runtime/bridge/log_bridge.rs b/src-tauri/src/runtime/bridge/log_bridge.rs index 37c81dcc2..119a03758 100644 --- a/src-tauri/src/runtime/bridge/log_bridge.rs +++ b/src-tauri/src/runtime/bridge/log_bridge.rs @@ -1,4 +1,4 @@ -//! @alphahuman/log bridge — structured logging from JS skills. +//! @openhuman/log bridge — structured logging from JS skills. //! //! Exposes log levels: debug, info, warn, error. //! Logs are forwarded to Rust's `log` crate AND emitted as Tauri events diff --git a/src-tauri/src/runtime/bridge/store.rs b/src-tauri/src/runtime/bridge/store.rs index 90a31e5a9..4ab169dcd 100644 --- a/src-tauri/src/runtime/bridge/store.rs +++ b/src-tauri/src/runtime/bridge/store.rs @@ -1,4 +1,4 @@ -//! @alphahuman/store bridge — persisted key-value state for skills. +//! @openhuman/store bridge — persisted key-value state for skills. //! //! Thin wrapper around the __kv table in each skill's SQLite database. //! Provides a simpler API than raw SQL for common state persistence patterns. diff --git a/src-tauri/src/runtime/loader.rs b/src-tauri/src/runtime/loader.rs index 7479035de..8b82b8068 100644 --- a/src-tauri/src/runtime/loader.rs +++ b/src-tauri/src/runtime/loader.rs @@ -1,8 +1,8 @@ -//! Custom module resolver and loader for `@alphahuman/*` imports. +//! Custom module resolver and loader for `@openhuman/*` imports. //! //! NOTE: Currently unused. Skills access bridge APIs via globals (db, store, console) //! injected by qjs_skill_instance.rs. This module is reserved for future ES module -//! import support (e.g., `import { db } from '@alphahuman/db'`). +//! import support (e.g., `import { db } from '@openhuman/db'`). //! //! The globals-based approach was chosen because: //! - Globals are simpler and sufficient for the initial implementation diff --git a/src-tauri/src/runtime/manifest.rs b/src-tauri/src/runtime/manifest.rs index c667b8883..4624b7e2f 100644 --- a/src-tauri/src/runtime/manifest.rs +++ b/src-tauri/src/runtime/manifest.rs @@ -51,14 +51,14 @@ pub struct SkillManifest { #[serde(default)] pub platforms: Option>, /// Skill type for the unified registry dispatch. - /// "alphahuman" → executed via QuickJS runtime (default). + /// "openhuman" → executed via QuickJS runtime (default). /// "openclaw" → loaded and executed from SKILL.md/SKILL.toml. #[serde(default = "default_skill_type")] pub skill_type: String, } fn default_skill_type() -> String { - "alphahuman".to_string() + "openhuman".to_string() } fn default_runtime() -> String { diff --git a/src-tauri/src/runtime/types.rs b/src-tauri/src/runtime/types.rs index 14908d90a..86ab4c4b2 100644 --- a/src-tauri/src/runtime/types.rs +++ b/src-tauri/src/runtime/types.rs @@ -170,14 +170,14 @@ fn default_memory_limit() -> usize { 256 * 1024 * 1024 // 256 MB } -/// A skill entry in the unified registry (covers both alphahuman and openclaw types). +/// A skill entry in the unified registry (covers both openhuman and openclaw types). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UnifiedSkillEntry { /// Unique skill identifier. pub id: String, /// Human-readable name. pub name: String, - /// Skill type: "alphahuman" (QuickJS) or "openclaw" (SKILL.md/TOML). + /// Skill type: "openhuman" (QuickJS) or "openclaw" (SKILL.md/TOML). pub skill_type: String, /// Version string. pub version: String, diff --git a/src-tauri/src/services/quickjs_libs/bootstrap.js b/src-tauri/src/services/quickjs_libs/bootstrap.js index 64e56b915..a184ff7f8 100644 --- a/src-tauri/src/services/quickjs_libs/bootstrap.js +++ b/src-tauri/src/services/quickjs_libs/bootstrap.js @@ -846,7 +846,7 @@ globalThis.data = { body: JSON.stringify({ error: 'No OAuth credential. Complete OAuth setup first.' }), }; } - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var cleanPath = path.charAt(0) === '/' ? path.slice(1) : path; var proxyUrl = backendUrl + '/proxy/by-id/' + globalThis.__oauthCredential.credentialId + '/' + cleanPath; @@ -875,7 +875,7 @@ globalThis.data = { revoke: async function () { if (__oauthCredential) { try { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var revokeOpts = JSON.stringify({ method: 'DELETE', @@ -1022,7 +1022,7 @@ globalThis.model = { * @returns {string} */ generate: async function (prompt, options) { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var body = { prompt: prompt }; if (options && options.maxTokens) body.maxTokens = options.maxTokens; @@ -1052,7 +1052,7 @@ globalThis.model = { * @returns {string} */ summarize: async function (text, options) { - var backendUrl = __platform.env('BACKEND_URL') || 'https://api.alphahuman.xyz'; + var backendUrl = __platform.env('BACKEND_URL') || 'https://api.tinyhumans.ai'; var jwtToken = __ops.get_session_token() || ''; var body = { text: text }; if (options && options.maxTokens) body.maxTokens = options.maxTokens; diff --git a/src-tauri/src/unified_skills/generator.rs b/src-tauri/src/unified_skills/generator.rs index 0295f1575..f0969d2db 100644 --- a/src-tauri/src/unified_skills/generator.rs +++ b/src-tauri/src/unified_skills/generator.rs @@ -1,22 +1,22 @@ //! Programmatic skill generation for the unified skill registry. //! //! Supports generating both skill types: -//! - `alphahuman`: writes manifest.json + index.js to the QuickJS skills directory. -//! - `openclaw`: writes SKILL.md or SKILL.toml to the alphahuman workspace skills directory. +//! - `openhuman`: writes manifest.json + index.js to the QuickJS skills directory. +//! - `openclaw`: writes SKILL.md or SKILL.toml to the openhuman workspace skills directory. use crate::unified_skills::GenerateSkillSpec; use directories::UserDirs; use serde::Serialize; use std::path::{Path, PathBuf}; -/// Generate an alphahuman (QuickJS) skill at `//`. +/// Generate an openhuman (QuickJS) skill at `//`. /// /// Returns the list of file paths that were written (manifest.json + index.js). /// /// When `spec.full_index_js` is `Some`, its content is written directly to /// `index.js` instead of using the default template. This allows the /// self-evolve loop to persist LLM-generated code verbatim. -pub async fn generate_alphahuman( +pub async fn generate_openhuman( spec: &GenerateSkillSpec, skills_dir: &Path, ) -> Result, String> { @@ -37,7 +37,7 @@ pub async fn generate_alphahuman( let manifest = serde_json::json!({ "id": dir_name, "name": spec.name, - "skill_type": "alphahuman", + "skill_type": "openhuman", "runtime": "quickjs", "entry": "index.js", "version": "1.0.0", @@ -69,7 +69,7 @@ pub async fn generate_alphahuman( Ok(vec![manifest_path, index_path]) } -/// Generate an openclaw (SKILL.md/TOML) skill in `~/.alphahuman/workspace/skills//`. +/// Generate an openclaw (SKILL.md/TOML) skill in `~/.openhuman/workspace/skills//`. /// Returns the path of the created skill directory. pub async fn generate_openclaw(spec: &GenerateSkillSpec) -> Result { let dir_name = sanitize_id(&spec.name); @@ -140,12 +140,12 @@ pub async fn generate_openclaw(spec: &GenerateSkillSpec) -> Result Result { let dirs = UserDirs::new().ok_or("Cannot resolve home directory")?; Ok(dirs .home_dir() - .join(".alphahuman") + .join(".openhuman") .join("workspace") .join("skills")) } @@ -159,7 +159,7 @@ fn build_index_js(tool_fn: &str, description: &str, tool_code: &str) -> String { .unwrap_or_else(|_| r#""unknown""#.to_string()); format!( - r#"// Auto-generated alphahuman skill + r#"// Auto-generated openhuman skill tools = [ {{ name: "{tool_fn}", diff --git a/src-tauri/src/unified_skills/llm_generator.rs b/src-tauri/src/unified_skills/llm_generator.rs index d1c9f08e3..de2e6a5f7 100644 --- a/src-tauri/src/unified_skills/llm_generator.rs +++ b/src-tauri/src/unified_skills/llm_generator.rs @@ -8,7 +8,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; /// System prompt embedded at compile time. -const SYSTEM_PROMPT: &str = "You are a skill generator for the AlphaHuman platform. +const SYSTEM_PROMPT: &str = "You are a skill generator for the OpenHuman platform. Generate a complete QuickJS skill as a single index.js file. CRITICAL CONSTRAINTS: @@ -197,9 +197,9 @@ impl LlmGenerator { .chars() .take(200) .collect::(), - skill_type: "alphahuman".to_string(), + skill_type: "openhuman".to_string(), // `tool_code` holds the full source when `full_index_js` is set; - // this ensures the fallback path in `generate_alphahuman` also has + // this ensures the fallback path in `generate_openhuman` also has // something reasonable to log. tool_code: Some(full_index_js.clone()), markdown_content: None, diff --git a/src-tauri/src/unified_skills/mod.rs b/src-tauri/src/unified_skills/mod.rs index 87137f2f1..18427f5d2 100644 --- a/src-tauri/src/unified_skills/mod.rs +++ b/src-tauri/src/unified_skills/mod.rs @@ -2,7 +2,7 @@ //! //! A single registry that aggregates both skill types: //! -//! - `alphahuman`: JavaScript-based skills executed in the QuickJS runtime. +//! - `openhuman`: JavaScript-based skills executed in the QuickJS runtime. //! - `openclaw`: File-based skills defined in SKILL.md or SKILL.toml. //! //! All skills expose a common [`UnifiedSkillEntry`] interface and return @@ -14,7 +14,7 @@ pub mod openclaw_executor; pub mod self_evolve; pub mod skill_tester; -use crate::alphahuman::skills::{load_skills, Skill}; +use crate::openhuman::skills::{load_skills, Skill}; use crate::runtime::qjs_engine::RuntimeEngine; use crate::runtime::types::{ToolDefinition, UnifiedSkillEntry, UnifiedSkillResult}; use chrono::Utc; @@ -30,16 +30,16 @@ pub struct GenerateSkillSpec { pub name: String, /// Human-readable description of what the skill does. pub description: String, - /// Skill type: "alphahuman" or "openclaw". + /// Skill type: "openhuman" or "openclaw". pub skill_type: String, - /// For alphahuman skills: the JavaScript body of the generated tool function. + /// For openhuman skills: the JavaScript body of the generated tool function. pub tool_code: Option, /// For openclaw skills: markdown content written to SKILL.md. pub markdown_content: Option, /// For openclaw skills: shell command written into SKILL.toml as a tool. pub shell_command: Option, /// Complete LLM-generated `index.js` source. When present, - /// `generator::generate_alphahuman` writes this directly to disk instead + /// `generator::generate_openhuman` writes this directly to disk instead /// of building from the default template. #[serde(default)] pub full_index_js: Option, @@ -55,7 +55,7 @@ impl UnifiedSkillRegistry { Self { engine } } - /// Return the resolved skills source directory (where alphahuman skill + /// Return the resolved skills source directory (where openhuman skill /// directories are stored). pub fn skills_dir(&self) -> Result { self.engine.skills_source_dir() @@ -68,12 +68,12 @@ impl UnifiedSkillRegistry { /// List all skills from both subsystems. /// - /// - alphahuman skills come from `RuntimeEngine::discover_skills()` (manifest.json). - /// - openclaw skills come from the alphahuman workspace skills directory (SKILL.md/TOML). + /// - openhuman skills come from `RuntimeEngine::discover_skills()` (manifest.json). + /// - openclaw skills come from the openhuman workspace skills directory (SKILL.md/TOML). pub async fn list_all(&self) -> Vec { let mut entries = Vec::new(); - // --- alphahuman skills (QuickJS runtime) --- + // --- openhuman skills (QuickJS runtime) --- if let Ok(manifests) = self.engine.discover_skills().await { let snapshots = self.engine.list_skills(); @@ -102,7 +102,7 @@ impl UnifiedSkillRegistry { for skill in &openclaw_skills { let id = skill_to_id(skill); - // Skip if already listed by the alphahuman runtime (avoid duplicates). + // Skip if already listed by the openhuman runtime (avoid duplicates). if entries.iter().any(|e| e.id == id) { continue; } @@ -148,14 +148,14 @@ impl UnifiedSkillRegistry { .ok_or_else(|| format!("Skill '{skill_id}' not found in unified registry"))?; match entry.skill_type.as_str() { - "alphahuman" => self.execute_alphahuman(skill_id, tool_name, args).await, + "openhuman" => self.execute_openhuman(skill_id, tool_name, args).await, "openclaw" => self.execute_openclaw(skill_id, tool_name, args).await, other => Err(format!("Unknown skill type: '{other}'")), } } - /// Dispatch to QuickJS runtime for alphahuman skills. - async fn execute_alphahuman( + /// Dispatch to QuickJS runtime for openhuman skills. + async fn execute_openhuman( &self, skill_id: &str, tool_name: &str, @@ -192,10 +192,10 @@ impl UnifiedSkillRegistry { /// Generate a new skill from a spec, write it to disk, and return its registry entry. pub async fn generate(&self, spec: GenerateSkillSpec) -> Result { match spec.skill_type.as_str() { - "alphahuman" => { + "openhuman" => { // Find the skills source directory from the engine. let skills_dir = self.engine.skills_source_dir()?; - generator::generate_alphahuman(&spec, &skills_dir).await?; + generator::generate_openhuman(&spec, &skills_dir).await?; // Rediscover so the new skill appears in subsequent list_all() calls. let _ = self.engine.discover_skills().await; @@ -206,7 +206,7 @@ impl UnifiedSkillRegistry { Ok(UnifiedSkillEntry { id, name: spec.name, - skill_type: "alphahuman".to_string(), + skill_type: "openhuman".to_string(), version: "1.0.0".to_string(), description: spec.description, tools: vec![], @@ -227,7 +227,7 @@ impl UnifiedSkillRegistry { setup: None, }) } - other => Err(format!("Unknown skill_type: '{other}'. Use 'alphahuman' or 'openclaw'.")), + other => Err(format!("Unknown skill_type: '{other}'. Use 'openhuman' or 'openclaw'.")), } } } @@ -253,9 +253,9 @@ fn sanitize_id(name: &str) -> String { .join("-") } -/// Returns `~/.alphahuman/workspace` as the base for openclaw skills. +/// Returns `~/.openhuman/workspace` as the base for openclaw skills. fn workspace_dir() -> PathBuf { UserDirs::new() - .map(|d| d.home_dir().join(".alphahuman").join("workspace")) - .unwrap_or_else(|| PathBuf::from(".alphahuman/workspace")) + .map(|d| d.home_dir().join(".openhuman").join("workspace")) + .unwrap_or_else(|| PathBuf::from(".openhuman/workspace")) } diff --git a/src-tauri/src/unified_skills/openclaw_executor.rs b/src-tauri/src/unified_skills/openclaw_executor.rs index 90edaa69f..55090804b 100644 --- a/src-tauri/src/unified_skills/openclaw_executor.rs +++ b/src-tauri/src/unified_skills/openclaw_executor.rs @@ -4,7 +4,7 @@ //! - SKILL.toml → structured tool definitions (shell/http commands) //! - SKILL.md → markdown prompt content (returned as text) -use crate::alphahuman::skills::{Skill, SkillTool}; +use crate::openhuman::skills::{Skill, SkillTool}; use crate::runtime::types::{ToolContent, UnifiedSkillResult}; use chrono::Utc; use std::collections::HashMap; diff --git a/src-tauri/src/unified_skills/self_evolve.rs b/src-tauri/src/unified_skills/self_evolve.rs index 74d86c0b9..8317b27c5 100644 --- a/src-tauri/src/unified_skills/self_evolve.rs +++ b/src-tauri/src/unified_skills/self_evolve.rs @@ -154,7 +154,7 @@ impl SkillEvolver { skill_id = sanitize_id(&spec.name); // -- Write files to disk -- - let written = generator::generate_alphahuman(&spec, &skills_dir) + let written = generator::generate_openhuman(&spec, &skills_dir) .await .map_err(|e| format!("File generation failed (iter {i}): {e}"))?; diff --git a/src-tauri/src/utils/config.rs b/src-tauri/src/utils/config.rs index db6f20c3b..23a2ee17d 100644 --- a/src-tauri/src/utils/config.rs +++ b/src-tauri/src/utils/config.rs @@ -5,13 +5,13 @@ use std::env; /// Default backend URL (can be overridden via BACKEND_URL env var) -pub const DEFAULT_BACKEND_URL: &str = "https://api.alphahuman.xyz"; +pub const DEFAULT_BACKEND_URL: &str = "https://api.tinyhumans.ai"; /// Application identifier for keychain storage -pub const APP_IDENTIFIER: &str = "com.alphahuman.app"; +pub const APP_IDENTIFIER: &str = "com.openhuman.app"; /// Service name for keychain -pub const KEYCHAIN_SERVICE: &str = "AlphaHuman"; +pub const KEYCHAIN_SERVICE: &str = "OpenHuman"; /// Get the backend URL from environment or use default /// Checks VITE_BACKEND_URL first, then BACKEND_URL, then defaults diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 2c4727282..6c55fe36b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "https://schema.tauri.app/config/2", "productName": "OpenHuman", "version": "0.49.3", - "identifier": "com.alphahuman.app", + "identifier": "com.tinyhumansai.openhuman", "build": { "beforeDevCommand": "npm run dev", "devUrl": "http://localhost:1420", @@ -39,8 +39,9 @@ ], "resources": [ "../skills/skills", - "../ai" + "ai" ], + "createUpdaterArtifacts": true, "macOS": { "minimumSystemVersion": "10.15", "dmg": { @@ -49,6 +50,12 @@ } }, "plugins": { + "updater": { + "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEVBMjYzN0QxNjE4MjYzQzgKUldUSVk0SmgwVGNtNnJnNkFrZnloeDVUME1CczNDS3lMQ1hWVkxlVldCdjRCUFozYjFSekpVNWwK", + "endpoints": [ + "https://github.com/tinyhumansai/openhuman/releases/latest/download/latest.json" + ] + }, "deep-link": { "desktop": { "schemes": [ diff --git a/src/AppRoutes.tsx b/src/AppRoutes.tsx index fe41326bc..70f6124bb 100644 --- a/src/AppRoutes.tsx +++ b/src/AppRoutes.tsx @@ -8,7 +8,6 @@ import Conversations from './pages/Conversations'; import Home from './pages/Home'; import Intelligence from './pages/Intelligence'; import Invites from './pages/Invites'; -import Login from './pages/Login'; import Mnemonic from './pages/Mnemonic'; import Onboarding from './pages/onboarding/Onboarding'; import Settings from './pages/Settings'; @@ -65,14 +64,6 @@ const AppRoutes = () => { } /> - - - - } - /> {/* Protected routes */} { - const [platformInfo, setPlatformInfo] = useState(null); - const [selectedPlatform, setSelectedPlatform] = useState(null); - const [selectedArchitecture, setSelectedArchitecture] = useState(null); - const [releaseLinks, setReleaseLinks] = useState(null); - const [architectureLinks, setArchitectureLinks] = useState( - null - ); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - // Only show download screen on web (not in Tauri app) - if (isTauri()) { - return; - } - - const detected = detectPlatform(); - setPlatformInfo(detected); - setSelectedPlatform(detected.platform); - setSelectedArchitecture(detected.architecture); - - // Fetch latest release from GitHub - const loadReleaseLinks = async () => { - try { - setIsLoading(true); - setError(null); - const release = await fetchLatestRelease(); - const links = parseReleaseAssets(release.assets); - const archLinks = parseReleaseAssetsByArchitecture(release.assets); - setReleaseLinks(links); - setArchitectureLinks(archLinks); - - // Auto-select best architecture for detected platform - 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]; - setSelectedArchitecture(preferredLink.architecture); - } - } catch (err) { - console.error('Failed to fetch release links:', err); - setError(err instanceof Error ? err.message : 'Failed to load download links'); - } finally { - setIsLoading(false); - } - }; - - loadReleaseLinks(); - }, []); - - // Don't render if running in Tauri or platform not detected - if (isTauri() || !platformInfo || !selectedPlatform) { - return null; - } - - // Get download URL for selected platform and architecture - const getDownloadUrl = (): string => { - if (!selectedPlatform || !architectureLinks) { - return getDownloadLink(selectedPlatform || 'unknown', releaseLinks || undefined); - } - - const platformArchLinks = - architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks]; - if (platformArchLinks && selectedArchitecture) { - const link = platformArchLinks.find(l => l.architecture === selectedArchitecture); - if (link) { - return link.url; - } - // Fallback to first available architecture - if (platformArchLinks.length > 0) { - return platformArchLinks[0].url; - } - } - - return getDownloadLink(selectedPlatform, releaseLinks || undefined); - }; - - const downloadUrl = getDownloadUrl(); - const platformName = getPlatformDisplayName(selectedPlatform || 'unknown'); - - const handleDownload = () => { - window.open(downloadUrl, '_blank'); - }; - - // Get available architectures for selected platform - const getAvailableArchitectures = (): ArchitectureDownloadLink[] => { - if (!selectedPlatform || !architectureLinks) { - return []; - } - return architectureLinks[selectedPlatform as keyof PlatformArchitectureLinks] || []; - }; - - const availableArchitectures = getAvailableArchitectures(); - const hasMultipleArchitectures = availableArchitectures.length > 1; - - return ( -
- {/* Loading state */} - {isLoading && ( -
-
-
-
-

Loading download links...

-
-
-
- )} - - {/* Error state */} - {error && !isLoading && ( -
-
-

{error}. Using fallback download links.

-
-
- )} - - {/* Auto-detected platform */} - {!isLoading && ( -
-
-
-
-
- - {downloadOptions.find(opt => opt.platform === selectedPlatform)?.icon} - -
-

Recommended for you

-

{platformName}

-
-
- -
- - {/* Architecture selection */} - {hasMultipleArchitectures && ( -
-

Select architecture:

-
- {availableArchitectures.map(archLink => { - const isSelected = selectedArchitecture === archLink.architecture; - const isRecommended = platformInfo?.architecture === archLink.architecture; - return ( - - ); - })} -
-
- )} -
-
-
- )} - - {/* Other platforms */} - {!isLoading && ( -
-

Or download for other platforms:

-
- {downloadOptions - .filter(opt => opt.platform !== selectedPlatform) - .map(option => { - 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 hasMultipleArchs = platformArchLinks && platformArchLinks.length > 1; - - return ( -
- - {hasMultipleArchs && ( -
- {platformArchLinks.map(archLink => ( - - ))} -
- )} -
- ); - })} -
-
- )} -
- ); -}; - -export default DownloadScreen; diff --git a/src/components/RotatingTetrahedronCanvas.tsx b/src/components/RotatingTetrahedronCanvas.tsx index c6f6f85ad..11c5285e4 100644 --- a/src/components/RotatingTetrahedronCanvas.tsx +++ b/src/components/RotatingTetrahedronCanvas.tsx @@ -1,7 +1,31 @@ -import { useEffect, useRef } from 'react'; -import * as THREE from 'three'; +'use client'; -const RotatingTetrahedronCanvas = () => { +import * as THREE from 'three'; +import { useEffect, useRef } from 'react'; +import { ConvexGeometry } from 'three/addons/geometries/ConvexGeometry.js'; + +/** Start from a regular tetrahedron and lightly truncate each corner to create small blunted edges. */ +function bluntedTetrahedronPoints(scale: number, bluntness = 0.12): THREE.Vector3[] { + const tetra = [ + new THREE.Vector3(1, 1, 1), + new THREE.Vector3(-1, -1, 1), + new THREE.Vector3(-1, 1, -1), + new THREE.Vector3(1, -1, -1), + ]; + + const points: THREE.Vector3[] = []; + + for (let i = 0; i < tetra.length; i += 1) { + for (let j = 0; j < tetra.length; j += 1) { + if (i === j) continue; + points.push(tetra[i].clone().lerp(tetra[j], bluntness).multiplyScalar(scale)); + } + } + + return points; +} + +export default function RotatingTetrahedronCanvas() { const canvasRef = useRef(null); useEffect(() => { @@ -15,41 +39,39 @@ const RotatingTetrahedronCanvas = () => { powerPreference: 'high-performance', }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + renderer.outputColorSpace = THREE.SRGBColorSpace; + renderer.toneMapping = THREE.NoToneMapping; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100); - camera.position.set(0, 0, 4.6); + camera.position.set(0, 0.15, 4.8); - const fillMaterial = new THREE.MeshPhongMaterial({ - color: '#7f5af0', - emissive: '#201040', - emissiveIntensity: 0.8, - shininess: 50, + const geometry = new ConvexGeometry(bluntedTetrahedronPoints(0.98, 0.11)); + const fillMaterial = new THREE.MeshLambertMaterial({ + color: '#b8e986', transparent: true, - opacity: 0.65, - flatShading: true, + opacity: 0.4, + emissive: '#0c1208', + emissiveIntensity: 0.08, }); - - const wireMaterial = new THREE.MeshBasicMaterial({ - color: '#a78bfa', - wireframe: true, - transparent: true, - opacity: 0.95, - }); - - const geometry = new THREE.TetrahedronGeometry(1.3, 0); const fillMesh = new THREE.Mesh(geometry, fillMaterial); - const wireMesh = new THREE.Mesh(geometry, wireMaterial); + const edgeGeometry = new THREE.EdgesGeometry(geometry); + const edgeMaterial = new THREE.LineBasicMaterial({ color: '#b8e986' }); + + const edges = new THREE.LineSegments(edgeGeometry, edgeMaterial); + fillMesh.rotation.x = 0.35; + fillMesh.rotation.y = -0.15; + edges.rotation.x = 0.35; + edges.rotation.y = -0.15; scene.add(fillMesh); - scene.add(wireMesh); - - const ambientLight = new THREE.AmbientLight('#b4b1ff', 0.45); - const keyLight = new THREE.PointLight('#7f5af0', 1.2, 20); - keyLight.position.set(2.8, 2.5, 4); + scene.add(edges); + const ambientLight = new THREE.AmbientLight('#ffffff', 0.1); + const sun = new THREE.DirectionalLight('#ffffff', 1.1); + sun.position.set(4.5, 6, 5); scene.add(ambientLight); - scene.add(keyLight); + scene.add(sun); let animationFrame = 0; @@ -70,9 +92,10 @@ const RotatingTetrahedronCanvas = () => { resize(); const animate = () => { - fillMesh.rotation.x += 0.006; - fillMesh.rotation.y += 0.009; - wireMesh.rotation.copy(fillMesh.rotation); + fillMesh.rotation.y += 0.0038; + fillMesh.rotation.x += 0.0002; + edges.rotation.y += 0.0038; + edges.rotation.x += 0.0002; renderer.render(scene, camera); animationFrame = window.requestAnimationFrame(animate); @@ -83,14 +106,19 @@ const RotatingTetrahedronCanvas = () => { return () => { window.cancelAnimationFrame(animationFrame); observer.disconnect(); + edgeGeometry.dispose(); geometry.dispose(); fillMaterial.dispose(); - wireMaterial.dispose(); + edgeMaterial.dispose(); renderer.dispose(); }; }, []); - return ; -}; - -export default RotatingTetrahedronCanvas; + return ( + + ); +} diff --git a/src/components/SkillsGrid.tsx b/src/components/SkillsGrid.tsx index 380549b7a..f14728540 100644 --- a/src/components/SkillsGrid.tsx +++ b/src/components/SkillsGrid.tsx @@ -36,7 +36,7 @@ function normalizeUnifiedEntry(e: Record): SkillListEntry { icon: SKILL_ICONS[e.id as string], ignoreInProduction: (e.ignoreInProduction as boolean) ?? false, hasSetup, - skill_type: (e.skill_type as 'alphahuman' | 'openclaw') ?? 'alphahuman', + skill_type: (e.skill_type as 'openhuman' | 'openclaw') ?? 'openhuman', }; } @@ -44,7 +44,7 @@ interface SkillRowProps { skillId: string; name: string; icon?: React.ReactElement; - skillType?: 'alphahuman' | 'openclaw'; + skillType?: 'openhuman' | 'openclaw'; onConnect: (e: React.MouseEvent) => void; } @@ -119,13 +119,13 @@ export default function SkillsGrid() { const [activeSkillName, setActiveSkillName] = useState(''); const [activeSkillDescription, setActiveSkillDescription] = useState(''); const [activeSkillHasSetup, setActiveSkillHasSetup] = useState(false); - const [activeSkillType, setActiveSkillType] = useState<'alphahuman' | 'openclaw'>('alphahuman'); + const [activeSkillType, setActiveSkillType] = useState<'openhuman' | 'openclaw'>('openhuman'); // Get Redux state for sorting const skillsState = useAppSelector(state => state.skills.skills); const skillStates = useAppSelector(state => state.skills.skillStates); - // Load skills from the unified registry (covers both alphahuman and openclaw types). + // Load skills from the unified registry (covers both openhuman and openclaw types). // Extracted so it can be called after skill creation (e.g. from SelfEvolveModal). const refreshSkills = async () => { try { @@ -167,7 +167,7 @@ export default function SkillsGrid() { icon: SKILL_ICONS[m.id as string], ignoreInProduction: (m.ignoreInProduction as boolean) ?? false, hasSetup, - skill_type: 'alphahuman' as const, + skill_type: 'openhuman' as const, }; }) .filter(s => IS_DEV || !s.ignoreInProduction); @@ -261,7 +261,7 @@ export default function SkillsGrid() { setActiveSkillName(skill.name); setActiveSkillDescription(skill.description); setActiveSkillHasSetup(skill.hasSetup); - setActiveSkillType(skill.skill_type ?? 'alphahuman'); + setActiveSkillType(skill.skill_type ?? 'openhuman'); setSetupModalOpen(true); }; @@ -299,7 +299,7 @@ export default function SkillsGrid() { spec: { name: `generated-demo-${Date.now()}`, description: 'Auto-generated skill demonstrating the unified registry', - skill_type: 'alphahuman', + skill_type: 'openhuman', tool_code: 'return { message: `Hello from generated skill! args=${JSON.stringify(args)}` };', }, @@ -398,7 +398,6 @@ export default function SkillsGrid() { {selfEvolveOpen && ( setSelfEvolveOpen(false)} onSkillCreated={refreshSkills} /> )} - ); } diff --git a/src/components/TelegramLoginButton.tsx b/src/components/TelegramLoginButton.tsx deleted file mode 100644 index 7e9e840b0..000000000 --- a/src/components/TelegramLoginButton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { TELEGRAM_BOT_USERNAME } from '../utils/config'; -import { openUrl } from '../utils/openUrl'; -import { isTauri } from '../utils/tauriCommands'; - -interface TelegramLoginButtonProps { - className?: string; - text?: string; - disabled?: boolean; -} - -const TelegramLoginButton = ({ - className = '', - text = 'Yes, Login with Telegram', - disabled: externalDisabled = false, -}: TelegramLoginButtonProps) => { - const handleTelegramLogin = async () => { - if (externalDisabled) return; - - console.log('Starting Telegram login', isTauri()); - - // Desktop (Tauri): use system browser → backend Telegram widget → deep link back to app. - if (isTauri()) await openUrl(`https://t.me/${TELEGRAM_BOT_USERNAME}?start=login_desktop`); - // Web fallback: open bot (existing flow). - else await openUrl(`https://t.me/${TELEGRAM_BOT_USERNAME}?start=login`); - }; - - const isDisabled = externalDisabled; - - return ( - - ); -}; - -export default TelegramLoginButton; diff --git a/src/components/TypewriterGreeting.tsx b/src/components/TypewriterGreeting.tsx index 25f481047..2763db4bf 100644 --- a/src/components/TypewriterGreeting.tsx +++ b/src/components/TypewriterGreeting.tsx @@ -68,7 +68,7 @@ const TypewriterGreeting = ({ ]); return ( -

+

{displayedText} |

diff --git a/src/components/intelligence/mockData.ts b/src/components/intelligence/mockData.ts index 739222102..87458201d 100644 --- a/src/components/intelligence/mockData.ts +++ b/src/components/intelligence/mockData.ts @@ -222,7 +222,7 @@ export const MOCK_ACTIONABLE_ITEMS: ActionableItem[] = [ { id: '15', - title: 'Renew SSL certificate for api.alphahuman.com', + title: 'Renew SSL certificate for api.openhuman.com', description: 'Certificate expires in 5 days. Automatic renewal failed - manual intervention required.', source: 'system', diff --git a/src/components/oauth/OAuthLoginSection.tsx b/src/components/oauth/OAuthLoginSection.tsx index dffc41310..94ee9f8f9 100644 --- a/src/components/oauth/OAuthLoginSection.tsx +++ b/src/components/oauth/OAuthLoginSection.tsx @@ -1,4 +1,3 @@ -import TelegramLoginButton from '../TelegramLoginButton'; import OAuthProviderButton from './OAuthProviderButton'; import { oauthProviderConfigs } from './providerConfigs'; @@ -8,33 +7,24 @@ interface OAuthLoginSectionProps { showTelegram?: boolean; } -const OAuthLoginSection = ({ - className = '', - disabled = false, - showTelegram = true, -}: OAuthLoginSectionProps) => { +const OAuthLoginSection = ({ className = '', disabled = false }: OAuthLoginSectionProps) => { return (
- {/* OAuth Providers */}
- {oauthProviderConfigs.map(provider => ( - - ))} +

+ Continue with +

+
+ {oauthProviderConfigs.map(provider => ( + + ))} +
- - {/* Divider */} - {showTelegram && ( - <> -
-
-
or
-
-
- - {/* Telegram Login */} - - - )}
); }; diff --git a/src/components/oauth/OAuthProviderButton.tsx b/src/components/oauth/OAuthProviderButton.tsx index d9ede35aa..1b630e93c 100644 --- a/src/components/oauth/OAuthProviderButton.tsx +++ b/src/components/oauth/OAuthProviderButton.tsx @@ -54,15 +54,13 @@ const OAuthProviderButton = ({ ); }; diff --git a/src/components/settings/SettingsHome.tsx b/src/components/settings/SettingsHome.tsx index 1124920b9..e3544e908 100644 --- a/src/components/settings/SettingsHome.tsx +++ b/src/components/settings/SettingsHome.tsx @@ -303,17 +303,17 @@ const SettingsHome = () => { {/* Main Settings */}
{mainMenuItems.map((item, index) => ( - - ))} + + ))}
{/* Destructive Actions */} diff --git a/src/components/settings/panels/AgentChatPanel.tsx b/src/components/settings/panels/AgentChatPanel.tsx index 25f4c9b01..ef726127a 100644 --- a/src/components/settings/panels/AgentChatPanel.tsx +++ b/src/components/settings/panels/AgentChatPanel.tsx @@ -1,12 +1,12 @@ import { useEffect, useState } from 'react'; -import { alphahumanAgentChat } from '../../../utils/tauriCommands'; +import { openhumanAgentChat } from '../../../utils/tauriCommands'; import SettingsHeader from '../components/SettingsHeader'; import { useSettingsNavigation } from '../hooks/useSettingsNavigation'; type ChatMessage = { role: 'user' | 'agent'; text: string }; -const STORAGE_KEY = 'alphahuman.settings.agentChat.history'; +const STORAGE_KEY = 'openhuman.settings.agentChat.history'; const AgentChatPanel = () => { const { navigateBack } = useSettingsNavigation(); @@ -62,7 +62,7 @@ const AgentChatPanel = () => { setInput(''); setMessages(prev => [...prev, { role: 'user', text }]); try { - const response = await alphahumanAgentChat( + const response = await openhumanAgentChat( text, providerOverride.trim() ? providerOverride : undefined, modelOverride.trim() ? modelOverride : undefined, diff --git a/src/components/settings/panels/DeveloperOptionsPanel.tsx b/src/components/settings/panels/DeveloperOptionsPanel.tsx index bb404f7d3..89fe40470 100644 --- a/src/components/settings/panels/DeveloperOptionsPanel.tsx +++ b/src/components/settings/panels/DeveloperOptionsPanel.tsx @@ -38,7 +38,7 @@ const developerItems = [ { id: 'tauri-commands', title: 'Tauri Command Console', - description: 'Run Alphahuman Tauri commands for quick testing', + description: 'Run OpenHuman Tauri commands for quick testing', route: 'tauri-commands', icon: ( diff --git a/src/components/settings/panels/MemoryDebugPanel.tsx b/src/components/settings/panels/MemoryDebugPanel.tsx index fdd857d6c..0a2fc7f97 100644 --- a/src/components/settings/panels/MemoryDebugPanel.tsx +++ b/src/components/settings/panels/MemoryDebugPanel.tsx @@ -1,12 +1,12 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { + type MemoryDebugDocument, memoryDeleteDocument, memoryListDocuments, memoryListNamespaces, memoryQueryNamespace, memoryRecallNamespace, - type MemoryDebugDocument, } from '../../../utils/tauriCommands'; import SettingsHeader from '../components/SettingsHeader'; import { useSettingsNavigation } from '../hooks/useSettingsNavigation'; @@ -109,7 +109,11 @@ const MemoryDebugPanel = () => { setQueryError(null); setQueryResult(null); try { - const result = await memoryQueryNamespace(namespaceInput.trim(), queryInput.trim(), maxChunks); + const result = await memoryQueryNamespace( + namespaceInput.trim(), + queryInput.trim(), + maxChunks + ); setQueryResult(result); } catch (error) { setQueryError(error instanceof Error ? error.message : String(error)); @@ -179,8 +183,12 @@ const MemoryDebugPanel = () => { key={`${doc.namespace}:${doc.documentId}`} className="rounded border border-stone-700 bg-black/20 p-2">
ID: {doc.documentId}
-
Namespace: {doc.namespace}
- {doc.title ?
Title: {doc.title}
: null} +
+ Namespace: {doc.namespace} +
+ {doc.title ? ( +
Title: {doc.title}
+ ) : null}
{ useEffect(() => { const loadIntegrations = async () => { try { - const response = await alphahumanListIntegrations(); + const response = await openhumanListIntegrations(); setIntegrations(response.result); - const configResponse = await alphahumanGetConfig(); + const configResponse = await openhumanGetConfig(); const config = configResponse.result.config as Record; const browserConfig = (config.browser as Record) ?? {}; - const runtimeFlags = await alphahumanGetRuntimeFlags(); + const runtimeFlags = await openhumanGetRuntimeFlags(); setBrowserAllowAll(runtimeFlags.result.browser_allow_all); const entries = await Promise.all( response.result.map(async integration => { @@ -65,7 +63,7 @@ const SkillsPanel = () => { ); setEnabledMap(Object.fromEntries(entries)); } catch (error) { - console.warn('Could not load integrations from Alphahuman:', error); + console.warn('Could not load integrations from OpenHuman:', error); const message = error instanceof Error ? error.message : String(error); setError(message); } finally { @@ -113,7 +111,7 @@ const SkillsPanel = () => { const next = event.target.checked; setBrowserAllowAllBusy(true); try { - const response = await alphahumanSetBrowserAllowAll(next); + const response = await openhumanSetBrowserAllowAll(next); setBrowserAllowAll(response.result.browser_allow_all); } catch (err) { const message = err instanceof Error ? err.message : String(err); @@ -140,7 +138,7 @@ const SkillsPanel = () => { {loading &&
Loading integrations...
} {!loading && integrations.length === 0 && (
- No integrations registered in Alphahuman. + No integrations registered in OpenHuman.
)} {!loading && @@ -163,7 +161,7 @@ const SkillsPanel = () => { setToggleBusy(prev => ({ ...prev, [key]: true })); try { if (integration.name === 'Browser') { - await alphahumanUpdateBrowserSettings({ enabled: nextEnabled }); + await openhumanUpdateBrowserSettings({ enabled: nextEnabled }); } else { const skillId = integrationSkillId(integration); if (nextEnabled) { diff --git a/src/components/settings/panels/TauriCommandsPanel.tsx b/src/components/settings/panels/TauriCommandsPanel.tsx index 4bf86523e..02720ad31 100644 --- a/src/components/settings/panels/TauriCommandsPanel.tsx +++ b/src/components/settings/panels/TauriCommandsPanel.tsx @@ -11,27 +11,27 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { formatRelativeTime, useDaemonHealth } from '../../../hooks/useDaemonHealth'; import { - alphahumanAgentChat, - alphahumanDecryptSecret, - alphahumanDoctorModels, - alphahumanDoctorReport, - alphahumanEncryptSecret, - alphahumanGetConfig, - alphahumanGetIntegrationInfo, - alphahumanHardwareDiscover, - alphahumanHardwareIntrospect, - alphahumanListIntegrations, - alphahumanMigrateOpenclaw, - alphahumanModelsRefresh, - alphahumanServiceInstall, - alphahumanServiceStatus, - alphahumanServiceUninstall, - alphahumanUpdateGatewaySettings, - alphahumanUpdateMemorySettings, - alphahumanUpdateModelSettings, - alphahumanUpdateRuntimeSettings, - alphahumanUpdateTunnelSettings, isTauri, + openhumanAgentChat, + openhumanDecryptSecret, + openhumanDoctorModels, + openhumanDoctorReport, + openhumanEncryptSecret, + openhumanGetConfig, + openhumanGetIntegrationInfo, + openhumanHardwareDiscover, + openhumanHardwareIntrospect, + openhumanListIntegrations, + openhumanMigrateOpenclaw, + openhumanModelsRefresh, + openhumanServiceInstall, + openhumanServiceStatus, + openhumanServiceUninstall, + openhumanUpdateGatewaySettings, + openhumanUpdateMemorySettings, + openhumanUpdateModelSettings, + openhumanUpdateRuntimeSettings, + openhumanUpdateTunnelSettings, runtimeDisableSkill, runtimeEnableSkill, runtimeIsSkillEnabled, @@ -110,7 +110,7 @@ const TauriCommandsPanel = () => { // Enhanced System Configuration state management const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); - const [originalConfig, setOriginalConfig] = useState>({}); + const [originalConfig, setOriginalConfig] = useState>({}); const [fieldErrors, setFieldErrors] = useState>({}); const [lastSaveTime, setLastSaveTime] = useState(null); const [validationLoading, setValidationLoading] = useState(false); @@ -344,7 +344,7 @@ const TauriCommandsPanel = () => { }; const loadConfig = async () => { - const response = await runWithResult(() => alphahumanGetConfig(), 'loadConfig'); + const response = await runWithResult(() => openhumanGetConfig(), 'loadConfig'); if (!response) { setError('Failed to load configuration'); return; @@ -440,7 +440,7 @@ const TauriCommandsPanel = () => { setOperationLoading('saveModelSettings'); try { - const result = await alphahumanUpdateModelSettings({ + const result = await openhumanUpdateModelSettings({ api_key: apiKey.trim() ? apiKey : null, api_url: apiUrl.trim() ? apiUrl : null, default_provider: defaultProvider.trim() ? defaultProvider : null, @@ -512,7 +512,7 @@ const TauriCommandsPanel = () => { // Test connection by attempting to refresh models with current settings const result = await Promise.race([ - alphahumanModelsRefresh(defaultProvider, false), + openhumanModelsRefresh(defaultProvider, false), timeoutPromise, ]); @@ -557,12 +557,12 @@ const TauriCommandsPanel = () => { }; const saveTunnelSettings = () => - run(() => alphahumanUpdateTunnelSettings(buildTunnelConfig()), 'saveTunnelSettings'); + run(() => openhumanUpdateTunnelSettings(buildTunnelConfig()), 'saveTunnelSettings'); const saveGatewaySettings = () => run( () => - alphahumanUpdateGatewaySettings({ + openhumanUpdateGatewaySettings({ host: gatewayHost.trim() ? gatewayHost : null, port: parseOptionalNumber(gatewayPort), require_pairing: gatewayPairing, @@ -574,7 +574,7 @@ const TauriCommandsPanel = () => { const saveMemorySettings = () => run( () => - alphahumanUpdateMemorySettings({ + openhumanUpdateMemorySettings({ backend: memoryBackend.trim() ? memoryBackend : null, auto_save: memoryAutoSave, embedding_provider: embeddingProvider.trim() ? embeddingProvider : null, @@ -587,7 +587,7 @@ const TauriCommandsPanel = () => { const saveRuntimeSettings = () => run( () => - alphahumanUpdateRuntimeSettings({ + openhumanUpdateRuntimeSettings({ kind: runtimeKind.trim() ? runtimeKind : null, reasoning_enabled: reasoningEnabled, }), @@ -636,7 +636,7 @@ const TauriCommandsPanel = () => { setChatInput(''); const response = await runWithResult( () => - alphahumanAgentChat( + openhumanAgentChat( userMessage, chatProvider.trim() ? chatProvider : undefined, chatModel.trim() ? chatModel : undefined, @@ -1052,19 +1052,19 @@ const TauriCommandsPanel = () => { Stop
run(alphahumanServiceStatus, 'serviceStatus')} + onClick={() => run(openhumanServiceStatus, 'serviceStatus')} loading={operationLoading === 'serviceStatus'} variant="outline"> Status run(alphahumanServiceInstall, 'serviceInstall')} + onClick={() => run(openhumanServiceInstall, 'serviceInstall')} loading={operationLoading === 'serviceInstall'} variant="outline"> Install run(alphahumanServiceUninstall, 'serviceUninstall')} + onClick={() => run(openhumanServiceUninstall, 'serviceUninstall')} loading={operationLoading === 'serviceUninstall'} variant="outline"> Uninstall @@ -1180,13 +1180,13 @@ const TauriCommandsPanel = () => { run(() => alphahumanEncryptSecret(encryptInput), 'encryptSecret')} + onClick={() => run(() => openhumanEncryptSecret(encryptInput), 'encryptSecret')} loading={operationLoading === 'encryptSecret'} disabled={!encryptInput.trim()}> Encrypt run(() => alphahumanDecryptSecret(decryptInput), 'decryptSecret')} + onClick={() => run(() => openhumanDecryptSecret(decryptInput), 'decryptSecret')} loading={operationLoading === 'decryptSecret'} disabled={!decryptInput.trim()} variant="outline"> @@ -1195,7 +1195,7 @@ const TauriCommandsPanel = () => { run( - () => alphahumanModelsRefresh(providerOverride || undefined, false), + () => openhumanModelsRefresh(providerOverride || undefined, false), 'modelsRefresh' ) } @@ -1205,7 +1205,7 @@ const TauriCommandsPanel = () => { run( - () => alphahumanModelsRefresh(providerOverride || undefined, true), + () => openhumanModelsRefresh(providerOverride || undefined, true), 'modelsForceRefresh' ) } @@ -1214,13 +1214,13 @@ const TauriCommandsPanel = () => { Force Refresh run(alphahumanListIntegrations, 'listIntegrations')} + onClick={() => run(openhumanListIntegrations, 'listIntegrations')} loading={operationLoading === 'listIntegrations'}> List Integrations - run(() => alphahumanGetIntegrationInfo(integrationName), 'getIntegrationInfo') + run(() => openhumanGetIntegrationInfo(integrationName), 'getIntegrationInfo') } loading={operationLoading === 'getIntegrationInfo'} disabled={!integrationName.trim()} @@ -1431,14 +1431,14 @@ const TauriCommandsPanel = () => {
run(alphahumanDoctorReport, 'doctorReport')} + onClick={() => run(openhumanDoctorReport, 'doctorReport')} loading={operationLoading === 'doctorReport'}> Run Doctor Report run( - () => alphahumanDoctorModels(providerOverride || undefined, true), + () => openhumanDoctorModels(providerOverride || undefined, true), 'probeModels' ) } @@ -1481,13 +1481,13 @@ const TauriCommandsPanel = () => { run(alphahumanHardwareDiscover, 'hardwareDiscover')} + onClick={() => run(openhumanHardwareDiscover, 'hardwareDiscover')} loading={operationLoading === 'hardwareDiscover'}> Discover Devices - run(() => alphahumanHardwareIntrospect(hardwarePath), 'hardwareIntrospect') + run(() => openhumanHardwareIntrospect(hardwarePath), 'hardwareIntrospect') } loading={operationLoading === 'hardwareIntrospect'} disabled={!hardwarePath.trim()} @@ -1497,7 +1497,7 @@ const TauriCommandsPanel = () => { run( - () => alphahumanMigrateOpenclaw(migrationSource || undefined, true), + () => openhumanMigrateOpenclaw(migrationSource || undefined, true), 'migrationDryRun' ) } @@ -1507,7 +1507,7 @@ const TauriCommandsPanel = () => { run( - () => alphahumanMigrateOpenclaw(migrationSource || undefined, false), + () => openhumanMigrateOpenclaw(migrationSource || undefined, false), 'runMigration' ) } diff --git a/src/components/settings/panels/__tests__/memoryDebugUtils.test.ts b/src/components/settings/panels/__tests__/memoryDebugUtils.test.ts index 1948ba707..e1fc935ae 100644 --- a/src/components/settings/panels/__tests__/memoryDebugUtils.test.ts +++ b/src/components/settings/panels/__tests__/memoryDebugUtils.test.ts @@ -35,4 +35,3 @@ describe('normalizeMemoryDocuments', () => { expect(normalizeMemoryDocuments(null)).toEqual([]); }); }); - diff --git a/src/components/settings/panels/components/SectionCard.tsx b/src/components/settings/panels/components/SectionCard.tsx index 3e9877e0d..444541f4f 100644 --- a/src/components/settings/panels/components/SectionCard.tsx +++ b/src/components/settings/panels/components/SectionCard.tsx @@ -56,7 +56,9 @@ const SectionCard: React.FC = ({ {loading ? (
) : ( - React.cloneElement(icon, { className: 'h-5 w-5' } as any) + React.cloneElement(icon as React.ReactElement<{ className?: string }>, { + className: 'h-5 w-5', + }) )}
diff --git a/src/components/skills/SkillSetupModal.tsx b/src/components/skills/SkillSetupModal.tsx index 78dc71bb7..717e55d07 100644 --- a/src/components/skills/SkillSetupModal.tsx +++ b/src/components/skills/SkillSetupModal.tsx @@ -16,7 +16,7 @@ interface SkillSetupModalProps { skillDescription: string; /** Whether this skill has interactive setup hooks. */ hasSetup?: boolean; - skillType?: 'alphahuman' | 'openclaw'; + skillType?: 'openhuman' | 'openclaw'; onClose: () => void; } @@ -25,7 +25,7 @@ export default function SkillSetupModal({ skillName, skillDescription, hasSetup = true, - skillType = 'alphahuman', + skillType = 'openhuman', onClose, }: SkillSetupModalProps) { const modalRef = useRef(null); diff --git a/src/components/skills/shared.tsx b/src/components/skills/shared.tsx index a934cce1f..1a2bfe697 100644 --- a/src/components/skills/shared.tsx +++ b/src/components/skills/shared.tsx @@ -66,7 +66,7 @@ export interface SkillListEntry { ignoreInProduction?: boolean; icon?: React.ReactElement; hasSetup: boolean; - /** Unified registry type: "alphahuman" (QuickJS) or "openclaw" (SKILL.md/TOML). */ + /** Unified registry type: "openhuman" (QuickJS) or "openclaw" (SKILL.md/TOML). */ skill_type?: SkillType; } diff --git a/src/hooks/useDaemonHealth.ts b/src/hooks/useDaemonHealth.ts index c75f35087..d1e13c510 100644 --- a/src/hooks/useDaemonHealth.ts +++ b/src/hooks/useDaemonHealth.ts @@ -21,11 +21,11 @@ import { } from '../store/daemonSlice'; import { useAppDispatch, useAppSelector } from '../store/hooks'; import { - alphahumanAgentServerStatus, - alphahumanServiceStart, - alphahumanServiceStatus, - alphahumanServiceStop, type CommandResponse, + openhumanAgentServerStatus, + openhumanServiceStart, + openhumanServiceStatus, + openhumanServiceStop, type ServiceStatus, } from '../utils/tauriCommands'; @@ -44,7 +44,7 @@ export const useDaemonHealth = (userId?: string) => { const probeAgentStatus = useCallback(async (): Promise => { try { - const result = await alphahumanAgentServerStatus(); + const result = await openhumanAgentServerStatus(); const running = !!result?.result?.running; dispatch(setDaemonStatus({ userId: uid, status: running ? 'running' : 'disconnected' })); return running; @@ -74,7 +74,7 @@ export const useDaemonHealth = (userId?: string) => { const startDaemon = useCallback(async (): Promise | null> => { try { dispatch(setDaemonStatus({ userId: uid, status: 'starting' })); - const result = await alphahumanServiceStart(); + const result = await openhumanServiceStart(); const running = await waitForAgentStatus(true); if (running) { if (result?.result) { @@ -95,7 +95,7 @@ export const useDaemonHealth = (userId?: string) => { const stopDaemon = useCallback(async (): Promise | null> => { try { dispatch(setDaemonStatus({ userId: uid, status: 'starting' })); - const result = await alphahumanServiceStop(); + const result = await openhumanServiceStop(); await waitForAgentStatus(false, 7000); return result; } catch (error) { @@ -110,14 +110,14 @@ export const useDaemonHealth = (userId?: string) => { dispatch(setDaemonStatus({ userId: uid, status: 'starting' })); // Stop first - await alphahumanServiceStop(); + await openhumanServiceStop(); await waitForAgentStatus(false, 7000); // Wait a moment for clean shutdown await new Promise(resolve => setTimeout(resolve, 2000)); // Start again - await alphahumanServiceStart(); + await openhumanServiceStart(); const success = await waitForAgentStatus(true, 12000); if (success) { @@ -141,7 +141,7 @@ export const useDaemonHealth = (userId?: string) => { try { const running = await probeAgentStatus(); if (running) { - return await alphahumanServiceStatus(); + return await openhumanServiceStatus(); } return null; } catch (error) { diff --git a/src/hooks/useIntelligenceApiFallback.ts b/src/hooks/useIntelligenceApiFallback.ts index ffbc31f9e..d476cc759 100644 --- a/src/hooks/useIntelligenceApiFallback.ts +++ b/src/hooks/useIntelligenceApiFallback.ts @@ -1,9 +1,12 @@ import { useCallback, useEffect, useState } from 'react'; import { MOCK_ACTIONABLE_ITEMS } from '../components/intelligence/mockData'; -import { intelligenceApi, type ConnectedTool } from '../services/intelligenceApi'; -import type { ActionableItem, ActionableItemStatus } from '../types/intelligence'; -import { transformBackendItemsToFrontend, transformBackendMessagesToFrontend } from '../utils/intelligenceTransforms'; +import { type ConnectedTool, intelligenceApi } from '../services/intelligenceApi'; +import type { ActionableItem, ActionableItemStatus, ChatMessage } from '../types/intelligence'; +import { + transformBackendItemsToFrontend, + transformBackendMessagesToFrontend, +} from '../utils/intelligenceTransforms'; /** * Fallback implementation of Intelligence API hooks without React Query @@ -62,12 +65,7 @@ export const useActionableItems = (options?: { } }, [options?.refetchInterval, fetchItems]); - return { - data, - loading, - error, - refetch: fetchItems, - }; + return { data, loading, error, refetch: fetchItems }; }; interface UseUpdateActionableItemResult { @@ -86,29 +84,25 @@ export const useUpdateActionableItem = (): UseUpdateActionableItemResult => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const mutateAsync = useCallback(async (variables: { - itemId: string; - status: ActionableItemStatus; - }) => { - try { - setLoading(true); - setError(null); - await intelligenceApi.updateItemStatus(variables.itemId, variables.status); - return { ...variables, updatedAt: new Date() }; - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to update item'; - setError(errorMessage); - throw err; - } finally { - setLoading(false); - } - }, []); + const mutateAsync = useCallback( + async (variables: { itemId: string; status: ActionableItemStatus }) => { + try { + setLoading(true); + setError(null); + await intelligenceApi.updateItemStatus(variables.itemId, variables.status); + return { ...variables, updatedAt: new Date() }; + } catch (err) { + const errorMessage = err instanceof Error ? err.message : 'Failed to update item'; + setError(errorMessage); + throw err; + } finally { + setLoading(false); + } + }, + [] + ); - return { - mutateAsync, - loading, - error, - }; + return { mutateAsync, loading, error }; }; interface UseSnoozeActionableItemResult { @@ -127,10 +121,7 @@ export const useSnoozeActionableItem = (): UseSnoozeActionableItemResult => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const mutateAsync = useCallback(async (variables: { - itemId: string; - snoozeUntil: Date; - }) => { + const mutateAsync = useCallback(async (variables: { itemId: string; snoozeUntil: Date }) => { try { setLoading(true); setError(null); @@ -145,18 +136,11 @@ export const useSnoozeActionableItem = (): UseSnoozeActionableItemResult => { } }, []); - return { - mutateAsync, - loading, - error, - }; + return { mutateAsync, loading, error }; }; interface UseChatSessionResult { - data: { - threadId: string; - messages: any[]; - } | null; + data: { threadId: string; messages: ChatMessage[] } | null; loading: boolean; error: string | null; } @@ -165,7 +149,7 @@ interface UseChatSessionResult { * Hook for creating or getting chat session (fallback version) */ export const useChatSession = (itemId: string | null): UseChatSessionResult => { - const [data, setData] = useState<{ threadId: string; messages: any[] } | null>(null); + const [data, setData] = useState<{ threadId: string; messages: ChatMessage[] } | null>(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -193,22 +177,14 @@ export const useChatSession = (itemId: string | null): UseChatSessionResult => { fetchSession(); }, [itemId]); - return { - data, - loading, - error, - }; + return { data, loading, error }; }; interface UseExecuteTaskResult { mutateAsync: (variables: { itemId: string; connectedTools: ConnectedTool[]; - }) => Promise<{ - executionId: string; - sessionId: string; - status: string; - }>; + }) => Promise<{ executionId: string; sessionId: string; status: string }>; loading: boolean; error: string | null; } @@ -220,29 +196,28 @@ export const useExecuteTask = (): UseExecuteTaskResult => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const mutateAsync = useCallback(async (variables: { - itemId: string; - connectedTools: ConnectedTool[]; - }) => { - try { - setLoading(true); - setError(null); - const result = await intelligenceApi.executeTask(variables.itemId, variables.connectedTools); - return result; - } catch (err) { - const errorMessage = err instanceof Error ? err.message : 'Failed to execute task'; - setError(errorMessage); - throw err; - } finally { - setLoading(false); - } - }, []); + const mutateAsync = useCallback( + async (variables: { itemId: string; connectedTools: ConnectedTool[] }) => { + try { + setLoading(true); + setError(null); + const result = await intelligenceApi.executeTask( + variables.itemId, + variables.connectedTools + ); + return result; + } catch (err) { + const errorMessage = err instanceof Error ? err.message : 'Failed to execute task'; + setError(errorMessage); + throw err; + } finally { + setLoading(false); + } + }, + [] + ); - return { - mutateAsync, - loading, - error, - }; + return { mutateAsync, loading, error }; }; // Export query key utilities for consistency @@ -253,4 +228,4 @@ export const intelligenceKeys = { thread: (itemId: string) => [...intelligenceKeys.all, 'thread', itemId] as const, messages: (threadId: string) => [...intelligenceKeys.all, 'messages', threadId] as const, execution: (executionId: string) => [...intelligenceKeys.all, 'execution', executionId] as const, -}; \ No newline at end of file +}; diff --git a/src/hooks/useIntelligenceSocket.ts b/src/hooks/useIntelligenceSocket.ts index 43f16926d..02f63b409 100644 --- a/src/hooks/useIntelligenceSocket.ts +++ b/src/hooks/useIntelligenceSocket.ts @@ -3,7 +3,12 @@ import { useDispatch, useSelector } from 'react-redux'; import { socketService } from '../services/socketService'; import type { RootState } from '../store'; -import { addMessage, setExecutionResult, setTyping, updateExecutionProgress } from '../store/intelligenceSlice'; +import { + addMessage, + setExecutionResult, + setTyping, + updateExecutionProgress, +} from '../store/intelligenceSlice'; import { createChatMessage } from '../utils/intelligenceTransforms'; import { emitViaRustSocket } from '../utils/tauriSocket'; @@ -14,7 +19,7 @@ interface ProcessMessagePayload { message: string; threadId: string; sessionId?: string; - context?: Record; + context?: Record; } interface AgentResponsePayload { @@ -22,8 +27,8 @@ interface AgentResponsePayload { threadId: string; sessionId?: string; shouldExecute?: boolean; - executionPlan?: any; - metadata?: Record; + executionPlan?: unknown; + metadata?: Record; } interface ExecutionProgressPayload { @@ -47,21 +52,16 @@ interface ExecutionCompletePayload { executionId: string; sessionId: string; status: 'completed' | 'failed'; - result?: any; + result?: unknown; error?: string; - artifacts?: Array<{ - type: string; - url: string; - title: string; - description?: string; - }>; + artifacts?: Array<{ type: string; url: string; title: string; description?: string }>; } interface ChatInitPayload { - tools: any[]; + tools: Record[]; threadId: string; sessionId?: string; - context?: Record; + context?: Record; } /** @@ -69,7 +69,7 @@ interface ChatInitPayload { */ function isTauri(): boolean { try { - return (window as any)?.__TAURI__ !== undefined; + return typeof window !== 'undefined' && '__TAURI__' in window; } catch { return false; } @@ -93,44 +93,53 @@ export const useIntelligenceSocket = () => { /** * Send message to AI agent via WebSocket */ - const sendMessage = useCallback(async (payload: ProcessMessagePayload) => { - if (isTauri()) { - // Use Rust socket for Tauri environment - emitViaRustSocket('processMessageForUser', payload); - } else if (socket?.connected) { - socket.emit('processMessageForUser', payload); - } else { - console.warn('Cannot send message - socket not connected'); - throw new Error('Socket not connected'); - } - }, [socket]); + const sendMessage = useCallback( + async (payload: ProcessMessagePayload) => { + if (isTauri()) { + // Use Rust socket for Tauri environment + emitViaRustSocket('processMessageForUser', payload); + } else if (socket?.connected) { + socket.emit('processMessageForUser', payload); + } else { + console.warn('Cannot send message - socket not connected'); + throw new Error('Socket not connected'); + } + }, + [socket] + ); /** * Initialize chat session with tools */ - const sendChatInit = useCallback(async (payload: ChatInitPayload) => { - if (isTauri()) { - emitViaRustSocket('chat:init', payload); - } else if (socket?.connected) { - socket.emit('chat:init', payload); - } else { - console.warn('Cannot initialize chat - socket not connected'); - throw new Error('Socket not connected'); - } - }, [socket]); + const sendChatInit = useCallback( + async (payload: ChatInitPayload) => { + if (isTauri()) { + emitViaRustSocket('chat:init', payload); + } else if (socket?.connected) { + socket.emit('chat:init', payload); + } else { + console.warn('Cannot initialize chat - socket not connected'); + throw new Error('Socket not connected'); + } + }, + [socket] + ); /** * Send typing indicator */ - const sendTyping = useCallback((threadId: string, isTyping: boolean) => { - const payload = { threadId, isTyping }; + const sendTyping = useCallback( + (threadId: string, isTyping: boolean) => { + const payload = { threadId, isTyping }; - if (isTauri()) { - emitViaRustSocket('chat:typing', payload); - } else if (socket?.connected) { - socket.emit('chat:typing', payload); - } - }, [socket]); + if (isTauri()) { + emitViaRustSocket('chat:typing', payload); + } else if (socket?.connected) { + socket.emit('chat:typing', payload); + } + }, + [socket] + ); /** * Register WebSocket event handlers @@ -148,17 +157,11 @@ export const useIntelligenceSocket = () => { if (data.message && data.threadId) { const aiMessage = createChatMessage(data.message, 'ai'); - dispatch(addMessage({ - threadId: data.threadId, - message: aiMessage, - })); + dispatch(addMessage({ threadId: data.threadId, message: aiMessage })); } // Stop typing indicator - dispatch(setTyping({ - threadId: data.threadId, - isTyping: false, - })); + dispatch(setTyping({ threadId: data.threadId, isTyping: false })); // Handle execution trigger if (data.shouldExecute && data.executionPlan) { @@ -179,10 +182,9 @@ export const useIntelligenceSocket = () => { }); if (data.progress) { - dispatch(updateExecutionProgress({ - executionId: data.executionId, - progress: data.progress, - })); + dispatch( + updateExecutionProgress({ executionId: data.executionId, progress: data.progress }) + ); } }; @@ -195,12 +197,14 @@ export const useIntelligenceSocket = () => { hasArtifacts: !!data.artifacts?.length, }); - dispatch(setExecutionResult({ - executionId: data.executionId, - result: data.result, - status: data.status, - error: data.error, - })); + dispatch( + setExecutionResult({ + executionId: data.executionId, + result: data.result, + status: data.status, + error: data.error, + }) + ); // Send completion message if we have artifacts if (data.artifacts?.length && data.sessionId) { @@ -215,10 +219,7 @@ export const useIntelligenceSocket = () => { // Typing indicator handler const handleTyping = (data: { threadId: string; isTyping: boolean }) => { - dispatch(setTyping({ - threadId: data.threadId, - isTyping: data.isTyping, - })); + dispatch(setTyping({ threadId: data.threadId, isTyping: data.isTyping })); }; // Register all handlers @@ -309,12 +310,7 @@ export const useIntelligenceSocketManager = () => { } }, [token, isConnected, connect]); - return { - connect, - disconnect, - isConnected, - isReady: isConnected && !!token, - }; + return { connect, disconnect, isConnected, isReady: isConnected && !!token }; }; /** @@ -326,63 +322,59 @@ export const useIntelligenceEvents = () => { /** * Subscribe to agent responses for a specific thread */ - const onAgentResponse = useCallback(( - threadId: string, - callback: (data: AgentResponsePayload) => void - ) => { - if (!socket) return () => {}; + const onAgentResponse = useCallback( + (threadId: string, callback: (data: AgentResponsePayload) => void) => { + if (!socket) return () => {}; - const handler = (data: AgentResponsePayload) => { - if (data.threadId === threadId) { - callback(data); - } - }; + const handler = (data: AgentResponsePayload) => { + if (data.threadId === threadId) { + callback(data); + } + }; - socket.on('agentResponse', handler); - return () => socket.off('agentResponse', handler); - }, [socket]); + socket.on('agentResponse', handler); + return () => socket.off('agentResponse', handler); + }, + [socket] + ); /** * Subscribe to execution progress for a specific execution */ - const onExecutionProgress = useCallback(( - executionId: string, - callback: (data: ExecutionProgressPayload) => void - ) => { - if (!socket) return () => {}; + const onExecutionProgress = useCallback( + (executionId: string, callback: (data: ExecutionProgressPayload) => void) => { + if (!socket) return () => {}; - const handler = (data: ExecutionProgressPayload) => { - if (data.executionId === executionId) { - callback(data); - } - }; + const handler = (data: ExecutionProgressPayload) => { + if (data.executionId === executionId) { + callback(data); + } + }; - socket.on('execution:step_progress', handler); - return () => socket.off('execution:step_progress', handler); - }, [socket]); + socket.on('execution:step_progress', handler); + return () => socket.off('execution:step_progress', handler); + }, + [socket] + ); /** * Subscribe to execution completion for a specific execution */ - const onExecutionComplete = useCallback(( - executionId: string, - callback: (data: ExecutionCompletePayload) => void - ) => { - if (!socket) return () => {}; + const onExecutionComplete = useCallback( + (executionId: string, callback: (data: ExecutionCompletePayload) => void) => { + if (!socket) return () => {}; - const handler = (data: ExecutionCompletePayload) => { - if (data.executionId === executionId) { - callback(data); - } - }; + const handler = (data: ExecutionCompletePayload) => { + if (data.executionId === executionId) { + callback(data); + } + }; - socket.on('execution:complete', handler); - return () => socket.off('execution:complete', handler); - }, [socket]); + socket.on('execution:complete', handler); + return () => socket.off('execution:complete', handler); + }, + [socket] + ); - return { - onAgentResponse, - onExecutionProgress, - onExecutionComplete, - }; -}; \ No newline at end of file + return { onAgentResponse, onExecutionProgress, onExecutionComplete }; +}; diff --git a/src/lib/ai/__tests__/loader.test.ts b/src/lib/ai/__tests__/loader.test.ts index a046c25ee..e4beb60ce 100644 --- a/src/lib/ai/__tests__/loader.test.ts +++ b/src/lib/ai/__tests__/loader.test.ts @@ -76,7 +76,7 @@ describe('Unified AI Loader', () => { expect(config.soul).toEqual(mockSoulConfig); expect(config.tools).toEqual(mockToolsConfig); expect(config.metadata.hasFallbacks).toBe(false); - expect(config.metadata.loadingDuration).toBeGreaterThan(0); + expect(config.metadata.loadingDuration).toBeGreaterThanOrEqual(0); }); it('should return cached config on subsequent calls', async () => { @@ -247,7 +247,7 @@ describe('Unified AI Loader', () => { expect(clearSoulCache).toHaveBeenCalled(); expect(clearToolsCache).toHaveBeenCalled(); - expect(localStorageMock.removeItem).toHaveBeenCalledWith('alphahuman.ai.cache'); + expect(localStorageMock.removeItem).toHaveBeenCalledWith('openhuman.ai.cache'); }); }); }); diff --git a/src/lib/ai/constitution/__tests__/loader.test.ts b/src/lib/ai/constitution/__tests__/loader.test.ts index bd440e6d3..37c35461c 100644 --- a/src/lib/ai/constitution/__tests__/loader.test.ts +++ b/src/lib/ai/constitution/__tests__/loader.test.ts @@ -350,7 +350,7 @@ describe('loadConstitution', () => { await loadConstitution(); expect(fetch).toHaveBeenCalledWith( - 'https://raw.githubusercontent.com/alphahumanxyz/constitution/refs/heads/main/CONSTITUTION.md' + 'https://raw.githubusercontent.com/openhumanxyz/constitution/refs/heads/main/CONSTITUTION.md' ); }); }); diff --git a/src/lib/ai/constitution/loader.ts b/src/lib/ai/constitution/loader.ts index 5e5a45616..38f03f677 100644 --- a/src/lib/ai/constitution/loader.ts +++ b/src/lib/ai/constitution/loader.ts @@ -8,7 +8,7 @@ import type { } from './types'; const CONSTITUTION_URL = - 'https://raw.githubusercontent.com/alphahumanxyz/constitution/refs/heads/main/CONSTITUTION.md'; + 'https://raw.githubusercontent.com/openhumanxyz/constitution/refs/heads/main/CONSTITUTION.md'; /** * Load the constitution from the public GitHub repository. diff --git a/src/lib/ai/loader.ts b/src/lib/ai/loader.ts index b871816bb..22b6563e3 100644 --- a/src/lib/ai/loader.ts +++ b/src/lib/ai/loader.ts @@ -16,7 +16,7 @@ import type { AIConfigMetadata, } from './types'; -const AI_CACHE_KEY = 'alphahuman.ai.cache'; +const AI_CACHE_KEY = 'openhuman.ai.cache'; const AI_CACHE_TTL = 1000 * 60 * 30; // 30 minutes const CACHE_VERSION = '1.0.0'; diff --git a/src/lib/ai/memory/manager.ts b/src/lib/ai/memory/manager.ts index dfffb2717..5f647ed1d 100644 --- a/src/lib/ai/memory/manager.ts +++ b/src/lib/ai/memory/manager.ts @@ -121,7 +121,7 @@ export class MemoryManager { } /** - * Index all memory files from the ~/.alphahuman/ directory. + * Index all memory files from the ~/.openhuman/ directory. */ async indexAll(): Promise { let totalIndexed = 0; diff --git a/src/lib/ai/memory/schema.ts b/src/lib/ai/memory/schema.ts index f6705b722..97e3246a4 100644 --- a/src/lib/ai/memory/schema.ts +++ b/src/lib/ai/memory/schema.ts @@ -4,7 +4,7 @@ * The memory index uses JSON files on disk (managed by Rust memory_fs.rs). * This file documents the schema for TypeScript reference. * - * Filesystem layout under ~/.alphahuman/: + * Filesystem layout under ~/.openhuman/: * * ``` * index/ diff --git a/src/lib/ai/memory/types.ts b/src/lib/ai/memory/types.ts index 5a85b07be..4fe594c16 100644 --- a/src/lib/ai/memory/types.ts +++ b/src/lib/ai/memory/types.ts @@ -86,7 +86,7 @@ export interface EmbeddingCacheEntry { updatedAt: number; } -/** Memory file layout under ~/.alphahuman/ */ +/** Memory file layout under ~/.openhuman/ */ export const MEMORY_PATHS = { CONSTITUTION: 'CONSTITUTION.md', MEMORY_ROOT: 'memory.md', diff --git a/src/lib/ai/openclaw-loader.ts b/src/lib/ai/openclaw-loader.ts index 944dd07e1..0f1eab631 100644 --- a/src/lib/ai/openclaw-loader.ts +++ b/src/lib/ai/openclaw-loader.ts @@ -7,13 +7,13 @@ * Matches the Rust backend's `build_system_prompt()` approach exactly: * each file is injected as a `### FILENAME` section within `## Project Context`. */ -import agentsMd from '../../../ai/AGENTS.md?raw'; -import bootstrapMd from '../../../ai/BOOTSTRAP.md?raw'; -import identityMd from '../../../ai/IDENTITY.md?raw'; -import memoryMd from '../../../ai/MEMORY.md?raw'; -import soulMd from '../../../ai/SOUL.md?raw'; -import toolsMd from '../../../ai/TOOLS.md?raw'; -import userMd from '../../../ai/USER.md?raw'; +import agentsMd from '../../../src-tauri/ai/AGENTS.md?raw'; +import bootstrapMd from '../../../src-tauri/ai/BOOTSTRAP.md?raw'; +import identityMd from '../../../src-tauri/ai/IDENTITY.md?raw'; +import memoryMd from '../../../src-tauri/ai/MEMORY.md?raw'; +import soulMd from '../../../src-tauri/ai/SOUL.md?raw'; +import toolsMd from '../../../src-tauri/ai/TOOLS.md?raw'; +import userMd from '../../../src-tauri/ai/USER.md?raw'; const MAX_CHARS = 20_000; diff --git a/src/lib/ai/soul/loader.ts b/src/lib/ai/soul/loader.ts index 3ca9e6e52..b49660b08 100644 --- a/src/lib/ai/soul/loader.ts +++ b/src/lib/ai/soul/loader.ts @@ -1,4 +1,4 @@ -import soulMd from '../../../../ai/SOUL.md?raw'; +import soulMd from '../../../../src-tauri/ai/SOUL.md?raw'; import type { BehaviorPattern, EmergencyResponse, @@ -12,8 +12,8 @@ import type { } from './types'; const SOUL_GITHUB_URL = - 'https://raw.githubusercontent.com/alphahumanxyz/alphahuman/refs/heads/main/ai/SOUL.md'; -const SOUL_CACHE_KEY = 'alphahuman.soul.cache'; + 'https://raw.githubusercontent.com/openhumanxyz/openhuman/refs/heads/main/src-tauri/ai/SOUL.md'; +const SOUL_CACHE_KEY = 'openhuman.soul.cache'; const SOUL_CACHE_TTL = 1000 * 60 * 30; // 30 minutes let cachedSoulConfig: SoulConfig | null = null; diff --git a/src/lib/ai/tools/__tests__/loader.test.ts b/src/lib/ai/tools/__tests__/loader.test.ts index c45c1e31a..a9c773178 100644 --- a/src/lib/ai/tools/__tests__/loader.test.ts +++ b/src/lib/ai/tools/__tests__/loader.test.ts @@ -8,7 +8,7 @@ import { clearToolsCache, loadTools, parseTools } from '../loader'; import type { ToolsConfig } from '../types'; // Mock the bundled tools markdown -vi.mock('../../../../../ai/TOOLS.md?raw', () => ({ +vi.mock('../../../../../src-tauri/ai/TOOLS.md?raw', () => ({ default: `# OpenHuman Tools ## Overview @@ -67,9 +67,6 @@ const localStorageMock = { Object.defineProperty(window, 'localStorage', { value: localStorageMock }); -// Mock fetch -global.fetch = vi.fn(); - describe('Tools Loader', () => { beforeEach(() => { vi.clearAllMocks(); @@ -162,7 +159,7 @@ describe('Tools Loader', () => { - *None* #### get_history -**Description**: Get history +**Description**: Get chat history **Parameters**: - *None* @@ -192,7 +189,7 @@ describe('Tools Loader', () => { }); describe('loadTools', () => { - it('should load from cache when available', async () => { + it('should load from localStorage when cache is valid', async () => { const mockConfig: ToolsConfig = { raw: 'cached markdown', tools: [], @@ -217,10 +214,9 @@ describe('Tools Loader', () => { const result = await loadTools(); expect(result).toEqual(mockConfig); - expect(fetch).not.toHaveBeenCalled(); }); - it('should load from GitHub when cache is expired', async () => { + it('should load bundled TOOLS when cache is expired', async () => { const expiredCacheEntry = { config: {} as ToolsConfig, timestamp: Date.now() - 1000 * 60 * 60, // 1 hour ago @@ -229,37 +225,28 @@ describe('Tools Loader', () => { localStorageMock.getItem.mockReturnValue(JSON.stringify(expiredCacheEntry)); - (fetch as any).mockResolvedValue({ ok: true, text: () => Promise.resolve('# Remote Tools') }); - const result = await loadTools(); - expect(fetch).toHaveBeenCalledWith( - 'https://raw.githubusercontent.com/alphahumanxyz/alphahuman/refs/heads/main/ai/TOOLS.md' - ); - expect(result.raw).toBe('# Remote Tools'); + expect(result.tools.length).toBeGreaterThan(0); + expect(result.raw).toBeDefined(); expect(result.isDefault).toBe(false); }); - it('should fallback to bundled tools when GitHub fails', async () => { + it('should load bundled tools when localStorage is empty', async () => { localStorageMock.getItem.mockReturnValue(null); - (fetch as any).mockRejectedValue(new Error('Network error')); - const result = await loadTools(); - expect(result.isDefault).toBe(true); - expect(result.tools).toHaveLength(4); // From mocked bundled tools + expect(result.tools.length).toBeGreaterThan(0); }); - it('should cache the loaded configuration', async () => { + it('should persist loaded configuration to localStorage', async () => { localStorageMock.getItem.mockReturnValue(null); - (fetch as any).mockResolvedValue({ ok: true, text: () => Promise.resolve('# Remote Tools') }); - await loadTools(); expect(localStorageMock.setItem).toHaveBeenCalledWith( - 'alphahuman.tools.cache', + 'openhuman.tools.cache', expect.stringContaining('"version":"1.0.0"') ); }); @@ -269,7 +256,7 @@ describe('Tools Loader', () => { it('should clear localStorage cache', () => { clearToolsCache(); - expect(localStorageMock.removeItem).toHaveBeenCalledWith('alphahuman.tools.cache'); + expect(localStorageMock.removeItem).toHaveBeenCalledWith('openhuman.tools.cache'); }); it('should handle localStorage errors gracefully', () => { diff --git a/src/lib/ai/tools/loader.ts b/src/lib/ai/tools/loader.ts index 126c9c935..1c1fd83bc 100644 --- a/src/lib/ai/tools/loader.ts +++ b/src/lib/ai/tools/loader.ts @@ -1,4 +1,4 @@ -import toolsMd from '../../../../ai/TOOLS.md?raw'; +import toolsMd from '../../../../src-tauri/ai/TOOLS.md?raw'; import type { SkillGroup, ToolCategory, @@ -11,7 +11,7 @@ import type { } from './types'; // GitHub URL removed - always use bundled file updated by auto-update system -const TOOLS_CACHE_KEY = 'alphahuman.tools.cache'; +const TOOLS_CACHE_KEY = 'openhuman.tools.cache'; const TOOLS_CACHE_TTL = 1000 * 60 * 30; // 30 minutes const CACHE_VERSION = '1.0.0'; @@ -164,8 +164,8 @@ function parseToolBlock(block: string, defaultSkillId: string): ToolDefinition | const descriptionMatch = block.match(/\*\*Description\*\*:\s*(.+)/); const description = descriptionMatch?.[1]?.trim() || 'No description available'; - // Extract parameters and build input schema - const parametersSection = extractSection(block, 'Parameters'); + // Extract parameters and build input schema (tool blocks use **Parameters**: not ## headings) + const parametersSection = extractParametersSectionFromToolBlock(block); const inputSchema = parseParametersToSchema(parametersSection); // Try to determine actual skillId from tool name or description @@ -359,6 +359,12 @@ function generateStatistics( /** * Utility functions */ +/** Parameters under a tool block use `**Parameters**:` (see OpenClaw TOOLS.md format). */ +function extractParametersSectionFromToolBlock(block: string): string { + const m = block.match(/\*\*Parameters\*\*:\s*\n([\s\S]*)/i); + return m?.[1]?.trim() ?? ''; +} + function extractSection(raw: string, heading: string): string { const regex = new RegExp(`## ${heading}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`, 'i'); const match = raw.match(regex); diff --git a/src/lib/intelligence/chatTools.ts b/src/lib/intelligence/chatTools.ts index 9b58aeb0d..9f6828260 100644 --- a/src/lib/intelligence/chatTools.ts +++ b/src/lib/intelligence/chatTools.ts @@ -11,8 +11,8 @@ import debug from 'debug'; import type { ConnectedTool } from '../../services/intelligenceApi'; import { socketService } from '../../services/socketService'; import { store } from '../../store'; -import { emitViaRustSocket } from '../../utils/tauriSocket'; import { transformMCPToConnectedTools } from '../../utils/intelligenceTransforms'; +import { emitViaRustSocket } from '../../utils/tauriSocket'; import type { MCPTool } from '../mcp'; import { deriveConnectionStatus } from '../skills/hooks'; @@ -146,7 +146,7 @@ export function initializeChatWithTools( connectedTools, sessionId, threadId, - timestamp: Date.now() + timestamp: Date.now(), }; // Detailed logging of available tools diff --git a/src/lib/skills/types.ts b/src/lib/skills/types.ts index 6eb8f8085..edc44f915 100644 --- a/src/lib/skills/types.ts +++ b/src/lib/skills/types.ts @@ -10,7 +10,7 @@ export type SkillPlatform = "windows" | "macos" | "linux" | "android" | "ios"; /** Unified registry skill type discriminant. */ -export type SkillType = 'alphahuman' | 'openclaw'; +export type SkillType = 'openhuman' | 'openclaw'; export interface SkillManifest { id: string; @@ -36,7 +36,7 @@ export interface SkillManifest { platforms?: SkillPlatform[]; /** When true, skill is hidden in production builds. */ ignoreInProduction?: boolean; - /** Unified registry type: "alphahuman" (QuickJS) or "openclaw" (skill.md/TOML). */ + /** Unified registry type: "openhuman" (QuickJS) or "openclaw" (skill.md/TOML). */ skill_type?: SkillType; } @@ -212,4 +212,3 @@ export interface SkillState { /** Persisted OAuth credential so it survives app restarts. */ oauthCredential?: OAuthCredential; } - diff --git a/src/lib/tools/auto-update.ts b/src/lib/tools/auto-update.ts index c613600a4..d37e254ad 100644 --- a/src/lib/tools/auto-update.ts +++ b/src/lib/tools/auto-update.ts @@ -17,7 +17,7 @@ interface RuntimeToolResponse { tool: { name: string; description: string; - input_schema: { type: string; properties: Record; required?: string[] }; + input_schema: { type: string; properties: Record; required?: string[] }; }; } @@ -73,8 +73,8 @@ export async function updateToolsDocumentation(): Promise { const markdownContent = generateToolsMarkdown(toolsBySkill); console.log(`🔧 Generated markdown length: ${markdownContent.length} characters`); - // Write to ai/TOOLS.md using new Tauri command - console.log('🔍 Step 6: Writing to ai/TOOLS.md file...'); + // Write to src-tauri/ai/TOOLS.md using Tauri command + console.log('🔍 Step 6: Writing to src-tauri/ai/TOOLS.md file...'); console.log('🔧 About to call write_ai_config_file with filename: TOOLS.md'); console.log('🔧 Content length:', markdownContent.length); @@ -175,8 +175,9 @@ ${Object.entries(toolsBySkill) for (const [paramName, paramDef] of Object.entries(properties)) { const isRequired = required.includes(paramName); const requiredText = isRequired ? ' **(required)**' : ''; - const type = (paramDef as any).type || 'any'; - const description = (paramDef as any).description || 'No description'; + const def = paramDef as { type?: string; description?: string }; + const type = def.type || 'any'; + const description = def.description || 'No description'; content.push(`- **${paramName}** (${type})${requiredText}: ${description}`); } } else { @@ -186,9 +187,9 @@ ${Object.entries(toolsBySkill) content.push('\n**Usage Context**: Available in all environments\n'); // Generate example usage - const exampleParams: Record = {}; + const exampleParams: Record = {}; for (const [paramName, paramDef] of Object.entries(properties)) { - const type = (paramDef as any).type; + const type = (paramDef as { type?: string }).type; exampleParams[paramName] = getExampleValue(paramName, type); } @@ -244,7 +245,7 @@ function formatSkillName(skillId: string): string { /** * Generate example value for a parameter */ -function getExampleValue(paramName: string, type: string): any { +function getExampleValue(paramName: string, type: string | undefined): unknown { switch (type) { case 'string': return `example_${paramName}`; diff --git a/src/lib/tools/file-watcher.ts b/src/lib/tools/file-watcher.ts index 8dbb84517..97df4ec4a 100644 --- a/src/lib/tools/file-watcher.ts +++ b/src/lib/tools/file-watcher.ts @@ -9,7 +9,7 @@ import { clearToolsCache } from '../ai/tools/loader'; // Track file modification time to detect changes let lastModifiedTime: number | null = null; -let watcherInterval: NodeJS.Timeout | null = null; +let watcherInterval: ReturnType | null = null; /** * Start watching TOOLS.md file for changes @@ -44,7 +44,7 @@ export function stopToolsFileWatcher(): void { async function checkForToolsChanges(): Promise { try { // Check if the bundled TOOLS.md has changed by fetching from public directory - const response = await fetch('/ai/TOOLS.md'); + const response = await fetch('/src-tauri/ai/TOOLS.md'); if (!response.ok) return; const content = await response.text(); @@ -77,7 +77,7 @@ async function checkForToolsChanges(): Promise { console.error('❌ Failed to reload AI config after file change:', error); } } - } catch (error) { + } catch (_err) { // Silently ignore errors (file not found, network issues, etc.) // This prevents console spam during development } diff --git a/src/pages/Intelligence.tsx b/src/pages/Intelligence.tsx index 1c353ab79..201d176f4 100644 --- a/src/pages/Intelligence.tsx +++ b/src/pages/Intelligence.tsx @@ -10,15 +10,16 @@ import { useSnoozeActionableItem, useUpdateActionableItem, } from '../hooks/useIntelligenceApiFallback'; -import { useIntelligenceSocket, useIntelligenceSocketManager } from '../hooks/useIntelligenceSocket'; +import { + useIntelligenceSocket, + useIntelligenceSocketManager, +} from '../hooks/useIntelligenceSocket'; import { useIntelligenceStats } from '../hooks/useIntelligenceStats'; import type { RootState } from '../store'; -import { - setSourceFilter, - setSearchFilter, -} from '../store/intelligenceSlice'; +import { setSearchFilter, setSourceFilter } from '../store/intelligenceSlice'; import type { ActionableItem, + ActionableItemSource, ActionableItemStatus, ConfirmationModal as ConfirmationModalType, ToastNotification, @@ -57,8 +58,16 @@ export default function Intelligence() { onCancel: () => {}, }); - // Use API data or fallback to empty array - const items = apiItems || []; + const addToast = useCallback((toast: Omit) => { + const newToast: ToastNotification = { ...toast, id: `toast-${Date.now()}-${Math.random()}` }; + setToasts(prev => [...prev, newToast]); + }, []); + + const removeToast = useCallback((id: string) => { + setToasts(prev => prev.filter(toast => toast.id !== id)); + }, []); + + const items = useMemo(() => apiItems ?? [], [apiItems]); // Initialize socket connection useEffect(() => { @@ -67,16 +76,18 @@ export default function Intelligence() { } }, [socketConnected, socketManager]); - // Handle API errors with toast notifications + // Handle API errors with toast notifications (defer to avoid setState-in-effect) useEffect(() => { - if (itemsError) { + if (!itemsError) return; + const t = window.setTimeout(() => { addToast({ type: 'error', title: 'Failed to load items', message: typeof itemsError === 'string' ? itemsError : 'Unable to fetch actionable items', }); - } - }, [itemsError]); + }, 0); + return () => clearTimeout(t); + }, [itemsError, addToast]); // Filter and group items const filteredItems = useMemo(() => { @@ -96,55 +107,47 @@ export default function Intelligence() { return getItemStats(filteredItems); }, [filteredItems]); - // Toast utilities - const addToast = useCallback((toast: Omit) => { - const newToast: ToastNotification = { ...toast, id: `toast-${Date.now()}-${Math.random()}` }; - setToasts(prev => [...prev, newToast]); - }, []); - - const removeToast = useCallback((id: string) => { - setToasts(prev => prev.filter(toast => toast.id !== id)); - }, []); - // Item action handlers with real backend integration - const handleUpdateItemStatus = useCallback(async (itemId: string, status: ActionableItemStatus) => { - try { - await updateItemStatus({ itemId, status }); + const handleUpdateItemStatus = useCallback( + async (itemId: string, status: ActionableItemStatus) => { + try { + await updateItemStatus({ itemId, status }); - // Success toast - let message = ''; - switch (status) { - case 'completed': - message = 'Task marked as completed'; - break; - case 'dismissed': - message = 'Task dismissed'; - break; - case 'active': - message = 'Task reactivated'; - break; - default: - message = 'Status updated'; + // Success toast + let message = ''; + switch (status) { + case 'completed': + message = 'Task marked as completed'; + break; + case 'dismissed': + message = 'Task dismissed'; + break; + case 'active': + message = 'Task reactivated'; + break; + default: + message = 'Status updated'; + } + + addToast({ type: 'success', title: 'Status Updated', message }); + } catch (error) { + console.error('Failed to update item status:', error); + addToast({ + type: 'error', + title: 'Update Failed', + message: error instanceof Error ? error.message : 'Failed to update item status', + }); } + }, + [updateItemStatus, addToast] + ); - addToast({ - type: 'success', - title: 'Status Updated', - message, - }); - } catch (error) { - console.error('Failed to update item status:', error); - addToast({ - type: 'error', - title: 'Update Failed', - message: error instanceof Error ? error.message : 'Failed to update item status', - }); - } - }, [updateItemStatus]); - - const handleComplete = useCallback(async (item: ActionableItem) => { - await handleUpdateItemStatus(item.id, 'completed'); - }, [handleUpdateItemStatus]); + const handleComplete = useCallback( + async (item: ActionableItem) => { + await handleUpdateItemStatus(item.id, 'completed'); + }, + [handleUpdateItemStatus] + ); const handleDismiss = useCallback( (item: ActionableItem) => { @@ -166,10 +169,7 @@ export default function Intelligence() { type: 'info', title: 'Dismissed', message: item.title.length > 40 ? `${item.title.substring(0, 40)}...` : item.title, - action: { - label: 'Undo', - handler: () => handleUpdateItemStatus(item.id, 'active'), - }, + action: { label: 'Undo', handler: () => handleUpdateItemStatus(item.id, 'active') }, }); } catch (error) { console.error('Failed to dismiss item:', error); @@ -206,23 +206,40 @@ export default function Intelligence() { ); // Combined AI and socket status indicator - const systemStatus = socketConnected && aiStatus === 'ready' ? 'ready' : - itemsLoading ? 'loading' : - !socketConnected ? 'disconnected' : aiStatus; + const systemStatus = + socketConnected && aiStatus === 'ready' + ? 'ready' + : itemsLoading + ? 'loading' + : !socketConnected + ? 'disconnected' + : aiStatus; const systemStatusLabel = - systemStatus === 'ready' ? 'System Ready' : - systemStatus === 'loading' ? 'Loading...' : - systemStatus === 'disconnected' ? 'Connecting...' : - systemStatus === 'initializing' ? 'Initializing...' : - systemStatus === 'error' ? 'System Error' : 'System Idle'; + systemStatus === 'ready' + ? 'System Ready' + : systemStatus === 'loading' + ? 'Loading...' + : systemStatus === 'disconnected' + ? 'Connecting...' + : systemStatus === 'initializing' + ? 'Initializing...' + : systemStatus === 'error' + ? 'System Error' + : 'System Idle'; const systemStatusDot = - systemStatus === 'ready' ? 'bg-sage-400' : - systemStatus === 'loading' ? 'bg-amber-400 animate-pulse' : - systemStatus === 'disconnected' ? 'bg-amber-400 animate-pulse' : - systemStatus === 'initializing' ? 'bg-amber-400 animate-pulse' : - systemStatus === 'error' ? 'bg-coral-400' : 'bg-stone-600'; + systemStatus === 'ready' + ? 'bg-sage-400' + : systemStatus === 'loading' + ? 'bg-amber-400 animate-pulse' + : systemStatus === 'disconnected' + ? 'bg-amber-400 animate-pulse' + : systemStatus === 'initializing' + ? 'bg-amber-400 animate-pulse' + : systemStatus === 'error' + ? 'bg-coral-400' + : 'bg-stone-600'; return (
@@ -258,7 +275,9 @@ export default function Intelligence() {