gemini-cli-devtools 0.1.4 → 0.2.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/dist/client/main.js +76 -0
- package/dist/src/index.d.ts +46 -0
- package/dist/src/index.js +81 -272
- package/dist/src/types.d.ts +36 -0
- package/dist/src/types.js +6 -0
- package/package.json +13 -14
- package/dist/client/assets/index-CAfB090D.js +0 -55
- package/dist/client/index.html +0 -25
- package/dist/src/bin.js +0 -43
package/dist/src/index.js
CHANGED
|
@@ -4,25 +4,19 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import http from 'node:http';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import fs from 'node:fs';
|
|
10
|
-
import path from 'node:path';
|
|
11
|
-
import os from 'node:os';
|
|
7
|
+
import { randomUUID } from 'node:crypto';
|
|
8
|
+
import { readFileSync } from 'node:fs';
|
|
12
9
|
import { fileURLToPath } from 'node:url';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
import { EventEmitter } from 'node:events';
|
|
13
12
|
import { WebSocketServer } from 'ws';
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const srcDir = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
-
// In dev: src/index.ts -> srcDir is "src"
|
|
19
|
-
// In prod: dist/src/index.js -> srcDir is "dist/src"
|
|
20
|
-
return srcDir.endsWith('/src') && !srcDir.includes('/dist/');
|
|
21
|
-
})();
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const indexHtml = readFileSync(join(__dirname, '../../client/index.html'), 'utf-8');
|
|
15
|
+
const mainJs = readFileSync(join(__dirname, '../client/main.js'), 'utf-8');
|
|
22
16
|
/**
|
|
23
17
|
* DevTools Viewer
|
|
24
18
|
*
|
|
25
|
-
*
|
|
19
|
+
* Receives logs via WebSocket from CLI sessions.
|
|
26
20
|
*/
|
|
27
21
|
export class DevTools extends EventEmitter {
|
|
28
22
|
static instance;
|
|
@@ -31,8 +25,8 @@ export class DevTools extends EventEmitter {
|
|
|
31
25
|
server = null;
|
|
32
26
|
wss = null;
|
|
33
27
|
sessions = new Map();
|
|
28
|
+
heartbeatTimer = null;
|
|
34
29
|
port = 25417;
|
|
35
|
-
watchedFiles = new Map(); // filePath -> lastSize
|
|
36
30
|
constructor() {
|
|
37
31
|
super();
|
|
38
32
|
}
|
|
@@ -42,126 +36,17 @@ export class DevTools extends EventEmitter {
|
|
|
42
36
|
}
|
|
43
37
|
return DevTools.instance;
|
|
44
38
|
}
|
|
45
|
-
getNetworkLogs() {
|
|
46
|
-
return this.logs;
|
|
47
|
-
}
|
|
48
|
-
getConsoleLogs() {
|
|
49
|
-
return this.consoleLogs;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Main entry for log discovery.
|
|
53
|
-
* It scans both user home and system tmp for .gemini/tmp folders.
|
|
54
|
-
*/
|
|
55
|
-
setLogFile() {
|
|
56
|
-
const potentialRoots = [
|
|
57
|
-
path.join(os.homedir(), '.gemini', 'tmp'),
|
|
58
|
-
path.join(os.tmpdir(), '.gemini', 'tmp'),
|
|
59
|
-
];
|
|
60
|
-
for (const baseDir of potentialRoots) {
|
|
61
|
-
if (fs.existsSync(baseDir)) {
|
|
62
|
-
console.log(`🔍 Scanning for logs in: ${baseDir}`);
|
|
63
|
-
this.deepDiscover(baseDir);
|
|
64
|
-
this.watchRoot(baseDir);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
watchRoot(root) {
|
|
69
|
-
try {
|
|
70
|
-
fs.watch(root, { recursive: true }, (_event, filename) => {
|
|
71
|
-
if (filename &&
|
|
72
|
-
filename.includes('session-') &&
|
|
73
|
-
filename.endsWith('.jsonl')) {
|
|
74
|
-
this.deepDiscover(root);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
setInterval(() => this.deepDiscover(root), 2000);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
deepDiscover(dir) {
|
|
83
|
-
try {
|
|
84
|
-
const items = fs.readdirSync(dir);
|
|
85
|
-
for (const item of items) {
|
|
86
|
-
const fullPath = path.join(dir, item);
|
|
87
|
-
let stats;
|
|
88
|
-
try {
|
|
89
|
-
stats = fs.statSync(fullPath);
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (stats.isDirectory()) {
|
|
95
|
-
if (item === 'logs' || item.length > 20) {
|
|
96
|
-
this.deepDiscover(fullPath);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else if (item.startsWith('session-') && item.endsWith('.jsonl')) {
|
|
100
|
-
if (!this.watchedFiles.has(fullPath)) {
|
|
101
|
-
this.watchedFiles.set(fullPath, 0);
|
|
102
|
-
this.readNewLogs(fullPath, 0);
|
|
103
|
-
}
|
|
104
|
-
else if (stats.size > this.watchedFiles.get(fullPath)) {
|
|
105
|
-
this.readNewLogs(fullPath, this.watchedFiles.get(fullPath));
|
|
106
|
-
this.watchedFiles.set(fullPath, stats.size);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
/* ignore */
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
readNewLogs(filePath, startByte) {
|
|
116
|
-
try {
|
|
117
|
-
const filename = path.basename(filePath);
|
|
118
|
-
const sessionMatch = filename.match(/session-(.*)\.jsonl/);
|
|
119
|
-
const fallbackSessionId = sessionMatch ? sessionMatch[1] : undefined;
|
|
120
|
-
const stream = fs.createReadStream(filePath, { start: startByte });
|
|
121
|
-
let buffer = '';
|
|
122
|
-
stream.on('data', (chunk) => {
|
|
123
|
-
buffer += chunk.toString();
|
|
124
|
-
const lines = buffer.split('\n');
|
|
125
|
-
buffer = lines.pop() || '';
|
|
126
|
-
for (const line of lines) {
|
|
127
|
-
if (!line.trim())
|
|
128
|
-
continue;
|
|
129
|
-
try {
|
|
130
|
-
const entry = JSON.parse(line);
|
|
131
|
-
const sid = entry.sessionId || fallbackSessionId;
|
|
132
|
-
if (entry.type === 'console') {
|
|
133
|
-
this.addInternalConsoleLog(entry.payload, sid, entry.timestamp);
|
|
134
|
-
}
|
|
135
|
-
else if (entry.type === 'network') {
|
|
136
|
-
this.addInternalNetworkLog(entry.payload, sid, entry.timestamp);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
/* ignore */
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
this.watchedFiles.set(filePath, fs.statSync(filePath).size);
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
/* ignore */
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
/* ignore */
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
39
|
addInternalConsoleLog(payload, sessionId, timestamp) {
|
|
156
|
-
|
|
40
|
+
const entry = {
|
|
157
41
|
...payload,
|
|
158
|
-
id:
|
|
42
|
+
id: randomUUID(),
|
|
159
43
|
sessionId,
|
|
160
44
|
timestamp: timestamp || Date.now(),
|
|
161
|
-
}
|
|
45
|
+
};
|
|
46
|
+
this.consoleLogs.push(entry);
|
|
162
47
|
if (this.consoleLogs.length > 5000)
|
|
163
48
|
this.consoleLogs.shift();
|
|
164
|
-
this.emit('console-update');
|
|
49
|
+
this.emit('console-update', entry);
|
|
165
50
|
}
|
|
166
51
|
addInternalNetworkLog(payload, sessionId, timestamp) {
|
|
167
52
|
if (!payload.id)
|
|
@@ -173,7 +58,6 @@ export class DevTools extends EventEmitter {
|
|
|
173
58
|
if (payload.chunk) {
|
|
174
59
|
const chunks = existing.chunks || [];
|
|
175
60
|
chunks.push(payload.chunk);
|
|
176
|
-
console.log(`[DevTools] Received chunk ${payload.chunk.index} for request ${payload.id}, total chunks: ${chunks.length}`);
|
|
177
61
|
this.logs[existingIndex] = {
|
|
178
62
|
...existing,
|
|
179
63
|
chunks,
|
|
@@ -191,31 +75,47 @@ export class DevTools extends EventEmitter {
|
|
|
191
75
|
: existing.response,
|
|
192
76
|
};
|
|
193
77
|
}
|
|
78
|
+
this.emit('update', this.logs[existingIndex]);
|
|
194
79
|
}
|
|
195
80
|
else if (payload.url) {
|
|
196
|
-
|
|
81
|
+
const entry = {
|
|
197
82
|
...payload,
|
|
198
83
|
sessionId,
|
|
199
84
|
timestamp: timestamp || Date.now(),
|
|
200
85
|
chunks: payload.chunk ? [payload.chunk] : undefined,
|
|
201
|
-
}
|
|
86
|
+
};
|
|
87
|
+
this.logs.push(entry);
|
|
202
88
|
if (this.logs.length > 2000)
|
|
203
89
|
this.logs.shift();
|
|
90
|
+
this.emit('update', entry);
|
|
204
91
|
}
|
|
205
|
-
this.emit('update');
|
|
206
92
|
}
|
|
207
93
|
getUrl() {
|
|
208
94
|
return `http://127.0.0.1:${this.port}`;
|
|
209
95
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
96
|
+
getPort() {
|
|
97
|
+
return this.port;
|
|
98
|
+
}
|
|
99
|
+
stop() {
|
|
100
|
+
return new Promise((resolve) => {
|
|
101
|
+
if (this.heartbeatTimer) {
|
|
102
|
+
clearInterval(this.heartbeatTimer);
|
|
103
|
+
this.heartbeatTimer = null;
|
|
104
|
+
}
|
|
105
|
+
if (this.wss) {
|
|
106
|
+
this.wss.close();
|
|
107
|
+
this.wss = null;
|
|
108
|
+
}
|
|
109
|
+
if (this.server) {
|
|
110
|
+
this.server.close(() => resolve());
|
|
111
|
+
this.server = null;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
resolve();
|
|
115
|
+
}
|
|
116
|
+
// Reset singleton so a fresh start() is possible
|
|
117
|
+
DevTools.instance = undefined;
|
|
118
|
+
});
|
|
219
119
|
}
|
|
220
120
|
start() {
|
|
221
121
|
return new Promise((resolve) => {
|
|
@@ -223,100 +123,53 @@ export class DevTools extends EventEmitter {
|
|
|
223
123
|
resolve(this.getUrl());
|
|
224
124
|
return;
|
|
225
125
|
}
|
|
226
|
-
const clientPath = this.getClientPath();
|
|
227
126
|
this.server = http.createServer((req, res) => {
|
|
228
127
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
229
128
|
// API routes
|
|
230
|
-
if (req.url === '/
|
|
231
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
232
|
-
res.end(JSON.stringify(this.logs));
|
|
233
|
-
}
|
|
234
|
-
else if (req.url === '/console-logs') {
|
|
235
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
236
|
-
res.end(JSON.stringify(this.consoleLogs));
|
|
237
|
-
}
|
|
238
|
-
else if (req.url === '/sessions') {
|
|
239
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
240
|
-
const sessionIds = Array.from(this.sessions.keys());
|
|
241
|
-
res.end(JSON.stringify(sessionIds));
|
|
242
|
-
}
|
|
243
|
-
else if (req.url === '/events') {
|
|
129
|
+
if (req.url === '/events') {
|
|
244
130
|
res.writeHead(200, {
|
|
245
131
|
'Content-Type': 'text/event-stream',
|
|
246
132
|
'Cache-Control': 'no-cache',
|
|
247
133
|
Connection: 'keep-alive',
|
|
248
134
|
});
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
135
|
+
// Send full snapshot on connect
|
|
136
|
+
const snapshot = JSON.stringify({
|
|
137
|
+
networkLogs: this.logs,
|
|
138
|
+
consoleLogs: this.consoleLogs,
|
|
139
|
+
sessions: Array.from(this.sessions.keys()),
|
|
140
|
+
});
|
|
141
|
+
res.write(`event: snapshot\ndata: ${snapshot}\n\n`);
|
|
142
|
+
// Incremental updates
|
|
143
|
+
const onNetwork = (log) => {
|
|
144
|
+
res.write(`event: network\ndata: ${JSON.stringify(log)}\n\n`);
|
|
145
|
+
};
|
|
146
|
+
const onConsole = (log) => {
|
|
147
|
+
res.write(`event: console\ndata: ${JSON.stringify(log)}\n\n`);
|
|
148
|
+
};
|
|
149
|
+
const onSession = () => {
|
|
150
|
+
const sessions = Array.from(this.sessions.keys());
|
|
151
|
+
res.write(`event: session\ndata: ${JSON.stringify(sessions)}\n\n`);
|
|
152
|
+
};
|
|
153
|
+
this.on('update', onNetwork);
|
|
154
|
+
this.on('console-update', onConsole);
|
|
155
|
+
this.on('session-update', onSession);
|
|
255
156
|
req.on('close', () => {
|
|
256
|
-
this.off('update',
|
|
257
|
-
this.off('console-update',
|
|
258
|
-
this.off('session-update',
|
|
157
|
+
this.off('update', onNetwork);
|
|
158
|
+
this.off('console-update', onConsole);
|
|
159
|
+
this.off('session-update', onSession);
|
|
259
160
|
});
|
|
260
161
|
}
|
|
261
|
-
else if (req.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
req.on('end', () => {
|
|
265
|
-
try {
|
|
266
|
-
const entry = JSON.parse(body);
|
|
267
|
-
if (entry.type === 'console') {
|
|
268
|
-
this.addInternalConsoleLog(entry.payload, entry.sessionId, entry.timestamp);
|
|
269
|
-
}
|
|
270
|
-
else if (entry.type === 'network') {
|
|
271
|
-
this.addInternalNetworkLog(entry.payload, entry.sessionId, entry.timestamp);
|
|
272
|
-
}
|
|
273
|
-
res.writeHead(200);
|
|
274
|
-
res.end('OK');
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
res.writeHead(400);
|
|
278
|
-
res.end('Invalid JSON');
|
|
279
|
-
}
|
|
280
|
-
});
|
|
162
|
+
else if (req.url === '/' || req.url === '/index.html') {
|
|
163
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
164
|
+
res.end(indexHtml);
|
|
281
165
|
}
|
|
282
|
-
else if (req.
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
req.on('end', () => {
|
|
286
|
-
const tmpIn = path.join(os.tmpdir(), `req-${Date.now()}.json`);
|
|
287
|
-
fs.writeFileSync(tmpIn, body);
|
|
288
|
-
const script = `
|
|
289
|
-
import sys
|
|
290
|
-
sys.path.insert(0, '/tmp/proto_gen')
|
|
291
|
-
from google.cloud.aiplatform.v1 import prediction_service_pb2
|
|
292
|
-
from google.protobuf.json_format import Parse
|
|
293
|
-
from google.protobuf import text_format
|
|
294
|
-
import json
|
|
295
|
-
|
|
296
|
-
with open(sys.argv[1]) as f:
|
|
297
|
-
msg = Parse(f.read(), prediction_service_pb2.GenerateContentRequest(), ignore_unknown_fields=True)
|
|
298
|
-
print(text_format.MessageToString(msg, as_utf8=True), end='')
|
|
299
|
-
`;
|
|
300
|
-
execFile('/tmp/proto_venv/bin/python3', ['-c', script, tmpIn], { maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
301
|
-
fs.unlinkSync(tmpIn);
|
|
302
|
-
if (err) {
|
|
303
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
304
|
-
res.end(stderr || err.message);
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
308
|
-
res.end(stdout);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
else if (isDev) {
|
|
314
|
-
// Dev mode: proxy to Vite
|
|
315
|
-
this.proxyToVite(req, res);
|
|
166
|
+
else if (req.url === '/assets/main.js') {
|
|
167
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
168
|
+
res.end(mainJs);
|
|
316
169
|
}
|
|
317
170
|
else {
|
|
318
|
-
|
|
319
|
-
|
|
171
|
+
res.writeHead(404);
|
|
172
|
+
res.end('Not Found');
|
|
320
173
|
}
|
|
321
174
|
});
|
|
322
175
|
this.server.on('error', (e) => {
|
|
@@ -351,7 +204,6 @@ print(text_format.MessageToString(msg, as_utf8=True), end='')
|
|
|
351
204
|
ws,
|
|
352
205
|
lastPing: Date.now(),
|
|
353
206
|
});
|
|
354
|
-
console.log(`📡 WebSocket registered: ${sessionId}`);
|
|
355
207
|
// Notify session update
|
|
356
208
|
this.emit('session-update');
|
|
357
209
|
// Send registration acknowledgement
|
|
@@ -365,28 +217,25 @@ print(text_format.MessageToString(msg, as_utf8=True), end='')
|
|
|
365
217
|
this.handleWebSocketMessage(sessionId, message);
|
|
366
218
|
}
|
|
367
219
|
}
|
|
368
|
-
catch
|
|
369
|
-
|
|
220
|
+
catch {
|
|
221
|
+
// Invalid WebSocket message
|
|
370
222
|
}
|
|
371
223
|
});
|
|
372
224
|
ws.on('close', () => {
|
|
373
225
|
if (sessionId) {
|
|
374
|
-
console.log(`📡 WebSocket disconnected: ${sessionId}`);
|
|
375
226
|
this.sessions.delete(sessionId);
|
|
376
|
-
this.emit('session-disconnected', sessionId);
|
|
377
227
|
this.emit('session-update');
|
|
378
228
|
}
|
|
379
229
|
});
|
|
380
|
-
ws.on('error', (
|
|
381
|
-
|
|
230
|
+
ws.on('error', () => {
|
|
231
|
+
// WebSocket error — no action needed
|
|
382
232
|
});
|
|
383
233
|
});
|
|
384
234
|
// Heartbeat mechanism
|
|
385
|
-
setInterval(() => {
|
|
235
|
+
this.heartbeatTimer = setInterval(() => {
|
|
386
236
|
const now = Date.now();
|
|
387
237
|
this.sessions.forEach((session, sessionId) => {
|
|
388
238
|
if (now - session.lastPing > 30000) {
|
|
389
|
-
console.log(`⚠️ Session ${sessionId} timeout, closing...`);
|
|
390
239
|
session.ws.close();
|
|
391
240
|
this.sessions.delete(sessionId);
|
|
392
241
|
}
|
|
@@ -412,47 +261,7 @@ print(text_format.MessageToString(msg, as_utf8=True), end='')
|
|
|
412
261
|
this.addInternalNetworkLog(message.payload, sessionId, message.timestamp);
|
|
413
262
|
break;
|
|
414
263
|
default:
|
|
415
|
-
|
|
264
|
+
break;
|
|
416
265
|
}
|
|
417
266
|
}
|
|
418
|
-
proxyToVite(req, res) {
|
|
419
|
-
const proxyReq = http.request({
|
|
420
|
-
hostname: '127.0.0.1',
|
|
421
|
-
port: VITE_DEV_PORT,
|
|
422
|
-
path: req.url,
|
|
423
|
-
method: req.method,
|
|
424
|
-
headers: req.headers,
|
|
425
|
-
}, (proxyRes) => {
|
|
426
|
-
res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
|
|
427
|
-
proxyRes.pipe(res);
|
|
428
|
-
});
|
|
429
|
-
proxyReq.on('error', () => {
|
|
430
|
-
res.writeHead(502);
|
|
431
|
-
res.end('Vite dev server not ready');
|
|
432
|
-
});
|
|
433
|
-
req.pipe(proxyReq);
|
|
434
|
-
}
|
|
435
|
-
serveStatic(req, res, clientPath) {
|
|
436
|
-
const url = req.url === '/' ? '/index.html' : req.url || '/index.html';
|
|
437
|
-
const filePath = path.join(clientPath, url);
|
|
438
|
-
fs.readFile(filePath, (err, data) => {
|
|
439
|
-
if (err) {
|
|
440
|
-
res.writeHead(404);
|
|
441
|
-
res.end('Not Found');
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
const ext = path.extname(filePath);
|
|
445
|
-
const contentTypes = {
|
|
446
|
-
'.html': 'text/html',
|
|
447
|
-
'.js': 'application/javascript',
|
|
448
|
-
'.css': 'text/css',
|
|
449
|
-
'.svg': 'image/svg+xml',
|
|
450
|
-
'.json': 'application/json',
|
|
451
|
-
};
|
|
452
|
-
res.writeHead(200, {
|
|
453
|
-
'Content-Type': contentTypes[ext] || 'text/plain',
|
|
454
|
-
});
|
|
455
|
-
res.end(data);
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
267
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
export interface NetworkLog {
|
|
7
|
+
id: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
method: string;
|
|
11
|
+
url: string;
|
|
12
|
+
headers: Record<string, string | string[] | undefined>;
|
|
13
|
+
body?: string;
|
|
14
|
+
pending?: boolean;
|
|
15
|
+
chunks?: Array<{
|
|
16
|
+
index: number;
|
|
17
|
+
data: string;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
}>;
|
|
20
|
+
response?: {
|
|
21
|
+
status: number;
|
|
22
|
+
headers: Record<string, string | string[] | undefined>;
|
|
23
|
+
body?: string;
|
|
24
|
+
durationMs: number;
|
|
25
|
+
};
|
|
26
|
+
error?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ConsoleLogPayload {
|
|
29
|
+
type: 'log' | 'warn' | 'error' | 'debug' | 'info';
|
|
30
|
+
content: string;
|
|
31
|
+
}
|
|
32
|
+
export interface InspectorConsoleLog extends ConsoleLogPayload {
|
|
33
|
+
id: string;
|
|
34
|
+
sessionId?: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gemini-cli-devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/src/index.d.ts",
|
|
10
|
+
"default": "./dist/src/index.js"
|
|
11
|
+
}
|
|
9
12
|
},
|
|
10
13
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"build": "
|
|
13
|
-
"build:client": "vite build"
|
|
14
|
+
"build": "npm run build:client && tsc --outDir dist/src --declaration --module ESNext --target ESNext --moduleResolution bundler src/index.ts",
|
|
15
|
+
"build:client": "node esbuild.client.js"
|
|
14
16
|
},
|
|
15
17
|
"files": [
|
|
16
18
|
"dist"
|
|
@@ -19,19 +21,16 @@
|
|
|
19
21
|
"node": ">=20"
|
|
20
22
|
},
|
|
21
23
|
"dependencies": {
|
|
22
|
-
"react": "^18.2.0",
|
|
23
|
-
"react-dom": "^18.2.0",
|
|
24
24
|
"ws": "^8.16.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
+
"@types/node": "^20.11.24",
|
|
27
28
|
"@types/react": "^18.2.0",
|
|
28
29
|
"@types/react-dom": "^18.2.0",
|
|
29
30
|
"@types/ws": "^8.5.10",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"concurrently": "^8.2.2",
|
|
35
|
-
"tsx": "^4.7.0"
|
|
31
|
+
"esbuild": "^0.24.0",
|
|
32
|
+
"react": "^18.2.0",
|
|
33
|
+
"react-dom": "^18.2.0",
|
|
34
|
+
"typescript": "^5.3.3"
|
|
36
35
|
}
|
|
37
36
|
}
|