leadsradar-agent 1.0.2 → 1.0.4

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.
package/README.md CHANGED
@@ -37,13 +37,13 @@ Chrome 探栗插件(数据全部在本机浏览器内采集)
37
37
 
38
38
  每个技能是一个 `SKILL.md`,装进宿主的技能/指令库即生效:
39
39
 
40
- | 技能 | 一句话 | 状态 |
41
- |---|---|---|
42
- | **[情报栗](skills/leadsradar-radar/)** | 发作品/账号/关键词「探一下」——现采现报:客户线索、赛道机会、对标巡逻 | ✅ 可用 |
43
- | **[洞察栗](skills/leadsradar-insights/)** | 拆解爆款为什么爆、查历史研究报告并解读成人话 | ✅ 可用 |
44
- | **[创作栗](skills/leadsradar-creator/)** | 发作品说一句话——存选题、下无水印素材、提文案 | ✅ 可用 |
45
- | **[成交栗](skills/leadsradar-closer/)** | 从评论区挖客户——意向分级、跟进名单、可直接发的回复话术 | ✅ 可用 |
46
- | **[管家栗](skills/leadsradar-helper/)** | 「栗子在吗」的应答前台——查连接登录、报库存、答教程 | ✅ 可用 |
40
+ | | 技能 | 一句话 | 状态 |
41
+ |---|---|---|---|
42
+ | <img src="assets/chestnut-3.webp" width="44" alt="情报栗" /> | **[情报栗](skills/leadsradar-radar/)** | 发作品/账号/关键词「探一下」——现采现报:客户线索、赛道机会、对标巡逻 | ✅ 可用 |
43
+ | <img src="assets/chestnut-1.webp" width="44" alt="洞察栗" /> | **[洞察栗](skills/leadsradar-insights/)** | 拆解爆款为什么爆、查历史研究报告并解读成人话 | ✅ 可用 |
44
+ | <img src="assets/chestnut-6.webp" width="44" alt="创作栗" /> | **[创作栗](skills/leadsradar-creator/)** | 发作品说一句话——存选题、下无水印素材、提文案 | ✅ 可用 |
45
+ | <img src="assets/chestnut-7.webp" width="44" alt="成交栗" /> | **[成交栗](skills/leadsradar-closer/)** | 从评论区挖客户——意向分级、跟进名单、可直接发的回复话术 | ✅ 可用 |
46
+ | <img src="assets/chestnut-4.webp" width="44" alt="管家栗" /> | **[管家栗](skills/leadsradar-helper/)** | 「栗子在吗」的应答前台——查连接登录、报库存、答教程 | ✅ 可用 |
47
47
 
48
48
  状态说明:五技能全量可用(⭐R53 四大数字员工重组:随手调研+对标巡逻合并为情报栗、数据问答升级洞察栗、素材管家更名创作栗、成交栗/管家栗新建)——洞察栗支持查本地缓存的四类 AI 研究报告(作品拆解/账号研究/赛道研究/账号复盘,附 web 直达链接);监控/档案/日报类查询通道开发中,上线后技能自动点亮。
49
49
 
package/README_en.md CHANGED
@@ -32,13 +32,13 @@ Your phone (lead report / patrol digest / topic card)
32
32
 
33
33
  Each skill is a `SKILL.md` you drop into your host's skill/instruction library:
34
34
 
35
- | Skill | One-liner | Status |
36
- |---|---|---|
37
- | **[Radar · Intel Chestnut](skills/leadsradar-radar/)** | Send a link / keyword + "tan yi xia" — instant lead reports, niche opportunities & benchmark patrol | ✅ |
38
- | **[Insights Chestnut](skills/leadsradar-insights/)** | Break down why a post went viral; look up & translate past research reports | ✅ |
39
- | **[Creator Chestnut](skills/leadsradar-creator/)** | Send a post link + one sentence — save topic, download media, extract copy | ✅ |
40
- | **[Closer Chestnut](skills/leadsradar-closer/)** | Mine customers from comments — intent grading, follow-up lists, ready-to-send replies | ✅ |
41
- | **[Helper Chestnut](skills/leadsradar-helper/)** | Front desk for the "Lizi" wake word — check connection/login, report inventory, answer FAQs | ✅ |
35
+ | | Skill | One-liner | Status |
36
+ |---|---|---|---|
37
+ | <img src="assets/chestnut-3.webp" width="44" alt="Radar" /> | **[Radar · Intel Chestnut](skills/leadsradar-radar/)** | Send a link / keyword + "tan yi xia" — instant lead reports, niche opportunities & benchmark patrol | ✅ |
38
+ | <img src="assets/chestnut-1.webp" width="44" alt="Insights" /> | **[Insights Chestnut](skills/leadsradar-insights/)** | Break down why a post went viral; look up & translate past research reports | ✅ |
39
+ | <img src="assets/chestnut-6.webp" width="44" alt="Creator" /> | **[Creator Chestnut](skills/leadsradar-creator/)** | Send a post link + one sentence — save topic, download media, extract copy | ✅ |
40
+ | <img src="assets/chestnut-7.webp" width="44" alt="Closer" /> | **[Closer Chestnut](skills/leadsradar-closer/)** | Mine customers from comments — intent grading, follow-up lists, ready-to-send replies | ✅ |
41
+ | <img src="assets/chestnut-4.webp" width="44" alt="Helper" /> | **[Helper Chestnut](skills/leadsradar-helper/)** | Front desk for the "Lizi" wake word — check connection/login, report inventory, answer FAQs | ✅ |
42
42
 
