Improve development environment with Docker Compose profiles (#435)

* Add improved development environment with backend in Docker and frontend locally

- Created dev.bat script to run backend services in Docker and frontend locally
- Added docker-compose.backend.yml for backend-only Docker setup
- Updated package.json to run frontend on port 3737
- Fixed api.ts to use default port 8181 instead of throwing error
- Script automatically stops production containers to avoid port conflicts
- Provides instant HMR for frontend development

* Refactor development environment setup: replace dev.bat with Makefile for cross-platform support and enhanced commands

* Enhance development environment: add environment variable checks and update test commands for frontend and backend

* Improve development environment with Docker Compose profiles

This commit enhances the development workflow by replacing the separate
docker-compose.backend.yml file with Docker Compose profiles, fixing
critical service discovery issues, and adding comprehensive developer
tooling through an improved Makefile system.

Key improvements:
- Replace docker-compose.backend.yml with cleaner profile approach
- Fix service discovery by maintaining consistent container names
- Fix port mappings (3737:3737 instead of 3737:5173)
- Add make doctor for environment validation
- Fix port configuration and frontend HMR
- Improve error handling with .SHELLFLAGS in Makefile
- Add comprehensive port configuration via environment variables
- Simplify make dev-local to only run essential services
- Add logging directory creation for local development
- Document profile strategy in docker-compose.yml

These changes provide three flexible development modes:
- Hybrid mode (default): Backend in Docker, frontend local with HMR
- Docker mode: Everything in Docker for production-like testing
- Local mode: API server and UI run locally

Co-authored-by: Zak Stam <zaksnet@users.noreply.github.com>

* Fix make stop command to properly handle Docker Compose profiles

The stop command now explicitly specifies all profiles to ensure
all containers are stopped regardless of how they were started.

* Fix README to document correct make commands

- Changed 'make lint' to 'make lint-frontend' and 'make lint-backend'
- Removed non-existent 'make logs-server' command
- Added 'make watch-mcp' and 'make watch-agents' commands
- All documented make commands now match what's available in Makefile

* fix: Address critical issues from code review #435

- Create robust environment validation script (check-env.js) that properly parses .env files
- Fix Docker healthcheck port mismatch (5173 -> 3737)
- Remove hard-coded port flags from package.json to allow environment configuration
- Fix Docker detection logic using /.dockerenv instead of HOSTNAME
- Normalize container names to lowercase (archon-server, archon-mcp, etc.)
- Improve stop-local command with port-based fallback for process killing
- Fix API configuration fallback chain to include VITE_PORT
- Fix Makefile shell variable expansion using runtime evaluation
- Update .PHONY targets with comprehensive list
- Add --profile flags to Docker Compose commands in README
- Add VITE_ARCHON_SERVER_PORT to docker-compose.yml
- Add Node.js 18+ to prerequisites
- Use dynamic ports in Makefile help messages
- Add lint alias combining frontend and backend linting
- Update .env.example documentation
- Scope .gitignore logs entry to /logs/

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix container name resolution for MCP server

- Add dynamic container name resolution with three-tier strategy
- Support environment variables for custom container names
- Add service discovery labels to docker-compose services
- Update BackendStartupError with correct container name references

* Fix frontend test failures in API configuration tests

- Update environment variable names to use VITE_ prefix that matches production code
- Fix MCP client service tests to use singleton instance export
- Update default behavior tests to expect fallback to port 8181
- All 77 frontend tests now pass

* Fix make stop-local to avoid Docker daemon interference

Replace aggressive kill -9 with targeted process termination:
- Filter processes by command name (node/vite/python/uvicorn) before killing
- Use graceful SIGTERM instead of SIGKILL
- Add process verification to avoid killing Docker-related processes
- Improve logging with descriptive step messages

* refactor: Simplify development workflow based on comprehensive review

- Reduced Makefile from 344 lines (43 targets) to 83 lines (8 essential targets)
- Removed unnecessary environment variables (*_CONTAINER_NAME variables)
- Fixed Windows compatibility by removing Unix-specific commands
- Added security fixes to check-env.js (path validation)
- Simplified MCP container discovery to use fixed container names
- Fixed 'make stop' to properly handle Docker Compose profiles
- Updated documentation to reflect simplified workflow
- Restored original .env.example with comprehensive Supabase key documentation

This addresses all critical issues from code review:
- Cross-platform compatibility 
- Security vulnerabilities fixed 
- 81% reduction in complexity 
- Maintains all essential functionality 

All tests pass: Frontend (77/77), Backend (267/267)

* feat: Add granular test and lint commands to Makefile

- Split test command into test-fe and test-be for targeted testing
- Split lint command into lint-fe and lint-be for targeted linting
- Keep original test and lint commands that run both
- Update help text with new commands for better developer experience

* feat: Improve Docker Compose detection and prefer modern syntax

- Prefer 'docker compose' (plugin) over 'docker-compose' (standalone)
- Add better error handling in Makefile with proper exit on failures
- Add Node.js check before running environment scripts
- Pass environment variables correctly to frontend in hybrid mode
- Update all documentation to use modern 'docker compose' syntax
- Auto-detect which Docker Compose version is available

* docs: Update CONTRIBUTING.md to reflect simplified development workflow

- Add Node.js 18+ as prerequisite for hybrid development
- Mark Make as optional throughout the documentation
- Update all docker-compose commands to modern 'docker compose' syntax
- Add Make command alternatives for testing (make test, test-fe, test-be)
- Document make dev for hybrid development mode
- Remove linting requirements until codebase errors are resolved

* fix: Rename frontend service to archon-frontend for consistency

Aligns frontend service naming with other services (archon-server, archon-mcp, archon-agents) for better consistency in Docker image naming patterns.

---------

Co-authored-by: Zak Stam <zakscomputers@hotmail.com>
Co-authored-by: Zak Stam <zaksnet@users.noreply.github.com>
This commit is contained in:
Wirasm 2025-08-22 17:18:10 +03:00 committed by GitHub
parent cb4dba14a0
commit 86dd1b0749
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 481 additions and 75 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ __pycache__
.serena
.claude/settings.local.json
PRPs/local
/logs/

View File

@ -53,8 +53,10 @@ Archon uses true microservices architecture with clear separation of concerns:
### Prerequisites
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Node.js 18+](https://nodejs.org/) (for hybrid development mode)
- [Supabase](https://supabase.com/) account (free tier works)
- [OpenAI API key](https://platform.openai.com/api-keys) or alternative LLM provider
- (Optional) [Make](https://www.gnu.org/software/make/) for simplified workflows
- Basic knowledge of Python (FastAPI) and TypeScript (React)
### Initial Setup
@ -74,7 +76,11 @@ After forking the repository, you'll need to:
3. **Start Development Environment**
```bash
docker-compose up --build -d
# Using Docker Compose directly
docker compose --profile full up --build -d
# Or using Make (if installed)
make dev-docker
```
4. **Configure API Keys**
@ -211,14 +217,17 @@ Test these things using both the UI and the MCP server. This process will be sim
**Test commands:**
```bash
# Backend tests
cd python && python -m pytest
# Frontend tests
cd archon-ui-main && npm run test
# Using Make (if installed)
make test # Run all tests
make test-fe # Frontend tests only
make test-be # Backend tests only
# Or manually
cd python && python -m pytest # Backend tests
cd archon-ui-main && npm run test # Frontend tests
# Full integration test
docker-compose up --build -d
docker compose --profile full up --build -d
# Test via UI at http://localhost:3737
```
@ -324,7 +333,10 @@ Test these things using both the UI and the MCP server. This process will be sim
2. **Testing Your Changes**
```bash
# Run Python tests
# Using Make (if installed)
make test-be
# Or manually
cd python && python -m pytest tests/
# Run specific test categories
@ -334,8 +346,8 @@ Test these things using both the UI and the MCP server. This process will be sim
3. **Code Quality**
```bash
# We encourage you to use linters for all code
# Follow service patterns from existing code
# Maintain consistency with the codebase
```
### Frontend Development (React)
@ -353,7 +365,10 @@ Test these things using both the UI and the MCP server. This process will be sim
2. **Testing Your Changes**
```bash
# Run frontend tests
# Using Make (if installed)
make test-fe
# Or manually
cd archon-ui-main && npm run test
# Run with coverage
@ -365,7 +380,10 @@ Test these things using both the UI and the MCP server. This process will be sim
3. **Development Server**
```bash
# For faster iteration, run frontend locally
# Using Make for hybrid mode (if installed)
make dev # Backend in Docker, frontend local
# Or manually for faster iteration
cd archon-ui-main && npm run dev
# Still connects to Docker backend services
```

109
Makefile Normal file
View File

@ -0,0 +1,109 @@
# Archon Makefile - Simple, Secure, Cross-Platform
SHELL := /bin/bash
.SHELLFLAGS := -ec
# Docker compose command - prefer newer 'docker compose' plugin over standalone 'docker-compose'
COMPOSE ?= $(shell docker compose version >/dev/null 2>&1 && echo "docker compose" || echo "docker-compose")
.PHONY: help dev dev-docker stop test test-fe test-be lint lint-fe lint-be clean install check
help:
@echo "Archon Development Commands"
@echo "==========================="
@echo " make dev - Backend in Docker, frontend local (recommended)"
@echo " make dev-docker - Everything in Docker"
@echo " make stop - Stop all services"
@echo " make test - Run all tests"
@echo " make test-fe - Run frontend tests only"
@echo " make test-be - Run backend tests only"
@echo " make lint - Run all linters"
@echo " make lint-fe - Run frontend linter only"
@echo " make lint-be - Run backend linter only"
@echo " make clean - Remove containers and volumes"
@echo " make install - Install dependencies"
@echo " make check - Check environment setup"
# Install dependencies
install:
@echo "Installing dependencies..."
@cd archon-ui-main && npm install
@cd python && uv sync
@echo "✓ Dependencies installed"
# Check environment
check:
@echo "Checking environment..."
@node -v >/dev/null 2>&1 || { echo "✗ Node.js not found (require Node 18+)."; exit 1; }
@node check-env.js
@echo "Checking Docker..."
@docker --version > /dev/null 2>&1 || { echo "✗ Docker not found"; exit 1; }
@$(COMPOSE) version > /dev/null 2>&1 || { echo "✗ Docker Compose not found"; exit 1; }
@echo "✓ Environment OK"
# Hybrid development (recommended)
dev: check
@echo "Starting hybrid development..."
@echo "Backend: Docker | Frontend: Local with hot reload"
@$(COMPOSE) --profile backend up -d --build
@set -a; [ -f .env ] && . ./.env; set +a; \
echo "Backend running at http://$${HOST:-localhost}:$${ARCHON_SERVER_PORT:-8181}"
@echo "Starting frontend..."
@cd archon-ui-main && \
VITE_ARCHON_SERVER_PORT=$${ARCHON_SERVER_PORT:-8181} \
VITE_ARCHON_SERVER_HOST=$${HOST:-} \
npm run dev
# Full Docker development
dev-docker: check
@echo "Starting full Docker environment..."
@$(COMPOSE) --profile full up -d --build
@echo "✓ All services running"
@echo "Frontend: http://localhost:3737"
@echo "API: http://localhost:8181"
# Stop all services
stop:
@echo "Stopping all services..."
@$(COMPOSE) --profile backend --profile frontend --profile full down
@echo "✓ Services stopped"
# Run all tests
test: test-fe test-be
# Run frontend tests
test-fe:
@echo "Running frontend tests..."
@cd archon-ui-main && npm test
# Run backend tests
test-be:
@echo "Running backend tests..."
@cd python && uv run pytest
# Run all linters
lint: lint-fe lint-be
# Run frontend linter
lint-fe:
@echo "Linting frontend..."
@cd archon-ui-main && npm run lint
# Run backend linter
lint-be:
@echo "Linting backend..."
@cd python && uv run ruff check --fix
# Clean everything (with confirmation)
clean:
@echo "⚠️ This will remove all containers and volumes"
@read -p "Are you sure? (y/N) " -n 1 -r; \
echo; \
if [[ $$REPLY =~ ^[Yy]$$ ]]; then \
$(COMPOSE) down -v --remove-orphans; \
echo "✓ Cleaned"; \
else \
echo "Cancelled"; \
fi
.DEFAULT_GOAL := help

201
README.md
View File

@ -43,8 +43,10 @@ This new vision for Archon replaces the old one (the agenteer). Archon used to b
### Prerequisites
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Node.js 18+](https://nodejs.org/) (for hybrid development mode)
- [Supabase](https://supabase.com/) account (free tier or local Supabase both work)
- [OpenAI API key](https://platform.openai.com/api-keys) (Gemini and Ollama are supported too!)
- (OPTIONAL) [Make](https://www.gnu.org/software/make/) (see [Installing Make](#installing-make) below)
### Setup Instructions
@ -70,13 +72,17 @@ This new vision for Archon replaces the old one (the agenteer). Archon used to b
3. **Database Setup**: In your [Supabase project](https://supabase.com/dashboard) SQL Editor, copy, paste, and execute the contents of `migration/complete_setup.sql`
4. **Start Services**:
4. **Start Services** (choose one):
**Full Docker Mode (Recommended for Normal Archon Usage)**
```bash
docker-compose up --build -d
docker compose --profile full up --build -d
# or
make dev-docker # (Alternative: Requires make installed )
```
This starts the core microservices:
This starts all core microservices in Docker:
- **Server**: Core API and business logic (Port: 8181)
- **MCP Server**: Protocol interface for AI clients (Port: 8051)
- **Agents (coming soon!)**: AI operations and streaming (Port: 8052)
@ -89,6 +95,19 @@ This new vision for Archon replaces the old one (the agenteer). Archon used to b
- Go to **Settings** → Select your LLM/embedding provider and set the API key (OpenAI is default)
- Test by uploading a document or crawling a website
### 🚀 Quick Command Reference
| Command | Description |
| ----------------- | ------------------------------------------------------- |
| `make dev` | Start hybrid dev (backend in Docker, frontend local) ⭐ |
| `make dev-docker` | Everything in Docker |
| `make stop` | Stop all services |
| `make test` | Run all tests |
| `make lint` | Run linters |
| `make install` | Install dependencies |
| `make check` | Check environment setup |
| `make clean` | Remove containers and volumes (with confirmation) |
## 🔄 Database Reset (Start Fresh if Needed)
If you need to completely reset your database and start fresh:
@ -105,7 +124,7 @@ If you need to completely reset your database and start fresh:
3. **Restart Services**:
```bash
docker-compose up -d
docker compose --profile full up -d
```
4. **Reconfigure**:
@ -116,6 +135,41 @@ The reset script safely removes all tables, functions, triggers, and policies wi
</details>
## 🛠️ Installing Make (OPTIONAL)
Make is required for the local development workflow. Installation varies by platform:
### Windows
```bash
# Option 1: Using Chocolatey
choco install make
# Option 2: Using Scoop
scoop install make
# Option 3: Using WSL2
wsl --install
# Then in WSL: sudo apt-get install make
```
### macOS
```bash
# Make comes pre-installed on macOS
# If needed: brew install make
```
### Linux
```bash
# Debian/Ubuntu
sudo apt-get install make
# RHEL/CentOS/Fedora
sudo yum install make
```
## ⚡ Quick Test
Once everything is running:
@ -221,11 +275,11 @@ Archon uses true microservices architecture with clear separation of concerns:
By default, Archon services run on the following ports:
- **Archon-UI**: 3737
- **Archon-Server**: 8181
- **Archon-MCP**: 8051
- **Archon-Agents**: 8052
- **Archon-Docs**: 3838 (optional)
- **archon-ui**: 3737
- **archon-server**: 8181
- **archon-mcp**: 8051
- **archon-agents**: 8052
- **archon-docs**: 3838 (optional)
### Changing Ports
@ -269,27 +323,140 @@ This is useful when:
After changing hostname or ports:
1. Restart Docker containers: `docker-compose down && docker-compose up -d`
1. Restart Docker containers: `docker compose down && docker compose --profile full up -d`
2. Access the UI at: `http://${HOST}:${ARCHON_UI_PORT}`
3. Update your AI client configuration with the new hostname and MCP port
## 🔧 Development
For development with hot reload:
### Quick Start
```bash
# Backend services (with auto-reload)
docker-compose up archon-server archon-mcp archon-agents --build
# Install dependencies
make install
# Frontend (with hot reload)
cd archon-ui-main && npm run dev
# Start development (recommended)
make dev # Backend in Docker, frontend local with hot reload
# Documentation (with hot reload)
cd docs && npm start
# Alternative: Everything in Docker
make dev-docker # All services in Docker
# Stop everything (local FE needs to be stopped manually)
make stop
```
### Development Modes
#### Hybrid Mode (Recommended) - `make dev`
Best for active development with instant frontend updates:
- Backend services run in Docker (isolated, consistent)
- Frontend runs locally with hot module replacement
- Instant UI updates without Docker rebuilds
#### Full Docker Mode - `make dev-docker`
For all services in Docker environment:
- All services run in Docker containers
- Better for integration testing
- Slower frontend updates
### Testing & Code Quality
```bash
# Run tests
make test # Run all tests
make test-fe # Run frontend tests
make test-be # Run backend tests
# Run linters
make lint # Lint all code
make lint-fe # Lint frontend code
make lint-be # Lint backend code
# Check environment
make check # Verify environment setup
# Clean up
make clean # Remove containers and volumes (asks for confirmation)
```
### Viewing Logs
```bash
# View logs using Docker Compose directly
docker compose logs -f # All services
docker compose logs -f archon-server # API server
docker compose logs -f archon-mcp # MCP server
docker compose logs -f archon-ui # Frontend
```
**Note**: The backend services are configured with `--reload` flag in their uvicorn commands and have source code mounted as volumes for automatic hot reloading when you make changes.
## 🔍 Troubleshooting
### Common Issues and Solutions
#### Port Conflicts
If you see "Port already in use" errors:
```bash
# Check what's using a port (e.g., 3737)
lsof -i :3737
# Stop all containers and local services
make stop
# Change the port in .env
```
#### Docker Permission Issues (Linux)
If you encounter permission errors with Docker:
```bash
# Add your user to the docker group
sudo usermod -aG docker $USER
# Log out and back in, or run
newgrp docker
```
#### Windows-Specific Issues
- **Make not found**: Install Make via Chocolatey, Scoop, or WSL2 (see [Installing Make](#installing-make))
- **Line ending issues**: Configure Git to use LF endings:
```bash
git config --global core.autocrlf false
```
#### Frontend Can't Connect to Backend
- Check backend is running: `curl http://localhost:8181/health`
- Verify port configuration in `.env`
- For custom ports, ensure both `ARCHON_SERVER_PORT` and `VITE_ARCHON_SERVER_PORT` are set
#### Docker Compose Hangs
If `docker compose` commands hang:
```bash
# Reset Docker Compose
docker compose down --remove-orphans
docker system prune -f
# Restart Docker Desktop (if applicable)
```
#### Hot Reload Not Working
- **Frontend**: Ensure you're running in hybrid mode (`make dev`) for best HMR experience
- **Backend**: Check that volumes are mounted correctly in `docker-compose.yml`
- **File permissions**: On some systems, mounted volumes may have permission issues
## 📈 Progress
<p align="center">

View File

@ -18,8 +18,8 @@ RUN mkdir -p /app/coverage && chmod 777 /app/coverage
# Copy source code
COPY . .
# Expose Vite's default port
EXPOSE 5173
# Expose the port configured in package.json (3737)
EXPOSE 3737
# Start Vite dev server with host binding for Docker
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
# Start Vite dev server (already configured with --port 3737 --host in package.json)
CMD ["npm", "run", "dev"]

View File

@ -28,12 +28,12 @@ export const BackendStartupError: React.FC = () => {
<span className="font-semibold">Check Docker Logs</span>
</div>
<p className="text-red-100 font-mono text-sm mb-3">
Check the <span className="text-red-400 font-bold">Archon-Server</span> logs in Docker Desktop for detailed error information.
Check the <span className="text-red-400 font-bold">Archon API server</span> container logs in Docker Desktop for detailed error information.
</p>
<div className="space-y-2 text-xs text-red-300">
<p>1. Open Docker Desktop</p>
<p>2. Go to Containers tab</p>
<p>3. Click on <span className="text-red-400 font-semibold">Archon-Server</span></p>
<p>3. Look for the Archon server container (typically named <span className="text-red-400 font-semibold">archon-server</span> or similar)</p>
<p>4. View the logs for the specific error message</p>
</div>
</div>

View File

@ -20,14 +20,11 @@ export function getApiUrl(): string {
// For development, construct from window location
const protocol = window.location.protocol;
const host = window.location.hostname;
const port = import.meta.env.ARCHON_SERVER_PORT;
// Use configured port or default to 8181
const port = import.meta.env.VITE_ARCHON_SERVER_PORT || '8181';
if (!port) {
throw new Error(
'ARCHON_SERVER_PORT environment variable is required. ' +
'Please set it in your environment variables. ' +
'Default value: 8181'
);
if (!import.meta.env.VITE_ARCHON_SERVER_PORT) {
console.info('[Archon] Using default ARCHON_SERVER_PORT: 8181');
}
return `${protocol}//${host}:${port}`;

View File

@ -41,23 +41,33 @@ describe('API Configuration', () => {
expect(getApiUrl()).toBe('');
});
it('should throw error when ARCHON_SERVER_PORT is not set in development', async () => {
// Development mode without port
it('should use default port 8181 when no port environment variables are set in development', async () => {
// Development mode without any port variables
delete (import.meta.env as any).PROD;
delete (import.meta.env as any).VITE_API_URL;
delete (import.meta.env as any).VITE_ARCHON_SERVER_PORT;
delete (import.meta.env as any).VITE_PORT;
delete (import.meta.env as any).ARCHON_SERVER_PORT;
// Mock window.location
Object.defineProperty(window, 'location', {
value: {
protocol: 'http:',
hostname: 'localhost'
},
writable: true
});
const { getApiUrl } = await import('../../src/config/api');
expect(() => getApiUrl()).toThrow('ARCHON_SERVER_PORT environment variable is required');
expect(() => getApiUrl()).toThrow('Default value: 8181');
expect(getApiUrl()).toBe('http://localhost:8181');
});
it('should use ARCHON_SERVER_PORT when set in development', async () => {
// Development mode with custom port
it('should use VITE_ARCHON_SERVER_PORT when set in development', async () => {
// Development mode with custom port via VITE_ prefix
delete (import.meta.env as any).PROD;
delete (import.meta.env as any).VITE_API_URL;
(import.meta.env as any).ARCHON_SERVER_PORT = '9191';
(import.meta.env as any).VITE_ARCHON_SERVER_PORT = '9191';
// Mock window.location
Object.defineProperty(window, 'location', {
@ -73,10 +83,10 @@ describe('API Configuration', () => {
});
it('should use custom port with https protocol', async () => {
// Development mode with custom port and https
// Development mode with custom port and https via VITE_ prefix
delete (import.meta.env as any).PROD;
delete (import.meta.env as any).VITE_API_URL;
(import.meta.env as any).ARCHON_SERVER_PORT = '8443';
(import.meta.env as any).VITE_ARCHON_SERVER_PORT = '8443';
// Mock window.location with https
Object.defineProperty(window, 'location', {
@ -139,7 +149,7 @@ describe('API Configuration', () => {
vi.resetModules();
delete (import.meta.env as any).PROD;
delete (import.meta.env as any).VITE_API_URL;
(import.meta.env as any).ARCHON_SERVER_PORT = port;
(import.meta.env as any).VITE_ARCHON_SERVER_PORT = port;
Object.defineProperty(window, 'location', {
value: {
@ -174,11 +184,10 @@ describe('MCP Client Service Configuration', () => {
it('should throw error when ARCHON_MCP_PORT is not set', async () => {
delete (import.meta.env as any).ARCHON_MCP_PORT;
const { MCPClientService } = await import('../../src/services/mcpClientService');
const service = new MCPClientService();
const { mcpClientService } = await import('../../src/services/mcpClientService');
await expect(service.createArchonClient()).rejects.toThrow('ARCHON_MCP_PORT environment variable is required');
await expect(service.createArchonClient()).rejects.toThrow('Default value: 8051');
await expect(mcpClientService.createArchonClient()).rejects.toThrow('ARCHON_MCP_PORT environment variable is required');
await expect(mcpClientService.createArchonClient()).rejects.toThrow('Default value: 8051');
});
it('should use ARCHON_MCP_PORT when set', async () => {
@ -205,11 +214,10 @@ describe('MCP Client Service Configuration', () => {
})
});
const { MCPClientService } = await import('../../src/services/mcpClientService');
const service = new MCPClientService();
const { mcpClientService } = await import('../../src/services/mcpClientService');
try {
await service.createArchonClient();
await mcpClientService.createArchonClient();
// Verify the fetch was called with the correct URL
expect(global.fetch).toHaveBeenCalledWith(

View File

@ -15,7 +15,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
// Get host and port from environment variables or use defaults
// For internal Docker communication, use the service name
// For external access, use the HOST from environment
const isDocker = process.env.DOCKER_ENV === 'true' || !!process.env.HOSTNAME;
const isDocker = process.env.DOCKER_ENV === 'true' || existsSync('/.dockerenv');
const internalHost = 'archon-server'; // Docker service name for internal communication
const externalHost = process.env.HOST || 'localhost'; // Host for external access
const host = isDocker ? internalHost : externalHost;
@ -278,7 +278,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
],
server: {
host: '0.0.0.0', // Listen on all network interfaces with explicit IP
port: 5173, // Match the port expected in Docker
port: parseInt(process.env.ARCHON_UI_PORT || env.ARCHON_UI_PORT || '3737'), // Use configurable port
strictPort: true, // Exit if port is in use
proxy: {
'/api': {

73
check-env.js Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Secure path resolution
const projectRoot = process.cwd();
const envPath = path.resolve(projectRoot, '.env');
// Security: Validate path is within project
if (!envPath.startsWith(projectRoot)) {
console.error('Security error: Invalid .env path');
process.exit(1);
}
// Check if .env exists
if (!fs.existsSync(envPath)) {
console.error('ERROR: .env file not found!');
console.error('Copy .env.example to .env and add your credentials:');
console.error(' cp .env.example .env');
process.exit(1);
}
// Parse .env file
const envContent = fs.readFileSync(envPath, 'utf8');
const envVars = {};
envContent.split('\n').forEach(line => {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) return;
const [key, ...valueParts] = trimmed.split('=');
if (key) {
const value = valueParts.join('=').trim().replace(/^["']|["']$/g, '');
envVars[key.trim()] = value;
}
});
// Only check ESSENTIAL variables
const required = ['SUPABASE_URL', 'SUPABASE_SERVICE_KEY'];
const errors = [];
required.forEach(varName => {
if (!envVars[varName] || envVars[varName] === '') {
errors.push(`Missing: ${varName}`);
}
});
if (errors.length > 0) {
console.error('ERROR: Required environment variables missing:');
errors.forEach(err => console.error(` - ${err}`));
console.error('\nPlease add these to your .env file');
process.exit(1);
}
// Validate URL format
try {
new URL(envVars['SUPABASE_URL']);
} catch (e) {
console.error('ERROR: SUPABASE_URL is not a valid URL');
console.error(` Found: ${envVars['SUPABASE_URL']}`);
console.error(' Expected format: https://your-project.supabase.co');
process.exit(1);
}
// Basic validation for service key
if (envVars['SUPABASE_SERVICE_KEY'].length < 10) {
console.error('ERROR: SUPABASE_SERVICE_KEY appears to be invalid (too short)');
console.error(' Please check your Supabase project settings');
process.exit(1);
}
console.log('✓ Environment configured correctly');

View File

@ -1,13 +1,22 @@
# Docker Compose Profiles Strategy:
# - "backend": Starts only backend services (server, mcp, agents) for hybrid development
# - "frontend": Starts only the frontend UI service
# - "full": Starts all services for complete Docker deployment
# Use --profile flag to control which services start:
# docker compose --profile backend up # Backend only for hybrid dev (or docker-compose)
# docker compose --profile full up # Everything in Docker (or docker-compose)
services:
# Server Service (FastAPI + Socket.IO + Crawling)
archon-server:
profiles: ["backend", "full"]
build:
context: ./python
dockerfile: Dockerfile.server
args:
BUILDKIT_INLINE_CACHE: 1
ARCHON_SERVER_PORT: ${ARCHON_SERVER_PORT:-8181}
container_name: Archon-Server
container_name: archon-server
ports:
- "${ARCHON_SERVER_PORT:-8181}:${ARCHON_SERVER_PORT:-8181}"
environment:
@ -55,13 +64,14 @@ services:
# Lightweight MCP Server Service (HTTP-based)
archon-mcp:
profiles: ["backend", "full"]
build:
context: ./python
dockerfile: Dockerfile.mcp
args:
BUILDKIT_INLINE_CACHE: 1
ARCHON_MCP_PORT: ${ARCHON_MCP_PORT:-8051}
container_name: Archon-MCP
container_name: archon-mcp
ports:
- "${ARCHON_MCP_PORT:-8051}:${ARCHON_MCP_PORT:-8051}"
environment:
@ -99,13 +109,14 @@ services:
# AI Agents Service (ML/Reranking)
archon-agents:
profiles: ["backend", "full"]
build:
context: ./python
dockerfile: Dockerfile.agents
args:
BUILDKIT_INLINE_CACHE: 1
ARCHON_AGENTS_PORT: ${ARCHON_AGENTS_PORT:-8052}
container_name: Archon-Agents
container_name: archon-agents
ports:
- "${ARCHON_AGENTS_PORT:-8052}:${ARCHON_AGENTS_PORT:-8052}"
environment:
@ -132,19 +143,21 @@ services:
start_period: 40s
# Frontend
frontend:
archon-frontend:
profiles: ["frontend", "full"]
build: ./archon-ui-main
container_name: Archon-UI
container_name: archon-ui
ports:
- "${ARCHON_UI_PORT:-3737}:5173"
- "${ARCHON_UI_PORT:-3737}:3737"
environment:
- VITE_API_URL=http://${HOST:-localhost}:${ARCHON_SERVER_PORT:-8181}
- VITE_ARCHON_SERVER_PORT=${ARCHON_SERVER_PORT:-8181}
- ARCHON_SERVER_PORT=${ARCHON_SERVER_PORT:-8181}
- HOST=${HOST:-localhost}
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5173"]
test: ["CMD", "curl", "-f", "http://localhost:3737"]
interval: 30s
timeout: 10s
retries: 3

View File

@ -49,7 +49,7 @@ class MCPServerManager:
"""Manages the MCP Docker container lifecycle."""
def __init__(self):
self.container_name = "Archon-MCP" # Container name from docker-compose.yml
self.container_name = None # Will be resolved dynamically
self.docker_client = None
self.container = None
self.status: str = "stopped"
@ -62,16 +62,29 @@ class MCPServerManager:
self._min_operation_interval = 2.0 # Minimum 2 seconds between operations
self._initialize_docker_client()
def _resolve_container(self):
"""Simple container resolution - just use fixed name."""
if not self.docker_client:
return None
try:
# Simple: Just look for the fixed container name
container = self.docker_client.containers.get("archon-mcp")
self.container_name = "archon-mcp"
mcp_logger.info("Found MCP container")
return container
except NotFound:
mcp_logger.warning("MCP container not found - is it running?")
self.container_name = "archon-mcp"
return None
def _initialize_docker_client(self):
"""Initialize Docker client and get container reference."""
try:
self.docker_client = docker.from_env()
try:
self.container = self.docker_client.containers.get(self.container_name)
mcp_logger.info(f"Found Docker container: {self.container_name}")
except NotFound:
mcp_logger.warning(f"Docker container {self.container_name} not found")
self.container = None
self.container = self._resolve_container()
if not self.container:
mcp_logger.warning("MCP container not found during initialization")
except Exception as e:
mcp_logger.error(f"Failed to initialize Docker client: {str(e)}")
self.docker_client = None
@ -85,10 +98,17 @@ class MCPServerManager:
if self.container:
self.container.reload() # Refresh container info
else:
self.container = self.docker_client.containers.get(self.container_name)
# Try to resolve container again if we don't have it
self.container = self._resolve_container()
if not self.container:
return "not_found"
return self.container.status
except NotFound:
# Try to resolve again in case container was recreated
self.container = self._resolve_container()
if self.container:
return self.container.status
return "not_found"
except Exception as e:
mcp_logger.error(f"Error getting container status: {str(e)}")