Autosave: 20260320-055648
This commit is contained in:
parent
b94f93da93
commit
2daa593025
@ -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**
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
assets/pasted-20260320-043305-7cfc035f.png
Normal file
BIN
assets/pasted-20260320-043305-7cfc035f.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
9
branding_decision.md
Normal file
9
branding_decision.md
Normal file
@ -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.
|
||||
@ -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).*
|
||||
@ -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.
|
||||
77
frontend/app/ai-log/page.tsx
Normal file
77
frontend/app/ai-log/page.tsx
Normal file
@ -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 (
|
||||
<div className="container mx-auto px-4 py-8 h-[calc(100vh-64px)] flex flex-col">
|
||||
<div className="flex justify-between items-end mb-6 shrink-0">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">NEURAL_<span className="text-primary">TELEMETRY</span></h1>
|
||||
<p className="text-muted-foreground">Raw input/output logs from all connected LLMs.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="flex items-center gap-2 px-3 py-1.5 bg-card border border-border rounded font-mono text-xs hover:border-primary transition-colors">
|
||||
<Filter className="w-3 h-3" /> FILTER
|
||||
</button>
|
||||
<button className="flex items-center gap-2 px-3 py-1.5 bg-card border border-border rounded font-mono text-xs hover:text-primary transition-colors">
|
||||
<RefreshCw className="w-3 h-3" /> REFRESH
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 bg-card border border-border rounded-lg overflow-hidden flex flex-col">
|
||||
<div className="grid grid-cols-12 gap-4 p-3 border-b border-border bg-background/50 font-mono text-xs text-muted-foreground shrink-0">
|
||||
<div className="col-span-2">TIMESTAMP / AGENT</div>
|
||||
<div className="col-span-1">TYPE</div>
|
||||
<div className="col-span-4">PROMPT_PREVIEW</div>
|
||||
<div className="col-span-4">RESPONSE_PREVIEW</div>
|
||||
<div className="col-span-1 text-right">COST</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto p-2 space-y-2">
|
||||
{mockLogs.map((log, i) => (
|
||||
<motion.div
|
||||
key={log.id}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="grid grid-cols-12 gap-4 p-3 bg-background border border-border/50 rounded font-mono text-sm hover:border-primary/50 transition-colors cursor-pointer"
|
||||
>
|
||||
<div className="col-span-2 flex flex-col justify-center">
|
||||
<span className="text-primary">{log.time}</span>
|
||||
<span className="text-xs text-muted-foreground">{log.agent}</span>
|
||||
</div>
|
||||
<div className="col-span-1 flex items-center">
|
||||
<span className={`px-2 py-0.5 rounded text-xs ${log.type === 'APPROVE' ? 'bg-primary/20 text-primary' : log.type === 'REJECT' ? 'bg-destructive/20 text-destructive' : 'bg-accent/20 text-accent'}`}>
|
||||
{log.type}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-4 text-muted-foreground truncate flex items-center">
|
||||
{log.prompt}
|
||||
</div>
|
||||
<div className="col-span-4 truncate flex items-center">
|
||||
{log.response}
|
||||
</div>
|
||||
<div className="col-span-1 text-right flex items-center justify-end text-xs text-muted-foreground">
|
||||
{log.cost}
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
|
||||
<div className="text-center p-8 text-muted-foreground font-mono text-sm">
|
||||
<TerminalSquare className="w-8 h-8 mx-auto mb-2 opacity-50" />
|
||||
End of stream. Waiting for new inferences...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
87
frontend/app/dashboard/page.tsx
Normal file
87
frontend/app/dashboard/page.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { Activity, Zap, ShieldAlert, Cpu } from 'lucide-react';
|
||||
|
||||
export default function DashboardPage() {
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">SYSTEM_<span className="text-primary">OVERVIEW</span></h1>
|
||||
<p className="text-muted-foreground">Real-time status of all autonomous agents.</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 bg-card border border-border rounded font-mono text-sm">
|
||||
Status: <span className="text-primary animate-pulse">RUNNING</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||
{[
|
||||
{ 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) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="p-6 bg-card border border-border rounded-lg"
|
||||
>
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div className="text-muted-foreground font-mono text-sm">{stat.title}</div>
|
||||
<stat.icon className={`w-5 h-5 ${stat.color}`} />
|
||||
</div>
|
||||
<div className={`text-3xl font-bold font-mono ${stat.color}`}>{stat.value}</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid lg:grid-cols-3 gap-8">
|
||||
<div className="col-span-2">
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.4 }}
|
||||
className="p-6 bg-card border border-border rounded-lg h-96 flex flex-col"
|
||||
>
|
||||
<h2 className="text-xl font-bold font-mono mb-4 border-b border-border pb-2">LIVE_ACTIVITY_LOG</h2>
|
||||
<div className="flex-1 overflow-auto font-mono text-sm space-y-3">
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:42:01]</span> <span>Scout Agent detected new items on eBay_UK...</span></div>
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:41:55]</span> <span>Analyst Agent processing 14 lots for "RTX 4090"...</span></div>
|
||||
<div className="flex gap-4 text-accent"><span className="text-primary">[10:41:30]</span> <span>MATCH FOUND: "RTX 4090 Box Only" - Rejected by AI (Reason: Scam)</span></div>
|
||||
<div className="flex gap-4 text-primary"><span className="text-primary">[10:40:12]</span> <span>HIGH VALUE MATCH: "ThinkPad T14 Gen 3" - $450 (Est: $800). Alert Sent.</span></div>
|
||||
<div className="flex gap-4 text-muted-foreground"><span className="text-primary">[10:39:45]</span> <span>Strategist Agent optimizing scrape timings for ShopGoodwill...</span></div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
<div>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.5 }}
|
||||
className="p-6 bg-card border border-border rounded-lg h-96"
|
||||
>
|
||||
<h2 className="text-xl font-bold font-mono mb-4 border-b border-border pb-2">NODE_HEALTH</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>eBay US</span> <span className="text-primary">100%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '100%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>eBay UK</span> <span className="text-primary">98%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '98%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>HiBid</span> <span className="text-accent">85%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-accent h-1.5 rounded-full" style={{width: '85%'}}></div></div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-sm mb-1 font-mono"><span>ShopGoodwill</span> <span className="text-primary">99%</span></div>
|
||||
<div className="w-full bg-background rounded-full h-1.5"><div className="bg-primary h-1.5 rounded-full" style={{width: '99%'}}></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
133
frontend/app/globals.css
Normal file
133
frontend/app/globals.css
Normal file
@ -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;
|
||||
}
|
||||
83
frontend/app/keywords/page.tsx
Normal file
83
frontend/app/keywords/page.tsx
Normal file
@ -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 (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">TARGET_<span className="text-accent">VECTORS</span></h1>
|
||||
<p className="text-muted-foreground">Define what the AI agents should hunt for.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-4 py-2 bg-accent hover:bg-accent/90 text-accent-foreground rounded font-mono text-sm font-bold shadow-[0_0_15px_rgba(251,191,36,0.3)]">
|
||||
<Plus className="w-4 h-4" /> ADD_TARGET
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="bg-card border border-border rounded-lg overflow-hidden">
|
||||
<div className="grid grid-cols-12 gap-4 p-4 border-b border-border bg-background/50 font-mono text-xs text-muted-foreground">
|
||||
<div className="col-span-1">ORDER</div>
|
||||
<div className="col-span-5">SEARCH_TERM</div>
|
||||
<div className="col-span-2">MAX_PRICE</div>
|
||||
<div className="col-span-2">PRIORITY</div>
|
||||
<div className="col-span-2 text-right">ACTIONS</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{mockTargets.map((target, i) => (
|
||||
<motion.div
|
||||
key={target.id}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="grid grid-cols-12 gap-4 p-4 border-b border-border/50 items-center hover:bg-background/30 transition-colors group"
|
||||
>
|
||||
<div className="col-span-1 text-muted-foreground">
|
||||
<GripVertical className="w-4 h-4 cursor-grab" />
|
||||
</div>
|
||||
<div className="col-span-5 font-bold flex items-center gap-2">
|
||||
<Search className="w-4 h-4 text-primary" />
|
||||
{target.term}
|
||||
</div>
|
||||
<div className="col-span-2 font-mono">
|
||||
${target.maxPrice}
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-16 h-1.5 bg-background rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent" style={{width: `${(target.weight / 2) * 100}%`}}></div>
|
||||
</div>
|
||||
<span className="font-mono text-xs">{target.weight}x</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2 flex justify-end gap-2">
|
||||
<button className="p-2 hover:bg-background rounded text-muted-foreground hover:text-primary transition-colors">
|
||||
<Settings2 className="w-4 h-4" />
|
||||
</button>
|
||||
<button className="p-2 hover:bg-background rounded text-muted-foreground hover:text-destructive transition-colors">
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-8 p-6 border border-border border-dashed rounded-lg bg-card/30">
|
||||
<h3 className="font-mono text-primary mb-2 flex items-center gap-2"><Settings2 className="w-4 h-4" /> AI_FILTERING_TEMPLATE</h3>
|
||||
<p className="text-sm text-muted-foreground mb-4">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."</p>
|
||||
<div className="w-full h-24 bg-background border border-border rounded p-3 font-mono text-sm text-muted-foreground cursor-text">
|
||||
// Enter custom instructions for the Analyst Agent here...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
frontend/app/layout.tsx
Normal file
31
frontend/app/layout.tsx
Normal file
@ -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 (
|
||||
<html lang="en" className={`${inter.variable} ${jetbrainsMono.variable} dark`}>
|
||||
<body className={`${inter.className} bg-background text-foreground antialiased min-h-screen flex flex-col scanlines`}>
|
||||
{/* Ambient background particles/grid layer could go here */}
|
||||
<div className="fixed inset-0 cyber-grid -z-10 opacity-30 pointer-events-none" />
|
||||
<Navbar />
|
||||
<main className="flex-1">
|
||||
{children}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
69
frontend/app/listings/page.tsx
Normal file
69
frontend/app/listings/page.tsx
Normal file
@ -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 (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">ACTIVE_<span className="text-primary">LISTINGS</span></h1>
|
||||
<p className="text-muted-foreground">Filtered lots currently matching your target criteria.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="px-4 py-2 bg-card border border-border rounded font-mono text-sm hover:border-primary transition-colors">Export CSV</button>
|
||||
<button className="px-4 py-2 bg-primary text-primary-foreground rounded font-mono text-sm font-bold shadow-[0_0_10px_rgba(0,255,136,0.3)]">Force Refresh</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4">
|
||||
{mockListings.map((lot, i) => (
|
||||
<motion.div
|
||||
key={lot.id}
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className="flex flex-col md:flex-row gap-4 p-4 bg-card border border-border hover:border-primary/50 transition-colors rounded-lg group"
|
||||
>
|
||||
<div className="w-full md:w-48 h-32 bg-background rounded border border-border flex items-center justify-center text-muted-foreground font-mono text-xs overflow-hidden relative">
|
||||
<div className="absolute inset-0 bg-gradient-to-tr from-primary/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity"></div>
|
||||
[IMAGE_DATA]
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col justify-between">
|
||||
<div>
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<h3 className="font-bold text-lg leading-tight group-hover:text-primary transition-colors">{lot.title}</h3>
|
||||
<div className={`px-2 py-1 text-xs font-mono rounded ${lot.verdict === 'URGENT' ? 'bg-destructive/20 text-destructive border border-destructive/30' : 'bg-primary/10 text-primary border border-primary/30'}`}>
|
||||
{lot.verdict}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-sm font-mono text-muted-foreground mb-4">
|
||||
<span className="flex items-center gap-1"><ExternalLink className="w-3 h-3" /> {lot.site}</span>
|
||||
<span className="flex items-center gap-1 text-accent"><Clock className="w-3 h-3" /> {lot.time}</span>
|
||||
<span className="flex items-center gap-1"><Brain className="w-3 h-3 text-primary" /> Verified</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between items-end">
|
||||
<div>
|
||||
<div className="text-2xl font-bold font-mono">{lot.price}</div>
|
||||
<div className="text-xs font-mono text-muted-foreground">Est. Value: <span className="line-through">{lot.estValue}</span></div>
|
||||
</div>
|
||||
<button className="px-6 py-2 bg-background border border-border hover:border-primary hover:text-primary rounded font-mono text-sm transition-all group-hover:shadow-[0_0_15px_rgba(0,255,136,0.1)]">
|
||||
ANALYZE LOT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
144
frontend/app/page.tsx
Normal file
144
frontend/app/page.tsx
Normal file
@ -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 (
|
||||
<div className="relative overflow-hidden w-full">
|
||||
{/* Hero Section */}
|
||||
<section className="container mx-auto px-4 pt-32 pb-24 text-center relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="max-w-4xl mx-auto"
|
||||
>
|
||||
<div className="mb-6 inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/30 text-primary text-sm font-mono uppercase">
|
||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse"></span>
|
||||
System v4 Deployed
|
||||
</div>
|
||||
<h1 className="text-5xl md:text-7xl font-bold mb-6 tracking-tight">
|
||||
The AI Sniper That <br />
|
||||
<span className="text-primary neon-text-primary"><GlitchText text="NEVER SLEEPS" /></span>
|
||||
</h1>
|
||||
<p className="text-xl md:text-2xl text-muted-foreground mb-10 max-w-2xl mx-auto">
|
||||
BidWraith watches every global auction site, scores every lot with AI, and alerts you the moment a real deal drops.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Link href="/dashboard" className="inline-flex items-center justify-center gap-2 bg-primary hover:bg-primary/90 text-primary-foreground px-8 py-4 rounded-md font-bold text-lg transition-all shadow-[0_0_20px_rgba(0,255,136,0.3)] hover:shadow-[0_0_30px_rgba(0,255,136,0.5)]">
|
||||
Initialize Console <ArrowRight className="w-5 h-5" />
|
||||
</Link>
|
||||
<Link href="#features" className="inline-flex items-center justify-center gap-2 bg-card hover:bg-card/80 border border-border px-8 py-4 rounded-md font-bold text-lg transition-colors">
|
||||
Read Briefing
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</section>
|
||||
|
||||
{/* Stats Strip */}
|
||||
<section className="border-y border-border bg-card/50 backdrop-blur-sm py-8 relative z-10">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center font-mono">
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-primary mb-1">24/7</div>
|
||||
<div className="text-sm text-muted-foreground">Uptime</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-accent mb-1">< 1s</div>
|
||||
<div className="text-sm text-muted-foreground">Alert Latency</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-primary mb-1">42</div>
|
||||
<div className="text-sm text-muted-foreground">API Endpoints</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-3xl font-bold text-accent mb-1">100%</div>
|
||||
<div className="text-sm text-muted-foreground">Stealth Rate</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Features Section */}
|
||||
<section id="features" className="py-24 relative z-10">
|
||||
<div className="container mx-auto px-4">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl md:text-5xl font-bold mb-4">Core <span className="text-primary">Directives</span></h2>
|
||||
<p className="text-muted-foreground text-lg max-w-2xl mx-auto">Advanced architecture designed to give you an unfair advantage in the global market.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-8 max-w-5xl mx-auto">
|
||||
{features.map((feature, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ delay: idx * 0.1 }}
|
||||
className="p-8 rounded-xl bg-card border border-border hover:border-primary/50 transition-colors group relative overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-primary/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||
<feature.icon className="w-12 h-12 text-primary mb-6" />
|
||||
<h3 className="text-2xl font-bold mb-3">{feature.title}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Diagram Section */}
|
||||
<section className="py-24 bg-card/30 border-t border-border relative z-10">
|
||||
<div className="container mx-auto px-4 text-center">
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-12">The <span className="text-accent">Execution</span> Pipeline</h2>
|
||||
<div className="flex flex-col md:flex-row items-center justify-center gap-4 md:gap-8 text-lg font-mono">
|
||||
<div className="p-4 border border-border rounded bg-card w-48 shadow-[0_0_15px_rgba(251,191,36,0.1)]">Targets & Rules</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-primary/50 rounded bg-primary/5 w-48 shadow-[0_0_15px_rgba(0,255,136,0.2)] text-primary">Ghost Scraper</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-border rounded bg-card w-48 shadow-[0_0_15px_rgba(251,191,36,0.1)]">AI Analysis</div>
|
||||
<ArrowRight className="w-6 h-6 text-muted-foreground rotate-90 md:rotate-0" />
|
||||
<div className="p-4 border border-accent/50 rounded bg-accent/5 w-48 shadow-[0_0_15px_rgba(251,191,36,0.2)] text-accent">Real-time Alerts</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Footer CTA */}
|
||||
<section className="py-32 text-center relative z-10">
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-8">Ready to dominate the market?</h2>
|
||||
<Link href="/dashboard" className="inline-flex items-center gap-2 text-primary hover:text-accent font-mono text-xl transition-colors">
|
||||
> ACCESS_SYSTEM_NOW <span className="animate-pulse">_</span>
|
||||
</Link>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
98
frontend/app/settings/page.tsx
Normal file
98
frontend/app/settings/page.tsx
Normal file
@ -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 (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">SYSTEM_<span className="text-primary">CONFIG</span></h1>
|
||||
<p className="text-muted-foreground">Adjust core parameters, AI models, and notification routing.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-6 py-2 bg-primary hover:bg-primary/90 text-primary-foreground rounded font-mono text-sm font-bold shadow-[0_0_15px_rgba(0,255,136,0.3)] transition-all">
|
||||
<Save className="w-4 h-4" /> COMMIT_CHANGES
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 gap-8">
|
||||
<div className="md:col-span-2 space-y-6">
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Cpu className="w-5 h-5 text-primary" /> AI_ENGINE_SETTINGS</h2>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Primary Provider</label>
|
||||
<select className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary">
|
||||
<option>Anthropic (Claude 3.5 Sonnet)</option>
|
||||
<option>OpenAI (GPT-4o)</option>
|
||||
<option>Groq (Llama 3 70B)</option>
|
||||
<option>Ollama (Local)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Strictness Level</label>
|
||||
<select className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary">
|
||||
<option>High (Miss deals, zero noise)</option>
|
||||
<option selected>Balanced</option>
|
||||
<option>Low (Catch everything, more noise)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">API Key</label>
|
||||
<input type="password" value="*************************" className="w-full bg-background border border-border rounded px-3 py-2 text-sm focus:outline-none focus:border-primary" readOnly/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.1}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Bell className="w-5 h-5 text-accent" /> ALERT_ROUTING</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between p-3 bg-background border border-border rounded">
|
||||
<div>
|
||||
<div className="font-bold">Telegram Bot</div>
|
||||
<div className="text-xs text-muted-foreground">Status: Connected (@BidWraithBot)</div>
|
||||
</div>
|
||||
<div className="w-10 h-5 bg-primary rounded-full relative cursor-pointer"><div className="absolute right-1 top-1 w-3 h-3 bg-primary-foreground rounded-full"></div></div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-3 bg-background border border-border rounded">
|
||||
<div>
|
||||
<div className="font-bold">Discord Webhook</div>
|
||||
<div className="text-xs text-muted-foreground">Status: Not Configured</div>
|
||||
</div>
|
||||
<div className="w-10 h-5 bg-border rounded-full relative cursor-pointer"><div className="absolute left-1 top-1 w-3 h-3 bg-muted-foreground rounded-full"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.2}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Shield className="w-5 h-5 text-muted-foreground" /> STEALTH_MODE</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-xs font-mono text-muted-foreground mb-1">Humanization Level</label>
|
||||
<input type="range" min="1" max="100" defaultValue="75" className="w-full accent-primary" />
|
||||
<div className="flex justify-between text-xs text-muted-foreground mt-1"><span>Fast/Bot</span><span>Slow/Human</span></div>
|
||||
</div>
|
||||
<div className="pt-2">
|
||||
<label className="flex items-center gap-2 text-sm cursor-pointer">
|
||||
<input type="checkbox" defaultChecked className="accent-primary w-4 h-4" /> Use Proxy Rotation
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.div initial={{opacity: 0}} animate={{opacity: 1}} transition={{delay: 0.3}} className="p-6 bg-card border border-border rounded-lg">
|
||||
<h2 className="text-lg font-bold font-mono mb-4 flex items-center gap-2 border-b border-border pb-2"><Database className="w-5 h-5 text-muted-foreground" /> DATA_MANAGEMENT</h2>
|
||||
<div className="space-y-2">
|
||||
<button className="w-full py-2 bg-background border border-border hover:border-primary text-sm font-mono rounded transition-colors text-left px-3">Export Database Backup</button>
|
||||
<button className="w-full py-2 bg-background border border-border hover:border-primary text-sm font-mono rounded transition-colors text-left px-3">Clear Old Logs (>30d)</button>
|
||||
<button className="w-full py-2 bg-destructive/10 border border-destructive/30 text-destructive hover:bg-destructive hover:text-destructive-foreground text-sm font-mono rounded transition-colors text-left px-3 mt-4">FACTORY RESET</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
90
frontend/app/sites/page.tsx
Normal file
90
frontend/app/sites/page.tsx
Normal file
@ -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 (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<div className="flex justify-between items-end mb-8">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold font-mono tracking-tight mb-2">NETWORK_<span className="text-primary">NODES</span></h1>
|
||||
<p className="text-muted-foreground">Manage auction platforms targeted by the scraping engine.</p>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-4 py-2 bg-card border border-primary text-primary hover:bg-primary hover:text-primary-foreground transition-all rounded font-mono text-sm shadow-[0_0_15px_rgba(0,255,136,0.1)]">
|
||||
<Terminal className="w-4 h-4" /> ADAPT_NEW_SITE
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{mockSites.map((site, i) => (
|
||||
<motion.div
|
||||
key={site.id}
|
||||
initial={{ opacity: 0, scale: 0.95 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: i * 0.1 }}
|
||||
className={`p-6 rounded-lg border ${site.status === 'healthy' ? 'bg-card border-border' : 'bg-card border-accent/50'}`}
|
||||
>
|
||||
<div className="flex justify-between items-start mb-6">
|
||||
<div>
|
||||
<h3 className="font-bold text-lg">{site.name}</h3>
|
||||
<div className="text-xs font-mono text-muted-foreground">{site.url}</div>
|
||||
</div>
|
||||
{site.status === 'healthy' ? (
|
||||
<ShieldCheck className="w-6 h-6 text-primary" />
|
||||
) : (
|
||||
<ShieldAlert className="w-6 h-6 text-accent animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 font-mono text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Latency:</span>
|
||||
<span className={site.status === 'healthy' ? 'text-foreground' : 'text-accent'}>{site.lag}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Last Ping:</span>
|
||||
<span>{site.lastScrape}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">Selectors:</span>
|
||||
<span className="text-primary">Verified</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 pt-4 border-t border-border flex gap-2">
|
||||
<button className="flex-1 py-1.5 bg-background border border-border hover:border-primary/50 rounded text-xs transition-colors flex items-center justify-center gap-1">
|
||||
<Cpu className="w-3 h-3" /> Inspect
|
||||
</button>
|
||||
<button className="flex-1 py-1.5 bg-background border border-border hover:border-destructive/50 rounded text-xs transition-colors text-muted-foreground hover:text-destructive">
|
||||
Pause
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-12 p-6 bg-primary/5 border border-primary/20 rounded-lg">
|
||||
<h3 className="font-mono text-primary mb-4 flex items-center gap-2">
|
||||
<Cpu className="w-5 h-5" /> AUTO_ADAPTATION_ENGINE
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-3xl mb-4">
|
||||
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.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<input type="text" placeholder="https://example-auction.com" className="flex-1 bg-background border border-border rounded px-4 py-2 font-mono text-sm focus:outline-none focus:border-primary transition-colors" />
|
||||
<button className="px-6 py-2 bg-primary text-primary-foreground font-bold font-mono rounded hover:bg-primary/90 transition-colors">
|
||||
INITIATE_SCAN
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
16
frontend/components/GlitchText.tsx
Normal file
16
frontend/components/GlitchText.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function GlitchText({ text, className = "" }: { text: string; className?: string }) {
|
||||
return (
|
||||
<span
|
||||
className={`glitch-wrapper inline-block ${className}`}
|
||||
data-text={text}
|
||||
>
|
||||
<span className="glitch-text font-bold" data-text={text}>
|
||||
{text}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
59
frontend/components/Navbar.tsx
Normal file
59
frontend/components/Navbar.tsx
Normal file
@ -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 (
|
||||
<header className="sticky top-0 z-40 w-full border-b border-border bg-background/80 backdrop-blur-md">
|
||||
<div className="container mx-auto flex h-16 items-center justify-between px-4">
|
||||
<Link href="/" className="flex items-center gap-2 group">
|
||||
<Activity className="h-6 w-6 text-primary group-hover:text-accent transition-colors" />
|
||||
<GlitchText text="BIDWRAITH" className="text-xl tracking-wider text-foreground" />
|
||||
</Link>
|
||||
<nav className="hidden md:flex gap-6">
|
||||
{navItems.map((item) => {
|
||||
const isActive = pathname.startsWith(item.href);
|
||||
return (
|
||||
<Link
|
||||
key={item.name}
|
||||
href={item.href}
|
||||
className={`flex items-center gap-2 text-sm font-medium transition-colors relative ${isActive ? 'text-primary' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.name}
|
||||
{isActive && (
|
||||
<motion.div
|
||||
layoutId="navbar-indicator"
|
||||
className="absolute -bottom-[21px] left-0 right-0 h-0.5 bg-primary shadow-[0_0_8px_rgba(0,255,136,0.8)]"
|
||||
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="hidden lg:flex items-center gap-2 text-xs font-mono text-primary/70">
|
||||
<span className="w-2 h-2 rounded-full bg-primary animate-pulse shadow-[0_0_8px_rgba(0,255,136,0.8)]"></span>
|
||||
SYSTEM_ONLINE
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
17
frontend/dev.log
Normal file
17
frontend/dev.log
Normal file
@ -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
|
||||
395
frontend/package-lock.json
generated
395
frontend/package-lock.json
generated
@ -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"
|
||||
},
|
||||
|
||||
@ -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"
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 391 B |
@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 128 B |
@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
Before Width: | Height: | Size: 385 B |
13
worker.py
13
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")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user