refactor: remove Tauri integration and update tools discovery mechanism

- Eliminated the Tauri integration files and related functions to streamline the tools discovery process.
- Updated the tools discovery logic to utilize a mock registry instead of relying on Tauri, enhancing compatibility and simplifying the workflow.
- Adjusted comments in the release workflow to reflect the changes in tools discovery and removed references to the now-removed Tauri binary.
This commit is contained in:
Steven Enamakel
2026-03-26 18:29:44 -07:00
parent 16b14d4fc2
commit 851f2308bd
5 changed files with 5 additions and 490 deletions
+3 -3
View File
@@ -313,9 +313,9 @@ jobs:
WITH_UPDATER: 'true'
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
with:
# `openhuman-tools-discovery` is feature-gated in Cargo.toml so it
# does not get bundled into release app packages and break macOS
# codesign as an unsigned subcomponent.
# Tools discovery now uses a JS mock registry (no Rust discovery
# binary target), so there is no extra helper executable for Tauri
# to copy/sign inside release app bundles.
args: -c ${{ steps.config-overrides.outputs.json }} ${{ matrix.settings.args }}
includeDebug: false
includeRelease: true
+2 -108
View File
@@ -12,12 +12,6 @@ import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { generateOpenClawMarkdown } from './openClaw-formatter.js';
import {
executeTauriDiscovery,
getTauriEnvironmentInfo,
prepareTauriEnvironment,
validateTauriEnvironment,
} from './tauri-integration.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROJECT_ROOT = join(__dirname, '../..');
@@ -42,39 +36,7 @@ const ENVIRONMENTS = {
* @returns {Promise<Array>} Array of discovered tools with skill metadata
*/
async function discoverTools() {
console.log('🔍 Discovering tools from V8 skills runtime...');
// Check if Tauri environment is available
const tauriAvailable = await validateTauriEnvironment();
if (tauriAvailable) {
try {
console.log('🔧 Preparing Tauri environment...');
await prepareTauriEnvironment();
console.log('🚀 Executing Tauri tools discovery...');
const realTools = await executeTauriDiscovery({
timeout: 60000, // 60 seconds
retries: 2,
verbose: process.env.VERBOSE === 'true',
});
if (realTools && realTools.length > 0) {
console.log(
`✅ Discovered ${realTools.length} tools from ${new Set(realTools.map(t => t.skillId)).size} skills via Tauri`
);
return realTools;
}
} catch (error) {
console.warn('⚠️ Could not discover tools from Tauri runtime:', error.message);
console.log('📋 Using development mock data instead');
}
} else {
console.warn('⚠️ Tauri environment not available');
console.log('📋 Using development mock data instead');
}
// Fallback to mock data for development
console.log('🔍 Discovering tools from mock registry...');
const mockTools = generateMockToolsForDevelopment();
console.log(
`✅ Using mock data: ${mockTools.length} tools from ${new Set(mockTools.map(t => t.skillId)).size} skills`
@@ -195,77 +157,9 @@ async function main() {
}
}
/**
* Attempts to discover tools from a running Tauri process
* @returns {Promise<Array>} Array of tools from Tauri runtime
*/
async function discoverToolsFromTauri() {
return new Promise((resolve, reject) => {
// Try to spawn a minimal Tauri process for tool discovery
const isWindows = process.platform === 'win32';
const tauriCommand = isWindows ? 'cargo.exe' : 'cargo';
const args = [
'run',
'--manifest-path',
join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'),
'--bin',
'openhuman-tools-discovery',
'--features',
'tools-discovery-bin',
];
console.log('🔧 Attempting to run tools discovery via Cargo...');
const child = spawn(tauriCommand, args, {
stdio: ['pipe', 'pipe', 'pipe'],
cwd: PROJECT_ROOT,
env: { ...process.env, TAURI_TOOLS_DISCOVERY: 'true' },
});
let output = '';
let errorOutput = '';
child.stdout.on('data', data => {
output += data.toString();
});
child.stderr.on('data', data => {
errorOutput += data.toString();
});
child.on('close', code => {
if (code === 0 && output.trim()) {
try {
const result = JSON.parse(output.trim());
if (result.success && result.tools) {
resolve(result.tools);
} else {
reject(new Error(result.error || 'Unknown error from Tauri'));
}
} catch (parseError) {
reject(new Error(`Failed to parse Tauri output: ${parseError.message}`));
}
} else {
reject(new Error(`Tauri process failed (code ${code}): ${errorOutput}`));
}
});
child.on('error', error => {
reject(new Error(`Failed to spawn Tauri process: ${error.message}`));
});
// Timeout after 30 seconds
setTimeout(() => {
child.kill();
reject(new Error('Tauri discovery process timed out'));
}, 30000);
});
}
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
export { discoverTools, discoverToolsFromTauri, generateMockToolsForDevelopment };
export { discoverTools, generateMockToolsForDevelopment };
@@ -1,223 +0,0 @@
#!/usr/bin/env node
/**
* Tauri Integration for Tools Discovery
*
* Provides integration utilities for discovering tools via Tauri runtime.
* Handles cross-platform execution, error handling, and fallbacks.
*/
import { spawn } from 'child_process';
import { join } from 'path';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PROJECT_ROOT = join(__dirname, '../..');
/**
* Platform-specific command detection
* @returns {Object} Command and arguments for spawning Tauri process
*/
export function getTauriCommand() {
const isWindows = process.platform === 'win32';
return {
command: isWindows ? 'cargo.exe' : 'cargo',
args: [
'run',
'--manifest-path',
join(PROJECT_ROOT, 'src-tauri', 'Cargo.toml'),
'--bin',
'openhuman-tools-discovery',
'--features',
'tools-discovery-bin',
],
};
}
/**
* Validates if Tauri development environment is available
* @returns {Promise<boolean>} True if Tauri can be used
*/
export async function validateTauriEnvironment() {
return new Promise(resolve => {
const { command } = getTauriCommand();
const child = spawn(command, ['--version'], { stdio: ['pipe', 'pipe', 'pipe'] });
child.on('close', code => {
resolve(code === 0);
});
child.on('error', () => {
resolve(false);
});
// Timeout after 10 seconds
setTimeout(() => {
child.kill();
resolve(false);
}, 10000);
});
}
/**
* Executes tools discovery via Tauri runtime
* @param {Object} options - Configuration options
* @returns {Promise<Array>} Discovered tools
*/
export async function executeTauriDiscovery(options = {}) {
const {
timeout = 45000, // 45 seconds
retries = 2,
verbose = false,
} = options;
for (let attempt = 1; attempt <= retries; attempt++) {
try {
if (verbose) {
console.log(`🔄 Tauri discovery attempt ${attempt}/${retries}...`);
}
const result = await runTauriDiscovery(timeout, verbose);
return result;
} catch (error) {
if (attempt === retries) {
throw error;
}
if (verbose) {
console.warn(`⚠️ Attempt ${attempt} failed:`, error.message);
console.log('🔄 Retrying...');
}
}
}
}
/**
* Internal function to run Tauri discovery process
* @param {number} timeout - Timeout in milliseconds
* @param {boolean} verbose - Enable verbose logging
* @returns {Promise<Array>} Discovered tools
*/
async function runTauriDiscovery(timeout, verbose) {
return new Promise((resolve, reject) => {
const { command, args } = getTauriCommand();
if (verbose) {
console.log(`🔧 Executing: ${command} ${args.join(' ')}`);
}
const child = spawn(command, args, {
stdio: ['pipe', 'pipe', 'pipe'],
cwd: PROJECT_ROOT,
env: {
...process.env,
TAURI_TOOLS_DISCOVERY: 'true',
RUST_LOG: verbose ? 'debug' : 'warn',
RUST_BACKTRACE: '1',
},
});
let output = '';
let errorOutput = '';
child.stdout.on('data', data => {
const text = data.toString();
output += text;
if (verbose && text.trim()) {
console.log('📤 Tauri output:', text.trim());
}
});
child.stderr.on('data', data => {
const text = data.toString();
errorOutput += text;
if (verbose && text.trim()) {
console.log('📤 Tauri stderr:', text.trim());
}
});
child.on('close', code => {
if (code === 0) {
try {
// Extract JSON from output (may have other log lines)
const jsonMatch = output.match(/\{.*"success".*\}/s);
if (!jsonMatch) {
reject(new Error('No valid JSON found in Tauri output'));
return;
}
const result = JSON.parse(jsonMatch[0]);
if (result.success) {
resolve(result.tools || []);
} else {
reject(new Error(result.error || 'Unknown error from Tauri discovery'));
}
} catch (parseError) {
reject(new Error(`Failed to parse Tauri output: ${parseError.message}`));
}
} else {
const errorMsg = errorOutput.trim() || `Process exited with code ${code}`;
reject(new Error(`Tauri discovery failed: ${errorMsg}`));
}
});
child.on('error', error => {
reject(new Error(`Failed to spawn Tauri process: ${error.message}`));
});
// Timeout handling
const timeoutId = setTimeout(() => {
child.kill('SIGTERM');
// Force kill after 5 more seconds
setTimeout(() => {
if (!child.killed) {
child.kill('SIGKILL');
}
}, 5000);
reject(new Error(`Tauri discovery timed out after ${timeout}ms`));
}, timeout);
child.on('close', () => {
clearTimeout(timeoutId);
});
});
}
/**
* Prepares the environment for tools discovery
* Ensures build dependencies and environment are ready
* @returns {Promise<void>}
*/
export async function prepareTauriEnvironment() {
console.log('🔧 Preparing Tauri environment for tools discovery...');
// Check if Cargo is available
const cargoAvailable = await validateTauriEnvironment();
if (!cargoAvailable) {
throw new Error('Cargo/Rust toolchain not found. Please install Rust and Cargo.');
}
console.log('✅ Tauri environment ready');
}
/**
* Gets information about the current Tauri setup
* @returns {Promise<Object>} Environment information
*/
export async function getTauriEnvironmentInfo() {
const cargoAvailable = await validateTauriEnvironment();
return {
cargoAvailable,
platform: process.platform,
architecture: process.arch,
projectRoot: PROJECT_ROOT,
command: getTauriCommand(),
};
}
-6
View File
@@ -19,11 +19,6 @@ crate-type = ["staticlib", "cdylib", "rlib"]
name = "OpenHuman"
path = "src/main.rs"
[[bin]]
name = "openhuman-tools-discovery"
path = "src/bin/openhuman-tools-discovery.rs"
required-features = ["tools-discovery-bin"]
[[bin]]
name = "openhuman-core"
path = "src/bin/openhuman-core.rs"
@@ -185,7 +180,6 @@ tempfile = "3"
custom-protocol = ["tauri/custom-protocol"]
sandbox-landlock = ["dep:landlock"]
sandbox-bubblewrap = []
tools-discovery-bin = []
# OpenHuman feature flags
hardware = ["dep:nusb", "dep:tokio-serial"]
@@ -1,150 +0,0 @@
//! 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.
//!
//! This binary is invoked during the build process to generate TOOLS.md automatically.
use std::env;
use std::path::PathBuf;
use tokio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Check if we're in tools discovery mode
if env::var("TAURI_TOOLS_DISCOVERY").is_err() {
eprintln!("This binary should only be run for tools discovery");
std::process::exit(1);
}
// Initialize minimal logging for discovery
env_logger::init();
// Platform check - V8 runtime only available on desktop
#[cfg(any(target_os = "android", target_os = "ios"))]
{
// Mobile platforms don't support V8 runtime
let result = serde_json::json!({
"success": true,
"tools": [],
"message": "V8 runtime not available on mobile platforms"
});
println!("{}", serde_json::to_string(&result)?);
return Ok(());
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
// Desktop platforms with V8 runtime
match discover_tools_desktop().await {
Ok(tools) => {
let result = serde_json::json!({
"success": true,
"tools": tools
});
println!("{}", serde_json::to_string(&result)?);
}
Err(error) => {
let result = serde_json::json!({
"success": false,
"error": error.to_string(),
"tools": []
});
println!("{}", serde_json::to_string(&result)?);
std::process::exit(1);
}
}
}
Ok(())
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
async fn discover_tools_desktop() -> Result<Vec<serde_json::Value>, Box<dyn std::error::Error>> {
// For now, return mock data until we can properly access the runtime engine
// The runtime module is private and the engine initialization is complex
log::info!("Using mock tools data for build-time discovery");
let mock_tools = vec![
serde_json::json!({
"skillId": "telegram",
"name": "send_message",
"description": "Send a message to a Telegram chat or user",
"inputSchema": {
"type": "object",
"properties": {
"chat_id": { "type": "string", "description": "Telegram chat ID or username" },
"message": { "type": "string", "description": "Message text to send" },
"parse_mode": { "type": "string", "description": "Message formatting mode" }
},
"required": ["chat_id", "message"]
}
}),
serde_json::json!({
"skillId": "telegram",
"name": "get_chat_history",
"description": "Retrieve message history from a Telegram chat",
"inputSchema": {
"type": "object",
"properties": {
"chat_id": { "type": "string", "description": "Telegram chat ID or username" },
"limit": { "type": "number", "description": "Number of messages to retrieve" }
},
"required": ["chat_id"]
}
}),
serde_json::json!({
"skillId": "notion",
"name": "create_page",
"description": "Create a new page in Notion workspace",
"inputSchema": {
"type": "object",
"properties": {
"parent_id": { "type": "string", "description": "Parent database or page ID" },
"title": { "type": "string", "description": "Page title" },
"content": { "type": "array", "description": "Page content blocks" }
},
"required": ["parent_id", "title"]
}
}),
serde_json::json!({
"skillId": "gmail",
"name": "send_email",
"description": "Send an email via Gmail",
"inputSchema": {
"type": "object",
"properties": {
"to": { "type": "string", "description": "Recipient email address" },
"subject": { "type": "string", "description": "Email subject line" },
"body": { "type": "string", "description": "Email body content" }
},
"required": ["to", "subject", "body"]
}
})
];
log::info!("Using {} mock tools for build-time generation", mock_tools.len());
Ok(mock_tools)
}
/// Determines the skills directory based on the current environment
fn determine_skills_directory() -> Result<PathBuf, Box<dyn std::error::Error>> {
// Try to find skills directory relative to project root
let current_dir = env::current_dir()?;
// Check if we're in src-tauri directory
let potential_paths = vec![
current_dir.join("skills"),
current_dir.parent().map(|p| p.join("skills")).unwrap_or_default(),
current_dir.join("../skills").canonicalize().unwrap_or_default(),
];
for path in potential_paths {
if path.exists() && path.is_dir() {
log::info!("Found skills directory at: {:?}", path);
return Ok(path);
}
}
Err("Could not find skills directory".into())
}