@0x2e8/phantom-ai-crawler 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # šŸŽ­ Phantom AI
2
+
3
+ Adaptive AI-powered web crawler with behavioral mutation engine.
4
+
5
+ Powered by **Claude Sonnet 4.5+** - the crawler evolves its behavior to match what targets expect.
6
+
7
+ ## ✨ Features
8
+
9
+ - 🧠 **AI-Driven**: Uses Claude Sonnet 4.5 for behavioral analysis
10
+ - šŸ”„ **Self-Mutating**: DNA evolves based on target responses
11
+ - 🚦 **Green Light System**: Trust-based progression from RED → GREEN
12
+ - šŸ“Š **Real-time Dashboard**: Web UI for monitoring and control
13
+ - šŸŽÆ **Multi-target**: Crawl multiple sites simultaneously
14
+ - šŸ”’ **Stealth**: Adapts to avoid detection
15
+
16
+ ## šŸš€ Quick Start
17
+
18
+ ### Installation
19
+
20
+ ```bash
21
+ # Via npx (no install)
22
+ npx phantom-ai-crawler
23
+
24
+ # Or install globally
25
+ npm install -g phantom-ai-crawler
26
+ phantom-ai
27
+
28
+ # Or local install
29
+ npm install phantom-ai-crawler
30
+ npx phantom-ai
31
+ ```
32
+
33
+ ### First Run
34
+
35
+ ```bash
36
+ # 1. Setup (configure API key)
37
+ phantom-ai setup
38
+
39
+ # 2. Start server
40
+ phantom-ai start
41
+
42
+ # 3. Open dashboard
43
+ # http://localhost:8081
44
+ ```
45
+
46
+ ## šŸ› ļø Commands
47
+
48
+ ```bash
49
+ phantom-ai # Start server (default)
50
+ phantom-ai start # Start backend + dashboard
51
+ phantom-ai setup # Run configuration wizard
52
+ phantom-ai status # Check configuration
53
+ ```
54
+
55
+ ### Options
56
+
57
+ ```bash
58
+ phantom-ai start -p 3000 # Backend on port 3000
59
+ phantom-ai start -u 8080 # Dashboard on port 8080
60
+ phantom-ai start --setup # Force reconfiguration
61
+ ```
62
+
63
+ ## šŸ”§ Configuration
64
+
65
+ The setup wizard will ask for:
66
+
67
+ 1. **Anthropic API Key** - Get from https://console.anthropic.com
68
+ 2. **Claude Model** - Recommended: `claude-4-5-sonnet-20250929`
69
+ 3. **Backend Port** - Default: `4000`
70
+ 4. **Dashboard Port** - Default: `8081`
71
+
72
+ Config is saved to `.env` in your working directory.
73
+
74
+ ## šŸ“ Project Structure
75
+
76
+ ```
77
+ phantom-ai/
78
+ ā”œā”€ā”€ .env # Your configuration
79
+ ā”œā”€ā”€ phantom.db # SQLite database
80
+ ā”œā”€ā”€ src/
81
+ │ ā”œā”€ā”€ cli.ts # CLI entry point
82
+ │ └── server/ # Backend API
83
+ ā”œā”€ā”€ dashboard/ # Web UI
84
+ └── prisma/ # Database schema
85
+ ```
86
+
87
+ ## šŸ”Œ API Endpoints
88
+
89
+ | Endpoint | Method | Description |
90
+ |----------|--------|-------------|
91
+ | `/health` | GET | Server status |
92
+ | `/api/targets` | GET | List targets |
93
+ | `/api/targets` | POST | Create target |
94
+ | `/api/targets/:id` | GET | Target details |
95
+ | `/api/dna/:id/current` | GET | Current DNA |
96
+ | `/api/mcp/analyze/:id` | POST | Run MCP analysis |
97
+
98
+ ## 🧬 How It Works
99
+
100
+ 1. **Discovery** (šŸ”“ RED): Initial reconnaissance phase
101
+ 2. **Learning** (🟔 YELLOW): Testing behavioral patterns
102
+ 3. **Established** (🟢 GREEN): Trusted access achieved
103
+ 4. **Maintenance**: Continuous adaptation
104
+
105
+ The MCP (Model Context Protocol) analyzes each interaction and suggests DNA mutations to improve trust scores.
106
+
107
+ ## šŸ“ Requirements
108
+
109
+ - Node.js 18+
110
+ - Anthropic API key
111
+ - Claude Sonnet 4.5+ access
112
+
113
+ ## šŸ› Troubleshooting
114
+
115
+ **Port already in use:**
116
+ ```bash
117
+ phantom-ai start -p 3000 -u 8080 # Use different ports
118
+ ```
119
+
120
+ **Database issues:**
121
+ ```bash
122
+ rm phantom.db # Reset database
123
+ phantom-ai setup
124
+ ```
125
+
126
+ **API key not working:**
127
+ ```bash
128
+ phantom-ai status # Check configuration
129
+ phantom-ai setup # Reconfigure
130
+ ```
131
+
132
+ ## šŸ—ļø Development
133
+
134
+ ```bash
135
+ git clone https://github.com/0x2e8/phantom-ai.git
136
+ cd phantom-ai
137
+ npm install
138
+ npm run dev # Development mode
139
+ npm run build # Build for production
140
+ ```
141
+
142
+ ## šŸ“¦ Publishing to NPM
143
+
144
+ ```bash
145
+ # 1. Update version
146
+ npm version patch
147
+
148
+ # 2. Build
149
+ npm run build
150
+
151
+ # 3. Publish
152
+ npm publish
153
+
154
+ # Or dry run first
155
+ npm publish --dry-run
156
+ ```
157
+
158
+ ## šŸ“„ License
159
+
160
+ MIT
161
+
162
+ ---
163
+
164
+ Built with šŸŽ­ by 0x2e8
165
+
@@ -0,0 +1,258 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Phantom AI - Dashboard</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
9
+ <style>
10
+ * { font-family: 'Inter', sans-serif; }
11
+ .mono { font-family: 'JetBrains Mono', monospace; }
12
+ .glass {
13
+ background: rgba(17, 24, 39, 0.8);
14
+ backdrop-filter: blur(12px);
15
+ border: 1px solid rgba(255, 255, 255, 0.08);
16
+ }
17
+ .pulse-ring {
18
+ animation: pulse-ring 2s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
19
+ }
20
+ @keyframes pulse-ring {
21
+ 0% { transform: scale(0.8); opacity: 0.8; }
22
+ 100% { transform: scale(2); opacity: 0; }
23
+ }
24
+ .gradient-text {
25
+ background: linear-gradient(135deg, #a78bfa 0%, #60a5fa 100%);
26
+ -webkit-background-clip: text;
27
+ -webkit-text-fill-color: transparent;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body class="bg-gray-950 text-gray-100 min-h-screen">
32
+ <!-- Header -->
33
+ <header class="glass sticky top-0 z-50 border-b border-gray-800">
34
+ <div class="max-w-7xl mx-auto px-4 py-4">
35
+ <div class="flex items-center justify-between">
36
+ <div class="flex items-center gap-3">
37
+ <div class="relative">
38
+ <div class="w-10 h-10 rounded-xl bg-gradient-to-br from-purple-600 to-blue-600 flex items-center justify-center">
39
+ <span class="text-xl">šŸŽ­</span>
40
+ </div>
41
+ <div class="absolute inset-0 rounded-xl bg-purple-500 pulse-ring opacity-50"></div>
42
+ </div>
43
+ <div>
44
+ <h1 class="text-xl font-bold gradient-text">Phantom AI</h1>
45
+ <p class="text-xs text-gray-500">Adaptive Web Crawler</p>
46
+ </div>
47
+ </div>
48
+ <div class="flex items-center gap-3">
49
+ <div id="api-status" class="flex items-center gap-2 px-3 py-1.5 rounded-full bg-gray-900 border border-gray-800">
50
+ <div class="w-2 h-2 rounded-full bg-gray-500"></div>
51
+ <span class="text-xs text-gray-400 mono">API</span>
52
+ </div>
53
+ <div id="mcp-status" class="flex items-center gap-2 px-3 py-1.5 rounded-full bg-gray-900 border border-gray-800">
54
+ <div class="w-2 h-2 rounded-full bg-gray-500"></div>
55
+ <span class="text-xs text-gray-400 mono">MCP</span>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </header>
61
+
62
+ <main class="max-w-7xl mx-auto px-4 py-8">
63
+ <!-- Stats -->
64
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
65
+ <div class="glass rounded-xl p-4">
66
+ <p class="text-gray-500 text-xs mb-1 uppercase tracking-wider">Targets</p>
67
+ <p id="stat-targets" class="text-2xl font-bold text-white mono">0</p>
68
+ </div>
69
+ <div class="glass rounded-xl p-4">
70
+ <p class="text-gray-500 text-xs mb-1 uppercase tracking-wider">Active</p>
71
+ <p id="stat-active" class="text-2xl font-bold text-green-400 mono">0</p>
72
+ </div>
73
+ <div class="glass rounded-xl p-4">
74
+ <p class="text-gray-500 text-xs mb-1 uppercase tracking-wider">Green Light</p>
75
+ <p id="stat-green" class="text-2xl font-bold text-emerald-400 mono">0</p>
76
+ </div>
77
+ <div class="glass rounded-xl p-4">
78
+ <p class="text-gray-500 text-xs mb-1 uppercase tracking-wider">MCP</p>
79
+ <p id="stat-mcp" class="text-sm font-medium text-purple-400 mono truncate">-</p>
80
+ </div>
81
+ </div>
82
+
83
+ <!-- Add Target -->
84
+ <div class="glass rounded-xl p-6 mb-8">
85
+ <h2 class="text-lg font-semibold mb-4 flex items-center gap-2">
86
+ <span class="text-purple-400">āž•</span> New Target
87
+ </h2>
88
+ <form id="add-target-form" class="flex gap-3">
89
+ <input
90
+ type="url"
91
+ id="target-url"
92
+ placeholder="https://example.com"
93
+ required
94
+ class="flex-1 bg-gray-900 border border-gray-800 rounded-lg px-4 py-3 text-white placeholder-gray-600 focus:outline-none focus:border-purple-500 focus:ring-1 focus:ring-purple-500/50"
95
+ >
96
+ <select id="target-type" class="bg-gray-900 border border-gray-800 rounded-lg px-4 py-3 text-white focus:outline-none focus:border-purple-500">
97
+ <option value="web">Web</option>
98
+ <option value="api">API</option>
99
+ <option value="mobile">Mobile</option>
100
+ </select>
101
+ <button type="submit" class="bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 text-white px-6 py-3 rounded-lg font-medium transition-all">
102
+ Add
103
+ </button>
104
+ </form>
105
+ </div>
106
+
107
+ <!-- Targets -->
108
+ <div class="glass rounded-xl overflow-hidden">
109
+ <div class="px-6 py-4 border-b border-gray-800 flex items-center justify-between">
110
+ <h2 class="text-lg font-semibold flex items-center gap-2">
111
+ <span class="text-purple-400">šŸŽÆ</span> Targets
112
+ </h2>
113
+ <button onclick="loadTargets()" class="text-sm text-purple-400 hover:text-purple-300 transition-colors">
114
+ ↻ Refresh
115
+ </button>
116
+ </div>
117
+ <div id="targets-list" class="divide-y divide-gray-800/50">
118
+ <div class="px-6 py-12 text-center text-gray-500">
119
+ <div class="animate-pulse flex flex-col items-center">
120
+ <div class="w-12 h-12 rounded-full bg-gray-800 mb-4"></div>
121
+ <div class="h-4 w-32 bg-gray-800 rounded"></div>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </main>
127
+
128
+ <script>
129
+ // Auto-detect API URL (works with proxy)
130
+ const API_URL = window.location.origin;
131
+
132
+ async function checkHealth() {
133
+ try {
134
+ const res = await fetch('/health');
135
+ const data = await res.json();
136
+
137
+ // API status
138
+ const apiStatus = document.getElementById('api-status');
139
+ apiStatus.innerHTML = `<div class="w-2 h-2 rounded-full bg-green-500 animate-pulse"></div><span class="text-xs text-gray-300 mono">API:ON</span>`;
140
+ apiStatus.classList.add('border-green-500/30');
141
+
142
+ // MCP status
143
+ const mcpStatus = document.getElementById('mcp-status');
144
+ if (data.mcp?.configured) {
145
+ mcpStatus.innerHTML = `<div class="w-2 h-2 rounded-full bg-purple-500 animate-pulse"></div><span class="text-xs text-gray-300 mono">MCP:ON</span>`;
146
+ mcpStatus.classList.add('border-purple-500/30');
147
+ document.getElementById('stat-mcp').textContent = data.mcp.model.split('-').slice(2, 4).join('-');
148
+ } else {
149
+ mcpStatus.innerHTML = `<div class="w-2 h-2 rounded-full bg-yellow-500"></div><span class="text-xs text-gray-300 mono">MCP:MOCK</span>`;
150
+ mcpStatus.classList.add('border-yellow-500/30');
151
+ }
152
+ } catch (e) {
153
+ document.getElementById('api-status').innerHTML = `<div class="w-2 h-2 rounded-full bg-red-500"></div><span class="text-xs text-gray-300 mono">API:ERR</span>`;
154
+ }
155
+ }
156
+
157
+ function getStatusColor(status) {
158
+ return {
159
+ 'RED': 'bg-red-500',
160
+ 'YELLOW': 'bg-yellow-500',
161
+ 'GREEN': 'bg-green-500',
162
+ 'ESTABLISHED': 'bg-emerald-500'
163
+ }[status] || 'bg-gray-500';
164
+ }
165
+
166
+ function getStatusBg(status) {
167
+ return {
168
+ 'ESTABLISHED': 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20',
169
+ 'GREEN': 'bg-green-500/10 text-green-400 border-green-500/20'
170
+ }[status] || 'bg-gray-800 text-gray-400 border-gray-700';
171
+ }
172
+
173
+ async function loadTargets() {
174
+ try {
175
+ const res = await fetch('/api/targets');
176
+ const targets = await res.json();
177
+
178
+ // Update stats
179
+ document.getElementById('stat-targets').textContent = targets.length;
180
+ document.getElementById('stat-active').textContent = targets.filter(t => t.status === 'learning').length;
181
+ document.getElementById('stat-green').textContent = targets.filter(t =>
182
+ t.greenLightStatus === 'GREEN' || t.greenLightStatus === 'ESTABLISHED'
183
+ ).length;
184
+
185
+ const list = document.getElementById('targets-list');
186
+ if (targets.length === 0) {
187
+ list.innerHTML = `
188
+ <div class="px-6 py-16 text-center text-gray-500">
189
+ <p class="text-4xl mb-4 opacity-50">šŸ‘»</p>
190
+ <p class="mb-2">No targets yet</p>
191
+ <p class="text-sm text-gray-600">Add your first target above</p>
192
+ </div>
193
+ `;
194
+ return;
195
+ }
196
+
197
+ list.innerHTML = targets.map(t => `
198
+ <div class="px-6 py-4 flex items-center justify-between hover:bg-gray-800/30 transition-colors group">
199
+ <div class="flex items-center gap-4">
200
+ <div class="w-2.5 h-2.5 rounded-full ${getStatusColor(t.greenLightStatus)} ring-2 ring-gray-800"></div>
201
+ <div>
202
+ <p class="font-medium text-white group-hover:text-purple-400 transition-colors">${t.url}</p>
203
+ <p class="text-xs text-gray-600 mono">${t.id.slice(0, 8)}... • ${t.status}</p>
204
+ </div>
205
+ </div>
206
+ <div class="flex items-center gap-4">
207
+ <div class="text-right">
208
+ <p class="text-sm font-medium text-white">${t.trustScore}%</p>
209
+ <p class="text-xs text-gray-600">trust</p>
210
+ </div>
211
+ <span class="px-3 py-1 rounded-full text-xs font-medium border ${getStatusBg(t.greenLightStatus)}">
212
+ ${t.greenLightStatus}
213
+ </span>
214
+ </div>
215
+ </div>
216
+ `).join('');
217
+ } catch (e) {
218
+ document.getElementById('targets-list').innerHTML = `
219
+ <div class="px-6 py-12 text-center text-red-400">
220
+ <p>Failed to load targets</p>
221
+ <p class="text-sm text-gray-600 mt-2">${e.message}</p>
222
+ </div>
223
+ `;
224
+ }
225
+ }
226
+
227
+ document.getElementById('add-target-form').addEventListener('submit', async (e) => {
228
+ e.preventDefault();
229
+ const url = document.getElementById('target-url').value;
230
+ const type = document.getElementById('target-type').value;
231
+
232
+ try {
233
+ const res = await fetch('/api/targets', {
234
+ method: 'POST',
235
+ headers: { 'Content-Type': 'application/json' },
236
+ body: JSON.stringify({ url, type })
237
+ });
238
+
239
+ if (res.ok) {
240
+ document.getElementById('target-url').value = '';
241
+ loadTargets();
242
+ } else {
243
+ const err = await res.json();
244
+ alert('Error: ' + (err.error || 'Unknown error'));
245
+ }
246
+ } catch (e) {
247
+ alert('Error: ' + e.message);
248
+ }
249
+ });
250
+
251
+ // Init
252
+ checkHealth();
253
+ loadTargets();
254
+ setInterval(() => { checkHealth(); loadTargets(); }, 5000);
255
+ </script>
256
+ </body>
257
+ </html>
258
+
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const inquirer_1 = __importDefault(require("inquirer"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const ora_1 = __importDefault(require("ora"));
11
+ const child_process_1 = require("child_process");
12
+ const fs_1 = require("fs");
13
+ const path_1 = require("path");
14
+ const program = new commander_1.Command();
15
+ const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../package.json'), 'utf8'));
16
+ const ENV_PATH = (0, path_1.resolve)(process.cwd(), '.env');
17
+ const DASHBOARD_DIR = (0, path_1.join)(__dirname, '../dashboard');
18
+ // Banner
19
+ console.log(chalk_1.default.magenta(`
20
+ ╔══════════════════════════════════════════════════════════╗
21
+ ā•‘ ā•‘
22
+ ā•‘ šŸŽ­ ${chalk_1.default.bold('PHANTOM AI')} - Adaptive Web Crawler v${pkg.version} ā•‘
23
+ ā•‘ ā•‘
24
+ ā•‘ AI-powered behavioral mutation engine ā•‘
25
+ ā•‘ Requires: Claude Sonnet 4.5+ ā•‘
26
+ ā•‘ ā•‘
27
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
28
+ `));
29
+ // Check if setup is needed
30
+ function needsSetup() {
31
+ if (!(0, fs_1.existsSync)(ENV_PATH))
32
+ return true;
33
+ const env = (0, fs_1.readFileSync)(ENV_PATH, 'utf8');
34
+ return !env.includes('ANTHROPIC_API_KEY') || env.includes('your-api-key-here');
35
+ }
36
+ // Setup wizard
37
+ async function setupWizard() {
38
+ console.log(chalk_1.default.yellow('āš™ļø Initial Setup Required\n'));
39
+ const answers = await inquirer_1.default.prompt([
40
+ {
41
+ type: 'input',
42
+ name: 'apiKey',
43
+ message: chalk_1.default.cyan('šŸ”‘ Enter your Anthropic API Key:'),
44
+ validate: (input) => {
45
+ if (!input.startsWith('sk-ant-api')) {
46
+ return 'Please enter a valid Anthropic API key (starts with sk-ant-api)';
47
+ }
48
+ return true;
49
+ }
50
+ },
51
+ {
52
+ type: 'list',
53
+ name: 'model',
54
+ message: chalk_1.default.cyan('🧠 Select Claude Model:'),
55
+ choices: [
56
+ { name: 'Claude 4.5 Sonnet (Recommended)', value: 'claude-4-5-sonnet-20250929' },
57
+ { name: 'Claude 4.5 Sonnet Latest', value: 'claude-4-5-sonnet-latest' },
58
+ { name: 'Claude 4 Opus', value: 'claude-4-opus-20251001' }
59
+ ],
60
+ default: 'claude-4-5-sonnet-20250929'
61
+ },
62
+ {
63
+ type: 'input',
64
+ name: 'apiPort',
65
+ message: chalk_1.default.cyan('šŸ”Œ Backend Port:'),
66
+ default: '4000',
67
+ validate: (input) => !isNaN(parseInt(input)) || 'Please enter a valid port number'
68
+ },
69
+ {
70
+ type: 'input',
71
+ name: 'uiPort',
72
+ message: chalk_1.default.cyan('🌐 Dashboard Port:'),
73
+ default: '8081',
74
+ validate: (input) => !isNaN(parseInt(input)) || 'Please enter a valid port number'
75
+ }
76
+ ]);
77
+ const envContent = `# Phantom AI Configuration
78
+ # Generated: ${new Date().toISOString()}
79
+
80
+ ANTHROPIC_API_KEY="${answers.apiKey}"
81
+ CLAUDE_MODEL="${answers.model}"
82
+ MCP_MAX_TOKENS=8192
83
+ MCP_TEMPERATURE=0.2
84
+
85
+ PORT=${answers.apiPort}
86
+ NODE_ENV=development
87
+
88
+ NEXT_PUBLIC_API_URL="http://localhost:${answers.apiPort}"
89
+ NEXT_PUBLIC_WS_URL="http://localhost:${answers.apiPort}"
90
+ UI_PORT=${answers.uiPort}
91
+
92
+ DATABASE_URL="file:${process.cwd()}/phantom.db"
93
+
94
+ JWT_SECRET="${Math.random().toString(36).substring(2)}${Math.random().toString(36).substring(2)}"
95
+ `;
96
+ (0, fs_1.writeFileSync)(ENV_PATH, envContent);
97
+ console.log(chalk_1.default.green('\nāœ… Configuration saved to .env'));
98
+ // Initialize database
99
+ const spinner = (0, ora_1.default)('Initializing database...').start();
100
+ try {
101
+ (0, child_process_1.execSync)('npx prisma migrate deploy', {
102
+ cwd: process.cwd(),
103
+ stdio: 'pipe'
104
+ });
105
+ spinner.succeed('Database initialized');
106
+ }
107
+ catch (e) {
108
+ spinner.warn('Database may already be initialized');
109
+ }
110
+ return answers;
111
+ }
112
+ // Start backend
113
+ async function startBackend(port) {
114
+ return new Promise((resolve, reject) => {
115
+ const spinner = (0, ora_1.default)('Starting backend...').start();
116
+ const backend = (0, child_process_1.spawn)('node', [(0, path_1.join)(__dirname, 'server/index.js')], {
117
+ cwd: process.cwd(),
118
+ env: { ...process.env, PORT: port },
119
+ detached: false
120
+ });
121
+ backend.stdout?.on('data', (data) => {
122
+ const line = data.toString();
123
+ if (line.includes('running on port')) {
124
+ spinner.succeed(chalk_1.default.green(`Backend running on port ${port}`));
125
+ resolve(backend);
126
+ }
127
+ });
128
+ backend.stderr?.on('data', (data) => {
129
+ // Ignore common startup warnings
130
+ });
131
+ setTimeout(() => {
132
+ spinner.fail('Backend failed to start');
133
+ reject(new Error('Timeout'));
134
+ }, 30000);
135
+ });
136
+ }
137
+ // Start frontend with Python (simple and reliable)
138
+ async function startFrontend(port) {
139
+ return new Promise((resolve, reject) => {
140
+ const spinner = (0, ora_1.default)('Starting dashboard...').start();
141
+ const frontend = (0, child_process_1.spawn)('python3', ['-m', 'http.server', port], {
142
+ cwd: DASHBOARD_DIR,
143
+ detached: false
144
+ });
145
+ // Give it a moment to start
146
+ setTimeout(() => {
147
+ spinner.succeed(chalk_1.default.green(`Dashboard running on port ${port}`));
148
+ resolve(frontend);
149
+ }, 2000);
150
+ frontend.on('error', (err) => {
151
+ spinner.fail(`Dashboard failed: ${err.message}`);
152
+ reject(err);
153
+ });
154
+ setTimeout(() => {
155
+ spinner.fail('Dashboard failed to start');
156
+ reject(new Error('Timeout'));
157
+ }, 10000);
158
+ });
159
+ }
160
+ // Main start command
161
+ program
162
+ .command('start')
163
+ .alias('s')
164
+ .description('Start Phantom AI (backend + dashboard)')
165
+ .option('-p, --port <port>', 'Backend port', '4000')
166
+ .option('-u, --ui-port <port>', 'Dashboard port', '8081')
167
+ .option('--setup', 'Force setup wizard')
168
+ .action(async (options) => {
169
+ try {
170
+ // Setup if needed
171
+ if (options.setup || needsSetup()) {
172
+ await setupWizard();
173
+ }
174
+ // Read config
175
+ const env = (0, fs_1.readFileSync)(ENV_PATH, 'utf8');
176
+ const apiPort = options.port || env.match(/PORT=(\d+)/)?.[1] || '4000';
177
+ const uiPort = options.uiPort || env.match(/UI_PORT=(\d+)/)?.[1] || '8081';
178
+ console.log(chalk_1.default.blue('\nšŸš€ Starting Phantom AI...\n'));
179
+ // Start services
180
+ const backend = await startBackend(apiPort);
181
+ const frontend = await startFrontend(uiPort);
182
+ // Print success
183
+ console.log(chalk_1.default.green('\nāœ… Phantom AI is running!\n'));
184
+ console.log(chalk_1.default.white('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'));
185
+ console.log(chalk_1.default.white('│') + chalk_1.default.cyan(' 🌐 Dashboard: ') + chalk_1.default.yellow(`http://localhost:${uiPort} `) + chalk_1.default.white('│'));
186
+ console.log(chalk_1.default.white('│') + chalk_1.default.cyan(' šŸ”Œ API: ') + chalk_1.default.yellow(`http://localhost:${apiPort} `) + chalk_1.default.white('│'));
187
+ console.log(chalk_1.default.white('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜'));
188
+ console.log(chalk_1.default.gray('\nPress Ctrl+C to stop\n'));
189
+ // Handle shutdown
190
+ process.on('SIGINT', () => {
191
+ console.log(chalk_1.default.yellow('\n\nšŸ›‘ Shutting down...'));
192
+ backend.kill();
193
+ frontend.kill();
194
+ process.exit(0);
195
+ });
196
+ }
197
+ catch (error) {
198
+ console.error(chalk_1.default.red('\nāŒ Error:'), error);
199
+ process.exit(1);
200
+ }
201
+ });
202
+ // Setup command
203
+ program
204
+ .command('setup')
205
+ .description('Run setup wizard')
206
+ .action(async () => {
207
+ await setupWizard();
208
+ console.log(chalk_1.default.green('\nāœ… Setup complete! Run "phantom-ai start" to begin.'));
209
+ });
210
+ // Status command
211
+ program
212
+ .command('status')
213
+ .description('Check Phantom AI status')
214
+ .action(async () => {
215
+ if (needsSetup()) {
216
+ console.log(chalk_1.default.yellow('āš ļø Not configured. Run: phantom-ai setup'));
217
+ return;
218
+ }
219
+ const env = (0, fs_1.readFileSync)(ENV_PATH, 'utf8');
220
+ const model = env.match(/CLAUDE_MODEL="([^"]+)"/)?.[1];
221
+ const hasKey = !env.includes('your-api-key-here');
222
+ console.log(chalk_1.default.blue('\nšŸ“Š Configuration Status:\n'));
223
+ console.log(chalk_1.default.white(' API Key: '), hasKey ? chalk_1.default.green('āœ“ Configured') : chalk_1.default.red('āœ— Missing'));
224
+ console.log(chalk_1.default.white(' Model: '), chalk_1.default.cyan(model || 'Not set'));
225
+ console.log(chalk_1.default.white(' Database: '), (0, fs_1.existsSync)('./phantom.db') ? chalk_1.default.green('āœ“ Initialized') : chalk_1.default.yellow('Will create on start'));
226
+ });
227
+ // Default action
228
+ if (process.argv.length === 2) {
229
+ program.parse(['node', 'cli', 'start']);
230
+ }
231
+ else {
232
+ program.parse();
233
+ }
234
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ export declare const prisma: PrismaClient<import(".prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library").DefaultArgs>;
3
+ export declare const redis: {
4
+ get: (key: string) => Promise<any>;
5
+ setex: (key: string, seconds: number, value: string) => Promise<Map<any, any>>;
6
+ ping: () => Promise<string>;
7
+ quit: () => Promise<void>;
8
+ };
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAU9C,eAAO,MAAM,MAAM,gIAAqB,CAAC;AAIzC,eAAO,MAAM,KAAK;eACC,MAAM;iBACJ,MAAM,WAAW,MAAM,SAAS,MAAM;;;CAG1D,CAAC"}
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.redis = exports.prisma = void 0;
7
+ const express_1 = __importDefault(require("express"));
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const http_1 = require("http");
10
+ const socket_io_1 = require("socket.io");
11
+ const dotenv_1 = __importDefault(require("dotenv"));
12
+ const client_1 = require("@prisma/client");
13
+ const path_1 = require("path");
14
+ // Load env
15
+ dotenv_1.default.config({ path: (0, path_1.resolve)(process.cwd(), '.env') });
16
+ const app = (0, express_1.default)();
17
+ const httpServer = (0, http_1.createServer)(app);
18
+ const io = new socket_io_1.Server(httpServer, { cors: { origin: '*' } });
19
+ exports.prisma = new client_1.PrismaClient();
20
+ // In-memory store (no Redis required)
21
+ const memoryStore = new Map();
22
+ exports.redis = {
23
+ get: async (key) => memoryStore.get(key) || null,
24
+ setex: async (key, seconds, value) => memoryStore.set(key, value),
25
+ ping: async () => 'PONG',
26
+ quit: async () => { }
27
+ };
28
+ // Middleware
29
+ app.use((0, cors_1.default)());
30
+ app.use(express_1.default.json());
31
+ // Health check
32
+ app.get('/health', async (req, res) => {
33
+ try {
34
+ await exports.prisma.$queryRaw `SELECT 1`;
35
+ res.json({
36
+ status: 'ok',
37
+ timestamp: new Date().toISOString(),
38
+ version: '1.0.0',
39
+ mcp: {
40
+ model: process.env.CLAUDE_MODEL || 'not configured',
41
+ configured: !!process.env.ANTHROPIC_API_KEY && !process.env.ANTHROPIC_API_KEY?.includes('your-api-key')
42
+ }
43
+ });
44
+ }
45
+ catch (error) {
46
+ res.status(503).json({ status: 'unhealthy', error: String(error) });
47
+ }
48
+ });
49
+ // Targets API
50
+ app.get('/api/targets', async (req, res) => {
51
+ try {
52
+ const targets = await exports.prisma.target.findMany({
53
+ include: {
54
+ _count: { select: { learningEvents: true, requestLogs: true } }
55
+ },
56
+ orderBy: { createdAt: 'desc' }
57
+ });
58
+ res.json(targets);
59
+ }
60
+ catch (error) {
61
+ res.status(500).json({ error: String(error) });
62
+ }
63
+ });
64
+ app.post('/api/targets', async (req, res) => {
65
+ try {
66
+ const { url, type = 'web' } = req.body;
67
+ if (!url)
68
+ return res.status(400).json({ error: 'URL required' });
69
+ const target = await exports.prisma.target.create({
70
+ data: {
71
+ url,
72
+ type,
73
+ status: 'discovering',
74
+ greenLightStatus: 'RED',
75
+ trustScore: 0
76
+ }
77
+ });
78
+ res.json(target);
79
+ }
80
+ catch (error) {
81
+ res.status(500).json({ error: String(error) });
82
+ }
83
+ });
84
+ app.get('/api/targets/:id', async (req, res) => {
85
+ try {
86
+ const target = await exports.prisma.target.findUnique({
87
+ where: { id: req.params.id },
88
+ include: {
89
+ dnaSnapshots: { orderBy: { createdAt: 'desc' }, take: 5 },
90
+ learningEvents: { orderBy: { createdAt: 'desc' }, take: 10 },
91
+ _count: { select: { requestLogs: true } }
92
+ }
93
+ });
94
+ if (!target)
95
+ return res.status(404).json({ error: 'Not found' });
96
+ res.json(target);
97
+ }
98
+ catch (error) {
99
+ res.status(500).json({ error: String(error) });
100
+ }
101
+ });
102
+ // DNA API
103
+ app.get('/api/dna/:targetId/current', async (req, res) => {
104
+ try {
105
+ const target = await exports.prisma.target.findUnique({
106
+ where: { id: req.params.targetId },
107
+ include: { currentDna: true }
108
+ });
109
+ if (!target?.currentDna)
110
+ return res.json(null);
111
+ res.json(JSON.parse(target.currentDna.dnaJson));
112
+ }
113
+ catch (error) {
114
+ res.status(500).json({ error: String(error) });
115
+ }
116
+ });
117
+ // MCP API
118
+ app.post('/api/mcp/analyze/:targetId', async (req, res) => {
119
+ // Placeholder - MCP analysis would go here
120
+ res.json({
121
+ analysis: 'MCP analysis endpoint ready',
122
+ mock: !process.env.ANTHROPIC_API_KEY,
123
+ model: process.env.CLAUDE_MODEL
124
+ });
125
+ });
126
+ // Start server
127
+ const PORT = parseInt(process.env.PORT || '4000');
128
+ httpServer.listen(PORT, () => {
129
+ console.log(`šŸš€ Backend running on port ${PORT}`);
130
+ });
131
+ // Graceful shutdown
132
+ process.on('SIGTERM', async () => {
133
+ await exports.prisma.$disconnect();
134
+ httpServer.close(() => process.exit(0));
135
+ });
136
+ process.on('SIGINT', async () => {
137
+ await exports.prisma.$disconnect();
138
+ httpServer.close(() => process.exit(0));
139
+ });
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@0x2e8/phantom-ai-crawler",
3
+ "version": "1.0.0",
4
+ "description": "Adaptive AI-powered web crawler with behavioral mutation engine",
5
+ "main": "dist/cli.js",
6
+ "bin": {
7
+ "phantom-ai": "dist/cli.js",
8
+ "phantom": "dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/cli.js",
13
+ "dev": "tsx src/cli.ts",
14
+ "postinstall": "node scripts/postinstall.js"
15
+ },
16
+ "keywords": [
17
+ "crawler",
18
+ "scraper",
19
+ "ai",
20
+ "claude",
21
+ "anthropic",
22
+ "adaptive",
23
+ "stealth",
24
+ "pentest"
25
+ ],
26
+ "author": "0x2e8",
27
+ "private": false,
28
+ "license": "MIT",
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "dependencies": {
33
+ "@anthropic-ai/sdk": "^0.32.0",
34
+ "@prisma/client": "^5.22.0",
35
+ "commander": "^12.0.0",
36
+ "cors": "^2.8.5",
37
+ "dotenv": "^16.4.5",
38
+ "express": "^4.21.0",
39
+ "inquirer": "^8.2.6",
40
+ "socket.io": "^4.8.0",
41
+ "chalk": "^4.1.2",
42
+ "ora": "^5.4.1"
43
+ },
44
+ "devDependencies": {
45
+ "@types/cors": "^2.8.17",
46
+ "@types/express": "^4.17.21",
47
+ "@types/inquirer": "^9.0.7",
48
+ "@types/node": "^20.0.0",
49
+ "prisma": "^5.22.0",
50
+ "tsx": "^4.0.0",
51
+ "typescript": "^5.6.0"
52
+ },
53
+ "files": [
54
+ "dist/",
55
+ "dashboard/",
56
+ "prisma/",
57
+ "scripts/",
58
+ "README.md"
59
+ ],
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/0x2e8/phantom-ai.git"
63
+ }
64
+ }
65
+
66
+
67
+
68
+
69
+
@@ -0,0 +1,107 @@
1
+ -- CreateTable
2
+ CREATE TABLE "Target" (
3
+ "id" TEXT NOT NULL PRIMARY KEY,
4
+ "url" TEXT NOT NULL,
5
+ "type" TEXT NOT NULL DEFAULT 'web',
6
+ "status" TEXT NOT NULL DEFAULT 'discovering',
7
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
8
+ "updatedAt" DATETIME NOT NULL,
9
+ "lastSeen" DATETIME,
10
+ "greenLightStatus" TEXT NOT NULL DEFAULT 'RED',
11
+ "trustScore" INTEGER NOT NULL DEFAULT 0,
12
+ "establishedAt" DATETIME,
13
+ "maintainedFor" INTEGER NOT NULL DEFAULT 0,
14
+ "currentDnaId" TEXT,
15
+ CONSTRAINT "Target_currentDnaId_fkey" FOREIGN KEY ("currentDnaId") REFERENCES "DnaSnapshot" ("id") ON DELETE SET NULL ON UPDATE CASCADE
16
+ );
17
+
18
+ -- CreateTable
19
+ CREATE TABLE "DnaSnapshot" (
20
+ "id" TEXT NOT NULL PRIMARY KEY,
21
+ "targetId" TEXT NOT NULL,
22
+ "version" TEXT NOT NULL DEFAULT '1.0.0',
23
+ "dnaJson" TEXT NOT NULL,
24
+ "parentId" TEXT,
25
+ "isActive" BOOLEAN NOT NULL DEFAULT false,
26
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
27
+ CONSTRAINT "DnaSnapshot_targetId_fkey" FOREIGN KEY ("targetId") REFERENCES "Target" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
28
+ CONSTRAINT "DnaSnapshot_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "DnaSnapshot" ("id") ON DELETE SET NULL ON UPDATE CASCADE
29
+ );
30
+
31
+ -- CreateTable
32
+ CREATE TABLE "LearningEvent" (
33
+ "id" TEXT NOT NULL PRIMARY KEY,
34
+ "targetId" TEXT NOT NULL,
35
+ "dnaVersionId" TEXT NOT NULL,
36
+ "eventType" TEXT NOT NULL,
37
+ "title" TEXT NOT NULL,
38
+ "description" TEXT NOT NULL,
39
+ "mcpInsight" TEXT,
40
+ "mcpConfidence" REAL,
41
+ "mcpModel" TEXT NOT NULL DEFAULT 'claude-4-5-sonnet',
42
+ "dnaChanges" TEXT,
43
+ "beforeState" TEXT,
44
+ "afterState" TEXT,
45
+ "trustImpact" INTEGER NOT NULL DEFAULT 0,
46
+ "durationMs" INTEGER,
47
+ "challengeType" TEXT,
48
+ "challengeSolved" BOOLEAN,
49
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
50
+ CONSTRAINT "LearningEvent_targetId_fkey" FOREIGN KEY ("targetId") REFERENCES "Target" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
51
+ CONSTRAINT "LearningEvent_dnaVersionId_fkey" FOREIGN KEY ("dnaVersionId") REFERENCES "DnaSnapshot" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
52
+ );
53
+
54
+ -- CreateTable
55
+ CREATE TABLE "GreenLightState" (
56
+ "id" TEXT NOT NULL PRIMARY KEY,
57
+ "targetId" TEXT NOT NULL,
58
+ "status" TEXT NOT NULL,
59
+ "trustScore" INTEGER NOT NULL,
60
+ "signalsJson" TEXT NOT NULL,
61
+ "establishedAt" DATETIME,
62
+ "maintainedFor" INTEGER NOT NULL DEFAULT 0,
63
+ "lostAt" DATETIME,
64
+ "reasonLost" TEXT,
65
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
66
+ CONSTRAINT "GreenLightState_targetId_fkey" FOREIGN KEY ("targetId") REFERENCES "Target" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
67
+ );
68
+
69
+ -- CreateTable
70
+ CREATE TABLE "RequestLog" (
71
+ "id" TEXT NOT NULL PRIMARY KEY,
72
+ "targetId" TEXT NOT NULL,
73
+ "dnaVersionId" TEXT,
74
+ "method" TEXT NOT NULL,
75
+ "url" TEXT NOT NULL,
76
+ "headers" TEXT NOT NULL,
77
+ "body" TEXT,
78
+ "responseStatus" INTEGER,
79
+ "responseHeaders" TEXT,
80
+ "responseBodyPreview" TEXT,
81
+ "wasBlocked" BOOLEAN NOT NULL DEFAULT false,
82
+ "blockReason" TEXT,
83
+ "challengeDetected" BOOLEAN NOT NULL DEFAULT false,
84
+ "challengeType" TEXT,
85
+ "timingMs" INTEGER,
86
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
87
+ CONSTRAINT "RequestLog_targetId_fkey" FOREIGN KEY ("targetId") REFERENCES "Target" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
88
+ CONSTRAINT "RequestLog_dnaVersionId_fkey" FOREIGN KEY ("dnaVersionId") REFERENCES "DnaSnapshot" ("id") ON DELETE SET NULL ON UPDATE CASCADE
89
+ );
90
+
91
+ -- CreateIndex
92
+ CREATE INDEX "Target_url_idx" ON "Target"("url");
93
+
94
+ -- CreateIndex
95
+ CREATE INDEX "Target_status_idx" ON "Target"("status");
96
+
97
+ -- CreateIndex
98
+ CREATE INDEX "DnaSnapshot_targetId_idx" ON "DnaSnapshot"("targetId");
99
+
100
+ -- CreateIndex
101
+ CREATE INDEX "LearningEvent_targetId_idx" ON "LearningEvent"("targetId");
102
+
103
+ -- CreateIndex
104
+ CREATE INDEX "GreenLightState_targetId_idx" ON "GreenLightState"("targetId");
105
+
106
+ -- CreateIndex
107
+ CREATE INDEX "RequestLog_targetId_idx" ON "RequestLog"("targetId");
@@ -0,0 +1,3 @@
1
+ # Please do not edit this file manually
2
+ # It should be added in your version-control system (i.e. Git)
3
+ provider = "sqlite"
@@ -0,0 +1,116 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "sqlite"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model Target {
11
+ id String @id @default(uuid())
12
+ url String
13
+ type String @default("web")
14
+ status String @default("discovering")
15
+ createdAt DateTime @default(now())
16
+ updatedAt DateTime @updatedAt
17
+ lastSeen DateTime?
18
+
19
+ greenLightStatus String @default("RED")
20
+ trustScore Int @default(0)
21
+ establishedAt DateTime?
22
+ maintainedFor Int @default(0)
23
+
24
+ currentDnaId String?
25
+ currentDna DnaSnapshot? @relation("CurrentDNA", fields: [currentDnaId], references: [id])
26
+
27
+ dnaSnapshots DnaSnapshot[]
28
+ learningEvents LearningEvent[]
29
+ greenLightHistory GreenLightState[]
30
+ requestLogs RequestLog[]
31
+
32
+ @@index([url])
33
+ @@index([status])
34
+ }
35
+
36
+ model DnaSnapshot {
37
+ id String @id @default(uuid())
38
+ targetId String
39
+ target Target @relation(fields: [targetId], references: [id])
40
+ version String @default("1.0.0")
41
+ dnaJson String
42
+ parentId String?
43
+ parent DnaSnapshot? @relation("DNALineage", fields: [parentId], references: [id])
44
+ children DnaSnapshot[] @relation("DNALineage")
45
+ isActive Boolean @default(false)
46
+ createdAt DateTime @default(now())
47
+ currentFor Target[] @relation("CurrentDNA")
48
+ events LearningEvent[]
49
+ requests RequestLog[]
50
+
51
+ @@index([targetId])
52
+ }
53
+
54
+ model LearningEvent {
55
+ id String @id @default(uuid())
56
+ targetId String
57
+ target Target @relation(fields: [targetId], references: [id])
58
+ dnaVersionId String
59
+ dnaVersion DnaSnapshot @relation(fields: [dnaVersionId], references: [id])
60
+ eventType String
61
+ title String
62
+ description String
63
+ mcpInsight String?
64
+ mcpConfidence Float?
65
+ mcpModel String @default("claude-4-5-sonnet")
66
+ dnaChanges String?
67
+ beforeState String?
68
+ afterState String?
69
+ trustImpact Int @default(0)
70
+ durationMs Int?
71
+ challengeType String?
72
+ challengeSolved Boolean?
73
+ createdAt DateTime @default(now())
74
+
75
+ @@index([targetId])
76
+ }
77
+
78
+ model GreenLightState {
79
+ id String @id @default(uuid())
80
+ targetId String
81
+ target Target @relation(fields: [targetId], references: [id])
82
+ status String
83
+ trustScore Int
84
+ signalsJson String
85
+ establishedAt DateTime?
86
+ maintainedFor Int @default(0)
87
+ lostAt DateTime?
88
+ reasonLost String?
89
+ createdAt DateTime @default(now())
90
+
91
+ @@index([targetId])
92
+ }
93
+
94
+ model RequestLog {
95
+ id String @id @default(uuid())
96
+ targetId String
97
+ target Target @relation(fields: [targetId], references: [id])
98
+ dnaVersionId String?
99
+ dnaVersion DnaSnapshot? @relation(fields: [dnaVersionId], references: [id])
100
+ method String
101
+ url String
102
+ headers String
103
+ body String?
104
+ responseStatus Int?
105
+ responseHeaders String?
106
+ responseBodyPreview String?
107
+ wasBlocked Boolean @default(false)
108
+ blockReason String?
109
+ challengeDetected Boolean @default(false)
110
+ challengeType String?
111
+ timingMs Int?
112
+ createdAt DateTime @default(now())
113
+
114
+ @@index([targetId])
115
+ }
116
+
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require('child_process');
4
+ const { existsSync } = require('fs');
5
+ const { resolve } = require('path');
6
+
7
+ console.log('šŸ”§ Phantom AI - Post Install Setup\n');
8
+
9
+ try {
10
+ // Generate Prisma client
11
+ console.log('šŸ“¦ Generating Prisma client...');
12
+ execSync('npx prisma generate', {
13
+ stdio: 'inherit',
14
+ cwd: resolve(__dirname, '..')
15
+ });
16
+
17
+ console.log('\nāœ… Setup complete!');
18
+ console.log('\nRun: phantom-ai setup - to configure API key');
19
+ console.log('Run: phantom-ai start - to start the server\n');
20
+ } catch (e) {
21
+ console.error('āŒ Setup failed:', e.message);
22
+ process.exit(1);
23
+ }
24
+