diff --git a/README.md b/README.md
index 464d1ea..f37d9c8 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Telegram C2 command, and a cyber-terminal dashboard.
```
worker.py
-├── Thread A — FastAPI + Dashboard (port 7000)
+├── Thread A — FastAPI + Dashboard (port 3001)
├── Thread B — Async Playwright Scraper (nuclear_engine)
└── Thread C — Telegram C2 Command Listener
```
@@ -45,7 +45,7 @@ playwright install chromium
python worker.py
```
-Then open: **http://localhost:7000**
+Then open: **http://localhost:3001**
---
diff --git a/assets/pasted-20260320-043305-7cfc035f.png b/assets/pasted-20260320-043305-7cfc035f.png
new file mode 100644
index 0000000..f1e2b7c
Binary files /dev/null and b/assets/pasted-20260320-043305-7cfc035f.png differ
diff --git a/branding_decision.md b/branding_decision.md
new file mode 100644
index 0000000..1eb7370
--- /dev/null
+++ b/branding_decision.md
@@ -0,0 +1,9 @@
+# Branding Decision: BidWraith
+
+**Name:** BidWraith (Combined)
+**Rationale:** The combined form implies a singular, stealthy, powerful entity (a "wraith" of the bidding world). It fits the "cyberpunk/tech" aesthetic better than the separated version.
+
+**Visual Aesthetic:**
+- **Palette:** Deep void blacks (#050505), toxic neons (acid green #39FF14, cyber blue #00F3FF, or hazard yellow #FFD700).
+- **Typography:** Monospaced fonts for technical feel, combined with bold, futuristic headers.
+- **Vibe:** "Tech-noir", interactive data streams, floating UI elements, and high-fidelity animations.
diff --git a/docs/Abbas.md b/docs/Abbas.md
index c75ee2e..b81645f 100644
--- a/docs/Abbas.md
+++ b/docs/Abbas.md
@@ -10,6 +10,7 @@
- Direct, minimal punctuation. Prefers intent understood from brief messages; implement changes efficiently without over-explaining.
- When stuck (e.g. CLI, setup), appreciates **step-by-step** instructions, one by one.
- Cares about “best ultimate outcome”; open to bold changes when given full permission.
+- Demands excellence in UX/UI: expects modern, premium, high-quality, and magical interfaces that compete with global top-tier SaaS. Refuses "toy" designs or fake functions.
---
@@ -28,5 +29,4 @@
---
-*The AI adds to this file when it learns or discovers something about Abbas (general, not project-specific).*
-
+*The AI adds to this file when it learns or discovers something about Abbas (general, not project-specific).*
\ No newline at end of file
diff --git a/docs/FEEDBACK.md b/docs/FEEDBACK.md
index c68565e..dc04441 100644
--- a/docs/FEEDBACK.md
+++ b/docs/FEEDBACK.md
@@ -17,8 +17,4 @@
- Chose default Node installer path over portable; docs updated to match.
- Asked for MD file discipline (when to update what); FEEDBACK.md and ERROR.md added on request.
- **Frontend:** Strongly disliked the Session 22 redesign (sidebar nav, grid/glow background, new fonts, heavy panels). Prefers the original React UI and even the legacy HTML dashboard over that. Reverted in Session 24. Future UI changes should be small and match his taste — ask or reference what he likes before a big visual overhaul.
-
----
-
-*Add new bullets above when something is learned that future sessions should use.*
-
+- **Design Preference:** Demands professional, high-end UX/UI that can compete with top-tier international SaaS (Google-level design, magical 3D/animations, premium feel). Explicit permission granted to use any tech (Next.js, React, Tailwind, Framer Motion, Three.js, GSAP, etc.) to achieve this. Requires light/dark mode support with vivid, joyful, magical themes (e.g., bright lavender/ivory palette for light mode). Rejection of "toy-like" designs.
\ No newline at end of file
diff --git a/frontend/app/ai-log/page.tsx b/frontend/app/ai-log/page.tsx
new file mode 100644
index 0000000..f0369db
--- /dev/null
+++ b/frontend/app/ai-log/page.tsx
@@ -0,0 +1,77 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { TerminalSquare, Filter, RefreshCw } from 'lucide-react';
+
+const mockLogs = [
+ { id: 1, time: '10:41:30', agent: 'Analyst', type: 'REJECT', cost: '$0.0012', prompt: 'Evaluate lot: "RTX 4090 Box Only" against criteria...', response: '{"verdict": "REJECT", "reason": "Listing explicitly states \'Box Only\', violating target criteria."}' },
+ { id: 2, time: '10:40:12', agent: 'Analyst', type: 'APPROVE', cost: '$0.0025', prompt: 'Evaluate lot: "ThinkPad T14 Gen 3" against criteria...', response: '{"verdict": "APPROVE", "reason": "Matches specs, good condition, price $450 is significantly below $800 avg."}' },
+ { id: 3, time: '10:39:45', agent: 'Strategist', type: 'OPTIMIZE', cost: '$0.0050', prompt: 'Analyze last 24h win rates on ShopGoodwill...', response: '{"action": "UPDATE_SCHEDULE", "target": "ShopGoodwill", "new_cron": "0 * * * *"}' },
+];
+
+export default function AILogPage() {
+ return (
+
+
+
+
NEURAL_TELEMETRY
+
Raw input/output logs from all connected LLMs.
+
+
+
+ FILTER
+
+
+ REFRESH
+
+
+
+
+
+
+
TIMESTAMP / AGENT
+
TYPE
+
PROMPT_PREVIEW
+
RESPONSE_PREVIEW
+
COST
+
+
+
+ {mockLogs.map((log, i) => (
+
+
+ {log.time}
+ {log.agent}
+
+
+
+ {log.type}
+
+
+
+ {log.prompt}
+
+
+ {log.response}
+
+
+ {log.cost}
+
+
+ ))}
+
+
+
+ End of stream. Waiting for new inferences...
+
+
+
+
+ );
+}
diff --git a/frontend/app/dashboard/page.tsx b/frontend/app/dashboard/page.tsx
new file mode 100644
index 0000000..929d66c
--- /dev/null
+++ b/frontend/app/dashboard/page.tsx
@@ -0,0 +1,87 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { Activity, Zap, ShieldAlert, Cpu } from 'lucide-react';
+
+export default function DashboardPage() {
+ return (
+
+
+
+
SYSTEM_OVERVIEW
+
Real-time status of all autonomous agents.
+
+
+ Status: RUNNING
+
+
+
+
+ {[
+ { title: 'Lots Scanned', value: '142,893', icon: Activity, color: 'text-primary' },
+ { title: 'Active Targets', value: '84', icon: Zap, color: 'text-accent' },
+ { title: 'Alerts Fired', value: '1,204', icon: ShieldAlert, color: 'text-destructive' },
+ { title: 'AI Decisions', value: '89,430', icon: Cpu, color: 'text-primary' },
+ ].map((stat, i) => (
+
+
+ {stat.value}
+
+ ))}
+
+
+
+
+
+ LIVE_ACTIVITY_LOG
+
+
[10:42:01] Scout Agent detected new items on eBay_UK...
+
[10:41:55] Analyst Agent processing 14 lots for "RTX 4090"...
+
[10:41:30] MATCH FOUND: "RTX 4090 Box Only" - Rejected by AI (Reason: Scam)
+
[10:40:12] HIGH VALUE MATCH: "ThinkPad T14 Gen 3" - $450 (Est: $800). Alert Sent.
+
[10:39:45] Strategist Agent optimizing scrape timings for ShopGoodwill...
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/app/globals.css b/frontend/app/globals.css
new file mode 100644
index 0000000..9110754
--- /dev/null
+++ b/frontend/app/globals.css
@@ -0,0 +1,133 @@
+@import "tailwindcss";
+
+@theme {
+ --color-background: oklch(0.145 0 0);
+ --color-foreground: oklch(0.985 0 0);
+ --color-card: oklch(0.145 0 0);
+ --color-card-foreground: oklch(0.985 0 0);
+ --color-popover: oklch(0.145 0 0);
+ --color-popover-foreground: oklch(0.985 0 0);
+ --color-primary: oklch(0.835 0.28 152); /* Neon green #00ff88 equivalent */
+ --color-primary-foreground: oklch(0.145 0 0);
+ --color-secondary: oklch(0.269 0 0);
+ --color-secondary-foreground: oklch(0.985 0 0);
+ --color-muted: oklch(0.269 0 0);
+ --color-muted-foreground: oklch(0.708 0 0);
+ --color-accent: oklch(0.85 0.17 95); /* Neon gold #fbbf24 */
+ --color-accent-foreground: oklch(0.145 0 0);
+ --color-destructive: oklch(0.637 0.237 25.331); /* Neon red #ef4444 */
+ --color-destructive-foreground: oklch(0.985 0 0);
+ --color-border: oklch(0.269 0 0);
+ --color-input: oklch(0.269 0 0);
+ --color-ring: oklch(0.835 0.28 152);
+ --radius: 0.5rem;
+}
+
+@layer base {
+ :root {
+ --background: 222 47% 6%;
+ --foreground: 210 40% 98%;
+ --border: 217 32% 17%;
+ }
+
+ body {
+ background-color: #0a0e17;
+ color: #f8fafc;
+ border-color: #1e293b;
+ background-image:
+ radial-gradient(circle at 15% 50%, rgba(0, 255, 136, 0.04) 0%, transparent 25%),
+ radial-gradient(circle at 85% 30%, rgba(251, 191, 36, 0.04) 0%, transparent 25%);
+ }
+}
+
+/* Custom Cyberpunk Styles */
+.neon-text-primary {
+ text-shadow: 0 0 10px rgba(0, 255, 136, 0.5), 0 0 20px rgba(0, 255, 136, 0.3);
+}
+
+.neon-text-accent {
+ text-shadow: 0 0 10px rgba(251, 191, 36, 0.5), 0 0 20px rgba(251, 191, 36, 0.3);
+}
+
+.neon-box-primary {
+ box-shadow: 0 0 15px rgba(0, 255, 136, 0.2), inset 0 0 10px rgba(0, 255, 136, 0.1);
+ border: 1px solid rgba(0, 255, 136, 0.4);
+}
+
+.neon-box-accent {
+ box-shadow: 0 0 15px rgba(251, 191, 36, 0.2), inset 0 0 10px rgba(251, 191, 36, 0.1);
+ border: 1px solid rgba(251, 191, 36, 0.4);
+}
+
+.cyber-grid {
+ background-size: 40px 40px;
+ background-image:
+ linear-gradient(to right, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
+ linear-gradient(to bottom, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
+ mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
+ -webkit-mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
+}
+
+.glitch-wrapper {
+ position: relative;
+}
+
+.glitch-text::before,
+.glitch-text::after {
+ content: attr(data-text);
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0.8;
+}
+
+.glitch-text::before {
+ color: #0ff;
+ z-index: -1;
+ animation: glitch-anim-1 2s infinite linear alternate-reverse;
+}
+
+.glitch-text::after {
+ color: #f0f;
+ z-index: -2;
+ animation: glitch-anim-2 3s infinite linear alternate-reverse;
+}
+
+@keyframes glitch-anim-1 {
+ 0% { clip-path: inset(20% 0 80% 0); transform: translate(-2px, 1px); }
+ 20% { clip-path: inset(60% 0 10% 0); transform: translate(2px, -1px); }
+ 40% { clip-path: inset(40% 0 50% 0); transform: translate(-2px, 2px); }
+ 60% { clip-path: inset(80% 0 5% 0); transform: translate(2px, -2px); }
+ 80% { clip-path: inset(10% 0 70% 0); transform: translate(-1px, 1px); }
+ 100% { clip-path: inset(30% 0 50% 0); transform: translate(1px, -1px); }
+}
+
+@keyframes glitch-anim-2 {
+ 0% { clip-path: inset(10% 0 60% 0); transform: translate(2px, -1px); }
+ 20% { clip-path: inset(30% 0 20% 0); transform: translate(-2px, 1px); }
+ 40% { clip-path: inset(70% 0 10% 0); transform: translate(2px, -2px); }
+ 60% { clip-path: inset(20% 0 50% 0); transform: translate(-2px, 2px); }
+ 80% { clip-path: inset(50% 0 30% 0); transform: translate(1px, -1px); }
+ 100% { clip-path: inset(5% 0 80% 0); transform: translate(-1px, 1px); }
+}
+
+/* CRT Scanline effect */
+.scanlines::before {
+ content: " ";
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background: linear-gradient(
+ to bottom,
+ rgba(18, 16, 16, 0) 50%,
+ rgba(0, 0, 0, 0.25) 50%
+ );
+ background-size: 100% 4px;
+ z-index: 50;
+ pointer-events: none;
+}
\ No newline at end of file
diff --git a/frontend/app/keywords/page.tsx b/frontend/app/keywords/page.tsx
new file mode 100644
index 0000000..3351cdf
--- /dev/null
+++ b/frontend/app/keywords/page.tsx
@@ -0,0 +1,83 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { Plus, Search, GripVertical, Settings2, Trash2 } from 'lucide-react';
+
+const mockTargets = [
+ { id: 1, term: 'ThinkPad T14 Gen 3', maxPrice: 600, weight: 1.5, status: 'active' },
+ { id: 2, term: 'RTX 3080', maxPrice: 350, weight: 2.0, status: 'active' },
+ { id: 3, term: 'iPhone 12 Pro Unlocked', maxPrice: 200, weight: 1.0, status: 'paused' },
+];
+
+export default function KeywordsPage() {
+ return (
+
+
+
+
TARGET_VECTORS
+
Define what the AI agents should hunt for.
+
+
+ ADD_TARGET
+
+
+
+
+
+
ORDER
+
SEARCH_TERM
+
MAX_PRICE
+
PRIORITY
+
ACTIONS
+
+
+
+ {mockTargets.map((target, i) => (
+
+
+
+
+
+
+ {target.term}
+
+
+ ${target.maxPrice}
+
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
AI_FILTERING_TEMPLATE
+
You can define a natural language description for the LLM to verify against. e.g. "Item must not be broken. Must include power cable. Ignore 'box only' listings."
+
+ // Enter custom instructions for the Analyst Agent here...
+
+
+
+ );
+}
diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
new file mode 100644
index 0000000..5055068
--- /dev/null
+++ b/frontend/app/layout.tsx
@@ -0,0 +1,31 @@
+import type { Metadata } from "next";
+import { Inter, JetBrains_Mono } from "next/font/google";
+import "./globals.css";
+import Navbar from "@/components/Navbar";
+
+const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
+const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-mono" });
+
+export const metadata: Metadata = {
+ title: "BidWraith | The AI Auction Sniper That Never Sleeps",
+ description: "BidWraith continuously watches global auction sites, finds under-priced deals, and sends real-time alerts. Catch every deal before anyone else.",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+ return (
+
+
+ {/* Ambient background particles/grid layer could go here */}
+
+
+
+ {children}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/app/listings/page.tsx b/frontend/app/listings/page.tsx
new file mode 100644
index 0000000..75c4d6e
--- /dev/null
+++ b/frontend/app/listings/page.tsx
@@ -0,0 +1,69 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { ExternalLink, Clock, Brain } from 'lucide-react';
+
+const mockListings = [
+ { id: 1, title: 'Lenovo ThinkPad T14 Gen 3 AMD Ryzen 7', price: '$450.00', estValue: '$800.00', site: 'eBay US', time: '14m 30s', verdict: 'HIGH_OPPORTUNITY' },
+ { id: 2, title: 'NVIDIA RTX 3080 Founders Edition', price: '$320.00', estValue: '$450.00', site: 'HiBid', time: '1h 12m', verdict: 'GOOD_DEAL' },
+ { id: 3, title: 'Lot of 10x iPhone 12 Pro 128GB Unlocked', price: '$1200.00', estValue: '$2500.00', site: 'ShopGoodwill', time: '4h 05m', verdict: 'RESELLER_DREAM' },
+ { id: 4, title: 'Sony A7IV Mirrorless Camera Body', price: '$1500.00', estValue: '$1900.00', site: 'eBay UK', time: '5m 10s', verdict: 'URGENT' },
+];
+
+export default function ListingsPage() {
+ return (
+
+
+
+
ACTIVE_LISTINGS
+
Filtered lots currently matching your target criteria.
+
+
+ Export CSV
+ Force Refresh
+
+
+
+
+ {mockListings.map((lot, i) => (
+
+
+
+
+
+
{lot.title}
+
+ {lot.verdict}
+
+
+
+ {lot.site}
+ {lot.time}
+ Verified
+
+
+
+
+
{lot.price}
+
Est. Value: {lot.estValue}
+
+
+ ANALYZE LOT
+
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
new file mode 100644
index 0000000..7e966b4
--- /dev/null
+++ b/frontend/app/page.tsx
@@ -0,0 +1,144 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { ArrowRight, Crosshair, Brain, BellRing, Ghost } from 'lucide-react';
+import Link from 'next/link';
+import GlitchText from '@/components/GlitchText';
+
+const features = [
+ {
+ icon: Crosshair,
+ title: "Always-On Radar",
+ description: "Monitors dozens of auction sites simultaneously. The engine never sleeps, so you never miss an ending lot.",
+ },
+ {
+ icon: Brain,
+ title: "AI-Grade Filtering",
+ description: "External LLMs score and filter every lot against your precise custom targets. We drop the noise and show only true deals.",
+ },
+ {
+ icon: BellRing,
+ title: "Real-Time Comms",
+ description: "Instant alerts delivered via Telegram, Discord, or Email the minute a high-value lot appears or is about to close.",
+ },
+ {
+ icon: Ghost,
+ title: "Stealth Engine",
+ description: "Human-like browsing algorithms bypass standard detection, ensuring reliable intelligence gathering from any platform.",
+ }
+];
+
+export default function LandingPage() {
+ return (
+
+ {/* Hero Section */}
+
+
+
+
+ System v4 Deployed
+
+
+ The AI Sniper That
+
+
+
+ BidWraith watches every global auction site, scores every lot with AI, and alerts you the moment a real deal drops.
+
+
+
+
+ Initialize Console
+
+
+ Read Briefing
+
+
+
+
+
+ {/* Stats Strip */}
+
+
+ {/* Features Section */}
+
+
+
+
Core Directives
+
Advanced architecture designed to give you an unfair advantage in the global market.
+
+
+
+ {features.map((feature, idx) => (
+
+
+
+ {feature.title}
+
+ {feature.description}
+
+
+ ))}
+
+
+
+
+ {/* Diagram Section */}
+
+
+
The Execution Pipeline
+
+
Targets & Rules
+
+
Ghost Scraper
+
+
AI Analysis
+
+
Real-time Alerts
+
+
+
+
+ {/* Footer CTA */}
+
+ Ready to dominate the market?
+
+ > ACCESS_SYSTEM_NOW _
+
+
+
+ );
+}
diff --git a/frontend/app/settings/page.tsx b/frontend/app/settings/page.tsx
new file mode 100644
index 0000000..8ce8053
--- /dev/null
+++ b/frontend/app/settings/page.tsx
@@ -0,0 +1,98 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { Save, Bell, Shield, Database, Cpu } from 'lucide-react';
+
+export default function SettingsPage() {
+ return (
+
+
+
+
SYSTEM_CONFIG
+
Adjust core parameters, AI models, and notification routing.
+
+
+ COMMIT_CHANGES
+
+
+
+
+
+
+ AI_ENGINE_SETTINGS
+
+
+ Primary Provider
+
+ Anthropic (Claude 3.5 Sonnet)
+ OpenAI (GPT-4o)
+ Groq (Llama 3 70B)
+ Ollama (Local)
+
+
+
+ Strictness Level
+
+ High (Miss deals, zero noise)
+ Balanced
+ Low (Catch everything, more noise)
+
+
+
+ API Key
+
+
+
+
+
+
+ ALERT_ROUTING
+
+
+
+
Telegram Bot
+
Status: Connected (@BidWraithBot)
+
+
+
+
+
+
Discord Webhook
+
Status: Not Configured
+
+
+
+
+
+
+
+
+
+ STEALTH_MODE
+
+
+
Humanization Level
+
+
Fast/Bot Slow/Human
+
+
+
+ Use Proxy Rotation
+
+
+
+
+
+
+ DATA_MANAGEMENT
+
+ Export Database Backup
+ Clear Old Logs (>30d)
+ FACTORY RESET
+
+
+
+
+
+ );
+}
diff --git a/frontend/app/sites/page.tsx b/frontend/app/sites/page.tsx
new file mode 100644
index 0000000..4d78bc7
--- /dev/null
+++ b/frontend/app/sites/page.tsx
@@ -0,0 +1,90 @@
+"use client";
+
+import { motion } from 'framer-motion';
+import { ShieldCheck, ShieldAlert, Cpu, Terminal } from 'lucide-react';
+
+const mockSites = [
+ { id: 1, name: 'eBay US', url: 'ebay.com', status: 'healthy', lag: '240ms', lastScrape: '2s ago' },
+ { id: 2, name: 'eBay UK', url: 'ebay.co.uk', status: 'healthy', lag: '310ms', lastScrape: '5s ago' },
+ { id: 3, name: 'HiBid', url: 'hibid.com', status: 'warning', lag: '1200ms', lastScrape: '1m ago' },
+ { id: 4, name: 'ShopGoodwill', url: 'shopgoodwill.com', status: 'healthy', lag: '450ms', lastScrape: '12s ago' },
+];
+
+export default function SitesPage() {
+ return (
+
+
+
+
NETWORK_NODES
+
Manage auction platforms targeted by the scraping engine.
+
+
+ ADAPT_NEW_SITE
+
+
+
+
+ {mockSites.map((site, i) => (
+
+
+
+
{site.name}
+
{site.url}
+
+ {site.status === 'healthy' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ Latency:
+ {site.lag}
+
+
+ Last Ping:
+ {site.lastScrape}
+
+
+ Selectors:
+ Verified
+
+
+
+
+
+ Inspect
+
+
+ Pause
+
+
+
+ ))}
+
+
+
+
+ AUTO_ADAPTATION_ENGINE
+
+
+ Ghost Node can autonomously learn new site structures. Provide a target URL, and the Scout Agent will attempt to generate valid CSS selectors for listings, prices, and countdown timers.
+
+
+
+
+ INITIATE_SCAN
+
+
+
+
+ );
+}
diff --git a/frontend/components/GlitchText.tsx b/frontend/components/GlitchText.tsx
new file mode 100644
index 0000000..447cd19
--- /dev/null
+++ b/frontend/components/GlitchText.tsx
@@ -0,0 +1,16 @@
+"use client";
+
+import React from 'react';
+
+export default function GlitchText({ text, className = "" }: { text: string; className?: string }) {
+ return (
+
+
+ {text}
+
+
+ );
+}
diff --git a/frontend/components/Navbar.tsx b/frontend/components/Navbar.tsx
new file mode 100644
index 0000000..ec9eb7c
--- /dev/null
+++ b/frontend/components/Navbar.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { Activity, LayoutDashboard, List, Search, Globe, Settings, TerminalSquare } from 'lucide-react';
+import GlitchText from './GlitchText';
+import { motion } from 'framer-motion';
+
+const navItems = [
+ { name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard },
+ { name: 'Listings', href: '/listings', icon: List },
+ { name: 'Targets', href: '/keywords', icon: Search },
+ { name: 'Sites', href: '/sites', icon: Globe },
+ { name: 'AI Log', href: '/ai-log', icon: TerminalSquare },
+ { name: 'Settings', href: '/settings', icon: Settings },
+];
+
+export default function Navbar() {
+ const pathname = usePathname();
+
+ return (
+
+
+
+
+
+
+
+ {navItems.map((item) => {
+ const isActive = pathname.startsWith(item.href);
+ return (
+
+
+ {item.name}
+ {isActive && (
+
+ )}
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/frontend/dev.log b/frontend/dev.log
new file mode 100644
index 0000000..22cb552
--- /dev/null
+++ b/frontend/dev.log
@@ -0,0 +1,17 @@
+
+> frontend@0.1.0 dev
+> next dev
+
+⚠ Warning: Next.js inferred your workspace root, but it may not be correct.
+ We detected multiple lockfiles and selected the directory of /home/ubuntu/executor/package-lock.json as the root directory.
+ To silence this warning, set `turbopack.root` in your Next.js config, or consider removing one of the lockfiles if it's not needed.
+ See https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopack#root-directory for more information.
+ Detected additional lockfiles:
+ * /home/ubuntu/executor/workspace/frontend/package-lock.json
+
+▲ Next.js 16.1.6 (Turbopack)
+- Local: http://localhost:3000
+- Network: http://10.128.0.61:3000
+
+✓ Starting...
+✓ Ready in 2.1s
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 3deea1c..f78b023 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -16,21 +16,17 @@
"@radix-ui/react-toast": "^1.2.15",
"@tanstack/react-query": "^5.90.21",
"class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "framer-motion": "^12.36.0",
- "lucide-react": "^0.577.0",
"motion": "^12.36.0",
"next": "16.1.6",
"radix-ui": "^1.4.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"shadcn": "^4.0.6",
- "tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"zustand": "^5.0.11"
},
"devDependencies": {
- "@tailwindcss/postcss": "^4",
+ "@tailwindcss/postcss": "^4.2.2",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
@@ -38,10 +34,16 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^5.1.4",
+ "autoprefixer": "^10.4.27",
+ "clsx": "^2.1.1",
"eslint": "^9",
"eslint-config-next": "16.1.6",
+ "framer-motion": "^12.38.0",
"jsdom": "^28.1.0",
- "tailwindcss": "^4",
+ "lucide-react": "^0.577.0",
+ "postcss": "^8.5.8",
+ "tailwind-merge": "^3.5.0",
+ "tailwindcss": "^4.0.0",
"typescript": "^5",
"vitest": "^4.0.18"
}
@@ -4710,49 +4712,56 @@
}
},
"node_modules/@tailwindcss/node": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz",
- "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz",
+ "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.5",
"enhanced-resolve": "^5.19.0",
"jiti": "^2.6.1",
- "lightningcss": "1.31.1",
+ "lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
- "tailwindcss": "4.2.1"
+ "tailwindcss": "4.2.2"
}
},
+ "node_modules/@tailwindcss/node/node_modules/tailwindcss": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
+ "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@tailwindcss/oxide": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz",
- "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz",
+ "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 20"
},
"optionalDependencies": {
- "@tailwindcss/oxide-android-arm64": "4.2.1",
- "@tailwindcss/oxide-darwin-arm64": "4.2.1",
- "@tailwindcss/oxide-darwin-x64": "4.2.1",
- "@tailwindcss/oxide-freebsd-x64": "4.2.1",
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1",
- "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1",
- "@tailwindcss/oxide-linux-arm64-musl": "4.2.1",
- "@tailwindcss/oxide-linux-x64-gnu": "4.2.1",
- "@tailwindcss/oxide-linux-x64-musl": "4.2.1",
- "@tailwindcss/oxide-wasm32-wasi": "4.2.1",
- "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1",
- "@tailwindcss/oxide-win32-x64-msvc": "4.2.1"
+ "@tailwindcss/oxide-android-arm64": "4.2.2",
+ "@tailwindcss/oxide-darwin-arm64": "4.2.2",
+ "@tailwindcss/oxide-darwin-x64": "4.2.2",
+ "@tailwindcss/oxide-freebsd-x64": "4.2.2",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.2.2",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.2.2",
+ "@tailwindcss/oxide-linux-x64-musl": "4.2.2",
+ "@tailwindcss/oxide-wasm32-wasi": "4.2.2",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.2.2"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz",
- "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz",
+ "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==",
"cpu": [
"arm64"
],
@@ -4767,9 +4776,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz",
- "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz",
+ "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==",
"cpu": [
"arm64"
],
@@ -4784,9 +4793,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz",
- "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz",
+ "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==",
"cpu": [
"x64"
],
@@ -4801,9 +4810,9 @@
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz",
- "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz",
+ "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==",
"cpu": [
"x64"
],
@@ -4818,9 +4827,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz",
- "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz",
+ "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==",
"cpu": [
"arm"
],
@@ -4835,9 +4844,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz",
- "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz",
+ "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==",
"cpu": [
"arm64"
],
@@ -4852,9 +4861,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz",
- "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz",
+ "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==",
"cpu": [
"arm64"
],
@@ -4869,9 +4878,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz",
- "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz",
+ "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==",
"cpu": [
"x64"
],
@@ -4886,9 +4895,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz",
- "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz",
+ "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==",
"cpu": [
"x64"
],
@@ -4903,9 +4912,9 @@
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz",
- "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz",
+ "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
@@ -4932,74 +4941,10 @@
"node": ">=14.0.0"
}
},
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
- "version": "1.8.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.1.0",
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
- "version": "1.8.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
- "version": "1.1.0",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1",
- "@tybys/wasm-util": "^0.10.1"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Brooooooklyn"
- }
- },
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
- "version": "0.10.1",
- "dev": true,
- "inBundle": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
- "version": "2.8.1",
- "dev": true,
- "inBundle": true,
- "license": "0BSD",
- "optional": true
- },
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz",
- "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz",
+ "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==",
"cpu": [
"arm64"
],
@@ -5014,9 +4959,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz",
- "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz",
+ "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==",
"cpu": [
"x64"
],
@@ -5031,19 +4976,26 @@
}
},
"node_modules/@tailwindcss/postcss": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.1.tgz",
- "integrity": "sha512-OEwGIBnXnj7zJeonOh6ZG9woofIjGrd2BORfvE5p9USYKDCZoQmfqLcfNiRWoJlRWLdNPn2IgVZuWAOM4iTYMw==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz",
+ "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
- "@tailwindcss/node": "4.2.1",
- "@tailwindcss/oxide": "4.2.1",
+ "@tailwindcss/node": "4.2.2",
+ "@tailwindcss/oxide": "4.2.2",
"postcss": "^8.5.6",
- "tailwindcss": "4.2.1"
+ "tailwindcss": "4.2.2"
}
},
+ "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
+ "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@tanstack/query-core": {
"version": "5.90.20",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz",
@@ -6448,6 +6400,43 @@
"node": ">= 0.4"
}
},
+ "node_modules/autoprefixer": {
+ "version": "10.4.27",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz",
+ "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.28.1",
+ "caniuse-lite": "^1.0.30001774",
+ "fraction.js": "^5.3.4",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -7408,9 +7397,9 @@
}
},
"node_modules/enhanced-resolve": {
- "version": "5.20.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz",
- "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==",
+ "version": "5.20.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
+ "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8518,13 +8507,27 @@
"node": ">= 0.6"
}
},
+ "node_modules/fraction.js": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
+ "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
"node_modules/framer-motion": {
- "version": "12.36.0",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.36.0.tgz",
- "integrity": "sha512-4PqYHAT7gev0ke0wos+PyrcFxI0HScjm3asgU8nSYa8YzJFuwgIvdj3/s3ZaxLq0bUSboIn19A2WS/MHwLCvfw==",
+ "version": "12.38.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz",
+ "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==",
"license": "MIT",
"dependencies": {
- "motion-dom": "^12.36.0",
+ "motion-dom": "^12.38.0",
"motion-utils": "^12.36.0",
"tslib": "^2.4.0"
},
@@ -9969,9 +9972,9 @@
}
},
"node_modules/lightningcss": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
- "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
"dev": true,
"license": "MPL-2.0",
"dependencies": {
@@ -9985,23 +9988,23 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
- "lightningcss-android-arm64": "1.31.1",
- "lightningcss-darwin-arm64": "1.31.1",
- "lightningcss-darwin-x64": "1.31.1",
- "lightningcss-freebsd-x64": "1.31.1",
- "lightningcss-linux-arm-gnueabihf": "1.31.1",
- "lightningcss-linux-arm64-gnu": "1.31.1",
- "lightningcss-linux-arm64-musl": "1.31.1",
- "lightningcss-linux-x64-gnu": "1.31.1",
- "lightningcss-linux-x64-musl": "1.31.1",
- "lightningcss-win32-arm64-msvc": "1.31.1",
- "lightningcss-win32-x64-msvc": "1.31.1"
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
}
},
"node_modules/lightningcss-android-arm64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
- "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
"cpu": [
"arm64"
],
@@ -10020,9 +10023,9 @@
}
},
"node_modules/lightningcss-darwin-arm64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
- "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
"cpu": [
"arm64"
],
@@ -10041,9 +10044,9 @@
}
},
"node_modules/lightningcss-darwin-x64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
- "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
"cpu": [
"x64"
],
@@ -10062,9 +10065,9 @@
}
},
"node_modules/lightningcss-freebsd-x64": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
- "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
"cpu": [
"x64"
],
@@ -10083,9 +10086,9 @@
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
- "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
"cpu": [
"arm"
],
@@ -10104,9 +10107,9 @@
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
- "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
"cpu": [
"arm64"
],
@@ -10125,9 +10128,9 @@
}
},
"node_modules/lightningcss-linux-arm64-musl": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
- "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
"cpu": [
"arm64"
],
@@ -10146,9 +10149,9 @@
}
},
"node_modules/lightningcss-linux-x64-gnu": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
- "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
"cpu": [
"x64"
],
@@ -10167,9 +10170,9 @@
}
},
"node_modules/lightningcss-linux-x64-musl": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
- "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
"cpu": [
"x64"
],
@@ -10188,9 +10191,9 @@
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
- "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
"cpu": [
"arm64"
],
@@ -10209,9 +10212,9 @@
}
},
"node_modules/lightningcss-win32-x64-msvc": {
- "version": "1.31.1",
- "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
- "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
"cpu": [
"x64"
],
@@ -10324,6 +10327,7 @@
"version": "0.577.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.577.0.tgz",
"integrity": "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==",
+ "dev": true,
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -10520,9 +10524,9 @@
}
},
"node_modules/motion-dom": {
- "version": "12.36.0",
- "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.36.0.tgz",
- "integrity": "sha512-Ep1pq8P88rGJ75om8lTCA13zqd7ywPGwCqwuWwin6BKc0hMLkVfcS6qKlRqEo2+t0DwoUcgGJfXwaiFn4AOcQA==",
+ "version": "12.38.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz",
+ "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.36.0"
@@ -11327,6 +11331,13 @@
"node": ">=4"
}
},
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/powershell-utils": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz",
@@ -12838,9 +12849,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz",
- "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0.tgz",
+ "integrity": "sha512-ULRPI3A+e39T7pSaf1xoi58AqqJxVCLg8F/uM5A3FadUbnyDTgltVnXJvdkTjwCOGA6NazqHVcwPJC5h2vRYVQ==",
"dev": true,
"license": "MIT"
},
diff --git a/frontend/package.json b/frontend/package.json
index bc5b462..1f9aa45 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -26,21 +26,17 @@
"@radix-ui/react-toast": "^1.2.15",
"@tanstack/react-query": "^5.90.21",
"class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "framer-motion": "^12.36.0",
- "lucide-react": "^0.577.0",
"motion": "^12.36.0",
"next": "16.1.6",
"radix-ui": "^1.4.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"shadcn": "^4.0.6",
- "tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"zustand": "^5.0.11"
},
"devDependencies": {
- "@tailwindcss/postcss": "^4",
+ "@tailwindcss/postcss": "^4.2.2",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
@@ -48,10 +44,16 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^5.1.4",
+ "autoprefixer": "^10.4.27",
+ "clsx": "^2.1.1",
"eslint": "^9",
"eslint-config-next": "16.1.6",
+ "framer-motion": "^12.38.0",
"jsdom": "^28.1.0",
- "tailwindcss": "^4",
+ "lucide-react": "^0.577.0",
+ "postcss": "^8.5.8",
+ "tailwind-merge": "^3.5.0",
+ "tailwindcss": "^4.0.0",
"typescript": "^5",
"vitest": "^4.0.18"
}
diff --git a/frontend/public/file.svg b/frontend/public/file.svg
deleted file mode 100644
index 004145c..0000000
--- a/frontend/public/file.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/public/globe.svg b/frontend/public/globe.svg
deleted file mode 100644
index 567f17b..0000000
--- a/frontend/public/globe.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/public/next.svg b/frontend/public/next.svg
deleted file mode 100644
index 5174b28..0000000
--- a/frontend/public/next.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/public/vercel.svg b/frontend/public/vercel.svg
deleted file mode 100644
index 7705396..0000000
--- a/frontend/public/vercel.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/public/window.svg b/frontend/public/window.svg
deleted file mode 100644
index b2b2a44..0000000
--- a/frontend/public/window.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/worker.py b/worker.py
index 56eb7a9..e376f20 100644
--- a/worker.py
+++ b/worker.py
@@ -1,7 +1,7 @@
"""
Ghost Node — Worker
Three-thread architecture:
- Thread A → FastAPI dashboard (port 7000)
+ Thread A → FastAPI dashboard (port 3001)
Thread B → Async Playwright scraper (nuclear_engine)
Thread C → Telegram C2 polling loop
"""
@@ -4586,6 +4586,7 @@ async def nuclear_engine() -> None:
_boost_secs = int(_get_config("boost_interval_mins", "2")) * 60
_db_boost = SessionLocal()
try:
+ from datetime import timedelta
_soon_cutoff = datetime.now() + timedelta(minutes=30)
_closing_soon = _db_boost.query(Listing).filter(
Listing.time_left_mins != None,
@@ -5497,12 +5498,12 @@ def engine_restart():
then spawns a brand-new Python process running the same script with
the same arguments via subprocess.Popen.
3. After spawning the child, the current process calls os._exit(0) to
- terminate itself immediately and release port 7000.
+ terminate itself immediately and release port 3001.
Why not os.execv?
os.execv works on Linux but on Windows it does NOT replace the current
process — it creates a new one while the old one keeps running, which
- causes an "address already in use" error on port 7000.
+ causes an "address already in use" error on port 3001.
Why subprocess.Popen + os._exit(0)?
Popen detaches the child before the parent exits, so the child is
@@ -5527,7 +5528,7 @@ def engine_restart():
except Exception as exc:
print(f"[GhostNode] ❌ Restart failed: {exc}")
return
- # Kill this process immediately — port 7000 is now free for the child
+ # Kill this process immediately — port 3001 is now free for the child
os._exit(0)
threading.Thread(target=_do_restart, daemon=True, name="GhostNode-Restart").start()
@@ -6035,7 +6036,7 @@ if __name__ == "__main__":
)
closing_thread.start()
- print("[GhostNode] 🕵️ Ghost Node online — Dashboard → http://localhost:7000")
+ print("[GhostNode] 🕵️ Ghost Node online — Dashboard → http://localhost:3001")
# Thread A (FastAPI via uvicorn — blocks main thread)
- uvicorn.run(app, host="0.0.0.0", port=7000, log_level="warning")
+ uvicorn.run(app, host="0.0.0.0", port=3001, log_level="warning")