walla-cli 0.1.7__tar.gz → 0.1.9__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.
- {walla_cli-0.1.7 → walla_cli-0.1.9}/AGENTS.md +3 -1
- {walla_cli-0.1.7 → walla_cli-0.1.9}/PKG-INFO +43 -35
- {walla_cli-0.1.7 → walla_cli-0.1.9}/README.md +41 -33
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/WIRE.md +24 -0
- walla_cli-0.1.9/docs/assets/walla-demo-poster.jpg +0 -0
- walla_cli-0.1.9/docs/assets/walla-demo.mp4 +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/objective_function.md +1 -1
- walla_cli-0.1.9/fixtures/sell_item_request.json +51 -0
- walla_cli-0.1.9/fixtures/wire_contracts.json +230 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/pyproject.toml +2 -2
- {walla_cli-0.1.7 → walla_cli-0.1.9}/scripts/check_code_quality.py +120 -1
- walla_cli-0.1.9/skills/walla/SKILL.md +34 -0
- walla_cli-0.1.9/skills/walla-buy/SKILL.md +35 -0
- walla_cli-0.1.9/skills/walla-sell/SKILL.md +41 -0
- walla_cli-0.1.9/tests/test_desk.py +196 -0
- walla_cli-0.1.9/tests/test_live.py +159 -0
- walla_cli-0.1.9/tests/test_sell.py +334 -0
- walla_cli-0.1.9/tests/test_wire_contracts.py +382 -0
- walla_cli-0.1.9/uv.lock +2644 -0
- walla_cli-0.1.9/walla/__init__.py +7 -0
- walla_cli-0.1.9/walla/account/desk.py +230 -0
- walla_cli-0.1.9/walla/account/sell.py +248 -0
- walla_cli-0.1.9/walla/account/sell_wire.py +144 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/banner.py +12 -8
- walla_cli-0.1.9/walla/cli/cmd_desk.py +37 -0
- walla_cli-0.1.9/walla/cli/cmd_sell.py +130 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/main.py +5 -4
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/instruct.py +37 -21
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/path.py +5 -0
- walla_cli-0.1.9/walla/hunter/converge.py +221 -0
- walla_cli-0.1.9/walla/hunter/pursuits.py +70 -0
- walla_cli-0.1.9/walla/hunter/stack.py +55 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/mcp/server.py +11 -0
- walla_cli-0.1.7/skills/walla/SKILL.md +0 -44
- walla_cli-0.1.7/tests/test_live.py +0 -68
- walla_cli-0.1.7/walla/__init__.py +0 -7
- {walla_cli-0.1.7 → walla_cli-0.1.9}/.cursor/rules/quality.mdc +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/.github/workflows/ci.yml +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/.gitignore +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/LICENSE +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/assets/walla-github-banner.jpg +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/code_quality.md +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/data_engineering_standards.md +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/mcp.md +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/docs/rate_limit_analysis.md +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/fixtures/categories.json +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/fixtures/item_detail.json +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/fixtures/offer_buyer_request.json +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/fixtures/search_bicicleta.json +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/scripts/dogfood_run.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/scripts/probe_rate.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_account.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_account_more.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_catch.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_chat_open.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_cli_json.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_core.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_edges.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_export.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_http_more.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_negotiate.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_parsers.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_polite.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_regressions.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_search_api.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_session_store.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_shortlist.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/tests/test_verdict.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/actions.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/chat.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/cookies.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/inbox.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/login.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/offer_wire.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/prompt.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/account/session_store.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/catch.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/cmd_account.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/cmd_look.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/cmd_ops.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/cli/console.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/envelope.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/errors.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/exceptions.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/core/human_fix.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/http/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/http/client.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/http/headers.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/http/polite.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/export.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/export_pdf.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/negotiate.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/profile_store.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/shortlist.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/verdict.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/hunter/watches.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/mcp/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/mcp/_entry.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/models/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/models/account.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/models/listing.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/models/profile.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/search/__init__.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/search/api.py +0 -0
- {walla_cli-0.1.7 → walla_cli-0.1.9}/walla/search/parse.py +0 -0
|
@@ -57,9 +57,11 @@ Ranks: models 10 → exceptions 15 → http 20 → core 30 → search/account/hu
|
|
|
57
57
|
|
|
58
58
|
- **Do** keep files <= 250 LOC.
|
|
59
59
|
- **Do** fail closed; typed `error_type`.
|
|
60
|
-
- **Do** require `--yes` for say/offer.
|
|
60
|
+
- **Do** require `--yes` for bare say/offer/sell/unsell. `pursue` and `desk` send negotiation chat without a per-message prompt. Never pay.
|
|
61
61
|
- **Don't** commit session.json, cookies, or tokens.
|
|
62
62
|
- **Don't** invent wire shapes without a fixture.
|
|
63
63
|
- **Don't** post buyer offers as `{item_id, amount, currency}` (HTTP 400).
|
|
64
64
|
Use `walla.account.offer_wire.build_offer_body` / `fixtures/offer_buyer_request.json`.
|
|
65
|
+
- **Don't** create listings without `Accept: application/vnd.upload-v2+json`
|
|
66
|
+
(HTTP 405). Use `walla sell` / `fixtures/sell_item_request.json`.
|
|
65
67
|
- **Don't** require `.env` credentials; login is cookie paste.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: walla-cli
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Wallapop.es CLI - look · offer · talk for humans and agents
|
|
3
|
+
Version: 0.1.9
|
|
4
|
+
Summary: Wallapop.es CLI - look · offer · talk · sell for humans and agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/berendgort/wallapop-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/berendgort/wallapop-cli
|
|
7
7
|
Project-URL: Issues, https://github.com/berendgort/wallapop-cli/issues
|
|
@@ -51,43 +51,50 @@ Description-Content-Type: text/markdown
|
|
|
51
51
|
██║███╗██║ ██╔══██║ ██║ ██║ ██╔══██║ ╚════╝ ██║ ██║ ██║
|
|
52
52
|
╚███╔███╔╝ ██║ ██║ ███████╗ ███████╗ ██║ ██║ ╚██████╗ ███████╗ ██║
|
|
53
53
|
╚══╝╚══╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝
|
|
54
|
-
look · offer · talk
|
|
54
|
+
look · offer · talk · sell
|
|
55
55
|
Dr. Berend Gort · www.berendgort.dev
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-

