@blockrun/clawrouter 0.12.32 → 0.12.33
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 +33 -12
- package/dist/cli.js +261 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +272 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/imagegen/SKILL.md +7 -7
- package/skills/x-api/SKILL.md +5 -5
package/dist/index.js
CHANGED
|
@@ -1640,6 +1640,7 @@ import { finished } from "stream";
|
|
|
1640
1640
|
import { homedir as homedir4 } from "os";
|
|
1641
1641
|
import { join as join5 } from "path";
|
|
1642
1642
|
import { mkdir as mkdir3, writeFile as writeFile2, readFile, stat as fsStat } from "fs/promises";
|
|
1643
|
+
import { readFileSync, existsSync } from "fs";
|
|
1643
1644
|
import { createPublicClient as createPublicClient2, http as http2 } from "viem";
|
|
1644
1645
|
import { base as base2 } from "viem/chains";
|
|
1645
1646
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
@@ -6064,6 +6065,22 @@ async function proxyPartnerRequest(req, res, apiBase, payFetch) {
|
|
|
6064
6065
|
}).catch(() => {
|
|
6065
6066
|
});
|
|
6066
6067
|
}
|
|
6068
|
+
function readImageFileAsDataUri(filePath) {
|
|
6069
|
+
const resolved = filePath.startsWith("~/") ? join5(homedir4(), filePath.slice(2)) : filePath;
|
|
6070
|
+
if (!existsSync(resolved)) {
|
|
6071
|
+
throw new Error(`Image file not found: ${resolved}`);
|
|
6072
|
+
}
|
|
6073
|
+
const ext = resolved.split(".").pop()?.toLowerCase() ?? "png";
|
|
6074
|
+
const mimeMap = {
|
|
6075
|
+
png: "image/png",
|
|
6076
|
+
jpg: "image/jpeg",
|
|
6077
|
+
jpeg: "image/jpeg",
|
|
6078
|
+
webp: "image/webp"
|
|
6079
|
+
};
|
|
6080
|
+
const mime = mimeMap[ext] ?? "image/png";
|
|
6081
|
+
const data = readFileSync(resolved);
|
|
6082
|
+
return `data:${mime};base64,${data.toString("base64")}`;
|
|
6083
|
+
}
|
|
6067
6084
|
async function uploadDataUriToHost(dataUri) {
|
|
6068
6085
|
const match = dataUri.match(/^data:(image\/\w+);base64,(.+)$/);
|
|
6069
6086
|
if (!match) throw new Error("Invalid data URI format");
|
|
@@ -6358,7 +6375,9 @@ async function startProxy(options) {
|
|
|
6358
6375
|
console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
|
|
6359
6376
|
}
|
|
6360
6377
|
} catch (downloadErr) {
|
|
6361
|
-
console.warn(
|
|
6378
|
+
console.warn(
|
|
6379
|
+
`[ClawRouter] Failed to download image, using original URL: ${downloadErr instanceof Error ? downloadErr.message : String(downloadErr)}`
|
|
6380
|
+
);
|
|
6362
6381
|
}
|
|
6363
6382
|
}
|
|
6364
6383
|
}
|
|
@@ -6375,6 +6394,76 @@ async function startProxy(options) {
|
|
|
6375
6394
|
}
|
|
6376
6395
|
return;
|
|
6377
6396
|
}
|
|
6397
|
+
if (req.url === "/v1/images/image2image" && req.method === "POST") {
|
|
6398
|
+
const chunks = [];
|
|
6399
|
+
for await (const chunk of req) {
|
|
6400
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
6401
|
+
}
|
|
6402
|
+
const reqBody = Buffer.concat(chunks);
|
|
6403
|
+
try {
|
|
6404
|
+
const upstream = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
6405
|
+
method: "POST",
|
|
6406
|
+
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
6407
|
+
body: reqBody
|
|
6408
|
+
});
|
|
6409
|
+
const text = await upstream.text();
|
|
6410
|
+
if (!upstream.ok) {
|
|
6411
|
+
res.writeHead(upstream.status, { "Content-Type": "application/json" });
|
|
6412
|
+
res.end(text);
|
|
6413
|
+
return;
|
|
6414
|
+
}
|
|
6415
|
+
let result;
|
|
6416
|
+
try {
|
|
6417
|
+
result = JSON.parse(text);
|
|
6418
|
+
} catch {
|
|
6419
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6420
|
+
res.end(text);
|
|
6421
|
+
return;
|
|
6422
|
+
}
|
|
6423
|
+
if (result.data?.length) {
|
|
6424
|
+
await mkdir3(IMAGE_DIR, { recursive: true });
|
|
6425
|
+
const port2 = server.address()?.port ?? 8402;
|
|
6426
|
+
for (const img of result.data) {
|
|
6427
|
+
const dataUriMatch = img.url?.match(/^data:(image\/\w+);base64,(.+)$/);
|
|
6428
|
+
if (dataUriMatch) {
|
|
6429
|
+
const [, mimeType, b64] = dataUriMatch;
|
|
6430
|
+
const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
|
|
6431
|
+
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
6432
|
+
await writeFile2(join5(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
|
|
6433
|
+
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
6434
|
+
console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
|
|
6435
|
+
} else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
|
|
6436
|
+
try {
|
|
6437
|
+
const imgResp = await fetch(img.url);
|
|
6438
|
+
if (imgResp.ok) {
|
|
6439
|
+
const contentType = imgResp.headers.get("content-type") ?? "image/png";
|
|
6440
|
+
const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
|
|
6441
|
+
const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
|
|
6442
|
+
const buf = Buffer.from(await imgResp.arrayBuffer());
|
|
6443
|
+
await writeFile2(join5(IMAGE_DIR, filename), buf);
|
|
6444
|
+
img.url = `http://localhost:${port2}/images/${filename}`;
|
|
6445
|
+
console.log(`[ClawRouter] Image downloaded & saved \u2192 ${img.url}`);
|
|
6446
|
+
}
|
|
6447
|
+
} catch (downloadErr) {
|
|
6448
|
+
console.warn(
|
|
6449
|
+
`[ClawRouter] Failed to download image, using original URL: ${downloadErr instanceof Error ? downloadErr.message : String(downloadErr)}`
|
|
6450
|
+
);
|
|
6451
|
+
}
|
|
6452
|
+
}
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6456
|
+
res.end(JSON.stringify(result));
|
|
6457
|
+
} catch (err) {
|
|
6458
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
6459
|
+
console.error(`[ClawRouter] Image editing error: ${msg}`);
|
|
6460
|
+
if (!res.headersSent) {
|
|
6461
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
6462
|
+
res.end(JSON.stringify({ error: "Image editing failed", details: msg }));
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
return;
|
|
6466
|
+
}
|
|
6378
6467
|
if (req.url?.match(/^\/v1\/(?:x|partner)\//)) {
|
|
6379
6468
|
try {
|
|
6380
6469
|
await proxyPartnerRequest(req, res, apiBase, payFetch);
|
|
@@ -6989,6 +7078,177 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
6989
7078
|
}
|
|
6990
7079
|
return;
|
|
6991
7080
|
}
|
|
7081
|
+
if (lastContent.startsWith("/img2img")) {
|
|
7082
|
+
const imgArgs = lastContent.slice("/img2img".length).trim();
|
|
7083
|
+
let img2imgModel = "openai/gpt-image-1";
|
|
7084
|
+
let img2imgSize = "1024x1024";
|
|
7085
|
+
let imagePath = null;
|
|
7086
|
+
let maskPath = null;
|
|
7087
|
+
let img2imgPrompt = imgArgs;
|
|
7088
|
+
const imageMatch = imgArgs.match(/--image\s+(\S+)/);
|
|
7089
|
+
if (imageMatch) {
|
|
7090
|
+
imagePath = imageMatch[1];
|
|
7091
|
+
img2imgPrompt = img2imgPrompt.replace(/--image\s+\S+/, "").trim();
|
|
7092
|
+
}
|
|
7093
|
+
const maskMatch = imgArgs.match(/--mask\s+(\S+)/);
|
|
7094
|
+
if (maskMatch) {
|
|
7095
|
+
maskPath = maskMatch[1];
|
|
7096
|
+
img2imgPrompt = img2imgPrompt.replace(/--mask\s+\S+/, "").trim();
|
|
7097
|
+
}
|
|
7098
|
+
const img2imgSizeMatch = imgArgs.match(/--size\s+(\d+x\d+)/);
|
|
7099
|
+
if (img2imgSizeMatch) {
|
|
7100
|
+
img2imgSize = img2imgSizeMatch[1];
|
|
7101
|
+
img2imgPrompt = img2imgPrompt.replace(/--size\s+\d+x\d+/, "").trim();
|
|
7102
|
+
}
|
|
7103
|
+
const img2imgModelMatch = imgArgs.match(/--model\s+(\S+)/);
|
|
7104
|
+
if (img2imgModelMatch) {
|
|
7105
|
+
const raw = img2imgModelMatch[1];
|
|
7106
|
+
const IMG2IMG_ALIASES = {
|
|
7107
|
+
"gpt-image": "openai/gpt-image-1",
|
|
7108
|
+
"gpt-image-1": "openai/gpt-image-1"
|
|
7109
|
+
};
|
|
7110
|
+
img2imgModel = IMG2IMG_ALIASES[raw] ?? raw;
|
|
7111
|
+
img2imgPrompt = img2imgPrompt.replace(/--model\s+\S+/, "").trim();
|
|
7112
|
+
}
|
|
7113
|
+
const usageText = [
|
|
7114
|
+
"Usage: /img2img --image <path> <prompt>",
|
|
7115
|
+
"",
|
|
7116
|
+
"Options:",
|
|
7117
|
+
" --image <path> Source image path (required)",
|
|
7118
|
+
" --mask <path> Mask image path (optional, white = area to edit)",
|
|
7119
|
+
" --model <model> Model (default: gpt-image-1)",
|
|
7120
|
+
" --size <WxH> Output size (default: 1024x1024)",
|
|
7121
|
+
"",
|
|
7122
|
+
"Models:",
|
|
7123
|
+
" gpt-image-1 OpenAI GPT Image 1 \u2014 $0.02/image",
|
|
7124
|
+
"",
|
|
7125
|
+
"Examples:",
|
|
7126
|
+
" /img2img --image ~/photo.png change background to starry sky",
|
|
7127
|
+
" /img2img --image ./cat.jpg --mask ./mask.png remove the background",
|
|
7128
|
+
" /img2img --image /tmp/portrait.png --size 1536x1024 add a hat"
|
|
7129
|
+
].join("\n");
|
|
7130
|
+
const sendImg2ImgText = (text) => {
|
|
7131
|
+
const completionId = `chatcmpl-img2img-${Date.now()}`;
|
|
7132
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
7133
|
+
if (isStreaming) {
|
|
7134
|
+
res.writeHead(200, {
|
|
7135
|
+
"Content-Type": "text/event-stream",
|
|
7136
|
+
"Cache-Control": "no-cache",
|
|
7137
|
+
Connection: "keep-alive"
|
|
7138
|
+
});
|
|
7139
|
+
res.write(
|
|
7140
|
+
`data: ${JSON.stringify({ id: completionId, object: "chat.completion.chunk", created: timestamp, model: "clawrouter/img2img", choices: [{ index: 0, delta: { role: "assistant", content: text }, finish_reason: null }] })}
|
|
7141
|
+
|
|
7142
|
+
`
|
|
7143
|
+
);
|
|
7144
|
+
res.write(
|
|
7145
|
+
`data: ${JSON.stringify({ id: completionId, object: "chat.completion.chunk", created: timestamp, model: "clawrouter/img2img", choices: [{ index: 0, delta: {}, finish_reason: "stop" }] })}
|
|
7146
|
+
|
|
7147
|
+
`
|
|
7148
|
+
);
|
|
7149
|
+
res.write("data: [DONE]\n\n");
|
|
7150
|
+
res.end();
|
|
7151
|
+
} else {
|
|
7152
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
7153
|
+
res.end(
|
|
7154
|
+
JSON.stringify({
|
|
7155
|
+
id: completionId,
|
|
7156
|
+
object: "chat.completion",
|
|
7157
|
+
created: timestamp,
|
|
7158
|
+
model: "clawrouter/img2img",
|
|
7159
|
+
choices: [
|
|
7160
|
+
{
|
|
7161
|
+
index: 0,
|
|
7162
|
+
message: { role: "assistant", content: text },
|
|
7163
|
+
finish_reason: "stop"
|
|
7164
|
+
}
|
|
7165
|
+
],
|
|
7166
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
7167
|
+
})
|
|
7168
|
+
);
|
|
7169
|
+
}
|
|
7170
|
+
};
|
|
7171
|
+
if (!imagePath || !img2imgPrompt) {
|
|
7172
|
+
sendImg2ImgText(usageText);
|
|
7173
|
+
return;
|
|
7174
|
+
}
|
|
7175
|
+
let imageDataUri;
|
|
7176
|
+
let maskDataUri;
|
|
7177
|
+
try {
|
|
7178
|
+
imageDataUri = readImageFileAsDataUri(imagePath);
|
|
7179
|
+
if (maskPath) maskDataUri = readImageFileAsDataUri(maskPath);
|
|
7180
|
+
} catch (fileErr) {
|
|
7181
|
+
const fileErrMsg = fileErr instanceof Error ? fileErr.message : String(fileErr);
|
|
7182
|
+
sendImg2ImgText(`Failed to read image file: ${fileErrMsg}`);
|
|
7183
|
+
return;
|
|
7184
|
+
}
|
|
7185
|
+
console.log(
|
|
7186
|
+
`[ClawRouter] /img2img \u2192 ${img2imgModel} (${img2imgSize}): ${img2imgPrompt.slice(0, 80)}`
|
|
7187
|
+
);
|
|
7188
|
+
try {
|
|
7189
|
+
const img2imgBody = JSON.stringify({
|
|
7190
|
+
model: img2imgModel,
|
|
7191
|
+
prompt: img2imgPrompt,
|
|
7192
|
+
image: imageDataUri,
|
|
7193
|
+
...maskDataUri ? { mask: maskDataUri } : {},
|
|
7194
|
+
size: img2imgSize,
|
|
7195
|
+
n: 1
|
|
7196
|
+
});
|
|
7197
|
+
const img2imgResponse = await payFetch(`${apiBase}/v1/images/image2image`, {
|
|
7198
|
+
method: "POST",
|
|
7199
|
+
headers: { "content-type": "application/json", "user-agent": USER_AGENT },
|
|
7200
|
+
body: img2imgBody
|
|
7201
|
+
});
|
|
7202
|
+
const img2imgResult = await img2imgResponse.json();
|
|
7203
|
+
let responseText;
|
|
7204
|
+
if (!img2imgResponse.ok || img2imgResult.error) {
|
|
7205
|
+
const errMsg = typeof img2imgResult.error === "string" ? img2imgResult.error : img2imgResult.error?.message ?? `HTTP ${img2imgResponse.status}`;
|
|
7206
|
+
responseText = `Image editing failed: ${errMsg}`;
|
|
7207
|
+
console.log(`[ClawRouter] /img2img error: ${errMsg}`);
|
|
7208
|
+
} else {
|
|
7209
|
+
const images = img2imgResult.data ?? [];
|
|
7210
|
+
if (images.length === 0) {
|
|
7211
|
+
responseText = "Image editing returned no results.";
|
|
7212
|
+
} else {
|
|
7213
|
+
const lines = [];
|
|
7214
|
+
for (const img of images) {
|
|
7215
|
+
if (img.url) {
|
|
7216
|
+
if (img.url.startsWith("data:")) {
|
|
7217
|
+
try {
|
|
7218
|
+
const hostedUrl = await uploadDataUriToHost(img.url);
|
|
7219
|
+
lines.push(hostedUrl);
|
|
7220
|
+
} catch (uploadErr) {
|
|
7221
|
+
console.error(
|
|
7222
|
+
`[ClawRouter] /img2img: failed to upload data URI: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
7223
|
+
);
|
|
7224
|
+
lines.push("Image edited but upload failed. Try again.");
|
|
7225
|
+
}
|
|
7226
|
+
} else {
|
|
7227
|
+
lines.push(img.url);
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
if (img.revised_prompt) lines.push(`Revised prompt: ${img.revised_prompt}`);
|
|
7231
|
+
}
|
|
7232
|
+
lines.push("", `Model: ${img2imgModel} | Size: ${img2imgSize}`);
|
|
7233
|
+
responseText = lines.join("\n");
|
|
7234
|
+
}
|
|
7235
|
+
console.log(`[ClawRouter] /img2img success: ${images.length} image(s)`);
|
|
7236
|
+
}
|
|
7237
|
+
sendImg2ImgText(responseText);
|
|
7238
|
+
} catch (err) {
|
|
7239
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
7240
|
+
console.error(`[ClawRouter] /img2img error: ${errMsg}`);
|
|
7241
|
+
if (!res.headersSent) {
|
|
7242
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
7243
|
+
res.end(
|
|
7244
|
+
JSON.stringify({
|
|
7245
|
+
error: { message: `Image editing failed: ${errMsg}`, type: "img2img_error" }
|
|
7246
|
+
})
|
|
7247
|
+
);
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
return;
|
|
7251
|
+
}
|
|
6992
7252
|
if (parsed.stream === true) {
|
|
6993
7253
|
parsed.stream = false;
|
|
6994
7254
|
bodyModified = true;
|
|
@@ -7778,7 +8038,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
7778
8038
|
// src/index.ts
|
|
7779
8039
|
import {
|
|
7780
8040
|
writeFileSync as writeFileSync2,
|
|
7781
|
-
existsSync as
|
|
8041
|
+
existsSync as existsSync3,
|
|
7782
8042
|
readdirSync,
|
|
7783
8043
|
mkdirSync as mkdirSync2,
|
|
7784
8044
|
copyFileSync,
|
|
@@ -8220,7 +8480,7 @@ function injectModelsConfig(logger) {
|
|
|
8220
8480
|
const configPath = join7(configDir, "openclaw.json");
|
|
8221
8481
|
let config = {};
|
|
8222
8482
|
let needsWrite = false;
|
|
8223
|
-
if (!
|
|
8483
|
+
if (!existsSync3(configDir)) {
|
|
8224
8484
|
try {
|
|
8225
8485
|
mkdirSync2(configDir, { recursive: true });
|
|
8226
8486
|
logger.info("Created OpenClaw config directory");
|
|
@@ -8231,7 +8491,7 @@ function injectModelsConfig(logger) {
|
|
|
8231
8491
|
return;
|
|
8232
8492
|
}
|
|
8233
8493
|
}
|
|
8234
|
-
if (
|
|
8494
|
+
if (existsSync3(configPath)) {
|
|
8235
8495
|
try {
|
|
8236
8496
|
const content = readTextFileSync(configPath).trim();
|
|
8237
8497
|
if (content) {
|
|
@@ -8379,7 +8639,7 @@ function injectModelsConfig(logger) {
|
|
|
8379
8639
|
}
|
|
8380
8640
|
function injectAuthProfile(logger) {
|
|
8381
8641
|
const agentsDir = join7(homedir6(), ".openclaw", "agents");
|
|
8382
|
-
if (!
|
|
8642
|
+
if (!existsSync3(agentsDir)) {
|
|
8383
8643
|
try {
|
|
8384
8644
|
mkdirSync2(agentsDir, { recursive: true });
|
|
8385
8645
|
} catch (err) {
|
|
@@ -8397,7 +8657,7 @@ function injectAuthProfile(logger) {
|
|
|
8397
8657
|
for (const agentId of agents) {
|
|
8398
8658
|
const authDir = join7(agentsDir, agentId, "agent");
|
|
8399
8659
|
const authPath = join7(authDir, "auth-profiles.json");
|
|
8400
|
-
if (!
|
|
8660
|
+
if (!existsSync3(authDir)) {
|
|
8401
8661
|
try {
|
|
8402
8662
|
mkdirSync2(authDir, { recursive: true });
|
|
8403
8663
|
} catch {
|
|
@@ -8408,7 +8668,7 @@ function injectAuthProfile(logger) {
|
|
|
8408
8668
|
version: 1,
|
|
8409
8669
|
profiles: {}
|
|
8410
8670
|
};
|
|
8411
|
-
if (
|
|
8671
|
+
if (existsSync3(authPath)) {
|
|
8412
8672
|
try {
|
|
8413
8673
|
const existing = JSON.parse(readTextFileSync(authPath));
|
|
8414
8674
|
if (existing.version && existing.profiles) {
|
|
@@ -8552,7 +8812,7 @@ async function createWalletCommand() {
|
|
|
8552
8812
|
let walletKey;
|
|
8553
8813
|
let address;
|
|
8554
8814
|
try {
|
|
8555
|
-
if (
|
|
8815
|
+
if (existsSync3(WALLET_FILE)) {
|
|
8556
8816
|
walletKey = readTextFileSync(WALLET_FILE).trim();
|
|
8557
8817
|
if (walletKey.startsWith("0x") && walletKey.length === 66) {
|
|
8558
8818
|
const account = privateKeyToAccount4(walletKey);
|
|
@@ -8582,7 +8842,7 @@ Run \`openclaw plugins install @blockrun/clawrouter\` to generate a wallet.`,
|
|
|
8582
8842
|
];
|
|
8583
8843
|
let hasMnemonic = false;
|
|
8584
8844
|
try {
|
|
8585
|
-
if (
|
|
8845
|
+
if (existsSync3(MNEMONIC_FILE)) {
|
|
8586
8846
|
const mnemonic = readTextFileSync(MNEMONIC_FILE).trim();
|
|
8587
8847
|
if (mnemonic) {
|
|
8588
8848
|
hasMnemonic = true;
|
|
@@ -8624,7 +8884,7 @@ Run \`openclaw plugins install @blockrun/clawrouter\` to generate a wallet.`,
|
|
|
8624
8884
|
if (subcommand === "solana") {
|
|
8625
8885
|
try {
|
|
8626
8886
|
let solanaAddr;
|
|
8627
|
-
if (
|
|
8887
|
+
if (existsSync3(MNEMONIC_FILE)) {
|
|
8628
8888
|
const existingMnemonic = readTextFileSync(MNEMONIC_FILE).trim();
|
|
8629
8889
|
if (existingMnemonic) {
|
|
8630
8890
|
await savePaymentChain("solana");
|
|
@@ -8669,7 +8929,7 @@ Run \`openclaw plugins install @blockrun/clawrouter\` to generate a wallet.`,
|
|
|
8669
8929
|
}
|
|
8670
8930
|
if (subcommand === "migrate-solana") {
|
|
8671
8931
|
try {
|
|
8672
|
-
if (!
|
|
8932
|
+
if (!existsSync3(MNEMONIC_FILE)) {
|
|
8673
8933
|
return {
|
|
8674
8934
|
text: "No mnemonic file found. Solana wallet not set up \u2014 nothing to migrate.",
|
|
8675
8935
|
isError: true
|
|
@@ -8772,7 +9032,7 @@ Run \`openclaw plugins install @blockrun/clawrouter\` to generate a wallet.`,
|
|
|
8772
9032
|
}
|
|
8773
9033
|
let solanaSection = "";
|
|
8774
9034
|
try {
|
|
8775
|
-
if (
|
|
9035
|
+
if (existsSync3(MNEMONIC_FILE)) {
|
|
8776
9036
|
const { deriveSolanaKeyBytes: deriveSolanaKeyBytes2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
8777
9037
|
const mnemonic = readTextFileSync(MNEMONIC_FILE).trim();
|
|
8778
9038
|
if (mnemonic) {
|