@polderlabs/bizar 4.4.12 → 4.4.13
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/bizar-dash/dist/assets/main-BB5mJurD.js +352 -0
- package/bizar-dash/dist/assets/main-BB5mJurD.js.map +1 -0
- package/bizar-dash/dist/assets/{main-BKXEqU1w.css → main-BsnQLXdh.css} +1 -1
- package/bizar-dash/dist/index.html +2 -2
- package/bizar-dash/src/server/minimax.mjs +231 -105
- package/bizar-dash/src/server/providers-store.mjs +10 -6
- package/bizar-dash/src/server/routes/minimax.mjs +50 -57
- package/bizar-dash/src/web/styles/minimax-usage.css +136 -0
- package/bizar-dash/src/web/views/MiniMaxUsage.tsx +387 -22
- package/cli/bin.mjs +263 -3
- package/package.json +1 -1
- package/bizar-dash/dist/assets/main-EK_fzXn_.js +0 -352
- package/bizar-dash/dist/assets/main-EK_fzXn_.js.map +0 -1
|
@@ -9,11 +9,15 @@
|
|
|
9
9
|
* POST /api/minimax/remains/refresh — force re-fetch from the API
|
|
10
10
|
* POST /api/minimax/test — smoke-test the key with a one-shot chat call
|
|
11
11
|
* GET /api/minimax/cache — read the on-disk cache file (for debugging)
|
|
12
|
+
* DELETE /api/minimax/cache — clear cache
|
|
13
|
+
* POST /api/minimax/onboarding — onboarding wizard state (dismissed, hiddenModels)
|
|
14
|
+
* POST /api/minimax/onboarding/save-key — write the user's key to opencode's
|
|
15
|
+
* auth.json (the canonical place)
|
|
12
16
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* The MiniMax key is read from opencode's auth store, NOT from
|
|
18
|
+
* settings.json. The dashboard's onboarding wizard writes the key
|
|
19
|
+
* directly to ~/.local/share/opencode/auth.json so opencode itself
|
|
20
|
+
* can pick it up — that way the user only enters the key once.
|
|
17
21
|
*/
|
|
18
22
|
import { Router } from 'express';
|
|
19
23
|
import {
|
|
@@ -21,7 +25,10 @@ import {
|
|
|
21
25
|
chatCompletion,
|
|
22
26
|
readCachedRemains,
|
|
23
27
|
clearRemainsCache,
|
|
24
|
-
|
|
28
|
+
getStatus,
|
|
29
|
+
writeAuthFile,
|
|
30
|
+
writeOnboarding,
|
|
31
|
+
readOnboarding,
|
|
25
32
|
maskKey,
|
|
26
33
|
KNOWN_MODELS,
|
|
27
34
|
} from '../minimax.mjs';
|
|
@@ -38,39 +45,46 @@ export function createMinimaxRouter({ state, broadcast }) {
|
|
|
38
45
|
|
|
39
46
|
// GET / — health + config summary
|
|
40
47
|
router.get('/minimax/status', wrap(async (_req, res) => {
|
|
41
|
-
|
|
42
|
-
const cached = readCachedRemains();
|
|
43
|
-
res.json({
|
|
44
|
-
enabled: settings.enabled,
|
|
45
|
-
configured: !!settings.apiKey,
|
|
46
|
-
apiKeyHint: maskKey(settings.apiKey),
|
|
47
|
-
groupId: settings.groupId,
|
|
48
|
-
baseUrl: settings.baseUrl,
|
|
49
|
-
chatBaseUrl: settings.chatBaseUrl,
|
|
50
|
-
knownModels: KNOWN_MODELS,
|
|
51
|
-
cache: cached
|
|
52
|
-
? {
|
|
53
|
-
fetchedAt: cached.fetchedAt,
|
|
54
|
-
apiKeyHint: cached.apiKeyHint,
|
|
55
|
-
groupId: cached.groupId,
|
|
56
|
-
modelCount: (cached.models || []).length,
|
|
57
|
-
}
|
|
58
|
-
: null,
|
|
59
|
-
});
|
|
48
|
+
res.json(getStatus());
|
|
60
49
|
}));
|
|
61
50
|
|
|
62
|
-
// GET /
|
|
63
|
-
router.get('/minimax/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
// GET /onboarding — wizard state (dismissed?, hidden models)
|
|
52
|
+
router.get('/minimax/onboarding', wrap(async (_req, res) => {
|
|
53
|
+
res.json(readOnboarding());
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
// POST /onboarding — update wizard state
|
|
57
|
+
router.post('/minimax/onboarding', wrap(async (req, res) => {
|
|
58
|
+
const patch = req.body || {};
|
|
59
|
+
const next = writeOnboarding(patch);
|
|
60
|
+
res.json(next);
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
// POST /onboarding/save-key — write the key to opencode's auth.json
|
|
64
|
+
router.post('/minimax/onboarding/save-key', wrap(async (req, res) => {
|
|
65
|
+
const { key, groupId } = req.body || {};
|
|
66
|
+
if (typeof key !== 'string' || !key.trim()) {
|
|
67
|
+
res.status(400).json({ ok: false, error: 'no_key', message: 'Key is required' });
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
try {
|
|
71
|
+
const path = writeAuthFile(key.trim(), groupId || 'default');
|
|
72
|
+
// Clear the remains cache so the next load picks up the new key.
|
|
73
|
+
clearRemainsCache();
|
|
74
|
+
// Mark the onboarding as dismissed (user has the key now).
|
|
75
|
+
writeOnboarding({ dismissedAt: Date.now() });
|
|
76
|
+
if (broadcast) {
|
|
77
|
+
broadcast({ type: 'minimax:configured', source: 'auth.json' });
|
|
78
|
+
}
|
|
79
|
+
res.json({ ok: true, path, apiKeyHint: maskKey(key) });
|
|
80
|
+
} catch (err) {
|
|
81
|
+
res.status(500).json({ ok: false, error: 'write_failed', message: err.message });
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
|
|
85
|
+
// GET /remains — current snapshot (cache-or-fetch)
|
|
86
|
+
router.get('/minimax/remains', wrap(async (_req, res) => {
|
|
87
|
+
const result = await fetchRemains();
|
|
74
88
|
if (broadcast && result.ok) {
|
|
75
89
|
broadcast({ type: 'minimax:remains', remains: result });
|
|
76
90
|
}
|
|
@@ -79,17 +93,7 @@ export function createMinimaxRouter({ state, broadcast }) {
|
|
|
79
93
|
|
|
80
94
|
// POST /remains/refresh — force re-fetch (bypass cache TTL)
|
|
81
95
|
router.post('/minimax/remains/refresh', wrap(async (_req, res) => {
|
|
82
|
-
const
|
|
83
|
-
if (!settings.enabled) {
|
|
84
|
-
res.json({ ok: false, error: 'disabled', message: 'MiniMax integration is disabled in settings' });
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const result = await fetchRemains({
|
|
88
|
-
apiKey: settings.apiKey,
|
|
89
|
-
groupId: settings.groupId,
|
|
90
|
-
baseUrl: settings.baseUrl,
|
|
91
|
-
force: true,
|
|
92
|
-
});
|
|
96
|
+
const result = await fetchRemains({ force: true });
|
|
93
97
|
if (broadcast && result.ok) {
|
|
94
98
|
broadcast({ type: 'minimax:remains:refreshed', remains: result });
|
|
95
99
|
}
|
|
@@ -98,15 +102,6 @@ export function createMinimaxRouter({ state, broadcast }) {
|
|
|
98
102
|
|
|
99
103
|
// POST /test — smoke-test the key with a chat completion
|
|
100
104
|
router.post('/minimax/test', wrap(async (req, res) => {
|
|
101
|
-
const settings = readMinimaxSettings();
|
|
102
|
-
if (!settings.enabled) {
|
|
103
|
-
res.json({ ok: false, error: 'disabled', message: 'MiniMax integration is disabled in settings' });
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (!settings.apiKey) {
|
|
107
|
-
res.json({ ok: false, error: 'no_api_key', message: 'MiniMax API key is not configured' });
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
105
|
const body = req.body || {};
|
|
111
106
|
const prompt = typeof body.prompt === 'string' && body.prompt.trim()
|
|
112
107
|
? body.prompt
|
|
@@ -115,10 +110,8 @@ export function createMinimaxRouter({ state, broadcast }) {
|
|
|
115
110
|
? body.model.trim()
|
|
116
111
|
: 'MiniMax-M3';
|
|
117
112
|
const result = await chatCompletion({
|
|
118
|
-
apiKey: settings.apiKey,
|
|
119
113
|
prompt,
|
|
120
114
|
model,
|
|
121
|
-
baseUrl: settings.chatBaseUrl,
|
|
122
115
|
maxTokens: typeof body.maxTokens === 'number' ? body.maxTokens : 32,
|
|
123
116
|
});
|
|
124
117
|
res.json(result);
|
|
@@ -129,7 +122,7 @@ export function createMinimaxRouter({ state, broadcast }) {
|
|
|
129
122
|
res.json(readCachedRemains() || null);
|
|
130
123
|
}));
|
|
131
124
|
|
|
132
|
-
// DELETE /cache — clear cache
|
|
125
|
+
// DELETE /cache — clear cache
|
|
133
126
|
router.delete('/minimax/cache', wrap(async (_req, res) => {
|
|
134
127
|
clearRemainsCache();
|
|
135
128
|
if (broadcast) broadcast({ type: 'minimax:cache:cleared' });
|
|
@@ -213,6 +213,142 @@
|
|
|
213
213
|
font-family: var(--font-mono, ui-monospace, monospace);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/* ── Onboarding wizard ─────────────────────────────────────────── */
|
|
217
|
+
.view-minimax-onboarding {
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-direction: column;
|
|
220
|
+
gap: 16px;
|
|
221
|
+
padding: 16px 20px 32px;
|
|
222
|
+
max-width: 800px;
|
|
223
|
+
margin: 0 auto;
|
|
224
|
+
width: 100%;
|
|
225
|
+
}
|
|
226
|
+
.view-minimax-onboarding .minimax-wizard-stepper {
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
justify-content: space-between;
|
|
230
|
+
gap: 6px;
|
|
231
|
+
padding: 12px 16px;
|
|
232
|
+
background: var(--bg-1);
|
|
233
|
+
border: 1px solid var(--border);
|
|
234
|
+
border-radius: 8px;
|
|
235
|
+
}
|
|
236
|
+
.view-minimax-onboarding .minimax-wizard-step {
|
|
237
|
+
display: flex;
|
|
238
|
+
align-items: center;
|
|
239
|
+
gap: 8px;
|
|
240
|
+
flex: 1;
|
|
241
|
+
font-size: 12px;
|
|
242
|
+
color: var(--text-muted);
|
|
243
|
+
}
|
|
244
|
+
.view-minimax-onboarding .minimax-wizard-step-bullet {
|
|
245
|
+
width: 24px;
|
|
246
|
+
height: 24px;
|
|
247
|
+
display: inline-flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
border-radius: 50%;
|
|
251
|
+
background: var(--bg-2);
|
|
252
|
+
border: 1px solid var(--border);
|
|
253
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
254
|
+
font-size: 11px;
|
|
255
|
+
color: var(--text);
|
|
256
|
+
flex-shrink: 0;
|
|
257
|
+
}
|
|
258
|
+
.view-minimax-onboarding .minimax-wizard-step.is-current .minimax-wizard-step-bullet {
|
|
259
|
+
background: var(--accent);
|
|
260
|
+
border-color: var(--accent);
|
|
261
|
+
color: #fff;
|
|
262
|
+
}
|
|
263
|
+
.view-minimax-onboarding .minimax-wizard-step.is-done .minimax-wizard-step-bullet {
|
|
264
|
+
background: var(--success, #3fb950);
|
|
265
|
+
border-color: var(--success, #3fb950);
|
|
266
|
+
color: #fff;
|
|
267
|
+
}
|
|
268
|
+
.view-minimax-onboarding .minimax-wizard-step.is-done { color: var(--success, #3fb950); }
|
|
269
|
+
.view-minimax-onboarding .minimax-wizard-step.is-current { color: var(--text); font-weight: 500; }
|
|
270
|
+
.view-minimax-onboarding .minimax-wizard-step-label { font-size: 12px; }
|
|
271
|
+
.view-minimax-onboarding .minimax-wizard-step.is-current .minimax-wizard-step-label {
|
|
272
|
+
font-weight: 500;
|
|
273
|
+
}
|
|
274
|
+
.view-minimax-onboarding .minimax-wizard-body {
|
|
275
|
+
padding: 4px 4px 0;
|
|
276
|
+
display: flex;
|
|
277
|
+
flex-direction: column;
|
|
278
|
+
gap: 12px;
|
|
279
|
+
}
|
|
280
|
+
.view-minimax-onboarding .minimax-wizard-title {
|
|
281
|
+
font-size: 16px;
|
|
282
|
+
font-weight: 600;
|
|
283
|
+
margin: 0;
|
|
284
|
+
color: var(--text);
|
|
285
|
+
display: flex;
|
|
286
|
+
align-items: center;
|
|
287
|
+
}
|
|
288
|
+
.view-minimax-onboarding .minimax-wizard-prose {
|
|
289
|
+
margin: 0;
|
|
290
|
+
color: var(--text-muted);
|
|
291
|
+
font-size: 13px;
|
|
292
|
+
line-height: 1.55;
|
|
293
|
+
}
|
|
294
|
+
.view-minimax-onboarding .minimax-wizard-prose code {
|
|
295
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
296
|
+
font-size: 12px;
|
|
297
|
+
padding: 1px 5px;
|
|
298
|
+
border-radius: 3px;
|
|
299
|
+
background: var(--bg-2);
|
|
300
|
+
color: var(--text);
|
|
301
|
+
}
|
|
302
|
+
.view-minimax-onboarding .minimax-wizard-prose--muted { font-size: 12px; opacity: 0.85; }
|
|
303
|
+
.view-minimax-onboarding .minimax-wizard-list {
|
|
304
|
+
margin: 0;
|
|
305
|
+
padding-left: 22px;
|
|
306
|
+
font-size: 13px;
|
|
307
|
+
color: var(--text-muted);
|
|
308
|
+
line-height: 1.6;
|
|
309
|
+
}
|
|
310
|
+
.view-minimax-onboarding .minimax-wizard-list li { margin-bottom: 4px; }
|
|
311
|
+
.view-minimax-onboarding .minimax-wizard-link {
|
|
312
|
+
color: var(--accent);
|
|
313
|
+
text-decoration: underline;
|
|
314
|
+
display: inline-flex;
|
|
315
|
+
align-items: center;
|
|
316
|
+
gap: 3px;
|
|
317
|
+
}
|
|
318
|
+
.view-minimax-onboarding .minimax-wizard-actions {
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
gap: 8px;
|
|
322
|
+
margin-top: 8px;
|
|
323
|
+
flex-wrap: wrap;
|
|
324
|
+
}
|
|
325
|
+
.view-minimax-onboarding .minimax-wizard-error {
|
|
326
|
+
display: flex;
|
|
327
|
+
gap: 8px;
|
|
328
|
+
padding: 8px 10px;
|
|
329
|
+
border-radius: 6px;
|
|
330
|
+
background: rgba(248, 81, 73, 0.08);
|
|
331
|
+
border: 1px solid rgba(248, 81, 73, 0.30);
|
|
332
|
+
color: var(--text);
|
|
333
|
+
font-size: 12px;
|
|
334
|
+
}
|
|
335
|
+
.view-minimax-onboarding .minimax-wizard-footer {
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 6px;
|
|
339
|
+
font-size: 11px;
|
|
340
|
+
color: var(--text-muted);
|
|
341
|
+
padding: 0 4px;
|
|
342
|
+
margin-top: 8px;
|
|
343
|
+
}
|
|
344
|
+
.view-minimax-onboarding .minimax-wizard-footer code {
|
|
345
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
346
|
+
font-size: 10px;
|
|
347
|
+
padding: 0 3px;
|
|
348
|
+
background: rgba(0,0,0,0.25);
|
|
349
|
+
border-radius: 2px;
|
|
350
|
+
}
|
|
351
|
+
|
|
216
352
|
/* ── Subscription Key card ──────────────────────────────────────── */
|
|
217
353
|
.view-minimax-usage .minimax-link {
|
|
218
354
|
color: var(--accent);
|