Compare commits
No commits in common. "ff98adba88ef71ee7ccbeaf0378dd36f4f84a38a" and "d86f05195532f509af7b1ce10517917892fe4968" have entirely different histories.
ff98adba88
...
d86f051955
@ -1,545 +0,0 @@
|
|||||||
# VAPORA Justfile - Namespaced CI/CD Recipe Collection
|
|
||||||
# Workspace: Rust + Nushell + Provisioning/Nickel
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# just - List all recipes
|
|
||||||
# just ci::help - Show CI namespace recipes
|
|
||||||
# just ci::full - Run complete CI pipeline
|
|
||||||
#
|
|
||||||
# Namespace Structure:
|
|
||||||
# ci::* - CI/CD pipelines and checks
|
|
||||||
# build::* - Build recipes
|
|
||||||
# test::* - Test recipes
|
|
||||||
# fmt::* - Format and code quality
|
|
||||||
# check::* - Validation and analysis
|
|
||||||
# dev::* - Development utilities
|
|
||||||
# vapora::* - Vapora-specific operations
|
|
||||||
|
|
||||||
set shell := ["nu", "-c"]
|
|
||||||
set dotenv-load := true
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Default & Help
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
[no-cd]
|
|
||||||
default:
|
|
||||||
@just -l
|
|
||||||
|
|
||||||
[no-cd]
|
|
||||||
help:
|
|
||||||
@echo "📖 VAPORA Justfile Namespaces"
|
|
||||||
@echo ""
|
|
||||||
@echo "CI/CD Pipelines:"
|
|
||||||
@echo " just ci::help - Show CI recipes"
|
|
||||||
@echo " just ci::full - Complete CI: check + test + build"
|
|
||||||
@echo " just ci::lint - Lint all code"
|
|
||||||
@echo " just ci::check - Check + format + lint"
|
|
||||||
@echo " just ci::test-all - Test all features"
|
|
||||||
@echo " just ci::build-debug - Debug build"
|
|
||||||
@echo " just ci::build-release - Release build"
|
|
||||||
@echo ""
|
|
||||||
@echo "Build:"
|
|
||||||
@echo " just build::debug - Build workspace (debug)"
|
|
||||||
@echo " just build::release - Build workspace (release)"
|
|
||||||
@echo ""
|
|
||||||
@echo "Test:"
|
|
||||||
@echo " just test::all - Run all tests"
|
|
||||||
@echo " just test::lib - Library tests only"
|
|
||||||
@echo " just test::crate NAME - Test specific crate"
|
|
||||||
@echo ""
|
|
||||||
@echo "Format & Quality:"
|
|
||||||
@echo " just fmt::check - Check formatting"
|
|
||||||
@echo " just fmt::fix - Auto-format code"
|
|
||||||
@echo " just fmt::clippy - Lint code"
|
|
||||||
@echo ""
|
|
||||||
@echo "Validation:"
|
|
||||||
@echo " just check::code - Quick syntax check"
|
|
||||||
@echo " just check::security - Security audit"
|
|
||||||
@echo " just check::coupling - Analyze coupling"
|
|
||||||
@echo ""
|
|
||||||
@echo "Development:"
|
|
||||||
@echo " just dev::clean - Clean artifacts"
|
|
||||||
@echo " just dev::doc - Generate documentation"
|
|
||||||
@echo ""
|
|
||||||
@echo "Vapora-specific:"
|
|
||||||
@echo " just vapora::test-backend - Test backend"
|
|
||||||
@echo " just vapora::test-agents - Test agents"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# CI/CD Namespace - CI Pipelines & Orchestration
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
ci_help := '''
|
|
||||||
🔧 VAPORA CI Namespace
|
|
||||||
|
|
||||||
CI/CD Pipelines:
|
|
||||||
just ci::full Complete CI pipeline (all checks)
|
|
||||||
just ci::check Code check + format + lint
|
|
||||||
just ci::lint Lint all code (strict)
|
|
||||||
just ci::test-all Test all features
|
|
||||||
just ci::build-debug Debug build
|
|
||||||
just ci::build-release Release build
|
|
||||||
|
|
||||||
Pre-commit & Quick:
|
|
||||||
just ci::quick Fast checks (format + lint only)
|
|
||||||
just ci::pre-commit Pre-commit validation
|
|
||||||
just ci::fast Minimal CI for iteration
|
|
||||||
|
|
||||||
Main Branch:
|
|
||||||
just ci::main Main branch comprehensive checks
|
|
||||||
|
|
||||||
Development:
|
|
||||||
just ci::watch Watch for changes and lint
|
|
||||||
just ci::debug CI with environment info
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Show CI namespace help
|
|
||||||
[no-cd]
|
|
||||||
ci::help:
|
|
||||||
@echo "{{ci_help}}"
|
|
||||||
|
|
||||||
# Complete CI pipeline: check + test + build (strict)
|
|
||||||
[no-cd]
|
|
||||||
ci::full: fmt::fix fmt::check fmt::clippy test::all build::debug
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Full CI Pipeline Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Code quality checks: format + lint + verify
|
|
||||||
[no-cd]
|
|
||||||
ci::check: fmt::check fmt::clippy check::code
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Code Quality Checks Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Lint all code (strict: -D warnings)
|
|
||||||
[no-cd]
|
|
||||||
ci::lint: fmt::clippy
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Linting Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Test all features (lib + integration + doc)
|
|
||||||
[no-cd]
|
|
||||||
ci::test-all: test::all
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ All Tests Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Debug build
|
|
||||||
[no-cd]
|
|
||||||
ci::build-debug: build::debug
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Debug Build Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Release build (optimized)
|
|
||||||
[no-cd]
|
|
||||||
ci::build-release: build::release
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Release Build Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Fast CI check: format + lint only (no build/test)
|
|
||||||
[no-cd]
|
|
||||||
ci::quick: fmt::check fmt::clippy
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Quick Check Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Pre-commit hook: format + check + lint vapora crates
|
|
||||||
[no-cd]
|
|
||||||
ci::pre-commit: fmt::fix fmt::check fmt::clippy-vapora check::code
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Pre-commit Checks Passed"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Main branch CI: comprehensive validation
|
|
||||||
[no-cd]
|
|
||||||
ci::main: check::code fmt::check fmt::clippy test::all build::debug check::security check::coupling
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Main Branch CI Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# Fast iteration CI: minimal checks
|
|
||||||
[no-cd]
|
|
||||||
ci::fast: check::code fmt::clippy-vapora test::lib
|
|
||||||
@echo ""
|
|
||||||
@echo "✅ Fast CI Complete"
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Build Namespace
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Build workspace in debug mode
|
|
||||||
[no-cd]
|
|
||||||
build::debug:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔨 Building workspace (debug mode)..."
|
|
||||||
cargo build --workspace
|
|
||||||
|
|
||||||
# Build workspace in release mode (optimized)
|
|
||||||
[no-cd]
|
|
||||||
build::release:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔨 Building workspace (release mode, optimized)..."
|
|
||||||
cargo build --release --workspace
|
|
||||||
|
|
||||||
# Build all crates with per-crate status
|
|
||||||
[no-cd]
|
|
||||||
build::all:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔨 Building all crates (detailed)..."
|
|
||||||
nu ./scripts/build.nu --all
|
|
||||||
|
|
||||||
# Build specific crate (arg: NAME=crate_name)
|
|
||||||
[no-cd]
|
|
||||||
build::crate NAME='vapora-backend':
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print $"🔨 Building (${{ NAME }})..."
|
|
||||||
cargo build -p {{ NAME }}
|
|
||||||
|
|
||||||
# Build specific crate in release mode
|
|
||||||
[no-cd]
|
|
||||||
build::crate-release NAME='vapora-backend':
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print $"🔨 Building (${{ NAME }}) in release mode..."
|
|
||||||
cargo build --release -p {{ NAME }}
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Test Namespace
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Run all tests (lib + integration + doc)
|
|
||||||
[no-cd]
|
|
||||||
test::all:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Running all tests (workspace)..."
|
|
||||||
cargo test --workspace
|
|
||||||
|
|
||||||
# Run library tests only (fast, no integration tests)
|
|
||||||
[no-cd]
|
|
||||||
test::lib:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Running library tests only..."
|
|
||||||
cargo test --lib --no-fail-fast
|
|
||||||
|
|
||||||
# Run doc tests only
|
|
||||||
[no-cd]
|
|
||||||
test::doc:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Running doc tests..."
|
|
||||||
cargo test --doc
|
|
||||||
|
|
||||||
# Test specific crate (arg: NAME=vapora-backend)
|
|
||||||
[no-cd]
|
|
||||||
test::crate NAME='vapora-backend':
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print $"🧪 Testing (${{ NAME }})..."
|
|
||||||
cargo test -p {{ NAME }}
|
|
||||||
|
|
||||||
# Run tests with output visible
|
|
||||||
[no-cd]
|
|
||||||
test::verbose:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Running tests with output..."
|
|
||||||
cargo test --workspace -- --nocapture
|
|
||||||
|
|
||||||
# Generate coverage report
|
|
||||||
[no-cd]
|
|
||||||
test::coverage:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Running tests with coverage..."
|
|
||||||
if (which cargo-tarpaulin | is-empty) {
|
|
||||||
print "⚠️ cargo-tarpaulin not installed. Install with: cargo install cargo-tarpaulin"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
cargo tarpaulin --workspace --out Html --output-dir coverage
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Format & Code Quality Namespace
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Check formatting without modifying files
|
|
||||||
[no-cd]
|
|
||||||
fmt::check:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📋 Checking code format..."
|
|
||||||
cargo fmt --all -- --check
|
|
||||||
|
|
||||||
# Format code using rustfmt
|
|
||||||
[no-cd]
|
|
||||||
fmt::fix:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "✨ Formatting code..."
|
|
||||||
cargo fmt --all
|
|
||||||
|
|
||||||
# Lint code (strict: -D warnings)
|
|
||||||
[no-cd]
|
|
||||||
fmt::clippy:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔗 Linting code (strict mode)..."
|
|
||||||
cargo clippy --all-targets -- -D warnings
|
|
||||||
|
|
||||||
# Lint only vapora crates (ignore external dependencies)
|
|
||||||
[no-cd]
|
|
||||||
fmt::clippy-vapora:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔗 Linting vapora crates only..."
|
|
||||||
cargo clippy -p vapora-backend -p vapora-agents -p vapora-knowledge-graph -p vapora-llm-router -p vapora-swarm -p vapora-shared -p vapora-analytics -p vapora-telemetry -p vapora-tracking -p vapora-worktree --all-targets -- -D warnings
|
|
||||||
|
|
||||||
# Lint in release mode (catches more optimizations)
|
|
||||||
[no-cd]
|
|
||||||
fmt::clippy-release:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔗 Linting code (release mode)..."
|
|
||||||
cargo clippy --release --all-targets -- -D warnings
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Check Namespace - Validation & Analysis
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Quick syntax/dependency check (fastest)
|
|
||||||
[no-cd]
|
|
||||||
check::code:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔍 Checking code (syntax/deps only)..."
|
|
||||||
cargo check --all-targets
|
|
||||||
|
|
||||||
# Security audit + dependency checks
|
|
||||||
[no-cd]
|
|
||||||
check::security:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔒 Running security audit..."
|
|
||||||
if (which cargo-audit | is-empty) {
|
|
||||||
print "⚠️ cargo-audit not installed. Install with: cargo install cargo-audit"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
cargo audit --deny warnings
|
|
||||||
|
|
||||||
# Analyze coupling metrics with AI
|
|
||||||
[no-cd]
|
|
||||||
check::coupling:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📊 Analyzing coupling metrics..."
|
|
||||||
if (which cargo-coupling | is-empty) {
|
|
||||||
print "⚠️ cargo-coupling not installed. Install with: cargo install cargo-coupling"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
cargo coupling --ai
|
|
||||||
|
|
||||||
# Check licenses and advisories
|
|
||||||
[no-cd]
|
|
||||||
check::deny:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📜 Checking licenses and advisories..."
|
|
||||||
if (which cargo-deny | is-empty) {
|
|
||||||
print "⚠️ cargo-deny not installed. Install with: cargo install cargo-deny"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
cargo deny check licenses advisories
|
|
||||||
|
|
||||||
# Find unused dependencies
|
|
||||||
[no-cd]
|
|
||||||
check::unused:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔍 Checking for unused dependencies..."
|
|
||||||
if (which cargo-udeps | is-empty) {
|
|
||||||
print "⚠️ cargo-udeps not installed. Install with: cargo install cargo-udeps"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
cargo +nightly udeps --workspace
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Development Namespace
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Clean build artifacts
|
|
||||||
[no-cd]
|
|
||||||
dev::clean:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧹 Cleaning build artifacts..."
|
|
||||||
nu ./scripts/clean.nu
|
|
||||||
|
|
||||||
# Update dependencies
|
|
||||||
[no-cd]
|
|
||||||
dev::update-deps:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📦 Updating dependencies..."
|
|
||||||
cargo update
|
|
||||||
print "✓ Dependencies updated. Review changes and test thoroughly."
|
|
||||||
|
|
||||||
# Generate documentation
|
|
||||||
[no-cd]
|
|
||||||
dev::doc:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📚 Generating documentation..."
|
|
||||||
cargo doc --workspace --no-deps --document-private-items
|
|
||||||
|
|
||||||
# Generate and serve documentation locally
|
|
||||||
[no-cd]
|
|
||||||
dev::doc-serve:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "📚 Generating documentation and serving at http://localhost:8000..."
|
|
||||||
cargo doc --workspace --no-deps --document-private-items --open
|
|
||||||
|
|
||||||
# Run benchmarks
|
|
||||||
[no-cd]
|
|
||||||
dev::bench:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "⚡ Running benchmarks..."
|
|
||||||
cargo bench --workspace
|
|
||||||
|
|
||||||
# Run benchmarks and save baseline
|
|
||||||
[no-cd]
|
|
||||||
dev::bench-baseline:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "⚡ Running benchmarks and saving baseline..."
|
|
||||||
cargo bench --workspace -- --save-baseline main
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Vapora-Specific Namespace
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Test vapora-backend service
|
|
||||||
[no-cd]
|
|
||||||
vapora::test-backend:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Testing vapora-backend..."
|
|
||||||
cargo test -p vapora-backend --lib --no-fail-fast
|
|
||||||
|
|
||||||
# Test vapora-agents service
|
|
||||||
[no-cd]
|
|
||||||
vapora::test-agents:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Testing vapora-agents..."
|
|
||||||
cargo test -p vapora-agents --lib --no-fail-fast
|
|
||||||
|
|
||||||
# Test vapora-llm-router service
|
|
||||||
[no-cd]
|
|
||||||
vapora::test-llm-router:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Testing vapora-llm-router..."
|
|
||||||
cargo test -p vapora-llm-router --lib --no-fail-fast
|
|
||||||
|
|
||||||
# Test vapora-knowledge-graph service
|
|
||||||
[no-cd]
|
|
||||||
vapora::test-kg:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Testing vapora-knowledge-graph..."
|
|
||||||
cargo test -p vapora-knowledge-graph --lib --no-fail-fast
|
|
||||||
|
|
||||||
# Test all vapora crates
|
|
||||||
[no-cd]
|
|
||||||
vapora::test-all:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🧪 Testing all vapora crates..."
|
|
||||||
cargo test -p vapora-backend \
|
|
||||||
-p vapora-agents \
|
|
||||||
-p vapora-knowledge-graph \
|
|
||||||
-p vapora-llm-router \
|
|
||||||
-p vapora-swarm \
|
|
||||||
-p vapora-shared \
|
|
||||||
--lib
|
|
||||||
|
|
||||||
# Check backend compilation and linting
|
|
||||||
[no-cd]
|
|
||||||
vapora::check-backend:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔍 Checking vapora-backend..."
|
|
||||||
cargo check -p vapora-backend --all-targets
|
|
||||||
cargo clippy -p vapora-backend --all-targets -- -D warnings
|
|
||||||
|
|
||||||
# Check agents compilation and linting
|
|
||||||
[no-cd]
|
|
||||||
vapora::check-agents:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print "🔍 Checking vapora-agents..."
|
|
||||||
cargo check -p vapora-agents --all-targets
|
|
||||||
cargo clippy -p vapora-agents --all-targets -- -D warnings
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Convenience Aliases (Backward Compatibility)
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Backward compat: old flat recipe names map to namespaced versions
|
|
||||||
@build := 'build::debug'
|
|
||||||
@build-release := 'build::release'
|
|
||||||
@test := 'test::all'
|
|
||||||
@test-lib := 'test::lib'
|
|
||||||
@check := 'check::code'
|
|
||||||
@fmt := 'fmt::fix'
|
|
||||||
@fmt-check := 'fmt::check'
|
|
||||||
@clippy := 'fmt::clippy'
|
|
||||||
@audit := 'check::security'
|
|
||||||
@coupling := 'check::coupling'
|
|
||||||
@ci := 'ci::full'
|
|
||||||
@quick-check := 'ci::quick'
|
|
||||||
@pre-commit := 'ci::pre-commit'
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Helpers & Advanced
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
# Run recipe with timing information
|
|
||||||
[no-cd]
|
|
||||||
timed RECIPE:
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print $"⏱️ Running: just {{ RECIPE }} (with timing)"
|
|
||||||
time just {{ RECIPE }}
|
|
||||||
|
|
||||||
# Run CI and display environment info
|
|
||||||
[no-cd]
|
|
||||||
ci::debug: check::code
|
|
||||||
#!/usr/bin/env nu
|
|
||||||
print ""
|
|
||||||
print "🔍 Environment Information:"
|
|
||||||
print $"Rust version: (rustc --version)"
|
|
||||||
print $"Cargo version: (cargo --version)"
|
|
||||||
print $"Nu version: (nu --version)"
|
|
||||||
print ""
|
|
||||||
print "Running full CI..."
|
|
||||||
just ci::full
|
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# Examples & Quick Reference
|
|
||||||
# ============================================================================
|
|
||||||
|
|
||||||
[no-cd]
|
|
||||||
examples:
|
|
||||||
@echo ""
|
|
||||||
@echo "📖 Quick Command Reference"
|
|
||||||
@echo ""
|
|
||||||
@echo "View help:"
|
|
||||||
@echo " just - List all recipes"
|
|
||||||
@echo " just ci::help - Show CI namespace help"
|
|
||||||
@echo " just help - Show full help"
|
|
||||||
@echo ""
|
|
||||||
@echo "Development workflow:"
|
|
||||||
@echo " just fmt::fix - Auto-format code"
|
|
||||||
@echo " just check::code - Quick syntax check"
|
|
||||||
@echo " just fmt::clippy-vapora - Lint vapora crates"
|
|
||||||
@echo " just vapora::test-backend - Test backend"
|
|
||||||
@echo ""
|
|
||||||
@echo "Pre-commit:"
|
|
||||||
@echo " just ci::pre-commit - Run pre-commit checks"
|
|
||||||
@echo ""
|
|
||||||
@echo "Full validation:"
|
|
||||||
@echo " just ci::full - Complete CI pipeline"
|
|
||||||
@echo " just ci::main - Main branch validation"
|
|
||||||
@echo " just check::security - Security checks"
|
|
||||||
@echo ""
|
|
||||||
@echo "Build & test:"
|
|
||||||
@echo " just build::debug - Debug build"
|
|
||||||
@echo " just build::release - Release build"
|
|
||||||
@echo " just test::all - Run all tests"
|
|
||||||
@echo " just test::coverage - Generate coverage"
|
|
||||||
@echo ""
|
|
||||||
@echo "Analysis:"
|
|
||||||
@echo " just check::coupling - Coupling metrics"
|
|
||||||
@echo " just check::unused - Find unused deps"
|
|
||||||
@echo " just dev::bench - Run benchmarks"
|
|
||||||
@echo ""
|
|
||||||
@ -87,25 +87,28 @@ repos:
|
|||||||
# stages: [pre-commit]
|
# stages: [pre-commit]
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Markdown Hooks (DISABLED - too many legacy formatting issues)
|
# Markdown Hooks (RECOMMENDED - enable for documentation quality)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# TODO: Re-enable after fixing markdown files to pass markdownlint
|
- repo: local
|
||||||
# - repo: local
|
hooks:
|
||||||
# hooks:
|
- id: markdownlint
|
||||||
# - id: markdownlint
|
name: Markdown linting (markdownlint-cli2)
|
||||||
# name: Markdown linting (markdownlint-cli2)
|
entry: markdownlint-cli2
|
||||||
# entry: markdownlint-cli2
|
language: system
|
||||||
# language: system
|
types: [markdown]
|
||||||
# types: [markdown]
|
exclude: |
|
||||||
# exclude: |
|
(?x)^(
|
||||||
# ^(
|
\.typedialog/|
|
||||||
# \.typedialog|
|
\.woodpecker/|
|
||||||
# \.woodpecker|
|
\.vale/|
|
||||||
# \.vale|
|
assets/prompt_gen\.md|
|
||||||
# assets/(prompt_gen|README)|
|
assets/README\.md|
|
||||||
# (README|SECURITY|CONTRIBUTING|CODE_OF_CONDUCT)\.md
|
README\.md|
|
||||||
# )
|
SECURITY\.md|
|
||||||
# stages: [pre-commit]
|
CONTRIBUTING\.md|
|
||||||
|
CODE_OF_CONDUCT\.md
|
||||||
|
)
|
||||||
|
stages: [pre-commit]
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# General Pre-commit Hooks
|
# General Pre-commit Hooks
|
||||||
@ -123,7 +126,7 @@ repos:
|
|||||||
- id: check-toml
|
- id: check-toml
|
||||||
|
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
exclude: ^(\.woodpecker/|kubernetes/|provisioning/)
|
exclude: ^\.woodpecker/
|
||||||
|
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: \.svg$
|
exclude: \.svg$
|
||||||
|
|||||||
@ -1,320 +0,0 @@
|
|||||||
# CI System - Configuration Guide
|
|
||||||
|
|
||||||
**Installed**: 2026-01-11
|
|
||||||
**Detected Languages**: rust, nushell, nickel, bash, markdown
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### Option 1: Using configure.sh (Recommended)
|
|
||||||
|
|
||||||
A convenience script is installed in `.typedialog/ci/`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Use web backend (default) - Opens in browser
|
|
||||||
.typedialog/ci/configure.sh
|
|
||||||
|
|
||||||
# Use TUI backend - Terminal interface
|
|
||||||
.typedialog/ci/configure.sh tui
|
|
||||||
|
|
||||||
# Use CLI backend - Command-line prompts
|
|
||||||
.typedialog/ci/configure.sh cli
|
|
||||||
```
|
|
||||||
|
|
||||||
**This script automatically:**
|
|
||||||
- Sources `.typedialog/ci/envrc` for environment setup
|
|
||||||
- Loads defaults from `config.ncl` (Nickel format)
|
|
||||||
- Uses cascading search for fragments (local → Tools)
|
|
||||||
- Creates backup before overwriting existing config
|
|
||||||
- Saves output in Nickel format using nickel-roundtrip with documented template
|
|
||||||
- Generates `config.ncl` compatible with `nickel doc` command
|
|
||||||
|
|
||||||
### Option 2: Direct TypeDialog Commands
|
|
||||||
|
|
||||||
Use TypeDialog nickel-roundtrip directly with manual paths:
|
|
||||||
|
|
||||||
#### Web Backend (Recommended - Easy Viewing)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd .typedialog/ci # Change to CI directory
|
|
||||||
source envrc # Load environment
|
|
||||||
typedialog-web nickel-roundtrip config.ncl form.toml \
|
|
||||||
--output config.ncl \
|
|
||||||
--ncl-template $TOOLS_PATH/dev-system/ci/templates/config.ncl.j2
|
|
||||||
```
|
|
||||||
|
|
||||||
#### TUI Backend
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd .typedialog/ci
|
|
||||||
source envrc
|
|
||||||
typedialog-tui nickel-roundtrip config.ncl form.toml \
|
|
||||||
--output config.ncl \
|
|
||||||
--ncl-template $TOOLS_PATH/dev-system/ci/templates/config.ncl.j2
|
|
||||||
```
|
|
||||||
|
|
||||||
#### CLI Backend
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd .typedialog/ci
|
|
||||||
source envrc
|
|
||||||
typedialog nickel-roundtrip config.ncl form.toml \
|
|
||||||
--output config.ncl \
|
|
||||||
--ncl-template $TOOLS_PATH/dev-system/ci/templates/config.ncl.j2
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** The `--ncl-template` flag uses a Tera template that adds:
|
|
||||||
- Descriptive comments for each section
|
|
||||||
- Documentation compatible with `nickel doc config.ncl`
|
|
||||||
- Consistent formatting and structure
|
|
||||||
|
|
||||||
**All backends will:**
|
|
||||||
- Show only options relevant to your detected languages
|
|
||||||
- Guide you through all configuration choices
|
|
||||||
- Validate your inputs
|
|
||||||
- Generate config.ncl in Nickel format
|
|
||||||
|
|
||||||
### Option 3: Manual Configuration
|
|
||||||
|
|
||||||
Edit `config.ncl` directly:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
vim .typedialog/ci/config.ncl
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configuration Format: Nickel
|
|
||||||
|
|
||||||
**This project uses Nickel format by default** for all configuration files.
|
|
||||||
|
|
||||||
### Why Nickel?
|
|
||||||
|
|
||||||
- ✅ **Typed configuration** - Static type checking with `nickel typecheck`
|
|
||||||
- ✅ **Documentation** - Generate docs with `nickel doc config.ncl`
|
|
||||||
- ✅ **Validation** - Built-in schema validation
|
|
||||||
- ✅ **Comments** - Rich inline documentation support
|
|
||||||
- ✅ **Modular** - Import/export system for reusable configs
|
|
||||||
|
|
||||||
### Nickel Template
|
|
||||||
|
|
||||||
The output structure is controlled by a **Tera template** at:
|
|
||||||
- **Tools default**: `$TOOLS_PATH/dev-system/ci/templates/config.ncl.j2`
|
|
||||||
- **Local override**: `.typedialog/ci/config.ncl.j2` (optional)
|
|
||||||
|
|
||||||
**To customize the template:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Copy the default template
|
|
||||||
cp $TOOLS_PATH/dev-system/ci/templates/config.ncl.j2 \
|
|
||||||
.typedialog/ci/config.ncl.j2
|
|
||||||
|
|
||||||
# Edit to add custom comments, documentation, or structure
|
|
||||||
vim .typedialog/ci/config.ncl.j2
|
|
||||||
|
|
||||||
# Your template will now be used automatically
|
|
||||||
```
|
|
||||||
|
|
||||||
**Template features:**
|
|
||||||
- Customizable comments per section
|
|
||||||
- Control field ordering
|
|
||||||
- Add project-specific documentation
|
|
||||||
- Configure output for `nickel doc` command
|
|
||||||
|
|
||||||
### TypeDialog Environment Variables
|
|
||||||
|
|
||||||
You can customize TypeDialog behavior with environment variables:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Web server configuration
|
|
||||||
export TYPEDIALOG_PORT=9000 # Port for web backend (default: 9000)
|
|
||||||
export TYPEDIALOG_HOST=localhost # Host binding (default: localhost)
|
|
||||||
|
|
||||||
# Localization
|
|
||||||
export TYPEDIALOG_LANG=en_US.UTF-8 # Form language (default: system locale)
|
|
||||||
|
|
||||||
# Run with custom settings
|
|
||||||
TYPEDIALOG_PORT=8080 .typedialog/ci/configure.sh web
|
|
||||||
```
|
|
||||||
|
|
||||||
**Common use cases:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Access from other machines in network
|
|
||||||
TYPEDIALOG_HOST=0.0.0.0 TYPEDIALOG_PORT=8080 .typedialog/ci/configure.sh web
|
|
||||||
|
|
||||||
# Use different port if 9000 is busy
|
|
||||||
TYPEDIALOG_PORT=3000 .typedialog/ci/configure.sh web
|
|
||||||
|
|
||||||
# Spanish interface
|
|
||||||
TYPEDIALOG_LANG=es_ES.UTF-8 .typedialog/ci/configure.sh web
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Structure
|
|
||||||
|
|
||||||
Your config.ncl is organized in the `ci` namespace (Nickel format):
|
|
||||||
|
|
||||||
```nickel
|
|
||||||
{
|
|
||||||
ci = {
|
|
||||||
project = {
|
|
||||||
name = "rust",
|
|
||||||
detected_languages = ["rust, nushell, nickel, bash, markdown"],
|
|
||||||
primary_language = "rust",
|
|
||||||
},
|
|
||||||
tools = {
|
|
||||||
# Tools are added based on detected languages
|
|
||||||
},
|
|
||||||
features = {
|
|
||||||
# CI features (pre-commit, GitHub Actions, etc.)
|
|
||||||
},
|
|
||||||
ci_providers = {
|
|
||||||
# CI provider configurations
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available Fragments
|
|
||||||
|
|
||||||
Tool configurations are modular. Check `.typedialog/ci/fragments/` for:
|
|
||||||
|
|
||||||
- rust-tools.toml - Tools for rust
|
|
||||||
- nushell-tools.toml - Tools for nushell
|
|
||||||
- nickel-tools.toml - Tools for nickel
|
|
||||||
- bash-tools.toml - Tools for bash
|
|
||||||
- markdown-tools.toml - Tools for markdown
|
|
||||||
- general-tools.toml - Cross-language tools
|
|
||||||
- ci-providers.toml - GitHub Actions, Woodpecker, etc.
|
|
||||||
|
|
||||||
## Cascading Override System
|
|
||||||
|
|
||||||
This project uses a **local → Tools cascading search** for all resources:
|
|
||||||
|
|
||||||
### How It Works
|
|
||||||
|
|
||||||
Resources are searched in priority order:
|
|
||||||
|
|
||||||
1. **Local files** (`.typedialog/ci/`) - **FIRST** (highest priority)
|
|
||||||
2. **Tools files** (`$TOOLS_PATH/dev-system/ci/`) - **FALLBACK** (default)
|
|
||||||
|
|
||||||
### Affected Resources
|
|
||||||
|
|
||||||
| Resource | Local Path | Tools Path |
|
|
||||||
|----------|------------|------------|
|
|
||||||
| Fragments | `.typedialog/ci/fragments/` | `$TOOLS_PATH/dev-system/ci/forms/fragments/` |
|
|
||||||
| Schemas | `.typedialog/ci/schemas/` | `$TOOLS_PATH/dev-system/ci/schemas/` |
|
|
||||||
| Validators | `.typedialog/ci/validators/` | `$TOOLS_PATH/dev-system/ci/validators/` |
|
|
||||||
| Defaults | `.typedialog/ci/defaults/` | `$TOOLS_PATH/dev-system/ci/defaults/` |
|
|
||||||
| Nickel Template | `.typedialog/ci/config.ncl.j2` | `$TOOLS_PATH/dev-system/ci/templates/config.ncl.j2` |
|
|
||||||
|
|
||||||
### Environment Setup (.envrc)
|
|
||||||
|
|
||||||
The `.typedialog/ci/.envrc` file configures search paths:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Source this file to load environment
|
|
||||||
source .typedialog/ci/.envrc
|
|
||||||
|
|
||||||
# Or use direnv for automatic loading
|
|
||||||
echo 'source .typedialog/ci/.envrc' >> .envrc
|
|
||||||
```
|
|
||||||
|
|
||||||
**What's in .envrc:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export NICKEL_IMPORT_PATH="schemas:$TOOLS_PATH/dev-system/ci/schemas:validators:..."
|
|
||||||
export TYPEDIALOG_FRAGMENT_PATH=".:$TOOLS_PATH/dev-system/ci/forms"
|
|
||||||
export NCL_TEMPLATE="<local or Tools path to config.ncl.j2>"
|
|
||||||
export TYPEDIALOG_PORT=9000 # Web server port
|
|
||||||
export TYPEDIALOG_HOST=localhost # Web server host
|
|
||||||
export TYPEDIALOG_LANG="${LANG}" # Form localization
|
|
||||||
```
|
|
||||||
|
|
||||||
### Creating Overrides
|
|
||||||
|
|
||||||
**By default:** All resources come from Tools (no duplication).
|
|
||||||
|
|
||||||
**To customize:** Create file in local directory with same name:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Override a fragment
|
|
||||||
cp $TOOLS_PATH/dev-system/ci/fragments/rust-tools.toml \
|
|
||||||
.typedialog/ci/fragments/rust-tools.toml
|
|
||||||
|
|
||||||
# Edit your local version
|
|
||||||
vim .typedialog/ci/fragments/rust-tools.toml
|
|
||||||
|
|
||||||
# Override Nickel template (customize comments, structure, nickel doc output)
|
|
||||||
cp $TOOLS_PATH/dev-system/ci/templates/config.ncl.j2 \
|
|
||||||
.typedialog/ci/config.ncl.j2
|
|
||||||
|
|
||||||
# Edit to customize documentation and structure
|
|
||||||
vim .typedialog/ci/config.ncl.j2
|
|
||||||
|
|
||||||
# Now your version will be used instead of Tools version
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits:**
|
|
||||||
|
|
||||||
- ✅ Override only what you need
|
|
||||||
- ✅ Everything else stays synchronized with Tools
|
|
||||||
- ✅ No duplication by default
|
|
||||||
- ✅ Automatic updates when Tools is updated
|
|
||||||
|
|
||||||
**See:** `$TOOLS_PATH/dev-system/ci/docs/cascade-override.md` for complete documentation.
|
|
||||||
|
|
||||||
## Testing Your Configuration
|
|
||||||
|
|
||||||
### Validate Configuration
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nu $env.TOOLS_PATH/dev-system/ci/scripts/validator.nu \
|
|
||||||
--config .typedialog/ci/config.ncl \
|
|
||||||
--project . \
|
|
||||||
--namespace ci
|
|
||||||
```
|
|
||||||
|
|
||||||
### Regenerate CI Files
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nu $env.TOOLS_PATH/dev-system/ci/scripts/generate-configs.nu \
|
|
||||||
--config .typedialog/ci/config.ncl \
|
|
||||||
--templates $env.TOOLS_PATH/dev-system/ci/templates \
|
|
||||||
--output . \
|
|
||||||
--namespace ci
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Tasks
|
|
||||||
|
|
||||||
### Add a New Tool
|
|
||||||
|
|
||||||
Edit `config.ncl` and add under `ci.tools`:
|
|
||||||
|
|
||||||
```nickel
|
|
||||||
{
|
|
||||||
ci = {
|
|
||||||
tools = {
|
|
||||||
newtool = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
version = "latest",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Disable a Feature
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[ci.features]
|
|
||||||
enable_pre_commit = false
|
|
||||||
```
|
|
||||||
|
|
||||||
## Need Help?
|
|
||||||
|
|
||||||
For detailed documentation, see:
|
|
||||||
- $env.TOOLS_PATH/dev-system/ci/docs/configuration-guide.md
|
|
||||||
- $env.TOOLS_PATH/dev-system/ci/docs/installation-guide.md
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
# CI Configuration - Nickel Format
|
|
||||||
# Auto-generated by dev-system CI installer
|
|
||||||
#
|
|
||||||
# This file is managed by TypeDialog using nickel-roundtrip.
|
|
||||||
# Edit via: .typedialog/ci/configure.sh
|
|
||||||
# Or manually edit and validate with: nickel typecheck config.ncl
|
|
||||||
#
|
|
||||||
# Documentation: nickel doc config.ncl
|
|
||||||
|
|
||||||
{
|
|
||||||
# CI namespace - all configuration lives under 'ci'
|
|
||||||
ci = {
|
|
||||||
# Project Information
|
|
||||||
# Detected languages and primary language for this project
|
|
||||||
project = {
|
|
||||||
# Project name
|
|
||||||
name = "vapora",
|
|
||||||
# Project description
|
|
||||||
description = "vapora",
|
|
||||||
# Project website or documentation site URL
|
|
||||||
site_url = "https://repo.jesusperez.pro/jesus/Vapora",
|
|
||||||
# Project repository URL (GitHub, GitLab, etc.)
|
|
||||||
repo_url = "https://repo.jesusperez.pro/jesus/Vapora",
|
|
||||||
# Languages detected in codebase (auto-detected by installer)
|
|
||||||
detected_languages = [
|
|
||||||
"rust",
|
|
||||||
"nushell",
|
|
||||||
"nickel",
|
|
||||||
"bash",
|
|
||||||
"markdown"
|
|
||||||
],
|
|
||||||
# Primary language (determines default tooling)
|
|
||||||
primary_language = "rust",
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Tools Configuration
|
|
||||||
# Each tool can be enabled/disabled and configured here
|
|
||||||
tools = {
|
|
||||||
# Taplo - TOML formatter and linter
|
|
||||||
taplo = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# YAMLlint - YAML formatter and linter
|
|
||||||
yamllint = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Clippy - Rust linting tool
|
|
||||||
clippy = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
deny_warnings = true,
|
|
||||||
},
|
|
||||||
# Cargo Audit - Security vulnerability scanner
|
|
||||||
audit = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Cargo Deny - Dependency checker
|
|
||||||
deny = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Cargo SBOM - Software Bill of Materials
|
|
||||||
sbom = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# LLVM Coverage - Code coverage tool
|
|
||||||
llvm-cov = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Shellcheck - Bash/shell script linter
|
|
||||||
shellcheck = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Shfmt - Shell script formatter
|
|
||||||
shfmt = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Markdownlint - Markdown linter
|
|
||||||
markdownlint = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
# Vale - Prose linter
|
|
||||||
vale = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Nickel - Configuration language type checker
|
|
||||||
nickel = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
check_all = true,
|
|
||||||
},
|
|
||||||
# NuShell - Shell script validator
|
|
||||||
nushell = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "builtin",
|
|
||||||
check_all = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Features
|
|
||||||
# High-level feature flags for CI behavior
|
|
||||||
features = {
|
|
||||||
enable_ci_cd = true,
|
|
||||||
enable_pre_commit = true,
|
|
||||||
generate_taplo_config = true,
|
|
||||||
generate_contributing = true,
|
|
||||||
generate_security = true,
|
|
||||||
generate_code_of_conduct = true,
|
|
||||||
generate_dockerfiles = true,
|
|
||||||
enable_cross_compilation = true,
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Provider Configurations
|
|
||||||
# Settings for GitHub Actions, Woodpecker, GitLab CI, etc.
|
|
||||||
ci_providers = {
|
|
||||||
# GitHub Actions
|
|
||||||
github_actions = {
|
|
||||||
enabled = true,
|
|
||||||
branches_push = "main,develop",
|
|
||||||
branches_pr = "main",
|
|
||||||
},
|
|
||||||
# Woodpecker CI
|
|
||||||
woodpecker = {
|
|
||||||
enabled = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Settings
|
|
||||||
settings = {
|
|
||||||
parallel_jobs = 1,
|
|
||||||
job_timeout_minutes = 1,
|
|
||||||
require_status_checks = true,
|
|
||||||
run_on_draft_prs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@ -1,203 +0,0 @@
|
|||||||
# CI Configuration - Nickel Format
|
|
||||||
# Auto-generated by dev-system CI installer
|
|
||||||
#
|
|
||||||
# This file is managed by TypeDialog using nickel-roundtrip.
|
|
||||||
# Edit via: .typedialog/ci/configure.sh
|
|
||||||
# Or manually edit and validate with: nickel typecheck config.ncl
|
|
||||||
#
|
|
||||||
# Documentation: nickel doc config.ncl
|
|
||||||
|
|
||||||
{
|
|
||||||
# CI namespace - all configuration lives under 'ci'
|
|
||||||
ci = {
|
|
||||||
# Project Information
|
|
||||||
# Detected languages and primary language for this project
|
|
||||||
project = {
|
|
||||||
# Project name
|
|
||||||
name = "",
|
|
||||||
# Project description
|
|
||||||
description = "",
|
|
||||||
# Project website or documentation site URL
|
|
||||||
site_url = "",
|
|
||||||
# Project repository URL (GitHub, GitLab, etc.)
|
|
||||||
repo_url = "",
|
|
||||||
# Languages detected in codebase (auto-detected by installer)
|
|
||||||
detected_languages = [
|
|
||||||
"rust",
|
|
||||||
"markdown",
|
|
||||||
"nickel"
|
|
||||||
],
|
|
||||||
# Primary language (determines default tooling)
|
|
||||||
primary_language = "rust",
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Tools Configuration
|
|
||||||
# Each tool can be enabled/disabled and configured here
|
|
||||||
tools = {
|
|
||||||
# Taplo - TOML formatter and linter
|
|
||||||
taplo = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# YAMLlint - YAML formatter and linter
|
|
||||||
yamllint = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Clippy - Rust linting tool
|
|
||||||
clippy = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
deny_warnings = true,
|
|
||||||
},
|
|
||||||
# Cargo Audit - Security vulnerability scanner
|
|
||||||
audit = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Cargo Deny - Dependency checker
|
|
||||||
deny = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Cargo SBOM - Software Bill of Materials
|
|
||||||
sbom = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# LLVM Coverage - Code coverage tool
|
|
||||||
llvm-cov = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "cargo",
|
|
||||||
},
|
|
||||||
# Shellcheck - Bash/shell script linter
|
|
||||||
shellcheck = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Shfmt - Shell script formatter
|
|
||||||
shfmt = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Markdownlint - Markdown linter
|
|
||||||
markdownlint = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
# Vale - Prose linter
|
|
||||||
vale = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Nickel - Configuration language type checker
|
|
||||||
nickel = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
check_all = true,
|
|
||||||
},
|
|
||||||
# NuShell - Shell script validator
|
|
||||||
nushell = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "builtin",
|
|
||||||
check_all = true,
|
|
||||||
},
|
|
||||||
# Ruff - Fast Python linter
|
|
||||||
ruff = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Black - Python code formatter
|
|
||||||
black = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Mypy - Python static type checker
|
|
||||||
mypy = {
|
|
||||||
enabled = false,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Pytest - Python testing framework
|
|
||||||
pytest = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "pip",
|
|
||||||
},
|
|
||||||
# Golangci-lint - Go linter aggregator
|
|
||||||
"golangci-lint" = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Gofmt - Go code formatter
|
|
||||||
gofmt = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "builtin",
|
|
||||||
},
|
|
||||||
# Staticcheck - Go static analysis
|
|
||||||
staticcheck = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# Gosec - Go security checker
|
|
||||||
gosec = {
|
|
||||||
enabled = false,
|
|
||||||
install_method = "brew",
|
|
||||||
},
|
|
||||||
# ESLint - JavaScript linter
|
|
||||||
eslint = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
# Prettier - Code formatter
|
|
||||||
prettier = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
# TypeScript - Type checking
|
|
||||||
typescript = {
|
|
||||||
enabled = false,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
# Jest - JavaScript testing framework
|
|
||||||
jest = {
|
|
||||||
enabled = true,
|
|
||||||
install_method = "npm",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Features
|
|
||||||
# High-level feature flags for CI behavior
|
|
||||||
features = {
|
|
||||||
enable_ci_cd = true,
|
|
||||||
enable_pre_commit = true,
|
|
||||||
generate_taplo_config = true,
|
|
||||||
generate_contributing = true,
|
|
||||||
generate_security = true,
|
|
||||||
generate_code_of_conduct = true,
|
|
||||||
generate_dockerfiles = true,
|
|
||||||
enable_cross_compilation = true,
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Provider Configurations
|
|
||||||
# Settings for GitHub Actions, Woodpecker, GitLab CI, etc.
|
|
||||||
ci_providers = {
|
|
||||||
# GitHub Actions
|
|
||||||
github_actions = {
|
|
||||||
enabled = true,
|
|
||||||
branches_push = "main,develop",
|
|
||||||
branches_pr = "main",
|
|
||||||
},
|
|
||||||
# Woodpecker CI
|
|
||||||
woodpecker = {
|
|
||||||
enabled = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
# CI Settings
|
|
||||||
settings = {
|
|
||||||
parallel_jobs = 1,
|
|
||||||
job_timeout_minutes = 1,
|
|
||||||
require_status_checks = true,
|
|
||||||
run_on_draft_prs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# CI Configuration Script
|
|
||||||
# Auto-generated by dev-system/ci installer
|
|
||||||
#
|
|
||||||
# Interactive configuration for CI tools using TypeDialog.
|
|
||||||
# Uses Nickel format for configuration files.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
TYPEDIALOG_CI="${SCRIPT_DIR}"
|
|
||||||
|
|
||||||
# Source envrc to load fragment paths and other environment variables
|
|
||||||
if [[ -f "${TYPEDIALOG_CI}/envrc" ]]; then
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source "${TYPEDIALOG_CI}/envrc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Configuration files
|
|
||||||
FORM_FILE="${TYPEDIALOG_CI}/form.toml"
|
|
||||||
CONFIG_FILE="${TYPEDIALOG_CI}/config.ncl"
|
|
||||||
|
|
||||||
# NCL_TEMPLATE is set by envrc (cascading: local → Tools)
|
|
||||||
# If not set, use default from Tools
|
|
||||||
NCL_TEMPLATE="${NCL_TEMPLATE:-${TOOLS_PATH}/dev-system/ci/templates/config.ncl.j2}"
|
|
||||||
|
|
||||||
# TypeDialog environment variables (can be overridden)
|
|
||||||
# Port for web backend (default: 9000)
|
|
||||||
export TYPEDIALOG_PORT="${TYPEDIALOG_PORT:-9000}"
|
|
||||||
|
|
||||||
# Host for web backend (default: localhost)
|
|
||||||
export TYPEDIALOG_HOST="${TYPEDIALOG_HOST:-localhost}"
|
|
||||||
|
|
||||||
# Locale for form localization (default: system locale)
|
|
||||||
export TYPEDIALOG_LANG="${TYPEDIALOG_LANG:-${LANG:-en_US.UTF-8}}"
|
|
||||||
|
|
||||||
# Detect which TypeDialog backend to use (default: web)
|
|
||||||
BACKEND="${1:-web}"
|
|
||||||
|
|
||||||
# Validate backend
|
|
||||||
case "$BACKEND" in
|
|
||||||
cli|tui|web)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 [cli|tui|web]"
|
|
||||||
echo ""
|
|
||||||
echo "Launches TypeDialog for interactive CI configuration."
|
|
||||||
echo "Backend options:"
|
|
||||||
echo " cli - Command-line interface (simple prompts)"
|
|
||||||
echo " tui - Terminal UI (interactive panels)"
|
|
||||||
echo " web - Web server (browser-based) [default]"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Check if form exists
|
|
||||||
if [[ ! -f "$FORM_FILE" ]]; then
|
|
||||||
echo "Error: Form file not found: $FORM_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create backup if config exists
|
|
||||||
if [[ -f "$CONFIG_FILE" ]]; then
|
|
||||||
BACKUP="${CONFIG_FILE}.$(date +%Y%m%d_%H%M%S).bak"
|
|
||||||
cp "$CONFIG_FILE" "$BACKUP"
|
|
||||||
echo "ℹ️ Backed up existing config to: $(basename "$BACKUP")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Launch TypeDialog with Nickel roundtrip (preserves Nickel format)
|
|
||||||
echo "🔧 Launching TypeDialog ($BACKEND backend)..."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Show web server info if using web backend
|
|
||||||
if [[ "$BACKEND" == "web" ]]; then
|
|
||||||
echo "🌐 Web server will start on: http://${TYPEDIALOG_HOST}:${TYPEDIALOG_PORT}"
|
|
||||||
echo " (Override with: TYPEDIALOG_PORT=8080 TYPEDIALOG_HOST=0.0.0.0 $0)"
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Build nickel-roundtrip command with optional template
|
|
||||||
NCL_TEMPLATE_ARG=""
|
|
||||||
if [[ -f "$NCL_TEMPLATE" ]]; then
|
|
||||||
NCL_TEMPLATE_ARG="--ncl-template $NCL_TEMPLATE"
|
|
||||||
echo "ℹ️ Using Nickel template: $NCL_TEMPLATE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$BACKEND" in
|
|
||||||
cli)
|
|
||||||
typedialog nickel-roundtrip "$CONFIG_FILE" "$FORM_FILE" --output "$CONFIG_FILE" $NCL_TEMPLATE_ARG
|
|
||||||
;;
|
|
||||||
tui)
|
|
||||||
typedialog-tui nickel-roundtrip "$CONFIG_FILE" "$FORM_FILE" --output "$CONFIG_FILE" $NCL_TEMPLATE_ARG
|
|
||||||
;;
|
|
||||||
web)
|
|
||||||
typedialog-web nickel-roundtrip "$CONFIG_FILE" "$FORM_FILE" --output "$CONFIG_FILE" $NCL_TEMPLATE_ARG
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
if [[ $EXIT_CODE -eq 0 ]]; then
|
|
||||||
echo ""
|
|
||||||
echo "✅ Configuration saved to: $CONFIG_FILE"
|
|
||||||
echo ""
|
|
||||||
echo "Next steps:"
|
|
||||||
echo " - Review the configuration: cat $CONFIG_FILE"
|
|
||||||
echo " - Apply CI tools: (run your CI setup command)"
|
|
||||||
echo " - Re-run this script anytime to update: $0"
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
echo "❌ Configuration cancelled or failed (exit code: $EXIT_CODE)"
|
|
||||||
if [[ -f "${CONFIG_FILE}.bak" ]]; then
|
|
||||||
echo " Previous config restored from backup"
|
|
||||||
fi
|
|
||||||
exit $EXIT_CODE
|
|
||||||
fi
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
# Auto-generated by dev-system/ci
|
|
||||||
#
|
|
||||||
# Cascading Path Strategy:
|
|
||||||
# 1. Local files in .typedialog/ci/ take precedence (overrides)
|
|
||||||
# 2. Central files in $TOOLS_PATH/dev-system/ci/ as fallback (defaults)
|
|
||||||
#
|
|
||||||
# To customize: Create file in .typedialog/ci/{schemas,validators,defaults,fragments}/
|
|
||||||
# Your local version will be used instead of the Tools version.
|
|
||||||
|
|
||||||
# Nickel import paths (cascading: local → Tools)
|
|
||||||
export NICKEL_IMPORT_PATH="schemas:$TOOLS_PATH/dev-system/ci/schemas:validators:$TOOLS_PATH/dev-system/ci/validators:defaults:$TOOLS_PATH/dev-system/ci/defaults"
|
|
||||||
|
|
||||||
# TypeDialog fragment search paths (cascading: local → Tools)
|
|
||||||
export TYPEDIALOG_FRAGMENT_PATH=".typedialog/ci:$TOOLS_PATH/dev-system/ci/forms"
|
|
||||||
|
|
||||||
# Nickel template for config.ncl generation (with cascading)
|
|
||||||
# Local template takes precedence if exists
|
|
||||||
if [[ -f ".typedialog/ci/config.ncl.j2" ]]; then
|
|
||||||
export NCL_TEMPLATE=".typedialog/ci/config.ncl.j2"
|
|
||||||
else
|
|
||||||
export NCL_TEMPLATE="$TOOLS_PATH/dev-system/ci/templates/config.ncl.j2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# TypeDialog web backend configuration (override if needed)
|
|
||||||
export TYPEDIALOG_PORT=${TYPEDIALOG_PORT:-9000}
|
|
||||||
export TYPEDIALOG_HOST=${TYPEDIALOG_HOST:-localhost}
|
|
||||||
export TYPEDIALOG_LANG=${TYPEDIALOG_LANG:-${LANG:-en_US.UTF-8}}
|
|
||||||
@ -1,231 +0,0 @@
|
|||||||
description = "Interactive configuration for continuous integration and code quality tools"
|
|
||||||
display_mode = "complete"
|
|
||||||
locales_path = ""
|
|
||||||
name = "CI Configuration Form"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
border_bottom = true
|
|
||||||
border_top = true
|
|
||||||
name = "project_header"
|
|
||||||
title = "📦 Project Information"
|
|
||||||
type = "section_header"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
help = "Name of the project"
|
|
||||||
name = "project_name"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"name",
|
|
||||||
]
|
|
||||||
placeholder = "my-project"
|
|
||||||
prompt = "Project name"
|
|
||||||
required = true
|
|
||||||
type = "text"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
help = "Optional description"
|
|
||||||
name = "project_description"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"description",
|
|
||||||
]
|
|
||||||
placeholder = "Brief description of what this project does"
|
|
||||||
prompt = "Project description"
|
|
||||||
required = false
|
|
||||||
type = "text"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
default = ""
|
|
||||||
help = "Project website or documentation site URL"
|
|
||||||
name = "project_site_url"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"site_url",
|
|
||||||
]
|
|
||||||
placeholder = "https://example.com"
|
|
||||||
prompt = "Project Site URL"
|
|
||||||
required = false
|
|
||||||
type = "text"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
default = ""
|
|
||||||
help = "Project repository URL (GitHub, GitLab, etc.)"
|
|
||||||
name = "project_repo_url"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"repo_url",
|
|
||||||
]
|
|
||||||
placeholder = "https://github.com/user/repo"
|
|
||||||
prompt = "Project Repo URL"
|
|
||||||
required = false
|
|
||||||
type = "text"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
border_bottom = true
|
|
||||||
border_top = true
|
|
||||||
name = "languages_header"
|
|
||||||
title = "🔍 Detected Languages"
|
|
||||||
type = "section_header"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
default = "rust"
|
|
||||||
display_mode = "grid"
|
|
||||||
help = "Select all languages detected or used in the project"
|
|
||||||
min_selected = 1
|
|
||||||
name = "detected_languages"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"detected_languages",
|
|
||||||
]
|
|
||||||
prompt = "Which languages are used in this project?"
|
|
||||||
required = true
|
|
||||||
searchable = true
|
|
||||||
type = "multiselect"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "rust"
|
|
||||||
label = "🦀 Rust"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "nushell"
|
|
||||||
label = "🐚 NuShell"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "nickel"
|
|
||||||
label = "⚙️ Nickel"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "bash"
|
|
||||||
label = "🔧 Bash/Shell"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "markdown"
|
|
||||||
label = "📝 Markdown/Documentation"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
help = "Main language used for defaults (e.g., in GitHub Actions workflows)"
|
|
||||||
name = "primary_language"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"project",
|
|
||||||
"primary_language",
|
|
||||||
]
|
|
||||||
options_from = "detected_languages"
|
|
||||||
prompt = "Primary language"
|
|
||||||
required = true
|
|
||||||
type = "select"
|
|
||||||
default = "rust"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "rust"
|
|
||||||
label = "🦀 Rust"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "nushell"
|
|
||||||
label = "🐚 NuShell"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "nickel"
|
|
||||||
label = "⚙️ Nickel"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "bash"
|
|
||||||
label = "🔧 Bash"
|
|
||||||
|
|
||||||
[[elements.options]]
|
|
||||||
value = "markdown"
|
|
||||||
label = "📝 Markdown"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/rust-tools.toml"]
|
|
||||||
name = "rust_tools_group"
|
|
||||||
type = "group"
|
|
||||||
when = "rust in detected_languages"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/nushell-tools.toml"]
|
|
||||||
name = "nushell_tools_group"
|
|
||||||
type = "group"
|
|
||||||
when = "nushell in detected_languages"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/nickel-tools.toml"]
|
|
||||||
name = "nickel_tools_group"
|
|
||||||
type = "group"
|
|
||||||
when = "nickel in detected_languages"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/bash-tools.toml"]
|
|
||||||
name = "bash_tools_group"
|
|
||||||
type = "group"
|
|
||||||
when = "bash in detected_languages"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/markdown-tools.toml"]
|
|
||||||
name = "markdown_tools_group"
|
|
||||||
type = "group"
|
|
||||||
when = "markdown in detected_languages"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/general-tools.toml"]
|
|
||||||
name = "general_tools_group"
|
|
||||||
type = "group"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
border_bottom = true
|
|
||||||
border_top = true
|
|
||||||
name = "ci_cd_header"
|
|
||||||
title = "🔄 CI/CD Configuration"
|
|
||||||
type = "section_header"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
default = "true"
|
|
||||||
help = "Set up continuous integration and deployment pipelines"
|
|
||||||
name = "enable_ci_cd"
|
|
||||||
nickel_path = [
|
|
||||||
"ci",
|
|
||||||
"features",
|
|
||||||
"enable_ci_cd",
|
|
||||||
]
|
|
||||||
prompt = "Enable CI/CD integration?"
|
|
||||||
type = "confirm"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/ci-providers.toml"]
|
|
||||||
name = "ci_providers_group"
|
|
||||||
type = "group"
|
|
||||||
when = "enable_ci_cd == true"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/ci-settings.toml"]
|
|
||||||
name = "ci_settings_group"
|
|
||||||
type = "group"
|
|
||||||
when = "enable_ci_cd == true"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/build-deployment.toml"]
|
|
||||||
name = "build_deployment_group"
|
|
||||||
type = "group"
|
|
||||||
when = "enable_ci_cd == true"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
includes = ["fragments/documentation.toml"]
|
|
||||||
name = "documentation_group"
|
|
||||||
type = "group"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
border_bottom = true
|
|
||||||
border_top = true
|
|
||||||
name = "confirmation_header"
|
|
||||||
title = "✅ Ready to Install"
|
|
||||||
type = "section_header"
|
|
||||||
|
|
||||||
[[elements]]
|
|
||||||
content = "Review your configuration above. After confirming, the CI system will be installed with your chosen settings."
|
|
||||||
name = "confirmation_footer"
|
|
||||||
type = "footer"
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
# Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
We, as members, contributors, and leaders, pledge to make participation in our project and community a harassment-free experience for everyone, regardless of:
|
|
||||||
|
|
||||||
- Age
|
|
||||||
- Body size
|
|
||||||
- Visible or invisible disability
|
|
||||||
- Ethnicity
|
|
||||||
- Sex characteristics
|
|
||||||
- Gender identity and expression
|
|
||||||
- Level of experience
|
|
||||||
- Education
|
|
||||||
- Socioeconomic status
|
|
||||||
- Nationality
|
|
||||||
- Personal appearance
|
|
||||||
- Race
|
|
||||||
- Caste
|
|
||||||
- Color
|
|
||||||
- Religion
|
|
||||||
- Sexual identity and orientation
|
|
||||||
|
|
||||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to a positive environment for our community include:
|
|
||||||
|
|
||||||
- Demonstrating empathy and kindness toward other people
|
|
||||||
- Being respectful of differing opinions, viewpoints, and experiences
|
|
||||||
- Giving and gracefully accepting constructive feedback
|
|
||||||
- Accepting responsibility and apologizing to those affected by mistakes
|
|
||||||
- Focusing on what is best not just for us as individuals, but for the overall community
|
|
||||||
|
|
||||||
Examples of unacceptable behavior include:
|
|
||||||
|
|
||||||
- The use of sexualized language or imagery
|
|
||||||
- Trolling, insulting, or derogatory comments
|
|
||||||
- Personal or political attacks
|
|
||||||
- Public or private harassment
|
|
||||||
- Publishing others' private information (doxing)
|
|
||||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
||||||
|
|
||||||
## Enforcement Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate corrective action in response to unacceptable behavior.
|
|
||||||
|
|
||||||
Maintainers have the right and responsibility to:
|
|
||||||
|
|
||||||
- Remove, edit, or reject comments, commits, code, and other contributions
|
|
||||||
- Ban contributors for behavior they deem inappropriate, threatening, or harmful
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies to:
|
|
||||||
|
|
||||||
- All community spaces (GitHub, forums, chat, events, etc.)
|
|
||||||
- Official project channels and representations
|
|
||||||
- Interactions between community members related to the project
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to project maintainers:
|
|
||||||
|
|
||||||
- Email: [project contact]
|
|
||||||
- GitHub: Private security advisory
|
|
||||||
- Issues: Report with `conduct` label (public discussions only)
|
|
||||||
|
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
|
||||||
|
|
||||||
### Enforcement Guidelines
|
|
||||||
|
|
||||||
**1. Correction**
|
|
||||||
- Community impact: Use of inappropriate language or unwelcoming behavior
|
|
||||||
- Action: Private written warning with explanation and clarity on impact
|
|
||||||
- Consequence: Warning and no further violations
|
|
||||||
|
|
||||||
**2. Warning**
|
|
||||||
- Community impact: Violation through single incident or series of actions
|
|
||||||
- Action: Written warning with severity consequences for continued behavior
|
|
||||||
- Consequence: Suspension from community interaction
|
|
||||||
|
|
||||||
**3. Temporary Ban**
|
|
||||||
- Community impact: Serious violation of standards
|
|
||||||
- Action: Temporary ban from community interaction
|
|
||||||
- Consequence: Revocation of ban after reflection period
|
|
||||||
|
|
||||||
**4. Permanent Ban**
|
|
||||||
- Community impact: Pattern of violating community standards
|
|
||||||
- Action: Permanent ban from community interaction
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Thank you for being part of our community!**
|
|
||||||
|
|
||||||
We believe in creating a welcoming and inclusive space where everyone can contribute their best work. Together, we make this project better.
|
|
||||||
129
CONTRIBUTING.md
129
CONTRIBUTING.md
@ -1,129 +0,0 @@
|
|||||||
# Contributing to
|
|
||||||
|
|
||||||
Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to this project.
|
|
||||||
|
|
||||||
## Code of Conduct
|
|
||||||
|
|
||||||
This project adheres to a Code of Conduct. By participating, you are expected to uphold this code. Please see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for details.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Rust 1.70+ (if project uses Rust)
|
|
||||||
- NuShell (if project uses Nushell scripts)
|
|
||||||
- Git
|
|
||||||
|
|
||||||
### Development Setup
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Clone your fork: `git clone `
|
|
||||||
3. Add upstream: `git remote add upstream `
|
|
||||||
4. Create a branch: `git checkout -b feature/your-feature`
|
|
||||||
|
|
||||||
## Development Workflow
|
|
||||||
|
|
||||||
### Before You Code
|
|
||||||
|
|
||||||
- Check existing issues and pull requests to avoid duplication
|
|
||||||
- Create an issue to discuss major changes before implementing
|
|
||||||
- Assign yourself to let others know you're working on it
|
|
||||||
|
|
||||||
### Code Standards
|
|
||||||
|
|
||||||
#### Rust
|
|
||||||
|
|
||||||
- Run `cargo fmt --all` before committing
|
|
||||||
- All code must pass `cargo clippy -- -D warnings`
|
|
||||||
- Write tests for new functionality
|
|
||||||
- Maintain 100% documentation coverage for public APIs
|
|
||||||
|
|
||||||
#### Nushell
|
|
||||||
|
|
||||||
- Validate scripts with `nu --ide-check 100 script.nu`
|
|
||||||
- Follow consistent naming conventions
|
|
||||||
- Use type hints where applicable
|
|
||||||
|
|
||||||
#### Nickel
|
|
||||||
|
|
||||||
- Type check schemas with `nickel typecheck`
|
|
||||||
- Document schema fields with comments
|
|
||||||
- Test schema validation
|
|
||||||
|
|
||||||
### Commit Guidelines
|
|
||||||
|
|
||||||
- Write clear, descriptive commit messages
|
|
||||||
- Reference issues with `Fixes #123` or `Related to #123`
|
|
||||||
- Keep commits focused on a single concern
|
|
||||||
- Use imperative mood: "Add feature" not "Added feature"
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
All changes must include tests:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
cargo test --workspace
|
|
||||||
|
|
||||||
# Run with coverage
|
|
||||||
cargo llvm-cov --all-features --lcov
|
|
||||||
|
|
||||||
# Run locally before pushing
|
|
||||||
just ci-full
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pull Request Process
|
|
||||||
|
|
||||||
1. Update documentation for any changed functionality
|
|
||||||
2. Add tests for new code
|
|
||||||
3. Ensure all CI checks pass
|
|
||||||
4. Request review from maintainers
|
|
||||||
5. Be responsive to feedback and iterate quickly
|
|
||||||
|
|
||||||
## Review Process
|
|
||||||
|
|
||||||
- Maintainers will review your PR within 3-5 business days
|
|
||||||
- Feedback is constructive and meant to improve the code
|
|
||||||
- All discussions should be respectful and professional
|
|
||||||
- Once approved, maintainers will merge the PR
|
|
||||||
|
|
||||||
## Reporting Bugs
|
|
||||||
|
|
||||||
Found a bug? Please file an issue with:
|
|
||||||
|
|
||||||
- **Title**: Clear, descriptive title
|
|
||||||
- **Description**: What happened and what you expected
|
|
||||||
- **Steps to reproduce**: Minimal reproducible example
|
|
||||||
- **Environment**: OS, Rust version, etc.
|
|
||||||
- **Screenshots**: If applicable
|
|
||||||
|
|
||||||
## Suggesting Enhancements
|
|
||||||
|
|
||||||
Have an idea? Please file an issue with:
|
|
||||||
|
|
||||||
- **Title**: Clear feature title
|
|
||||||
- **Description**: What, why, and how
|
|
||||||
- **Use cases**: Real-world scenarios where this would help
|
|
||||||
- **Alternative approaches**: If you've considered any
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- Keep README.md up to date
|
|
||||||
- Document public APIs with rustdoc comments
|
|
||||||
- Add examples for non-obvious functionality
|
|
||||||
- Update CHANGELOG.md with your changes
|
|
||||||
|
|
||||||
## Release Process
|
|
||||||
|
|
||||||
Maintainers handle releases following semantic versioning:
|
|
||||||
- MAJOR: Breaking changes
|
|
||||||
- MINOR: New features (backward compatible)
|
|
||||||
- PATCH: Bug fixes
|
|
||||||
|
|
||||||
## Questions?
|
|
||||||
|
|
||||||
- Check existing documentation and issues
|
|
||||||
- Ask in discussions or open an issue
|
|
||||||
- Join our community channels
|
|
||||||
|
|
||||||
Thank you for contributing!
|
|
||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<img src="assets/vapora.svg" alt="Vapora Logo" width="400">
|
<img src="assets/vapora.svg" alt="Vapora Logo" width="400">
|
||||||
|
|
||||||
|
|
||||||
🌊 Intelligent Development Orchestration Platform <br>
|
🌊 Intelligent Development Orchestration Platform <br>
|
||||||
🎯 Specialized agents orchestrate pipelines for your team <br>
|
🎯 Specialized agents orchestrate pipelines for your team <br>
|
||||||
🤖 Multi-IA router (Claude, OpenAI, Gemini, Ollama) <br>
|
🤖 Multi-IA router (Claude, OpenAI, Gemini, Ollama) <br>
|
||||||
|
|||||||
98
SECURITY.md
98
SECURITY.md
@ -1,98 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
This project provides security updates for the following versions:
|
|
||||||
|
|
||||||
| Version | Supported |
|
|
||||||
|---------|-----------|
|
|
||||||
| 1.x | ✅ Yes |
|
|
||||||
| 0.x | ❌ No |
|
|
||||||
|
|
||||||
Only the latest major version receives security patches. Users are encouraged to upgrade to the latest version.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
**Do not open public GitHub issues for security vulnerabilities.**
|
|
||||||
|
|
||||||
Instead, please report security issues to the maintainers privately:
|
|
||||||
|
|
||||||
### Reporting Process
|
|
||||||
|
|
||||||
1. Email security details to the maintainers (see project README for contact)
|
|
||||||
2. Include:
|
|
||||||
- Description of the vulnerability
|
|
||||||
- Steps to reproduce (if possible)
|
|
||||||
- Potential impact
|
|
||||||
- Suggested fix (if you have one)
|
|
||||||
|
|
||||||
3. Expect acknowledgment within 48 hours
|
|
||||||
4. We will work on a fix and coordinate disclosure timing
|
|
||||||
|
|
||||||
### Responsible Disclosure
|
|
||||||
|
|
||||||
- Allow reasonable time for a fix before public disclosure
|
|
||||||
- Work with us to understand and validate the issue
|
|
||||||
- Maintain confidentiality until the fix is released
|
|
||||||
|
|
||||||
## Security Best Practices
|
|
||||||
|
|
||||||
### For Users
|
|
||||||
|
|
||||||
- Keep dependencies up to date
|
|
||||||
- Use the latest version of this project
|
|
||||||
- Review security advisories regularly
|
|
||||||
- Report vulnerabilities responsibly
|
|
||||||
|
|
||||||
### For Contributors
|
|
||||||
|
|
||||||
- Run `cargo audit` before submitting PRs
|
|
||||||
- Use `cargo deny` to check license compliance
|
|
||||||
- Follow secure coding practices
|
|
||||||
- Don't hardcode secrets or credentials
|
|
||||||
- Validate all external inputs
|
|
||||||
|
|
||||||
## Dependency Security
|
|
||||||
|
|
||||||
We use automated tools to monitor dependencies:
|
|
||||||
|
|
||||||
- **cargo-audit**: Scans for known security vulnerabilities
|
|
||||||
- **cargo-deny**: Checks licenses and bans unsafe dependencies
|
|
||||||
|
|
||||||
These run in CI on every push and PR.
|
|
||||||
|
|
||||||
## Code Review
|
|
||||||
|
|
||||||
All code changes go through review before merging:
|
|
||||||
- At least one maintainer review required
|
|
||||||
- Security implications considered
|
|
||||||
- Tests required for all changes
|
|
||||||
- CI checks must pass
|
|
||||||
|
|
||||||
## Known Vulnerabilities
|
|
||||||
|
|
||||||
We maintain transparency about known issues:
|
|
||||||
- Documented in GitHub security advisories
|
|
||||||
- Announced in release notes
|
|
||||||
- Tracked in issues with `security` label
|
|
||||||
|
|
||||||
## Security Contact
|
|
||||||
|
|
||||||
For security inquiries, please contact:
|
|
||||||
- Email: [project maintainers]
|
|
||||||
- Issue: Open a private security advisory on GitHub
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
Security fixes are highlighted in CHANGELOG.md with [SECURITY] prefix.
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
||||||
- [CWE: Common Weakness Enumeration](https://cwe.mitre.org/)
|
|
||||||
- [Rust Security](https://www.rust-lang.org/governance/security-disclosures)
|
|
||||||
- [npm Security](https://docs.npmjs.com/about-npm/security)
|
|
||||||
|
|
||||||
## Questions?
|
|
||||||
|
|
||||||
If you have security questions (not vulnerabilities), open a discussion or issue with the `security` label.
|
|
||||||
File diff suppressed because one or more lines are too long
@ -11,14 +11,14 @@
|
|||||||
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:1"/>
|
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:1"/>
|
||||||
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:1"/>
|
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:1"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|
||||||
<!-- Gradiente vertical -->
|
<!-- Gradiente vertical -->
|
||||||
<linearGradient id="vertGrad" x1="0%" y1="100%" x2="0%" y2="0%">
|
<linearGradient id="vertGrad" x1="0%" y1="100%" x2="0%" y2="0%">
|
||||||
<stop offset="0%" style="stop-color:#22d3ee;stop-opacity:1"/>
|
<stop offset="0%" style="stop-color:#22d3ee;stop-opacity:1"/>
|
||||||
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:0.8"/>
|
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:0.8"/>
|
||||||
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:0.4"/>
|
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:0.4"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|
||||||
<!-- Filtro glow tech -->
|
<!-- Filtro glow tech -->
|
||||||
<filter id="techGlow">
|
<filter id="techGlow">
|
||||||
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<feMergeNode in="SourceGraphic"/>
|
<feMergeNode in="SourceGraphic"/>
|
||||||
</feMerge>
|
</feMerge>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
<!-- Filtro glow fuerte -->
|
<!-- Filtro glow fuerte -->
|
||||||
<filter id="strongGlow">
|
<filter id="strongGlow">
|
||||||
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
<feMergeNode in="SourceGraphic"/>
|
<feMergeNode in="SourceGraphic"/>
|
||||||
</feMerge>
|
</feMerge>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
<!-- Filtro glass -->
|
<!-- Filtro glass -->
|
||||||
<filter id="glass">
|
<filter id="glass">
|
||||||
<feGaussianBlur in="SourceGraphic" stdDeviation="0.5" result="blur"/>
|
<feGaussianBlur in="SourceGraphic" stdDeviation="0.5" result="blur"/>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<feBlend in="SourceGraphic" in2="goo"/>
|
<feBlend in="SourceGraphic" in2="goo"/>
|
||||||
</filter>
|
</filter>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<!-- Fondo -->
|
<!-- Fondo -->
|
||||||
<rect width="800" height="400" fill="#000000"/>
|
<rect width="800" height="400" fill="#000000"/>
|
||||||
|
|
||||||
@ -60,12 +60,12 @@
|
|||||||
<line x1="533" y1="0" x2="533" y2="400"/>
|
<line x1="533" y1="0" x2="533" y2="400"/>
|
||||||
<line x1="667" y1="0" x2="667" y2="400"/>
|
<line x1="667" y1="0" x2="667" y2="400"/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<!-- Símbolo técnico: flujo de datos ascendente -->
|
<!-- Símbolo técnico: flujo de datos ascendente -->
|
||||||
<g transform="translate(267, 280)">
|
<g transform="translate(267, 280)">
|
||||||
<!-- Base: plataforma -->
|
<!-- Base: plataforma -->
|
||||||
<rect x="-25" y="0" width="50" height="6.67" fill="url(#techGrad)" opacity="0.8" rx="3.33"/>
|
<rect x="-25" y="0" width="50" height="6.67" fill="url(#techGrad)" opacity="0.8" rx="3.33"/>
|
||||||
|
|
||||||
<!-- Stream principal - línea central tipo señal -->
|
<!-- Stream principal - línea central tipo señal -->
|
||||||
<path d="M 0 0 L 0 -50 L 8.33 -58 L -8.33 -75 L 8.33 -92 L -8.33 -108 L 8.33 -125 L 0 -133 L 0 -200" stroke="url(#vertGrad)" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#techGlow)">
|
<path d="M 0 0 L 0 -50 L 8.33 -58 L -8.33 -75 L 8.33 -92 L -8.33 -108 L 8.33 -125 L 0 -133 L 0 -200" stroke="url(#vertGrad)" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#techGlow)">
|
||||||
<animate attributeName="stroke-dasharray" values="0,500;500,0;0,500" dur="4s" repeatCount="indefinite"/>
|
<animate attributeName="stroke-dasharray" values="0,500;500,0;0,500" dur="4s" repeatCount="indefinite"/>
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<path d="M 58 0 L 58 -33 L 53 -50 L 63 -67 L 53 -83 L 63 -100 L 58 -117 L 58 -142" stroke="#22d3ee" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.5">
|
<path d="M 58 0 L 58 -33 L 53 -50 L 63 -67 L 53 -83 L 63 -100 L 58 -117 L 58 -142" stroke="#22d3ee" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.5">
|
||||||
<animate attributeName="stroke-dasharray" values="0,333;333,0;0,333" dur="5.5s" repeatCount="indefinite"/>
|
<animate attributeName="stroke-dasharray" values="0,333;333,0;0,333" dur="5.5s" repeatCount="indefinite"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<!-- Nodos de datos en el flujo principal -->
|
<!-- Nodos de datos en el flujo principal -->
|
||||||
<circle cx="0" cy="-67" r="5" fill="#22d3ee" filter="url(#strongGlow)">
|
<circle cx="0" cy="-67" r="5" fill="#22d3ee" filter="url(#strongGlow)">
|
||||||
<animate attributeName="cy" values="-67;-183;-67" dur="3s" repeatCount="indefinite"/>
|
<animate attributeName="cy" values="-67;-183;-67" dur="3s" repeatCount="indefinite"/>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
<animate attributeName="cy" values="-67;-142;-67" dur="5s" repeatCount="indefinite"/>
|
<animate attributeName="cy" values="-67;-142;-67" dur="5s" repeatCount="indefinite"/>
|
||||||
<animate attributeName="opacity" values="0;0.5;0" dur="5s" repeatCount="indefinite"/>
|
<animate attributeName="opacity" values="0;0.5;0" dur="5s" repeatCount="indefinite"/>
|
||||||
</circle>
|
</circle>
|
||||||
|
|
||||||
<!-- Hexágonos técnicos flotantes -->
|
<!-- Hexágonos técnicos flotantes -->
|
||||||
<polygon points="0,-158 5,-162 5,-167 0,-170 -5,-167 -5,-162" stroke="#22d3ee" fill="none" stroke-width="1.67" opacity="0.6">
|
<polygon points="0,-158 5,-162 5,-167 0,-170 -5,-167 -5,-162" stroke="#22d3ee" fill="none" stroke-width="1.67" opacity="0.6">
|
||||||
<animate attributeName="transform" values="translate(0,0);translate(0,-50);translate(0,0)" dur="4s" repeatCount="indefinite"/>
|
<animate attributeName="transform" values="translate(0,0);translate(0,-50);translate(0,0)" dur="4s" repeatCount="indefinite"/>
|
||||||
@ -162,7 +162,7 @@
|
|||||||
<animate attributeName="opacity" values="0;0.3;0" dur="3.5s" repeatCount="indefinite"/>
|
<animate attributeName="opacity" values="0;0.3;0" dur="3.5s" repeatCount="indefinite"/>
|
||||||
</line>
|
</line>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<!-- Texto VAPORA -->
|
<!-- Texto VAPORA -->
|
||||||
<g filter="url(#glass)">
|
<g filter="url(#glass)">
|
||||||
<text x="550" y="207" font-family="'JetBrains Mono', 'Fira Code', monospace" font-size="90" font-weight="800" fill="url(#techGrad)" letter-spacing="5" text-anchor="middle">
|
<text x="550" y="207" font-family="'JetBrains Mono', 'Fira Code', monospace" font-size="90" font-weight="800" fill="url(#techGrad)" letter-spacing="5" text-anchor="middle">
|
||||||
@ -183,7 +183,7 @@
|
|||||||
<text x="550" y="240" font-family="'Inter', sans-serif" font-size="20" fill="#a855f7" opacity="0.8" letter-spacing="0.25em" text-anchor="middle">
|
<text x="550" y="240" font-family="'Inter', sans-serif" font-size="20" fill="#a855f7" opacity="0.8" letter-spacing="0.25em" text-anchor="middle">
|
||||||
Evaporate complexity
|
Evaporate complexity
|
||||||
</text>
|
</text>
|
||||||
|
|
||||||
<!-- Indicador técnico decorativo -->
|
<!-- Indicador técnico decorativo -->
|
||||||
<g transform="translate(550, 280)">
|
<g transform="translate(550, 280)">
|
||||||
<rect x="0" y="0" width="2" height="13.33" fill="#22d3ee" opacity="0.6">
|
<rect x="0" y="0" width="2" height="13.33" fill="#22d3ee" opacity="0.6">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
@ -11,14 +11,14 @@
|
|||||||
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:1"/>
|
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:1"/>
|
||||||
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:1"/>
|
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:1"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|
||||||
<!-- Gradiente vertical -->
|
<!-- Gradiente vertical -->
|
||||||
<linearGradient id="vertGrad" x1="0%" y1="100%" x2="0%" y2="0%">
|
<linearGradient id="vertGrad" x1="0%" y1="100%" x2="0%" y2="0%">
|
||||||
<stop offset="0%" style="stop-color:#22d3ee;stop-opacity:1"/>
|
<stop offset="0%" style="stop-color:#22d3ee;stop-opacity:1"/>
|
||||||
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:0.8"/>
|
<stop offset="50%" style="stop-color:#a855f7;stop-opacity:0.8"/>
|
||||||
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:0.4"/>
|
<stop offset="100%" style="stop-color:#ec4899;stop-opacity:0.4"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|
||||||
<!-- Filtro glow tech -->
|
<!-- Filtro glow tech -->
|
||||||
<filter id="techGlow">
|
<filter id="techGlow">
|
||||||
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<feMergeNode in="SourceGraphic"/>
|
<feMergeNode in="SourceGraphic"/>
|
||||||
</feMerge>
|
</feMerge>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
<!-- Filtro glow fuerte -->
|
<!-- Filtro glow fuerte -->
|
||||||
<filter id="strongGlow">
|
<filter id="strongGlow">
|
||||||
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
<feMergeNode in="SourceGraphic"/>
|
<feMergeNode in="SourceGraphic"/>
|
||||||
</feMerge>
|
</feMerge>
|
||||||
</filter>
|
</filter>
|
||||||
|
|
||||||
<!-- Filtro glass -->
|
<!-- Filtro glass -->
|
||||||
<filter id="glass">
|
<filter id="glass">
|
||||||
<feGaussianBlur in="SourceGraphic" stdDeviation="0.5" result="blur"/>
|
<feGaussianBlur in="SourceGraphic" stdDeviation="0.5" result="blur"/>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<feBlend in="SourceGraphic" in2="goo"/>
|
<feBlend in="SourceGraphic" in2="goo"/>
|
||||||
</filter>
|
</filter>
|
||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<!-- Fondo -->
|
<!-- Fondo -->
|
||||||
<rect width="800" height="400" fill="#000000"/>
|
<rect width="800" height="400" fill="#000000"/>
|
||||||
|
|
||||||
@ -60,12 +60,12 @@
|
|||||||
<line x1="533" y1="0" x2="533" y2="400"/>
|
<line x1="533" y1="0" x2="533" y2="400"/>
|
||||||
<line x1="667" y1="0" x2="667" y2="400"/>
|
<line x1="667" y1="0" x2="667" y2="400"/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<!-- Símbolo técnico: flujo de datos ascendente -->
|
<!-- Símbolo técnico: flujo de datos ascendente -->
|
||||||
<g transform="translate(267, 280)">
|
<g transform="translate(267, 280)">
|
||||||
<!-- Base: plataforma -->
|
<!-- Base: plataforma -->
|
||||||
<rect x="-25" y="0" width="50" height="6.67" fill="url(#techGrad)" opacity="0.8" rx="3.33"/>
|
<rect x="-25" y="0" width="50" height="6.67" fill="url(#techGrad)" opacity="0.8" rx="3.33"/>
|
||||||
|
|
||||||
<!-- Stream principal - línea central tipo señal -->
|
<!-- Stream principal - línea central tipo señal -->
|
||||||
<path d="M 0 0 L 0 -50 L 8.33 -58 L -8.33 -75 L 8.33 -92 L -8.33 -108 L 8.33 -125 L 0 -133 L 0 -200" stroke="url(#vertGrad)" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#techGlow)">
|
<path d="M 0 0 L 0 -50 L 8.33 -58 L -8.33 -75 L 8.33 -92 L -8.33 -108 L 8.33 -125 L 0 -133 L 0 -200" stroke="url(#vertGrad)" stroke-width="5" fill="none" stroke-linecap="round" stroke-linejoin="round" filter="url(#techGlow)">
|
||||||
<animate attributeName="stroke-dasharray" values="0,500;500,0;0,500" dur="4s" repeatCount="indefinite"/>
|
<animate attributeName="stroke-dasharray" values="0,500;500,0;0,500" dur="4s" repeatCount="indefinite"/>
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<path d="M 58 0 L 58 -33 L 53 -50 L 63 -67 L 53 -83 L 63 -100 L 58 -117 L 58 -142" stroke="#22d3ee" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.5">
|
<path d="M 58 0 L 58 -33 L 53 -50 L 63 -67 L 53 -83 L 63 -100 L 58 -117 L 58 -142" stroke="#22d3ee" stroke-width="2.5" fill="none" stroke-linecap="round" opacity="0.5">
|
||||||
<animate attributeName="stroke-dasharray" values="0,333;333,0;0,333" dur="5.5s" repeatCount="indefinite"/>
|
<animate attributeName="stroke-dasharray" values="0,333;333,0;0,333" dur="5.5s" repeatCount="indefinite"/>
|
||||||
</path>
|
</path>
|
||||||
|
|
||||||
<!-- Nodos de datos en el flujo principal -->
|
<!-- Nodos de datos en el flujo principal -->
|
||||||
<circle cx="0" cy="-67" r="5" fill="#22d3ee" filter="url(#strongGlow)">
|
<circle cx="0" cy="-67" r="5" fill="#22d3ee" filter="url(#strongGlow)">
|
||||||
<animate attributeName="cy" values="-67;-183;-67" dur="3s" repeatCount="indefinite"/>
|
<animate attributeName="cy" values="-67;-183;-67" dur="3s" repeatCount="indefinite"/>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
<animate attributeName="cy" values="-67;-142;-67" dur="5s" repeatCount="indefinite"/>
|
<animate attributeName="cy" values="-67;-142;-67" dur="5s" repeatCount="indefinite"/>
|
||||||
<animate attributeName="opacity" values="0;0.5;0" dur="5s" repeatCount="indefinite"/>
|
<animate attributeName="opacity" values="0;0.5;0" dur="5s" repeatCount="indefinite"/>
|
||||||
</circle>
|
</circle>
|
||||||
|
|
||||||
<!-- Hexágonos técnicos flotantes -->
|
<!-- Hexágonos técnicos flotantes -->
|
||||||
<polygon points="0,-158 5,-162 5,-167 0,-170 -5,-167 -5,-162" stroke="#22d3ee" fill="none" stroke-width="1.67" opacity="0.6">
|
<polygon points="0,-158 5,-162 5,-167 0,-170 -5,-167 -5,-162" stroke="#22d3ee" fill="none" stroke-width="1.67" opacity="0.6">
|
||||||
<animate attributeName="transform" values="translate(0,0);translate(0,-50);translate(0,0)" dur="4s" repeatCount="indefinite"/>
|
<animate attributeName="transform" values="translate(0,0);translate(0,-50);translate(0,0)" dur="4s" repeatCount="indefinite"/>
|
||||||
@ -162,7 +162,7 @@
|
|||||||
<animate attributeName="opacity" values="0;0.3;0" dur="3.5s" repeatCount="indefinite"/>
|
<animate attributeName="opacity" values="0;0.3;0" dur="3.5s" repeatCount="indefinite"/>
|
||||||
</line>
|
</line>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<!-- Texto VAPORA -->
|
<!-- Texto VAPORA -->
|
||||||
<g filter="url(#glass)">
|
<g filter="url(#glass)">
|
||||||
<text x="550" y="207" font-family="'JetBrains Mono', 'Fira Code', monospace" font-size="90" font-weight="800" fill="url(#techGrad)" letter-spacing="5" text-anchor="middle">
|
<text x="550" y="207" font-family="'JetBrains Mono', 'Fira Code', monospace" font-size="90" font-weight="800" fill="url(#techGrad)" letter-spacing="5" text-anchor="middle">
|
||||||
@ -183,7 +183,7 @@
|
|||||||
<text x="550" y="240" font-family="'Inter', sans-serif" font-size="20" fill="#a855f7" opacity="0.8" letter-spacing="0.25em" text-anchor="middle">
|
<text x="550" y="240" font-family="'Inter', sans-serif" font-size="20" fill="#a855f7" opacity="0.8" letter-spacing="0.25em" text-anchor="middle">
|
||||||
Evaporate complexity
|
Evaporate complexity
|
||||||
</text>
|
</text>
|
||||||
|
|
||||||
<!-- Indicador técnico decorativo -->
|
<!-- Indicador técnico decorativo -->
|
||||||
<g transform="translate(550, 280)">
|
<g transform="translate(550, 280)">
|
||||||
<rect x="0" y="0" width="2" height="13.33" fill="#22d3ee" opacity="0.6">
|
<rect x="0" y="0" width="2" height="13.33" fill="#22d3ee" opacity="0.6">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
@ -1,40 +1,46 @@
|
|||||||
# VAPORA Server Configuration
|
# VAPORA Server Configuration
|
||||||
# Phase 0: Environment-based configuration
|
# Phase 0: Environment-based configuration
|
||||||
# Note: Load runtime configuration from environment variables, not this file
|
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
# Server configuration (override with env vars: VAPORA_HOST, VAPORA_PORT)
|
# Server will read from environment variables:
|
||||||
host = "127.0.0.1"
|
# VAPORA_HOST (default: 127.0.0.1)
|
||||||
port = 3000
|
# VAPORA_PORT (default: 3000)
|
||||||
|
host = "${VAPORA_HOST:-127.0.0.1}"
|
||||||
|
port = ${VAPORA_PORT:-3000}
|
||||||
|
|
||||||
[server.tls]
|
[server.tls]
|
||||||
# TLS configuration (optional)
|
# TLS configuration (optional)
|
||||||
# Override with: VAPORA_TLS_ENABLED, VAPORA_TLS_CERT_PATH, VAPORA_TLS_KEY_PATH
|
# VAPORA_TLS_CERT_PATH
|
||||||
enabled = false
|
# VAPORA_TLS_KEY_PATH
|
||||||
cert_path = ""
|
enabled = ${VAPORA_TLS_ENABLED:-false}
|
||||||
key_path = ""
|
cert_path = "${VAPORA_TLS_CERT_PATH:-}"
|
||||||
|
key_path = "${VAPORA_TLS_KEY_PATH:-}"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# Database connection (override with: VAPORA_DB_URL, VAPORA_DB_MAX_CONNECTIONS)
|
# Database connection
|
||||||
url = "ws://localhost:8000"
|
# VAPORA_DB_URL (required)
|
||||||
max_connections = 10
|
url = "${VAPORA_DB_URL}"
|
||||||
|
max_connections = ${VAPORA_DB_MAX_CONNECTIONS:-10}
|
||||||
|
|
||||||
[nats]
|
[nats]
|
||||||
# NATS JetStream configuration (override with: VAPORA_NATS_URL, VAPORA_NATS_STREAM)
|
# NATS JetStream configuration
|
||||||
url = "nats://localhost:4222"
|
# VAPORA_NATS_URL (default: nats://localhost:4222)
|
||||||
stream_name = "vapora-tasks"
|
url = "${VAPORA_NATS_URL:-nats://localhost:4222}"
|
||||||
|
stream_name = "${VAPORA_NATS_STREAM:-vapora-tasks}"
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
# Authentication configuration (override with: VAPORA_JWT_SECRET, VAPORA_JWT_EXPIRATION_HOURS)
|
# Authentication configuration
|
||||||
jwt_secret = "change-in-production"
|
# VAPORA_JWT_SECRET (required in production)
|
||||||
jwt_expiration_hours = 24
|
jwt_secret = "${VAPORA_JWT_SECRET}"
|
||||||
|
jwt_expiration_hours = ${VAPORA_JWT_EXPIRATION_HOURS:-24}
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
# Logging configuration (override with: VAPORA_LOG_LEVEL, VAPORA_LOG_JSON)
|
# Logging configuration
|
||||||
level = "info"
|
# VAPORA_LOG_LEVEL (default: info)
|
||||||
json = false
|
level = "${VAPORA_LOG_LEVEL:-info}"
|
||||||
|
json = ${VAPORA_LOG_JSON:-false}
|
||||||
|
|
||||||
[metrics]
|
[metrics]
|
||||||
# Metrics configuration (override with: VAPORA_METRICS_ENABLED, VAPORA_METRICS_PORT)
|
# Metrics configuration
|
||||||
enabled = true
|
enabled = ${VAPORA_METRICS_ENABLED:-true}
|
||||||
port = 9090
|
port = ${VAPORA_METRICS_PORT:-9090}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
//! VAPORA Agent Server Binary
|
//! VAPORA Agent Server Binary
|
||||||
//! Provides HTTP server for agent coordination and health checks
|
//! Provides HTTP server for agent coordination and health checks
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{extract::State, routing::get, Json, Router};
|
use axum::{extract::State, routing::get, Json, Router};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
use vapora_agents::{config::AgentConfig, coordinator::AgentCoordinator, registry::AgentRegistry};
|
use vapora_agents::{config::AgentConfig, coordinator::AgentCoordinator, registry::AgentRegistry};
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// vapora-agents: Agent configuration module
|
// vapora-agents: Agent configuration module
|
||||||
// Load and parse agent definitions from TOML
|
// Load and parse agent definitions from TOML
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::Path;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
// vapora-agents: Agent coordinator - orchestrates agent workflows
|
// vapora-agents: Agent coordinator - orchestrates agent workflows
|
||||||
// Phase 2: Complete implementation with NATS integration
|
// Phase 2: Complete implementation with NATS integration
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::Utc;
|
|
||||||
use thiserror::Error;
|
|
||||||
use tracing::{debug, info, warn};
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
use crate::learning_profile::{ExecutionData, LearningProfile, TaskTypeExpertise};
|
use crate::learning_profile::{ExecutionData, LearningProfile, TaskTypeExpertise};
|
||||||
use crate::messages::{AgentMessage, TaskAssignment};
|
use crate::messages::{AgentMessage, TaskAssignment};
|
||||||
use crate::registry::{AgentRegistry, RegistryError};
|
use crate::registry::{AgentRegistry, RegistryError};
|
||||||
use crate::scoring::AgentScoringService;
|
use crate::scoring::AgentScoringService;
|
||||||
|
use chrono::Utc;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use tracing::{debug, info, warn};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CoordinatorError {
|
pub enum CoordinatorError {
|
||||||
@ -32,11 +30,10 @@ pub enum CoordinatorError {
|
|||||||
InvalidTaskState(String),
|
InvalidTaskState(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
use vapora_llm_router::BudgetManager;
|
|
||||||
use vapora_swarm::coordinator::SwarmCoordinator;
|
|
||||||
|
|
||||||
use crate::config::AgentConfig;
|
use crate::config::AgentConfig;
|
||||||
use crate::profile_adapter::ProfileAdapter;
|
use crate::profile_adapter::ProfileAdapter;
|
||||||
|
use vapora_llm_router::BudgetManager;
|
||||||
|
use vapora_swarm::coordinator::SwarmCoordinator;
|
||||||
|
|
||||||
/// Agent coordinator orchestrates task assignment and execution
|
/// Agent coordinator orchestrates task assignment and execution
|
||||||
pub struct AgentCoordinator {
|
pub struct AgentCoordinator {
|
||||||
@ -360,9 +357,8 @@ impl AgentCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Load learning profile for agent from KG execution history.
|
/// Load learning profile for agent from KG execution history.
|
||||||
/// Queries KG for task-type specific executions and builds expertise
|
/// Queries KG for task-type specific executions and builds expertise metrics.
|
||||||
/// metrics. This is the core integration between KG persistence and
|
/// This is the core integration between KG persistence and learning profiles.
|
||||||
/// learning profiles.
|
|
||||||
///
|
///
|
||||||
/// Process:
|
/// Process:
|
||||||
/// 1. Query KG for task-type specific executions (limited to recent)
|
/// 1. Query KG for task-type specific executions (limited to recent)
|
||||||
@ -415,8 +411,7 @@ impl AgentCoordinator {
|
|||||||
profile.set_task_type_expertise(task_type.to_string(), expertise);
|
profile.set_task_type_expertise(task_type.to_string(), expertise);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Loaded learning profile for agent {} task_type {} (success_rate={:.2}, \
|
"Loaded learning profile for agent {} task_type {} (success_rate={:.2}, confidence={:.2})",
|
||||||
confidence={:.2})",
|
|
||||||
agent_id,
|
agent_id,
|
||||||
task_type,
|
task_type,
|
||||||
profile.get_task_type_score(task_type),
|
profile.get_task_type_score(task_type),
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
|
|
||||||
/// Per-task-type expertise tracking for agents with recency bias.
|
/// Per-task-type expertise tracking for agents with recency bias.
|
||||||
/// Recent performance (last 7 days) weighted 3x higher than historical
|
/// Recent performance (last 7 days) weighted 3x higher than historical averages.
|
||||||
/// averages.
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LearningProfile {
|
pub struct LearningProfile {
|
||||||
pub agent_id: String,
|
pub agent_id: String,
|
||||||
@ -59,8 +58,7 @@ impl LearningProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get recent success rate for task type (weighted with recency bias).
|
/// Get recent success rate for task type (weighted with recency bias).
|
||||||
/// Returns recent_success_rate if available, falls back to overall
|
/// Returns recent_success_rate if available, falls back to overall success_rate.
|
||||||
/// success_rate.
|
|
||||||
pub fn get_recent_score(&self, task_type: &str) -> f64 {
|
pub fn get_recent_score(&self, task_type: &str) -> f64 {
|
||||||
self.task_type_expertise
|
self.task_type_expertise
|
||||||
.get(task_type)
|
.get(task_type)
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
// Agent definition loader - loads agent configurations from JSON files
|
// Agent definition loader - loads agent configurations from JSON files
|
||||||
// Phase 3: Support for agent definition files
|
// Phase 3: Support for agent definition files
|
||||||
|
|
||||||
|
use crate::config::AgentDefinition;
|
||||||
|
use serde_json;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use serde_json;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::config::AgentDefinition;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum LoaderError {
|
pub enum LoaderError {
|
||||||
#[error("Failed to read file: {0}")]
|
#[error("Failed to read file: {0}")]
|
||||||
@ -89,12 +87,10 @@ impl AgentDefinitionLoader {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use serde_json::json;
|
|
||||||
use tempfile::TempDir;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use serde_json::json;
|
||||||
|
use std::io::Write;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_from_file() -> Result<()> {
|
fn test_load_from_file() -> Result<()> {
|
||||||
|
|||||||
@ -2,10 +2,9 @@
|
|||||||
// Phase 5.2: Bridges agent registry with swarm coordination
|
// Phase 5.2: Bridges agent registry with swarm coordination
|
||||||
// Phase 5.3: Integrates per-task-type learning profiles from KG
|
// Phase 5.3: Integrates per-task-type learning profiles from KG
|
||||||
|
|
||||||
use vapora_swarm::messages::AgentProfile;
|
|
||||||
|
|
||||||
use crate::learning_profile::{LearningProfile, TaskTypeExpertise};
|
use crate::learning_profile::{LearningProfile, TaskTypeExpertise};
|
||||||
use crate::registry::AgentMetadata;
|
use crate::registry::AgentMetadata;
|
||||||
|
use vapora_swarm::messages::AgentProfile;
|
||||||
|
|
||||||
/// Adapter that converts AgentMetadata to SwarmCoordinator AgentProfile
|
/// Adapter that converts AgentMetadata to SwarmCoordinator AgentProfile
|
||||||
pub struct ProfileAdapter;
|
pub struct ProfileAdapter;
|
||||||
@ -41,8 +40,7 @@ impl ProfileAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create learning profile from agent with task-type expertise.
|
/// Create learning profile from agent with task-type expertise.
|
||||||
/// Integrates per-task-type learning data from KG for intelligent
|
/// Integrates per-task-type learning data from KG for intelligent assignment.
|
||||||
/// assignment.
|
|
||||||
pub fn create_learning_profile(agent_id: String) -> LearningProfile {
|
pub fn create_learning_profile(agent_id: String) -> LearningProfile {
|
||||||
LearningProfile::new(agent_id)
|
LearningProfile::new(agent_id)
|
||||||
}
|
}
|
||||||
@ -59,8 +57,7 @@ impl ProfileAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update agent profile success rate from learning profile task-type score.
|
/// Update agent profile success rate from learning profile task-type score.
|
||||||
/// Uses learned expertise for the specified task type, with fallback to
|
/// Uses learned expertise for the specified task type, with fallback to default.
|
||||||
/// default.
|
|
||||||
pub fn update_profile_with_learning(
|
pub fn update_profile_with_learning(
|
||||||
mut profile: AgentProfile,
|
mut profile: AgentProfile,
|
||||||
learning_profile: &LearningProfile,
|
learning_profile: &LearningProfile,
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
// vapora-agents: Agent registry - manages agent lifecycle and availability
|
// vapora-agents: Agent registry - manages agent lifecycle and availability
|
||||||
// Phase 2: Complete implementation with 12 agent roles
|
// Phase 2: Complete implementation with 12 agent roles
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
// NATS message consumer routing tasks to executor pool
|
// NATS message consumer routing tasks to executor pool
|
||||||
// Bridges NATS JetStream with executor channels
|
// Bridges NATS JetStream with executor channels
|
||||||
|
|
||||||
|
use crate::messages::TaskAssignment;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
use crate::messages::TaskAssignment;
|
|
||||||
|
|
||||||
/// NATS consumer routing tasks to agent executors
|
/// NATS consumer routing tasks to agent executors
|
||||||
pub struct NatsConsumer {
|
pub struct NatsConsumer {
|
||||||
executor_pool: HashMap<String, mpsc::Sender<TaskAssignment>>,
|
executor_pool: HashMap<String, mpsc::Sender<TaskAssignment>>,
|
||||||
@ -85,9 +83,8 @@ impl std::error::Error for TaskRoutingError {}
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_consumer_registration() {
|
async fn test_consumer_registration() {
|
||||||
|
|||||||
@ -2,17 +2,16 @@
|
|||||||
// Phase 5.5: Persistence of execution history to KG for learning
|
// Phase 5.5: Persistence of execution history to KG for learning
|
||||||
// Each agent has dedicated executor managing its state machine
|
// Each agent has dedicated executor managing its state machine
|
||||||
|
|
||||||
use std::sync::Arc;
|
use crate::messages::TaskAssignment;
|
||||||
|
use crate::registry::AgentMetadata;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
use vapora_knowledge_graph::{ExecutionRecord, KGPersistence, PersistedExecution};
|
use vapora_knowledge_graph::{ExecutionRecord, KGPersistence, PersistedExecution};
|
||||||
use vapora_llm_router::EmbeddingProvider;
|
use vapora_llm_router::EmbeddingProvider;
|
||||||
|
|
||||||
use super::state_machine::{Agent, ExecutionResult, Idle};
|
use super::state_machine::{Agent, ExecutionResult, Idle};
|
||||||
use crate::messages::TaskAssignment;
|
|
||||||
use crate::registry::AgentMetadata;
|
|
||||||
|
|
||||||
/// Per-agent executor handling task processing with persistence (Phase 5.5)
|
/// Per-agent executor handling task processing with persistence (Phase 5.5)
|
||||||
pub struct AgentExecutor {
|
pub struct AgentExecutor {
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
// Type-state machine for agent lifecycle
|
// Type-state machine for agent lifecycle
|
||||||
// Ensures safe state transitions at compile time
|
// Ensures safe state transitions at compile time
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::messages::TaskAssignment;
|
use crate::messages::TaskAssignment;
|
||||||
use crate::registry::AgentMetadata;
|
use crate::registry::AgentMetadata;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Agent states - compile-time enforced state machine
|
/// Agent states - compile-time enforced state machine
|
||||||
/// Initial state: Agent is idle
|
/// Initial state: Agent is idle
|
||||||
@ -141,9 +139,8 @@ impl Agent<Failed> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_type_state_transitions() {
|
fn test_type_state_transitions() {
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
|
use crate::learning_profile::LearningProfile;
|
||||||
use vapora_swarm::messages::AgentProfile;
|
use vapora_swarm::messages::AgentProfile;
|
||||||
|
|
||||||
use crate::learning_profile::LearningProfile;
|
/// Unified agent score combining SwarmCoordinator metrics and learning expertise.
|
||||||
|
|
||||||
/// Unified agent score combining SwarmCoordinator metrics and learning
|
|
||||||
/// expertise.
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AgentScore {
|
pub struct AgentScore {
|
||||||
/// Agent identifier
|
/// Agent identifier
|
||||||
@ -94,8 +92,7 @@ impl AgentScoringService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate blended score prioritizing task-type expertise.
|
/// Calculate blended score prioritizing task-type expertise.
|
||||||
/// Uses recent_success_rate if available (recency bias from learning
|
/// Uses recent_success_rate if available (recency bias from learning profile).
|
||||||
/// profile).
|
|
||||||
pub fn rank_agents_with_recency(
|
pub fn rank_agents_with_recency(
|
||||||
candidates: Vec<AgentProfile>,
|
candidates: Vec<AgentProfile>,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
// Adapter implementing SwarmCoordination trait using real SwarmCoordinator
|
// Adapter implementing SwarmCoordination trait using real SwarmCoordinator
|
||||||
// Decouples agent orchestration from swarm details
|
// Decouples agent orchestration from swarm details
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use vapora_swarm::coordinator::SwarmCoordinator;
|
|
||||||
|
|
||||||
use crate::coordination::{AgentAssignment, AgentLoad, AgentProfile, SwarmCoordination};
|
use crate::coordination::{AgentAssignment, AgentLoad, AgentProfile, SwarmCoordination};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use vapora_swarm::coordinator::SwarmCoordinator;
|
||||||
|
|
||||||
/// Adapter: SwarmCoordination → SwarmCoordinator
|
/// Adapter: SwarmCoordination → SwarmCoordinator
|
||||||
/// Implements the coordination abstraction using the real swarm coordinator.
|
/// Implements the coordination abstraction using the real swarm coordinator.
|
||||||
@ -44,8 +42,7 @@ impl SwarmCoordination for SwarmCoordinationAdapter {
|
|||||||
_required_expertise: Option<&str>,
|
_required_expertise: Option<&str>,
|
||||||
) -> anyhow::Result<AgentAssignment> {
|
) -> anyhow::Result<AgentAssignment> {
|
||||||
// For now, return a placeholder - real swarm selection would happen here
|
// For now, return a placeholder - real swarm selection would happen here
|
||||||
// This is a simplified version - full implementation would query
|
// This is a simplified version - full implementation would query swarm.submit_task_for_bidding()
|
||||||
// swarm.submit_task_for_bidding()
|
|
||||||
Ok(AgentAssignment {
|
Ok(AgentAssignment {
|
||||||
agent_id: "default-agent".to_string(),
|
agent_id: "default-agent".to_string(),
|
||||||
agent_name: "Default Agent".to_string(),
|
agent_name: "Default Agent".to_string(),
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
use chrono::{Duration, Utc};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{Duration, Utc};
|
|
||||||
use vapora_agents::{
|
use vapora_agents::{
|
||||||
AgentCoordinator, AgentMetadata, AgentRegistry, ExecutionData, ProfileAdapter,
|
AgentCoordinator, AgentMetadata, AgentRegistry, ExecutionData, ProfileAdapter,
|
||||||
TaskTypeExpertise,
|
TaskTypeExpertise,
|
||||||
|
|||||||
@ -247,8 +247,7 @@ fn test_confidence_prevents_overfitting() {
|
|||||||
|
|
||||||
let ranked = AgentScoringService::rank_agents(candidates, "coding", &learning_profiles);
|
let ranked = AgentScoringService::rank_agents(candidates, "coding", &learning_profiles);
|
||||||
|
|
||||||
// agent-exp should rank higher despite slightly lower expertise due to
|
// agent-exp should rank higher despite slightly lower expertise due to confidence weighting
|
||||||
// confidence weighting
|
|
||||||
assert_eq!(ranked[0].agent_id, "agent-exp");
|
assert_eq!(ranked[0].agent_id, "agent-exp");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +287,6 @@ fn test_multiple_task_types_independent() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_coordinator_assignment_with_learning_scores() {
|
async fn test_coordinator_assignment_with_learning_scores() {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use vapora_agents::{AgentCoordinator, AgentMetadata, AgentRegistry};
|
use vapora_agents::{AgentCoordinator, AgentMetadata, AgentRegistry};
|
||||||
|
|
||||||
// Create registry with test agents
|
// Create registry with test agents
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
// Integration tests for SwarmCoordinator integration with AgentCoordinator
|
// Integration tests for SwarmCoordinator integration with AgentCoordinator
|
||||||
// Tests verify swarm task assignment, profile synchronization, and metrics
|
// Tests verify swarm task assignment, profile synchronization, and metrics integration
|
||||||
// integration
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use vapora_agents::registry::AgentMetadata;
|
use vapora_agents::registry::AgentMetadata;
|
||||||
use vapora_agents::{AgentCoordinator, AgentRegistry, ProfileAdapter};
|
use vapora_agents::{AgentCoordinator, AgentRegistry, ProfileAdapter};
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
use std::collections::VecDeque;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::{Duration, Utc};
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use crate::error::{AnalyticsError, Result};
|
use crate::error::{AnalyticsError, Result};
|
||||||
use crate::events::*;
|
use crate::events::*;
|
||||||
|
use chrono::{Duration, Utc};
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Streaming pipeline for event processing
|
/// Streaming pipeline for event processing
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// Agents API endpoints
|
// Agents API endpoints
|
||||||
|
|
||||||
|
use crate::api::ApiResult;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -10,7 +11,6 @@ use serde::Deserialize;
|
|||||||
use vapora_shared::models::{Agent, AgentStatus};
|
use vapora_shared::models::{Agent, AgentStatus};
|
||||||
|
|
||||||
use crate::api::state::AppState;
|
use crate::api::state::AppState;
|
||||||
use crate::api::ApiResult;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct UpdateStatusPayload {
|
pub struct UpdateStatusPayload {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// Analytics API endpoints - KG analytics and insights
|
// Analytics API endpoints - KG analytics and insights
|
||||||
// Phase 6: REST endpoints for performance, cost, and learning analytics
|
// Phase 6: REST endpoints for performance, cost, and learning analytics
|
||||||
|
|
||||||
|
use crate::api::state::AppState;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -12,8 +13,6 @@ use vapora_knowledge_graph::{
|
|||||||
AgentPerformance, CostEfficiencyReport, DashboardMetrics, TaskTypeAnalytics,
|
AgentPerformance, CostEfficiencyReport, DashboardMetrics, TaskTypeAnalytics,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api::state::AppState;
|
|
||||||
|
|
||||||
/// Query parameters for analytics endpoints
|
/// Query parameters for analytics endpoints
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct AnalyticsQuery {
|
pub struct AnalyticsQuery {
|
||||||
@ -26,6 +25,7 @@ fn default_period() -> String {
|
|||||||
"week".to_string()
|
"week".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Analytics response wrapper
|
/// Analytics response wrapper
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct AnalyticsResponse<T> {
|
pub struct AnalyticsResponse<T> {
|
||||||
@ -73,8 +73,8 @@ pub async fn get_agent_performance(
|
|||||||
Path(agent_id): Path<String>,
|
Path(agent_id): Path<String>,
|
||||||
Query(_params): Query<AnalyticsQuery>,
|
Query(_params): Query<AnalyticsQuery>,
|
||||||
) -> Result<AnalyticsResponse<AgentPerformance>, AnalyticsError> {
|
) -> Result<AnalyticsResponse<AgentPerformance>, AnalyticsError> {
|
||||||
// For now, return a placeholder since AppState doesn't have KGAnalyticsService
|
// For now, return a placeholder since AppState doesn't have KGAnalyticsService yet
|
||||||
// yet In real implementation, we'd fetch from service
|
// In real implementation, we'd fetch from service
|
||||||
Err(AnalyticsError::NotFound(format!(
|
Err(AnalyticsError::NotFound(format!(
|
||||||
"Agent analytics service not yet initialized for {}",
|
"Agent analytics service not yet initialized for {}",
|
||||||
agent_id
|
agent_id
|
||||||
|
|||||||
@ -25,7 +25,6 @@ mod tests {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_health_endpoint() {
|
async fn test_health_endpoint() {
|
||||||
let response = health().await;
|
let response = health().await;
|
||||||
// Response type verification - actual testing will be in integration
|
// Response type verification - actual testing will be in integration tests
|
||||||
// tests
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
use vapora_knowledge_graph::{KGPersistence, TimePeriod};
|
use vapora_knowledge_graph::{KGPersistence, TimePeriod};
|
||||||
|
|||||||
@ -15,8 +15,7 @@ pub mod swarm;
|
|||||||
pub mod tasks;
|
pub mod tasks;
|
||||||
pub mod tracking;
|
pub mod tracking;
|
||||||
pub mod websocket;
|
pub mod websocket;
|
||||||
// pub mod workflows; // TODO: Phase 4 - Re-enable when workflow module imports
|
// pub mod workflows; // TODO: Phase 4 - Re-enable when workflow module imports are fixed
|
||||||
// are fixed
|
|
||||||
|
|
||||||
pub use error::ApiResult;
|
pub use error::ApiResult;
|
||||||
// pub use error::ApiError; // Temporarily commented - remove ApiError export
|
// pub use error::ApiError; // Temporarily commented - remove ApiError export
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// Projects API endpoints
|
// Projects API endpoints
|
||||||
|
|
||||||
|
use crate::api::ApiResult;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -9,7 +10,6 @@ use axum::{
|
|||||||
use vapora_shared::models::Project;
|
use vapora_shared::models::Project;
|
||||||
|
|
||||||
use crate::api::state::AppState;
|
use crate::api::state::AppState;
|
||||||
use crate::api::ApiResult;
|
|
||||||
|
|
||||||
/// List all projects for a tenant
|
/// List all projects for a tenant
|
||||||
///
|
///
|
||||||
|
|||||||
@ -85,14 +85,12 @@ pub struct TaskTypeMetricsResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers - Get cost breakdown by provider
|
/// GET /api/v1/analytics/providers - Get cost breakdown by provider
|
||||||
pub async fn get_provider_cost_breakdown(State(state): State<AppState>) -> impl IntoResponse {
|
pub async fn get_provider_cost_breakdown(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
debug!("GET /api/v1/analytics/providers - cost breakdown");
|
debug!("GET /api/v1/analytics/providers - cost breakdown");
|
||||||
|
|
||||||
match state
|
match state.provider_analytics_service.get_cost_breakdown_by_provider().await {
|
||||||
.provider_analytics_service
|
|
||||||
.get_cost_breakdown_by_provider()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(breakdown) => {
|
Ok(breakdown) => {
|
||||||
let total_cost: u32 = breakdown.values().sum();
|
let total_cost: u32 = breakdown.values().sum();
|
||||||
let mut providers: Vec<ProviderBreakdown> = breakdown
|
let mut providers: Vec<ProviderBreakdown> = breakdown
|
||||||
@ -139,14 +137,12 @@ pub async fn get_provider_cost_breakdown(State(state): State<AppState>) -> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/efficiency - Get provider efficiency ranking
|
/// GET /api/v1/analytics/providers/efficiency - Get provider efficiency ranking
|
||||||
pub async fn get_provider_efficiency(State(state): State<AppState>) -> impl IntoResponse {
|
pub async fn get_provider_efficiency(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
debug!("GET /api/v1/analytics/providers/efficiency");
|
debug!("GET /api/v1/analytics/providers/efficiency");
|
||||||
|
|
||||||
match state
|
match state.provider_analytics_service.get_provider_efficiency_ranking().await {
|
||||||
.provider_analytics_service
|
|
||||||
.get_provider_efficiency_ranking()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(efficiencies) => {
|
Ok(efficiencies) => {
|
||||||
let providers = efficiencies
|
let providers = efficiencies
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -184,37 +180,34 @@ pub async fn get_provider_efficiency(State(state): State<AppState>) -> impl Into
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider - Get detailed analytics for a
|
/// GET /api/v1/analytics/providers/:provider - Get detailed analytics for a provider
|
||||||
/// provider
|
|
||||||
pub async fn get_provider_analytics(
|
pub async fn get_provider_analytics(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(provider): Path<String>,
|
Path(provider): Path<String>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
debug!("GET /api/v1/analytics/providers/{} - analytics", provider);
|
debug!("GET /api/v1/analytics/providers/{} - analytics", provider);
|
||||||
|
|
||||||
match state
|
match state.provider_analytics_service.get_provider_analytics(&provider).await {
|
||||||
.provider_analytics_service
|
Ok(analytics) => {
|
||||||
.get_provider_analytics(&provider)
|
(
|
||||||
.await
|
StatusCode::OK,
|
||||||
{
|
Json(ProviderAnalyticsData {
|
||||||
Ok(analytics) => (
|
success: true,
|
||||||
StatusCode::OK,
|
provider: analytics.provider,
|
||||||
Json(ProviderAnalyticsData {
|
total_cost_cents: analytics.total_cost_cents,
|
||||||
success: true,
|
total_tasks: analytics.total_tasks,
|
||||||
provider: analytics.provider,
|
successful_tasks: analytics.successful_tasks,
|
||||||
total_cost_cents: analytics.total_cost_cents,
|
failed_tasks: analytics.failed_tasks,
|
||||||
total_tasks: analytics.total_tasks,
|
success_rate: analytics.success_rate,
|
||||||
successful_tasks: analytics.successful_tasks,
|
avg_cost_per_task_cents: analytics.avg_cost_per_task_cents,
|
||||||
failed_tasks: analytics.failed_tasks,
|
total_input_tokens: analytics.total_input_tokens,
|
||||||
success_rate: analytics.success_rate,
|
total_output_tokens: analytics.total_output_tokens,
|
||||||
avg_cost_per_task_cents: analytics.avg_cost_per_task_cents,
|
cost_per_1m_tokens: analytics.cost_per_1m_tokens,
|
||||||
total_input_tokens: analytics.total_input_tokens,
|
error: None,
|
||||||
total_output_tokens: analytics.total_output_tokens,
|
}),
|
||||||
cost_per_1m_tokens: analytics.cost_per_1m_tokens,
|
)
|
||||||
error: None,
|
.into_response()
|
||||||
}),
|
}
|
||||||
)
|
|
||||||
.into_response(),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get provider analytics: {}", e);
|
error!("Failed to get provider analytics: {}", e);
|
||||||
(
|
(
|
||||||
@ -239,33 +232,30 @@ pub async fn get_provider_analytics(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider/forecast - Get cost forecast for a
|
/// GET /api/v1/analytics/providers/:provider/forecast - Get cost forecast for a provider
|
||||||
/// provider
|
|
||||||
pub async fn get_provider_forecast(
|
pub async fn get_provider_forecast(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(provider): Path<String>,
|
Path(provider): Path<String>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
debug!("GET /api/v1/analytics/providers/{}/forecast", provider);
|
debug!("GET /api/v1/analytics/providers/{}/forecast", provider);
|
||||||
|
|
||||||
match state
|
match state.provider_analytics_service.forecast_provider_costs(&provider).await {
|
||||||
.provider_analytics_service
|
Ok(forecast) => {
|
||||||
.forecast_provider_costs(&provider)
|
(
|
||||||
.await
|
StatusCode::OK,
|
||||||
{
|
Json(ProviderCostForecastData {
|
||||||
Ok(forecast) => (
|
success: true,
|
||||||
StatusCode::OK,
|
provider: forecast.provider,
|
||||||
Json(ProviderCostForecastData {
|
current_daily_cost_cents: forecast.current_daily_cost_cents,
|
||||||
success: true,
|
projected_weekly_cost_cents: forecast.projected_weekly_cost_cents,
|
||||||
provider: forecast.provider,
|
projected_monthly_cost_cents: forecast.projected_monthly_cost_cents,
|
||||||
current_daily_cost_cents: forecast.current_daily_cost_cents,
|
trend: forecast.trend,
|
||||||
projected_weekly_cost_cents: forecast.projected_weekly_cost_cents,
|
confidence: forecast.confidence,
|
||||||
projected_monthly_cost_cents: forecast.projected_monthly_cost_cents,
|
error: None,
|
||||||
trend: forecast.trend,
|
}),
|
||||||
confidence: forecast.confidence,
|
)
|
||||||
error: None,
|
.into_response()
|
||||||
}),
|
}
|
||||||
)
|
|
||||||
.into_response(),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get provider forecast: {}", e);
|
error!("Failed to get provider forecast: {}", e);
|
||||||
(
|
(
|
||||||
@ -286,8 +276,7 @@ pub async fn get_provider_forecast(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider/tasks/:task_type - Provider
|
/// GET /api/v1/analytics/providers/:provider/tasks/:task_type - Provider performance by task type
|
||||||
/// performance by task type
|
|
||||||
pub async fn get_provider_task_type_metrics(
|
pub async fn get_provider_task_type_metrics(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path((provider, task_type)): Path<(String, String)>,
|
Path((provider, task_type)): Path<(String, String)>,
|
||||||
@ -302,20 +291,22 @@ pub async fn get_provider_task_type_metrics(
|
|||||||
.get_provider_task_type_metrics(&provider, &task_type)
|
.get_provider_task_type_metrics(&provider, &task_type)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(metrics) => (
|
Ok(metrics) => {
|
||||||
StatusCode::OK,
|
(
|
||||||
Json(TaskTypeMetricsResponse {
|
StatusCode::OK,
|
||||||
success: true,
|
Json(TaskTypeMetricsResponse {
|
||||||
provider: metrics.provider,
|
success: true,
|
||||||
task_type: metrics.task_type,
|
provider: metrics.provider,
|
||||||
total_cost_cents: metrics.total_cost_cents,
|
task_type: metrics.task_type,
|
||||||
task_count: metrics.task_count,
|
total_cost_cents: metrics.total_cost_cents,
|
||||||
success_rate: metrics.success_rate,
|
task_count: metrics.task_count,
|
||||||
avg_duration_ms: metrics.avg_duration_ms,
|
success_rate: metrics.success_rate,
|
||||||
error: None,
|
avg_duration_ms: metrics.avg_duration_ms,
|
||||||
}),
|
error: None,
|
||||||
)
|
}),
|
||||||
.into_response(),
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get task type metrics: {}", e);
|
error!("Failed to get task type metrics: {}", e);
|
||||||
(
|
(
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
// API state - Shared application state for Axum handlers
|
// API state - Shared application state for Axum handlers
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::services::{AgentService, ProjectService, ProviderAnalyticsService, TaskService};
|
use crate::services::{AgentService, ProjectService, ProviderAnalyticsService, TaskService};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Application state shared across all API handlers
|
/// Application state shared across all API handlers
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
// Swarm API endpoints for task coordination and agent management
|
// Swarm API endpoints for task coordination and agent management
|
||||||
// Phase 5.2: SwarmCoordinator integration with REST API
|
// Phase 5.2: SwarmCoordinator integration with REST API
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::Extension, http::StatusCode, response::IntoResponse, routing::get, Json, Router,
|
extract::Extension, http::StatusCode, response::IntoResponse, routing::get, Json, Router,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use vapora_swarm::coordinator::SwarmCoordinator;
|
use vapora_swarm::coordinator::SwarmCoordinator;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// Tasks API endpoints
|
// Tasks API endpoints
|
||||||
|
|
||||||
|
use crate::api::ApiResult;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -10,7 +11,6 @@ use serde::Deserialize;
|
|||||||
use vapora_shared::models::{Task, TaskPriority, TaskStatus};
|
use vapora_shared::models::{Task, TaskPriority, TaskStatus};
|
||||||
|
|
||||||
use crate::api::state::AppState;
|
use crate::api::state::AppState;
|
||||||
use crate::api::ApiResult;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct TaskQueryParams {
|
pub struct TaskQueryParams {
|
||||||
|
|||||||
@ -3,7 +3,12 @@
|
|||||||
//! Integrates vapora-tracking system with the main backend API,
|
//! Integrates vapora-tracking system with the main backend API,
|
||||||
//! providing unified access to project tracking data.
|
//! providing unified access to project tracking data.
|
||||||
|
|
||||||
use axum::{extract::Query, http::StatusCode, routing::get, Json, Router};
|
use axum::{
|
||||||
|
extract::Query,
|
||||||
|
http::StatusCode,
|
||||||
|
routing::get,
|
||||||
|
Json, Router,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// vapora-backend: Audit trail system
|
// vapora-backend: Audit trail system
|
||||||
// Phase 3: Track all workflow events and actions
|
// Phase 3: Track all workflow events and actions
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Configuration module for VAPORA Backend
|
// Configuration module for VAPORA Backend
|
||||||
// Loads config from vapora.toml with environment variable interpolation
|
// Loads config from vapora.toml with environment variable interpolation
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use vapora_shared::{Result, VaporaError};
|
use vapora_shared::{Result, VaporaError};
|
||||||
|
|
||||||
/// Main configuration structure
|
/// Main configuration structure
|
||||||
@ -72,8 +71,7 @@ pub struct MetricsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Load configuration from a TOML file with environment variable
|
/// Load configuration from a TOML file with environment variable interpolation
|
||||||
/// interpolation
|
|
||||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
|
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
|||||||
@ -7,14 +7,13 @@ mod config;
|
|||||||
mod services;
|
mod services;
|
||||||
mod workflow;
|
mod workflow;
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{
|
use axum::{
|
||||||
routing::{delete, get, post, put},
|
routing::{delete, get, post, put},
|
||||||
Extension, Router,
|
Extension, Router,
|
||||||
};
|
};
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::sync::Arc;
|
||||||
use tower_http::cors::{Any, CorsLayer};
|
use tower_http::cors::{Any, CorsLayer};
|
||||||
use tracing::{info, Level};
|
use tracing::{info, Level};
|
||||||
use vapora_swarm::{SwarmCoordinator, SwarmMetrics};
|
use vapora_swarm::{SwarmCoordinator, SwarmMetrics};
|
||||||
@ -68,12 +67,7 @@ async fn main() -> Result<()> {
|
|||||||
let kg_persistence = Arc::new(vapora_knowledge_graph::KGPersistence::new(db.clone()));
|
let kg_persistence = Arc::new(vapora_knowledge_graph::KGPersistence::new(db.clone()));
|
||||||
|
|
||||||
// Create application state
|
// Create application state
|
||||||
let app_state = AppState::new(
|
let app_state = AppState::new(project_service, task_service, agent_service, provider_analytics_service);
|
||||||
project_service,
|
|
||||||
task_service,
|
|
||||||
agent_service,
|
|
||||||
provider_analytics_service,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create SwarmMetrics for Prometheus monitoring
|
// Create SwarmMetrics for Prometheus monitoring
|
||||||
let metrics = match SwarmMetrics::new() {
|
let metrics = match SwarmMetrics::new() {
|
||||||
|
|||||||
@ -241,9 +241,8 @@ impl AgentService {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB
|
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
||||||
// instance or mocking. For Phase 1, we'll add integration tests that use a
|
// or mocking. For Phase 1, we'll add integration tests that use a test database.
|
||||||
// test database.
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_agent_service_creation() {
|
fn test_agent_service_creation() {
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
// Phase 6: REST API analytics endpoints
|
// Phase 6: REST API analytics endpoints
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use surrealdb::engine::remote::ws::Client;
|
use surrealdb::engine::remote::ws::Client;
|
||||||
use surrealdb::Surreal;
|
use surrealdb::Surreal;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|||||||
@ -63,10 +63,7 @@ impl ProjectService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query(
|
.query("SELECT * FROM projects WHERE tenant_id = $tenant_id AND status = $status ORDER BY created_at DESC")
|
||||||
"SELECT * FROM projects WHERE tenant_id = $tenant_id AND status = $status ORDER \
|
|
||||||
BY created_at DESC",
|
|
||||||
)
|
|
||||||
.bind(("tenant_id", tenant_id.to_string()))
|
.bind(("tenant_id", tenant_id.to_string()))
|
||||||
.bind(("status", status_str.to_string()))
|
.bind(("status", status_str.to_string()))
|
||||||
.await?;
|
.await?;
|
||||||
@ -196,13 +193,11 @@ impl ProjectService {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
use vapora_shared::models::ProjectStatus;
|
use vapora_shared::models::ProjectStatus;
|
||||||
|
|
||||||
use super::*;
|
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
||||||
|
// or mocking. For Phase 1, we'll add integration tests that use a test database.
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB
|
|
||||||
// instance or mocking. For Phase 1, we'll add integration tests that use a
|
|
||||||
// test database.
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_project_service_creation() {
|
fn test_project_service_creation() {
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
// Analyzes provider costs, efficiency, and performance
|
// Analyzes provider costs, efficiency, and performance
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use surrealdb::engine::remote::ws::Client;
|
use surrealdb::engine::remote::ws::Client;
|
||||||
use surrealdb::Surreal;
|
use surrealdb::Surreal;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use vapora_knowledge_graph::models::{
|
use vapora_knowledge_graph::models::{
|
||||||
ProviderAnalytics, ProviderCostForecast, ProviderEfficiency, ProviderTaskTypeMetrics,
|
ProviderAnalytics, ProviderEfficiency, ProviderTaskTypeMetrics, ProviderCostForecast,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -23,10 +22,7 @@ impl ProviderAnalyticsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get analytics for a specific provider
|
/// Get analytics for a specific provider
|
||||||
pub async fn get_provider_analytics(
|
pub async fn get_provider_analytics(&self, provider: &str) -> anyhow::Result<ProviderAnalytics> {
|
||||||
&self,
|
|
||||||
provider: &str,
|
|
||||||
) -> anyhow::Result<ProviderAnalytics> {
|
|
||||||
debug!("Querying analytics for provider: {}", provider);
|
debug!("Querying analytics for provider: {}", provider);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
@ -156,8 +152,7 @@ impl ProviderAnalyticsService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
efficiency_scores
|
efficiency_scores.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
|
||||||
.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
|
|
||||||
|
|
||||||
let result: Vec<ProviderEfficiency> = efficiency_scores
|
let result: Vec<ProviderEfficiency> = efficiency_scores
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -236,10 +231,7 @@ impl ProviderAnalyticsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get cost forecast for a provider
|
/// Get cost forecast for a provider
|
||||||
pub async fn forecast_provider_costs(
|
pub async fn forecast_provider_costs(&self, provider: &str) -> anyhow::Result<ProviderCostForecast> {
|
||||||
&self,
|
|
||||||
provider: &str,
|
|
||||||
) -> anyhow::Result<ProviderCostForecast> {
|
|
||||||
debug!("Forecasting costs for provider: {}", provider);
|
debug!("Forecasting costs for provider: {}", provider);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
@ -306,8 +298,9 @@ impl ProviderAnalyticsService {
|
|||||||
let projected_monthly_cost_cents = (avg_daily_cost * 30.0) as u32;
|
let projected_monthly_cost_cents = (avg_daily_cost * 30.0) as u32;
|
||||||
|
|
||||||
let trend = if daily_costs.len() >= 2 {
|
let trend = if daily_costs.len() >= 2 {
|
||||||
let recent_avg = daily_costs[0..daily_costs.len().min(5)].iter().sum::<u32>() as f64
|
let recent_avg =
|
||||||
/ daily_costs[0..daily_costs.len().min(5)].len() as f64;
|
daily_costs[0..daily_costs.len().min(5)].iter().sum::<u32>() as f64
|
||||||
|
/ daily_costs[0..daily_costs.len().min(5)].len() as f64;
|
||||||
let older_avg = daily_costs[daily_costs.len().min(5)..].iter().sum::<u32>() as f64
|
let older_avg = daily_costs[daily_costs.len().min(5)..].iter().sum::<u32>() as f64
|
||||||
/ daily_costs[daily_costs.len().min(5)..].len().max(1) as f64;
|
/ daily_costs[daily_costs.len().min(5)..].len().max(1) as f64;
|
||||||
|
|
||||||
@ -351,10 +344,10 @@ impl ProviderAnalyticsService {
|
|||||||
|
|
||||||
for record in response.iter() {
|
for record in response.iter() {
|
||||||
if let Some(obj) = record.as_object() {
|
if let Some(obj) = record.as_object() {
|
||||||
if let (Some(provider), Some(cost)) = (
|
if let (Some(provider), Some(cost)) =
|
||||||
obj.get("provider").and_then(|v| v.as_str()),
|
(obj.get("provider").and_then(|v| v.as_str()),
|
||||||
obj.get("cost_cents").and_then(|v| v.as_u64()),
|
obj.get("cost_cents").and_then(|v| v.as_u64()))
|
||||||
) {
|
{
|
||||||
*breakdown.entry(provider.to_string()).or_insert(0) += cost as u32;
|
*breakdown.entry(provider.to_string()).or_insert(0) += cost as u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,11 +369,11 @@ impl ProviderAnalyticsService {
|
|||||||
|
|
||||||
for record in response.iter() {
|
for record in response.iter() {
|
||||||
if let Some(obj) = record.as_object() {
|
if let Some(obj) = record.as_object() {
|
||||||
if let (Some(provider), Some(task_type), Some(cost)) = (
|
if let (Some(provider), Some(task_type), Some(cost)) =
|
||||||
obj.get("provider").and_then(|v| v.as_str()),
|
(obj.get("provider").and_then(|v| v.as_str()),
|
||||||
obj.get("task_type").and_then(|v| v.as_str()),
|
obj.get("task_type").and_then(|v| v.as_str()),
|
||||||
obj.get("cost_cents").and_then(|v| v.as_u64()),
|
obj.get("cost_cents").and_then(|v| v.as_u64()))
|
||||||
) {
|
{
|
||||||
breakdown
|
breakdown
|
||||||
.entry(provider.to_string())
|
.entry(provider.to_string())
|
||||||
.or_default()
|
.or_default()
|
||||||
|
|||||||
@ -49,10 +49,7 @@ impl TaskService {
|
|||||||
pub async fn list_tasks(&self, project_id: &str, tenant_id: &str) -> Result<Vec<Task>> {
|
pub async fn list_tasks(&self, project_id: &str, tenant_id: &str) -> Result<Vec<Task>> {
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query(
|
.query("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id ORDER BY task_order ASC")
|
||||||
"SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id \
|
|
||||||
ORDER BY task_order ASC",
|
|
||||||
)
|
|
||||||
.bind(("project_id", project_id.to_string()))
|
.bind(("project_id", project_id.to_string()))
|
||||||
.bind(("tenant_id", tenant_id.to_string()))
|
.bind(("tenant_id", tenant_id.to_string()))
|
||||||
.await?;
|
.await?;
|
||||||
@ -77,10 +74,7 @@ impl TaskService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query(
|
.query("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id AND status = $status ORDER BY task_order ASC")
|
||||||
"SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id \
|
|
||||||
AND status = $status ORDER BY task_order ASC",
|
|
||||||
)
|
|
||||||
.bind(("project_id", project_id.to_string()))
|
.bind(("project_id", project_id.to_string()))
|
||||||
.bind(("tenant_id", tenant_id.to_string()))
|
.bind(("tenant_id", tenant_id.to_string()))
|
||||||
.bind(("status", status_str.to_string()))
|
.bind(("status", status_str.to_string()))
|
||||||
@ -99,10 +93,7 @@ impl TaskService {
|
|||||||
) -> Result<Vec<Task>> {
|
) -> Result<Vec<Task>> {
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query(
|
.query("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id AND assignee = $assignee ORDER BY priority DESC, task_order ASC")
|
||||||
"SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id \
|
|
||||||
AND assignee = $assignee ORDER BY priority DESC, task_order ASC",
|
|
||||||
)
|
|
||||||
.bind(("project_id", project_id.to_string()))
|
.bind(("project_id", project_id.to_string()))
|
||||||
.bind(("tenant_id", tenant_id.to_string()))
|
.bind(("tenant_id", tenant_id.to_string()))
|
||||||
.bind(("assignee", assignee.to_string()))
|
.bind(("assignee", assignee.to_string()))
|
||||||
@ -266,10 +257,7 @@ impl TaskService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query(
|
.query("SELECT VALUE task_order FROM tasks WHERE project_id = $project_id AND status = $status ORDER BY task_order DESC LIMIT 1")
|
||||||
"SELECT VALUE task_order FROM tasks WHERE project_id = $project_id AND status = \
|
|
||||||
$status ORDER BY task_order DESC LIMIT 1",
|
|
||||||
)
|
|
||||||
.bind(("project_id", project_id.to_string()))
|
.bind(("project_id", project_id.to_string()))
|
||||||
.bind(("status", status_str.to_string()))
|
.bind(("status", status_str.to_string()))
|
||||||
.await?;
|
.await?;
|
||||||
@ -283,9 +271,8 @@ impl TaskService {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB
|
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
||||||
// instance or mocking. For Phase 1, we'll add integration tests that use a
|
// or mocking. For Phase 1, we'll add integration tests that use a test database.
|
||||||
// test database.
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_task_service_creation() {
|
fn test_task_service_creation() {
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
// vapora-backend: Workflow service
|
// vapora-backend: Workflow service
|
||||||
// Phase 3: Service layer for workflow management
|
// Phase 3: Service layer for workflow management
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
use tracing::{error, info};
|
|
||||||
|
|
||||||
use crate::api::websocket::{WorkflowBroadcaster, WorkflowUpdate};
|
use crate::api::websocket::{WorkflowBroadcaster, WorkflowUpdate};
|
||||||
use crate::audit::{events, AuditEntry, AuditTrail};
|
use crate::audit::{events, AuditEntry, AuditTrail};
|
||||||
use crate::workflow::{EngineError, Workflow, WorkflowEngine};
|
use crate::workflow::{EngineError, Workflow, WorkflowEngine};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WorkflowServiceError {
|
pub enum WorkflowServiceError {
|
||||||
@ -217,17 +215,16 @@ impl WorkflowService {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use vapora_agents::{
|
|
||||||
config::{AgentConfig, RegistryConfig},
|
|
||||||
coordinator::AgentCoordinator,
|
|
||||||
registry::AgentRegistry,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::workflow::{
|
use crate::workflow::{
|
||||||
executor::StepExecutor,
|
executor::StepExecutor,
|
||||||
state::{Phase, StepStatus, WorkflowStep},
|
state::{Phase, StepStatus, WorkflowStep},
|
||||||
};
|
};
|
||||||
|
use vapora_agents::{
|
||||||
|
config::{AgentConfig, RegistryConfig},
|
||||||
|
coordinator::AgentCoordinator,
|
||||||
|
registry::AgentRegistry,
|
||||||
|
};
|
||||||
|
|
||||||
fn create_test_workflow() -> Workflow {
|
fn create_test_workflow() -> Workflow {
|
||||||
Workflow::new(
|
Workflow::new(
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
// vapora-backend: Workflow engine
|
// vapora-backend: Workflow engine
|
||||||
// Phase 3: Orchestrate workflow execution with state management
|
// Phase 3: Orchestrate workflow execution with state management
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
use tokio::sync::RwLock;
|
|
||||||
use tracing::{debug, error, info, warn};
|
|
||||||
|
|
||||||
use crate::workflow::executor::{ExecutorError, StepExecutor};
|
use crate::workflow::executor::{ExecutorError, StepExecutor};
|
||||||
use crate::workflow::scheduler::{Scheduler, SchedulerError};
|
use crate::workflow::scheduler::{Scheduler, SchedulerError};
|
||||||
use crate::workflow::state::{StepStatus, Workflow, WorkflowStatus};
|
use crate::workflow::state::{StepStatus, Workflow, WorkflowStatus};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -355,13 +353,12 @@ impl WorkflowEngine {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::workflow::state::{Phase, WorkflowStep};
|
||||||
use vapora_agents::config::{AgentConfig, RegistryConfig};
|
use vapora_agents::config::{AgentConfig, RegistryConfig};
|
||||||
use vapora_agents::coordinator::AgentCoordinator;
|
use vapora_agents::coordinator::AgentCoordinator;
|
||||||
use vapora_agents::registry::AgentRegistry;
|
use vapora_agents::registry::AgentRegistry;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::workflow::state::{Phase, WorkflowStep};
|
|
||||||
|
|
||||||
fn create_test_workflow() -> Workflow {
|
fn create_test_workflow() -> Workflow {
|
||||||
Workflow::new(
|
Workflow::new(
|
||||||
"test-wf-1".to_string(),
|
"test-wf-1".to_string(),
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
// vapora-backend: Workflow step executor
|
// vapora-backend: Workflow step executor
|
||||||
// Phase 3: Execute workflow steps with agent coordination
|
// Phase 3: Execute workflow steps with agent coordination
|
||||||
|
|
||||||
use std::sync::Arc;
|
use crate::workflow::state::{StepStatus, WorkflowStep};
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
use vapora_agents::coordinator::AgentCoordinator;
|
use vapora_agents::coordinator::AgentCoordinator;
|
||||||
|
|
||||||
use crate::workflow::state::{StepStatus, WorkflowStep};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum ExecutorError {
|
pub enum ExecutorError {
|
||||||
@ -162,11 +160,10 @@ impl StepExecutor {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
use vapora_agents::config::{AgentConfig, RegistryConfig};
|
use vapora_agents::config::{AgentConfig, RegistryConfig};
|
||||||
use vapora_agents::registry::AgentRegistry;
|
use vapora_agents::registry::AgentRegistry;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn create_test_step(id: &str, role: &str) -> WorkflowStep {
|
fn create_test_step(id: &str, role: &str) -> WorkflowStep {
|
||||||
WorkflowStep {
|
WorkflowStep {
|
||||||
id: id.to_string(),
|
id: id.to_string(),
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
// vapora-backend: Workflow YAML parser
|
// vapora-backend: Workflow YAML parser
|
||||||
// Phase 3: Parse workflow definitions from YAML
|
// Phase 3: Parse workflow definitions from YAML
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use crate::workflow::state::{Phase, StepStatus, Workflow, WorkflowStep};
|
use crate::workflow::state::{Phase, StepStatus, Workflow, WorkflowStep};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ParserError {
|
pub enum ParserError {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
// vapora-backend: Workflow dependency scheduler
|
// vapora-backend: Workflow dependency scheduler
|
||||||
// Phase 3: Topological sort for dependency resolution and parallel execution
|
// Phase 3: Topological sort for dependency resolution and parallel execution
|
||||||
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
use crate::workflow::state::WorkflowStep;
|
use crate::workflow::state::WorkflowStep;
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum SchedulerError {
|
pub enum SchedulerError {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod provider_analytics_tests {
|
mod provider_analytics_tests {
|
||||||
use vapora_knowledge_graph::models::{
|
use vapora_knowledge_graph::models::{
|
||||||
ProviderAnalytics, ProviderCostForecast, ProviderEfficiency, ProviderTaskTypeMetrics,
|
ProviderAnalytics, ProviderEfficiency, ProviderTaskTypeMetrics, ProviderCostForecast,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -123,9 +123,7 @@ mod provider_analytics_tests {
|
|||||||
|
|
||||||
// Verify reasonable projections (weekly should be ~7x daily)
|
// Verify reasonable projections (weekly should be ~7x daily)
|
||||||
let expected_weekly = forecast.current_daily_cost_cents as u32 * 7;
|
let expected_weekly = forecast.current_daily_cost_cents as u32 * 7;
|
||||||
assert!(
|
assert!((forecast.projected_weekly_cost_cents as i32 - expected_weekly as i32).abs() <= 100);
|
||||||
(forecast.projected_weekly_cost_cents as i32 - expected_weekly as i32).abs() <= 100
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -199,7 +197,7 @@ mod provider_analytics_tests {
|
|||||||
let high_quality_high_cost = ProviderEfficiency {
|
let high_quality_high_cost = ProviderEfficiency {
|
||||||
provider: "claude".to_string(),
|
provider: "claude".to_string(),
|
||||||
quality_score: 0.95,
|
quality_score: 0.95,
|
||||||
cost_score: 0.5, // Lower score because expensive
|
cost_score: 0.5, // Lower score because expensive
|
||||||
efficiency_ratio: 0.475, // 0.95 * 0.5
|
efficiency_ratio: 0.475, // 0.95 * 0.5
|
||||||
rank: 1,
|
rank: 1,
|
||||||
};
|
};
|
||||||
@ -208,7 +206,7 @@ mod provider_analytics_tests {
|
|||||||
let low_quality_low_cost = ProviderEfficiency {
|
let low_quality_low_cost = ProviderEfficiency {
|
||||||
provider: "ollama".to_string(),
|
provider: "ollama".to_string(),
|
||||||
quality_score: 0.7,
|
quality_score: 0.7,
|
||||||
cost_score: 0.95, // Higher score because cheap
|
cost_score: 0.95, // Higher score because cheap
|
||||||
efficiency_ratio: 0.665, // 0.7 * 0.95
|
efficiency_ratio: 0.665, // 0.7 * 0.95
|
||||||
rank: 1,
|
rank: 1,
|
||||||
};
|
};
|
||||||
@ -469,9 +467,7 @@ mod provider_analytics_tests {
|
|||||||
|
|
||||||
// Even though unstable provider is cheaper per task,
|
// Even though unstable provider is cheaper per task,
|
||||||
// reliability matters for efficiency
|
// reliability matters for efficiency
|
||||||
assert!(
|
assert!(failing_provider.avg_cost_per_task_cents < reliable_provider.avg_cost_per_task_cents);
|
||||||
failing_provider.avg_cost_per_task_cents < reliable_provider.avg_cost_per_task_cents
|
|
||||||
);
|
|
||||||
assert!(failing_provider.success_rate < reliable_provider.success_rate);
|
assert!(failing_provider.success_rate < reliable_provider.success_rate);
|
||||||
|
|
||||||
// Quality score should reflect reliability
|
// Quality score should reflect reliability
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
// Tests verify swarm statistics and health monitoring endpoints
|
// Tests verify swarm statistics and health monitoring endpoints
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use vapora_swarm::{AgentProfile, SwarmCoordinator};
|
use vapora_swarm::{AgentProfile, SwarmCoordinator};
|
||||||
|
|
||||||
/// Helper to create a test agent profile
|
/// Helper to create a test agent profile
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
// Tests the complete workflow system end-to-end
|
// Tests the complete workflow system end-to-end
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use vapora_agents::{
|
use vapora_agents::{
|
||||||
config::{AgentConfig, RegistryConfig},
|
config::{AgentConfig, RegistryConfig},
|
||||||
coordinator::AgentCoordinator,
|
coordinator::AgentCoordinator,
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
// API client module for VAPORA frontend
|
// API client module for VAPORA frontend
|
||||||
// Handles all HTTP communication with backend
|
// Handles all HTTP communication with backend
|
||||||
|
|
||||||
|
use crate::config::AppConfig;
|
||||||
use gloo_net::http::Request;
|
use gloo_net::http::Request;
|
||||||
|
|
||||||
// Re-export types from vapora-shared
|
// Re-export types from vapora-shared
|
||||||
pub use vapora_shared::models::{Agent, Project, Task, TaskPriority, TaskStatus, Workflow};
|
pub use vapora_shared::models::{Agent, Project, Task, TaskPriority, TaskStatus, Workflow};
|
||||||
|
|
||||||
use crate::config::AppConfig;
|
|
||||||
|
|
||||||
/// API client for backend communication
|
/// API client for backend communication
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ApiClient {
|
pub struct ApiClient {
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
// Main Kanban board component
|
// Main Kanban board component
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
use leptos::task::spawn_local;
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::api::{ApiClient, Task, TaskStatus};
|
use crate::api::{ApiClient, Task, TaskStatus};
|
||||||
use crate::components::KanbanColumn;
|
use crate::components::KanbanColumn;
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos::task::spawn_local;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
/// Main Kanban board component
|
/// Main Kanban board component
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Kanban column component with drag & drop support
|
// Kanban column component with drag & drop support
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
|
|
||||||
use crate::api::Task;
|
use crate::api::Task;
|
||||||
use crate::components::TaskCard;
|
use crate::components::TaskCard;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
/// Kanban column component
|
/// Kanban column component
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
// Task card component for Kanban board
|
// Task card component for Kanban board
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
|
|
||||||
use crate::api::{Task, TaskPriority};
|
use crate::api::{Task, TaskPriority};
|
||||||
use crate::components::Badge;
|
use crate::components::Badge;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
/// Task card component with drag support
|
/// Task card component with drag support
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -12,10 +12,7 @@ pub fn Button(
|
|||||||
#[prop(default = "")] class: &'static str,
|
#[prop(default = "")] class: &'static str,
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let default_class = "px-4 py-2 rounded-lg bg-gradient-to-r from-cyan-500/90 to-cyan-600/90 \
|
let default_class = "px-4 py-2 rounded-lg bg-gradient-to-r from-cyan-500/90 to-cyan-600/90 text-white font-medium transition-all duration-300 hover:from-cyan-400/90 hover:to-cyan-500/90 hover:shadow-lg hover:shadow-cyan-500/50 disabled:opacity-50 disabled:cursor-not-allowed";
|
||||||
text-white font-medium transition-all duration-300 \
|
|
||||||
hover:from-cyan-400/90 hover:to-cyan-500/90 hover:shadow-lg \
|
|
||||||
hover:shadow-cyan-500/50 disabled:opacity-50 disabled:cursor-not-allowed";
|
|
||||||
|
|
||||||
let final_class = format!("{} {}", default_class, class);
|
let final_class = format!("{} {}", default_class, class);
|
||||||
|
|
||||||
|
|||||||
@ -48,8 +48,7 @@ pub fn Card(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hover_class = if hover_effect {
|
let hover_class = if hover_effect {
|
||||||
"hover:border-cyan-400/70 hover:shadow-cyan-500/50 transition-all duration-300 \
|
"hover:border-cyan-400/70 hover:shadow-cyan-500/50 transition-all duration-300 cursor-pointer"
|
||||||
cursor-pointer"
|
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,9 +16,7 @@ pub fn Input(
|
|||||||
let value_signal: Signal<String> = value.unwrap_or_else(|| internal_value.into());
|
let value_signal: Signal<String> = value.unwrap_or_else(|| internal_value.into());
|
||||||
|
|
||||||
let combined_class = format!(
|
let combined_class = format!(
|
||||||
"w-full px-4 py-2 bg-white/10 border border-white/20 rounded-lg text-white \
|
"w-full px-4 py-2 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-cyan-400/70 focus:shadow-lg focus:shadow-cyan-500/30 transition-all duration-200 {}",
|
||||||
placeholder-white/50 focus:outline-none focus:border-cyan-400/70 focus:shadow-lg \
|
|
||||||
focus:shadow-cyan-500/30 transition-all duration-200 {}",
|
|
||||||
class
|
class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
// Agents marketplace page
|
// Agents marketplace page
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
use leptos::task::spawn_local;
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::api::{Agent, ApiClient};
|
use crate::api::{Agent, ApiClient};
|
||||||
use crate::components::{Badge, Button, Card, GlowColor, NavBar};
|
use crate::components::{Badge, Button, Card, GlowColor, NavBar};
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos::task::spawn_local;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
/// Agents marketplace page
|
/// Agents marketplace page
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Home page / landing page
|
// Home page / landing page
|
||||||
|
|
||||||
|
use crate::components::{Card, GlowColor, NavBar};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_router::components::A;
|
use leptos_router::components::A;
|
||||||
|
|
||||||
use crate::components::{Card, GlowColor, NavBar};
|
|
||||||
|
|
||||||
/// Home page component
|
/// Home page component
|
||||||
#[component]
|
#[component]
|
||||||
pub fn HomePage() -> impl IntoView {
|
pub fn HomePage() -> impl IntoView {
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// 404 Not Found page
|
// 404 Not Found page
|
||||||
|
|
||||||
|
use crate::components::NavBar;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_router::components::A;
|
use leptos_router::components::A;
|
||||||
|
|
||||||
use crate::components::NavBar;
|
|
||||||
|
|
||||||
/// 404 Not Found page
|
/// 404 Not Found page
|
||||||
#[component]
|
#[component]
|
||||||
pub fn NotFoundPage() -> impl IntoView {
|
pub fn NotFoundPage() -> impl IntoView {
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Project detail page with Kanban board
|
// Project detail page with Kanban board
|
||||||
|
|
||||||
|
use crate::components::{KanbanBoard, NavBar};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_router::hooks::use_params_map;
|
use leptos_router::hooks::use_params_map;
|
||||||
|
|
||||||
use crate::components::{KanbanBoard, NavBar};
|
|
||||||
|
|
||||||
/// Project detail page showing Kanban board
|
/// Project detail page showing Kanban board
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ProjectDetailPage() -> impl IntoView {
|
pub fn ProjectDetailPage() -> impl IntoView {
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
// Projects list page
|
// Projects list page
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
use leptos::task::spawn_local;
|
|
||||||
use leptos_router::components::A;
|
|
||||||
use log::warn;
|
|
||||||
|
|
||||||
use crate::api::{ApiClient, Project};
|
use crate::api::{ApiClient, Project};
|
||||||
use crate::components::{Badge, Button, Card, NavBar};
|
use crate::components::{Badge, Button, Card, NavBar};
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos::task::spawn_local;
|
||||||
|
use leptos_router::components::A;
|
||||||
|
use log::warn;
|
||||||
|
|
||||||
/// Projects list page
|
/// Projects list page
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
// Workflows page (placeholder for Phase 4)
|
// Workflows page (placeholder for Phase 4)
|
||||||
|
|
||||||
use leptos::prelude::*;
|
|
||||||
|
|
||||||
use crate::components::NavBar;
|
use crate::components::NavBar;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
|
||||||
/// Workflows page (to be implemented in Phase 4)
|
/// Workflows page (to be implemented in Phase 4)
|
||||||
#[component]
|
#[component]
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// vapora-knowledge-graph: Analytics module for KG insights
|
// vapora-knowledge-graph: Analytics module for KG insights
|
||||||
// Phase 5.5: Advanced persistence analytics, reporting, and trends
|
// Phase 5.5: Advanced persistence analytics, reporting, and trends
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
||||||
use crate::persistence::PersistedExecution;
|
use crate::persistence::PersistedExecution;
|
||||||
@ -407,9 +406,8 @@ impl KGAnalytics {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
fn create_test_execution(
|
fn create_test_execution(
|
||||||
agent_id: &str,
|
agent_id: &str,
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Execution record interface for learning calculations.
|
/// Execution record interface for learning calculations.
|
||||||
/// Implementations should provide timestamp and success flag.
|
/// Implementations should provide timestamp and success flag.
|
||||||
@ -12,8 +11,7 @@ pub trait ExecutionRecord: Send + Sync {
|
|||||||
|
|
||||||
/// Calculate learning curve as time-series of expertise evolution.
|
/// Calculate learning curve as time-series of expertise evolution.
|
||||||
/// Groups executions into daily windows and computes success rate per window.
|
/// Groups executions into daily windows and computes success rate per window.
|
||||||
/// Returns sorted Vec<(timestamp, success_rate)> where timestamp is start of
|
/// Returns sorted Vec<(timestamp, success_rate)> where timestamp is start of day.
|
||||||
/// day.
|
|
||||||
pub fn calculate_learning_curve(
|
pub fn calculate_learning_curve(
|
||||||
executions: Vec<impl ExecutionRecord>,
|
executions: Vec<impl ExecutionRecord>,
|
||||||
window_days: u32,
|
window_days: u32,
|
||||||
@ -43,11 +41,10 @@ pub fn calculate_learning_curve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Apply recency bias weighting to execution records.
|
/// Apply recency bias weighting to execution records.
|
||||||
/// Recent performance (last 7 days) weighted 3x higher than historical
|
/// Recent performance (last 7 days) weighted 3x higher than historical averages.
|
||||||
/// averages. Returns weighted success rate accounting for time decay.
|
/// Returns weighted success rate accounting for time decay.
|
||||||
///
|
///
|
||||||
/// Formula: weight = 3.0 * e^(-days_ago / 7.0) for days_ago < 7, else
|
/// Formula: weight = 3.0 * e^(-days_ago / 7.0) for days_ago < 7, else e^(-days_ago / 7.0)
|
||||||
/// e^(-days_ago / 7.0)
|
|
||||||
pub fn apply_recency_bias(executions: Vec<impl ExecutionRecord>, decay_days: u32) -> f64 {
|
pub fn apply_recency_bias(executions: Vec<impl ExecutionRecord>, decay_days: u32) -> f64 {
|
||||||
if executions.is_empty() {
|
if executions.is_empty() {
|
||||||
return 0.5;
|
return 0.5;
|
||||||
@ -118,8 +115,7 @@ fn align_to_window(timestamp: DateTime<Utc>, window_days: u32) -> DateTime<Utc>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate task-specific success metrics with confidence bounds.
|
/// Calculate task-specific success metrics with confidence bounds.
|
||||||
/// Returns (success_rate, confidence_score) where confidence reflects execution
|
/// Returns (success_rate, confidence_score) where confidence reflects execution count.
|
||||||
/// count.
|
|
||||||
pub fn calculate_task_type_metrics(
|
pub fn calculate_task_type_metrics(
|
||||||
executions: Vec<impl ExecutionRecord>,
|
executions: Vec<impl ExecutionRecord>,
|
||||||
min_executions_for_confidence: u32,
|
min_executions_for_confidence: u32,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// Metrics computation trait for breaking persistence ↔ analytics circular
|
// Metrics computation trait for breaking persistence ↔ analytics circular dependency
|
||||||
// dependency Phase 5.5: Abstraction layer for analytics computations
|
// Phase 5.5: Abstraction layer for analytics computations
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
@ -38,8 +38,7 @@ impl TimePeriod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Abstraction for computing analytics metrics from execution data.
|
/// Abstraction for computing analytics metrics from execution data.
|
||||||
/// Breaks the persistence ↔ analytics circular dependency by inverting control
|
/// Breaks the persistence ↔ analytics circular dependency by inverting control flow.
|
||||||
/// flow.
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AnalyticsComputation: Send + Sync {
|
pub trait AnalyticsComputation: Send + Sync {
|
||||||
/// Compute agent performance metrics for a time period.
|
/// Compute agent performance metrics for a time period.
|
||||||
|
|||||||
@ -1,17 +1,14 @@
|
|||||||
// KG Persistence Layer
|
// KG Persistence Layer
|
||||||
// Phase 5.5: Persist execution history to SurrealDB for durability and
|
// Phase 5.5: Persist execution history to SurrealDB for durability and analytics
|
||||||
// analytics
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::Utc;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use surrealdb::engine::remote::ws::Client;
|
|
||||||
use surrealdb::Surreal;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
||||||
use crate::models::ExecutionRecord;
|
use crate::models::ExecutionRecord;
|
||||||
|
use chrono::Utc;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use surrealdb::engine::remote::ws::Client;
|
||||||
|
use surrealdb::Surreal;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PersistedExecution {
|
pub struct PersistedExecution {
|
||||||
@ -156,9 +153,7 @@ impl KGPersistence {
|
|||||||
debug!("Fetching success rate for agent {}", agent_id);
|
debug!("Fetching success rate for agent {}", agent_id);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
"SELECT count(SELECT outcome FROM kg_executions WHERE outcome = 'success' AND \
|
"SELECT count(SELECT outcome FROM kg_executions WHERE outcome = 'success' AND agent_id = '{}') * 100.0 / count(SELECT * FROM kg_executions WHERE agent_id = '{}') AS rate FROM kg_executions",
|
||||||
agent_id = '{}') * 100.0 / count(SELECT * FROM kg_executions WHERE agent_id = '{}') \
|
|
||||||
AS rate FROM kg_executions",
|
|
||||||
agent_id, agent_id
|
agent_id, agent_id
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -236,8 +231,7 @@ impl KGPersistence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get task-type specific executions for agent (for learning profiles).
|
/// Get task-type specific executions for agent (for learning profiles).
|
||||||
/// Returns executions filtered by agent_id and task_type, limited to recent
|
/// Returns executions filtered by agent_id and task_type, limited to recent data.
|
||||||
/// data.
|
|
||||||
pub async fn get_executions_for_task_type(
|
pub async fn get_executions_for_task_type(
|
||||||
&self,
|
&self,
|
||||||
agent_id: &str,
|
agent_id: &str,
|
||||||
@ -250,8 +244,7 @@ impl KGPersistence {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
"SELECT * FROM kg_executions WHERE agent_id = '{}' AND task_type = '{}' ORDER BY \
|
"SELECT * FROM kg_executions WHERE agent_id = '{}' AND task_type = '{}' ORDER BY executed_at DESC LIMIT {}",
|
||||||
executed_at DESC LIMIT {}",
|
|
||||||
agent_id, task_type, limit
|
agent_id, task_type, limit
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -356,8 +349,7 @@ impl KGPersistence {
|
|||||||
) -> anyhow::Result<crate::analytics::TaskTypeAnalytics> {
|
) -> anyhow::Result<crate::analytics::TaskTypeAnalytics> {
|
||||||
// Fetch executions for task type
|
// Fetch executions for task type
|
||||||
let query = format!(
|
let query = format!(
|
||||||
"SELECT * FROM kg_executions WHERE task_type = '{}' ORDER BY executed_at DESC LIMIT \
|
"SELECT * FROM kg_executions WHERE task_type = '{}' ORDER BY executed_at DESC LIMIT 1000",
|
||||||
1000",
|
|
||||||
task_type
|
task_type
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Reasoning engine for inferring insights from execution history
|
/// Reasoning engine for inferring insights from execution history
|
||||||
pub struct ReasoningEngine;
|
pub struct ReasoningEngine;
|
||||||
@ -249,9 +248,8 @@ impl ReasoningEngine {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_predict_success() {
|
fn test_predict_success() {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use chrono::{Duration, Utc};
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use tracing::{debug, warn};
|
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
use chrono::{Duration, Utc};
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
/// Temporal Knowledge Graph for storing and querying agent execution history
|
/// Temporal Knowledge Graph for storing and querying agent execution history
|
||||||
/// Phase 5.1: Uses embedding-based similarity for semantic matching
|
/// Phase 5.1: Uses embedding-based similarity for semantic matching
|
||||||
@ -97,8 +95,7 @@ impl TemporalKG {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query similar tasks within 90 days (Phase 5.1: uses embeddings if
|
/// Query similar tasks within 90 days (Phase 5.1: uses embeddings if available)
|
||||||
/// available)
|
|
||||||
pub async fn query_similar_tasks(
|
pub async fn query_similar_tasks(
|
||||||
&self,
|
&self,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
@ -146,8 +143,7 @@ impl TemporalKG {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get recommendations from similar successful tasks (Phase 5.1:
|
/// Get recommendations from similar successful tasks (Phase 5.1: embedding-based)
|
||||||
/// embedding-based)
|
|
||||||
pub async fn get_recommendations(
|
pub async fn get_recommendations(
|
||||||
&self,
|
&self,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
|
use chrono::{Datelike, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{Datelike, Utc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
@ -171,8 +170,7 @@ impl BudgetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check budget status for role.
|
/// Check budget status for role.
|
||||||
/// Returns BudgetStatus with remaining balance, utilization %, and alert
|
/// Returns BudgetStatus with remaining balance, utilization %, and alert flags.
|
||||||
/// flags.
|
|
||||||
pub async fn check_budget(&self, role: &str) -> Result<BudgetStatus, String> {
|
pub async fn check_budget(&self, role: &str) -> Result<BudgetStatus, String> {
|
||||||
let budgets = self.budgets.read().await;
|
let budgets = self.budgets.read().await;
|
||||||
let mut spending = self.spending.write().await;
|
let mut spending = self.spending.write().await;
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// vapora-llm-router: Configuration module
|
// vapora-llm-router: Configuration module
|
||||||
// Load and parse LLM router configuration from TOML
|
// Load and parse LLM router configuration from TOML
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use prometheus::{GaugeVec, IntCounterVec, Registry};
|
use prometheus::{GaugeVec, IntCounterVec, Registry};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Prometheus metrics for cost tracking and budget enforcement.
|
/// Prometheus metrics for cost tracking and budget enforcement.
|
||||||
/// Exposes budget utilization, spending, and fallback events.
|
/// Exposes budget utilization, spending, and fallback events.
|
||||||
@ -18,8 +17,7 @@ pub struct CostMetrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CostMetrics {
|
impl CostMetrics {
|
||||||
/// Create new cost metrics collection (registers with default global
|
/// Create new cost metrics collection (registers with default global registry)
|
||||||
/// registry)
|
|
||||||
pub fn new() -> Result<Arc<Self>, prometheus::Error> {
|
pub fn new() -> Result<Arc<Self>, prometheus::Error> {
|
||||||
let registry = prometheus::default_registry();
|
let registry = prometheus::default_registry();
|
||||||
Self::with_registry(registry)
|
Self::with_registry(registry)
|
||||||
@ -136,8 +134,7 @@ mod tests {
|
|||||||
fn test_record_budget_update() {
|
fn test_record_budget_update() {
|
||||||
let metrics = create_test_metrics();
|
let metrics = create_test_metrics();
|
||||||
metrics.record_budget_update("developer", 25000, 0.167);
|
metrics.record_budget_update("developer", 25000, 0.167);
|
||||||
// Metric recorded (would verify via Prometheus gather in integration
|
// Metric recorded (would verify via Prometheus gather in integration test)
|
||||||
// test)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::config::ProviderConfig;
|
use crate::config::ProviderConfig;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Provider cost and efficiency score for decision making.
|
/// Provider cost and efficiency score for decision making.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
// vapora-llm-router: Cost tracking module
|
// vapora-llm-router: Cost tracking module
|
||||||
// Track LLM API costs and usage statistics
|
// Track LLM API costs and usage statistics
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct UsageStats {
|
pub struct UsageStats {
|
||||||
pub provider: String,
|
pub provider: String,
|
||||||
@ -115,7 +114,9 @@ impl CostTracker {
|
|||||||
|
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
"=== Cost Report ===\nTotal Cost: ${:.2}\nTotal Tasks: {}\n\n",
|
"=== Cost Report ===\n\
|
||||||
|
Total Cost: ${:.2}\n\
|
||||||
|
Total Tasks: {}\n\n",
|
||||||
report.total_cost_cents as f64 / 100.0,
|
report.total_cost_cents as f64 / 100.0,
|
||||||
report.total_tasks
|
report.total_tasks
|
||||||
));
|
));
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// Embedding provider implementations for vector similarity in Knowledge Graph
|
// Embedding provider implementations for vector similarity in Knowledge Graph
|
||||||
// Phase 5.1: Embedding-based KG similarity
|
// Phase 5.1: Embedding-based KG similarity
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
// vapora-llm-router: LLM Provider implementations
|
// vapora-llm-router: LLM Provider implementations
|
||||||
// Phase 3: Real providers via typedialog-ai
|
// Phase 3: Real providers via typedialog-ai
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@ -353,8 +352,7 @@ impl TypeDialogAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Estimate tokens from text (fallback for providers without token
|
/// Estimate tokens from text (fallback for providers without token counting)
|
||||||
/// counting)
|
|
||||||
fn estimate_tokens(text: &str) -> u64 {
|
fn estimate_tokens(text: &str) -> u64 {
|
||||||
// Rough estimate: 4 characters ≈ 1 token (works well for English/code)
|
// Rough estimate: 4 characters ≈ 1 token (works well for English/code)
|
||||||
(text.len() as u64).div_ceil(4)
|
(text.len() as u64).div_ceil(4)
|
||||||
@ -518,8 +516,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_llm_client_trait_exists() {
|
fn test_llm_client_trait_exists() {
|
||||||
// Tests compile-time verification that LLMClient trait is properly
|
// Tests compile-time verification that LLMClient trait is properly defined
|
||||||
// defined with required methods for all implementations
|
// with required methods for all implementations
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -540,8 +538,7 @@ mod tests {
|
|||||||
|
|
||||||
// 1000 input tokens + 1000 output tokens
|
// 1000 input tokens + 1000 output tokens
|
||||||
let cost = adapter.calculate_cost(1000, 1000);
|
let cost = adapter.calculate_cost(1000, 1000);
|
||||||
// (1000 / 1M * 0.80) + (1000 / 1M * 1.60) = 0.0008 + 0.0016 = 0.0024 = 0.24
|
// (1000 / 1M * 0.80) + (1000 / 1M * 1.60) = 0.0008 + 0.0016 = 0.0024 = 0.24 cents
|
||||||
// cents
|
|
||||||
assert_eq!(cost, 0);
|
assert_eq!(cost, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
// vapora-llm-router: Routing engine for task-optimal LLM selection
|
// vapora-llm-router: Routing engine for task-optimal LLM selection
|
||||||
// Phase 2: Complete implementation with fallback support
|
// Phase 2: Complete implementation with fallback support
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
use tracing::{debug, info, warn};
|
|
||||||
|
|
||||||
use crate::budget::BudgetManager;
|
use crate::budget::BudgetManager;
|
||||||
use crate::config::{LLMRouterConfig, ProviderConfig};
|
use crate::config::{LLMRouterConfig, ProviderConfig};
|
||||||
use crate::cost_ranker::CostRanker;
|
use crate::cost_ranker::CostRanker;
|
||||||
use crate::cost_tracker::CostTracker;
|
use crate::cost_tracker::CostTracker;
|
||||||
use crate::providers::*;
|
use crate::providers::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum RouterError {
|
pub enum RouterError {
|
||||||
@ -173,11 +171,7 @@ impl LLMRouter {
|
|||||||
|
|
||||||
if status.near_threshold {
|
if status.near_threshold {
|
||||||
// Budget near threshold - prefer cost-efficient providers
|
// Budget near threshold - prefer cost-efficient providers
|
||||||
debug!(
|
debug!("Budget near threshold for role {}, selecting cost-efficient provider", role);
|
||||||
"Budget near threshold for role {}, selecting cost-efficient \
|
|
||||||
provider",
|
|
||||||
role
|
|
||||||
);
|
|
||||||
return self.select_cost_efficient_provider(task_type).await;
|
return self.select_cost_efficient_provider(task_type).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,14 +372,12 @@ impl LLMRouter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Try each fallback provider (placeholder implementation)
|
// Try each fallback provider (placeholder implementation)
|
||||||
// In production, you would retry the original prompt with each fallback
|
// In production, you would retry the original prompt with each fallback provider
|
||||||
// provider For now, we log which providers would be tried and return
|
// For now, we log which providers would be tried and return error
|
||||||
// error
|
|
||||||
for provider_name in fallback_chain {
|
for provider_name in fallback_chain {
|
||||||
warn!("Trying fallback provider: {}", provider_name);
|
warn!("Trying fallback provider: {}", provider_name);
|
||||||
// Actual retry logic would go here with cost tracking
|
// Actual retry logic would go here with cost tracking
|
||||||
// For this phase, we return the error as fallbacks are handled at
|
// For this phase, we return the error as fallbacks are handled at routing level
|
||||||
// routing level
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RouterError::AllProvidersFailed)
|
Err(RouterError::AllProvidersFailed)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use vapora_llm_router::{BudgetManager, RoleBudget};
|
use vapora_llm_router::{BudgetManager, RoleBudget};
|
||||||
|
|
||||||
fn create_test_budgets() -> HashMap<String, RoleBudget> {
|
fn create_test_budgets() -> HashMap<String, RoleBudget> {
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
// vapora-mcp-server: Model Context Protocol server for VAPORA v1.0
|
// vapora-mcp-server: Model Context Protocol server for VAPORA v1.0
|
||||||
// Phase 2: Standalone MCP server with HTTP endpoints
|
// Phase 2: Standalone MCP server with HTTP endpoints
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Json, Path},
|
extract::{Json, Path},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -13,6 +11,7 @@ use axum::{
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use std::net::SocketAddr;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
@ -336,9 +335,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use axum_test::TestServer;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use axum_test::TestServer;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_health_endpoint() {
|
async fn test_health_endpoint() {
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use tracing::{debug, info, warn};
|
|
||||||
|
|
||||||
use crate::error::{Result, SwarmError};
|
use crate::error::{Result, SwarmError};
|
||||||
use crate::messages::*;
|
use crate::messages::*;
|
||||||
use crate::metrics::SwarmMetrics;
|
use crate::metrics::SwarmMetrics;
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
/// Swarm coordinator manages agent negotiation and task assignment
|
/// Swarm coordinator manages agent negotiation and task assignment
|
||||||
pub struct SwarmCoordinator {
|
pub struct SwarmCoordinator {
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
// Prometheus metrics for swarm coordination
|
// Prometheus metrics for swarm coordination
|
||||||
// Phase 5.2: Monitor assignment latency, coalition formation, and consensus
|
// Phase 5.2: Monitor assignment latency, coalition formation, and consensus voting
|
||||||
// voting
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use prometheus::{HistogramVec, IntCounter, IntCounterVec, IntGauge, Registry};
|
use prometheus::{HistogramVec, IntCounter, IntCounterVec, IntGauge, Registry};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Swarm metrics collection for Prometheus monitoring
|
/// Swarm metrics collection for Prometheus monitoring
|
||||||
pub struct SwarmMetrics {
|
pub struct SwarmMetrics {
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
|
use parking_lot::RwLock;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
|
|
||||||
/// Metrics collector for system observability
|
/// Metrics collector for system observability
|
||||||
pub struct MetricsCollector {
|
pub struct MetricsCollector {
|
||||||
/// Task execution count
|
/// Task execution count
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use tracing::{info_span, warn_span, Span};
|
use tracing::{info_span, warn_span, Span};
|
||||||
|
|
||||||
/// Span context for task execution tracing
|
/// Span context for task execution tracing
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
|
use crate::error::{Result, TelemetryError};
|
||||||
use opentelemetry::global;
|
use opentelemetry::global;
|
||||||
use opentelemetry_jaeger::new_agent_pipeline;
|
use opentelemetry_jaeger::new_agent_pipeline;
|
||||||
use tracing_subscriber::layer::SubscriberExt;
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
use tracing_subscriber::{EnvFilter, Registry};
|
use tracing_subscriber::{EnvFilter, Registry};
|
||||||
|
|
||||||
use crate::error::{Result, TelemetryError};
|
|
||||||
|
|
||||||
/// Configuration for telemetry initialization
|
/// Configuration for telemetry initialization
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TelemetryConfig {
|
pub struct TelemetryConfig {
|
||||||
|
|||||||
@ -2,14 +2,16 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|||||||
use vapora_tracking::parsers::{ClaudeTodoParser, MarkdownParser};
|
use vapora_tracking::parsers::{ClaudeTodoParser, MarkdownParser};
|
||||||
|
|
||||||
fn markdown_parse_changes_bench(c: &mut Criterion) {
|
fn markdown_parse_changes_bench(c: &mut Criterion) {
|
||||||
let content = "---\nproject: vapora\nlast_sync: 2025-11-10T14:30:00Z\n---\n\n## \
|
let content = "---\nproject: vapora\nlast_sync: 2025-11-10T14:30:00Z\n---\n\n\
|
||||||
2025-11-10T14:30:00Z - Implemented WebSocket sync\n**Impact**: backend | \
|
## 2025-11-10T14:30:00Z - Implemented WebSocket sync\n\
|
||||||
**Breaking**: no | **Files**: 5\nNon-blocking async synchronization using \
|
**Impact**: backend | **Breaking**: no | **Files**: 5\n\
|
||||||
tokio channels.\n\n## 2025-11-09T10:15:00Z - Fixed database \
|
Non-blocking async synchronization using tokio channels.\n\n\
|
||||||
indices\n**Impact**: performance | **Breaking**: no | **Files**: 2\nOptimized \
|
## 2025-11-09T10:15:00Z - Fixed database indices\n\
|
||||||
query performance for tracking entries.\n\n## 2025-11-08T16:45:00Z - Added \
|
**Impact**: performance | **Breaking**: no | **Files**: 2\n\
|
||||||
error context\n**Impact**: infrastructure | **Breaking**: no | **Files**: \
|
Optimized query performance for tracking entries.\n\n\
|
||||||
3\nImproved error messages with structured logging.\n";
|
## 2025-11-08T16:45:00Z - Added error context\n\
|
||||||
|
**Impact**: infrastructure | **Breaking**: no | **Files**: 3\n\
|
||||||
|
Improved error messages with structured logging.\n";
|
||||||
|
|
||||||
c.bench_function("markdown_parse_changes_small", |b| {
|
c.bench_function("markdown_parse_changes_small", |b| {
|
||||||
b.iter(|| MarkdownParser::parse_changes(black_box(content), black_box("/test")))
|
b.iter(|| MarkdownParser::parse_changes(black_box(content), black_box("/test")))
|
||||||
@ -17,16 +19,19 @@ fn markdown_parse_changes_bench(c: &mut Criterion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn markdown_parse_todos_bench(c: &mut Criterion) {
|
fn markdown_parse_todos_bench(c: &mut Criterion) {
|
||||||
let content = "---\nproject: vapora\nlast_sync: 2025-11-10T14:30:00Z\n---\n\n## [ ] Implement \
|
let content = "---\nproject: vapora\nlast_sync: 2025-11-10T14:30:00Z\n---\n\n\
|
||||||
webhook system\n**Priority**: H | **Estimate**: L | **Tags**: #feature \
|
## [ ] Implement webhook system\n\
|
||||||
#api\n**Created**: 2025-11-10T14:30:00Z | **Due**: 2025-11-15\nImplement \
|
**Priority**: H | **Estimate**: L | **Tags**: #feature #api\n\
|
||||||
bidirectional webhook system for real-time events.\n\n## [>] Refactor database \
|
**Created**: 2025-11-10T14:30:00Z | **Due**: 2025-11-15\n\
|
||||||
layer\n**Priority**: M | **Estimate**: M | **Tags**: #refactor \
|
Implement bidirectional webhook system for real-time events.\n\n\
|
||||||
#database\n**Created**: 2025-11-08T10:00:00Z | **Due**: 2025-11-20\nImprove \
|
## [>] Refactor database layer\n\
|
||||||
database abstraction and reduce code duplication.\n\n## [x] Setup CI/CD \
|
**Priority**: M | **Estimate**: M | **Tags**: #refactor #database\n\
|
||||||
pipeline\n**Priority**: H | **Estimate**: S | **Tags**: \
|
**Created**: 2025-11-08T10:00:00Z | **Due**: 2025-11-20\n\
|
||||||
#infrastructure\n**Created**: 2025-11-05T08:00:00Z\nGitHub Actions workflow \
|
Improve database abstraction and reduce code duplication.\n\n\
|
||||||
for automated testing.\n";
|
## [x] Setup CI/CD pipeline\n\
|
||||||
|
**Priority**: H | **Estimate**: S | **Tags**: #infrastructure\n\
|
||||||
|
**Created**: 2025-11-05T08:00:00Z\n\
|
||||||
|
GitHub Actions workflow for automated testing.\n";
|
||||||
|
|
||||||
c.bench_function("markdown_parse_todos_small", |b| {
|
c.bench_function("markdown_parse_todos_small", |b| {
|
||||||
b.iter(|| MarkdownParser::parse_todos(black_box(content), black_box("/test")))
|
b.iter(|| MarkdownParser::parse_todos(black_box(content), black_box("/test")))
|
||||||
|
|||||||
@ -2,8 +2,8 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
|||||||
|
|
||||||
/// Storage benchmarks for vapora-tracking
|
/// Storage benchmarks for vapora-tracking
|
||||||
///
|
///
|
||||||
/// Note: These are placeholder benchmarks that can be extended with async
|
/// Note: These are placeholder benchmarks that can be extended with async benchmarks
|
||||||
/// benchmarks using criterion's async support with `b.to_async()`.
|
/// using criterion's async support with `b.to_async()`.
|
||||||
fn storage_placeholder(_c: &mut Criterion) {
|
fn storage_placeholder(_c: &mut Criterion) {
|
||||||
// Placeholder: Full async benchmarks require tokio runtime setup
|
// Placeholder: Full async benchmarks require tokio runtime setup
|
||||||
// This can be extended in the future with criterion 0.5+ async support
|
// This can be extended in the future with criterion 0.5+ async support
|
||||||
|
|||||||
@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
//! # VAPORA Tracking Adapter
|
//! # VAPORA Tracking Adapter
|
||||||
//!
|
//!
|
||||||
//! Integration adapter for `tracking-core` library with VAPORA-specific
|
//! Integration adapter for `tracking-core` library with VAPORA-specific features.
|
||||||
//! features.
|
|
||||||
//!
|
//!
|
||||||
//! This crate re-exports the standalone `tracking-core` library and adds:
|
//! This crate re-exports the standalone `tracking-core` library and adds:
|
||||||
//! - VAPORA agent integration
|
//! - VAPORA agent integration
|
||||||
@ -91,12 +90,11 @@ pub mod events {
|
|||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
//! Prelude for common imports
|
//! Prelude for common imports
|
||||||
|
pub use crate::plugin::TrackingPlugin;
|
||||||
pub use tracking_core::{
|
pub use tracking_core::{
|
||||||
EntryType, Estimate, Impact, Priority, Result, TodoStatus, TrackingDb, TrackingEntry,
|
EntryType, Estimate, Impact, Priority, Result, TodoStatus, TrackingDb, TrackingEntry,
|
||||||
TrackingError, TrackingSource,
|
TrackingError, TrackingSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::plugin::TrackingPlugin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use std::path::PathBuf;
|
use crate::error::Result;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::error::Result;
|
|
||||||
|
|
||||||
/// Handle to an active worktree managed by the system
|
/// Handle to an active worktree managed by the system
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct WorktreeHandle {
|
pub struct WorktreeHandle {
|
||||||
|
|||||||
@ -1,15 +1,13 @@
|
|||||||
|
use crate::error::{Result, WorktreeError};
|
||||||
|
use crate::handle::WorktreeHandle;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::error::{Result, WorktreeError};
|
|
||||||
use crate::handle::WorktreeHandle;
|
|
||||||
|
|
||||||
/// Manages git worktree lifecycle for code-modifying agents
|
/// Manages git worktree lifecycle for code-modifying agents
|
||||||
pub struct WorktreeManager {
|
pub struct WorktreeManager {
|
||||||
/// Path to the root repository
|
/// Path to the root repository
|
||||||
@ -304,9 +302,8 @@ impl WorktreeManager {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use tempfile::TempDir;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_manager_creation() -> Result<()> {
|
async fn test_manager_creation() -> Result<()> {
|
||||||
|
|||||||
879
index.html
Normal file
879
index.html
Normal file
@ -0,0 +1,879 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title
|
||||||
|
data-en="Vapora - Intelligent Development Orchestration"
|
||||||
|
data-es="Vapora - Orquestación Inteligente de Desarrollo"
|
||||||
|
>
|
||||||
|
Vapora
|
||||||
|
</title>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700;800&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "JetBrains Mono", monospace;
|
||||||
|
background: #0a0118;
|
||||||
|
color: #ffffff;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
background:
|
||||||
|
radial-gradient(
|
||||||
|
circle at 20% 50%,
|
||||||
|
rgba(168, 85, 247, 0.15) 0%,
|
||||||
|
transparent 50%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
circle at 80% 80%,
|
||||||
|
rgba(34, 211, 238, 0.15) 0%,
|
||||||
|
transparent 50%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
circle at 40% 90%,
|
||||||
|
rgba(236, 72, 153, 0.1) 0%,
|
||||||
|
transparent 50%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-toggle {
|
||||||
|
position: fixed;
|
||||||
|
top: 2rem;
|
||||||
|
right: 2rem;
|
||||||
|
z-index: 100;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border: 1px solid rgba(34, 211, 238, 0.3);
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 0.3rem 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #94a3b8;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-family: "JetBrains Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-btn.active {
|
||||||
|
background: linear-gradient(135deg, #22d3ee 0%, #a855f7 100%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-btn:hover {
|
||||||
|
color: #22d3ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 5rem 0 4rem;
|
||||||
|
animation: fadeInUp 0.8s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(34, 211, 238, 0.2);
|
||||||
|
border: 1px solid #22d3ee;
|
||||||
|
color: #22d3ee;
|
||||||
|
padding: 0.5rem 1.5rem;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-container {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-container img {
|
||||||
|
max-width: 440px;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
filter: drop-shadow(0 0 30px rgba(34, 211, 238, 0.4));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagline {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #22d3ee;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2.8rem;
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
#22d3ee 0%,
|
||||||
|
#a855f7 50%,
|
||||||
|
#ec4899 100%
|
||||||
|
);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
color: #cbd5e1;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto 2rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: #22d3ee;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
margin: 4rem 0;
|
||||||
|
animation: fadeInUp 0.8s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
color: #22d3ee;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title span {
|
||||||
|
background: linear-gradient(135deg, #ec4899 0%, #a855f7 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problems-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-card {
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
border: 1px solid rgba(168, 85, 247, 0.3);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
border-color: rgba(34, 211, 238, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-number {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
background: linear-gradient(135deg, #22d3ee 0%, #a855f7 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
line-height: 1;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-card h3 {
|
||||||
|
color: #ec4899;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
margin-bottom: 0.7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.problem-card p {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-stack {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-badge {
|
||||||
|
background: rgba(34, 211, 238, 0.15);
|
||||||
|
border: 1px solid #22d3ee;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #22d3ee;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-box {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(34, 211, 238, 0.1) 0%,
|
||||||
|
rgba(168, 85, 247, 0.1) 100%
|
||||||
|
);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2rem;
|
||||||
|
border-left: 4px solid #22d3ee;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-box:hover {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(34, 211, 238, 0.15) 0%,
|
||||||
|
rgba(168, 85, 247, 0.15) 100%
|
||||||
|
);
|
||||||
|
transform: translateY(-3px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-icon {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-title {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #22d3ee;
|
||||||
|
margin-bottom: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-text {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agents-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-item {
|
||||||
|
background: rgba(236, 72, 153, 0.1);
|
||||||
|
padding: 1.2rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
border: 1px solid rgba(236, 72, 153, 0.3);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-item:hover {
|
||||||
|
background: rgba(236, 72, 153, 0.15);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-name {
|
||||||
|
color: #ec4899;
|
||||||
|
font-weight: 700;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-role {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-section {
|
||||||
|
text-align: center;
|
||||||
|
margin: 5rem 0 3rem;
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgba(34, 211, 238, 0.1) 0%,
|
||||||
|
rgba(236, 72, 153, 0.1) 100%
|
||||||
|
);
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid rgba(168, 85, 247, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
background: linear-gradient(135deg, #22d3ee 0%, #ec4899 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-button {
|
||||||
|
display: inline-block;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
#22d3ee 0%,
|
||||||
|
#a855f7 50%,
|
||||||
|
#ec4899 100%
|
||||||
|
);
|
||||||
|
color: #fff;
|
||||||
|
padding: 1.1rem 2.8rem;
|
||||||
|
border-radius: 50px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 10px 30px rgba(34, 211, 238, 0.3);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-button:hover {
|
||||||
|
transform: translateY(-3px) scale(1.05);
|
||||||
|
box-shadow: 0 20px 50px rgba(34, 211, 238, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem 0 2rem;
|
||||||
|
color: #64748b;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
margin-top: 4rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p:first-child {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p:last-child {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
.logo-container img {
|
||||||
|
max-width: 352px;
|
||||||
|
}
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
.cta-title {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
.language-toggle {
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="gradient-bg"></div>
|
||||||
|
|
||||||
|
<div class="language-toggle">
|
||||||
|
<button
|
||||||
|
class="lang-btn active"
|
||||||
|
data-lang="en"
|
||||||
|
onclick="switchLanguage('en')"
|
||||||
|
>
|
||||||
|
EN
|
||||||
|
</button>
|
||||||
|
<button class="lang-btn" data-lang="es" onclick="switchLanguage('es')">
|
||||||
|
ES
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<span
|
||||||
|
class="status-badge"
|
||||||
|
data-en="✅ v1.2.0"
|
||||||
|
data-es="✅ v1.2.0"
|
||||||
|
>✅ v1.2.0</span
|
||||||
|
>
|
||||||
|
<div class="logo-container">
|
||||||
|
<img
|
||||||
|
src="assets/vapora.svg"
|
||||||
|
alt="Vapora - Development Orchestration"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p class="tagline">Evaporate complexity</p>
|
||||||
|
<h1
|
||||||
|
data-en="Development Flows<br>When Teams and AI Orchestrate"
|
||||||
|
data-es="El Desarrollo Fluye<br>Cuando Equipos e IA Orquestan"
|
||||||
|
>
|
||||||
|
Development Flows
|
||||||
|
</h1>
|
||||||
|
<p class="hero-subtitle">
|
||||||
|
<span
|
||||||
|
class="highlight"
|
||||||
|
data-en="Specialized agents"
|
||||||
|
data-es="Agentes especializados"
|
||||||
|
>Specialized agents</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-en="orchestrate pipelines for design, implementation, testing, documentation and deployment. Agents learn from history and optimize costs automatically."
|
||||||
|
data-es="orquestan pipelines para diseño, implementación, testing, documentación y deployment. Los agentes aprenden del historial y optimizan costos automáticamente."
|
||||||
|
>orchestrate pipelines for design, implementation, testing,
|
||||||
|
documentation and deployment. Agents learn from history and optimize
|
||||||
|
costs automatically.</span
|
||||||
|
>
|
||||||
|
<strong data-en="100% self-hosted." data-es="100% self-hosted."
|
||||||
|
>100% self-hosted.</strong
|
||||||
|
>
|
||||||
|
<span data-en="No SaaS." data-es="Sin SaaS.">No SaaS.</span>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<span
|
||||||
|
data-en="The 4 Problems It Solves"
|
||||||
|
data-es="Los 4 Problemas que Resuelve"
|
||||||
|
>The 4 Problems It Solves</span
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<div class="problems-grid">
|
||||||
|
<div class="problem-card">
|
||||||
|
<div class="problem-number">01</div>
|
||||||
|
<h3 data-en="Context Switching" data-es="Cambio de Contexto">
|
||||||
|
Context Switching
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
data-en="Developers jump between tools constantly. Vapora unifies everything in one intelligent system where context flows."
|
||||||
|
data-es="Los developers saltan constantemente entre herramientas. Vapora unifica todo en un sistema inteligente donde el contexto fluye."
|
||||||
|
>
|
||||||
|
Developers jump between tools constantly. Vapora unifies
|
||||||
|
everything in one intelligent system where context flows.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="problem-card">
|
||||||
|
<div class="problem-number">02</div>
|
||||||
|
<h3
|
||||||
|
data-en="Knowledge Fragmentation"
|
||||||
|
data-es="Fragmentación de Conocimiento"
|
||||||
|
>
|
||||||
|
Knowledge Fragmentation
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
data-en="Decisions lost in threads, code scattered, docs unmaintained. RAG search and semantic indexing make knowledge discoverable."
|
||||||
|
data-es="Decisiones perdidas en threads, código disperso, docs desactualizadas. Búsqueda RAG e indexing semántico hacen el conocimiento visible."
|
||||||
|
>
|
||||||
|
Decisions lost in threads, code scattered, docs unmaintained. RAG
|
||||||
|
search and semantic indexing make knowledge discoverable.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="problem-card">
|
||||||
|
<div class="problem-number">03</div>
|
||||||
|
<h3 data-en="Manual Coordination" data-es="Coordinación Manual">
|
||||||
|
Manual Coordination
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
data-en="Orchestrating code review, testing, documentation and deployment manually creates bottlenecks. Multi-agent workflows solve this."
|
||||||
|
data-es="Orquestar manualmente code review, testing, documentación y deployment crea cuellos. Los workflows multi-agente lo resuelven."
|
||||||
|
>
|
||||||
|
Orchestrating code review, testing, documentation and deployment
|
||||||
|
manually creates bottlenecks. Multi-agent workflows solve this.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="problem-card">
|
||||||
|
<div class="problem-number">04</div>
|
||||||
|
<h3 data-en="Dev-Ops Friction" data-es="Fricción Dev-Ops">
|
||||||
|
Dev-Ops Friction
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
data-en="Handoffs between developers and operations lack visibility and context. Vapora maintains unified deployment readiness."
|
||||||
|
data-es="Los handoffs entre developers y operaciones carecen de visibilidad y contexto. Vapora mantiene unificada la deployment readiness."
|
||||||
|
>
|
||||||
|
Handoffs between developers and operations lack visibility and
|
||||||
|
context. Vapora maintains unified deployment readiness.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<span data-en="How It Works" data-es="Cómo Funciona"
|
||||||
|
>How It Works</span
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<div class="features-grid">
|
||||||
|
<div class="feature-box">
|
||||||
|
<div class="feature-icon">🤖</div>
|
||||||
|
<h3
|
||||||
|
class="feature-title"
|
||||||
|
data-en="Specialized Agents"
|
||||||
|
data-es="Agentes Especializados"
|
||||||
|
>
|
||||||
|
Specialized Agents
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="feature-text"
|
||||||
|
data-en="Customizable agents for every role: architecture, development, testing, documentation, deployment and more. Agents learn from execution history with recency bias for continuous improvement."
|
||||||
|
data-es="Agentes customizables para cada rol: arquitectura, desarrollo, testing, documentación, deployment y más. Los agentes aprenden del historial de ejecución con sesgo de recencia para mejora continua."
|
||||||
|
>
|
||||||
|
Customizable agents for every role: architecture, development,
|
||||||
|
testing, documentation, deployment and more. Agents learn from
|
||||||
|
execution history with recency bias for continuous improvement.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-box" style="border-left-color: #a855f7">
|
||||||
|
<div class="feature-icon">🧠</div>
|
||||||
|
<h3
|
||||||
|
class="feature-title"
|
||||||
|
style="color: #a855f7"
|
||||||
|
data-en="Intelligent Orchestration"
|
||||||
|
data-es="Orquestación Inteligente"
|
||||||
|
>
|
||||||
|
Intelligent Orchestration
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="feature-text"
|
||||||
|
data-en="Agents coordinate automatically based on dependencies, context and expertise. Learning-based selection improves over time. Budget enforcement with automatic fallback ensures cost control."
|
||||||
|
data-es="Los agentes se coordinan automáticamente basados en dependencias, contexto y expertise. La selección basada en aprendizaje mejora con el tiempo. La aplicación de presupuestos con fallback automático garantiza el control de costos."
|
||||||
|
>
|
||||||
|
Agents coordinate automatically based on dependencies, context and
|
||||||
|
expertise. Learning-based selection improves over time. Budget
|
||||||
|
enforcement with automatic fallback ensures cost control.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-box" style="border-left-color: #ec4899">
|
||||||
|
<div class="feature-icon">☸️</div>
|
||||||
|
<h3
|
||||||
|
class="feature-title"
|
||||||
|
style="color: #ec4899"
|
||||||
|
data-en="Cloud-Native & Self-Hosted"
|
||||||
|
data-es="Cloud-Native y Self-Hosted"
|
||||||
|
>
|
||||||
|
Cloud-Native & Self-Hosted
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
class="feature-text"
|
||||||
|
data-en="Deploy to any Kubernetes cluster (EKS, GKE, AKS, vanilla K8s). Local Docker Compose development. Zero vendor lock-in."
|
||||||
|
data-es="Despliega en cualquier cluster Kubernetes (EKS, GKE, AKS, vanilla K8s). Desarrollo local con Docker Compose. Sin vendor lock-in."
|
||||||
|
>
|
||||||
|
Deploy to any Kubernetes cluster (EKS, GKE, AKS, vanilla K8s).
|
||||||
|
Local Docker Compose development. Zero vendor lock-in.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<span data-en="Technology Stack" data-es="Stack Tecnológico"
|
||||||
|
>Technology Stack</span
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<div class="tech-stack">
|
||||||
|
<span class="tech-badge">Rust</span>
|
||||||
|
<span class="tech-badge">Axum</span>
|
||||||
|
<span class="tech-badge">SurrealDB</span>
|
||||||
|
<span class="tech-badge">NATS JetStream</span>
|
||||||
|
<span class="tech-badge">Leptos WASM</span>
|
||||||
|
<span class="tech-badge">Kubernetes</span>
|
||||||
|
<span class="tech-badge">Prometheus</span>
|
||||||
|
<span class="tech-badge">Grafana</span>
|
||||||
|
<span class="tech-badge">Knowledge Graph</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section">
|
||||||
|
<h2 class="section-title">
|
||||||
|
<span data-en="Available Agents" data-es="Agentes Disponibles"
|
||||||
|
>Available Agents</span
|
||||||
|
>
|
||||||
|
</h2>
|
||||||
|
<div class="agents-grid">
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Architect" data-es="Architect"
|
||||||
|
>Architect</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="System design"
|
||||||
|
data-es="Diseño de sistemas"
|
||||||
|
>System design</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Developer" data-es="Developer"
|
||||||
|
>Developer</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Code implementation"
|
||||||
|
data-es="Implementación de código"
|
||||||
|
>Code implementation</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span
|
||||||
|
class="agent-name"
|
||||||
|
data-en="CodeReviewer"
|
||||||
|
data-es="CodeReviewer"
|
||||||
|
>CodeReviewer</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Quality assurance"
|
||||||
|
data-es="Aseguramiento de calidad"
|
||||||
|
>Quality assurance</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Tester" data-es="Tester"
|
||||||
|
>Tester</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Tests & benchmarks"
|
||||||
|
data-es="Tests y benchmarks"
|
||||||
|
>Tests & benchmarks</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Documenter" data-es="Documenter"
|
||||||
|
>Documenter</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Documentation"
|
||||||
|
data-es="Documentación"
|
||||||
|
>Documentation</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Marketer" data-es="Marketer"
|
||||||
|
>Marketer</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Marketing content"
|
||||||
|
data-es="Contenido marketing"
|
||||||
|
>Marketing content</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Presenter" data-es="Presenter"
|
||||||
|
>Presenter</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Presentations"
|
||||||
|
data-es="Presentaciones"
|
||||||
|
>Presentations</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="DevOps" data-es="DevOps"
|
||||||
|
>DevOps</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="CI/CD deployment"
|
||||||
|
data-es="Despliegue CI/CD"
|
||||||
|
>CI/CD deployment</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Monitor" data-es="Monitor"
|
||||||
|
>Monitor</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Health & alerting"
|
||||||
|
data-es="Salud y alerting"
|
||||||
|
>Health & alerting</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span class="agent-name" data-en="Security" data-es="Security"
|
||||||
|
>Security</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Audit & compliance"
|
||||||
|
data-es="Auditoría y compliance"
|
||||||
|
>Audit & compliance</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span
|
||||||
|
class="agent-name"
|
||||||
|
data-en="ProjectManager"
|
||||||
|
data-es="ProjectManager"
|
||||||
|
>ProjectManager</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Roadmap tracking"
|
||||||
|
data-es="Tracking de roadmap"
|
||||||
|
>Roadmap tracking</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="agent-item">
|
||||||
|
<span
|
||||||
|
class="agent-name"
|
||||||
|
data-en="DecisionMaker"
|
||||||
|
data-es="DecisionMaker"
|
||||||
|
>DecisionMaker</span
|
||||||
|
><span
|
||||||
|
class="agent-role"
|
||||||
|
data-en="Conflict resolution"
|
||||||
|
data-es="Resolución de conflictos"
|
||||||
|
>Conflict resolution</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="cta-section">
|
||||||
|
<h2
|
||||||
|
class="cta-title"
|
||||||
|
data-en="Ready for intelligent orchestration?"
|
||||||
|
data-es="¿Listo para orquestación inteligente?"
|
||||||
|
>
|
||||||
|
Ready for intelligent orchestration?
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
style="color: #94a3b8; margin-bottom: 2rem; font-size: 1.05rem"
|
||||||
|
data-en="Built with Rust 🦀 | Open Source | Self-Hosted"
|
||||||
|
data-es="Construido con Rust 🦀 | Open Source | Self-Hosted"
|
||||||
|
>
|
||||||
|
Built with Rust 🦀 | Open Source | Self-Hosted
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vapora-platform/vapora"
|
||||||
|
class="cta-button"
|
||||||
|
data-en="Explore on GitHub →"
|
||||||
|
data-es="Explorar en GitHub →"
|
||||||
|
>Explore on GitHub →</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p
|
||||||
|
data-en="Vapora v1.2.0"
|
||||||
|
data-es="Vapora v1.2.0"
|
||||||
|
>
|
||||||
|
Vapora v1.2.0
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
data-en="Made with Vapora dreams and Rust reality ✨"
|
||||||
|
data-es="Hecho con sueños Vapora y realidad Rust ✨"
|
||||||
|
>
|
||||||
|
Made with Vapora dreams and Rust reality ✨
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
style="margin-top: 1rem; font-size: 0.8rem"
|
||||||
|
data-en="Intelligent Development Orchestration | Multi-Agent Multi-IA Platform"
|
||||||
|
data-es="Orquestación Inteligente de Desarrollo | Plataforma Multi-Agente Multi-IA"
|
||||||
|
>
|
||||||
|
Intelligent Development Orchestration | Multi-Agent Multi-IA Platform
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Language management
|
||||||
|
const LANG_KEY = "vapora-lang";
|
||||||
|
|
||||||
|
function getCurrentLanguage() {
|
||||||
|
return localStorage.getItem(LANG_KEY) || "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchLanguage(lang) {
|
||||||
|
localStorage.setItem(LANG_KEY, lang);
|
||||||
|
|
||||||
|
// Update language buttons
|
||||||
|
document.querySelectorAll(".lang-btn").forEach((btn) => {
|
||||||
|
btn.classList.remove("active");
|
||||||
|
if (btn.dataset.lang === lang) {
|
||||||
|
btn.classList.add("active");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update all translatable elements
|
||||||
|
document.querySelectorAll("[data-en][data-es]").forEach((el) => {
|
||||||
|
const content = el.dataset[lang];
|
||||||
|
// Use innerHTML for headings that might contain <br>, textContent for others
|
||||||
|
if (
|
||||||
|
el.tagName === "H1" ||
|
||||||
|
el.tagName === "H2" ||
|
||||||
|
el.tagName === "H3"
|
||||||
|
) {
|
||||||
|
el.innerHTML = content;
|
||||||
|
} else {
|
||||||
|
el.textContent = content;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.documentElement.lang = lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize language on page load
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const currentLang = getCurrentLanguage();
|
||||||
|
switchLanguage(currentLang);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -41,7 +41,7 @@ ci-full: ci-lint-rust ci-fmt-toml ci-lint-toml ci-lint-nickel ci-lint-markdown c
|
|||||||
# Check Rust code formatting
|
# Check Rust code formatting
|
||||||
ci-fmt:
|
ci-fmt:
|
||||||
@echo "📝 Checking Rust code formatting..."
|
@echo "📝 Checking Rust code formatting..."
|
||||||
cargo +nightly fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
# Check TOML file formatting
|
# Check TOML file formatting
|
||||||
ci-fmt-toml:
|
ci-fmt-toml:
|
||||||
@echo "📝 Checking TOML formatting..."
|
@echo "📝 Checking TOML formatting..."
|
||||||
@ -51,7 +51,7 @@ ci-fmt-toml:
|
|||||||
# Format all code
|
# Format all code
|
||||||
fmt:
|
fmt:
|
||||||
@echo "🎨 Formatting code..."
|
@echo "🎨 Formatting code..."
|
||||||
cargo +nightly fmt --all
|
cargo fmt --all
|
||||||
just fmt-toml
|
just fmt-toml
|
||||||
|
|
||||||
# Format TOML files
|
# Format TOML files
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user