leak-cli 2026.2.17-beta.0 → 2026.2.17

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.
package/.env.example CHANGED
@@ -8,6 +8,8 @@ SELLER_PAY_TO=0xYourAddress
8
8
  PRICE_USD=0.01
9
9
  CHAIN_ID=eip155:84532
10
10
  WINDOW_SECONDS=3600
11
+ ACCESS_MODE=payment-only-no-download-code # no-download-code-no-payment | download-code-only-no-payment | payment-only-no-download-code | download-code-and-payment
12
+ DOWNLOAD_CODE_HASH= # required for download-code modes; hash only
11
13
 
12
14
  # Required when FACILITATOR_MODE=cdp_mainnet (Base mainnet path)
13
15
  # FACILITATOR_URL=https://api.cdp.coinbase.com/platform/v2/x402
package/README.md CHANGED
@@ -18,6 +18,19 @@ Package name: `leak-cli`
18
18
 
19
19
  Command: `leak`
20
20
 
21
+ Check installed CLI version:
22
+
23
+ ```bash
24
+ leak version
25
+ # or: leak --version
26
+ ```
27
+
28
+ Start interactive publish wizard:
29
+
30
+ ```bash
31
+ leak publish
32
+ ```
33
+
21
34
  OpenClaw skill docs live in this repo at:
