Files
tennis-book/skills/tennis-booking/references/operations.md
2026-09-23 19:49:59 +08:00

153 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 主动询问)
```bash
printf "PSPLVISITORID: " >&2
IFS= read -rs PSPAL_VISITOR_ID
printf "\n" >&2
```
旧版 `bash` 不支持 `-s` 时:
```bash
stty -echo
printf "PSPLVISITORID: " >&2
read PSPAL_VISITOR_ID
stty echo
printf "\n" >&2
```
### 注入到 helper 调用
```bash
export POSPAL_VISITOR_ID="$PSPAL_VISITOR_ID"
node scripts/pospal.mjs build-booking-body < continuous-slots.json
```
helper 也支持 `--visitor <value>`,但**优先用 env**——避免值出现在进程列表 (`ps aux`)。
### Session 结束
```bash
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`。
## 工作流示例
### 单次查询
```bash
# 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
```
### 锁场
```bash
# 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` 未索取 | 写操作前必须先向用户隐藏式索取;缺则停下 |
## 调试与脱敏
```bash
# 任何写操作前,确认 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 示例。