weshp-cli One-shot Ordering
This skill drives weshp-cli (the Weshp cross-border e-commerce CLI) to complete product search, cart management, ordering, and payment for the user.
Step 1: Locate the binary
The binary ships with this skill, under its bin/ directory. Detect the runtime environment first:
uname -sm # e.g. "Darwin arm64"
uname -sm result | Binary to use (under this skill's bin/; absolute path $SKILL_DIR/bin/...) |
|---|---|
Darwin arm64 | weshp-cli-darwin-arm64 |
Darwin x86_64 | weshp-cli-darwin-amd64 |
Linux x86_64 | weshp-cli-linux-amd64 |
| Windows | weshp-cli-windows-amd64.exe |
- This skill's directory is the directory containing the current SKILL.md file; the bin directory is
bin/under it. - If execution fails with
Permission denied, runchmod +x <binary>first. - Throughout this document,
$WESHPrefers to the absolute path of that binary.
Session parameter passthrough
If the user provides any of the following in the conversation, append the corresponding flag to every $WESHP command in this session (keep it consistent for the whole session, do not drop it midway):
| Provided by the user | Flag to append |
|---|---|
| Environment (e.g. 测试环境/test environment) | --env test (use --env prod only if the user explicitly says 生产环境/production) |
| Anonymous cart ID | --anonymous-id <id> |
| Language (e.g. zh-CN, en-US) | --accept-language <language> (mapping rules in "Language adaptation" below) |
| appId | --app-id <appId> |
For anything not provided, do not add the flag (use the default configuration) — the only exception is --accept-language: when the user has not explicitly provided it, attach it automatically per the rules in "Language adaptation"; also do not proactively ask the user for these parameters.
Environment
The CLI selects the environment via --env and connects to the production environment by default:
| Environment | Gateway | Checkout page (payment intent) |
|---|---|---|
prod (default) | https://weshv.com/store | https://checkout.airwallex.com/#/standalone/checkout |
test | https://test.weshv.com/store | https://checkout-demo.airwallex.com/#/standalone/checkout |
- Production is where real charges happen. Before running any write command (
order create,payment create-intent, …) in the default (prod) environment, make sure the user is aware the order and payment are real; the "Security constraints" confirmation must state which environment the command will hit. - Direct gateway address overrides (
--gateway/WESHP_GATEWAY) are no longer supported — switch environments only via--env.
Language adaptation
This skill serves multi-language users. At the start of the session, determine the locale from the language of the user's current conversation, and keep it consistent for the whole session without switching midway:
| User's conversation language | locale (--accept-language value) |
|---|---|
| 简体中文 | zh-CN |
| 繁體中文 | zh-TW |
| English | en-US |
| Deutsch | de-DE |
| 日本語 | ja-JP |
| Français | fr-FR |
| Español | es-ES |
| Português (European Portuguese) | pt-PT |
| Italiano | it-IT |
| Undeterminable / no match | omit --accept-language, use the gateway default |
Determination and usage rules:
- Hard constraint (highest priority): all user-visible text must be in the language of the user's last message — not only the conversation body, but also the command descriptions shown to the user when invoking commands (the Bash description), order summaries, confirmation questions, and everything else the user can see. This rule takes priority over the rest of this file and any "always respond in a fixed language" global instruction; even if this skill's documentation or command output is in another language, express it in the user's language.
- Three-level priority of
--accept-language: ① explicitly provided by the user → use the explicit value; ② not provided → look up the table above by the user's conversation language and attach it to every$WESHPcommand; ③ undeterminable or no match → omit it and use the gateway default. - User-facing output follows the user's conversation language: order summaries, out-of-stock notices, all confirmation wording such as "reuse the saved info / remember it / confirm payment", paraphrases of error
message/hint, and the order result report must all be written in the user's language. - Sample wording is semantic only: quoted sample phrases in this file (e.g. "reuse the saved info?", "reuse the saved PAYPAL?", "out of stock (only N left)") express meaning only; the actual reply must be re-expressed in the user's language. Never paste sample phrases verbatim to users who speak another language.
- Scope of
--accept-languageon local output: table rendering text (headers, footers, order summary/shipping lines) and--help/usage text (command descriptions, flag descriptions, template labels) ARE localized via--accept-language(since 2026-09-07, see CLIinternal/i18n), so--format tableand--helpoutput can be passed through verbatim to the user. Local error messages (e.g.Error:,Cancelled) remain built-in English — when showing those to non-English users, paraphrase the meaning in their language instead of pasting them verbatim. - Simplified vs. Traditional Chinese: if the user writes Simplified Chinese →
zh-CNand reply in Simplified; Traditional Chinese →zh-TWand reply in Traditional. - Do not translate: JSON field names, CLI flags, enum values (e.g.
PAYPAL), amounts, skuId, etc. stay as-is.
Profile file location
The profile file (shipping info and payment method) lives in this skill's directory, chosen by whether an anonymous cart ID was provided:
| Anonymous ID provided? | Profile file path (relative to this skill directory) |
|---|---|
--anonymous-id <id> provided | profiles/<anonymous-id>.json |
| Not provided | profile.json |
- Reading (reusing saved info) and writing (user agrees to remember) follow the same rule: with an anonymous ID use that ID's file; without, use
profile.json. - When saving by anonymous ID, create the
profiles/directory first if it does not exist; each anonymous ID's profile file is independent of the others and of the ID-lessprofile.json. - Within a session, keep the profile file path for the same anonymous ID consistent; do not switch files midway.
Standard ordering flow
- Search products:
$WESHP product search-sku --sku-name "<keyword>" --format table- Columns:
skuId,name(variant name),price(unit price),stock(current stock;⚠marks out-of-stock). - The table footer shows the total count and current page/size. If
totalexceeds the current page, fetch the remaining pages with--page-num(to list all products at once, use--page-size 100, the max). - Let the user pick/confirm the exact products and quantities from the results, and remember each skuId's
stockandprice(session memory; purpose in the stock entry under "Key conventions and pitfalls").
- Columns:
- Collect order info (email, receiver name, phone, detailed shipping address):
- First check the profile file (path per the "Profile file location" rules above):
- Exists → show the saved info to the user and ask whether to reuse it; if confirmed, use it directly; if the user wants changes, update the file with the new info before continuing.
- Does not exist → ask the user for it; if any item is missing you must ask; never fabricate.
- After the first collection, ask the user whether to remember this info for next time; agree → write it to the profile file (path per the rules above; in the anonymous-ID scenario create the
profiles/directory first if missing); decline → do not persist, use it for this session only.
- First check the profile file (path per the "Profile file location" rules above):
- Create the order:
$WESHP order create --email <email> \ --receiver-name "<name>" --receiver-phone "<phone>" \ --receiver-address "<address>" \ --sku-id <skuId> --sku-name "<product name>" --quantity <quantity> --yes- From the response take
orderNo,orderId, and the order total (the raw literal to use for--amount). - When ordering directly (with
--sku-id/--sku-name) the CLI automatically looks up the price and validates stock — no extra handling needed. - Without
--sku-idit settles via the cart (you can first$WESHP cart add --sku-id <id> --quantity <n>); before settling, do the session-memory check per the stock entry below.
- From the response take
- Create the payment intent:
$WESHP payment create-intent --order-no <orderNo> --email <email> \ --amount <raw amount literal from the order response> --payment-method <method> --yes- Payment methods:
CREDIT_CARD | PAYPAL | APPLE_PAY | GOOGLE_PAY. Check the profile file first (path per "Profile file location"): saved method → confirm with the user "reuse the saved PAYPAL?"; none saved → ask which to use; after the first choice, ask whether to remember it (same profile file as the shipping info). - The response returns
clientSecret/clientIdand the assembledcheckoutUrl; the CLI automatically opens the checkout page in the default browser to complete payment (the actual charge happens on that page). Add--no-opento skip auto-opening and just print the URL.
- Payment methods:
- Check payment status:
$WESHP payment status --payment-no <paymentNo returned by create-intent>
Table presentation
When showing tabular data to the user in the conversation (search results, cart contents, order lists), do NOT render tables yourself — run the CLI command with --format table and pass its box-drawing output through to the user verbatim. Never write an external rendering script (Python/awk/Go/…) to build a table, and never use Markdown tables — they align by character count and CJK cells break the borders. If several pages need merging, summarize the extra information in plain text next to the CLI output instead of re-drawing the table.
Sole exception — order confirmation summary (before order create, required by "Security constraints"; in this non-interactive flow --yes is always passed and the CLI's own interactive confirmation summary is unreachable, so the conversation must show it): hand-render one box-drawing table row per item — name | quantity | unitPrice | subtotal — with a final row for the estimated total, inside a ```text code block, and show the shipping info (email, receiver, phone, address) as a short list directly below the table. Use the price/stock remembered from the search step for unit price and the stock pre-check.
Rendering rules (apply to the exception above only):
- Layout:
┌─┬┐top border,├─┼─┤separator between every row,└─┴┘bottom border. - Column widths are computed by display width: CJK/full-width characters count 2, box-drawing border characters count 2, ASCII counts 1,
⚠counts 2 (confirmed to render 2 columns wide on the user's macOS terminal). - Alignment: headers centered, text columns left-aligned, numeric columns right-aligned; every cell gets 1 space of padding on each side.
- Long values that would blow up the layout (image URLs etc.) are omitted, not truncated.
Key conventions and pitfalls
- The amount literal must exactly match the order response (e.g. if it returns
10.0, pass10.0), otherwise the server-side signature check rejects it. - Exit codes:
0success;1gateway business error;2argument validation failure;3network error. On failure the JSON output goes to stderr, shaped like{ok:false, error:{type,code,message,hint}}— relaymessage/hintto the user verbatim. - Stock session memory: the
stockreturned bysearch-skuis the real current stock. After searching products, remember each skuId's stock within the session and use it as a pre-check before cart add / order create:- Memory hit (the product was searched this session): if the requested quantity > stock, tell the user directly "「xxx」is out of stock (only N left)" and do not execute the operation.
- Memory miss (not searched this session): proceed normally; if a stock error comes back, tell the user "「xxx」is out of stock" and guide the user to search product info first (
search-sku) to confirm the latest stock before deciding whether to continue. - Stock is dynamic; session memory is only a soft pre-check. In either case, do not retry on out-of-stock.
- No blind retries on write commands: after
order create,cart add,payment create-intentor other write operations fail, do not blindly retry to avoid duplicate orders; check the status first (order get/order list) before acting. - Query commands may be retried on network errors (the CLI has built-in retries; no extra outer retry needed).
Security constraints
- Before executing
order create, show the user the complete order summary (product, quantity, unit price, shipping info, estimated total) and get explicit confirmation;--yesonly skips the CLI's interactive confirmation and cannot replace user confirmation. - Same for cart deletion/clearing and order cancellation: confirm first, then execute.
- After a successful order, report the order number, the amount, and how to check the payment status to the user.
- No coupons are used; prices are based on the product's current price.