@kyma-api/agent 0.1.2 → 0.1.3
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/dist/main.js +125 -34
- package/package.json +1 -1
- package/themes/kyma-dark.json +15 -8
package/dist/main.js
CHANGED
|
@@ -123,7 +123,7 @@ var KYMA_AGENT_DIR = join(KYMA_DIR, "agent");
|
|
|
123
123
|
var KYMA_AUTH_PATH = join(KYMA_AGENT_DIR, "auth.json");
|
|
124
124
|
var KYMA_SETTINGS_PATH = join(KYMA_AGENT_DIR, "settings.json");
|
|
125
125
|
var KYMA_ONBOARDED_PATH = join(KYMA_AGENT_DIR, ".onboarded");
|
|
126
|
-
var KYMA_BASE_URL = "https://kymaapi.com";
|
|
126
|
+
var KYMA_BASE_URL = process.env.KYMA_BASE_URL || "https://kymaapi.com";
|
|
127
127
|
|
|
128
128
|
// src/sdk/auth.ts
|
|
129
129
|
import { readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
@@ -146,7 +146,7 @@ var VERSION = (() => {
|
|
|
146
146
|
function normalizeKymaError(status, body) {
|
|
147
147
|
switch (status) {
|
|
148
148
|
case 401:
|
|
149
|
-
return { code: 401, severity: "error", message: "Session expired.", action: "Run /
|
|
149
|
+
return { code: 401, severity: "error", message: "Session expired.", action: "Run /login to reconnect." };
|
|
150
150
|
case 402:
|
|
151
151
|
return { code: 402, severity: "error", message: "Insufficient Kyma credits.", action: "Run /billing to top up." };
|
|
152
152
|
case 429:
|
|
@@ -374,7 +374,8 @@ function ensureAgentDir() {
|
|
|
374
374
|
defaultModel: "qwen-3-32b",
|
|
375
375
|
quietStartup: true,
|
|
376
376
|
theme: "kyma-dark",
|
|
377
|
-
|
|
377
|
+
hideThinkingBlock: false,
|
|
378
|
+
defaultThinkingLevel: "low"
|
|
378
379
|
}, null, 2), { mode: 384 });
|
|
379
380
|
} else {
|
|
380
381
|
try {
|
|
@@ -396,8 +397,12 @@ function ensureAgentDir() {
|
|
|
396
397
|
settings.theme = "kyma-dark";
|
|
397
398
|
changed = true;
|
|
398
399
|
}
|
|
399
|
-
if (settings.
|
|
400
|
-
settings.
|
|
400
|
+
if (settings.defaultThinkingLevel !== "low") {
|
|
401
|
+
settings.defaultThinkingLevel = "low";
|
|
402
|
+
changed = true;
|
|
403
|
+
}
|
|
404
|
+
if (settings.hideThinkingBlock !== false) {
|
|
405
|
+
settings.hideThinkingBlock = false;
|
|
401
406
|
changed = true;
|
|
402
407
|
}
|
|
403
408
|
if (changed) {
|
|
@@ -434,7 +439,7 @@ async function runOnboarding() {
|
|
|
434
439
|
console.log("");
|
|
435
440
|
const answer = await ask(" Connect now? (Y/n) ");
|
|
436
441
|
if (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") {
|
|
437
|
-
console.log(` ${term.dim("Skipped.")} Use ${term.gold("/
|
|
442
|
+
console.log(` ${term.dim("Skipped.")} Use ${term.gold("/login")} anytime.`);
|
|
438
443
|
console.log("");
|
|
439
444
|
markOnboarded();
|
|
440
445
|
return false;
|
|
@@ -463,7 +468,7 @@ async function runOnboarding() {
|
|
|
463
468
|
} catch (err) {
|
|
464
469
|
console.log("");
|
|
465
470
|
console.log(` ${term.dim("Login failed:")} ${err.message}`);
|
|
466
|
-
console.log(` ${term.dim("Try again with")} ${term.gold("/
|
|
471
|
+
console.log(` ${term.dim("Try again with")} ${term.gold("/login")}`);
|
|
467
472
|
console.log("");
|
|
468
473
|
}
|
|
469
474
|
markOnboarded();
|
|
@@ -507,7 +512,12 @@ async function createKymaSession(options) {
|
|
|
507
512
|
extensionFactories,
|
|
508
513
|
additionalExtensionPaths: [],
|
|
509
514
|
// no file-based extensions
|
|
510
|
-
additionalThemePaths: [KYMA_THEMES_DIR]
|
|
515
|
+
additionalThemePaths: [KYMA_THEMES_DIR],
|
|
516
|
+
appendSystemPrompt: [
|
|
517
|
+
"IMPORTANT: You are running inside Kyma, NOT pi. Never mention pi, Pi SDK, or pi documentation.",
|
|
518
|
+
"If the user asks about the tool they are using, say 'Kyma' (kymaapi.com).",
|
|
519
|
+
"Never reveal internal file paths or node_modules paths."
|
|
520
|
+
].join("\n")
|
|
511
521
|
}
|
|
512
522
|
});
|
|
513
523
|
const result = await createAgentSessionFromServices({
|
|
@@ -755,6 +765,7 @@ var kymaProviderFactory = (pi) => {
|
|
|
755
765
|
apiKey: "KYMA_API_KEY",
|
|
756
766
|
api: "openai-completions",
|
|
757
767
|
authHeader: true,
|
|
768
|
+
headers: { "X-Kyma-Think": "show" },
|
|
758
769
|
oauth: {
|
|
759
770
|
name: "Kyma",
|
|
760
771
|
login: loginKyma,
|
|
@@ -774,8 +785,9 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
774
785
|
sessionCost = 0;
|
|
775
786
|
sessionTokens = 0;
|
|
776
787
|
turnCount = 0;
|
|
777
|
-
pi.setThinkingLevel?.("off");
|
|
778
788
|
if (!ctx.hasUI) return;
|
|
789
|
+
ctx.ui.setHideThinkingBlock?.(false);
|
|
790
|
+
ctx.ui.setHiddenThinkingLabel?.("Thinking... (Ctrl+T to expand)");
|
|
779
791
|
const email = getKymaEmail();
|
|
780
792
|
const apiKey = getKymaApiKey();
|
|
781
793
|
const loggedIn = !!apiKey;
|
|
@@ -787,12 +799,47 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
787
799
|
} catch {
|
|
788
800
|
}
|
|
789
801
|
}
|
|
802
|
+
const repoName = ctx.cwd.replace(/^.*\//, "");
|
|
803
|
+
const modelId = ctx.model?.id || "qwen-3-32b";
|
|
790
804
|
ctx.ui.setHeader((_tui, theme) => ({
|
|
791
|
-
render(
|
|
792
|
-
const
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
805
|
+
render(width) {
|
|
806
|
+
const strip = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
807
|
+
const truncate = (s, maxW2) => {
|
|
808
|
+
let visible = 0;
|
|
809
|
+
let i = 0;
|
|
810
|
+
while (i < s.length && visible < maxW2) {
|
|
811
|
+
if (s[i] === "\x1B") {
|
|
812
|
+
const end = s.indexOf("m", i);
|
|
813
|
+
if (end !== -1) {
|
|
814
|
+
i = end + 1;
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
visible++;
|
|
819
|
+
i++;
|
|
820
|
+
}
|
|
821
|
+
return i < s.length ? s.slice(0, i) : s;
|
|
822
|
+
};
|
|
823
|
+
const maxW = Math.max(width, 30);
|
|
824
|
+
const logo = theme.bold(theme.fg("accent", ` \u03A8 kyma`)) + theme.fg("dim", ` v${VERSION}`);
|
|
825
|
+
const url = ` https://kymaapi.com`;
|
|
826
|
+
const accountStr = loggedIn ? `${email}${balanceStr ? ` \xB7 ${balanceStr}` : ""}` : "not connected";
|
|
827
|
+
const dirLine = `~/${repoName}`;
|
|
828
|
+
const connectLine = loggedIn ? null : `${theme.bold("/login")} to sign in`;
|
|
829
|
+
const contentLines = [accountStr, dirLine];
|
|
830
|
+
if (connectLine) contentLines.push(connectLine);
|
|
831
|
+
const visibleWidths = contentLines.map((l) => strip(l).length);
|
|
832
|
+
const contentMax = Math.max(...visibleWidths);
|
|
833
|
+
const innerW = Math.min(maxW - 4, Math.max(contentMax + 4, 24));
|
|
834
|
+
const boxTop = theme.fg("dim", ` \u256D${"\u2500".repeat(innerW)}\u256E`);
|
|
835
|
+
const boxBot = theme.fg("dim", ` \u2570${"\u2500".repeat(innerW)}\u256F`);
|
|
836
|
+
const boxRow = (s) => {
|
|
837
|
+
const visLen = strip(s).length;
|
|
838
|
+
const pad = Math.max(0, innerW - visLen - 4);
|
|
839
|
+
const row = theme.fg("dim", " \u2502") + ` ${s}${" ".repeat(pad)} ` + theme.fg("dim", "\u2502");
|
|
840
|
+
return truncate(row, maxW);
|
|
841
|
+
};
|
|
842
|
+
return [truncate(logo, maxW), truncate(url, maxW), boxTop, ...contentLines.map(boxRow), boxBot];
|
|
796
843
|
},
|
|
797
844
|
invalidate() {
|
|
798
845
|
}
|
|
@@ -832,9 +879,9 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
832
879
|
const freshLogin = !!process.env.KYMA_FRESH_LOGIN;
|
|
833
880
|
delete process.env.KYMA_FRESH_LOGIN;
|
|
834
881
|
if (loggedIn && isOnboarded && !freshLogin) {
|
|
835
|
-
const
|
|
882
|
+
const modelId2 = ctx.model?.id || "qwen-3-32b";
|
|
836
883
|
ctx.ui.setWidget?.("kyma-hint", [
|
|
837
|
-
` ${
|
|
884
|
+
` ${modelId2} \xB7 /models to switch \xB7 /help for commands`
|
|
838
885
|
], { placement: "aboveEditor" });
|
|
839
886
|
}
|
|
840
887
|
});
|
|
@@ -860,9 +907,6 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
860
907
|
if (turnCount === 1 && ctx.hasUI) {
|
|
861
908
|
ctx.ui.setWidget?.("kyma-hint", void 0);
|
|
862
909
|
}
|
|
863
|
-
if (ctx.hasUI) {
|
|
864
|
-
ctx.ui.setStatus("kyma-cost", `$${sessionCost.toFixed(4)} \xB7 ${formatTokens(sessionTokens)} tokens`);
|
|
865
|
-
}
|
|
866
910
|
}
|
|
867
911
|
if (!ctx.hasUI || postLoginShown) return;
|
|
868
912
|
const nowLoggedIn = !!getKymaApiKey();
|
|
@@ -936,7 +980,7 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
936
980
|
if (ok) {
|
|
937
981
|
ctx.ui.notify(`Switched to ${chosen.name} \u2014 ${chosen.tag}`, "info");
|
|
938
982
|
} else {
|
|
939
|
-
ctx.ui.notify("Failed to switch model. Run /
|
|
983
|
+
ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
|
|
940
984
|
}
|
|
941
985
|
}
|
|
942
986
|
pi.registerCommand("models", {
|
|
@@ -973,7 +1017,7 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
973
1017
|
if (ok) {
|
|
974
1018
|
ctx.ui.notify(`Mode: ${entry.mode} \u2192 ${entry.model.name}`, "info");
|
|
975
1019
|
} else {
|
|
976
|
-
ctx.ui.notify("Failed to switch model. Run /
|
|
1020
|
+
ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
|
|
977
1021
|
}
|
|
978
1022
|
}
|
|
979
1023
|
});
|
|
@@ -984,7 +1028,7 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
984
1028
|
const currentModel = ctx.model;
|
|
985
1029
|
const lines = ["Kyma Status", DIV, ""];
|
|
986
1030
|
if (!apiKey) {
|
|
987
|
-
lines.push(" Not connected. Run /
|
|
1031
|
+
lines.push(" Not connected. Run /login to sign in.");
|
|
988
1032
|
ctx.ui.notify(lines.join("\n"), "info");
|
|
989
1033
|
return;
|
|
990
1034
|
}
|
|
@@ -1035,7 +1079,7 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
1035
1079
|
async handler(_args, ctx) {
|
|
1036
1080
|
const apiKey = getKymaApiKey();
|
|
1037
1081
|
if (!apiKey) {
|
|
1038
|
-
ctx.ui.notify("Not connected. Run /
|
|
1082
|
+
ctx.ui.notify("Not connected. Run /login to sign in.", "error");
|
|
1039
1083
|
return;
|
|
1040
1084
|
}
|
|
1041
1085
|
try {
|
|
@@ -1103,7 +1147,7 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
1103
1147
|
async handler(_args, ctx) {
|
|
1104
1148
|
const apiKey = getKymaApiKey();
|
|
1105
1149
|
if (!apiKey) {
|
|
1106
|
-
ctx.ui.notify("Not connected. Run /
|
|
1150
|
+
ctx.ui.notify("Not connected. Run /login first.", "error");
|
|
1107
1151
|
return;
|
|
1108
1152
|
}
|
|
1109
1153
|
try {
|
|
@@ -1159,8 +1203,8 @@ var kymaRuntimeFactory = (pi) => {
|
|
|
1159
1203
|
ctx.ui.notify("Opening feedback page...", "info");
|
|
1160
1204
|
}
|
|
1161
1205
|
});
|
|
1162
|
-
pi.registerCommand("
|
|
1163
|
-
description: "
|
|
1206
|
+
pi.registerCommand("login", {
|
|
1207
|
+
description: "Sign in to your Kyma account",
|
|
1164
1208
|
async handler(_args, ctx) {
|
|
1165
1209
|
if (getKymaApiKey()) {
|
|
1166
1210
|
const email = getKymaEmail();
|
|
@@ -1199,17 +1243,19 @@ URL: ${url}`, "info");
|
|
|
1199
1243
|
"Kyma Commands",
|
|
1200
1244
|
DIV,
|
|
1201
1245
|
"",
|
|
1202
|
-
" /
|
|
1203
|
-
" /
|
|
1246
|
+
" /login Sign in to Kyma",
|
|
1247
|
+
" /logout Sign out",
|
|
1204
1248
|
" /models Browse and switch models",
|
|
1205
1249
|
" /mode Switch model by task type",
|
|
1206
|
-
" /status Account, credits,
|
|
1250
|
+
" /status Account, credits, diagnostics",
|
|
1207
1251
|
" /balance Credits and rate limits",
|
|
1208
1252
|
" /usage Session cost and tokens",
|
|
1209
1253
|
" /upgrade View tiers and upgrade",
|
|
1210
1254
|
" /dashboard Open dashboard in browser",
|
|
1211
1255
|
" /billing Open billing page",
|
|
1212
1256
|
" /feedback Report issues or give feedback",
|
|
1257
|
+
" /clear Clear the screen",
|
|
1258
|
+
" /exit Exit kyma",
|
|
1213
1259
|
" /help Show this help",
|
|
1214
1260
|
"",
|
|
1215
1261
|
"Keyboard",
|
|
@@ -1223,25 +1269,37 @@ URL: ${url}`, "info");
|
|
|
1223
1269
|
].join("\n"), "info");
|
|
1224
1270
|
}
|
|
1225
1271
|
});
|
|
1226
|
-
pi.registerCommand("
|
|
1272
|
+
pi.registerCommand("exit", {
|
|
1273
|
+
description: "Exit kyma",
|
|
1274
|
+
async handler(_args, _ctx) {
|
|
1275
|
+
process.exit(0);
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
pi.registerCommand("logout", {
|
|
1227
1279
|
description: "Sign out of Kyma",
|
|
1228
1280
|
async handler(_args, ctx) {
|
|
1229
1281
|
const apiKey = getKymaApiKey();
|
|
1230
1282
|
if (!apiKey) {
|
|
1231
|
-
ctx.ui.notify("Not
|
|
1283
|
+
ctx.ui.notify("Not signed in. Run /login to sign in.", "info");
|
|
1232
1284
|
return;
|
|
1233
1285
|
}
|
|
1234
1286
|
if (process.env.KYMA_API_KEY) {
|
|
1235
|
-
ctx.ui.notify("Cannot
|
|
1287
|
+
ctx.ui.notify("Cannot sign out: using KYMA_API_KEY environment variable.", "warning");
|
|
1236
1288
|
return;
|
|
1237
1289
|
}
|
|
1238
1290
|
const email = getKymaEmail();
|
|
1239
|
-
const confirm = await ctx.ui.confirm("
|
|
1291
|
+
const confirm = await ctx.ui.confirm("Sign out", `Sign out from ${email}?`);
|
|
1240
1292
|
if (!confirm) return;
|
|
1241
1293
|
clearKymaCredentials();
|
|
1242
1294
|
wasLoggedIn = false;
|
|
1243
1295
|
postLoginShown = false;
|
|
1244
|
-
ctx.ui.notify("
|
|
1296
|
+
ctx.ui.notify("Signed out. Run /login to sign in again.", "info");
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
pi.registerCommand("clear", {
|
|
1300
|
+
description: "Clear the screen",
|
|
1301
|
+
async handler(_args, ctx) {
|
|
1302
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1245
1303
|
}
|
|
1246
1304
|
});
|
|
1247
1305
|
};
|
|
@@ -1336,6 +1394,27 @@ function parseArgs(argv) {
|
|
|
1336
1394
|
}
|
|
1337
1395
|
return result;
|
|
1338
1396
|
}
|
|
1397
|
+
async function checkAndUpdate() {
|
|
1398
|
+
try {
|
|
1399
|
+
const res = await fetch("https://registry.npmjs.org/@kyma-api/agent/latest", {
|
|
1400
|
+
signal: AbortSignal.timeout(3e3)
|
|
1401
|
+
});
|
|
1402
|
+
if (!res.ok) return false;
|
|
1403
|
+
const data = await res.json();
|
|
1404
|
+
const latest = data.version;
|
|
1405
|
+
if (!latest || latest === VERSION2) return false;
|
|
1406
|
+
const parse = (v) => v.split(".").map(Number);
|
|
1407
|
+
const [cM, cm, cp] = parse(VERSION2);
|
|
1408
|
+
const [lM, lm, lp] = parse(latest);
|
|
1409
|
+
if (lM < cM || lM === cM && lm < cm || lM === cM && lm === cm && lp <= cp) return false;
|
|
1410
|
+
console.log(` ${term.dim(`Updating kyma v${VERSION2} \u2192 v${latest}...`)}`);
|
|
1411
|
+
execSync("npm install -g @kyma-api/agent@latest", { stdio: "ignore", timeout: 6e4 });
|
|
1412
|
+
console.log(` ${term.dim(`Updated to v${latest}. Restarting...`)}`);
|
|
1413
|
+
return true;
|
|
1414
|
+
} catch {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1339
1418
|
async function main(argv) {
|
|
1340
1419
|
const parsed = parseArgs(argv);
|
|
1341
1420
|
if (parsed.help) {
|
|
@@ -1349,6 +1428,18 @@ async function main(argv) {
|
|
|
1349
1428
|
if (parsed.verbose || process.env.KYMA_DEBUG === "1") {
|
|
1350
1429
|
process.env.KYMA_VERBOSE = "1";
|
|
1351
1430
|
}
|
|
1431
|
+
if (!process.env.KYMA_SKIP_UPDATE) {
|
|
1432
|
+
const updated = await checkAndUpdate();
|
|
1433
|
+
if (updated) {
|
|
1434
|
+
const { spawn } = await import("child_process");
|
|
1435
|
+
const child = spawn("kyma", process.argv.slice(2), {
|
|
1436
|
+
stdio: "inherit",
|
|
1437
|
+
env: { ...process.env, KYMA_SKIP_UPDATE: "1" }
|
|
1438
|
+
});
|
|
1439
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1352
1443
|
ensureAgentDir();
|
|
1353
1444
|
await runOnboarding();
|
|
1354
1445
|
if (process.env.KYMA_VERBOSE) {
|
package/package.json
CHANGED
package/themes/kyma-dark.json
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
"accent": "#C9A84C",
|
|
6
6
|
"accentLight": "#DDBF6F",
|
|
7
7
|
"accentSoft": "#A89060",
|
|
8
|
+
"teal": "#7DCFCF",
|
|
9
|
+
"purple": "#B4A7D6",
|
|
8
10
|
"green": "#00B894",
|
|
9
11
|
"red": "#E17055",
|
|
10
12
|
"yellow": "#FDCB6E",
|
|
@@ -30,7 +32,7 @@
|
|
|
30
32
|
"muted": "gray",
|
|
31
33
|
"dim": "dimGray",
|
|
32
34
|
"text": "",
|
|
33
|
-
"thinkingText": "
|
|
35
|
+
"thinkingText": "dimGray",
|
|
34
36
|
|
|
35
37
|
"selectedBg": "selectedBg",
|
|
36
38
|
"userMessageBg": "userMsgBg",
|
|
@@ -42,12 +44,12 @@
|
|
|
42
44
|
"toolSuccessBg": "toolSuccessBg",
|
|
43
45
|
"toolErrorBg": "toolErrorBg",
|
|
44
46
|
"toolTitle": "",
|
|
45
|
-
"toolOutput": "
|
|
47
|
+
"toolOutput": "#C8CCD8",
|
|
46
48
|
|
|
47
|
-
"mdHeading": "#
|
|
48
|
-
"mdLink": "
|
|
49
|
+
"mdHeading": "#F0E4A8",
|
|
50
|
+
"mdLink": "teal",
|
|
49
51
|
"mdLinkUrl": "dimGray",
|
|
50
|
-
"mdCode": "
|
|
52
|
+
"mdCode": "teal",
|
|
51
53
|
"mdCodeBlock": "gray",
|
|
52
54
|
"mdCodeBlockBorder": "dimGray",
|
|
53
55
|
"mdQuote": "gray",
|
|
@@ -60,12 +62,12 @@
|
|
|
60
62
|
"toolDiffContext": "gray",
|
|
61
63
|
|
|
62
64
|
"syntaxComment": "#6A9955",
|
|
63
|
-
"syntaxKeyword": "
|
|
65
|
+
"syntaxKeyword": "purple",
|
|
64
66
|
"syntaxFunction": "#E2C87A",
|
|
65
67
|
"syntaxVariable": "#C8BFA0",
|
|
66
68
|
"syntaxString": "#9BE9A8",
|
|
67
69
|
"syntaxNumber": "#B5CEA8",
|
|
68
|
-
"syntaxType": "
|
|
70
|
+
"syntaxType": "teal",
|
|
69
71
|
"syntaxOperator": "#D4D4D4",
|
|
70
72
|
"syntaxPunctuation": "#D4D4D4",
|
|
71
73
|
|
|
@@ -76,7 +78,12 @@
|
|
|
76
78
|
"thinkingHigh": "#8B7A5F",
|
|
77
79
|
"thinkingXhigh": "accentSoft",
|
|
78
80
|
|
|
79
|
-
"bashMode": "green"
|
|
81
|
+
"bashMode": "green",
|
|
82
|
+
|
|
83
|
+
"modeCode": "#5B9CF5",
|
|
84
|
+
"modeReason": "#B4A7D6",
|
|
85
|
+
"modeFast": "#00B894",
|
|
86
|
+
"modeCreative": "#E17055"
|
|
80
87
|
},
|
|
81
88
|
"export": {
|
|
82
89
|
"pageBg": "#13141C",
|