Directory Structure:
.env.example
.gitignore
doc/
index.html
metadata.json
package.json
src/
src/App.tsx
src/index.css
src/lib/utils.ts
src/main.tsx
src/types.ts
tsconfig.json
vite.config.ts

================================================================================
File: /.env.example
================================================================================
# GEMINI_API_KEY: Required for Gemini AI API calls.
# AI Studio automatically injects this at runtime from user secrets.
# Users configure this via the Secrets panel in the AI Studio UI.
GEMINI_API_KEY="MY_GEMINI_API_KEY"

# APP_URL: The URL where this applet is hosted.
# AI Studio automatically injects this at runtime with the Cloud Run service URL.
# Used for self-referential links, OAuth callbacks, and API endpoints.
APP_URL="MY_APP_URL"

================================================================================
File: /.gitignore
================================================================================
node_modules/
build/
dist/
coverage/
.DS_Store
*.log
.env*
!.env.example

================================================================================
File: /index.html
================================================================================
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Google AI Studio App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

================================================================================
File: /metadata.json
================================================================================
{
  "name": "PentAGI 网络安全渗透测评教学平台",
  "description": "先进的 AI 驱动自主渗透测试与安全自动化平台，具备实时可视化功能。",
  "requestFramePermissions": []
}

================================================================================
File: /package.json
================================================================================
{
  "name": "react-example",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --port=3000 --host=0.0.0.0",
    "build": "vite build",
    "preview": "vite preview",
    "clean": "rm -rf dist",
    "lint": "tsc --noEmit"
  },
  "dependencies": {
    "@google/genai": "^1.29.0",
    "@tailwindcss/vite": "^4.1.14",
    "@vitejs/plugin-react": "^5.0.4",
    "@xyflow/react": "^12.10.1",
    "clsx": "^2.1.1",
    "dotenv": "^17.2.3",
    "express": "^4.21.2",
    "lucide-react": "^0.546.0",
    "motion": "^12.38.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "recharts": "^3.8.0",
    "tailwind-merge": "^3.5.0",
    "vite": "^6.2.0"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/node": "^22.14.0",
    "autoprefixer": "^10.4.21",
    "tailwindcss": "^4.1.14",
    "tsx": "^4.21.0",
    "typescript": "~5.8.2",
    "vite": "^6.2.0"
  }
}

================================================================================
File: /tsconfig.json
================================================================================
{
  "compilerOptions": {
    "target": "ES2022",
    "experimentalDecorators": true,
    "useDefineForClassFields": false,
    "module": "ESNext",
    "lib": [
      "ES2022",
      "DOM",
      "DOM.Iterable"
    ],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "isolatedModules": true,
    "moduleDetection": "force",
    "allowJs": true,
    "jsx": "react-jsx",
    "paths": {
      "@/*": [
        "./*"
      ]
    },
    "allowImportingTsExtensions": true,
    "noEmit": true
  }
}

================================================================================
File: /vite.config.ts
================================================================================
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {defineConfig, loadEnv} from 'vite';

export default defineConfig(({mode}) => {
  const env = loadEnv(mode, '.', '');
  return {
    plugins: [react(), tailwindcss()],
    define: {
      'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
    },
    resolve: {
      alias: {
        '@': path.resolve(__dirname, '.'),
      },
    },
    server: {
      // HMR is disabled in AI Studio via DISABLE_HMR env var.
      // Do not modify—file watching is disabled to prevent flickering during agent edits.
      hmr: process.env.DISABLE_HMR !== 'true',
    },
  };
});

================================================================================
File: /src/App.tsx
================================================================================
[...full content of src/App.tsx...]

================================================================================
File: /src/index.css
================================================================================
@import "tailwindcss";

@theme {
  --color-cyber-bg: #050505;
  --color-cyber-panel: #0a0a0a;
  --color-cyber-accent: #00ff9f;
  --color-cyber-border: #1a1a1a;
  --color-cyber-text: #e0e0e0;
  --color-cyber-muted: #666666;
  
  --font-mono: "JetBrains Mono", "Fira Code", monospace;
}

@layer base {
  body {
    @apply bg-cyber-bg text-cyber-text font-mono overflow-hidden;
  }
}

.custom-scrollbar::-webkit-scrollbar {
  width: 4px;
  height: 4px;
}

.custom-scrollbar::-webkit-scrollbar-track {
  background: transparent;
}

.custom-scrollbar::-webkit-scrollbar-thumb {
  background: #1a1a1a;
  border-radius: 2px;
}

.custom-scrollbar::-webkit-scrollbar-thumb:hover {
  background: #00ff9f;
}

.neon-glow {
  text-shadow: 0 0 5px rgba(0, 255, 159, 0.5), 0 0 10px rgba(0, 255, 159, 0.3);
}

.neon-border {
  box-shadow: 0 0 5px rgba(0, 255, 159, 0.2);
  border-color: rgba(0, 255, 159, 0.3);
}

================================================================================
File: /src/lib/utils.ts
================================================================================
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

================================================================================
File: /src/main.tsx
================================================================================
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import App from './App.tsx';
import './index.css';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

================================================================================
File: /src/types.ts
================================================================================
export interface Task {
  id: string;
  title: string;
  status: 'pending' | 'running' | 'completed' | 'failed';
  description?: string;
}

export interface Flow {
  id: string;
  name: string;
  status: 'pending' | 'running' | 'completed' | 'failed';
  progress: number;
  target: string;
  createdAt: string;
  duration?: string;
  agent?: string;
}

export interface Agent {
  id: string;
  name?: string;
  role: string;
  status: string;
  currentThought: string;
  tokenUsage: number;
}

export interface Action {
  id: string;
  timestamp: string;
  type: string;
  command: string;
  status: 'success' | 'failed' | 'running';
}

export interface Evidence {
  id: string;
  host: string;
  severity: 'Critical' | 'High' | 'Medium' | 'Low';
  cve?: string;
  poc: string;
  cvss: number;
  description?: string;
  timestamp?: string;
  status: 'Detected' | 'Confirmed' | 'Exploited' | 'Remediated';
}

export interface Artifact {
  id: string;
  type: 'screenshot' | 'report' | 'log' | 'poc';
  url: string;
  title: string;
  timestamp: string;
  host?: string;
}

export interface Report {
  id: string;
  title: string;
  executiveSummary: string;
  recommendations: string;
  generatedAt: string;
  riskMatrix: {
    critical: number;
    high: number;
    medium: number;
    low: number;
  };
  findings: {
    id: string;
    cve?: string;
    host: string;
    severity: 'Critical' | 'High' | 'Medium' | 'Low';
    title: string;
  }[];
}
