@iducky/media-agent 1.1.0
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 +90 -0
- package/SHA256SUMS +94 -0
- package/bin/media-agent.mjs +89 -0
- package/docs/guides/capabilities.md +103 -0
- package/docs/guides/image-text-publishing.md +81 -0
- package/docs/guides/installation.md +103 -0
- package/docs/guides/runtime.md +13 -0
- package/manifest.json +382 -0
- package/package.json +42 -0
- package/pyproject.toml +20 -0
- package/resources/capabilities.json +34 -0
- package/resources/configs/accounts.yaml +21 -0
- package/resources/configs/profile.template.json +20 -0
- package/resources/configs/ranking-profiles.yaml +21 -0
- package/resources/configs/toutiao-profile.template.json +22 -0
- package/resources/configs/xiaohongshu-profile.template.json +27 -0
- package/resources/data/industry-taxonomy.yaml +326 -0
- package/skills/douyin-competitor-collect/SKILL.md +177 -0
- package/skills/douyin-competitor-collect/agents/openai.yaml +4 -0
- package/skills/douyin-competitor-collect/references/output-schema.md +178 -0
- package/skills/douyin-creator-image-text-publish/SKILL.md +44 -0
- package/skills/douyin-creator-image-text-publish/agents/openai.yaml +4 -0
- package/skills/douyin-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
- package/skills/douyin-creator-image-text-publish/references/execution-contract.md +46 -0
- package/skills/douyin-creator-image-text-publish/references/upstream.md +30 -0
- package/skills/douyin-creator-index/SKILL.md +32 -0
- package/skills/douyin-creator-index/agents/openai.yaml +4 -0
- package/skills/douyin-creator-login/SKILL.md +58 -0
- package/skills/douyin-creator-login/agents/openai.yaml +4 -0
- package/skills/douyin-creator-publish/SKILL.md +56 -0
- package/skills/douyin-creator-publish/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-leads/SKILL.md +26 -0
- package/skills/douyin-enterprise-leads/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-leads-login/SKILL.md +36 -0
- package/skills/douyin-enterprise-leads-login/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-short-video-export/SKILL.md +29 -0
- package/skills/douyin-enterprise-short-video-export/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-video-rankings/SKILL.md +51 -0
- package/skills/douyin-enterprise-video-rankings/agents/openai.yaml +4 -0
- package/skills/douyin-enterprise-video-rankings/references/industry-taxonomy.md +29 -0
- package/skills/douyin-web-login/SKILL.md +102 -0
- package/skills/douyin-web-login/agents/openai.yaml +4 -0
- package/skills/toutiao-creator-article-draft/SKILL.md +154 -0
- package/skills/toutiao-creator-article-draft/agents/openai.yaml +4 -0
- package/skills/toutiao-web-login/SKILL.md +96 -0
- package/skills/toutiao-web-login/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-image-text-publish/SKILL.md +46 -0
- package/skills/xiaohongshu-creator-image-text-publish/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/execution-contract.md +46 -0
- package/skills/xiaohongshu-creator-image-text-publish/references/upstream.md +31 -0
- package/skills/xiaohongshu-creator-login/SKILL.md +106 -0
- package/skills/xiaohongshu-creator-login/agents/openai.yaml +4 -0
- package/skills/xiaohongshu-creator-publish/SKILL.md +153 -0
- package/skills/xiaohongshu-creator-publish/agents/openai.yaml +4 -0
- package/src/media_agent/__init__.py +1 -0
- package/src/media_agent/cli.py +28 -0
- package/src/media_agent/commands.sh +436 -0
- package/src/media_agent/platforms/__init__.py +1 -0
- package/src/media_agent/platforms/douyin/__init__.py +1 -0
- package/src/media_agent/platforms/douyin/check_login.py +196 -0
- package/src/media_agent/platforms/douyin/collect_industry_taxonomy.py +184 -0
- package/src/media_agent/platforms/douyin/collect_video_rankings.py +352 -0
- package/src/media_agent/platforms/douyin/douyin_full_login.py +391 -0
- package/src/media_agent/platforms/douyin/douyin_hotspot_v2.py +454 -0
- package/src/media_agent/platforms/douyin/douyin_publish.py +1135 -0
- package/src/media_agent/platforms/douyin/enterprise_login.py +128 -0
- package/src/media_agent/platforms/douyin/export_short_video.py +70 -0
- package/src/media_agent/platforms/douyin/login_controller.py +508 -0
- package/src/media_agent/platforms/douyin/validate_industry_taxonomy.py +152 -0
- package/src/media_agent/platforms/douyin/validate_rankings.py +254 -0
- package/src/media_agent/platforms/toutiao/__init__.py +1 -0
- package/src/media_agent/platforms/toutiao/toutiao_check_login.py +54 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_controller.py +250 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_evidence.py +50 -0
- package/src/media_agent/platforms/toutiao/toutiao_login_ipc.py +70 -0
- package/src/media_agent/platforms/xiaohongshu/__init__.py +1 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_check_login.py +189 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_controller.py +449 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_evidence.py +64 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_ipc.py +120 -0
- package/src/media_agent/platforms/xiaohongshu/xiaohongshu_publish.py +925 -0
- package/src/media_agent/runtime/__init__.py +1 -0
- package/src/media_agent/runtime/account_manager.py +672 -0
- package/src/media_agent/runtime/browser.py +5 -0
- package/src/media_agent/runtime/paths.py +7 -0
- package/src/media_agent/script_map.json +23 -0
- package/src/node/config.mjs +48 -0
- package/src/node/integrity.mjs +34 -0
- package/src/node/skills.mjs +85 -0
- package/tools/archive_releases.py +83 -0
- package/tools/artifacts.py +56 -0
- package/tools/build_release.py +82 -0
- package/tools/check_catalog.py +23 -0
- package/tools/install_runtime.py +144 -0
- package/tools/run_tests.py +21 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: douyin-enterprise-video-rankings
|
|
3
|
+
description: 用于抖音企业号线索版后台的行业目录查询、一级/二级行业分类更新,以及按行业采集线索榜、引流榜和热门榜。也用于校验分类候选、榜单排名和 XLSX/JSON 数据质量。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 企业号行业与视频榜单
|
|
7
|
+
|
|
8
|
+
目标页:`https://leads.cluerich.com/pc/analysis/short-video/rank`。
|
|
9
|
+
|
|
10
|
+
## 按任务选择执行方式
|
|
11
|
+
|
|
12
|
+
- **查询已有行业**:读取实际运行时根目录的 `industry-taxonomy.yaml`;检查源码时对应 `data/industry-taxonomy.yaml`。返回一级/二级行业及 `source.collected_at`、`source.page`、`taxonomy_verified`,说明这是已保存基线,不冒充实时分类。此路径不开浏览器,不要求账号登录或在线 capability。文件缺失或未校验时只报告限制和可读内容,不自动启动在线采集;仅在用户明确要求最新分类或更新时转入分类更新流程。查询请求不授权覆盖正式分类。
|
|
13
|
+
- **更新行业分类**:按 [行业分类采集与校验](references/industry-taxonomy.md) 执行,只需 `leads_taxonomy` capability,生成候选目录及质量证据;不采集视频榜单,正式替换需批准。
|
|
14
|
+
- **采集视频榜单**:执行下文流程,只需 `leads_rankings` capability。按目标行业选择并读回即可,不以前置全量分类更新作为条件。目标行业不存在时说明页面证据,不静默改选行业。
|
|
15
|
+
|
|
16
|
+
在线操作复用目标账号的可见持久化 Profile、固定指纹和唯一 lock。未登录返回 `LOGIN_REQUIRED`,交给 `douyin-enterprise-leads-login`;不在数据任务中扫码。组合请求顺序执行分类与榜单任务,各用独立 `task_id` 和输出目录,不并发占用同一 Profile。
|
|
17
|
+
|
|
18
|
+
## 榜单命令与运行限制
|
|
19
|
+
|
|
20
|
+
命令接口如下;运行前必须检查实际安装版本的实现是否支持所需参数。
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
media-agent collect-video-rankings <profile_id> --industry-l1 <L1> --industry-l2 <L2> [--date YYYY-MM-DD] [--pages N]
|
|
24
|
+
media-agent validate-rankings <task_dir>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 参数门禁
|
|
28
|
+
|
|
29
|
+
- 必须显式给出行业,或从用户明确指定的 customer 配置读取并回显。
|
|
30
|
+
- 两者都没有时返回 `WAIT_INDUSTRY_SELECTION`;禁止沿用上次行业或静默使用默认行业。
|
|
31
|
+
- 默认日榜、前一天、三榜各 2 页 × 10 条,共 60 条。只能报告实际采集范围。
|
|
32
|
+
- 当前源码中的 `collect_video_rankings.py` 仍硬编码测试 Profile、日期和“汽车/汽车厂商”,`media-agent` 没有向脚本传递所选参数;执行前先审查已安装脚本是否已参数化。未参数化时返回 `IMPLEMENTATION_REQUIRED`,不得执行后把测试数据标成请求结果。本次 Skill 合并不表示 CLI 参数化已完成。
|
|
33
|
+
|
|
34
|
+
## 行业与分页
|
|
35
|
+
|
|
36
|
+
1. 获取 `leads_rankings` capability 和 Profile lock,真实检查 Leads 登录。
|
|
37
|
+
2. 打开级联选择器,点击一级行业;下拉关闭后重新打开,确认右栏属于目标一级行业,再点击二级行业。
|
|
38
|
+
3. 从页面当前选中值读回完整路径。验证失败时停止,不得继续采集。
|
|
39
|
+
4. 程序化交互不稳定时可使用真实桌面交互,但仍必须通过页面读回验收。
|
|
40
|
+
5. 分别采集线索榜、引流榜、热门榜。翻页后验证 active 页码、首行或排名变化,禁止重复第一页凑数。
|
|
41
|
+
6. `global_rank` 直接使用页面真实排名;不要叠加分页偏移。
|
|
42
|
+
|
|
43
|
+
## 字段与质量
|
|
44
|
+
|
|
45
|
+
至少保存标题、作者、抖音号、发布时间、封面、榜单、真实排名、页码、行业、日期、来源 URL、采集时间,以及每个指标的 display/numeric 值。页面没有视频链接时保留空值,标记 `PARTIAL`,禁止构造链接。
|
|
46
|
+
|
|
47
|
+
输出 XLSX、JSON、meta.json。XLSX 工作表使用“汇总”“线索榜”“引流榜”“热门榜”。meta 披露数量、实际排名范围、缺失排名、字段缺失、第二页 DOM 验证和行业读回结果。运行独立校验器,零错误后才交付。
|
|
48
|
+
|
|
49
|
+
正常关闭浏览器并释放 lock;本地文件必须作为真实附件发送后才算完成。
|
|
50
|
+
|
|
51
|
+
检查上述参数化限制时,必须读取实现 `src/media_agent/platforms/douyin/collect_video_rankings.py` 和命令路由 `src/media_agent/commands.sh`;已安装环境对应 `<MEDIA_AGENT_HOME>/.app/current/` 下的这些路径。命令存在不代表参数化限制已消除。
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 行业分类采集与校验
|
|
2
|
+
|
|
3
|
+
在用户需要最新行业目录、全量更新或校验分类候选时读取。仅查询已有目录时按主 Skill 读取静态基线;按行业采榜时无需全量枚举。
|
|
4
|
+
|
|
5
|
+
## 命令与运行限制
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
media-agent collect-industry-taxonomy <profile_id>
|
|
9
|
+
media-agent validate-industry-taxonomy <candidate.yaml>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
当前源码中的 `collect_industry_taxonomy.py` 仍硬编码测试 Profile,`media-agent` 没有向脚本传入目标 Profile。执行前确认安装版本已参数化;未参数化时返回 `IMPLEMENTATION_REQUIRED`,不得声称采集使用了请求的账号。本次合并不修改浏览器运行代码。
|
|
13
|
+
|
|
14
|
+
## 执行
|
|
15
|
+
|
|
16
|
+
1. 确认目标 Profile 有 `leads_taxonomy` capability,取得唯一 lock 并真实检查 Leads 登录。分类任务不要求 `leads_rankings`;未登录返回 `LOGIN_REQUIRED`。
|
|
17
|
+
2. 打开视频榜单行业级联选择器,枚举全部可见一级行业;虚拟列表必须滚动到末尾并证明已到终点。
|
|
18
|
+
3. 对每个一级行业执行“选择 → 关闭 → 重开”,再读取对应二级菜单;不要复用旧右栏内容,避免 React 级联污染。
|
|
19
|
+
4. 对每个一级行业至少抽检首、中、末二级项,点击后从输入框读回完整路径。
|
|
20
|
+
5. 保存 candidate YAML、meta JSON、读回验证 JSON 和必要截图,不直接覆盖正式基线,不顺带采集三类榜单。
|
|
21
|
+
6. 运行独立校验器;建议连续执行两次确定性采集,规范化后完全一致,再申请晋升正式基线。
|
|
22
|
+
|
|
23
|
+
## 验收与收尾
|
|
24
|
+
|
|
25
|
+
候选文件必须披露一级/二级数量、每个一级行业是否到达列表末尾、children 数量、读回尝试与通过数、采集时间和来源 URL。任何交叉污染、空子项、读回失败或两次差异都应返回 `PARTIAL` 或 `VALIDATION_FAILED`。
|
|
26
|
+
|
|
27
|
+
报告候选文件和验证结果,区分“候选生成”与“正式基线已更新”。正式替换仍需明确批准;查询、枚举和生成候选本身不授权覆盖已发布 taxonomy。正常关闭浏览器并释放 lock,禁止强杀浏览器。
|
|
28
|
+
|
|
29
|
+
检查上述参数化限制时,必须读取实现 `src/media_agent/platforms/douyin/collect_industry_taxonomy.py` 和命令路由 `src/media_agent/commands.sh`;已安装环境对应 `<MEDIA_AGENT_HOME>/.app/current/` 下的这些路径。命令存在不代表参数化限制已消除。
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: douyin-web-login
|
|
3
|
+
description: 登录和固化 douyin.com 抖音主站账号会话,并验证同一浏览器 Profile 与 creator.douyin.com 共享同一账号登录状态。用于复用已登录 Creator Profile 自动登录主站,处理“一键登录”后切换“登录其他账号”或右上角登录按钮的扫码流程,通过飞书发送二维码图片,扫码后悬浮头像核验目标账号,正常关闭后重启验证免扫码登录,并只读检查创作者中心仍为同一账号。不要用于竞品采集、发布、互动或 Creator 后台短信二次验证。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 抖音主站登录固化
|
|
7
|
+
|
|
8
|
+
仅处理 `douyin.com` 登录、账号核验和持久化验证。竞品搜索与数据采集必须作为后续独立任务执行。
|
|
9
|
+
|
|
10
|
+
## 执行边界
|
|
11
|
+
|
|
12
|
+
- 从远端正式社媒运行目录执行,先读取当地 `AGENTS.md`、`media-agent --help` 和 Profile 配置;不要假设命令名称。
|
|
13
|
+
- 复用目标账号现有的抖音 Creator 浏览器 Profile、`browser_data`、固定指纹和启动参数。禁止创建临时 Profile、复制 Cookie 或导出登录状态。
|
|
14
|
+
- 获取该 Profile 的唯一 lock。若已有活跃 owner,返回 `PROFILE_LOCKED`;不得抢锁、删除活锁或并行打开同一 `browser_data`。
|
|
15
|
+
- 保持一个 controller、browser、context 和 page。飞书回复结束、Agent context 压缩、客户端超时或用户新消息均不是关闭浏览器的理由。
|
|
16
|
+
- 使用可视浏览器。不得使用普通 HTTP 请求、Cookie 注入、验证码绕过、坐标盲点或批量进程终止。
|
|
17
|
+
- 如果当前运行时没有持久化 controller/IPC,先报告 `RUNTIME_CAPABILITY_MISSING`,不要用一次性浏览器假装完成跨消息扫码。
|
|
18
|
+
|
|
19
|
+
## 登录状态机
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
INIT -> LOCK_PROFILE -> OPEN_DOUYIN -> INSPECT_LOGIN
|
|
23
|
+
INSPECT_LOGIN -> VERIFY_ACCOUNT # 已自动登录
|
|
24
|
+
INSPECT_LOGIN -> SWITCH_OTHER_ACCOUNT # 出现一键登录
|
|
25
|
+
INSPECT_LOGIN -> OPEN_LOGIN_MODAL # 未登录
|
|
26
|
+
SWITCH_OTHER_ACCOUNT/OPEN_LOGIN_MODAL -> WAIT_QR_SCAN
|
|
27
|
+
WAIT_QR_SCAN -> VERIFYING_LOGIN -> VERIFY_ACCOUNT
|
|
28
|
+
VERIFY_ACCOUNT -> ACCOUNT_CONFIRMED -> SAVING_PROFILE
|
|
29
|
+
SAVING_PROFILE -> REOPEN_VERIFY -> COMPLETE
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
恢复状态:`QR_EXPIRED -> REFRESH_QR -> WAIT_QR_SCAN`。证据冲突时返回 `INDETERMINATE` 并短轮询;不得直接要求重新扫码。
|
|
33
|
+
|
|
34
|
+
## 打开与分流
|
|
35
|
+
|
|
36
|
+
1. 启动同一 Profile,保持已有 page 或只创建一个 page,打开 `https://www.douyin.com/`。
|
|
37
|
+
2. 等待页面稳定后同时读取 URL、可见 DOM、右上角区域、登录弹层和头像元素。
|
|
38
|
+
3. 按以下顺序分流:
|
|
39
|
+
- 右上角已有用户头像且无登录弹层:进入账号核验。
|
|
40
|
+
- 可见“一键登录”和“登录其他账号”:只点击一次“登录其他账号”。
|
|
41
|
+
- 右上角可见“登录”且无登录弹层:只点击一次“登录”。
|
|
42
|
+
- 登录二维码已经可见:保持当前弹层,不重复点击。
|
|
43
|
+
- 同时出现互相冲突的强证据:返回 `INDETERMINATE`,保存非敏感截图并继续短轮询。
|
|
44
|
+
4. 不要把视频播放遮罩、内容登录提示或页面内广告按钮当作右上角全站登录入口。
|
|
45
|
+
|
|
46
|
+
## 二维码与飞书交付
|
|
47
|
+
|
|
48
|
+
1. 在登录弹层内定位唯一、可见、近似正方形的二维码元素;优先截取元素,必要时截取包含二维码和“扫码登录”文字的最小弹层区域。
|
|
49
|
+
2. 验证截图存在、非空且二维码未被裁切或遮挡。
|
|
50
|
+
3. 通过飞书发送真实图片附件;远端本地路径、Markdown 路径或文字描述不算交付。
|
|
51
|
+
4. 消息包含 `task_id`、`profile_id`、`controller_pid`、`state=WAIT_QR_SCAN`,但不包含 Cookie、二维码内容、token、浏览器数据路径或其他凭据。
|
|
52
|
+
5. 用户只扫描最新附件。等待期间保持原 browser、page、controller 和 lock。
|
|
53
|
+
6. 二维码过期时只操作当前二维码容器内的刷新控件。刷新前后验证 controller PID、browser、page 均未变化,并重新发送新附件;旧二维码立即作废。
|
|
54
|
+
7. 用户确认扫码后,在原 page 轮询最多 60 秒。头像出现、登录弹层和二维码消失是主要证据;短暂 URL 不变不等于失败。
|
|
55
|
+
|
|
56
|
+
## 账号核验
|
|
57
|
+
|
|
58
|
+
1. 定位右上角唯一可见的用户头像;使用 DOM hover,不用固定坐标。
|
|
59
|
+
2. 等待用户信息卡出现,读取可见的昵称、抖音号以及能区分账号的非敏感字段。不要读取或返回 Cookie、手机号、token、私信内容或其他非必要数据。
|
|
60
|
+
3. 保存账号信息卡的非敏感截图,并通过飞书发送核验摘要。
|
|
61
|
+
4. 将规范化后的可见昵称或抖音号与任务中用户明确指定的目标账号比较:
|
|
62
|
+
- 明确一致:`ACCOUNT_CONFIRMED`。
|
|
63
|
+
- 明确不一致:`ACCOUNT_MISMATCH`,停止固化和后续业务;保持会话并请求用户决定,不自动退出或切号。
|
|
64
|
+
- 用户未提供目标账号或页面字段不足:`WAIT_ACCOUNT_CONFIRM`,请求用户确认;不得自行推断。
|
|
65
|
+
5. 不要仅凭头像图片、关注数、粉丝数或历史文档中的示例账号判定身份。
|
|
66
|
+
|
|
67
|
+
## 正常关闭与持久化复验
|
|
68
|
+
|
|
69
|
+
仅在账号已确认后执行:
|
|
70
|
+
|
|
71
|
+
1. 通过 controller 正常关闭 page/context/browser,等待 Cookie 和 Local Storage 写入原 `browser_data`。
|
|
72
|
+
2. 确认浏览器进程退出后由 owner 释放 lock;禁止 `kill`、`pkill`、批量杀 CloakBrowser 或强删未知 lock。
|
|
73
|
+
3. 等待至少 10 秒。
|
|
74
|
+
4. 使用完全相同的 Profile、`browser_data`、指纹和启动参数重新打开 `https://www.douyin.com/`,最多等待 60 秒。
|
|
75
|
+
5. 证明登录弹层和二维码未出现,右上角头像可见;再次 hover 并核验同一昵称或抖音号。
|
|
76
|
+
6. 保持同一 controller、context、Profile、`browser_data` 和指纹,在同一浏览器中打开 `https://creator.douyin.com/` 做只读一致性检查。不得启动第二个浏览器或复制 Cookie。
|
|
77
|
+
7. Creator 页面无需重新登录、登录弹层和二维码未出现,且后台可见账号与主站已确认账号一致时,记录 `creator_session_shared=true`。
|
|
78
|
+
8. Creator 要求重新登录时记录 `creator_session_shared=false` 和 `CREATOR_LOGIN_REQUIRED`;账号明确不一致时返回 `CROSS_SITE_ACCOUNT_MISMATCH`。不得为了让测试通过而退出、切号或覆盖原 Profile。
|
|
79
|
+
9. 再次正常关闭并确认浏览器进程与 lock 均已清理。
|
|
80
|
+
|
|
81
|
+
不要依赖单一 URL、Cookie 存在、缓存 `state.json`、右下角“保存登录信息”开关或固定等待时间判定持久化成功。
|
|
82
|
+
|
|
83
|
+
## 返回格式
|
|
84
|
+
|
|
85
|
+
成功时返回:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
profile_id=<profile_id>
|
|
89
|
+
task_id=<task_id>
|
|
90
|
+
login_status=logged_in
|
|
91
|
+
account_display_name=<可见昵称>
|
|
92
|
+
account_id=<可见抖音号或 unavailable>
|
|
93
|
+
account_verified=true
|
|
94
|
+
persistence_verified=true
|
|
95
|
+
creator_session_shared=true
|
|
96
|
+
creator_account_verified=true
|
|
97
|
+
relogin_qr_required=false
|
|
98
|
+
browser_process_remaining=0
|
|
99
|
+
lock_remaining=0
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
失败或等待人工时返回明确状态:`PROFILE_LOCKED`、`RUNTIME_CAPABILITY_MISSING`、`WAIT_QR_SCAN`、`QR_EXPIRED`、`INDETERMINATE`、`WAIT_ACCOUNT_CONFIRM`、`ACCOUNT_MISMATCH`、`CREATOR_LOGIN_REQUIRED`、`CROSS_SITE_ACCOUNT_MISMATCH` 或 `SESSION_LOST`。不要扩大表述为竞品采集已经可用。
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: toutiao-creator-article-draft
|
|
3
|
+
description: 在头条号后台编写并保存图文文章草稿。用于 mp.toutiao.com 的“创作 → 文章”任务,包括根据用户主题撰写标题和正文、通过编辑器图片图标选择免费正版图片、等待“草稿已保存”,返回后台并在“管理 → 草稿箱”核验目标文章;也用于只读查询某篇草稿是否存在。不要用于登录、发布文章、删除草稿或编辑已有文章。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 今日头条文章草稿
|
|
7
|
+
|
|
8
|
+
只处理新建文章、自动保存和草稿箱核验。登录失效时改用 `toutiao-web-login`;绝不点击“预览并发布”“定时发布”或任何发布确认控件。
|
|
9
|
+
|
|
10
|
+
## 执行边界
|
|
11
|
+
|
|
12
|
+
- 使用目标账号现有的可见持久化 Profile、固定指纹和唯一 lock;不得新建临时 Profile、复制登录态或并发控制同一账号。
|
|
13
|
+
- 先核验页面可见账号与任务目标一致。无法确认、账号不符或出现登录页时停止。
|
|
14
|
+
- 用户未提供标题或正文时,可根据明确主题原创;主题也不明确时返回 `CONTENT_REQUIRED`,不得猜测选题。
|
|
15
|
+
- 内容必须真实、审慎、可读,不编造新闻事实、数据、引语、人物经历或权威结论。医疗、法律、金融等高风险主题缺乏可靠来源时停止并说明。
|
|
16
|
+
- 只从编辑器的“免费正版图片”图库选图,不上传本地文件、不使用“我的素材”,不下载或转存图库图片。
|
|
17
|
+
- 草稿内容、配图和任务明确要求的封面是获准写操作。不得发布、定时发布、删除整篇草稿、勾选声明或改变位置、合集、同步发布等无关默认项。
|
|
18
|
+
- 执行文章任务期间不得创建、修改、修补或安装任何 Skill,也不得把一次页面失败写入其他 Skill 或记忆后改变当前流程。
|
|
19
|
+
- 用户已经明确授权当前页面的可逆点击操作时直接执行,不要为同一图片按钮、确认按钮或导航动作重复询问。
|
|
20
|
+
- 不读取、导出或回显 Cookie、token、Local Storage、Profile 内容或其他凭据。
|
|
21
|
+
|
|
22
|
+
## 状态机
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
INIT → CHECK_LOGIN → OPEN_ARTICLE_EDITOR → WRITE_CONTENT
|
|
26
|
+
→ SELECT_LICENSED_IMAGE → VERIFY_BODY_IMAGES → SET_COVER
|
|
27
|
+
→ WAIT_AUTO_SAVE → VERIFY_DRAFT_BOX
|
|
28
|
+
→ DRAFT_SAVED | DRAFT_INDETERMINATE
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 任务路由与隔离
|
|
32
|
+
|
|
33
|
+
先按本条消息的 `action` 选择路线,禁止根据当前页面或上一任务状态自行改线:
|
|
34
|
+
|
|
35
|
+
- `CREATE_TOUTIAO_ARTICLE_DRAFT`、`CREATE_TOUTIAO_ARTICLE_DRAFT_FROM_PROVIDED_CONTENT`:这是**新建任务**,必须从后台点击“创作 → 文章”进入新的空白编辑器;不得从“管理 → 草稿箱”打开或覆盖任何已有草稿。
|
|
36
|
+
- `VERIFY_TOUTIAO_ARTICLE_DRAFT`:只读进入“管理 → 草稿箱”核验,不得编辑。
|
|
37
|
+
- `RECOVER_EXISTING_TOUTIAO_DRAFT`,或用户明确要求继续/修改某篇已有草稿:从“管理 → 草稿箱”按完整标题和 `task_id` 恢复;不得新建。
|
|
38
|
+
|
|
39
|
+
若用户只说“继续”“处理一下”“加图”“修改”等,无法确定是新建文章还是修改已有草稿,返回 `OPERATION_INTENT_REQUIRED`,要求用户明确二选一。不得凭上一轮对话、当前 URL、草稿箱内容或浏览器是否打开来猜测。修改已有草稿还必须取得完整标题或其他足以唯一识别目标稿的非敏感信息;否则返回 `TARGET_DRAFT_REQUIRED`。
|
|
40
|
+
|
|
41
|
+
每次新建任务生成新的稳定 `task_id`,并清空上一任务的标题、正文摘要、图片搜索词、正文图片、封面、缩略图和状态证据。上一任务任何字段都不能作为本次成功证据。
|
|
42
|
+
|
|
43
|
+
新建路线进入编辑器后必须完成空白门禁:标题为空、正文为空、正文图片数为 0。三项全部成立才可填写,并返回 `empty_editor_verified=true`。任一项不为空时返回 `NEW_ARTICLE_PAGE_NOT_EMPTY`,不得清空或覆盖。页面出现“草稿 [无标题] 继续编辑”时,也必须按这三项实际内容判断,不能沿用旧任务。
|
|
44
|
+
|
|
45
|
+
## 打开文章编辑器
|
|
46
|
+
|
|
47
|
+
1. 打开 `https://mp.toutiao.com/`,等待头条号后台稳定。
|
|
48
|
+
2. 确认页面显示目标账号昵称;若出现二维码、登录表单或账号无法核验,返回 `LOGIN_REQUIRED` 或 `ACCOUNT_MISMATCH`。
|
|
49
|
+
3. 对新建 action,展开左侧“创作”,点击其子项“文章”。确认页面标题为“发布文章”,并可见标题输入区、正文编辑区和工具栏;不得先进入草稿箱,也不得点击已有草稿卡片。
|
|
50
|
+
4. 读取标题、正文和正文图片节点并执行空白门禁。全部为空时继续;任一不为空时返回 `NEW_ARTICLE_PAGE_NOT_EMPTY`。不得把已有草稿清空后冒充新稿。
|
|
51
|
+
5. 优先按可见文本、role、label、placeholder 和 DOM 关系定位,禁止依赖截图绝对坐标或易变 CSS hash。
|
|
52
|
+
|
|
53
|
+
## 编写标题和正文
|
|
54
|
+
|
|
55
|
+
1. 根据用户给出的主题、受众、语气、长度和事实材料先形成标题与正文;用户已提供成稿时保持原意,只做完成任务必需的格式调整。
|
|
56
|
+
2. 飞书消息直接包含明确的“【标题】”和“【正文】”时,将其视为 `CREATE_TOUTIAO_ARTICLE_DRAFT_FROM_PROVIDED_CONTENT`:原样填写,不自行改写、扩写、删减或纠错。标题超出 2–30 字时返回 `TITLE_INVALID`,不得自行缩短;正文为空时返回 `CONTENT_REQUIRED`。
|
|
57
|
+
3. 标题遵守页面显示的 2–30 字限制,准确概括文章,不用虚假悬念、夸张承诺或无关热点词。
|
|
58
|
+
4. 正文使用自然中文和短段落。除非用户明确要求,避免大量 emoji、营销口号和无法核实的具体数字。
|
|
59
|
+
5. 用 DOM 分别定位标题输入区和正文编辑区,先填写标题,再填写正文。不得以坐标盲点粘贴;标题计数超过 30(如 `111/30`)说明正文误入标题,必须先只清空标题并修正,不能继续选图。
|
|
60
|
+
6. 通过页面读回验证标题非空、为 2–30 字且无换行;正文包含开头和结尾的唯一文本片段、字数大于 0 且没有重复粘贴。
|
|
61
|
+
7. 记录最终标题作为后续草稿箱的主匹配键;同名可能存在时再使用本次保存时间和正文摘要消除歧义。
|
|
62
|
+
8. 标题、正文首尾和字数必须来自本次消息。若读回内容属于上一任务,返回 `DRAFT_IDENTITY_MISMATCH`,不得继续配图或报告保存成功。
|
|
63
|
+
|
|
64
|
+
## 添加免费正版配图
|
|
65
|
+
|
|
66
|
+
1. 将正文光标放在语义合适的位置,通常置于导语之后或相关段落之前。
|
|
67
|
+
2. 点击编辑器工具栏中的图片图标。确认右侧或弹层图片面板已打开。
|
|
68
|
+
3. 明确选择“免费正版图片”标签,不得停留在“上传图片”或“我的素材”。
|
|
69
|
+
4. 根据文章主题提取 1–3 个具体、非敏感关键词进行搜索;若首屏已有明显合适图片,可直接选择。
|
|
70
|
+
5. 根据缩略图可见内容选择一张与主题语义一致、无明显误导、无不当人物暗示且界面标示为免费正版的图片。图片数量、搜索词或来源标签不能代替内容核验;例如养老文章不得选择星空、城市、山水、科技、建筑或抽象背景。
|
|
71
|
+
本次图片必须由当前标题和正文提取关键词;不得沿用上一任务的搜索词、人物、场景或图片。例如沈从文/文学文章不得复用养老轮椅照。
|
|
72
|
+
6. 确认图片面板关闭或选中状态生效,并在正文编辑区看到新增图片节点。逐张记录可见主题;若无法证明图片已经插入或内容匹配,返回 `IMAGE_INSERT_INDETERMINATE`。
|
|
73
|
+
7. 图片搜索无结果时更换一次更宽泛的关键词;仍无合适图片则返回 `LICENSED_IMAGE_NOT_FOUND`,保留现场,不改用来源不明图片。
|
|
74
|
+
|
|
75
|
+
## 核验正文图片并设置封面
|
|
76
|
+
|
|
77
|
+
1. 插图后滚动检查整篇正文,按可见内容统计全部图片节点。最终应只有任务要求的图片;不得把正文图片与“展示封面”当成同一状态。
|
|
78
|
+
2. 发现错误图片时,点击该图片节点并使用图片自身的删除/移除控件;禁止框选大段正文后按删除键。删除后重新核验标题、正文首尾、字数和保留图片。
|
|
79
|
+
3. 在页面下方“展示封面”保持任务要求的模式,默认使用“单图”。若封面仍是旧图,点击封面上的“替换”。
|
|
80
|
+
4. 封面选择弹层优先使用“正文图片”,选择主题匹配的正文图;必要时才使用“免费正版图片”。
|
|
81
|
+
5. 点击目标图片只代表选中。必须看到红色边框和勾选,再点击弹层右下角红色“确认”;未点击“确认”不得报告封面已替换。
|
|
82
|
+
6. 等待弹层关闭,并验证“展示封面”缩略图已变成目标内容。不得以选择“无封面”规避问题。
|
|
83
|
+
7. 最终同时验证:正文无错误图、正确正文图仍在、封面内容匹配、错误封面不存在。只报告图片数量而不报告可见主题不算有效证据。
|
|
84
|
+
|
|
85
|
+
## 等待自动保存
|
|
86
|
+
|
|
87
|
+
1. 内容和图片就绪后停止编辑,观察页面左下角保存状态。
|
|
88
|
+
2. “草稿将自动保存”只代表自动保存机制或正在保存,不能作为成功证据。
|
|
89
|
+
3. 最多等待 60 秒,直到左下角明确显示“草稿已保存”。等待期间不刷新、不后退、不关闭浏览器,也不点击发布按钮。
|
|
90
|
+
4. 记录该可见文字和时间。若持续显示正在保存、出现错误或状态消失,返回 `AUTO_SAVE_TIMEOUT` 或 `DRAFT_INDETERMINATE` 并保留现场。
|
|
91
|
+
|
|
92
|
+
## 在草稿箱核验
|
|
93
|
+
|
|
94
|
+
1. 只有看到“草稿已保存”后,才点击左上角返回箭头或“返回头条号后台”。
|
|
95
|
+
2. 在后台展开左侧“管理”,点击“草稿箱”。不要把“作品管理”当作草稿箱。
|
|
96
|
+
3. 查找刚保存的文章卡片,优先精确匹配完整标题,再结合本次保存时间、文章类型和摘要排除同名旧稿。
|
|
97
|
+
4. 只有目标卡片在“管理 → 草稿箱”可见,才返回 `DRAFT_SAVED` 和 `draft_found=true`。
|
|
98
|
+
5. 页面未立即出现时,以 5–10 秒间隔重新读取或刷新草稿箱,最多 60 秒。仍未找到则返回 `DRAFT_INDETERMINATE`;禁止返回编辑器重建或重复保存文章。
|
|
99
|
+
6. 草稿卡片缩略图应与已确认封面一致。若仍显示旧图,等待约 10 秒刷新一次;仍不一致时重新打开同一草稿,只读检查正文图片和“展示封面”,不得直接假定缓存或盲目重复插图。
|
|
100
|
+
7. 最终卡片标题、正文摘要、正文图片语义和缩略图必须同时属于当前 `task_id`。任一证据来自上一任务时返回 `DRAFT_IDENTITY_MISMATCH`;即使页面显示“草稿已保存”也不能返回 `DRAFT_SAVED`。
|
|
101
|
+
|
|
102
|
+
## 浏览器重开后的恢复
|
|
103
|
+
|
|
104
|
+
1. 浏览器关闭后,原编辑器 page/context 已不存在,任何旧页面句柄、当前 URL、DOM、选区或“仍在编辑器”的假设立即失效。复用相同 Profile 只恢复登录状态,不恢复页面控制状态。
|
|
105
|
+
2. 重开前先确认本次 action:明确新建则按新建路线进入“创作 → 文章”;明确修改/恢复指定旧稿才进入“管理 → 草稿箱”。意图不明确时返回 `OPERATION_INTENT_REQUIRED`,不得导航。
|
|
106
|
+
3. 对修改/恢复任务,按完整标题、正文主题和最近保存时间找到目标草稿;不得从“创作 → 文章”新建空白草稿。
|
|
107
|
+
4. 打开目标草稿后重新读回标题、正文首尾、字数、全部正文图片主题和封面内容,确认身份后才继续修改。
|
|
108
|
+
5. 不得因恢复失败创建第二篇文章。
|
|
109
|
+
|
|
110
|
+
## 临时失败
|
|
111
|
+
|
|
112
|
+
- 单次浏览器控制失败时保持当前 browser、page、Profile 和 lock,短暂重试同一只读或可逆操作。
|
|
113
|
+
- 禁止因一次失败关闭浏览器、`kill` controller、释放 lock 或创建第二个浏览器。
|
|
114
|
+
- 连续失败时返回 `CUA_SESSION_FAILED` 并保留现场,供人工检查。
|
|
115
|
+
|
|
116
|
+
## 返回结果
|
|
117
|
+
|
|
118
|
+
至少返回:
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
state=draft_saved|title_invalid|content_required|operation_intent_required|target_draft_required|login_required|account_mismatch|new_article_page_not_empty|existing_draft_conflict|draft_identity_mismatch|licensed_image_not_found|image_insert_indeterminate|auto_save_timeout|draft_indeterminate|cua_session_failed
|
|
122
|
+
task_id=<稳定任务标识>
|
|
123
|
+
profile_id=<非敏感 Profile 标识>
|
|
124
|
+
account_name=<页面可见名称或 unknown>
|
|
125
|
+
operation_intent=new|modify_existing|verify_existing|unknown
|
|
126
|
+
browser_session_reopened=true|false
|
|
127
|
+
new_article_route_used=true|false
|
|
128
|
+
empty_editor_verified=true|false|not_applicable
|
|
129
|
+
existing_draft_reused=true|false
|
|
130
|
+
cross_task_evidence_detected=true|false
|
|
131
|
+
title=<页面读回完整标题>
|
|
132
|
+
body_verified=true|false
|
|
133
|
+
licensed_image_selected=true|false
|
|
134
|
+
licensed_image_query=<搜索词或 not_used>
|
|
135
|
+
image_inserted=true|false
|
|
136
|
+
body_image_count=<正文最终图片数>
|
|
137
|
+
body_image_subjects=<逐张可见主题>
|
|
138
|
+
current_task_image_verified=true|false
|
|
139
|
+
cover_mode=单图|三图|无封面|unknown
|
|
140
|
+
cover_confirm_clicked=true|false
|
|
141
|
+
cover_subject=<封面可见主题或 unknown>
|
|
142
|
+
auto_save_text=<页面可见保存状态或 unknown>
|
|
143
|
+
auto_save_confirmed=true|false
|
|
144
|
+
draft_found=true|false
|
|
145
|
+
section=管理/草稿箱|not_run
|
|
146
|
+
status_evidence=<可见文字、时间和匹配摘要>
|
|
147
|
+
current_url=<移除敏感查询参数后的 URL>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
新建任务还必须满足 `new_article_route_used=true`、`empty_editor_verified=true`、`existing_draft_reused=false`、`cross_task_evidence_detected=false` 和 `current_task_image_verified=true`。加上正文图片内容正确、封面内容正确且已点击弹层“确认”、`auto_save_text=草稿已保存`、`auto_save_confirmed=true`,并在“管理 → 草稿箱”找到目标文章,才能报告“文章草稿已保存并核验完成”。当前 URL 仍为 `/graphic/publish` 时不得声称已完成草稿箱核验。
|
|
151
|
+
|
|
152
|
+
## 收尾
|
|
153
|
+
|
|
154
|
+
成功或只读查询结束后正常关闭 page/context/browser 并释放 lock,让 Profile 正常写盘。失败或不确定状态默认保留现场供人工检查。禁止使用 `kill`、`pkill`、清空 `browser_data`、删除草稿或自动重新创建文章。
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: toutiao-web-login
|
|
3
|
+
description: 登录并固化 toutiao.com 今日头条主站账号会话。用于点击右上角登录、从登录弹层截取扫码二维码并通过飞书发送、扫码后核验右上角可见账号是否为用户指定账号,以及正常关闭后使用同一独立 Profile 重启验证免扫码登录。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 今日头条主站登录固化
|
|
7
|
+
|
|
8
|
+
仅处理 `toutiao.com` 的登录、账号核验和会话持久化,不发布、评论、点赞或采集内容。
|
|
9
|
+
|
|
10
|
+
## 运行边界
|
|
11
|
+
|
|
12
|
+
- 从正式社媒运行目录执行,并先读取当地 `AGENTS.md` 与 `media-agent --help`。
|
|
13
|
+
- 每个真实头条账号使用独立 `profile_id`、`browser_data`、固定指纹和 lock。禁止临时 Profile、跨账号共用状态、复制 Cookie 或导出登录态。
|
|
14
|
+
- 保持一个 controller、browser、context 和 page。飞书回复结束、新消息、上下文压缩或客户端超时不得关闭浏览器。
|
|
15
|
+
- 先获取 Profile 唯一 lock。活 owner 存在时返回 `PROFILE_LOCKED`,不得抢锁、强删或并行打开同一 `browser_data`。
|
|
16
|
+
- 使用可视浏览器和 DOM 定位;禁止 HTTP 登录、Cookie 注入、坐标盲点、`kill`、`pkill` 或批量结束浏览器。
|
|
17
|
+
- 不读取、不返回 Cookie、token、Local Storage、二维码内容、手机号或私信。
|
|
18
|
+
|
|
19
|
+
## 命令
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
media-agent toutiao-login-start <profile_id>
|
|
23
|
+
media-agent toutiao-login-status <profile_id>
|
|
24
|
+
media-agent toutiao-login-scan-done <profile_id>
|
|
25
|
+
media-agent toutiao-login-verify-account <profile_id> --expected-account-name <昵称>
|
|
26
|
+
media-agent toutiao-login-refresh-qr <profile_id>
|
|
27
|
+
media-agent toutiao-login-close <profile_id>
|
|
28
|
+
media-agent toutiao-check-login <profile_id>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
后续消息只通过带 `request_id` 的现有 Unix Socket 推进原 controller;不得再次执行 `toutiao-login-start`。
|
|
32
|
+
|
|
33
|
+
`toutiao-login-scan-done` 立即返回 `VERIFYING_LOGIN`;使用 `toutiao-login-status` 有界查询最终账号状态。账号预期值有误时,在原 controller 中调用 `toutiao-login-verify-account`,不得重新扫码。
|
|
34
|
+
|
|
35
|
+
## 状态机
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
INIT -> LOCK_PROFILE -> OPEN_TOUTIAO -> INSPECT_LOGIN
|
|
39
|
+
INSPECT_LOGIN -> OPEN_LOGIN_MODAL -> WAIT_QR_SCAN
|
|
40
|
+
WAIT_QR_SCAN -> VERIFYING_LOGIN -> VERIFY_ACCOUNT
|
|
41
|
+
VERIFY_ACCOUNT -> ACCOUNT_CONFIRMED -> SAVING_PROFILE
|
|
42
|
+
SAVING_PROFILE -> REOPEN_VERIFY -> COMPLETE
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
恢复:`QR_EXPIRED -> REFRESH_QR -> WAIT_QR_SCAN`。证据冲突进入 `INDETERMINATE` 并短轮询,不能直接要求重扫。
|
|
46
|
+
|
|
47
|
+
## 登录与二维码交付
|
|
48
|
+
|
|
49
|
+
1. 打开 `https://www.toutiao.com/`,等待页面稳定。
|
|
50
|
+
2. 若右上角已显示用户头像或账号名且登录弹层不存在,直接进入账号核验。
|
|
51
|
+
3. 否则只点击右上角全站“登录”一次。不要误点正文、侧栏或广告中的登录按钮。
|
|
52
|
+
4. 在弹层中确认“扫码登录”和完整二维码可见。优先截取二维码元素;无法可靠定位元素时,截取包含二维码和“扫码登录”文字的最小弹层区域。
|
|
53
|
+
5. 验证图片存在、非空、二维码未裁切或遮挡,通过飞书发送真实图片附件;本地路径和 Markdown 路径不算交付。
|
|
54
|
+
6. 回复包含 `task_id`、`profile_id`、`controller_pid`、`state=WAIT_QR_SCAN`,但不包含浏览器数据路径或凭据。
|
|
55
|
+
7. 用户只扫描最新附件并在今日头条 App 确认。等待时保持原 browser、page、controller 和 lock。
|
|
56
|
+
8. 二维码过期时只操作当前二维码容器内的刷新控件,确认 PID、browser、page 未变化后发送新附件,旧码作废。
|
|
57
|
+
9. 用户确认扫码后,在原 page 最多轮询 60 秒;右上角账号/头像出现且登录弹层、二维码消失是主要证据。
|
|
58
|
+
|
|
59
|
+
## 账号核验
|
|
60
|
+
|
|
61
|
+
1. 读取右上角唯一可见账号区域;如需 hover 才出现昵称,使用 DOM hover,不用固定坐标。
|
|
62
|
+
2. 保存包含可见账号名的非敏感截图,并通过飞书发送核验摘要。
|
|
63
|
+
3. 将规范化后的页面账号名与任务中 `expected_account_name` 比较:
|
|
64
|
+
- 明确一致:`ACCOUNT_CONFIRMED`。
|
|
65
|
+
- 明确不一致:`ACCOUNT_MISMATCH`,停止固化;保持会话并请求用户决定,不自动退出或切号。
|
|
66
|
+
- 页面字段不足或用户未指定:`WAIT_ACCOUNT_CONFIRM`,不得自行推断。
|
|
67
|
+
4. 不得仅凭头像、粉丝数或历史截图判定身份。任何历史验收昵称都不得硬编码进运行时或通用 Skill。
|
|
68
|
+
|
|
69
|
+
## 固化与同 Profile 重启验证
|
|
70
|
+
|
|
71
|
+
仅在账号已确认后执行:
|
|
72
|
+
|
|
73
|
+
1. 通过 controller 正常关闭 page/context/browser,使状态写入原 `browser_data`。
|
|
74
|
+
2. 确认浏览器进程退出后由 owner 释放 lock;等待至少 10 秒。
|
|
75
|
+
3. 使用完全相同的 Profile、指纹和启动参数重开 `https://www.toutiao.com/`,最多等待 60 秒。
|
|
76
|
+
4. 证明登录弹层和二维码未出现,右上角再次显示同一账号名。
|
|
77
|
+
5. 再次正常关闭,确认浏览器进程和 lock 均已清理。
|
|
78
|
+
|
|
79
|
+
只有完成以上完整链路才能报告 `persistence_verified=true`。Cookie 文件存在、缓存 `state.json` 或一次 URL 读数都不算成功证据。
|
|
80
|
+
|
|
81
|
+
## 返回格式
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
profile_id=<profile_id>
|
|
85
|
+
task_id=<task_id>
|
|
86
|
+
login_status=logged_in
|
|
87
|
+
account_display_name=<页面可见昵称>
|
|
88
|
+
expected_account_name=<用户指定昵称>
|
|
89
|
+
account_verified=true
|
|
90
|
+
persistence_verified=true
|
|
91
|
+
relogin_qr_required=false
|
|
92
|
+
browser_process_remaining=0
|
|
93
|
+
lock_remaining=0
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
等待或失败必须返回:`PROFILE_LOCKED`、`RUNTIME_CAPABILITY_MISSING`、`WAIT_QR_SCAN`、`QR_EXPIRED`、`INDETERMINATE`、`WAIT_ACCOUNT_CONFIRM`、`ACCOUNT_MISMATCH` 或 `SESSION_LOST`。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: xiaohongshu-creator-image-text-publish
|
|
3
|
+
description: 用于用户提供有序本地图片、标题和正文后,在小红书创作服务平台准备或发布图文笔记,以及核验或恢复该图文任务。不要用于视频、长文、登录或生成文案和图片。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 小红书图文发布(可见浏览器)
|
|
7
|
+
|
|
8
|
+
从 social-auto-upload 的图文 Skill 和 `XiaoHongShuNote` 提取页面流程,由 Agent 操作本项目可见持久化浏览器。状态为 **ADAPTED_UNVERIFIED**:已提取适配,尚未完成真实账号图文验收。
|
|
9
|
+
|
|
10
|
+
执行前必须读取 [任务与会话契约](references/execution-contract.md)。页面定位线索和上游固定版本见 [提取来源](references/upstream.md)。
|
|
11
|
+
|
|
12
|
+
## 输入与路由
|
|
13
|
+
|
|
14
|
+
- 必需:`profile_id`、稳定 `task_id`、有序 `images`(本地绝对路径)、用户提供的 `title` 和 `body`;可选 `tags`。正文允许用户明确指定空字符串,缺失不等于留空。
|
|
15
|
+
- “上传看看/准备/预览”走 `prepare`,停在 `PREPARED`;明确“发布这些图文”走 `publish`,授权绑定当前账号及完整内容;“查结果”走只读 `verify`。意图不明时先澄清。
|
|
16
|
+
- 图片顺序以传入列表为准,不按文件名排序。只接收图片;视频使用 `xiaohongshu-creator-publish`,长文不走本流程。
|
|
17
|
+
- 成稿原样填写;超出页面限制返回 `CONTENT_INVALID`,不截断、改写或自动生成标题、正文、封面和配图。用户要求定时或其他扩展设置时返回 `UNSUPPORTED_OPTION`,本版仅立即发布。
|
|
18
|
+
|
|
19
|
+
## 进入图文编辑页
|
|
20
|
+
|
|
21
|
+
1. 按契约核对 Profile、`creator_publish`、锁所有权及真实页面账号。保持同一个 browser/context/page,`headless=False`;不运行 `sau`,不安装或调用第三方 MCP,不复制 Cookie。
|
|
22
|
+
2. 从 `https://creator.xiaohongshu.com/` 点击实际可见的“发布笔记/上传图文”入口。上游路由线索为 `/publish/publish?from=homepage&target=image`;必须以当前页面图文标签和图片上传控件确认类型,不能沿用视频发布页或切到“写长文”。
|
|
23
|
+
3. 若原生文件选择器自动出现,取消并确认整个窗口消失;不从最近文件中盲选。对非必要位置权限选择不允许,关闭“恢复页面”提示,不恢复未知旧稿。
|
|
24
|
+
4. 在当前图文面板定位接收图片的 file input;候选选择器见来源文档。多个上传 input 并存时用所在面板和接收类型消歧,不直接取第一个。
|
|
25
|
+
5. 编辑器若已有其他图片、标题或正文,返回 `EDITOR_NOT_EMPTY`,不清空或覆盖旧稿;只有本任务明确恢复且身份重新核验通过的页面可继续。
|
|
26
|
+
|
|
27
|
+
## 上传并填写
|
|
28
|
+
|
|
29
|
+
1. 校验本地图片稳定可读、实际格式与页面允许格式一致,保存每张 SHA-256 和顺序;先检查任务记录中的重复与未决提交。
|
|
30
|
+
2. 用当前控制器的文件上传能力一次传入有序图片清单,进入 `UPLOADING`。标题框出现只是页面线索,不能证明全部图片上传完成。
|
|
31
|
+
3. 最多等待 5 分钟,读取逐张上传状态和错误;所有图片预览的数量、内容和顺序均与清单一致、进度已结束才可继续。少图、顺序不明或超时按契约停止,不整批重传。
|
|
32
|
+
4. 在“填写标题”输入框原样填写标题;确认正文 `contenteditable` 所在区域后原样填写正文,保留段落。不要把正文粘进标题,也不采用上游标题截取逻辑。
|
|
33
|
+
5. 只添加用户给定话题,核对候选的准确名称后选择;不能自动选择第一个推荐话题。找不到时返回 `TAG_UNRESOLVED`,数量超过当前页面允许值时返回 `CONTENT_INVALID`,不静默跳过、裁减或替换。
|
|
34
|
+
6. 收起话题浮层,分别读回标题、正文、话题和逐张图片。保持用户图片顺序及平台默认首图展示,不另做封面、裁剪、内容类型声明、转载来源、位置、商品或活动;页面强制要求未提供设置时返回 `SETTING_REQUIRED`。
|
|
35
|
+
7. 确认立即发布,读回可见范围及任何平台自动附加项。保存准备快照并返回 `PREPARED`。仅准备任务在此停止并保持会话,不声称已保存平台草稿。
|
|
36
|
+
|
|
37
|
+
## 单次提交与笔记核验
|
|
38
|
+
|
|
39
|
+
1. 按契约重新核验账号、授权、快照及素材,持久化 `SUBMITTING` 后,对唯一可见、启用、无遮挡的“发布”按钮执行一次真实 locator/pointer click。禁止 JS `element.click()` 和循环提交。
|
|
40
|
+
2. 等待同一页面结果,最长 180 秒,期间不刷新、不返回、不再点击。`/publish/success` 同时显示“发布成功”,或页面明确“发布成功/数秒后返回”,才是平台接收证据,记录 `SUBMITTED`。
|
|
41
|
+
3. 成功页可能自动回到空上传页,这不代表发布失败。看到接收证据后保持会话,等待约 10 秒,点击左侧“笔记管理”,明确选择“全部”。
|
|
42
|
+
4. 按目标账号、图文类型、完整标题、本次提交时间及图片预览综合识别,排除同名旧笔记。不要用视频时长作图文匹配条件。
|
|
43
|
+
5. 每 15–20 秒只读核验,最多 5 分钟。目标唯一出现但审核未知为 `SUBMITTED`;明确审核中为 `REVIEWING`;明确已发布为 `PUBLISHED`;明确未通过为 `REJECTED`。一直审核中仍返回 `REVIEWING`;未找到或有歧义为 `PUBLISH_INDETERMINATE`,禁止重发。
|
|
44
|
+
6. 没有明确接收证据或点击调用超时时依契约保留现场,仅作只读核验。成功页和本地点击返回不能直接升级为 `PUBLISHED`。
|
|
45
|
+
|
|
46
|
+
结果字段、跨消息恢复和收尾均按 [任务与会话契约](references/execution-contract.md) 执行。图文没有新增 CLI;现有 `xhs-publish-*` 仍是视频命令。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 dreammis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Agent 图文任务与会话契约
|
|
2
|
+
|
|
3
|
+
本文件定义 Agent 应遵守的步骤,不是已经实现这些门禁的发布 CLI。需要宿主提供可见浏览器控制、文件上传和任务记录读写能力;缺少能力时报告具体阻塞,不编造命令或执行结果。
|
|
4
|
+
|
|
5
|
+
## 会话前提
|
|
6
|
+
|
|
7
|
+
- 只使用目标账号已配置的持久化 Profile、`browser_data`、固定指纹和唯一 lock,确认 `creator_publish` capability。实际运行目录以部署配置为准,不硬编码开发机器路径。
|
|
8
|
+
- 当前 browser/context/page 和 lock 已归本任务时复用原控制器。其他任务持锁或无法证实所有权时返回 `PROFILE_LOCKED`,不抢锁、不强删锁、不启动第二个浏览器。
|
|
9
|
+
- 尚无会话时,由本项目既有可见浏览器运行时按原 Profile 配置及 `headless=False` 建立会话、取得锁;无法取得受控页面时返回 `BROWSER_SESSION_REQUIRED`。本 Skill 不提供另一套浏览器启动器。
|
|
10
|
+
- 在当前页面核验真实账号及后台菜单;不能仅凭 Cookie 文件、URL 或缓存认定登录。无法确认账号返回 `ACCOUNT_UNVERIFIED`,账号不符返回 `ACCOUNT_MISMATCH`,登录失效返回 `LOGIN_REQUIRED` 并交给平台专用登录 Skill。已有锁期间不要另跑会启动浏览器的登录检查命令。
|
|
11
|
+
- 保持现有窗口、控制器和锁直到任务结束。禁止无头浏览器、临时 context、复制登录态、Cookie 导入导出、第三方 MCP 或 `sau ... upload-note`。上游 `--headed` 不是现有会话的接管接口。
|
|
12
|
+
|
|
13
|
+
## 内容与准备快照
|
|
14
|
+
|
|
15
|
+
1. 输入缺失返回 `INPUT_REQUIRED`,等待用户提供;正文明确留空可接受。完整文案原样使用,不自动生成、截断或润色;图像不自动生成、编辑或替换。
|
|
16
|
+
2. 图片必须是稳定普通文件,记录绝对路径、大小、真实格式和 SHA-256,检查前后大小/修改时间一致;只按后缀判断格式不够。不支持或仍在写入时停止。
|
|
17
|
+
3. `media_digest` 是有序图片 SHA-256 字符串数组的 UTF-8 JSON 的 SHA-256。用以下 JSON 对象的 SHA-256 构造 `payload_digest`:`platform`、`profile_id`、`title`、`body`、有序 `tags`、有序 `images_sha256`、`publish_mode=immediate`。二者均采用 JSON 对象键排序、`ensure_ascii=False`、无多余空白;数组顺序不变。记录页面实际设置的快照,不能仅记录输入期望值。
|
|
18
|
+
4. 任务记录放在运行时的 `tasks/<platform>_image_text_publish/<profile_id>/<task_id>/`。标识只能用字母、数字、下划线、短横线,禁止路径穿越;该目录和任何截图、账本均不得进入 Git 或迁移包。
|
|
19
|
+
5. 持有账号锁时,扫描同平台同账号所有图文任务记录;相同 `media_digest` 已处于 `SUBMITTING`、`SUBMITTED`、`REVIEWING`、`PUBLISHED` 或 `PUBLISH_INDETERMINATE`,先核验旧任务,不新建发布。改标题或换 `task_id` 不解除阻止;其他账号的平台记录不能误挡当前任务。
|
|
20
|
+
6. 每个任务维护追加式 `events.jsonl`,记录任务、两个摘要、会话身份、状态、可见证据及时间;不能写入凭据。旧记录不可覆写。首次任务可新建记录;已知旧任务记录缺失、损坏、无法持久化或历史提交无法查清时返回 `LEDGER_UNAVAILABLE`,禁止提交。
|
|
21
|
+
7. 用编辑器内逐张预览核对数量、内容和顺序;头像、推荐图片、上传占位符不计入。数量一致但顺序或对应内容无法核实,也不能给出 `images_verified=true`。返回 `UPLOAD_INCOMPLETE` 或 `IMAGE_ORDER_UNVERIFIED`,保持现场,不整批重传。
|
|
22
|
+
8. 标题、正文、话题和页面设置均须读回。正文仅可为比较而统一 CRLF/LF;不能通过删空格、删段落等方式掩盖实际差异。平台话题 token 应与正文分别核验。身份或内容不一致返回 `CONTENT_MISMATCH`。
|
|
23
|
+
9. 门禁均通过后持久化 `PREPARED` 事件,保存快照及截图证据路径。仅准备时保持浏览器和 lock,返回 `submit_attempted=false`;不声称已保存平台草稿,除非另有真实草稿保存与列表证据。
|
|
24
|
+
|
|
25
|
+
## 发布授权与一次提交
|
|
26
|
+
|
|
27
|
+
- 授权包含当前 `task_id`、账号、`payload_digest` 和页面设置。用户明确要求发布给定成稿时,该指令就是本任务授权,不重复索取同一授权;“准备看看”没有发布授权。后续“发布”只能绑定唯一、完整读回的准备任务。
|
|
28
|
+
- 正文、图片字节、顺序、账号或设置有变化时,准备快照及旧内容授权失效。先说明差异、重新核验并确认变更后的内容,不偷偷替换。
|
|
29
|
+
- 提交前再次核验账号、页面、图片哈希与顺序、完整文案、设置和按钮唯一/可见/启用/无遮挡。先追加并持久化 `SUBMITTING`、`submit_attempted=true`、授权摘要和时间,再发出一次真实点击。记录写入失败则不点击。
|
|
30
|
+
- 点击调用超时或抛异常,也属于已经尝试提交;禁止重新调用点击,不能等工具返回成功才记下提交意图。日志无法确定是否点过时同样按不确定处理。
|
|
31
|
+
- 提交后有明确接收证据才能记 `SUBMITTED`;只有平台目标作品状态才能给出 `REVIEWING`、`PUBLISHED`、`REJECTED`。按钮消失、URL 改变、固定等待结束和本地日志不能单独证明发布。
|
|
32
|
+
- 无响应、网络超时、作品缺失或同名歧义都进入 `PUBLISH_INDETERMINATE`。先等待规定窗口再只读核验;平台无明确接收结果时保持当前页,可在同一 context 的只读标签页查看作品管理,不新开浏览器。禁止自动再次提交、上传或改标题重发。
|
|
33
|
+
|
|
34
|
+
## 中断、恢复与收尾
|
|
35
|
+
|
|
36
|
+
- 会话关闭后,旧 page、DOM、准备快照的页面证据全部失效。持久化 Profile 只证明可能保留登录,不证明编辑器保留。
|
|
37
|
+
- 恢复前读取旧任务记录。有提交意图或意图不明时,只读核验作品,不能重新准备发布。
|
|
38
|
+
- 明确从未尝试提交时,允许由现有运行时重开同一 Profile;重新核验账号,按平台真实草稿证据唯一恢复本任务。没有可核验草稿时返回 `PREPARE_SESSION_LOST`,不得自动新建、重传或点击;用户明确要求重新准备后才可继续。
|
|
39
|
+
- 临时控制失败保持现场;只能重试已确定无提交副作用的读取/可逆动作,不能把失败处理包装成再次点击发布。
|
|
40
|
+
- 仅准备或结果不确定时默认保留会话与锁。用户要求关闭时先持久化状态,再正常关闭本任务拥有的 page/context/browser,确认退出后释放本任务锁;不确定状态仍禁止重发。用户未要求关闭时,已发布/明确拒绝/只读查询完成可正常收尾。禁止 `kill`、清空 Profile 或删除作品。
|
|
41
|
+
|
|
42
|
+
## 最小返回
|
|
43
|
+
|
|
44
|
+
返回 `state`、`platform`、`task_id`、`profile_id`、`account_verified`、`media_digest`、`payload_digest`、`expected_image_count`、`actual_image_count`、`images_verified`、`image_order_verified`、`title`、`body_verified`、`tags_verified`、`settings_readback`、`submit_attempted`、`work_found`、`work_id`(拿不到为 null)、`status_evidence`、`browser_retained`、`lock_retained`。
|
|
45
|
+
|
|
46
|
+
缺失证据用 false/unknown/null 表达,不能补造。准备完成、平台接收、审核中和审核通过必须分别报告。
|