diff --git a/README.md b/README.md index 18a7c8f..cccd81a 100644 --- a/README.md +++ b/README.md @@ -1,361 +1,445 @@ # RDContext -**Local, Private, and AI-Ready Code Documentation Server** +**Servidor Local, Privado e Otimizado para IA de Documentação de Código** -RDContext is a local-first, privacy-focused tool to build AI-friendly context for any library based on its documentation files — including private repositories. Extract, index, and serve documentation for AI coding assistants, IDEs, and LLM workflows. Get better results. +RDContext é uma ferramenta local e focada em privacidade para construir contexto amigável à IA para qualquer biblioteca baseada em seus arquivos de documentação — incluindo repositórios privados. Extraia, indexe e sirva documentação para assistentes de IA, IDEs e fluxos de trabalho com LLM. --- -## Overview +## Início Rápido -RDContext MCP pulls up-to-date, version-specific, relevant documentation and code examples from a GitHub repository and makes it available to your IDE. +### 🚀 Instalação Automatizada (Recomendada) -Add `use rdcontext` to your prompt in Cursor: +```bash +# Clone o repositório +git clone https://github.com/resultadosdigitais/rdcontext.git +cd rdcontext -``` -Add a collapsible sidebar shadcn to the base layout of the app. use shadcn-ui, use rdcontext +# Dar permissão de execução ao script +chmod +x install-rdcontext-cursor.sh + +# Execute o script de instalação +./install-rdcontext-cursor.sh ``` -RDContext fetches up-to-date code examples and documentation right into your LLM's context. +Este script irá: +- ✅ Verificar versão do Node.js (18.12+ obrigatório, 20+ LTS recomendado) +- ✅ Instalar rdcontext globalmente +- ✅ Configurar API keys (Gemini/OpenAI) de forma segura +- ✅ Configurar token do GitHub para repos privados +- ✅ Configurar MCP para o Cursor automaticamente +- ✅ Adicionar bibliotecas de exemplo (FrontHub, Tangram) -1. Write your prompt -2. Tell the LLM to use RDContext -3. Get working code answers +### 📋 Instalação Manual -No tab-switching, no hallucinated APIs that don't exist, no outdated code generations. +**Requisitos:** +- Node.js 18.12+ (20+ LTS recomendado) +- npm ou bun +- Git -## How it works +```bash +# Instalar globalmente +npm install -g rdcontext -1. **Add a Library:** - Use the CLI to fetch documentation files (Markdown/MDX) from the specified repo/branch/tag/folders. - For private repos, supply a GitHub token. +# Ou usar diretamente +npx rdcontext --help +``` -2. **AI Extraction:** - Each documentation file is processed by a LLM to extract code snippets, titles, and descriptions optimized for LLM retrieval. +--- -3. **Local Indexing:** - All extracted data is stored in a local libSQL database in your user data directory. +## Visão Geral -4. **Query & Serve:** - Use the CLI to query docs/snippets, or start the MCP server to integrate with AI tools. +O RDContext MCP busca documentação e exemplos de código atualizados e específicos de versão de repositórios GitHub e os disponibiliza para sua IDE. -## Features +Adicione `use rdcontext` ao seu prompt no Cursor: -- **CLI:** Add, list and remove documentation of your tech stack using our CLI. -- **MCP Server:** Exposes a Model Context Protocol (MCP) server for integration with AI tools (Cursor, Windsurf, etc.). -- **Local and Private:** All data is stored locally using [libSQL](https://github.com/tursodatabase/libsql). No cloud or third-party storage required. -- **Customizable:** Choose which folders/files to index, and control which branches/tags to use. -- **Internal Library Support:** Add documentation from private GitHub repositories using a personal access token. -- **Cross-Platform:** Works on Linux, macOS, and Windows. +``` +Crie um componente Button usando o Tangram Design System, use rdcontext +``` ---- +O RDContext busca exemplos de código e documentação atualizados diretamente no contexto do seu LLM. -## Installation +1. Escreva seu prompt +2. Diga ao LLM para usar RDContext +3. Obtenha respostas de código funcionais -You can install RDContext globally via npm: +Sem mudança de abas, sem APIs alucinadas, sem gerações de código desatualizadas. -```bash -npm install -g rdcontext -``` +## Como funciona -Or use it directly with `npx` (no installation required): +1. **Adicionar uma Biblioteca:** + Use a CLI para buscar arquivos de documentação (Markdown/MDX) de repo/branch/tag/pastas especificadas. -```bash -npx -y rdcontext -``` +2. **Extração por IA:** + Cada arquivo de documentação é processado por LLM para extrair snippets de código, títulos e descrições otimizadas para recuperação. ---- +3. **Indexação Local:** + Todos os dados extraídos são armazenados em um banco de dados SQLite local no diretório de dados do usuário. -## Environment Setup +4. **Consulta e Servir:** + Use a CLI para consultar docs/snippets, ou inicie o servidor MCP para integrar com ferramentas de IA. -**You must set the `OPENAI_API_KEY` environment variable for RDContext to work.** +## Funcionalidades -```bash -export OPENAI_API_KEY=sk-... -``` - -You can get your API key from [OpenAI's dashboard](https://platform.openai.com/api-keys). +- **CLI:** Adicione, liste e remova documentação usando nossa CLI +- **Servidor MCP:** Servidor Model Context Protocol para o Cursor +- **Local e Privado:** Todos os dados armazenados localmente usando SQLite. Sem nuvem necessária +- **Personalizável:** Escolha pastas/arquivos para indexar, controle branches/tags +- **Repos Privados:** Adicione documentação de repositórios GitHub privados +- **Multiplataforma:** Funciona no Linux, macOS e Windows --- -## Usage +## Configuração do Ambiente + +### API Keys -### CLI Overview +**Obrigatório:** Configure pelo menos uma API key de provedor de IA: -All commands are available via the `rdcontext` CLI (or `npx -y rdcontext `). +#### Instalação Interativa (Recomendado) -#### Add a Library +O script de instalação sempre pergunta ao usuário pelas configurações necessárias: -Index documentation from a GitHub repository (public or private): +- **API Keys** são solicitadas interativamente +- **GitHub Token** é configurado conforme escolha do usuário +- **Provedor de IA** é selecionado pelo usuário +- **Configurações MCP** são criadas automaticamente + +#### Configuração Manual ```bash -rdcontext add [--branch ] [--tag ] [--folders ...] [--token ] +# Para Gemini (recomendado) +export GEMINI_API_KEY="sua-chave-aqui" +export AI_PROVIDER="gemini" + +# Para OpenAI (alternativo) +export OPENAI_API_KEY="sua-chave-aqui" +export AI_PROVIDER="openai" ``` -- `--branch `: Git branch to index (default: repo default branch) -- `--tag `: Git tag to index (mutually exclusive with `--branch`) -- `--folders ...`: Only index documentation in these folders (default: all) -- `--token `: GitHub token for private repo access +**Configuração via arquivo .env:** +```bash +# ~/.env ou ~/.bashrc ou ~/.zshrc +export GEMINI_API_KEY="sua-api-key-do-gemini" +export OPENAI_API_KEY="sua-api-key-do-openai" # opcional +export AI_PROVIDER="gemini" # ou "openai" +``` -**Examples:** +Obtenha suas chaves: +- **Gemini:** https://makersuite.google.com/app/apikey +- **OpenAI:** https://platform.openai.com/api-keys -Add up-to-date RDContext documentation: +### Token do GitHub (Opcional) + +Para repositórios privados: ```bash -rdcontext add cozmo-dev/rdcontext --branch main +export GITHUB_TOKEN=ghp_seu_token_github_aqui ``` -Add documentation of a specific ShadCN UI version: +Obtenha seu token: https://github.com/settings/tokens + +--- + +## Uso + +### Comandos da CLI + +#### Adicionar uma Biblioteca ```bash -rdcontext add shadcn-ui/ui --tag shadcn-ui@0.9.4 +rdcontext add [--branch ] [--tag ] [--folders ] [--token ] ``` -Add documentation of a private repo of your GitHub org: +**Exemplos:** ```bash -rdcontext add myorg/myrepo --branch main --folders docs src/guides --token ghp_xxx +# Adicionar o Tangram (design system) +rdcontext add "resultadosdigitais/tangram" --folders "docs/examples/components" "docs/docs" "docs/code" --token ghp_xxx + +# Adicionar o FrontHub (microfrontends) +rdcontext add "resultadosdigitais/front-hub" --folders "packages/front-hub-docs/docs" --token ghp_xxx + +# Adicionar versão específica +rdcontext add "shadcn-ui/ui" --tag v0.9.4 + +# Repo privado com token +rdcontext add "myorg/myrepo" --folders "docs" --token ghp_xxx ``` -#### List Indexed Libraries +#### Listar Bibliotecas ```bash rdcontext list ``` -#### Get Documentation - -Fetch up-to-date documentation for a library, optionally filtered by topic: +#### Consultar Documentação ```bash -rdcontext get [topic] [--k ] +rdcontext get [tópico] [--k ] ``` -- `topic`: (optional) Focus on a specific topic (e.g., "hooks", "routing") -- `--k`: Number of top snippets to return (default: 10) +**Exemplos:** +```bash +# Buscar exemplos de botões +rdcontext get resultadosdigitais/tangram "botão" -**Example:** +# Buscar exemplos de componentes +rdcontext get resultadosdigitais/front-hub "componente" -```bash -rdcontext get shadcn-ui/ui "Select" +# Buscar padrões de design +rdcontext get resultadosdigitais/tangram "padrões de design" ``` -#### Remove a Library +#### Remover Biblioteca ```bash rdcontext rm ``` -#### Start the MCP Server - -Expose the documentation server for AI tools (Cursor, Windsurf, etc.): - -```bash -rdcontext start [--transport stdio|httpStream] [--port ] -``` -- `--transport`: Communication method (`stdio` for local, `httpStream` for HTTP API, default: `stdio`) -- `--port`: Port for HTTP transport (default: 3000) --- -### MCP server - -RDContext exposes a Model Context Protocol (MCP) server, making it easy to integrate with popular AI coding tools and IDEs. +## Integração com o Cursor -Requirements: +### 🚀 Configuração Automática (Recomendada) -- Node.js >= v18.0.0 -- Cursor, Windsurf, Claude Desktop or another MCP Client +Use o script de instalação que configura automaticamente o MCP: -
-Cursor +```bash +./install-rdcontext-cursor.sh +``` -Go to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server` +### ⚙️ Configuração Manual -Pasting the following configuration into your Cursor `~/.cursor/mcp.json` file is the recommended approach. You may also install in a specific project by creating `.cursor/mcp.json` in your project folder. See [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) for more info. +Se preferir configurar manualmente, adicione ao `~/.cursor/mcp.json`: ```json { "mcpServers": { - "libcontext": { - "command": "libcontext", + "rdcontext": { + "command": "rdcontext", "args": ["start"], "env": { - "OPENAI_API_KEY": "sk-..." + "AI_PROVIDER": "gemini", + "GEMINI_API_KEY": "sua-api-key-aqui", + "GEMINI_EMBEDDING_MODEL": "text-embedding-004" } } } } ``` -
-Alternative: Without global installation +### 🔧 Como usar no Cursor -Or if you have not installed globally: +1. **Instale o rdcontext** usando o script de instalação +2. **Reinicie o Cursor** para aplicar as configurações MCP +3. **Digite no editor**: `"Mostre exemplos de botões do Tangram"` +4. **Use o contexto**: O rdcontext fornecerá exemplos reais e atualizados -```json -{ - "mcpServers": { - "rdcontext": { - "command": "npx", - "args": ["-y", "rdcontext", "start"], - "env": { - "OPENAI_API_KEY": "sk-..." - } - } - } -} +--- + +## Requisitos de Versão do Node.js + +**Mínimo:** Node.js 18.12+ +**Recomendado:** Node.js 20+ LTS + +O RDContext usa recursos modernos do JavaScript: +- ES Modules (`import`/`export`) +- `await` de nível superior +- API Fetch nativa +- APIs crypto modernas + +### Solução de Problemas do Node.js + +**Verificar versão:** +```bash +node --version ``` -
+**Atualizar Node.js:** +```bash +# Ubuntu/Debian +curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - +sudo apt-get install -y nodejs -
-Alternative: Using with Bun runtime +# macOS +brew install node -```json -{ - "mcpServers": { - "rdcontext": { - "command": "bunx", - "args": ["-y", "rdcontext", "start"], - "env": { - "OPENAI_API_KEY": "sk-..." - } - } - } -} +# Ou use nvm +nvm install --lts +nvm use --lts ``` -
+**Erros comuns:** +- `SyntaxError: Unexpected token 'export'` → Atualize o Node.js +- `ReferenceError: fetch is not defined` → Atualize para Node.js 18+ +- `Cannot use import statement` → Atualize o Node.js -
+--- -
-Windsurf +## Armazenamento de Dados -Add this to your Windsurf MCP config file. See [Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp) for more info. +- **Banco de Dados:** Usa diretório padrão de dados do SO + - Linux: `~/.local/share/rdcontext/rdcontext.db` + - macOS: `~/Library/Application Support/rdcontext/rdcontext.db` + - Windows: `%LOCALAPPDATA%\rdcontext\Data\rdcontext.db` -```json -{ - "mcpServers": { - "rdcontext": { - "command": "rdcontext", - "args": ["start"], - "env": { - "OPENAI_API_KEY": "sk-..." - } - } - } -} -``` +- **Sem Nuvem:** Todos os dados permanecem na sua máquina +- **Privacidade:** Sem telemetria ou compartilhamento de dados externos -
+--- -
-Docker -If you prefer to run the MCP server in a Docker container: -1. **Build the Docker Image:** +## 🎯 Casos de Uso e Comandos - Then, build the image in the project root using a tag (e.g., `rdcontext`). **Make sure Docker Desktop (or the Docker daemon) is running.** Run the following command in the same directory where you saved the `Dockerfile`: +### 🛠️ Comandos Principais - ```bash - docker build -t rdcontext . - ``` +```bash +# Listar bibliotecas +rdcontext list -2. **Configure Your MCP Client:** +# Adicionar nova biblioteca +rdcontext add --folders docs,src - Update your MCP client's configuration to use the Docker command. +# Remover biblioteca +rdcontext rm - _Example for a cline_mcp_settings.json:_ +# Buscar documentação +rdcontext get "tema" - ```json - { - "mcpServers": { - "RDContext": { - "autoApprove": [], - "disabled": false, - "timeout": 60, - "command": "docker", - "args": ["run", "-i", "--rm", "rdcontext"], - "transportType": "stdio" - } - } - } - ``` +# Iniciar servidor MCP +rdcontext start +``` - _Note: This is an example configuration. Please refer to the specific examples for your MCP client (like Cursor, VS Code, etc.) earlier in this README to adapt the structure (e.g., `mcpServers` vs `servers`). Also, ensure the image name in `args` matches the tag used during the `docker build` command._ +### 🚀 Exemplos Práticos -
+**Para Desenvolvedores:** +```bash +rdcontext get "resultadosdigitais/tangram" "padrões de design" +rdcontext get "resultadosdigitais/tangram" "formulário validação" +rdcontext get "resultadosdigitais/tangram" "ícones" +``` -## Tips +**Para Criação de Telas:** +```bash +rdcontext get "resultadosdigitais/front-hub" "layout responsivo" +rdcontext get "resultadosdigitais/front-hub" "microfrontend" +rdcontext get "resultadosdigitais/front-hub" "integração" +``` -### Add a Rule +### 🎯 Teste no Cursor -> If you don't want to add `use rdcontext` to every prompt, you can define a simple rule in your `.windsurfrules` file in Windsurf or from `Cursor Settings > Rules` section in Cursor (or the equivalent in your MCP client) to auto-invoke RDContext on any code-related question: -> -> ```toml -> [[calls]] -> match = "when the user requests code examples, setup or configuration steps, or library/API documentation" -> tool = "rdcontext" -> ``` -> -> From then on you'll get RDContext's docs in any related conversation without typing anything extra. You can add your use cases to the match part. +Digite no editor: +``` +👉 "Mostre exemplos de formulários do Tangram" +``` --- -## Data Storage +## Solução de Problemas -- **Database:** - Uses your OS's standard data directory (e.g., `~/.local/share/rdcontext/rdcontext.db` on Linux). -- **No Cloud:** - All data remains on your machine unless you explicitly share it. +### Problemas Comuns ---- +**"rdcontext: command not found"** +```bash +# Recarregar shell +source ~/.bashrc # ou ~/.zshrc -## Security & Privacy +# Ou instalar globalmente +npm install -g rdcontext +``` -- **Private by Default:** - All indexes are stored locally. - ⚠️ During the _AI Extraction_ step the selected documentation is sent to the OpenAI API (or whichever LLM you configure). - If you need zero-egress processing, self-host the model or disable extraction. -- **Private Repo Support:** - Your GitHub token is only used locally to fetch documentation. +**Erro de API Key** +```bash +echo $GEMINI_API_KEY +export GEMINI_API_KEY="sua-chave" +``` ---- +**Erro de permissão** +```bash +chmod +x $(which rdcontext) +``` + +**Servidor não responde** +```bash +ps aux | grep rdcontext +pkill -f rdcontext +rdcontext start +``` + +**"No sessionId" no navegador** +- Isso é normal para servidores MCP +- Use através da sua IDE, não diretamente no navegador -## Contributing +**Limites de Rate da API** +- Use token do GitHub para limites maiores +- Gemini tem tier gratuito generoso +- OpenAI requer conta paga para uso em produção -- **Run in development mode:** - ```bash - bun dev - ``` +**Erros de Build** +```bash +# Limpar cache e reinstalar +npm cache clean --force +npm install -g rdcontext +``` + +### Obtendo Ajuda + +1. Verifique este README +2. Execute `rdcontext --help` +3. Verifique Issues no GitHub +4. Verifique versão do Node.js (18.12+ obrigatório) --- -## Troubleshooting +## 📚 Scripts de Instalação + +### `install-rdcontext-cursor.sh` +Script principal para instalação no Cursor: +- ✅ Instalação limpa e interativa +- ✅ Configuração automática do MCP +- ✅ Preserva configurações MCP existentes +- ✅ Adiciona bibliotecas da RD Station automaticamente -- **Permission Errors:** - Ensure the data directory is writable (see error message for path). -- **Private Repo Issues:** - Double-check your GitHub token and repo access. -- **OpenAI Errors:** - Ensure your `OPENAI_API_KEY` environment variable is set. +```bash +# Dar permissão de execução +chmod +x install-rdcontext-cursor.sh + +# Executar instalação +./install-rdcontext-cursor.sh +``` --- -## License +## 🛠️ Desenvolvimento + +```bash +# Clonar repositório +git clone https://github.com/resultadosdigitais/rdcontext.git +cd rdcontext + +# Instalar dependências +npm install -MIT +# Build +npm run build + +# Instalar localmente +npm install -g . + +# Executar testes +npm test +``` --- -## Credits +## Licença -Inspired by [upstash/context7](https://github.com/upstash/context7), but designed for local/private workflows. +Licença MIT - veja o arquivo [LICENSE](LICENSE) para detalhes. --- -**Build your own private, AI-ready documentation server—locally.** +**✨ Feliz codificação com RDContext!** \ No newline at end of file diff --git a/install-rdcontext-cursor.sh b/install-rdcontext-cursor.sh new file mode 100755 index 0000000..93d2805 --- /dev/null +++ b/install-rdcontext-cursor.sh @@ -0,0 +1,436 @@ +#!/usr/bin/env bash + +# Script de instalação do rdcontext focado no Cursor +# Versão idempotente - evita duplicar variáveis no shell + +set -euo pipefail + +# Cores para output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Inicializa variáveis para evitar erros com set -u +GEMINI_API_KEY="" +OPENAI_API_KEY="" +GITHUB_TOKEN="" +AI_PROVIDER="gemini" # valor padrão + +# Funções de log +log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } +log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } +log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } + +print_header() { + echo + echo " ____ ____ ____ _ _ " + echo "| _ \| _ \ / ___|___ _ __ | |_ _____ _| |_ " + echo "| |_) | | | | | / _ \| '_ \| __/ _ \ \/ / __|" + echo "| _ <| |_| | |__| (_) | | | | || __/> <|_ |" + echo "|_| \_\____/ \____\___/|_| |_|\__\___/_/\_\\__|" + echo " " + echo "🚀 Instalador rdcontext para Cursor" + echo +} + +# Adiciona variáveis de ambiente sem duplicar +add_to_shell_config() { + local config_file=$1 + local var_name=$2 + local config_string=$3 + + # Só adiciona se ainda não existir no arquivo (verifica declaração export real) + if ! grep -qE "^[[:space:]]*export[[:space:]]+$var_name=" "$config_file" 2>/dev/null; then + # Garante que não há caracteres especiais na string de configuração + CLEAN_CONFIG=$(echo "$config_string" | tr -d '\r') + echo "$CLEAN_CONFIG" >> "$config_file" + log_success "Adicionado $var_name em $config_file" + else + log_info "$var_name já foi configurado em $config_file, pulando..." + fi +} + +# Verifica dependências +check_dependencies() { + log_info "Verificando dependências..." + + if ! command -v node &>/dev/null; then + log_error "❌ Node.js não encontrado!" + exit 1 + fi + NODE_VERSION=$(node --version | sed 's/^v//' | cut -d'.' -f1) + if [ "$NODE_VERSION" -lt 18 ]; then + log_error "❌ Node.js $(node --version) é muito antigo!" + exit 1 + else + log_success "Node.js $(node --version) ✅" + fi + + if ! command -v npm &>/dev/null; then + log_error "❌ npm não encontrado!" + exit 1 + else + log_success "npm $(npm --version) encontrado" + fi + + if ! command -v git &>/dev/null; then + log_error "❌ Git não encontrado!" + exit 1 + else + log_success "Git $(git --version | awk '{print $3}') encontrado" + fi + + if ! command -v jq &>/dev/null; then + log_warning "⚠️ jq não encontrado. Instalando..." + if command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y jq + elif command -v yum &>/dev/null; then + sudo yum install -y jq + elif command -v brew &>/dev/null; then + brew install jq + else + log_error "❌ Não foi possível instalar jq automaticamente" + exit 1 + fi + log_success "jq instalado com sucesso" + else + log_success "jq encontrado" + fi + + # Verifica Bun + if ! command -v bun &>/dev/null; then + log_error "❌ Bun não encontrado!" + echo + echo "📦 O rdcontext requer o Bun para funcionar corretamente." + echo " Scripts como 'npm run dev', 'npm run build' e 'npm run lint' dependem do Bun." + echo + echo "🔧 Para instalar o Bun:" + echo " curl -fsSL https://bun.sh/install | bash" + echo + echo " Ou visite: https://bun.sh/docs/installation" + echo + log_error "❌ Instale o Bun e execute este script novamente." + exit 1 + else + log_success "Bun $(bun --version) encontrado" + fi +} + +# Função para instalação global do npm com fallback para ~/.local +npm_global_install() { + local PREFIX + PREFIX="$(npm config get prefix 2>/dev/null || echo '')" + if [ -n "$PREFIX" ] && [ -w "$PREFIX" ]; then + npm install -g "$@" + else + if npm install -g "$@"; then :; else + log_warning "Sem permissão no prefix do npm. Usando ~/.local" + mkdir -p "$HOME/.local" + npm install -g --prefix "$HOME/.local" "$@" + # Adiciona ao PATH se não estiver presente + ensure_path_contains "$HOME/.local/bin" + fi + fi +} + +# Adiciona um diretório ao PATH se não estiver presente +ensure_path_contains() { + local dir="$1" + if [[ ":$PATH:" != *":$dir:"* ]]; then + export PATH="$dir:$PATH" + # Adiciona ao .bashrc e .zshrc se existirem + for rcfile in ~/.bashrc ~/.zshrc; do + if [ -f "$rcfile" ] && ! grep -q "export PATH=\"$dir:\$PATH\"" "$rcfile"; then + echo "export PATH=\"$dir:\$PATH\"" >> "$rcfile" + log_info "Adicionado $dir ao PATH em $rcfile" + fi + done + fi +} + +# Instala rdcontext +install_rdcontext() { + log_info "Verificando se rdcontext já está instalado..." + + # Verifica se rdcontext já está funcionando + if command -v rdcontext &>/dev/null; then + log_success "rdcontext já está instalado e funcionando!" + if rdcontext --version &>/dev/null; then + log_success "Versão: $(rdcontext --version | tail -n1)" + return 0 + else + log_warning "rdcontext encontrado mas não está funcionando. Reinstalando..." + fi + fi + + log_info "Instalando rdcontext..." + + # Remove instalação anterior se existir + if npm list -g rdcontext &>/dev/null; then + log_info "Removendo instalação anterior..." + npm uninstall -g rdcontext + fi + + # Verifica se estamos dentro do repositório rdcontext + if [ -f "./package.json" ] && grep -q "\"name\": \"rdcontext\"" "./package.json" 2>/dev/null; then + log_info "Instalando a partir do repositório local..." + npm install + npm run build + npm_global_install . + else + log_info "Instalando a partir do GitHub..." + npm_global_install git+https://github.com/resultadosdigitais/rdcontext.git + fi + + if command -v rdcontext &>/dev/null; then + log_success "rdcontext $(rdcontext --version | tail -n1) instalado com sucesso!" + else + log_error "❌ Falha na instalação do rdcontext" + exit 1 + fi +} + +# Configura API Keys +configure_api_keys() { + echo + log_info "Configurando API Keys..." + echo "1) Gemini (Google)" + echo "2) OpenAI" + echo "3) Pular" + read -p "Escolha uma opção (1-3): " -n 1 -r + echo + + case $REPLY in + 1) + read -rs -p "Digite sua Gemini API Key: " GEMINI_API_KEY + echo + if [ -n "$GEMINI_API_KEY" ]; then + CONFIG_STRING=" +# rdcontext configuration +export GEMINI_API_KEY=\"$GEMINI_API_KEY\" +export AI_PROVIDER=\"gemini\" +export GEMINI_EMBEDDING_MODEL=\"text-embedding-004\"" + add_to_shell_config ~/.bashrc GEMINI_API_KEY "$CONFIG_STRING" + [ -f ~/.zshrc ] && add_to_shell_config ~/.zshrc GEMINI_API_KEY "$CONFIG_STRING" + export GEMINI_API_KEY="$GEMINI_API_KEY" + export AI_PROVIDER="gemini" + fi + ;; + 2) + read -rs -p "Digite sua OpenAI API Key: " OPENAI_API_KEY + echo + if [ -n "$OPENAI_API_KEY" ]; then + CONFIG_STRING=" +# rdcontext configuration +export OPENAI_API_KEY=\"$OPENAI_API_KEY\" +export AI_PROVIDER=\"openai\" +export OPENAI_EMBEDDING_MODEL=\"text-embedding-3-large\"" + add_to_shell_config ~/.bashrc OPENAI_API_KEY "$CONFIG_STRING" + [ -f ~/.zshrc ] && add_to_shell_config ~/.zshrc OPENAI_API_KEY "$CONFIG_STRING" + export OPENAI_API_KEY="$OPENAI_API_KEY" + export AI_PROVIDER="openai" + fi + ;; + *) log_info "Configuração de API Key pulada." ;; + esac +} + +# Configura GitHub Token +configure_github_token() { + echo + read -p "Deseja configurar GitHub Token agora? (y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + read -rs -p "Digite seu GitHub Token: " GITHUB_TOKEN + echo + if [ -n "$GITHUB_TOKEN" ]; then + # Limpa o token de caracteres especiais + CLEAN_TOKEN=$(echo "$GITHUB_TOKEN" | tr -d '\r\n' | xargs) + CONFIG_STRING=" +# rdcontext GitHub configuration +export GITHUB_TOKEN=\"$CLEAN_TOKEN\"" + add_to_shell_config ~/.bashrc GITHUB_TOKEN "$CONFIG_STRING" + [ -f ~/.zshrc ] && add_to_shell_config ~/.zshrc GITHUB_TOKEN "$CONFIG_STRING" + export GITHUB_TOKEN="$CLEAN_TOKEN" + log_success "✅ GitHub Token configurado e limpo!" + else + log_warning "⚠️ Token vazio, GitHub Token não configurado" + fi + fi +} + +# Configura MCP no Cursor +configure_cursor_mcp() { + local cursor_config_dir="$HOME/.cursor" + local mcp_config="$cursor_config_dir/mcp.json" + + mkdir -p "$cursor_config_dir" + cp "$mcp_config" "$mcp_config.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true + + # Verifica se o arquivo mcp.json já existe + if [ -f "$mcp_config" ]; then + log_info "Atualizando configuração MCP existente..." + + # Atualiza o arquivo existente, preservando outras configurações + # Cria objeto de ambiente apenas com chaves que têm valores + local env_obj="{}" + if [ -n "$GEMINI_API_KEY" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$GEMINI_API_KEY" '. + {"GEMINI_API_KEY": $key}') + fi + if [ -n "$OPENAI_API_KEY" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$OPENAI_API_KEY" '. + {"OPENAI_API_KEY": $key}') + fi + if [ -n "$GITHUB_TOKEN" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$GITHUB_TOKEN" '. + {"GITHUB_TOKEN": $key}') + fi + if [ -n "$AI_PROVIDER" ]; then + env_obj=$(echo "$env_obj" | jq --arg provider "$AI_PROVIDER" '. + {"AI_PROVIDER": $provider}') + fi + + # Sempre adiciona os modelos de embedding + env_obj=$(echo "$env_obj" | jq '. + {"GEMINI_EMBEDDING_MODEL": "text-embedding-004"}') + env_obj=$(echo "$env_obj" | jq '. + {"OPENAI_EMBEDDING_MODEL": "text-embedding-3-large"}') + + jq --argjson env "$env_obj" \ + '.mcpServers.rdcontext |= ((. // { "env": {} }) + { "command": "rdcontext", "args": ["start"] } | .env += $env)' \ + "$mcp_config" > "$mcp_config.tmp" && mv "$mcp_config.tmp" "$mcp_config" + log_success "Configuração MCP atualizada em $mcp_config" + else + # Cria um novo arquivo se não existir + log_info "Criando nova configuração MCP..." + + # Cria objeto de ambiente apenas com chaves que têm valores + local env_obj="{}" + if [ -n "$GEMINI_API_KEY" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$GEMINI_API_KEY" '. + {"GEMINI_API_KEY": $key}') + fi + if [ -n "$OPENAI_API_KEY" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$OPENAI_API_KEY" '. + {"OPENAI_API_KEY": $key}') + fi + if [ -n "$GITHUB_TOKEN" ]; then + env_obj=$(echo "$env_obj" | jq --arg key "$GITHUB_TOKEN" '. + {"GITHUB_TOKEN": $key}') + fi + if [ -n "$AI_PROVIDER" ]; then + env_obj=$(echo "$env_obj" | jq --arg provider "$AI_PROVIDER" '. + {"AI_PROVIDER": $provider}') + fi + + # Sempre adiciona os modelos de embedding + env_obj=$(echo "$env_obj" | jq '. + {"GEMINI_EMBEDDING_MODEL": "text-embedding-004"}') + env_obj=$(echo "$env_obj" | jq '. + {"OPENAI_EMBEDDING_MODEL": "text-embedding-3-large"}') + + jq -n --argjson env "$env_obj" \ + '{ + "mcpServers": { + "rdcontext": { + "command": "rdcontext", + "args": ["start"], + "env": $env + } + } + }' > "$mcp_config" + log_success "Configuração MCP criada em $mcp_config" + fi +} + +# Adiciona bibliotecas de exemplo +add_example_libraries() { + echo + read -r -p "Deseja adicionar as bibliotecas da RD Station (Tangram e FrontHub)? (y/n): " add_examples + + if [[ $add_examples =~ ^[Yy]$ ]]; then + if [ -z "$GITHUB_TOKEN" ]; then + log_error "❌ GitHub Token necessário para adicionar bibliotecas da RD Station" + echo "Configure o token primeiro com: export GITHUB_TOKEN=\"seu_token\"" + return + fi + + # Valida e limpa o token + CLEAN_TOKEN=$(echo "$GITHUB_TOKEN" | tr -d '\r\n' | xargs) + if [ -z "$CLEAN_TOKEN" ]; then + log_error "❌ GitHub Token está vazio após limpeza" + return + fi + + log_info "🔑 Token GitHub validado e limpo" + + # Verifica se tem API Key configurada + if [ -z "$GEMINI_API_KEY" ] && [ -z "$OPENAI_API_KEY" ]; then + log_error "❌ API Key necessária para processar documentação!" + echo "Configure uma API Key primeiro (Gemini ou OpenAI)" + return + fi + + log_info "Adicionando FrontHub..." + log_info "Comando: rdcontext add \"resultadosdigitais/front-hub\" --folders \"packages/front-hub-docs/docs\" --token [GITHUB_TOKEN]" + echo + # Limpa o token de caracteres especiais e espaços + CLEAN_TOKEN=$(echo "$GITHUB_TOKEN" | tr -d '\r\n' | xargs) + rdcontext add "resultadosdigitais/front-hub" --folders "packages/front-hub-docs/docs" --token "$CLEAN_TOKEN" + log_success "FrontHub adicionado com sucesso!" + + log_info "Adicionando Tangram Design System..." + log_info "Comando: rdcontext add \"resultadosdigitais/tangram\" --folders \"docs/examples/components\" \"docs/docs\" \"docs/code\" --token [GITHUB_TOKEN]" + echo + rdcontext add "resultadosdigitais/tangram" --folders "docs/examples/components" "docs/docs" "docs/code" --token "$CLEAN_TOKEN" + log_success "Tangram adicionado com sucesso!" + fi +} + +# Testa a instalação +test_installation() { + if rdcontext --version &>/dev/null; then + log_success "✅ rdcontext está funcionando!" + else + log_error "❌ Erro ao executar rdcontext" + exit 1 + fi + rdcontext list +} + +# Mostra próximos passos +show_next_steps() { + echo + echo "🎉 Instalação concluída com sucesso!" + echo + echo "📋 Próximos passos:" + echo + echo "1. Reinicie o Cursor para aplicar as configurações MCP" + echo + echo "2. No Cursor, teste digitando:" + echo " 'Mostre exemplos de botões do Tangram'" + echo + echo "3. Para adicionar mais bibliotecas:" + echo " rdcontext add \"owner/repo\" --folders \"pasta1\" \"pasta2\" --token SEU_GITHUB_TOKEN" + echo + echo "4. Comandos úteis:" + echo " rdcontext list # Lista bibliotecas" + echo " rdcontext get \"repo\" \"query\" # Busca contexto" + echo + echo "5. Comandos específicos para RD Station:" + echo " rdcontext add \"resultadosdigitais/front-hub\" --folders \"packages/front-hub-docs/docs\" --token SEU_GITHUB_TOKEN" + echo + echo " rdcontext add \"resultadosdigitais/tangram\" --folders \"docs/examples/components\" \"docs/docs\" \"docs/code\" --token SEU_GITHUB_TOKEN" + echo + echo + echo "📚 Documentação completa:" + echo " https://github.com/resultadosdigitais/rdcontext" + echo " README.md - Guia completo de instalação e uso" + echo +} + +main() { + print_header + check_dependencies + install_rdcontext + configure_api_keys + configure_github_token + configure_cursor_mcp + add_example_libraries + test_installation + show_next_steps +} + +main "$@" diff --git a/package-lock.json b/package-lock.json index 869ca97..c82da4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,25 @@ { - "name": "libcontext", + "name": "rdcontext", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "libcontext", + "name": "rdcontext", "version": "0.0.0", "dependencies": { + "@google/genai": "^0.2.0", "@libsql/client": "0.15.10", "@octokit/rest": "22.0.0", "drizzle-orm": "0.44.3", "fastmcp": "3.10.0", "openai": "5.10.1", + "sqlite-vec": "^0.1.7-alpha.2", "yargs": "18.0.0", "zod": "3.25.76" }, "bin": { - "libcontext": "dist/index.js" + "rdcontext": "dist/index.js" }, "devDependencies": { "@biomejs/biome": "2.1.1", @@ -1016,6 +1018,19 @@ "node": ">=18" } }, + "node_modules/@google/genai": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-0.2.0.tgz", + "integrity": "sha512-r7EiRHSqc6D1lDIMvM4OemjUwPpUbYb9jTxe1eLCiFbooHrmPc6U9z3n56E/iWzigkZmjRh4IC0CMzoB1aql9w==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^9.14.2", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@libsql/client": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.15.10.tgz", @@ -1446,6 +1461,15 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1483,11 +1507,40 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/before-after-hook": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==" }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -1507,6 +1560,12 @@ "node": ">=18" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1832,6 +1891,15 @@ "node": ">= 0.4" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2050,6 +2118,12 @@ "express": ">= 4.11" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-content-type-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", @@ -2215,6 +2289,68 @@ "node": ">=10" } }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/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==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2296,6 +2432,32 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2307,6 +2469,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -2352,6 +2527,19 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", @@ -2451,11 +2639,41 @@ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/libsql": { "version": "0.5.17", "resolved": "https://registry.npmjs.org/libsql/-/libsql-0.5.17.tgz", @@ -3013,6 +3231,84 @@ "source-map": "^0.6.0" } }, + "node_modules/sqlite-vec": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec/-/sqlite-vec-0.1.7-alpha.2.tgz", + "integrity": "sha512-rNgRCv+4V4Ed3yc33Qr+nNmjhtrMnnHzXfLVPeGb28Dx5mmDL3Ngw/Wk8vhCGjj76+oC6gnkmMG8y73BZWGBwQ==", + "license": "MIT OR Apache", + "optionalDependencies": { + "sqlite-vec-darwin-arm64": "0.1.7-alpha.2", + "sqlite-vec-darwin-x64": "0.1.7-alpha.2", + "sqlite-vec-linux-arm64": "0.1.7-alpha.2", + "sqlite-vec-linux-x64": "0.1.7-alpha.2", + "sqlite-vec-windows-x64": "0.1.7-alpha.2" + } + }, + "node_modules/sqlite-vec-darwin-arm64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-darwin-arm64/-/sqlite-vec-darwin-arm64-0.1.7-alpha.2.tgz", + "integrity": "sha512-raIATOqFYkeCHhb/t3r7W7Cf2lVYdf4J3ogJ6GFc8PQEgHCPEsi+bYnm2JT84MzLfTlSTIdxr4/NKv+zF7oLPw==", + "cpu": [ + "arm64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sqlite-vec-darwin-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-darwin-x64/-/sqlite-vec-darwin-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-jeZEELsQjjRsVojsvU5iKxOvkaVuE+JYC8Y4Ma8U45aAERrDYmqZoHvgSG7cg1PXL3bMlumFTAmHynf1y4pOzA==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/sqlite-vec-linux-arm64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-linux-arm64/-/sqlite-vec-linux-arm64-0.1.7-alpha.2.tgz", + "integrity": "sha512-6Spj4Nfi7tG13jsUG+W7jnT0bCTWbyPImu2M8nWp20fNrd1SZ4g3CSlDAK8GBdavX7wRlbBHCZ+BDa++rbDewA==", + "cpu": [ + "arm64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sqlite-vec-linux-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-linux-x64/-/sqlite-vec-linux-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-IcgrbHaDccTVhXDf8Orwdc2+hgDLAFORl6OBUhcvlmwswwBP1hqBTSEhovClG4NItwTOBNgpwOoQ7Qp3VDPWLg==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/sqlite-vec-windows-x64": { + "version": "0.1.7-alpha.2", + "resolved": "https://registry.npmjs.org/sqlite-vec-windows-x64/-/sqlite-vec-windows-x64-0.1.7-alpha.2.tgz", + "integrity": "sha512-TRP6hTjAcwvQ6xpCZvjP00pdlda8J38ArFy1lMYhtQWXiIBmWnhMaMbq4kaeCYwvTTddfidatRS+TJrwIKB/oQ==", + "cpu": [ + "x64" + ], + "license": "MIT OR Apache", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -3106,6 +3402,12 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -3193,6 +3495,19 @@ "resolved": "https://registry.npmjs.org/uri-templates/-/uri-templates-0.2.0.tgz", "integrity": "sha512-EWkjYEN0L6KOfEoOH6Wj4ghQqU7eBZMJqRHQnxQAq+dSEzRPClkWjf8557HkWQXF6BrAUoLSAyy9i3RVTliaNg==" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3209,6 +3524,22 @@ "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/src/ai/embedding-utils.ts b/src/ai/embedding-utils.ts index d8c8696..167ff66 100644 --- a/src/ai/embedding-utils.ts +++ b/src/ai/embedding-utils.ts @@ -15,12 +15,24 @@ export class EmbeddingNormalizer { } } - // Gemini embeddings are already 3072d - validate and return + // Normalize Gemini embeddings to 3072 dimensions private static normalizeGemini(embedding: number[]): number[] { - if (embedding.length !== 3072) { - throw new Error(`Invalid Gemini embedding dimensions: expected 3072, got ${embedding.length}`); + if (embedding.length === 3072) { + // Already 3072d - return as-is + return embedding; } - return embedding; + + if (embedding.length === 768) { + // Pad 768d embeddings to 3072d with zeros + // This is a simple approach - in production you might want more sophisticated normalization + const normalized = new Array(3072).fill(0); + for (let i = 0; i < 768; i++) { + normalized[i] = embedding[i]; + } + return normalized; + } + + throw new Error(`Invalid Gemini embedding dimensions: expected 768 or 3072, got ${embedding.length}`); } // OpenAI embeddings: truncate from 1536d to 3072d (Matryoshka principle) @@ -108,7 +120,7 @@ export class EmbeddingNormalizer { static validateEmbedding(embedding: number[], provider: EmbeddingProvider): boolean { switch (provider) { case 'gemini': - return embedding.length === 3072; + return [768, 3072].includes(embedding.length); case 'openai': return [3072, 1536, 3072].includes(embedding.length); default: @@ -120,7 +132,7 @@ export class EmbeddingNormalizer { static getExpectedDimensions(provider: EmbeddingProvider): number[] { switch (provider) { case 'gemini': - return [3072]; + return [768, 3072]; case 'openai': return [3072, 1536, 3072]; default: diff --git a/src/db/schema-v2.ts b/src/db/schema-v2.ts index 2c03488..b347745 100644 --- a/src/db/schema-v2.ts +++ b/src/db/schema-v2.ts @@ -59,7 +59,7 @@ export interface VectorRecord { // Embedding dimension constants export const EMBEDDING_DIMS = { OPENAI: 1536, - GEMINI: 3072, + GEMINI: 768, // text-embedding-004 returns 768 dimensions NORMALIZED: 3072, // Common dimension for cross-provider comparison } as const; diff --git a/src/db/vector-store.ts b/src/db/vector-store.ts index 19c2c69..b0a3b83 100644 --- a/src/db/vector-store.ts +++ b/src/db/vector-store.ts @@ -31,6 +31,15 @@ export class VectorStore { return embedding; } + if (provider === 'gemini' && embedding.length === 768) { + // Pad 768d Gemini embeddings to 3072d with zeros + const normalized = new Array(3072).fill(0); + for (let i = 0; i < 768; i++) { + normalized[i] = embedding[i]; + } + return normalized; + } + if (provider === 'openai' && embedding.length === 1536) { // Truncate OpenAI embeddings to first 3072 dimensions // This preserves most semantic information (Matryoshka embedding principle)