# ctx-background-bridge **Repository Path**: elihe999/ctx-background-bridge ## Basic Information - **Project Name**: ctx-background-bridge - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-27 - **Last Updated**: 2026-10-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: Neo, tools ## README # Native Host Bridge > 浏览器扩展 ↔ Windows 本机能力 桥接工具。 > 提供三种接入方式: > > 1. **Chrome Native Messaging**(4 字节长度前缀 + JSON over stdin/stdout,每次调用拉起独立进程) > 2. **WebSocket 守护进程**(`ws://127.0.0.1:8765`,双向长连接,带可选签名认证信封) > 3. **HTTP 单向通道**(`POST http://127.0.0.1:8766/native`,仅 localhost 可访问) 三条通道共用同一套命令集:`PING`、`NOTIFICATION`(含多渠道转发)、`TENANTS_LIST`、`CONTENT_*`(Supabase raw_contents 增改查删 + 批量)、`SUGGEST_OBSERVATION_CREATE`(联想词观测)、`TRENDING_SNAPSHOT_CREATE`(热榜快照)等。同时附带一个 Tkinter GUI 管理端(注册扩展、启停守护、渠道配置、数据查询、测试)。 --- ## 功能速览 | 能力 | 说明 | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | 双运行模式 | 无参数 → Native Messaging 单次调用;`--daemon` → WebSocket + HTTP 守护常驻 | | Windows Toast | `NOTIFICATION` 弹出 Win10+ 系统通知,失败回退到终端打印 | | 通知多渠道转发 | 同一条 `NOTIFICATION` 同时投递:飞书机器人 / 企业微信群机器人 / SMTP 邮件(每个渠道可独立开关,见 GUI「设置」) | | Supabase 语义化命令 | 直连 Supabase 读写 `tenants` / `raw_contents` / `author_profiles` / `suggest_observation_*` / `trending_snapshots` 等表,作为外部导入服务的「备用直写通道」;完全独立于外部 HTTP 导入服务 | | GUI 管理端 | 扩展注册 / 监控面板(启停守护、日志流、健康探测)/ 设置(5 个子模块)/ 测试面板 / 数据查询 | | 配置双通道 | 优先读 `.env`(或 `NHB_ENV_FILE` 指定文件),为空时回退 `~/.native-host-bridge/settings.json`(GUI 设置持久化位置) | | 本地回环安全 | WS/HTTP 仅监听 `127.0.0.1`;可选 `NHB_WS_SECRET` 启用签名信封 + Nonce 防重放;.env 配 Supabase 时 GUI 自动隐藏对应设置项 | --- ## 数据表关系(ER 图) ctx-background-bridge 直连 Supabase 写入的「社交媒体数据抓取表」共 7 张,核心是 `raw_contents`(内容抓取)、`author_profiles`(由内容衍生的作者档案)、`suggest_observation_runs` / `suggest_keyword_observations`(联想词抓取)、`trending_snapshots`(热榜抓取);它们通过 `tenant_id` 统一归属租户,并通过 `parent_id` / `author_id` / `run_id` / `target_id` 串联。 ```mermaid erDiagram tenants ||--o{ raw_contents : "tenant_id" tenants ||--o{ author_profiles : "tenant_id" tenants ||--o{ suggest_observation_runs : "tenant_id" tenants ||--o{ trending_snapshots : "tenant_id" raw_contents ||--o{ raw_contents : "parent_id → source_id (同 platform:post→comments)" author_profiles ||--o{ raw_contents : "author_id (内容触发 upsert)" monitor_targets ||--o{ suggest_observation_runs : "target_id (可空/虚拟)" monitor_targets ||--o{ trending_snapshots : "target_id (可空)" suggest_observation_runs ||--o{ suggest_keyword_observations : "run_id" tenants { uuid id PK string name } raw_contents { uuid id PK uuid tenant_id FK string platform string content_type "post/comment/review/article/profile/other" text content string source_id UK "UNIQUE(platform,source_id)" string parent_id FK "→ raw_contents.source_id" string author_id FK "→ author_profiles" jsonb engagement "标准键归一 likes/comments/shares..." string import_batch_id "批次溯源/撤销" timestamptz time } author_profiles { uuid tenant_id PK FK string platform PK string author_id PK string author_name text bio int following_count int post_count string join_date string verified_reason } monitor_targets { uuid id PK uuid tenant_id FK string platform string type "external_suggest 等" } suggest_observation_runs { uuid run_id PK uuid tenant_id FK uuid target_id FK "可空/虚拟" string platform string seed_keyword string status "success/failed/login_required" timestamptz started_at timestamptz finished_at } suggest_keyword_observations { uuid run_id PK FK string keyword PK int rank boolean is_new boolean is_dropped } trending_snapshots { uuid id PK uuid tenant_id FK uuid target_id FK "可空 ON DELETE SET NULL" string platform string keyword int rank timestamptz snapshot_at } ``` 关系要点: - **自引用树**:`raw_contents.parent_id → raw_contents.source_id`(同一 `platform` 内),一条 `post` 挂多条 `comment`;评论缺父帖时 bridge 自动建占位父帖、真实正文后到再升级。 - **作者快照**:`raw_contents` 写入时若含 `author_id`,自动 upsert `author_profiles`(冲突键 `tenant_id+platform+author_id`),是「评论→用户画像」的落点。 - **联想词一对多**:`suggest_observation_runs` 1—N `suggest_keyword_observations`(冲突键 `run_id+keyword`),喂「消失/复苏预警」。 - **任务归属**:`target_id` 来自 `monitor_targets`,ctx 直写时通常可空或自动建虚拟目标(`type='external_suggest'`)。 - 所有表共享 `tenant_id`(取 `SELECT id FROM tenants LIMIT 1`);`raw_contents` 去重键 `UNIQUE(platform,source_id)`。 --- ## 目录结构 ``` ctx-background-bridge/ ├── main.go # Go 入口:-daemon 切换模式 ├── gui.py # 桌面 GUI 入口(另可运行 run_gui.py) ├── run_gui.py ├── build.bat # Windows 构建脚本 ├── requirements.txt # Python GUI 依赖 ├── .env.example # 环境变量示例 ├── protocol.md # 命令级协议(PING~TRENDING_SNAPSHOT 全套) ├── ws-integration.md # WebSocket / HTTP 通道接入指南 ├── IMPORT_ROADMAP.md # Supabase 导入能力演进路线(已落地 IMP-003 / QRY-001) ├── delivery/ # 架构文档(初始版本,功能演进见 README §已实现能力映射) ├── scripts/ │ ├── registrar.py # 命令行扩展注册工具(CLI 版) │ ├── install-host.ps1 # 一键安装:注册 manifest + 注册表 │ ├── uninstall-host.ps1 │ ├── start-server.ps1 # 启动 WS 守护 │ ├── stop-server.ps1 │ └── load-env.ps1 # powershell 加载 .env 注入环境 ├── internal/ │ ├── native/ # Native Messaging 核心:协议编解码 + HandleMessage 分发 │ ├── ws/ # WebSocket 守护 + /health + /native HTTP │ ├── auth/ # 认证信封 + Nonce 防重放 │ ├── bridge/ # Go 侧 bridge client(对外封装) │ ├── envfile/ # .env 加载(NHB_ENV_FILE → cwd → exe 目录) │ ├── supabase/ # Supabase 客户端(env 优先,settings.json 兜底) │ └── notify/ # 通知渠道:Toast / 飞书 / 企微 / SMTP + settings.json 读取 └── gui/ ├── app.py # GUI 主应用(Tab:监控 / 注册 / 测试 / 设置) ├── envfile.py # Python 版 .env 加载,与 Go 端行为一致 ├── settings_store.py # ~/.native-host-bridge/settings.json 读写 ├── theme.py # 主题(亮色 / 深色 + 配色 Token) ├── tab_monitor.py # 监控面板:启停守护、日志流、健康探测 ├── tab_registry.py # 扩展注册:增删改查 + 自动写注册表/manifest ├── tab_test.py # 测试面板:发 PING / NOTIFICATION 给本地 exe ├── tab_settings.py # 设置主 Tab:左侧导航、右侧子模块面板 ├── submodule_feishu.py # 飞书机器人 ├── submodule_wecom.py # 企业微信群机器人 ├── submodule_email.py # SMTP 邮件 ├── submodule_supabase.py # Supabase URL/Key(env 配好则 GUI 自动隐藏该页) └── submodule_query.py # 数据查询:TENANTS_LIST + CONTENT_LIST ``` --- ## 快速开始 ### 0. 前置 - Go 1.22+ - Python 3.10+(仅 GUI 管理端需要;Go 二进制自包含无 Python 依赖) - Windows 10+(通知 Toast / 注册表用) ### 1. 构建 Go 二进制 ```bat REM Windows build.bat ``` 产物:`native-host-bridge.exe` ### 2. 安装 Native Messaging Host(让 Chrome 能调用到 exe) ```powershell # 注册扩展(支持多个扩展 ID,会同时写 manifest 与 HKCU 注册表) python scripts/registrar.py add dbkjojfjeeaedgmcnjiknijjmgaonlnd python scripts/registrar.py status # 或一键 PowerShell 安装脚本 powershell -ExecutionPolicy Bypass -File scripts/install-host.ps1 ``` 也可以直接运行 GUI,在「扩展注册」Tab 图形化管理。 ### 3. (可选)启动 WebSocket 守护进程 三条通道**互相独立**,想接 WS/HTTP 才需要这步。 ```powershell # 直接启动 .\native-host-bridge.exe --daemon # 或 PowerShell 脚本 scripts\start-server.ps1 ``` 启动后可用健康检查验证: ```bash curl http://127.0.0.1:8766/health # {"ok":true} ``` ### 4. (可选)启动 GUI 管理端 ```bash pip install -r requirements.txt python gui.py ``` GUI 四个 Tab: | Tab | 作用 | | ---- | ------------------------------------------------------------------------------ | | 监控面板 | 一键启动 / 停止守护进程,实时抓取 stdout 日志,定时探测 `/health` 显示运行状态,编辑 `NHB_WS_SECRET` | | 扩展注册 | 增删 Chrome 扩展 ID,自动更新 manifest `path` + 写注册表(HKCU Chrome / Edge),一键「安装」「卸载」Host | | 测试 | 将自定义 JSON payload 发给 `native-host-bridge.exe` 单次执行(模拟 Chrome 调用),查看完整响应 | | 设置 | 子模块:飞书 / 企微 / SMTP 邮件 / Supabase(env 已配则隐藏)/ 数据查询 | --- ## 环境变量与配置优先级 配置分两层,**两层完全独立**:Go 守护进程 / Native Messaging 调用走 Go 版 `internal/envfile` + `internal/supabase/client.go` / `internal/notify/settings.go`;GUI 走 `gui/envfile.py` + `gui/settings_store.py`。两者的 `.env` 候选路径与优先级完全对齐。 ### .env 加载顺序 1. `NHB_ENV_FILE` 环境变量指定的绝对路径 2. 当前工作目录下的 `.env` 3. 可执行文件同级目录的 `.env` → `../.env` → `../../.env` **已存在的系统环境变量不会被 `.env` 覆盖**(与 `docker-compose` 默认行为一致)。 ### 可用环境变量 ```env # ============ WS 守护鉴权(可选)============ NHB_WS_SECRET=your-secret # 留空=关闭签名认证信封;生产建议设置 # ============ Supabase(可选,env 优先于 settings.json)============ SUPABASE_URL=https://xxx.supabase.co SUPABASE_KEY=eyJhbGc...(anon 或 service_role) # 注意:env 同时有 URL 和 KEY 时,GUI「设置」会自动隐藏「Supabase 数据库」页签, # 因为 Go 端会直接用 env,settings.json 段不再生效。 ``` ### settings.json 位置 ``` ~/.native-host-bridge/settings.json ``` 各渠道配置按 section 存储(`feishu` / `wecom` / `email` / `supabase`),字段名与 `internal/notify/settings.go` 中 `*Section` 结构体一一对应;GUI「设置」Tab 的保存 / 加载直接操作这份文件。 > **什么时候用 env?什么时候用 GUI 设置?** > > - 部署在固定机器、配置不常改 → 用 `.env`(稳定、一致,不受 GUI 操作影响) > - 需要在 GUI 里随时开关 / 改配置 / 点「测试连接」 → 用 settings.json(GUI 设置页直接写) > - **Supabase 例外**:env 一旦配好(URL+KEY 同时有值),GUI 自动隐藏该页,避免用户改了无效设置产生困惑。 > - 通知渠道(飞书/企微/SMTP)**不**自动隐藏——env 若也有对应变量(目前代码仅 GUI 设置 → settings.json 读写,未用 env 读通知渠道),两边一致即可;以后想加 env 通知渠道,只要在 `internal/notify/*` 的 `loadSection` 之前加 env 优先逻辑。 --- ## 支持的命令集 > 所有命令在 Native Messaging、WS 守护、HTTP `/native` **三条通道上的语义完全一致**——WS/HTTP 通道里直接调用 `native.HandleMessage` 统一分发。协议详情见 [`protocol.md`](protocol.md)。 ### 基础 | type | 说明 | | -------------- | -------------------------------------------------------------------------------------------------------- | | `PING` | 健康检查,返回 `PONG` + `received_at` + `host` | | `NOTIFICATION` | 弹 Windows Toast;并按 settings.json 启用状态 fan-out 到 飞书 / 企微 / SMTP(`notify.ForwardAll`,任一失败仅记日志不阻断) | | `TENANTS_LIST` | 查询 `tenants` 表:按名称模糊搜、status/plan 过滤、分页,`total` 从 `Content-Range` 解析 | ### raw_contents 增改查删(Supabase 直写) | type | 说明 | | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CONTENT_CREATE` | 写入单条;自动算 `content_hash=sha256(content)`;自动**归一互动指标键**(`点赞`/`reposts`/`播放` 等 → `likes`/`shares`/`views`…)+ 数字归一("1.2万"→12000);评论缺失父帖时**自动建占位父帖并在后续真实正文到达时升级**;去重 `UNIQUE(platform,source_id)`,`mode=skip\|upsert`;命中 `author_id` 自动 upsert `author_profiles` | | `CONTENT_CREATE_BATCH` | 批量写;自动父子关联(缺失 `parent_id` 的 comment 指向最近的非 comment 条 source_id);顶层 `import_batch_id` / `mode` 回填到未指定条目;顺序处理,单条失败不阻断,结果逐条 `index` 对应返回 | | `CONTENT_UPDATE` | `by: {source_id,platform}` 或 `by: {id}` 定位;`mode=merge`(默认,只改非 null 字段)/ `replace`;字段级时间 / 数字 / engagement 再归一;内容改动重算 hash;`created_at` / `fetch_time` 强制剔除(禁止覆盖) | | `CONTENT_LIST` | 多维筛选:platform/content_type/author_id/keyword/hashtag/ip_location/author_type/media_type/target_id/source_channel/time_from/time_to + sort/limit/page;`total` + `total_pages` 一并返回 | | `CONTENT_DELETE` | `ids[]` 批量删(上限 200)或 `by: {source_id,platform}` / `{id}` / `{import_batch_id}`;返回 `deleted` | ### 其它 Supabase 直写 | type | 说明 | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SUGGEST_OBSERVATION_CREATE` | 路线图 IMP-003:写 `suggest_observation_runs` + `suggest_keyword_observations`;`target_id` 缺省时按 `(tenant_id,platform,seed_keyword)` 自动匹配或建虚拟 `monitor_target` | | `TRENDING_SNAPSHOT_CREATE` | 热榜快照:批量 INSERT `trending_snapshots`;`target_id` 可选,FK `ON DELETE SET NULL` | ### 错误格式 未知 type / 参数不合法 → 返回 `{"type":"ERROR","error":"..."}`。所有业务命令(NOTIFICATION/TENANTS_LIST/CONTENT\_* 等)失败都包在自身响应里:`{"type":"<原type>","payload":{"ok":false,"error":"..."}}`,调用方不需要改错误解析代码。 --- ## 通知多渠道转发(NOTIFICATION fan-out) 接收到 `NOTIFICATION` 后,除了弹本地 Toast,还会在 `notify.ForwardAll` 里依次调用以下转发器,**任一失败仅记日志,不影响其它渠道和 Toast**: | 渠道 | 配置 section(settings.json) | GUI 子模块 | 关键校验 | | -------- | -------------------------------------------------------- | ------------- | ---------------------------------------------------------------------------- | | 飞书机器人 | `feishu`(enabled + webhook + keyword/sign_secret 可选) | 飞书通知 | 响应体 `StatusCode == 0` 才算成功 | | 企业微信群机器人 | `wecom`(enabled + webhook) | 企微通知 | 响应体 `errcode == 0` | | SMTP 邮件 | `email`(enabled + host/port/user/pass/from/to) | 邮件通知 | STARTTLS 默认开启 | 所有渠道的「测试连接」「保存配置」都在 GUI「设置」Tab 对应子模块里完成。 --- ## 安全要点(精简版) 完整设计见 `delivery/安全设计.md`,落地现状摘要: | 项 | 落地 | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | WS/HTTP 监听范围 | 仅 `127.0.0.1`,外部网卡不可达 | | HTTP `/native` 来源校验 | `RemoteAddr` 必须是 `127.0.0.1` 或 `::1` | | WS 信封签名(可选) | `NHB_WS_SECRET` 非空时启用;`sign = hex(sha256(payload_json + timestamp + nonce + secret))`;timestamp 偏移 >5min 拒绝;相同 nonce 拒绝(进程内存) | | 配置密钥存储 | .env(推荐) / settings.json 在用户目录,仅本用户可读写;GUI 中 API Key 用「密码输入框」(显示 `*`) | | Supabase service_role key | 仅本地工具持有;不注入浏览器扩展侧;生产建议走 env 而非 settings.json | | 扩展 origin 绑定 | Native Messaging manifest 里 `allowed_origins` 白名单;只有明确添加的扩展 ID 才能调用 exe | | 错误信息 | 不含栈、密钥片段;业务错误体尽量用 `message` 字段,不泄漏内部细节 | --- ## 已实现能力与架构文档的映射(供阅读 delivery/ 文档时参考) `delivery/` 下的高层架构 / 系统设计 / 部署设计 / 安全设计等是 G3/G4 评审时的初始版本,后续功能按路线图与实际需要迭代演进了,并不与文档 100% 对齐。下表是「交付文档表述 → 实际落地」的速查: | 交付文档点 | 实际落地(2026-08) | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | | 通知域仅 Windows Toast | 扩展为 Toast + 飞书/企微/SMTP fan-out(`internal/notify/*.go`),每渠道独立开关 + 独立 GUI 设置子模块 | | 配置域仅 .env | 扩展为 env + `~/.native-host-bridge/settings.json` 双通道;env 优先、settings.json 兜底;Supabase env 配好时 GUI 自动隐藏对应页 | | 桥接域仅 PING/NOTIFICATION | 扩展为:TENANTS_LIST、CONTENT_CREATE/BATCH/UPDATE/LIST/DELETE、SUGGEST_OBSERVATION_CREATE、TRENDING_SNAPSHOT_CREATE 共 8+ Supabase 直写语义化命令 | | 无 GUI 描述 | 新增 Tkinter GUI(监控/注册/测试/设置四大 Tab + 5 设置子模块 + 数据查询);入口 `gui.py` / `run_gui.py` | | 扩展注册仅 CLI(registrar.py / install-host.ps1) | GUI「扩展注册」Tab 增删改查 + 自动写注册表/manifest | | 无「直连 Supabase 作为导入备份通道」 | 已实现:所有 CONTENT\_* / SUGGEST / TRENDING 命令直连 Supabase(`internal/supabase/client.go` + `internal/native/host.go` handle* 系列) | | 联想词观测仅爬虫写两张表(路线图坑 IMP-003) | 已补 SUGGEST_OBSERVATION_CREATE 语义化命令,ctx 插件可经 native messaging / WS 直接写入 | | 查询能力薄弱(路线图 QRY-001) | 已补 CONTENT_LIST + TENANTS_LIST + GUI「数据查询」子模块前端操作界面 | `delivery/` 下文档保留做历史存档;事实来源以本 README、`protocol.md`、`ws-integration.md`、`IMPORT_ROADMAP.md` 与源代码为准。 --- ## 测试 ```bash # Go 全量测试(协议、Supabase 归一化、envfile、认证信封等) go test ./... # Python GUI 语法静态校验 python -m py_compile gui/app.py gui/tab_settings.py gui/submodule_supabase.py ``` --- ## 常见问题 **Q1. 扩展报错「找不到 Native Messaging Host」?** A:运行 `python scripts/registrar.py status` 检查;通常是注册表路径下的 `(Default)` 值没有正确指到 manifest,或 manifest 里的 `path` 不是 exe 绝对路径。GUI「扩展注册」Tab 点「安装 Host」能一键重建。 **Q2. GUI 设置里没有 Supabase 页?** A:说明已经通过 `.env` 或系统环境变量配置了 `SUPABASE_URL` + `SUPABASE_KEY`,代码会直接走 env,设置页的配置不会生效,所以 GUI 自动隐藏。想在 GUI 里改,把 env 中这两个变量移除(或注释掉 `.env` 那两行)重启 GUI 就会出现。 **Q3. WS 通道不想开认证?** A:不设置 `NHB_WS_SECRET` 即可(只监听 127.0.0.1,默认本机安全);部署到多用户共用机器建议设置密钥。 **Q4. Native Messaging 与 WS 守护能否同时用?** A:完全独立。扩展用 chrome.native 直接调 exe(每条消息一个进程);第三方工具连 WS/HTTP(长连接,进程常驻),两条链路彼此不共享状态不冲突。