Compare commits
3 Commits
d86f051955
...
ff98adba88
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff98adba88 | ||
|
|
75b1a0eb11 | ||
|
|
ac3f93fe1d |
545
.coder/archive/justfile.backup
Normal file
545
.coder/archive/justfile.backup
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
# 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,28 +87,25 @@ repos:
|
|||||||
# stages: [pre-commit]
|
# stages: [pre-commit]
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Markdown Hooks (RECOMMENDED - enable for documentation quality)
|
# Markdown Hooks (DISABLED - too many legacy formatting issues)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
- repo: local
|
# TODO: Re-enable after fixing markdown files to pass markdownlint
|
||||||
hooks:
|
# - repo: local
|
||||||
- id: markdownlint
|
# hooks:
|
||||||
name: Markdown linting (markdownlint-cli2)
|
# - id: markdownlint
|
||||||
entry: markdownlint-cli2
|
# name: Markdown linting (markdownlint-cli2)
|
||||||
language: system
|
# entry: markdownlint-cli2
|
||||||
types: [markdown]
|
# language: system
|
||||||
exclude: |
|
# types: [markdown]
|
||||||
(?x)^(
|
# exclude: |
|
||||||
\.typedialog/|
|
# ^(
|
||||||
\.woodpecker/|
|
# \.typedialog|
|
||||||
\.vale/|
|
# \.woodpecker|
|
||||||
assets/prompt_gen\.md|
|
# \.vale|
|
||||||
assets/README\.md|
|
# assets/(prompt_gen|README)|
|
||||||
README\.md|
|
# (README|SECURITY|CONTRIBUTING|CODE_OF_CONDUCT)\.md
|
||||||
SECURITY\.md|
|
# )
|
||||||
CONTRIBUTING\.md|
|
# stages: [pre-commit]
|
||||||
CODE_OF_CONDUCT\.md
|
|
||||||
)
|
|
||||||
stages: [pre-commit]
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# General Pre-commit Hooks
|
# General Pre-commit Hooks
|
||||||
@ -126,7 +123,7 @@ repos:
|
|||||||
- id: check-toml
|
- id: check-toml
|
||||||
|
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
exclude: ^\.woodpecker/
|
exclude: ^(\.woodpecker/|kubernetes/|provisioning/)
|
||||||
|
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: \.svg$
|
exclude: \.svg$
|
||||||
|
|||||||
320
.typedialog/ci/README.md
Normal file
320
.typedialog/ci/README.md
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
# 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
|
||||||
145
.typedialog/ci/config.ncl
Normal file
145
.typedialog/ci/config.ncl
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# 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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
203
.typedialog/ci/config.ncl.20260111_155400.bak
Normal file
203
.typedialog/ci/config.ncl.20260111_155400.bak
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# 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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
116
.typedialog/ci/configure.sh
Executable file
116
.typedialog/ci/configure.sh
Executable file
@ -0,0 +1,116 @@
|
|||||||
|
#!/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
|
||||||
27
.typedialog/ci/envrc
Normal file
27
.typedialog/ci/envrc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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}}
|
||||||
231
.typedialog/ci/form.toml
Normal file
231
.typedialog/ci/form.toml
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
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"
|
||||||
103
CODE_OF_CONDUCT.md
Normal file
103
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# 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
Normal file
129
CONTRIBUTING.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# 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,6 +2,7 @@
|
|||||||
|
|
||||||
<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
Normal file
98
SECURITY.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# 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.
|
||||||
@ -1,46 +1,40 @@
|
|||||||
# 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 will read from environment variables:
|
# Server configuration (override with env vars: VAPORA_HOST, VAPORA_PORT)
|
||||||
# VAPORA_HOST (default: 127.0.0.1)
|
host = "127.0.0.1"
|
||||||
# VAPORA_PORT (default: 3000)
|
port = 3000
|
||||||
host = "${VAPORA_HOST:-127.0.0.1}"
|
|
||||||
port = ${VAPORA_PORT:-3000}
|
|
||||||
|
|
||||||
[server.tls]
|
[server.tls]
|
||||||
# TLS configuration (optional)
|
# TLS configuration (optional)
|
||||||
# VAPORA_TLS_CERT_PATH
|
# Override with: VAPORA_TLS_ENABLED, VAPORA_TLS_CERT_PATH, VAPORA_TLS_KEY_PATH
|
||||||
# VAPORA_TLS_KEY_PATH
|
enabled = false
|
||||||
enabled = ${VAPORA_TLS_ENABLED:-false}
|
cert_path = ""
|
||||||
cert_path = "${VAPORA_TLS_CERT_PATH:-}"
|
key_path = ""
|
||||||
key_path = "${VAPORA_TLS_KEY_PATH:-}"
|
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
# Database connection
|
# Database connection (override with: VAPORA_DB_URL, VAPORA_DB_MAX_CONNECTIONS)
|
||||||
# VAPORA_DB_URL (required)
|
url = "ws://localhost:8000"
|
||||||
url = "${VAPORA_DB_URL}"
|
max_connections = 10
|
||||||
max_connections = ${VAPORA_DB_MAX_CONNECTIONS:-10}
|
|
||||||
|
|
||||||
[nats]
|
[nats]
|
||||||
# NATS JetStream configuration
|
# NATS JetStream configuration (override with: VAPORA_NATS_URL, VAPORA_NATS_STREAM)
|
||||||
# VAPORA_NATS_URL (default: nats://localhost:4222)
|
url = "nats://localhost:4222"
|
||||||
url = "${VAPORA_NATS_URL:-nats://localhost:4222}"
|
stream_name = "vapora-tasks"
|
||||||
stream_name = "${VAPORA_NATS_STREAM:-vapora-tasks}"
|
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
# Authentication configuration
|
# Authentication configuration (override with: VAPORA_JWT_SECRET, VAPORA_JWT_EXPIRATION_HOURS)
|
||||||
# VAPORA_JWT_SECRET (required in production)
|
jwt_secret = "change-in-production"
|
||||||
jwt_secret = "${VAPORA_JWT_SECRET}"
|
jwt_expiration_hours = 24
|
||||||
jwt_expiration_hours = ${VAPORA_JWT_EXPIRATION_HOURS:-24}
|
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
# Logging configuration
|
# Logging configuration (override with: VAPORA_LOG_LEVEL, VAPORA_LOG_JSON)
|
||||||
# VAPORA_LOG_LEVEL (default: info)
|
level = "info"
|
||||||
level = "${VAPORA_LOG_LEVEL:-info}"
|
json = false
|
||||||
json = ${VAPORA_LOG_JSON:-false}
|
|
||||||
|
|
||||||
[metrics]
|
[metrics]
|
||||||
# Metrics configuration
|
# Metrics configuration (override with: VAPORA_METRICS_ENABLED, VAPORA_METRICS_PORT)
|
||||||
enabled = ${VAPORA_METRICS_ENABLED:-true}
|
enabled = true
|
||||||
port = ${VAPORA_METRICS_PORT:-9090}
|
port = 9090
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
//! 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,8 +1,9 @@
|
|||||||
// 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 serde::{Deserialize, Serialize};
|
|
||||||
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,16 +1,18 @@
|
|||||||
// 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 {
|
||||||
@ -30,11 +32,12 @@ pub enum CoordinatorError {
|
|||||||
InvalidTaskState(String),
|
InvalidTaskState(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::config::AgentConfig;
|
|
||||||
use crate::profile_adapter::ProfileAdapter;
|
|
||||||
use vapora_llm_router::BudgetManager;
|
use vapora_llm_router::BudgetManager;
|
||||||
use vapora_swarm::coordinator::SwarmCoordinator;
|
use vapora_swarm::coordinator::SwarmCoordinator;
|
||||||
|
|
||||||
|
use crate::config::AgentConfig;
|
||||||
|
use crate::profile_adapter::ProfileAdapter;
|
||||||
|
|
||||||
/// Agent coordinator orchestrates task assignment and execution
|
/// Agent coordinator orchestrates task assignment and execution
|
||||||
pub struct AgentCoordinator {
|
pub struct AgentCoordinator {
|
||||||
registry: Arc<AgentRegistry>,
|
registry: Arc<AgentRegistry>,
|
||||||
@ -357,8 +360,9 @@ 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 metrics.
|
/// Queries KG for task-type specific executions and builds expertise
|
||||||
/// This is the core integration between KG persistence and learning profiles.
|
/// metrics. This is the core integration between KG persistence and
|
||||||
|
/// 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)
|
||||||
@ -411,7 +415,8 @@ 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}, confidence={:.2})",
|
"Loaded learning profile for agent {} task_type {} (success_rate={:.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,11 +1,12 @@
|
|||||||
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 averages.
|
/// Recent performance (last 7 days) weighted 3x higher than historical
|
||||||
|
/// averages.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LearningProfile {
|
pub struct LearningProfile {
|
||||||
pub agent_id: String,
|
pub agent_id: String,
|
||||||
@ -58,7 +59,8 @@ 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 success_rate.
|
/// Returns recent_success_rate if available, falls back to overall
|
||||||
|
/// 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,12 +1,14 @@
|
|||||||
// 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}")]
|
||||||
@ -87,11 +89,13 @@ impl AgentDefinitionLoader {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use serde_json::json;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use serde_json::json;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_load_from_file() -> Result<()> {
|
fn test_load_from_file() -> Result<()> {
|
||||||
let temp_dir = TempDir::new().map_err(|e| LoaderError::IoError(e))?;
|
let temp_dir = TempDir::new().map_err(|e| LoaderError::IoError(e))?;
|
||||||
|
|||||||
@ -2,9 +2,10 @@
|
|||||||
// 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;
|
||||||
@ -40,7 +41,8 @@ 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 assignment.
|
/// Integrates per-task-type learning data from KG for intelligent
|
||||||
|
/// 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)
|
||||||
}
|
}
|
||||||
@ -57,7 +59,8 @@ 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 default.
|
/// Uses learned expertise for the specified task type, with fallback to
|
||||||
|
/// 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,10 +1,11 @@
|
|||||||
// 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 chrono::{DateTime, Utc};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
// 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>>,
|
||||||
@ -83,9 +85,10 @@ impl std::error::Error for TaskRoutingError {}
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_consumer_registration() {
|
async fn test_consumer_registration() {
|
||||||
let mut consumer = NatsConsumer::new();
|
let mut consumer = NatsConsumer::new();
|
||||||
|
|||||||
@ -2,16 +2,17 @@
|
|||||||
// 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 crate::messages::TaskAssignment;
|
|
||||||
use crate::registry::AgentMetadata;
|
|
||||||
use chrono::Utc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
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,11 +1,13 @@
|
|||||||
// 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 crate::messages::TaskAssignment;
|
use std::marker::PhantomData;
|
||||||
use crate::registry::AgentMetadata;
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
use crate::messages::TaskAssignment;
|
||||||
|
use crate::registry::AgentMetadata;
|
||||||
|
|
||||||
/// Agent states - compile-time enforced state machine
|
/// Agent states - compile-time enforced state machine
|
||||||
/// Initial state: Agent is idle
|
/// Initial state: Agent is idle
|
||||||
@ -139,9 +141,10 @@ impl Agent<Failed> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_type_state_transitions() {
|
fn test_type_state_transitions() {
|
||||||
// Create metadata for testing
|
// Create metadata for testing
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
use crate::learning_profile::LearningProfile;
|
|
||||||
use vapora_swarm::messages::AgentProfile;
|
use vapora_swarm::messages::AgentProfile;
|
||||||
|
|
||||||
/// Unified agent score combining SwarmCoordinator metrics and learning expertise.
|
use crate::learning_profile::LearningProfile;
|
||||||
|
|
||||||
|
/// 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
|
||||||
@ -92,7 +94,8 @@ 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 profile).
|
/// Uses recent_success_rate if available (recency bias from learning
|
||||||
|
/// 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,11 +1,13 @@
|
|||||||
// 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 crate::coordination::{AgentAssignment, AgentLoad, AgentProfile, SwarmCoordination};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
use vapora_swarm::coordinator::SwarmCoordinator;
|
use vapora_swarm::coordinator::SwarmCoordinator;
|
||||||
|
|
||||||
|
use crate::coordination::{AgentAssignment, AgentLoad, AgentProfile, SwarmCoordination};
|
||||||
|
|
||||||
/// Adapter: SwarmCoordination → SwarmCoordinator
|
/// Adapter: SwarmCoordination → SwarmCoordinator
|
||||||
/// Implements the coordination abstraction using the real swarm coordinator.
|
/// Implements the coordination abstraction using the real swarm coordinator.
|
||||||
pub struct SwarmCoordinationAdapter {
|
pub struct SwarmCoordinationAdapter {
|
||||||
@ -42,7 +44,8 @@ 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 swarm.submit_task_for_bidding()
|
// This is a simplified version - full implementation would query
|
||||||
|
// 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,6 +1,7 @@
|
|||||||
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,7 +247,8 @@ 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 confidence weighting
|
// agent-exp should rank higher despite slightly lower expertise due to
|
||||||
|
// confidence weighting
|
||||||
assert_eq!(ranked[0].agent_id, "agent-exp");
|
assert_eq!(ranked[0].agent_id, "agent-exp");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,6 +288,7 @@ 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,8 +1,10 @@
|
|||||||
// Integration tests for SwarmCoordinator integration with AgentCoordinator
|
// Integration tests for SwarmCoordinator integration with AgentCoordinator
|
||||||
// Tests verify swarm task assignment, profile synchronization, and metrics integration
|
// Tests verify swarm task assignment, profile synchronization, and metrics
|
||||||
|
// 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,12 +1,14 @@
|
|||||||
use crate::error::{AnalyticsError, Result};
|
|
||||||
use crate::events::*;
|
|
||||||
use chrono::{Duration, Utc};
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use chrono::{Duration, Utc};
|
||||||
|
use dashmap::DashMap;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::error::{AnalyticsError, Result};
|
||||||
|
use crate::events::*;
|
||||||
|
|
||||||
/// Streaming pipeline for event processing
|
/// Streaming pipeline for event processing
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EventPipeline {
|
pub struct EventPipeline {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
// Agents API endpoints
|
// Agents API endpoints
|
||||||
|
|
||||||
use crate::api::ApiResult;
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -11,6 +10,7 @@ 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,7 +1,6 @@
|
|||||||
// 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,
|
||||||
@ -13,6 +12,8 @@ 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 {
|
||||||
@ -25,7 +26,6 @@ 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 yet
|
// For now, return a placeholder since AppState doesn't have KGAnalyticsService
|
||||||
// In real implementation, we'd fetch from service
|
// yet 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,6 +25,7 @@ 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 tests
|
// Response type verification - actual testing will be in integration
|
||||||
|
// tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
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,7 +15,8 @@ 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 are fixed
|
// pub mod workflows; // TODO: Phase 4 - Re-enable when workflow module imports
|
||||||
|
// 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,6 +1,5 @@
|
|||||||
// Projects API endpoints
|
// Projects API endpoints
|
||||||
|
|
||||||
use crate::api::ApiResult;
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
@ -10,6 +9,7 @@ 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,12 +85,14 @@ 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(
|
pub async fn get_provider_cost_breakdown(State(state): State<AppState>) -> impl IntoResponse {
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
debug!("GET /api/v1/analytics/providers - cost breakdown");
|
debug!("GET /api/v1/analytics/providers - cost breakdown");
|
||||||
|
|
||||||
match state.provider_analytics_service.get_cost_breakdown_by_provider().await {
|
match state
|
||||||
|
.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
|
||||||
@ -137,12 +139,14 @@ pub async fn get_provider_cost_breakdown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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(
|
pub async fn get_provider_efficiency(State(state): State<AppState>) -> impl IntoResponse {
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
debug!("GET /api/v1/analytics/providers/efficiency");
|
debug!("GET /api/v1/analytics/providers/efficiency");
|
||||||
|
|
||||||
match state.provider_analytics_service.get_provider_efficiency_ranking().await {
|
match state
|
||||||
|
.provider_analytics_service
|
||||||
|
.get_provider_efficiency_ranking()
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(efficiencies) => {
|
Ok(efficiencies) => {
|
||||||
let providers = efficiencies
|
let providers = efficiencies
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -180,16 +184,20 @@ pub async fn get_provider_efficiency(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider - Get detailed analytics for a provider
|
/// GET /api/v1/analytics/providers/:provider - Get detailed analytics for a
|
||||||
|
/// 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.provider_analytics_service.get_provider_analytics(&provider).await {
|
match state
|
||||||
Ok(analytics) => {
|
.provider_analytics_service
|
||||||
(
|
.get_provider_analytics(&provider)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(analytics) => (
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Json(ProviderAnalyticsData {
|
Json(ProviderAnalyticsData {
|
||||||
success: true,
|
success: true,
|
||||||
@ -206,8 +214,7 @@ pub async fn get_provider_analytics(
|
|||||||
error: None,
|
error: None,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.into_response()
|
.into_response(),
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get provider analytics: {}", e);
|
error!("Failed to get provider analytics: {}", e);
|
||||||
(
|
(
|
||||||
@ -232,16 +239,20 @@ pub async fn get_provider_analytics(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider/forecast - Get cost forecast for a provider
|
/// GET /api/v1/analytics/providers/:provider/forecast - Get cost forecast for a
|
||||||
|
/// 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.provider_analytics_service.forecast_provider_costs(&provider).await {
|
match state
|
||||||
Ok(forecast) => {
|
.provider_analytics_service
|
||||||
(
|
.forecast_provider_costs(&provider)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(forecast) => (
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Json(ProviderCostForecastData {
|
Json(ProviderCostForecastData {
|
||||||
success: true,
|
success: true,
|
||||||
@ -254,8 +265,7 @@ pub async fn get_provider_forecast(
|
|||||||
error: None,
|
error: None,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.into_response()
|
.into_response(),
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to get provider forecast: {}", e);
|
error!("Failed to get provider forecast: {}", e);
|
||||||
(
|
(
|
||||||
@ -276,7 +286,8 @@ pub async fn get_provider_forecast(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/v1/analytics/providers/:provider/tasks/:task_type - Provider performance by task type
|
/// GET /api/v1/analytics/providers/:provider/tasks/:task_type - Provider
|
||||||
|
/// 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)>,
|
||||||
@ -291,8 +302,7 @@ 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,
|
StatusCode::OK,
|
||||||
Json(TaskTypeMetricsResponse {
|
Json(TaskTypeMetricsResponse {
|
||||||
success: true,
|
success: true,
|
||||||
@ -305,8 +315,7 @@ pub async fn get_provider_task_type_metrics(
|
|||||||
error: None,
|
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,9 @@
|
|||||||
// API state - Shared application state for Axum handlers
|
// API state - Shared application state for Axum handlers
|
||||||
|
|
||||||
use crate::services::{AgentService, ProjectService, ProviderAnalyticsService, TaskService};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::services::{AgentService, ProjectService, ProviderAnalyticsService, TaskService};
|
||||||
|
|
||||||
/// Application state shared across all API handlers
|
/// Application state shared across all API handlers
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
// 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,6 +1,5 @@
|
|||||||
// 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,
|
||||||
@ -11,6 +10,7 @@ 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,12 +3,7 @@
|
|||||||
//! 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::{
|
use axum::{extract::Query, http::StatusCode, routing::get, Json, Router};
|
||||||
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,9 +1,10 @@
|
|||||||
// 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,9 +1,10 @@
|
|||||||
// 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
|
||||||
@ -71,7 +72,8 @@ pub struct MetricsConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Load configuration from a TOML file with environment variable interpolation
|
/// Load configuration from a TOML file with environment variable
|
||||||
|
/// 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,13 +7,14 @@ 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};
|
||||||
@ -67,7 +68,12 @@ 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(project_service, task_service, agent_service, provider_analytics_service);
|
let app_state = AppState::new(
|
||||||
|
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,8 +241,9 @@ impl AgentService {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
// Note: These are placeholder tests. Real tests require a running SurrealDB
|
||||||
// or mocking. For Phase 1, we'll add integration tests that use a test database.
|
// instance or mocking. For Phase 1, we'll add integration tests that use a
|
||||||
|
// test database.
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_agent_service_creation() {
|
fn test_agent_service_creation() {
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
// 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,7 +63,10 @@ impl ProjectService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query("SELECT * FROM projects WHERE tenant_id = $tenant_id AND status = $status ORDER BY created_at DESC")
|
.query(
|
||||||
|
"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?;
|
||||||
@ -193,11 +196,13 @@ impl ProjectService {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use vapora_shared::models::ProjectStatus;
|
use vapora_shared::models::ProjectStatus;
|
||||||
|
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
use super::*;
|
||||||
// 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,11 +2,12 @@
|
|||||||
// 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, ProviderEfficiency, ProviderTaskTypeMetrics, ProviderCostForecast,
|
ProviderAnalytics, ProviderCostForecast, ProviderEfficiency, ProviderTaskTypeMetrics,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -22,7 +23,10 @@ impl ProviderAnalyticsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get analytics for a specific provider
|
/// Get analytics for a specific provider
|
||||||
pub async fn get_provider_analytics(&self, provider: &str) -> anyhow::Result<ProviderAnalytics> {
|
pub async fn get_provider_analytics(
|
||||||
|
&self,
|
||||||
|
provider: &str,
|
||||||
|
) -> anyhow::Result<ProviderAnalytics> {
|
||||||
debug!("Querying analytics for provider: {}", provider);
|
debug!("Querying analytics for provider: {}", provider);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
@ -152,7 +156,8 @@ impl ProviderAnalyticsService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
efficiency_scores.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
|
efficiency_scores
|
||||||
|
.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()
|
||||||
@ -231,7 +236,10 @@ impl ProviderAnalyticsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get cost forecast for a provider
|
/// Get cost forecast for a provider
|
||||||
pub async fn forecast_provider_costs(&self, provider: &str) -> anyhow::Result<ProviderCostForecast> {
|
pub async fn forecast_provider_costs(
|
||||||
|
&self,
|
||||||
|
provider: &str,
|
||||||
|
) -> anyhow::Result<ProviderCostForecast> {
|
||||||
debug!("Forecasting costs for provider: {}", provider);
|
debug!("Forecasting costs for provider: {}", provider);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
@ -298,8 +306,7 @@ 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 =
|
let recent_avg = daily_costs[0..daily_costs.len().min(5)].iter().sum::<u32>() 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;
|
/ 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;
|
||||||
@ -344,10 +351,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,11 +376,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,7 +49,10 @@ 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("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id ORDER BY task_order ASC")
|
.query(
|
||||||
|
"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?;
|
||||||
@ -74,7 +77,10 @@ impl TaskService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id AND status = $status ORDER BY task_order ASC")
|
.query(
|
||||||
|
"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()))
|
||||||
@ -93,7 +99,10 @@ impl TaskService {
|
|||||||
) -> Result<Vec<Task>> {
|
) -> Result<Vec<Task>> {
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query("SELECT * FROM tasks WHERE project_id = $project_id AND tenant_id = $tenant_id AND assignee = $assignee ORDER BY priority DESC, task_order ASC")
|
.query(
|
||||||
|
"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()))
|
||||||
@ -257,7 +266,10 @@ impl TaskService {
|
|||||||
|
|
||||||
let mut response = self
|
let mut response = self
|
||||||
.db
|
.db
|
||||||
.query("SELECT VALUE task_order FROM tasks WHERE project_id = $project_id AND status = $status ORDER BY task_order DESC LIMIT 1")
|
.query(
|
||||||
|
"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?;
|
||||||
@ -271,8 +283,9 @@ impl TaskService {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Note: These are placeholder tests. Real tests require a running SurrealDB instance
|
// Note: These are placeholder tests. Real tests require a running SurrealDB
|
||||||
// or mocking. For Phase 1, we'll add integration tests that use a test database.
|
// instance or mocking. For Phase 1, we'll add integration tests that use a
|
||||||
|
// test database.
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_task_service_creation() {
|
fn test_task_service_creation() {
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
// 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 {
|
||||||
@ -215,17 +217,18 @@ impl WorkflowService {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use crate::workflow::{
|
|
||||||
executor::StepExecutor,
|
|
||||||
state::{Phase, StepStatus, WorkflowStep},
|
|
||||||
};
|
|
||||||
use vapora_agents::{
|
use vapora_agents::{
|
||||||
config::{AgentConfig, RegistryConfig},
|
config::{AgentConfig, RegistryConfig},
|
||||||
coordinator::AgentCoordinator,
|
coordinator::AgentCoordinator,
|
||||||
registry::AgentRegistry,
|
registry::AgentRegistry,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::workflow::{
|
||||||
|
executor::StepExecutor,
|
||||||
|
state::{Phase, StepStatus, 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,14 +1,16 @@
|
|||||||
// 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)]
|
||||||
@ -353,12 +355,13 @@ 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,13 +1,15 @@
|
|||||||
// 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 crate::workflow::state::{StepStatus, WorkflowStep};
|
|
||||||
use chrono::Utc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
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 {
|
||||||
@ -160,10 +162,11 @@ 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,11 +1,13 @@
|
|||||||
// 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 crate::workflow::state::{Phase, StepStatus, Workflow, WorkflowStep};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::workflow::state::{Phase, StepStatus, Workflow, WorkflowStep};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ParserError {
|
pub enum ParserError {
|
||||||
#[error("Failed to read file: {0}")]
|
#[error("Failed to read file: {0}")]
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
// 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 crate::workflow::state::WorkflowStep;
|
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::workflow::state::WorkflowStep;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum SchedulerError {
|
pub enum SchedulerError {
|
||||||
#[error("Circular dependency detected in workflow")]
|
#[error("Circular dependency detected in workflow")]
|
||||||
|
|||||||
@ -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, ProviderEfficiency, ProviderTaskTypeMetrics, ProviderCostForecast,
|
ProviderAnalytics, ProviderCostForecast, ProviderEfficiency, ProviderTaskTypeMetrics,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -123,7 +123,9 @@ 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!((forecast.projected_weekly_cost_cents as i32 - expected_weekly as i32).abs() <= 100);
|
assert!(
|
||||||
|
(forecast.projected_weekly_cost_cents as i32 - expected_weekly as i32).abs() <= 100
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -467,7 +469,9 @@ 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!(failing_provider.avg_cost_per_task_cents < reliable_provider.avg_cost_per_task_cents);
|
assert!(
|
||||||
|
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,6 +2,7 @@
|
|||||||
// 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,6 +2,7 @@
|
|||||||
// 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,11 +1,12 @@
|
|||||||
// 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,8 +1,9 @@
|
|||||||
// 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,8 +1,9 @@
|
|||||||
// 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,7 +12,10 @@ 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 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 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";
|
||||||
|
|
||||||
let final_class = format!("{} {}", default_class, class);
|
let final_class = format!("{} {}", default_class, class);
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,8 @@ 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 cursor-pointer"
|
"hover:border-cyan-400/70 hover:shadow-cyan-500/50 transition-all duration-300 \
|
||||||
|
cursor-pointer"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,9 @@ 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 placeholder-white/50 focus:outline-none focus:border-cyan-400/70 focus:shadow-lg focus:shadow-cyan-500/30 transition-all duration-200 {}",
|
"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 {}",
|
||||||
class
|
class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
// 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,9 +1,10 @@
|
|||||||
// 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,9 +1,10 @@
|
|||||||
// 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,9 +1,10 @@
|
|||||||
// 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,14 @@
|
|||||||
// Projects list page
|
// Projects list page
|
||||||
|
|
||||||
use crate::api::{ApiClient, Project};
|
|
||||||
use crate::components::{Badge, Button, Card, NavBar};
|
|
||||||
use crate::config::AppConfig;
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos::task::spawn_local;
|
use leptos::task::spawn_local;
|
||||||
use leptos_router::components::A;
|
use leptos_router::components::A;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
||||||
|
use crate::api::{ApiClient, Project};
|
||||||
|
use crate::components::{Badge, Button, Card, NavBar};
|
||||||
|
use crate::config::AppConfig;
|
||||||
|
|
||||||
/// Projects list page
|
/// Projects list page
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ProjectsPage() -> impl IntoView {
|
pub fn ProjectsPage() -> impl IntoView {
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
// Workflows page (placeholder for Phase 4)
|
// Workflows page (placeholder for Phase 4)
|
||||||
|
|
||||||
use crate::components::NavBar;
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::NavBar;
|
||||||
|
|
||||||
/// Workflows page (to be implemented in Phase 4)
|
/// Workflows page (to be implemented in Phase 4)
|
||||||
#[component]
|
#[component]
|
||||||
pub fn WorkflowsPage() -> impl IntoView {
|
pub fn WorkflowsPage() -> impl IntoView {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
// 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;
|
||||||
@ -406,9 +407,10 @@ impl KGAnalytics {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
fn create_test_execution(
|
fn create_test_execution(
|
||||||
agent_id: &str,
|
agent_id: &str,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use chrono::{DateTime, Duration, Utc};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Duration, Utc};
|
||||||
|
|
||||||
/// 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.
|
||||||
pub trait ExecutionRecord: Send + Sync {
|
pub trait ExecutionRecord: Send + Sync {
|
||||||
@ -11,7 +12,8 @@ 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 day.
|
/// Returns sorted Vec<(timestamp, success_rate)> where timestamp is start of
|
||||||
|
/// 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,
|
||||||
@ -41,10 +43,11 @@ 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 averages.
|
/// Recent performance (last 7 days) weighted 3x higher than historical
|
||||||
/// Returns weighted success rate accounting for time decay.
|
/// averages. Returns weighted success rate accounting for time decay.
|
||||||
///
|
///
|
||||||
/// Formula: weight = 3.0 * e^(-days_ago / 7.0) for days_ago < 7, else e^(-days_ago / 7.0)
|
/// Formula: weight = 3.0 * e^(-days_ago / 7.0) for days_ago < 7, else
|
||||||
|
/// 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;
|
||||||
@ -115,7 +118,8 @@ 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 count.
|
/// Returns (success_rate, confidence_score) where confidence reflects execution
|
||||||
|
/// 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 dependency
|
// Metrics computation trait for breaking persistence ↔ analytics circular
|
||||||
// Phase 5.5: Abstraction layer for analytics computations
|
// dependency 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,7 +38,8 @@ 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 flow.
|
/// Breaks the persistence ↔ analytics circular dependency by inverting control
|
||||||
|
/// 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,15 +1,18 @@
|
|||||||
// KG Persistence Layer
|
// KG Persistence Layer
|
||||||
// Phase 5.5: Persist execution history to SurrealDB for durability and analytics
|
// Phase 5.5: Persist execution history to SurrealDB for durability and
|
||||||
|
// analytics
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
|
||||||
use crate::models::ExecutionRecord;
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
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;
|
||||||
|
|
||||||
|
use crate::metrics::{AnalyticsComputation, TimePeriod};
|
||||||
|
use crate::models::ExecutionRecord;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PersistedExecution {
|
pub struct PersistedExecution {
|
||||||
pub execution_id: String,
|
pub execution_id: String,
|
||||||
@ -153,7 +156,9 @@ 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 agent_id = '{}') * 100.0 / count(SELECT * FROM kg_executions WHERE agent_id = '{}') AS rate FROM kg_executions",
|
"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, agent_id
|
agent_id, agent_id
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -231,7 +236,8 @@ 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 data.
|
/// Returns executions filtered by agent_id and task_type, limited to recent
|
||||||
|
/// 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,
|
||||||
@ -244,7 +250,8 @@ impl KGPersistence {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let query = format!(
|
let query = format!(
|
||||||
"SELECT * FROM kg_executions WHERE agent_id = '{}' AND task_type = '{}' ORDER BY executed_at DESC LIMIT {}",
|
"SELECT * FROM kg_executions WHERE agent_id = '{}' AND task_type = '{}' ORDER BY \
|
||||||
|
executed_at DESC LIMIT {}",
|
||||||
agent_id, task_type, limit
|
agent_id, task_type, limit
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -349,7 +356,8 @@ 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 1000",
|
"SELECT * FROM kg_executions WHERE task_type = '{}' ORDER BY executed_at DESC LIMIT \
|
||||||
|
1000",
|
||||||
task_type
|
task_type
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::models::*;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::models::*;
|
||||||
|
|
||||||
/// Reasoning engine for inferring insights from execution history
|
/// Reasoning engine for inferring insights from execution history
|
||||||
pub struct ReasoningEngine;
|
pub struct ReasoningEngine;
|
||||||
|
|
||||||
@ -248,9 +249,10 @@ impl ReasoningEngine {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_predict_success() {
|
fn test_predict_success() {
|
||||||
let records = vec![
|
let records = vec![
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use crate::error::Result;
|
use std::sync::Arc;
|
||||||
use crate::models::*;
|
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::sync::Arc;
|
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::models::*;
|
||||||
|
|
||||||
/// 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
|
||||||
pub struct TemporalKG {
|
pub struct TemporalKG {
|
||||||
@ -95,7 +97,8 @@ impl TemporalKG {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query similar tasks within 90 days (Phase 5.1: uses embeddings if available)
|
/// Query similar tasks within 90 days (Phase 5.1: uses embeddings if
|
||||||
|
/// available)
|
||||||
pub async fn query_similar_tasks(
|
pub async fn query_similar_tasks(
|
||||||
&self,
|
&self,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
@ -143,7 +146,8 @@ impl TemporalKG {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get recommendations from similar successful tasks (Phase 5.1: embedding-based)
|
/// Get recommendations from similar successful tasks (Phase 5.1:
|
||||||
|
/// embedding-based)
|
||||||
pub async fn get_recommendations(
|
pub async fn get_recommendations(
|
||||||
&self,
|
&self,
|
||||||
task_type: &str,
|
task_type: &str,
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
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;
|
||||||
|
|
||||||
@ -170,7 +171,8 @@ impl BudgetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check budget status for role.
|
/// Check budget status for role.
|
||||||
/// Returns BudgetStatus with remaining balance, utilization %, and alert flags.
|
/// Returns BudgetStatus with remaining balance, utilization %, and alert
|
||||||
|
/// 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,9 +1,10 @@
|
|||||||
// 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,7 @@
|
|||||||
use prometheus::{GaugeVec, IntCounterVec, Registry};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use prometheus::{GaugeVec, IntCounterVec, Registry};
|
||||||
|
|
||||||
/// 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.
|
||||||
pub struct CostMetrics {
|
pub struct CostMetrics {
|
||||||
@ -17,7 +18,8 @@ pub struct CostMetrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CostMetrics {
|
impl CostMetrics {
|
||||||
/// Create new cost metrics collection (registers with default global registry)
|
/// Create new cost metrics collection (registers with default global
|
||||||
|
/// 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)
|
||||||
@ -134,7 +136,8 @@ 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 test)
|
// Metric recorded (would verify via Prometheus gather in integration
|
||||||
|
// test)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::config::ProviderConfig;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::config::ProviderConfig;
|
||||||
|
|
||||||
/// 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)]
|
||||||
pub struct ProviderCostScore {
|
pub struct ProviderCostScore {
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
// 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,
|
||||||
@ -114,9 +115,7 @@ impl CostTracker {
|
|||||||
|
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
output.push_str(&format!(
|
output.push_str(&format!(
|
||||||
"=== Cost Report ===\n\
|
"=== Cost Report ===\nTotal Cost: ${:.2}\nTotal Tasks: {}\n\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,9 +1,10 @@
|
|||||||
// 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,9 +1,10 @@
|
|||||||
// 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)]
|
||||||
@ -352,7 +353,8 @@ impl TypeDialogAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Estimate tokens from text (fallback for providers without token counting)
|
/// Estimate tokens from text (fallback for providers without token
|
||||||
|
/// 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)
|
||||||
@ -516,8 +518,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 defined
|
// Tests compile-time verification that LLMClient trait is properly
|
||||||
// with required methods for all implementations
|
// defined with required methods for all implementations
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -538,7 +540,8 @@ 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 cents
|
// (1000 / 1M * 0.80) + (1000 / 1M * 1.60) = 0.0008 + 0.0016 = 0.0024 = 0.24
|
||||||
|
// cents
|
||||||
assert_eq!(cost, 0);
|
assert_eq!(cost, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
// 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 {
|
||||||
@ -171,7 +173,11 @@ 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!("Budget near threshold for role {}, selecting cost-efficient provider", role);
|
debug!(
|
||||||
|
"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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,12 +378,14 @@ 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 provider
|
// In production, you would retry the original prompt with each fallback
|
||||||
// For now, we log which providers would be tried and return error
|
// provider For now, we log which providers would be tried and return
|
||||||
|
// 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 routing level
|
// For this phase, we return the error as fallbacks are handled at
|
||||||
|
// routing level
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RouterError::AllProvidersFailed)
|
Err(RouterError::AllProvidersFailed)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
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,6 +1,8 @@
|
|||||||
// 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,
|
||||||
@ -11,7 +13,6 @@ 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};
|
||||||
|
|
||||||
@ -335,9 +336,10 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use axum_test::TestServer;
|
use axum_test::TestServer;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_health_endpoint() {
|
async fn test_health_endpoint() {
|
||||||
let app = Router::new().route("/health", get(health));
|
let app = Router::new().route("/health", get(health));
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
|
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,8 +1,10 @@
|
|||||||
// Prometheus metrics for swarm coordination
|
// Prometheus metrics for swarm coordination
|
||||||
// Phase 5.2: Monitor assignment latency, coalition formation, and consensus voting
|
// Phase 5.2: Monitor assignment latency, coalition formation, and consensus
|
||||||
|
// 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,8 +1,9 @@
|
|||||||
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,4 +1,5 @@
|
|||||||
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,10 +1,11 @@
|
|||||||
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,16 +2,14 @@ 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\
|
2025-11-10T14:30:00Z - Implemented WebSocket sync\n**Impact**: backend | \
|
||||||
**Impact**: backend | **Breaking**: no | **Files**: 5\n\
|
**Breaking**: no | **Files**: 5\nNon-blocking async synchronization using \
|
||||||
Non-blocking async synchronization using tokio channels.\n\n\
|
tokio channels.\n\n## 2025-11-09T10:15:00Z - Fixed database \
|
||||||
## 2025-11-09T10:15:00Z - Fixed database indices\n\
|
indices\n**Impact**: performance | **Breaking**: no | **Files**: 2\nOptimized \
|
||||||
**Impact**: performance | **Breaking**: no | **Files**: 2\n\
|
query performance for tracking entries.\n\n## 2025-11-08T16:45:00Z - Added \
|
||||||
Optimized query performance for tracking entries.\n\n\
|
error context\n**Impact**: infrastructure | **Breaking**: no | **Files**: \
|
||||||
## 2025-11-08T16:45:00Z - Added error context\n\
|
3\nImproved error messages with structured logging.\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")))
|
||||||
@ -19,19 +17,16 @@ 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\
|
let content = "---\nproject: vapora\nlast_sync: 2025-11-10T14:30:00Z\n---\n\n## [ ] Implement \
|
||||||
## [ ] Implement webhook system\n\
|
webhook system\n**Priority**: H | **Estimate**: L | **Tags**: #feature \
|
||||||
**Priority**: H | **Estimate**: L | **Tags**: #feature #api\n\
|
#api\n**Created**: 2025-11-10T14:30:00Z | **Due**: 2025-11-15\nImplement \
|
||||||
**Created**: 2025-11-10T14:30:00Z | **Due**: 2025-11-15\n\
|
bidirectional webhook system for real-time events.\n\n## [>] Refactor database \
|
||||||
Implement bidirectional webhook system for real-time events.\n\n\
|
layer\n**Priority**: M | **Estimate**: M | **Tags**: #refactor \
|
||||||
## [>] Refactor database layer\n\
|
#database\n**Created**: 2025-11-08T10:00:00Z | **Due**: 2025-11-20\nImprove \
|
||||||
**Priority**: M | **Estimate**: M | **Tags**: #refactor #database\n\
|
database abstraction and reduce code duplication.\n\n## [x] Setup CI/CD \
|
||||||
**Created**: 2025-11-08T10:00:00Z | **Due**: 2025-11-20\n\
|
pipeline\n**Priority**: H | **Estimate**: S | **Tags**: \
|
||||||
Improve database abstraction and reduce code duplication.\n\n\
|
#infrastructure\n**Created**: 2025-11-05T08:00:00Z\nGitHub Actions workflow \
|
||||||
## [x] Setup CI/CD pipeline\n\
|
for automated testing.\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 benchmarks
|
/// Note: These are placeholder benchmarks that can be extended with async
|
||||||
/// using criterion's async support with `b.to_async()`.
|
/// benchmarks 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,7 +3,8 @@
|
|||||||
|
|
||||||
//! # VAPORA Tracking Adapter
|
//! # VAPORA Tracking Adapter
|
||||||
//!
|
//!
|
||||||
//! Integration adapter for `tracking-core` library with VAPORA-specific features.
|
//! Integration adapter for `tracking-core` library with VAPORA-specific
|
||||||
|
//! 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
|
||||||
@ -90,11 +91,12 @@ 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,9 +1,11 @@
|
|||||||
use crate::error::Result;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
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,13 +1,15 @@
|
|||||||
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
|
||||||
@ -302,9 +304,10 @@ impl WorktreeManager {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_manager_creation() -> Result<()> {
|
async fn test_manager_creation() -> Result<()> {
|
||||||
let repo_dir = TempDir::new().map_err(WorktreeError::IoError)?;
|
let repo_dir = TempDir::new().map_err(WorktreeError::IoError)?;
|
||||||
|
|||||||
879
index.html
879
index.html
@ -1,879 +0,0 @@
|
|||||||
<!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 fmt --all -- --check
|
cargo +nightly 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 fmt --all
|
cargo +nightly fmt --all
|
||||||
just fmt-toml
|
just fmt-toml
|
||||||
|
|
||||||
# Format TOML files
|
# Format TOML files
|
||||||
|
|||||||
499
kubernetes/monitoring/grafana-analytics-dashboard.json
Normal file
499
kubernetes/monitoring/grafana-analytics-dashboard.json
Normal file
@ -0,0 +1,499 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"liveNow": false,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 0,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_overall_success_rate",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Overall Success Rate",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"pieType": "pie"
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_total_tasks_executed",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Total Tasks Executed",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "Cost (cents)",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 4,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_total_cost_cents",
|
||||||
|
"legendFormat": "Total Cost (cents)",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Total Execution Cost",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"max": 1,
|
||||||
|
"min": 0,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "percentage",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "yellow",
|
||||||
|
"value": 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 90
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "percentunit"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 5,
|
||||||
|
"options": {
|
||||||
|
"gauge": {
|
||||||
|
"maxValue": 1,
|
||||||
|
"minValue": 0,
|
||||||
|
"orientation": "auto",
|
||||||
|
"showThresholdLabels": false,
|
||||||
|
"showThresholdMarkers": true
|
||||||
|
},
|
||||||
|
"text": {}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_cost_per_task_cents",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Cost Per Task",
|
||||||
|
"type": "gauge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 8,
|
||||||
|
"x": 0,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 6,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "background",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "center",
|
||||||
|
"orientation": "auto",
|
||||||
|
"text": {},
|
||||||
|
"textMode": "auto"
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_active_agents",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Active Agents",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 8,
|
||||||
|
"x": 8,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 7,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "background",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "center",
|
||||||
|
"orientation": "auto",
|
||||||
|
"text": {},
|
||||||
|
"textMode": "auto"
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_unique_task_types",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Unique Task Types",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 4,
|
||||||
|
"w": 8,
|
||||||
|
"x": 16,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 8,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "background",
|
||||||
|
"graphMode": "none",
|
||||||
|
"justifyMode": "center",
|
||||||
|
"orientation": "auto",
|
||||||
|
"text": {},
|
||||||
|
"textMode": "auto"
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_analytics_errors_total",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Analytics Errors",
|
||||||
|
"type": "stat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schemaVersion": 38,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [
|
||||||
|
"vapora",
|
||||||
|
"analytics",
|
||||||
|
"performance"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-6h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "VAPORA Analytics Dashboard",
|
||||||
|
"uid": "vapora-analytics",
|
||||||
|
"version": 0,
|
||||||
|
"weekStart": ""
|
||||||
|
}
|
||||||
760
kubernetes/monitoring/grafana-provider-analytics-dashboard.json
Normal file
760
kubernetes/monitoring/grafana-provider-analytics-dashboard.json
Normal file
@ -0,0 +1,760 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": {
|
||||||
|
"type": "grafana",
|
||||||
|
"uid": "-- Grafana --"
|
||||||
|
},
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"liveNow": false,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["value", "percent"],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "right",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"pieType": "donut",
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_cost_cents_total",
|
||||||
|
"format": "heatmap",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Cost Distribution by Provider",
|
||||||
|
"type": "piechart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fillOpacity": 100,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "normal"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["mean", "max"],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_task_count",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Task Count by Provider",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"0": {
|
||||||
|
"color": "dark-red",
|
||||||
|
"text": "Failed"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"color": "dark-green",
|
||||||
|
"text": "Succeeded"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 0.5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "percentunit"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Success Rate"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.hideFrom",
|
||||||
|
"value": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 8,
|
||||||
|
"x": 0,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 3,
|
||||||
|
"options": {
|
||||||
|
"orientation": "auto",
|
||||||
|
"reduceOptions": {
|
||||||
|
"values": false,
|
||||||
|
"fields": "",
|
||||||
|
"calcs": ["lastNotNull"]
|
||||||
|
},
|
||||||
|
"showThresholdLabels": false,
|
||||||
|
"showThresholdMarkers": true,
|
||||||
|
"text": {}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_success_rate",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Success Rate by Provider",
|
||||||
|
"type": "gauge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "smooth",
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 8,
|
||||||
|
"x": 8,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 4,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["mean", "max", "min"],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "right",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_avg_cost_per_task_cents",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Average Cost Per Task by Provider",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 8,
|
||||||
|
"x": 16,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"id": 5,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["value"],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"pieType": "pie",
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_input_tokens_total",
|
||||||
|
"format": "heatmap",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Input Tokens by Provider",
|
||||||
|
"type": "piechart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "smooth",
|
||||||
|
"lineWidth": 2,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "never",
|
||||||
|
"spanNulls": true,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 6,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["mean", "max"],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_projected_monthly_cost_cents",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Projected Monthly Cost by Provider",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"displayMode": "auto",
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "yellow",
|
||||||
|
"value": 0.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 0.8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Rank"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "custom.displayMode",
|
||||||
|
"value": "color-background"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "color",
|
||||||
|
"value": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 16
|
||||||
|
},
|
||||||
|
"id": 7,
|
||||||
|
"options": {
|
||||||
|
"showHeader": true,
|
||||||
|
"sortBy": [
|
||||||
|
{
|
||||||
|
"displayName": "Rank",
|
||||||
|
"desc": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_efficiency_rank",
|
||||||
|
"format": "table",
|
||||||
|
"instant": true,
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Provider Efficiency Ranking",
|
||||||
|
"transformations": [
|
||||||
|
{
|
||||||
|
"id": "organize",
|
||||||
|
"options": {
|
||||||
|
"excludeByName": {
|
||||||
|
"Time": true,
|
||||||
|
"__name__": true
|
||||||
|
},
|
||||||
|
"indexByName": {},
|
||||||
|
"renameByName": {
|
||||||
|
"provider": "Provider",
|
||||||
|
"Value": "Rank"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "table"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "Cost per 1M Tokens",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "bars",
|
||||||
|
"fillOpacity": 100,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false,
|
||||||
|
"legend": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green",
|
||||||
|
"value": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 0,
|
||||||
|
"y": 24
|
||||||
|
},
|
||||||
|
"id": 8,
|
||||||
|
"options": {
|
||||||
|
"legend": {
|
||||||
|
"calcs": ["value"],
|
||||||
|
"displayMode": "table",
|
||||||
|
"placement": "right",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "single",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_cost_per_1m_tokens",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Cost per 1M Tokens by Provider",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "prometheus",
|
||||||
|
"uid": "prometheus"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"0": {
|
||||||
|
"color": "dark-red",
|
||||||
|
"text": "Low"
|
||||||
|
},
|
||||||
|
"0.33": {
|
||||||
|
"color": "orange",
|
||||||
|
"text": "Medium"
|
||||||
|
},
|
||||||
|
"0.66": {
|
||||||
|
"color": "dark-green",
|
||||||
|
"text": "High"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "range"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "dark-red",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "orange",
|
||||||
|
"value": 0.33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "dark-green",
|
||||||
|
"value": 0.66
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "percentunit"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 8,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 24
|
||||||
|
},
|
||||||
|
"id": 9,
|
||||||
|
"options": {
|
||||||
|
"orientation": "auto",
|
||||||
|
"reduceOptions": {
|
||||||
|
"values": false,
|
||||||
|
"fields": "",
|
||||||
|
"calcs": ["lastNotNull"]
|
||||||
|
},
|
||||||
|
"showThresholdLabels": false,
|
||||||
|
"showThresholdMarkers": true,
|
||||||
|
"text": {}
|
||||||
|
},
|
||||||
|
"pluginVersion": "8.0.0",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "vapora_provider_forecast_confidence",
|
||||||
|
"intervalFactor": 2,
|
||||||
|
"legendFormat": "{{provider}}",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Cost Forecast Confidence by Provider",
|
||||||
|
"type": "gauge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "30s",
|
||||||
|
"schemaVersion": 37,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": ["provider", "analytics", "cost", "efficiency"],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-6h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "Provider Analytics - Phase 7",
|
||||||
|
"uid": "provider-analytics-phase7",
|
||||||
|
"version": 0
|
||||||
|
}
|
||||||
105
kubernetes/monitoring/prometheus-alerts.yaml
Normal file
105
kubernetes/monitoring/prometheus-alerts.yaml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: prometheus-vapora-alerts
|
||||||
|
namespace: monitoring
|
||||||
|
data:
|
||||||
|
vapora-alerts.yml: |
|
||||||
|
groups:
|
||||||
|
- name: vapora_analytics
|
||||||
|
interval: 30s
|
||||||
|
rules:
|
||||||
|
# Performance Alerts
|
||||||
|
- alert: LowAgentSuccessRate
|
||||||
|
expr: vapora_overall_success_rate < 0.8
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: analytics
|
||||||
|
annotations:
|
||||||
|
summary: "Low agent success rate: {{ $value | humanizePercentage }}"
|
||||||
|
description: "Overall agent success rate is below 80% (current: {{ $value | humanizePercentage }})"
|
||||||
|
|
||||||
|
- alert: CriticalAgentSuccessRate
|
||||||
|
expr: vapora_overall_success_rate < 0.6
|
||||||
|
for: 2m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
component: analytics
|
||||||
|
annotations:
|
||||||
|
summary: "Critical agent success rate: {{ $value | humanizePercentage }}"
|
||||||
|
description: "Overall agent success rate is below 60% (current: {{ $value | humanizePercentage }})"
|
||||||
|
|
||||||
|
# Cost Alerts
|
||||||
|
- alert: HighExecutionCost
|
||||||
|
expr: vapora_cost_per_task_cents > 100
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: cost
|
||||||
|
annotations:
|
||||||
|
summary: "High average cost per task: {{ $value | humanize }} cents"
|
||||||
|
description: "Average cost per task has exceeded 100 cents (current: {{ $value | humanize }} cents)"
|
||||||
|
|
||||||
|
- alert: BudgetThresholdExceeded
|
||||||
|
expr: vapora_budget_threshold_alerts_total > 0
|
||||||
|
for: 1m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: budget
|
||||||
|
annotations:
|
||||||
|
summary: "Budget threshold alerts detected"
|
||||||
|
description: "Budget threshold has been exceeded {{ $value | humanize }} times"
|
||||||
|
|
||||||
|
# System Health Alerts
|
||||||
|
- alert: NoActiveAgents
|
||||||
|
expr: vapora_active_agents == 0
|
||||||
|
for: 1m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
component: agents
|
||||||
|
annotations:
|
||||||
|
summary: "No active agents"
|
||||||
|
description: "No active agents detected. System cannot process tasks."
|
||||||
|
|
||||||
|
- alert: HighAnalyticsQueryErrors
|
||||||
|
expr: vapora_analytics_errors_total > 10
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: analytics
|
||||||
|
annotations:
|
||||||
|
summary: "High analytics query errors: {{ $value | humanize }} errors"
|
||||||
|
description: "More than 10 analytics query errors detected in the last 5 minutes"
|
||||||
|
|
||||||
|
- alert: TaskExecutionStalled
|
||||||
|
expr: rate(vapora_total_tasks_executed[5m]) < 0.1
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: execution
|
||||||
|
annotations:
|
||||||
|
summary: "Task execution rate is very low"
|
||||||
|
description: "Less than 0.1 tasks/second being executed. System may be stalled."
|
||||||
|
|
||||||
|
# Analytics Query Performance
|
||||||
|
- alert: SlowAnalyticsQueries
|
||||||
|
expr: histogram_quantile(0.95, vapora_analytics_query_duration_ms) > 5000
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
component: analytics
|
||||||
|
annotations:
|
||||||
|
summary: "Slow analytics queries detected"
|
||||||
|
description: "95th percentile query duration exceeds 5 seconds (current: {{ $value | humanize }}ms)"
|
||||||
|
|
||||||
|
# Budget Enforcement
|
||||||
|
- alert: BudgetExceeded
|
||||||
|
expr: vapora_budget_threshold_alerts_total > 5
|
||||||
|
for: 2m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
component: budget
|
||||||
|
annotations:
|
||||||
|
summary: "Multiple budget threshold violations"
|
||||||
|
description: "Budget has been exceeded multiple times. Cost control measures may be needed."
|
||||||
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