antigravity-chat-proxy 0.1.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 +362 -0
- package/app/api/v1/artifacts/[convId]/[filename]/route.ts +75 -0
- package/app/api/v1/artifacts/[convId]/route.ts +47 -0
- package/app/api/v1/artifacts/active/[filename]/route.ts +50 -0
- package/app/api/v1/artifacts/active/route.ts +89 -0
- package/app/api/v1/artifacts/route.ts +43 -0
- package/app/api/v1/chat/action/route.ts +30 -0
- package/app/api/v1/chat/approve/route.ts +21 -0
- package/app/api/v1/chat/history/route.ts +23 -0
- package/app/api/v1/chat/mode/route.ts +59 -0
- package/app/api/v1/chat/new/route.ts +21 -0
- package/app/api/v1/chat/reject/route.ts +21 -0
- package/app/api/v1/chat/route.ts +105 -0
- package/app/api/v1/chat/state/route.ts +23 -0
- package/app/api/v1/chat/stream/route.ts +258 -0
- package/app/api/v1/conversations/active/route.ts +117 -0
- package/app/api/v1/conversations/route.ts +189 -0
- package/app/api/v1/conversations/select/route.ts +114 -0
- package/app/api/v1/debug/dom/route.ts +30 -0
- package/app/api/v1/debug/scrape/route.ts +56 -0
- package/app/api/v1/health/route.ts +13 -0
- package/app/api/v1/windows/cdp-start/route.ts +32 -0
- package/app/api/v1/windows/cdp-status/route.ts +32 -0
- package/app/api/v1/windows/close/route.ts +67 -0
- package/app/api/v1/windows/open/route.ts +49 -0
- package/app/api/v1/windows/recent/route.ts +25 -0
- package/app/api/v1/windows/route.ts +27 -0
- package/app/api/v1/windows/select/route.ts +35 -0
- package/app/debug/page.tsx +228 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +1234 -0
- package/app/layout.tsx +42 -0
- package/app/page.tsx +10 -0
- package/bin/cli.js +601 -0
- package/components/agent-message.tsx +63 -0
- package/components/artifact-panel.tsx +133 -0
- package/components/chat-container.tsx +82 -0
- package/components/chat-input.tsx +92 -0
- package/components/conversation-selector.tsx +97 -0
- package/components/header.tsx +302 -0
- package/components/hitl-dialog.tsx +23 -0
- package/components/message-list.tsx +41 -0
- package/components/thinking-block.tsx +14 -0
- package/components/tool-call-card.tsx +75 -0
- package/components/typing-indicator.tsx +11 -0
- package/components/user-message.tsx +13 -0
- package/components/welcome-screen.tsx +38 -0
- package/hooks/use-artifacts.ts +85 -0
- package/hooks/use-chat.ts +278 -0
- package/hooks/use-conversations.ts +190 -0
- package/lib/actions/hitl.ts +113 -0
- package/lib/actions/new-chat.ts +116 -0
- package/lib/actions/send-message.ts +31 -0
- package/lib/actions/switch-conversation.ts +92 -0
- package/lib/cdp/connection.ts +95 -0
- package/lib/cdp/process-manager.ts +327 -0
- package/lib/cdp/recent-projects.ts +137 -0
- package/lib/cdp/selectors.ts +11 -0
- package/lib/context.ts +38 -0
- package/lib/init.ts +48 -0
- package/lib/logger.ts +32 -0
- package/lib/scraper/agent-mode.ts +122 -0
- package/lib/scraper/agent-state.ts +756 -0
- package/lib/scraper/chat-history.ts +138 -0
- package/lib/scraper/ide-conversations.ts +124 -0
- package/lib/sse/diff-states.ts +141 -0
- package/lib/types.ts +146 -0
- package/lib/utils.ts +7 -0
- package/next.config.ts +7 -0
- package/package.json +50 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
interface WindowInfo {
|
|
6
|
+
index: number;
|
|
7
|
+
title: string;
|
|
8
|
+
url: string;
|
|
9
|
+
active: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ScrapeResult {
|
|
13
|
+
raw: string;
|
|
14
|
+
parsed: {
|
|
15
|
+
isRunning: boolean;
|
|
16
|
+
turnCount: number;
|
|
17
|
+
stepGroupCount: number;
|
|
18
|
+
thinking: { time: string }[];
|
|
19
|
+
toolCalls: any[];
|
|
20
|
+
responses: string[];
|
|
21
|
+
notifications: string[];
|
|
22
|
+
error: string | null;
|
|
23
|
+
fileChanges: { fileName: string; type: string }[];
|
|
24
|
+
lastTurnResponseHTML: string;
|
|
25
|
+
};
|
|
26
|
+
meta: {
|
|
27
|
+
timestamp: string;
|
|
28
|
+
activeWindowIdx: number;
|
|
29
|
+
turnCount: number;
|
|
30
|
+
toolCallCount: number;
|
|
31
|
+
responseCount: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default function DebugPage() {
|
|
36
|
+
const [windows, setWindows] = useState<WindowInfo[]>([]);
|
|
37
|
+
const [selectedIdx, setSelectedIdx] = useState<number | null>(null);
|
|
38
|
+
const [scrapeResult, setScrapeResult] = useState<ScrapeResult | null>(null);
|
|
39
|
+
const [loading, setLoading] = useState(false);
|
|
40
|
+
const [error, setError] = useState('');
|
|
41
|
+
const [activeTab, setActiveTab] = useState<'raw' | 'parsed' | 'response'>('parsed');
|
|
42
|
+
|
|
43
|
+
const loadWindows = useCallback(async () => {
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch('/api/v1/windows');
|
|
46
|
+
const data = await res.json();
|
|
47
|
+
setWindows(data.windows || []);
|
|
48
|
+
const active = data.windows?.find((w: WindowInfo) => w.active);
|
|
49
|
+
if (active) setSelectedIdx(active.index);
|
|
50
|
+
} catch (e: any) {
|
|
51
|
+
setError('Failed to load windows: ' + e.message);
|
|
52
|
+
}
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
useEffect(() => { loadWindows(); }, [loadWindows]);
|
|
56
|
+
|
|
57
|
+
const selectWindow = async (idx: number) => {
|
|
58
|
+
setSelectedIdx(idx);
|
|
59
|
+
setError('');
|
|
60
|
+
try {
|
|
61
|
+
await fetch('/api/v1/windows/select', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
body: JSON.stringify({ index: idx }),
|
|
65
|
+
});
|
|
66
|
+
await loadWindows();
|
|
67
|
+
} catch (e: any) {
|
|
68
|
+
setError('Failed to select window: ' + e.message);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const scrape = async () => {
|
|
73
|
+
setLoading(true);
|
|
74
|
+
setError('');
|
|
75
|
+
setScrapeResult(null);
|
|
76
|
+
try {
|
|
77
|
+
const res = await fetch('/api/v1/debug/scrape');
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
const data = await res.json();
|
|
80
|
+
throw new Error(data.error || `HTTP ${res.status}`);
|
|
81
|
+
}
|
|
82
|
+
const data = await res.json();
|
|
83
|
+
setScrapeResult(data);
|
|
84
|
+
} catch (e: any) {
|
|
85
|
+
setError(e.message);
|
|
86
|
+
} finally {
|
|
87
|
+
setLoading(false);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div style={styles.page}>
|
|
93
|
+
<header style={styles.header}>
|
|
94
|
+
<div style={styles.headerLeft}>
|
|
95
|
+
<a href="/" style={styles.backLink}>← Chat</a>
|
|
96
|
+
<h1 style={styles.title}>🔬 Scraper Debug</h1>
|
|
97
|
+
</div>
|
|
98
|
+
<span style={styles.badge}>Debug Tool</span>
|
|
99
|
+
</header>
|
|
100
|
+
|
|
101
|
+
{/* Window Selector */}
|
|
102
|
+
<section style={styles.section}>
|
|
103
|
+
<h2 style={styles.sectionTitle}>1. Select Window</h2>
|
|
104
|
+
<div style={styles.windowGrid}>
|
|
105
|
+
{windows.map((w) => (
|
|
106
|
+
<button
|
|
107
|
+
key={w.index}
|
|
108
|
+
style={{
|
|
109
|
+
...styles.windowCard,
|
|
110
|
+
...(selectedIdx === w.index ? styles.windowCardActive : {}),
|
|
111
|
+
}}
|
|
112
|
+
onClick={() => selectWindow(w.index)}
|
|
113
|
+
>
|
|
114
|
+
<div style={windowDotStyle(selectedIdx === w.index)} />
|
|
115
|
+
<div style={styles.windowInfo}>
|
|
116
|
+
<span style={styles.windowTitle}>{w.title || `Window ${w.index}`}</span>
|
|
117
|
+
<span style={styles.windowUrl}>{w.url?.substring(0, 60)}</span>
|
|
118
|
+
</div>
|
|
119
|
+
{selectedIdx === w.index && <span style={styles.activeBadge}>Active</span>}
|
|
120
|
+
</button>
|
|
121
|
+
))}
|
|
122
|
+
{windows.length === 0 && (
|
|
123
|
+
<div style={styles.emptyState}>No Antigravity windows found. Is the IDE running?</div>
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
</section>
|
|
127
|
+
|
|
128
|
+
{/* Scrape Button */}
|
|
129
|
+
<section style={styles.section}>
|
|
130
|
+
<h2 style={styles.sectionTitle}>2. Scrape Last Agent Response</h2>
|
|
131
|
+
<button style={styles.scrapeBtn} onClick={scrape} disabled={loading || selectedIdx === null}>
|
|
132
|
+
{loading ? '⏳ Scraping...' : '🔍 Scrape Now'}
|
|
133
|
+
</button>
|
|
134
|
+
{error && <div style={styles.errorBox}>⚠️ {error}</div>}
|
|
135
|
+
</section>
|
|
136
|
+
|
|
137
|
+
{/* Results */}
|
|
138
|
+
{scrapeResult && (
|
|
139
|
+
<section style={{ ...styles.section, flex: 1, display: 'flex', flexDirection: 'column' as const, overflow: 'hidden' }}>
|
|
140
|
+
{/* Meta Stats */}
|
|
141
|
+
<div style={styles.metaBar}>
|
|
142
|
+
<span>⏱ {scrapeResult.meta.timestamp}</span>
|
|
143
|
+
<span>🔄 Turns: {scrapeResult.meta.turnCount}</span>
|
|
144
|
+
<span>🔧 Tools: {scrapeResult.meta.toolCallCount}</span>
|
|
145
|
+
<span>💬 Responses: {scrapeResult.meta.responseCount}</span>
|
|
146
|
+
<span>{scrapeResult.parsed.isRunning ? '🟢 Running' : '⚪ Idle'}</span>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
{/* Tabs */}
|
|
150
|
+
<div style={styles.tabs}>
|
|
151
|
+
<button style={{ ...styles.tab, ...(activeTab === 'parsed' ? styles.tabActive : {}) }} onClick={() => setActiveTab('parsed')}>
|
|
152
|
+
Parsed State
|
|
153
|
+
</button>
|
|
154
|
+
<button style={{ ...styles.tab, ...(activeTab === 'response' ? styles.tabActive : {}) }} onClick={() => setActiveTab('response')}>
|
|
155
|
+
Rendered Response
|
|
156
|
+
</button>
|
|
157
|
+
<button style={{ ...styles.tab, ...(activeTab === 'raw' ? styles.tabActive : {}) }} onClick={() => setActiveTab('raw')}>
|
|
158
|
+
Raw HTML
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
{/* Tab Content */}
|
|
163
|
+
<div style={styles.tabContent}>
|
|
164
|
+
{activeTab === 'parsed' && (
|
|
165
|
+
<div style={styles.jsonView}>
|
|
166
|
+
<pre style={styles.pre}>{JSON.stringify(scrapeResult.parsed, null, 2)}</pre>
|
|
167
|
+
</div>
|
|
168
|
+
)}
|
|
169
|
+
{activeTab === 'response' && (
|
|
170
|
+
<div style={styles.renderedView}>
|
|
171
|
+
{scrapeResult.parsed.responses.length > 0 ? (
|
|
172
|
+
scrapeResult.parsed.responses.map((html, i) => (
|
|
173
|
+
<div key={i} style={styles.responseBlock}>
|
|
174
|
+
<div style={styles.responseLabel}>Response #{i}</div>
|
|
175
|
+
<div className="agent-response" dangerouslySetInnerHTML={{ __html: html }} />
|
|
176
|
+
</div>
|
|
177
|
+
))
|
|
178
|
+
) : (
|
|
179
|
+
<div style={styles.emptyState}>No responses scraped from the agent panel.</div>
|
|
180
|
+
)}
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
{activeTab === 'raw' && (
|
|
184
|
+
<div style={styles.rawView}>
|
|
185
|
+
<pre style={styles.pre}>{scrapeResult.raw}</pre>
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
</section>
|
|
190
|
+
)}
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* ── Inline Styles ── */
|
|
196
|
+
const windowDotStyle = (active: boolean): React.CSSProperties => ({ width: '8px', height: '8px', borderRadius: '50%', background: active ? '#34d399' : '#686888', boxShadow: active ? '0 0 8px rgba(52, 211, 153, 0.4)' : 'none', flexShrink: 0 });
|
|
197
|
+
|
|
198
|
+
const styles: Record<string, React.CSSProperties> = {
|
|
199
|
+
page: { display: 'flex', flexDirection: 'column', height: '100vh', maxWidth: '1100px', margin: '0 auto', padding: '0 16px', overflow: 'hidden' },
|
|
200
|
+
header: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px 0', borderBottom: '1px solid rgba(255,255,255,0.06)' },
|
|
201
|
+
headerLeft: { display: 'flex', alignItems: 'center', gap: '16px' },
|
|
202
|
+
backLink: { color: '#6366f1', textDecoration: 'none', fontSize: '13px', fontWeight: 500 },
|
|
203
|
+
title: { fontSize: '20px', fontWeight: 700 },
|
|
204
|
+
badge: { fontSize: '10px', textTransform: 'uppercase' as const, letterSpacing: '0.1em', color: '#686888', border: '1px solid rgba(255,255,255,0.06)', padding: '4px 10px', borderRadius: '12px' },
|
|
205
|
+
section: { padding: '16px 0' },
|
|
206
|
+
sectionTitle: { fontSize: '14px', fontWeight: 600, color: '#9898b0', marginBottom: '12px', textTransform: 'uppercase' as const, letterSpacing: '0.05em' },
|
|
207
|
+
windowGrid: { display: 'flex', flexDirection: 'column' as const, gap: '8px' },
|
|
208
|
+
windowCard: { display: 'flex', alignItems: 'center', gap: '12px', width: '100%', padding: '12px 16px', background: '#12121a', border: '1px solid rgba(255,255,255,0.06)', borderRadius: '10px', cursor: 'pointer', transition: 'all 0.15s ease', textAlign: 'left' as const, color: '#9898b0', fontFamily: 'inherit', fontSize: '13px' },
|
|
209
|
+
windowCardActive: { borderColor: 'rgba(99, 102, 241, 0.4)', background: 'rgba(99, 102, 241, 0.06)', color: '#e8e8f0' },
|
|
210
|
+
windowInfo: { flex: 1, display: 'flex', flexDirection: 'column' as const, gap: '2px', overflow: 'hidden' },
|
|
211
|
+
windowTitle: { fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' as const },
|
|
212
|
+
windowUrl: { fontSize: '10px', color: '#686888', fontFamily: "'JetBrains Mono', monospace", overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' as const },
|
|
213
|
+
activeBadge: { fontSize: '10px', color: '#34d399', background: 'rgba(52, 211, 153, 0.1)', padding: '2px 8px', borderRadius: '8px', fontWeight: 600, flexShrink: 0 },
|
|
214
|
+
scrapeBtn: { padding: '10px 24px', borderRadius: '10px', border: 'none', background: 'linear-gradient(135deg, #6366f1, #a855f7)', color: 'white', fontSize: '14px', fontWeight: 600, cursor: 'pointer', transition: 'all 0.2s ease', fontFamily: 'inherit' },
|
|
215
|
+
errorBox: { marginTop: '12px', padding: '10px 14px', background: 'rgba(239, 68, 68, 0.06)', border: '1px solid rgba(239, 68, 68, 0.4)', borderRadius: '8px', color: '#ef4444', fontSize: '13px' },
|
|
216
|
+
metaBar: { display: 'flex', gap: '16px', flexWrap: 'wrap' as const, padding: '10px 14px', background: '#12121a', borderRadius: '8px', fontSize: '11px', color: '#9898b0', fontFamily: "'JetBrains Mono', monospace", marginBottom: '12px' },
|
|
217
|
+
tabs: { display: 'flex', gap: '4px', marginBottom: '12px' },
|
|
218
|
+
tab: { padding: '8px 16px', borderRadius: '8px', border: '1px solid rgba(255,255,255,0.06)', background: 'transparent', color: '#9898b0', fontSize: '12px', fontWeight: 500, cursor: 'pointer', fontFamily: 'inherit', transition: 'all 0.15s ease' },
|
|
219
|
+
tabActive: { background: 'rgba(99, 102, 241, 0.1)', borderColor: 'rgba(99, 102, 241, 0.4)', color: '#e8e8f0' },
|
|
220
|
+
tabContent: { flex: 1, overflow: 'auto', borderRadius: '10px', border: '1px solid rgba(255,255,255,0.06)', background: '#0d0d14' },
|
|
221
|
+
jsonView: { padding: '16px' },
|
|
222
|
+
rawView: { padding: '16px' },
|
|
223
|
+
renderedView: { padding: '16px' },
|
|
224
|
+
pre: { margin: 0, fontSize: '12px', lineHeight: 1.6, color: '#9898b0', fontFamily: "'JetBrains Mono', monospace", whiteSpace: 'pre-wrap' as const, wordBreak: 'break-all' as const },
|
|
225
|
+
responseBlock: { padding: '16px', background: 'rgba(255,255,255,0.02)', borderRadius: '8px', marginBottom: '12px', border: '1px solid rgba(255,255,255,0.04)' },
|
|
226
|
+
responseLabel: { fontSize: '10px', color: '#686888', textTransform: 'uppercase' as const, letterSpacing: '0.08em', marginBottom: '8px', fontWeight: 600 },
|
|
227
|
+
emptyState: { textAlign: 'center' as const, padding: '32px', color: '#686888', fontSize: '13px' },
|
|
228
|
+
};
|
package/app/favicon.ico
ADDED
|
Binary file
|