SvenandClaude Opus 5 99757361ef first commit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00
2026-08-20 11:05:58 +02:00

Swyx Tab Bridge — Firefox-Add-on

Verwaltet Firefox-Tabs über die WebSocket-Verbindung zu SwyxTray: Tabs auslesen, öffnen und schließen.

Rollenverteilung

Ein Browser-Add-on kann keinen WebSocket-Server betreiben — es kann nur Client sein. Das Add-on verbindet sich daher zu SwyxTray (Default ws://127.0.0.1:17655) und beantwortet die dort eintreffenden Aufträge.

[ SwyxTray, Port 17655 ]  <--- verbindet sich ---  [ Firefox-Add-on: WS-Client ]
     |  {"type":"tab","id":1,"action":"list"}  ->
     <-  {"cmd":"tabresult","id":1,"ok":true,"tabs":[…]}

Zuständig ist das Add-on ausschließlich für Tab-Nachrichten ("type":"tab"). Alles andere auf der Verbindung — Telefonie-Kommandos, Events, Nachrichten an andere Komponenten — wird ignoriert: keine Antwort, kein Fehler.

Protokoll

Alle Nachrichten sind JSON-Textframes. Die id der Anfrage wird unverändert in die Antwort gespiegelt; die Antwort trägt immer "cmd":"tabresult".

1. Offene Tabs auslesen (list)

 {"type":"tab","id":1,"action":"list"}
 {"cmd":"tabresult","id":1,"ok":true,
   "tabs":[{"id":42,"title":"Kundenakte Muster GmbH","url":"https://crm.example.local/kunden/4711","active":false},
           {"id":43,"title":"Posteingang","url":"https://mail.example.local/","active":true}]}

Optionale Felder zum Einschränken: currentWindowOnly (bool), windowId (number), url / title (Match-Pattern, z.B. "*://*.example.local/*").

2. Tab mit mitgegebener URL öffnen (open)

 {"type":"tab","id":2,"action":"open","url":"https://crm.example.local/kunden/4711"}
 {"cmd":"tabresult","id":2,"ok":true,"tabId":44}

Optionale Felder:

Feld Typ Default Beschreibung
active boolean true false = im Hintergrund öffnen
reuse boolean false ist die URL schon offen, wird der Tab aktiviert statt neu geöffnet (Antwort enthält dann "reused":true)
newWindow boolean false in neuem Fenster öffnen
windowId number Zielfenster
index number Position in der Tableiste
pinned boolean false angeheftet öffnen

Erlaubt sind http, https, ftp, file; javascript:, data: u.ä. werden abgewiesen.

3. Tab löschen (close)

 {"type":"tab","id":3,"action":"close","tabId":42}
 {"cmd":"tabresult","id":3,"ok":true}

tabId darf auch ein Array sein ([42,43]); die Antwort enthält dann "closed":[42,43].

Anmeldung (hello)

Direkt nach dem Verbindungsaufbau meldet sich das Add-on einmal an — immer, nicht nur mit Token:

 {"cmd":"hello","client":"swyx-tab-bridge","version":"1.0.0",
   "actions":["list","open","close","activate","focus"]}

Ist unter Einstellungen ein Token gesetzt, kommt es als Feld token mit. Eine Antwort wird nicht erwartet. SwyxTray kann die Gegenstelle erst dadurch identifizieren und den Verbindungsaufbau protokollieren; ohne hello ist auf der Leitung nicht unterscheidbar, wer sich verbunden hat.

Fehler

 {"cmd":"tabresult","id":5,"ok":false,"error":"Feld 'url' fehlt."}

error ist ein zusätzliches Klartextfeld zur Diagnose — maßgeblich ist "ok":false. Fehlerfälle: fehlendes/ungültiges url bzw. tabId, unerlaubtes URL-Protokoll, unbekannte action, nicht existierender Tab.

SwyxTray wertet einen Auftrag nach 5 s ohne Antwort als gescheitert. Das Add-on bricht deshalb jede Aktion nach 4 s ab (ACTION_TIMEOUT_MS in background.js) und antwortet dann mit "ok":false — es bleibt also nie stumm.

Zusätzliche Aktionen

Über die drei SwyxTray-Aktionen hinaus versteht das Add-on:

 {"type":"tab","id":4,"action":"activate","tabId":42}
 {"cmd":"tabresult","id":4,"ok":true,"tabId":42}

 {"type":"tab","id":5,"action":"focus","url":"https://crm.example.local/kunden/4711"}
 {"cmd":"tabresult","id":5,"ok":true,"focused":true,"opened":false,"tabId":42}
  • activate holt einen bekannten Tab per tabId in den Vordergrund (inkl. Fenster).
  • focus sucht die passende Seite und aktiviert sie; ist sie nicht offen, wird sie geöffnet (focused:false, opened:true). Optional: match (prefix | exact | origin, Default prefix), open:false (nicht öffnen), activate:false, oder Suche per title statt url. Fragment (#…) und abschließende Slashes werden beim Vergleich ignoriert.

Ignorierte Nachrichten

Nachricht Verhalten
alles ohne "type":"tab" (z.B. {"cmd":"call",…}) wird ignoriert
ungültiges JSON wird ignoriert

Installation (temporär, zum Entwickeln)

  1. about:debugging#/runtime/this-firefox öffnen
  2. „Temporäres Add-on laden…”manifest.json in diesem Ordner auswählen
  3. Server-Adresse ggf. unter Einstellungen im Popup anpassen (Default ws://127.0.0.1:17655)

Temporär geladene Add-ons verschwinden beim Firefox-Neustart. Für den Dauerbetrieb muss das Add-on signiert werden (web-ext sign, AMO-Account) oder es wird Firefox ESR / Developer Edition mit xpinstall.signatures.required = false verwendet.

Paket bauen:

npx web-ext lint
npx web-ext build          # erzeugt web-ext-artifacts/*.zip -> signieren bzw. in .xpi umbenennen

Signierung und Datenerhebung

Seit dem 3. November 2025 müssen neue Erweiterungen auf AMO Mozillas eingebautes Einwilligungssystem bedienen. Im Manifest steht deshalb:

"data_collection_permissions": { "required": ["browsingActivity"] }

Mozilla definiert Übermittlung als Daten, die außerhalb des Add-ons oder des lokalen Browsers verarbeitet werden. Das Add-on gibt Tab-Titel und URLs an SwyxTray weiter — also aus dem Browser heraus, wenn auch nur an eine lokale Anwendung auf demselben Rechner und nicht ins Netz. "none" wäre eine Untertreibung, browsingActivity beschreibt genau das (besuchte Seiten, URLs).

strict_min_version bleibt bewusst bei 115.0, obwohl der Schlüssel erst ab Firefox 140 ausgewertet wird. Ältere Versionen ignorieren ihn folgenlos; ein Anheben auf 140.0 würde ESR 115 und ESR 128 ausschließen. web-ext lint meldet dafür zwei Warnungen — die blockieren die Signierung nicht.

Installation auf Windows (per SSH)

deploy/deploy-windows.sh zählt die Version hoch, baut das .xpi, überträgt es per scp und führt deploy/Install-SwyxTabBridge.ps1 auf dem Zielrechner aus:

./deploy/deploy-windows.sh                    # Testrechner, ohne Parameter
./deploy/deploy-windows.sh --keep-firefox     # laufenden Firefox nicht beenden
./deploy/deploy-windows.sh --uninstall        # rückgängig machen

Der nackte Aufruf erledigt alles: Version hochzählen, bei AMO signieren, übertragen, Policy schreiben und den laufenden Firefox beenden (nur den aus dem Zielverzeichnis — eine zweite Installation daneben bleibt offen). Ziel ist die Release-Installation, die ausschließlich signierte Add-ons annimmt; jeder Lauf wird deshalb signiert. Ziel-Rechner, Firefox-Verzeichnis sowie Signatur- und Neustart-Verhalten sind als Konstanten oben im Skript voreingestellt.

Standardmäßig wird eine Enterprise-Policy (force_installed) geschrieben, sodass das Add-on beim nächsten Firefox-Start ohne Rückfrage für alle Profile installiert wird. Details, Signierung und Optionen: deploy/README.md.

Tests

Selbsttest der Kommandoverarbeitung ohne Firefox — background.js läuft mit gestubbten browser-/WebSocket-APIs:

node test-server/test-background.mjs

Testserver, der SwyxTray simuliert (ohne Abhängigkeiten, nur Node):

node test-server/server.js                    # lauscht auf ws://127.0.0.1:17655
node test-server/server.js --log /pfad/x.log  # anderes Protokoll
node test-server/server.js --no-log           # nur Konsole

Der Server protokolliert Verbindungsaufbau, Anmeldung und Trennung mit Zeitstempel auf der Konsole und in test-server/swyx-tray.log:

[2026-08-17 16:16:09.809] Verbindung geöffnet von 127.0.0.1.
[2026-08-17 16:16:09.809] Angemeldet: swyx-tab-bridge v1.0.12 (Aktionen: list, open, close, activate, focus; ohne Token)
[2026-08-17 16:16:12.314] Verbindung getrennt: swyx-tab-bridge v1.0.12 (Dauer 3 s).

Meldet sich eine Gegenstelle binnen drei Sekunden nicht mit hello an, wird das als „unbekannte Gegenstelle" vermerkt. Das ist die Vorlage dafür, was SwyxTray mitschreiben sollte.

Eingabe gesendete Nachricht
list / list current {"type":"tab","action":"list"}
open <url> [background] {"type":"tab","action":"open","url":"…"}
close <tabId> {"type":"tab","action":"close","tabId":42}
activate <tabId> {"type":"tab","action":"activate","tabId":42}
focus <url> [titel…] {"type":"tab","action":"focus","url":"…"}
raw {…} beliebiges JSON (ohne type:"tab" bleibt es unbeantwortet)
quit beenden

Einstellungen

Die Einstellungsseite zeigt oben, ob das Add-on mit der Tray-App verbunden ist — Zustand, Serveradresse, Zeitpunkt des Verbindungsaufbaus und der letzte Fehler, laufend aktualisiert. Dieselbe Anzeige gibt es kompakt im Popup.

Über das Symbol in der Symbolleiste → Einstellungen:

  • WebSocket-Serverws://… oder wss://… (Default ws://127.0.0.1:17655)
  • Token — optionales Shared Secret. Ist es gesetzt, geht es in der hello-Nachricht mit.
  • Automatisch verbinden — Auto-Reconnect mit exponentiellem Backoff (1 s → max. 30 s)

Das Symbol zeigt den Verbindungszustand: kein Badge = verbunden, = Verbindungsaufbau, ! = getrennt.

Dateien

Datei Zweck
manifest.json Add-on-Manifest (MV2, persistenter Hintergrund)
background.js WebSocket-Client, Reconnect, Aktionen
popup.html/js Statusanzeige, Verbinden/Trennen
options.html/js Server-URL, Token, Auto-Connect
test-server/server.js Testserver (simuliert SwyxTray)
test-server/test-background.mjs Selbsttest der Kommandoverarbeitung
deploy/deploy-windows.sh Version hochzaehlen, bauen, per SSH ausrollen
deploy/Install-SwyxTabBridge.ps1 Installation auf dem Windows-Rechner

Hinweise

  • Manifest V2 ist bewusst gewählt: Nur mit persistentem Hintergrundskript bleibt die WebSocket-Verbindung dauerhaft offen. Unter MV3 (nicht-persistente Event-Page) würde die Verbindung nach Leerlauf abgebaut. Firefox unterstützt MV2 weiterhin.
  • ws://127.0.0.1 ist erlaubt (das Add-on läuft im moz-extension:-Kontext, keine Mixed-Content-Blockade). Für Verbindungen über das Netzwerk wss:// verwenden.
  • SwyxTray sollte nur auf 127.0.0.1 lauschen — sonst kann jeder im Netz Tabs öffnen, schließen und die Tab-Liste mitlesen.
  • Die Permission tabs ist nötig, um title und url der Tabs zu lesen.
S
Description
No description provided
Readme
67 KiB
Languages
JavaScript 42.8%
PowerShell 33.4%
Shell 19.5%
HTML 4.3%