@genkaku/dsh-user-plugin 0.1.18 → 0.1.20

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.
Files changed (2) hide show
  1. package/lib/client.js +105 -25
  2. package/package.json +2 -2
package/lib/client.js CHANGED
@@ -78,9 +78,48 @@ function Icon({ size = 16 }) {
78
78
  var row = { display: "flex", justifyContent: "space-between", gap: 12, padding: "6px 0" };
79
79
  var dim = { opacity: 0.6 };
80
80
  var box = { border: "1px solid rgba(255,255,255,0.12)", borderRadius: 10, padding: 12, marginTop: 12 };
81
+ function useScrollThumb() {
82
+ const [node, setNode] = (0, import_react.useState)(null);
83
+ const nodeRef = (0, import_react.useRef)(null);
84
+ const [thumb, setThumb] = (0, import_react.useState)(null);
85
+ const attach = (0, import_react.useCallback)((next) => {
86
+ nodeRef.current = next;
87
+ setNode(next);
88
+ }, []);
89
+ const update = (0, import_react.useCallback)(() => {
90
+ const el = nodeRef.current;
91
+ if (el == null) return;
92
+ const ratio = el.scrollHeight > el.clientHeight + 1 ? el.clientHeight / el.scrollHeight : 1;
93
+ setThumb(ratio >= 1 ? null : { top: el.scrollTop / el.scrollHeight * 100, height: Math.max(ratio * 100, 8) });
94
+ }, []);
95
+ (0, import_react.useEffect)(() => {
96
+ if (node == null) return;
97
+ update();
98
+ node.addEventListener("scroll", update, { passive: true });
99
+ const ro = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(update);
100
+ ro?.observe(node);
101
+ const mo = typeof MutationObserver === "undefined" ? null : new MutationObserver(update);
102
+ mo?.observe(node, { childList: true, subtree: true });
103
+ return () => {
104
+ node.removeEventListener("scroll", update);
105
+ ro?.disconnect();
106
+ mo?.disconnect();
107
+ };
108
+ }, [node, update]);
109
+ const jump = (0, import_react.useCallback)((event) => {
110
+ const el = nodeRef.current;
111
+ const rail = event.currentTarget;
112
+ if (el == null || rail == null) return;
113
+ const rect = rail.getBoundingClientRect();
114
+ if (rect.height <= 0) return;
115
+ el.scrollTop = Math.max(0, (event.clientY - rect.top) / rect.height) * el.scrollHeight;
116
+ }, []);
117
+ return { attach, thumb, update, jump };
118
+ }
81
119
  function Page() {
82
120
  const [status, setStatus] = (0, import_react.useState)(null);
83
121
  const [error, setError] = (0, import_react.useState)(null);
122
+ const models = useScrollThumb();
84
123
  const load = (0, import_react.useCallback)(async () => {
85
124
  for (const port of CANDIDATE_PORTS) {
86
125
  try {
@@ -118,44 +157,85 @@ function Page() {
118
157
  }
119
158
  if (status == null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: 16, ...dim }, children: "Loading worker status\u2026" });
120
159
  const offers = status.offers ?? [];
121
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: 16, maxWidth: 720 }, children: [
160
+ const price = (micro) => {
161
+ const n = Number(micro);
162
+ if (!Number.isFinite(n)) return "\u2014";
163
+ return n === 0 ? "free" : `${(n / 1e6).toFixed(2)} USDC`;
164
+ };
165
+ const eth = (wei) => {
166
+ const n = Number(wei);
167
+ return Number.isFinite(n) ? `${(n / 1e18).toFixed(4)} ETH` : "\u2014";
168
+ };
169
+ const usdc = (micro) => {
170
+ const n = Number(micro);
171
+ return Number.isFinite(n) ? `${(n / 1e6).toFixed(2)} USDC` : "\u2014";
172
+ };
173
+ const short = (addr) => addr == null || addr.length < 12 ? addr ?? "\u2014" : `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`;
174
+ const wallets = new Set(offers.map((o) => o.offer?.workerWallet).filter((w) => typeof w === "string" && w !== ""));
175
+ const workerCount = wallets.size > 0 ? wallets.size : (status.workers ?? []).length;
176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: 16, maxWidth: 760 }, children: [
177
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
178
+ .gk-net-wrap { position: relative; padding-right: 12px; }
179
+ .gk-net-models { max-height: min(380px, 48vh); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; }
180
+ .gk-net-models::-webkit-scrollbar { display: none; }
181
+ .gk-net-rail { position: absolute; top: 2px; bottom: 2px; right: 2px; width: 8px; border-radius: 4px; background: rgba(127,137,153,.16); cursor: pointer; }
182
+ .gk-net-thumb { position: absolute; left: 0; width: 8px; min-height: 16px; border-radius: 4px; background: rgba(127,137,153,.7); }
183
+ .gk-net-rail:hover .gk-net-thumb { background: rgba(127,137,153,.9); }
184
+ .gk-net-row { display: grid; grid-template-columns: minmax(0, 1fr) 92px 116px; gap: 10px; align-items: center; padding: 7px 0; border-top: 0.5px solid rgba(127,137,153,.18); }
185
+ .gk-net-row:first-child { border-top: none; }
186
+ ` }),
122
187
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { margin: 0 }, children: "GenKaKu network" }),
123
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...dim, marginTop: 4 }, children: status.role ?? "unknown role" }),
188
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...dim, marginTop: 4 }, children: [
189
+ "user \xB7 ",
190
+ status.env ?? "base-sepolia"
191
+ ] }),
124
192
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: box, children: [
125
193
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
126
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Peer" }),
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: status.peerId ?? "\u2014" })
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Wallet" }),
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { title: status.wallet, children: short(status.wallet) })
196
+ ] }),
197
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Balance" }),
199
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
200
+ eth(status.balances?.eth),
201
+ " \xB7 ",
202
+ usdc(status.balances?.usdc)
203
+ ] })
128
204
  ] }),
129
205
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
130
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Sessions served" }),
131
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: status.sessions ?? 0 })
206
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Payments" }),
207
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: status.settle === true ? "escrow enabled" : "free / dev" })
132
208
  ] }),
133
209
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Published on-chain" }),
135
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: status.published === true ? "yes" : "no" })
210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Workers discovered" }),
211
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: workerCount })
136
212
  ] }),
137
213
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
138
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Addresses" }),
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: (status.peerAddrs ?? []).length })
214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: "Models offered" }),
215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: offers.length })
140
216
  ] })
141
217
  ] }),
142
218
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: box, children: [
143
219
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...dim, fontSize: 12, textTransform: "uppercase", letterSpacing: 1 }, children: "Models on the network" }),
144
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
145
- .gk-net-models { max-height: min(360px, 45vh); overflow-y: auto; overscroll-behavior: contain; padding-right: 6px; scrollbar-width: thin; }
146
- .gk-net-models::-webkit-scrollbar { width: 10px; }
147
- .gk-net-models::-webkit-scrollbar-track { background: transparent; }
148
- .gk-net-models::-webkit-scrollbar-thumb { background: rgba(127,137,153,.55); border: 2px solid transparent; border-radius: 6px; background-clip: content-box; }
149
- ` }),
150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "gk-net-models", children: offers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { ...dim, marginBottom: 0 }, children: "Nothing offered yet. The worker auto-lists local Ollama models on start." }) : offers.map((offer, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: row, children: [
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: offer.model ?? "\u2014" }),
152
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: dim, children: [
153
- offer.pricePerHour ?? "?",
154
- " / hour",
155
- offer.tier === "chat" ? " \xB7 not for agents" : "",
156
- offer.addr != null && status.transports?.[offer.addr] === "relay" ? " \xB7 via seed VM" : offer.addr != null && status.transports?.[offer.addr] === "direct" ? " \xB7 direct" : ""
157
- ] })
158
- ] }, `${offer.model ?? i}`)) })
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gk-net-wrap", children: [
221
+ /* @__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) => {
222
+ const offer = entry.offer ?? {};
223
+ const transport = entry.addr == null ? null : status.transports?.[entry.addr];
224
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "gk-net-row", children: [
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
226
+ offer.model ?? "model name missing",
227
+ 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
228
+ ] }),
229
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...dim, textAlign: "right", fontSize: 12 }, children: offer.workerName ?? "\u2014" }),
230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { textAlign: "right", fontSize: 12 }, children: [
231
+ price(offer.pricePerHour),
232
+ " ",
233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: dim, children: transport === "relay" ? "\xB7 via seed VM" : transport === "direct" ? "\xB7 direct" : "" })
234
+ ] })
235
+ ] }, `${entry.addr ?? ""}:${offer.model ?? i}`);
236
+ }) }),
237
+ 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}%` } }) })
238
+ ] })
159
239
  ] })
160
240
  ] });
161
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genkaku/dsh-user-plugin",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Buy peer-to-peer inference from the GenKaKu network",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@deepseek-ai/dsh-llm": "0.2.2-rc.1",
42
- "@genkaku/dsh-runtime": "0.1.19",
42
+ "@genkaku/dsh-runtime": "0.1.20",
43
43
  "@genkaku/protocol": "0.1.13"
44
44
  },
45
45
  "peerDependencies": {