|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
Demo music: [Funkee Monkeee](https://mixkit.co/free-stock-music/funkee-monkeee-1140/) by Michael Ramir C.
|
|
61
|
+
([Mixkit Stock Music Free License](https://mixkit.co/license/#musicFree)).
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
**walla** turns Claude, GPT, or Cursor into a Wallapop helper that actually
|
|
64
|
+
*does* the work for you. You drop a few photos and answer a couple of
|
|
65
|
+
questions; the agent publishes the listing. When buyers message, it reads
|
|
66
|
+
the chats, replies for you, and negotiates down to your minimum price —
|
|
67
|
+
then shows you the best deal. You only open the Wallapop app to accept.
|
|
68
|
+
No typing chats. No babysitting the inbox.
|
|
69
|
+
|
|
70
|
+
Unofficial Wallapop.es CLI + MCP + Python library. Not affiliated with
|
|
71
|
+
Wallapop. Respect ToS and rate limits.
|
|
64
72
|
|
|
65
73
|
### What this unlocks
|
|
66
74
|
|
|
67
75
|
You tell Cursor: *“Find me a used kite near Barcelona under €400, message
|
|
68
76
|
the seller, and offer if it’s a GRAB.”*
|
|
69
77
|
|
|
70
|
-
The agent runs `walla` — ranks listings **GRAB / LOOK / PASS**,
|
|
71
|
-
|
|
78
|
+
The agent runs `walla` — ranks listings **GRAB / LOOK / PASS**, messages the
|
|
79
|
+
shortlist, and follows replies until a price is agreed. You close the deal
|
|
80
|
+
in the Wallapop app.
|
|
72
81
|
|
|
73
82
|
```bash
|
|
74
83
|
walla setup --lat 41.39 --lon 2.17 --km 30 --label Barcelona \
|
|
75
84
|
--budget 400 --aggression fair --must "kite cabrinha"
|
|
76
|
-
walla search "tabla kite Cabrinha" --max 40 --json
|
|
77
|
-
# agent: GRAB · Cabrinha Moto 10m · €320 · 4 km
|
|
78
|
-
# https://es.wallapop.com/item/...
|
|
79
|
-
|
|
80
|
-
walla search "…" --export md,csv,html,pdf --out ./shortlist --json
|
|
81
|
-
# or later: walla export --format md,csv,html,pdf --out ./shortlist --json
|
|
82
|
-
|
|
83
85
|
walla login # paste session cookie once
|
|
84
|
-
walla
|
|
85
|
-
walla
|
|
86
|
-
walla offer <id> --eur 280 --yes # only after you approve; never pays
|
|
86
|
+
walla pursue "tabla kite Cabrinha" --json
|
|
87
|
+
walla desk --json # one inbox read; replies; stack.best
|
|
87
88
|
```
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
Sell is the same idea: answer the photo questions, publish once, then desk
|
|
91
|
+
talks to buyers.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
walla sell ./shot.jpg --json
|
|
95
|
+
walla sell ./shot.jpg --title "…" --desc "…" --eur 40 \
|
|
96
|
+
--category 10105 --root 12579 --floor 35 --yes --json
|
|
97
|
+
```
|
|
91
98
|
|
|
92
99
|
**Quality bar (enforced in CI):**
|
|
93
100
|
|
|
@@ -139,26 +146,25 @@ Optional MCP:
|
|
|
139
146
|
| Ask | Command |
|
|
140
147
|
|-----|---------|
|
|
141
148
|
| Mandate | `walla setup --budget 400 --aggression fair --must "kite"` |
|
|
142
|
-
| Look | `walla search "tabla kite" --max 40 --json`
|
|
143
|
-
|
|
|
144
|
-
|
|
|
145
|
-
|
|
|
149
|
+
| Look | `walla search "tabla kite" --max 40 --json` |
|
|
150
|
+
| Buy | `walla pursue "<query>" --json` then `walla desk --json` |
|
|
151
|
+
| Sell | `walla sell <photos> --json`, then the same command with `--yes` |
|
|
152
|
+
| Close | Human pays or accepts in the Wallapop app |
|
|
146
153
|
|
|
147
|
-
### HITL
|
|
154
|
+
### HITL
|
|
148
155
|
|
|
149
156
|
| Step | Agent alone | Ask human |
|
|
150
157
|
|------|-------------|-----------|
|
|
151
158
|
| Search inside mandate | yes | if query vague or budget unset |
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
| `offer --yes` | never; refuse if EUR > budget | yes to that exact EUR |
|
|
156
|
-
| Pay / buy / reserve | **never** | human finishes in the Wallapop app |
|
|
159
|
+
| `pursue` / `desk` | yes, including the chat messages | never for each text |
|
|
160
|
+
| Publish or delete a listing | no | `--yes` once the questions are answered |
|
|
161
|
+
| Pay / accept / meet | **never** | human finishes in the Wallapop app |
|
|
157
162
|
|
|
158
163
|
Rules:
|
|
159
164
|
|
|
160
|
-
-
|
|
161
|
-
-
|
|
165
|
+
- `pursue` and `desk` send negotiation chat. Do not ask the human to send.
|
|
166
|
+
- Bare `say` / `offer` / `sell` / `unsell` still need `--yes`.
|
|
167
|
+
- `--yes` never completes a purchase or accepts a sale.
|
|
162
168
|
- If they only asked to look, do not send.
|
|
163
169
|
- Ambiguous match or multiple GRABs: ask once with candidates.
|
|
164
170
|
- Always present Wallapop shortlists ranked best-first with a markdown link on every item URL.
|
|
@@ -187,9 +193,11 @@ walla doctor --json
|
|
|
187
193
|
| `walla search` / `item` / `categories` | Look |
|
|
188
194
|
| `walla watch add\|list\|check` | Local saved searches |
|
|
189
195
|
| `walla login` / `logout` / `whoami` | Session (paste cookie; optional `--password`) |
|
|
196
|
+
| `walla pursue` / `desk` | Message a shortlist and follow the inbox |
|
|
190
197
|
| `walla negotiate` | Win-win Spanish draft (never sends) |
|
|
191
|
-
| `walla inbox` / `thread` / `say` | Talk |
|
|
192
|
-
| `walla offer` |
|
|
198
|
+
| `walla inbox` / `thread` / `say` | Talk (`say` needs `--yes`) |
|
|
199
|
+
| `walla offer` | Formal offer (needs `--yes`) |
|
|
200
|
+
| `walla sell` / `unsell` | Publish or delete a listing (`--yes`) |
|
|
193
201
|
| `walla fav list\|add\|rm` | Favorites |
|
|
194
202
|
| `walla instruct` / `doctor` | Agent recipe + health |
|
|
195
203
|
|
|
@@ -7,43 +7,50 @@
|
|
|
7
7
|
██║███╗██║ ██╔══██║ ██║ ██║ ██╔══██║ ╚════╝ ██║ ██║ ██║
|
|
8
8
|
╚███╔███╔╝ ██║ ██║ ███████╗ ███████╗ ██║ ██║ ╚██████╗ ███████╗ ██║
|
|
9
9
|
╚══╝╚══╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝
|
|
10
|
-
look · offer · talk
|
|
10
|
+
look · offer · talk · sell
|
|
11
11
|
Dr. Berend Gort · www.berendgort.dev
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-

|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Demo music: [Funkee Monkeee](https://mixkit.co/free-stock-music/funkee-monkeee-1140/) by Michael Ramir C.
|
|
17
|
+
([Mixkit Stock Music Free License](https://mixkit.co/license/#musicFree)).
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**walla** turns Claude, GPT, or Cursor into a Wallapop helper that actually
|
|
20
|
+
*does* the work for you. You drop a few photos and answer a couple of
|
|
21
|
+
questions; the agent publishes the listing. When buyers message, it reads
|
|
22
|
+
the chats, replies for you, and negotiates down to your minimum price —
|
|
23
|
+
then shows you the best deal. You only open the Wallapop app to accept.
|
|
24
|
+
No typing chats. No babysitting the inbox.
|
|
25
|
+
|
|
26
|
+
Unofficial Wallapop.es CLI + MCP + Python library. Not affiliated with
|
|
27
|
+
Wallapop. Respect ToS and rate limits.
|
|
20
28
|
|
|
21
29
|
### What this unlocks
|
|
22
30
|
|
|
23
31
|
You tell Cursor: *“Find me a used kite near Barcelona under €400, message
|
|
24
32
|
the seller, and offer if it’s a GRAB.”*
|
|
25
33
|
|
|
26
|
-
The agent runs `walla` — ranks listings **GRAB / LOOK / PASS**,
|
|
27
|
-
|
|
34
|
+
The agent runs `walla` — ranks listings **GRAB / LOOK / PASS**, messages the
|
|
35
|
+
shortlist, and follows replies until a price is agreed. You close the deal
|
|
36
|
+
in the Wallapop app.
|
|
28
37
|
|
|
29
38
|
```bash
|
|
30
39
|
walla setup --lat 41.39 --lon 2.17 --km 30 --label Barcelona \
|
|
31
40
|
--budget 400 --aggression fair --must "kite cabrinha"
|
|
32
|
-
walla search "tabla kite Cabrinha" --max 40 --json
|
|
33
|
-
# agent: GRAB · Cabrinha Moto 10m · €320 · 4 km
|
|
34
|
-
# https://es.wallapop.com/item/...
|
|
35
|
-
|
|
36
|
-
walla search "…" --export md,csv,html,pdf --out ./shortlist --json
|
|
37
|
-
# or later: walla export --format md,csv,html,pdf --out ./shortlist --json
|
|
38
|
-
|
|
39
41
|
walla login # paste session cookie once
|
|
40
|
-
walla
|
|
41
|
-
walla
|
|
42
|
-
walla offer <id> --eur 280 --yes # only after you approve; never pays
|
|
42
|
+
walla pursue "tabla kite Cabrinha" --json
|
|
43
|
+
walla desk --json # one inbox read; replies; stack.best
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
Sell is the same idea: answer the photo questions, publish once, then desk
|
|
47
|
+
talks to buyers.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
walla sell ./shot.jpg --json
|
|
51
|
+
walla sell ./shot.jpg --title "…" --desc "…" --eur 40 \
|
|
52
|
+
--category 10105 --root 12579 --floor 35 --yes --json
|
|
53
|
+
```
|
|
47
54
|
|
|
48
55
|
**Quality bar (enforced in CI):**
|
|
49
56
|
|
|
@@ -95,26 +102,25 @@ Optional MCP:
|
|
|
95
102
|
| Ask | Command |
|
|
96
103
|
|-----|---------|
|
|
97
104
|
| Mandate | `walla setup --budget 400 --aggression fair --must "kite"` |
|
|
98
|
-
| Look | `walla search "tabla kite" --max 40 --json`
|
|
99
|
-
|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
105
|
+
| Look | `walla search "tabla kite" --max 40 --json` |
|
|
106
|
+
| Buy | `walla pursue "<query>" --json` then `walla desk --json` |
|
|
107
|
+
| Sell | `walla sell <photos> --json`, then the same command with `--yes` |
|
|
108
|
+
| Close | Human pays or accepts in the Wallapop app |
|
|
102
109
|
|
|
103
|
-
### HITL
|
|
110
|
+
### HITL
|
|
104
111
|
|
|
105
112
|
| Step | Agent alone | Ask human |
|
|
106
113
|
|------|-------------|-----------|
|
|
107
114
|
| Search inside mandate | yes | if query vague or budget unset |
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
| `offer --yes` | never; refuse if EUR > budget | yes to that exact EUR |
|
|
112
|
-
| Pay / buy / reserve | **never** | human finishes in the Wallapop app |
|
|
115
|
+
| `pursue` / `desk` | yes, including the chat messages | never for each text |
|
|
116
|
+
| Publish or delete a listing | no | `--yes` once the questions are answered |
|
|
117
|
+
| Pay / accept / meet | **never** | human finishes in the Wallapop app |
|
|
113
118
|
|
|
114
119
|
Rules:
|
|
115
120
|
|
|
116
|
-
-
|
|
117
|
-
-
|
|
121
|
+
- `pursue` and `desk` send negotiation chat. Do not ask the human to send.
|
|
122
|
+
- Bare `say` / `offer` / `sell` / `unsell` still need `--yes`.
|
|
123
|
+
- `--yes` never completes a purchase or accepts a sale.
|
|
118
124
|
- If they only asked to look, do not send.
|
|
119
125
|
- Ambiguous match or multiple GRABs: ask once with candidates.
|
|
120
126
|
- Always present Wallapop shortlists ranked best-first with a markdown link on every item URL.
|
|
@@ -143,9 +149,11 @@ walla doctor --json
|
|
|
143
149
|
| `walla search` / `item` / `categories` | Look |
|
|
144
150
|
| `walla watch add\|list\|check` | Local saved searches |
|
|
145
151
|
| `walla login` / `logout` / `whoami` | Session (paste cookie; optional `--password`) |
|
|
152
|
+
| `walla pursue` / `desk` | Message a shortlist and follow the inbox |
|
|
146
153
|
| `walla negotiate` | Win-win Spanish draft (never sends) |
|
|
147
|
-
| `walla inbox` / `thread` / `say` | Talk |
|
|
148
|
-
| `walla offer` |
|
|
154
|
+
| `walla inbox` / `thread` / `say` | Talk (`say` needs `--yes`) |
|
|
155
|
+
| `walla offer` | Formal offer (needs `--yes`) |
|
|
156
|
+
| `walla sell` / `unsell` | Publish or delete a listing (`--yes`) |
|
|
149
157
|
| `walla fav list\|add\|rm` | Favorites |
|
|
150
158
|
| `walla instruct` / `doctor` | Agent recipe + health |
|
|
151
159
|
|
|
@@ -57,6 +57,30 @@ login ever succeeds.
|
|
|
57
57
|
Some sellers disable offers → **409** `offer creation not allowed`; fall back to chat text.
|
|
58
58
|
- Favorites: `/api/v3/users/me/favorites`, `/api/v3/items/{id}/favorite`
|
|
59
59
|
|
|
60
|
+
## Sell / Vender (auth)
|
|
61
|
+
|
|
62
|
+
Browser: `https://es.wallapop.com/app/catalog/upload/consumer-goods`.
|
|
63
|
+
|
|
64
|
+
1. `POST /api/v3/steps` `{mode:{action:"upload",id:<uuid>}}` → step `title`
|
|
65
|
+
2. `POST /api/v3/steps` `current_step=title` draft `{title}` → `photo`
|
|
66
|
+
3. `POST /api/v3/upload/{upload_id}/pictures` multipart `file` → **204**
|
|
67
|
+
4. `POST /api/v3/steps` `current_step=photo` → `category`
|
|
68
|
+
5. `POST /api/v3/steps` `current_step=category` draft
|
|
69
|
+
`{title, category_leaf_id, root_category_id}` (**ids as strings**) → `loading`
|
|
70
|
+
6. Poll `GET /api/v3/suggested-item-data/{upload_id}` (404 then empty 200)
|
|
71
|
+
7. `POST /api/v3/steps` `current_step=loading` → `listing`
|
|
72
|
+
8. Create: `POST /api/v3/items` multipart `image` + `item` (JSON string).
|
|
73
|
+
Header **`Accept: application/vnd.upload-v2+json`** (without it → HTTP 405).
|
|
74
|
+
Extra photos: `POST /api/v3/items/{id}/picture2` multipart `image` + `order`.
|
|
75
|
+
9. Delete: `DELETE /api/v3/items/{id}` → 204.
|
|
76
|
+
|
|
77
|
+
Fixture: `fixtures/sell_item_request.json` / `walla.account.sell_wire.build_item_body`.
|
|
78
|
+
|
|
79
|
+
Every CLI call (method, path, auth, body) is listed in `fixtures/wire_contracts.json`.
|
|
80
|
+
`scripts/check_code_quality.py` fails if `walla/account`, `walla/search`, or `walla/http`
|
|
81
|
+
grows a `/api/` or `/bff/` literal that the catalog does not list.
|
|
82
|
+
CLI: `walla sell photo.jpg … --yes` (draft without `--yes`).
|
|
83
|
+
|
|
60
84
|
Writes that fail closed as `error_type: unsupported` until fixtures exist.
|
|
61
85
|
|
|
62
86
|
## Rate limits
|
|
Binary file
|
|
Binary file
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
1. Find the listing (search + verdict GRAB / LOOK / PASS).
|
|
4
4
|
2. Do not miss a reply (inbox / thread).
|
|
5
|
-
3.
|
|
5
|
+
3. `walla say` / `walla offer` still need `--yes`. `walla pursue` and `walla desk` send negotiation chat on purpose. Never pay.
|
|
6
6
|
4. Never leak session cookies or bearer tokens.
|
|
7
7
|
5. Stay polite on rate limits.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"endpoint": "POST /api/v3/items",
|
|
3
|
+
"content_type": "multipart/form-data",
|
|
4
|
+
"accept": "application/vnd.upload-v2+json",
|
|
5
|
+
"fields": {
|
|
6
|
+
"image": "first JPEG/PNG/WebP file",
|
|
7
|
+
"item": "JSON string (see example)"
|
|
8
|
+
},
|
|
9
|
+
"steps": [
|
|
10
|
+
"POST /api/v3/steps mode.upload",
|
|
11
|
+
"POST /api/v3/steps current_step=title draft.title",
|
|
12
|
+
"POST /api/v3/upload/{upload_id}/pictures multipart file",
|
|
13
|
+
"POST /api/v3/steps current_step=photo",
|
|
14
|
+
"POST /api/v3/steps current_step=category draft.category_leaf_id+root_category_id (strings)",
|
|
15
|
+
"GET /api/v3/suggested-item-data/{upload_id} until 200",
|
|
16
|
+
"POST /api/v3/steps current_step=loading",
|
|
17
|
+
"POST /api/v3/items Accept upload-v2"
|
|
18
|
+
],
|
|
19
|
+
"delete": "DELETE /api/v3/items/{id}",
|
|
20
|
+
"example": {
|
|
21
|
+
"attributes": {
|
|
22
|
+
"title": "TEST walla CLI - borrar",
|
|
23
|
+
"description": "Anuncio de prueba. NO COMPRAR.",
|
|
24
|
+
"price_amount": 9,
|
|
25
|
+
"condition": "good"
|
|
26
|
+
},
|
|
27
|
+
"category_leaf_id": "10105",
|
|
28
|
+
"apply_discount": false,
|
|
29
|
+
"location": {
|
|
30
|
+
"latitude": 41.3874,
|
|
31
|
+
"longitude": 2.1686,
|
|
32
|
+
"approximated": true
|
|
33
|
+
},
|
|
34
|
+
"delivery": {
|
|
35
|
+
"allowed_by_user": false,
|
|
36
|
+
"max_weight_kg": null,
|
|
37
|
+
"cost_configuration_id": null
|
|
38
|
+
},
|
|
39
|
+
"upload_id": "00000000-0000-0000-0000-000000000000"
|
|
40
|
+
},
|
|
41
|
+
"required_keys": [
|
|
42
|
+
"attributes",
|
|
43
|
+
"category_leaf_id",
|
|
44
|
+
"apply_discount",
|
|
45
|
+
"location",
|
|
46
|
+
"delivery",
|
|
47
|
+
"upload_id"
|
|
48
|
+
],
|
|
49
|
+
"attribute_required_keys": ["title", "description", "price_amount"],
|
|
50
|
+
"conditions": ["as_good_as_new", "good", "fair", "has_given_it_all"]
|
|
51
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shared_headers": ["X-DeviceOS", "X-AppVersion", "Accept-Language"],
|
|
3
|
+
"requests": [
|
|
4
|
+
{
|
|
5
|
+
"id": "search",
|
|
6
|
+
"cli": "search",
|
|
7
|
+
"method": "GET",
|
|
8
|
+
"path": "/api/v3/search",
|
|
9
|
+
"auth": false,
|
|
10
|
+
"ok_status": [200]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "item",
|
|
14
|
+
"cli": "item",
|
|
15
|
+
"method": "GET",
|
|
16
|
+
"path": "/api/v3/items/{id}",
|
|
17
|
+
"auth": false,
|
|
18
|
+
"ok_status": [200]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "categories",
|
|
22
|
+
"cli": "categories",
|
|
23
|
+
"method": "GET",
|
|
24
|
+
"path": "/api/v3/categories",
|
|
25
|
+
"auth": false,
|
|
26
|
+
"ok_status": [200]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "session_mint",
|
|
30
|
+
"cli": "login",
|
|
31
|
+
"method": "GET",
|
|
32
|
+
"path": "/api/auth/session",
|
|
33
|
+
"auth": false,
|
|
34
|
+
"ok_status": [200]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "password_login",
|
|
38
|
+
"cli": "login",
|
|
39
|
+
"method": "POST",
|
|
40
|
+
"path": "/api/v3/access/login",
|
|
41
|
+
"auth": false,
|
|
42
|
+
"body_keys": ["username", "password"],
|
|
43
|
+
"ok_status": [200]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "refresh",
|
|
47
|
+
"cli": "login",
|
|
48
|
+
"method": "POST",
|
|
49
|
+
"path": "/api/v3/access/refresh",
|
|
50
|
+
"auth": false,
|
|
51
|
+
"body_keys": ["refresh_token"],
|
|
52
|
+
"ok_status": [200]
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "whoami",
|
|
56
|
+
"cli": "whoami",
|
|
57
|
+
"method": "GET",
|
|
58
|
+
"path": "/api/v3/users/me",
|
|
59
|
+
"auth": true,
|
|
60
|
+
"ok_status": [200, 404]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "inbox",
|
|
64
|
+
"cli": "inbox",
|
|
65
|
+
"method": "GET",
|
|
66
|
+
"path": "/bff/messaging/inbox",
|
|
67
|
+
"auth": true,
|
|
68
|
+
"ok_status": [200],
|
|
69
|
+
"known_bad": [{"status": 405, "cause": "GET /api/v3/conversations"}]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "chat_open",
|
|
73
|
+
"cli": "chat",
|
|
74
|
+
"method": "POST",
|
|
75
|
+
"path": "/api/v3/conversations",
|
|
76
|
+
"auth": true,
|
|
77
|
+
"body_keys": ["item_id"],
|
|
78
|
+
"ok_status": [200, 201]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "im_token",
|
|
82
|
+
"cli": "say",
|
|
83
|
+
"method": "GET",
|
|
84
|
+
"path": "/api/v3/instant-messaging/token",
|
|
85
|
+
"auth": true,
|
|
86
|
+
"ok_status": [200]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "say_pubnub",
|
|
90
|
+
"cli": "say",
|
|
91
|
+
"method": "GET",
|
|
92
|
+
"path": "https://ps2.pndsn.com/publish/",
|
|
93
|
+
"needle": "ps2.pndsn.com",
|
|
94
|
+
"auth": false,
|
|
95
|
+
"ok_status": [200],
|
|
96
|
+
"known_bad": [{"status": 404, "cause": "REST messages"}]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "offer",
|
|
100
|
+
"cli": "offer",
|
|
101
|
+
"method": "POST",
|
|
102
|
+
"path": "/api/v3/delivery/buyer/offers",
|
|
103
|
+
"auth": true,
|
|
104
|
+
"body_keys": [
|
|
105
|
+
"offer_id",
|
|
106
|
+
"offer_price_amount",
|
|
107
|
+
"offer_price_currency",
|
|
108
|
+
"item_ids"
|
|
109
|
+
],
|
|
110
|
+
"forbidden_body_keys": ["item_id", "amount", "currency"],
|
|
111
|
+
"ok_status": [200, 201],
|
|
112
|
+
"known_bad": [
|
|
113
|
+
{"status": 400, "cause": "wrong body or missing X-AppVersion"},
|
|
114
|
+
{"status": 409, "cause": "seller disabled offers"}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "favorites",
|
|
119
|
+
"cli": "fav list",
|
|
120
|
+
"method": "GET",
|
|
121
|
+
"path": "/api/v3/users/me/favorites",
|
|
122
|
+
"auth": true,
|
|
123
|
+
"ok_status": [200]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"id": "favorites_fallback",
|
|
127
|
+
"cli": "fav list",
|
|
128
|
+
"method": "GET",
|
|
129
|
+
"path": "/api/v3/favorites",
|
|
130
|
+
"auth": true,
|
|
131
|
+
"ok_status": [200]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "favorite_add",
|
|
135
|
+
"cli": "fav add",
|
|
136
|
+
"method": "POST",
|
|
137
|
+
"path": "/api/v3/items/{id}/favorite",
|
|
138
|
+
"needle": "/favorite",
|
|
139
|
+
"auth": true,
|
|
140
|
+
"ok_status": [200, 201, 204]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"id": "favorite_rm",
|
|
144
|
+
"cli": "fav rm",
|
|
145
|
+
"method": "DELETE",
|
|
146
|
+
"path": "/api/v3/items/{id}/favorite",
|
|
147
|
+
"needle": "/favorite",
|
|
148
|
+
"auth": true,
|
|
149
|
+
"ok_status": [200, 204]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"id": "sell_steps",
|
|
153
|
+
"cli": "sell",
|
|
154
|
+
"method": "POST",
|
|
155
|
+
"path": "/api/v3/steps",
|
|
156
|
+
"auth": true,
|
|
157
|
+
"ok_status": [200]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"id": "sell_pictures",
|
|
161
|
+
"cli": "sell",
|
|
162
|
+
"method": "POST",
|
|
163
|
+
"path": "/api/v3/upload/{id}/pictures",
|
|
164
|
+
"needle": "/api/v3/upload/",
|
|
165
|
+
"auth": true,
|
|
166
|
+
"multipart": ["file"],
|
|
167
|
+
"ok_status": [200, 204]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "sell_suggest",
|
|
171
|
+
"cli": "sell",
|
|
172
|
+
"method": "GET",
|
|
173
|
+
"path": "/api/v3/suggested-item-data/{id}",
|
|
174
|
+
"needle": "/suggested-item-data/",
|
|
175
|
+
"auth": true,
|
|
176
|
+
"ok_status": [200, 404]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"id": "sell_create",
|
|
180
|
+
"cli": "sell",
|
|
181
|
+
"method": "POST",
|
|
182
|
+
"path": "/api/v3/items",
|
|
183
|
+
"needle": "/api/v3/items",
|
|
184
|
+
"auth": true,
|
|
185
|
+
"accept": "application/vnd.upload-v2+json",
|
|
186
|
+
"multipart": ["image", "item"],
|
|
187
|
+
"ok_status": [200, 201],
|
|
188
|
+
"known_bad": [{"status": 405, "cause": "missing upload-v2 Accept"}]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"id": "sell_picture2",
|
|
192
|
+
"cli": "sell",
|
|
193
|
+
"method": "POST",
|
|
194
|
+
"path": "/api/v3/items/{id}/picture2",
|
|
195
|
+
"needle": "/picture2",
|
|
196
|
+
"auth": true,
|
|
197
|
+
"multipart": ["image", "order"],
|
|
198
|
+
"ok_status": [200, 201, 204]
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"id": "unsell",
|
|
202
|
+
"cli": "unsell",
|
|
203
|
+
"method": "DELETE",
|
|
204
|
+
"path": "/api/v3/items/{id}",
|
|
205
|
+
"needle": "/api/v3/items/",
|
|
206
|
+
"auth": true,
|
|
207
|
+
"ok_status": [200, 204]
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"id": "inbox_not_conversations",
|
|
211
|
+
"cli": "inbox",
|
|
212
|
+
"method": "GET",
|
|
213
|
+
"path": "/api/v3/conversations",
|
|
214
|
+
"forbidden": true,
|
|
215
|
+
"auth": true,
|
|
216
|
+
"ok_status": [],
|
|
217
|
+
"known_bad": [{"status": 405, "cause": "inbox is /bff/messaging/inbox"}]
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"id": "say_not_rest_messages",
|
|
221
|
+
"cli": "say",
|
|
222
|
+
"method": "POST",
|
|
223
|
+
"path": "/api/v3/instant-messaging/messages",
|
|
224
|
+
"forbidden": true,
|
|
225
|
+
"auth": true,
|
|
226
|
+
"ok_status": [],
|
|
227
|
+
"known_bad": [{"status": 404, "cause": "say uses PubNub publish"}]
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "walla-cli"
|
|
3
|
-
version = "0.1.
|
|
4
|
-
description = "Wallapop.es CLI - look · offer · talk for humans and agents"
|
|
3
|
+
version = "0.1.9"
|
|
4
|
+
description = "Wallapop.es CLI - look · offer · talk · sell for humans and agents"
|
|
5
5
|
authors = [{ name = "Dr. Berend Gort", email = "berend.gort@gmail.com" }]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = { text = "MIT" }
|