supsub-focus Skill
「关注点」(focus)是 SupSub 里按主题聚合的内容流:它跨多个来源(微信公众号 MP、网站 WEBSITE、推特 X)把同一主题的文章汇集到一起。本 skill 负责查看关注点列表、浏览某个关注点里的内容(区分已读/未读),以及删除关注点。
与
supsub-sub的区别:sub管理「订阅源」(一个具体的公众号/网站,以及其下文章);focus管理「主题聚合视图」(跨多个源的内容流)。两者不要混淆。 与supsub-search的区别:search是按关键词做一次性全文检索;focus是浏览既有的、持续更新的主题流。
Prerequisites
- 安装:
curl -fsSL https://raw.githubusercontent.com/SupSub-AI/supsub-cli/master/scripts/install.sh | bash(native 安装,装到~/.local、支持后台自动更新);或包管理器npm i -g @supsub/cli/pnpm add -g @supsub/cli - 已登录:
supsub auth status显示 Authenticated(首次使用先supsub auth login) - 未授权(exit 2 / UNAUTHORIZED)时不要止步于「你未登录」:直接运行
supsub auth login为用户打开浏览器授权(命令会自动打开浏览器并阻塞等待授权,请用足够长的超时,如 10 分钟;用户只需在浏览器点确认,无需在终端输入任何内容),授权成功后重试原命令。无浏览器 / 无头环境再回退为提示用户SUPSUB_NO_BROWSER=1 supsub auth login。
Commands
List focuses(关注点列表)
supsub focus list
无参数。每行字段:id, icon(emoji), title, unreadCount。
# 列出全部关注点
supsub focus list
# JSON 输出
supsub focus list -o json
JSON shape: {"success":true,"data":[{"id":42,"icon":"🤖","title":"...","unreadCount":3}, ...]}
已读/未读:每个关注点的
unreadCount就是该关注点当前的未读条目数。用户问「我哪个关注点还有没读的 / 各关注点还剩多少没看」时,直接读这个字段,无需进 contents。
Browse contents in a focus(查看关注点内容)
supsub focus contents --id <focusId> [--unread | --all] [--brief] [--page <n>] [--page-size <n>]
| Flag | Default | Description |
|---|---|---|
--id |
required | 关注点 ID(正整数),来自 supsub focus list 的 id |
--unread |
(default) | 仅返回未读内容 |
--all |
— | 返回全部内容(已读 + 未读) |
--brief |
— | 精简输出:只留 contentId / title / sourceType / sourceName / publishedAt(+Text) / isRead |
--page |
1 | 页码(正整数) |
--page-size |
20 | 每页条数,1-100 |
⚠️
--unread与--all互斥:同时指定会抛INVALID_ARGS。不传任何一个时,默认行为等价于--unread。
⚠️ 「最近」不等于「未读」:「看一下最近 X 的内容」「X 关注点最近有什么」这类按时间浏览的请求用 --all,
把 isRead 当标注(「其中 N 条你还没看过」)而不是过滤条件;只有用户明说「未读 / 没看的 / 还剩多少没读」
才用默认。否则该关注点读完后会返回空数组,回复「没有内容」——而用户问的是「最近」,不是「没读的」。
关注点聚合多来源,故每行都带 sourceType / sourceName,便于看清这条内容来自哪个号/网站/推特。
每行字段:contentId, url, title, coverImage, keywords[], tags[], summary, sourceType, sourceName, publishedAt, isRead。
# 默认(仅未读)—— 等价于 --unread
supsub focus contents --id 42
# 全部内容(含已读)
supsub focus contents --id 42 --all
# 翻到第 2 页 / 一次多拿一些(上限 100)
supsub focus contents --id 42 --page 2
supsub focus contents --id 42 --page-size 100 -o json
# 全部 + JSON
supsub focus contents --id 42 --all -o json
JSON shape: {"success":true,"data":[{"contentId":"...","url":"...","title":"...","coverImage":"...","keywords":[...],"tags":[...],"summary":"...","sourceType":"MP","sourceName":"...","publishedAt":<timestamp 或字符串>,"isRead":false}, ...]}
publishedAt的原始形态随后端版本而异(Unix 秒数字 /"YYYY-MM-DD HH:mm:ss"字符串), 不用自己兼容——直接读 CLI 补好的publishedAtText(恒为"YYYY-MM-DD HH:mm")。sourceType可能是MP/WEBSITE/X(推特)。批量枚举一律加
--brief:完整输出每条都带summary/keywords/tags,100 条约 90KB, 会撑爆工具输出上限被迫落盘;--brief同样 100 条约 14KB。只在需要给用户讲内容时才用完整输出。翻页策略:浏览类请求只拉第 1 页并告知总量;「全部 / 统计 / 导出」类请求用
--page-size 100自动循环翻页,不要逐页询问用户。详见supsub-unread。
Mark a focus as read(整个关注点标记已读)
supsub focus mark-read --id <focusId> --all
| Flag | Required | Description |
|---|---|---|
--id |
yes | 关注点 ID(正整数) |
--all |
yes | 确认整个关注点全部标为已读(不可逆) |
⚠️ 只支持整个关注点已读,没有单篇已读。 文章没有「详情 / 阅读」这一步,产生不了自然的单篇已读事件,所以 CLI 只保留用户明确表达的「这个关注点我看完了」。传
--content-id/--type/--source-type会抛INVALID_ARGS。用户说「把这篇标为已读」时如实说明不支持。⚠️
--all必填且不可逆(无 mark-as-unread)。执行前必须向用户二次确认:复述关注点标题 + 当前unreadCount,获得明确同意后才执行。CLI 不会再问一次:这条命令(以及
focus remove)没有交互式确认提示,一执行就生效。若把命令交给用户自己在终端跑, 不要说「执行后 CLI 会提示确认」——那是不存在的安全网。
# 整个关注点已读(需用户确认后执行)
supsub focus mark-read --id 42 --all -o json
JSON shape: {"success":true,"data":{"message":"已标记该关注点全部内容为已读(不可逆)"}}
Remove a focus(删除关注点)
supsub focus remove --id <focusId>
| Flag | Required | Description |
|---|---|---|
--id |
yes | 关注点 ID(正整数) |
supsub focus remove --id 42
supsub focus remove --id 42 -o json
JSON shape: {"success":true,"data":{"message":"..."}}
⚠️ 破坏性且不可逆:删除后 CLI 没有任何新增关注点的命令(无
focus add),删掉就建不回来。执行前务必向用户确认。
已读 / 未读(重点)
已读状态由服务端维护,CLI 既能读取也能标记(只能标为已读,不能标回未读):
focus list每项的unreadCount= 该关注点的未读条目数。这是判断「哪个关注点还有没看的」的最快入口。focus contents默认(或显式--unread)只返回未读条目;--all返回全部(已读 + 未读)。focus contents每条的isRead(布尔)= 该条目是否已读:表格里渲染为read列(已读显示✓,未读为空)。- 标记已读用
focus mark-read --all:只有「整个关注点已读」一档,没有单篇已读。 - 没有取消已读的命令:标错了无法在 CLI 里恢复。
--all级操作不可逆,执行前必须向用户二次确认。 - 跨订阅源 + 关注点的未读概览与「清未读」工作流见
supsub-unread(supsub unread一条命令看全)。
Agent Usage Notes
- 解析数据时统一用
-o json;表格输出有截断、列宽限制,不适合做下游处理。 - 所有 JSON 响应都是
{"success":true,"data":<payload>}结构(来自src/ui/output.ts)。 - 拿
focusId的唯一来源是supsub focus list的id(正整数);--id非正整数会报INVALID_ARGS(exit 64),且不会发起请求。 - 用户问「这个关注点里都有哪些内容/文章」通常意味着
--all(含已读);问「还有哪些没看 / 未读」用默认--unread。 focus contents默认每页 20 条,用--page/--page-size(上限 100)翻页取更早的内容。focus mark-read只做整个关注点已读(单篇已读不支持:文章没有详情/阅读这一步);--all必填且不可逆,执行前必须向用户二次确认。- 本 skill 不负责:订阅源增删查(→
supsub-sub)、订阅分组(→supsub-group)、跨源未读概览与清未读工作流(→supsub-unread)、按关键词全文搜索(→supsub-search)、发现新公众号(→supsub-mp)。focus 没有 add。 - Exit codes:
0OK,2UNAUTHORIZED,64INVALID_ARGS(--id/--page/--page-size校验失败、--all与--unread互斥、mark-read 未给--all或误传单篇参数),1业务错误(后端 4xx,如关注点不存在),10网络错误,11服务端错误(5xx)。