dsh-site-bridge 0.7.2 → 0.7.5

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.
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "default_locale": "en",
4
4
  "name": "__MSG_appName__",
5
- "version": "0.7.2",
5
+ "version": "0.7.5",
6
6
  "description": "__MSG_appDesc__",
7
7
  "minimum_chrome_version": "116",
8
8
  "permissions": [
@@ -206,12 +206,23 @@ async function currentBrowserTab() {
206
206
  { active: true, currentWindow: true }
207
207
  ]
208
208
  for (const scope of scopes) {
209
+ let tabs = []
209
210
  try {
210
- const tabs = await chrome.tabs.query(scope)
211
- if (!Array.isArray(tabs) || tabs.length === 0) continue
212
- return tabs.find((tab) => scheme(tab) === 'web') ?? tabs[0]
211
+ tabs = await chrome.tabs.query(scope)
213
212
  } catch {
214
- // try the next scope
213
+ continue
214
+ }
215
+ if (!Array.isArray(tabs) || tabs.length === 0) continue
216
+ const ordered = [...tabs.filter((tab) => scheme(tab) === 'web'), ...tabs.filter((tab) => scheme(tab) !== 'web')]
217
+ for (const tab of ordered) {
218
+ // Ask Chrome whether this tab is readable at all: tabs in app windows of
219
+ // other extensions are listed but cannot be touched.
220
+ try {
221
+ await chrome.tabs.get(tab.id)
222
+ return tab
223
+ } catch {
224
+ // not ours to read — try the next candidate
225
+ }
215
226
  }
216
227
  }
217
228
  return null
package/extension/sw.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * host, which redacts and never writes it to disk.
16
16
  */
17
17
 
18
- const EXT_VERSION = '0.1.0'
18
+ const EXT_VERSION = chrome.runtime.getManifest().version
19
19
  const NET_CAP = 600
20
20
  // Bodies are kept up to this size in the worker, then marked as truncated.
21
21
  // Raise it per machine with chrome.storage.local.set({ maxBodyChars }): the
@@ -254,7 +254,11 @@ async function attach(tabId, attachedBy = 'agent') {
254
254
  await evt('active', { tabId })
255
255
  return existing.target
256
256
  }
257
- await chrome.debugger.attach({ tabId }, '1.3')
257
+ try {
258
+ await chrome.debugger.attach({ tabId }, '1.3')
259
+ } catch (error) {
260
+ throw new Error(`chrome.debugger.attach отказал: ${String(error?.message ?? error)}`)
261
+ }
258
262
  await chrome.debugger.sendCommand({ tabId }, 'Network.enable', {
259
263
  maxTotalBufferSize: 64_000_000,
260
264
  maxResourceBufferSize: 16_000_000,
@@ -297,7 +301,11 @@ async function claimTab(tabId, attachedBy = 'agent') {
297
301
  } catch (error) {
298
302
  // Chrome refuses to read pages of other extensions and its own service
299
303
  // pages; say that in words a person can act on.
300
- throw new Error(`эту вкладку нельзя подключить: ${String(error?.message ?? error)}`)
304
+ const detail = String(error?.message ?? error)
305
+ const hint = /chrome-extension:\/\//.test(detail)
306
+ ? ' Похоже, вкладка открыта в окне-приложении другого расширения — откройте её как обычную вкладку.'
307
+ : ''
308
+ throw new Error(`эту вкладку нельзя подключить: ${detail}${hint}`)
301
309
  }
302
310
  if (!/^https?:|^file:/.test(tab.url ?? '')) {
303
311
  const scheme = String(tab.url ?? '').split(':')[0] || 'неизвестная схема'
@@ -1502,17 +1510,26 @@ async function dispatch(op, args) {
1502
1510
  return { ok: true, version: EXT_VERSION }
1503
1511
  case 'tabs.list': {
1504
1512
  const tabs = await chrome.tabs.query({})
1513
+ // Window type explains why a tab can be listed but not read: app windows
1514
+ // belong to another extension, and Chrome refuses access to them.
1515
+ const windows = await chrome.windows.getAll({}).catch(() => [])
1516
+ const windowType = new Map(windows.map((window) => [window.id, window.type ?? 'normal']))
1505
1517
  const list = tabs
1506
1518
  .filter((tab) => /^https?:|^file:/.test(tab.url ?? ''))
1507
- .map((tab) => ({
1508
- id: tab.id,
1509
- title: tab.title,
1510
- url: tab.url,
1511
- active: tab.active,
1512
- windowId: tab.windowId,
1513
- attached: state.sessions.has(tab.id),
1514
- target: tab.id === state.activeTabId
1515
- }))
1519
+ .map((tab) => {
1520
+ const type = windowType.get(tab.windowId) ?? 'unknown'
1521
+ return {
1522
+ id: tab.id,
1523
+ title: tab.title,
1524
+ url: tab.url,
1525
+ active: tab.active,
1526
+ windowId: tab.windowId,
1527
+ windowType: type,
1528
+ readable: type === 'normal',
1529
+ attached: state.sessions.has(tab.id),
1530
+ target: tab.id === state.activeTabId
1531
+ }
1532
+ })
1516
1533
  await evt('tabs', { tabs: list })
1517
1534
  return { tabs: list }
1518
1535
  }
package/lib/index.js CHANGED
@@ -332,10 +332,10 @@ export function apply(ctx, config) {
332
332
  }
333
333
  const result = await instance.enqueue('tabs.list', {}, { timeout: 20000 })
334
334
  const tabs = Array.isArray(result?.tabs) ? result.tabs : []
335
- const lines = tabs.map(
336
- (tab) =>
337
- `${tab.target ? '*' : tab.attached ? '+' : ' '} [${tab.id}] ${tab.title || '(без названия)'} — ${tab.url}`
338
- )
335
+ const lines = tabs.map((tab) => {
336
+ const window = tab.windowType && tab.windowType !== 'normal' ? ` [окно: ${tab.windowType}, недоступно]` : ''
337
+ return `${tab.target ? '*' : tab.attached ? '+' : ' '} [${tab.id}] ${tab.title || '(без названия)'} — ${tab.url}${window}`
338
+ })
339
339
  return ok(
340
340
  tabs.length === 0
341
341
  ? 'Нет доступных вкладок (нужны http(s)/file://).'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-site-bridge",
3
- "version": "0.7.2",
3
+ "version": "0.7.5",
4
4
  "description": "Chrome/Edge MV3 bridge for DeepSeek Harness: capture page markup (DOM, styles, selectors) and BFF traffic (xhr/fetch with headers and bodies) into a workspace snapshot bundle, drive the page with trusted CDP input, and verify injected scripts. Authorization never leaves the browser and is never written to disk.",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",