@sleepinsummer/agent-browser-cli 0.2.9 → 0.3.1-beta.2

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.
@@ -19,6 +19,25 @@ let lastCommandAt = 0;
19
19
  const DEFAULT_WS_PORT = 18765;
20
20
  const CLI_API_PORT = 18767;
21
21
  let wsPort = DEFAULT_WS_PORT;
22
+ const browserId = `browser-${crypto.randomUUID()}`;
23
+ let profileId = null;
24
+ let profileLabel = null;
25
+
26
+ async function loadClientIdentity() {
27
+ const data = await chrome.storage.local.get({ profileId: null, profileLabel: null });
28
+ profileId = data.profileId || `profile-${crypto.randomUUID()}`;
29
+ profileLabel = data.profileLabel || null;
30
+ if (!data.profileId) await chrome.storage.local.set({ profileId });
31
+ return { browserId, profileId, profileLabel };
32
+ }
33
+
34
+ function withClientIdentity(payload) {
35
+ return Object.assign({
36
+ browser_id: browserId,
37
+ profile_id: profileId || 'profile-pending',
38
+ profile_label: profileLabel || undefined
39
+ }, payload);
40
+ }
22
41
 
23
42
  async function handleExtMessage(msg, sender) {
24
43
  if (msg.cmd === 'status') return handleStatus();
@@ -28,11 +47,23 @@ async function handleExtMessage(msg, sender) {
28
47
  if (msg.cmd === 'cdp') return await handleCDP(msg, sender);
29
48
  if (msg.cmd === 'batch') return await handleBatch(msg, sender);
30
49
  if (msg.cmd === 'openTab') return await handleOpenTab(msg);
50
+ if (msg.cmd === 'closeTab') return await handleCloseTab(msg, sender);
51
+ if (msg.cmd === 'networkStart') return await handleNetworkStart(msg, sender);
52
+ if (msg.cmd === 'networkList') return await handleNetworkList(msg, sender);
53
+ if (msg.cmd === 'networkDetail') return await handleNetworkDetail(msg, sender);
54
+ if (msg.cmd === 'networkClear') return await handleNetworkClear(msg, sender);
55
+ if (msg.cmd === 'networkStop') return await handleNetworkStop(msg, sender);
56
+ if (msg.cmd === 'consoleStart') return await handleConsoleStart(msg, sender);
57
+ if (msg.cmd === 'consoleList') return await handleConsoleList(msg, sender);
58
+ if (msg.cmd === 'consoleClear') return await handleConsoleClear(msg, sender);
59
+ if (msg.cmd === 'consoleStop') return await handleConsoleStop(msg, sender);
60
+ if (msg.cmd === 'debugClearAll') return await handleDebugClearAll();
31
61
  if (msg.cmd === 'tabs') {
32
62
  try {
33
63
  if (msg.method === 'switch') {
34
64
  const tab = await chrome.tabs.update(msg.tabId, { active: true });
35
- await chrome.windows.update(tab.windowId, { focused: true });
65
+ // 默认只切换 Chrome 内部 active tab,不抢占系统前台窗口。
66
+ if (msg.allowFocus === true && tab.windowId) await chrome.windows.update(tab.windowId, { focused: true });
36
67
  return { ok: true };
37
68
  } else {
38
69
  const tabs = (await chrome.tabs.query({})).filter(t => isScriptable(t.url));
@@ -84,7 +115,10 @@ function handleStatus() {
84
115
  wsConnected: !!ws && ws.readyState === WebSocket.OPEN,
85
116
  wsUrl: getWsUrl(),
86
117
  wsPort,
87
- lastCommandAt
118
+ lastCommandAt,
119
+ browserId,
120
+ profileId,
121
+ profileLabel
88
122
  }
89
123
  };
90
124
  }
@@ -128,18 +162,385 @@ async function handleCookies(msg, sender) {
128
162
  }
129
163
  }
130
164
 
165
+
166
+ const debugSessions = new Map();
167
+
168
+ function resolveTabId(msg, sender) {
169
+ const tabId = Number(msg.tabId || sender.tab?.id);
170
+ if (!Number.isInteger(tabId) || tabId <= 0) throw new Error('no tabId');
171
+ return tabId;
172
+ }
173
+
174
+ function getDebugSession(tabId) {
175
+ let session = debugSessions.get(tabId);
176
+ if (!session) {
177
+ session = {
178
+ tabId,
179
+ attached: false,
180
+ network: false,
181
+ console: false,
182
+ requests: new Map(),
183
+ requestOrder: [],
184
+ logs: []
185
+ };
186
+ debugSessions.set(tabId, session);
187
+ }
188
+ return session;
189
+ }
190
+
191
+ async function ensureDebugAttached(session) {
192
+ if (session.attached) return;
193
+ await chrome.debugger.attach({ tabId: session.tabId }, '1.3');
194
+ session.attached = true;
195
+ }
196
+
197
+ async function detachDebugIfIdle(session) {
198
+ if (!session.attached || session.network || session.console) return;
199
+ try { await chrome.debugger.detach({ tabId: session.tabId }); } catch (_) {}
200
+ session.attached = false;
201
+ }
202
+
203
+ async function handleNetworkStart(msg, sender) {
204
+ try {
205
+ const tabId = resolveTabId(msg, sender);
206
+ const session = getDebugSession(tabId);
207
+ await ensureDebugAttached(session);
208
+ await chrome.debugger.sendCommand({ tabId }, 'Network.enable', {});
209
+ session.network = true;
210
+ return { ok: true, status: 'started', tabId, count: session.requestOrder.length };
211
+ } catch (e) {
212
+ return { ok: false, error: e.message };
213
+ }
214
+ }
215
+
216
+ async function handleNetworkList(msg, sender) {
217
+ try {
218
+ const tabId = resolveTabId(msg, sender);
219
+ const session = getDebugSession(tabId);
220
+ const filter = String(msg.filter || '').toLowerCase();
221
+ const limit = Math.max(1, Math.min(Number(msg.limit || 100), 1000));
222
+ let items = session.requestOrder.map(id => session.requests.get(id)).filter(Boolean);
223
+ if (filter) {
224
+ items = items.filter(item => [item.url, item.method, item.status, item.mimeType, item.resourceType].some(v => String(v || '').toLowerCase().includes(filter)));
225
+ }
226
+ items = items.slice(-limit).map(summarizeRequest);
227
+ return { ok: true, status: session.network ? 'started' : 'stopped', tabId, count: items.length, requests: items };
228
+ } catch (e) {
229
+ return { ok: false, error: e.message };
230
+ }
231
+ }
232
+
233
+ async function handleNetworkDetail(msg, sender) {
234
+ try {
235
+ const tabId = resolveTabId(msg, sender);
236
+ const requestId = String(msg.requestId || '');
237
+ const session = getDebugSession(tabId);
238
+ const item = session.requests.get(requestId);
239
+ if (!item) return { ok: false, error: 'unknown requestId: ' + requestId };
240
+ const detail = Object.assign({}, item);
241
+ if (item.completed && !item.failed && session.attached) {
242
+ try {
243
+ const body = await chrome.debugger.sendCommand({ tabId }, 'Network.getResponseBody', { requestId });
244
+ detail.body = truncateText(body.body || '', 20000);
245
+ detail.base64Encoded = !!body.base64Encoded;
246
+ detail.bodyTruncated = String(body.body || '').length > 20000;
247
+ } catch (e) {
248
+ detail.bodyError = e.message;
249
+ }
250
+ }
251
+ return { ok: true, tabId, request: detail };
252
+ } catch (e) {
253
+ return { ok: false, error: e.message };
254
+ }
255
+ }
256
+
257
+ async function handleNetworkClear(msg, sender) {
258
+ try {
259
+ const tabId = resolveTabId(msg, sender);
260
+ const session = getDebugSession(tabId);
261
+ session.requests.clear();
262
+ session.requestOrder = [];
263
+ return { ok: true, status: 'cleared', tabId };
264
+ } catch (e) {
265
+ return { ok: false, error: e.message };
266
+ }
267
+ }
268
+
269
+ async function handleNetworkStop(msg, sender) {
270
+ try {
271
+ const tabId = resolveTabId(msg, sender);
272
+ const session = getDebugSession(tabId);
273
+ if (session.attached) {
274
+ try { await chrome.debugger.sendCommand({ tabId }, 'Network.disable', {}); } catch (_) {}
275
+ }
276
+ session.network = false;
277
+ session.requests.clear();
278
+ session.requestOrder = [];
279
+ await detachDebugIfIdle(session);
280
+ return { ok: true, status: 'stopped', cleared: true, tabId };
281
+ } catch (e) {
282
+ return { ok: false, error: e.message };
283
+ }
284
+ }
285
+
286
+ async function handleConsoleStart(msg, sender) {
287
+ try {
288
+ const tabId = resolveTabId(msg, sender);
289
+ const session = getDebugSession(tabId);
290
+ await ensureDebugAttached(session);
291
+ await chrome.debugger.sendCommand({ tabId }, 'Runtime.enable', {});
292
+ await chrome.debugger.sendCommand({ tabId }, 'Log.enable', {}).catch(() => null);
293
+ session.console = true;
294
+ return { ok: true, status: 'started', tabId, count: session.logs.length };
295
+ } catch (e) {
296
+ return { ok: false, error: e.message };
297
+ }
298
+ }
299
+
300
+ async function handleConsoleList(msg, sender) {
301
+ try {
302
+ const tabId = resolveTabId(msg, sender);
303
+ const session = getDebugSession(tabId);
304
+ const level = String(msg.level || '').toLowerCase();
305
+ const limit = Math.max(1, Math.min(Number(msg.limit || 100), 1000));
306
+ let logs = session.logs;
307
+ if (level) logs = logs.filter(item => String(item.level || '').toLowerCase() === level);
308
+ return { ok: true, status: session.console ? 'started' : 'stopped', tabId, count: logs.length, logs: logs.slice(-limit) };
309
+ } catch (e) {
310
+ return { ok: false, error: e.message };
311
+ }
312
+ }
313
+
314
+ async function handleConsoleClear(msg, sender) {
315
+ try {
316
+ const tabId = resolveTabId(msg, sender);
317
+ const session = getDebugSession(tabId);
318
+ session.logs = [];
319
+ return { ok: true, status: 'cleared', tabId };
320
+ } catch (e) {
321
+ return { ok: false, error: e.message };
322
+ }
323
+ }
324
+
325
+ async function handleConsoleStop(msg, sender) {
326
+ try {
327
+ const tabId = resolveTabId(msg, sender);
328
+ const session = getDebugSession(tabId);
329
+ if (session.attached) {
330
+ try { await chrome.debugger.sendCommand({ tabId }, 'Runtime.disable', {}); } catch (_) {}
331
+ try { await chrome.debugger.sendCommand({ tabId }, 'Log.disable', {}); } catch (_) {}
332
+ }
333
+ session.console = false;
334
+ session.logs = [];
335
+ await detachDebugIfIdle(session);
336
+ return { ok: true, status: 'stopped', cleared: true, tabId };
337
+ } catch (e) {
338
+ return { ok: false, error: e.message };
339
+ }
340
+ }
341
+
342
+ function summarizeRequest(item) {
343
+ return {
344
+ requestId: item.requestId,
345
+ url: item.url,
346
+ method: item.method,
347
+ status: item.status,
348
+ mimeType: item.mimeType,
349
+ resourceType: item.resourceType,
350
+ completed: !!item.completed,
351
+ failed: !!item.failed,
352
+ errorText: item.errorText,
353
+ timestamp: item.timestamp
354
+ };
355
+ }
356
+
357
+ function rememberRequest(session, requestId) {
358
+ if (!session.requests.has(requestId)) session.requestOrder.push(requestId);
359
+ while (session.requestOrder.length > 1000) {
360
+ const old = session.requestOrder.shift();
361
+ session.requests.delete(old);
362
+ }
363
+ let item = session.requests.get(requestId);
364
+ if (!item) {
365
+ item = { requestId };
366
+ session.requests.set(requestId, item);
367
+ }
368
+ return item;
369
+ }
370
+
371
+ function pushLog(session, item) {
372
+ session.logs.push(item);
373
+ if (session.logs.length > 1000) session.logs.splice(0, session.logs.length - 1000);
374
+ }
375
+
376
+ function remoteObjectText(arg) {
377
+ if (!arg) return '';
378
+ if ('value' in arg) {
379
+ if (typeof arg.value === 'string') return truncateText(arg.value, 2000);
380
+ try { return truncateText(JSON.stringify(arg.value), 2000); } catch (_) { return String(arg.value); }
381
+ }
382
+ return truncateText(arg.description || arg.type || '', 2000);
383
+ }
384
+
385
+ function truncateText(text, max) {
386
+ const value = String(text || '');
387
+ return value.length > max ? value.slice(0, max) : value;
388
+ }
389
+
390
+ function onDebuggerEvent(source, method, params) {
391
+ const tabId = source.tabId;
392
+ if (!tabId) return;
393
+ const session = debugSessions.get(tabId);
394
+ if (!session) return;
395
+ if (method === 'Network.requestWillBeSent') {
396
+ const item = rememberRequest(session, params.requestId);
397
+ item.url = params.request?.url || item.url;
398
+ item.method = params.request?.method || item.method;
399
+ item.resourceType = params.type || item.resourceType;
400
+ item.timestamp = params.wallTime || params.timestamp || item.timestamp;
401
+ item.requestHeaders = params.request?.headers;
402
+ } else if (method === 'Network.responseReceived') {
403
+ const item = rememberRequest(session, params.requestId);
404
+ item.status = params.response?.status;
405
+ item.statusText = params.response?.statusText;
406
+ item.mimeType = params.response?.mimeType;
407
+ item.responseHeaders = params.response?.headers;
408
+ item.url = params.response?.url || item.url;
409
+ item.resourceType = params.type || item.resourceType;
410
+ } else if (method === 'Network.loadingFinished') {
411
+ const item = rememberRequest(session, params.requestId);
412
+ item.completed = true;
413
+ item.encodedDataLength = params.encodedDataLength;
414
+ } else if (method === 'Network.loadingFailed') {
415
+ const item = rememberRequest(session, params.requestId);
416
+ item.completed = true;
417
+ item.failed = true;
418
+ item.errorText = params.errorText;
419
+ } else if (method === 'Runtime.consoleAPICalled') {
420
+ pushLog(session, {
421
+ level: params.type || 'log',
422
+ text: (params.args || []).map(remoteObjectText).join(' '),
423
+ timestamp: params.timestamp || Date.now(),
424
+ url: params.stackTrace?.callFrames?.[0]?.url || '',
425
+ line: params.stackTrace?.callFrames?.[0]?.lineNumber,
426
+ column: params.stackTrace?.callFrames?.[0]?.columnNumber
427
+ });
428
+ } else if (method === 'Runtime.exceptionThrown') {
429
+ pushLog(session, {
430
+ level: 'error',
431
+ text: params.exceptionDetails?.text || params.exceptionDetails?.exception?.description || 'exception thrown',
432
+ timestamp: params.timestamp || Date.now(),
433
+ url: params.exceptionDetails?.url || '',
434
+ line: params.exceptionDetails?.lineNumber,
435
+ column: params.exceptionDetails?.columnNumber
436
+ });
437
+ } else if (method === 'Log.entryAdded') {
438
+ const e = params.entry || {};
439
+ pushLog(session, {
440
+ level: e.level || 'log',
441
+ text: e.text || '',
442
+ timestamp: e.timestamp || Date.now(),
443
+ url: e.url || '',
444
+ line: e.lineNumber,
445
+ column: undefined
446
+ });
447
+ }
448
+ }
449
+
450
+ function onDebuggerDetach(source) {
451
+ if (!source.tabId) return;
452
+ const session = debugSessions.get(source.tabId);
453
+ if (session) {
454
+ session.attached = false;
455
+ session.network = false;
456
+ session.console = false;
457
+ }
458
+ }
459
+
460
+ chrome.debugger.onEvent.addListener(onDebuggerEvent);
461
+ chrome.debugger.onDetach.addListener(onDebuggerDetach);
462
+
463
+
464
+
465
+ async function handleCloseTab(msg, sender) {
466
+ try {
467
+ const tabId = Number(msg.tabId || sender.tab?.id);
468
+ if (!Number.isInteger(tabId) || tabId <= 0) throw new Error('tabId is required');
469
+ const session = debugSessions.get(tabId);
470
+ if (session?.attached) {
471
+ try { await chrome.debugger.detach({ tabId }); } catch (_) {}
472
+ }
473
+ debugSessions.delete(tabId);
474
+ await chrome.tabs.remove(tabId);
475
+ return { ok: true, data: { status: 'success', tabId } };
476
+ } catch (e) {
477
+ return { ok: false, error: e.message };
478
+ }
479
+ }
480
+
481
+ async function handleDebugClearAll() {
482
+ const tabIds = [...debugSessions.keys()];
483
+ for (const tabId of tabIds) {
484
+ const session = debugSessions.get(tabId);
485
+ if (!session) continue;
486
+ session.requests.clear();
487
+ session.requestOrder = [];
488
+ session.logs = [];
489
+ session.network = false;
490
+ session.console = false;
491
+ if (session.attached) {
492
+ try { await chrome.debugger.detach({ tabId }); } catch (_) {}
493
+ session.attached = false;
494
+ }
495
+ }
496
+ debugSessions.clear();
497
+ return { ok: true, status: 'cleared', tabs: tabIds.length };
498
+ }
499
+
131
500
  async function handleOpenTab(msg) {
132
501
  try {
133
502
  const url = normalizeOpenUrl(msg.url);
134
503
  const active = msg.active !== false;
504
+ if (msg.window === true) {
505
+ // window 模式默认不聚焦,避免新窗口打断用户当前工作区。
506
+ const win = await chrome.windows.create({ url, focused: msg.allowFocus === true });
507
+ const tab = Array.isArray(win.tabs) && win.tabs.length ? win.tabs[0] : null;
508
+ const group = tab?.id ? await groupTabIfRequested(tab.id, msg.groupTitle) : { ok: false, skipped: true, reason: 'window created without tab info' };
509
+ return { ok: true, data: { id: tab?.id, url: tab?.url || url, title: tab?.title || '', active: !!tab?.active, windowId: win.id, window: true, group } };
510
+ }
135
511
  const tab = await chrome.tabs.create({ url, active });
136
- if (active && tab.windowId) await chrome.windows.update(tab.windowId, { focused: true });
137
- return { ok: true, data: { id: tab.id, url: tab.url || url, title: tab.title || '', active: tab.active, windowId: tab.windowId } };
512
+ const group = await groupTabIfRequested(tab.id, msg.groupTitle);
513
+ // 默认创建/激活标签页但不聚焦浏览器窗口,避免打断当前工作区。
514
+ if (active && msg.allowFocus === true && tab.windowId) await chrome.windows.update(tab.windowId, { focused: true });
515
+ return { ok: true, data: { id: tab.id, url: tab.url || url, title: tab.title || '', active: tab.active, windowId: tab.windowId, window: false, group } };
138
516
  } catch (e) {
139
517
  return { ok: false, error: e.message };
140
518
  }
141
519
  }
142
520
 
521
+ async function groupTabIfRequested(tabId, title) {
522
+ const cleanTitle = String(title || '').trim();
523
+ if (!cleanTitle) return null;
524
+ if (!chrome.tabs?.group || !chrome.tabGroups?.update) {
525
+ return { ok: false, skipped: true, reason: 'tabGroups API unavailable' };
526
+ }
527
+ try {
528
+ const existing = await findTabGroupByTitle(cleanTitle);
529
+ const groupId = await chrome.tabs.group(existing ? { tabIds: tabId, groupId: existing.id } : { tabIds: tabId });
530
+ await chrome.tabGroups.update(groupId, { title: cleanTitle });
531
+ return { ok: true, id: groupId, title: cleanTitle };
532
+ } catch (e) {
533
+ // 分组只是整理标签,不影响打开页面的主流程。
534
+ return { ok: false, skipped: true, reason: e.message };
535
+ }
536
+ }
537
+
538
+ async function findTabGroupByTitle(title) {
539
+ if (!chrome.tabGroups?.query) return null;
540
+ const groups = await chrome.tabGroups.query({});
541
+ return groups.find(group => group.title === title) || null;
542
+ }
543
+
143
544
  function normalizeOpenUrl(url) {
144
545
  const raw = String(url || '').trim();
145
546
  if (!raw) throw new Error('url is required');
@@ -162,6 +563,10 @@ async function handleBatch(msg, sender) {
162
563
  R.push({ ok: true, data: tabs.map(t => ({ id: t.id, url: t.url, title: t.title, active: t.active, windowId: t.windowId })) });
163
564
  } else if (c.cmd === 'cdp') {
164
565
  const tabId = c.tabId || msg.tabId || sender.tab?.id;
566
+ if (c.method === 'Page.bringToFront' && c.allowFocus !== true && msg.allowFocus !== true) {
567
+ R.push({ skipped: true, reason: 'Page.bringToFront requires allowFocus=true' });
568
+ continue;
569
+ }
165
570
  if (attached !== tabId) {
166
571
  if (attached) { await chrome.debugger.detach({ tabId: attached }); attached = null; }
167
572
  await chrome.debugger.attach({ tabId }, '1.3');
@@ -183,6 +588,9 @@ async function handleBatch(msg, sender) {
183
588
  async function handleCDP(msg, sender) {
184
589
  const tabId = msg.tabId || sender.tab?.id;
185
590
  if (!tabId) return { ok: false, error: 'no tabId' };
591
+ if (msg.method === 'Page.bringToFront' && msg.allowFocus !== true) {
592
+ return { ok: true, data: { skipped: true, reason: 'Page.bringToFront requires allowFocus=true' } };
593
+ }
186
594
  try {
187
595
  await chrome.debugger.attach({ tabId }, '1.3');
188
596
  const result = await chrome.debugger.sendCommand({ tabId }, msg.method, msg.params || {});
@@ -439,11 +847,12 @@ async function connectWS() {
439
847
  ws.onopen = async () => {
440
848
  console.log('[TMWD-WS] Connected!');
441
849
  scheduleKeepalive(); // Keep SW alive while connected
850
+ await loadClientIdentity();
442
851
  const tabs = (await chrome.tabs.query({})).filter(t => isScriptable(t.url));
443
- ws.send(JSON.stringify({
852
+ ws.send(JSON.stringify(withClientIdentity({
444
853
  type: 'ext_ready',
445
854
  tabs: tabs.map(t => ({ id: t.id, url: t.url, title: t.title }))
446
- }));
855
+ })));
447
856
  console.log('[TMWD-WS] Sent ext_ready with', tabs.length, 'tabs');
448
857
  };
449
858
  ws.onmessage = async (event) => {
@@ -512,10 +921,11 @@ chrome.runtime.onInstalled.addListener(() => {
512
921
  async function sendTabsUpdate() {
513
922
  if (!ws || ws.readyState !== WebSocket.OPEN) return;
514
923
  const tabs = (await chrome.tabs.query({})).filter(t => isScriptable(t.url) && !/streamlit/i.test(t.title));
515
- ws.send(JSON.stringify({
924
+ await loadClientIdentity();
925
+ ws.send(JSON.stringify(withClientIdentity({
516
926
  type: 'tabs_update',
517
927
  tabs: tabs.map(t => ({ id: t.id, url: t.url, title: t.title }))
518
- }));
928
+ })));
519
929
  }
520
930
  chrome.tabs.onUpdated.addListener((_, changeInfo) => {
521
931
  if (changeInfo.status === 'complete') sendTabsUpdate();
@@ -142,13 +142,17 @@ async function handle(el) {
142
142
  if (cmd === 'cookies') {
143
143
  resp = await chrome.runtime.sendMessage({ cmd: 'cookies', url: req.url || location.href });
144
144
  } else if (cmd === 'cdp') {
145
- resp = await chrome.runtime.sendMessage({ cmd: 'cdp', method: req.method, params: req.params || {}, tabId: req.tabId });
145
+ resp = await chrome.runtime.sendMessage({ cmd: 'cdp', method: req.method, params: req.params || {}, tabId: req.tabId, allowFocus: req.allowFocus });
146
146
  } else if (cmd === 'batch') {
147
147
  resp = await chrome.runtime.sendMessage({ cmd: 'batch', commands: req.commands, tabId: req.tabId });
148
148
  } else if (cmd === 'tabs') {
149
- resp = await chrome.runtime.sendMessage({ cmd: 'tabs', method: req.method, tabId: req.tabId });
149
+ resp = await chrome.runtime.sendMessage({ cmd: 'tabs', method: req.method, tabId: req.tabId, allowFocus: req.allowFocus });
150
150
  } else if (cmd === 'openTab') {
151
- resp = await chrome.runtime.sendMessage({ cmd: 'openTab', url: req.url, active: req.active });
151
+ resp = await chrome.runtime.sendMessage({ cmd: 'openTab', url: req.url, active: req.active, allowFocus: req.allowFocus, groupTitle: req.groupTitle });
152
+ } else if (cmd === 'closeTab') {
153
+ resp = await chrome.runtime.sendMessage({ cmd: 'closeTab', tabId: req.tabId });
154
+ } else if (cmd === 'networkStart' || cmd === 'networkList' || cmd === 'networkDetail' || cmd === 'networkClear' || cmd === 'networkStop' || cmd === 'consoleStart' || cmd === 'consoleList' || cmd === 'consoleClear' || cmd === 'consoleStop' || cmd === 'debugClearAll') {
155
+ resp = await chrome.runtime.sendMessage(Object.assign({}, req, { cmd }));
152
156
  } else {
153
157
  resp = { ok: false, error: 'unknown cmd: ' + cmd };
154
158
  }
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "manifest_version": 3,
3
- "name": "TMWD CDP Bridge",
3
+ "name": "Agent Browser CLI Bridge",
4
4
  "version": "2.0",
5
- "description": "Cookie viewer + CDP bridge",
5
+ "description": "Browser control bridge for agent-browser-cli",
6
6
  "permissions": [
7
7
  "cookies",
8
8
  "tabs",
9
+ "tabGroups",
9
10
  "activeTab",
10
11
  "debugger",
11
12
  "scripting",
@@ -15,27 +16,50 @@
15
16
  "management",
16
17
  "contentSettings"
17
18
  ],
18
- "host_permissions": ["<all_urls>"],
19
+ "host_permissions": [
20
+ "<all_urls>"
21
+ ],
19
22
  "background": {
20
23
  "service_worker": "background.js"
21
24
  },
22
25
  "content_scripts": [
23
26
  {
24
- "matches": ["<all_urls>"],
25
- "js": ["disable_dialogs.js"],
27
+ "matches": [
28
+ "<all_urls>"
29
+ ],
30
+ "js": [
31
+ "disable_dialogs.js"
32
+ ],
26
33
  "run_at": "document_start",
27
34
  "all_frames": true,
28
35
  "world": "MAIN"
29
36
  },
30
37
  {
31
- "matches": ["<all_urls>"],
32
- "js": ["config.js", "content.js"],
38
+ "matches": [
39
+ "<all_urls>"
40
+ ],
41
+ "js": [
42
+ "config.js",
43
+ "content.js"
44
+ ],
33
45
  "run_at": "document_idle",
34
46
  "all_frames": true
35
47
  }
36
48
  ],
37
49
  "action": {
38
50
  "default_popup": "popup.html",
39
- "default_title": "TMWD CDP Bridge"
51
+ "default_title": "Agent Browser CLI Bridge",
52
+ "default_icon": {
53
+ "16": "icons/bot-16.png",
54
+ "32": "icons/bot-32.png",
55
+ "48": "icons/bot-48.png",
56
+ "128": "icons/bot-128.png"
57
+ }
58
+ },
59
+ "icons": {
60
+ "16": "icons/bot-16.png",
61
+ "32": "icons/bot-32.png",
62
+ "48": "icons/bot-48.png",
63
+ "128": "icons/bot-128.png"
40
64
  }
41
65
  }
@@ -29,7 +29,8 @@ function resolveBinary() {
29
29
  }
30
30
 
31
31
  const bin = resolveBinary();
32
- const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
32
+ const env = { ...process.env, AGENT_BROWSER_CLI_PACKAGE_DIR: path.resolve(__dirname, "..") };
33
+ const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit", env });
33
34
  if (result.error) {
34
35
  console.error(result.error.message);
35
36
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleepinsummer/agent-browser-cli",
3
- "version": "0.2.9",
3
+ "version": "0.3.1-beta.2",
4
4
  "description": "Agent-oriented browser sensing and control CLI backed by a native Rust daemon.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "README.md",
15
15
  "README_EN.md",
16
16
  "AI_INSTALL.md",
17
+ "CHANGELOG.md",
17
18
  "LICENSE"
18
19
  ],
19
20
  "scripts": {
@@ -23,11 +24,11 @@
23
24
  "postinstall": "node npm/postinstall.js"
24
25
  },
25
26
  "optionalDependencies": {
26
- "@sleepinsummer/agent-browser-cli-darwin-arm64": "0.2.9",
27
- "@sleepinsummer/agent-browser-cli-darwin-x64": "0.2.9",
28
- "@sleepinsummer/agent-browser-cli-linux-x64": "0.2.9",
29
- "@sleepinsummer/agent-browser-cli-linux-arm64": "0.2.9",
30
- "@sleepinsummer/agent-browser-cli-win32-x64": "0.2.9"
27
+ "@sleepinsummer/agent-browser-cli-darwin-arm64": "0.3.1-beta.2",
28
+ "@sleepinsummer/agent-browser-cli-darwin-x64": "0.3.1-beta.2",
29
+ "@sleepinsummer/agent-browser-cli-linux-x64": "0.3.1-beta.2",
30
+ "@sleepinsummer/agent-browser-cli-linux-arm64": "0.3.1-beta.2",
31
+ "@sleepinsummer/agent-browser-cli-win32-x64": "0.3.1-beta.2"
31
32
  },
32
33
  "engines": {
33
34
  "node": ">=18"