Page Collector — 团队页面收集(客户端)
把 WorkBuddy 里生成的 HTML 页面上传到团队共享服务,拿到可访问链接。
仅限公司内网环境使用,如果上传请求不通,请提示用户在内网使用或者连接VPN。
职责边界(务必遵守)
本 skill 是客户端,只做四件事,其余一概不做:
| 服务端负责 | 本 skill(客户端)负责 |
|---|---|
| 认证 token | 取 token |
| 获取大区 | — |
| 接受上传文件 | 调 HTTP 命令上传 |
| 组织文件存储 | — |
pc.sh 脚本不做:不认证、不校验 token、不解析大区、不解析 HTML / 不做依赖发现、不自动登录、不重试。
这些逻辑放进脚本就会造成两端职责交叉。
(注意:依赖发现与内联由 AI 在上传前自己完成,属于调用方的前置准备,不写进脚本——见「输入预处理」。)
流程
- 准备入口文件(见「输入预处理」,由 AI 自己完成)
- 确认页面标题(不确定就问用户)
- 确认可见范围
visibility:用户已说明分享范围就按其说法映射;没说就先问用户(不要自行默认) - 执行
PC_VISIBILITY=<范围> scripts/pc.sh upload "<标题>" <文件>上传 - 把返回的
url原样输出给用户
输入预处理(AI 侧完成,pc.sh 不参与)
pc.sh 只接受本地文件,且不做依赖发现、不解析 HTML、不下载。
所以上传前,由 AI 自己把输入整理成 index.html + 同层依赖文件再交给 pc.sh。
A. 用户给的是本地 HTML
- 依赖发现:解析 HTML,找出所有相对资源——
-<link rel="stylesheet" href>、<script src>
-<img src>、<source src>、<video poster>等
- CSS 里的url(...)(背景图、字体) - 归置资源(必须与服务端内容安全策略对齐,否则会被拒)——
- CSS → 内联进<style>…</style>
- 图片/字体 →data:(base64)内联;体积大时也可作为独立文件同层同传
- JS 绝对不要内联进<script>—— 服务端拒收含内联脚本的文件,只允许外链<script src="app.js"></script>。JS 必须落成独立.js文件,与 index.html 同层放置
- 若源 HTML 本身含内联<script>…</script>:先把它抽成独立.js文件、改成外链引用,否则上传必被拒
- 远程 URL 资源:能下就下载后内联/同传;下不到的保留原样 - 落盘到临时目录(如
mktemp -d),入口命名为index.html,其它资源都放同一层(不建子目录——服务端会扁平化文件名) - 上传
index.html及其依赖的.js等文件;成功后清理临时目录
> 两条硬约束(都来自服务端):
> 1. 落盘会把文件名扁平化(只取 basename),子目录(如 assets/)结构会丢 —— 所以依赖文件必须放同层。
> 2. 安全层禁止内联 <script> 内容(含 document.cookie、localStorage、sessionStorage、indexedDB、eval(、new Function(、javascript:、<base href=>、<meta http-equiv=refresh>、外链 <form action="https://">、CSS expression( 也一律拒绝)。
B. 用户贴的是链接(如 https://workbuddy.link/p/...)
- 下载:AI 自己抓取,存到合适的临时目录
bash TMP="$(mktemp -d)" curl -sL "<链接>" -o "$TMP/index.html" - 若下载结果引用了相对资源,按 A 的步骤做依赖发现与资源归置(CSS/图片可内联、JS 抽成独立
.js文件同传) - 上传
$TMP/index.html;成功后清理临时目录
注意
- 内联会让文件变大,注意服务端单文件上限(5MB)与整次上限(20MB);超限时提示用户精简资源
- 上传被拒时服务端返回
validation_failed,detail会点名命中的禁用模式(如inline <script>(只允许外链))——按它修正后再重试 - 临时文件放系统临时目录(
mktemp -d/$TMPDIR),不要污染用户的项目目录 - 以上处理全部在 AI 侧完成,
pc.sh始终保持极简(不在脚本里加下载/内联逻辑)
可见范围(visibility)
上传时由 PC_VISIBILITY 指定,客户端以 -F "visibility=<值>" 随表单发送,由服务端控制谁能看(客户端不做任何鉴权/过滤):
| 值 | 含义 | 谁能看 |
|---|---|---|
private |
私有 | 仅上传者本人 |
region |
大区可见 | 与上传者同大区的用户 |
group |
客群可见 | 与上传者同客群的用户 |
引导规则(重要)
用户没有明确说"分享给谁"时,先问,不要自己挑一个默认值。
询问时把三个选项翻成用户能听懂的话(给选项让用户选,不要直接报 private/region/group 这种内部值):
| 用户可能的说法 | 对应值 |
|---|---|
| 只给自己 / 私密 / 草稿 / 不想给别人看 | private |
| 本大区 / 同大区 / 我们大区内部 | region |
| 公司可见 / 全公司 / 客群可见 / 分享给同事 | group |
> 「公司可见」等同于 group(客群可见)——客群即公司范围内的组织单元,两者按同一档处理。
用户已经明确说了范围时,直接按上表映射,不必再问。
取值只能是这三个之一,pc.sh 会拦截非法值。
命令
PC=~/.workbuddy/skills/page-collector/scripts/pc.sh
# 上传(AI 先做依赖发现:CSS/图片可内联,JS 保持外链独立文件、与 index.html 同层同传)
$PC upload "Q3 test" /tmp/pc-xxxx/index.html /tmp/pc-xxxx/app.js
# 可见范围按上面「引导规则」确定(先问用户),再显式传入:
# private(仅本人)/ region(同大区)/ group(同客群=公司可见)
PC_VISIBILITY=private $PC upload "个人草稿" /tmp/pc-xxxx/index.html
PC_VISIBILITY=group $PC upload "客群周报" /tmp/pc-xxxx/index.html
# 也接受多个文件,但服务端会扁平化文件名,仅"同目录平铺"的资源才不丢引用
$PC upload "多文件示例" /abs/path/index.html /abs/path/style.css
# 列出页面
$PC list 20
# 获取单个页面
$PC get 004011006 pg-xxxx
环境变量:
| 变量 | 说明 |
|---|---|
PC_SERVER |
服务地址,默认 https://yypt.dc.servyou-it.com/website-collector |
PC_DESC |
upload 时的描述文字(可选) |
PC_VISIBILITY |
upload 时的可见范围:private / region / group(先问用户,见「可见范围」引导规则) |
输出是服务端原始 JSON,直接读即可。
Token
获取顺序(pc.sh 内部完成):
- 环境变量
sso-epctoken(税友工作台注入) - 否则读
~/.cache/17work-cli/config.json的token
发送方式(三管齐下,服务端自行选用):
sso-epctoken: <token>
Cookie: sso-token=<t>;portal-sso-token=<t>;sso-epctoken=<t>
Authorization: Bearer <token>
> 查环境变量是否存在要用 printenv 'sso-epctoken' 或 env \| grep -i epc。
> 不要写 $sso-epctoken——名字含连字符,Bash 会解析成默认值语法,造成"有值"的假象。
Token 过期处理
出现下列任一信号,即视为 token 失效:
- 响应含
auth.not.login或api.auth.unlogon - HTTP
401 - 返回 HTML 登录页
- 响应解析失败
情况 A:工作台已注入 sso-epctoken
先确认:printenv 'sso-epctoken' 有输出。
处理:让用户重新登录平台后,在当前会话重试原操作。
不要执行登录命令 —— 环境变量存在时跑登录不会生效。
情况 B:未注入环境变量
AI 自己先跑:
npx -y --registry=https://npm.dc.servyou-it.com @servyou-ai/17work-cli@latest login
- 浏览器弹出并完成 OAuth → 自动重试原命令
- 浏览器没弹 / 命令卡住 / 失败 → 引导用户在他自己的终端跑同一条命令,完成后回来告知,再重试
错误处理
| 现象 | 原因 | 处理 |
|---|---|---|
未取得 token |
无环境变量、也无 17work CLI 缓存 | 按上方"情况 B"登录 |
401 / api.auth.unlogon |
token 失效 | 见"Token 过期处理" |
| curl 连接被拒 | 服务端未运行 | 不要尝试启动/重启服务端(部署与运行不是本 skill 的职责);直接告知用户"服务地址不可达,请确认服务端状态",然后停止 |
sso_no_region |
该账号缺大区信息 | 联系管理员补齐组织架构 |
400 validation_failed |
上传内容命中服务端禁用模式 | 按 detail 点名的问题修正(如内联 <script>)后重试 |
403 forbidden |
当前用户无权访问该页面 | 告知用户(可见范围或白名单问题),非本 skill 能解决 |
备注
- 不依赖 Python / requests / agent-browser,只需要
curl和node - 服务端接口说明见
references/api.md