43
43
  **Wake words**: address your AI with **"Lizi"(栗子)** (e.g. "栗子,存一下这个选题 / Lizi, save this topic") or start with **"探一下 / tan yi xia"** (e.g. "探一下:家装获客这个词还有机会吗") to invoke the skills — "探栗 / LeadsRadar" also works; clear intent triggers them even without a wake word.
44
44
 
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -50,12 +50,16 @@ const SKILLS_LATEST = {
50
50
  insights: "2.2.0",
51
51
  creator: "1.2.0",
52
52
  closer: "1.3.0", // ⭐R78 栗子触达精准触发词查漏
53
- helper: "1.3.2", // ⭐R79 报到表格渲染 adapter.update 三态+FAQ 技能更新改 get_latest_skills 递内容(1.3.1=触达路由+设置/学习 FAQ)
53
+ helper: "1.3.4", // ⭐R89b 报到菜单改指令式(指令=教程=功能说明三合一:指令永远展示、说明进括号——用户拍板「我的指令就是教程就是指令,指令就是功能说明」,菜单从描述式「发链接/关键词『探一下』——现采现报…」改为指令句式「探一下 <作品链接/账号链接/平台+关键词>(评论捞客户线索…)」;其余展示位盘点已合规:options 技能卡 demos/WELCOME_FIXED_COPY/五节路由表均早已指令式)(1.3.2=⭐R79 报到表格渲染 adapter.update 三态+FAQ 技能更新改 get_latest_skills 递内容;1.3.1=触达路由+设置/学习 FAQ)→ 1.3.4=⭐R92 菜单行首 emoji 换真头像 markdown 图(本机 /chestnut/ 静态路由)
54
54
  };
55
55
  // ⭐R79b 插件商店最新版:插件发版时同步 bump(与 SKILLS_LATEST 同一维护纪律)——管家栗对照
56
56
  // extension.extensionVersion 落后时提醒用户手动提速更新(商店自动更为主)
57
57
  const PLUGIN_LATEST = "1.0.0";
