3.7 KiB
Goofish Login UX, Browser Lock, and Partial-Result Recovery — 2026-05
What happened
During a Goofish/Xianyu search task, a temporary helper opened a direct Taobao unified-login URL and sent its screenshot as a "real login QR". BOSS correctly objected that it looked like a Taobao login page and not the expected Xianyu entry.
Goofish web login is backed by Alibaba/Taobao account infrastructure, so login.taobao.com can be normal after following the Goofish login flow. However, for BOSS UX, do not present a direct Taobao URL/screenshot as if it were the Xianyu login entry.
Preferred login workflow
- Start/keep the dashboard service.
- Open
https://www.goofish.com/in the persistent Playwright profile (browser-data/). - Let BOSS interact with the visible browser window and click the Goofish page's own login/modal/QR controls.
- If a screenshot is needed, label it accurately: "Goofish page login/modal; may redirect to Taobao unified login".
- After BOSS says login is done, close any temporary helper Chromium using the same profile before running task automation.
- Verify with
GET /api/login/statusagainst a real search page, not homepage only.
Pitfall: ProcessSingleton / SingletonLock
If a temp QR/login helper is still using browser-data/, later dashboard/API/task runs may fail with:
browserType.launchPersistentContext: Failed to create a ProcessSingleton for your profile directory
... browser-data/SingletonLock: File exists (17)
Safe recovery used in this session:
cd /Users/chick/.Hermes/workspace/research/xianyu-hunter
pkill -f 'xianyu_goofish_login_entry_tmp.mjs|xianyu_qr_login_tmp.mjs' || true
pkill -f 'Google Chrome for Testing.*xianyu-hunter/browser-data' || true
sleep 2
for p in $(lsof -tiTCP:3000 -sTCP:LISTEN 2>/dev/null); do kill "$p" 2>/dev/null || true; done
sleep 1
PORT=3000 node server.mjs
Then verify:
curl -sS -m 60 http://127.0.0.1:3000/api/login/status | python3 -m json.tool
A good result includes loggedIn: true, loginWall: false, nonzero cookieCount, and product cards on a search URL.
Partial-result recovery
If a run is interrupted during fine_filter, tools/hermes_report.mjs may report 候选 0 because it only sees fineFiltered. Do not conclude there were no products. Inspect data/tasks.json and mine products.coarseFiltered or products.raw directly.
Example used for E3-1245v3:
python3 - <<'PY'
import json,re
from pathlib import Path
p=Path('data/tasks.json')
data=json.loads(p.read_text())
t=[x for x in data if x.get('id')=='<task_id>'][0]
items=t.get('products',{}).get('coarseFiltered',[]) or t.get('products',{}).get('raw',[])
def price_num(v):
m=re.search(r'(\d+(?:\.\d+)?)', str(v or '').replace(',',''))
return float(m.group(1)) if m else None
for it in items:
title=(it.get('title') or '').lower().replace('-',' ')
text=' '.join(str(it.get(k,'')) for k in ['title','description','detailDescription']).lower()
if '1245' in title and 'v3' in title and not any(w in text for w in ['回收','求购','主板','套装','整机','散热','维修','不包含 cpu']):
print(it.get('price') or it.get('detailPrice'), it.get('location') or it.get('sellerLocation'), it.get('title'), it.get('href') or it.get('url'))
PY
Presentation guidance
When reporting results to BOSS:
- State the live status first (login ok, task id, counts raw/coarse/fine, whether run completed or was interrupted).
- If a report says 0 candidates but raw/coarse has data, explicitly explain that this is a stage/report limitation.
- Rank candidates by closeness to budget and risk, and call out exclusions (e.g. "不包含 CPU", "不能进系统", "回收", "主板套装").