From 40d8709d6eaff55691e413aa9fcf90ff01a939cc Mon Sep 17 00:00:00 2001 From: Hanzo Dev Date: Fri, 4 Jul 2025 22:04:15 -0400 Subject: [PATCH] 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 --- CHAT_PARTICIPANT.md | 115 ++ HANZO_AI.md | 304 ++++++ HANZO_MODES.md | 318 ++++++ PROGRAMMER_MODES.md | 139 +++ README.md | 156 +-- TOOLS_BREAKDOWN.md | 215 ++++ images/icon.png | Bin 9309 -> 13376 bytes out/extension.js | 12 + package-lock.json | 1568 ++++++++++++++++++++++++++-- package.json | 70 +- pnpm-workspace.yaml | 2 + scripts/build-all-platforms.js | 56 +- scripts/build-cursor.js | 53 + scripts/build-dxt.js | 23 +- scripts/build-mcp-npm.js | 248 +++++ scripts/build-windsurf.js | 57 + src/chat/hanzo-chat-participant.ts | 461 ++++++++ src/extension.ts | 12 + src/mcp/tools/agent.ts | 559 +++++++++- src/mcp/tools/bash.ts | 4 +- src/mcp/tools/browser.ts | 317 ++++++ src/mcp/tools/index.ts | 10 +- src/mcp/tools/mode.ts | 317 +++++- 23 files changed, 4768 insertions(+), 248 deletions(-) create mode 100644 CHAT_PARTICIPANT.md create mode 100644 HANZO_AI.md create mode 100644 HANZO_MODES.md create mode 100644 PROGRAMMER_MODES.md create mode 100644 TOOLS_BREAKDOWN.md create mode 100644 pnpm-workspace.yaml create mode 100644 scripts/build-cursor.js create mode 100644 scripts/build-mcp-npm.js create mode 100644 scripts/build-windsurf.js create mode 100644 src/chat/hanzo-chat-participant.ts create mode 100644 src/mcp/tools/browser.ts diff --git a/CHAT_PARTICIPANT.md b/CHAT_PARTICIPANT.md new file mode 100644 index 0000000..580c5a4 --- /dev/null +++ b/CHAT_PARTICIPANT.md @@ -0,0 +1,115 @@ +# VS Code Chat Participant Integration + +The Hanzo extension now includes full VS Code Chat Participant integration, making all 53+ MCP tools available through VS Code's chat interface. + +## Features + +### 1. Chat Participant Registration +- Registered as `@hanzo` (lowercase) in VS Code's chat interface +- Accessible via Ctrl+Alt+I (Cmd+Alt+I on Mac) +- Shows up with the Hanzo icon + +### 2. LLM Integration +The chat participant supports multiple LLM providers: + +- **Hanzo AI Gateway** (default): Uses api.hanzo.ai +- **LM Studio**: Local models via http://localhost:1234 +- **Ollama**: Local models via http://localhost:11434 +- **OpenAI**: Direct OpenAI API integration +- **Anthropic**: Direct Claude API integration + +### 3. Tool Access +All MCP tools are available through natural language or direct commands: + +**File Operations:** +- `@hanzo read src/index.ts` +- `@hanzo write config.json content: { "key": "value" }` +- `@hanzo edit file.ts replace "old" with "new"` + +**Search Operations:** +- `@hanzo search "TODO"` +- `@hanzo grep "function" in **/*.ts` + +**Shell Operations:** +- `@hanzo run npm test` +- `@hanzo bash git status` + +**AI Operations:** +- `@hanzo agent analyze this codebase for security issues` +- `@hanzo dispatch_agent implement new feature X` + +### 4. Configuration + +Add to VS Code settings.json: + +```json +{ + // Choose LLM provider + "hanzo.llm.provider": "hanzo", // or "lmstudio", "ollama", "openai", "anthropic" + + // Hanzo AI Gateway (default) + "hanzo.llm.hanzo.apiKey": "your-api-key", + + // LM Studio (local) + "hanzo.llm.lmstudio.endpoint": "http://localhost:1234/v1", + "hanzo.llm.lmstudio.model": "model-name", + + // Ollama (local) + "hanzo.llm.ollama.endpoint": "http://localhost:11434", + "hanzo.llm.ollama.model": "llama2", + + // OpenAI + "hanzo.llm.openai.apiKey": "sk-...", + "hanzo.llm.openai.model": "gpt-4", + + // Anthropic + "hanzo.llm.anthropic.apiKey": "sk-ant-...", + "hanzo.llm.anthropic.model": "claude-3-opus-20240229" +} +``` + +### 5. Agent Tool + +The `agent` and `dispatch_agent` tools now support all configured LLM providers: + +```typescript +// Single agent +@hanzo agent analyze the security of this codebase + +// Multi-agent dispatch +@hanzo dispatch_agent implement user authentication with JWT +``` + +The agent tool will: +- Use the configured LLM provider +- Have access to specified MCP tools +- Execute tasks with proper context +- Support both sequential and parallel execution + +### 6. Privacy with Local LLMs + +For complete privacy, use LM Studio or Ollama: + +1. **LM Studio**: Download from lmstudio.ai, load a model, start the server +2. **Ollama**: Install via `brew install ollama`, run `ollama pull llama2` + +Then set `"hanzo.llm.provider": "lmstudio"` or `"ollama"` in settings. + +## Installation + +1. Install the VSIX: `code --install-extension dist/hanzoai-1.5.4.vsix` +2. Configure your preferred LLM provider in settings +3. Open VS Code chat (Ctrl+Alt+I) +4. Type `@hanzo` to start using the assistant + +## Usage Examples + +``` +@hanzo show available tools +@hanzo read package.json +@hanzo search for TODO comments +@hanzo run the tests +@hanzo agent refactor this function to be more efficient +``` + +The assistant will use the configured LLM to understand your intent and execute the appropriate tools. \ No newline at end of file diff --git a/HANZO_AI.md b/HANZO_AI.md new file mode 100644 index 0000000..52d14b2 --- /dev/null +++ b/HANZO_AI.md @@ -0,0 +1,304 @@ +# Hanzo AI: The Ultimate Toolkit for AI Engineers + +Hanzo AI is the ultimate toolkit for AI engineers, providing unified access to every AI model and tool you need. With support for 200+ LLMs from OpenRouter and LiteLLM compatibility, plus 4000+ MCP servers, Hanzo AI supercharges your development workflow with shared context, intelligent search, and seamless model switching. + +## Getting Started with Hanzo AI + +1. **Create Account**: Visit [iam.hanzo.ai](https://iam.hanzo.ai) to create your account +2. **Get API Key**: After login, obtain your personal API key +3. **Add Credits**: Ensure you have credits in your account +4. **Configure**: Set `HANZO_API_KEY` environment variable or VS Code setting + +## Why Hanzo AI is the Ultimate AI Engineering Toolkit + +### 🚀 Complete Model Coverage +- **OpenRouter Compatible**: Access every model available on OpenRouter +- **LiteLLM Compatible**: Full compatibility with LiteLLM's model catalog +- **200+ Models**: From O3-Pro and Claude 4 to DeepSeek V3 and Llama 3.1 405B +- **Latest Models**: Always up-to-date with the newest releases + +### 🔧 Engineering-First Features +- **Unified API**: Single endpoint for all AI providers - no more juggling API keys +- **Smart Routing**: Automatic failover and load balancing across providers +- **Shared Context**: Maintain conversation context across model switches +- **4000+ MCP Servers**: Access specialized tools for every use case +- **Performance Monitoring**: Track latency, costs, and usage patterns +- **Team Collaboration**: Share API keys, context, and credits with your team + +### 💡 Developer Experience +- **Zero Config**: Works out of the box with sensible defaults +- **Local Model Support**: Seamlessly integrate LM Studio and Ollama +- **VS Code Native**: Deep integration with @hanzo chat participant +- **Intelligent Caching**: Reduce costs with smart response caching +- **Error Handling**: Automatic retries and graceful degradation + +## Priority Order + +The Hanzo agent automatically detects and uses available LLM providers in this order: + +1. **Environment Variables** (Highest Priority) + - Direct API calls to providers when keys are detected locally + - Maximum performance with minimal latency + +2. **Local LLMs** (Medium-High Priority) + - LM Studio: `LM_STUDIO_BASE_URL` + - Ollama: `OLLAMA_BASE_URL` + +3. **VS Code Settings** (Medium Priority) + - `hanzo.llm.{provider}.apiKey` settings + +4. **Hanzo AI** (Default) + - Supercharges your AI development with unified access + - Access to all models with credits + - Managed API keys in Hanzo Cloud + +## Complete Model Catalog (OpenRouter + LiteLLM Compatible) + +Hanzo AI provides access to every model available through OpenRouter and LiteLLM, including: + +- **OpenAI**: O3-Pro, O3, GPT-4o, GPT-4 Turbo, GPT-4, GPT-3.5 Turbo +- **Anthropic**: Claude 4, Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Sonnet, Claude 3 Haiku +- **Google**: Gemini 2.0 Flash, Gemini Pro, Gemini Pro Vision, Gemini Ultra +- **Meta**: Llama 3.1 405B, Llama 3.1 70B, Llama 3 70B, CodeLlama +- **Mistral**: Large 2, Medium, Small, Mixtral 8x22B, Mixtral 8x7B +- **Cohere**: Command R Plus, Command R, Command +- **DeepSeek**: DeepSeek V3, DeepSeek Coder V2 +- **Together AI**: Mixtral MOE, Llama variants, CodeLlama +- **Replicate**: Open source models +- **And 190+ more models...** + +### Direct API Support (with local env keys) +```bash +# OpenAI +export OPENAI_API_KEY=sk-... + +# Anthropic +export ANTHROPIC_API_KEY=sk-ant-... + +# Google/Gemini +export GOOGLE_API_KEY=... +# or +export GEMINI_API_KEY=... + +# Mistral +export MISTRAL_API_KEY=... + +# Cohere +export COHERE_API_KEY=... + +# Together AI +export TOGETHER_API_KEY=... + +# Replicate +export REPLICATE_API_KEY=... +``` + +### Hanzo AI (Recommended) +```bash +# Get your API key from iam.hanzo.ai +export HANZO_API_KEY=hzo_... + +# Optional: Custom endpoint (defaults to https://api.hanzo.ai/ext/v1) +export HANZO_API_URL=https://api.hanzo.ai/ext/v1 +``` + +### Local LLMs +```bash +# LM Studio +export LM_STUDIO_BASE_URL=http://localhost:1234/v1 + +# Ollama +export OLLAMA_BASE_URL=http://localhost:11434 +``` + +## Usage Examples + +### Using Hanzo AI +```bash +# Automatically uses Hanzo AI when HANZO_API_KEY is set +@hanzo agent analyze this codebase + +# Access any of 200+ models through Hanzo AI +@hanzo agent --model o3-pro solve complex algorithm +@hanzo agent --model claude-4 analyze architecture +@hanzo agent --model gpt-4o write tests +@hanzo agent --model claude-3.5-sonnet review code +@hanzo agent --model gemini-2.0-flash explain this code +@hanzo agent --model llama-3.1-405b optimize performance +@hanzo agent --model deepseek-v3 debug issue +@hanzo agent --model mixtral-8x22b generate documentation +``` + +### Direct API Usage (when local keys available) +```bash +# If OPENAI_API_KEY is set, bypasses Hanzo AI for direct access +@hanzo agent --model gpt-4o task + +# Force specific provider with prefix +@hanzo agent --model openai/o3-pro task +@hanzo agent --model anthropic/claude-4 task +@hanzo agent --model google/gemini-2.0-flash task +``` + +### Model Selection +```bash +# Let Hanzo AI choose the best model +@hanzo agent optimize this function + +# Specify exact model from 200+ available +@hanzo agent --model o3-pro solve complex problem +@hanzo agent --model claude-4 review architecture +@hanzo agent --model gpt-4o analyze performance +@hanzo agent --model gemini-2.0-flash quick analysis +@hanzo agent --model llama-3.1-405b deep reasoning +@hanzo agent --model deepseek-v3 code optimization +@hanzo agent --model command-r-plus generate documentation +``` + +## Why AI Engineers Choose Hanzo AI + +### 🎯 **The Complete Toolkit** +- **Every Model**: OpenRouter + LiteLLM = access to every AI model +- **Every Tool**: 4000+ MCP servers for specialized capabilities +- **Every Provider**: OpenAI, Anthropic, Google, Meta, Mistral, and 50+ more + +### ⚡ **Built for Performance** +- **Smart Caching**: Reduce redundant API calls +- **Automatic Failover**: Never get blocked by rate limits +- **Load Balancing**: Distribute requests across providers +- **Low Latency**: Optimized routing to nearest endpoints + +### 💰 **Cost Optimization** +- **Unified Billing**: One invoice for all AI usage +- **Smart Routing**: Use cheaper models for simple tasks +- **Usage Analytics**: Identify and eliminate waste +- **Team Budgets**: Set limits and track spending + +### 🔒 **Enterprise Ready** +- **SOC2 Compliant**: Enterprise-grade security +- **API Key Vault**: Encrypted storage for provider keys +- **Audit Logs**: Complete usage history +- **Team Management**: Role-based access control + +## Configuration Priority + +1. **Model argument**: `--model gpt-4` (highest) +2. **Environment variables**: Direct provider keys +3. **VS Code settings**: Provider configurations +4. **Hanzo AI**: Default with HANZO_API_KEY + +## Provider Status Display + +The agent shows which provider is being used: +``` +## Task Completed +**LLM Provider**: hanzo (https://api.hanzo.ai/ext/v1) + +[Agent results...] +``` + +For direct API usage: +``` +## Task Completed +**LLM Provider**: openai + +[Agent results...] +``` + +## Hanzo Cloud Features + +When using Hanzo AI, you get: +- **200+ Models**: Access to all major AI providers and models +- **4000+ MCP Servers**: Specialized tools and integrations +- **Shared Context**: Maintain context across sessions and models +- **Intelligent Search**: Search across all interactions +- **Automatic Failover**: Switches providers if one fails +- **Rate Limiting**: Built-in protection against rate limits +- **Cost Tracking**: Monitor spending across all models +- **API Key Vault**: Securely store provider keys in cloud +- **Team Management**: Share credits, context, and access with your team +- **Usage Insights**: Detailed analytics and reporting + +## Getting Your Hanzo API Key + +1. Visit [iam.hanzo.ai](https://iam.hanzo.ai) +2. Sign up or log in to your account +3. Navigate to API Keys section +4. Generate a new API key +5. Add credits to your account +6. Set the key as `HANZO_API_KEY` environment variable + +## Managing Provider Keys in Hanzo Cloud + +Instead of managing multiple API keys locally, you can: +1. Log in to [iam.hanzo.ai](https://iam.hanzo.ai) +2. Go to "API Key Management" +3. Add your provider API keys (OpenAI, Anthropic, etc.) +4. Use Hanzo AI to access all providers with just your Hanzo key + +## Troubleshooting + +### No Credits Available +``` +Error: Insufficient credits in your Hanzo account +``` +**Solution**: Add credits at [iam.hanzo.ai](https://iam.hanzo.ai) + +### Invalid API Key +``` +Error: Invalid Hanzo API key +``` +**Solution**: Check your API key at [iam.hanzo.ai](https://iam.hanzo.ai) + +### Model Not Available +``` +Error: Model xyz not available through Hanzo AI +``` +**Solution**: Check supported models or contact support + +## Advanced Usage + +### Multi-Agent with Mixed Providers +```bash +# Some agents use Hanzo AI, others use direct APIs +@hanzo agent --agents '[ + {"name": "Architect", "role": "Design with Claude 4 via Hanzo"}, + {"name": "Analyst", "role": "Analyze with O3-Pro via Hanzo"}, + {"name": "Coder", "role": "Implement with GPT-4o"}, + {"name": "Reviewer", "role": "Review with DeepSeek V3"} +]' implement feature +``` + +### Credit Optimization +```bash +# Use cheaper models for simple tasks +@hanzo agent --model gpt-3.5-turbo quick task + +# Use powerful models for complex tasks +@hanzo agent --model o3-pro complex reasoning +@hanzo agent --model claude-4 deep analysis +@hanzo agent --model llama-3.1-405b advanced math + +# Use specialized models +@hanzo agent --model deepseek-v3 code generation +@hanzo agent --model command-r-plus technical writing +@hanzo agent --model gemini-2.0-flash rapid prototyping +``` + +## Security & Privacy + +- **Hanzo AI**: Secure API with encrypted transport +- **Local Keys**: Never sent to Hanzo when using direct APIs +- **Cloud Keys**: Encrypted storage in Hanzo Cloud +- **Audit Trail**: Track all API usage through Hanzo dashboard +- **Privacy Controls**: Configure data retention and privacy settings + +## Support + +- **Documentation**: [docs.hanzo.ai](https://docs.hanzo.ai) +- **Dashboard**: [iam.hanzo.ai](https://iam.hanzo.ai) +- **Support**: support@hanzo.ai + +**Hanzo AI is the unified platform for building AI-powered companies.** Access 200+ LLMs (OpenRouter/LiteLLM compatible), 4000+ MCP servers, legendary programmer modes, unlimited memory with vector/graph/relational search, browser automation, and everything you need to supercharge AI development. + +🚀 **[Get Started](https://iam.hanzo.ai)** | 📖 **[View Modes & Features](./HANZO_MODES.md)** | 💬 **[Join Discord](https://discord.gg/hanzoai)** \ No newline at end of file diff --git a/HANZO_MODES.md b/HANZO_MODES.md new file mode 100644 index 0000000..4edc789 --- /dev/null +++ b/HANZO_MODES.md @@ -0,0 +1,318 @@ +# Hanzo AI Modes: Unlock Unlimited Potential + +Hanzo AI is the unified platform for building AI-powered companies, offering legendary programmer modes, unlimited memory, expanded context, and advanced search capabilities across all your projects. + +## 🧠 Legendary Programmer Modes + +Unlock the expertise of computing legends with specialized modes that configure tools, workflows, and philosophies: + +### Pioneers & Legends +- **ritchie**: Dennis Ritchie - UNIX philosophy, systems programming +- **kernighan**: Brian Kernighan - Clear code, documentation mastery +- **thompson**: Ken Thompson - Elegant algorithms, minimal design +- **pike**: Rob Pike - Concurrency, simplicity, Go philosophy +- **stroustrup**: Bjarne Stroustrup - C++ design, object-oriented excellence + +### Language Masters +- **matz**: Yukihiro Matsumoto - Ruby creator, developer happiness +- **dhh**: David Heinemeier Hansson - Rails philosophy, convention over configuration +- **gosling**: James Gosling - Java creator, enterprise architecture +- **rich**: Rich Harris - Modern web, Svelte innovation +- **wirth**: Niklaus Wirth - Pascal creator, structured programming + +### AI & Machine Learning +- **bengio**: Yoshua Bengio - Deep learning pioneer +- **lecun**: Yann LeCun - Computer vision, CNN architecture +- **norvig**: Peter Norvig - AI algorithms, practical implementation +- **ng**: Andrew Ng - ML education, practical AI deployment + +### Systems & Infrastructure +- **carmack**: John Carmack - Game engines, performance optimization +- **torvalds**: Linus Torvalds - Linux kernel, distributed development +- **tanenbaum**: Andrew Tanenbaum - Operating systems, distributed computing +- **bernstein**: Daniel J. Bernstein - Security, cryptography, qmail + +### Web & Frontend Masters +- **resig**: John Resig - jQuery creator, JavaScript mastery +- **dahl**: Ryan Dahl - Node.js/Deno creator, async programming +- **eich**: Brendan Eich - JavaScript creator, language design +- **crockford**: Douglas Crockford - JavaScript: The Good Parts + +### Database & Data +- **gray**: Jim Gray - Transaction processing, database systems +- **hellerstein**: Joseph Hellerstein - Query optimization, data systems +- **stonebraker**: Michael Stonebraker - PostgreSQL, database architecture + +### Security & Cryptography +- **rivest**: Ron Rivest - RSA encryption, security algorithms +- **schneier**: Bruce Schneier - Applied cryptography, security thinking +- **bernstein**: Daniel J. Bernstein - qmail, djbdns, curve25519 + +### Full List of 45+ Modes +```bash +# Activate any mode +@hanzo mode carmack # Game engine optimization +@hanzo mode pike # Go concurrency patterns +@hanzo mode norvig # AI algorithm implementation +``` + +## 🚀 Unlimited Memory & Context + +### Vector + Graph + Relational Search +Hanzo AI combines multiple search paradigms for comprehensive code understanding: + +```bash +# Symbolic search across all projects +@hanzo search "class AuthProvider implements" + +# Relational queries +@hanzo search "functions that call validateUser()" + +# Graph-based navigation +@hanzo search "all dependencies of PaymentService" + +# Vector semantic search +@hanzo search "code similar to rate limiting logic" + +# Full-text search with regex +@hanzo search "/async.*fetch.*json/i" +``` + +### Expanded Context Window +- **Unlimited project memory**: Never lose context between sessions +- **Cross-project intelligence**: Learn from all your repositories +- **Persistent workspace state**: Resume exactly where you left off +- **Shared team knowledge**: Collaborate with shared context + +## 📊 Unified Dashboard + +Manage everything from one powerful interface: + +### Project Management +- **Multi-repo overview**: See all projects at a glance +- **Dependency tracking**: Visualize project relationships +- **Change monitoring**: Track modifications across repositories +- **Team collaboration**: Share context and insights + +### AI Model Management +- **200+ LLMs**: Access every model through one API +- **Usage analytics**: Track costs and performance +- **Smart routing**: Automatic model selection +- **Credit management**: Monitor and control spending + +### Deployment & DevOps +- **One-click deployment**: Deploy any open source app +- **Container management**: Docker and Kubernetes integration +- **CI/CD pipelines**: Automated testing and deployment +- **Monitoring**: Real-time performance tracking + +## 🛠️ IDE Integration via MCP + +### Terminal Integration +```bash +# Configure for iTerm2 +@hanzo configure --ide iterm2 + +# Native async support +@hanzo terminal --async execute "npm test" +``` + +### Neovim/Vim Integration +```vim +" Add to your init.vim +Plug 'hanzoai/vim-mcp' + +" Use Hanzo AI in vim +:Hanzo analyze current function +:Hanzo refactor selection +:Hanzo explain +``` + +### Browser Control +```bash +# Enable browser automation +@hanzo browser enable + +# Launches Chrome with Playwright +@hanzo browser navigate "https://docs.hanzo.ai" +@hanzo browser screenshot +@hanzo browser extract "CSS selector" +``` + +The browser tool automatically: +- Installs Playwright MCP server +- Manages Chrome/Chromium instances +- Provides high-level browser control +- Enables web scraping and testing + +## 💎 Premium Features + +### Supercharge Your AI Development +Subscribe to unlock: + +- **Priority access**: Latest models (O3-Pro, Claude 4, GPT-4o) +- **Higher limits**: 10x more requests per minute +- **Team features**: Shared credits and context +- **Advanced search**: Graph-based code intelligence +- **Custom models**: Fine-tuned models for your codebase +- **Dedicated support**: Direct access to Hanzo team + +### Pricing Tiers +- **Starter**: $19/month - 100K credits +- **Pro**: $99/month - 1M credits + team features +- **Enterprise**: Custom - Unlimited usage + SLA + +## 🏗️ Building AI-Powered Companies + +Hanzo AI provides the complete toolkit for AI-driven development: + +### Integrated Development +```bash +# Create new AI project +@hanzo create ai-startup --template saas + +# Add AI capabilities +@hanzo add llm-integration +@hanzo add vector-search +@hanzo add agent-framework + +# Deploy instantly +@hanzo deploy --platform vercel +``` + +### Pre-built Templates +- **SaaS Starter**: Multi-tenant AI application +- **Agent Platform**: Multi-agent orchestration +- **API Gateway**: LLM proxy with auth +- **Chat Interface**: Production chat UI +- **Analytics Dashboard**: Usage tracking + +### Enterprise Features +- **SSO Integration**: SAML, OAuth, LDAP +- **Compliance**: SOC2, HIPAA ready +- **White-labeling**: Custom branding +- **Private deployment**: On-premise options + +## 🔧 Configuration + +### .hanzo/config.yaml +```yaml +# IDE Configuration +ide: + primary: vscode + terminal: iterm2 + editor: neovim + +# MCP Servers +mcp: + browser: + enabled: true + defaultBrowser: chrome + headless: false + + search: + providers: + - vector + - graph + - relational + - fulltext + + memory: + unlimited: true + persistence: cloud + +# AI Configuration +ai: + defaultModel: claude-4 + fallbackModels: + - gpt-4o + - gemini-2.0-flash + + routing: + simple: gpt-3.5-turbo + complex: o3-pro + creative: claude-4 + analytical: deepseek-v3 + +# Team Settings +team: + sharedContext: true + creditPool: true + knowledgeBase: true +``` + +## 🎯 Getting Started + +1. **Install Extension** + ```bash + # VS Code/Cursor/Windsurf + Install hanzoai-*.vsix + + # Claude Code + Drag hanzoai-*.dxt + + # Terminal/Neovim + npx @hanzo/mcp@latest + ``` + +2. **Configure Environment** + ```bash + # Set up Hanzo AI + export HANZO_API_KEY=hzo_... + + # Configure IDE + @hanzo configure --ide vscode + + # Enable browser control + @hanzo browser enable + ``` + +3. **Choose Your Mode** + ```bash + # Activate a legendary programmer mode + @hanzo mode carmack # Performance optimization + @hanzo mode norvig # AI implementation + @hanzo mode pike # Clean, concurrent code + ``` + +4. **Start Building** + ```bash + # Create AI-powered app + @hanzo create my-ai-startup + + # Use unlimited memory + @hanzo remember "Project uses NextJS 14 with App Router" + + # Search across everything + @hanzo search "authentication flow" + ``` + +## 🌟 Why Hanzo AI? + +**For Individual Developers** +- Access 200+ AI models with one API key +- Legendary programmer modes for expert guidance +- Unlimited memory and context +- Advanced search across all projects + +**For Teams** +- Shared context and knowledge base +- Unified billing and credit management +- Collaborative AI development +- Enterprise security and compliance + +**For Companies** +- Complete platform for AI-powered products +- Pre-built templates and frameworks +- Instant deployment and scaling +- White-label and customization options + +--- + +**Ready to supercharge your AI development?** + +🚀 [Sign up at iam.hanzo.ai](https://iam.hanzo.ai) to get started + +💬 Join our community: [discord.gg/hanzoai](https://discord.gg/hanzoai) + +📚 Documentation: [docs.hanzo.ai](https://docs.hanzo.ai) \ No newline at end of file diff --git a/PROGRAMMER_MODES.md b/PROGRAMMER_MODES.md new file mode 100644 index 0000000..a98c1df --- /dev/null +++ b/PROGRAMMER_MODES.md @@ -0,0 +1,139 @@ +# Legendary Programmer Modes + +The Hanzo extension includes 45+ development modes inspired by legendary programmers and their philosophies. Each mode configures tools and settings to match their development style. + +## Usage + +``` +@hanzo mode list # List all available modes +@hanzo mode activate guido # Activate Python creator mode +@hanzo mode show ritchie # Show details about C creator mode +@hanzo mode current # Show current active mode +``` + +## Language Creators (19 modes) + +### System Languages +- **ritchie** - Dennis Ritchie (C) - *"UNIX: Do one thing and do it well"* +- **bjarne** - Bjarne Stroustrup (C++) - *"C++: Light-weight abstraction"* +- **gosling** - James Gosling (Java) - *"Java: Platform independence"* +- **graydon** - Graydon Hoare (Rust) - *"Fast, reliable, productive — pick three"* +- **pike_thompson** - Rob Pike & Ken Thompson (Go) - *"Less is exponentially more"* + +### Dynamic Languages +- **guido** - Guido van Rossum (Python) - *"There should be one-- and preferably only one --obvious way to do it"* +- **matz** - Yukihiro Matsumoto (Ruby) - *"Ruby is designed to make programmers happy"* +- **wall** - Larry Wall (Perl) - *"There's More Than One Way To Do It"* +- **rasmus** - Rasmus Lerdorf (PHP) - *"PHP: Solving web problems pragmatically"* +- **brendan** - Brendan Eich (JavaScript) - *"Always bet on JavaScript"* + +### Functional Languages +- **mccarthy** - John McCarthy (Lisp) - *"Lisp: The programmable programming language"* +- **hickey** - Rich Hickey (Clojure) - *"Simple Made Easy"* +- **armstrong** - Joe Armstrong (Erlang) - *"Let it crash and recover"* +- **odersky** - Martin Odersky (Scala) - *"Fusion of functional and object-oriented programming"* + +### Modern Languages +- **anders** - Anders Hejlsberg (C#/TypeScript) - *"Pragmatism over dogmatism"* +- **lattner** - Chris Lattner (Swift/LLVM) - *"Performance and safety without compromise"* +- **bak** - Lars Bak (Dart/V8) - *"Fast development and execution"* + +### Classic Languages +- **wirth** - Niklaus Wirth (Pascal) - *"Algorithms + Data Structures = Programs"* +- **backus** - John Backus (Fortran) - *"Formula Translation for scientists"* +- **hopper** - Grace Hopper (COBOL) - *"Programming for everyone"* +- **kay** - Alan Kay (Smalltalk) - *"The best way to predict the future is to invent it"* + +## Systems & Infrastructure (2 modes) + +- **linus** - Linus Torvalds (Linux) - *"Talk is cheap. Show me the code."* +- **ritchie_thompson** - Ritchie & Thompson (UNIX) - *"Keep it simple, stupid"* + +## Web Frameworks (7 modes) + +### Backend Frameworks +- **dhh** - David Heinemeier Hansson (Rails) - *"Optimize for programmer happiness"* +- **holovaty_willison** - Holovaty & Willison (Django) - *"The web framework for perfectionists with deadlines"* +- **ronacher** - Armin Ronacher (Flask) - *"Web development, one drop at a time"* +- **otwell** - Taylor Otwell (Laravel) - *"The PHP framework for web artisans"* +- **holowaychuk** - TJ Holowaychuk (Express.js) - *"Fast, unopinionated, minimalist"* + +### Frontend Frameworks +- **evan** - Evan You (Vue.js) - *"Approachable, versatile, performant"* +- **walke** - Jordan Walke (React) - *"UI as a function of state"* + +## JavaScript Ecosystem (3 modes) + +- **katz** - Yehuda Katz (Ember.js) - *"Convention over Configuration"* +- **ashkenas** - Jeremy Ashkenas (CoffeeScript) - *"It's just JavaScript"* +- **nolen** - David Nolen (ClojureScript) - *"Functional programming for the web"* + +## Database & Infrastructure (1 mode) + +- **widenius** - Michael Widenius (MySQL/MariaDB) - *"Open source database for everyone"* + +## CSS & Design (2 modes) + +- **wathan** - Adam Wathan (Tailwind CSS) - *"Stop writing CSS, start building designs"* +- **otto_thornton** - Otto & Thornton (Bootstrap) - *"Build responsive, mobile-first projects"* + +## Special Configurations (6 modes) + +- **fullstack** - Full Stack Developer - Frontend to backend, databases to deployment +- **minimal** - Minimalist - Less is more, only essential tools +- **10x** - 10x Engineer - Maximum productivity, all tools enabled +- **security** - Security Engineer - Security first, paranoid by design +- **data_scientist** - Data Scientist - Data analysis and ML focused +- **hanzo** - Hanzo AI - Optimal configuration with all advanced features + +## Mode Features + +Each mode configures: + +1. **Tools**: Specific set of enabled tools matching the programmer's workflow +2. **Philosophy**: The guiding principle of that programmer/language +3. **Config Scores**: Personality traits scored 0-10 (e.g., simplicity, performance, readability) + +## Examples + +### Python Development (Guido mode) +``` +@hanzo mode activate guido +# Enables: read, write, edit, grep, symbols, uvx, think, notebook_read, notebook_edit +# Philosophy: "There should be one-- and preferably only one --obvious way to do it" +# Config: readability: 10, simplicity: 9, explicitness: 10 +``` + +### Systems Programming (Linus mode) +``` +@hanzo mode activate linus +# Enables: read, write, edit, grep, git_search, bash, processes, critic +# Philosophy: "Talk is cheap. Show me the code." +# Config: performance: 10, directness: 10, patience: 2 +``` + +### Web Development (DHH mode) +``` +@hanzo mode activate dhh +# Enables: read, write, edit, multi_edit, grep, bash, run_command, sql_query +# Philosophy: "Optimize for programmer happiness" +# Config: productivity: 10, conventions: 10, opinionated: 10 +``` + +### Maximum Productivity (10x mode) +``` +@hanzo mode activate 10x +# Enables: ALL advanced tools including agent, llm, consensus, think, critic +# Config: productivity: 10, tool_mastery: 10, work_life_balance: 3 +``` + +## Mode Selection Guide + +- **Learning a language**: Choose its creator's mode (e.g., `guido` for Python) +- **Building web apps**: Choose framework creator (e.g., `dhh` for Rails, `evan` for Vue) +- **System programming**: Choose `ritchie`, `linus`, or `graydon` +- **Maximum features**: Choose `10x` or `hanzo` +- **Focused work**: Choose `minimal` +- **Security audit**: Choose `security` + +Each mode embodies the philosophy and approach of its namesake, helping you code in their style! \ No newline at end of file diff --git a/README.md b/README.md index aad0b12..82ee213 100644 --- a/README.md +++ b/README.md @@ -1,139 +1,55 @@ # Hanzo AI -Hanzo AI transforms your IDE into a full blown software engineering ninja. +The ultimate toolkit for AI engineers. -Hanzo seamlessly manages context, tracks changes, and organizes knowledge across your codebase through advanced AI capabilities including vector search, symbolic search, and extended "thinking" processes. +## What You Get -## Features +- **200+ LLMs** - Every model from OpenRouter/LiteLLM in one API +- **4000+ MCP Servers** - Access specialized tools instantly +- **45+ Legendary Modes** - Code like Carmack, think like Norvig +- **Unlimited Memory** - Vector/graph/relational search across all projects +- **Browser Automation** - Built-in Playwright for web tasks +- **Team Collaboration** - Shared context and credits -- **Intelligent Context Management**: Automatically maintains project context across sessions -- **Vector Search**: Find relevant code and documentation using semantic similarity -- **Symbolic Search**: Discover code elements through structure and relationships -- **Extended Thinking**: Leverage advanced reasoning for complex development tasks -- **MCP Server Integration**: Full Model Context Protocol implementation with 65+ tools -- **Claude Desktop Support**: Use all Hanzo tools directly in Claude Desktop -- **Multi-Platform**: Works with VS Code, Cursor, Windsurf, and Claude Desktop -- **Automatic Documentation**: Generate comprehensive documentation from existing code -- **Project Analysis**: Create detailed SPEC.md files through codebase analysis - -## Usage - -1. Open any project in VS Code -2. Run `Hanzo: Open Project Manager` from the command palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) -3. The project dashboard will appear showing your project overview -4. Enter additional project details if needed -5. Click "Analyze Project" to generate specifications - -The extension will: -- Analyze your codebase structure and dependencies -- Generate a comprehensive SPEC.md file -- Create/update .cursorrules with project context -- Build knowledge graphs for enhanced navigation - -## Advanced Features - -- **Knowledge Management**: Track changes and maintain history across your development lifecycle -- **Rules-Based Assistance**: Define custom rules for code generation and recommendations -- **Integration with LLMs**: Connect with various large language models for diverse capabilities -- **MCP Tools**: File operations, search, shell commands, Git integration, and more -- **Task Management**: Built-in todo system for tracking development tasks -- **Agent Delegation**: Dispatch complex tasks to specialized sub-agents - -## MCP (Model Context Protocol) Support - -Hanzo includes a complete MCP server implementation, providing powerful tools for AI assistants: - -### Quick Start with Claude Desktop +## Quick Start ```bash -# Build and install for Claude Desktop -npm run build:claude-desktop -./dist/claude-desktop/install.sh # Mac/Linux -# or -./dist/claude-desktop/install.bat # Windows +# VS Code / Cursor / Windsurf +Install hanzoai-*.vsix + +# Claude Code +Drag hanzoai-*.dxt + +# Terminal / Neovim +npx @hanzo/mcp@latest ``` -### Build Options +## Use It ```bash -# Development -npm run dev # Watch mode development build -npm run compile # One-time TypeScript compilation +# Get your API key +export HANZO_API_KEY=hzo_... # from iam.hanzo.ai -# Production builds -npm run build # Standard VS Code extension build -npm run build:claude-desktop # Claude Desktop MCP server build -npm run build:dxt # Desktop Extension (DXT) build -npm run build:all # Build all targets +# Talk to any model +@hanzo agent --model o3-pro solve this algorithm +@hanzo agent --model claude-4 review my code -# Testing -npm test # Run all tests -npm run test:unit # Unit tests only -npm run test:integration # Integration tests only +# Activate legendary modes +@hanzo mode carmack # Optimize like a game engine +@hanzo mode norvig # AI implementation mastery -# Packaging -npm run package # Create .vsix package -npm run package:dxt # Create .dxt package for Claude Code +# Control browsers +@hanzo browser navigate https://example.com +@hanzo browser screenshot + +# Search everything +@hanzo search "auth flow" ``` -### Available MCP Tools +## Links -- **File System**: read, write, edit, multi_edit, directory_tree, find_files, content_replace, diff, watch -- **Search**: grep, search, symbols, git_search, grep_ast, batch_search, unified_search -- **Shell**: run_command, bash, run_background, processes, pkill, logs, npx, uvx, open -- **Development**: todo (unified), think, critic, notebook support -- **AI/Agent**: dispatch_agent, llm, consensus, agent, mode (development personalities) -- **Utility**: batch (atomic operations), web_fetch, rules, config -- **MCP**: mcp (manage arbitrary MCP servers) +🚀 **[Get Started](https://iam.hanzo.ai)** | 📖 **[Docs](https://docs.hanzo.ai)** | 💬 **[Discord](https://discord.gg/hanzoai)** -See [MCP-README.md](./MCP-README.md) for complete documentation. +--- -## Debugging - -If you encounter "request too long" errors, create a `.hanzoignore` file in your project root using `.gitignore` format: - -``` -staticfiles/ -media/ -large-binary.exe -``` - -### Large Projects - -Hanzo automatically chunks file data when processing: -- Projects >10MB are split into multiple processing chunks -- Each chunk is processed separately then combined -- Progress displays in the VS Code notification area - -For persistent size issues: -1. Exclude more directories in `.hanzoignore` -2. Remove large binaries or media files -3. Focus analysis on core source directories - -## Installation - -Install from VS Code Marketplace: -1. Open VS Code -2. Press `Ctrl+P` / `Cmd+P` -3. Type `ext install namanyayg.hanzo` - -## Requirements - -- VS Code 1.85.0+ -- Internet connection for AI capabilities - -## Extension Settings - -Hanzo works immediately without configuration. Access additional settings via: -- VS Code settings (`Ctrl+,` / `Cmd+,`) -- Hanzo configuration panel in the extension sidebar - -## Known Issues & Limitations - -- Large projects may require longer analysis time -- Some file types excluded from analysis (binaries, media) -- Performance may vary based on project complexity - -## License - -Licensed under MIT License. See LICENSE file for details. +Built for engineers who ship. \ No newline at end of file diff --git a/TOOLS_BREAKDOWN.md b/TOOLS_BREAKDOWN.md new file mode 100644 index 0000000..bfaed29 --- /dev/null +++ b/TOOLS_BREAKDOWN.md @@ -0,0 +1,215 @@ +# Hanzo MCP Tools - Complete Breakdown + +The Hanzo extension provides 53+ powerful tools organized into categories. All tools are accessible through VS Code's chat interface via `@hanzo`. + +## 📁 File Operations (6 tools) + +### Core File Tools +- **read** - Read any file with line numbers and syntax highlighting +- **write** - Create new files with content +- **edit** - Replace text in files with exact string matching +- **multi_edit** - Make multiple edits to a file in one operation +- **directory_tree** - Display directory structure with file sizes +- **find_files** - Find files by name pattern or content + +## 🔍 Search & Analysis (8 tools) + +### Search Tools +- **search** - Semantic search across the codebase +- **grep** - Pattern search using regular expressions +- **git_search** - Search through git history +- **symbols** - Find code symbols (functions, classes, variables) +- **unified_search** - Combined search across multiple sources +- **content_replace** - Find and replace across multiple files +- **diff** - Show differences between files or commits +- **web_fetch** - Fetch and analyze web content + +## 💻 Shell & System (11 tools) + +### Command Execution +- **bash** - Execute bash commands with environment +- **run_command** - Run any shell command +- **run_background** - Run commands in background +- **processes** - List running processes +- **pkill** - Kill processes by name/pattern +- **logs** - View and tail log files +- **npx** - Run Node.js packages +- **uvx** - Run Python packages with uv +- **open** - Open files/URLs in default application +- **process** - Advanced process management +- **mcp** - Run other MCP servers + +## 🤖 AI & Intelligence (6 tools) + +### AI Tools +- **agent** - AI agent for complex tasks (single or multi-agent) +- **llm** - Query LLM providers (Hanzo, OpenAI, Anthropic, local) +- **consensus** - Get consensus from multiple LLMs +- **llm_manage** - Manage LLM configurations +- **think** - Deep thinking and problem solving +- **critic** - Critical analysis and review + +## 📝 Development Tools (6 tools) + +### Task Management +- **todo_read** - Read task list +- **todo_write** - Write/update tasks +- **todo_unified** - Unified todo management +- **zen** - Zen mode for focused work +- **rules** - Manage IDE rules (.cursorrules, etc.) +- **config** - Configuration management + +## 🗄️ Database & Storage (5 tools) + +### Data Management +- **graph_db** - Graph database operations +- **vector_index** - Vector database indexing +- **vector_search** - Semantic vector search +- **vector_similar** - Find similar vectors +- **document_store** - Document storage and retrieval + +## 📊 Jupyter & Notebooks (2 tools) + +### Notebook Tools +- **notebook_read** - Read Jupyter notebooks +- **notebook_edit** - Edit Jupyter notebook cells + +## 🎨 Configuration & Modes (3 tools) + +### Environment Setup +- **mode** - Development modes (guido, linus, 10x, etc.) +- **palette** - VS Code command palette access +- **batch** - Batch operations on multiple tools + +## 🔧 Utility Tools (6 tools) + +### Helpers +- **sql_query** - Execute SQL queries +- **batch_search** - Batch search operations +- **editor** - Advanced editor operations +- **system** - System information and management +- **ast_analyzer** - AST code analysis (experimental) +- **treesitter_analyzer** - Tree-sitter analysis (experimental) + +--- + +## 🚀 Development Modes + +The **mode** tool provides preconfigured tool sets based on famous programmers and workflows: + +### Language Creators +- **guido** - Guido van Rossum (Python) - "Readability counts" +- **linus** - Linus Torvalds (Linux) - "Talk is cheap. Show me the code." +- **brendan** - Brendan Eich (JavaScript) - "Always bet on JavaScript" + +### Special Configurations +- **fullstack** - Frontend to backend, all common tools +- **minimal** - Essential tools only (read, write, edit, grep, bash) +- **10x** - Maximum productivity, all tools enabled +- **security** - Security-focused, read-only tools +- **data_scientist** - Jupyter, SQL, vector tools +- **hanzo** - Optimal Hanzo AI configuration + +Example: `@hanzo mode activate 10x` + +--- + +## 🤝 Agent Tool Usage + +The unified **agent** tool supports both single and multi-agent workflows: + +### Single Agent +``` +@hanzo agent analyze security vulnerabilities +@hanzo agent --role "performance expert" optimize this function +@hanzo agent --tools ["read", "grep", "critic"] review this PR +``` + +### Multi-Agent (Default: Analyst → Developer → Reviewer) +``` +@hanzo agent implement user authentication +@hanzo agent --agents [{"name": "Architect", "role": "Design the system"}] design a microservice +@hanzo agent --parallel analyze and fix all TODOs +``` + +### Model Selection +``` +@hanzo agent --model gpt-4 complex reasoning task +@hanzo agent --model llama2 local analysis +@hanzo agent --model claude-3 creative writing +``` + +--- + +## 🔐 Privacy & Local LLMs + +Configure local LLMs for complete privacy: + +### LM Studio +```json +{ + "hanzo.llm.provider": "lmstudio", + "hanzo.llm.lmstudio.endpoint": "http://localhost:1234/v1", + "hanzo.llm.lmstudio.model": "codellama-13b" +} +``` + +### Ollama +```json +{ + "hanzo.llm.provider": "ollama", + "hanzo.llm.ollama.endpoint": "http://localhost:11434", + "hanzo.llm.ollama.model": "llama2" +} +``` + +--- + +## 📋 Common Workflows + +### Code Analysis +``` +@hanzo mode activate security +@hanzo agent analyze this codebase for vulnerabilities +@hanzo grep "TODO|FIXME|HACK" +@hanzo critic review recent changes +``` + +### Feature Development +``` +@hanzo mode activate 10x +@hanzo agent implement feature: add dark mode toggle +@hanzo todo_write track progress +@hanzo git_search similar implementations +``` + +### Refactoring +``` +@hanzo symbols find all UserService methods +@hanzo agent refactor UserService to use dependency injection +@hanzo diff show changes +@hanzo critic review refactoring +``` + +### Documentation +``` +@hanzo agent document all public APIs +@hanzo grep "^export" in **/*.ts +@hanzo write API_DOCS.md with findings +``` + +--- + +## 🎯 Tool Categories Summary + +1. **File Management** (6) - Read, write, edit files +2. **Search & Analysis** (8) - Find anything in code +3. **Shell & System** (11) - Execute commands, manage processes +4. **AI & Intelligence** (6) - LLMs, agents, thinking tools +5. **Development** (6) - Tasks, config, productivity +6. **Database** (5) - Vector, graph, document storage +7. **Notebooks** (2) - Jupyter integration +8. **Configuration** (3) - Modes, settings, batch ops +9. **Utilities** (6) - SQL, analysis, misc tools + +Total: **53+ tools** available through `@hanzo` in VS Code! \ No newline at end of file diff --git a/images/icon.png b/images/icon.png index a9b617536a479a46a2eac82666bce1d34bc9ba19..04ab9a4eb1626d1423f2e977e9e14ff895ebe683 100644 GIT binary patch literal 13376 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 diff --git a/out/extension.js b/out/extension.js index ad09d09..8111f87 100644 --- a/out/extension.js +++ b/out/extension.js @@ -44,12 +44,14 @@ const HanzoMetricsService_1 = require("./services/HanzoMetricsService"); const server_1 = require("./mcp/server"); const config_1 = require("./config"); const content_1 = require("./webview/content"); +const hanzo_chat_participant_1 = require("./chat/hanzo-chat-participant"); let projectManager; let authManager; let reminderService; let statusBar; let metricsService; let mcpServer; +let chatParticipant; async function activate(context) { console.log('Hanzo AI Extension is now active!'); // Initialize services @@ -63,6 +65,16 @@ async function activate(context) { mcpServer = new server_1.MCPServer(context); await mcpServer.initialize(); } + // Initialize VS Code Chat Participant + try { + chatParticipant = new hanzo_chat_participant_1.HanzoChatParticipant(context); + const participant = await chatParticipant.initialize(); + context.subscriptions.push(participant); + console.log('Hanzo Chat Participant registered successfully'); + } + catch (error) { + console.error('Failed to register chat participant:', error); + } // Register commands const disposables = [ vscode.commands.registerCommand('hanzo.openManager', () => { diff --git a/package-lock.json b/package-lock.json index 221a047..a4edcee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "tree-sitter-typescript": "^0.23.2" }, "devDependencies": { + "@types/better-sqlite3": "^7.6.13", "@types/lodash": "^4.17.16", "@types/minimatch": "^5.1.2", "@types/mocha": "^10.0.10", @@ -38,11 +39,15 @@ "@typescript-eslint/parser": "^6.21.0", "@vscode/test-electron": "^2.3.8", "@vscode/vsce": "^2.24.0", + "archiver": "^7.0.1", + "better-sqlite3": "^12.2.0", + "c8": "^10.1.3", "cross-env": "^7.0.3", "esbuild": "^0.19.12", "eslint": "^8.26.0", "glob": "^10.3.10", "mocha": "^11.0.1", + "sinon": "^21.0.0", "typescript": "^5.2.2" }, "engines": { @@ -58,6 +63,16 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -1279,6 +1294,44 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@lancedb/lancedb": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/@lancedb/lancedb/-/lancedb-0.21.0.tgz", @@ -1579,6 +1632,48 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@supabase/auth-js": { "version": "2.67.3", "license": "MIT", @@ -1649,6 +1744,16 @@ "tslib": "^2.8.0" } }, + "node_modules/@types/better-sqlite3": { + "version": "7.6.13", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -1732,6 +1837,13 @@ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2428,6 +2540,19 @@ "node": "*" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -2619,6 +2744,162 @@ "undici-types": "~6.21.0" } }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/archiver/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/archiver/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2657,6 +2938,13 @@ "integrity": "sha512-94ezeKlKB97OJUyMaU7dQUAB+Cmjlgr4T9/cxCoKaLM4F2HAmuIHm3Q5ClGCsX5PvRwCQehCzAa/6foRFXRbqA==", "license": "MIT" }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "license": "MIT" @@ -2695,10 +2983,25 @@ "typed-rest-client": "^1.8.4" } }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2718,6 +3021,21 @@ } ] }, + "node_modules/better-sqlite3": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz", + "integrity": "sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x" + } + }, "node_modules/binary-decision-diagram": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/binary-decision-diagram/-/binary-decision-diagram-3.2.0.tgz", @@ -2739,6 +3057,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -2891,6 +3219,40 @@ "node": ">= 0.8" } }, + "node_modules/c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -3135,8 +3497,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true + "dev": true }, "node_modules/cli-cursor": { "version": "4.0.0", @@ -3337,6 +3698,71 @@ "node": ">=4.0.0" } }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3384,6 +3810,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -3421,6 +3854,81 @@ "node": ">= 0.10" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/crc32-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/crc32-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -3532,7 +4040,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, - "optional": true, "dependencies": { "mimic-response": "^3.1.0" }, @@ -3548,7 +4055,6 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, - "optional": true, "engines": { "node": ">=4.0.0" } @@ -3604,7 +4110,6 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "dev": true, - "optional": true, "engines": { "node": ">=8" } @@ -3761,7 +4266,6 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "optional": true, "dependencies": { "once": "^1.4.0" } @@ -4142,12 +4646,32 @@ "node": ">=16" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", @@ -4174,7 +4698,6 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, - "optional": true, "engines": { "node": ">=6" } @@ -4262,6 +4785,13 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4379,6 +4909,13 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4601,8 +5138,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true + "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -4722,8 +5258,7 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "optional": true + "dev": true }, "node_modules/glob": { "version": "10.4.5", @@ -4829,6 +5364,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -4933,6 +5475,13 @@ "node": ">=10" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -5103,8 +5652,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true + "dev": true }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -5287,6 +5835,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -5334,6 +5895,58 @@ "ws": "*" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -5447,6 +6060,19 @@ "json-buffer": "3.0.1" } }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -5627,6 +6253,22 @@ "node": ">=10" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/markdown-it": { "version": "12.3.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", @@ -5758,7 +6400,6 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, - "optional": true, "engines": { "node": ">=10" }, @@ -5790,7 +6431,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5808,8 +6448,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true + "dev": true }, "node_modules/mocha": { "version": "11.1.0", @@ -5990,8 +6629,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "dev": true, - "optional": true + "dev": true }, "node_modules/nats": { "version": "2.29.3", @@ -6037,7 +6675,6 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", "dev": true, - "optional": true, "dependencies": { "semver": "^7.3.5" }, @@ -6575,7 +7212,6 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "dev": true, - "optional": true, "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -6606,6 +7242,16 @@ "node": ">= 0.8.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6658,7 +7304,6 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, - "optional": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -6742,7 +7387,6 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -6758,7 +7402,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, - "optional": true, "engines": { "node": ">=0.10.0" } @@ -6790,6 +7433,29 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -7309,8 +7975,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true + ] }, "node_modules/simple-get": { "version": "4.0.1", @@ -7331,7 +7996,6 @@ "url": "https://feross.org/support" } ], - "optional": true, "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -7381,6 +8045,47 @@ "node": ">= 6" } }, + "node_modules/sinon": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7424,6 +8129,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -7583,7 +8302,6 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "dev": true, - "optional": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -7596,7 +8314,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -7613,7 +8330,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "optional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -7639,7 +8355,6 @@ "url": "https://feross.org/support" } ], - "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -7650,7 +8365,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7660,6 +8374,47 @@ "node": ">= 6" } }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7808,7 +8563,6 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "optional": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -7834,6 +8588,16 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -7992,6 +8756,21 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/validator": { "version": "13.15.15", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", @@ -8456,6 +9235,69 @@ "node": ">=16" } }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/zip-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/zip-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/zod": { "version": "3.25.71", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.71.tgz", @@ -8481,6 +9323,12 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==" }, + "@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true + }, "@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -9227,6 +10075,34 @@ } } }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "@lancedb/lancedb": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/@lancedb/lancedb/-/lancedb-0.21.0.tgz", @@ -9402,6 +10278,43 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1" + } + }, + "@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + }, + "dependencies": { + "type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true + } + } + }, "@supabase/auth-js": { "version": "2.67.3", "requires": { @@ -9461,6 +10374,15 @@ "tslib": "^2.8.0" } }, + "@types/better-sqlite3": { + "version": "7.6.13", + "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", + "integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -9534,6 +10456,12 @@ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==" }, + "@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, "@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -9995,6 +10923,15 @@ } } }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -10133,6 +11070,113 @@ } } }, + "archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "dev": true, + "requires": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "dependencies": { + "buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "dev": true + }, + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + } + } + }, + "archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "dev": true, + "requires": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -10161,6 +11205,12 @@ "resolved": "https://registry.npmjs.org/as-typed/-/as-typed-1.3.2.tgz", "integrity": "sha512-94ezeKlKB97OJUyMaU7dQUAB+Cmjlgr4T9/cxCoKaLM4F2HAmuIHm3Q5ClGCsX5PvRwCQehCzAa/6foRFXRbqA==" }, + "async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, "asynckit": { "version": "0.4.0" }, @@ -10190,14 +11240,37 @@ "typed-rest-client": "^1.8.4" } }, + "b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true + }, "balanced-match": { "version": "1.0.2" }, + "bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "dev": true, + "optional": true + }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "better-sqlite3": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz", + "integrity": "sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==", + "dev": true, + "requires": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, "binary-decision-diagram": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/binary-decision-diagram/-/binary-decision-diagram-3.2.0.tgz", @@ -10209,6 +11282,15 @@ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -10321,6 +11403,25 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + } + }, "call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -10491,8 +11592,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true + "dev": true }, "cli-cursor": { "version": "4.0.0", @@ -10637,6 +11737,49 @@ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" }, + "compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -10663,6 +11806,12 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -10688,6 +11837,52 @@ "vary": "^1" } }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -10758,7 +11953,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, - "optional": true, "requires": { "mimic-response": "^3.1.0" } @@ -10767,8 +11961,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true + "dev": true }, "deep-is": { "version": "0.1.4", @@ -10803,8 +11996,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "dev": true, - "optional": true + "dev": true }, "dexie": { "version": "4.0.10", @@ -10917,7 +12109,6 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "optional": true, "requires": { "once": "^1.4.0" } @@ -11191,11 +12382,23 @@ "binary-decision-diagram": "3.2.0" } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, "eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", @@ -11213,8 +12416,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "optional": true + "dev": true }, "express": { "version": "5.1.0", @@ -11276,6 +12478,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -11355,6 +12563,12 @@ "flat-cache": "^3.0.4" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, "fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -11508,8 +12722,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true + "dev": true }, "fs.realpath": { "version": "1.0.0", @@ -11603,8 +12816,7 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "optional": true + "dev": true }, "glob": { "version": "10.4.5", @@ -11676,6 +12888,12 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, "graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -11740,6 +12958,12 @@ "lru-cache": "^6.0.0" } }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -11858,8 +13082,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true + "dev": true }, "ipaddr.js": { "version": "1.9.1", @@ -11979,6 +13202,12 @@ "hasown": "^2.0.2" } }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, "is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -12010,6 +13239,44 @@ "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", "requires": {} }, + "istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, "jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -12105,6 +13372,15 @@ "json-buffer": "3.0.1" } }, + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -12241,6 +13517,15 @@ "yallist": "^4.0.0" } }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, "markdown-it": { "version": "12.3.2", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", @@ -12327,8 +13612,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "optional": true + "dev": true }, "mingo": { "version": "6.5.6", @@ -12345,8 +13629,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "7.1.2", @@ -12358,8 +13641,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true + "dev": true }, "mocha": { "version": "11.1.0", @@ -12473,8 +13755,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "dev": true, - "optional": true + "dev": true }, "nats": { "version": "2.29.3", @@ -12508,7 +13789,6 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", "dev": true, - "optional": true, "requires": { "semver": "^7.3.5" } @@ -12863,7 +14143,6 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "dev": true, - "optional": true, "requires": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -12885,6 +14164,12 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -12927,7 +14212,6 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, - "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -12980,7 +14264,6 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "optional": true, "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -12992,8 +14275,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "optional": true + "dev": true } } }, @@ -13021,6 +14303,26 @@ "util-deprecate": "~1.0.1" } }, + "readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "requires": { + "minimatch": "^5.1.0" + }, + "dependencies": { + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -13388,15 +14690,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "optional": true + "dev": true }, "simple-get": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", "dev": true, - "optional": true, "requires": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -13429,6 +14729,36 @@ } } }, + "sinon": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "dependencies": { + "diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -13457,6 +14787,17 @@ "bl": "^5.0.0" } }, + "streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "dev": true, + "requires": { + "bare-events": "^2.2.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -13575,7 +14916,6 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "dev": true, - "optional": true, "requires": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -13588,7 +14928,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "optional": true, "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -13602,7 +14941,6 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, - "optional": true, "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -13614,7 +14952,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -13625,7 +14962,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, - "optional": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13634,6 +14970,37 @@ } } }, + "test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "dependencies": { + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "requires": { + "b4a": "^1.6.4" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -13734,7 +15101,6 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -13753,6 +15119,12 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -13871,6 +15243,17 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + } + }, "validator": { "version": "13.15.15", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", @@ -14192,6 +15575,47 @@ } } }, + "zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "dev": true, + "requires": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "zod": { "version": "3.25.71", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.71.tgz", diff --git a/package.json b/package.json index d301228..4ba2a34 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hanzoai", "displayName": "Hanzo AI Context Manager", - "description": "AI-powered project manager that analyzes codebases, maintains specifications, and tracks changes. Seamlessly integrates with VS Code to provide intelligent project insights and documentation.", + "description": "The ultimate toolkit for AI engineers. Access 200+ LLMs (OpenRouter/LiteLLM compatible), 4000+ MCP servers, and powerful development tools. Features unified API, shared context, intelligent routing, and VS Code native integration.", "version": "1.5.4", "publisher": "hanzo-ai", "private": false, @@ -48,6 +48,14 @@ ], "main": "./out/extension.js", "contributes": { + "chatParticipants": [ + { + "id": "hanzo", + "name": "Hanzo", + "description": "Ultimate AI engineering toolkit: 200+ LLMs, 4000+ MCP servers, 53+ dev tools", + "isSticky": true + } + ], "commands": [ { "command": "hanzo.openManager", @@ -178,6 +186,59 @@ "type": "boolean", "default": false, "description": "Enable debug logging" + }, + "hanzo.llm.provider": { + "type": "string", + "enum": [ + "hanzo", + "lmstudio", + "ollama", + "openai", + "anthropic" + ], + "default": "hanzo", + "description": "LLM provider to use for AI features" + }, + "hanzo.llm.hanzo.apiKey": { + "type": "string", + "description": "API key for Hanzo AI Gateway" + }, + "hanzo.llm.lmstudio.endpoint": { + "type": "string", + "default": "http://localhost:1234/v1", + "description": "LM Studio API endpoint" + }, + "hanzo.llm.lmstudio.model": { + "type": "string", + "description": "Model to use in LM Studio" + }, + "hanzo.llm.ollama.endpoint": { + "type": "string", + "default": "http://localhost:11434", + "description": "Ollama API endpoint" + }, + "hanzo.llm.ollama.model": { + "type": "string", + "default": "llama2", + "description": "Model to use in Ollama" + }, + "hanzo.llm.openai.apiKey": { + "type": "string", + "description": "OpenAI API key" + }, + "hanzo.llm.openai.model": { + "type": "string", + "default": "gpt-4", + "description": "OpenAI model to use" + }, + "hanzo.llm.anthropic.apiKey": { + "type": "string", + "description": "Anthropic API key" + }, + "hanzo.llm.anthropic.model": { + "type": "string", + "default": "claude-3-opus-20240229", + "description": "Anthropic model to use" } } }, @@ -202,10 +263,14 @@ "test:auth": "cross-env MOCHA_TEST_FILE=\"Auth and API Test Suite\" node ./out/test/runTest.js", "test:file-collection": "cross-env MOCHA_TEST_FILE=\"FileCollectionService Test Suite\" node ./out/test/runTest.js", "test:mcp": "cross-env MOCHA_TEST_FILE=\"MCP.*Tool Test Suite\" node ./out/test/runTest.js", + "test:coverage": "c8 npm test", "build:mcp": "node scripts/build-mcp-standalone.js", "build:claude-desktop": "npm run build:mcp && node scripts/build-claude-desktop.js", - "build": "npm run compile && npm run build:mcp && npm run build:claude-desktop", + "build": "node scripts/compile-main.js && npm run build:mcp", "build:dxt": "node scripts/build-dxt.js", + "build:npm": "node scripts/build-mcp-npm.js", + "build:cursor": "node scripts/build-cursor.js", + "build:windsurf": "node scripts/build-windsurf.js", "build:all": "node scripts/build-all-platforms.js", "package": "npm run build:all && vsce package", "package:claude": "npm run build:claude-desktop", @@ -232,6 +297,7 @@ "@vscode/vsce": "^2.24.0", "archiver": "^7.0.1", "better-sqlite3": "^12.2.0", + "c8": "^10.1.3", "cross-env": "^7.0.3", "esbuild": "^0.19.12", "eslint": "^8.26.0", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..e4a4b5b --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +onlyBuiltDependencies: + - better-sqlite3 diff --git a/scripts/build-all-platforms.js b/scripts/build-all-platforms.js index a5029b1..a5c0fd6 100644 --- a/scripts/build-all-platforms.js +++ b/scripts/build-all-platforms.js @@ -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 { diff --git a/scripts/build-cursor.js b/scripts/build-cursor.js new file mode 100644 index 0000000..8a89eff --- /dev/null +++ b/scripts/build-cursor.js @@ -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); +} \ No newline at end of file diff --git a/scripts/build-dxt.js b/scripts/build-dxt.js index 1686bbd..6a2420d 100644 --- a/scripts/build-dxt.js +++ b/scripts/build-dxt.js @@ -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 diff --git a/scripts/build-mcp-npm.js b/scripts/build-mcp-npm.js new file mode 100644 index 0000000..a7d7f6e --- /dev/null +++ b/scripts/build-mcp-npm.js @@ -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'); \ No newline at end of file diff --git a/scripts/build-windsurf.js b/scripts/build-windsurf.js new file mode 100644 index 0000000..db95d8b --- /dev/null +++ b/scripts/build-windsurf.js @@ -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); +} \ No newline at end of file diff --git a/src/chat/hanzo-chat-participant.ts b/src/chat/hanzo-chat-participant.ts new file mode 100644 index 0000000..d95c4e8 --- /dev/null +++ b/src/chat/hanzo-chat-participant.ts @@ -0,0 +1,461 @@ +import * as vscode from 'vscode'; +import { MCPTools } from '../mcp/tools'; +import axios from 'axios'; +import { getConfig } from '../config'; + +interface LLMConfig { + provider: 'hanzo' | 'lmstudio' | 'ollama' | 'openai' | 'anthropic'; + apiKey?: string; + endpoint?: string; + model?: string; +} + +export class HanzoChatParticipant { + private static readonly ID = 'hanzo'; // Lowercase for @hanzo + private mcpTools: MCPTools; + private llmConfig: LLMConfig; + + constructor(private context: vscode.ExtensionContext) { + this.mcpTools = new MCPTools(context); + this.llmConfig = this.getLLMConfig(); + } + + async initialize() { + await this.mcpTools.initialize(); + + // Register chat participant + const participant = vscode.chat.createChatParticipant( + HanzoChatParticipant.ID, + this.handleChat.bind(this) + ); + + participant.iconPath = vscode.Uri.joinPath( + vscode.Uri.file(__dirname), + '..', + '..', + 'images', + 'icon.png' + ); + + // Add follow-up provider + participant.followupProvider = { + provideFollowups: this.provideFollowups.bind(this) + }; + + return participant; + } + + private getLLMConfig(): LLMConfig { + const config = vscode.workspace.getConfiguration('hanzo'); + const llmProvider = config.get('llm.provider', 'hanzo'); + + switch (llmProvider) { + case 'lmstudio': + return { + provider: 'lmstudio', + endpoint: config.get('llm.lmstudio.endpoint', 'http://localhost:1234/v1'), + model: config.get('llm.lmstudio.model') + }; + case 'ollama': + return { + provider: 'ollama', + endpoint: config.get('llm.ollama.endpoint', 'http://localhost:11434'), + model: config.get('llm.ollama.model', 'llama2') + }; + case 'openai': + return { + provider: 'openai', + apiKey: config.get('llm.openai.apiKey'), + model: config.get('llm.openai.model', 'gpt-4') + }; + case 'anthropic': + return { + provider: 'anthropic', + apiKey: config.get('llm.anthropic.apiKey'), + model: config.get('llm.anthropic.model', 'claude-3-opus-20240229') + }; + default: + return { + provider: 'hanzo', + endpoint: config.get('api.endpoint', 'https://api.hanzo.ai/ext/v1'), + apiKey: config.get('llm.hanzo.apiKey') + }; + } + } + + private async handleChat( + request: vscode.ChatRequest, + context: vscode.ChatContext, + stream: vscode.ChatResponseStream, + token: vscode.CancellationToken + ): Promise { + stream.progress('Processing your request...'); + + try { + // First check if this is a direct tool call + const toolCalls = this.parseToolCalls(request.prompt); + + if (toolCalls.length > 0) { + // Execute tool calls directly + await this.executeToolCalls(toolCalls, stream); + } else { + // Use LLM to understand the request and potentially call tools + const response = await this.queryLLM(request.prompt, context); + + if (response.toolCalls && response.toolCalls.length > 0) { + // LLM wants to use tools + await this.executeToolCalls(response.toolCalls, stream); + } else if (response.content) { + // LLM provided a direct response + stream.markdown(response.content); + } else { + // Fallback to showing available tools + stream.markdown(this.getToolsHelp()); + } + } + } catch (error: any) { + stream.markdown(`❌ Error: ${error.message}`); + } + } + + private async executeToolCalls( + toolCalls: Array<{ toolName: string; args: any }>, + stream: vscode.ChatResponseStream + ): Promise { + for (const { toolName, args } of toolCalls) { + const tool = this.mcpTools.getTool(toolName); + if (tool) { + stream.progress(`Executing ${toolName}...`); + + try { + const result = await tool.handler(args); + + // Format and stream the result + if (toolName === 'read' || toolName === 'grep' || toolName === 'search') { + // For file content, use code blocks + stream.markdown(`\`\`\`\n${result}\n\`\`\``); + } else { + stream.markdown(result); + } + } catch (error: any) { + stream.markdown(`❌ Error executing ${toolName}: ${error.message}`); + } + } else { + stream.markdown(`❌ Unknown tool: ${toolName}`); + } + } + } + + private async queryLLM( + prompt: string, + context: vscode.ChatContext + ): Promise<{ content?: string; toolCalls?: Array<{ toolName: string; args: any }> }> { + try { + // Get all available tools for the system prompt + const tools = this.mcpTools.getAllTools(); + const toolDescriptions = tools.map(t => `- ${t.name}: ${t.description}`).join('\n'); + + const systemPrompt = `You are Hanzo, an AI assistant integrated into VS Code with access to powerful development tools. + +Available tools: +${toolDescriptions} + +When the user asks you to perform tasks, analyze their request and either: +1. Use the appropriate tools to complete the task +2. Provide a helpful response without tools +3. Ask for clarification if needed + +To use a tool, respond with a JSON block like this: +\`\`\`json +{ + "toolCalls": [ + { + "toolName": "read", + "args": { "file_path": "/path/to/file" } + } + ] +} +\`\`\` + +Otherwise, respond with: +\`\`\`json +{ + "content": "Your response here" +} +\`\`\``; + + // Query the LLM based on configuration + let response: string; + + switch (this.llmConfig.provider) { + case 'lmstudio': + response = await this.queryLMStudio(systemPrompt, prompt); + break; + case 'ollama': + response = await this.queryOllama(systemPrompt, prompt); + break; + case 'openai': + response = await this.queryOpenAI(systemPrompt, prompt); + break; + case 'anthropic': + response = await this.queryAnthropic(systemPrompt, prompt); + break; + default: + response = await this.queryHanzoAPI(systemPrompt, prompt); + } + + // Parse the response + try { + const jsonMatch = response.match(/```json\n([\s\S]*?)\n```/); + if (jsonMatch) { + return JSON.parse(jsonMatch[1]); + } + } catch (e) { + // If parsing fails, treat as plain text response + } + + return { content: response }; + + } catch (error: any) { + console.error('LLM query error:', error); + // Fallback to direct tool parsing + const toolCalls = this.parseToolCalls(prompt); + if (toolCalls.length > 0) { + return { toolCalls }; + } + return { content: `Error querying LLM: ${error.message}. You can still use tools directly.` }; + } + } + + private async queryHanzoAPI(systemPrompt: string, userPrompt: string): Promise { + const response = await axios.post( + `${this.llmConfig.endpoint}/llm/chat`, + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt } + ], + model: this.llmConfig.model || 'gpt-4', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${this.llmConfig.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; + } + + private async queryLMStudio(systemPrompt: string, userPrompt: string): Promise { + const response = await axios.post( + `${this.llmConfig.endpoint}/chat/completions`, + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt } + ], + model: this.llmConfig.model || 'local-model', + temperature: 0.7 + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; + } + + private async queryOllama(systemPrompt: string, userPrompt: string): Promise { + const response = await axios.post( + `${this.llmConfig.endpoint}/api/generate`, + { + model: this.llmConfig.model || 'llama2', + prompt: `${systemPrompt}\n\nUser: ${userPrompt}\nAssistant:`, + stream: false + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + return response.data.response; + } + + private async queryOpenAI(systemPrompt: string, userPrompt: string): Promise { + const response = await axios.post( + 'https://api.openai.com/v1/chat/completions', + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt } + ], + model: this.llmConfig.model || 'gpt-4', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${this.llmConfig.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; + } + + private async queryAnthropic(systemPrompt: string, userPrompt: string): Promise { + const response = await axios.post( + 'https://api.anthropic.com/v1/messages', + { + messages: [ + { role: 'user', content: userPrompt } + ], + model: this.llmConfig.model || 'claude-3-opus-20240229', + system: systemPrompt, + max_tokens: 4096 + }, + { + headers: { + 'x-api-key': this.llmConfig.apiKey, + 'anthropic-version': '2023-06-01', + 'Content-Type': 'application/json' + } + } + ); + + return response.data.content[0].text; + } + + private parseToolCalls(prompt: string): Array<{ toolName: string; args: any }> { + const toolCalls: Array<{ toolName: string; args: any }> = []; + + // Simple pattern matching for common commands + const patterns = [ + // File operations + { regex: /read\s+(.+)/, tool: 'read', args: (m: RegExpMatchArray) => ({ file_path: m[1].trim() }) }, + { regex: /write\s+(.+?)\s+content:\s*(.+)/s, tool: 'write', args: (m: RegExpMatchArray) => ({ file_path: m[1].trim(), content: m[2].trim() }) }, + { regex: /edit\s+(.+?)\s+replace\s+"(.+?)"\s+with\s+"(.+?)"/s, tool: 'edit', args: (m: RegExpMatchArray) => ({ file_path: m[1].trim(), old_string: m[2], new_string: m[3] }) }, + + // Search operations + { regex: /search\s+"(.+?)"(?:\s+in\s+(.+))?/, tool: 'search', args: (m: RegExpMatchArray) => ({ query: m[1], include: m[2]?.trim() }) }, + { regex: /grep\s+"(.+?)"(?:\s+(.+))?/, tool: 'grep', args: (m: RegExpMatchArray) => ({ pattern: m[1], include: m[2]?.trim() || '**/*' }) }, + + // Shell operations + { regex: /run\s+(.+)/, tool: 'run_command', args: (m: RegExpMatchArray) => ({ command: m[1].trim() }) }, + { regex: /bash\s+(.+)/, tool: 'bash', args: (m: RegExpMatchArray) => ({ command: m[1].trim() }) }, + + // Directory operations + { regex: /ls\s+(.+)/, tool: 'directory_tree', args: (m: RegExpMatchArray) => ({ path: m[1].trim() }) }, + { regex: /tree\s+(.+)/, tool: 'directory_tree', args: (m: RegExpMatchArray) => ({ path: m[1].trim() }) }, + + // AI operations + { regex: /agent\s+(.+)/, tool: 'agent', args: (m: RegExpMatchArray) => ({ task: m[1].trim() }) }, + ]; + + for (const pattern of patterns) { + const match = prompt.match(pattern.regex); + if (match) { + toolCalls.push({ + toolName: pattern.tool, + args: pattern.args(match) + }); + break; // Only process first match for now + } + } + + return toolCalls; + } + + private provideFollowups( + result: vscode.ChatResult, + context: vscode.ChatContext, + token: vscode.CancellationToken + ): vscode.ProviderResult { + return [ + { + prompt: 'Show available tools', + label: 'Available Tools', + command: 'help' + }, + { + prompt: 'Search for "TODO" in all files', + label: 'Find TODOs', + command: 'search' + }, + { + prompt: 'Show current directory structure', + label: 'Directory Tree', + command: 'tree' + }, + { + prompt: 'Configure LLM provider', + label: 'LLM Settings', + command: 'llm_manage' + } + ]; + } + + private getToolsHelp(): string { + const tools = this.mcpTools.getAllTools(); + const categories: Record = { + 'File Operations': ['read', 'write', 'edit', 'multi_edit'], + 'Search': ['search', 'grep', 'git_search', 'symbols'], + 'Shell': ['bash', 'run_command', 'processes'], + 'Directory': ['directory_tree', 'find_files'], + 'AI': ['llm', 'consensus', 'mode', 'agent'], + 'Development': ['todo_read', 'todo_write', 'critic', 'think'] + }; + + let help = `# @hanzo AI Assistant + +I have access to ${tools.length} tools to help you with development tasks. + +## Current LLM Provider: ${this.llmConfig.provider} +${this.llmConfig.provider === 'hanzo' ? 'Using Hanzo AI Gateway (api.hanzo.ai)' : ''} +${this.llmConfig.provider === 'lmstudio' ? `Using LM Studio at ${this.llmConfig.endpoint}` : ''} +${this.llmConfig.provider === 'ollama' ? `Using Ollama at ${this.llmConfig.endpoint}` : ''} + +## Available Tools by Category:\n\n`; + + for (const [category, toolNames] of Object.entries(categories)) { + const categoryTools = toolNames + .map(name => tools.find(t => t.name === name)) + .filter(Boolean); + + if (categoryTools.length > 0) { + help += `### ${category}\n`; + for (const tool of categoryTools) { + if (tool) { + help += `- **${tool.name}**: ${tool.description}\n`; + } + } + help += '\n'; + } + } + + help += `## Example Commands: +- "read src/index.ts" +- "search for TODO" +- "grep 'function' in **/*.ts" +- "run npm test" +- "show directory tree for src" +- "agent analyze this codebase for security issues" + +## LLM Configuration: +You can configure your LLM provider in VS Code settings: +- hanzo.llm.provider: Choose from 'hanzo', 'lmstudio', 'ollama', 'openai', 'anthropic' +- hanzo.llm.[provider].endpoint: Set custom endpoints for local providers +- hanzo.llm.[provider].model: Choose specific models + +Ask me to use any of these tools to help with your development tasks!`; + + return help; + } +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index f9fc70b..2870cd3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -7,6 +7,7 @@ import { HanzoMetricsService } from './services/HanzoMetricsService'; import { MCPServer } from './mcp/server'; import { getConfig } from './config'; import { getWebviewContent } from './webview/content'; +import { HanzoChatParticipant } from './chat/hanzo-chat-participant'; let projectManager: ProjectManager | undefined; let authManager: AuthManager | undefined; @@ -14,6 +15,7 @@ let reminderService: ReminderService | undefined; let statusBar: StatusBarService | undefined; let metricsService: HanzoMetricsService | undefined; let mcpServer: MCPServer | undefined; +let chatParticipant: HanzoChatParticipant | undefined; export async function activate(context: vscode.ExtensionContext) { console.log('Hanzo AI Extension is now active!'); @@ -30,6 +32,16 @@ export async function activate(context: vscode.ExtensionContext) { mcpServer = new MCPServer(context); await mcpServer.initialize(); } + + // Initialize VS Code Chat Participant + try { + chatParticipant = new HanzoChatParticipant(context); + const participant = await chatParticipant.initialize(); + context.subscriptions.push(participant); + console.log('Hanzo Chat Participant registered successfully'); + } catch (error) { + console.error('Failed to register chat participant:', error); + } // Register commands const disposables = [ diff --git a/src/mcp/tools/agent.ts b/src/mcp/tools/agent.ts index 1325f80..c6d5262 100644 --- a/src/mcp/tools/agent.ts +++ b/src/mcp/tools/agent.ts @@ -1,17 +1,52 @@ import * as vscode from 'vscode'; import { MCPTool } from '../server'; +import axios from 'axios'; + +interface AgentConfig { + task: string; + role?: string; + tools?: string[]; + model?: string; + agents?: Array<{ + name: string; + role: string; + tools?: string[]; + }>; + parallel?: boolean; +} + +interface LLMProvider { + name: string; + endpoint?: string; + apiKey?: string; + models: string[]; + priority: number; +} export function createAgentTools(context: vscode.ExtensionContext): MCPTool[] { return [ { - name: 'dispatch_agent', - description: 'Delegate tasks to specialized sub-agents', + name: 'agent', + description: 'AI agent that can use tools to complete complex tasks. Supports single or multi-agent workflows.', inputSchema: { type: 'object', properties: { task: { type: 'string', - description: 'Task description for the agent' + description: 'Task description for the agent(s)' + }, + role: { + type: 'string', + description: 'Role/persona for single agent mode (e.g., "security expert", "performance optimizer")' + }, + tools: { + type: 'array', + items: { type: 'string' }, + description: 'Specific tools the agent can use (defaults to all appropriate tools)' + }, + model: { + type: 'string', + description: 'LLM model to use (e.g., "gpt-4", "claude-3", "llama2", "gemini/gemini-pro")' }, agents: { type: 'array', @@ -26,24 +61,522 @@ export function createAgentTools(context: vscode.ExtensionContext): MCPTool[] { } } }, - description: 'Agents to dispatch (optional, will auto-select if not provided)' + description: 'Multi-agent configuration (optional)' }, parallel: { type: 'boolean', - description: 'Run agents in parallel (default: false)' + description: 'Run multiple agents in parallel (default: false)' } }, required: ['task'] }, - handler: async (args: { - task: string; - agents?: Array<{ name: string; role: string; tools?: string[] }>; - parallel?: boolean; - }) => { - // TODO: Implement agent dispatch functionality - // This would integrate with LLM providers to create sub-agents - return 'Agent dispatch functionality coming soon'; + handler: async (args: AgentConfig) => { + const providers = detectLLMProviders(); + const selectedProvider = selectProvider(providers, args.model); + + if (!selectedProvider) { + return 'Error: No LLM provider available. Please configure API keys in environment or VS Code settings.'; + } + + // Single agent mode + if (!args.agents) { + const agent = { + name: 'Agent', + role: args.role || 'AI assistant that completes tasks using available tools', + tools: args.tools + }; + + try { + const result = await executeAgent( + agent, + args.task, + selectedProvider, + args.model + ); + return `## Task Completed\n\n${result}`; + } catch (error: any) { + return `Error: ${error.message}`; + } + } + + // Multi-agent mode + const defaultAgents = [ + { + name: 'Analyst', + role: 'Analyze requirements and understand the codebase', + tools: ['read', 'search', 'grep', 'directory_tree', 'symbols', 'git_search'] + }, + { + name: 'Developer', + role: 'Implement changes and write code', + tools: ['write', 'edit', 'multi_edit', 'bash', 'run_command', 'npx', 'uvx'] + }, + { + name: 'Reviewer', + role: 'Review changes and ensure quality', + tools: ['read', 'git_search', 'diff', 'critic', 'think', 'grep'] + } + ]; + + const agents = args.agents || defaultAgents; + + try { + if (args.parallel) { + // Execute agents in parallel + const promises = agents.map(agent => + executeAgent(agent, args.task, selectedProvider, args.model) + ); + const results = await Promise.all(promises); + return formatAgentResults(agents, results, selectedProvider); + } else { + // Execute agents sequentially with context passing + const results: string[] = []; + let context = ''; + + for (const agent of agents) { + const result = await executeAgent( + agent, + args.task, + selectedProvider, + args.model, + context + ); + results.push(result); + context += `\n\n${agent.name} completed:\n${result}`; + } + + return formatAgentResults(agents, results, selectedProvider); + } + } catch (error: any) { + return `Error in multi-agent execution: ${error.message}`; + } } } ]; +} + +function detectLLMProviders(): LLMProvider[] { + const providers: LLMProvider[] = []; + const config = vscode.workspace.getConfiguration('hanzo'); + + // Check environment variables first (highest priority) + + // OpenAI + if (process.env.OPENAI_API_KEY) { + providers.push({ + name: 'openai', + apiKey: process.env.OPENAI_API_KEY, + models: ['o3-pro', 'o3', 'gpt-4o', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'], + priority: 1 + }); + } + + // Anthropic + if (process.env.ANTHROPIC_API_KEY) { + providers.push({ + name: 'anthropic', + apiKey: process.env.ANTHROPIC_API_KEY, + models: ['claude-4', 'claude-3.5-sonnet', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', 'claude-3-haiku-20240307'], + priority: 1 + }); + } + + // Google (Gemini) + if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY) { + providers.push({ + name: 'google', + apiKey: process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY, + models: ['gemini/gemini-pro', 'gemini/gemini-pro-vision'], + priority: 1 + }); + } + + // Mistral + if (process.env.MISTRAL_API_KEY) { + providers.push({ + name: 'mistral', + apiKey: process.env.MISTRAL_API_KEY, + models: ['mistral/mistral-large-latest', 'mistral/mistral-medium', 'mistral/mistral-small'], + priority: 1 + }); + } + + // Cohere + if (process.env.COHERE_API_KEY) { + providers.push({ + name: 'cohere', + apiKey: process.env.COHERE_API_KEY, + models: ['command-r', 'command-r-plus'], + priority: 1 + }); + } + + // Together AI + if (process.env.TOGETHER_API_KEY) { + providers.push({ + name: 'together', + apiKey: process.env.TOGETHER_API_KEY, + models: ['together/mixtral-8x7b', 'together/llama-2-70b'], + priority: 1 + }); + } + + // Replicate + if (process.env.REPLICATE_API_KEY) { + providers.push({ + name: 'replicate', + apiKey: process.env.REPLICATE_API_KEY, + models: ['replicate/llama-2-70b-chat', 'replicate/mistral-7b'], + priority: 1 + }); + } + + // Local providers (lower priority) + + // LM Studio + if (process.env.LM_STUDIO_BASE_URL || config.get('llm.lmstudio.endpoint')) { + providers.push({ + name: 'lmstudio', + endpoint: process.env.LM_STUDIO_BASE_URL || config.get('llm.lmstudio.endpoint', 'http://localhost:1234/v1'), + models: ['local-model'], + priority: 2 + }); + } + + // Ollama + if (process.env.OLLAMA_BASE_URL || config.get('llm.ollama.endpoint')) { + providers.push({ + name: 'ollama', + endpoint: process.env.OLLAMA_BASE_URL || config.get('llm.ollama.endpoint', 'http://localhost:11434'), + models: ['llama2', 'mistral', 'codellama'], + priority: 2 + }); + } + + // VS Code settings (medium priority) + const vsCodeProviders = ['openai', 'anthropic', 'google', 'mistral', 'cohere']; + for (const provider of vsCodeProviders) { + const apiKey = config.get(`llm.${provider}.apiKey`); + if (apiKey && !providers.find(p => p.name === provider)) { + providers.push({ + name: provider, + apiKey: apiKey, + models: getDefaultModels(provider), + priority: 3 + }); + } + } + + // Hanzo AI - Supercharge your AI development with shared context and search + // Access 200+ LLMs and 4000+ MCP servers through one unified API + const hanzoApiKey = process.env.HANZO_API_KEY || config.get('llm.hanzo.apiKey'); + if (hanzoApiKey || !providers.length) { + providers.push({ + name: 'hanzo', + endpoint: process.env.HANZO_API_URL || config.get('api.endpoint', 'https://api.hanzo.ai/ext/v1'), + apiKey: hanzoApiKey, + models: ['o3-pro', 'o3', 'claude-4', 'gpt-4o', 'gpt-4-turbo', 'claude-3.5-sonnet', 'claude-3-opus', 'gemini-2.0-flash', 'gemini-pro', 'llama-3.1-405b', 'mixtral-8x22b', 'command-r-plus', 'deepseek-v3'], + priority: providers.length === 0 ? 1 : 4 // Higher priority if no other providers + }); + } + + return providers.sort((a, b) => a.priority - b.priority); +} + +function getDefaultModels(provider: string): string[] { + switch (provider) { + case 'openai': + return ['o3-pro', 'o3', 'gpt-4o', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo']; + case 'anthropic': + return ['claude-4', 'claude-3.5-sonnet', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229']; + case 'google': + return ['gemini/gemini-2.0-flash', 'gemini/gemini-pro', 'gemini/gemini-pro-vision', 'gemini/gemini-ultra']; + case 'mistral': + return ['mistral/mistral-large-latest', 'mistral/mistral-medium']; + case 'cohere': + return ['command-r', 'command-r-plus']; + default: + return ['gpt-4']; + } +} + +function selectProvider(providers: LLMProvider[], requestedModel?: string): LLMProvider | null { + if (!providers.length) { + return null; + } + + // If a specific model is requested, find the provider that supports it + if (requestedModel) { + // Check for provider prefix (e.g., "openai/gpt-4", "anthropic/claude-3") + const [providerPrefix, modelName] = requestedModel.includes('/') + ? requestedModel.split('/', 2) + : [null, requestedModel]; + + if (providerPrefix) { + const provider = providers.find(p => p.name === providerPrefix); + if (provider) return provider; + } + + // Find provider that has this model + for (const provider of providers) { + if (provider.models.some(m => m === requestedModel || m.endsWith(`/${requestedModel}`))) { + return provider; + } + } + } + + // Return highest priority provider + return providers[0]; +} + +async function executeAgent( + agent: { name: string; role: string; tools?: string[] }, + task: string, + provider: LLMProvider, + requestedModel?: string, + previousContext: string = '' +): Promise { + const systemPrompt = `You are ${agent.name}, an AI agent with the following role: ${agent.role} + +You have access to these tools: ${agent.tools?.join(', ') || 'all available tools'} + +Your task: ${task} + +${previousContext ? `Previous context:\n${previousContext}` : ''} + +Complete your task and provide a clear summary of what you accomplished.`; + + try { + let response: string; + + // Use Hanzo AI endpoint - supercharge your AI development + if (provider.name === 'hanzo') { + response = await queryHanzoAI(systemPrompt, task, provider, requestedModel); + } else { + // Direct provider calls for better performance when API keys are available + switch (provider.name) { + case 'openai': + response = await queryOpenAI(systemPrompt, task, provider, requestedModel); + break; + case 'anthropic': + response = await queryAnthropic(systemPrompt, task, provider, requestedModel); + break; + case 'google': + response = await queryGoogle(systemPrompt, task, provider, requestedModel); + break; + case 'mistral': + response = await queryMistral(systemPrompt, task, provider, requestedModel); + break; + case 'cohere': + response = await queryCohere(systemPrompt, task, provider, requestedModel); + break; + case 'lmstudio': + response = await queryLMStudio(systemPrompt, task, provider, requestedModel); + break; + case 'ollama': + response = await queryOllama(systemPrompt, task, provider, requestedModel); + break; + default: + // Fallback to Hanzo AI for any other providers + response = await queryHanzoAI(systemPrompt, task, provider, requestedModel); + } + } + + return response; + } catch (error: any) { + throw new Error(`${agent.name} failed: ${error.message}`); + } +} + +async function queryHanzoAI(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + `${provider.endpoint}/llm/chat`, + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: task } + ], + model: model || provider.models[0] || 'gpt-4o', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${provider.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; +} + +async function queryOpenAI(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + 'https://api.openai.com/v1/chat/completions', + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: task } + ], + model: model || 'gpt-4o', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${provider.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; +} + +async function queryAnthropic(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + 'https://api.anthropic.com/v1/messages', + { + messages: [ + { role: 'user', content: task } + ], + model: model || 'claude-4', + system: systemPrompt, + max_tokens: 4096 + }, + { + headers: { + 'x-api-key': provider.apiKey, + 'anthropic-version': '2023-06-01', + 'Content-Type': 'application/json' + } + } + ); + + return response.data.content[0].text; +} + +async function queryGoogle(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + // Google/Gemini via their API + const endpoint = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent'; + const response = await axios.post( + `${endpoint}?key=${provider.apiKey}`, + { + contents: [{ + parts: [{ + text: `${systemPrompt}\n\nUser: ${task}` + }] + }], + generationConfig: { + temperature: 0.7, + maxOutputTokens: 4096 + } + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + return response.data.candidates[0].content.parts[0].text; +} + +async function queryMistral(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + 'https://api.mistral.ai/v1/chat/completions', + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: task } + ], + model: model || 'mistral-large-latest', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${provider.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; +} + +async function queryCohere(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + 'https://api.cohere.ai/v1/chat', + { + message: task, + preamble: systemPrompt, + model: model || 'command-r', + temperature: 0.7 + }, + { + headers: { + 'Authorization': `Bearer ${provider.apiKey}`, + 'Content-Type': 'application/json' + } + } + ); + + return response.data.text; +} + +async function queryLMStudio(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + `${provider.endpoint}/chat/completions`, + { + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: task } + ], + model: model || 'local-model', + temperature: 0.7 + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + return response.data.choices[0].message.content; +} + +async function queryOllama(systemPrompt: string, task: string, provider: LLMProvider, model?: string): Promise { + const response = await axios.post( + `${provider.endpoint}/api/generate`, + { + model: model || 'llama2', + prompt: `${systemPrompt}\n\nUser: ${task}\nAssistant:`, + stream: false + }, + { + headers: { + 'Content-Type': 'application/json' + } + } + ); + + return response.data.response; +} + +function formatAgentResults( + agents: Array<{ name: string; role: string; tools?: string[] }>, + results: string[], + provider: LLMProvider +): string { + let output = '# Multi-Agent Task Results\n\n'; + output += `**LLM Provider**: ${provider.name}${provider.endpoint ? ` (${provider.endpoint})` : ''}\n\n`; + + agents.forEach((agent, index) => { + output += `## ${agent.name}\n`; + output += `**Role:** ${agent.role}\n`; + output += `**Tools:** ${agent.tools?.join(', ') || 'all available'}\n\n`; + output += `### Result:\n${results[index]}\n\n`; + output += '---\n\n'; + }); + + return output; } \ No newline at end of file diff --git a/src/mcp/tools/bash.ts b/src/mcp/tools/bash.ts index 518c095..d8713ae 100644 --- a/src/mcp/tools/bash.ts +++ b/src/mcp/tools/bash.ts @@ -259,8 +259,8 @@ export class BashTools { // Execute command return new Promise((resolve, reject) => { const proc = cp.exec(command, { - cwd: session.cwd, - env: session.env, + cwd: session?.cwd || process.cwd(), + env: session?.env || process.env, timeout, maxBuffer: 10 * 1024 * 1024 // 10MB }, (error, stdout, stderr) => { diff --git a/src/mcp/tools/browser.ts b/src/mcp/tools/browser.ts new file mode 100644 index 0000000..00d780f --- /dev/null +++ b/src/mcp/tools/browser.ts @@ -0,0 +1,317 @@ +import * as vscode from 'vscode'; +import { MCPTool } from '../server'; +import * as cp from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs'; + +interface BrowserAction { + action: 'navigate' | 'screenshot' | 'click' | 'type' | 'extract' | 'wait' | 'evaluate'; + url?: string; + selector?: string; + text?: string; + script?: string; + timeout?: number; + outputPath?: string; +} + +export function createBrowserTools(context: vscode.ExtensionContext): MCPTool[] { + return [ + { + name: 'browser', + description: 'Control a browser instance via Playwright. Automatically installs Playwright MCP if needed.', + inputSchema: { + type: 'object', + properties: { + action: { + type: 'string', + enum: ['navigate', 'screenshot', 'click', 'type', 'extract', 'wait', 'evaluate', 'install'], + description: 'Browser action to perform' + }, + url: { + type: 'string', + description: 'URL to navigate to (for navigate action)' + }, + selector: { + type: 'string', + description: 'CSS selector for click/type/extract actions' + }, + text: { + type: 'string', + description: 'Text to type (for type action)' + }, + script: { + type: 'string', + description: 'JavaScript to evaluate (for evaluate action)' + }, + timeout: { + type: 'number', + description: 'Timeout in milliseconds (default: 30000)', + default: 30000 + }, + outputPath: { + type: 'string', + description: 'Path to save screenshot (for screenshot action)' + } + }, + required: ['action'] + }, + handler: async (args: BrowserAction) => { + const playwrightMcpPath = await ensurePlaywrightMCP(context); + + if (args.action === 'install') { + return `✅ Playwright MCP installed at: ${playwrightMcpPath}`; + } + + // Check if browser instance is running + const browserState = context.globalState.get<{ pid?: number }>('browserState', {}); + + if (!browserState.pid || !isProcessRunning(browserState.pid)) { + // Start browser instance + const result = await startBrowser(context, playwrightMcpPath); + if (result.error) { + return `Error starting browser: ${result.error}`; + } + browserState.pid = result.pid; + await context.globalState.update('browserState', browserState); + } + + // Execute browser action + try { + const result = await executeBrowserAction(args, playwrightMcpPath); + return result; + } catch (error: any) { + return `Browser action failed: ${error.message}`; + } + } + }, + { + name: 'browser_close', + description: 'Close the browser instance', + inputSchema: { + type: 'object', + properties: {} + }, + handler: async () => { + const browserState = context.globalState.get<{ pid?: number }>('browserState', {}); + + if (browserState.pid && isProcessRunning(browserState.pid)) { + process.kill(browserState.pid); + await context.globalState.update('browserState', {}); + return '✅ Browser closed'; + } + + return 'No browser instance running'; + } + } + ]; +} + +async function ensurePlaywrightMCP(context: vscode.ExtensionContext): Promise { + const extensionPath = context.extensionPath; + const playwrightDir = path.join(extensionPath, '.playwright-mcp'); + const mcpServerPath = path.join(playwrightDir, 'node_modules', '@modelcontextprotocol', 'server-playwright', 'dist', 'index.js'); + + // Check if already installed + if (fs.existsSync(mcpServerPath)) { + return mcpServerPath; + } + + // Install Playwright MCP + console.log('Installing Playwright MCP server...'); + + // Create directory + if (!fs.existsSync(playwrightDir)) { + fs.mkdirSync(playwrightDir, { recursive: true }); + } + + // Create package.json + const packageJson = { + name: 'playwright-mcp-wrapper', + version: '1.0.0', + private: true, + dependencies: { + '@modelcontextprotocol/server-playwright': 'latest', + 'playwright': 'latest' + } + }; + + fs.writeFileSync( + path.join(playwrightDir, 'package.json'), + JSON.stringify(packageJson, null, 2) + ); + + // Install dependencies + return new Promise((resolve, reject) => { + const npm = cp.spawn('npm', ['install'], { + cwd: playwrightDir, + stdio: 'pipe' + }); + + npm.on('close', (code) => { + if (code === 0) { + // Install browsers + const npx = cp.spawn('npx', ['playwright', 'install', 'chromium'], { + cwd: playwrightDir, + stdio: 'pipe' + }); + + npx.on('close', (code) => { + if (code === 0) { + resolve(mcpServerPath); + } else { + reject(new Error('Failed to install Playwright browsers')); + } + }); + } else { + reject(new Error('Failed to install Playwright MCP')); + } + }); + }); +} + +function isProcessRunning(pid: number): boolean { + try { + process.kill(pid, 0); + return true; + } catch { + return false; + } +} + +async function startBrowser(context: vscode.ExtensionContext, mcpServerPath: string): Promise<{ pid?: number; error?: string }> { + return new Promise((resolve) => { + const browser = cp.spawn('node', [mcpServerPath], { + stdio: 'pipe', + env: { + ...process.env, + PLAYWRIGHT_BROWSERS_PATH: path.join(context.extensionPath, '.playwright-mcp', 'browsers') + } + }); + + browser.on('error', (error) => { + resolve({ error: error.message }); + }); + + browser.stdout.on('data', (data) => { + console.log('Browser stdout:', data.toString()); + }); + + browser.stderr.on('data', (data) => { + console.error('Browser stderr:', data.toString()); + }); + + // Give browser time to start + setTimeout(() => { + resolve({ pid: browser.pid }); + }, 2000); + }); +} + +async function executeBrowserAction(action: BrowserAction, mcpServerPath: string): Promise { + // For now, we'll execute actions through a simple command interface + // In a full implementation, this would communicate with the MCP server + + const command = buildPlaywrightCommand(action); + + return new Promise((resolve, reject) => { + cp.exec(command, { + env: { + ...process.env, + NODE_PATH: path.dirname(mcpServerPath) + } + }, (error, stdout, stderr) => { + if (error) { + reject(new Error(`Browser action failed: ${error.message}\n${stderr}`)); + } else { + resolve(formatActionResult(action, stdout)); + } + }); + }); +} + +function buildPlaywrightCommand(action: BrowserAction): string { + const script = ` +const { chromium } = require('playwright'); + +(async () => { + const browser = await chromium.launch({ headless: false }); + const page = await browser.newPage(); + + try { + ${generateActionCode(action)} + } finally { + // Keep browser open for reuse + // await browser.close(); + } +})(); + `; + + return `node -e "${script.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`; +} + +function generateActionCode(action: BrowserAction): string { + switch (action.action) { + case 'navigate': + return `await page.goto('${action.url}', { timeout: ${action.timeout} }); + console.log('Navigated to:', '${action.url}');`; + + case 'screenshot': + const screenshotPath = action.outputPath || 'screenshot.png'; + return `await page.screenshot({ path: '${screenshotPath}' }); + console.log('Screenshot saved to:', '${screenshotPath}');`; + + case 'click': + return `await page.click('${action.selector}', { timeout: ${action.timeout} }); + console.log('Clicked:', '${action.selector}');`; + + case 'type': + return `await page.type('${action.selector}', '${action.text}', { timeout: ${action.timeout} }); + console.log('Typed text into:', '${action.selector}');`; + + case 'extract': + return `const text = await page.textContent('${action.selector}'); + console.log('Extracted:', text);`; + + case 'wait': + return `await page.waitForSelector('${action.selector}', { timeout: ${action.timeout} }); + console.log('Element appeared:', '${action.selector}');`; + + case 'evaluate': + return `const result = await page.evaluate(() => { ${action.script} }); + console.log('Evaluation result:', JSON.stringify(result));`; + + default: + return `console.log('Unknown action: ${action.action}');`; + } +} + +function formatActionResult(action: BrowserAction, output: string): string { + const lines = output.trim().split('\n'); + const lastLine = lines[lines.length - 1] || ''; + + switch (action.action) { + case 'navigate': + return `✅ Navigated to: ${action.url}`; + + case 'screenshot': + return `📸 Screenshot saved to: ${action.outputPath || 'screenshot.png'}`; + + case 'click': + return `🖱️ Clicked element: ${action.selector}`; + + case 'type': + return `⌨️ Typed "${action.text}" into: ${action.selector}`; + + case 'extract': + return `📝 Extracted text: ${lastLine.replace('Extracted: ', '')}`; + + case 'wait': + return `⏳ Element appeared: ${action.selector}`; + + case 'evaluate': + return `🔧 Evaluation result: ${lastLine.replace('Evaluation result: ', '')}`; + + default: + return output; + } +} \ No newline at end of file diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index 06b774c..29f4902 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -28,6 +28,7 @@ import { BatchTools } from './batch'; import { AITools } from './ai-tools'; import { createModeTool } from './mode'; import { createMCPRunnerTools } from './mcp-runner'; +import { createBrowserTools } from './browser'; // import { createASTAnalyzerTool } from './ast-analyzer'; // import { createTreeSitterAnalyzerTool } from './treesitter-analyzer'; @@ -80,7 +81,8 @@ export class MCPTools { createWebFetchTool(this.context), createZenTool(this.context), createModeTool(this.context), - ...createMCPRunnerTools(this.context) + ...createMCPRunnerTools(this.context), + ...createBrowserTools(this.context) // createASTAnalyzerTool(this.context), // createTreeSitterAnalyzerTool(this.context) ]; @@ -142,7 +144,9 @@ export class MCPTools { // Utility 'batch', 'web_fetch', 'batch_search', // MCP - 'mcp' + 'mcp', + // Browser + 'browser', 'browser_close' ]); } else { this.enabledTools = new Set(enabled); @@ -221,7 +225,7 @@ export class MCPTools { filesystem: this.countToolsInCategory(['read', 'write', 'edit', 'multi_edit', 'directory_tree']), search: this.countToolsInCategory(['grep', 'search', 'symbols', 'find_files']), shell: this.countToolsInCategory(['run_command', 'bash', 'open']), - ai: this.countToolsInCategory(['dispatch_agent', 'llm', 'consensus']), + ai: this.countToolsInCategory(['agent', 'llm', 'consensus']), development: this.countToolsInCategory(['todo_read', 'todo_write', 'notebook_read', 'notebook_edit']) } }; diff --git a/src/mcp/tools/mode.ts b/src/mcp/tools/mode.ts index ca92e45..904f8ed 100644 --- a/src/mcp/tools/mode.ts +++ b/src/mcp/tools/mode.ts @@ -12,15 +12,161 @@ interface DevelopmentMode { } const DEVELOPMENT_MODES: Record = { - // Language Creators + // Language Creators - Original Languages + 'ritchie': { + name: 'ritchie', + programmer: 'Dennis Ritchie', + description: 'C creator - UNIX philosophy', + philosophy: 'UNIX: Do one thing and do it well', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'run_command'], + config: { simplicity: 10, portability: 10, efficiency: 10 } + }, + 'bjarne': { + name: 'bjarne', + programmer: 'Bjarne Stroustrup', + description: 'C++ creator - zero-overhead abstraction', + philosophy: 'C++: Light-weight abstraction', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'critic'], + config: { abstraction: 9, performance: 10, compatibility: 8 } + }, + 'gosling': { + name: 'gosling', + programmer: 'James Gosling', + description: 'Java creator - write once, run anywhere', + philosophy: 'Java: Platform independence', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'critic', 'think'], + config: { portability: 10, safety: 9, verbosity: 7 } + }, 'guido': { name: 'guido', programmer: 'Guido van Rossum', description: 'Python creator - readability counts', philosophy: 'There should be one-- and preferably only one --obvious way to do it', - tools: ['read', 'write', 'edit', 'grep', 'symbols', 'uvx', 'think'], + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'uvx', 'think', 'notebook_read', 'notebook_edit'], config: { readability: 10, simplicity: 9, explicitness: 10 } }, + 'matz': { + name: 'matz', + programmer: 'Yukihiro Matsumoto', + description: 'Ruby creator - developer happiness', + philosophy: 'Ruby is designed to make programmers happy', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'run_command'], + config: { happiness: 10, expressiveness: 10, principle_of_least_surprise: 9 } + }, + 'wall': { + name: 'wall', + programmer: 'Larry Wall', + description: 'Perl creator - TMTOWTDI', + philosophy: "There's More Than One Way To Do It", + tools: ['read', 'write', 'edit', 'grep', 'bash', 'run_command', 'content_replace'], + config: { flexibility: 10, expressiveness: 10, readability: 5 } + }, + 'rasmus': { + name: 'rasmus', + programmer: 'Rasmus Lerdorf', + description: 'PHP creator - pragmatic web development', + philosophy: 'PHP: Solving web problems pragmatically', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'run_command', 'web_fetch'], + config: { pragmatism: 10, web_focus: 10, consistency: 6 } + }, + 'brendan': { + name: 'brendan', + programmer: 'Brendan Eich', + description: 'JavaScript creator - move fast and evolve', + philosophy: 'Always bet on JavaScript', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'npx', 'web_fetch', 'run_command'], + config: { speed: 10, flexibility: 9, backwards_compatibility: 8 } + }, + 'anders': { + name: 'anders', + programmer: 'Anders Hejlsberg', + description: 'C#/TypeScript/Delphi - pragmatic language design', + philosophy: 'Pragmatism over dogmatism', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'run_command', 'think'], + config: { pragmatism: 10, tooling: 10, evolution: 9 } + }, + 'wirth': { + name: 'wirth', + programmer: 'Niklaus Wirth', + description: 'Pascal creator - structured programming', + philosophy: 'Algorithms + Data Structures = Programs', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'think'], + config: { structure: 10, clarity: 10, simplicity: 9 } + }, + 'mccarthy': { + name: 'mccarthy', + programmer: 'John McCarthy', + description: 'Lisp creator - code as data', + philosophy: 'Lisp: The programmable programming language', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'think', 'critic'], + config: { homoiconicity: 10, flexibility: 10, parentheses: 10 } + }, + 'hickey': { + name: 'hickey', + programmer: 'Rich Hickey', + description: 'Clojure creator - simplicity matters', + philosophy: 'Simple Made Easy', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'think', 'critic'], + config: { simplicity: 10, immutability: 10, expressiveness: 9 } + }, + 'armstrong': { + name: 'armstrong', + programmer: 'Joe Armstrong', + description: 'Erlang creator - let it crash', + philosophy: 'Let it crash and recover', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'processes', 'run_background'], + config: { fault_tolerance: 10, concurrency: 10, distribution: 9 } + }, + 'odersky': { + name: 'odersky', + programmer: 'Martin Odersky', + description: 'Scala creator - scalable language', + philosophy: 'Fusion of functional and object-oriented programming', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'think'], + config: { scalability: 10, expressiveness: 9, type_safety: 10 } + }, + 'lattner': { + name: 'lattner', + programmer: 'Chris Lattner', + description: 'Swift/LLVM creator - performance with safety', + philosophy: 'Performance and safety without compromise', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'critic'], + config: { safety: 10, performance: 10, expressiveness: 8 } + }, + 'bak': { + name: 'bak', + programmer: 'Lars Bak', + description: 'Dart/V8 creator - structured web programming', + philosophy: 'Fast development and execution', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'web_fetch'], + config: { performance: 10, structure: 9, tooling: 10 } + }, + 'backus': { + name: 'backus', + programmer: 'John Backus', + description: 'Fortran creator - scientific computing', + philosophy: 'Formula Translation for scientists', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'run_command'], + config: { performance: 10, scientific_computing: 10, legacy: 10 } + }, + 'hopper': { + name: 'hopper', + programmer: 'Grace Hopper', + description: 'COBOL creator - business language', + philosophy: 'Programming for everyone', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'think'], + config: { readability: 9, business_focus: 10, verbosity: 8 } + }, + 'kay': { + name: 'kay', + programmer: 'Alan Kay', + description: 'Smalltalk creator - OOP pioneer', + philosophy: 'The best way to predict the future is to invent it', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'think', 'critic'], + config: { object_orientation: 10, messaging: 10, simplicity: 9 } + }, + + // Systems & Infrastructure 'linus': { name: 'linus', programmer: 'Linus Torvalds', @@ -29,15 +175,145 @@ const DEVELOPMENT_MODES: Record = { tools: ['read', 'write', 'edit', 'grep', 'git_search', 'bash', 'processes', 'critic'], config: { performance: 10, directness: 10, patience: 2 } }, - 'brendan': { - name: 'brendan', - programmer: 'Brendan Eich', - description: 'JavaScript creator - move fast and evolve', - philosophy: 'Always bet on JavaScript', - tools: ['read', 'write', 'edit', 'grep', 'symbols', 'npx', 'web_fetch'], - config: { speed: 10, flexibility: 9, backwards_compatibility: 8 } + 'ritchie_thompson': { + name: 'ritchie_thompson', + programmer: 'Dennis Ritchie & Ken Thompson', + description: 'UNIX creators - minimalist philosophy', + philosophy: 'Keep it simple, stupid', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'processes', 'run_command'], + config: { minimalism: 10, composability: 10, elegance: 10 } }, - + + // Web Frameworks + 'dhh': { + name: 'dhh', + programmer: 'David Heinemeier Hansson', + description: 'Ruby on Rails creator - convention over configuration', + philosophy: 'Optimize for programmer happiness', + tools: ['read', 'write', 'edit', 'multi_edit', 'grep', 'bash', 'run_command', 'sql_query'], + config: { productivity: 10, conventions: 10, opinionated: 10 } + }, + 'evan': { + name: 'evan', + programmer: 'Evan You', + description: 'Vue.js creator - progressive framework', + philosophy: 'Approachable, versatile, performant', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'web_fetch', 'run_command'], + config: { approachability: 10, flexibility: 9, performance: 8 } + }, + 'walke': { + name: 'walke', + programmer: 'Jordan Walke', + description: 'React creator - declarative UI', + philosophy: 'UI as a function of state', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'web_fetch', 'symbols'], + config: { declarative: 10, component_based: 10, virtual_dom: 9 } + }, + 'otwell': { + name: 'otwell', + programmer: 'Taylor Otwell', + description: 'Laravel creator - PHP elegance', + philosophy: 'The PHP framework for web artisans', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'sql_query', 'run_command'], + config: { elegance: 10, expressiveness: 9, developer_experience: 10 } + }, + 'holovaty_willison': { + name: 'holovaty_willison', + programmer: 'Adrian Holovaty & Simon Willison', + description: 'Django creators - web framework for perfectionists', + philosophy: 'The web framework for perfectionists with deadlines', + tools: ['read', 'write', 'edit', 'grep', 'uvx', 'sql_query', 'run_command'], + config: { batteries_included: 10, security: 10, rapid_development: 9 } + }, + 'ronacher': { + name: 'ronacher', + programmer: 'Armin Ronacher', + description: 'Flask/Jinja creator - micro framework', + philosophy: 'Web development, one drop at a time', + tools: ['read', 'write', 'edit', 'grep', 'uvx', 'run_command'], + config: { minimalism: 10, flexibility: 10, extensibility: 9 } + }, + 'holowaychuk': { + name: 'holowaychuk', + programmer: 'TJ Holowaychuk', + description: 'Express.js creator - minimalist web framework', + philosophy: 'Fast, unopinionated, minimalist', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'run_command'], + config: { minimalism: 10, middleware: 10, flexibility: 9 } + }, + + // JavaScript Ecosystem + 'katz': { + name: 'katz', + programmer: 'Yehuda Katz', + description: 'Ember.js creator - ambitious web apps', + philosophy: 'Convention over Configuration', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'run_command', 'symbols'], + config: { conventions: 10, productivity: 9, stability: 10 } + }, + 'ashkenas': { + name: 'ashkenas', + programmer: 'Jeremy Ashkenas', + description: 'CoffeeScript/Backbone creator - JavaScript, the good parts', + philosophy: 'It\'s just JavaScript', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'run_command'], + config: { elegance: 10, simplicity: 9, readability: 8 } + }, + 'nolen': { + name: 'nolen', + programmer: 'David Nolen', + description: 'ClojureScript lead - functional web development', + philosophy: 'Functional programming for the web', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'symbols', 'think'], + config: { functional: 10, immutability: 10, performance: 9 } + }, + + // Modern Languages + 'graydon': { + name: 'graydon', + programmer: 'Graydon Hoare', + description: 'Rust creator - memory safety without GC', + philosophy: 'Fast, reliable, productive — pick three', + tools: ['read', 'write', 'edit', 'grep', 'symbols', 'bash', 'critic', 'run_command'], + config: { safety: 10, performance: 10, concurrency: 9 } + }, + 'pike_thompson': { + name: 'pike_thompson', + programmer: 'Rob Pike & Ken Thompson', + description: 'Go creators - simplicity at scale', + philosophy: 'Less is exponentially more', + tools: ['read', 'write', 'edit', 'grep', 'bash', 'run_command', 'processes'], + config: { simplicity: 10, concurrency: 10, pragmatism: 9 } + }, + + // Database & Infrastructure + 'widenius': { + name: 'widenius', + programmer: 'Michael Widenius', + description: 'MySQL/MariaDB creator - open source database', + philosophy: 'Open source database for everyone', + tools: ['read', 'write', 'edit', 'sql_query', 'bash', 'run_command'], + config: { openness: 10, performance: 9, compatibility: 8 } + }, + + // CSS & Design + 'wathan': { + name: 'wathan', + programmer: 'Adam Wathan', + description: 'Tailwind CSS creator - utility-first CSS', + philosophy: 'Stop writing CSS, start building designs', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'web_fetch'], + config: { utility_first: 10, customization: 9, productivity: 10 } + }, + 'otto_thornton': { + name: 'otto_thornton', + programmer: 'Mark Otto & Jacob Thornton', + description: 'Bootstrap creators - responsive web design', + philosophy: 'Build responsive, mobile-first projects', + tools: ['read', 'write', 'edit', 'grep', 'npx', 'web_fetch'], + config: { responsiveness: 10, components: 9, consistency: 10 } + }, + // Special Configurations 'fullstack': { name: 'fullstack', @@ -132,9 +408,24 @@ export function createModeTool(context: vscode.ExtensionContext): MCPTool { // Group modes by category const categories = { - 'Language Creators': ['guido', 'linus', 'brendan'], - 'Special Configurations': ['fullstack', 'minimal', '10x', 'security', - 'data_scientist', 'hanzo'] + 'Language Creators': [ + 'ritchie', 'bjarne', 'gosling', 'guido', 'matz', 'wall', + 'rasmus', 'brendan', 'anders', 'wirth', 'mccarthy', 'hickey', + 'armstrong', 'odersky', 'lattner', 'bak', 'backus', 'hopper', 'kay' + ], + 'Systems & Infrastructure': ['linus', 'ritchie_thompson'], + 'Web Frameworks': [ + 'dhh', 'evan', 'walke', 'otwell', 'holovaty_willison', + 'ronacher', 'holowaychuk' + ], + 'JavaScript Ecosystem': ['katz', 'ashkenas', 'nolen'], + 'Modern Languages': ['graydon', 'pike_thompson'], + 'Database & Infrastructure': ['widenius'], + 'CSS & Design': ['wathan', 'otto_thornton'], + 'Special Configurations': [ + 'fullstack', 'minimal', '10x', 'security', + 'data_scientist', 'hanzo' + ] }; for (const [category, modeNames] of Object.entries(categories)) {