Files

10 KiB

name, description, version, author, license, metadata
name description version author license metadata
miaoshou-erp Miaoshou (妙手) ERP operations: cron auto-import from AtomK, product import via Excel upload, and collect box management. 1.2.0 Hermes Agent MIT
hermes
tags related_skills
miaoshou
erp
cross-border
e-commerce
product-import
collect-box
atomk-platform
tongtool-workflows
credential-management

Miaoshou (妙手) ERP

Three workflows for Miaoshou ERP: cron auto-import from AtomK, batch product import via Excel upload, and exploring/managing the collect box (通用采集箱).

Section 1: Batch Product Import

Automate batch product import from AtomK to Miaoshou ERP via Excel upload.

When to use: Importing large numbers of products from AtomK into Miaoshou for management.

Key patterns:

  • Generate Excel file from AtomK product data
  • Upload to Miaoshou via UI (or API)
  • Handle validation errors and duplicate detection
  • Map product fields between AtomK and Miaoshou formats

See: references/miaoshou-batch-import.md for full import workflow.

Section 2: Collect Box Management

Explore and interact with Miaoshou ERP's "通用采集箱" (Common Collect Box) — URLs, collection methods, import paths, and login automation.

When to use: Adding products to the collect box, checking collected items, importing from collect box to formal listings.

Key topics:

  • Collect box URL patterns and API endpoints
  • Collection methods (URL import, manual add, API)
  • Import from collect box to product listings
  • Login automation for Miaoshou

See: references/miaoshou-collect-box.md for full collect box guide.

Section 3: Cron Auto-Import (AtomK → Miaoshou)

The production auto-import pipeline runs hourly via a no_agent Hermes cron job that invokes a wrapper shell script. The wrapper appends timestamp headers to the cron log, runs the Python import script, and appends an exit-code footer. No LLM session is spawned — the script executes directly, completing in ~3 seconds rather than 3-5 minutes.

Cron job: atomk-miaoshou-hourly (schedule: 0 * * * *, no_agent=true) Wrapper script: /home/ubuntu/.hermes/scripts/miaoshou_hourly.sh Main script: /home/ubuntu/auto_miaoshou_import.py Python: /home/ubuntu/.hermes/hermes-agent/venv/bin/python3 Working dir: /home/ubuntu

Why no_agent (Not LLM-Driven)

The cron job was previously LLM-driven (Agent mode). Each run spawned a full LLM session that loaded skills, ran terminal commands, read files, and produced a report — consuming 3-5 minutes of cron queue time per hour. Since Hermes cron runs jobs sequentially in FIFO order, this caused massive queue congestion: ad-hoc cron jobs got delayed by 17+ hours (scheduled 19:16, queued to 13:08 next day).

The no_agent wrapper script eliminates the LLM overhead entirely. See references/cron-queue-pitfalls.md for the full diagnosis and fix.

Key Files

File Purpose
/home/ubuntu/.hermes/scripts/miaoshou_hourly.sh Cron wrapper: timestamp header → run script → exit-code footer
/home/ubuntu/auto_miaoshou_import.py Main import script (441 lines)
/home/ubuntu/.hermes/miaoshou_import_state.json Tracks which AtomK products have been imported (cumulative count + IDs)
/home/ubuntu/.hermes/cookies/miaoshou_cookies.json Miaoshou session cookies for browser automation
/home/ubuntu/.hermes/miaoshou_import.log Script's own internal log (Python log() writes here)
/home/ubuntu/.hermes/miaoshou_cron.log Cron wrapper log (stdout/stderr + timestamp headers)
/home/ubuntu/.hermes/credentials.env Centralized credentials (chmod 600) — read by atomk_credentials.py
/home/ubuntu/.hermes/scripts/atomk_credentials.py Python credential loader — provides get_atomk_auth(), get_miaoshou_auth(), etc.

Two-Log Architecture

The script logs to TWO separate files — this is important when diagnosing runs:

  • miaoshou_import.log — the script's Python log() function writes here. Contains the actual import narrative (products found, imported, skipped). This is the authoritative record.
  • miaoshou_cron.log — the cron wrapper appends stdout/stderr plus === TIMESTAMP === headers and === END (exit code: N) === footers. If the script produces no stdout (all output goes to log()), the cron log only contains the header/footer markers.

Normal Behavior

  • BATCH_SIZE = 6 per run (hourly)
  • On each run: authenticates to AtomK API → fetches pending products → filters already-imported → opens Miaoshou via DrissionPage → imports each product to collect box
  • If AtomK has 0 new products: script prints "没有新产品需要导入,本次跳过" and exits 0 (this is normal, not an error)
  • Cumulative import count is displayed at end: 📊 累计已导入: N 个产品

Running Manually

Direct run (for debugging — stdout visible):

cd /home/ubuntu && /home/ubuntu/.hermes/hermes-agent/venv/bin/python3 /home/ubuntu/auto_miaoshou_import.py