58
- const ADAPTER_VERSION = "1.2.22"; // ⭐R79 1.2.21→1.2.22:①适配器自更新——启动后台异步查云端最新 mjs(npmmirror→unpkg 双源 fallback),提取其中 ADAPTER_VERSION 比对,更新则 tmp+rename 原子覆盖自己(本地文件型宿主覆盖下载目录 mjs、npx 型覆盖 _npx 缓存内的自己,下次进程启动即新版;失败静默保持旧版、只升不降、24h 节流);②connection_status 的 adapter.update 透出自更新三态(checking/up-to-date/updated-pending-restart)——升级挂「栗子在吗」常径不设专门触发词,宿主报到表格渲染「已自动升级,重启宿主生效」;③新工具 leadsradar_get_latest_skills(12→13 工具版判据):技能落后时宿主取最新 SKILL.md 全文递给用户粘贴(技能库装在宿主手里无法代写)。云端生效前提=npm 发版 leadsradar-agent(自更新与技能下载的同一源头) ⭐R76 1.2.20→1.2.21:①connection_status 附 skills_latest 五技能版本表(识别技能落后+指路更新——宿主技能版本不可自动更,Agent 对照自检指路);②R74/R75 期间加的工具(add_monitor/pair_login/get_daily_report,10→12)未 bump 版本号,复测无法分辨 mjs 新旧,一并 bump(v1.2.21=12 工具版判据) ⭐R56b 1.2.19→1.2.20:卫星登录态透传四处(中转宿主 loggedIn 恒 null 根修)+中转连接文案说人话(去宿主名硬编码黑话) ⭐msg11 1.2.18→1.2.19:AI 唤醒探栗 MCP——connection_status(「栗子在吗」探活指令)时 TL MCP 未运行则自动拉起(读 NM 注册表拿 exe 路径,detached spawn;只在交互信号点拉,不在 agent 启动时拉以尊重「托盘退出」;未装静默缓存跳过) ⭐B7b-P1 1.2.17→1.2.18:结果认领闭环(三原则 b 协议化——插件是结果的持有者与通知源,宿主是可断线重来的消费者):①extension.hello 附未领取结果摘要 pendingResults[{taskId,mode,keyword,url,createdAt}](connection_status 的 extension.pendingResults 透出,AI 开工前即知有存货);②新 MCP 工具 leadsradar_claim_pending_result(领取插件侧已完成但无人认领的任务结果——超时/宿主重启后回来领,不占采集限额;走普通任务通道 mode=claim_pending_result,卫星模式自动兼容);③device.extension.state 卫星透传摘要;④step=3 hint 有存货时提示「先领取再决定重发」(配合 1.2.17 的超时文案,AI 标准动作=超时→领取→查库→才重发,根除额度双耗);⭐1.2.16→1.2.17:HTTP 模式默认端口 17374→17375(撞车根修:17374 是本地服务 Rust IPC 的 NDJSON 端口,agent HTTP 监听同端口时扣子等 HTTP 宿主把请求头打到 Rust → service.log 刷 bad json;改 17375 后两端口各归其主,已按 17374 配 URL 的宿主需改指 17375,可用 LEADSRADAR_AGENT_HTTP_PORT 覆盖)+ B3 断开原因钩子(插件断开的 close frame code+reason 不再丢弃:disconnectDiagnosis() 区分「开关关/桥不可用/浏览器被杀或插件被禁」给精准指引——旧版一律报「start chrome」实测无效指引;插件侧 reason 真源 local-agent-connector.ts stop()="LF Agent disabled"/stopForAvailability()="…not publicly available",SW 被杀无告别帧=1006;卫星经 device.extension.state 同步诊断);⭐A2/B7/B9 1.2.15→1.2.16:撞墙自修三连——①任务中断秒失败(插件断开即中止全部等待任务 TASK_ABORTED,旧版傻等 300s 超时,2026-10-16 杀浏览器实测抓到);②撞墙文案自动探测插件所在浏览器+profile(扫 Chrome/Edge 各 profile 的 Preferences 找 unpacked 探栗 path,给出精确 start 命令——旧版「start chrome 开默认 profile、插件装在 Profile 1 → 桥永远不起」实测 bug);③extension.account.update 登录态保鲜(解绑/登出实时同步,旧版冻结在握手值「解绑了仍显示已登录」实测);⭐r96ze 1.2.14→1.2.15:卫星状态谎报根修(用户实报「未批准的 dsh 显示已连接可以开工」)——statusSnapshot 卫星分支旧逻辑借中转通道状态(主 Broker 与插件的连接)冒充自身就绪,未批准卫星恒报 step=3;新逻辑 selfPaired 标志(收到 purpose="session" 挑战=已配对、pairing=失效回退,SW 挑战类型即配对态真值),step 判定通道死→1/未配对→2/配对+通道→3,step=2 hint 明示「批准前任务会被拒绝别急着开工」(任务层本有 PAIRING_REQUIRED 门禁无越权,仅状态误导);⭐r96y 1.2.13→1.2.14:欢迎文案 v2(「探一下」品牌动词融入全部示例,示例即激活词教学;删「不用记命令」与能力清单黑话)+ 对外文案 9 处旧菜单名「智能体接管」→「智能体连接」(r96r-5 改名时适配器侧漏网:hint/错误 message/description/log,宿主 AI 按旧名指路用户找不到菜单);⭐r96t 1.2.12→1.2.13:HOST_LABELS 删 stepfun=「阶跃 AI」(渠道下线:用户拍板排除——自定义 MCP 入口未确认开放+用户量知名度低);⭐r96g 1.2.11→1.2.12:HOST_LABELS 补 cherry=「Cherry Studio」/stepfun=「阶跃 AI」(CLI·进阶档扩容:codex 回归+cherry+stepfun,dsh 并入该档);⭐r96e 1.2.10→1.2.11:HOST_LABELS 补 trae=「Trae」(Trae/编程 CLI 宿主:项目 .trae/mcp.json 配置拉起,本仓 dogfooding 实测);⭐r96 1.2.10:HOST_LABELS 补 qwen-office=「千问办公」;⭐r93 1.2.9:dsh=「DeepSeek」;⭐r90c 1.2.8:HTTP 模式;⭐r86c 1.2.7:kimi-work;⭐r85b 1.2.6:doubao/feishu 多客户端各自 HOST;⭐r85 1.2.5:Windows 动态端口自愈;⭐r82 1.2.4:initialize 注入呈现规范;⭐r81 1.2.3:登录态;⭐r77c 1.2.1:密钥迁用户目录;⭐r76 1.2.0:多宿主中转
58
+ const ADAPTER_VERSION = "1.2.24"; /* ⭐R92b 1.2.23→1.2.24:EADDRINUSE 崩进程根修——R92 tryListen 重构成
59
+ ws({server:httpSrv}) 同端口复用时把 EADDRINUSE handler 误挂 httpSrv,而 ws 库会把底层 server 的 error 冒泡转发到
60
+ WebSocketServer 实例 emit(转发 listener 构造时先注册,wss 零 listener 同步 throw 崩进程,httpSrv 上后注册的 handler
61
+ 执行不到)——任何 17373 被占场景新实例必崩(WorkBuddy 实报 MCP -32000 Connection closed),修=handler 挂回 wss +
62
+ httpSrv 留兜底日志。 ⭐R89 1.2.22→1.2.23:卫星模式等待插件话术补探测链(⭐2026-10-23 用户实报「刚开机测栗子在吗没自动连上」,WorkBuddy 卫星只泛泛说「去浏览器确认插件启用+开关打开」——根因=卫星分支 step=1 hint 是写死文案,没接主 Broker 分支同款 disconnectDiagnosis() || extensionLaunchHint() 探测链,说不出「插件装在 Chrome 的 Profile 1,开那个窗口 5 秒自动连」的精确指引;卫星经 device.extension.state 已同步主 Broker lastClose(诊断可用)、Profile 探测是无状态扫盘(卫星可跑),两条都安全) ⭐R79 1.2.21→1.2.22:①适配器自更新——启动后台异步查云端最新 mjs(npmmirror→unpkg 双源 fallback),提取其中 ADAPTER_VERSION 比对,更新则 tmp+rename 原子覆盖自己(本地文件型宿主覆盖下载目录 mjs、npx 型覆盖 _npx 缓存内的自己,下次进程启动即新版;失败静默保持旧版、只升不降、24h 节流);②connection_status 的 adapter.update 透出自更新三态(checking/up-to-date/updated-pending-restart)——升级挂「栗子在吗」常径不设专门触发词,宿主报到表格渲染「已自动升级,重启宿主生效」;③新工具 leadsradar_get_latest_skills(12→13 工具版判据):技能落后时宿主取最新 SKILL.md 全文递给用户粘贴(技能库装在宿主手里无法代写)。云端生效前提=npm 发版 leadsradar-agent(自更新与技能下载的同一源头) ⭐R76 1.2.20→1.2.21:①connection_status 附 skills_latest 五技能版本表(识别技能落后+指路更新——宿主技能版本不可自动更,Agent 对照自检指路);②R74/R75 期间加的工具(add_monitor/pair_login/get_daily_report,10→12)未 bump 版本号,复测无法分辨 mjs 新旧,一并 bump(v1.2.21=12 工具版判据) ⭐R56b 1.2.19→1.2.20:卫星登录态透传四处(中转宿主 loggedIn 恒 null 根修)+中转连接文案说人话(去宿主名硬编码黑话) ⭐msg11 1.2.18→1.2.19:AI 唤醒探栗 MCP——connection_status(「栗子在吗」探活指令)时 TL MCP 未运行则自动拉起(读 NM 注册表拿 exe 路径,detached spawn;只在交互信号点拉,不在 agent 启动时拉以尊重「托盘退出」;未装静默缓存跳过) ⭐B7b-P1 1.2.17→1.2.18:结果认领闭环(三原则 b 协议化——插件是结果的持有者与通知源,宿主是可断线重来的消费者):①extension.hello 附未领取结果摘要 pendingResults[{taskId,mode,keyword,url,createdAt}](connection_status 的 extension.pendingResults 透出,AI 开工前即知有存货);②新 MCP 工具 leadsradar_claim_pending_result(领取插件侧已完成但无人认领的任务结果——超时/宿主重启后回来领,不占采集限额;走普通任务通道 mode=claim_pending_result,卫星模式自动兼容);③device.extension.state 卫星透传摘要;④step=3 hint 有存货时提示「先领取再决定重发」(配合 1.2.17 的超时文案,AI 标准动作=超时→领取→查库→才重发,根除额度双耗);⭐1.2.16→1.2.17:HTTP 模式默认端口 17374→17375(撞车根修:17374 是本地服务 Rust IPC 的 NDJSON 端口,agent HTTP 监听同端口时扣子等 HTTP 宿主把请求头打到 Rust → service.log 刷 bad json;改 17375 后两端口各归其主,已按 17374 配 URL 的宿主需改指 17375,可用 LEADSRADAR_AGENT_HTTP_PORT 覆盖)+ B3 断开原因钩子(插件断开的 close frame code+reason 不再丢弃:disconnectDiagnosis() 区分「开关关/桥不可用/浏览器被杀或插件被禁」给精准指引——旧版一律报「start chrome」实测无效指引;插件侧 reason 真源 local-agent-connector.ts stop()="LF Agent disabled"/stopForAvailability()="…not publicly available",SW 被杀无告别帧=1006;卫星经 device.extension.state 同步诊断);⭐A2/B7/B9 1.2.15→1.2.16:撞墙自修三连——①任务中断秒失败(插件断开即中止全部等待任务 TASK_ABORTED,旧版傻等 300s 超时,2026-10-16 杀浏览器实测抓到);②撞墙文案自动探测插件所在浏览器+profile(扫 Chrome/Edge 各 profile 的 Preferences 找 unpacked 探栗 path,给出精确 start 命令——旧版「start chrome 开默认 profile、插件装在 Profile 1 → 桥永远不起」实测 bug);③extension.account.update 登录态保鲜(解绑/登出实时同步,旧版冻结在握手值「解绑了仍显示已登录」实测);⭐r96ze 1.2.14→1.2.15:卫星状态谎报根修(用户实报「未批准的 dsh 显示已连接可以开工」)——statusSnapshot 卫星分支旧逻辑借中转通道状态(主 Broker 与插件的连接)冒充自身就绪,未批准卫星恒报 step=3;新逻辑 selfPaired 标志(收到 purpose="session" 挑战=已配对、pairing=失效回退,SW 挑战类型即配对态真值),step 判定通道死→1/未配对→2/配对+通道→3,step=2 hint 明示「批准前任务会被拒绝别急着开工」(任务层本有 PAIRING_REQUIRED 门禁无越权,仅状态误导);⭐r96y 1.2.13→1.2.14:欢迎文案 v2(「探一下」品牌动词融入全部示例,示例即激活词教学;删「不用记命令」与能力清单黑话)+ 对外文案 9 处旧菜单名「智能体接管」→「智能体连接」(r96r-5 改名时适配器侧漏网:hint/错误 message/description/log,宿主 AI 按旧名指路用户找不到菜单);⭐r96t 1.2.12→1.2.13:HOST_LABELS 删 stepfun=「阶跃 AI」(渠道下线:用户拍板排除——自定义 MCP 入口未确认开放+用户量知名度低);⭐r96g 1.2.11→1.2.12:HOST_LABELS 补 cherry=「Cherry Studio」/stepfun=「阶跃 AI」(CLI·进阶档扩容:codex 回归+cherry+stepfun,dsh 并入该档);⭐r96e 1.2.10→1.2.11:HOST_LABELS 补 trae=「Trae」(Trae/编程 CLI 宿主:项目 .trae/mcp.json 配置拉起,本仓 dogfooding 实测);⭐r96 1.2.10:HOST_LABELS 补 qwen-office=「千问办公」;⭐r93 1.2.9:dsh=「DeepSeek」;⭐r90c 1.2.8:HTTP 模式;⭐r86c 1.2.7:kimi-work;⭐r85b 1.2.6:doubao/feishu 多客户端各自 HOST;⭐r85 1.2.5:Windows 动态端口自愈;⭐r82 1.2.4:initialize 注入呈现规范;⭐r81 1.2.3:登录态;⭐r77c 1.2.1:密钥迁用户目录;⭐r76 1.2.0:多宿主中转 */
59
63
  const HOST_LABELS = {
60
64
  "doubao-work": "豆包工作",
61
65
  // ⭐r85 字节系多客户端实测(用户已验证豆包客户端支持 stdio 连接器,与豆包工作同源):
@@ -178,6 +182,33 @@ function extensionLaunchHint() {
178
182
  return `已探测到插件装在 ${found.map((f) => `${f.browser === "msedge" ? "Edge" : "Chrome"} 的 ${f.profile}`).join(" 和 ")}——若你有终端权限,运行 ${cmd} 打开对应窗口,插件约 5 秒自动重连后重试`;
179
183
  }
180
184
 
185
+ /* ⭐R92 自动拉起装插件的浏览器(用户拍板「宿主应该自动打开我的插件,为啥要额外操作?终端操作劝退小白」):
186
+ 插件未连 + 探测到插件所在浏览器/profile → 本进程直接 detached 拉起浏览器窗口(不再只给命令让用户/AI 去跑)。
187
+ 节流 60s(重复拉只会开一串新窗口);仅在宿主探活(connection_status → statusSnapshot step=1 hint 组装)时触发,
188
+ 进程启动时不拉(用户没喊就别动他屏幕)。cmd start 的 "" 占位防带引号参数被当窗口标题吃掉。 */
189
+ let __autoLaunchAt = 0;
190
+ function autoLaunchExtensionHost() {
191
+ if (Date.now() - __autoLaunchAt < 60_000) return false;
192
+ const found = detectExtensionProfiles();
193
+ if (!found.length) return false;
194
+ const pref = preferredBrowser();
195
+ let targets = found;
196
+ if (pref) {
197
+ const pinned = found.filter((f) => f.browser === pref || (pref === "edge" && f.browser === "msedge"));
198
+ if (pinned.length) targets = pinned;
199
+ }
200
+ const t = targets[0];
201
+ if (!t) return false;
202
+ __autoLaunchAt = Date.now();
203
+ try {
204
+ spawn("cmd.exe", ["/c", "start", "", t.browser, `--profile-directory=${t.profile}`], { detached: true, stdio: "ignore", windowsHide: true }).unref();
205
+ log(`[lf-agent] 已自动拉起装插件的浏览器:${t.browser}(${t.profile})`);
206
+ return true;
207
+ } catch {
208
+ return false;
209
+ }
210
+ }
211
+
181
212
  /* ================= Ed25519 设备身份(持久化,deviceId+公钥稳定,避免重复配对) ================= */
182
213
 
183
214
  function loadOrCreateKeys() {
@@ -290,8 +321,14 @@ class AgentBroker {
290
321
  probe.on("error", () => clearTimeout(kill));
291
322
  } catch { /* 旧实例连不上也无妨,按原节奏重试 */ }
292
323
  };
293
- const attach = (server) => {
324
+ const attach = (server, httpSrv) => {
294
325
  server.on("connection", (ws) => this.handleConnection(ws));
326
+ /* ⭐R92b EADDRINUSE handler 必须挂 wss(server 实例):ws 库在 options.server 模式会把底层 httpSrv
327
+ 的 error 冒泡转发到 WebSocketServer 实例 emit,且该转发 listener 在构造时注册(先于 attach)——
328
+ wss 上零 listener 即同步 throw 崩进程,后注册的 httpSrv handler 永远执行不到。
329
+ (R92 把 handler 从 wss 迁到 httpSrv 引发本 bug:任何 17373 被占的场景新实例必崩,
330
+ WorkBuddy 实报 MCP -32000 Connection closed、手动复跑实证栈
331
+ "Emitted 'error' event on WebSocketServer instance") */
295
332
  server.on("error", (err) => {
296
333
  if (err?.code === "EADDRINUSE") {
297
334
  if (this.relay) return; // ⭐r76 已进入卫星中转模式,不再抢端口
@@ -317,26 +354,43 @@ class AgentBroker {
317
354
  });
318
355
  }
319
356
  log(`[lf-agent] 端口 ${PORT} 被占用,3 秒后重试绑定(${listenAttempts}/20)…`);
320
- try { server.close(); } catch { /* noop */ }
357
+ try { httpSrv.close(); } catch { /* noop */ }
321
358
  setTimeout(() => { if (!this.relay) tryListen(); }, 3000);
322
359
  } else {
323
360
  log(`[lf-agent] Broker error: ${err?.message}`);
324
361
  }
325
362
  });
363
+ httpSrv.on("error", (err) => log(`[lf-agent] httpSrv error 兜底: ${err?.message}`)); // ⭐R92b 防漏网
326
364
  };
