feat: publish xianyu hunter hermes skill package

This commit is contained in:
2026-05-06 19:26:45 +08:00
commit 6384156097
59 changed files with 9627 additions and 0 deletions
@@ -0,0 +1,99 @@
# Web Hermes Analysis + Notifications (2026-05)
Session learning from extending BOSS's local `xianyu-hunter` fork with Web-visible analysis and notification controls.
## Product shape BOSS expects
When adding analysis/notification capability, make it visible in the Web dashboard, not only as backend APIs:
- Header button: **通知设置**.
- Task controls: **执行分析** beside edit/duplicate/start/rerun/delete.
- New task tab: **Hermes 分析** with recommendation/caution/reject summary and item cards.
- Product list should show analysis verdict badges and concise reasons inline.
- Analysis should persist into `data/tasks.json` and generate a Markdown report under `reports/`.
## Backend API pattern
Add a lightweight local analysis layer and notifier:
- `lib/analyzer.mjs`
- `buildAnalysis(task, { limit })` returns `{ items, summary }`.
- `renderAnalysisMarkdown(task, summary)` writes `reports/<task_id>-analysis.md`.
- Include item-level `hermesAnalysis: { score, verdict, reason, flags, positives, analyzedAt }`.
- `lib/notifier.mjs`
- `GET /api/notify-config` and `PUT /api/notify-config` backed by `data/notify-config.json`.
- `sendNotifications(task, summary, { force })` supports:
- `hermes-webhook`: POST `{ message, target, source, taskId }`.
- `bark`: POST `{ title, body, group }` to `https://api.day.app/<key>` or configured endpoint.
- `pushplus`: POST `{ token, title, content, template:'txt' }`.
- `webhook`: generic JSON `{ title, message, taskId }`.
- `server.mjs`
- `POST /api/tasks/:id/analyze` should call `taskManager.analyzeTask`, write report, persist summary, and optionally notify.
## TaskManager persistence details
- Add `getTaskFull(id)` for routes that need full in-memory task data.
- Add `setTaskAnalysis(id, analysis)` that merges item `hermesAnalysis` into `products.fineFiltered`, stores `task.hermesAnalysis`, persists to disk, and emits `task:updated`.
- Include `hermesAnalysis` in `_serialize`, `_serializeFull`, and `_loadFromDisk`.
- Clear `task.hermesAnalysis = null` when resetting products/rerunning a task.
- New/duplicated tasks should initialize `hermesAnalysis: null`.
## Frontend implementation details
- Bump asset query versions in `index.html` after changing CSS/JS to avoid stale browser cache (`style.css?v=11`, `app.js?v=11`, etc.).
- `public/app.js` helpers:
- `analyzeTaskNow(id)` calls `POST /api/tasks/:id/analyze` with `{ notify: true }`, then refreshes task detail.
- `renderAnalysis()` renders empty state, stat cards, report path, and scored item cards.
- When rendering raw product rows, map analysis from `products.fineFiltered` by `id`; raw items often do not contain the merged `hermesAnalysis` directly.
- Preserve notification channel `id` when saving from the form; otherwise repeated saves create new channel IDs.
## Verification checklist
Run syntax checks:
```bash
cd /Users/chick/.Hermes/workspace/research/xianyu-hunter
node --check server.mjs
node --check lib/task.mjs
node --check lib/analyzer.mjs
node --check lib/notifier.mjs
node --check public/app.js
```
Restart exact stale listener if `xianyu_ops.mjs stop` says `no-recorded-server` but port is still occupied:
```bash
pid=$(lsof -nP -iTCP:3000 -sTCP:LISTEN -t || true)
[ -z "$pid" ] || kill "$pid"
node tools/xianyu_ops.mjs start --port 3000
```
Smoke test APIs:
```bash
curl -fsS http://127.0.0.1:3000/api/notify-config | python3 -m json.tool
curl -fsS http://127.0.0.1:3000/api/tasks -o /tmp/xh_tasks.json
TASK=$(python3 - <<'PY'
import json
j=json.load(open('/tmp/xh_tasks.json'))
print(j[0]['id'] if j else '')
PY
)
curl -fsS -X POST "http://127.0.0.1:3000/api/tasks/$TASK/analyze" \
-H 'Content-Type: application/json' \
-d '{"notify":false,"limit":10}' | python3 -m json.tool
```
Important pitfall: piping a large `/api/tasks` response directly into `python3 - <<'PY'` consumes stdin for the script, not JSON. Save curl output to a temp file first.
## Model-specific scoring pitfall: E3-1245v3
For CPU searches like `E3-1245v3`, scoring must distinguish true target models from related models used as SEO keywords.
Rules added in `lib/analyzer.mjs`:
- If the task query indicates `E3-1245v3`, require an exact-ish match: `e3\s*-?\s*1245\s*[_-]?\s*v3`.
- Penalize titles whose main model is another E3 v3, e.g. `E3-1275v3 ... 性能超 E3-1245v3`, because the title may only use 1245v3 as a comparison/keyword.
- Flag failure terms beyond obvious `坏/不亮/暗病`, including `不能进系统`.
This reduced false recommendations in the E3-1245v3 task from related CPUs and broken parts.