#!/usr/bin/env python3
"""
SecuBox Evolution Dashboard
Interactive Streamlit landing page showing project evolution, history, WIP, TODO, and README
"""
import streamlit as st
import requests
import re
from datetime import datetime
from collections import Counter
# Page config
st.set_page_config(
page_title="SecuBox Evolution",
page_icon="🛡️",
layout="wide",
initial_sidebar_state="expanded"
)
# Custom CSS for dark cyberpunk theme
st.markdown("""
""", unsafe_allow_html=True)
# GitHub raw URLs
GITHUB_BASE = "https://raw.githubusercontent.com/gkerma/secubox-openwrt/master"
FILES = {
"HISTORY": f"{GITHUB_BASE}/.claude/HISTORY.md",
"WIP": f"{GITHUB_BASE}/.claude/WIP.md",
"TODO": f"{GITHUB_BASE}/.claude/TODO.md",
"README": f"{GITHUB_BASE}/README.md"
}
@st.cache_data(ttl=300)
def fetch_file(url):
"""Fetch file content from GitHub"""
try:
response = requests.get(url, timeout=10)
if response.status_code == 200:
return response.text
return None
except:
return None
def parse_history(content):
"""Parse HISTORY.md to extract milestones"""
if not content:
return []
milestones = []
# Match patterns like "1. **Title (2026-02-06)**" or "14. **P2P MirrorBox..."
pattern = r'(\d+)\.\s+\*\*([^*]+)\*\*'
for match in re.finditer(pattern, content):
num = match.group(1)
title = match.group(2).strip()
# Extract date if present
date_match = re.search(r'\((\d{4}-\d{2}-\d{2})\)', title)
date = date_match.group(1) if date_match else None
title_clean = re.sub(r'\s*\(\d{4}-\d{2}-\d{2}\)\s*', '', title)
milestones.append({
'num': int(num),
'title': title_clean,
'date': date
})
return milestones
def parse_packages(content):
"""Extract package names from content"""
if not content:
return []
packages = set()
# Match `package-name` or secubox-app-xxx patterns
patterns = [
r'`(secubox-[a-z0-9-]+)`',
r'`(luci-app-[a-z0-9-]+)`',
r'\*\*([a-z0-9-]+)\*\*:',
]
for pattern in patterns:
for match in re.finditer(pattern, content):
pkg = match.group(1)
if len(pkg) > 3:
packages.add(pkg)
return list(packages)
def count_features(content):
"""Count features mentioned in content"""
if not content:
return {}
features = {
'AI/LocalAI': len(re.findall(r'LocalAI|AI-powered|LLM|agent', content, re.I)),
'Security': len(re.findall(r'CrowdSec|WAF|firewall|threat|CVE|security', content, re.I)),
'DNS': len(re.findall(r'DNS|Vortex|dnsctl|AdGuard', content, re.I)),
'Mesh/P2P': len(re.findall(r'mesh|P2P|gossip|mirror|peer', content, re.I)),
'Containers': len(re.findall(r'LXC|Docker|container', content, re.I)),
'UI/LuCI': len(re.findall(r'LuCI|dashboard|UI|interface', content, re.I)),
}
return features
def main():
# Header
st.markdown('
🛡️ SecuBox Evolution
', unsafe_allow_html=True)
st.markdown('', unsafe_allow_html=True)
# Fetch all files
with st.spinner("Fetching latest data from GitHub..."):
history = fetch_file(FILES["HISTORY"])
wip = fetch_file(FILES["WIP"])
todo = fetch_file(FILES["TODO"])
readme = fetch_file(FILES["README"])
# Parse data
milestones = parse_history(history)
packages = parse_packages(history or "")
features = count_features(history or "")
# Metrics row
col1, col2, col3, col4 = st.columns(4)
with col1:
st.markdown(f"""
{len(milestones)}
Milestones
""", unsafe_allow_html=True)
with col2:
st.markdown(f"""
""", unsafe_allow_html=True)
with col3:
# Count TODO items
todo_count = len(re.findall(r'^- \[[ x]\]', todo or "", re.M))
st.markdown(f"""
""", unsafe_allow_html=True)
with col4:
# Latest date
latest_date = "N/A"
for m in reversed(milestones):
if m['date']:
latest_date = m['date']
break
st.markdown(f"""
{latest_date}
Last Update
""", unsafe_allow_html=True)
st.markdown("
", unsafe_allow_html=True)
# Sidebar
with st.sidebar:
st.markdown("### 🔍 Search")
search_query = st.text_input("Search in all files", placeholder="e.g., CrowdSec, HAProxy...")
st.markdown("### 📊 Feature Distribution")
if features:
for feat, count in sorted(features.items(), key=lambda x: -x[1]):
if count > 0:
st.progress(min(count / 50, 1.0), text=f"{feat}: {count}")
st.markdown("### 🏷️ Recent Packages")
for pkg in packages[-10:]:
st.markdown(f'{pkg}', unsafe_allow_html=True)
st.markdown("---")
st.markdown("### ⚡ Quick Links")
st.markdown("[GitHub Repository](https://github.com/gkerma/secubox-openwrt)")
st.markdown("[SecuBox Portal](https://secubox.in)")
if st.button("🔄 Refresh Data"):
st.cache_data.clear()
st.rerun()
# Main tabs
tab1, tab2, tab3, tab4, tab5 = st.tabs(["📜 History", "🔧 WIP", "📋 TODO", "📖 README", "📈 Timeline"])
with tab1:
st.markdown("## 📜 Project History")
if search_query and history:
# Highlight search results
highlighted = history.replace(search_query, f'**:green[{search_query}]**')
st.markdown(highlighted)
elif history:
# Show milestones as cards
for m in reversed(milestones[-20:]):
date_str = f"📅 {m['date']}" if m['date'] else ""
st.markdown(f"""
{date_str}
{m['num']}. {m['title']}
""", unsafe_allow_html=True)
with st.expander("📄 View Full History"):
st.markdown(history)
else:
st.error("Could not fetch HISTORY.md")
with tab2:
st.markdown("## 🔧 Work In Progress")
if search_query and wip:
highlighted = wip.replace(search_query, f'**:orange[{search_query}]**')
st.markdown(highlighted)
elif wip:
st.markdown(wip)
else:
st.error("Could not fetch WIP.md")
with tab3:
st.markdown("## 📋 TODO List")
if search_query and todo:
highlighted = todo.replace(search_query, f'**:yellow[{search_query}]**')
st.markdown(highlighted)
elif todo:
# Parse and display TODO items
lines = todo.split('\n')
completed = 0
pending = 0
for line in lines:
if re.match(r'^- \[x\]', line):
completed += 1
elif re.match(r'^- \[ \]', line):
pending += 1
col1, col2 = st.columns(2)
with col1:
st.metric("✅ Completed", completed)
with col2:
st.metric("⏳ Pending", pending)
if completed + pending > 0:
progress = completed / (completed + pending)
st.progress(progress, text=f"Progress: {progress*100:.1f}%")
st.markdown("---")
st.markdown(todo)
else:
st.error("Could not fetch TODO.md")
with tab4:
st.markdown("## 📖 README")
if search_query and readme:
highlighted = readme.replace(search_query, f'**:blue[{search_query}]**')
st.markdown(highlighted)
elif readme:
st.markdown(readme)
else:
st.error("Could not fetch README.md")
with tab5:
st.markdown("## 📈 Evolution Timeline")
if milestones:
# Group by month
months = {}
for m in milestones:
if m['date']:
month = m['date'][:7] # YYYY-MM
if month not in months:
months[month] = []
months[month].append(m)
# Display timeline
for month in sorted(months.keys(), reverse=True):
items = months[month]
month_name = datetime.strptime(month, "%Y-%m").strftime("%B %Y")
st.markdown(f"### 📅 {month_name}")
for item in items:
st.markdown(f"""
{item['title']}
Milestone #{item['num']}
""", unsafe_allow_html=True)
# Chart
st.markdown("### 📊 Milestones per Month")
month_counts = {m: len(items) for m, items in months.items()}
if month_counts:
import pandas as pd
df = pd.DataFrame(list(month_counts.items()), columns=['Month', 'Count'])
df = df.sort_values('Month')
st.bar_chart(df.set_index('Month'))
else:
st.info("No dated milestones found in history")
# Footer
st.markdown("---")
st.markdown("""
SecuBox Evolution Dashboard • Auto-synced with GitHub master branch
Data refreshes every 5 minutes •
View on GitHub
""", unsafe_allow_html=True)
if __name__ == "__main__":
main()