mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-29 15:30:40 -07:00
Debug command. (#23851)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -803,7 +803,26 @@ function setupNetworkLogging(
|
||||
// Flush buffered logs
|
||||
flushBuffer();
|
||||
break;
|
||||
|
||||
case 'trigger-debugger': {
|
||||
import('node:inspector')
|
||||
.then((inspector) => {
|
||||
inspector.open();
|
||||
debugLogger.log(
|
||||
'Node debugger attached. Open chrome://inspect in Chrome to start debugging.',
|
||||
);
|
||||
return import('./events.js');
|
||||
})
|
||||
.then(({ appEvents, AppEvent, TransientMessageType }) => {
|
||||
appEvents.emit(AppEvent.TransientMessage, {
|
||||
message: 'Debugger attached from DevTools.',
|
||||
type: TransientMessageType.Hint,
|
||||
});
|
||||
})
|
||||
.catch((err) =>
|
||||
debugLogger.debug('Failed to trigger debugger:', err),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'ping':
|
||||
sendMessage({ type: 'pong', timestamp: Date.now() });
|
||||
break;
|
||||
|
||||
@@ -51,10 +51,11 @@ gemini.tsx / nonInteractiveCli.ts
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
| --------- | --------- | --------------------------------------------------------------------------- |
|
||||
| `/ws` | WebSocket | Log ingestion from CLI sessions (register, network, console) |
|
||||
| `/events` | SSE | Pushes snapshot on connect, then incremental network/console/session events |
|
||||
| Endpoint | Method | Description |
|
||||
| ----------------------- | --------- | --------------------------------------------------------------------------- |
|
||||
| `/ws` | WebSocket | Log ingestion from CLI sessions (register, network, console) |
|
||||
| `/events` | SSE | Pushes snapshot on connect, then incremental network/console/session events |
|
||||
| `/api/trigger-debugger` | POST | Triggers the Node.js debugger for a specific CLI session via WebSocket |
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
@@ -39,6 +39,21 @@ export default function App() {
|
||||
null,
|
||||
);
|
||||
|
||||
// --- Toast Logic ---
|
||||
const [toastMessage, setToastMessage] = useState<string | null>(null);
|
||||
const toastTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const showToast = (msg: string) => {
|
||||
setToastMessage(msg);
|
||||
if (toastTimeoutRef.current) {
|
||||
clearTimeout(toastTimeoutRef.current);
|
||||
}
|
||||
toastTimeoutRef.current = setTimeout(() => {
|
||||
setToastMessage(null);
|
||||
toastTimeoutRef.current = null;
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
// --- Theme Logic ---
|
||||
const [themeMode, setThemeMode] = useState<ThemeMode>(() => {
|
||||
const saved = localStorage.getItem('devtools-theme');
|
||||
@@ -306,21 +321,52 @@ export default function App() {
|
||||
>
|
||||
{selectedSessionId &&
|
||||
connectedSessions.includes(selectedSessionId) && (
|
||||
<button
|
||||
onClick={handleExport}
|
||||
style={{
|
||||
fontSize: '11px',
|
||||
padding: '4px 8px',
|
||||
border: `1px solid ${t.border}`,
|
||||
background: t.bg,
|
||||
color: t.text,
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
📤 Export
|
||||
</button>
|
||||
<>
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
await fetch('/api/trigger-debugger', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ sessionId: selectedSessionId }),
|
||||
});
|
||||
showToast(
|
||||
'Node debugger attached. Open chrome://inspect in Chrome to start debugging.',
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Failed to trigger debugger:', e);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
fontSize: '11px',
|
||||
padding: '4px 8px',
|
||||
border: `1px solid ${t.border}`,
|
||||
background: t.bg,
|
||||
color: t.text,
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
title="Attach Node Debugger and open chrome://inspect"
|
||||
>
|
||||
🐞 Debug Node
|
||||
</button>
|
||||
<button
|
||||
onClick={handleExport}
|
||||
style={{
|
||||
fontSize: '11px',
|
||||
padding: '4px 8px',
|
||||
border: `1px solid ${t.border}`,
|
||||
background: t.bg,
|
||||
color: t.text,
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
📤 Export
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
|
||||
<label
|
||||
@@ -487,6 +533,38 @@ export default function App() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Toast Notification */}
|
||||
{toastMessage && (
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
bottom: '24px',
|
||||
right: '24px',
|
||||
background: t.accent,
|
||||
color: '#fff',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
||||
fontSize: '13px',
|
||||
fontWeight: 500,
|
||||
zIndex: 1000,
|
||||
animation: 'fadeInOut 5s ease forwards',
|
||||
}}
|
||||
>
|
||||
{toastMessage}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CSS Animations */}
|
||||
<style>{`
|
||||
@keyframes fadeInOut {
|
||||
0% { opacity: 0; transform: translateY(10px); }
|
||||
5% { opacity: 1; transform: translateY(0); }
|
||||
95% { opacity: 1; transform: translateY(0); }
|
||||
100% { opacity: 0; transform: translateY(10px); }
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,41 @@ export class DevTools extends EventEmitter {
|
||||
}
|
||||
|
||||
// API routes
|
||||
if (req.url === '/events') {
|
||||
if (req.url === '/api/trigger-debugger' && req.method === 'POST') {
|
||||
let body = '';
|
||||
req.on('data', (chunk) => {
|
||||
body += chunk;
|
||||
});
|
||||
req.on('end', () => {
|
||||
try {
|
||||
const parsed: unknown = JSON.parse(body);
|
||||
if (
|
||||
typeof parsed !== 'object' ||
|
||||
parsed === null ||
|
||||
!('sessionId' in parsed) ||
|
||||
typeof parsed.sessionId !== 'string'
|
||||
) {
|
||||
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: 'Invalid request' }));
|
||||
return;
|
||||
}
|
||||
const sessionId = parsed.sessionId;
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (session) {
|
||||
session.ws.send(JSON.stringify({ type: 'trigger-debugger' }));
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ success: true }));
|
||||
} else {
|
||||
res.writeHead(404, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: 'Session not found' }));
|
||||
}
|
||||
} catch (_err) {
|
||||
res.writeHead(400, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ error: 'Invalid request' }));
|
||||
}
|
||||
});
|
||||
} else if (req.url === '/events') {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
|
||||
Reference in New Issue
Block a user