@blockrun/clawrouter 0.12.24 → 0.12.26
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/README.md +21 -15
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.js +88 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,8 @@ One wallet, 41+ models, zero API keys.
|
|
|
48
48
|
| [vs OpenRouter](#-vs-openrouter) | Why ClawRouter wins |
|
|
49
49
|
| [Support](#-support) | Telegram, X, founders |
|
|
50
50
|
|
|
51
|
+
**API Docs:** [Image Generation](docs/image-generation.md) · [Architecture](docs/architecture.md) · [Configuration](docs/configuration.md)
|
|
52
|
+
|
|
51
53
|
---
|
|
52
54
|
|
|
53
55
|
## 🚀 Quick Start
|
|
@@ -202,14 +204,17 @@ Request → 402 (price: $0.003) → wallet signs USDC → retry → response
|
|
|
202
204
|
|
|
203
205
|
USDC stays in your wallet until spent - non-custodial. Price is visible in the 402 header before signing.
|
|
204
206
|
|
|
205
|
-
**Dual-chain support:** Pay with USDC on **Base (EVM)** or **Solana
|
|
207
|
+
**Dual-chain support:** Pay with **USDC** on **Base (EVM)** or **USDC on Solana** — no SOL token accepted. Both wallets are derived from a single BIP-39 mnemonic on first run.
|
|
206
208
|
|
|
207
209
|
```bash
|
|
208
210
|
/wallet # Check balance and address (both chains)
|
|
209
|
-
/wallet export # Export
|
|
210
|
-
/wallet
|
|
211
|
-
/wallet
|
|
211
|
+
/wallet export # Export mnemonic + keys for backup
|
|
212
|
+
/wallet recover # Restore wallet from mnemonic on a new machine
|
|
213
|
+
/wallet solana # Switch to Solana USDC payments
|
|
214
|
+
/wallet base # Switch back to Base (EVM) USDC payments
|
|
215
|
+
/chain solana # Alias for /wallet solana
|
|
212
216
|
/stats # View usage and savings
|
|
217
|
+
/stats clear # Reset usage statistics
|
|
213
218
|
```
|
|
214
219
|
|
|
215
220
|
**Fund your wallet:**
|
|
@@ -262,7 +267,7 @@ npx @blockrun/clawrouter doctor
|
|
|
262
267
|
This collects diagnostics and sends them to Claude Sonnet for AI-powered analysis:
|
|
263
268
|
|
|
264
269
|
```
|
|
265
|
-
🩺 BlockRun Doctor v0.
|
|
270
|
+
🩺 BlockRun Doctor v0.12.24
|
|
266
271
|
|
|
267
272
|
System
|
|
268
273
|
✓ OS: darwin arm64
|
|
@@ -325,16 +330,17 @@ npm test
|
|
|
325
330
|
|
|
326
331
|
## 📚 More Resources
|
|
327
332
|
|
|
328
|
-
| Resource
|
|
329
|
-
|
|
|
330
|
-
| [Documentation](https://blockrun.ai/docs)
|
|
331
|
-
| [Model Pricing](https://blockrun.ai/models)
|
|
332
|
-
| [
|
|
333
|
-
| [
|
|
334
|
-
| [
|
|
335
|
-
| [
|
|
336
|
-
| [
|
|
337
|
-
| [
|
|
333
|
+
| Resource | Description |
|
|
334
|
+
| ------------------------------------------------- | ------------------------ |
|
|
335
|
+
| [Documentation](https://blockrun.ai/docs) | Full docs |
|
|
336
|
+
| [Model Pricing](https://blockrun.ai/models) | All models & prices |
|
|
337
|
+
| [Image Generation](docs/image-generation.md) | API examples, 5 models |
|
|
338
|
+
| [Routing Profiles](docs/routing-profiles.md) | ECO/AUTO/PREMIUM details |
|
|
339
|
+
| [Architecture](docs/architecture.md) | Technical deep dive |
|
|
340
|
+
| [Configuration](docs/configuration.md) | Environment variables |
|
|
341
|
+
| [vs OpenRouter](docs/vs-openrouter.md) | Why ClawRouter wins |
|
|
342
|
+
| [Features](docs/features.md) | All features |
|
|
343
|
+
| [Troubleshooting](docs/troubleshooting.md) | Common issues |
|
|
338
344
|
|
|
339
345
|
---
|
|
340
346
|
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// src/proxy.ts
|
|
4
4
|
import { createServer } from "http";
|
|
5
5
|
import { finished } from "stream";
|
|
6
|
+
import { homedir as homedir4 } from "os";
|
|
7
|
+
import { join as join5 } from "path";
|
|
8
|
+
import { mkdir as mkdir3, writeFile as writeFile2, readFile, stat as fsStat } from "fs/promises";
|
|
6
9
|
import { createPublicClient as createPublicClient2, http as http2 } from "viem";
|
|
7
10
|
import { base as base2 } from "viem/chains";
|
|
8
11
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
@@ -5032,6 +5035,7 @@ ${lines.join("\n")}`;
|
|
|
5032
5035
|
// src/proxy.ts
|
|
5033
5036
|
var BLOCKRUN_API = "https://blockrun.ai/api";
|
|
5034
5037
|
var BLOCKRUN_SOLANA_API = "https://sol.blockrun.ai/api";
|
|
5038
|
+
var IMAGE_DIR = join5(homedir4(), ".openclaw", "blockrun", "images");
|
|
5035
5039
|
var AUTO_MODEL = "blockrun/auto";
|
|
5036
5040
|
var ROUTING_PROFILES = /* @__PURE__ */ new Set([
|
|
5037
5041
|
"blockrun/free",
|
|
@@ -5813,6 +5817,81 @@ async function startProxy(options) {
|
|
|
5813
5817
|
res.end(JSON.stringify({ object: "list", data: models }));
|
|
5814
5818
|
return;
|
|
5815
5819
|
}
|
|
5820
|
+
if (req.url?.startsWith("/images/") && req.method === "GET") {
|
|
5821
|
+
const filename = req.url.slice("/images/".length).split("?")[0].replace(/[^a-zA-Z0-9._-]/g, "");
|
|
5822
|
+
if (!filename) {
|
|
5823
|
+
res.writeHead(400);
|
|
5824
|
+
res.end("Bad request");
|
|
5825
|
+
return;
|
|
5826
|
+
}
|
|
5827
|
+
const filePath = join5(IMAGE_DIR, filename);
|
|
5828
|
+
try {
|
|
5829
|
+
const s = await fsStat(filePath);
|
|
5830
|
+
if (!s.isFile()) throw new Error("not a file");
|
|
5831
|
+
const ext = filename.split(".").pop()?.toLowerCase() ?? "png";
|
|
5832
|
+
const mime = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", webp: "image/webp", gif: "image/gif" };
|
|
5833
|
+
const data = await readFile(filePath);
|
|
5834
|
+
res.writeHead(200, { "Content-Type": mime[ext] ?? "application/octet-stream", "Content-Length": data.length });
|
|
5835
|
+
res.end(data);
|
|
5836
|
+
} catch {
|
|
5837
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
5838
|
+
res.end(JSON.stringify({ error: "Image not found" }));
|
|
5839
|
+
}
|
|
5840
|
+
return;
|
|
5841
|
+
}
|
|
5842
|
+
if (req.url === "/v1/images/generations" && req.method === "POST") {
|
|
5843
|
+
const chunks = [];
|
|
5844
|
+
for await (const chunk of req) {
|
|
5845
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
5846
|
+
}
|
|
5847
|
+
const reqBody = Buffer.concat(chunks);
|
|
5848
|
+
try {
|
|
5849
|
+
const upstream = await payFetch(`${apiBase}/v1/images/generations`, {
|
|
5850
|
+
method: "POST",
|
|
5851
|
+
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
5852
|
+
body: reqBody
|
|
5853
|
+
});
|
|
5854
|
+
const text = await upstream.text();
|
|
5855
|
+
if (!upstream.ok) {
|
|
5856
|
+
res.writeHead(upstream.status, { "Content-Type": "application/json" });
|
|
5857
|
+
res.end(text);
|
|
5858
|
+
return;
|
|
5859
|
+
}
|
|
5860
|
+
let result;
|
|
5861
|
+
try {
|
|
5862
|
+
result = JSON.parse(text);
|
|
5863
|
+
} catch {
|
|
5864
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5865
|
+
res.end(text);
|
|
5866
|
+
return;
|
|
5867
|
+
}
|
|
5868
|
+
if (result.data?.length) {
|
|
5869
|
+
await mkdir3(IMAGE_DIR, { recursive: true });
|
|
5870
|
+
const port2 = server.address()?.port ?? 8402;
|
|
5871
|
+
for (const img of result.data) {
|
|
5872
|
+
const m = img.url?.match(/^data:(image\/\w+);base64,(.+)$/);
|
|
5873
|
+
if (m) {
|
|
5874
|
+
const [, mimeType, b64] = m;
|
|
5875
|
+
const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
|
|
5876
|
+
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
5877
|
+
await writeFile2(join5(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
|
|
5878
|
+
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
5879
|
+
console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
|
|
5880
|
+
}
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5883
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5884
|
+
res.end(JSON.stringify(result));
|
|
5885
|
+
} catch (err) {
|
|
5886
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5887
|
+
console.error(`[ClawRouter] Image generation error: ${msg}`);
|
|
5888
|
+
if (!res.headersSent) {
|
|
5889
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
5890
|
+
res.end(JSON.stringify({ error: "Image generation failed", details: msg }));
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
return;
|
|
5894
|
+
}
|
|
5816
5895
|
if (req.url?.match(/^\/v1\/(?:x|partner)\//)) {
|
|
5817
5896
|
try {
|
|
5818
5897
|
await proxyPartnerRequest(req, res, apiBase, payFetch);
|