diff --git a/deploy-clock.sh b/deploy-clock.sh index 1cfb595..a23f6b3 100755 --- a/deploy-clock.sh +++ b/deploy-clock.sh @@ -4,17 +4,21 @@ set -euo pipefail # ═══════════════════════════════════════════════════════════════════════ # ByteLyst ChronoMind - Production Deployment Script # ═══════════════════════════════════════════════════════════════════════ -# Usage: ./deploy-clock.sh [--force] [--skip-health-check] +# Usage: ./deploy-clock.sh [option] # -# What it does: -# 1. Dirty check: uncommitted changes, unpushed commits -# 2. Pull and rebase origin/main -# 3. Build and deploy Docker containers -# 4. Verify endpoints: https://api.bytelyst.com/chronomind, http://localhost:3030 +# Options (interactive menu when no arguments): +# 1 - Normal deployment (with cache, with health checks) +# 2 - Force deployment (skip dirty checks, with cache) +# 3 - Skip health checks (with cache) +# 4 - No-cache build (force rebuild, with health checks) +# 5 - Force + No-cache (skip checks, force rebuild) +# 6 - Force + Skip health checks (skip both) +# 7 - All options: Force + Skip health + No-cache # -# Options: +# Command-line options: # --force Skip dirty checks and force deployment # --skip-health-check Skip endpoint health verification +# --no-cache Force rebuild without cache # ═══════════════════════════════════════════════════════════════════════ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' @@ -31,15 +35,47 @@ cd "$SCRIPT_DIR" FORCE=false SKIP_HEALTH_CHECK=false +NO_CACHE=false +# Parse command-line arguments while [[ $# -gt 0 ]]; do case "$1" in --force) FORCE=true; shift ;; --skip-health-check) SKIP_HEALTH_CHECK=true; shift ;; - *) fail "Unknown option: $1" ;; + --no-cache) NO_CACHE=true; shift ;; + *) fail "Unknown option: $1";; esac done +# ── Interactive Menu ───────────────────────────────────────────────── +if [ "$FORCE" = false ] && [ "$SKIP_HEALTH_CHECK" = false ] && [ "$NO_CACHE" = false ]; then + echo "" + echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${NC} ByteLyst ChronoMind - Deployment Options ${CYAN}║${NC}" + echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e " ${GREEN}1${NC} - Normal deployment (with cache, with health checks)" + echo -e " ${GREEN}2${NC} - Force deployment (skip dirty checks, with cache)" + echo -e " ${GREEN}3${NC} - Skip health checks (with cache)" + echo -e " ${GREEN}4${NC} - No-cache build (force rebuild, with health checks)" + echo -e " ${GREEN}5${NC} - Force + No-cache (skip checks, force rebuild)" + echo -e " ${GREEN}6${NC} - Force + Skip health checks (skip both)" + echo -e " ${GREEN}7${NC} - All options: Force + Skip health + No-cache" + echo "" + read -r -p "Select option (1-7): " choice + + case $choice in + 1) ;; + 2) FORCE=true ;; + 3) SKIP_HEALTH_CHECK=true ;; + 4) NO_CACHE=true ;; + 5) FORCE=true; NO_CACHE=true ;; + 6) FORCE=true; SKIP_HEALTH_CHECK=true ;; + 7) FORCE=true; SKIP_HEALTH_CHECK=true; NO_CACHE=true ;; + *) fail "Invalid option. Please select 1-7." ;; + esac +fi + # ── Prerequisites ──────────────────────────────────────────────────── if [ ! -d "$REPO_DIR" ]; then fail "Repo directory not found: $REPO_DIR" @@ -105,6 +141,48 @@ if [ "$SKIP_HEALTH_CHECK" = false ]; then fi fi +# ── Package Publication Check ─────────────────────────────────────────── +log "Checking @bytelyst package publication status..." + +# Read Gitea token from file +unset GITEA_NPM_TOKEN +if [ -f "/opt/bytelyst/.gitea_token" ]; then + GITEA_NPM_TOKEN="$(< /opt/bytelyst/.gitea_token)" +elif [ -f "$HOME/.gitea_npm_token" ]; then + GITEA_NPM_TOKEN="$(< "$HOME/.gitea_npm_token")" +fi + +if [ -z "$GITEA_NPM_TOKEN" ]; then + warn "Gitea token not found, skipping package publication check" +else + GITEA_REGISTRY="http://localhost:3300/api/packages/ByteLyst/npm/" + CRITICAL_PACKAGES=( + "@bytelyst/config|@bytelyst%2fconfig" + "@bytelyst/cosmos|@bytelyst%2fcosmos" + "@bytelyst/errors|@bytelyst%2ferrors" + "@bytelyst/fastify-core|@bytelyst%2ffastify-core" + ) + MISSING_PACKAGES=() + + for entry in "${CRITICAL_PACKAGES[@]}"; do + package="${entry%%|*}" + encoded="${entry##*|}" + if ! curl -sf -H "Authorization: token ${GITEA_NPM_TOKEN}" "${GITEA_REGISTRY}${encoded}" > /dev/null 2>&1; then + MISSING_PACKAGES+=("$package") + fi + done + + if [ "${#MISSING_PACKAGES[@]}" -eq 0 ]; then + ok "All critical @bytelyst packages are published" + else + warn "Some @bytelyst packages may not be published: ${MISSING_PACKAGES[*]}" + read -r -p "Continue anyway? (y/N): " continue_anyway + if [[ ! "$continue_anyway" =~ ^[Yy]$ ]]; then + fail "Deployment cancelled" + fi + fi +fi + # ── Build and Deploy ────────────────────────────────────────────────── log "Building and deploying Docker containers..." @@ -114,8 +192,15 @@ if [ ! -f "docker-compose.yml" ]; then fi # Build and start services -log "Building Docker images..." -docker compose build || fail "Docker build failed" +BUILD_ARGS=() +if [ "$NO_CACHE" = true ]; then + BUILD_ARGS+=(--no-cache) + log "Building Docker images without cache..." +else + log "Building Docker images..." +fi + +docker compose build "${BUILD_ARGS[@]}" || fail "Docker build failed" log "Starting services..." docker compose up -d || fail "Docker compose up failed" @@ -171,7 +256,7 @@ fi log "Verifying production endpoints..." API_ENDPOINT="https://api.bytelyst.com/chronomind" -WEB_ENDPOINT="http://localhost:3030" +WEB_ENDPOINT="https://clock.bytelyst.com" # Check API endpoint if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then @@ -219,5 +304,5 @@ fi log "══════════════════════════════════════════════════════════════════════" ok "Deployment completed successfully!" log "Backend: http://localhost:4011 → $API_ENDPOINT" -log "Web: http://localhost:3030" +log "Web: http://localhost:3030 → $WEB_ENDPOINT" log "══════════════════════════════════════════════════════════════════════" diff --git a/deploy-notes.sh b/deploy-notes.sh index a50032a..ae6356d 100755 --- a/deploy-notes.sh +++ b/deploy-notes.sh @@ -4,17 +4,21 @@ set -euo pipefail # ═══════════════════════════════════════════════════════════════════════ # ByteLyst NoteLett - Production Deployment Script # ═══════════════════════════════════════════════════════════════════════ -# Usage: ./deploy-notes.sh [--force] [--skip-health-check] +# Usage: ./deploy-notes.sh [option] # -# What it does: -# 1. Dirty check: uncommitted changes, unpushed commits -# 2. Pull and rebase origin/main -# 3. Build and deploy Docker containers -# 4. Verify endpoints: https://api.bytelyst.com/notelett, http://localhost:3000 +# Options (interactive menu when no arguments): +# 1 - Normal deployment (with cache, with health checks) +# 2 - Force deployment (skip dirty checks, with cache) +# 3 - Skip health checks (with cache) +# 4 - No-cache build (force rebuild, with health checks) +# 5 - Force + No-cache (skip checks, force rebuild) +# 6 - Force + Skip health checks (skip both) +# 7 - All options: Force + Skip health + No-cache # -# Options: +# Command-line options: # --force Skip dirty checks and force deployment # --skip-health-check Skip endpoint health verification +# --no-cache Force rebuild without cache # ═══════════════════════════════════════════════════════════════════════ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' @@ -31,15 +35,47 @@ cd "$SCRIPT_DIR" FORCE=false SKIP_HEALTH_CHECK=false +NO_CACHE=false +# Parse command-line arguments while [[ $# -gt 0 ]]; do case "$1" in --force) FORCE=true; shift ;; --skip-health-check) SKIP_HEALTH_CHECK=true; shift ;; - *) fail "Unknown option: $1" ;; + --no-cache) NO_CACHE=true; shift ;; + *) fail "Unknown option: $1";; esac done +# ── Interactive Menu ───────────────────────────────────────────────── +if [ "$FORCE" = false ] && [ "$SKIP_HEALTH_CHECK" = false ] && [ "$NO_CACHE" = false ]; then + echo "" + echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" + echo -e "${CYAN}║${NC} ByteLyst NoteLett - Deployment Options ${CYAN}║${NC}" + echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e " ${GREEN}1${NC} - Normal deployment (with cache, with health checks)" + echo -e " ${GREEN}2${NC} - Force deployment (skip dirty checks, with cache)" + echo -e " ${GREEN}3${NC} - Skip health checks (with cache)" + echo -e " ${GREEN}4${NC} - No-cache build (force rebuild, with health checks)" + echo -e " ${GREEN}5${NC} - Force + No-cache (skip checks, force rebuild)" + echo -e " ${GREEN}6${NC} - Force + Skip health checks (skip both)" + echo -e " ${GREEN}7${NC} - All options: Force + Skip health + No-cache" + echo "" + read -r -p "Select option (1-7): " choice + + case $choice in + 1) ;; + 2) FORCE=true ;; + 3) SKIP_HEALTH_CHECK=true ;; + 4) NO_CACHE=true ;; + 5) FORCE=true; NO_CACHE=true ;; + 6) FORCE=true; SKIP_HEALTH_CHECK=true ;; + 7) FORCE=true; SKIP_HEALTH_CHECK=true; NO_CACHE=true ;; + *) fail "Invalid option. Please select 1-7." ;; + esac +fi + # ── Prerequisites ──────────────────────────────────────────────────── if [ ! -d "$REPO_DIR" ]; then fail "Repo directory not found: $REPO_DIR" @@ -105,6 +141,48 @@ if [ "$SKIP_HEALTH_CHECK" = false ]; then fi fi +# ── Package Publication Check ─────────────────────────────────────────── +log "Checking @bytelyst package publication status..." + +# Read Gitea token from file +unset GITEA_NPM_TOKEN +if [ -f "/opt/bytelyst/.gitea_token" ]; then + GITEA_NPM_TOKEN="$(< /opt/bytelyst/.gitea_token)" +elif [ -f "$HOME/.gitea_npm_token" ]; then + GITEA_NPM_TOKEN="$(< "$HOME/.gitea_npm_token")" +fi + +if [ -z "$GITEA_NPM_TOKEN" ]; then + warn "Gitea token not found, skipping package publication check" +else + GITEA_REGISTRY="http://localhost:3300/api/packages/ByteLyst/npm/" + CRITICAL_PACKAGES=( + "@bytelyst/config|@bytelyst%2fconfig" + "@bytelyst/cosmos|@bytelyst%2fcosmos" + "@bytelyst/errors|@bytelyst%2ferrors" + "@bytelyst/fastify-core|@bytelyst%2ffastify-core" + ) + MISSING_PACKAGES=() + + for entry in "${CRITICAL_PACKAGES[@]}"; do + package="${entry%%|*}" + encoded="${entry##*|}" + if ! curl -sf -H "Authorization: token ${GITEA_NPM_TOKEN}" "${GITEA_REGISTRY}${encoded}" > /dev/null 2>&1; then + MISSING_PACKAGES+=("$package") + fi + done + + if [ "${#MISSING_PACKAGES[@]}" -eq 0 ]; then + ok "All critical @bytelyst packages are published" + else + warn "Some @bytelyst packages may not be published: ${MISSING_PACKAGES[*]}" + read -r -p "Continue anyway? (y/N): " continue_anyway + if [[ ! "$continue_anyway" =~ ^[Yy]$ ]]; then + fail "Deployment cancelled" + fi + fi +fi + # ── Build and Deploy ────────────────────────────────────────────────── log "Building and deploying Docker containers..." @@ -114,8 +192,15 @@ if [ ! -f "docker-compose.yml" ]; then fi # Build and start services -log "Building Docker images..." -docker compose build || fail "Docker build failed" +BUILD_ARGS=() +if [ "$NO_CACHE" = true ]; then + BUILD_ARGS+=(--no-cache) + log "Building Docker images without cache..." +else + log "Building Docker images..." +fi + +docker compose build "${BUILD_ARGS[@]}" || fail "Docker build failed" log "Starting services..." docker compose up -d || fail "Docker compose up failed" @@ -152,7 +237,7 @@ fi # Check web health WEB_HEALTH=false for _ in {1..30}; do - if curl -sf http://localhost:3000 > /dev/null 2>&1; then + if curl -sf http://localhost:3045 > /dev/null 2>&1; then WEB_HEALTH=true break fi @@ -162,7 +247,7 @@ done echo "" if [ "$WEB_HEALTH" = true ]; then - ok "Web health check passed (http://localhost:3000)" + ok "Web health check passed (http://localhost:3045)" else warn "Web health check failed (may be starting up)" fi @@ -171,7 +256,7 @@ fi log "Verifying production endpoints..." API_ENDPOINT="https://api.bytelyst.com/notelett" -WEB_ENDPOINT="http://localhost:3000" +WEB_ENDPOINT="https://notes.bytelyst.com" # Check API endpoint if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then @@ -202,7 +287,7 @@ else fi # Test web is serving content -WEB_URL="http://localhost:3000" +WEB_URL="http://localhost:3045" if curl -sf "$WEB_URL" > /dev/null 2>&1; then ok "Web frontend is serving content" # Check if it's actually HTML @@ -219,5 +304,5 @@ fi log "══════════════════════════════════════════════════════════════════════" ok "Deployment completed successfully!" log "Backend: http://localhost:4016 → $API_ENDPOINT" -log "Web: http://localhost:3000" +log "Web: http://localhost:3045 → $WEB_ENDPOINT" log "══════════════════════════════════════════════════════════════════════" diff --git a/scripts/monitor-lucky25-execution.sh b/scripts/monitor-lucky25-execution.sh new file mode 100755 index 0000000..249e88f --- /dev/null +++ b/scripts/monitor-lucky25-execution.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ════════════════════════════════════════════════════════════════ +# Lucky25 Execution Monitoring Script +# ════════════════════════════════════════════════════════════════ +# Runs every 15 minutes to monitor lucky25 test plan execution +# Logs status to /var/log/lucky25-monitoring.log +# ════════════════════════════════════════════════════════════════ + +LOG_FILE="/var/log/lucky25-monitoring.log" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +BACKEND_DIR="${SCRIPT_DIR}/../learning_ai_invt_trdg/backend" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" +} + +log "════════════════════════════════════════════════════════════════" +log "Starting Lucky25 Execution Monitoring" +log "════════════════════════════════════════════════════════════════" + +# Create log file if it doesn't exist +touch "$LOG_FILE" + +cd "$BACKEND_DIR" + +# Run the status check using node with the compiled JS +node -e " +const { config } = require('./dist/src/config/index.js'); +const { MANUAL_ENTRY_CONTAINER, queryDocuments } = require('./dist/src/services/tradingRecordStore.js'); + +async function main() { + const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.type = @type ORDER BY c.created_at DESC'; + const rows = await queryDocuments(MANUAL_ENTRY_CONTAINER, query, [ + { name: '@productId', value: config.PRODUCT_ID }, + { name: '@type', value: 'manual_entry' }, + ]); + + const lucky25Plans = rows.filter(row => + row.hashtags && Array.isArray(row.hashtags) && row.hashtags.includes('lucky25') && row.active === true + ); + + const byStatus = {}; + for (const plan of lucky25Plans) { + const status = plan.status || 'unknown'; + byStatus[status] = (byStatus[status] || 0) + 1; + } + + console.log('Lucky25 Plans Status:'); + console.log('Total: ' + lucky25Plans.length); + console.log('Status breakdown:'); + for (const [status, count] of Object.entries(byStatus)) { + console.log(' ' + status + ': ' + count); + } + + const executedPlans = lucky25Plans.filter(p => + p.status !== 'simple_armed_buy' && p.status !== 'deleted' + ); + + console.log('Execution Progress:'); + console.log('Executed: ' + executedPlans.length + '/' + lucky25Plans.length); + console.log('Rate: ' + ((executedPlans.length / lucky25Plans.length) * 100).toFixed(1) + '%'); + + if (executedPlans.length > 0) { + console.log('Recent executions:'); + const recent = executedPlans.slice(0, 3); + for (const plan of recent) { + console.log(' ' + plan.symbol + ' - ' + plan.status + ' - ' + plan.label); + } + } +} + +main().catch(console.error); +" + +log "Monitoring check completed" +log "════════════════════════════════════════════════════════════════"