cli-web-amazon 0.1.1__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.
Files changed (34) hide show
  1. cli_web_amazon-0.1.1/PKG-INFO +14 -0
  2. cli_web_amazon-0.1.1/cli_web/amazon/README.md +83 -0
  3. cli_web_amazon-0.1.1/cli_web/amazon/__init__.py +3 -0
  4. cli_web_amazon-0.1.1/cli_web/amazon/__main__.py +6 -0
  5. cli_web_amazon-0.1.1/cli_web/amazon/amazon_cli.py +155 -0
  6. cli_web_amazon-0.1.1/cli_web/amazon/commands/__init__.py +1 -0
  7. cli_web_amazon-0.1.1/cli_web/amazon/commands/bestsellers.py +61 -0
  8. cli_web_amazon-0.1.1/cli_web/amazon/commands/product.py +36 -0
  9. cli_web_amazon-0.1.1/cli_web/amazon/commands/search.py +45 -0
  10. cli_web_amazon-0.1.1/cli_web/amazon/commands/suggest.py +36 -0
  11. cli_web_amazon-0.1.1/cli_web/amazon/core/__init__.py +1 -0
  12. cli_web_amazon-0.1.1/cli_web/amazon/core/client.py +416 -0
  13. cli_web_amazon-0.1.1/cli_web/amazon/core/exceptions.py +76 -0
  14. cli_web_amazon-0.1.1/cli_web/amazon/core/models.py +63 -0
  15. cli_web_amazon-0.1.1/cli_web/amazon/skills/SKILL.md +105 -0
  16. cli_web_amazon-0.1.1/cli_web/amazon/tests/TEST.md +173 -0
  17. cli_web_amazon-0.1.1/cli_web/amazon/tests/__init__.py +1 -0
  18. cli_web_amazon-0.1.1/cli_web/amazon/tests/test_core.py +369 -0
  19. cli_web_amazon-0.1.1/cli_web/amazon/tests/test_e2e.py +355 -0
  20. cli_web_amazon-0.1.1/cli_web/amazon/utils/__init__.py +1 -0
  21. cli_web_amazon-0.1.1/cli_web/amazon/utils/config.py +5 -0
  22. cli_web_amazon-0.1.1/cli_web/amazon/utils/doctor.py +188 -0
  23. cli_web_amazon-0.1.1/cli_web/amazon/utils/helpers.py +127 -0
  24. cli_web_amazon-0.1.1/cli_web/amazon/utils/mcp_server.py +290 -0
  25. cli_web_amazon-0.1.1/cli_web/amazon/utils/output.py +130 -0
  26. cli_web_amazon-0.1.1/cli_web/amazon/utils/repl_skin.py +486 -0
  27. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/PKG-INFO +14 -0
  28. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/SOURCES.txt +32 -0
  29. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/dependency_links.txt +1 -0
  30. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/entry_points.txt +2 -0
  31. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/requires.txt +6 -0
  32. cli_web_amazon-0.1.1/cli_web_amazon.egg-info/top_level.txt +1 -0
  33. cli_web_amazon-0.1.1/setup.cfg +4 -0
  34. cli_web_amazon-0.1.1/setup.py +25 -0
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: cli-web-amazon
3
+ Version: 0.1.1
4
+ Summary: Amazon CLI — Search, browse, and shop Amazon from your terminal
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: click>=8.0
7
+ Requires-Dist: httpx>=0.25
8
+ Requires-Dist: curl_cffi>=0.7
9
+ Requires-Dist: beautifulsoup4>=4.12
10
+ Requires-Dist: rich>=13.0
11
+ Requires-Dist: prompt_toolkit>=3.0
12
+ Dynamic: requires-dist
13
+ Dynamic: requires-python
14
+ Dynamic: summary
@@ -0,0 +1,83 @@
1
+ # cli-web-amazon
2
+
3
+ > Generated by [CLI-Anything-Web](../../../../cli-anything-web-plugin/) from [amazon.com](https://www.amazon.com)
4
+
5
+ Search Amazon products, view details, browse Best Sellers, and get autocomplete suggestions. No authentication required — all commands use public Amazon endpoints.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install cli-web-amazon
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Search
16
+
17
+ ```bash
18
+ cli-web-amazon search "laptop"
19
+ cli-web-amazon search "headphones" --dept electronics --page 2
20
+ cli-web-amazon search "coffee maker" --json
21
+ ```
22
+
23
+ ### Autocomplete Suggestions
24
+
25
+ ```bash
26
+ cli-web-amazon suggest "headp"
27
+ cli-web-amazon suggest "lapt" --json
28
+ ```
29
+
30
+ ### Product Details
31
+
32
+ ```bash
33
+ cli-web-amazon product get B0GRZ78683
34
+ cli-web-amazon product get B0GRZ78683 --json
35
+ ```
36
+
37
+ ### Best Sellers
38
+
39
+ ```bash
40
+ cli-web-amazon bestsellers electronics
41
+ cli-web-amazon bestsellers books --page 2
42
+ cli-web-amazon bestsellers --json
43
+ ```
44
+
45
+ ## JSON Output
46
+
47
+ Every command supports `--json` for structured output suitable for piping and scripting:
48
+
49
+ ```bash
50
+ cli-web-amazon search "laptop" --json | jq '.[0]'
51
+ cli-web-amazon product get B0GRZ78683 --json | jq '.price'
52
+ cli-web-amazon bestsellers electronics --json | jq '.[].title'
53
+ ```
54
+
55
+ ## REPL Mode
56
+
57
+ Run without arguments to enter interactive REPL mode:
58
+
59
+ ```bash
60
+ cli-web-amazon
61
+ ```
62
+
63
+ Type `help` inside the REPL to see all available commands.
64
+
65
+ ## Testing
66
+
67
+ ```bash
68
+ cd amazon/agent-harness
69
+ pip install -e .
70
+
71
+ # Unit tests (no network)
72
+ python -m pytest cli_web/amazon/tests/test_core.py -v
73
+
74
+ # All tests including E2E
75
+ python -m pytest cli_web/amazon/tests/ -v -s
76
+ ```
77
+
78
+ ## Protocol
79
+
80
+ - **Website:** https://www.amazon.com
81
+ - **Protocol:** SSR HTML + REST JSON hybrid
82
+ - **Auth:** None — all commands use public Amazon endpoints
83
+ - **HTTP library:** curl_cffi (Chrome impersonation — bypasses Amazon's 503 bot block)
@@ -0,0 +1,3 @@
1
+ """cli-web-amazon — Amazon CLI package."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,6 @@
1
+ """Allow running as: python -m cli_web.amazon"""
2
+
3
+ from .amazon_cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,155 @@
1
+ """cli-web-amazon entry point — Amazon CLI."""
2
+
3
+ import sys
4
+
5
+ # Windows UTF-8 fix — must be before any imports that print
6
+ if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"):
7
+ try:
8
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
9
+ except AttributeError:
10
+ pass
11
+ if sys.stderr.encoding and sys.stderr.encoding.lower() not in ("utf-8", "utf8"):
12
+ try:
13
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
14
+ except AttributeError:
15
+ pass
16
+
17
+ import shlex
18
+
19
+ import click
20
+
21
+ from .commands.bestsellers import bestsellers
22
+ from .commands.product import product
23
+ from .commands.search import search
24
+ from .commands.suggest import suggest
25
+ from .core.exceptions import AmazonError
26
+ from .utils.repl_skin import ReplSkin
27
+
28
+ __version__ = "1.0.0"
29
+
30
+ _skin = ReplSkin("amazon", version=__version__)
31
+
32
+
33
+ def _print_repl_help():
34
+ """Print REPL command reference."""
35
+ _skin.info("Available commands:")
36
+ print()
37
+ print(" suggest <query> Autocomplete suggestions")
38
+ print(" search <query> [OPTIONS] Search Amazon products")
39
+ print(" --page N Page number (default: 1)")
40
+ print(" --dept <department> Department filter")
41
+ print()
42
+ print(" product get <ASIN> Product detail by ASIN")
43
+ print()
44
+ print(" bestsellers [<category>] Best Sellers list")
45
+ print(" category: electronics, books, toys-and-games, music, ...")
46
+ print(" --page N Page number")
47
+ print()
48
+ print(" Global options: --json Output as JSON")
49
+ print()
50
+ print(" help Show this help")
51
+ print(" quit Exit REPL")
52
+ print()
53
+
54
+
55
+ @click.group(invoke_without_command=True)
56
+ @click.option(
57
+ "--json", "json_mode", is_flag=True, default=False, help="Output all results as JSON."
58
+ )
59
+ @click.version_option(__version__, "--version", "-V")
60
+ @click.pass_context
61
+ def cli(ctx, json_mode):
62
+ """cli-web-amazon — Browse and search Amazon from your terminal.
63
+
64
+ Run without a subcommand to enter interactive REPL mode.
65
+
66
+ Examples:
67
+ cli-web-amazon search laptop
68
+ cli-web-amazon product get B0GRZ78683
69
+ cli-web-amazon bestsellers electronics
70
+ cli-web-amazon suggest headphones
71
+ """
72
+ ctx.ensure_object(dict)
73
+ ctx.obj["json"] = json_mode
74
+
75
+ if ctx.invoked_subcommand is None:
76
+ # Enter REPL mode
77
+ _run_repl(ctx, json_mode)
78
+
79
+
80
+ def _run_repl(ctx, json_mode: bool):
81
+ """Run interactive REPL mode."""
82
+ _skin.print_banner()
83
+
84
+ if not json_mode:
85
+ _skin.info("Type 'help' for commands, 'quit' to exit.")
86
+ print()
87
+
88
+ pt_session = _skin.create_prompt_session()
89
+
90
+ while True:
91
+ try:
92
+ line = _skin.get_input(pt_session)
93
+ except (EOFError, KeyboardInterrupt):
94
+ _skin.print_goodbye()
95
+ break
96
+
97
+ if not line:
98
+ continue
99
+
100
+ cmd = line.strip().lower()
101
+ if cmd in ("quit", "exit", "q"):
102
+ _skin.print_goodbye()
103
+ break
104
+ if cmd in ("help", "?", "h"):
105
+ _print_repl_help()
106
+ continue
107
+
108
+ try:
109
+ args = shlex.split(line)
110
+ except ValueError as exc:
111
+ _skin.error(f"Parse error: {exc}")
112
+ continue
113
+
114
+ # Preserve --json flag
115
+ repl_args = ["--json"] + args if json_mode else args
116
+
117
+ try:
118
+ cli.main(args=repl_args, standalone_mode=False)
119
+ except SystemExit:
120
+ pass
121
+ except click.UsageError as exc:
122
+ _skin.error(str(exc))
123
+ except Exception as exc:
124
+ if json_mode and isinstance(exc, AmazonError):
125
+ import json as _json
126
+
127
+ click.echo(_json.dumps(exc.to_dict()))
128
+ else:
129
+ _skin.error(str(exc))
130
+
131
+
132
+ # Register subcommands
133
+ cli.add_command(search)
134
+ cli.add_command(suggest)
135
+ cli.add_command(product)
136
+ cli.add_command(bestsellers)
137
+
138
+
139
+ def main():
140
+ """Entry point for cli-web-amazon."""
141
+ cli()
142
+
143
+
144
+ # MCP server mode — exposes every command as an MCP tool over stdio.
145
+ # Canonical adapter: cli-web-core/cli_web_core/mcp_server.py (vendored copy).
146
+ from cli_web.amazon import __version__ as _pkg_version # noqa: E402
147
+ from cli_web.amazon.utils.doctor import register_doctor_command # noqa: E402
148
+ from cli_web.amazon.utils.mcp_server import register_mcp_command # noqa: E402
149
+
150
+ register_mcp_command(cli, app_name="amazon", version=_pkg_version)
151
+ register_doctor_command(cli, app_name="amazon", pkg="amazon")
152
+
153
+
154
+ if __name__ == "__main__":
155
+ main()
@@ -0,0 +1 @@
1
+ """CLI command groups for cli-web-amazon."""
@@ -0,0 +1,61 @@
1
+ """Best sellers commands for cli-web-amazon."""
2
+
3
+ import click
4
+
5
+ from ..core.client import AmazonClient
6
+ from ..utils.helpers import handle_errors, print_json
7
+ from ..utils.output import print_bestsellers
8
+
9
+ COMMON_CATEGORIES = [
10
+ "electronics",
11
+ "books",
12
+ "toys-and-games",
13
+ "music",
14
+ "video-games",
15
+ "home-garden",
16
+ "clothing-shoes-jewelry",
17
+ "sports-outdoors",
18
+ "kitchen",
19
+ "office-products",
20
+ "pet-supplies",
21
+ "beauty",
22
+ "health-household",
23
+ "automotive",
24
+ "tools-home-improvement",
25
+ ]
26
+
27
+
28
+ @click.command("bestsellers")
29
+ @click.argument("category", default="electronics")
30
+ @click.option(
31
+ "--page", type=int, default=1, show_default=True, help="Page number (each page has ~50 items)."
32
+ )
33
+ @click.option("--json", "use_json", is_flag=True, default=False, help="Output as JSON.")
34
+ def bestsellers(category, page, use_json):
35
+ """Browse Amazon Best Sellers by category.
36
+
37
+ CATEGORY defaults to 'electronics'. Other common values:
38
+ books, toys-and-games, music, video-games, home-garden,
39
+ clothing-shoes-jewelry, sports-outdoors, kitchen, beauty
40
+
41
+ Examples:
42
+ cli-web-amazon bestsellers
43
+ cli-web-amazon bestsellers books
44
+ cli-web-amazon bestsellers electronics --page 2
45
+ cli-web-amazon bestsellers toys-and-games --json
46
+ """
47
+ with handle_errors(json_mode=use_json):
48
+ with AmazonClient() as client:
49
+ items = client.get_bestsellers(category=category, page=page)
50
+
51
+ if use_json:
52
+ print_json([i.to_dict() for i in items])
53
+ else:
54
+ if not items:
55
+ click.echo(
56
+ f"No best sellers found for category '{category}'.\n"
57
+ f"Try one of: {', '.join(COMMON_CATEGORIES[:5])}"
58
+ )
59
+ else:
60
+ print_bestsellers(items, category=category)
61
+ click.echo(f"\n{len(items)} items. Use --page to see more.")
@@ -0,0 +1,36 @@
1
+ """Product commands for cli-web-amazon."""
2
+
3
+ import click
4
+
5
+ from ..core.client import AmazonClient
6
+ from ..utils.helpers import handle_errors, print_json
7
+ from ..utils.output import print_product
8
+
9
+
10
+ @click.group("product")
11
+ def product():
12
+ """Amazon product operations."""
13
+ pass
14
+
15
+
16
+ @product.command("get")
17
+ @click.argument("asin")
18
+ @click.option("--json", "use_json", is_flag=True, default=False, help="Output as JSON.")
19
+ def get_product(asin, use_json):
20
+ """Get product details by ASIN.
21
+
22
+ ASIN is Amazon's Standard Identification Number (e.g., B0GRZ78683).
23
+
24
+ Examples:
25
+ cli-web-amazon product get B0GRZ78683
26
+ cli-web-amazon product get B087JWTWF9 --json
27
+ """
28
+ with handle_errors(json_mode=use_json):
29
+ asin = asin.upper().strip()
30
+ with AmazonClient() as client:
31
+ p = client.get_product(asin)
32
+
33
+ if use_json:
34
+ print_json(p.to_dict())
35
+ else:
36
+ print_product(p)
@@ -0,0 +1,45 @@
1
+ """Search commands for cli-web-amazon."""
2
+
3
+ import click
4
+
5
+ from ..core.client import AmazonClient
6
+ from ..utils.helpers import handle_errors, print_json
7
+ from ..utils.output import print_search_results
8
+
9
+
10
+ @click.command("search")
11
+ @click.argument("query")
12
+ @click.option("--page", type=int, default=1, show_default=True, help="Page number of results.")
13
+ @click.option(
14
+ "--dept",
15
+ "--department",
16
+ "department",
17
+ default=None,
18
+ help="Department filter (e.g., 'electronics', 'books').",
19
+ )
20
+ @click.option("--json", "use_json", is_flag=True, default=False, help="Output as JSON.")
21
+ def search(query, page, department, use_json):
22
+ """Search Amazon products by keyword.
23
+
24
+ Returns product cards with ASIN, title, price, and rating.
25
+
26
+ Examples:
27
+ cli-web-amazon search laptop
28
+ cli-web-amazon search "wireless headphones" --page 2
29
+ cli-web-amazon search camera --dept electronics
30
+ """
31
+ with handle_errors(json_mode=use_json):
32
+ with AmazonClient() as client:
33
+ results = client.search(query, page=page, department=department)
34
+
35
+ if use_json:
36
+ print_json([r.to_dict() for r in results])
37
+ else:
38
+ if not results:
39
+ click.echo(f"No results found for '{query}'.")
40
+ else:
41
+ title = f"Search: {query}"
42
+ if page > 1:
43
+ title += f" (page {page})"
44
+ print_search_results(results, title=title)
45
+ click.echo(f"\n{len(results)} results. Use --page to see more.")
@@ -0,0 +1,36 @@
1
+ """Autocomplete suggestion commands for cli-web-amazon."""
2
+
3
+ import click
4
+
5
+ from ..core.client import AmazonClient
6
+ from ..utils.helpers import handle_errors, print_json
7
+ from ..utils.output import print_suggestions
8
+
9
+
10
+ @click.command("suggest")
11
+ @click.argument("query")
12
+ @click.option(
13
+ "--limit",
14
+ type=int,
15
+ default=11,
16
+ show_default=True,
17
+ help="Maximum number of suggestions to return.",
18
+ )
19
+ @click.option("--json", "use_json", is_flag=True, default=False, help="Output as JSON.")
20
+ def suggest(query, limit, use_json):
21
+ """Get autocomplete suggestions for a search query.
22
+
23
+ Example: cli-web-amazon suggest laptop
24
+ """
25
+ with handle_errors(json_mode=use_json):
26
+ with AmazonClient() as client:
27
+ results = client.get_suggestions(query, limit=limit)
28
+
29
+ if use_json:
30
+ print_json([s.to_dict() for s in results])
31
+ else:
32
+ if not results:
33
+ click.echo(f"No suggestions for '{query}'.")
34
+ else:
35
+ click.echo(f"Suggestions for '{query}':")
36
+ print_suggestions(results)
@@ -0,0 +1 @@
1
+ """Core modules for cli-web-amazon."""