Files
2026-09-23 19:49:59 +08:00

4.9 KiB
Raw Permalink Blame History

agent 调用方式

必备工具

  • HTTP 客户端:agent 自带 web_fetch / curl / Node 22 fetch 任一
  • Node 22:执行 scripts/pospal.mjs(Linux / macOS 自带 node 或 NVM)
  • 隐藏式输入:Linux/macOS bash read -rs、或 Node readline 关闭回显
  • 单次请求硬性超时:AbortSignal.timeout(12000)(12 秒)

凭证管理

首次获取(agent 主动询问)

printf "PSPLVISITORID: " >&2
IFS= read -rs PSPAL_VISITOR_ID
printf "\n" >&2

旧版 bash 不支持 -s 时:

stty -echo
printf "PSPLVISITORID: " >&2
read PSPAL_VISITOR_ID
stty echo
printf "\n" >&2

注入到 helper 调用

export POSPAL_VISITOR_ID="$PSPAL_VISITOR_ID"
node scripts/pospal.mjs build-booking-body < continuous-slots.json

helper 也支持 --visitor <value>,但优先用 env——避免值出现在进程列表 (ps aux)。

Session 结束

unset POSPAL_VISITOR_ID

新 session 必须重新索取,不允许持久化。

helper 子命令

子命令 作用 何时用
parse-availability 把 list 端点原始 JSON 转结构化 slots(含状态判定、活动合并) 每次拿到 list 响应后必跑
find-continuous 从 slots 中找符合 --start HH --end HH 的完整连续组合 拿到结构化 slots 后
build-booking-body 从连续组合生成锁场请求体 锁场前
parse-booking-response 解析锁场响应,剥离 script.paySign 锁场后
fingerprint 访客凭证 → 12 字符 hex 指纹 日志关联
redact 任意 JSON → 移除敏感字段 落盘或汇报前

所有子命令从 stdin 读 JSON(除 fingerprint),都支持 --help。

工作流示例

单次查询

# 1. 调 list 端点
RAW=$(curl -sS -X POST 'https://wxservice-stg48.pospal.cn/wxapi/AppointmentVenue/LoadValidClassRoomApptSettingV2' \
  -H 'Accept: */*' \
  -H 'APPTYPE: 1' \
  -H 'Content-Type: application/json' \
  -H 'PSPLVISITORAUTO: API' \
  -H 'Referer: https://servicewechat.com/wx2088ca46b47d8be7/11/page-frame.html' \
  -H 'STOREID: 6038652' \
  -H 'VERSIONINFO: NC|2026.07.03' \
  -d '{"dateTime":"2026-07-16","userId":6038652,"projectUid":"1775556129325750199"}')

# 2. 解析
echo "$RAW" | node scripts/pospal.mjs parse-availability --date 2026-07-16

# 3. 找连续组合
echo "$RAW" | node scripts/pospal.mjs parse-availability --date 2026-07-16 \
  | node scripts/pospal.mjs find-continuous --start 19 --end 21

锁场

# 1. 重新查一次(不复用旧缓存)
RAW=$(curl -sS -X POST '...' -d '...')

# 2. 解析 + 找连续 + 构造请求体
BODY=$(echo "$RAW" | node scripts/pospal.mjs parse-availability --date 2026-07-16 \
  | node scripts/pospal.mjs find-continuous --start 19 --end 21 \
  | node scripts/pospal.mjs build-booking-body)

# 3. 调锁场
RESP=$(curl -sS -X POST 'https://wxservice-stg48.pospal.cn/wxapi/AppointmentVenue/SaveVenueAppointmentV2' \
  -H "PSPLVISITORID: $POSPAL_VISITOR_ID" \
  -H @write-headers.txt \
  -d "$BODY")

# 4. 解析并脱敏
echo "$RESP" | node scripts/pospal.mjs parse-booking-response --slots continuous-slots.json

write-headers.txt 模板见 references/protocol.md 末尾。

监控循环(agent 自行实现)

for date in today, today+1, ..., today+6:
  slots = curl list(date) → parse-availability
  cont = find-continuous(slots, target_start, target_end)
  key = (date, cont.txtClassroomUid, cont.startTime, cont.endTime, sum_price)
  if cont and key not in seen:
    notify(cont)
    seen.add(key)
  elif not cont and key in seen:
    notify("removed: {key}")
    seen.discard(key)
sleep 10

整点(如 19:00:00.000)agent 主动绕过冷却立即查一次。同一 date 的并发查询只允许一个在飞。

失败处理速查

现象 agent 动作
列表返回 successed: false 视为该日无可订数据,不重试
列表返回缺字段 视为接口变更,停止对该球场所有操作,告诉用户"接口字段变化,暂停服务"
锁场 successed: false 换时段最多重试 1 次,仍失败则停下
锁场 HTTP 5xx / 网络错误 不重试,告诉用户"结果不确定,请去小程序核实"
锁场后 script.expireTime 已过 锁场已失效,告知用户
enrollSlots 含目标时段 该时段按已订处理,不计入连续组合
PSPLVISITORID 未索取 写操作前必须先向用户隐藏式索取;缺则停下

调试与脱敏

# 任何写操作前,确认 visitor 指纹
node scripts/pospal.mjs fingerprint "$POSPAL_VISITOR_ID"
# → "a3f9b21c0e4d" (12 字符)

# 落盘任何响应前必须 redact
curl ...list... | node scripts/pospal.mjs redact > list-redacted.json

# 看 helper 自检
node scripts/pospal.mjs parse-availability --date 2026-07-16 \
  < evals/fixtures/availability-sample.json

完整 list-headers.txt / write-headers.txt 模板见 references/protocol.md 末尾的 curl 示例。