@genkaku/dsh-user-plugin 0.1.22 → 0.1.24
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/lib/client.js +182 -23
- package/package.json +3 -3
package/lib/client.js
CHANGED
|
@@ -126,6 +126,9 @@ function Page() {
|
|
|
126
126
|
const [notice, setNotice] = (0, import_react.useState)(null);
|
|
127
127
|
const [busy, setBusy] = (0, import_react.useState)(null);
|
|
128
128
|
const [newWorker, setNewWorker] = (0, import_react.useState)("");
|
|
129
|
+
const [exported, setExported] = (0, import_react.useState)(null);
|
|
130
|
+
const [importText, setImportText] = (0, import_react.useState)("");
|
|
131
|
+
const [showImport, setShowImport] = (0, import_react.useState)(false);
|
|
129
132
|
const originRef = (0, import_react.useRef)(null);
|
|
130
133
|
const models = useScrollThumb();
|
|
131
134
|
const load = (0, import_react.useCallback)(async () => {
|
|
@@ -164,6 +167,7 @@ function Page() {
|
|
|
164
167
|
});
|
|
165
168
|
const doc = await res.json().catch(() => null);
|
|
166
169
|
if (!res.ok) throw new Error(doc?.error?.message ?? `HTTP ${res.status}`);
|
|
170
|
+
return doc ?? {};
|
|
167
171
|
}, []);
|
|
168
172
|
const saveWorkers = (0, import_react.useCallback)(async (next) => {
|
|
169
173
|
setBusy("workers");
|
|
@@ -195,6 +199,78 @@ function Page() {
|
|
|
195
199
|
setBusy(null);
|
|
196
200
|
}
|
|
197
201
|
}, [load, post]);
|
|
202
|
+
const exportKey = (0, import_react.useCallback)(async () => {
|
|
203
|
+
setBusy("export");
|
|
204
|
+
setNotice(null);
|
|
205
|
+
try {
|
|
206
|
+
const doc = await post("/genkaku/wallet/export", { confirm: true });
|
|
207
|
+
setExported(typeof doc.privateKey === "string" ? doc.privateKey : null);
|
|
208
|
+
setNotice(t(
|
|
209
|
+
"Never share this key. Anyone who has it owns the wallet and its funds.",
|
|
210
|
+
"\u7D55\u5C0D\u4E0D\u8981\u5206\u4EAB\u9019\u628A\u79C1\u9470\u3002\u62FF\u5230\u5B83\u7684\u4EBA\u5C31\u7B49\u65BC\u64C1\u6709\u9019\u500B\u9322\u5305\u8207\u88E1\u9762\u7684\u8CC7\u91D1\u3002"
|
|
211
|
+
));
|
|
212
|
+
} catch (e) {
|
|
213
|
+
setNotice(e instanceof Error ? e.message : String(e));
|
|
214
|
+
} finally {
|
|
215
|
+
setBusy(null);
|
|
216
|
+
}
|
|
217
|
+
}, [post]);
|
|
218
|
+
const importKey = (0, import_react.useCallback)(async () => {
|
|
219
|
+
if (!window.confirm(t(
|
|
220
|
+
"Importing a key replaces this profile's user wallet. The current address keeps its funds and is no longer used. Continue?",
|
|
221
|
+
"\u532F\u5165\u79C1\u9470\u6703\u53D6\u4EE3\u6B64 profile \u7684\u4F7F\u7528\u8005\u9322\u5305\u3002\u76EE\u524D\u4F4D\u5740\u88E1\u7684\u8CC7\u91D1\u4E0D\u6703\u8F49\u79FB\uFF0C\u4E14\u4E0D\u518D\u4F7F\u7528\u3002\u8981\u7E7C\u7E8C\u55CE\uFF1F"
|
|
222
|
+
))) return;
|
|
223
|
+
setBusy("import");
|
|
224
|
+
setNotice(null);
|
|
225
|
+
try {
|
|
226
|
+
await post("/genkaku/wallet/import", { privateKey: importText.trim() });
|
|
227
|
+
setImportText("");
|
|
228
|
+
setShowImport(false);
|
|
229
|
+
setNotice(t("Wallet imported. The bridge is restarting.", "\u5DF2\u532F\u5165\u9322\u5305\uFF0Cbridge \u6B63\u5728\u91CD\u65B0\u555F\u52D5\u3002"));
|
|
230
|
+
setTimeout(() => {
|
|
231
|
+
void load();
|
|
232
|
+
}, 3e3);
|
|
233
|
+
} catch (e) {
|
|
234
|
+
setNotice(e instanceof Error ? e.message : String(e));
|
|
235
|
+
} finally {
|
|
236
|
+
setBusy(null);
|
|
237
|
+
}
|
|
238
|
+
}, [importText, load, post]);
|
|
239
|
+
const rotateKey = (0, import_react.useCallback)(async () => {
|
|
240
|
+
if (!window.confirm(t(
|
|
241
|
+
"Generate a fresh wallet? The old address keeps its ETH and USDC; this profile stops using it.",
|
|
242
|
+
"\u8981\u7522\u751F\u65B0\u7684\u9322\u5305\u55CE\uFF1F\u820A\u4F4D\u5740\u7684 ETH \u8207 USDC \u6703\u7559\u5728\u539F\u8655\uFF0C\u6B64 profile \u4E0D\u518D\u4F7F\u7528\u5B83\u3002"
|
|
243
|
+
))) return;
|
|
244
|
+
setBusy("rotate");
|
|
245
|
+
setNotice(null);
|
|
246
|
+
try {
|
|
247
|
+
await post("/genkaku/wallet/new", {});
|
|
248
|
+
setExported(null);
|
|
249
|
+
setNotice(t("New wallet generated. The bridge is restarting.", "\u5DF2\u7522\u751F\u65B0\u9322\u5305\uFF0Cbridge \u6B63\u5728\u91CD\u65B0\u555F\u52D5\u3002"));
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
void load();
|
|
252
|
+
}, 3e3);
|
|
253
|
+
} catch (e) {
|
|
254
|
+
setNotice(e instanceof Error ? e.message : String(e));
|
|
255
|
+
} finally {
|
|
256
|
+
setBusy(null);
|
|
257
|
+
}
|
|
258
|
+
}, [load, post]);
|
|
259
|
+
const mintTestUsdc = (0, import_react.useCallback)(async () => {
|
|
260
|
+
setBusy("mint");
|
|
261
|
+
setNotice(null);
|
|
262
|
+
try {
|
|
263
|
+
const doc = await post("/genkaku/wallet/mint", { amountUsdc: "100" });
|
|
264
|
+
setNotice(t(`Minted 100 test USDC (tx ${String(doc.tx).slice(0, 12)}\u2026).`, `\u5DF2\u9818\u53D6 100 \u6E2C\u8A66 USDC\uFF08tx ${String(doc.tx).slice(0, 12)}\u2026\uFF09\u3002`));
|
|
265
|
+
setTimeout(() => {
|
|
266
|
+
void load();
|
|
267
|
+
}, 4e3);
|
|
268
|
+
} catch (e) {
|
|
269
|
+
setNotice(e instanceof Error ? e.message : String(e));
|
|
270
|
+
} finally {
|
|
271
|
+
setBusy(null);
|
|
272
|
+
}
|
|
273
|
+
}, [load, post]);
|
|
198
274
|
const refreshNetwork = (0, import_react.useCallback)(async () => {
|
|
199
275
|
setBusy("refresh");
|
|
200
276
|
setNotice(null);
|
|
@@ -235,13 +311,20 @@ function Page() {
|
|
|
235
311
|
const n = Number(micro);
|
|
236
312
|
return Number.isFinite(n) ? `${(n / 1e6).toFixed(2)} USDC` : "\u2014";
|
|
237
313
|
};
|
|
314
|
+
const noGas = (() => {
|
|
315
|
+
try {
|
|
316
|
+
return BigInt(status.balances?.eth ?? "0") === 0n;
|
|
317
|
+
} catch {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
})();
|
|
238
321
|
const short = (addr) => addr == null || addr.length < 12 ? addr ?? "\u2014" : `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`;
|
|
239
322
|
const wallets = new Set(offers.map((o) => o.offer?.workerWallet).filter((w) => typeof w === "string" && w !== ""));
|
|
240
323
|
const workerCount = wallets.size > 0 ? wallets.size : (status.workers ?? []).length;
|
|
241
324
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: 16, maxWidth: 760 }, children: [
|
|
242
325
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
243
326
|
.gk-net-wrap { position: relative; padding-right: 12px; }
|
|
244
|
-
.gk-net-models { max-height: min(
|
|
327
|
+
.gk-net-models { max-height: min(320px, 38vh); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
|
|
245
328
|
.gk-net-models::-webkit-scrollbar { display: none; }
|
|
246
329
|
.gk-net-rail { position: absolute; top: 2px; bottom: 2px; right: 2px; width: 8px; border-radius: 4px; background: rgba(127,137,153,.16); cursor: pointer; }
|
|
247
330
|
.gk-net-thumb { position: absolute; left: 0; width: 8px; min-height: 16px; border-radius: 4px; background: rgba(127,137,153,.7); }
|
|
@@ -295,28 +378,82 @@ function Page() {
|
|
|
295
378
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
|
|
296
379
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Models offered" }),
|
|
297
380
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: offers.length })
|
|
298
|
-
] })
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
381
|
+
] }),
|
|
382
|
+
noGas && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...dim, fontSize: 12, marginTop: 8 }, children: [
|
|
383
|
+
t(
|
|
384
|
+
"This wallet has no Base Sepolia ETH yet. Get test ETH for gas from a faucet, then mint test USDC here.",
|
|
385
|
+
"\u9019\u500B\u9322\u5305\u9084\u6C92\u6709 Base Sepolia ETH\u3002\u5148\u5230 faucet \u9818\u6E2C\u8A66 ETH \u4ED8 gas\uFF0C\u518D\u56DE\u4F86\u9818\u6E2C\u8A66 USDC\u3002"
|
|
386
|
+
),
|
|
387
|
+
" ",
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "https://www.alchemy.com/faucets/base-sepolia", target: "_blank", rel: "noreferrer", children: t("Open faucet", "\u958B\u555F faucet") })
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 8, marginTop: 10 }, children: [
|
|
391
|
+
status.env === "base-sepolia" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
392
|
+
import_dsh_client_ui_primitives.Button,
|
|
393
|
+
{
|
|
394
|
+
variant: "outline",
|
|
395
|
+
size: "sm",
|
|
396
|
+
disabled: busy !== null || noGas,
|
|
397
|
+
onClick: () => {
|
|
398
|
+
void mintTestUsdc();
|
|
399
|
+
},
|
|
400
|
+
children: busy === "mint" ? t("Minting\u2026", "\u9818\u53D6\u4E2D\u2026") : t("Mint 100 test USDC", "\u9818\u53D6 100 \u6E2C\u8A66 USDC")
|
|
401
|
+
}
|
|
402
|
+
),
|
|
403
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", disabled: busy !== null, onClick: () => {
|
|
404
|
+
void exportKey();
|
|
405
|
+
}, children: busy === "export" ? t("Revealing\u2026", "\u8B80\u53D6\u4E2D\u2026") : t("Export key", "\u532F\u51FA\u79C1\u9470") }),
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", disabled: busy !== null, onClick: () => setShowImport((v) => !v), children: t("Import key", "\u532F\u5165\u79C1\u9470") }),
|
|
407
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", disabled: busy !== null, onClick: () => {
|
|
408
|
+
void rotateKey();
|
|
409
|
+
}, children: t("New wallet", "\u7522\u751F\u65B0\u9322\u5305") })
|
|
410
|
+
] }),
|
|
411
|
+
exported != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 10 }, children: [
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...dim, fontSize: 12, marginBottom: 4 }, children: t("Private key \u2014 keep it offline. Testnet only.", "\u79C1\u9470\u2014\u2014\u8ACB\u96E2\u7DDA\u4FDD\u5B58\u3002\u50C5\u9650\u6E2C\u8A66\u7DB2\u3002") }),
|
|
413
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
414
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Input, { readOnly: true, value: exported, onFocus: (e) => e.currentTarget.select(), "aria-label": t("Private key", "\u79C1\u9470") }),
|
|
415
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
416
|
+
import_dsh_client_ui_primitives.Button,
|
|
417
|
+
{
|
|
418
|
+
variant: "ghost",
|
|
419
|
+
size: "sm",
|
|
420
|
+
onClick: () => {
|
|
421
|
+
if (navigator.clipboard != null) {
|
|
422
|
+
void navigator.clipboard.writeText(exported);
|
|
423
|
+
setNotice(t("Private key copied.", "\u5DF2\u8907\u88FD\u79C1\u9470\u3002"));
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
children: t("copy", "\u8907\u88FD")
|
|
427
|
+
}
|
|
428
|
+
),
|
|
429
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", onClick: () => setExported(null), children: t("hide", "\u96B1\u85CF") })
|
|
430
|
+
] })
|
|
431
|
+
] }),
|
|
432
|
+
showImport && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 10 }, children: [
|
|
433
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...dim, fontSize: 12, marginBottom: 4 }, children: t("Paste a 0x\u2026 32-byte private key", "\u8CBC\u4E0A 0x\u2026 32 byte \u79C1\u9470") }),
|
|
434
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
436
|
+
import_dsh_client_ui_primitives.Input,
|
|
437
|
+
{
|
|
438
|
+
value: importText,
|
|
439
|
+
placeholder: "0x\u2026",
|
|
440
|
+
onChange: (e) => setImportText(e.target.value),
|
|
441
|
+
"aria-label": t("Private key to import", "\u8981\u532F\u5165\u7684\u79C1\u9470")
|
|
442
|
+
}
|
|
443
|
+
),
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
445
|
+
import_dsh_client_ui_primitives.Button,
|
|
446
|
+
{
|
|
447
|
+
variant: "primary",
|
|
448
|
+
size: "sm",
|
|
449
|
+
disabled: busy !== null || !/^(0x)?[0-9a-fA-F]{64}$/.test(importText.trim()),
|
|
450
|
+
onClick: () => {
|
|
451
|
+
void importKey();
|
|
452
|
+
},
|
|
453
|
+
children: busy === "import" ? t("Importing\u2026", "\u532F\u5165\u4E2D\u2026") : t("Import", "\u532F\u5165")
|
|
454
|
+
}
|
|
455
|
+
)
|
|
456
|
+
] })
|
|
320
457
|
] })
|
|
321
458
|
] }),
|
|
322
459
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: box, children: [
|
|
@@ -393,6 +530,28 @@ function Page() {
|
|
|
393
530
|
}, children: busy === "refresh" ? t("Refreshing\u2026", "\u91CD\u65B0\u6383\u63CF\u4E2D\u2026") : t("Refresh network", "\u91CD\u65B0\u6383\u63CF\u7DB2\u8DEF") }),
|
|
394
531
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...dim, fontSize: 12 }, children: t("Re-reads the directory and the seed now.", "\u7ACB\u5373\u91CD\u8B80\u93C8\u4E0A\u76EE\u9304\u8207 seed\u3002") })
|
|
395
532
|
] })
|
|
533
|
+
] }),
|
|
534
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: box, children: [
|
|
535
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...dim, fontSize: 12, textTransform: "uppercase", letterSpacing: 1 }, children: "Models on the network" }),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gk-net-wrap", children: [
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gk-net-models", ref: models.attach, onScroll: models.update, children: offers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { ...dim, marginBottom: 0 }, children: "Nothing offered yet. A worker lists its local Ollama models on start." }) : offers.map((entry, i) => {
|
|
538
|
+
const offer = entry.offer ?? {};
|
|
539
|
+
const transport = entry.addr == null ? null : status.transports?.[entry.addr];
|
|
540
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gk-net-row", children: [
|
|
541
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
|
|
542
|
+
offer.model ?? "model name missing",
|
|
543
|
+
offer.tier === "chat" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...dim, fontSize: 11, marginLeft: 8 }, children: "not for agents" }) : offer.tier != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...dim, fontSize: 11, marginLeft: 8 }, children: offer.tier }) : null
|
|
544
|
+
] }),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...dim, textAlign: "right", fontSize: 12 }, children: offer.workerName ?? "\u2014" }),
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { textAlign: "right", fontSize: 12 }, children: [
|
|
547
|
+
price(offer.pricePerHour),
|
|
548
|
+
" ",
|
|
549
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: transport === "relay" ? "\xB7 via seed VM" : transport === "direct" ? "\xB7 direct" : "" })
|
|
550
|
+
] })
|
|
551
|
+
] }, `${entry.addr ?? ""}:${offer.model ?? i}`);
|
|
552
|
+
}) }),
|
|
553
|
+
models.thumb != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gk-net-rail", "aria-hidden": "true", onPointerDown: (e) => models.jump(e), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gk-net-thumb", style: { top: `${models.thumb.top}%`, height: `${models.thumb.height}%` } }) })
|
|
554
|
+
] })
|
|
396
555
|
] })
|
|
397
556
|
] });
|
|
398
557
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genkaku/dsh-user-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "Buy peer-to-peer inference from the GenKaKu network",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@deepseek-ai/dsh-llm": "0.2.2-rc.1",
|
|
42
|
-
"@genkaku/dsh-runtime": "0.1.
|
|
43
|
-
"@genkaku/protocol": "0.1.
|
|
42
|
+
"@genkaku/dsh-runtime": "0.1.23",
|
|
43
|
+
"@genkaku/protocol": "0.1.16"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@deepseek-ai/cordis": "^4.1.0",
|