sellerclaw-cli 3.1.2__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/PKG-INFO +7 -4
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/README.md +6 -3
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/pyproject.toml +1 -1
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_command_group.py +28 -14
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/listings.py +11 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/orders.py +9 -1
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/research_seo.py +10 -2
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/listings.md +1 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/orders.md +1 -1
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/research.md +4 -2
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/mcp_apps.py +501 -97
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/mcp_server.py +20 -11
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/.gitignore +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/LICENSE +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/plugin/claude/README.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/__init__.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/__main__.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_agent_id.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_auth.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_client.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_config.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_errors.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_generated/.gitkeep +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_job_wait.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_output.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_runtime.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_session_key.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/_task_context.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/assets/icon.png +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/cli.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/__init__.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/_auth_cli.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/_discover.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/_listing_shape.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/account.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/action_requests.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ad_accounts.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/agent_files.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/amazon.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/amazon_fba.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/amazon_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/amazon_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/amazon_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/analytics.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/attributes.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/bigcommerce.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/bigcommerce_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/bigcommerce_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/bigcommerce_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/catalog.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/catalog_file.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/categories.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/channels.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/chats.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/competitors.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_feedback.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_finances.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_promoted.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_shipping.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/ebay_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/email.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/etsy.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/etsy_finances.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/etsy_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/etsy_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/etsy_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/facebook_ads.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/goals.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/google_ads.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/integrations.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/kb.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/klaviyo.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/listing_problems.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/media.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/models.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/pdf.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/price_list.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/research_catalog.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/research_social.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/research_trends.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/reviews.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_domain.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_media.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_menus.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_pages.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_payouts.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sellercart_products.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/sheets.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_collections.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_finances.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_menus.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_pages.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/shopify_themes.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/social.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/spreadsheet.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/store_audit.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/subagent_tasks.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/suppliers.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/team.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/team_tasks.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/tiktok_shop_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/tiktok_shop_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/tiktok_shop_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/walmart.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/walmart_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/walmart_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/walmart_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/web.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/wix.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/wix_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/wix_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/wix_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/woocommerce.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/woocommerce_listings.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/woocommerce_orders.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/commands/woocommerce_store.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/__init__.py +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/ads.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/analytics.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/catalog.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/email.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/start.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/storefront.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/suppliers.md +0 -0
- {sellerclaw_cli-3.1.2 → sellerclaw_cli-3.2.0}/sellerclaw_cli/guides/topics.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sellerclaw-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: Command-line client and MCP server for the SellerClaw Agent API — run your stores, orders, listings, ads and suppliers from a terminal, scripts, or Claude. LLM-friendly JSON, browser sign-in.
|
|
5
5
|
Project-URL: Homepage, https://sellerclaw.ai
|
|
6
6
|
Project-URL: Documentation, https://github.com/sellerai-com/sellerclaw-cli#readme
|
|
@@ -525,10 +525,13 @@ New CLI commands appear automatically — there is nothing per-command to mainta
|
|
|
525
525
|
Alongside those four, a client that supports [MCP Apps](https://modelcontextprotocol.io) gets
|
|
526
526
|
**interactive cards** for the questions a seller asks most — what needs them today
|
|
527
527
|
(`sellerclaw_attention`), how a store is doing (`sellerclaw_store_summary`), the orders or one
|
|
528
|
-
order (`sellerclaw_orders`), listings or one listing (`sellerclaw_listings`),
|
|
528
|
+
order (`sellerclaw_orders`), listings or one listing (`sellerclaw_listings`), a catalog product
|
|
529
|
+
with its supplier and every store it is listed in (`sellerclaw_products`), ads across every
|
|
529
530
|
platform (`sellerclaw_ads`), the health of every connection (`sellerclaw_connections`), and a
|
|
530
|
-
request waiting on the owner (`sellerclaw_approval`). The
|
|
531
|
-
|
|
531
|
+
request waiting on the owner (`sellerclaw_approval`). The order, listing and product cards find what
|
|
532
|
+
the owner names in their own words — an order number, a title, a SKU — and open it when only one
|
|
533
|
+
matches. The cards show;
|
|
534
|
+
changing anything still goes through `sellerclaw_run`. A client without cards gets the same answers as a short text summary plus
|
|
532
535
|
the full structured result.
|
|
533
536
|
|
|
534
537
|
The guides live in the package ([`sellerclaw_cli/guides/`](sellerclaw_cli/guides/)) and are the same
|
|
@@ -490,10 +490,13 @@ New CLI commands appear automatically — there is nothing per-command to mainta
|
|
|
490
490
|
Alongside those four, a client that supports [MCP Apps](https://modelcontextprotocol.io) gets
|
|
491
491
|
**interactive cards** for the questions a seller asks most — what needs them today
|
|
492
492
|
(`sellerclaw_attention`), how a store is doing (`sellerclaw_store_summary`), the orders or one
|
|
493
|
-
order (`sellerclaw_orders`), listings or one listing (`sellerclaw_listings`),
|
|
493
|
+
order (`sellerclaw_orders`), listings or one listing (`sellerclaw_listings`), a catalog product
|
|
494
|
+
with its supplier and every store it is listed in (`sellerclaw_products`), ads across every
|
|
494
495
|
platform (`sellerclaw_ads`), the health of every connection (`sellerclaw_connections`), and a
|
|
495
|
-
request waiting on the owner (`sellerclaw_approval`). The
|
|
496
|
-
|
|
496
|
+
request waiting on the owner (`sellerclaw_approval`). The order, listing and product cards find what
|
|
497
|
+
the owner names in their own words — an order number, a title, a SKU — and open it when only one
|
|
498
|
+
matches. The cards show;
|
|
499
|
+
changing anything still goes through `sellerclaw_run`. A client without cards gets the same answers as a short text summary plus
|
|
497
500
|
the full structured result.
|
|
498
501
|
|
|
499
502
|
The guides live in the package ([`sellerclaw_cli/guides/`](sellerclaw_cli/guides/)) and are the same
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sellerclaw-cli"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.2.0"
|
|
8
8
|
description = "Command-line client and MCP server for the SellerClaw Agent API — run your stores, orders, listings, ads and suppliers from a terminal, scripts, or Claude. LLM-friendly JSON, browser sign-in."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -18,10 +18,11 @@ import difflib
|
|
|
18
18
|
import inspect
|
|
19
19
|
import mimetypes
|
|
20
20
|
import re
|
|
21
|
-
from collections.abc import Sequence
|
|
21
|
+
from collections.abc import Mapping, Sequence
|
|
22
22
|
from dataclasses import dataclass, replace
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Any
|
|
25
|
+
from urllib.parse import quote
|
|
25
26
|
|
|
26
27
|
import typer
|
|
27
28
|
|
|
@@ -237,12 +238,14 @@ def _validate_flag(f: Flag, value: object) -> None:
|
|
|
237
238
|
"""Reject out-of-range / out-of-choice values locally (clear error, no server round-trip)."""
|
|
238
239
|
if value is None or value == [] or value is False:
|
|
239
240
|
return
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
241
|
+
# A repeatable flag arrives as a list; each value is held to the same choices as a single one.
|
|
242
|
+
for item in value if isinstance(value, list) else [value]:
|
|
243
|
+
if f.choices and isinstance(item, str) and item not in f.choices:
|
|
244
|
+
emit_error(
|
|
245
|
+
UserInputError(
|
|
246
|
+
f"{f.primary_option}: must be one of {', '.join(f.choices)} (got {item!r})"
|
|
247
|
+
)
|
|
244
248
|
)
|
|
245
|
-
)
|
|
246
249
|
if isinstance(value, int) and not isinstance(value, bool):
|
|
247
250
|
if f.minimum is not None and value < f.minimum:
|
|
248
251
|
emit_error(UserInputError(f"{f.primary_option}: must be >= {f.minimum} (got {value})"))
|
|
@@ -348,6 +351,19 @@ def positionals_of(path: str) -> list[str]:
|
|
|
348
351
|
return _PATH_PARAM_RE.findall(path)
|
|
349
352
|
|
|
350
353
|
|
|
354
|
+
def fill_path(path: str, values: Mapping[str, Any]) -> str:
|
|
355
|
+
"""``path`` with each ``{placeholder}`` replaced by its value, encoded as one path segment.
|
|
356
|
+
|
|
357
|
+
What people call things does not stay inside a URL's rules: an order number is ``#1001``, and
|
|
358
|
+
put in the path as it is, ``#`` starts the fragment — the request reaches ``/agent/orders/``
|
|
359
|
+
and asks for something else entirely. Encoded, every value is one segment whatever it holds,
|
|
360
|
+
and the server reads it back decoded.
|
|
361
|
+
"""
|
|
362
|
+
for name, value in values.items():
|
|
363
|
+
path = path.replace("{" + name + "}", quote(str(value), safe=""))
|
|
364
|
+
return path
|
|
365
|
+
|
|
366
|
+
|
|
351
367
|
def command_help(cmd: Cmd) -> str:
|
|
352
368
|
"""Help blurb shown by ``<group> <cmd> --help`` and embedded in discovery output."""
|
|
353
369
|
pieces: list[str] = []
|
|
@@ -634,9 +650,10 @@ def _expand_id_prefix(cmd: Cmd, positionals: dict[str, Any], prefix: str) -> str
|
|
|
634
650
|
list_path = cmd.resolve_list_path
|
|
635
651
|
if not list_path:
|
|
636
652
|
return None
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
653
|
+
list_path = fill_path(
|
|
654
|
+
list_path,
|
|
655
|
+
{name: value for name, value in positionals.items() if name != cmd.active_positional},
|
|
656
|
+
)
|
|
640
657
|
try:
|
|
641
658
|
with Client.from_env() as client:
|
|
642
659
|
data = client.request("GET", list_path)
|
|
@@ -717,9 +734,7 @@ def _make_callback(group: str, cmd: Cmd):
|
|
|
717
734
|
cmd, values, values.get(cmd.active_positional)
|
|
718
735
|
)
|
|
719
736
|
values[cmd.active_positional] = resolved_active
|
|
720
|
-
path = cmd.path
|
|
721
|
-
for name in positionals:
|
|
722
|
-
path = path.replace("{" + name + "}", str(values[name]))
|
|
737
|
+
path = fill_path(cmd.path, {name: values[name] for name in positionals})
|
|
723
738
|
body: Any = None
|
|
724
739
|
if cmd.takes_body:
|
|
725
740
|
raw_body = kwargs.pop("body")
|
|
@@ -754,8 +769,7 @@ def _make_callback(group: str, cmd: Cmd):
|
|
|
754
769
|
params[f.query_key] = value
|
|
755
770
|
poll_path = cmd.job_poll_path
|
|
756
771
|
if poll_path is not None:
|
|
757
|
-
for name in positionals
|
|
758
|
-
poll_path = poll_path.replace("{" + name + "}", str(values[name]))
|
|
772
|
+
poll_path = fill_path(poll_path, {name: values[name] for name in positionals})
|
|
759
773
|
run_operation(
|
|
760
774
|
ctx,
|
|
761
775
|
cmd.method,
|
|
@@ -130,6 +130,17 @@ SPECS = (
|
|
|
130
130
|
),
|
|
131
131
|
choices=("owner", "agent", "sync", "marketplace", "unknown"),
|
|
132
132
|
),
|
|
133
|
+
flag(
|
|
134
|
+
"sale_state",
|
|
135
|
+
repeatable=True,
|
|
136
|
+
help=(
|
|
137
|
+
"Whether a shopper can buy it; repeat to combine. --sale-state out_of_stock "
|
|
138
|
+
"--sale-state not_selling = 'what is not selling': live listings with nothing "
|
|
139
|
+
"to sell, or that the channel hides, is reviewing, refused or lost. A live "
|
|
140
|
+
"listing nobody can buy is still status 'active', so --status cannot ask this."
|
|
141
|
+
),
|
|
142
|
+
choices=("selling", "out_of_stock", "not_selling", "not_published"),
|
|
143
|
+
),
|
|
133
144
|
flag("limit", type=int, minimum=1, maximum=200, default=25, help="Max results per page."),
|
|
134
145
|
flag("offset", type=int, minimum=0, default=0, help="Results to skip (paging)."),
|
|
135
146
|
),
|
|
@@ -66,7 +66,15 @@ SPECS = (
|
|
|
66
66
|
),
|
|
67
67
|
),
|
|
68
68
|
),
|
|
69
|
-
Cmd(
|
|
69
|
+
Cmd(
|
|
70
|
+
"get",
|
|
71
|
+
"GET",
|
|
72
|
+
"/agent/orders/{order_id}",
|
|
73
|
+
summary=(
|
|
74
|
+
"Get one order by its id, its whole order number (#1001, the # optional) or the "
|
|
75
|
+
"marketplace's order id. A number two stores share answers 409 naming both."
|
|
76
|
+
),
|
|
77
|
+
),
|
|
70
78
|
Cmd(
|
|
71
79
|
"search",
|
|
72
80
|
"GET",
|
|
@@ -87,7 +87,15 @@ SPECS = (
|
|
|
87
87
|
"/agent/research/seo/serp-competitors",
|
|
88
88
|
summary="serp competitors research.",
|
|
89
89
|
body=(
|
|
90
|
-
body_field(
|
|
90
|
+
body_field(
|
|
91
|
+
"keywords",
|
|
92
|
+
repeatable=True,
|
|
93
|
+
required=True,
|
|
94
|
+
help=(
|
|
95
|
+
"Keywords whose Google results to read (1-200); the domains ranking for them "
|
|
96
|
+
"are the competitors. Not a domain."
|
|
97
|
+
),
|
|
98
|
+
),
|
|
91
99
|
body_field("location_name", help="Location name (e.g. 'United States')."),
|
|
92
100
|
body_field("location_code", type=int, help="Numeric location code (overrides name)."),
|
|
93
101
|
body_field("language_name", help="Language name (e.g. 'English')."),
|
|
@@ -121,7 +129,7 @@ SPECS = (
|
|
|
121
129
|
body_field("location_code", type=int, help="Numeric location code (overrides name)."),
|
|
122
130
|
body_field("language_name", help="Language name (e.g. 'English (United States)')."),
|
|
123
131
|
body_field("language_code", help="Marketplace language code (e.g. 'en_US')."),
|
|
124
|
-
body_field("depth", type=int, help="Number of reviews to fetch (1-
|
|
132
|
+
body_field("depth", type=int, help="Number of reviews to fetch (1-50). Defaults to 10."),
|
|
125
133
|
),
|
|
126
134
|
),
|
|
127
135
|
Cmd(
|
|
@@ -8,6 +8,7 @@ for `sellerclaw_describe` only for a command not shown here, or when a call erro
|
|
|
8
8
|
```text
|
|
9
9
|
sellerclaw_run(group="channels", command="list") # store ids
|
|
10
10
|
sellerclaw_run(group="listings", command="search", flags={"q": "wireless mouse"}) # find across all stores
|
|
11
|
+
sellerclaw_run(group="listings", command="search", flags={"sale_state": ["out_of_stock", "not_selling"]}) # what shoppers cannot buy
|
|
11
12
|
sellerclaw_run(group="shopify-listings", command="summary", positionals={"store_id": STORE_ID})
|
|
12
13
|
```
|
|
13
14
|
|
|
@@ -36,7 +36,7 @@ Creating the fulfillment tells the *channel* and the buyer. The SellerClaw order
|
|
|
36
36
|
separately — do it right after, or the order stays in the seller's open work:
|
|
37
37
|
|
|
38
38
|
```text
|
|
39
|
-
# ORDER_ID
|
|
39
|
+
# ORDER_ID: the SellerClaw order id, or the order number the owner quotes (#1001).
|
|
40
40
|
sellerclaw_run(group="orders", command="set-shipped", positionals={"order_id": ORDER_ID},
|
|
41
41
|
body={"tracking_number": "1Z999AA10123456784", "tracking_carrier": "UPS"})
|
|
42
42
|
```
|
|
@@ -13,7 +13,7 @@ sellerclaw_run(group="research-trends", command="related-queries", flags={"keywo
|
|
|
13
13
|
|
|
14
14
|
# SEO / keyword research (body-driven)
|
|
15
15
|
sellerclaw_run(group="research-seo", command="keyword-ideas", body={"keyword": "wireless mouse"})
|
|
16
|
-
sellerclaw_run(group="research-seo", command="serp-competitors", body={"
|
|
16
|
+
sellerclaw_run(group="research-seo", command="serp-competitors", body={"keywords": ["wireless mouse", "bluetooth mouse"]})
|
|
17
17
|
|
|
18
18
|
# What the marketplace itself already lists (query, gtin, or a competitor's storefront)
|
|
19
19
|
sellerclaw_run(group="research-catalog", command="ebay-search",
|
|
@@ -40,7 +40,9 @@ sellerclaw_run(group="web", command="scrape", flags={"url": "https://rival.examp
|
|
|
40
40
|
|
|
41
41
|
## A listing on a marketplace is data, not a page
|
|
42
42
|
|
|
43
|
-
`listing-get` returns a rival's price, stock, seller, condition, rating and specifications as fields
|
|
43
|
+
`listing-get` returns a rival's price, stock, seller, condition, rating and specifications as fields,
|
|
44
|
+
plus the seller's own selling points (`features`) and `description` where the storefront publishes
|
|
45
|
+
them — most publish no specifications, so capacity, materials and what is in the box are read there.
|
|
44
46
|
Scraping the same page returns markdown a price still has to be guessed out of — and Amazon, Etsy and
|
|
45
47
|
eBay answer plain fetches with a bot wall often enough that the guess is frequently of nothing. Reach
|
|
46
48
|
for `web scrape` only for storefronts this does not cover.
|