teleton 0.7.3 → 0.7.4
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 +31 -12
- package/dist/{chunk-DAMCNMYL.js → chunk-BGC2IUM5.js} +9 -9
- package/dist/{chunk-FNV5FF35.js → chunk-EK7M5K26.js} +29 -13
- package/dist/{chunk-BU453WX4.js → chunk-LAQOUFOJ.js} +2034 -1551
- package/dist/chunk-QOQWUUA4.js +158 -0
- package/dist/{chunk-RBU6JXD3.js → chunk-XDYDA2KV.js} +1 -1
- package/dist/{chunk-A4GCOHCE.js → chunk-YFG2QHLA.js} +178 -6
- package/dist/cli/index.js +154 -273
- package/dist/index.js +5 -5
- package/dist/{memory-5SS3Q5EA.js → memory-JQZ6MTRU.js} +2 -2
- package/dist/{migrate-M7SJMDOL.js → migrate-GS5ACQDA.js} +2 -2
- package/dist/{server-FOC5P7U6.js → server-TCJOBV3D.js} +292 -10
- package/dist/{setup-server-BVVD2PR6.js → setup-server-YHYJLAMA.js} +6 -110
- package/dist/{tool-index-MIVK3D7H.js → tool-index-6HBRVXVG.js} +1 -1
- package/dist/web/assets/index-B6M9knfJ.css +1 -0
- package/dist/web/assets/index-DAGeQfVZ.js +72 -0
- package/dist/web/assets/{index.es-7MTSV5SL.js → index.es-CqZHj0tz.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- package/dist/web/assets/index-By_fs4Jl.js +0 -72
- package/dist/web/assets/index-CRDIf07k.css +0 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getModelsForProvider
|
|
3
|
+
} from "./chunk-QOQWUUA4.js";
|
|
1
4
|
import {
|
|
2
5
|
CONFIGURABLE_KEYS,
|
|
3
6
|
WorkspaceSecurityError,
|
|
@@ -16,13 +19,16 @@ import {
|
|
|
16
19
|
validateWritePath,
|
|
17
20
|
writePluginSecret,
|
|
18
21
|
writeRawConfig
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-YFG2QHLA.js";
|
|
23
|
+
import "./chunk-BGC2IUM5.js";
|
|
21
24
|
import "./chunk-TSKJCWQQ.js";
|
|
22
25
|
import {
|
|
23
26
|
getErrorMessage
|
|
24
27
|
} from "./chunk-XBE4JB7C.js";
|
|
25
|
-
import
|
|
28
|
+
import {
|
|
29
|
+
getProviderMetadata,
|
|
30
|
+
validateApiKeyFormat
|
|
31
|
+
} from "./chunk-RMLQS3X6.js";
|
|
26
32
|
import "./chunk-UCN6TI25.js";
|
|
27
33
|
import "./chunk-XBKSS6DM.js";
|
|
28
34
|
import "./chunk-RO62LO6Z.js";
|
|
@@ -214,7 +220,7 @@ function createToolsRoutes(deps) {
|
|
|
214
220
|
try {
|
|
215
221
|
const config = deps.agent.getConfig();
|
|
216
222
|
const body = await c.req.json();
|
|
217
|
-
const { enabled, topK } = body;
|
|
223
|
+
const { enabled, topK, alwaysInclude, skipUnlimitedProviders } = body;
|
|
218
224
|
if (enabled !== void 0) {
|
|
219
225
|
config.tool_rag.enabled = enabled;
|
|
220
226
|
}
|
|
@@ -224,6 +230,28 @@ function createToolsRoutes(deps) {
|
|
|
224
230
|
}
|
|
225
231
|
config.tool_rag.top_k = topK;
|
|
226
232
|
}
|
|
233
|
+
if (alwaysInclude !== void 0) {
|
|
234
|
+
if (!Array.isArray(alwaysInclude) || alwaysInclude.some((s) => typeof s !== "string" || s.length === 0)) {
|
|
235
|
+
return c.json(
|
|
236
|
+
{ success: false, error: "alwaysInclude must be an array of non-empty strings" },
|
|
237
|
+
400
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
config.tool_rag.always_include = alwaysInclude;
|
|
241
|
+
}
|
|
242
|
+
if (skipUnlimitedProviders !== void 0) {
|
|
243
|
+
config.tool_rag.skip_unlimited_providers = skipUnlimitedProviders;
|
|
244
|
+
}
|
|
245
|
+
const raw = readRawConfig(deps.configPath);
|
|
246
|
+
setNestedValue(raw, "tool_rag.enabled", config.tool_rag.enabled);
|
|
247
|
+
setNestedValue(raw, "tool_rag.top_k", config.tool_rag.top_k);
|
|
248
|
+
setNestedValue(raw, "tool_rag.always_include", config.tool_rag.always_include);
|
|
249
|
+
setNestedValue(
|
|
250
|
+
raw,
|
|
251
|
+
"tool_rag.skip_unlimited_providers",
|
|
252
|
+
config.tool_rag.skip_unlimited_providers
|
|
253
|
+
);
|
|
254
|
+
writeRawConfig(raw, deps.configPath);
|
|
227
255
|
const toolIndex = deps.toolRegistry.getToolIndex();
|
|
228
256
|
const response = {
|
|
229
257
|
success: true,
|
|
@@ -231,7 +259,9 @@ function createToolsRoutes(deps) {
|
|
|
231
259
|
enabled: config.tool_rag.enabled,
|
|
232
260
|
indexed: toolIndex?.isIndexed ?? false,
|
|
233
261
|
topK: config.tool_rag.top_k,
|
|
234
|
-
totalTools: deps.toolRegistry.count
|
|
262
|
+
totalTools: deps.toolRegistry.count,
|
|
263
|
+
alwaysInclude: config.tool_rag.always_include,
|
|
264
|
+
skipUnlimitedProviders: config.tool_rag.skip_unlimited_providers
|
|
235
265
|
}
|
|
236
266
|
};
|
|
237
267
|
return c.json(response);
|
|
@@ -509,6 +539,69 @@ function createMemoryRoutes(deps) {
|
|
|
509
539
|
return c.json(response, 500);
|
|
510
540
|
}
|
|
511
541
|
});
|
|
542
|
+
app.get("/sources/:sourceKey", (c) => {
|
|
543
|
+
try {
|
|
544
|
+
const sourceKey = decodeURIComponent(c.req.param("sourceKey"));
|
|
545
|
+
const rows = deps.memory.db.prepare(
|
|
546
|
+
`
|
|
547
|
+
SELECT id, text, source, path, start_line, end_line, updated_at
|
|
548
|
+
FROM knowledge
|
|
549
|
+
WHERE COALESCE(path, source) = ?
|
|
550
|
+
ORDER BY start_line ASC, updated_at DESC
|
|
551
|
+
`
|
|
552
|
+
).all(sourceKey);
|
|
553
|
+
const chunks = rows.map((row) => ({
|
|
554
|
+
id: row.id,
|
|
555
|
+
text: row.text,
|
|
556
|
+
source: row.path || row.source,
|
|
557
|
+
startLine: row.start_line,
|
|
558
|
+
endLine: row.end_line,
|
|
559
|
+
updatedAt: row.updated_at
|
|
560
|
+
}));
|
|
561
|
+
const response = {
|
|
562
|
+
success: true,
|
|
563
|
+
data: chunks
|
|
564
|
+
};
|
|
565
|
+
return c.json(response);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
const response = {
|
|
568
|
+
success: false,
|
|
569
|
+
error: getErrorMessage(error)
|
|
570
|
+
};
|
|
571
|
+
return c.json(response, 500);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
app.get("/sources", (c) => {
|
|
575
|
+
try {
|
|
576
|
+
const rows = deps.memory.db.prepare(
|
|
577
|
+
`
|
|
578
|
+
SELECT
|
|
579
|
+
COALESCE(path, source) AS source_key,
|
|
580
|
+
COUNT(*) AS entry_count,
|
|
581
|
+
MAX(updated_at) AS last_updated
|
|
582
|
+
FROM knowledge
|
|
583
|
+
GROUP BY source_key
|
|
584
|
+
ORDER BY last_updated DESC
|
|
585
|
+
`
|
|
586
|
+
).all();
|
|
587
|
+
const sources = rows.map((row) => ({
|
|
588
|
+
source: row.source_key,
|
|
589
|
+
entryCount: row.entry_count,
|
|
590
|
+
lastUpdated: row.last_updated
|
|
591
|
+
}));
|
|
592
|
+
const response = {
|
|
593
|
+
success: true,
|
|
594
|
+
data: sources
|
|
595
|
+
};
|
|
596
|
+
return c.json(response);
|
|
597
|
+
} catch (error) {
|
|
598
|
+
const response = {
|
|
599
|
+
success: false,
|
|
600
|
+
error: getErrorMessage(error)
|
|
601
|
+
};
|
|
602
|
+
return c.json(response, 500);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
512
605
|
return app;
|
|
513
606
|
}
|
|
514
607
|
|
|
@@ -750,6 +843,16 @@ function errorResponse(c, error, status = 500) {
|
|
|
750
843
|
const response = { success: false, error: message };
|
|
751
844
|
return c.json(response, code);
|
|
752
845
|
}
|
|
846
|
+
var IMAGE_MIME_TYPES = {
|
|
847
|
+
".png": "image/png",
|
|
848
|
+
".jpg": "image/jpeg",
|
|
849
|
+
".jpeg": "image/jpeg",
|
|
850
|
+
".gif": "image/gif",
|
|
851
|
+
".webp": "image/webp",
|
|
852
|
+
".svg": "image/svg+xml",
|
|
853
|
+
".bmp": "image/bmp",
|
|
854
|
+
".ico": "image/x-icon"
|
|
855
|
+
};
|
|
753
856
|
function getWorkspaceStats(dir) {
|
|
754
857
|
let files = 0;
|
|
755
858
|
let size = 0;
|
|
@@ -822,6 +925,45 @@ function createWorkspaceRoutes(_deps) {
|
|
|
822
925
|
return errorResponse(c, error);
|
|
823
926
|
}
|
|
824
927
|
});
|
|
928
|
+
app.get("/raw", (c) => {
|
|
929
|
+
try {
|
|
930
|
+
const path = c.req.query("path");
|
|
931
|
+
if (!path) {
|
|
932
|
+
const response = { success: false, error: "Missing 'path' query parameter" };
|
|
933
|
+
return c.json(response, 400);
|
|
934
|
+
}
|
|
935
|
+
const validated = validateReadPath(path);
|
|
936
|
+
const mime = IMAGE_MIME_TYPES[validated.extension];
|
|
937
|
+
if (!mime) {
|
|
938
|
+
const response = {
|
|
939
|
+
success: false,
|
|
940
|
+
error: "Unsupported file type for raw preview"
|
|
941
|
+
};
|
|
942
|
+
return c.json(response, 415);
|
|
943
|
+
}
|
|
944
|
+
const stats = statSync(validated.absolutePath);
|
|
945
|
+
if (stats.size > 5 * 1024 * 1024) {
|
|
946
|
+
const response = {
|
|
947
|
+
success: false,
|
|
948
|
+
error: "Image too large for preview (max 5MB)"
|
|
949
|
+
};
|
|
950
|
+
return c.json(response, 413);
|
|
951
|
+
}
|
|
952
|
+
const buffer = readFileSync2(validated.absolutePath);
|
|
953
|
+
const headers = {
|
|
954
|
+
"Content-Type": mime,
|
|
955
|
+
"Content-Length": String(buffer.byteLength),
|
|
956
|
+
"Content-Disposition": "inline",
|
|
957
|
+
"Cache-Control": "private, max-age=60"
|
|
958
|
+
};
|
|
959
|
+
if (validated.extension === ".svg") {
|
|
960
|
+
headers["Content-Security-Policy"] = "sandbox";
|
|
961
|
+
}
|
|
962
|
+
return c.body(buffer, 200, headers);
|
|
963
|
+
} catch (error) {
|
|
964
|
+
return errorResponse(c, error);
|
|
965
|
+
}
|
|
966
|
+
});
|
|
825
967
|
app.get("/read", (c) => {
|
|
826
968
|
try {
|
|
827
969
|
const path = c.req.query("path");
|
|
@@ -960,6 +1102,7 @@ function createWorkspaceRoutes(_deps) {
|
|
|
960
1102
|
// src/webui/routes/tasks.ts
|
|
961
1103
|
import { Hono as Hono9 } from "hono";
|
|
962
1104
|
var VALID_STATUSES = ["pending", "in_progress", "done", "failed", "cancelled"];
|
|
1105
|
+
var TERMINAL_STATUSES = ["done", "failed", "cancelled"];
|
|
963
1106
|
function createTasksRoutes(deps) {
|
|
964
1107
|
const app = new Hono9();
|
|
965
1108
|
function store() {
|
|
@@ -1032,6 +1175,32 @@ function createTasksRoutes(deps) {
|
|
|
1032
1175
|
return c.json(response, 500);
|
|
1033
1176
|
}
|
|
1034
1177
|
});
|
|
1178
|
+
app.post("/clean", async (c) => {
|
|
1179
|
+
try {
|
|
1180
|
+
const body = await c.req.json().catch(() => ({ status: void 0 }));
|
|
1181
|
+
const status = body.status;
|
|
1182
|
+
if (!status || !TERMINAL_STATUSES.includes(status)) {
|
|
1183
|
+
const response2 = {
|
|
1184
|
+
success: false,
|
|
1185
|
+
error: `Invalid status. Must be one of: ${TERMINAL_STATUSES.join(", ")}`
|
|
1186
|
+
};
|
|
1187
|
+
return c.json(response2, 400);
|
|
1188
|
+
}
|
|
1189
|
+
const tasks = store().listTasks({ status });
|
|
1190
|
+
let deleted = 0;
|
|
1191
|
+
for (const t of tasks) {
|
|
1192
|
+
if (store().deleteTask(t.id)) deleted++;
|
|
1193
|
+
}
|
|
1194
|
+
const response = { success: true, data: { deleted } };
|
|
1195
|
+
return c.json(response);
|
|
1196
|
+
} catch (error) {
|
|
1197
|
+
const response = {
|
|
1198
|
+
success: false,
|
|
1199
|
+
error: getErrorMessage(error)
|
|
1200
|
+
};
|
|
1201
|
+
return c.json(response, 500);
|
|
1202
|
+
}
|
|
1203
|
+
});
|
|
1035
1204
|
app.post("/clean-done", (c) => {
|
|
1036
1205
|
try {
|
|
1037
1206
|
const doneTasks = store().listTasks({ status: "done" });
|
|
@@ -1077,17 +1246,21 @@ function createConfigRoutes(deps) {
|
|
|
1077
1246
|
try {
|
|
1078
1247
|
const raw = readRawConfig(deps.configPath);
|
|
1079
1248
|
const data = Object.entries(CONFIGURABLE_KEYS).map(([key, meta]) => {
|
|
1080
|
-
const
|
|
1081
|
-
const isSet =
|
|
1249
|
+
const rawValue = getNestedValue(raw, key);
|
|
1250
|
+
const isSet = rawValue != null && rawValue !== "" && !(Array.isArray(rawValue) && rawValue.length === 0);
|
|
1251
|
+
const displayValue = isSet ? meta.type === "array" ? JSON.stringify(rawValue) : meta.mask(String(rawValue)) : null;
|
|
1082
1252
|
return {
|
|
1083
1253
|
key,
|
|
1254
|
+
label: meta.label,
|
|
1084
1255
|
set: isSet,
|
|
1085
|
-
value:
|
|
1256
|
+
value: displayValue,
|
|
1086
1257
|
sensitive: meta.sensitive,
|
|
1087
1258
|
type: meta.type,
|
|
1088
1259
|
category: meta.category,
|
|
1089
1260
|
description: meta.description,
|
|
1090
|
-
...meta.options ? { options: meta.options } : {}
|
|
1261
|
+
...meta.options ? { options: meta.options } : {},
|
|
1262
|
+
...meta.optionLabels ? { optionLabels: meta.optionLabels } : {},
|
|
1263
|
+
...meta.itemType ? { itemType: meta.itemType } : {}
|
|
1091
1264
|
};
|
|
1092
1265
|
});
|
|
1093
1266
|
const response = { success: true, data };
|
|
@@ -1119,6 +1292,55 @@ function createConfigRoutes(deps) {
|
|
|
1119
1292
|
return c.json({ success: false, error: "Invalid JSON body" }, 400);
|
|
1120
1293
|
}
|
|
1121
1294
|
const value = body.value;
|
|
1295
|
+
if (meta.type === "array") {
|
|
1296
|
+
if (!Array.isArray(value)) {
|
|
1297
|
+
return c.json(
|
|
1298
|
+
{ success: false, error: "Value must be an array for array keys" },
|
|
1299
|
+
400
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
for (let i = 0; i < value.length; i++) {
|
|
1303
|
+
const itemStr = String(value[i]);
|
|
1304
|
+
const itemErr = meta.validate(itemStr);
|
|
1305
|
+
if (itemErr) {
|
|
1306
|
+
return c.json(
|
|
1307
|
+
{
|
|
1308
|
+
success: false,
|
|
1309
|
+
error: `Invalid item at index ${i} for ${key}: ${itemErr}`
|
|
1310
|
+
},
|
|
1311
|
+
400
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
try {
|
|
1316
|
+
const parsed = value.map((item) => meta.parse(String(item)));
|
|
1317
|
+
const raw = readRawConfig(deps.configPath);
|
|
1318
|
+
setNestedValue(raw, key, parsed);
|
|
1319
|
+
writeRawConfig(raw, deps.configPath);
|
|
1320
|
+
const runtimeConfig = deps.agent.getConfig();
|
|
1321
|
+
setNestedValue(runtimeConfig, key, parsed);
|
|
1322
|
+
const result = {
|
|
1323
|
+
key,
|
|
1324
|
+
label: meta.label,
|
|
1325
|
+
set: parsed.length > 0,
|
|
1326
|
+
value: JSON.stringify(parsed),
|
|
1327
|
+
sensitive: meta.sensitive,
|
|
1328
|
+
type: meta.type,
|
|
1329
|
+
category: meta.category,
|
|
1330
|
+
description: meta.description,
|
|
1331
|
+
...meta.itemType ? { itemType: meta.itemType } : {}
|
|
1332
|
+
};
|
|
1333
|
+
return c.json({ success: true, data: result });
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
return c.json(
|
|
1336
|
+
{
|
|
1337
|
+
success: false,
|
|
1338
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1339
|
+
},
|
|
1340
|
+
500
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1122
1344
|
if (value == null || typeof value !== "string") {
|
|
1123
1345
|
return c.json(
|
|
1124
1346
|
{ success: false, error: "Missing or invalid 'value' field" },
|
|
@@ -1136,11 +1358,24 @@ function createConfigRoutes(deps) {
|
|
|
1136
1358
|
const parsed = meta.parse(value);
|
|
1137
1359
|
const raw = readRawConfig(deps.configPath);
|
|
1138
1360
|
setNestedValue(raw, key, parsed);
|
|
1361
|
+
if (key === "telegram.owner_id" && typeof parsed === "number") {
|
|
1362
|
+
const adminIds = getNestedValue(raw, "telegram.admin_ids") ?? [];
|
|
1363
|
+
if (!adminIds.includes(parsed)) {
|
|
1364
|
+
setNestedValue(raw, "telegram.admin_ids", [...adminIds, parsed]);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1139
1367
|
writeRawConfig(raw, deps.configPath);
|
|
1140
1368
|
const runtimeConfig = deps.agent.getConfig();
|
|
1141
1369
|
setNestedValue(runtimeConfig, key, parsed);
|
|
1370
|
+
if (key === "telegram.owner_id" && typeof parsed === "number") {
|
|
1371
|
+
const rtAdminIds = getNestedValue(runtimeConfig, "telegram.admin_ids") ?? [];
|
|
1372
|
+
if (!rtAdminIds.includes(parsed)) {
|
|
1373
|
+
setNestedValue(runtimeConfig, "telegram.admin_ids", [...rtAdminIds, parsed]);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1142
1376
|
const result = {
|
|
1143
1377
|
key,
|
|
1378
|
+
label: meta.label,
|
|
1144
1379
|
set: true,
|
|
1145
1380
|
value: meta.mask(value),
|
|
1146
1381
|
sensitive: meta.sensitive,
|
|
@@ -1178,13 +1413,15 @@ function createConfigRoutes(deps) {
|
|
|
1178
1413
|
deleteNestedValue(runtimeConfig, key);
|
|
1179
1414
|
const result = {
|
|
1180
1415
|
key,
|
|
1416
|
+
label: meta.label,
|
|
1181
1417
|
set: false,
|
|
1182
1418
|
value: null,
|
|
1183
1419
|
sensitive: meta.sensitive,
|
|
1184
1420
|
type: meta.type,
|
|
1185
1421
|
category: meta.category,
|
|
1186
1422
|
description: meta.description,
|
|
1187
|
-
...meta.options ? { options: meta.options } : {}
|
|
1423
|
+
...meta.options ? { options: meta.options } : {},
|
|
1424
|
+
...meta.itemType ? { itemType: meta.itemType } : {}
|
|
1188
1425
|
};
|
|
1189
1426
|
return c.json({ success: true, data: result });
|
|
1190
1427
|
} catch (err) {
|
|
@@ -1194,6 +1431,51 @@ function createConfigRoutes(deps) {
|
|
|
1194
1431
|
);
|
|
1195
1432
|
}
|
|
1196
1433
|
});
|
|
1434
|
+
app.get("/models/:provider", (c) => {
|
|
1435
|
+
const provider = c.req.param("provider");
|
|
1436
|
+
const models = getModelsForProvider(provider);
|
|
1437
|
+
return c.json({ success: true, data: models });
|
|
1438
|
+
});
|
|
1439
|
+
app.get("/provider-meta/:provider", (c) => {
|
|
1440
|
+
const provider = c.req.param("provider");
|
|
1441
|
+
try {
|
|
1442
|
+
const meta = getProviderMetadata(provider);
|
|
1443
|
+
const needsKey = provider !== "claude-code" && provider !== "cocoon" && provider !== "local";
|
|
1444
|
+
return c.json({
|
|
1445
|
+
success: true,
|
|
1446
|
+
data: {
|
|
1447
|
+
needsKey,
|
|
1448
|
+
keyHint: meta.keyHint,
|
|
1449
|
+
keyPrefix: meta.keyPrefix,
|
|
1450
|
+
consoleUrl: meta.consoleUrl,
|
|
1451
|
+
displayName: meta.displayName
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
} catch (err) {
|
|
1455
|
+
return c.json(
|
|
1456
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
1457
|
+
400
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
});
|
|
1461
|
+
app.post("/validate-api-key", async (c) => {
|
|
1462
|
+
try {
|
|
1463
|
+
const body = await c.req.json();
|
|
1464
|
+
if (!body.provider || !body.apiKey) {
|
|
1465
|
+
return c.json({ success: false, error: "Missing provider or apiKey" }, 400);
|
|
1466
|
+
}
|
|
1467
|
+
const error = validateApiKeyFormat(body.provider, body.apiKey);
|
|
1468
|
+
return c.json({
|
|
1469
|
+
success: true,
|
|
1470
|
+
data: { valid: !error, error: error ?? null }
|
|
1471
|
+
});
|
|
1472
|
+
} catch (err) {
|
|
1473
|
+
return c.json(
|
|
1474
|
+
{ success: false, error: err instanceof Error ? err.message : String(err) },
|
|
1475
|
+
400
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1197
1479
|
return app;
|
|
1198
1480
|
}
|
|
1199
1481
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getModelsForProvider
|
|
3
|
+
} from "./chunk-QOQWUUA4.js";
|
|
1
4
|
import {
|
|
2
5
|
ConfigSchema,
|
|
3
6
|
DealsConfigSchema,
|
|
@@ -8,7 +11,7 @@ import {
|
|
|
8
11
|
isNewWorkspace,
|
|
9
12
|
saveWallet,
|
|
10
13
|
walletExists
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BGC2IUM5.js";
|
|
12
15
|
import {
|
|
13
16
|
getClaudeCodeApiKey,
|
|
14
17
|
isClaudeCodeTokenValid
|
|
@@ -285,111 +288,6 @@ var TelegramAuthManager = class {
|
|
|
285
288
|
|
|
286
289
|
// src/webui/routes/setup.ts
|
|
287
290
|
var log2 = createLogger("Setup");
|
|
288
|
-
var MODEL_OPTIONS = {
|
|
289
|
-
anthropic: [
|
|
290
|
-
{
|
|
291
|
-
value: "claude-opus-4-6",
|
|
292
|
-
name: "Claude Opus 4.6",
|
|
293
|
-
description: "Most capable, 1M ctx, $5/M"
|
|
294
|
-
},
|
|
295
|
-
{
|
|
296
|
-
value: "claude-opus-4-5-20251101",
|
|
297
|
-
name: "Claude Opus 4.5",
|
|
298
|
-
description: "Previous gen, 200K ctx, $5/M"
|
|
299
|
-
},
|
|
300
|
-
{ value: "claude-sonnet-4-0", name: "Claude Sonnet 4", description: "Balanced, $3/M" },
|
|
301
|
-
{
|
|
302
|
-
value: "claude-haiku-4-5-20251001",
|
|
303
|
-
name: "Claude Haiku 4.5",
|
|
304
|
-
description: "Fast & cheap, $1/M"
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
value: "claude-haiku-4-5-20251001",
|
|
308
|
-
name: "Claude Haiku 4.5",
|
|
309
|
-
description: "Fast & cheap, $1/M"
|
|
310
|
-
}
|
|
311
|
-
],
|
|
312
|
-
openai: [
|
|
313
|
-
{ value: "gpt-5", name: "GPT-5", description: "Most capable, 400K ctx, $1.25/M" },
|
|
314
|
-
{ value: "gpt-4o", name: "GPT-4o", description: "Balanced, 128K ctx, $2.50/M" },
|
|
315
|
-
{ value: "gpt-4.1", name: "GPT-4.1", description: "1M ctx, $2/M" },
|
|
316
|
-
{ value: "gpt-4.1-mini", name: "GPT-4.1 Mini", description: "1M ctx, cheap, $0.40/M" },
|
|
317
|
-
{ value: "o3", name: "o3", description: "Reasoning, 200K ctx, $2/M" }
|
|
318
|
-
],
|
|
319
|
-
google: [
|
|
320
|
-
{ value: "gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "Fast, 1M ctx, $0.30/M" },
|
|
321
|
-
{
|
|
322
|
-
value: "gemini-2.5-pro",
|
|
323
|
-
name: "Gemini 2.5 Pro",
|
|
324
|
-
description: "Most capable, 1M ctx, $1.25/M"
|
|
325
|
-
},
|
|
326
|
-
{ value: "gemini-2.0-flash", name: "Gemini 2.0 Flash", description: "Cheap, 1M ctx, $0.10/M" }
|
|
327
|
-
],
|
|
328
|
-
xai: [
|
|
329
|
-
{ value: "grok-4-fast", name: "Grok 4 Fast", description: "Vision, 2M ctx, $0.20/M" },
|
|
330
|
-
{ value: "grok-4", name: "Grok 4", description: "Reasoning, 256K ctx, $3/M" },
|
|
331
|
-
{ value: "grok-3", name: "Grok 3", description: "Stable, 131K ctx, $3/M" }
|
|
332
|
-
],
|
|
333
|
-
groq: [
|
|
334
|
-
{
|
|
335
|
-
value: "meta-llama/llama-4-maverick-17b-128e-instruct",
|
|
336
|
-
name: "Llama 4 Maverick",
|
|
337
|
-
description: "Vision, 131K ctx, $0.20/M"
|
|
338
|
-
},
|
|
339
|
-
{ value: "qwen/qwen3-32b", name: "Qwen3 32B", description: "Reasoning, 131K ctx, $0.29/M" },
|
|
340
|
-
{
|
|
341
|
-
value: "deepseek-r1-distill-llama-70b",
|
|
342
|
-
name: "DeepSeek R1 70B",
|
|
343
|
-
description: "Reasoning, 131K ctx, $0.75/M"
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
value: "llama-3.3-70b-versatile",
|
|
347
|
-
name: "Llama 3.3 70B",
|
|
348
|
-
description: "General purpose, 131K ctx, $0.59/M"
|
|
349
|
-
}
|
|
350
|
-
],
|
|
351
|
-
openrouter: [
|
|
352
|
-
{ value: "anthropic/claude-opus-4.5", name: "Claude Opus 4.5", description: "200K ctx, $5/M" },
|
|
353
|
-
{ value: "openai/gpt-5", name: "GPT-5", description: "400K ctx, $1.25/M" },
|
|
354
|
-
{ value: "google/gemini-2.5-flash", name: "Gemini 2.5 Flash", description: "1M ctx, $0.30/M" },
|
|
355
|
-
{
|
|
356
|
-
value: "deepseek/deepseek-r1",
|
|
357
|
-
name: "DeepSeek R1",
|
|
358
|
-
description: "Reasoning, 64K ctx, $0.70/M"
|
|
359
|
-
},
|
|
360
|
-
{ value: "x-ai/grok-4", name: "Grok 4", description: "256K ctx, $3/M" }
|
|
361
|
-
],
|
|
362
|
-
moonshot: [
|
|
363
|
-
{ value: "kimi-k2.5", name: "Kimi K2.5", description: "Free, 256K ctx, multimodal" },
|
|
364
|
-
{
|
|
365
|
-
value: "kimi-k2-thinking",
|
|
366
|
-
name: "Kimi K2 Thinking",
|
|
367
|
-
description: "Free, 256K ctx, reasoning"
|
|
368
|
-
}
|
|
369
|
-
],
|
|
370
|
-
mistral: [
|
|
371
|
-
{
|
|
372
|
-
value: "devstral-small-2507",
|
|
373
|
-
name: "Devstral Small",
|
|
374
|
-
description: "Coding, 128K ctx, $0.10/M"
|
|
375
|
-
},
|
|
376
|
-
{
|
|
377
|
-
value: "devstral-medium-latest",
|
|
378
|
-
name: "Devstral Medium",
|
|
379
|
-
description: "Coding, 262K ctx, $0.40/M"
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
value: "mistral-large-latest",
|
|
383
|
-
name: "Mistral Large",
|
|
384
|
-
description: "General, 128K ctx, $2/M"
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
value: "magistral-small",
|
|
388
|
-
name: "Magistral Small",
|
|
389
|
-
description: "Reasoning, 128K ctx, $0.50/M"
|
|
390
|
-
}
|
|
391
|
-
]
|
|
392
|
-
};
|
|
393
291
|
function maskKey(key) {
|
|
394
292
|
if (key.length <= 10) return "***";
|
|
395
293
|
return key.slice(0, 6) + "..." + key.slice(-4);
|
|
@@ -446,8 +344,7 @@ function createSetupRoutes() {
|
|
|
446
344
|
});
|
|
447
345
|
app.get("/models/:provider", (c) => {
|
|
448
346
|
const provider = c.req.param("provider");
|
|
449
|
-
const
|
|
450
|
-
const models = MODEL_OPTIONS[modelKey] || [];
|
|
347
|
+
const models = getModelsForProvider(provider);
|
|
451
348
|
const result = [
|
|
452
349
|
...models,
|
|
453
350
|
{
|
|
@@ -760,7 +657,6 @@ function createSetupRoutes() {
|
|
|
760
657
|
},
|
|
761
658
|
storage: {
|
|
762
659
|
sessions_file: `${workspace.root}/sessions.json`,
|
|
763
|
-
pairing_file: `${workspace.root}/pairing.json`,
|
|
764
660
|
memory_file: `${workspace.root}/memory.json`,
|
|
765
661
|
history_limit: 100
|
|
766
662
|
},
|
|
@@ -779,7 +675,7 @@ function createSetupRoutes() {
|
|
|
779
675
|
logging: { level: "info", pretty: true },
|
|
780
676
|
dev: { hot_reload: false },
|
|
781
677
|
tool_rag: {
|
|
782
|
-
enabled:
|
|
678
|
+
enabled: false,
|
|
783
679
|
top_k: 25,
|
|
784
680
|
always_include: [
|
|
785
681
|
"telegram_send_message",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{box-sizing:border-box;margin:0;padding:0}:root{color-scheme:dark;--bg: #000000;--surface: rgba(255, 255, 255, .05);--surface-hover: rgba(255, 255, 255, .08);--surface-active: rgba(255, 255, 255, .12);--glass: rgba(255, 255, 255, .06);--glass-border: rgba(255, 255, 255, .1);--glass-border-strong: rgba(255, 255, 255, .15);--text: rgba(255, 255, 255, .92);--text-secondary: rgba(255, 255, 255, .55);--text-tertiary: rgba(255, 255, 255, .5);--text-on-accent: #ffffff;--accent: #0A84FF;--accent-dim: rgba(10, 132, 255, .15);--green: #30D158;--green-dim: rgba(48, 209, 88, .15);--orange: rgba(255, 255, 255, .55);--orange-dim: rgba(255, 255, 255, .06);--red: #FF453A;--red-dim: rgba(255, 69, 58, .15);--purple: #BF5AF2;--purple-dim: rgba(191, 90, 242, .15);--cyan: #64D2FF;--cyan-dim: rgba(100, 210, 255, .15);--separator: rgba(255, 255, 255, .08);--sidebar-bg: rgba(255, 255, 255, .03);--scrollbar: rgba(255, 255, 255, .1);--scrollbar-hover: rgba(255, 255, 255, .2);--shadow-sm: 0 1px 3px rgba(0, 0, 0, .3);--thumb-bg: #ffffff;--radius-sm: 10px;--radius-md: 14px;--radius-lg: 20px;--radius-xl: 26px;--font-xs: 11px;--font-sm: 12px;--font-md: 13px;--font-base: 14px;--font-lg: 16px;--font-xl: 20px;--font-mono: "SF Mono", "Fira Code", "Cascadia Code", monospace;--space-xs: 4px;--space-sm: 8px;--space-md: 12px;--space-lg: 16px;--space-xl: 24px;--space-2xl: 32px;--blur: 40px;--blur-heavy: 80px}html,body{height:100%}body{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;background:var(--bg);color:var(--text);line-height:1.5;font-size:14px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#root{min-height:100vh}.container{display:flex;min-height:100vh}.sidebar{width:220px;padding:20px 12px;background:var(--sidebar-bg);border-right:1px solid var(--separator);display:flex;flex-direction:column;gap:4px;position:sticky;top:0;height:100vh;overflow-y:auto}.sidebar-brand{padding:4px 12px 20px;font-size:15px;font-weight:600;letter-spacing:-.2px;color:var(--text)}.sidebar nav{display:flex;flex-direction:column;gap:2px}.sidebar a{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--radius-sm);color:var(--text-secondary);text-decoration:none;font-size:13px;font-weight:500;transition:all .2s ease}.sidebar a:hover{color:var(--text);background:var(--surface);text-decoration:none}.sidebar a.active{color:var(--text);background:var(--surface-hover);text-decoration:none}.sidebar-link-disabled{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--radius-sm);color:var(--text-tertiary);font-size:13px;font-weight:500;opacity:.4;cursor:default;-webkit-user-select:none;user-select:none}.main{flex:1;padding:32px;max-width:1080px;min-width:0;margin:0 auto}.header{margin-bottom:28px}.header h1{font-size:22px;font-weight:600;letter-spacing:-.4px;margin-bottom:4px}.header p{color:var(--text-secondary);font-size:13px}.card{background:var(--glass);backdrop-filter:blur(var(--blur)) saturate(180%);-webkit-backdrop-filter:blur(var(--blur)) saturate(180%);border:1px solid var(--glass-border);border-radius:var(--radius-lg);padding:20px;margin-bottom:16px}.card h2{font-size:15px;font-weight:600;letter-spacing:-.2px}.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:20px}.stat-card{background:var(--glass);backdrop-filter:blur(var(--blur)) saturate(180%);-webkit-backdrop-filter:blur(var(--blur)) saturate(180%);border:1px solid var(--glass-border);border-radius:var(--radius-md);padding:16px}.stat-card h3{font-size:12px;font-weight:500;color:var(--text-secondary);margin-bottom:6px;text-transform:uppercase;letter-spacing:.5px}.stat-card .value{font-size:24px;font-weight:600;letter-spacing:-.5px}button{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;background:var(--accent);color:var(--text-on-accent);border:none;padding:8px 16px;border-radius:var(--radius-sm);cursor:pointer;font-size:13px;font-weight:500;transition:opacity .15s ease}button:hover{opacity:.85}button:disabled{opacity:.4;cursor:not-allowed}input,textarea,select{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;background:var(--surface);border:1px solid var(--glass-border);color:var(--text);padding:10px 14px;border-radius:var(--radius-sm);font-size:13px;outline:none;transition:border-color .2s ease}select{-moz-appearance:none;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.55)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 12px center;padding-right:36px;cursor:pointer}.custom-select{position:relative}.custom-select-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;background:var(--surface);border:1px solid var(--glass-border);color:var(--text);padding:10px 14px;border-radius:var(--radius-sm);font-size:13px;font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;cursor:pointer;transition:border-color .2s ease}.custom-select-trigger:hover{border-color:var(--glass-border-strong);opacity:1}.custom-select-trigger:focus{border-color:var(--accent)}.custom-select-trigger svg{color:var(--text-secondary);flex-shrink:0}.custom-select-menu{background:var(--bg);border:1px solid var(--glass-border-strong);border-radius:var(--radius-sm);padding:4px;z-index:10000;box-shadow:0 8px 24px #00000080;max-height:200px;overflow-y:auto}.custom-select-option{padding:8px 12px;border-radius:6px;font-size:13px;color:var(--text-secondary);cursor:pointer;transition:all .1s ease}.custom-select-option:hover,.custom-select-option.focused,.custom-select-option.active{background:var(--surface-hover);color:var(--text)}.custom-select-option.active.focused{background:var(--surface-active);color:var(--text)}input:focus,textarea:focus,select:focus{border-color:var(--accent)}input::placeholder,textarea::placeholder{color:var(--text-tertiary)}textarea{width:100%;min-height:400px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:13px;line-height:1.6;resize:vertical;border-radius:var(--radius-md)}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:none;opacity:.8}.badge{display:inline-flex;align-items:center;padding:2px 7px;border-radius:4px;font-size:11px;font-weight:500;letter-spacing:.2px;background:var(--surface);color:var(--text-secondary);border:1px solid var(--separator)}.badge.count{color:var(--text)}.badge.warn{color:var(--text-secondary);border-color:#ffffff1f}.badge.error{color:var(--red);border-color:color-mix(in srgb,var(--red) 30%,transparent)}.badge.always{color:var(--green);border-color:color-mix(in srgb,var(--green) 30%,transparent)}.tabs{display:flex;gap:2px;padding:3px;background:var(--surface);border:1px solid var(--glass-border);border-radius:var(--radius-sm);margin-bottom:16px}.tab{position:relative;padding:7px 16px;background:none;border:none;color:var(--text-secondary);cursor:pointer;border-radius:8px;font-size:13px;font-weight:500;transition:all .2s ease;flex:1;text-align:center}.tab:hover{color:var(--text);opacity:1}.tab.active{color:var(--text);background:var(--surface-active);box-shadow:0 1px 3px #0003}.tab .tab-count{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;margin-left:6px;border-radius:9px;font-size:11px;font-weight:600;background:var(--glass);color:var(--text-tertiary)}.tab.active .tab-count{background:var(--surface-active);color:var(--text)}button.btn-ghost{background:var(--surface);color:var(--text-secondary);border:1px solid var(--glass-border)}button.btn-ghost:hover{background:var(--surface-hover);color:var(--text);opacity:1}button.btn-danger{background:var(--surface);color:var(--text);border:1px solid var(--glass-border)}button.btn-danger:hover{background:var(--surface-hover);opacity:1}button.btn-sm{padding:5px 10px;font-size:12px;border-radius:8px}.tag-pill{display:inline-flex;align-items:center;padding:3px 9px;border-radius:12px;font-size:11px;font-weight:500;background:var(--surface);color:var(--text-secondary);border:1px solid var(--glass-border);cursor:pointer;transition:all .15s ease}.tag-pill:hover,.tag-pill.active{background:var(--surface-hover);color:var(--text);border-color:var(--glass-border-strong)}.form-group{margin-bottom:16px}.form-group label:not(.label-inline):not(.card-toggle):not(.toggle){display:block;margin-bottom:6px;font-size:13px;font-weight:500;color:var(--text)}.alert{padding:10px 14px;border-radius:var(--radius-sm);margin-bottom:16px;font-size:13px}.alert.success,.alert.error{background:#ffffff0a;color:var(--text-secondary);border:1px solid rgba(255,255,255,.08)}.file-row{transition:background-color .15s ease}.file-row:hover{background-color:var(--sidebar-bg)}.icon-button{background:none;border:none;cursor:pointer;padding:4px 6px;font-size:15px;opacity:.5;filter:grayscale(1);transition:opacity .15s,filter .15s}.icon-button:hover{opacity:1;filter:none}.log-entry{font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:12px;padding:5px 0;border-bottom:1px solid var(--separator);line-height:1.5}.log-entry:last-child{border-bottom:none}.accordion-header{position:relative;z-index:2;padding:14px 16px;cursor:pointer;display:flex;align-items:center;gap:12px;transition:background-color .15s ease}.accordion-header:hover{background-color:var(--sidebar-bg)}.accordion-chevron{font-size:10px;color:var(--text-secondary);width:12px;flex-shrink:0}.tool-row{position:relative;padding:10px 14px;background:var(--surface);border-radius:var(--radius-sm);display:flex;justify-content:space-between;align-items:center;transition:background .15s ease}.tool-row:hover{background:var(--surface-hover)}.tool-name{font-size:13px;font-weight:500;margin-bottom:2px}.tool-desc{font-size:12px;color:var(--text-secondary)}.plugin-meta{font-size:12px;color:var(--text-secondary);margin-bottom:8px}.result-item{padding:14px;background:var(--surface);border-radius:var(--radius-sm);margin-bottom:8px}.result-meta{font-size:12px;color:var(--text-secondary);margin-bottom:6px}.result-text{font-size:13px;line-height:1.6}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}.status-dot.connected{background:var(--green)}.status-dot.disconnected{background:var(--red)}.login-container{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:2rem}.login-card{background:var(--glass);backdrop-filter:blur(var(--blur)) saturate(180%);-webkit-backdrop-filter:blur(var(--blur)) saturate(180%);border:1px solid var(--glass-border);border-radius:var(--radius-xl);padding:32px;max-width:380px;width:100%}.login-card h1{font-size:20px;font-weight:600;margin-bottom:8px;letter-spacing:-.3px}.login-card p{color:var(--text-secondary);font-size:13px;margin-bottom:24px;line-height:1.5}.section-title{font-size:13px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:12px}.empty{color:var(--text-tertiary);font-size:13px;padding:20px 0;text-align:center}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--scrollbar);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-hover)}.scope-seg{display:inline-flex;padding:3px;background:var(--glass);border-radius:10px;gap:2px}.scope-seg button{padding:4px 10px;font-size:11px;font-weight:500;background:none;color:var(--text-tertiary);border:none;border-radius:7px;cursor:pointer;transition:all .2s ease}.scope-seg button:hover:not(:disabled):not(.active){color:var(--text-secondary);opacity:1}.scope-seg button.active{background:var(--surface-active);color:var(--text)}.scope-seg.lg{padding:4px;border-radius:12px;gap:4px;width:100%}.scope-seg.lg button{flex:1;padding:10px 20px;font-size:14px;font-weight:600;border-radius:8px}.scope-seg.disabled{opacity:.4;pointer-events:none}.toggle{position:relative;width:42px;height:26px;flex-shrink:0;cursor:pointer}.toggle input{opacity:0;width:0;height:0;position:absolute}.toggle-track{position:absolute;top:0;right:0;bottom:0;left:0;background:var(--scrollbar);border-radius:13px;transition:background .25s ease}.toggle input:checked+.toggle-track{background:var(--accent)}.toggle-thumb{position:absolute;top:3px;left:3px;width:20px;height:20px;background:var(--thumb-bg);border-radius:50%;transition:transform .25s cubic-bezier(.4,0,.2,1);box-shadow:var(--shadow-sm)}.toggle input:checked~.toggle-thumb{transform:translate(16px)}.toggle input:disabled+.toggle-track{opacity:.4}.toggle input:disabled~.toggle-thumb{opacity:.4}.modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.modal{background:var(--bg);border:1px solid var(--glass-border-strong);border-radius:var(--radius-lg);padding:24px;max-width:480px;width:90%;max-height:80vh;overflow-y:auto;box-shadow:0 16px 48px #00000080}.loading{color:var(--text-tertiary);font-size:13px;padding:40px 0;text-align:center}.setup-container{max-width:720px;margin:0 auto;padding:40px 24px;min-height:100vh}.setup-header{margin-bottom:32px}.setup-header h1{font-size:22px;font-weight:600;letter-spacing:-.4px;margin-bottom:8px}.setup-content{margin-top:28px}.setup-nav{display:flex;gap:10px;margin-top:20px;padding-top:16px;border-top:1px solid var(--separator);max-width:720px}.step-indicator{display:flex;align-items:flex-start;padding:16px 0;margin-bottom:12px;max-width:720px}.step-cell{display:flex;flex-direction:column;align-items:flex-start;flex:1;min-width:0;position:relative}.step-cell:last-child{flex:0 0 auto}.step-cell-top{display:flex;align-items:center;width:100%}.step-dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:600;flex-shrink:0;background:var(--surface);color:var(--text-tertiary);border:1px solid var(--glass-border);transition:all .2s ease}.step-dot.active{background:var(--surface-active);color:var(--text);border-color:var(--glass-border-strong)}.step-dot.completed{background:var(--green-dim);color:var(--green);border-color:#30d1584d}.step-line{flex:1;height:1px;background:var(--glass-border);margin:0 8px;min-width:8px}.step-line.completed{background:#30d1584d}.step-label{font-size:10px;color:var(--text-primary);opacity:.3;text-align:center;white-space:nowrap;margin-top:6px;width:28px;position:relative;left:0;transition:opacity .2s ease}.step-label{overflow:visible;width:max-content;transform:translate(calc(12px - 50%))}.step-label.active{opacity:1;font-weight:500;color:var(--accent)}.step-label.completed{opacity:.5}.provider-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}.provider-card{background:var(--surface);border:1px solid var(--glass-border);border-radius:var(--radius-md);padding:14px;cursor:pointer;transition:all .15s ease}.provider-card:hover{background:var(--surface-hover);border-color:var(--glass-border-strong)}.provider-card.selected{border-color:#ffffff4d;background:#ffffff14}.provider-card h3{font-size:13px;font-weight:600;margin-bottom:4px}.provider-card .provider-meta{font-size:11px;color:var(--text-secondary)}.mnemonic-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:6px;margin:12px 0;list-style:none;padding:0}.mnemonic-word{display:flex;align-items:center;gap:6px;padding:6px 8px;background:var(--surface);border-radius:6px;font-size:12px;font-family:SF Mono,Fira Code,monospace}.mnemonic-word .num{color:var(--text-tertiary);font-size:10px;min-width:16px}.guide-dropdown{margin-bottom:20px;border-radius:var(--radius-sm);border:1px solid rgba(255,255,255,.08);background:#ffffff08}.guide-dropdown summary{padding:10px 14px;font-size:13px;font-weight:500;color:var(--text);cursor:pointer;list-style:none;display:flex;align-items:center;gap:8px}.guide-dropdown summary::-webkit-details-marker{display:none}.guide-dropdown summary:before{content:"▶";font-size:9px;color:var(--text-tertiary);transition:transform .2s ease}.guide-dropdown[open] summary:before{transform:rotate(90deg)}.guide-dropdown summary:hover{color:var(--text)}.guide-content{padding:0 14px 14px;font-size:13px;line-height:1.6;color:var(--text-secondary);border-top:1px solid rgba(255,255,255,.06)}.guide-section{margin-top:12px}.guide-section strong{color:var(--text);font-size:12px;text-transform:uppercase;letter-spacing:.5px}.guide-section ol{margin:6px 0 0 20px;padding:0}.guide-section ol li{margin-bottom:4px}.guide-section p{margin:6px 0 0}.guide-section code{background:#ffffff14;padding:1px 5px;border-radius:3px;font-size:12px}.warning-card{padding:14px 16px;border-radius:var(--radius-sm);margin-bottom:16px;font-size:13px;line-height:1.6;background:#ffffff0a;color:var(--text-secondary);border:1px solid rgba(255,255,255,.08)}.warning-card strong{color:var(--text)}.info-panel{padding:12px 14px;border-radius:var(--radius-sm);margin-bottom:16px;font-size:13px;line-height:1.5;background:#ffffff0a;color:var(--text-secondary);border:1px solid rgba(255,255,255,.08)}.code-input{text-align:center;font-size:24px;font-weight:600;letter-spacing:8px;padding:12px 20px;max-width:200px;font-family:SF Mono,Fira Code,monospace}.step-title{font-size:var(--font-lg);font-weight:600;letter-spacing:-.2px;margin-bottom:var(--space-xs)}.step-description{font-size:var(--font-md);color:#ffffffbf;margin-bottom:var(--space-lg)}.helper-text{font-size:var(--font-sm);color:var(--text-secondary);margin-top:var(--space-xs)}.helper-text.error{color:var(--red)}.helper-text.success{color:var(--green)}.form-row{display:flex;align-items:center;gap:var(--space-sm)}.label-inline{display:flex;align-items:flex-start;gap:12px;cursor:pointer}.info-box{padding:var(--space-md) 14px;border-radius:var(--radius-sm);font-size:var(--font-md);line-height:1.5;background:var(--surface);color:var(--text-secondary);border:1px solid var(--separator);margin-bottom:var(--space-lg)}.code-block{display:inline-block;padding:10px 20px;background:var(--surface);border-radius:var(--radius-sm);font-size:var(--font-base);font-family:var(--font-mono)}.mono{font-family:var(--font-mono)}.text-center{text-align:center}.text-muted{color:var(--text-secondary)}.w-full{width:100%}.card-toggle{display:flex;align-items:center;justify-content:space-between}.card-toggle.open{margin-bottom:var(--space-md)}.module-list{display:flex;flex-direction:column}.module-item{padding:14px 0;border-bottom:1px solid var(--glass-border)}.module-item:first-child{padding-top:0}.module-item:last-child{border-bottom:none}.module-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.module-info{display:flex;flex-direction:column;gap:2px}.module-info strong{font-size:var(--font-md)}.module-desc{font-size:var(--font-sm);color:var(--text-tertiary)}.module-body{margin-top:var(--space-md);padding-top:var(--space-sm)}.review-list{display:flex;flex-direction:column;gap:var(--space-xs);font-size:var(--font-md)}.review-label{color:var(--text-secondary)}.review-unset{color:var(--text-tertiary);font-style:italic}.label-inline input[type=checkbox],.label-inline input[type=radio]{-moz-appearance:none;appearance:none;-webkit-appearance:none;width:18px;height:18px;padding:0;flex-shrink:0;border:1.5px solid var(--glass-border-strong);background:var(--surface);cursor:pointer;transition:all .15s ease;position:relative;margin-top:3px}.label-inline input[type=checkbox]{border-radius:5px}.label-inline input[type=radio]{border-radius:50%}.label-inline input[type=checkbox]:checked{background:var(--accent);border-color:var(--accent)}.label-inline input[type=checkbox]:checked:after{content:"";position:absolute;left:5px;top:2px;width:5px;height:9px;border:solid var(--text-on-accent);border-width:0 2px 2px 0;transform:rotate(45deg)}.label-inline input[type=radio]:checked{border-color:var(--accent);background:var(--surface)}.label-inline input[type=radio]:checked:after{content:"";position:absolute;top:4px;left:4px;width:8px;height:8px;border-radius:50%;background:var(--accent)}.label-inline input[type=checkbox]:focus-visible,.label-inline input[type=radio]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}button.btn-lg{padding:12px 24px;font-size:var(--font-base);font-weight:600}.step-content{animation:step-fade-in .15s ease-out;max-width:720px}@keyframes step-fade-in{0%{opacity:0}to{opacity:1}}.provider-switch-zone{padding:14px 16px;background:var(--surface);border:1px solid var(--glass-border-strong);border-radius:var(--radius-sm);animation:step-fade-in .15s ease-out}.spinner{display:inline-block;width:14px;height:14px;border:2px solid var(--glass-border);border-top-color:currentColor;border-radius:50%;animation:spin .6s linear infinite;vertical-align:middle}.spinner.sm{width:12px;height:12px;border-width:1.5px}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:768px){.container{flex-direction:column}.sidebar{width:100%;height:auto;position:relative;flex-direction:row;overflow-x:auto;padding:12px;border-right:none;border-bottom:1px solid var(--separator)}.sidebar-brand{padding:0 12px 0 4px}.sidebar-brand img{height:32px!important}.sidebar nav{flex-direction:row;gap:2px}.sidebar a{white-space:nowrap;padding:6px 10px}.step-indicator{padding:12px 0;margin-bottom:8px}.step-dot{width:22px;height:22px;font-size:9px}.step-label{font-size:8px}.main{padding:20px 16px}button{min-height:44px;padding:10px 16px}button.btn-sm,button.btn-ghost{min-height:36px}input,textarea,select,.custom-select-trigger{min-height:44px;font-size:16px}}.pill-bar{display:inline-flex;gap:var(--space-sm);padding:var(--space-xs);background:var(--surface);border:1px solid var(--glass-border);border-radius:var(--radius-md);margin-bottom:var(--space-xl);overflow-x:auto}.pill-bar button{padding:var(--space-sm) var(--space-lg);border-radius:var(--radius-sm);border:none;background:transparent;color:var(--text-secondary);font-size:var(--font-md);font-weight:500;cursor:pointer;white-space:nowrap;transition:all .15s ease}.pill-bar button:hover{color:var(--text);background:var(--surface-hover)}.pill-bar button.active{background:var(--accent);color:var(--text-on-accent)}
|