@byoky/openclaw-plugin 0.3.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 byoky contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,43 @@
1
+ import { OpenClawPluginApi } from 'openclaw/plugin-sdk/core';
2
+
3
+ type PluginConfigUiHint = {
4
+ label?: string;
5
+ help?: string;
6
+ tags?: string[];
7
+ advanced?: boolean;
8
+ sensitive?: boolean;
9
+ placeholder?: string;
10
+ };
11
+ type PluginConfigValidation = {
12
+ ok: true;
13
+ value?: unknown;
14
+ } | {
15
+ ok: false;
16
+ errors: string[];
17
+ };
18
+ type OpenClawPluginConfigSchema = {
19
+ safeParse?: (value: unknown) => {
20
+ success: boolean;
21
+ data?: unknown;
22
+ error?: {
23
+ issues?: Array<{
24
+ path: Array<string | number>;
25
+ message: string;
26
+ }>;
27
+ };
28
+ };
29
+ parse?: (value: unknown) => unknown;
30
+ validate?: (value: unknown) => PluginConfigValidation;
31
+ uiHints?: Record<string, PluginConfigUiHint>;
32
+ jsonSchema?: Record<string, unknown>;
33
+ };
34
+
35
+ declare const byokyPlugin: {
36
+ id: string;
37
+ name: string;
38
+ description: string;
39
+ configSchema: OpenClawPluginConfigSchema;
40
+ register(api: OpenClawPluginApi): void;
41
+ };
42
+
43
+ export { byokyPlugin as default };
package/dist/index.js ADDED
@@ -0,0 +1,501 @@
1
+ // src/index.ts
2
+ import {
3
+ emptyPluginConfigSchema
4
+ } from "openclaw/plugin-sdk/core";
5
+ import { createServer } from "http";
6
+ var DEFAULT_BRIDGE_PORT = 19280;
7
+ var ANTHROPIC_MODELS = [
8
+ {
9
+ id: "claude-opus-4-20250514",
10
+ name: "Claude Opus 4",
11
+ reasoning: true,
12
+ input: ["text", "image"],
13
+ cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
14
+ contextWindow: 2e5,
15
+ maxTokens: 32e3
16
+ },
17
+ {
18
+ id: "claude-sonnet-4-20250514",
19
+ name: "Claude Sonnet 4",
20
+ reasoning: true,
21
+ input: ["text", "image"],
22
+ cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
23
+ contextWindow: 2e5,
24
+ maxTokens: 16e3
25
+ },
26
+ {
27
+ id: "claude-haiku-4-5-20251001",
28
+ name: "Claude Haiku 4.5",
29
+ reasoning: false,
30
+ input: ["text", "image"],
31
+ cost: { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
32
+ contextWindow: 2e5,
33
+ maxTokens: 8192
34
+ }
35
+ ];
36
+ var OPENAI_MODELS = [
37
+ {
38
+ id: "gpt-4.1",
39
+ name: "GPT-4.1",
40
+ reasoning: false,
41
+ input: ["text", "image"],
42
+ cost: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 },
43
+ contextWindow: 1047576,
44
+ maxTokens: 32768
45
+ },
46
+ {
47
+ id: "o3",
48
+ name: "o3",
49
+ reasoning: true,
50
+ input: ["text", "image"],
51
+ cost: { input: 10, output: 40, cacheRead: 2.5, cacheWrite: 0 },
52
+ contextWindow: 2e5,
53
+ maxTokens: 1e5
54
+ },
55
+ {
56
+ id: "o4-mini",
57
+ name: "o4-mini",
58
+ reasoning: true,
59
+ input: ["text", "image"],
60
+ cost: { input: 1.1, output: 4.4, cacheRead: 0.275, cacheWrite: 0 },
61
+ contextWindow: 2e5,
62
+ maxTokens: 1e5
63
+ },
64
+ {
65
+ id: "gpt-4.1-mini",
66
+ name: "GPT-4.1 Mini",
67
+ reasoning: false,
68
+ input: ["text", "image"],
69
+ cost: { input: 0.4, output: 1.6, cacheRead: 0.1, cacheWrite: 0 },
70
+ contextWindow: 1047576,
71
+ maxTokens: 32768
72
+ }
73
+ ];
74
+ var GEMINI_MODELS = [
75
+ {
76
+ id: "gemini-2.5-pro",
77
+ name: "Gemini 2.5 Pro",
78
+ reasoning: true,
79
+ input: ["text", "image"],
80
+ cost: { input: 1.25, output: 10, cacheRead: 0.315, cacheWrite: 0 },
81
+ contextWindow: 1048576,
82
+ maxTokens: 65536
83
+ },
84
+ {
85
+ id: "gemini-2.5-flash",
86
+ name: "Gemini 2.5 Flash",
87
+ reasoning: true,
88
+ input: ["text", "image"],
89
+ cost: { input: 0.15, output: 0.6, cacheRead: 0.0375, cacheWrite: 0 },
90
+ contextWindow: 1048576,
91
+ maxTokens: 65536
92
+ }
93
+ ];
94
+ var DEEPSEEK_MODELS = [
95
+ {
96
+ id: "deepseek-chat",
97
+ name: "DeepSeek V3",
98
+ reasoning: false,
99
+ input: ["text"],
100
+ cost: { input: 0.27, output: 1.1, cacheRead: 0.07, cacheWrite: 0 },
101
+ contextWindow: 65536,
102
+ maxTokens: 8192
103
+ },
104
+ {
105
+ id: "deepseek-reasoner",
106
+ name: "DeepSeek R1",
107
+ reasoning: true,
108
+ input: ["text"],
109
+ cost: { input: 0.55, output: 2.19, cacheRead: 0.14, cacheWrite: 0 },
110
+ contextWindow: 65536,
111
+ maxTokens: 8192
112
+ }
113
+ ];
114
+ var XAI_MODELS = [
115
+ {
116
+ id: "grok-3",
117
+ name: "Grok 3",
118
+ reasoning: false,
119
+ input: ["text"],
120
+ cost: { input: 3, output: 15, cacheRead: 0, cacheWrite: 0 },
121
+ contextWindow: 131072,
122
+ maxTokens: 16384
123
+ },
124
+ {
125
+ id: "grok-3-mini",
126
+ name: "Grok 3 Mini",
127
+ reasoning: true,
128
+ input: ["text"],
129
+ cost: { input: 0.3, output: 0.5, cacheRead: 0, cacheWrite: 0 },
130
+ contextWindow: 131072,
131
+ maxTokens: 16384
132
+ }
133
+ ];
134
+ var MISTRAL_MODELS = [
135
+ {
136
+ id: "mistral-large-latest",
137
+ name: "Mistral Large",
138
+ reasoning: false,
139
+ input: ["text", "image"],
140
+ cost: { input: 2, output: 6, cacheRead: 0, cacheWrite: 0 },
141
+ contextWindow: 128e3,
142
+ maxTokens: 8192
143
+ }
144
+ ];
145
+ var GROQ_MODELS = [
146
+ {
147
+ id: "llama-3.3-70b-versatile",
148
+ name: "Llama 3.3 70B",
149
+ reasoning: false,
150
+ input: ["text"],
151
+ cost: { input: 0.59, output: 0.79, cacheRead: 0, cacheWrite: 0 },
152
+ contextWindow: 128e3,
153
+ maxTokens: 32768
154
+ }
155
+ ];
156
+ var EMPTY_MODELS = [];
157
+ var PROVIDERS = [
158
+ { id: "anthropic", name: "Anthropic", api: "anthropic-messages", models: ANTHROPIC_MODELS },
159
+ { id: "openai", name: "OpenAI", api: "openai-completions", models: OPENAI_MODELS },
160
+ { id: "gemini", name: "Google Gemini", api: "openai-completions", models: GEMINI_MODELS },
161
+ { id: "mistral", name: "Mistral", api: "openai-completions", models: MISTRAL_MODELS },
162
+ { id: "cohere", name: "Cohere", api: "openai-completions", models: EMPTY_MODELS },
163
+ { id: "xai", name: "xAI (Grok)", api: "openai-completions", models: XAI_MODELS },
164
+ { id: "deepseek", name: "DeepSeek", api: "openai-completions", models: DEEPSEEK_MODELS },
165
+ { id: "perplexity", name: "Perplexity", api: "openai-completions", models: EMPTY_MODELS },
166
+ { id: "groq", name: "Groq", api: "openai-completions", models: GROQ_MODELS },
167
+ { id: "together", name: "Together AI", api: "openai-completions", models: EMPTY_MODELS },
168
+ { id: "fireworks", name: "Fireworks AI", api: "openai-completions", models: EMPTY_MODELS },
169
+ { id: "openrouter", name: "OpenRouter", api: "openai-completions", models: EMPTY_MODELS },
170
+ { id: "replicate", name: "Replicate", api: "openai-completions", models: EMPTY_MODELS },
171
+ { id: "huggingface", name: "Hugging Face", api: "openai-completions", models: EMPTY_MODELS },
172
+ { id: "azure_openai", name: "Azure OpenAI", api: "openai-completions", models: EMPTY_MODELS }
173
+ ];
174
+ var byokyPlugin = {
175
+ id: "byoky",
176
+ name: "Byoky Wallet",
177
+ description: "Route LLM API calls through your Byoky browser wallet \u2014 keys never leave the extension",
178
+ configSchema: emptyPluginConfigSchema(),
179
+ register(api) {
180
+ for (const provider of PROVIDERS) {
181
+ const openclawId = `byoky-${provider.id}`;
182
+ api.registerProvider({
183
+ id: openclawId,
184
+ label: `${provider.name} (via Byoky)`,
185
+ docsPath: "/providers/byoky",
186
+ auth: [
187
+ {
188
+ id: "browser",
189
+ label: `${provider.name} (via Byoky)`,
190
+ hint: "Route through Byoky wallet \u2014 key stays in extension",
191
+ kind: "custom",
192
+ run: (ctx) => runProviderAuth(ctx, provider)
193
+ }
194
+ ],
195
+ wizard: {
196
+ onboarding: {
197
+ choiceId: openclawId,
198
+ choiceLabel: `${provider.name} (via Byoky)`,
199
+ choiceHint: "Route through Byoky wallet",
200
+ groupId: "byoky",
201
+ groupLabel: "Byoky Wallet",
202
+ groupHint: "Keys never leave the extension",
203
+ methodId: "browser"
204
+ }
205
+ }
206
+ });
207
+ }
208
+ api.registerCommand({
209
+ name: "byoky",
210
+ description: "Show Byoky bridge status and connected providers",
211
+ acceptsArgs: false,
212
+ handler: async () => {
213
+ const health = await checkBridgeHealth();
214
+ if (!health) {
215
+ return {
216
+ text: "Byoky Bridge: **offline**\n\nStart the bridge with `openclaw models auth login --provider byoky-anthropic` or ensure it is running on port " + DEFAULT_BRIDGE_PORT + "."
217
+ };
218
+ }
219
+ const providerList = health.providers.length > 0 ? health.providers.join(", ") : "none";
220
+ return {
221
+ text: `Byoky Bridge: **online** (port ${DEFAULT_BRIDGE_PORT})
222
+ Providers: ${providerList}`
223
+ };
224
+ }
225
+ });
226
+ }
227
+ };
228
+ var index_default = byokyPlugin;
229
+ async function checkBridgeHealth() {
230
+ try {
231
+ const controller = new AbortController();
232
+ const timeout = setTimeout(() => controller.abort(), 3e3);
233
+ const res = await fetch(`http://127.0.0.1:${DEFAULT_BRIDGE_PORT}/health`, {
234
+ signal: controller.signal
235
+ });
236
+ clearTimeout(timeout);
237
+ if (!res.ok) return null;
238
+ const data = await res.json();
239
+ if (data.status !== "ok") return null;
240
+ return { providers: data.providers ?? [] };
241
+ } catch {
242
+ return null;
243
+ }
244
+ }
245
+ async function runProviderAuth(ctx, provider) {
246
+ ctx.prompter.note(
247
+ `Opening your browser to connect ${provider.name} via Byoky wallet.
248
+ Unlock your wallet and approve the connection.
249
+ The Byoky Bridge must be installed: npm i -g @byoky/bridge && byoky-bridge install`
250
+ );
251
+ const result = await startCallbackServer(ctx, provider.id);
252
+ try {
253
+ if (!result.providers || !result.providers.includes(provider.id)) {
254
+ throw new Error(`${provider.name} not available in your Byoky wallet`);
255
+ }
256
+ const openclawId = `byoky-${provider.id}`;
257
+ return {
258
+ profiles: [
259
+ {
260
+ profileId: `${openclawId}:byoky`,
261
+ credential: {
262
+ type: "api_key",
263
+ provider: openclawId,
264
+ key: "byoky-proxy"
265
+ }
266
+ }
267
+ ],
268
+ configPatch: {
269
+ models: {
270
+ providers: {
271
+ [openclawId]: {
272
+ baseUrl: `http://127.0.0.1:${result.port}/${provider.id}`,
273
+ api: provider.api,
274
+ apiKey: "byoky-proxy",
275
+ models: provider.models
276
+ }
277
+ }
278
+ }
279
+ },
280
+ defaultModel: provider.models.length > 0 ? `${openclawId}/${provider.models[0].id}` : void 0,
281
+ notes: [
282
+ `Connected ${provider.name} via Byoky Bridge on port ${result.port}.`,
283
+ "Key stays in your browser extension \u2014 the bridge relays requests.",
284
+ "The bridge must be running for API calls to work.",
285
+ ...provider.models.length > 0 ? [`Available models: ${provider.models.map((m) => m.id).join(", ")}`] : ["No pre-defined models \u2014 set agents.defaults.model manually."]
286
+ ]
287
+ };
288
+ } finally {
289
+ result.server.close();
290
+ }
291
+ }
292
+ async function startCallbackServer(ctx, requestProviderId) {
293
+ return new Promise((resolve) => {
294
+ let resolved = false;
295
+ const server = createServer((req, res) => {
296
+ const reqOrigin = req.headers.origin || "";
297
+ let isLocalhost = false;
298
+ try {
299
+ const parsed = new URL(reqOrigin);
300
+ isLocalhost = parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost";
301
+ } catch {
302
+ }
303
+ res.setHeader(
304
+ "Access-Control-Allow-Origin",
305
+ isLocalhost ? reqOrigin : "http://127.0.0.1"
306
+ );
307
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
308
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
309
+ if (req.method === "OPTIONS") {
310
+ res.writeHead(204);
311
+ res.end();
312
+ return;
313
+ }
314
+ if (req.method === "POST" && req.url === "/callback") {
315
+ let body = "";
316
+ req.on("data", (chunk) => {
317
+ body += chunk.toString();
318
+ });
319
+ req.on("end", () => {
320
+ try {
321
+ const data = JSON.parse(body);
322
+ res.writeHead(200, { "Content-Type": "application/json" });
323
+ res.end(JSON.stringify({ ok: true }));
324
+ if (!resolved) {
325
+ resolved = true;
326
+ resolve({
327
+ providers: data.providers || [],
328
+ port: data.bridgePort || DEFAULT_BRIDGE_PORT,
329
+ server
330
+ });
331
+ }
332
+ } catch {
333
+ res.writeHead(400);
334
+ res.end("Invalid JSON");
335
+ }
336
+ });
337
+ return;
338
+ }
339
+ if (req.method === "GET") {
340
+ res.writeHead(200, { "Content-Type": "text/html" });
341
+ res.end(buildAuthPage(requestProviderId));
342
+ return;
343
+ }
344
+ res.writeHead(404);
345
+ res.end();
346
+ });
347
+ server.listen(0, "127.0.0.1", () => {
348
+ const addr = server.address();
349
+ if (typeof addr === "object" && addr) {
350
+ ctx.openUrl(`http://127.0.0.1:${addr.port}`);
351
+ }
352
+ });
353
+ setTimeout(() => {
354
+ if (!resolved) {
355
+ resolved = true;
356
+ resolve({ providers: [], port: DEFAULT_BRIDGE_PORT, server });
357
+ }
358
+ }, 12e4);
359
+ });
360
+ }
361
+ var VALID_PROVIDER_IDS = new Set(PROVIDERS.map((p) => p.id));
362
+ function buildAuthPage(requestProviderId) {
363
+ let providerFilter;
364
+ if (VALID_PROVIDER_IDS.has(requestProviderId)) {
365
+ providerFilter = `[{ id: ${JSON.stringify(requestProviderId)}, required: true }]`;
366
+ } else {
367
+ providerFilter = "[]";
368
+ }
369
+ return `<!DOCTYPE html>
370
+ <html lang="en">
371
+ <head>
372
+ <meta charset="UTF-8" />
373
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
374
+ <title>Byoky \u2014 Connect to OpenClaw</title>
375
+ <style>
376
+ * { margin: 0; padding: 0; box-sizing: border-box; }
377
+ body {
378
+ font-family: -apple-system, system-ui, sans-serif;
379
+ background: #0a0a18; color: #f5f5f7;
380
+ min-height: 100vh; display: flex;
381
+ align-items: center; justify-content: center;
382
+ }
383
+ .card {
384
+ background: #1c1c22; border-radius: 16px;
385
+ padding: 40px; max-width: 440px; width: 100%; text-align: center;
386
+ }
387
+ h1 {
388
+ font-size: 24px; font-weight: 700;
389
+ background: linear-gradient(135deg, #e0f2fe, #0ea5e9);
390
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
391
+ margin-bottom: 8px;
392
+ }
393
+ .subtitle { color: #8e8e9a; font-size: 14px; margin-bottom: 24px; }
394
+ .status {
395
+ padding: 16px; border-radius: 8px;
396
+ margin-bottom: 16px; font-size: 14px; line-height: 1.6;
397
+ }
398
+ .waiting { background: rgba(14,165,233,0.1); color: #7dd3fc; }
399
+ .success { background: rgba(52,211,153,0.1); color: #34d399; }
400
+ .error { background: rgba(244,63,94,0.1); color: #f43f5e; }
401
+ .info { color: #55555f; font-size: 12px; line-height: 1.6; }
402
+ .security { color: #34d399; font-size: 12px; margin-top: 16px; line-height: 1.6; }
403
+ </style>
404
+ </head>
405
+ <body>
406
+ <div class="card">
407
+ <h1>Byoky</h1>
408
+ <p class="subtitle">Connect wallet to OpenClaw</p>
409
+ <div id="status" class="status waiting">
410
+ Connecting to Byoky wallet...
411
+ </div>
412
+ <p class="info">
413
+ Your Byoky extension must be installed and unlocked.<br />
414
+ The Byoky Bridge must be installed for the proxy to work.
415
+ </p>
416
+ <p class="security">
417
+ Keys never leave your browser extension.<br />
418
+ API calls are proxied through the local Byoky Bridge.
419
+ </p>
420
+ </div>
421
+ <script>
422
+ (async () => {
423
+ const status = document.getElementById('status');
424
+ try {
425
+ // Step 1: Connect to Byoky wallet
426
+ const requestId = crypto.randomUUID();
427
+ window.postMessage({
428
+ type: 'BYOKY_CONNECT_REQUEST',
429
+ id: requestId,
430
+ requestId,
431
+ payload: { providers: ${providerFilter} },
432
+ }, '*');
433
+
434
+ const response = await new Promise((resolve, reject) => {
435
+ function handler(event) {
436
+ const msg = event.detail;
437
+ if (!msg || msg.requestId !== requestId) return;
438
+ document.removeEventListener('byoky-message', handler);
439
+ if (msg.type === 'BYOKY_CONNECT_RESPONSE') resolve(msg.payload);
440
+ else reject(new Error(msg.payload?.message || 'Connection failed'));
441
+ }
442
+ document.addEventListener('byoky-message', handler);
443
+ setTimeout(() => reject(new Error('Timeout \u2014 is Byoky installed and unlocked?')), 30000);
444
+ });
445
+
446
+ const providers = response.providers || {};
447
+ const available = Object.entries(providers)
448
+ .filter(([, v]) => v.available)
449
+ .map(([id]) => id);
450
+
451
+ if (available.length === 0) {
452
+ throw new Error('No matching providers found in your Byoky wallet');
453
+ }
454
+
455
+ status.textContent = 'Wallet connected! Starting bridge proxy...';
456
+
457
+ // Step 2: Tell the extension to start the bridge proxy
458
+ const bridgeRequestId = crypto.randomUUID();
459
+ window.postMessage({
460
+ type: 'BYOKY_INTERNAL_FROM_PAGE',
461
+ requestId: bridgeRequestId,
462
+ action: 'startBridgeProxy',
463
+ payload: { sessionKey: response.sessionKey, port: ${DEFAULT_BRIDGE_PORT} },
464
+ }, '*');
465
+
466
+ const bridgeResult = await new Promise((resolve, reject) => {
467
+ function handler(event) {
468
+ const msg = event.detail;
469
+ if (!msg || msg.requestId !== bridgeRequestId) return;
470
+ document.removeEventListener('byoky-message', handler);
471
+ resolve(msg.payload);
472
+ }
473
+ document.addEventListener('byoky-message', handler);
474
+ setTimeout(() => reject(new Error('Bridge proxy start timed out')), 15000);
475
+ });
476
+
477
+ const bridgePort = bridgeResult?.port || ${DEFAULT_BRIDGE_PORT};
478
+
479
+ status.textContent = 'Bridge proxy active on port ' + bridgePort + '. Connected ' + available.length + ' provider(s): ' + available.join(', ');
480
+ status.className = 'status success';
481
+
482
+ // Step 3: Send result back to OpenClaw callback server
483
+ await fetch('/callback', {
484
+ method: 'POST',
485
+ headers: { 'Content-Type': 'application/json' },
486
+ body: JSON.stringify({ providers: available, bridgePort: bridgePort }),
487
+ });
488
+
489
+ setTimeout(() => { status.textContent = 'Done \u2014 you can close this tab.'; }, 2000);
490
+ } catch (err) {
491
+ status.textContent = 'Error: ' + err.message;
492
+ status.className = 'status error';
493
+ }
494
+ })();
495
+ </script>
496
+ </body>
497
+ </html>`;
498
+ }
499
+ export {
500
+ index_default as default
501
+ };
@@ -0,0 +1,26 @@
1
+ {
2
+ "id": "byoky",
3
+ "enabledByDefault": false,
4
+ "providers": [
5
+ "byoky-anthropic",
6
+ "byoky-openai",
7
+ "byoky-gemini",
8
+ "byoky-mistral",
9
+ "byoky-cohere",
10
+ "byoky-xai",
11
+ "byoky-deepseek",
12
+ "byoky-perplexity",
13
+ "byoky-groq",
14
+ "byoky-together",
15
+ "byoky-fireworks",
16
+ "byoky-openrouter",
17
+ "byoky-replicate",
18
+ "byoky-huggingface",
19
+ "byoky-azure_openai"
20
+ ],
21
+ "configSchema": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "properties": {}
25
+ }
26
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@byoky/openclaw-plugin",
3
+ "version": "0.3.0",
4
+ "description": "Byoky wallet provider plugin for OpenClaw — manage AI API keys from your browser wallet",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "openclaw.plugin.json",
11
+ "auth-page"
12
+ ],
13
+ "openclaw": {
14
+ "extensions": [
15
+ "./dist/index.js"
16
+ ]
17
+ },
18
+ "keywords": [
19
+ "byoky",
20
+ "openclaw",
21
+ "ai",
22
+ "api-key",
23
+ "wallet",
24
+ "plugin"
25
+ ],
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/MichaelLod/byoky.git",
30
+ "directory": "packages/openclaw-plugin"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "25.5.0",
34
+ "openclaw": "^2026.3.13",
35
+ "tsup": "^8.0.0",
36
+ "typescript": "^5.5.0"
37
+ },
38
+ "scripts": {
39
+ "build": "tsup",
40
+ "dev": "tsup --watch"
41
+ }
42
+ }