Skip to main content

debug-store

Developer-only skill for poking at vibe-seller stores from outside the task system — inspect the SQLite DB, drive a store's browser-use wrapper directly via the CDP proxy, manage VIBE_TASK_ID for stable sessions, recover wedged daemons, find seller SKUs, and authenticate without the JWT cookie path. Load when the user says 'debug a store', 'why is store X broken', 'check the wrapper for store X', 'I need to drive Ziniao directly without creating a task', or anything that touches the runtime store layer outside the normal task → agent flow.

インストールへ移動

ソース情報

リポジトリ
zpoint/vibe-seller
ソースの最終更新活動
2026年8月12日 03:15
検出された SKILL.md の言語
英語
スター
68
フォーク
14

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
debug-store
description
Developer-only skill for poking at vibe-seller stores from outside the task system — inspect the SQLite DB, drive a store's browser-use wrapper directly via the CDP proxy, manage VIBE_TASK_ID for stable sessions, recover wedged daemons, find seller SKUs, and authenticate without the JWT cookie path. Load when the user says 'debug a store', 'why is store X broken', 'check the wrapper for store X', 'I need to drive Ziniao directly without creating a task', or anything that touches the runtime store layer outside the normal task → agent flow.
# Debug Store Infrastructure (developer-only) This is the inside-out view of vibe-seller stores: how to inspect and drive the runtime — the database, the browser-use wrapper, the CDP proxy, the per-store Ziniao session — *without* going through the task system, the web UI, or the JWT-cookie auth wall. This is for the platform builder, not for end-user agents running tasks. For end-user/agent flows (running campaigns, etc.), see `amazon-ads` and `new-product-launch`. ## What you can do without a task The vibe-seller per-store wrapper is just a shell script that talks to a long-running CDP-mux proxy. The wrapper auto-starts the proxy and the browser via an internal API call (with a baked-in `ai_bot` JWT, so you don't need user creds). All you need is: 1. A fresh `VIBE_TASK_ID` env var (lowercase UUID; first 8 chars must be hex). 2. The store slug (look it up in `~/.vibe-seller/data/vibe_seller.db` — `stores.name`, then slugify; or just list `~/.vibe-seller/bin/` for the directories that actually exist). Then `~/.vibe-seller/bin/<slug>/browser-use open <url>` works. ## DB cheatsheet ```bash DB=~/.vibe-seller/data/vibe_seller.db sqlite3 "$DB" .tables sqlite3 "$DB" "SELECT id, name, browser_backend, platforms, countries FROM stores;" sqlite3 "$DB" ".schema stores" sqlite3 "$DB" "SELECT id, username, email, role FROM users;" sqlite3 "$DB" "SELECT store_id, status, current_platform, current_country, active_tab_count, cdp_port, chrome_pid FROM browser_sessions;" sqlite3 "$DB" "SELECT id, status, substr(result,1,120), substr(error,1,120) FROM tasks WHERE created_at > datetime('now','-1 hour') ORDER BY created_at DESC LIMIT 10;" ``` The `stores` table has no `slug` column — the wrapper directory (`~/.vibe-seller/bin/<slug>/`) is where the actual usable name lives. `name` in DB is the user-facing label and may differ from the slug when names contain spaces / non-ascii. Match by ID when scripting. The user table is seeded on first boot with two entries: - a human admin whose username/email/password come from the `ADMIN_USERNAME` / `ADMIN_EMAIL` / `ADMIN_PASSWORD` env vars (defaults: `admin` / `admin@vibe-seller.local` / `admin`). After the first login the user can change these, so don't assume the seeded values are still current — read them from the DB. - `ai_bot` (id `00000000-0000-0000-0000-000000000002`, email `ai@vibe-seller.local`, `password_hash='disabled'`) — its JWT is baked into the wrapper for `browser/start` API calls. **Interactive login for `role='ai_bot'` is rejected by `auth.py`**, so don't try to use this account for HTTP API calls. Use it only as the internal-token subject (which the wrapper already does for you) or follow Option A below to create your own admin user. User-created accounts may also exist alongside these two seeds. `password_hash` is bcrypt; the literal `disabled` means the account cannot log in regardless of role. ## Wrapper architecture in 30 seconds Each store has a generated wrapper at `~/.vibe-seller/bin/<slug>/browser-use`. The wrapper: 1. Resolves `SESSION` from `VIBE_TASK_ID`: - With `VIBE_TASK_ID` set → `<slug>-<first 8 hex>` - Without → `<slug>` (the global session) 2. Validates the session name against `^<slug>(-aux|-[0-9a-fA-F]{8})?$`. 3. Auto-starts the CDP proxy + Ziniao Chrome by calling `POST http://127.0.0.1:7777/api/stores/<store_id>/browser/start` with a hardcoded `ai_bot` JWT. Polls until **that store's** proxy port responds — ports are allocated per store from `_BASE_PROXY_PORT` (9222), so real stores sit on 9223, 9226, 9227… Read the actual port out of the wrapper (`grep -o '127\.0\.0\.1:9[0-9]\{3\}'`) or the `browser_sessions` row; never assume 9222. 4. Exports `BU_CDP_WS=ws://127.0.0.1:<proxy_port>/client-<VIBE_TASK_ID>` so the browser-use daemon connects through the mux proxy as a unique client. (browser-use 0.13 dropped `--cdp-url` for this env var — the wrapper *rejects* `--cdp-url`, see the blocked-flags list above.) 5. Execs the real `browser-use` binary with the rest of the args. The wrapper blocks `--profile`, `--cdp-url`, and `--connect` flags because those break the mux. `--headed` is also blocked (managed by the wrapper). For non-seller-center pages, use `--session <slug>-aux`. **Behavior depends on backend:** - **Wrapper format v4** — every session carries an EXPLICIT `BU_CDP_WS` (an endpoint-less daemon ambiently attached to a DIFFERENT store's browser — observed live; that class is now unrepresentable). Ziniao stores: `-aux` is the store's DEDICATED login-less Chromium, lazily started via `POST /api/stores/{id}/browser/aux/start` (own CDPMuxProxy, own `downloads/{slug}-aux/` dir, NO seller login — never use it for seller central). Chrome stores: aux is a stable `client-aux` on the main proxy. If an aux session shows another store's account, the wrapper predates v3/v4 — restart the server to regenerate. ## VIBE_TASK_ID — the recurring footgun A fresh `VIBE_TASK_ID` per real task is what the runtime gives every task agent. Outside the task system, **rotate it manually after**: - Every long pause (> 15 min idle, especially if the user resumed after sleeping for hours). - Any time you see `Error: Session '<slug>-<8hex>' is already running with different config.` — means the daemon for that ID has stale CDP config. - Any time `browser-use sessions` shows the daemon for your ID with `CONFIG=?` (TTY-detection failure mode). - Any time eval calls return `TimeoutError: timed out` or `Client is stopping` — daemon has wedged. Rotate: ```bash NEW="$(uuidgen | tr '[:upper:]' '[:lower:]')" echo "export VIBE_TASK_ID='$NEW'" > /tmp/vs_session_env.sh . /tmp/vs_session_env.sh ~/.vibe-seller/bin/<slug>/browser-use sessions ~/.vibe-seller/bin/<slug>/browser-use open <some-url> ``` > **A rotated `VIBE_TASK_ID` gets REAPED within 5 minutes — do not use > one for manual driving.** `VIBE_TASK_ID=<uuid>` resolves the session to > `<slug>-<8hex>`, which is exactly the shape > `daemon_reaper.task_prefix_for_bu_name()` reads as *"owned by a task"*. > There is no task row for a hand-made UUID, so the 5-minute sweep > classifies the daemon as orphaned and kills it. The next `js()` in your > heredoc then dies with a bare, undiagnosable traceback — > `FileNotFoundError: [Errno 2] No such file or directory` out of > `_ipc.connect` — because `ensure_daemon()` runs **once** before > `exec(code)` and nothing re-checks the socket mid-script. Confirm with: > `grep -i reaped logs/backend_7777.log` > → `Reaped 1 orphaned browser-use daemon(s): [(<pid>, '<8hex>')]`. > > For manual driving use a session the reaper **skips** — one with no > task suffix: unset `VIBE_TASK_ID` entirely (session `<slug>`, the > global one) or pass `--session <slug>-aux`. Rotation advice above > applies to a *wedged* daemon inside a real task, not to your shell. ## Reviving a wedged daemon ```bash # 1. List daemons to find the wedged one ~/.vibe-seller/bin/<slug>/browser-use sessions # 2. Force-kill (the wrapper's `close` subcommand may itself hang) pkill -9 -f "skill_cli.daemon.*<slug>-<8hex>" # 3. Rotate VIBE_TASK_ID and re-open NEW="$(uuidgen | tr '[:upper:]' '[:lower:]')" export VIBE_TASK_ID="$NEW" ~/.vibe-seller/bin/<slug>/browser-use open about:blank ``` The Ziniao Chrome process and the CDP mux proxy survive daemon kills — they're per-store, not per-task. Don't kill them unless you've tried everything else. To verify the CDP proxy is actually responding: ```bash # This store's mux port — NOT a fixed 9222 (allocated per store). PORT=$(grep -oE '127\.0\.0\.1:9[0-9]{3}' ~/.vibe-seller/bin/<slug>/browser-use | head -1 | cut -d: -f2) curl -sf -m 2 --noproxy '*' "http://127.0.0.1:$PORT/json/version" ps aux | grep -E "ziniaobrowser" | grep -v grep ``` `--noproxy '*'` matters: with ClashX/etc. exported, curl sends the loopback request to the proxy and you get an empty body instead of a connection error — which reads as "the browser is up but broken". The mux proxy is an asyncio server **inside** the FastAPI process, so `grep cdp_mux_proxy` in `ps` finds nothing even when it is running. **Wedge signature:** the port accepts the TCP connection and then never answers (curl hangs to `-m` timeout, HTTP 000). Distinct from a clean "connection refused" — see [docs/ziniao-concurrency.md](../../../docs/ziniao-concurrency.md) runbook. ## Skipping JWT-cookie auth The vibe-seller HTTP API (`/api/tasks`, `/api/stores`, etc.) gates everything on a JWT cookie. From a Claude Code shell, you don't have that cookie. Two ways to work around without touching the user's admin password: ### Option A — reusable `taskbot_debug` account, login via API, then deactivate Use the single stable `taskbot_debug` account for every debug session. The flow below is idempotent: it creates the account on first use, reactivates + rotates the password on every later use, and deactivates it when you're done. ```bash # 1. Generate password + bcrypt hash PW=$(python3 -c "import secrets;print('tmp_'+secrets.token_hex(8))") HASH=$(./.venv/bin/python3 -c "from app.password import hash_password;print(hash_password('$PW'))") # run from repo root # 2. Upsert the stable debug user (admin role, fixed id + username) DBG_UID="taskbot-debug" NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)" sqlite3 ~/.vibe-seller/data/vibe_seller.db \ "INSERT INTO users (id, username, email, password_hash, role, is_active, plan_mode_default, debug_mode, default_profile_id, created_at, updated_at) VALUES ('$DBG_UID','taskbot_debug',NULL,'$HASH','admin',1,1,0,'default', '$NOW','$NOW') ON CONFLICT(id) DO UPDATE SET password_hash='$HASH', is_active=1, updated_at='$NOW';" # 3. Login → cookie curl -s -c /tmp/vs_cookie.txt -H 'Content-Type: application/json' \ -X POST http://localhost:7777/api/auth/login \ -d "{\"identifier\":\"taskbot_debug\",\"password\":\"$PW\"}" # 4. Use the cookie for any API call curl -s -b /tmp/vs_cookie.txt http://localhost:7777/api/stores # 5. Cleanup before ending the session sqlite3 ~/.vibe-seller/data/vibe_seller.db \ "UPDATE users SET is_active=0 WHERE id='$DBG_UID';" ``` `is_active=0` blocks future logins for this account. The `tasks.created_by` column uses FK = restrict, so the row itself can never be deleted once it owns tasks — that's fine, it's one stable row across all sessions. If you forget step 5 the account stays dormant with a throwaway password; the next session rotates it. ### Option B — drive the wrapper directly (no API auth needed) If your only goal is to drive a store's browser, you don't need the HTTP API at all. The wrapper itself authenticates the `browser/start` call with the `ai_bot` JWT baked into the script. Just rotate `VIBE_TASK_ID` and call `browser-use open <url>`. This is the right choice when: - You're inspecting a single store from outside (debugging, verifying a workflow before turning it into a task). - You don't need the per-task workspace isolation. - You're OK with sharing the global `<slug>` session (or pinning a per-shell `<slug>-<8hex>` session via `VIBE_TASK_ID`). This is the WRONG choice when: - You want isolation across concurrent runs (use real tasks). - You need the agent's MCP tools (`vibe_seller_write_workspace_file`, catalog injection, etc.) — those only exist inside a real task. ## Calling the HTTP API Once you have a cookie file (Option A) — assume `COOKIE=/tmp/vs_cookie.txt` and `BASE=http://localhost:7777` below — every authenticated route is just `curl -b "$COOKIE" "$BASE/<path>"`. Use `-c "$COOKIE"` on the login call (writes), `-b` everywhere else (reads). The API surface (full list in `docs/api.md`) breaks into a few groups: | Group | Common routes | Use for | |---|---|---| | Auth | `POST /api/auth/login`, `GET /api/auth/me`, `POST /api/auth/logout` | Cookie lifecycle | | Stores | `GET /api/stores`, `GET /api/stores/<id>`, `POST /api/stores/<id>/browser/start` (`?force=1`), `POST /api/stores/<id>/browser/aux/start` | Store metadata + per-store browser lifecycle | | Tasks | `POST /api/tasks`, `GET /api/tasks`, `GET /api/tasks/<id>`, `POST /api/tasks/<id>/messages`, `POST /api/tasks/<id>/stop` | Create / list / inspect / message / stop tasks | | Schedules | `GET /api/schedules`, `POST /api/schedules`, `POST /api/schedules/<id>/run` | Cron-style routines | | Events | `GET /api/events/stream` (SSE), `GET /api/events/recent` | Live + historical event feed | > **There is no `browser/stop` route** — stopping is internal only > (`BrowserManager.stop_session` / `aux_browser.stop_aux`, called by store > deletion and the idle sweeper). To stop one store's env by hand, send > Ziniao's own per-store `stopBrowser` with that store's `browser_oauth`; > never kill the shared Ziniao client, which would destroy every other > store's live browser (see
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る