dsh-site-bridge 0.5.1 → 0.5.3

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.5.1",
5
+ "version": "0.5.3",
6
6
  "description": "__MSG_appDesc__",
7
7
  "minimum_chrome_version": "116",
8
8
  "permissions": [
@@ -101,7 +101,8 @@ function render(status) {
101
101
  const targets = Array.isArray(status.targets) ? status.targets : []
102
102
  const tabsRow = $('tabs-row')
103
103
  const tabsSelect = $('tabs-select')
104
- $('claim-more').hidden = !hasTarget
104
+ const selfAttached = selfTabId != null && targets.some((item) => item.id === selfTabId)
105
+ $('claim-more').hidden = !hasTarget || selfAttached
105
106
  if (targets.length > 1) {
106
107
  tabsRow.hidden = false
107
108
  tabsSelect.textContent = ''
@@ -146,8 +147,16 @@ function render(status) {
146
147
  }
147
148
  }
148
149
 
150
+ // Which tab this popup is open on: attaching that tab again is a no-op, so the
151
+ // attach button is only offered when the current tab is not attached yet.
152
+ let selfTabId = null
153
+
149
154
  async function refresh() {
150
155
  try {
156
+ if (chrome.tabs?.query) {
157
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
158
+ selfTabId = tab?.id ?? null
159
+ }
151
160
  render(await send({ type: 'status' }))
152
161
  } catch {
153
162
  render(null)
@@ -230,16 +239,33 @@ $('import-file').addEventListener('change', async (event) => {
230
239
  }
231
240
  })
232
241
 
233
- $('claim').addEventListener('click', async () => {
234
- const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
235
- if (!tab?.id) return
236
- const result = await send({ type: 'claim', tabId: tab.id })
237
- if (!result?.ok) {
238
- setNote(t('claimFailed', [String(result?.error ?? t('claimFailedUnknown'))]), true)
242
+ async function attachCurrentTab() {
243
+ let tabId = null
244
+ try {
245
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
246
+ tabId = tab?.id ?? null
247
+ } catch {
248
+ tabId = null
249
+ }
250
+ if (tabId == null) {
251
+ setNote(t('claimFailed', [t('claimFailedUnknown')]), true)
252
+ return
253
+ }
254
+ try {
255
+ const result = await send({ type: 'claim', tabId })
256
+ if (!result?.ok) {
257
+ setNote(t('claimFailed', [String(result?.error ?? t('claimFailedUnknown'))]), true)
258
+ return
259
+ }
260
+ setNote('')
261
+ } catch (error) {
262
+ setNote(t('claimFailed', [String(error?.message ?? error)]), true)
239
263
  return
240
264
  }
241
265
  await refresh()
242
- })
266
+ }
267
+
268
+ $('claim').addEventListener('click', attachCurrentTab)
243
269
 
244
270
  $('capture').addEventListener('click', async () => {
245
271
  const status = await send({ type: 'status' })
@@ -268,11 +294,7 @@ $('pick').addEventListener('click', async () => {
268
294
  await refresh()
269
295
  })
270
296
 
271
- $('claim-more').addEventListener('click', async () => {
272
- const result = await send({ type: 'claim' })
273
- if (!result?.ok && result?.error) setNote(String(result.error), true)
274
- await refresh()
275
- })
297
+ $('claim-more').addEventListener('click', attachCurrentTab)
276
298
 
277
299
  $('tabs-select').addEventListener('change', async (event) => {
278
300
  const tabId = Number(event.target.value)
package/extension/sw.js CHANGED
@@ -272,11 +272,19 @@ async function attach(tabId) {
272
272
  }
273
273
 
274
274
  async function claimTab(tabId) {
275
- const tab = await chrome.tabs.get(tabId)
275
+ // Without an explicit id, claim whatever tab the user is looking at, so a
276
+ // caller that only knows "this tab" cannot silently pass NaN.
277
+ let id = Number(tabId)
278
+ if (!Number.isFinite(id)) {
279
+ const [active] = await chrome.tabs.query({ active: true, lastFocusedWindow: true })
280
+ id = active?.id
281
+ }
282
+ if (!Number.isFinite(id)) throw new Error('no tab to claim: pass tabId or open a page first')
283
+ const tab = await chrome.tabs.get(id)
276
284
  if (!/^https?:|^file:/.test(tab.url ?? '')) {
277
285
  throw new Error(`cannot drive ${tab.url || 'this tab'}: only http(s) and file:// pages are supported`)
278
286
  }
279
- return attach(tabId)
287
+ return attach(id)
280
288
  }
281
289
 
282
290
  chrome.debugger.onDetach.addListener((source, reason) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-site-bridge",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
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",
@@ -22,7 +22,7 @@ const sleep = (ms) => new Promise((done) => setTimeout(done, ms))
22
22
 
23
23
  const statuses = {
24
24
  'connected-one': {
25
- ok: true, configured: true, connected: true, port: 47321, recording: false, captured: 0,
25
+ ok: true, configured: true, connected: true, port: 47321, recording: false, captured: 0, selfTabId: 1,
26
26
  activeTabId: 1,
27
27
  target: { id: 1, title: 'Example Store — Products', url: 'https://shop.example/products' },
28
28
  targets: [
@@ -30,7 +30,7 @@ const statuses = {
30
30
  ]
31
31
  },
32
32
  connected: {
33
- ok: true, configured: true, connected: true, port: 47321, recording: true, captured: 12,
33
+ ok: true, configured: true, connected: true, port: 47321, recording: true, captured: 12, selfTabId: 3,
34
34
  activeTabId: 1,
35
35
  target: { id: 1, title: 'Ozon: Торговая площадка', url: 'https://seller.ozon.ru/app/products' },
36
36
  targets: [
@@ -59,6 +59,7 @@ const stub = `
59
59
  window.chrome = {
60
60
  runtime: { sendMessage: async (m) => (m.type === 'status' ? ${JSON.stringify(statuses[state] ?? statuses.connected)} : { ok: true }) },
61
61
  storage: { local: { get: async () => ({ port: 47321, token: 'GWCIveb--rxL_wKChN9Wl-OJmXFGTK4' }), set: async () => {} } },
62
+ tabs: { query: async () => [{ id: ${JSON.stringify(statuses[state]?.selfTabId ?? 1)} }] },
62
63
  i18n: {
63
64
  getUILanguage: () => ${JSON.stringify(locale.replace('_', '-'))},
64
65
  getMessage: (key, subs) => {