22
35
  - [`/skills/leak-buy`](https://github.com/eucalyptus-viminalis/leak/tree/main/skills/leak-buy)
23
36
  - [`/skills/leak-publish`](https://github.com/eucalyptus-viminalis/leak/tree/main/skills/leak-publish)
@@ -34,6 +47,12 @@ Once `leak` is configured, commands become very simple to use:
34
47
 
35
48
  **Selling**:
36
49
 
50
+ ```bash
51
+ leak publish
52
+ ```
53
+
54
+ or direct flags:
55
+
37
56
  ```bash
38
57
  leak --file ./your-file.bin --public
39
58
  ```
@@ -41,13 +60,27 @@ leak --file ./your-file.bin --public
41
60
  **Buying**:
42
61
 
43
62
  ```bash
44
- leak buy <promo_or_download_link> --buyer-private-key-file <path>
63
+ leak buy <promo_or_download_link> [--download-code <code>] [--buyer-private-key-file <path>]
64
+ ```
65
+
66
+ **Hosting multiple files on one machine (path prefixes)**:
67
+
68
+ ```bash
69
+ leak host --config ./examples/multi-host.example.json
45
70
  ```
46
71
 
47
72
  ### Seller Quickstart 1: Local testnet sale (fastest path)
48
73
 
49
74
  Goal: run a local sale and verify the x402 flow end to end.
50
75
 
76
+ Interactive wizard path:
77
+
78
+ ```bash
79
+ leak publish --file ./your-file.bin
80
+ ```
81
+
82
+ Direct flags path:
83
+
51
84
  Prereqs: fund a buyer test wallet on Base Sepolia ([Circle Faucet](https://faucet.circle.com)); no CDP mainnet setup is needed.
52
85
 
53
86
  ```bash
@@ -84,6 +117,73 @@ Use the output URLs like this:
84
117
  - open the promo URL in a browser and confirm title, description, and image render correctly for social cards
85
118
  - while the tunnel is still running, run the Buyer section below to validate payment + download end-to-end
86
119
 
120
+ ### Seller Quickstart 3: Multi-file hosting with one domain + path prefixes
121
+
122
+ Goal: run multiple leak endpoints on one machine and expose them as:
123
+ - `https://<host>/leak/lolboy/` + `/download`
124
+ - `https://<host>/leak/peter/` + `/download`
125
+
126
+ Use the built-in multi-host runner:
127
+
128
+ ```bash
129
+ leak host --config ./examples/multi-host.example.json
130
+ ```
131
+
132
+ What this command does:
133
+ - starts one leak worker per route (one local port per artifact)
134
+ - starts one reverse proxy that maps `/<prefix>/*` to the right worker
135
+ - sets `PUBLIC_BASE_URL` per worker to `<resolvedOrigin><prefix>` so promo/download URLs are prefix-aware
136
+
137
+ Dry-run before launching:
138
+
139
+ ```bash
140
+ leak host --config ./examples/multi-host.example.json --dry-run
141
+ ```
142
+
143
+ Local validation with the default example:
144
+
145
+ ```bash
146
+ curl -i http://127.0.0.1:4080/leak/lolboy/
147
+ curl -i http://127.0.0.1:4080/leak/lolboy/download
148
+ curl -i http://127.0.0.1:4080/leak/peter/
149
+ curl -i http://127.0.0.1:4080/health
150
+ ```
151
+
152
+ Public origin modes:
153
+ - local-only (default): no tunnel, origin is `http://127.0.0.1:<proxy-port>`
154
+ - quick tunnel: add `--public` and leak host will start one Cloudflare quick tunnel for the shared proxy
155
+ - configured origin: set optional `publicOrigin` in config for named/manual ingress
156
+
157
+ Quick tunnel run (non-interactive):
158
+
159
+ ```bash
160
+ leak host --config ./examples/multi-host.example.json --public --public-confirm I_UNDERSTAND_PUBLIC_EXPOSURE
161
+ ```
162
+
163
+ Configured-origin run (named/manual tunnel):
164
+
165
+ ```json
166
+ {
167
+ "publicOrigin": "https://your-hostname.example",
168
+ "proxy": { "host": "127.0.0.1", "port": 4080 },
169
+ "routes": [ ... ]
170
+ }
171
+ ```
172
+
173
+ Precedence note:
174
+ - if `--public` is used and `publicOrigin` exists in config, leak host uses configured `publicOrigin` and does not start a quick tunnel
175
+
176
+ Capacity baseline (M1 Mac mini, 8 GB RAM, up to 10 concurrent downloads):
177
+
178
+ | Total hosted content | RAM working set | Disk free target | Practical uplink target |
179
+ | --- | --- | --- | --- |
180
+ | `5 MB` | `~4-5 GB` | `>=20 GB` | `10-20 Mbps` |
181
+ | `50 MB` | `~4-5 GB` | `>=20 GB` | `20-50 Mbps` |
182
+ | `500 MB` | `~4.5-5.5 GB` | `>=22-25 GB` | `50-150 Mbps` |
183
+ | `5 GB` | `~5-6 GB` | `>=30-40 GB` | `200+ Mbps` |
184
+
185
+ These numbers assume streamed downloads (no whole-file memory loading), one route per worker, and one local reverse proxy.
186
+
87
187
  ### Buyer Skeleton (direct CLI)
88
188
 
89
189
  Use the direct CLI buy flow:
@@ -92,10 +192,19 @@ Use the direct CLI buy flow:
92
192
  leak buy "https://xxxx.trycloudflare.com/" --buyer-private-key-file ./buyer.key
93
193
  ```
94
194
 
95
- `leak buy` accepts either the promo URL (`/`) or direct x402 URL (`/download`).
195
+ For download-code modes, add:
196
+
197
+ ```bash
198
+ leak buy "https://xxxx.trycloudflare.com/" --download-code "friends-only"
199
+ ```
200
+
201
+ `leak buy` accepts either the promo URL (`/`) or direct `/download` URL.
96
202
  By default, the file is saved to your current directory using the server-provided filename; use `--out` or `--basename` to control naming.
97
203
  When settlement metadata is returned, `leak buy` also prints a receipt block with network + transaction hash (and Basescan link on Base networks).
98
204
 
205
+ If the sale access mode includes payment, pass a buyer key (`--buyer-private-key-file` or `--buyer-private-key-stdin`).
206
+ If the sale access mode includes download-code, pass `--download-code <code>` (or `--download-code-stdin`).
207
+
99
208
  Security note: use a dedicated buyer key with limited funds.
100
209
 
101
210
  ### Buyer Skeleton (Clawhub skill flow)
@@ -109,8 +218,9 @@ The hardened skills require a preinstalled `leak` binary on PATH.
109
218
 
110
219
  Recommended first-time agent UX for unknown URLs:
111
220
  - ask only for skill-install approval (`clawhub install leak-buy`)
112
- - ask for an existing buyer key file path
113
- - run: `bash skills/leak-buy/scripts/buy.sh "<promo_or_download_url>" --buyer-private-key-file <buyer_key_file_path>`
221
+ - ask for an existing buyer key file path when payment is required
222
+ - ask for download code when download-code is required
223
+ - run: `bash skills/leak-buy/scripts/buy.sh "<promo_or_download_url>" --buyer-private-key-file <buyer_key_file_path>` (append `--download-code <code>` when needed)
114
224
  - avoid protocol deep-dives unless the user explicitly asks for x402 internals
115
225
 
116
226
  ### Next: Mainnet checklist (optional)
@@ -153,6 +263,23 @@ Reference: see [Testnet vs Mainnet facilitator setup](#testnet-vs-mainnet-facili
153
263
 
154
264
  The easiest way to run the server is the `leak` CLI, which prompts for missing info (price + duration) and auto-stops after the sale window (or `window + ended-window`, if configured).
155
265
 
266
+ Recommended for humans: use `leak publish` for a guided interactive wizard.
267
+ Recommended for scripts/automation: use `leak --file ...` direct flags.
268
+
269
+ ```bash
270
+ leak publish
271
+ ```
272
+
273
+ Wizard behavior:
274
+ - Basic step always asks core publish inputs (file, access mode, price/window, network, public tunnel).
275
+ - Advanced step is optional and includes facilitator, port, OG metadata, and ended-window fields.
276
+ - Final summary always requires explicit confirmation before launch.
277
+ - Wizard offers (optional) saving values to `~/.leak/config.json`.
278
+ - Publish runs are always supervised: if the worker crashes, leak restarts it automatically with the remaining sale time.
279
+ - Sale deadlines are fixed at first launch; restarts do not extend total availability.
280
+ - Run-state is persisted at `~/.leak/runs/<run_id>.json` (plus `~/.leak/runs/latest.json` pointer).
281
+ - In `--public` mode, tunnel URLs may rotate after a restart; leak reprints new links and persists latest URLs in run-state.
282
+
156
283
  ```bash
157
284
  cd ~/leak
158
285
  npm run leak -- --file /path/to/vape.jpg
@@ -175,6 +302,13 @@ It will ask:
175
302
  - **How long?** (e.g. `15m`, `1h`)
176
303
 
177
304
  Optional flags:
305
+ - `--access-mode <mode>` where mode is one of:
306
+ - `no-download-code-no-payment`
307
+ - `download-code-only-no-payment`
308
+ - `payment-only-no-download-code` (default)
309
+ - `download-code-and-payment`
310
+ - `--download-code "friends-only"` (required for download-code modes)
311
+ - `--download-code-stdin` (read download code from stdin)
178
312
  - `--price 0.01` (USDC)
179
313
  - `--window 1h` (or seconds)
180
314
  - `--confirmed` (settle on-chain before issuing token)
@@ -184,7 +318,7 @@ Optional flags:
184
318
  - `--og-image-url https://...` (absolute `http(s)` URL) or `--og-image-url ./cover.png` (local image path)
185
319
  - `--ended-window-seconds 86400` (keep ended promo page online before auto-stop)
186
320
  - `--network eip155:84532`
187
- - `--pay-to 0x...` (must be a valid Ethereum address)
321
+ - `--pay-to 0x...` (required only for payment modes; must be a valid Ethereum address)
188
322
  - `--port 4021`
189
323
 
190
324
  ### Persistent config (`leak config`)
@@ -257,12 +391,16 @@ npm run leak -- --file ./song.mp3 --pay-to 0x... --price 1 --window 1h --public
257
391
  When a local image path is used for `--og-image-url`, leak serves it from `/og-image` and points OG/Twitter metadata at that endpoint.
258
392
  Without `--og-image-url`, leak serves a generated raster OG card from `/og.png` (and keeps `/og.svg` for debug/backward compatibility).
259
393
 
260
- This mirrors the behavior of the original Python scaffold implementation:
394
+ Payment-mode behavior (`payment-only-no-download-code` / `download-code-and-payment`):
261
395
 
262
396
  - `GET /download` without payment → **402** with `PAYMENT-REQUIRED` header
263
397
  - `GET /download` with valid payment headers → returns a **time-limited token** JSON
264
398
  - `GET /download?token=...` → streams the artifact
265
399
 
400
+ Download-code behavior (`download-code-*` modes):
401
+ - send `X-LEAK-DOWNLOAD-CODE: <code>` on `GET /download`
402
+ - missing/invalid code returns **401**
403
+
266
404
  ### Testnet vs Mainnet facilitator setup
267
405
 
268
406
  `CHAIN_ID=eip155:8453` by itself is **not enough** for production.
@@ -336,7 +474,7 @@ Server will print:
336
474
  - `http://localhost:4021/` (promo page)
337
475
  - `http://localhost:4021/info` (machine-readable info)
338
476
  - `http://localhost:4021/health`
339
- - `http://localhost:4021/download` (x402-protected)
477
+ - `http://localhost:4021/download` (protection depends on `ACCESS_MODE`)
340
478
 
341
479
  ---
342
480
 
@@ -348,7 +486,10 @@ Server will print:
348
486
  curl -i http://localhost:4021/download
349
487
  ```
350
488
 
351
- You should get `402` and a `PAYMENT-REQUIRED` header.
489
+ You should get mode-specific behavior:
490
+ - payment mode: `402` + `PAYMENT-REQUIRED`
491
+ - download-code mode without header: `401`
492
+ - no-payment/no-download-code mode: direct file response
352
493
 
353
494
  ### B) Paid request → token
354
495
 
@@ -406,10 +547,10 @@ export LEAK_DEV=1 # allows BASE_URL to default to http://127.0.0.1:4021
406
547
  ```
407
548
 
408
549
  What it does:
409
- - first `GET /download` expects **402** + `PAYMENT-REQUIRED`
410
- - creates a payment payload, retries with `PAYMENT-SIGNATURE`
411
- - receives `{ token, download_url, filename, mime_type }`
412
- - downloads via `?token=` and saves to disk
550
+ - if payment is required, first `GET /download` gets **402** + `PAYMENT-REQUIRED`
551
+ - if download-code is required, sends `X-LEAK-DOWNLOAD-CODE`
552
+ - handles payment/token flow when required
553
+ - saves the downloaded artifact
413
554
 
414
555
  ### C) Use token → download
415
556
 
@@ -425,16 +566,16 @@ curl -L -o out.bin "http://localhost:4021/download?token=..."
425
566
  - `200` while sale is active
426
567
  - `200` once sale has ended (ended state is shown in page content/metadata)
427
568
  - `GET|HEAD /.well-known/skills/index.json` RFC skill discovery index
428
- - `GET|HEAD /.well-known/skills/leak/SKILL.md` RFC skill metadata markdown
429
- - `GET|HEAD /.well-known/skills/leak/resource.json` RFC sale/resource metadata (`200` live, `410` ended)
569
+ - `GET|HEAD /.well-known/skills/leak-buy/SKILL.md` RFC skill metadata markdown
570
+ - `GET|HEAD /.well-known/skills/leak-buy/resource.json` RFC sale/resource metadata (`200` live, `410` ended)
430
571
  - `GET /.well-known/leak` legacy discovery endpoint (backward-compatible)
431
572
  - `GET /info` machine-readable JSON status (compat endpoint)
432
573
  - `GET|HEAD /og-image` configured OG image file (when using local `--og-image-url` path)
433
574
  - `GET|HEAD /og.png` generated default OG image (used when `--og-image-url` is not set)
434
575
  - `GET|HEAD /og.svg` debug/backward-compatible OG SVG
435
576
  - `GET /health` free health check
436
- - `GET /download` x402-protected download endpoint
437
- - active sale: normal x402/token flow
577
+ - `GET /download` access-controlled download endpoint
578
+ - active sale: behavior depends on `ACCESS_MODE`
438
579
  - ended sale: `410`
439
580
 
440
581
  ---
@@ -455,8 +596,14 @@ curl -L -o out.bin "http://localhost:4021/download?token=..."
455
596
  - `FACILITATOR_URL`
456
597
  - default with `FACILITATOR_MODE=testnet`: `https://x402.org/facilitator`
457
598
  - default with `FACILITATOR_MODE=cdp_mainnet`: `https://api.cdp.coinbase.com/platform/v2/x402`
458
- - `SELLER_PAY_TO` receiving address (valid Ethereum address, `0x` + 40 hex chars)
599
+ - `SELLER_PAY_TO` receiving address (required only for payment modes; valid Ethereum address, `0x` + 40 hex chars)
459
600
  - `PRICE_USD` (string like `1.00`)
601
+ - `ACCESS_MODE`:
602
+ - `no-download-code-no-payment`
603
+ - `download-code-only-no-payment`
604
+ - `payment-only-no-download-code` (default)
605
+ - `download-code-and-payment`
606
+ - `DOWNLOAD_CODE_HASH` (required for download-code modes; hash only, not raw code)
460
607
  - `CHAIN_ID`
461
608
  - default: `eip155:84532` (Base Sepolia) for `x402.org/facilitator`
462
609
  - Base mainnet: `eip155:8453` (requires `FACILITATOR_MODE=cdp_mainnet` plus CDP keys)
@@ -0,0 +1,50 @@
1
+ {
2
+ "_hints": {
3
+ "accessMode_source_of_truth": "src/access_mode.js (ACCESS_MODE_VALUES)",
4
+ "accessMode_allowed_values": [
5
+ "no-download-code-no-payment",
6
+ "download-code-only-no-payment",
7
+ "payment-only-no-download-code",
8
+ "download-code-and-payment"
9
+ ]
10
+ },
11
+ "proxy": {
12
+ "host": "127.0.0.1",
13
+ "port": 4080
14
+ },
15
+ "defaults": {
16
+ "window": "1h",
17
+ "network": "eip155:84532",
18
+ "payTo": "0x1111111111111111111111111111111111111111",
19
+ "price": "0.01",
20
+ "facilitatorMode": "testnet",
21
+ "facilitatorUrl": "https://x402.org/facilitator",
22
+ "confirmationPolicy": "confirmed",
23
+ "endedWindowSeconds": 86400
24
+ },
25
+ "routes": [
26
+ {
27
+ "slug": "lolboy",
28
+ "prefix": "/leak/lolboy",
29
+ "port": 4101,
30
+ "artifactPath": "./protected/lol.mp3",
31
+ "accessMode": "payment-only-no-download-code",
32
+ "ogTitle": "lolboy",
33
+ "ogDescription": "limited drop",
34
+ "payTo": "0x1111111111111111111111111111111111111111",
35
+ "price": "0.01"
36
+ },
37
+ {
38
+ "slug": "peter",
39
+ "prefix": "/leak/peter",
40
+ "port": 4102,
41
+ "artifactPath": "./protected/peterkek.mp3",
42
+ "accessMode": "download-code-and-payment",
43
+ "downloadCode": "friends-only",
44
+ "ogTitle": "peter",
45
+ "ogDescription": "friends release",
46
+ "payTo": "0x1111111111111111111111111111111111111111",
47
+ "price": "0.02"
48
+ }
49
+ ]
50
+ }
package/package.json CHANGED
@@ -1,16 +1,19 @@
1
1
  {
2
2
  "name": "leak-cli",
3
- "version": "2026.2.17-beta.0",
3
+ "version": "2026.2.17",
4
4
  "description": "Self-hosted pop-up stores for creators -- with agent-friendly automation built in",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "files": [
8
8
  "src/",
9
9
  "scripts/cli.js",
10
+ "scripts/host.js",
10
11
  "scripts/leak.js",
11
12
  "scripts/buy.js",
12
13
  "scripts/config.js",
13
14
  "scripts/config_store.js",
15
+ "scripts/ui.js",
16
+ "examples/",
14
17
  "README.md",
15
18
  ".env.example",
16
19
  "LICENSE"
@@ -22,6 +25,7 @@
22
25
  "start": "node src/index.js",
23
26
  "dev": "node --watch src/index.js",
24
27
  "cli": "node scripts/cli.js",
28
+ "host": "node scripts/host.js",
25
29
  "buyer": "node scripts/buyer_test.js",
26
30
  "leak": "node scripts/leak.js",
27
31
  "buy": "node scripts/buy.js",
@@ -29,9 +33,10 @@
29
33
  "check:changelog-version": "node scripts/check_changelog_version.js",
30
34
  "check:no-local-paths": "node scripts/check_no_local_paths.js",
31
35
  "check:skill-security": "bash scripts/check_skill_security.sh",
32
- "check:syntax": "node --check src/index.js && node --check src/chain_meta.js && node --check scripts/cli.js && node --check scripts/leak.js && node --check scripts/buy.js && node --check scripts/config.js",
33
- "check:smoke": "node scripts/cli.js --help && node scripts/leak.js --help && node scripts/buy.js --help && node scripts/config.js --help",
34
- "check:release": "npm run check:version-sync && npm run check:skill-security && npm run check:syntax && npm run check:smoke && npm run check:no-local-paths && npm pack --dry-run --cache ./.npm-cache",
36
+ "check:download-code-terminology": "bash scripts/check_download_code_terminology.sh",
37
+ "check:syntax": "node --check src/index.js && node --check src/chain_meta.js && node --check src/access_mode.js && node --check src/download_code.js && node --check scripts/ui.js && node --check scripts/cli.js && node --check scripts/host.js && node --check scripts/leak.js && node --check scripts/buy.js && node --check scripts/config.js",
38
+ "check:smoke": "node scripts/cli.js --help && node scripts/cli.js publish --help && node scripts/cli.js host --help && node scripts/cli.js --version && node scripts/cli.js version && node scripts/leak.js --help && node scripts/buy.js --help && node scripts/config.js --help && node scripts/host.js --help",
39
+ "check:release": "npm run check:version-sync && npm run check:skill-security && npm run check:download-code-terminology && npm run check:syntax && npm run check:smoke && npm run check:no-local-paths && npm pack --dry-run --cache ./.npm-cache",
35
40
  "release:beta": "npm publish --tag beta --provenance",
36
41
  "release:latest": "npm publish --tag latest --provenance"
37
42
  },