feat: Transform Hanzo AI into ultimate AI engineering toolkit
Major Updates: - Position as unified platform for building AI-powered companies - Add 200+ LLMs support (OpenRouter/LiteLLM compatible) - Implement 45+ legendary programmer modes (carmack, norvig, pike, etc) - Add browser automation via Playwright MCP integration - Create multi-platform build system (VS Code, Cursor, Windsurf, Claude Code) - Implement VS Code Chat Participant as @hanzo - Update branding: "Ultimate toolkit for AI engineers" New Features: - Unlimited memory with vector/graph/relational search - Browser control tool with auto-Playwright installation - Smart LLM routing with Hanzo AI fallback - Support for O3, O3-Pro, Claude 4, and latest models - Team collaboration with shared context/credits Build System: - Unified build script for all platforms - Versioned output files (hanzoai-1.5.4.vsix/dxt) - NPM package for CLI installation via npx - Platform-specific VSIX for Cursor/Windsurf Documentation: - Short punchy README focused on benefits - Comprehensive HANZO_MODES.md for legendary modes - Updated HANZO_AI.md with complete feature set - Links to docs.hanzo.ai for full documentation
This commit is contained in:
@@ -11,22 +11,28 @@ const PLATFORMS = {
|
||||
outputDir: 'out',
|
||||
package: false
|
||||
},
|
||||
'claude-desktop': {
|
||||
name: 'Claude Desktop MCP',
|
||||
buildCmd: 'npm run build:claude-desktop',
|
||||
outputDir: 'dist/claude-desktop',
|
||||
package: false // Already packaged by build script
|
||||
},
|
||||
'dxt': {
|
||||
name: 'Claude Code DXT',
|
||||
buildCmd: 'npm run build:dxt',
|
||||
outputDir: 'dist/dxt',
|
||||
package: false // Already packaged by build script
|
||||
},
|
||||
'mcp-standalone': {
|
||||
name: 'MCP Standalone',
|
||||
buildCmd: 'npm run build:mcp',
|
||||
outputDir: 'dist/mcp-standalone',
|
||||
'mcp-npm': {
|
||||
name: 'MCP NPM Package',
|
||||
buildCmd: 'node scripts/build-mcp-npm.js',
|
||||
outputDir: 'dist/npm',
|
||||
package: false
|
||||
},
|
||||
'cursor': {
|
||||
name: 'Cursor IDE Extension',
|
||||
buildCmd: 'npm run build:cursor',
|
||||
outputDir: 'dist/cursor',
|
||||
package: true
|
||||
},
|
||||
'windsurf': {
|
||||
name: 'Windsurf Extension',
|
||||
buildCmd: 'npm run build:windsurf',
|
||||
outputDir: 'dist/windsurf',
|
||||
package: true
|
||||
}
|
||||
};
|
||||
@@ -47,6 +53,14 @@ async function buildAllPlatforms() {
|
||||
console.log(` Output: ${config.outputDir}`);
|
||||
|
||||
try {
|
||||
// Skip if build command doesn't exist yet
|
||||
if (platform === 'cursor' || platform === 'windsurf') {
|
||||
if (!fs.existsSync(`scripts/build-${platform}.js`)) {
|
||||
console.log(` ⏭️ Skipped (build script not implemented yet)`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Run build command
|
||||
console.log(` Running: ${config.buildCmd}`);
|
||||
execSync(config.buildCmd, { stdio: 'inherit' });
|
||||
@@ -75,6 +89,18 @@ async function buildAllPlatforms() {
|
||||
success: true,
|
||||
path: config.outputDir
|
||||
});
|
||||
} else if (platform === 'dxt') {
|
||||
// DXT outputs to dist/ directly
|
||||
const dxtFile = 'dist/hanzo-ai.dxt';
|
||||
if (fs.existsSync(dxtFile)) {
|
||||
const stats = fs.statSync(dxtFile);
|
||||
console.log(` ✅ Success! Created ${dxtFile} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`);
|
||||
results.push({
|
||||
platform,
|
||||
success: true,
|
||||
path: dxtFile
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new Error('Output directory not created');
|
||||
}
|
||||
@@ -99,7 +125,9 @@ async function buildAllPlatforms() {
|
||||
if (vsixFiles.length > 0) {
|
||||
const vsixFile = vsixFiles[0];
|
||||
const targetPath = path.join('dist', vsixFile);
|
||||
fs.renameSync(vsixFile, targetPath);
|
||||
if (fs.existsSync(vsixFile)) {
|
||||
fs.renameSync(vsixFile, targetPath);
|
||||
}
|
||||
console.log(` ✅ Created: ${targetPath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -121,6 +149,10 @@ async function buildAllPlatforms() {
|
||||
listDistFiles('dist', ' ');
|
||||
|
||||
console.log('\n✨ Build complete!');
|
||||
console.log('\n📦 Installation methods:');
|
||||
console.log(' Claude Code: Drag dist/hanzoai-*.dxt into Claude Code');
|
||||
console.log(' Claude Desktop/Code: npx @hanzo/mcp@latest');
|
||||
console.log(' VS Code: Install dist/hanzoai-*.vsix');
|
||||
}
|
||||
|
||||
function createZipArchive(sourceDir, outputPath) {
|
||||
@@ -146,7 +178,7 @@ function listDistFiles(dir, prefix = '') {
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
console.log(`${prefix}📁 ${item}/`);
|
||||
if (item !== 'node_modules') {
|
||||
if (item !== 'node_modules' && items.length < 20) {
|
||||
listDistFiles(fullPath, prefix + ' ');
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('🚀 Building Hanzo MCP for Cursor IDE...\n');
|
||||
|
||||
// Cursor uses the same VSIX format as VS Code
|
||||
// We'll build a standard VSIX that Cursor can install
|
||||
|
||||
const distDir = path.join(__dirname, '..', 'dist', 'cursor');
|
||||
|
||||
// Ensure dist directory exists
|
||||
if (!fs.existsSync(distDir)) {
|
||||
fs.mkdirSync(distDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
// First compile the TypeScript
|
||||
console.log('📦 Compiling TypeScript...');
|
||||
execSync('node scripts/compile-main.js', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Build MCP components
|
||||
console.log('🔧 Building MCP components...');
|
||||
execSync('npm run build:mcp', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Package the extension
|
||||
console.log('📦 Packaging Cursor extension...');
|
||||
execSync('vsce package --no-dependencies --out dist/cursor/', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Read package.json to get version
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||
const version = packageJson.version;
|
||||
|
||||
// Rename the output file to include cursor in the name
|
||||
const vsixFiles = fs.readdirSync(distDir).filter(f => f.endsWith('.vsix'));
|
||||
if (vsixFiles.length > 0) {
|
||||
const oldPath = path.join(distDir, vsixFiles[0]);
|
||||
const newPath = path.join(distDir, `hanzoai-cursor-${version}.vsix`);
|
||||
fs.renameSync(oldPath, newPath);
|
||||
|
||||
console.log(`\n✅ Successfully built Cursor extension: ${newPath}`);
|
||||
console.log(`📦 File size: ${(fs.statSync(newPath).size / 1024 / 1024).toFixed(2)} MB`);
|
||||
console.log('\n📥 To install in Cursor:');
|
||||
console.log(' 1. Open Cursor');
|
||||
console.log(' 2. Press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows/Linux)');
|
||||
console.log(' 3. Run "Extensions: Install from VSIX..."');
|
||||
console.log(` 4. Select ${newPath}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Build failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
+12
-11
@@ -10,7 +10,9 @@ console.log('Building Hanzo MCP Desktop Extension (.dxt)...\n');
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
const dxtDir = path.join(rootDir, 'dxt');
|
||||
const distDir = path.join(rootDir, 'dist');
|
||||
const outputFile = path.join(distDir, 'hanzo-ai.dxt');
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
|
||||
const version = packageJson.version;
|
||||
const outputFile = path.join(distDir, `hanzoai-${version}.dxt`);
|
||||
|
||||
// Ensure dist directory exists
|
||||
if (!fs.existsSync(distDir)) {
|
||||
@@ -120,19 +122,18 @@ console.log('\\nFor more information: https://github.com/hanzoai/extension');
|
||||
|
||||
archive.append(installScript, { name: 'install.js', mode: 0o755 });
|
||||
|
||||
// Add icon if it exists
|
||||
const iconPath = path.join(dxtDir, 'icon.png');
|
||||
// Add icon
|
||||
console.log('Adding icon...');
|
||||
const iconPath = path.join(__dirname, '..', 'images', 'icon.png');
|
||||
if (fs.existsSync(iconPath)) {
|
||||
console.log('Adding icon...');
|
||||
archive.file(iconPath, { name: 'icon.png' });
|
||||
} else {
|
||||
// Create a simple icon if none exists
|
||||
console.log('Creating default icon...');
|
||||
const defaultIcon = Buffer.from(
|
||||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
|
||||
'base64'
|
||||
);
|
||||
archive.append(defaultIcon, { name: 'icon.png' });
|
||||
console.error('Warning: icon.png not found at', iconPath);
|
||||
// Fallback to DXT directory icon if available
|
||||
const dxtIconPath = path.join(dxtDir, 'icon.png');
|
||||
if (fs.existsSync(dxtIconPath)) {
|
||||
archive.file(dxtIconPath, { name: 'icon.png' });
|
||||
}
|
||||
}
|
||||
|
||||
// Add README
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('Building @hanzo/mcp npm package...\n');
|
||||
|
||||
// Ensure dist directory exists
|
||||
if (!fs.existsSync('dist')) {
|
||||
fs.mkdirSync('dist');
|
||||
}
|
||||
|
||||
const npmDir = path.join('dist', 'npm');
|
||||
if (!fs.existsSync(npmDir)) {
|
||||
fs.mkdirSync(npmDir, { recursive: true });
|
||||
}
|
||||
|
||||
// First build the MCP server
|
||||
console.log('Building MCP server...');
|
||||
execSync('npm run build:mcp', { stdio: 'inherit' });
|
||||
|
||||
// Copy server file
|
||||
console.log('Copying server files...');
|
||||
fs.copyFileSync('dist/mcp-server.js', path.join(npmDir, 'server.js'));
|
||||
|
||||
// Create package.json for npm
|
||||
const packageJson = {
|
||||
name: '@hanzo/mcp',
|
||||
version: require('../package.json').version,
|
||||
description: 'Hanzo AI MCP server - powerful development tools for Claude Desktop and Claude Code',
|
||||
main: 'server.js',
|
||||
bin: {
|
||||
'hanzo-mcp': './cli.js'
|
||||
},
|
||||
scripts: {
|
||||
start: 'node server.js'
|
||||
},
|
||||
keywords: [
|
||||
'mcp',
|
||||
'model-context-protocol',
|
||||
'claude',
|
||||
'claude-desktop',
|
||||
'claude-code',
|
||||
'ai',
|
||||
'development-tools',
|
||||
'hanzo'
|
||||
],
|
||||
author: 'Hanzo Industries Inc',
|
||||
license: 'MIT',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'git+https://github.com/hanzoai/extension.git'
|
||||
},
|
||||
homepage: 'https://github.com/hanzoai/extension#readme',
|
||||
bugs: {
|
||||
url: 'https://github.com/hanzoai/extension/issues'
|
||||
},
|
||||
engines: {
|
||||
node: '>=16.0.0'
|
||||
},
|
||||
files: [
|
||||
'server.js',
|
||||
'cli.js',
|
||||
'README.md'
|
||||
],
|
||||
publishConfig: {
|
||||
access: 'public',
|
||||
registry: 'https://registry.npmjs.org/'
|
||||
}
|
||||
};
|
||||
|
||||
// Create CLI wrapper
|
||||
const cliScript = `#!/usr/bin/env node
|
||||
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0];
|
||||
|
||||
if (command === 'install' || (!command && !args.includes('--help')) || args.includes('--claude-code')) {
|
||||
console.log('\\n📦 Installing Hanzo MCP...\\n');
|
||||
|
||||
// Detect Claude Desktop config location
|
||||
let configPath;
|
||||
if (process.platform === 'darwin') {
|
||||
configPath = path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
||||
} else if (process.platform === 'win32') {
|
||||
configPath = path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json');
|
||||
} else {
|
||||
configPath = path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
||||
}
|
||||
|
||||
// Check if running in Claude Code (no config needed)
|
||||
if (process.env.CLAUDE_CODE || args.includes('--claude-code')) {
|
||||
console.log('✅ Hanzo MCP is ready for Claude Code!');
|
||||
console.log('\\nTo use in Claude Code:');
|
||||
console.log('1. The MCP server is available at:', path.join(__dirname, 'server.js'));
|
||||
console.log('2. Tools will be automatically available in your conversations');
|
||||
return;
|
||||
}
|
||||
|
||||
// For Claude Desktop, update config
|
||||
console.log('Configuring for Claude Desktop...');
|
||||
console.log('Config location:', configPath);
|
||||
|
||||
try {
|
||||
// Ensure directory exists
|
||||
const configDir = path.dirname(configPath);
|
||||
if (!fs.existsSync(configDir)) {
|
||||
fs.mkdirSync(configDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Read existing config or create new
|
||||
let config = {};
|
||||
if (fs.existsSync(configPath)) {
|
||||
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
}
|
||||
|
||||
// Ensure mcpServers exists
|
||||
if (!config.mcpServers) {
|
||||
config.mcpServers = {};
|
||||
}
|
||||
|
||||
// Add Hanzo MCP
|
||||
config.mcpServers['hanzo-mcp'] = {
|
||||
command: 'node',
|
||||
args: [path.join(__dirname, 'server.js')],
|
||||
env: {}
|
||||
};
|
||||
|
||||
// Write config
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
|
||||
console.log('\\n✅ Hanzo MCP installed successfully!');
|
||||
console.log('\\n🔄 Please restart Claude Desktop to use the new tools.');
|
||||
console.log('\\n📚 Available tools:');
|
||||
console.log(' - File operations (read, write, edit)');
|
||||
console.log(' - Search (grep, git_search, symbols)');
|
||||
console.log(' - Shell commands (bash, processes)');
|
||||
console.log(' - AI tools (llm, consensus, mode)');
|
||||
console.log(' - And many more!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\\n❌ Installation failed:', error.message);
|
||||
console.error('\\nManual installation:');
|
||||
console.error('1. Add to your Claude Desktop config:');
|
||||
console.error(JSON.stringify({
|
||||
mcpServers: {
|
||||
'hanzo-mcp': {
|
||||
command: 'node',
|
||||
args: [path.join(__dirname, 'server.js')]
|
||||
}
|
||||
}
|
||||
}, null, 2));
|
||||
}
|
||||
|
||||
} else if (command === 'start') {
|
||||
// Start the MCP server directly
|
||||
const server = spawn('node', [path.join(__dirname, 'server.js')], {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
console.error('Failed to start server:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
} else {
|
||||
console.log('Hanzo MCP - Model Context Protocol Server');
|
||||
console.log('');
|
||||
console.log('Usage:');
|
||||
console.log(' npx @hanzo/mcp Install and configure');
|
||||
console.log(' npx @hanzo/mcp install Install and configure');
|
||||
console.log(' npx @hanzo/mcp start Start the MCP server');
|
||||
console.log('');
|
||||
console.log('Options:');
|
||||
console.log(' --claude-code Configure for Claude Code');
|
||||
}
|
||||
`;
|
||||
|
||||
// Create README
|
||||
const readme = `# @hanzo/mcp
|
||||
|
||||
Hanzo AI MCP (Model Context Protocol) server - powerful development tools for Claude Desktop and Claude Code.
|
||||
|
||||
## Quick Install
|
||||
|
||||
\`\`\`bash
|
||||
npx @hanzo/mcp@latest
|
||||
\`\`\`
|
||||
|
||||
This will automatically configure the MCP server for your environment.
|
||||
|
||||
## Manual Installation
|
||||
|
||||
### Claude Desktop
|
||||
|
||||
Add to your \`claude_desktop_config.json\`:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"mcpServers": {
|
||||
"hanzo-mcp": {
|
||||
"command": "npx",
|
||||
"args": ["@hanzo/mcp@latest", "start"]
|
||||
}
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### Claude Code
|
||||
|
||||
For Claude Code, install the DXT extension or run:
|
||||
|
||||
\`\`\`bash
|
||||
npx @hanzo/mcp@latest --claude-code
|
||||
\`\`\`
|
||||
|
||||
## Available Tools
|
||||
|
||||
- **File Operations**: read, write, edit, multi_edit, directory_tree
|
||||
- **Search**: grep, git_search, find_files, symbols
|
||||
- **Shell**: bash, run_command, processes, open
|
||||
- **AI Tools**: llm, consensus, agent, mode
|
||||
- **Development**: todo, critic, think, rules
|
||||
- **Web**: web_fetch, batch_search
|
||||
- **And many more!**
|
||||
|
||||
## Documentation
|
||||
|
||||
See [https://github.com/hanzoai/extension](https://github.com/hanzoai/extension) for full documentation.
|
||||
`;
|
||||
|
||||
// Write files
|
||||
console.log('Creating npm package files...');
|
||||
fs.writeFileSync(path.join(npmDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
||||
fs.writeFileSync(path.join(npmDir, 'cli.js'), cliScript);
|
||||
fs.chmodSync(path.join(npmDir, 'cli.js'), '755');
|
||||
fs.writeFileSync(path.join(npmDir, 'README.md'), readme);
|
||||
|
||||
console.log(`\n✅ NPM package created at: ${npmDir}`);
|
||||
console.log('\nTo publish:');
|
||||
console.log(` cd ${npmDir}`);
|
||||
console.log(' npm publish\n');
|
||||
console.log('Users can then install with:');
|
||||
console.log(' npx @hanzo/mcp@latest');
|
||||
@@ -0,0 +1,57 @@
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('🏄 Building Hanzo MCP for Windsurf IDE...\n');
|
||||
|
||||
// Windsurf uses the same VSIX format as VS Code
|
||||
// We'll build a standard VSIX that Windsurf can install
|
||||
|
||||
const distDir = path.join(__dirname, '..', 'dist', 'windsurf');
|
||||
|
||||
// Ensure dist directory exists
|
||||
if (!fs.existsSync(distDir)) {
|
||||
fs.mkdirSync(distDir, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
// First compile the TypeScript
|
||||
console.log('📦 Compiling TypeScript...');
|
||||
execSync('node scripts/compile-main.js', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Build MCP components
|
||||
console.log('🔧 Building MCP components...');
|
||||
execSync('npm run build:mcp', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Package the extension
|
||||
console.log('📦 Packaging Windsurf extension...');
|
||||
execSync('vsce package --no-dependencies --out dist/windsurf/', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||
|
||||
// Read package.json to get version
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||
const version = packageJson.version;
|
||||
|
||||
// Rename the output file to include windsurf in the name
|
||||
const vsixFiles = fs.readdirSync(distDir).filter(f => f.endsWith('.vsix'));
|
||||
if (vsixFiles.length > 0) {
|
||||
const oldPath = path.join(distDir, vsixFiles[0]);
|
||||
const newPath = path.join(distDir, `hanzoai-windsurf-${version}.vsix`);
|
||||
fs.renameSync(oldPath, newPath);
|
||||
|
||||
console.log(`\n✅ Successfully built Windsurf extension: ${newPath}`);
|
||||
console.log(`📦 File size: ${(fs.statSync(newPath).size / 1024 / 1024).toFixed(2)} MB`);
|
||||
console.log('\n📥 To install in Windsurf:');
|
||||
console.log(' 1. Open Windsurf');
|
||||
console.log(' 2. Press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows/Linux)');
|
||||
console.log(' 3. Run "Extensions: Install from VSIX..."');
|
||||
console.log(` 4. Select ${newPath}`);
|
||||
console.log('\n💡 Windsurf integration includes:');
|
||||
console.log(' - Full MCP tools access via @hanzo chat participant');
|
||||
console.log(' - Access to 200+ LLMs through Hanzo AI');
|
||||
console.log(' - 4000+ MCP servers integration');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Build failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user