fix: Update runner Docker socket configuration and Gitea instance URL
- Changed docker-compose.yml to mount OrbStack Docker socket path (/Users/brunogao/.orbstack/run/docker.sock) - Updated GITEA_INSTANCE_URL to use 192.168.1.83:33000 instead of gitea:3000 for proper DNS resolution - Both runner-docker and runner-k8s now correctly point to OrbStack Docker daemon - This resolves the 'Cannot connect to the Docker daemon' error and DNS resolution failures
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
# Environment variables for AI CLI
|
||||
# Copy this file to .env and update with your actual keys
|
||||
|
||||
# OpenRouter API Key
|
||||
OPENROUTER_API_KEY=sk-or-xxx
|
||||
|
||||
# Ollama settings (if using)
|
||||
OLLAMA_HOST=http://localhost:11434
|
||||
@@ -0,0 +1,187 @@
|
||||
# LJWX AI CLI - Your Intelligent Development Companion
|
||||
|
||||
LJWX AI CLI is a powerful command-line tool that brings AI assistance directly to your terminal. It supports multiple AI providers (OpenRouter, Ollama) and maintains context across sessions, making it perfect for sustained development work.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Provider Support**: Works with OpenRouter (Claude 4.5*, GPT-4, etc.) and Ollama (local models)
|
||||
- **Persistent Context**: Maintains conversation history across CLI sessions
|
||||
- **Project Awareness**: Automatically reads git diffs, file trees, and project structure
|
||||
- **Multiple Commands**: Chat, edit, review, plan, and configure
|
||||
- **Claude-Style Interface**: Familiar experience similar to Claude Code
|
||||
|
||||
*Note: Claude 4.5 models may require special access. Claude 3.5 models are generally available.
|
||||
|
||||
## Installation
|
||||
|
||||
### Quick Install (Recommended)
|
||||
|
||||
1. Clone or download this repository
|
||||
2. Run the installation script:
|
||||
```bash
|
||||
chmod +x install.sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
The installation script will:
|
||||
- Install Python dependencies
|
||||
- Create a symlink to make `ljwx-ai` globally available
|
||||
- Provide instructions to update your shell configuration
|
||||
|
||||
### Manual Installation
|
||||
|
||||
1. Clone or download this repository
|
||||
2. Make the CLI executable:
|
||||
```bash
|
||||
chmod +x ljwx-ai
|
||||
```
|
||||
3. Install Python dependencies:
|
||||
```bash
|
||||
pip3 install -r requirements.txt --break-system-packages
|
||||
```
|
||||
4. Make globally available by adding to your PATH:
|
||||
- Add the script's directory to your PATH in `~/.zshrc` or `~/.bashrc`:
|
||||
```bash
|
||||
export PATH="$PATH:/path/to/ljwx-ai/directory"
|
||||
```
|
||||
- Or create a symlink in a directory already in PATH:
|
||||
```bash
|
||||
ln -s /full/path/to/ljwx-ai ~/.local/bin/ljwx-ai
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Initialize the CLI with default configuration:
|
||||
|
||||
```bash
|
||||
./ljwx-ai init
|
||||
```
|
||||
|
||||
This creates a configuration file at `~/.ai-cli/config.yaml`.
|
||||
|
||||
### Configuration
|
||||
|
||||
Update your `~/.ai-cli/config.yaml` with your API keys:
|
||||
|
||||
```yaml
|
||||
default_provider: openrouter
|
||||
default_model: anthropic/claude-sonnet-4.5 # Note: Claude 4.5 may require special access
|
||||
max_context_messages: 10
|
||||
providers:
|
||||
openrouter:
|
||||
base_url: https://openrouter.ai/api/v1/chat/completions
|
||||
api_key: sk-or-xxx # Replace with your OpenRouter API key
|
||||
ollama:
|
||||
base_url: http://192.168.1.83:11434/api/chat # Internal IP address
|
||||
model: qwen3-coder:30b-a3b-q8_0
|
||||
```
|
||||
|
||||
**Note on Claude 4.5 Access**: The Claude 4.5 models (sonnet-4.5 and haiku-4.5) may be in restricted access. If you encounter issues accessing them, consider using Claude 3.5 models as alternatives:
|
||||
|
||||
- `anthropic/claude-3.5-sonnet`
|
||||
- `anthropic/claude-3.5-haiku`
|
||||
|
||||
**Note on Ollama Configuration**: The default Ollama configuration uses internal IP address 192.168.1.83 and the qwen3-coder:30b-a3b-q8_0 model. Update these values based on your Ollama setup.
|
||||
|
||||
## Usage
|
||||
|
||||
### Chat
|
||||
Chat with the AI assistant:
|
||||
|
||||
```bash
|
||||
./ljwx-ai chat "Explain how this function works"
|
||||
```
|
||||
|
||||
### Edit
|
||||
Get AI assistance for editing files:
|
||||
|
||||
```bash
|
||||
./ljwx-ai edit src/main.py
|
||||
./ljwx-ai edit src/main.py --prompt "Refactor this to improve performance"
|
||||
```
|
||||
|
||||
### Review
|
||||
Review code for issues and improvements:
|
||||
|
||||
```bash
|
||||
./ljwx-ai review src/
|
||||
./ljwx-ai review src/main.py --prompt "Check for security issues"
|
||||
```
|
||||
|
||||
### Plan
|
||||
Generate development plans:
|
||||
|
||||
```bash
|
||||
./ljwx-ai plan "Implement user authentication system"
|
||||
```
|
||||
|
||||
### Configuration Management
|
||||
Manage CLI configuration:
|
||||
|
||||
```bash
|
||||
./ljwx-ai config list # List current configuration
|
||||
# For Claude 4.5 Haiku (if available):
|
||||
./ljwx-ai config set model anthropic/claude-haiku-4.5
|
||||
# Or for Claude 4.5 Sonnet (if available):
|
||||
# ./ljwx-ai config set model anthropic/claude-sonnet-4.5
|
||||
# Or for generally available Claude 3.5 Sonnet (recommended):
|
||||
./ljwx-ai config set model anthropic/claude-3.5-sonnet
|
||||
./ljwx-ai config reset # Reset configuration
|
||||
```
|
||||
|
||||
### Provider Override
|
||||
You can override the default provider/model for any command:
|
||||
|
||||
```bash
|
||||
./ai --provider ollama chat "Explain this Python code"
|
||||
./ai --model anthropic/claude-4.5-haiku chat "Short response needed"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### init
|
||||
Initialize configuration and cache directories.
|
||||
|
||||
### chat
|
||||
Start a conversation with the AI assistant. The AI has access to your project context.
|
||||
|
||||
### edit
|
||||
Get AI assistance for editing specific files or directories.
|
||||
|
||||
### review
|
||||
Review code for potential issues, improvements, and best practices.
|
||||
|
||||
### plan
|
||||
Generate detailed development plans for features or tasks.
|
||||
|
||||
### config
|
||||
Manage configuration settings.
|
||||
|
||||
## Context Management
|
||||
|
||||
The CLI maintains conversation context in `.aicache/context.json` in your project directory. This allows for sustained conversations with memory of previous interactions.
|
||||
|
||||
## Project Awareness
|
||||
|
||||
When interacting with the AI, it automatically understands your project structure:
|
||||
- Git diffs
|
||||
- File tree
|
||||
- Current working directory
|
||||
|
||||
## Providers
|
||||
|
||||
### OpenRouter
|
||||
Supports Claude 4.5* (Sonnet, Haiku), GPT-4, and many other models through OpenRouter's unified API.
|
||||
|
||||
*Note: Claude 4.5 models may require special access from OpenRouter. Claude 3.5 models (sonnet, haiku) are generally available.
|
||||
|
||||
### Ollama
|
||||
Run local models through Ollama for privacy-focused development.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Feel free to submit issues and pull requests.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
@@ -0,0 +1,159 @@
|
||||
# LJWX AI CLI - Your Intelligent Development Companion
|
||||
|
||||
LJWX AI CLI is a powerful command-line tool that brings AI assistance directly to your terminal. It supports multiple AI providers (OpenRouter, Ollama) and maintains context across sessions, making it perfect for sustained development work.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Provider Support**: Works with OpenRouter (Claude 4.5*, GPT-4, etc.) and Ollama (local models)
|
||||
- **Persistent Context**: Maintains conversation history across CLI sessions
|
||||
- **Project Awareness**: Automatically reads git diffs, file trees, and project structure
|
||||
- **Multiple Commands**: Chat, edit, review, plan, and configure
|
||||
- **Claude-Style Interface**: Familiar experience similar to Claude Code
|
||||
|
||||
*Note: Claude 4.5 models may require special access. Claude 3.5 models are generally available.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone or download this repository
|
||||
2. Make the CLI executable:
|
||||
```bash
|
||||
chmod +x ai
|
||||
```
|
||||
3. Install Python dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
Initialize the CLI with default configuration:
|
||||
|
||||
```bash
|
||||
./ai init
|
||||
```
|
||||
|
||||
This creates a configuration file at `~/.ai-cli/config.yaml`.
|
||||
|
||||
### Configuration
|
||||
|
||||
Update your `~/.ai-cli/config.yaml` with your API keys:
|
||||
|
||||
```yaml
|
||||
default_provider: openrouter
|
||||
default_model: anthropic/claude-sonnet-4.5 # Note: Claude 4.5 may require special access
|
||||
max_context_messages: 10
|
||||
providers:
|
||||
openrouter:
|
||||
base_url: https://openrouter.ai/api/v1/chat/completions
|
||||
api_key: sk-or-xxx # Replace with your OpenRouter API key
|
||||
ollama:
|
||||
base_url: http://localhost:11434/api/chat
|
||||
model: qwen2.5-coder:32b
|
||||
```
|
||||
|
||||
**Note on Claude 4.5 Access**: The Claude 4.5 models (sonnet-4.5 and haiku-4.5) may be in restricted access. If you encounter issues accessing them, consider using Claude 3.5 models as alternatives:
|
||||
|
||||
- `anthropic/claude-3.5-sonnet`
|
||||
- `anthropic/claude-3.5-haiku`
|
||||
|
||||
## Usage
|
||||
|
||||
### Chat
|
||||
Chat with the AI assistant:
|
||||
|
||||
```bash
|
||||
./ai chat "Explain how this function works"
|
||||
```
|
||||
|
||||
### Edit
|
||||
Get AI assistance for editing files:
|
||||
|
||||
```bash
|
||||
./ai edit src/main.py
|
||||
./ai edit src/main.py --prompt "Refactor this to improve performance"
|
||||
```
|
||||
|
||||
### Review
|
||||
Review code for issues and improvements:
|
||||
|
||||
```bash
|
||||
./ai review src/
|
||||
./ai review src/main.py --prompt "Check for security issues"
|
||||
```
|
||||
|
||||
### Plan
|
||||
Generate development plans:
|
||||
|
||||
```bash
|
||||
./ai plan "Implement user authentication system"
|
||||
```
|
||||
|
||||
### Configuration Management
|
||||
Manage CLI configuration:
|
||||
|
||||
```bash
|
||||
./ai config list # List current configuration
|
||||
./ai config set model anthropic/claude-haiku-4.5 # Change to Claude 4.5 Haiku (if available)
|
||||
# Or for Claude 4.5 Sonnet:
|
||||
# ./ai config set model anthropic/claude-sonnet-4.5
|
||||
# Or for generally available Claude 3.5:
|
||||
# ./ai config set model anthropic/claude-3.5-sonnet
|
||||
./ai config reset # Reset configuration
|
||||
```
|
||||
|
||||
### Provider Override
|
||||
You can override the default provider/model for any command:
|
||||
|
||||
```bash
|
||||
./ai --provider ollama chat "Explain this Python code"
|
||||
./ai --model anthropic/claude-4.5-haiku chat "Short response needed"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### init
|
||||
Initialize configuration and cache directories.
|
||||
|
||||
### chat
|
||||
Start a conversation with the AI assistant. The AI has access to your project context.
|
||||
|
||||
### edit
|
||||
Get AI assistance for editing specific files or directories.
|
||||
|
||||
### review
|
||||
Review code for potential issues, improvements, and best practices.
|
||||
|
||||
### plan
|
||||
Generate detailed development plans for features or tasks.
|
||||
|
||||
### config
|
||||
Manage configuration settings.
|
||||
|
||||
## Context Management
|
||||
|
||||
The CLI maintains conversation context in `.aicache/context.json` in your project directory. This allows for sustained conversations with memory of previous interactions.
|
||||
|
||||
## Project Awareness
|
||||
|
||||
When interacting with the AI, it automatically understands your project structure:
|
||||
- Git diffs
|
||||
- File tree
|
||||
- Current working directory
|
||||
|
||||
## Providers
|
||||
|
||||
### OpenRouter
|
||||
Supports Claude 4.5* (Sonnet, Haiku), GPT-4, and many other models through OpenRouter's unified API.
|
||||
|
||||
*Note: Claude 4.5 models may require special access from OpenRouter. Claude 3.5 models (sonnet, haiku) are generally available.
|
||||
|
||||
### Ollama
|
||||
Run local models through Ollama for privacy-focused development.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Feel free to submit issues and pull requests.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
Submodule
+1
Submodule ai/ai-cli/cc-switch added at b617879035
@@ -0,0 +1,10 @@
|
||||
default_provider: openrouter
|
||||
default_model: anthropic/claude-haiku-4.5
|
||||
max_context_messages: 10
|
||||
providers:
|
||||
openrouter:
|
||||
base_url: https://openrouter.ai/api/v1/chat/completions
|
||||
api_key: sk-or-xxx # Replace with your OpenRouter API key
|
||||
ollama:
|
||||
base_url: http://192.168.1.83:11434/api/chat
|
||||
model: qwen3-coder:30b-a3b-q8_0
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Debug script to test OpenRouter API call."""
|
||||
import requests
|
||||
import os
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from src.utils.config import load_config, get_provider_config
|
||||
from src.providers.base import OpenRouterProvider
|
||||
|
||||
|
||||
def test_api_call():
|
||||
"""Test the OpenRouter API directly."""
|
||||
print("🔍 Testing OpenRouter API call...")
|
||||
|
||||
# Load config
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found")
|
||||
return
|
||||
|
||||
provider_config = get_provider_config('openrouter')
|
||||
if not provider_config:
|
||||
print("❌ OpenRouter provider config not found")
|
||||
return
|
||||
|
||||
# Check API key
|
||||
api_key = provider_config.get('api_key', 'sk-or-xxx')
|
||||
if api_key == 'sk-or-xxx' or not api_key:
|
||||
print("❌ No valid API key found in config")
|
||||
print(" Please update your config.yaml file or set OPENROUTER_API_KEY environment variable")
|
||||
return
|
||||
|
||||
print(f"✅ API key found (first 8 chars: {api_key[:8]}...)")
|
||||
|
||||
# Check model - environment variable takes precedence over config file
|
||||
env_model = os.environ.get('OPENROUTER_MODEL')
|
||||
model = env_model if env_model else config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
print(f"✅ Using model: {model} (from {'env' if env_model else 'config'})")
|
||||
|
||||
# Test the API call directly
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json',
|
||||
'HTTP-Referer': 'https://github.com/your-username/ai-cli',
|
||||
'X-Title': 'AI CLI Tool'
|
||||
}
|
||||
|
||||
# Simple test message
|
||||
messages = [
|
||||
{"role": "user", "content": "Hello, test message!"}
|
||||
]
|
||||
|
||||
payload = {
|
||||
'model': model,
|
||||
'messages': messages,
|
||||
}
|
||||
|
||||
print(f"📡 Sending request to: {provider_config['base_url']}")
|
||||
print(f"📦 Payload: {payload}")
|
||||
|
||||
try:
|
||||
response = requests.post(provider_config['base_url'], headers=headers, json=payload)
|
||||
print(f"📥 Response Status: {response.status_code}")
|
||||
print(f"📥 Response Headers: {dict(response.headers)}")
|
||||
print(f"📥 Response Text: {response.text[:500]}...") # First 500 chars
|
||||
|
||||
if response.status_code != 200:
|
||||
print("❌ API call failed with error above")
|
||||
else:
|
||||
print("✅ API call successful!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Exception during API call: {str(e)}")
|
||||
|
||||
|
||||
def check_model_availability():
|
||||
"""Check if the model exists on OpenRouter."""
|
||||
print("\n🔍 Checking model availability...")
|
||||
|
||||
config = load_config()
|
||||
model = config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
|
||||
provider_config = get_provider_config('openrouter')
|
||||
api_key = provider_config.get('api_key', 'sk-or-xxx')
|
||||
|
||||
if api_key == 'sk-or-xxx' or not api_key:
|
||||
print("❌ Cannot check model - no valid API key")
|
||||
return
|
||||
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
try:
|
||||
# Check model endpoint
|
||||
response = requests.get('https://openrouter.ai/api/v1/models', headers=headers)
|
||||
if response.status_code == 200:
|
||||
models_data = response.json()
|
||||
available_models = [m['id'] for m in models_data.get('data', [])]
|
||||
|
||||
print(f"📊 Found {len(available_models)} available models")
|
||||
|
||||
# Check if our model is available
|
||||
if model in available_models:
|
||||
print(f"✅ Model {model} is available")
|
||||
else:
|
||||
print(f"❌ Model {model} is NOT available")
|
||||
print(" Available Claude models might include:")
|
||||
claude_models = [m for m in available_models if 'claude' in m.lower()]
|
||||
for m in claude_models[:5]: # Show first 5
|
||||
print(f" - {m}")
|
||||
else:
|
||||
print(f"❌ Could not fetch models list: {response.status_code}")
|
||||
except Exception as e:
|
||||
print(f"❌ Error checking model availability: {str(e)}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_api_call()
|
||||
check_model_availability()
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Debug script to test what environment variables the Python script sees."""
|
||||
import os
|
||||
print(f"OPENROUTER_MODEL in Python: {os.environ.get('OPENROUTER_MODEL', 'NOT SET')}")
|
||||
print(f"OPENROUTER_API_KEY in Python: {'SET' if os.environ.get('OPENROUTER_API_KEY') else 'NOT SET'}")
|
||||
|
||||
# Check config file too
|
||||
import sys
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from src.utils.config import load_config
|
||||
config = load_config()
|
||||
print(f"Config default_model: {config.get('default_model', 'NOT SET') if config else 'CONFIG NOT LOADED'}")
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Debug script to see the full environment variables."""
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# Check environment variable directly
|
||||
model = os.environ.get('OPENROUTER_MODEL')
|
||||
print(f"OPENROUTER_MODEL = {model}")
|
||||
|
||||
# Also check via shell command
|
||||
result = subprocess.run(['echo', '$OPENROUTER_MODEL'], capture_output=True, text=True, shell=True)
|
||||
print(f"Shell echo result: {result.stdout.strip()}")
|
||||
|
||||
# Also try bash to check environment
|
||||
bash_result = subprocess.run(['bash', '-c', 'echo $OPENROUTER_MODEL'], capture_output=True, text=True)
|
||||
print(f"Bash result: {bash_result.stdout.strip()}")
|
||||
|
||||
# Check the original shell variable in a direct way
|
||||
os.environ['OPENROUTER_MODEL'] = 'anthropic/claude-haiku-4.5' # Override in Python
|
||||
print(f"Python set model to: {os.environ['OPENROUTER_MODEL']}")
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
# Installation script for LJWX AI CLI
|
||||
|
||||
set -e
|
||||
|
||||
echo "Installing LJWX AI CLI..."
|
||||
|
||||
# Detect OS
|
||||
OS=$(uname -s)
|
||||
|
||||
# Find the script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Check if we're in the correct directory
|
||||
if [ ! -f "ljwx-ai" ]; then
|
||||
echo "ljwx-ai executable not found in current directory!"
|
||||
echo "Please run this script from the ljwx-ai project directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the script is executable
|
||||
chmod +x ljwx-ai
|
||||
|
||||
echo "ljwx-ai found in: $SCRIPT_DIR"
|
||||
|
||||
# Try to install using one of these methods:
|
||||
if command -v pip3 &> /dev/null; then
|
||||
echo "Installing Python dependencies..."
|
||||
pip3 install -r requirements.txt --break-system-packages 2>/dev/null || pip3 install -r requirements.txt
|
||||
else
|
||||
echo "pip3 not found. Please install Python dependencies manually."
|
||||
fi
|
||||
|
||||
# Option 1: Create symlink in ~/.local/bin (user-specific, safe)
|
||||
LOCAL_BIN="$HOME/.local/bin"
|
||||
if [ -d "$LOCAL_BIN" ]; then
|
||||
echo "Creating symlink in $LOCAL_BIN..."
|
||||
ln -sf "$SCRIPT_DIR/ljwx-ai" "$LOCAL_BIN/ljwx-ai"
|
||||
echo "LJWX AI CLI installed! You can now use 'ljwx-ai' command."
|
||||
echo "Make sure $LOCAL_BIN is in your PATH by adding this to your shell profile (e.g., ~/.zshrc or ~/.bashrc):"
|
||||
echo "export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||
else
|
||||
echo "Directory $LOCAL_BIN does not exist. Creating it..."
|
||||
mkdir -p "$LOCAL_BIN"
|
||||
echo "Creating symlink in $LOCAL_BIN..."
|
||||
ln -sf "$SCRIPT_DIR/ljwx-ai" "$LOCAL_BIN/ljwx-ai"
|
||||
echo "LJWX AI CLI installed! You can now use 'ljwx-ai' command."
|
||||
echo "Add this to your shell profile (e.g., ~/.zshrc or ~/.bashrc):"
|
||||
echo "export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "To complete the installation, run:"
|
||||
echo "source ~/.zshrc # or ~/.bashrc, depending on your shell"
|
||||
echo ""
|
||||
echo "Then you can run:"
|
||||
echo "ljwx-ai init # to initialize the configuration"
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LJWX AI CLI - Your intelligent development companion.
|
||||
Supports multiple providers (OpenRouter, Ollama) with persistent context.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
|
||||
|
||||
from src.commands.init import init_command
|
||||
from src.commands.chat import chat_command
|
||||
from src.commands.edit import edit_command
|
||||
from src.commands.review import review_command
|
||||
from src.commands.plan import plan_command
|
||||
from src.commands.config import config_command
|
||||
|
||||
|
||||
def main():
|
||||
"""Main CLI entry point."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="LJWX AI CLI - Your intelligent development companion",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
ljwx-ai init # Initialize configuration
|
||||
ljwx-ai chat "Explain this code" # Chat with AI
|
||||
ljwx-ai edit src/file.py # Edit a file
|
||||
ljwx-ai review . # Review current directory
|
||||
ljwx-ai plan "Feature request" # Generate development plan
|
||||
ljwx-ai config set model anthropic/claude-4.5-sonnet
|
||||
"""
|
||||
)
|
||||
|
||||
# Global options
|
||||
parser.add_argument('--provider', help='Override default provider')
|
||||
parser.add_argument('--model', help='Override default model')
|
||||
|
||||
# Subcommands
|
||||
subparsers = parser.add_subparsers(dest='command', help='Available commands')
|
||||
|
||||
# Init command
|
||||
subparsers.add_parser('init', help='Initialize AI CLI configuration')
|
||||
|
||||
# Chat command
|
||||
chat_parser = subparsers.add_parser('chat', help='Chat with AI assistant')
|
||||
chat_parser.add_argument('message', nargs='*', help='Message to send to AI')
|
||||
|
||||
# Edit command
|
||||
edit_parser = subparsers.add_parser('edit', help='Edit files with AI assistance')
|
||||
edit_parser.add_argument('target', help='File or directory to edit')
|
||||
edit_parser.add_argument('--prompt', '-p', help='Custom prompt for editing')
|
||||
|
||||
# Review command
|
||||
review_parser = subparsers.add_parser('review', help='Review code with AI')
|
||||
review_parser.add_argument('target', help='File or directory to review')
|
||||
review_parser.add_argument('--prompt', '-p', help='Custom prompt for review')
|
||||
|
||||
# Plan command
|
||||
plan_parser = subparsers.add_parser('plan', help='Generate development plan')
|
||||
plan_parser.add_argument('prompt', help='Prompt for plan generation')
|
||||
|
||||
# Config command
|
||||
config_parser = subparsers.add_parser('config', help='Manage configuration')
|
||||
config_subparsers = config_parser.add_subparsers(dest='config_subcommand', help='Config subcommands')
|
||||
config_subparsers.add_parser('list', help='List current configuration')
|
||||
set_parser = config_subparsers.add_parser('set', help='Set configuration value')
|
||||
set_parser.add_argument('key', help='Configuration key')
|
||||
set_parser.add_argument('value', help='Configuration value')
|
||||
config_subparsers.add_parser('reset', help='Reset configuration')
|
||||
|
||||
# Parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# Run appropriate command
|
||||
if args.command == 'init':
|
||||
init_command()
|
||||
elif args.command == 'chat':
|
||||
message = ' '.join(args.message) if args.message else None
|
||||
chat_command(message, args.provider, args.model)
|
||||
elif args.command == 'edit':
|
||||
edit_command(args.target, args.prompt, args.provider, args.model)
|
||||
elif args.command == 'review':
|
||||
review_command(args.target, args.prompt, args.provider, args.model)
|
||||
elif args.command == 'plan':
|
||||
plan_command(args.prompt, args.provider, args.model)
|
||||
elif args.command == 'config':
|
||||
config_command(args.config_subcommand, args.key if hasattr(args, 'key') else None,
|
||||
args.value if hasattr(args, 'value') else None)
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "ljwx-ai-cli",
|
||||
"version": "1.0.0",
|
||||
"description": "Your intelligent development companion CLI tool",
|
||||
"main": "ljwx-ai",
|
||||
"scripts": {
|
||||
"start": "./ljwx-ai",
|
||||
"dev": "python ./ljwx-ai"
|
||||
},
|
||||
"keywords": [
|
||||
"ai",
|
||||
"cli",
|
||||
"development",
|
||||
"assistant",
|
||||
"openrouter",
|
||||
"claude",
|
||||
"ollama",
|
||||
"ljwx-ai"
|
||||
],
|
||||
"author": "LJWX AI CLI Developer",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"requests": "^2.31.0",
|
||||
"colorama": "^0.4.6",
|
||||
"pyyaml": "^6.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# AI CLI Requirements
|
||||
requests>=2.31.0
|
||||
colorama>=0.4.6
|
||||
pyyaml>=6.0
|
||||
@@ -0,0 +1,40 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open("README.md", "r", encoding="utf-8") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name="ljwx-ai-cli",
|
||||
version="1.0.0",
|
||||
author="AI CLI Developer",
|
||||
author_email="",
|
||||
description="Your intelligent development companion CLI tool",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="",
|
||||
packages=find_packages(where="src"),
|
||||
package_dir={"": "src"},
|
||||
classifiers=[
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
],
|
||||
python_requires=">=3.8",
|
||||
install_requires=[
|
||||
"requests>=2.31.0",
|
||||
"colorama>=0.4.6",
|
||||
"pyyaml>=6.0",
|
||||
],
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"ljwx-ai=ljwx_ai:main", # This may need to be adjusted
|
||||
],
|
||||
},
|
||||
)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
"""Chat command for AI CLI."""
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import load_config, get_provider_config
|
||||
from src.providers.base import get_provider
|
||||
from src.utils.context import load_context, save_context, add_message_to_context
|
||||
from src.utils.formatting import print_claude_header
|
||||
from src.utils.project_context import get_project_context
|
||||
|
||||
|
||||
def chat_command(message, provider_override=None, model_override=None):
|
||||
"""Chat with AI assistant."""
|
||||
if not message:
|
||||
print("❌ Please provide a message to send to AI.")
|
||||
return
|
||||
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found. Please run 'ai init' first.")
|
||||
return
|
||||
|
||||
# Determine provider and model
|
||||
provider_name = provider_override or config.get('default_provider', 'openrouter')
|
||||
provider_config = get_provider_config(provider_name)
|
||||
|
||||
if not provider_config:
|
||||
print(f"❌ Provider '{provider_name}' not configured.")
|
||||
return
|
||||
|
||||
# Get model - either from override, provider config, or default
|
||||
model = model_override
|
||||
if not model:
|
||||
# Try to get from provider config first, then fallback to default
|
||||
if provider_name in config.get('providers', {}):
|
||||
provider_specific = config['providers'][provider_name]
|
||||
if 'model' in provider_specific:
|
||||
model = provider_specific['model']
|
||||
|
||||
if not model:
|
||||
model = config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
|
||||
# Initialize provider
|
||||
provider = get_provider(provider_name, provider_config)
|
||||
|
||||
# Load context
|
||||
context_messages = load_context()
|
||||
|
||||
# Add user message to context
|
||||
user_message = {"role": "user", "content": message}
|
||||
context_messages.append(user_message)
|
||||
|
||||
# Add project context if this is the first message or context is empty
|
||||
if len(context_messages) == 1: # First message
|
||||
project_context = get_project_context()
|
||||
if project_context.strip():
|
||||
context_messages.insert(0, {
|
||||
"role": "system",
|
||||
"content": f"Project context:\n{project_context}"
|
||||
})
|
||||
|
||||
# Prepare messages for API
|
||||
# Limit context to max_context_messages
|
||||
max_context = config.get('max_context_messages', 10)
|
||||
recent_messages = context_messages[-max_context:]
|
||||
|
||||
# Print Claude-style header
|
||||
print_claude_header(provider_name, model)
|
||||
|
||||
try:
|
||||
# Get response from provider
|
||||
response = provider.get_completion(recent_messages, model)
|
||||
|
||||
# Add AI response to context
|
||||
ai_message = {"role": "assistant", "content": response}
|
||||
context_messages.append(ai_message)
|
||||
|
||||
# Save updated context
|
||||
save_context(context_messages)
|
||||
|
||||
# Print response
|
||||
print(f"💬 Answer:\n{response}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting response: {str(e)}")
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Config command for AI CLI."""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import load_config, save_config, get_config_path
|
||||
|
||||
|
||||
def config_command(subcommand, key=None, value=None):
|
||||
"""Manage configuration."""
|
||||
if subcommand == 'list' or subcommand is None:
|
||||
config = load_config()
|
||||
if config:
|
||||
print("Current configuration:")
|
||||
for k, v in config.items():
|
||||
if k == 'providers':
|
||||
print(f" {k}:")
|
||||
for provider_name, provider_config in v.items():
|
||||
print(f" {provider_name}:")
|
||||
for config_key, config_value in provider_config.items():
|
||||
# Hide API keys
|
||||
if 'key' in config_key.lower():
|
||||
print(f" {config_key}: {'*' * len(str(config_value))}")
|
||||
else:
|
||||
print(f" {config_key}: {config_value}")
|
||||
else:
|
||||
print(f" {k}: {v}")
|
||||
else:
|
||||
print("No configuration found. Please run 'ai init' first.")
|
||||
|
||||
elif subcommand == 'set':
|
||||
if not key or not value:
|
||||
print("❌ Please provide both key and value for config set command.")
|
||||
return
|
||||
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found. Please run 'ai init' first.")
|
||||
return
|
||||
|
||||
# Handle nested keys like 'providers.openrouter.api_key'
|
||||
keys = key.split('.')
|
||||
current = config
|
||||
|
||||
# Navigate to the parent of the target key
|
||||
for k in keys[:-1]:
|
||||
if k not in current:
|
||||
current[k] = {}
|
||||
current = current[k]
|
||||
|
||||
# Set the final key
|
||||
current[keys[-1]] = value
|
||||
|
||||
save_config(config)
|
||||
print(f"✅ Configuration updated: {key} = {value}")
|
||||
|
||||
elif subcommand == 'reset':
|
||||
config_path = get_config_path()
|
||||
if config_path.exists():
|
||||
config_path.unlink()
|
||||
print("✅ Configuration reset. Please run 'ljwx-ai init' to set up again.")
|
||||
else:
|
||||
print("✅ No configuration to reset.")
|
||||
|
||||
else:
|
||||
print(f"❌ Unknown config subcommand: {subcommand}")
|
||||
return
|
||||
@@ -0,0 +1,122 @@
|
||||
"""Edit command for AI CLI."""
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import load_config, get_provider_config
|
||||
from src.providers.base import get_provider
|
||||
from src.utils.context import load_context, save_context
|
||||
from src.utils.formatting import print_claude_header, print_info
|
||||
from src.utils.project_context import get_project_context, read_file_content
|
||||
|
||||
|
||||
def edit_command(target, custom_prompt, provider_override=None, model_override=None):
|
||||
"""Edit files with AI assistance."""
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found. Please run 'ai init' first.")
|
||||
return
|
||||
|
||||
# Determine provider and model
|
||||
provider_name = provider_override or config.get('default_provider', 'openrouter')
|
||||
provider_config = get_provider_config(provider_name)
|
||||
|
||||
if not provider_config:
|
||||
print(f"❌ Provider '{provider_name}' not configured.")
|
||||
return
|
||||
|
||||
# Get model - either from override, provider config, or default
|
||||
model = model_override
|
||||
if not model:
|
||||
# Try to get from provider config first, then fallback to default
|
||||
if provider_name in config.get('providers', {}):
|
||||
provider_specific = config['providers'][provider_name]
|
||||
if 'model' in provider_specific:
|
||||
model = provider_specific['model']
|
||||
|
||||
if not model:
|
||||
model = config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
|
||||
# Initialize provider
|
||||
provider = get_provider(provider_name, provider_config)
|
||||
|
||||
target_path = Path(target)
|
||||
|
||||
if not target_path.exists():
|
||||
print(f"❌ Target '{target}' does not exist.")
|
||||
return
|
||||
|
||||
# Read file content
|
||||
if target_path.is_file():
|
||||
file_content = read_file_content(str(target_path))
|
||||
file_context = f"File: {target_path}\n\n```{target_path.suffix[1:] if target_path.suffix else 'txt'}\n{file_content}\n```"
|
||||
elif target_path.is_dir():
|
||||
# For directories, get file tree and maybe first few files
|
||||
file_context = f"Directory: {target_path}\n\nFiles in directory:\n"
|
||||
for file_path in target_path.rglob('*'):
|
||||
if file_path.is_file() and file_path.suffix in ['.py', '.js', '.ts', '.jsx', '.tsx', '.md', '.txt', '.json', '.yaml', '.yml']:
|
||||
file_context += f"- {file_path}\n"
|
||||
# Only add content for small files
|
||||
if file_path.stat().st_size < 5000: # Less than 5KB
|
||||
content = read_file_content(str(file_path))
|
||||
file_context += f"\nContent of {file_path}:\n```\n{content}\n```\n"
|
||||
if len(file_context) > 10000: # Limit context size
|
||||
file_context += "\n...(truncated due to size)"
|
||||
break
|
||||
else:
|
||||
print(f"❌ Target '{target}' is neither a file nor a directory.")
|
||||
return
|
||||
|
||||
# Create prompt for editing
|
||||
if custom_prompt:
|
||||
full_prompt = f"{custom_prompt}\n\nHere is the target:\n{file_context}"
|
||||
else:
|
||||
full_prompt = f"I want you to help edit the following code/file. Please suggest improvements, fix issues, or implement features as needed.\n\n{file_context}"
|
||||
|
||||
# Load context
|
||||
context_messages = load_context()
|
||||
|
||||
# Add project context if this is the first message
|
||||
if not context_messages:
|
||||
project_context = get_project_context()
|
||||
if project_context.strip():
|
||||
context_messages.append({
|
||||
"role": "system",
|
||||
"content": f"Project context:\n{project_context}"
|
||||
})
|
||||
|
||||
# Add user message to context
|
||||
user_message = {"role": "user", "content": full_prompt}
|
||||
context_messages.append(user_message)
|
||||
|
||||
# Prepare messages for API
|
||||
# Limit context to max_context_messages
|
||||
max_context = config.get('max_context_messages', 10)
|
||||
recent_messages = context_messages[-max_context:]
|
||||
|
||||
# Print Claude-style header
|
||||
print_claude_header(provider_name, model)
|
||||
|
||||
try:
|
||||
# Get response from provider
|
||||
response = provider.get_completion(recent_messages, model)
|
||||
|
||||
# Add AI response to context
|
||||
ai_message = {"role": "assistant", "content": response}
|
||||
context_messages.append(ai_message)
|
||||
|
||||
# Save updated context
|
||||
save_context(context_messages)
|
||||
|
||||
# Print response
|
||||
print(f"💬 Answer:\n{response}")
|
||||
|
||||
# If target is a file and response looks like code, ask if user wants to apply changes
|
||||
if target_path.is_file():
|
||||
print_info(f"\n💡 To apply changes to {target_path}, you can copy the code above and update the file manually.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting response: {str(e)}")
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Initialize command for AI CLI."""
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import get_config_path, get_cache_dir
|
||||
|
||||
|
||||
def init_command():
|
||||
"""Initialize AI CLI configuration."""
|
||||
print("🚀 Initializing AI CLI...")
|
||||
|
||||
config_path = get_config_path()
|
||||
cache_dir = get_cache_dir()
|
||||
|
||||
# Create cache directory
|
||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
print(f"📁 Created cache directory: {cache_dir}")
|
||||
|
||||
# Create default config if it doesn't exist
|
||||
if not config_path.exists():
|
||||
default_config = {
|
||||
'default_provider': 'openrouter',
|
||||
'default_model': 'anthropic/claude-sonnet-4.5',
|
||||
'max_context_messages': 10,
|
||||
'providers': {
|
||||
'openrouter': {
|
||||
'base_url': 'https://openrouter.ai/api/v1/chat/completions',
|
||||
'api_key': 'sk-or-xxx'
|
||||
},
|
||||
'ollama': {
|
||||
'base_url': 'http://192.168.1.83:11434/api/chat',
|
||||
'model': 'qwen3-coder:30b-a3b-q8_0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Create parent directories if they don't exist
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(default_config, f, default_flow_style=False, allow_unicode=True)
|
||||
|
||||
print(f"⚙️ Created default configuration: {config_path}")
|
||||
print("\n📝 Please update your API keys in the configuration file.")
|
||||
else:
|
||||
print(f"✅ Configuration already exists: {config_path}")
|
||||
|
||||
print("✨ Initialization complete!")
|
||||
@@ -0,0 +1,87 @@
|
||||
"""Plan command for AI CLI."""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import load_config, get_provider_config
|
||||
from src.providers.base import get_provider
|
||||
from src.utils.context import load_context, save_context
|
||||
from src.utils.formatting import print_claude_header
|
||||
from src.utils.project_context import get_project_context
|
||||
|
||||
|
||||
def plan_command(prompt, provider_override=None, model_override=None):
|
||||
"""Generate development plan."""
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found. Please run 'ai init' first.")
|
||||
return
|
||||
|
||||
# Determine provider and model
|
||||
provider_name = provider_override or config.get('default_provider', 'openrouter')
|
||||
provider_config = get_provider_config(provider_name)
|
||||
|
||||
if not provider_config:
|
||||
print(f"❌ Provider '{provider_name}' not configured.")
|
||||
return
|
||||
|
||||
# Get model - either from override, provider config, or default
|
||||
model = model_override
|
||||
if not model:
|
||||
# Try to get from provider config first, then fallback to default
|
||||
if provider_name in config.get('providers', {}):
|
||||
provider_specific = config['providers'][provider_name]
|
||||
if 'model' in provider_specific:
|
||||
model = provider_specific['model']
|
||||
|
||||
if not model:
|
||||
model = config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
|
||||
# Initialize provider
|
||||
provider = get_provider(provider_name, provider_config)
|
||||
|
||||
# Create prompt for planning
|
||||
full_prompt = f"Generate a detailed development plan for the following requirement:\n\n{prompt}\n\nInclude task breakdown, implementation steps, potential challenges, and recommendations."
|
||||
|
||||
# Load context
|
||||
context_messages = load_context()
|
||||
|
||||
# Add project context if this is the first message
|
||||
if not context_messages:
|
||||
project_context = get_project_context()
|
||||
if project_context.strip():
|
||||
context_messages.append({
|
||||
"role": "system",
|
||||
"content": f"Project context:\n{project_context}"
|
||||
})
|
||||
|
||||
# Add user message to context
|
||||
user_message = {"role": "user", "content": full_prompt}
|
||||
context_messages.append(user_message)
|
||||
|
||||
# Prepare messages for API
|
||||
# Limit context to max_context_messages
|
||||
max_context = config.get('max_context_messages', 10)
|
||||
recent_messages = context_messages[-max_context:]
|
||||
|
||||
# Print Claude-style header
|
||||
print_claude_header(provider_name, model)
|
||||
|
||||
try:
|
||||
# Get response from provider
|
||||
response = provider.get_completion(recent_messages, model)
|
||||
|
||||
# Add AI response to context
|
||||
ai_message = {"role": "assistant", "content": response}
|
||||
context_messages.append(ai_message)
|
||||
|
||||
# Save updated context
|
||||
save_context(context_messages)
|
||||
|
||||
# Print response
|
||||
print(f"📋 Development Plan:\n{response}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting response: {str(e)}")
|
||||
@@ -0,0 +1,120 @@
|
||||
"""Review command for AI CLI."""
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add src to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
from src.utils.config import load_config, get_provider_config
|
||||
from src.providers.base import get_provider
|
||||
from src.utils.context import load_context, save_context
|
||||
from src.utils.formatting import print_claude_header, print_info
|
||||
from src.utils.project_context import get_project_context, read_file_content
|
||||
|
||||
|
||||
def review_command(target, custom_prompt, provider_override=None, model_override=None):
|
||||
"""Review code with AI."""
|
||||
config = load_config()
|
||||
if not config:
|
||||
print("❌ Configuration not found. Please run 'ai init' first.")
|
||||
return
|
||||
|
||||
# Determine provider and model
|
||||
provider_name = provider_override or config.get('default_provider', 'openrouter')
|
||||
provider_config = get_provider_config(provider_name)
|
||||
|
||||
if not provider_config:
|
||||
print(f"❌ Provider '{provider_name}' not configured.")
|
||||
return
|
||||
|
||||
# Get model - either from override, provider config, or default
|
||||
model = model_override
|
||||
if not model:
|
||||
# Try to get from provider config first, then fallback to default
|
||||
if provider_name in config.get('providers', {}):
|
||||
provider_specific = config['providers'][provider_name]
|
||||
if 'model' in provider_specific:
|
||||
model = provider_specific['model']
|
||||
|
||||
if not model:
|
||||
model = config.get('default_model', 'anthropic/claude-4.5-sonnet')
|
||||
|
||||
# Initialize provider
|
||||
provider = get_provider(provider_name, provider_config)
|
||||
|
||||
target_path = Path(target)
|
||||
|
||||
if not target_path.exists():
|
||||
print(f"❌ Target '{target}' does not exist.")
|
||||
return
|
||||
|
||||
# Read content based on target type
|
||||
if target_path.is_file():
|
||||
file_content = read_file_content(str(target_path))
|
||||
target_context = f"File: {target_path}\n\n```{target_path.suffix[1:] if target_path.suffix else 'txt'}\n{file_content}\n```"
|
||||
elif target_path.is_dir():
|
||||
# For directories, get a sample of files
|
||||
target_context = f"Directory: {target_path}\n\nContent review:\n"
|
||||
file_count = 0
|
||||
for file_path in target_path.rglob('*'):
|
||||
if file_path.is_file() and file_path.suffix in ['.py', '.js', '.ts', '.jsx', '.tsx', '.md', '.txt', '.json', '.yaml', '.yml']:
|
||||
content = read_file_content(str(file_path))
|
||||
target_context += f"\nFile: {file_path}\n```\n{content}\n```\n"
|
||||
file_count += 1
|
||||
if file_count >= 5 or len(target_context) > 10000: # Limit files or size
|
||||
if file_count >= 5:
|
||||
target_context += "\n...(additional files not included in review)"
|
||||
else:
|
||||
target_context += "\n...(truncated due to size)"
|
||||
break
|
||||
else:
|
||||
print(f"❌ Target '{target}' is neither a file nor a directory.")
|
||||
return
|
||||
|
||||
# Create prompt for review
|
||||
if custom_prompt:
|
||||
full_prompt = f"{custom_prompt}\n\nHere is the target to review:\n{target_context}"
|
||||
else:
|
||||
full_prompt = f"Please perform a code review on the following code/files. Identify potential issues, suggest improvements, and provide feedback on code quality, security, performance, and best practices.\n\n{target_context}"
|
||||
|
||||
# Load context
|
||||
context_messages = load_context()
|
||||
|
||||
# Add project context if this is the first message
|
||||
if not context_messages:
|
||||
project_context = get_project_context()
|
||||
if project_context.strip():
|
||||
context_messages.append({
|
||||
"role": "system",
|
||||
"content": f"Project context:\n{project_context}"
|
||||
})
|
||||
|
||||
# Add user message to context
|
||||
user_message = {"role": "user", "content": full_prompt}
|
||||
context_messages.append(user_message)
|
||||
|
||||
# Prepare messages for API
|
||||
# Limit context to max_context_messages
|
||||
max_context = config.get('max_context_messages', 10)
|
||||
recent_messages = context_messages[-max_context:]
|
||||
|
||||
# Print Claude-style header
|
||||
print_claude_header(provider_name, model)
|
||||
|
||||
try:
|
||||
# Get response from provider
|
||||
response = provider.get_completion(recent_messages, model)
|
||||
|
||||
# Add AI response to context
|
||||
ai_message = {"role": "assistant", "content": response}
|
||||
context_messages.append(ai_message)
|
||||
|
||||
# Save updated context
|
||||
save_context(context_messages)
|
||||
|
||||
# Print response
|
||||
print(f"📊 Review Report:\n{response}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error getting response: {str(e)}")
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,77 @@
|
||||
"""Base provider interface and concrete implementations."""
|
||||
import requests
|
||||
import json
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
class BaseProvider(ABC):
|
||||
"""Base class for AI providers."""
|
||||
|
||||
@abstractmethod
|
||||
def get_completion(self, messages: List[Dict[str, str]], model: str) -> str:
|
||||
"""Get completion from the provider."""
|
||||
pass
|
||||
|
||||
|
||||
class OpenRouterProvider(BaseProvider):
|
||||
"""OpenRouter provider implementation."""
|
||||
|
||||
def __init__(self, config: Dict[str, Any]):
|
||||
self.base_url = config['base_url']
|
||||
self.api_key = config['api_key']
|
||||
|
||||
def get_completion(self, messages: List[Dict[str, str]], model: str) -> str:
|
||||
"""Get completion from OpenRouter API."""
|
||||
headers = {
|
||||
'Authorization': f'Bearer {self.api_key}',
|
||||
'Content-Type': 'application/json',
|
||||
'HTTP-Referer': 'https://github.com/your-username/ai-cli', # Optional, for usage tracking
|
||||
'X-Title': 'AI CLI Tool' # Optional, for usage tracking
|
||||
}
|
||||
|
||||
payload = {
|
||||
'model': model,
|
||||
'messages': messages,
|
||||
}
|
||||
|
||||
response = requests.post(self.base_url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
return data['choices'][0]['message']['content']
|
||||
|
||||
|
||||
class OllamaProvider(BaseProvider):
|
||||
"""Ollama provider implementation."""
|
||||
|
||||
def __init__(self, config: Dict[str, Any]):
|
||||
self.base_url = config['base_url']
|
||||
self.default_model = config.get('model', 'llama3.1')
|
||||
|
||||
def get_completion(self, messages: List[Dict[str, str]], model: str) -> str:
|
||||
"""Get completion from Ollama API."""
|
||||
# Use provided model or default
|
||||
actual_model = model if model else self.default_model
|
||||
|
||||
payload = {
|
||||
'model': actual_model,
|
||||
'messages': messages,
|
||||
'stream': False
|
||||
}
|
||||
|
||||
response = requests.post(self.base_url, json=payload)
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
return data['message']['content']
|
||||
|
||||
|
||||
def get_provider(provider_name: str, config: Dict[str, Any]) -> BaseProvider:
|
||||
"""Factory function to get the appropriate provider."""
|
||||
if provider_name == 'openrouter':
|
||||
return OpenRouterProvider(config)
|
||||
elif provider_name == 'ollama':
|
||||
return OllamaProvider(config)
|
||||
else:
|
||||
raise ValueError(f"Unsupported provider: {provider_name}")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
"""Configuration utilities for AI CLI."""
|
||||
import os
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_config_path():
|
||||
"""Get the path to the configuration file."""
|
||||
home_dir = Path.home()
|
||||
return home_dir / '.ai-cli' / 'config.yaml'
|
||||
|
||||
|
||||
def get_cache_dir():
|
||||
"""Get the path to the cache directory."""
|
||||
current_dir = Path.cwd()
|
||||
return current_dir / '.aicache'
|
||||
|
||||
|
||||
def load_config():
|
||||
"""Load configuration from file and environment variables."""
|
||||
config_path = get_config_path()
|
||||
|
||||
if not config_path.exists():
|
||||
return None
|
||||
|
||||
with open(config_path, 'r', encoding='utf-8') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Override with environment variables if they exist
|
||||
openrouter_api_key = os.environ.get('OPENROUTER_API_KEY')
|
||||
if openrouter_api_key:
|
||||
if 'providers' not in config:
|
||||
config['providers'] = {}
|
||||
if 'openrouter' not in config['providers']:
|
||||
config['providers']['openrouter'] = {}
|
||||
config['providers']['openrouter']['api_key'] = openrouter_api_key
|
||||
|
||||
openrouter_model = os.environ.get('OPENROUTER_MODEL')
|
||||
if openrouter_model:
|
||||
config['default_model'] = openrouter_model
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def save_config(config):
|
||||
"""Save configuration to file."""
|
||||
config_path = get_config_path()
|
||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
|
||||
|
||||
|
||||
def get_provider_config(provider_name=None):
|
||||
"""Get provider configuration."""
|
||||
config = load_config()
|
||||
if not config:
|
||||
return None
|
||||
|
||||
if provider_name:
|
||||
provider_config = config.get('providers', {}).get(provider_name)
|
||||
# Override with environment variable if this is openrouter
|
||||
if provider_name == 'openrouter':
|
||||
openrouter_api_key = os.environ.get('OPENROUTER_API_KEY')
|
||||
if openrouter_api_key:
|
||||
if provider_config is None:
|
||||
provider_config = {}
|
||||
provider_config['api_key'] = openrouter_api_key
|
||||
return provider_config
|
||||
else:
|
||||
default_provider = config.get('default_provider', 'openrouter')
|
||||
return get_provider_config(default_provider)
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Context management utilities."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from ..utils.config import get_cache_dir
|
||||
|
||||
|
||||
def get_context_file_path():
|
||||
"""Get path to context cache file."""
|
||||
cache_dir = get_cache_dir()
|
||||
return cache_dir / 'context.json'
|
||||
|
||||
|
||||
def load_context():
|
||||
"""Load conversation context from cache."""
|
||||
context_file = get_context_file_path()
|
||||
|
||||
if context_file.exists():
|
||||
with open(context_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def save_context(messages):
|
||||
"""Save conversation context to cache."""
|
||||
context_file = get_context_file_path()
|
||||
context_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(context_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(messages, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
def add_message_to_context(role, content):
|
||||
"""Add a message to the context."""
|
||||
messages = load_context()
|
||||
messages.append({"role": role, "content": content})
|
||||
save_context(messages)
|
||||
@@ -0,0 +1,31 @@
|
||||
"""Formatting utilities for Claude-style output."""
|
||||
import sys
|
||||
|
||||
|
||||
def print_claude_header(provider_name, model):
|
||||
"""Print Claude-style header with provider and model info."""
|
||||
header = f"Claude-Code Mode · {provider_name.upper()}({model})"
|
||||
thinking_msg = "🧠 Thinking..."
|
||||
|
||||
print(header)
|
||||
print(thinking_msg)
|
||||
|
||||
|
||||
def print_success(message):
|
||||
"""Print success message."""
|
||||
print(f"✅ {message}")
|
||||
|
||||
|
||||
def print_error(message):
|
||||
"""Print error message."""
|
||||
print(f"❌ {message}")
|
||||
|
||||
|
||||
def print_info(message):
|
||||
"""Print info message."""
|
||||
print(f"ℹ️ {message}")
|
||||
|
||||
|
||||
def print_warning(message):
|
||||
"""Print warning message."""
|
||||
print(f"⚠️ {message}")
|
||||
@@ -0,0 +1,96 @@
|
||||
"""Project-aware context utilities."""
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any
|
||||
|
||||
|
||||
def get_git_diff():
|
||||
"""Get current git diff if in a git repository."""
|
||||
try:
|
||||
result = subprocess.run(['git', 'diff'], capture_output=True, text=True, cwd=Path.cwd())
|
||||
if result.returncode == 0 and result.stdout:
|
||||
return result.stdout
|
||||
return ""
|
||||
except FileNotFoundError:
|
||||
# Git not installed
|
||||
return ""
|
||||
|
||||
|
||||
def get_file_tree(max_depth=3):
|
||||
"""Get file tree of current directory."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['find', '.', '-maxdepth', str(max_depth), '-type', 'f'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=Path.cwd()
|
||||
)
|
||||
if result.returncode == 0:
|
||||
files = [line for line in result.stdout.split('\n') if line]
|
||||
return '\n'.join(files[:50]) # Limit to 50 files
|
||||
return ""
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
|
||||
|
||||
def get_project_structure():
|
||||
"""Get project structure information."""
|
||||
project_info = {
|
||||
'git_diff': get_git_diff(),
|
||||
'file_tree': get_file_tree(),
|
||||
'directories': [],
|
||||
'files': []
|
||||
}
|
||||
|
||||
# Get directories and files
|
||||
for root, dirs, files in os.walk('.'):
|
||||
# Skip hidden directories
|
||||
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
||||
|
||||
rel_root = os.path.relpath(root, '.')
|
||||
if rel_root != '.':
|
||||
project_info['directories'].append(rel_root)
|
||||
|
||||
for file in files:
|
||||
if not file.startswith('.'): # Skip hidden files
|
||||
file_path = os.path.join(rel_root, file) if rel_root != '.' else file
|
||||
project_info['files'].append(file_path)
|
||||
|
||||
# Limit to reasonable amounts
|
||||
project_info['directories'] = project_info['directories'][:20]
|
||||
project_info['files'] = project_info['files'][:50]
|
||||
|
||||
return project_info
|
||||
|
||||
|
||||
def read_file_content(file_path: str, max_lines=100):
|
||||
"""Read content of a specific file."""
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
lines = f.readlines()
|
||||
return ''.join(lines[:max_lines])
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def get_project_context():
|
||||
"""Get comprehensive project context."""
|
||||
context = f"# Project Context\n\n"
|
||||
|
||||
# Add file tree
|
||||
file_tree = get_file_tree()
|
||||
if file_tree:
|
||||
context += f"## Directory Structure\n```\n{file_tree}\n```\n\n"
|
||||
|
||||
# Add git diff if available
|
||||
git_diff = get_git_diff()
|
||||
if git_diff:
|
||||
context += f"## Current Changes (Git Diff)\n```\n{git_diff}\n```\n\n"
|
||||
|
||||
# Add project files list
|
||||
project_info = get_project_structure()
|
||||
if project_info['files']:
|
||||
context += f"## Project Files\n```\n" + "\n".join(project_info['files'][:30]) + "\n```\n\n"
|
||||
|
||||
return context
|
||||
@@ -0,0 +1,6 @@
|
||||
def hello_world():
|
||||
"""Simple function to say hello."""
|
||||
print("Hello, World!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
hello_world()
|
||||
@@ -0,0 +1,42 @@
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
|
||||
def test_model_access(model_id):
|
||||
api_key = os.getenv('OPENROUTER_API_KEY')
|
||||
headers = {
|
||||
'Authorization': f'Bearer {api_key}',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
messages = [
|
||||
{"role": "user", "content": "Test"}
|
||||
]
|
||||
|
||||
payload = {
|
||||
'model': model_id,
|
||||
'messages': messages,
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post("https://openrouter.ai/api/v1/chat/completions", headers=headers, json=payload)
|
||||
print(f"Model {model_id}: Status {response.status_code}")
|
||||
if response.status_code != 200:
|
||||
print(f" Error: {response.text}")
|
||||
else:
|
||||
print(f" Success: Model accessible")
|
||||
return response.status_code
|
||||
except Exception as e:
|
||||
print(f"Model {model_id}: Exception {str(e)}")
|
||||
return None
|
||||
|
||||
# Test different models
|
||||
test_models = [
|
||||
"anthropic/claude-sonnet-4.5",
|
||||
"anthropic/claude-haiku-4.5",
|
||||
"anthropic/claude-3.5-sonnet",
|
||||
"anthropic/claude-3.5-haiku"
|
||||
]
|
||||
|
||||
for model in test_models:
|
||||
test_model_access(model)
|
||||
Submodule
+1
Submodule ai/ai-cli/y-router added at 6ef40e4ebe
Submodule
+1
Submodule ai/claude-bluebook added at cbc925f514
Submodule
+1
Submodule ai/claude-code added at 7a05427a4b
Submodule
+1
Submodule ai/claude-code-cli/y-router added at 6ef40e4ebe
@@ -0,0 +1,121 @@
|
||||
# Cursor AI 配置工具
|
||||
|
||||
通过 cursor-agent 调用 OpenRouter API 的完整解决方案。
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 使用 OpenRouter API
|
||||
|
||||
```bash
|
||||
./cursor-agent.sh openrouter
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```bash
|
||||
./cursor-agent.sh cloud
|
||||
```
|
||||
|
||||
### 使用本地 Ollama
|
||||
|
||||
```bash
|
||||
./cursor-agent.sh local
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```bash
|
||||
./cursor-agent.sh ollama
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 统一配置文件
|
||||
|
||||
所有配置变量统一在 `config.sh` 中管理,避免重复定义:
|
||||
|
||||
- `OPENROUTER_KEY`: OpenRouter API Key
|
||||
- `LOCAL_API`: 本地 Ollama API 地址
|
||||
- `CLOUD_API`: OpenRouter API 地址
|
||||
- `LOCAL_MODEL`: 本地模型名称
|
||||
- `CLOUD_MODEL`: 云端模型名称
|
||||
|
||||
### 修改 API Key
|
||||
|
||||
编辑 `config.sh` 文件,修改 `OPENROUTER_KEY` 变量:
|
||||
|
||||
```bash
|
||||
OPENROUTER_KEY="sk-or-v1-your-api-key-here"
|
||||
```
|
||||
|
||||
## 工具说明
|
||||
|
||||
### cursor-agent.sh
|
||||
|
||||
**主要工具** - 通过环境变量配置并启动 Cursor:
|
||||
|
||||
- 自动设置 `OPENAI_API_KEY` 和 `OPENAI_API_BASE` 环境变量
|
||||
- 支持 OpenRouter 和本地 Ollama 两种模式
|
||||
- 自动检查并启动 Ollama 服务(本地模式)
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
./cursor-agent.sh openrouter # 使用 OpenRouter
|
||||
./cursor-agent.sh local # 使用本地 Ollama
|
||||
```
|
||||
|
||||
### cursor-model-switch.sh
|
||||
|
||||
**模型切换工具** - 快速切换 Cursor 使用的模型来源:
|
||||
|
||||
```bash
|
||||
./cursor-model-switch.sh cloud # 切换到 OpenRouter
|
||||
./cursor-model-switch.sh local # 切换到本地 Ollama
|
||||
```
|
||||
|
||||
### cursor-openrouter-proxy.sh
|
||||
|
||||
**OpenRouter 代理服务器** - 通过本地代理转发请求到 OpenRouter(实验性):
|
||||
|
||||
```bash
|
||||
./cursor-openrouter-proxy.sh start # 启动代理并打开 Cursor
|
||||
./cursor-openrouter-proxy.sh stop # 停止代理服务
|
||||
./cursor-openrouter-proxy.sh restart # 重启代理服务
|
||||
./cursor-openrouter-proxy.sh status # 查看代理状态
|
||||
```
|
||||
|
||||
**注意**:由于 Cursor 在应用层面检查订阅状态,此方案可能仍会被拦截。
|
||||
|
||||
### git-proxy-fix.sh
|
||||
|
||||
**Git 代理管理工具**:
|
||||
|
||||
```bash
|
||||
./git-proxy-fix.sh on # 开启代理
|
||||
./git-proxy-fix.sh off # 关闭代理
|
||||
./git-proxy-fix.sh # 自动检测并修复
|
||||
```
|
||||
|
||||
## 工作原理
|
||||
|
||||
Cursor 通过环境变量 `OPENAI_API_KEY` 和 `OPENAI_API_BASE` 来配置 API 连接:
|
||||
|
||||
- **OpenRouter 模式**: 设置 `OPENAI_API_KEY` 为 OpenRouter API Key,`OPENAI_API_BASE` 为 `https://openrouter.ai/api/v1`,模型为 `anthropic/claude-4.5-sonnet`
|
||||
- **本地模式**: 设置 `OPENAI_API_KEY` 为 `ollama`,`OPENAI_API_BASE` 为 `http://localhost:11434/v1`
|
||||
|
||||
`cursor-agent.sh` 脚本会:
|
||||
1. 设置环境变量并通过 `launchctl setenv` 设置系统级环境变量
|
||||
2. 在启动 Cursor 时传递环境变量,确保 Cursor 使用正确的 API 配置
|
||||
|
||||
### 免费用户使用 Claude 4.5
|
||||
|
||||
即使你是 Cursor 免费用户,通过 OpenRouter API 仍然可以访问 Claude 4.5:
|
||||
- Cursor 免费版限制:只能使用 GPT 4.1 或 Auto
|
||||
- 通过 OpenRouter:可以使用任何 OpenRouter 支持的模型(包括 Claude 4.5)
|
||||
- 使用方法:运行 `./cursor-agent.sh openrouter` 即可通过 OpenRouter API 使用 Claude 4.5
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 首次使用前请修改 `config.sh` 中的 `OPENROUTER_KEY` 为你的实际 API Key
|
||||
2. 使用本地模式前确保已安装并运行 Ollama
|
||||
3. 所有脚本需要执行权限,已自动设置
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
# 统一配置文件 - 管理所有变量避免重复定义
|
||||
OPENROUTER_KEY="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" # OpenRouter API Key
|
||||
LOCAL_API="http://localhost:11434/v1" # 本地 Ollama API
|
||||
CLOUD_API="https://openrouter.ai/api/v1" # OpenRouter API
|
||||
LOCAL_MODEL="deepseek-coder:33b" # 本地模型名称
|
||||
CLOUD_MODEL="anthropic/claude-4.5-sonnet" # 云端模型名称
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# Cursor Agent - 通过环境变量配置 OpenRouter API 并启动 Cursor
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/config.sh" # 加载统一配置
|
||||
|
||||
case "$1" in
|
||||
openrouter|cloud) # 使用 OpenRouter
|
||||
export OPENAI_API_KEY="$OPENROUTER_KEY"
|
||||
export OPENAI_API_BASE="$CLOUD_API"
|
||||
export MODEL="$CLOUD_MODEL"
|
||||
echo "🌐 已配置 OpenRouter API: $CLOUD_API"
|
||||
echo "🤖 模型: $CLOUD_MODEL"
|
||||
echo "🔑 API Key: ${OPENROUTER_KEY:0:20}..."
|
||||
# 设置系统环境变量供 Cursor 读取
|
||||
launchctl setenv OPENAI_API_KEY "$OPENROUTER_KEY" 2>/dev/null || true
|
||||
launchctl setenv OPENAI_API_BASE "$CLOUD_API" 2>/dev/null || true
|
||||
launchctl setenv MODEL "$CLOUD_MODEL" 2>/dev/null || true
|
||||
# 通过环境变量启动 Cursor
|
||||
env OPENAI_API_KEY="$OPENROUTER_KEY" OPENAI_API_BASE="$CLOUD_API" MODEL="$CLOUD_MODEL" open -a "Cursor"
|
||||
;;
|
||||
local|ollama) # 使用本地 Ollama
|
||||
if ! pgrep -x "ollama" >/dev/null; then ollama serve >/dev/null 2>&1 & sleep 2; fi # 检查并启动 Ollama
|
||||
if ! curl -s "$LOCAL_API/models" >/dev/null; then echo "❌ Ollama 未运行"; exit 1; fi # 检查连接
|
||||
export OPENAI_API_KEY="ollama"
|
||||
export OPENAI_API_BASE="$LOCAL_API"
|
||||
export MODEL="$LOCAL_MODEL"
|
||||
echo "✅ 已配置本地 Ollama: $LOCAL_API"
|
||||
echo "🤖 模型: $LOCAL_MODEL"
|
||||
# 设置系统环境变量供 Cursor 读取
|
||||
launchctl setenv OPENAI_API_KEY "ollama" 2>/dev/null || true
|
||||
launchctl setenv OPENAI_API_BASE "$LOCAL_API" 2>/dev/null || true
|
||||
launchctl setenv MODEL "$LOCAL_MODEL" 2>/dev/null || true
|
||||
# 通过环境变量启动 Cursor
|
||||
env OPENAI_API_KEY="ollama" OPENAI_API_BASE="$LOCAL_API" MODEL="$LOCAL_MODEL" open -a "Cursor"
|
||||
;;
|
||||
*) # 显示用法
|
||||
echo "用法: ./cursor-agent.sh [openrouter|local]"
|
||||
echo " openrouter - 使用 OpenRouter API (Claude 4.5/Qwen/DeepSeek)"
|
||||
echo " local - 使用本地 Ollama (DeepSeek)"
|
||||
echo ""
|
||||
echo "💡 提示: 作为 Cursor 免费用户,通过 OpenRouter API 可以访问 Claude 4.5"
|
||||
;;
|
||||
esac
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
# Created Time: 2025-11-09 06:27:13
|
||||
# Modified Time: 2025-11-09 06:28:44
|
||||
#set -e # 这告诉bash一但有任何一个语句返回非真的值,则退出bash。
|
||||
#!/bin/bash
|
||||
# ===============================================
|
||||
# 🧠 Cursor AI 模型切换脚本
|
||||
# 作者: Bruno Gao (灵境万象)
|
||||
# 功能: 一键切换 Cursor 使用的模型来源
|
||||
# - 本地 DeepSeek(通过 Ollama)
|
||||
# - OpenRouter Claude (Claude 4.5 / Qwen / DeepSeek)
|
||||
# ===============================================
|
||||
|
||||
# 加载统一配置
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/config.sh"
|
||||
|
||||
# 检查 Ollama 是否运行
|
||||
check_ollama() {
|
||||
if ! pgrep -x "ollama" >/dev/null; then
|
||||
echo "🟡 Ollama 未运行,正在启动..."
|
||||
ollama serve >/dev/null 2>&1 &
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# 检查端口是否可访问
|
||||
if ! curl -s "$LOCAL_API/models" >/dev/null; then
|
||||
echo "❌ 无法连接到 Ollama 接口 ($LOCAL_API)"
|
||||
echo "请确认 Ollama 已启动并监听 11434 端口"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 切换到本地模型
|
||||
switch_local() {
|
||||
check_ollama
|
||||
export OPENAI_API_KEY="ollama"
|
||||
export OPENAI_API_BASE="$LOCAL_API"
|
||||
echo "✅ 已切换到本地 DeepSeek 模型 (Ollama)"
|
||||
echo "🚀 正在打开 Cursor..."
|
||||
open -a "Cursor"
|
||||
}
|
||||
|
||||
# 切换到云端模型
|
||||
switch_cloud() {
|
||||
export OPENAI_API_KEY="$OPENROUTER_KEY"
|
||||
export OPENAI_API_BASE="$CLOUD_API"
|
||||
echo "🌐 已切换到 OpenRouter Claude/Qwen/DeepSeek"
|
||||
echo "🚀 正在打开 Cursor..."
|
||||
open -a "Cursor"
|
||||
}
|
||||
|
||||
# 脚本参数控制
|
||||
case "$1" in
|
||||
local)
|
||||
switch_local
|
||||
;;
|
||||
cloud)
|
||||
switch_cloud
|
||||
;;
|
||||
*)
|
||||
echo "用法: ./cursor-model-switch.sh [local|cloud]"
|
||||
echo "示例:"
|
||||
echo " ./cursor-model-switch.sh local # 切换到本地 DeepSeek 模型"
|
||||
echo " ./cursor-model-switch.sh cloud # 切换到 OpenRouter Claude"
|
||||
;;
|
||||
esac
|
||||
Executable
+116
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
# Cursor OpenRouter 代理 - 通过本地代理服务器绕过 Cursor 订阅检查
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/config.sh" # 加载统一配置
|
||||
|
||||
PROXY_PORT=11435 # 本地代理端口
|
||||
PROXY_PID_FILE="/tmp/cursor-openrouter-proxy.pid"
|
||||
|
||||
start_proxy() {
|
||||
if [ -f "$PROXY_PID_FILE" ] && kill -0 "$(cat "$PROXY_PID_FILE")" 2>/dev/null; then
|
||||
echo "✅ 代理服务已在运行 (PID: $(cat "$PROXY_PID_FILE"))"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 启动 Python 代理服务器
|
||||
python3 -c "
|
||||
import http.server
|
||||
import socketserver
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import sys
|
||||
import os
|
||||
|
||||
class ProxyHandler(http.server.BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
content_length = int(self.headers.get('Content-Length', 0))
|
||||
body = self.rfile.read(content_length)
|
||||
|
||||
try:
|
||||
data = json.loads(body.decode('utf-8'))
|
||||
# 修改请求以使用 OpenRouter
|
||||
data['model'] = '$CLOUD_MODEL'
|
||||
|
||||
# 转发到 OpenRouter
|
||||
req = urllib.request.Request('$CLOUD_API/chat/completions',
|
||||
data=json.dumps(data).encode('utf-8'),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $OPENROUTER_KEY',
|
||||
'HTTP-Referer': 'https://cursor.sh',
|
||||
'X-Title': 'Cursor OpenRouter Proxy'
|
||||
})
|
||||
|
||||
with urllib.request.urlopen(req) as response:
|
||||
resp_data = response.read()
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as e:
|
||||
self.send_response(500)
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({'error': str(e)}).encode('utf-8'))
|
||||
|
||||
def log_message(self, format, *args):
|
||||
pass # 静默日志
|
||||
|
||||
with socketserver.TCPServer(('', $PROXY_PORT), ProxyHandler) as httpd:
|
||||
with open('$PROXY_PID_FILE', 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
httpd.serve_forever()
|
||||
" >/dev/null 2>&1 &
|
||||
|
||||
sleep 1
|
||||
if [ -f "$PROXY_PID_FILE" ]; then
|
||||
echo "✅ OpenRouter 代理服务已启动 (端口: $PROXY_PORT)"
|
||||
echo "🌐 代理地址: http://localhost:$PROXY_PORT"
|
||||
else
|
||||
echo "❌ 代理服务启动失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
stop_proxy() {
|
||||
if [ -f "$PROXY_PID_FILE" ]; then
|
||||
PID=$(cat "$PROXY_PID_FILE")
|
||||
kill "$PID" 2>/dev/null && rm "$PROXY_PID_FILE" && echo "✅ 代理服务已停止" || echo "❌ 停止代理服务失败"
|
||||
else
|
||||
echo "ℹ️ 代理服务未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_proxy
|
||||
export OPENAI_API_KEY="dummy" # Cursor 需要这个变量存在
|
||||
export OPENAI_API_BASE="http://localhost:$PROXY_PORT"
|
||||
launchctl setenv OPENAI_API_KEY "dummy" 2>/dev/null || true
|
||||
launchctl setenv OPENAI_API_BASE "http://localhost:$PROXY_PORT" 2>/dev/null || true
|
||||
echo "🚀 正在启动 Cursor..."
|
||||
env OPENAI_API_KEY="dummy" OPENAI_API_BASE="http://localhost:$PROXY_PORT" open -a "Cursor"
|
||||
;;
|
||||
stop)
|
||||
stop_proxy
|
||||
;;
|
||||
restart)
|
||||
stop_proxy
|
||||
sleep 1
|
||||
start_proxy
|
||||
;;
|
||||
status)
|
||||
if [ -f "$PROXY_PID_FILE" ] && kill -0 "$(cat "$PROXY_PID_FILE")" 2>/dev/null; then
|
||||
echo "✅ 代理服务运行中 (PID: $(cat "$PROXY_PID_FILE"), 端口: $PROXY_PORT)"
|
||||
else
|
||||
echo "❌ 代理服务未运行"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "用法: ./cursor-openrouter-proxy.sh [start|stop|restart|status]"
|
||||
echo " start - 启动代理服务并打开 Cursor"
|
||||
echo " stop - 停止代理服务"
|
||||
echo " restart - 重启代理服务"
|
||||
echo " status - 查看代理服务状态"
|
||||
;;
|
||||
esac
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Git代理修复脚本
|
||||
PROXY="http://127.0.0.1:7890"
|
||||
check_proxy(){ lsof -i :7890 >/dev/null 2>&1; } # 检查代理是否运行
|
||||
unset_proxy(){ git config --global --unset http.proxy && git config --global --unset https.proxy && echo "✅ 已取消git代理设置"; } # 取消代理
|
||||
set_proxy(){ git config --global http.proxy "$PROXY" && git config --global https.proxy "$PROXY" && echo "✅ 已设置git代理: $PROXY"; } # 设置代理
|
||||
case "$1" in
|
||||
off) unset_proxy;; # 取消代理
|
||||
on) set_proxy;; # 设置代理
|
||||
*) if check_proxy;then echo "✅ 代理服务运行中 ($PROXY)";else echo "❌ 代理服务未运行,正在取消git代理设置..." && unset_proxy;fi;; # 自动检测并修复
|
||||
esac
|
||||
Submodule
+1
Submodule ai/deepseek-cli added at db2733f745
Submodule
+1
Submodule ai/devops-ai-stack-finalized added at 6dbe573d0a
Submodule
+1
Submodule ai/qwen-code added at c5286c0b3e
Submodule
+1
Submodule ai/y-router added at 6ef40e4ebe
Submodule
+1
Submodule dify_github added at c7980d1b48
@@ -0,0 +1,25 @@
|
||||
[common]
|
||||
server_addr = x.x.x.x # 国内服务器公网IP
|
||||
server_port = 7000
|
||||
authentication_method = "token"
|
||||
token = "lingjingwanxiang2024"
|
||||
|
||||
# WireGuard 控制端口转发
|
||||
[wireguard]
|
||||
type = udp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 51820
|
||||
remote_port = 51820
|
||||
|
||||
# SSH / VNC 远程访问隧道
|
||||
[ssh]
|
||||
type = tcp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 22
|
||||
remote_port = 2222
|
||||
|
||||
[vnc]
|
||||
type = tcp
|
||||
local_ip = 127.0.0.1
|
||||
local_port = 5900
|
||||
remote_port = 5900
|
||||
@@ -32,6 +32,7 @@ services:
|
||||
- GITEA__service__DISABLE_REGISTRATION=false # 允许注册
|
||||
- GITEA__service__REQUIRE_SIGNIN_VIEW=false
|
||||
- GITEA__actions__ENABLED=true # 启用Actions
|
||||
- GITEA__actions__DEFAULT_ACTIONS_URL=https://github.com
|
||||
# 禁用代理,确保健康检查和内部通信不受影响
|
||||
- http_proxy=
|
||||
- https_proxy=
|
||||
@@ -51,7 +52,7 @@ services:
|
||||
# Gitea Action Runner 1 - Docker 构建
|
||||
# ==========================================
|
||||
runner-docker:
|
||||
image: ghcr.io/go-gitea/act_runner:latest
|
||||
image: docker.m.daocloud.io/gitea/act_runner:latest
|
||||
container_name: gitea-runner-docker
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -59,18 +60,18 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- CONFIG_FILE=/config/runner-config.yaml
|
||||
- GITEA_INSTANCE_URL=http://gitea:3000
|
||||
- GITEA_INSTANCE_URL=http://192.168.1.83:33000
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN:-}
|
||||
- GITEA_RUNNER_NAME=runner-docker-01
|
||||
- GITEA_RUNNER_LABELS=docker:docker://ghcr.io/go-gitea/act_runner/act_runner:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /Users/brunogao/.orbstack/run/docker.sock:/var/run/docker.sock
|
||||
- ./runner-docker:/data
|
||||
- ./runner-config.yaml:/config/runner-config.yaml:ro
|
||||
networks:
|
||||
- gitea-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
|
||||
test: ["CMD", "curl", "-f", "http://gitea:3000/api/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
@@ -79,7 +80,7 @@ services:
|
||||
# Gitea Action Runner 2 - Kubernetes 部署
|
||||
# ==========================================
|
||||
runner-k8s:
|
||||
image: ghcr.io/go-gitea/act_runner:latest
|
||||
image: docker.m.daocloud.io/gitea/act_runner:latest
|
||||
container_name: gitea-runner-k8s
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -87,19 +88,19 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- CONFIG_FILE=/config/runner-k8s-config.yaml
|
||||
- GITEA_INSTANCE_URL=http://gitea:3000
|
||||
- GITEA_INSTANCE_URL=http://192.168.1.83:33000
|
||||
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN:-}
|
||||
- GITEA_RUNNER_NAME=runner-k8s-01
|
||||
- GITEA_RUNNER_LABELS=kubernetes:docker://ghcr.io/go-gitea/act_runner/act_runner:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /Users/brunogao/.orbstack/run/docker.sock:/var/run/docker.sock
|
||||
- $HOME/.kube/config:/root/.kube/config:ro
|
||||
- ./runner-k8s:/data
|
||||
- ./runner-k8s-config.yaml:/config/runner-k8s-config.yaml:ro
|
||||
networks:
|
||||
- gitea-network
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
|
||||
test: ["CMD", "curl", "-f", "http://gitea:3000/api/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
@@ -29,9 +29,9 @@ cache:
|
||||
port: 0
|
||||
password: ""
|
||||
container:
|
||||
network: "host"
|
||||
network: "container:gitea-runner-docker"
|
||||
privileged: false
|
||||
options: "user: root"
|
||||
options: "user: root,add-host=gitea:127.0.0.1"
|
||||
valid_volumes:
|
||||
- "/var/run/docker.sock"
|
||||
docker_host: "-"
|
||||
@@ -39,8 +39,8 @@ container:
|
||||
pull_policy: "if-not-present"
|
||||
# 确保使用正确的镜像,避免使用 gitea 官方镜像
|
||||
default_image: "node:20-alpine"
|
||||
# Optional gitea host
|
||||
host: ""
|
||||
# Optional gitea host - runner 容器内访问 Gitea (使用 Docker 宿主别名)
|
||||
host: "host.docker.internal"
|
||||
# Optional gitea token
|
||||
token: ""
|
||||
# Optional gitea client id
|
||||
@@ -48,4 +48,4 @@ container:
|
||||
# Optional gitea client secret
|
||||
client_secret: ""
|
||||
# Optional gitea server url
|
||||
server_url: "http://192.168.1.83:33000/"
|
||||
server_url: "http://127.0.0.1:33000/"
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"WARNING": "This file is automatically generated by act-runner. Do not edit it manually unless you know what you are doing. Removing this file will cause act runner to re-register as a new runner.",
|
||||
"id": 6,
|
||||
"uuid": "e995ea42-183e-4318-bbad-f9c59404394a",
|
||||
"name": "runner-docker-01",
|
||||
"token": "ac834988870d9ddc859f6e862ed5401732b4640c",
|
||||
"address": "http://gitea:3000",
|
||||
"labels": [
|
||||
"ubuntu-latest:docker://192.168.1.83:8443/bookstore/ci-simple:latest"
|
||||
],
|
||||
"ephemeral": false
|
||||
}
|
||||
@@ -24,9 +24,9 @@ cache:
|
||||
- "/var/run/docker.sock"
|
||||
|
||||
container:
|
||||
network: "host"
|
||||
network: "container:gitea-runner-k8s"
|
||||
privileged: false
|
||||
options: "user: root"
|
||||
options: "user: root,add-host=gitea:127.0.0.1"
|
||||
valid_volumes:
|
||||
- "/var/run/docker.sock"
|
||||
- "/root/.kube"
|
||||
@@ -34,8 +34,8 @@ container:
|
||||
force_pull: false
|
||||
pull_policy: "if-not-present"
|
||||
default_image: "alpine:3.18"
|
||||
host: ""
|
||||
host: "host.docker.internal"
|
||||
token: ""
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
server_url: "http://gitea:3000"
|
||||
server_url: "http://127.0.0.1:33000/"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"WARNING": "This file is automatically generated by act-runner. Do not edit it manually unless you know what you are doing. Removing this file will cause act runner to re-register as a new runner.",
|
||||
"id": 5,
|
||||
"uuid": "67da5597-d992-4570-9f34-3e55599c0898",
|
||||
"name": "runner-k8s-01",
|
||||
"token": "88cc1e823bf560c8099992c5a81775c237722caf",
|
||||
"address": "http://gitea:3000",
|
||||
"labels": [
|
||||
"kubernetes:docker://ghcr.io/go-gitea/act_runner/act_runner:latest"
|
||||
],
|
||||
"ephemeral": false
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
Submodule
+1
Submodule lmrouter added at 9f3650db56
Submodule
+1
Submodule lmstudio-cli added at 42c4bf356c
Submodule
+1
Submodule performance/.devperf_tmp/git/angular added at ec9dc94cee
Submodule
+1
Submodule performance/.devperf_tmp/git/linux added at 4427259cc7
Submodule
+1
Submodule performance/.devperf_tmp/git/react added at 100fc4a8cf
Submodule
+1
Submodule performance/.devperf_tmp/git/vscode added at ad3ca06ea4
@@ -0,0 +1,4 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:04 CST 2025
|
||||
aopalliance-1.0.jar>alimaven=
|
||||
aopalliance-1.0.pom>alimaven=
|
||||
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
0235ba8b489512805ac13a8f9ea77a1ca5ebe3e8
|
||||
@@ -0,0 +1,15 @@
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>aopalliance</groupId>
|
||||
<artifactId>aopalliance</artifactId>
|
||||
<name>AOP alliance</name>
|
||||
<version>1.0</version>
|
||||
<description>AOP Alliance</description>
|
||||
<url>http://aopalliance.sourceforge.net</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Public Domain</name>
|
||||
</license>
|
||||
</licenses>
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
5128a2b0efbba460a1178d07773618e0986ea152
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:41:55 CST 2025
|
||||
avalon-framework-4.1.3.pom>alimaven=
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>avalon-framework</groupId>
|
||||
<artifactId>avalon-framework</artifactId>
|
||||
<version>4.1.3</version>
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
853c9df18e44caf0bab1eab8be0d482f9ec9bcd7
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:30 CST 2025
|
||||
logback-classic-1.4.11.jar>alimaven=
|
||||
logback-classic-1.4.11.pom>alimaven=
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
54450c0c783e896a1a6d88c043bd2f1daba1c382
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-parent</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Logback Classic Module</name>
|
||||
<description>logback-classic module</description>
|
||||
|
||||
<properties>
|
||||
<module-name>ch.qos.logback.classic</module-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-ext</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency> -->
|
||||
|
||||
<!-- <dependency>
|
||||
<groupId>ch.qos.cal10n.plugins</groupId>
|
||||
<artifactId>maven-cal10n-plugin</artifactId>
|
||||
<version>${cal10n.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency> -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<type>test-jar</type>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jul-to-slf4j</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Must be after log4j-over-slf4j:
|
||||
* we want to use the classes from log4j-over-slf4j (so it must come first);
|
||||
* we want to use log4j.dtd from log4j. -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.reload4j</groupId>
|
||||
<artifactId>reload4j</artifactId>
|
||||
<version>1.2.18.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>janino</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.main</artifactId>
|
||||
<version>5.6.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
</manifestEntries>
|
||||
<manifestFile>
|
||||
${project.build.outputDirectory}/META-INF/MANIFEST.MF
|
||||
</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-test-jar</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>${maven-antrun-plugin.version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-junit</artifactId>
|
||||
<version>${ant.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-junitlauncher</artifactId>
|
||||
<version>${ant.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit-jupiter-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<version>${junit-vintage-engine.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<executions>
|
||||
<!-- Disabled osgi tests given current OSGi/ServiceLoader integration failure -->
|
||||
<!--
|
||||
<execution>
|
||||
|
||||
<id>ant-osgi-test</id>
|
||||
<phase>package</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<property name="currentVersion" value="${project.version}"/>
|
||||
<property name="slf4j.version" value="${slf4j.version}"/>
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
<ant antfile="${basedir}/osgi-build.xml"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
-->
|
||||
<execution>
|
||||
<id>ant-integration-test</id>
|
||||
<phase>package</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<property name="slf4j.version" value="${slf4j.version}"/>
|
||||
<ant antfile="${basedir}/integration.xml"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration combine.self="append">
|
||||
<compilerArgs>
|
||||
<arg>add-reads</arg>
|
||||
<arg>ch.qos.logback.core=ch.qos.logback.core=org.codehaus.janino.commons.compiler,org.codehaus.janino.janino</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-test</id>
|
||||
<configuration>
|
||||
<!-- x-show-module-resolution -->
|
||||
<argLine>
|
||||
--add-modules jakarta.mail
|
||||
--add-modules jakarta.servlet
|
||||
--add-opens ch.qos.logback.core/ch.qos.logback.core.testUtil=java.naming
|
||||
--add-opens ch.qos.logback.classic/ch.qos.logback.classic.testUtil=ch.qos.logback.core
|
||||
--add-opens ch.qos.logback.classic/ch.qos.logback.classic.jsonTest=ALL-UNNAMED
|
||||
</argLine>
|
||||
<parallel>classes</parallel>
|
||||
<threadCount>8</threadCount>
|
||||
|
||||
<!--<useUnlimitedThreads>false</useUnlimitedThreads>-->
|
||||
<forkCount>1C</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
<reportFormat>plain</reportFormat>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
<!-- See https://issues.apache.org/jira/browse/SUREFIRE-1265 -->
|
||||
<!--<childDelegation>true</childDelegation>-->
|
||||
<useModulePath>true</useModulePath>
|
||||
|
||||
<excludes>
|
||||
<exclude>**/test_osgi/BundleTest.java</exclude>
|
||||
<exclude>org.slf4j.implTest.MultithreadedInitializationTest.java</exclude>
|
||||
<exclude>org.slf4j.implTest.InitializationOutputTest.java</exclude>
|
||||
<exclude>ch.qos.logback.classic.util.ContextInitializerTest.java</exclude>
|
||||
<exclude>ch.qos.logback.classic.spi.InvocationTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>singleJVM</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<forkCount>4</forkCount>
|
||||
<reuseForks>false</reuseForks>
|
||||
<includes>
|
||||
<include>org.slf4j.implTest.MultithreadedInitializationTest.java</include>
|
||||
<include>org.slf4j.implTest.InitializationOutputTest.java</include>
|
||||
<include>ch.qos.logback.classic.util.ContextInitializerTest.java</include>
|
||||
<include>ch.qos.logback.classic.spi.InvocationTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Export-Package>ch.qos.logback.classic*</Export-Package>
|
||||
<!-- LB-CLASSIC It is necessary to specify the rolling
|
||||
file packages as classes are created via IOC (xml
|
||||
config files). They won't be found by Bnd's analysis
|
||||
of java code. -->
|
||||
<Import-Package>
|
||||
ch.qos.logback.classic*;version="${range;[==,+);${version_cleanup;${project.version}}}",
|
||||
sun.reflect;resolution:=optional,
|
||||
jakarta.*;resolution:=optional,
|
||||
org.xml.*;resolution:=optional,
|
||||
ch.qos.logback.core.rolling,
|
||||
ch.qos.logback.core.rolling.helper,
|
||||
ch.qos.logback.core.read,
|
||||
*
|
||||
</Import-Package>
|
||||
<!-- Needed to integrate ServiceLoader mechanism with OSGi -->
|
||||
<Require-Capability><![CDATA[
|
||||
osgi.extender;filter:="(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))";resolution:=optional,
|
||||
osgi.extender;filter:="(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))",
|
||||
osgi.serviceloader;filter:="(osgi.serviceloader=ch.qos.logback.classic.spi.Configurator)";osgi.serviceloader="ch.qos.logback.classic.spi.Configurator";resolution:=optional;cardinality:=multiple
|
||||
]]></Require-Capability>
|
||||
<Provide-Capability><![CDATA[
|
||||
osgi.service;objectClass:List<String>="jakarta.servlet.ServletContainerInitializer";effective:=active,
|
||||
osgi.service;objectClass:List<String>="org.slf4j.spi.SLF4JServiceProvider";effective:=active,
|
||||
osgi.serviceloader;osgi.serviceloader="jakarta.servlet.ServletContainerInitializer";register:="ch.qos.logback.classic.servlet.LogbackServletContainerInitializer",
|
||||
osgi.serviceloader;osgi.serviceloader="org.slf4j.spi.SLF4JServiceProvider";register:="ch.qos.logback.classic.spi.LogbackServiceProvider"
|
||||
]]></Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
455cc31d881b6d0c2da70975899bcd5fe714273f
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:30 CST 2025
|
||||
logback-core-1.4.11.jar>alimaven=
|
||||
logback-core-1.4.11.pom>alimaven=
|
||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
||||
2f9f280219a9922a74200eaf7138c4c17fb87c0f
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-parent</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>logback-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Logback Core Module</name>
|
||||
<description>logback-core module</description>
|
||||
|
||||
<properties>
|
||||
<module-name>ch.qos.logback.core</module-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>janino</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>commons-compiler</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.fusesource.jansi</groupId>
|
||||
<artifactId>jansi</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
|
||||
<!--<argLine>XXadd-opens ch.qos.logback.core/ch.qos.logback.core.testUtil=java.naming</argLine>-->
|
||||
<!--<argLine>add-opens ch.qos.logback.core/ch.qos.logback.core.testUtil=java.naming
|
||||
add-reads ch.qos.logback.core=ALL-UNNAMED</argLine>-->
|
||||
<argLine>
|
||||
--add-opens ch.qos.logback.core/ch.qos.logback.core.testUtil=java.naming
|
||||
--add-reads ch.qos.logback.core=ALL-UNNAMED
|
||||
</argLine>
|
||||
<parallel>classes</parallel>
|
||||
<threadCount>8</threadCount>
|
||||
<!--<useUnlimitedThreads>false</useUnlimitedThreads>-->
|
||||
<forkCount>1</forkCount>
|
||||
<reuseForks>true</reuseForks>
|
||||
<reportFormat>plain</reportFormat>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
<!-- See https://issues.apache.org/jira/browse/SUREFIRE-1265 -->
|
||||
<childDelegation>true</childDelegation>
|
||||
<excludes>
|
||||
<exclude>**/All*Test.java</exclude>
|
||||
<exclude>**/PackageTest.java</exclude>
|
||||
<!-- ConsoleAppenderTest redirects System.out which is not well tolerated by Maven -->
|
||||
<exclude>**/ConsoleAppenderTest.java</exclude>
|
||||
|
||||
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-test-jar</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>bundle-manifest</id>
|
||||
<phase>process-classes</phase>
|
||||
<goals>
|
||||
<goal>manifest</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Export-Package>ch.qos.logback.core*</Export-Package>
|
||||
<Import-Package>
|
||||
ch.qos.logback.core*;version="${range;[==,+);${version_cleanup;${project.version}}}",
|
||||
jakarta.*;resolution:=optional,
|
||||
org.xml.*;resolution:=optional,
|
||||
org.fusesource.jansi;resolution:=optional,
|
||||
org.codehaus.janino;resolution:=optional,
|
||||
org.codehaus.commons.compiler;resolution:=optional,
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
a7aa7a33d13883c3e557aa431f49607d8452b591
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:21 CST 2025
|
||||
logback-parent-1.4.11.pom>alimaven=
|
||||
+584
@@ -0,0 +1,584 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-parent</artifactId>
|
||||
<version>1.4.11</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Logback-Parent</name>
|
||||
<description>logback project pom.xml file</description>
|
||||
|
||||
<url>http://logback.qos.ch</url>
|
||||
|
||||
<organization>
|
||||
<name>QOS.ch</name>
|
||||
<url>http://www.qos.ch</url>
|
||||
</organization>
|
||||
<inceptionYear>2005</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Eclipse Public License - v 1.0</name>
|
||||
<url>http://www.eclipse.org/legal/epl-v10.html</url>
|
||||
</license>
|
||||
|
||||
<license>
|
||||
<name>GNU Lesser General Public License</name>
|
||||
<url>http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/qos-ch/logback</url>
|
||||
<connection>scm:git@github.com:qos-ch/logback.git</connection>
|
||||
</scm>
|
||||
|
||||
<modules>
|
||||
<module>logback-core</module>
|
||||
<module>logback-core-blackbox</module>
|
||||
<module>logback-classic</module>
|
||||
<module>logback-classic-blackbox</module>
|
||||
<module>logback-access</module>
|
||||
<module>logback-examples</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<!-- yyyy-MM-dd'T'HH:mm:ss'Z' -->
|
||||
<project.build.outputTimestamp>2023-08-09T19:23:17Z</project.build.outputTimestamp>
|
||||
<jdk.version>11</jdk.version>
|
||||
<maven.compiler.release>${jdk.version}</maven.compiler.release>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.version>4.13.1</junit.version>
|
||||
<junit-jupiter-api.version>5.9.1</junit-jupiter-api.version>
|
||||
<junit-vintage-engine.version>5.9.1</junit-vintage-engine.version>
|
||||
<junit-jupiter-params.version>5.9.1</junit-jupiter-params.version>
|
||||
<assertj-core.version>3.23.1</assertj-core.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
<jakarta.mail.version>2.1.0</jakarta.mail.version>
|
||||
<jakarta.activation.version>2.1.0</jakarta.activation.version>
|
||||
<jakarta.angus-mail.version>1.0.0</jakarta.angus-mail.version>
|
||||
|
||||
<jakarta.servlet.version>5.0.0</jakarta.servlet.version>
|
||||
<greenmail.version>2.0.0-alpha-1</greenmail.version>
|
||||
|
||||
<janino.version>3.1.8</janino.version>
|
||||
<!-- slf4j.version property is used below, in
|
||||
logback-classic/pom.xml, /logback-examples/src/main/resources/setClasspath.cmd, download.html
|
||||
-->
|
||||
<slf4j.version>2.0.7</slf4j.version>
|
||||
<cal10n.version>0.8.1</cal10n.version>
|
||||
<consolePlugin.version>1.1.0</consolePlugin.version>
|
||||
<tomcat.version>10.0.10</tomcat.version>
|
||||
<jetty.version>11.0.12</jetty.version>
|
||||
<jackson.version>2.15.0</jackson.version>
|
||||
|
||||
<!--<jansi.version>1.18</jansi.version>-->
|
||||
<jansi.version>2.4.0</jansi.version>
|
||||
|
||||
<mockito-core.version>4.8.0</mockito-core.version>
|
||||
<byte-buddy.version>1.12.14</byte-buddy.version>
|
||||
|
||||
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
|
||||
<maven-surefire-plugin.version>3.0.0-M7</maven-surefire-plugin.version>
|
||||
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
|
||||
<maven-install-plugin.version>3.0.0-M1</maven-install-plugin.version>
|
||||
<maven-javadoc-plugin.version>3.3.0</maven-javadoc-plugin.version>
|
||||
<maven-source-plugin.version>3.2.0</maven-source-plugin.version>
|
||||
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
|
||||
<license-maven-plugin.version>3.0</license-maven-plugin.version>
|
||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||
<maven-jxr-plugin.version>3.1.1</maven-jxr-plugin.version>
|
||||
<maven-release-plugin.version>3.0.0-M4</maven-release-plugin.version>
|
||||
<maven-deploy-plugin.version>3.0.0-M1</maven-deploy-plugin.version>
|
||||
<maven-dependency-plugin.version>3.2.0</maven-dependency-plugin.version>
|
||||
<maven-bundle-plugin.version>5.1.8</maven-bundle-plugin.version>
|
||||
<maven-antrun-plugin.version>3.1.0</maven-antrun-plugin.version>
|
||||
<ant.version>1.10.12</ant.version>
|
||||
<cobertura.maven.plugin.version>2.7</cobertura.maven.plugin.version>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>ceki</id>
|
||||
<name>Ceki Gulcu</name>
|
||||
<email>ceki@qos.ch</email>
|
||||
</developer>
|
||||
|
||||
<developer>
|
||||
<id>hixi</id>
|
||||
<name>Joern Huxhorn</name>
|
||||
<email>huxi@undisclosed.org</email>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit-jupiter-api.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit-jupiter-api.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-library</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- start of dependencies duplicated from logback-bom/pom.xml -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-access</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<!-- end of dependencies duplicated from logback-bom/pom.xml -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>janino</artifactId>
|
||||
<version>${janino.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.janino</groupId>
|
||||
<artifactId>commons-compiler</artifactId>
|
||||
<version>${janino.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.fusesource.jansi</groupId>
|
||||
<artifactId>jansi</artifactId>
|
||||
<version>${jansi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
<version>${jakarta.mail.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
<version>${jakarta.activation.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-mail</artifactId>
|
||||
<version>${jakarta.angus-mail.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>${jakarta.servlet.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.icegreen</groupId>
|
||||
<artifactId>greenmail</artifactId>
|
||||
<version>${greenmail.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-coyote</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito-core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
<version>${byte-buddy.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
<build>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-ssh</artifactId>
|
||||
<version>2.10</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>${maven-install-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${maven-resources-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>${maven-site-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
<configuration>
|
||||
<outputTimestamp>${project.build.outputTimestamp}</outputTimestamp>
|
||||
<archive>
|
||||
<index>true</index>
|
||||
<manifest>
|
||||
<!-- Add version information into the MANIFEST so it is accessible by
|
||||
calling Package#getImplementationVersion()
|
||||
-->
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>${maven-dependency-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>${maven-release-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>3.0.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>${maven-bundle-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<release>${jdk.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.simplify4u.plugins</groupId>
|
||||
<artifactId>pgpverify-maven-plugin</artifactId>
|
||||
<version>1.16.0</version>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
|
||||
</distributionManagement>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
<javadocDir>target/site/apidocs/</javadocDir>
|
||||
<linkJavadoc>true</linkJavadoc>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>${maven-jxr-plugin.version}</version>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
<javadocDir>target/site/apidocs/</javadocDir>
|
||||
<linkJavadoc>true</linkJavadoc>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
<linkJavadoc>true</linkJavadoc>
|
||||
<linksource>true</linksource>
|
||||
<doclint>none</doclint>
|
||||
<sourceFileExcludes>
|
||||
<sourceFileExclude>**/module-info.java</sourceFileExclude>
|
||||
</sourceFileExcludes>
|
||||
<links>
|
||||
<link>
|
||||
http://docs.oracle.com/javase/7/docs/api/
|
||||
</link>
|
||||
</links>
|
||||
|
||||
<groups>
|
||||
<group>
|
||||
<title>Logback Core</title>
|
||||
<packages>ch.qos.logback.core:ch.qos.logback.core.*
|
||||
</packages>
|
||||
</group>
|
||||
<group>
|
||||
<title>Logback Classic</title>
|
||||
<packages>
|
||||
ch.qos.logback:ch.qos.logback.classic:ch.qos.logback.classic.*
|
||||
</packages>
|
||||
</group>
|
||||
<group>
|
||||
<title>Logback Access</title>
|
||||
<packages>ch.qos.logback.access:ch.qos.logback.access.*
|
||||
</packages>
|
||||
</group>
|
||||
<group>
|
||||
<title>Examples</title>
|
||||
<packages>chapter*:joran*</packages>
|
||||
</group>
|
||||
</groups>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>testSkip</id>
|
||||
<properties>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>license</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>${license-maven-plugin.version}</version>
|
||||
<configuration>
|
||||
<header>src/main/licenseHeader.txt</header>
|
||||
<quiet>false</quiet>
|
||||
<failIfMissing>true</failIfMissing>
|
||||
<aggregate>true</aggregate>
|
||||
<includes>
|
||||
<include>src/**/*.java</include>
|
||||
<include>src/**/*.groovy</include>
|
||||
</includes>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<useDefaultMapping>true</useDefaultMapping>
|
||||
<properties>
|
||||
<year>1999</year>
|
||||
</properties>
|
||||
<headerDefinitions>
|
||||
<headerDefinition>src/main/javadocHeaders.xml</headerDefinition>
|
||||
</headerDefinitions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>javadocjar</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<doclint>none</doclint>
|
||||
<sourceFileExcludes>
|
||||
<sourceFileExclude>**/module-info.java</sourceFileExclude>
|
||||
</sourceFileExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>sign-artifacts</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
0217a638da743248ecd5c6093ed9e169510bd781
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:09 CST 2025
|
||||
classworlds-1.1-alpha-2.pom>alimaven=
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>classworlds</groupId>
|
||||
<artifactId>classworlds</artifactId>
|
||||
<name>classworlds</name>
|
||||
<version>1.1-alpha-2</version>
|
||||
<description></description>
|
||||
<url>http://classworlds.codehaus.org/</url>
|
||||
<ciManagement>
|
||||
<notifiers>
|
||||
<notifier>
|
||||
<address>classworlds-scm@lists.codehaus.org</address>
|
||||
</notifier>
|
||||
</notifiers>
|
||||
</ciManagement>
|
||||
<inceptionYear>2002</inceptionYear>
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>classworlds users</name>
|
||||
<subscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-user</subscribe>
|
||||
<unsubscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-user</unsubscribe>
|
||||
<archive>http://lists.codehaus.org/pipermail/classworlds-user/</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>classworlds developers</name>
|
||||
<subscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-dev</subscribe>
|
||||
<unsubscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-dev</unsubscribe>
|
||||
<archive>http://lists.codehaus.org/pipermail/classworlds-dev/</archive>
|
||||
</mailingList>
|
||||
<mailingList>
|
||||
<name>classworlds commit messages</name>
|
||||
<subscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-scm</subscribe>
|
||||
<unsubscribe>http://lists.codehaus.org/mailman/listinfo/classworlds-scm</unsubscribe>
|
||||
<archive>http://lists.codehaus.org/pipermail/classworlds-scm/</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>bob</id>
|
||||
<name>bob mcwhirter</name>
|
||||
<email>bob@werken.com</email>
|
||||
<organization>The Werken Company</organization>
|
||||
<roles>
|
||||
<role>Founder</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>jvanzyl</id>
|
||||
<name>Jason van Zyl</name>
|
||||
<email>jason@zenplex.com</email>
|
||||
<organization>Zenplex</organization>
|
||||
<roles>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>bwalding</id>
|
||||
<name>Ben Walding</name>
|
||||
<email>ben@walding.com</email>
|
||||
<organization>Walding Consulting Services</organization>
|
||||
<roles>
|
||||
<role>Developer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection>scm:cvs:pserver:anonymous@cvs.codehaus.org:/scm/cvspublic/:classworlds</connection>
|
||||
<url>http://cvs.classworlds.codehaus.org/</url>
|
||||
</scm>
|
||||
<organization>
|
||||
<name>The Codehaus</name>
|
||||
<url>http://codehaus.org/</url>
|
||||
</organization>
|
||||
<build>
|
||||
<sourceDirectory>src/java/main</sourceDirectory>
|
||||
<testSourceDirectory>src/java/test</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>default</id>
|
||||
<name>Default Site</name>
|
||||
<url>scp://classworlds.codehaus.org//www/classworlds.codehaus.org</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
</project>
|
||||
+1
@@ -0,0 +1 @@
|
||||
8c8ad6a96a8c1168f8b12ec8a227b8261b160b26
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
|
||||
#Tue Nov 11 18:42:20 CST 2025
|
||||
classmate-1.5.1.jar>alimaven=
|
||||
classmate-1.5.1.pom>alimaven=
|
||||
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user