baa-conductor

git clone 

commit
ef2db49
parent
9c76407
author
im_wower
date
2026-03-23 00:51:42 +0800 CST
fix(firefox): default to local mini endpoints
8 files changed,  +95, -51
M docs/api/firefox-local-ws.md
+6, -6
 1@@ -14,7 +14,7 @@ WS 地址直接由 `BAA_CONDUCTOR_LOCAL_API` 派生,不单独引入新的环
 2 
 3 例子:
 4 
 5-- `BAA_CONDUCTOR_LOCAL_API=http://127.0.0.1:4317` -> `ws://127.0.0.1:4317/ws/firefox`
 6+- `BAA_CONDUCTOR_LOCAL_API=http://100.71.210.78:4317` -> `ws://100.71.210.78:4317/ws/firefox`
 7 - `BAA_CONDUCTOR_LOCAL_API=http://100.71.210.78:4317` -> `ws://100.71.210.78:4317/ws/firefox`
 8 
 9 约束:
10@@ -75,8 +75,8 @@ WS 地址直接由 `BAA_CONDUCTOR_LOCAL_API` 派生,不单独引入新的环
11   "clientId": "firefox-ab12cd",
12   "protocol": "baa.firefox.local",
13   "version": 1,
14-  "wsUrl": "ws://127.0.0.1:4317/ws/firefox",
15-  "localApiBase": "http://127.0.0.1:4317",
16+  "wsUrl": "ws://100.71.210.78:4317/ws/firefox",
17+  "localApiBase": "http://100.71.210.78:4317",
18   "supports": {
19     "inbound": ["hello", "state_request", "action_request", "credentials", "api_endpoints", "client_log"],
20     "outbound": ["hello_ack", "state_snapshot", "action_result", "request_credentials", "error"]
21@@ -94,9 +94,9 @@ WS 地址直接由 `BAA_CONDUCTOR_LOCAL_API` 派生,不单独引入新的环
22     "version": 1,
23     "server": {
24       "identity": "mini-main@mini(primary)",
25-      "local_api_base": "http://127.0.0.1:4317",
26+      "local_api_base": "http://100.71.210.78:4317",
27       "ws_path": "/ws/firefox",
28-      "ws_url": "ws://127.0.0.1:4317/ws/firefox"
29+      "ws_url": "ws://100.71.210.78:4317/ws/firefox"
30     },
31     "system": {
32       "mode": "running",
33@@ -188,7 +188,7 @@ server 行为:
34 ## 最小 smoke
35 
36 ```bash
37-LOCAL_API_BASE="${BAA_CONDUCTOR_LOCAL_API:-http://127.0.0.1:4317}"
38+LOCAL_API_BASE="${BAA_CONDUCTOR_LOCAL_API:-http://100.71.210.78:4317}"
39 WS_URL="$(node --input-type=module -e 'const u = new URL(process.argv[1]); u.protocol = u.protocol === \"https:\" ? \"wss:\" : \"ws:\"; u.pathname = \"/ws/firefox\"; u.search = \"\"; u.hash = \"\"; console.log(u.toString());' "$LOCAL_API_BASE")"
40 
41 WS_URL="$WS_URL" node --input-type=module <<'EOF'
M docs/firefox/README.md
+7, -7
 1@@ -8,20 +8,20 @@
 2 
 3 ## 当前固定入口
 4 
 5-- Local WS bridge: `ws://127.0.0.1:4317/ws/firefox`
 6-- Public HTTP host: `https://conductor.makefile.so`
 7+- Local WS bridge: `ws://100.71.210.78:4317/ws/firefox`
 8+- Local HTTP host: `http://100.71.210.78:4317`
 9 
10 当前插件默认同时使用这两条链路:
11 
12 - 本地 WS:负责 Firefox bridge 握手、浏览器元数据同步、服务端快照展示
13-- 公网 HTTP:负责控制面状态同步,以及 `pause` / `resume` / `drain` 写入
14+- 本地 HTTP:负责控制面状态同步,以及 `pause` / `resume` / `drain` 写入
15 
16 不再允许在插件管理页中手工编辑地址。
17 
18 ## 目标
19 
20 - 让 Firefox 插件自动接入 `mini` 本地 `/ws/firefox`
21-- 保留 `conductor.makefile.so` 上的 HTTP 状态同步
22+- 保留 `mini` 本地 HTTP 状态同步
23 - 把管理页收口成 WS 状态、HTTP 状态、控制按钮
24 - 在本地服务重启或公网 HTTP 短暂失败后自动恢复
25 
26@@ -34,7 +34,7 @@
27 ## 启动行为
28 
29 - Firefox 启动时,`background.js` 会确保 `controller.html` 存在。
30-- `controller.html` 启动后立刻连接 `ws://127.0.0.1:4317/ws/firefox`。
31+- `controller.html` 启动后立刻连接 `ws://100.71.210.78:4317/ws/firefox`。
32 - WS 断开后按固定间隔自动重连;本地服务恢复后连接会自动恢复。
33 - `controller.html` 启动后也会立刻请求 `GET /v1/system/state`。
34 - HTTP 成功后按 `15` 秒周期继续同步。
35@@ -45,7 +45,7 @@
36 当前管理页只保留:
37 
38 - 本地 WS 状态卡片
39-- 公网 HTTP 状态卡片
40+- 本地 HTTP 状态卡片
41 - `暂停` / `恢复` / `排空` 按钮
42 - `WS 状态` 原始详情面板
43 - `HTTP 状态` 原始详情面板
44@@ -132,7 +132,7 @@
45 2. 确认 `controller.html` 自动打开。
46 3. 确认 `本地 WS` 最终显示 `已连接`。
47 4. 在 `WS 状态` 面板中确认:
48-   - `wsUrl` 是 `ws://127.0.0.1:4317/ws/firefox`
49+   - `wsUrl` 是 `ws://100.71.210.78:4317/ws/firefox`
50    - 有最近一次 `state_snapshot`
51 
52 ### 2. 验证断线重连
M plugins/baa-firefox/README.md
+7, -7
 1@@ -4,13 +4,13 @@
 2 
 3 ## 当前默认连接
 4 
 5-- 本地 WS bridge:`ws://127.0.0.1:4317/ws/firefox`
 6-- 公网 HTTP 入口:`https://conductor.makefile.so`
 7+- 本地 WS bridge:`ws://100.71.210.78:4317/ws/firefox`
 8+- 本地 HTTP 入口:`http://100.71.210.78:4317`
 9 
10 管理页已经收口为两块状态和三颗控制按钮:
11 
12 - 本地 WS 状态
13-- 公网 HTTP 状态
14+- 本地 HTTP 状态
15 - `Pause` / `Resume` / `Drain`
16 
17 不再允许用户手工编辑地址。
18@@ -19,7 +19,7 @@
19 
20 - keeps an always-open `controller.html`
21 - auto-connects the local Firefox bridge WS on startup
22-- keeps polling `conductor.makefile.so` over public HTTP with retry/backoff
23+- keeps polling the local conductor HTTP surface with retry/backoff
24 - sends `hello` / `credentials` / `api_endpoints` metadata to the local WS bridge
25 - lets the operator trigger `pause` / `resume` / `drain`
26 
27@@ -45,10 +45,10 @@
28 ## How To Run
29 
30 1. Load this extension temporarily.
31-2. Make sure local `conductor-daemon` is listening on `http://127.0.0.1:4317`.
32+2. Make sure local `conductor-daemon` is listening on `http://100.71.210.78:4317`.
33 3. Open `controller.html` and confirm:
34    - `本地 WS` becomes `已连接`
35-   - `公网 HTTP` reaches `已连接` or enters visible auto-retry
36+   - `本地 HTTP` reaches `已连接` or enters visible auto-retry
37 4. Click `暂停` / `恢复` / `排空` as needed.
38 5. Open Claude, ChatGPT, or Gemini normally if you want the browser bridge to report credentials and endpoints.
39 
40@@ -56,7 +56,7 @@
41 
42 - WS connect: controller page shows `本地 WS = 已连接`
43 - WS reconnect: stop local daemon and restart it; controller page should move to retrying and then recover automatically
44-- HTTP sync: `公网 HTTP` should keep refreshing every `15` seconds
45+- HTTP sync: `本地 HTTP` should keep refreshing every `15` seconds
46 - Control buttons: after clicking `暂停` / `恢复` / `排空`, the HTTP state should reflect the new mode
47 
48 ## Limitations
M plugins/baa-firefox/background.js
+57, -15
  1@@ -23,25 +23,65 @@ async function getStoredControllerTabId() {
  2   return data[STORAGE_KEY] || null;
  3 }
  4 
  5-async function queryControllerTab() {
  6+async function queryControllerTabs() {
  7   const tabs = await browser.tabs.query({ url: CONTROLLER_URL });
  8+  return [...tabs].sort((left, right) => {
  9+    const leftId = Number.isInteger(left.id) ? left.id : Number.MAX_SAFE_INTEGER;
 10+    const rightId = Number.isInteger(right.id) ? right.id : Number.MAX_SAFE_INTEGER;
 11+    return leftId - rightId;
 12+  });
 13+}
 14+
 15+function pickCanonicalControllerTab(tabs, preferredTabId = null) {
 16+  if (!Array.isArray(tabs) || tabs.length === 0) {
 17+    return null;
 18+  }
 19+
 20+  if (Number.isInteger(preferredTabId)) {
 21+    const preferred = tabs.find((tab) => tab.id === preferredTabId);
 22+    if (preferred) return preferred;
 23+  }
 24+
 25   return tabs[0] || null;
 26 }
 27 
 28+async function closeDuplicateControllerTabs(tabs, canonicalTabId) {
 29+  const duplicateIds = tabs
 30+    .map((tab) => tab.id)
 31+    .filter((tabId) => Number.isInteger(tabId) && tabId !== canonicalTabId);
 32+
 33+  if (duplicateIds.length === 0) {
 34+    return;
 35+  }
 36+
 37+  await browser.tabs.remove(duplicateIds);
 38+}
 39+
 40+async function resolveControllerTab(preferredTabId = null) {
 41+  const tabs = await queryControllerTabs();
 42+  if (tabs.length === 0) {
 43+    return null;
 44+  }
 45+
 46+  const storedId = await getStoredControllerTabId();
 47+  const canonicalTab = pickCanonicalControllerTab(
 48+    tabs,
 49+    Number.isInteger(storedId) ? storedId : preferredTabId
 50+  );
 51+
 52+  if (!canonicalTab || !Number.isInteger(canonicalTab.id)) {
 53+    return null;
 54+  }
 55+
 56+  await closeDuplicateControllerTabs(tabs, canonicalTab.id);
 57+  await setControllerTabId(canonicalTab.id);
 58+  return canonicalTab;
 59+}
 60+
 61 async function ensureControllerTab(options = {}) {
 62   const { activate = false } = options;
 63 
 64-  let tab = await queryControllerTab();
 65-  if (!tab) {
 66-    const storedId = await getStoredControllerTabId();
 67-    if (storedId) {
 68-      try {
 69-        tab = await browser.tabs.get(storedId);
 70-      } catch (_) {
 71-        tab = null;
 72-      }
 73-    }
 74-  }
 75+  let tab = await resolveControllerTab();
 76 
 77   if (tab) {
 78     await setControllerTabId(tab.id);
 79@@ -58,8 +98,7 @@ async function ensureControllerTab(options = {}) {
 80     url: CONTROLLER_URL,
 81     active: activate
 82   });
 83-  await setControllerTabId(created.id);
 84-  return created;
 85+  return await resolveControllerTab(created.id);
 86 }
 87 
 88 function normalizeMode(value) {
 89@@ -150,7 +189,10 @@ browser.runtime.onMessage.addListener((message) => {
 90   if (!message || typeof message !== "object") return undefined;
 91 
 92   if (message.type === "controller_ready" && Number.isInteger(message.tabId)) {
 93-    return setControllerTabId(message.tabId).then(() => ({ ok: true }));
 94+    return resolveControllerTab(message.tabId).then((tab) => ({
 95+      ok: true,
 96+      tabId: tab?.id ?? null
 97+    }));
 98   }
 99 
100   if (message.type === "focus_controller") {
M plugins/baa-firefox/controller.html
+3, -3
 1@@ -11,8 +11,8 @@
 2     <section class="topbar">
 3       <div>
 4         <p class="eyebrow">BAA Firefox 控制台</p>
 5-        <h1>本地 WS / 公网 HTTP</h1>
 6-        <p class="meta">本地 bridge 自动连接 mini,公网入口固定走 <code>https://conductor.makefile.so</code>。</p>
 7+        <h1>本地 WS / 本地 HTTP</h1>
 8+        <p class="meta">本地 bridge 自动连接 mini,本地控制面固定走 <code>http://100.71.210.78:4317</code>。</p>
 9       </div>
10     </section>
11 
12@@ -30,7 +30,7 @@
13       </article>
14 
15       <article class="card">
16-        <p class="label">公网 HTTP</p>
17+        <p class="label">本地 HTTP</p>
18         <p id="control-mode" class="value off">连接中</p>
19         <p id="control-meta" class="meta">等待同步</p>
20       </article>
M plugins/baa-firefox/controller.js
+3, -3
 1@@ -20,9 +20,9 @@ const CONTROLLER_STORAGE_KEYS = {
 2   geminiSendTemplate: "baaFirefox.geminiSendTemplate"
 3 };
 4 
 5-const DEFAULT_LOCAL_API_BASE = "http://127.0.0.1:4317";
 6-const DEFAULT_WS_URL = "ws://127.0.0.1:4317/ws/firefox";
 7-const DEFAULT_CONTROL_BASE_URL = "https://conductor.makefile.so";
 8+const DEFAULT_LOCAL_API_BASE = "http://100.71.210.78:4317";
 9+const DEFAULT_WS_URL = "ws://100.71.210.78:4317/ws/firefox";
10+const DEFAULT_CONTROL_BASE_URL = "http://100.71.210.78:4317";
11 const STATUS_SCHEMA_VERSION = 3;
12 const CREDENTIAL_SEND_INTERVAL = 30_000;
13 const CREDENTIAL_TTL = 15 * 60_000;
M plugins/baa-firefox/docs/conductor-control.md
+8, -8
 1@@ -2,13 +2,13 @@
 2 
 3 `baa-firefox` 现在默认同时接两条固定链路:
 4 
 5-- 本地 WS bridge:`ws://127.0.0.1:4317/ws/firefox`
 6-- 公网 HTTP 入口:`https://conductor.makefile.so`
 7+- 本地 WS bridge:`ws://100.71.210.78:4317/ws/firefox`
 8+- 本地 HTTP 入口:`http://100.71.210.78:4317`
 9 
10 管理页已经收口,只保留:
11 
12 - 本地 WS 状态
13-- 公网 HTTP 状态
14+- 本地 HTTP 状态
15 - `Pause` / `Resume` / `Drain` 按钮
16 
17 不再允许用户手工编辑 WS 地址或 HTTP 地址。
18@@ -28,8 +28,8 @@
19 
20 ## 固定地址
21 
22-- Local WS: `ws://127.0.0.1:4317/ws/firefox`
23-- Public HTTP: `https://conductor.makefile.so`
24+- Local WS: `ws://100.71.210.78:4317/ws/firefox`
25+- Local HTTP: `http://100.71.210.78:4317`
26 
27 当前实现不再从 UI 或 storage 读取用户自定义地址;旧配置会被固定地址覆盖。
28 
29@@ -63,7 +63,7 @@
30 
31 ## HTTP 侧职责
32 
33-公网 HTTP 仍然是管理页里控制状态的同步来源,也是控制按钮的写入通道。
34+本地 HTTP 是管理页里控制状态的同步来源,也是控制按钮的写入通道。
35 
36 读取:
37 
38@@ -91,7 +91,7 @@
39 - WS 卡片:连接状态、最近快照、最近错误
40 - HTTP 卡片:连接状态、当前 mode、最近成功/失败、下次重试
41 - WS 详情:本地 bridge 的原始状态摘要
42-- HTTP 详情:`conductor.makefile.so` 的原始状态摘要
43+- HTTP 详情:本地 `conductor-daemon` 的原始状态摘要
44 
45 不再展示:
46 
47@@ -105,6 +105,6 @@
48 1. 安装插件并启动 Firefox,确认 `controller.html` 自动打开。
49 2. 打开管理页,确认:
50    - `本地 WS` 最终变成 `已连接`
51-   - `公网 HTTP` 能显示 `已连接` 或自动重试中的明确状态
52+   - `本地 HTTP` 能显示 `已连接` 或自动重试中的明确状态
53 3. 停掉本地 `conductor-daemon`,确认 WS 状态进入重连中;恢复服务后确认自动回到 `已连接`。
54 4. 点击 `暂停` / `恢复` / `排空`,确认 HTTP 状态会更新 mode,且服务端状态与按钮动作一致。
M plugins/baa-firefox/manifest.json
+4, -2
 1@@ -23,10 +23,12 @@
 2     "https://gemini.google.com/*",
 3     "https://conductor.makefile.so/*",
 4     "http://127.0.0.1/*",
 5-    "ws://127.0.0.1/*"
 6+    "ws://127.0.0.1/*",
 7+    "http://100.71.210.78/*",
 8+    "ws://100.71.210.78/*"
 9   ],
10   "content_security_policy": {
11-    "extension_pages": "default-src 'self'; connect-src https://conductor.makefile.so ws://127.0.0.1:4317 http://127.0.0.1:4317"
12+    "extension_pages": "default-src 'self'; connect-src https://conductor.makefile.so ws://127.0.0.1:4317 http://127.0.0.1:4317 ws://100.71.210.78:4317 http://100.71.210.78:4317"
13   },
14   "background": {
15     "scripts": [