Wrapper script (same as cron):

/home/ubuntu/.hermes/scripts/miaoshou_hourly.sh

Production cron pattern (for Linux crontab — NOT for Hermes terminal()):

cd /home/ubuntu && { echo ""; echo "=== $(date '+%Y-%m-%d %H:%M:%S') ==="; /home/ubuntu/.hermes/hermes-agent/venv/bin/python3 /home/ubuntu/auto_miaoshou_import.py 2>&1; RC=$?; echo "=== END (exit code: $RC) ==="; } >> /home/ubuntu/.hermes/miaoshou_cron.log

Cron Job Management

# View current state
cronjob(action='list')

# The job is stored in /home/ubuntu/.hermes/cron/jobs.json
# Job ID: eee9ab11fbfc, name: atomk-miaoshou-hourly
# no_agent=true, script=miaoshou_hourly.sh

# To revert to LLM-driven (not recommended — causes queue congestion):
# cronjob(action='update', job_id='eee9ab11fbfc', no_agent=false, script='')

Pitfalls

  1. Empty stdout — the script logs internally via log() to miaoshou_import.log, not to stdout. When debugging, check BOTH log files.

  2. Cookie expiry — Miaoshou cookies in miaoshou_cookies.json can expire; the script uses DrissionPage which may need fresh login if cookies are stale.

  3. Chromium path — hardcoded to /home/ubuntu/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome; must match installed Playwright Chromium version.

  4. AtomK auth — credentials are loaded from ~/.hermes/credentials.env via atomk_credentials.get_atomk_auth(). If the script fails with KeyError, the credential file has FILL_ME placeholders that need real values. See credential-management skill for the full pattern.

  5. Cron log race condition — the hourly cron and manual runs both append to miaoshou_cron.log. Splitting the timestamp header and script execution across separate terminal() calls creates a gap where the hourly cron can interleave its write, causing the manual run's output to be silently dropped with no error. If log output appears missing, verify with stat -c '%y' that the file's mtime matches when the run should have completed.

  6. { } compound command unreliable via terminal() — the { } grouping with >> redirect can fail silently when passed to Hermes terminal(). Observed: exit code 0 returned but no output appended to the log file, no script execution, and file mtime unchanged. For Hermes-triggered runs, use a two-step approach instead:

    Step 1: Run the script directly and capture output:

    cd /home/ubuntu && /home/ubuntu/.hermes/hermes-agent/venv/bin/python3 /home/ubuntu/auto_miaoshou_import.py 2>&1; echo "EXIT_CODE=$?"
    

    The terminal() response contains the script's full stdout (including timestamped log lines), plus EXIT_CODE=N.

    Step 2: Append header, captured output, and footer to cron log:

    printf '\n=== %s ===\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> /home/ubuntu/.hermes/miaoshou_cron.log
    

    This two-step approach avoids the { } + >> issue.

  7. LLM-driven cron causes queue congestion — Hermes cron runs jobs sequentially in FIFO order. An LLM-driven job that takes 3-5 minutes blocks all subsequent jobs. When ad-hoc cron jobs are created during active sessions, they queue behind every pending hourly/scheduled job. Always use no_agent with a wrapper script for frequent recurring tasks. See references/cron-queue-pitfalls.md for the full diagnosis.

Section 4: Bridge CDP Navigation & Interaction

When using Bridge CDP to control the user's desktop browser:

Login URL

  • Correct: https://erp.91miaoshou.com/ — main page, auto-redirects to /welcome if logged in
  • Wrong: /auth/login — returns 404「页面未找到」. Do not use.
  • If not logged in, the main page will show the login form.

Navigation structure

  • Top nav: ul.nav-list.earth with <li id="goods"> for products, <li id="order"> for orders
  • Click #goods → navigates to /common_collect_box/index
  • Left sidebar: <span> text nodes (not <a> links). Match by innerText.trim()

Collect box tabs

Tab URL Purpose
产品采集 /common_collect_box/index Link import, bulk import
公用采集箱 /common_collect_box/items Collected products list
AI工作台 AI tools
侵权检测 Infringement check
  1. Click "链接采集" span tab
  2. Fill textarea.jx-textarea__inner with 1688 URL
  3. Acceptable formats: URL, URL$$title, URL||title
  4. Click "采集并自动认领" to collect

1688 authorization blocker

Collecting 1688 products requires 1688 account authorization first. A dialog appears: "应1688要求,请授权1688货源账号" with buttons "查看帮助教程" / "前往授权". User must complete "前往授权" manually.

"我知道了" dismiss

A tooltip with "我知道了" button sits near the textarea (x≈1200,y≈200). If collect button click has no effect, dismiss this tip first.

JS click() fallback

For Vue/Element UI components where element.click() is ignored, use Bridge CDP Input.dispatchMouseEvent via /cdp/send to send raw mouse events.