@vforsh/argus 0.1.18 → 0.1.20

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.
Files changed (116) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/argus.js +3008 -572
  3. package/dist/cli/plugins/pluginHost.d.ts.map +1 -1
  4. package/dist/cli/plugins/pluginHost.js +1 -0
  5. package/dist/cli/plugins/pluginHost.js.map +1 -1
  6. package/dist/cli/register/extensionCommands.d.ts.map +1 -1
  7. package/dist/cli/register/extensionCommands.js +131 -6
  8. package/dist/cli/register/extensionCommands.js.map +1 -1
  9. package/dist/cli/register/index.d.ts.map +1 -1
  10. package/dist/cli/register/index.js +6 -0
  11. package/dist/cli/register/index.js.map +1 -1
  12. package/dist/cli/register/recordCommands.d.ts +3 -0
  13. package/dist/cli/register/recordCommands.d.ts.map +1 -0
  14. package/dist/cli/register/recordCommands.js +90 -0
  15. package/dist/cli/register/recordCommands.js.map +1 -0
  16. package/dist/cli/register/skillCommands.d.ts +3 -0
  17. package/dist/cli/register/skillCommands.d.ts.map +1 -0
  18. package/dist/cli/register/skillCommands.js +13 -0
  19. package/dist/cli/register/skillCommands.js.map +1 -0
  20. package/dist/commands/domDrag.d.ts +21 -0
  21. package/dist/commands/domDrag.d.ts.map +1 -0
  22. package/dist/commands/domDrag.js +179 -0
  23. package/dist/commands/domDrag.js.map +1 -0
  24. package/dist/commands/extension/attach.d.ts +2 -0
  25. package/dist/commands/extension/attach.d.ts.map +1 -1
  26. package/dist/commands/extension/attach.js +31 -6
  27. package/dist/commands/extension/attach.js.map +1 -1
  28. package/dist/commands/extension/doctor.d.ts +6 -0
  29. package/dist/commands/extension/doctor.d.ts.map +1 -0
  30. package/dist/commands/extension/doctor.js +185 -0
  31. package/dist/commands/extension/doctor.js.map +1 -0
  32. package/dist/commands/extension/extensionId.d.ts +27 -0
  33. package/dist/commands/extension/extensionId.d.ts.map +1 -0
  34. package/dist/commands/extension/extensionId.js +37 -0
  35. package/dist/commands/extension/extensionId.js.map +1 -0
  36. package/dist/commands/extension/extensionPath.d.ts +15 -0
  37. package/dist/commands/extension/extensionPath.d.ts.map +1 -0
  38. package/dist/commands/extension/extensionPath.js +61 -0
  39. package/dist/commands/extension/extensionPath.js.map +1 -0
  40. package/dist/commands/extension/install.d.ts +16 -0
  41. package/dist/commands/extension/install.d.ts.map +1 -0
  42. package/dist/commands/extension/install.js +154 -0
  43. package/dist/commands/extension/install.js.map +1 -0
  44. package/dist/commands/extension/select.d.ts +7 -0
  45. package/dist/commands/extension/select.d.ts.map +1 -0
  46. package/dist/commands/extension/select.js +73 -0
  47. package/dist/commands/extension/select.js.map +1 -0
  48. package/dist/commands/extension/setup.d.ts +2 -1
  49. package/dist/commands/extension/setup.d.ts.map +1 -1
  50. package/dist/commands/extension/setup.js +5 -2
  51. package/dist/commands/extension/setup.js.map +1 -1
  52. package/dist/commands/extension/show.d.ts +4 -0
  53. package/dist/commands/extension/show.d.ts.map +1 -1
  54. package/dist/commands/extension/show.js +12 -88
  55. package/dist/commands/extension/show.js.map +1 -1
  56. package/dist/commands/extension/tabAttach.d.ts +28 -0
  57. package/dist/commands/extension/tabAttach.d.ts.map +1 -0
  58. package/dist/commands/extension/tabAttach.js +106 -0
  59. package/dist/commands/extension/tabAttach.js.map +1 -0
  60. package/dist/commands/extension/tabWatcher.d.ts +22 -0
  61. package/dist/commands/extension/tabWatcher.d.ts.map +1 -0
  62. package/dist/commands/extension/tabWatcher.js +89 -0
  63. package/dist/commands/extension/tabWatcher.js.map +1 -0
  64. package/dist/commands/extension/targetSelection.d.ts +62 -0
  65. package/dist/commands/extension/targetSelection.d.ts.map +1 -0
  66. package/dist/commands/extension/targetSelection.js +210 -0
  67. package/dist/commands/extension/targetSelection.js.map +1 -0
  68. package/dist/commands/extension/targets.d.ts +7 -0
  69. package/dist/commands/extension/targets.d.ts.map +1 -0
  70. package/dist/commands/extension/targets.js +73 -0
  71. package/dist/commands/extension/targets.js.map +1 -0
  72. package/dist/commands/extension/use.d.ts +13 -0
  73. package/dist/commands/extension/use.d.ts.map +1 -0
  74. package/dist/commands/extension/use.js +66 -0
  75. package/dist/commands/extension/use.js.map +1 -0
  76. package/dist/commands/record.d.ts +35 -0
  77. package/dist/commands/record.d.ts.map +1 -0
  78. package/dist/commands/record.js +210 -0
  79. package/dist/commands/record.js.map +1 -0
  80. package/dist/commands/skill.d.ts +6 -0
  81. package/dist/commands/skill.d.ts.map +1 -0
  82. package/dist/commands/skill.js +42 -0
  83. package/dist/commands/skill.js.map +1 -0
  84. package/dist/commands/watcherNativeHost.js +48 -1
  85. package/dist/commands/watcherNativeHost.js.map +1 -1
  86. package/dist/extension/dist/background/auth-header-monitor.js +77 -0
  87. package/dist/extension/dist/background/bridge-client.js +120 -0
  88. package/dist/extension/dist/background/cdp-proxy.js +201 -0
  89. package/dist/extension/dist/background/debugger-manager.js +296 -0
  90. package/dist/extension/dist/background/service-worker.js +2004 -0
  91. package/dist/extension/dist/background/service-worker.js.map +7 -0
  92. package/dist/extension/dist/popup/popup.js +730 -0
  93. package/dist/extension/dist/popup/popup.js.map +7 -0
  94. package/dist/extension/dist/popup/tabMarkup.js +104 -0
  95. package/dist/extension/dist/popup/viewState.js +60 -0
  96. package/dist/extension/dist/types/messages.js +5 -0
  97. package/dist/extension/icons/icon-128.png +0 -0
  98. package/dist/extension/icons/icon-16.png +0 -0
  99. package/dist/extension/icons/icon-48.png +0 -0
  100. package/dist/extension/manifest.json +26 -0
  101. package/dist/extension/src/popup/popup.html +756 -0
  102. package/dist/skill/argus/SKILL.md +202 -0
  103. package/dist/skill/argus/reference/CAPTURE.md +77 -0
  104. package/dist/skill/argus/reference/DIALOG.md +31 -0
  105. package/dist/skill/argus/reference/EVAL.md +137 -0
  106. package/dist/skill/argus/reference/EXTENSION.md +43 -0
  107. package/dist/skill/argus/reference/EXTENSION_IFRAME_EVAL.md +58 -0
  108. package/dist/skill/argus/reference/IFRAMES.md +46 -0
  109. package/dist/skill/argus/reference/INJECT.md +145 -0
  110. package/dist/skill/argus/reference/INSPECT.md +175 -0
  111. package/dist/skill/argus/reference/NET.md +108 -0
  112. package/dist/skill/argus/reference/PLUGINS.md +172 -0
  113. package/dist/skill/argus/reference/RUNTIME_CODE.md +42 -0
  114. package/dist/skill/argus/reference/START.md +120 -0
  115. package/dist/skill/argus/start-watcher.ts +108 -0
  116. package/package.json +2 -2
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/popup/classify-target.ts", "../../src/popup/target-list.ts", "../../src/popup/popup.ts"],
4
+ "sourcesContent": ["/**\n * Heuristic classification of iframe targets as \"low-interest\" (ad trackers,\n * consent managers, analytics pixels, etc.) so the popup can collapse them\n * behind a toggle instead of cluttering the target list.\n *\n * Runs purely on the URL and title strings already available in PopupTarget \u2014\n * no DOM access or background queries needed.\n */\n\ntype ClassifiableTarget = {\n\ttype: 'page' | 'iframe'\n\turl: string\n\ttitle: string\n}\n\ntype LowInterestUrlRule = {\n\thost: string\n\tpathPrefix?: string\n}\n\n/**\n * URL rules for iframes that are usually browser/app infrastructure, not the\n * user's debuggable surface. Host suffix matching covers subdomains.\n */\nconst LOW_INTEREST_URL_RULES: LowInterestUrlRule[] = [\n\t{ host: 'accounts.google.com', pathPrefix: '/RotateCookiesPage' },\n\t{ host: 'clients6.google.com', pathPrefix: '/static/proxy.html' },\n\t{ host: 'contacts.google.com', pathPrefix: '/u/2/widget/hovercard/' },\n\t{ host: 'docs.google.com', pathPrefix: '/_/og/bscframe' },\n\t{ host: 'docs.google.com', pathPrefix: '/offline/iframeapi' },\n\t{ host: 'doubleclick.net' },\n\t{ host: 'googlesyndication.com' },\n\t{ host: 'google.com', pathPrefix: '/recaptcha' },\n\t{ host: 'googletagmanager.com' },\n\t{ host: 'google-analytics.com' },\n\t{ host: 'googleadservices.com' },\n\t{ host: 'connect.facebook.net' },\n\t{ host: 'facebook.com', pathPrefix: '/tr' },\n\t{ host: 'ozone-project.com' },\n\t{ host: 'amazon-adsystem.com' },\n\t{ host: 'adnxs.com' },\n\t{ host: 'adsrvr.org' },\n\t{ host: 'criteo.com' },\n\t{ host: 'inmobi.com' },\n\t{ host: 'rubiconproject.com' },\n\t{ host: 'pubmatic.com' },\n]\n\n/**\n * Title patterns that indicate framework-internal / utility iframes.\n * Matched against the full title string.\n */\nconst LOW_INTEREST_TITLE_PATTERNS: RegExp[] = [\n\t/^__\\w+__$/, // __pb_locator__, __tcfapiLocator\n\t/^googlefc/i, // googlefcPresent, googlefcInactive, googlefcLoaded\n]\n\nexport function isLowInterestTarget(target: ClassifiableTarget): boolean {\n\tif (target.type === 'page') return false\n\n\tconst url = target.url\n\tif (!url || url === 'about:blank' || url === 'about:srcdoc') return true\n\n\tif (matchesLowInterestUrl(url)) return true\n\n\tconst title = target.title\n\tif (title && LOW_INTEREST_TITLE_PATTERNS.some((pattern) => pattern.test(title))) return true\n\n\treturn false\n}\n\nfunction matchesLowInterestUrl(url: string): boolean {\n\ttry {\n\t\tconst parsed = new URL(url)\n\t\treturn LOW_INTEREST_URL_RULES.some((rule) => matchesUrlRule(parsed, rule))\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction matchesUrlRule(url: URL, rule: LowInterestUrlRule): boolean {\n\tif (!matchesHost(url.hostname, rule.host)) return false\n\tif (!rule.pathPrefix) return true\n\n\treturn url.pathname.startsWith(rule.pathPrefix)\n}\n\nfunction matchesHost(hostname: string, host: string): boolean {\n\treturn hostname === host || hostname.endsWith(`.${host}`)\n}\n", "import { isLowInterestTarget } from './classify-target.js'\nimport type { PopupTarget, TabInfo } from './types.js'\n\nconst HIDE_TARGET_ICON = `\n\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t<path d=\"M10.7 5.1A10.7 10.7 0 0 1 12 5c5 0 8.5 4.5 9.5 6a13.4 13.4 0 0 1-2.7 3.2\"></path>\n\t\t<path d=\"M6.6 6.7A13.4 13.4 0 0 0 2.5 11c1 1.5 4.5 6 9.5 6a8.7 8.7 0 0 0 4.2-1.1\"></path>\n\t\t<path d=\"M14.1 14.1a3 3 0 0 1-4.2-4.2\"></path>\n\t\t<path d=\"M3 3l18 18\"></path>\n\t</svg>\n`\n\nconst SHOW_TARGET_ICON = `\n\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t<path d=\"M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6z\"></path>\n\t\t<circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\n\t</svg>\n`\n\nexport function renderTargetList(tab: TabInfo): string {\n\tconst targets = tab.targets ?? []\n\tconst hiddenTargets = tab.hiddenTargets ?? []\n\tif (targets.length <= 1 && hiddenTargets.length === 0) return ''\n\n\tconst primaryTargets: PopupTarget[] = []\n\tconst autoHiddenTargets: PopupTarget[] = []\n\tfor (const target of targets) {\n\t\tif (isLowInterestTarget(target)) {\n\t\t\tautoHiddenTargets.push(target)\n\t\t} else {\n\t\t\tprimaryTargets.push(target)\n\t\t}\n\t}\n\n\tconst primaryHtml = renderTargetItems(tab, primaryTargets, 'visible')\n\tconst hiddenFramesHtml = renderHiddenFramesSection(tab, autoHiddenTargets, hiddenTargets)\n\n\treturn `\n\t\t<div class=\"target-list\">\n\t\t\t${primaryHtml}\n\t\t\t${hiddenFramesHtml}\n\t\t</div>\n\t`\n}\n\nfunction renderHiddenFramesSection(tab: TabInfo, autoHiddenTargets: PopupTarget[], manuallyHiddenTargets: PopupTarget[]): string {\n\tconst count = autoHiddenTargets.length + manuallyHiddenTargets.length\n\tif (count === 0) {\n\t\treturn ''\n\t}\n\n\tconst hasSelectedAutoHiddenTarget = autoHiddenTargets.some((target) => isTargetSelected(tab.selectedFrameId, target.frameId))\n\tconst autoHiddenHtml = renderTargetItems(tab, autoHiddenTargets, 'visible')\n\tconst manuallyHiddenHtml = renderTargetItems(tab, manuallyHiddenTargets, 'hidden')\n\tconst expanded = hasSelectedAutoHiddenTarget ? 'open' : ''\n\n\treturn `\n <details class=\"target-collapsed target-hidden-list\" ${expanded}>\n <summary class=\"target-collapsed-toggle\">\n ${count} hidden frame${count === 1 ? '' : 's'}\n </summary>\n <div class=\"target-collapsed-list\">\n ${autoHiddenHtml}\n ${manuallyHiddenHtml}\n </div>\n </details>\n `\n}\n\nfunction renderTargetItems(tab: TabInfo, targets: PopupTarget[], visibility: 'visible' | 'hidden'): string {\n\treturn targets.map((target) => renderTargetItem(tab, target, visibility)).join('')\n}\n\nfunction renderTargetItem(tab: TabInfo, target: PopupTarget, visibility: 'visible' | 'hidden'): string {\n\tconst isSelected = isTargetSelected(tab.selectedFrameId, target.frameId)\n\tconst kindLabel = target.type === 'page' ? 'Page' : 'Iframe'\n\tconst title = target.title || kindLabel\n\tconst url = target.url || '(no url)'\n\tconst visibilityAction = renderTargetVisibilityAction(tab.tabId, target, visibility)\n\treturn `\n <div class=\"target-item ${isSelected ? 'selected' : ''} ${visibility === 'hidden' ? 'hidden-target' : ''}\">\n <button\n class=\"target-select-action\"\n data-action=\"select-target\"\n data-tab-id=\"${tab.tabId}\"\n data-frame-id=\"${escapeHtml(target.frameId ?? '')}\"\n type=\"button\"\n ${visibility === 'hidden' ? 'disabled' : ''}\n >\n <span class=\"target-kind\">${kindLabel}</span>\n <span class=\"target-meta\">\n <span class=\"target-title\" title=\"${escapeHtml(title)}\">${escapeHtml(title)}</span>\n <span class=\"target-url\" title=\"${escapeHtml(url)}\">${escapeHtml(url)}</span>\n </span>\n </button>\n ${visibilityAction}\n </div>\n `\n}\n\nfunction renderTargetVisibilityAction(tabId: number, target: PopupTarget, visibility: 'visible' | 'hidden'): string {\n\tif (target.type !== 'iframe' || !target.frameId) {\n\t\treturn ''\n\t}\n\n\tconst action = visibility === 'hidden' ? 'show-target' : 'hide-target'\n\tconst label = visibility === 'hidden' ? 'Show iframe target' : 'Hide iframe target'\n\tconst icon = visibility === 'hidden' ? SHOW_TARGET_ICON : HIDE_TARGET_ICON\n\n\treturn `\n\t\t<button\n\t\t\tclass=\"target-visibility-action\"\n\t\t\tdata-action=\"${action}\"\n\t\t\tdata-tab-id=\"${tabId}\"\n\t\t\tdata-frame-id=\"${escapeHtml(target.frameId)}\"\n\t\t\ttype=\"button\"\n\t\t\ttitle=\"${label}\"\n\t\t\taria-label=\"${label}\"\n\t\t>\n\t\t\t${icon}\n\t\t</button>\n\t`\n}\n\nfunction isTargetSelected(selectedFrameId: string | null | undefined, targetFrameId: string | null): boolean {\n\treturn selectedFrameId !== undefined && (selectedFrameId ?? null) === (targetFrameId ?? null)\n}\n\nfunction escapeHtml(text: string): string {\n\tconst div = document.createElement('div')\n\tdiv.textContent = text\n\treturn div.innerHTML\n}\n", "/**\n * Popup UI for the Argus CDP Bridge extension.\n * Displays tabs, target selection, and bridge/debugger health.\n */\n\nimport { renderTargetList } from './target-list.js'\nimport type { CurrentTargetSummary, PopupWatcherStatus, TabInfo } from './types.js'\n\ntype StatusPayload = {\n\tbridgeConnected: boolean\n\tattachedTabs: Array<{ tabId: number; url: string; title: string }>\n\twatchers: PopupWatcherStatus[]\n}\n\ntype StatusResponse = {\n\tsuccess: boolean\n\tstatus?: StatusPayload\n\terror?: string\n}\n\ntype TabsResponse = {\n\tsuccess: boolean\n\ttabs?: TabInfo[]\n\terror?: string\n}\n\ntype ActionResponse = {\n\tsuccess: boolean\n\terror?: string\n}\n\ntype PopupAction = 'attach' | 'detach' | 'focusTab' | 'selectTarget' | 'hideTarget' | 'showTarget'\ntype TabButtonAction = 'attach' | 'detach' | 'copy-info'\n\nconst COPY_ICON = `\n\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t<rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"></rect>\n\t\t<path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"></path>\n\t</svg>\n`\n\nconst CHECK_ICON = `\n\t<svg viewBox=\"0 0 16 16\" fill=\"none\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t<path d=\"M3 8.5l3.1 3.1L13 4.75\"></path>\n\t</svg>\n`\n\nconst DETACH_ICON = `\n\t<svg viewBox=\"0 0 16 16\" fill=\"none\" stroke-width=\"1.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t<path d=\"M5.4 1.75h5.2l3.65 3.65v5.2l-3.65 3.65H5.4l-3.65-3.65V5.4z\"></path>\n\t\t<path d=\"M6 6l4 4\"></path>\n\t\t<path d=\"M10 6l-4 4\"></path>\n\t</svg>\n`\n\n// DOM elements\nconst statusIndicator = document.getElementById('statusIndicator') as HTMLDivElement\nconst statusText = document.getElementById('statusText') as HTMLSpanElement\nconst attachedSection = document.getElementById('attachedSection') as HTMLDivElement\nconst attachedContent = document.getElementById('attachedContent') as HTMLDivElement\nconst availableSection = document.getElementById('availableSection') as HTMLDivElement\nconst availableContent = document.getElementById('availableContent') as HTMLDivElement\nconst attachedCount = document.getElementById('attachedCount') as HTMLSpanElement\nconst errorBanner = document.getElementById('errorBanner') as HTMLDivElement\nconst healthSummary = document.getElementById('healthSummary') as HTMLSpanElement\nconst healthNativeHost = document.getElementById('healthNativeHost') as HTMLDivElement\nconst healthWatcherReady = document.getElementById('healthWatcherReady') as HTMLDivElement\nconst healthWatcherId = document.getElementById('healthWatcherId') as HTMLDivElement\nconst healthAttachedCount = document.getElementById('healthAttachedCount') as HTMLDivElement\nconst healthSelectedTarget = document.getElementById('healthSelectedTarget') as HTMLDivElement\nconst healthLastMessage = document.getElementById('healthLastMessage') as HTMLDivElement\nconst healthPid = document.getElementById('healthPid') as HTMLDivElement\nconst copyAllButton = document.getElementById('copyAllButton') as HTMLButtonElement\nconst detachAllButton = document.getElementById('detachAllButton') as HTMLButtonElement\n\nlet prevStateHash = ''\nlet currentError: string | null = null\nlet latestCurrentWatcher: PopupWatcherStatus | null = null\n// Copy actions run per attached row, so keep the latest watcher list alongside the focused watcher.\nlet latestWatchers: PopupWatcherStatus[] = []\n\ncopyAllButton.addEventListener('click', () => {\n\tvoid copyAllWatchersInfo().catch((error) => {\n\t\tshowError(error instanceof Error ? error.message : 'Copy failed')\n\t})\n})\n\ndetachAllButton.addEventListener('click', () => {\n\tvoid detachAllWatchers()\n})\n\n// Prevent button clicks inside the health summary from toggling the <details> open/close.\ndocument.querySelector('.health-summary-actions')?.addEventListener('click', (event) => {\n\tevent.stopPropagation()\n})\n\nasync function sendMessage<T>(message: { action: string; tabId?: number; frameId?: string | null }): Promise<T> {\n\treturn new Promise((resolve) => {\n\t\tchrome.runtime.sendMessage(message, resolve)\n\t})\n}\n\nfunction setEmptyState(icon: string, message: string): void {\n\tavailableSection.classList.remove('hidden')\n\tattachedSection.classList.add('hidden')\n\tavailableContent.innerHTML = `\n <div class=\"empty-state\">\n <div class=\"icon\">${escapeHtml(icon)}</div>\n <div>${escapeHtml(message)}</div>\n </div>\n `\n}\n\nfunction updateStatus(connected: boolean, tabCount: number): void {\n\tstatusIndicator.classList.toggle('connected', connected)\n\tstatusText.textContent = connected ? 'Bridge connected' : 'Bridge disconnected'\n\tattachedCount.textContent = `${tabCount} attached`\n}\n\nfunction showError(message: string | null): void {\n\tcurrentError = message\n\terrorBanner.textContent = message ?? ''\n\terrorBanner.classList.toggle('hidden', !message)\n}\n\nfunction updateHealth(status: StatusPayload | undefined, watcher: PopupWatcherStatus | null): void {\n\tconst target = watcher?.currentTarget ?? null\n\tconst tabCount = status?.attachedTabs.length ?? 0\n\tconst nativeHostConnected = watcher?.nativeHostConnected ?? status?.bridgeConnected ?? false\n\tconst watcherReady = watcher?.watcherReady ?? false\n\tconst targetState = watcher?.targetState ?? 'not-selected'\n\n\thealthSummary.textContent = buildHealthSummaryText({\n\t\tnativeHostConnected,\n\t\twatcherReady,\n\t\ttargetState,\n\t\twatcherId: watcher?.watcherId ?? null,\n\t\ttabCount,\n\t})\n\tsetHealthValueState(healthNativeHost, nativeHostConnected ? 'Connected' : 'Disconnected', nativeHostConnected ? 'connected' : 'disconnected')\n\tsetHealthValueState(healthWatcherReady, watcherReady ? 'Ready' : 'Not ready', watcherReady ? 'connected' : 'disconnected')\n\thealthWatcherId.textContent = watcher?.watcherId ?? '-'\n\thealthAttachedCount.textContent = String(tabCount)\n\tsetHealthValueState(healthSelectedTarget, formatTargetState(target, targetState), getTargetStateClass(targetState))\n\thealthLastMessage.textContent = formatRelativeTimestamp(watcher?.lastMessageAt ?? null)\n\thealthPid.textContent = watcher?.nativeHostPid ? String(watcher.nativeHostPid) : '-'\n\tconst hasWatchers = latestWatchers.length > 0\n\tcopyAllButton.disabled = !hasWatchers\n\tdetachAllButton.disabled = !hasWatchers\n}\n\nfunction buildHealthSummaryText(input: {\n\tnativeHostConnected: boolean\n\twatcherReady: boolean\n\ttargetState: PopupWatcherStatus['targetState']\n\twatcherId: string | null\n\ttabCount: number\n}): string {\n\tconst parts: string[] = []\n\tif (input.watcherId) parts.push(input.watcherId)\n\tparts.push(input.nativeHostConnected ? 'Host connected' : 'Host disconnected')\n\tparts.push(input.watcherReady ? 'Watcher ready' : 'Watcher not ready')\n\tif (input.targetState === 'rebinding') parts.push('Target rebinding')\n\tif (input.tabCount > 0) parts.push(`${input.tabCount} tab${input.tabCount === 1 ? '' : 's'}`)\n\treturn parts.join(' \u00B7 ')\n}\n\nfunction setHealthValueState(element: HTMLElement, text: string, stateClass: 'connected' | 'disconnected' | 'warning' | null): void {\n\telement.textContent = text\n\telement.classList.toggle('connected', stateClass === 'connected')\n\telement.classList.toggle('disconnected', stateClass === 'disconnected')\n\telement.classList.toggle('warning', stateClass === 'warning')\n}\n\nfunction formatTargetState(target: CurrentTargetSummary | null, state: PopupWatcherStatus['targetState']): string {\n\tif (!target || state === 'not-selected') {\n\t\treturn '-'\n\t}\n\n\tconst label = target.type === 'page' ? 'Page' : 'Iframe'\n\treturn state === 'ready' ? `${label} ready` : `${label} rebinding`\n}\n\nfunction getTargetStateClass(state: PopupWatcherStatus['targetState']): 'connected' | 'disconnected' | 'warning' | null {\n\tif (state === 'ready') {\n\t\treturn 'connected'\n\t}\n\tif (state === 'rebinding') {\n\t\treturn 'warning'\n\t}\n\treturn null\n}\n\nfunction renderTabs(tabs: TabInfo[], currentTabId?: number): void {\n\tif (tabs.length === 0) {\n\t\tsetEmptyState('\uD83D\uDD0D', 'No tabs available')\n\t\treturn\n\t}\n\n\tconst attachedTabs = tabs.filter((tab) => tab.attached)\n\tlet availableTabs = tabs.filter((tab) => !tab.attached)\n\n\tif (currentTabId !== undefined) {\n\t\tconst currentTabIndex = availableTabs.findIndex((tab) => tab.tabId === currentTabId)\n\t\tif (currentTabIndex > 0) {\n\t\t\tconst [currentTab] = availableTabs.splice(currentTabIndex, 1)\n\t\t\tavailableTabs.unshift(currentTab)\n\t\t}\n\t}\n\n\trenderTabGroup(attachedSection, attachedContent, attachedTabs, true)\n\trenderTabGroup(availableSection, availableContent, availableTabs, false)\n}\n\nfunction renderTabItem(tab: TabInfo, showTargets: boolean): string {\n\tconst favicon = tab.faviconUrl\n\t\t? `<img class=\"tab-favicon\" src=\"${escapeHtml(tab.faviconUrl)}\" alt=\"\">`\n\t\t: `<div class=\"tab-favicon\" style=\"background: #e0e0e0\"></div>`\n\tconst watcherSuffix = tab.attached && tab.watcher?.watcherId ? ` (${tab.watcher.watcherId})` : ''\n\tconst actions = tab.attached ? renderAttachedTabActions(tab.tabId) : renderAttachButton(tab.tabId)\n\tconst fullTitle = (tab.title || 'Untitled') + watcherSuffix\n\n\treturn `\n <div class=\"tab-item ${tab.attached ? 'attached' : ''}\" data-tab-id=\"${tab.tabId}\">\n ${favicon}\n <div class=\"tab-info\">\n <div class=\"tab-title\" title=\"${escapeHtml(fullTitle)}\">${escapeHtml(fullTitle)}</div>\n <div class=\"tab-url\" title=\"${escapeHtml(tab.url)}\">${escapeHtml(tab.url)}</div>\n </div>\n ${actions}\n </div>\n ${showTargets ? renderTargetList(tab) : ''}\n `\n}\n\nfunction renderTabGroup(section: HTMLDivElement, content: HTMLDivElement, tabs: TabInfo[], showTargets: boolean): void {\n\tif (tabs.length === 0) {\n\t\tsection.classList.add('hidden')\n\t\tcontent.innerHTML = ''\n\t\treturn\n\t}\n\n\tsection.classList.remove('hidden')\n\tcontent.innerHTML = `<div class=\"tab-list\">${tabs.map((tab) => renderTabItem(tab, showTargets)).join('')}</div>`\n\tbindTabInteractions(content)\n}\n\nfunction bindTabInteractions(root: ParentNode): void {\n\troot.querySelectorAll('.tab-action').forEach((button) => {\n\t\tbutton.addEventListener('click', handleTabAction)\n\t})\n\troot.querySelectorAll('[data-action=\"select-target\"]').forEach((button) => {\n\t\tbutton.addEventListener('click', handleTargetSelection)\n\t})\n\troot.querySelectorAll('[data-action=\"hide-target\"], [data-action=\"show-target\"]').forEach((button) => {\n\t\tbutton.addEventListener('click', handleTargetVisibility)\n\t})\n\troot.querySelectorAll('.tab-item').forEach((item) => {\n\t\titem.addEventListener('click', handleTabItemClick)\n\t})\n}\n\nfunction renderAttachedTabActions(tabId: number): string {\n\treturn `\n\t\t<div class=\"tab-actions\">\n\t\t\t${renderIconActionButton(tabId, 'copy-info', 'copy', 'Copy watcher info', COPY_ICON)}\n\t\t\t${renderIconActionButton(tabId, 'detach', 'detach', 'Detach', DETACH_ICON)}\n\t\t</div>\n\t`\n}\n\nfunction renderAttachButton(tabId: number): string {\n\treturn `<button class=\"tab-action attach\" data-tab-id=\"${tabId}\" data-action=\"attach\" type=\"button\">Attach</button>`\n}\n\nfunction renderIconActionButton(tabId: number, action: Exclude<TabButtonAction, 'attach'>, variant: string, label: string, icon: string): string {\n\treturn `\n\t\t<button\n\t\t\tclass=\"tab-action icon-only ${variant}\"\n\t\t\tdata-tab-id=\"${tabId}\"\n\t\t\tdata-action=\"${action}\"\n\t\t\ttype=\"button\"\n\t\t\ttitle=\"${label}\"\n\t\t\taria-label=\"${label}\"\n\t\t>\n\t\t\t<span class=\"tab-action-icon\" aria-hidden=\"true\">${icon}</span>\n\t\t</button>\n\t`\n}\n\nasync function handleTabItemClick(event: Event): Promise<void> {\n\tconst target = event.target as HTMLElement\n\tif (target.closest('.tab-action')) {\n\t\treturn\n\t}\n\n\tconst tabItem = event.currentTarget as HTMLElement\n\tconst tabId = getTabId(tabItem)\n\tconst action = getTabItemAction(tabItem)\n\n\ttabItem.style.opacity = '0.6'\n\ttabItem.style.pointerEvents = 'none'\n\n\ttry {\n\t\tawait runPopupAction(action, { tabId })\n\t\tif (action === 'attach') {\n\t\t\tawait refreshTabs(true)\n\t\t}\n\t} catch (error) {\n\t\tshowError(error instanceof Error ? error.message : `${capitalize(action)} failed`)\n\t\ttabItem.style.opacity = '1'\n\t\ttabItem.style.pointerEvents = 'auto'\n\t}\n}\n\n/**\n * Attached rows act like \"jump to this Chrome tab\"; unattached rows keep the existing one-click attach flow.\n */\nfunction getTabItemAction(tabItem: HTMLElement): Extract<PopupAction, 'attach' | 'focusTab'> {\n\treturn tabItem.classList.contains('attached') ? 'focusTab' : 'attach'\n}\n\nasync function handleTabAction(event: Event): Promise<void> {\n\tconst button = (event.target as HTMLElement).closest('.tab-action') as HTMLButtonElement | null\n\tif (!button) {\n\t\treturn\n\t}\n\n\tconst tabId = getTabId(button)\n\tconst action = button.dataset.action as TabButtonAction\n\n\tif (action === 'copy-info') {\n\t\ttry {\n\t\t\tawait copyWatcherInfo(tabId, button)\n\t\t} catch (error) {\n\t\t\tshowError(error instanceof Error ? error.message : 'Copy failed')\n\t\t}\n\t\treturn\n\t}\n\n\tconst restoreButton = setBusyButtonState(button, action)\n\n\ttry {\n\t\tawait runPopupAction(action, { tabId })\n\t\tawait refreshTabs(true)\n\t} catch (error) {\n\t\tshowError(error instanceof Error ? error.message : `${capitalize(action)} failed`)\n\t\trestoreButton()\n\t}\n}\n\nasync function handleTargetSelection(event: Event): Promise<void> {\n\tconst button = event.currentTarget as HTMLButtonElement\n\tconst tabId = getTabId(button)\n\tconst frameId = button.dataset.frameId || null\n\n\tbutton.disabled = true\n\n\ttry {\n\t\tawait runPopupAction('selectTarget', { tabId, frameId })\n\t\tawait refreshTabs(true)\n\t} catch (error) {\n\t\tshowError(error instanceof Error ? error.message : 'Target selection failed')\n\t\tbutton.disabled = false\n\t}\n}\n\nasync function handleTargetVisibility(event: Event): Promise<void> {\n\tevent.stopPropagation()\n\tconst button = event.currentTarget as HTMLButtonElement\n\tconst tabId = getTabId(button)\n\tconst frameId = button.dataset.frameId || null\n\tconst action = button.dataset.action === 'show-target' ? 'showTarget' : 'hideTarget'\n\n\tbutton.disabled = true\n\n\ttry {\n\t\tawait runPopupAction(action, { tabId, frameId })\n\t\tawait refreshTabs(true)\n\t} catch (error) {\n\t\tshowError(error instanceof Error ? error.message : action === 'hideTarget' ? 'Target hide failed' : 'Target restore failed')\n\t\tbutton.disabled = false\n\t}\n}\n\nasync function runPopupAction(action: PopupAction, args: { tabId: number; frameId?: string | null }): Promise<void> {\n\tconst response = await sendMessage<ActionResponse>({ action, ...args })\n\tif (!response.success) {\n\t\tthrow new Error(response.error ?? `${capitalize(action)} failed`)\n\t}\n\n\tshowError(null)\n}\n\nasync function refreshTabs(forceRender = false): Promise<void> {\n\ttry {\n\t\tconst [statusResponse, tabsResponse, activeTab] = await Promise.all([\n\t\t\tsendMessage<StatusResponse>({ action: 'getStatus' }),\n\t\t\tsendMessage<TabsResponse>({ action: 'getTargets' }),\n\t\t\tgetCurrentTab(),\n\t\t])\n\n\t\tif (!statusResponse.success) {\n\t\t\tthrow new Error(statusResponse.error ?? 'Failed to load bridge status')\n\t\t}\n\n\t\tconst status = statusResponse.status\n\t\tlatestWatchers = status?.watchers ?? []\n\t\tlatestCurrentWatcher = selectCurrentWatcher(status ?? null, tabsResponse.tabs ?? [], activeTab?.id)\n\n\t\tconst stateHash = JSON.stringify({\n\t\t\tstatus,\n\t\t\ttabs: tabsResponse.tabs,\n\t\t\tcurrentTabId: activeTab?.id,\n\t\t\terror: currentError ?? tabsResponse.error ?? null,\n\t\t})\n\n\t\tif (!forceRender && stateHash === prevStateHash) {\n\t\t\treturn\n\t\t}\n\t\tprevStateHash = stateHash\n\n\t\tupdateStatus(status?.bridgeConnected ?? false, status?.attachedTabs.length ?? 0)\n\t\tupdateHealth(status, latestCurrentWatcher)\n\n\t\tif (tabsResponse.success && tabsResponse.tabs) {\n\t\t\trenderTabs(tabsResponse.tabs, activeTab?.id)\n\t\t\tshowError(currentError)\n\t\t\treturn\n\t\t}\n\n\t\tshowError(tabsResponse.error ?? 'Failed to load tabs')\n\t\tsetEmptyState('\u26A0\uFE0F', tabsResponse.error ?? 'Failed to load tabs')\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : 'Failed to refresh popup'\n\t\tshowError(message)\n\t\tupdateStatus(false, 0)\n\t\tlatestWatchers = []\n\t\tlatestCurrentWatcher = null\n\t\tupdateHealth(undefined, null)\n\t\tsetEmptyState('\u26A0\uFE0F', message)\n\t}\n}\n\nfunction formatRelativeTimestamp(timestamp: number | null): string {\n\tif (!timestamp) {\n\t\treturn '-'\n\t}\n\n\tconst elapsedMs = Math.max(0, Date.now() - timestamp)\n\tif (elapsedMs < 1000) {\n\t\treturn 'Just now'\n\t}\n\n\tconst elapsedSeconds = Math.floor(elapsedMs / 1000)\n\tif (elapsedSeconds < 60) {\n\t\treturn `${elapsedSeconds}s ago`\n\t}\n\n\tconst elapsedMinutes = Math.floor(elapsedSeconds / 60)\n\tif (elapsedMinutes < 60) {\n\t\treturn `${elapsedMinutes}m ago`\n\t}\n\n\tconst elapsedHours = Math.floor(elapsedMinutes / 60)\n\treturn `${elapsedHours}h ago`\n}\n\nasync function copyWatcherInfo(tabId: number, button: HTMLButtonElement): Promise<void> {\n\tconst watcher = findWatcherByTabId(latestWatchers, tabId)\n\tconst text = buildWatcherInfoText(watcher)\n\tif (!text) {\n\t\treturn\n\t}\n\n\tawait copyTextToClipboard(text)\n\tshowError(null)\n\trestoreButtonFeedback(button, 'Copied!', 1500, CHECK_ICON)\n}\n\nasync function copyAllWatchersInfo(): Promise<void> {\n\tconst text = buildAllWatchersInfoText(latestWatchers)\n\tif (!text) {\n\t\treturn\n\t}\n\n\tawait copyTextToClipboard(text)\n\tshowError(null)\n\trestoreButtonFeedback(copyAllButton, 'Copied!')\n}\n\nasync function copyTextToClipboard(text: string): Promise<void> {\n\ttry {\n\t\tawait navigator.clipboard.writeText(text)\n\t\treturn\n\t} catch {\n\t\t// Chrome extension popups can lose Clipboard API access depending on focus/permission state.\n\t}\n\n\tconst textarea = document.createElement('textarea')\n\ttextarea.value = text\n\ttextarea.setAttribute('readonly', 'true')\n\ttextarea.style.position = 'fixed'\n\ttextarea.style.opacity = '0'\n\ttextarea.style.pointerEvents = 'none'\n\tdocument.body.appendChild(textarea)\n\ttextarea.select()\n\ttextarea.setSelectionRange(0, textarea.value.length)\n\n\ttry {\n\t\tconst copied = document.execCommand('copy')\n\t\tif (!copied) {\n\t\t\tthrow new Error('Browser denied clipboard write')\n\t\t}\n\t} finally {\n\t\ttextarea.remove()\n\t}\n}\n\nasync function detachAllWatchers(): Promise<void> {\n\tif (latestWatchers.length === 0) {\n\t\treturn\n\t}\n\n\tconst restoreBusyState = setButtonFeedback(detachAllButton, 'Detaching...')\n\tconst failures = await detachWatchers(latestWatchers.map((watcher) => watcher.tabId))\n\trestoreBusyState()\n\tawait refreshTabs(true)\n\n\tif (failures.length > 0) {\n\t\tshowError(buildDetachAllError(failures.length))\n\t\treturn\n\t}\n\n\tshowError(null)\n\trestoreButtonFeedback(detachAllButton, 'Detached!')\n}\n\n/**\n * Detach watchers one by one so a single failure does not block the rest of the cleanup.\n */\nasync function detachWatchers(tabIds: number[]): Promise<number[]> {\n\tconst failures: number[] = []\n\n\tfor (const tabId of tabIds) {\n\t\ttry {\n\t\t\tawait runPopupAction('detach', { tabId })\n\t\t} catch {\n\t\t\tfailures.push(tabId)\n\t\t}\n\t}\n\n\treturn failures\n}\n\nfunction setBusyButtonState(button: HTMLButtonElement, action: Extract<TabButtonAction, 'attach' | 'detach'>): () => void {\n\tconst previousMarkup = button.innerHTML\n\tconst restoreFeedback = setButtonFeedback(button, action === 'attach' ? 'Attaching...' : 'Detaching...')\n\tif (action === 'attach') {\n\t\tbutton.textContent = 'Attaching...'\n\t}\n\n\treturn () => {\n\t\tbutton.innerHTML = previousMarkup\n\t\trestoreFeedback()\n\t}\n}\n\nfunction restoreButtonFeedback(button: HTMLButtonElement, label: string, timeoutMs = 1500, iconMarkup?: string): void {\n\tconst restore = setButtonFeedback(button, label, iconMarkup)\n\tsetTimeout(restore, timeoutMs)\n}\n\nfunction setButtonFeedback(button: HTMLButtonElement, label: string, iconMarkup?: string): () => void {\n\tconst previousTitle = button.title\n\tconst previousLabel = button.getAttribute('aria-label')\n\tconst previousText = getButtonLabel(button)\n\tconst previousIcon = getButtonIconMarkup(button)\n\tconst previousDisabled = button.disabled\n\n\tbutton.disabled = true\n\tbutton.title = label\n\tbutton.setAttribute('aria-label', label)\n\tsetButtonLabel(button, label)\n\tif (iconMarkup) {\n\t\tsetButtonIconMarkup(button, iconMarkup)\n\t}\n\n\treturn () => {\n\t\tbutton.disabled = previousDisabled\n\t\tbutton.title = previousTitle\n\t\tbutton.setAttribute('aria-label', previousLabel ?? previousTitle)\n\t\tsetButtonLabel(button, previousText)\n\t\tsetButtonIconMarkup(button, previousIcon)\n\t}\n}\n\nfunction buildWatcherInfoText(watcher: PopupWatcherStatus | null): string | null {\n\tif (!canCopyWatcherInfo(watcher)) {\n\t\treturn null\n\t}\n\n\tconst readyWatcher = watcher!\n\tconst target = readyWatcher.currentTarget!\n\tconst attached = target.attachedAt ? new Date(target.attachedAt).toISOString() : new Date().toISOString()\n\tconst fields = [\n\t\t['ID', readyWatcher.watcherId!],\n\t\t['Host', `${readyWatcher.watcherHost!}:${readyWatcher.watcherPort!}`],\n\t\t['PID', String(readyWatcher.nativeHostPid!)],\n\t\t['Target', target.title || '(no title)'],\n\t\t['URL', target.url || '(no url)'],\n\t\t['Attached', attached],\n\t]\n\n\treturn `Argus Watcher Info\\n${fields.map(([label, value]) => `${label}: ${value}`).join('\\n')}`\n}\n\nfunction buildAllWatchersInfoText(watchers: PopupWatcherStatus[]): string | null {\n\tconst watcherInfo = watchers.map((watcher) => buildWatcherInfoText(watcher)).filter((text): text is string => Boolean(text))\n\tif (watcherInfo.length === 0) {\n\t\treturn null\n\t}\n\n\treturn watcherInfo.join('\\n\\n')\n}\n\nfunction buildDetachAllError(failureCount: number): string {\n\treturn failureCount === 1 ? 'Failed to detach 1 watcher' : `Failed to detach ${failureCount} watchers`\n}\n\nfunction capitalize(text: string): string {\n\treturn text.charAt(0).toUpperCase() + text.slice(1)\n}\n\nfunction selectCurrentWatcher(status: StatusPayload | null, tabs: TabInfo[], activeTabId?: number): PopupWatcherStatus | null {\n\tif (!status) {\n\t\treturn null\n\t}\n\n\tif (activeTabId !== undefined) {\n\t\tconst activeWatcher = findWatcherByTabId(status.watchers, activeTabId)\n\t\tif (activeWatcher) {\n\t\t\treturn activeWatcher\n\t\t}\n\t}\n\n\tfor (const tab of tabs) {\n\t\tif (!tab.attached) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst watcher = findWatcherByTabId(status.watchers, tab.tabId)\n\t\tif (watcher) {\n\t\t\treturn watcher\n\t\t}\n\t}\n\n\treturn status.watchers[0] ?? null\n}\n\nfunction canCopyWatcherInfo(watcher: PopupWatcherStatus | null | undefined): boolean {\n\treturn Boolean(watcher?.watcherId && watcher?.watcherHost && watcher?.watcherPort != null && watcher?.nativeHostPid && watcher?.currentTarget)\n}\n\nfunction findWatcherByTabId(watchers: PopupWatcherStatus[], tabId: number): PopupWatcherStatus | null {\n\treturn watchers.find((watcher) => watcher.tabId === tabId) ?? null\n}\n\nfunction getTabId(element: HTMLElement): number {\n\treturn parseInt(element.dataset.tabId ?? '0', 10)\n}\n\nfunction getButtonLabel(button: HTMLButtonElement): string {\n\treturn button.querySelector<HTMLElement>('[data-button-label]')?.textContent ?? ''\n}\n\nfunction setButtonLabel(button: HTMLButtonElement, label: string): void {\n\tconst labelNode = button.querySelector<HTMLElement>('[data-button-label]')\n\tif (labelNode) {\n\t\tlabelNode.textContent = label\n\t}\n}\n\nfunction getButtonIconMarkup(button: HTMLButtonElement): string {\n\treturn button.querySelector<HTMLElement>('.tab-action-icon')?.innerHTML ?? ''\n}\n\nfunction setButtonIconMarkup(button: HTMLButtonElement, iconMarkup: string): void {\n\tconst iconNode = button.querySelector<HTMLElement>('.tab-action-icon')\n\tif (iconNode) {\n\t\ticonNode.innerHTML = iconMarkup\n\t}\n}\n\nfunction escapeHtml(text: string): string {\n\tconst div = document.createElement('div')\n\tdiv.textContent = text\n\treturn div.innerHTML\n}\n\nasync function getCurrentTab(): Promise<chrome.tabs.Tab | undefined> {\n\tconst tabs = await chrome.tabs.query({ active: true, currentWindow: true })\n\treturn tabs[0]\n}\n\nvoid refreshTabs()\nsetInterval(() => {\n\tvoid refreshTabs()\n}, 2000)\n"],
5
+ "mappings": "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",
6
+ "names": ["escapeHtml"]
7
+ }
@@ -0,0 +1,104 @@
1
+ export function renderTabsMarkup(options) {
2
+ const { tabs, currentTabId, selectedTabId, expandedTabIds } = options;
3
+ const attachedTabs = tabs.filter((tab) => tab.attached);
4
+ const availableTabs = sortAvailableTabs(tabs.filter((tab) => !tab.attached), currentTabId);
5
+ let html = '';
6
+ if (attachedTabs.length > 0) {
7
+ html += renderTabSection('Attached Tabs', attachedTabs, currentTabId, selectedTabId, expandedTabIds);
8
+ }
9
+ if (availableTabs.length > 0) {
10
+ if (attachedTabs.length > 0) {
11
+ html += '<div style="height: 16px"></div>';
12
+ }
13
+ html += renderTabSection('Available Tabs', availableTabs, currentTabId, selectedTabId, expandedTabIds);
14
+ }
15
+ return html;
16
+ }
17
+ function renderTabSection(title, tabs, currentTabId, selectedTabId, expandedTabIds) {
18
+ return `
19
+ <div class="section-title">${title}</div>
20
+ <div class="tab-list">
21
+ ${tabs.map((tab) => renderTabItem(tab, currentTabId, selectedTabId, expandedTabIds)).join('')}
22
+ </div>
23
+ `;
24
+ }
25
+ function renderTabItem(tab, currentTabId, selectedTabId, expandedTabIds) {
26
+ const favicon = tab.faviconUrl
27
+ ? `<img class="tab-favicon" src="${escapeHtml(tab.faviconUrl)}" alt="">`
28
+ : `<div class="tab-favicon" style="background: #e0e0e0"></div>`;
29
+ const actionButton = tab.attached
30
+ ? `<button class="tab-action detach" data-tab-id="${tab.tabId}" data-action="detach" type="button">Detach</button>`
31
+ : `<button class="tab-action attach" data-tab-id="${tab.tabId}" data-action="attach" type="button">Attach</button>`;
32
+ const isSelected = selectedTabId === tab.tabId;
33
+ const targetCount = tab.targets?.length ?? 0;
34
+ const isExpandable = tab.attached && targetCount > 1;
35
+ const isExpanded = isExpandable && expandedTabIds.has(tab.tabId);
36
+ const chips = [
37
+ tab.tabId === currentTabId ? `<span class="tab-chip current">Current</span>` : '',
38
+ isExpandable ? `<span class="tab-chip">${targetCount} targets</span>` : '',
39
+ ]
40
+ .filter(Boolean)
41
+ .join('');
42
+ return `
43
+ <div
44
+ class="tab-item ${tab.attached ? 'attached' : ''} ${isSelected ? 'selected' : ''} ${isExpandable || !tab.attached ? 'selectable' : ''}"
45
+ data-tab-id="${tab.tabId}"
46
+ data-expandable="${String(isExpandable)}"
47
+ >
48
+ ${favicon}
49
+ <div class="tab-info">
50
+ <div class="tab-title">${escapeHtml(tab.title || 'Untitled')}</div>
51
+ <div class="tab-url">${escapeHtml(tab.url)}</div>
52
+ </div>
53
+ ${chips}
54
+ ${actionButton}
55
+ </div>
56
+ ${isExpanded ? renderTargetList(tab) : ''}
57
+ `;
58
+ }
59
+ function renderTargetList(tab) {
60
+ const targets = tab.targets ?? [];
61
+ return `
62
+ <div class="target-list">
63
+ ${targets
64
+ .map((target) => {
65
+ const isSelected = tab.selectedFrameId !== undefined && (tab.selectedFrameId ?? null) === (target.frameId ?? null);
66
+ const kindLabel = target.type === 'page' ? 'Page' : 'Iframe';
67
+ return `
68
+ <button
69
+ class="target-item ${isSelected ? 'selected' : ''}"
70
+ data-action="select-target"
71
+ data-tab-id="${tab.tabId}"
72
+ data-frame-id="${escapeHtml(target.frameId ?? '')}"
73
+ type="button"
74
+ >
75
+ <span class="target-kind">${kindLabel}</span>
76
+ <span class="target-meta">
77
+ <span class="target-title">${escapeHtml(target.title || kindLabel)}</span>
78
+ <span class="target-url">${escapeHtml(target.url || '(no url)')}</span>
79
+ </span>
80
+ </button>
81
+ `;
82
+ })
83
+ .join('')}
84
+ </div>
85
+ `;
86
+ }
87
+ function sortAvailableTabs(tabs, currentTabId) {
88
+ if (currentTabId === undefined) {
89
+ return tabs;
90
+ }
91
+ const currentTabIndex = tabs.findIndex((tab) => tab.tabId === currentTabId);
92
+ if (currentTabIndex <= 0) {
93
+ return tabs;
94
+ }
95
+ const nextTabs = [...tabs];
96
+ const [currentTab] = nextTabs.splice(currentTabIndex, 1);
97
+ nextTabs.unshift(currentTab);
98
+ return nextTabs;
99
+ }
100
+ function escapeHtml(text) {
101
+ const div = document.createElement('div');
102
+ div.textContent = text;
103
+ return div.innerHTML;
104
+ }
@@ -0,0 +1,60 @@
1
+ export function derivePopupViewState(status) {
2
+ if (!status || status.bridgeState === 'not_configured') {
3
+ return {
4
+ phase: 'notConfigured',
5
+ statusLabel: 'Not configured',
6
+ title: 'Finish one-time setup',
7
+ description: 'Install the Argus native host for this extension, then reload the extension to enable the bridge.',
8
+ primaryAction: { kind: 'copySetupCommand', label: 'Copy setup command' },
9
+ showRecovery: true,
10
+ showTargetSummary: false,
11
+ showDiagnostics: false,
12
+ };
13
+ }
14
+ if (status.bridgeState !== 'connected' || !status.bridgeConnected) {
15
+ return {
16
+ phase: 'watcherNotRunning',
17
+ statusLabel: 'Bridge unavailable',
18
+ title: 'Argus bridge is unavailable',
19
+ description: 'The native host is installed, but the extension is not connected to the watcher right now. Retry the connection first.',
20
+ primaryAction: { kind: 'reconnect', label: 'Reconnect bridge' },
21
+ showRecovery: true,
22
+ showTargetSummary: false,
23
+ showDiagnostics: false,
24
+ };
25
+ }
26
+ if (status.attachedTabs.length === 0) {
27
+ return {
28
+ phase: 'ready',
29
+ statusLabel: 'Ready',
30
+ title: 'Attach a tab to get started',
31
+ description: 'The bridge is connected. Pick a tab below and attach it when you want Argus to control that page.',
32
+ primaryAction: null,
33
+ showRecovery: false,
34
+ showTargetSummary: false,
35
+ showDiagnostics: true,
36
+ };
37
+ }
38
+ if (status.currentTarget?.type === 'iframe') {
39
+ return {
40
+ phase: 'targetSelected',
41
+ statusLabel: 'Target selected',
42
+ title: 'Iframe target selected',
43
+ description: 'Commands will be routed to the selected iframe until you choose a different target.',
44
+ primaryAction: null,
45
+ showRecovery: false,
46
+ showTargetSummary: true,
47
+ showDiagnostics: true,
48
+ };
49
+ }
50
+ return {
51
+ phase: 'attached',
52
+ statusLabel: 'Attached',
53
+ title: 'Tab attached',
54
+ description: 'Argus is attached to a page target. Expand an attached tab if you want to switch into an iframe.',
55
+ primaryAction: null,
56
+ showRecovery: false,
57
+ showTargetSummary: true,
58
+ showDiagnostics: true,
59
+ };
60
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Native Messaging protocol types for communication between
3
+ * the Chrome extension and the argus-watcher (extension mode).
4
+ */
5
+ export {};
Binary file
Binary file
@@ -0,0 +1,26 @@
1
+ {
2
+ "manifest_version": 3,
3
+ "name": "Argus CDP Bridge",
4
+ "version": "0.1.0",
5
+ "description": "Bridge CDP access for Argus without --remote-debugging-port",
6
+ "permissions": ["cookies", "debugger", "tabs", "nativeMessaging", "storage"],
7
+ "host_permissions": ["<all_urls>"],
8
+ "background": {
9
+ "service_worker": "dist/background/service-worker.js",
10
+ "type": "module"
11
+ },
12
+ "action": {
13
+ "default_popup": "src/popup/popup.html",
14
+ "default_icon": {
15
+ "16": "icons/icon-16.png",
16
+ "48": "icons/icon-48.png",
17
+ "128": "icons/icon-128.png"
18
+ }
19
+ },
20
+ "icons": {
21
+ "16": "icons/icon-16.png",
22
+ "48": "icons/icon-48.png",
23
+ "128": "icons/icon-128.png"
24
+ },
25
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1lmJWE8y/3by5FlIta/a35cckp3mOVkFSmn8imDO+6S4xsD7naFwonrRMlMMd6lljOBG+sa5YgiMEeR1XwwyZlSDqXIOaNdizChK8wjtjhYldRmax9NQCbhejFWRyIDsR+B7xmbRsroCnSG667JR6D3q8L5v2Qbd/4rH+zZniqUdZKOPJEyjOBEbWoytX3nTWbJvCy+AHznAtnkIWysQyibUkMIBxDGNBSpx507Cc6kMrWZpnCSkjKtRj7qLpMEat4xQdkOhh3mZCisSimQoMD2Axhnqmyacj8IoKDQX+xkb6qLArO7nWr6QD4rOVWrTdgSBg+4TfW3C2zDCP5UhwIDAQAB"
26
+ }