327
365
  const tryListen = () => {
328
366
  if (this.relay) return; // ⭐r76 卫星模式下不监听端口(主 Broker 负责插件连接)
329
367
  listenAttempts += 1;
330
- const server = new WebSocketServer({ host: "127.0.0.1", port: PORT, path: "/extension" }, () => {
368
+ /* ⭐R92 头像静态路由:ws 同端口(17373)挂 GET /chestnut/{n}.webp——宿主 AI 菜单里的头像图
369
+ (markdown ![]() 指向本机端口,聊天宿主本地渲染即可拉到);图在 npm 包 assets/ 白名单内,
370
+ 本地开发(agent/ 无 assets)404 属预期。路径正则 \d+ 白名单防目录穿越。 */
371
+ const httpSrv = createHttpServer((req, res) => {
372
+ const m = /^\/chestnut\/(\d+)\.webp$/.exec((req.url || "").split("?")[0]);
373
+ if (m) {
374
+ try {
375
+ const buf = readFileSync(join(__dirname, "assets", `chestnut-${m[1]}.webp`));
376
+ res.writeHead(200, { "Content-Type": "image/webp", "Cache-Control": "public, max-age=86400" });
377
+ res.end(buf);
378
+ } catch { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("chestnut not found"); }
379
+ return;
380
+ }
381
+ res.writeHead(404, { "Content-Type": "text/plain" }); res.end("not found");
382
+ });
383
+ const server = new WebSocketServer({ server: httpSrv, path: "/extension" });
384
+ httpSrv.listen(PORT, "127.0.0.1", () => {
331
385
  listenAttempts = 0;
332
386
  this.portBound = true; // ⭐412 端口绑定成功(statusSnapshot 用它区分「端口被另一宿主占用」与「插件未开」)
333
387
  this.portBlocked = false; // ⭐r85 排除段漂走/占用者让位,绑定成功即解除保留态标记
334
388
  this.wss = server;
335
- log(`[lf-agent] Broker 已监听 ws://127.0.0.1:${PORT}/extension`);
389
+ log(`[lf-agent] Broker 已监听 ws://127.0.0.1:${PORT}/extension(含头像路由 /chestnut/{n}.webp)`);
336
390
  log(`[lf-agent] 设备「${DEVICE_NAME}」指纹:${fingerprint}`);
337
391
  log(`[lf-agent] 等待插件连接(插件 → 设置 → 智能体连接 → 打开开关)…`);
338
392
  });
339
- attach(server);
393
+ attach(server, httpSrv);
340
394
  };
341
395
  /** 卫星中转断开后回到端口竞争(主 Broker 可能已退出,端口已释放) */
342
396
  this.retryBindAfterRelayLoss = () => {
@@ -1197,7 +1251,7 @@ class AgentBroker {
1197
1251
  ? `已连接(本机多个 AI 助手共用这条插件连接),可以开始采集任务。${this.pendingResultsHint()}`
1198
1252
  : step === 2
1199
1253
  ? `等待用户批准配对:把 adapter.fingerprint 原样转告用户,请其到插件设置页确认是自己的设备后点「批准」,然后每 8 秒复查一次(注意:批准前任务会被拒绝,别急着开工)。`
1200
- : `中转模式等待插件:请让用户打开浏览器确认探栗插件已启用、设置页「智能体连接」开关已打开,然后每 8 秒复查一次。`,
1254
+ : `中转模式等待插件:${(() => { const ok = autoLaunchExtensionHost(); return ok ? "已自动为你打开装插件的浏览器窗口——插件约 5 秒自动重连,稍等片刻喊「栗子在吗」复查即可" : (this.disconnectDiagnosis() || extensionLaunchHint() || "请让用户打开浏览器确认探栗插件已启用、设置页「智能体连接」开关已打开"); })()},然后每 8 秒复查一次。`,
1201
1255
  },
1202
1256
  welcome: step === 3 ? { fixedCopy: WELCOME_FIXED_COPY } : null,
1203
1257
  };
@@ -1216,7 +1270,7 @@ class AgentBroker {
1216
1270
  : !this.portBound
1217
1271
  ? `本适配器的本机端口 ${PORT} 正在被占用且尚未完成中转协商(正在自动处理:同宿主孤儿会被接管,异宿主会自动转入中转共存)。请每 8 秒复查一次;若超过 1 分钟仍停留在此状态,请用户完全退出所有 AI 助手(含托盘)后重开。`
1218
1272
  : step === 1
1219
- ? `插件未连接:${this.disconnectDiagnosis() || extensionLaunchHint() || "若你有终端权限可运行 start chrome(或 start msedge)打开浏览器,插件约 5 秒内自动重连"};否则请用户在浏览器打开探栗插件 → 设置 → 智能体连接 → 打开顶部开关,然后每 8 秒复查一次。`
1273
+ ? `插件未连接:${(() => { const ok = autoLaunchExtensionHost(); return ok ? "已自动为你打开装插件的浏览器窗口——插件约 5 秒自动重连,稍等片刻喊「栗子在吗」复查即可" : (this.disconnectDiagnosis() || extensionLaunchHint() || "若你有终端权限可运行 start chrome(或 start msedge)打开浏览器,插件约 5 秒内自动重连"); })()};否则请用户在浏览器打开探栗插件 → 设置 → 智能体连接 → 打开顶部开关,然后每 8 秒复查一次。`
1220
1274
  : step === 2
1221
1275
  ? `等待用户批准配对:把 adapter.fingerprint 原样转告用户,请其到插件设置页核对指纹一致后点「批准」,然后每 8 秒复查一次。注意:若 extension.connected 为 false,说明这是插件断开前的旧状态——请提醒用户检查插件开关是否打开(或重新加载插件后重新打开),插件重连会自动重新握手。`
1222
1276
  : `已连接,可以开始采集任务。${this.pendingResultsHint()}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leadsradar-agent",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "探栗(LeadsRadar)AI 助手接入包——让豆包工作 / WorkBuddy / Codex / Claude 直接管住你的小红书·抖音获客雷达,全程本机流转",
5
5
  "type": "module",
6
6
  "main": "leadsradar-agent.mjs",
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "leadsradar-agent.mjs",
12
12
  "skills/",
13
+ "assets/",
13
14
  "README.md",
14
15
  "README_en.md"
15
16
  ],
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: leadsradar-helper
3
3
  title: 探栗·管家栗
4
- version: 1.3.2
4
+ version: 1.3.4
5
5
  status: available
6
6
  description: 探栗(LeadsRadar 浏览器插件)管家栗:栗子前台——应答「栗子」「栗子在吗」「栗子们」并自动报告连接/登录/任务三件事,「栗子档案」总览本地核心资产(先大纲后细节),「栗子查」细看某一类,「栗子登录」帮用户完成插件登录连接,「今天的日报/获客日报」取昨日获客简讯全量渲染,介绍四大数字员工(情报栗/洞察栗/创作栗/成交栗)并引导派活,解答使用教程与设置问题。用户说「栗子」「栗子在吗」「栗子们」「栗子档案」「栗子查」,或问「怎么用/我登录了吗/教程/怎么装/怎么配置智能体/在哪改设置/日报」时即指本技能。「栗子+动作词」是精准触发词家族(栗子下载/栗子入库/栗子提取→创作栗;栗子对标→情报栗;栗子研究→洞察栗;栗子触达→成交栗),管家栗遇到直接指派对应栗、不要自己接
7
7
  requires:
@@ -42,10 +42,10 @@ requires:
42
42
  | 登录状态 | ✅ 已登录 · 个人版 · 积分 120 |
43
43
  | 待领任务 | 无积压 |
44
44
 
45
- 🔍 情报栗:发链接/关键词「探一下」——现采现报(线索速报/账号速览/赛道机会/对标巡逻)
46
- 🧠 洞察栗:「栗子研究+对象」——拆解爆款、深度研究、查历史报告、复盘我的账号
47
- 🎬 创作栗:发作品链接说一句话——存选题、下素材、提文案
48
- 💰 成交栗:从评论区挖客户——意向分级、跟进名单、回复话术
45
+ ![情报栗](http://127.0.0.1:17373/chestnut/3.webp) **情报栗**——`探一下 <作品链接 / 账号链接 / 平台+关键词>`(评论捞客户线索 · 账号速览 · 赛道机会);`栗子对标 <账号链接>`(加对标开监控)
46
+ ![洞察栗](http://127.0.0.1:17373/chestnut/1.webp) **洞察栗**——`栗子研究 <作品链接 / 账号链接 / 赛道>`(拆解爆款 · 深度研究 · 查历史报告);`复盘我的账号`
47
+ ![创作栗](http://127.0.0.1:17373/chestnut/6.webp) **创作栗**——`栗子下载 <链接>`(无水印素材);`栗子入库 <链接>`(存选题);`栗子提取 <链接>`(提文案仿写)
48
+ ![成交栗](http://127.0.0.1:17373/chestnut/7.webp) **成交栗**——`栗子触达 <作品链接>`(意向分级 → 跟进名单 → 能直接发的回复话术)
49
49
 
50
50
  现在想干哪件?没想好就把你在看的小红书/抖音链接发我。
51
51
  ```
@@ -57,6 +57,8 @@ requires:
57
57
  - **未连接不报菜单**:按 onboarding 指引转述(每 8 秒复查最多 12 次),连上了再报到+菜单
58
58
  - **技能版本自检(⭐R76)**:connection_status 返回带 `skills_latest` 五技能版本表——与当前技能文件 frontmatter 的 version 对照,**落后就加一行提醒**:「⚠️ 技能有新版,按你的安装方式更新一下技能文件,我干活更顺」(Agent 只识别+指路,更新动作在用户手里)
59
59
 
60
+ - **栗子头像(⭐R92)**:菜单行首 `![栗名](http://127.0.0.1:17373/chestnut/N.webp)` 是本机适配器静态路由(五栗映射:管家=4 / 情报=3 / 洞察=1 / 创作=6 / 成交=7)——宿主渲染 markdown 图即出真头像,**照抄别删**;纯文本宿主降级为 alt 文字不影响阅读
61
+
60
62
  用户报了需求 → 按第五节路由表指路(宿主会自动进对应技能,指路话术一句带过即可,别抢活)。
61
63
 
62
64
  ## 三、状态查询