codemaxxing 0.1.13 → 0.2.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/dist/agent.d.ts +6 -0
- package/dist/agent.js +19 -1
- package/dist/index.js +271 -3
- package/dist/skills/registry.d.ts +13 -0
- package/dist/skills/registry.js +472 -0
- package/dist/themes.js +37 -77
- package/dist/utils/context.d.ts +1 -1
- package/dist/utils/context.js +6 -2
- package/dist/utils/skills.d.ts +60 -0
- package/dist/utils/skills.js +203 -0
- package/package.json +1 -1
- package/src/agent.ts +24 -1
- package/src/index.tsx +316 -1
- package/src/skills/registry.ts +482 -0
- package/src/themes.ts +39 -77
- package/src/utils/context.ts +8 -2
- package/src/utils/skills.ts +241 -0
package/src/index.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { execSync } from "child_process";
|
|
|
11
11
|
import { isGitRepo, getBranch, getStatus, getDiff, undoLastCommit } from "./utils/git.js";
|
|
12
12
|
import { getTheme, listThemes, THEMES, DEFAULT_THEME, type Theme } from "./themes.js";
|
|
13
13
|
import { PROVIDERS, getCredentials, openRouterOAuth, anthropicSetupToken, importCodexToken, importQwenToken, copilotDeviceFlow, saveApiKey } from "./utils/auth.js";
|
|
14
|
+
import { listInstalledSkills, installSkill, removeSkill, getRegistrySkills, searchRegistry, createSkillScaffold, getActiveSkills, getActiveSkillCount } from "./utils/skills.js";
|
|
14
15
|
|
|
15
16
|
const VERSION = "0.1.9";
|
|
16
17
|
|
|
@@ -46,6 +47,13 @@ const SLASH_COMMANDS = [
|
|
|
46
47
|
{ cmd: "/sessions", desc: "list past sessions" },
|
|
47
48
|
{ cmd: "/session delete", desc: "delete a session" },
|
|
48
49
|
{ cmd: "/resume", desc: "resume a past session" },
|
|
50
|
+
{ cmd: "/skills", desc: "manage skill packs" },
|
|
51
|
+
{ cmd: "/skills install", desc: "install a skill" },
|
|
52
|
+
{ cmd: "/skills remove", desc: "remove a skill" },
|
|
53
|
+
{ cmd: "/skills list", desc: "show installed skills" },
|
|
54
|
+
{ cmd: "/skills search", desc: "search registry" },
|
|
55
|
+
{ cmd: "/skills on", desc: "enable skill for session" },
|
|
56
|
+
{ cmd: "/skills off", desc: "disable skill for session" },
|
|
49
57
|
{ cmd: "/quit", desc: "exit" },
|
|
50
58
|
];
|
|
51
59
|
|
|
@@ -144,6 +152,9 @@ function App() {
|
|
|
144
152
|
const [loginPickerIndex, setLoginPickerIndex] = useState(0);
|
|
145
153
|
const [loginMethodPicker, setLoginMethodPicker] = useState<{ provider: string; methods: string[] } | null>(null);
|
|
146
154
|
const [loginMethodIndex, setLoginMethodIndex] = useState(0);
|
|
155
|
+
const [skillsPicker, setSkillsPicker] = useState<"menu" | "browse" | "installed" | "remove" | null>(null);
|
|
156
|
+
const [skillsPickerIndex, setSkillsPickerIndex] = useState(0);
|
|
157
|
+
const [sessionDisabledSkills, setSessionDisabledSkills] = useState<Set<string>>(new Set());
|
|
147
158
|
const [approval, setApproval] = useState<{
|
|
148
159
|
tool: string;
|
|
149
160
|
args: Record<string, unknown>;
|
|
@@ -323,7 +334,9 @@ function App() {
|
|
|
323
334
|
const selected = matches[idx];
|
|
324
335
|
if (selected) {
|
|
325
336
|
// Commands that need args (like /commit, /model) — fill input instead of executing
|
|
326
|
-
if (selected.cmd === "/commit" || selected.cmd === "/model" || selected.cmd === "/session delete"
|
|
337
|
+
if (selected.cmd === "/commit" || selected.cmd === "/model" || selected.cmd === "/session delete" ||
|
|
338
|
+
selected.cmd === "/skills install" || selected.cmd === "/skills remove" || selected.cmd === "/skills search" ||
|
|
339
|
+
selected.cmd === "/skills on" || selected.cmd === "/skills off") {
|
|
327
340
|
setInput(selected.cmd + " ");
|
|
328
341
|
setCmdIndex(0);
|
|
329
342
|
setInputKey((k) => k + 1);
|
|
@@ -384,10 +397,94 @@ function App() {
|
|
|
384
397
|
" /push — push to remote",
|
|
385
398
|
" /git on — enable auto-commits",
|
|
386
399
|
" /git off — disable auto-commits",
|
|
400
|
+
" /skills — manage skill packs",
|
|
387
401
|
" /quit — exit",
|
|
388
402
|
].join("\n"));
|
|
389
403
|
return;
|
|
390
404
|
}
|
|
405
|
+
// ── Skills commands (work without agent) ──
|
|
406
|
+
if (trimmed === "/skills") {
|
|
407
|
+
setSkillsPicker("menu");
|
|
408
|
+
setSkillsPickerIndex(0);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (trimmed.startsWith("/skills install ")) {
|
|
412
|
+
const name = trimmed.replace("/skills install ", "").trim();
|
|
413
|
+
const result = installSkill(name);
|
|
414
|
+
addMsg(result.ok ? "info" : "error", result.ok ? `✅ ${result.message}` : `✗ ${result.message}`);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (trimmed.startsWith("/skills remove ")) {
|
|
418
|
+
const name = trimmed.replace("/skills remove ", "").trim();
|
|
419
|
+
const result = removeSkill(name);
|
|
420
|
+
addMsg(result.ok ? "info" : "error", result.ok ? `✅ ${result.message}` : `✗ ${result.message}`);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (trimmed === "/skills list") {
|
|
424
|
+
const installed = listInstalledSkills();
|
|
425
|
+
if (installed.length === 0) {
|
|
426
|
+
addMsg("info", "No skills installed. Use /skills to browse & install.");
|
|
427
|
+
} else {
|
|
428
|
+
const active = getActiveSkills(process.cwd(), sessionDisabledSkills);
|
|
429
|
+
const lines = installed.map((s) => {
|
|
430
|
+
const isActive = active.includes(s.name);
|
|
431
|
+
const disabledBySession = sessionDisabledSkills.has(s.name);
|
|
432
|
+
const status = disabledBySession ? " (off)" : isActive ? " (on)" : "";
|
|
433
|
+
return ` ${isActive ? "●" : "○"} ${s.name} — ${s.description}${status}`;
|
|
434
|
+
});
|
|
435
|
+
addMsg("info", `Installed skills:\n${lines.join("\n")}`);
|
|
436
|
+
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if (trimmed.startsWith("/skills search ")) {
|
|
440
|
+
const query = trimmed.replace("/skills search ", "").trim();
|
|
441
|
+
const results = searchRegistry(query);
|
|
442
|
+
if (results.length === 0) {
|
|
443
|
+
addMsg("info", `No skills found matching "${query}".`);
|
|
444
|
+
} else {
|
|
445
|
+
const installed = listInstalledSkills().map((s) => s.name);
|
|
446
|
+
const lines = results.map((s) => {
|
|
447
|
+
const mark = installed.includes(s.name) ? " ✓" : "";
|
|
448
|
+
return ` ${s.name} — ${s.description}${mark}`;
|
|
449
|
+
});
|
|
450
|
+
addMsg("info", `Registry matches:\n${lines.join("\n")}`);
|
|
451
|
+
}
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (trimmed.startsWith("/skills create ")) {
|
|
455
|
+
const name = trimmed.replace("/skills create ", "").trim();
|
|
456
|
+
if (!name) {
|
|
457
|
+
addMsg("info", "Usage: /skills create <name>");
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const result = createSkillScaffold(name);
|
|
461
|
+
addMsg(result.ok ? "info" : "error", result.ok ? `✅ ${result.message}\n Edit: ${result.path}/prompt.md` : `✗ ${result.message}`);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (trimmed.startsWith("/skills on ")) {
|
|
465
|
+
const name = trimmed.replace("/skills on ", "").trim();
|
|
466
|
+
const installed = listInstalledSkills().map((s) => s.name);
|
|
467
|
+
if (!installed.includes(name)) {
|
|
468
|
+
addMsg("error", `Skill "${name}" is not installed.`);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
setSessionDisabledSkills((prev) => { const next = new Set(prev); next.delete(name); return next; });
|
|
472
|
+
if (agent) agent.enableSkill(name);
|
|
473
|
+
addMsg("info", `✅ Enabled skill: ${name}`);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (trimmed.startsWith("/skills off ")) {
|
|
477
|
+
const name = trimmed.replace("/skills off ", "").trim();
|
|
478
|
+
const installed = listInstalledSkills().map((s) => s.name);
|
|
479
|
+
if (!installed.includes(name)) {
|
|
480
|
+
addMsg("error", `Skill "${name}" is not installed.`);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
setSessionDisabledSkills((prev) => { const next = new Set(prev); next.add(name); return next; });
|
|
484
|
+
if (agent) agent.disableSkill(name);
|
|
485
|
+
addMsg("info", `✅ Disabled skill: ${name} (session only)`);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
391
488
|
if (trimmed.startsWith("/theme")) {
|
|
392
489
|
const themeName = trimmed.replace("/theme", "").trim();
|
|
393
490
|
if (!themeName) {
|
|
@@ -739,6 +836,148 @@ function App() {
|
|
|
739
836
|
return;
|
|
740
837
|
}
|
|
741
838
|
|
|
839
|
+
// Skills picker navigation
|
|
840
|
+
if (skillsPicker) {
|
|
841
|
+
if (skillsPicker === "menu") {
|
|
842
|
+
const menuItems = ["browse", "installed", "create", "remove"];
|
|
843
|
+
if (key.upArrow) {
|
|
844
|
+
setSkillsPickerIndex((prev) => (prev - 1 + menuItems.length) % menuItems.length);
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
if (key.downArrow) {
|
|
848
|
+
setSkillsPickerIndex((prev) => (prev + 1) % menuItems.length);
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (key.escape) {
|
|
852
|
+
setSkillsPicker(null);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (key.return) {
|
|
856
|
+
const selected = menuItems[skillsPickerIndex];
|
|
857
|
+
if (selected === "browse") {
|
|
858
|
+
setSkillsPicker("browse");
|
|
859
|
+
setSkillsPickerIndex(0);
|
|
860
|
+
} else if (selected === "installed") {
|
|
861
|
+
setSkillsPicker("installed");
|
|
862
|
+
setSkillsPickerIndex(0);
|
|
863
|
+
} else if (selected === "create") {
|
|
864
|
+
setSkillsPicker(null);
|
|
865
|
+
setInput("/skills create ");
|
|
866
|
+
setInputKey((k) => k + 1);
|
|
867
|
+
} else if (selected === "remove") {
|
|
868
|
+
const installed = listInstalledSkills();
|
|
869
|
+
if (installed.length === 0) {
|
|
870
|
+
setSkillsPicker(null);
|
|
871
|
+
addMsg("info", "No skills installed to remove.");
|
|
872
|
+
} else {
|
|
873
|
+
setSkillsPicker("remove");
|
|
874
|
+
setSkillsPickerIndex(0);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (skillsPicker === "browse") {
|
|
882
|
+
const registry = getRegistrySkills();
|
|
883
|
+
if (key.upArrow) {
|
|
884
|
+
setSkillsPickerIndex((prev) => (prev - 1 + registry.length) % registry.length);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (key.downArrow) {
|
|
888
|
+
setSkillsPickerIndex((prev) => (prev + 1) % registry.length);
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (key.escape) {
|
|
892
|
+
setSkillsPicker("menu");
|
|
893
|
+
setSkillsPickerIndex(0);
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
if (key.return) {
|
|
897
|
+
const selected = registry[skillsPickerIndex];
|
|
898
|
+
if (selected) {
|
|
899
|
+
const result = installSkill(selected.name);
|
|
900
|
+
addMsg(result.ok ? "info" : "error", result.ok ? `✅ ${result.message}` : `✗ ${result.message}`);
|
|
901
|
+
}
|
|
902
|
+
setSkillsPicker(null);
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (skillsPicker === "installed") {
|
|
908
|
+
const installed = listInstalledSkills();
|
|
909
|
+
if (installed.length === 0) {
|
|
910
|
+
setSkillsPicker("menu");
|
|
911
|
+
setSkillsPickerIndex(0);
|
|
912
|
+
addMsg("info", "No skills installed.");
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
if (key.upArrow) {
|
|
916
|
+
setSkillsPickerIndex((prev) => (prev - 1 + installed.length) % installed.length);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
if (key.downArrow) {
|
|
920
|
+
setSkillsPickerIndex((prev) => (prev + 1) % installed.length);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (key.escape) {
|
|
924
|
+
setSkillsPicker("menu");
|
|
925
|
+
setSkillsPickerIndex(0);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
if (key.return) {
|
|
929
|
+
// Toggle on/off for session
|
|
930
|
+
const selected = installed[skillsPickerIndex];
|
|
931
|
+
if (selected) {
|
|
932
|
+
const isDisabled = sessionDisabledSkills.has(selected.name);
|
|
933
|
+
if (isDisabled) {
|
|
934
|
+
setSessionDisabledSkills((prev) => { const next = new Set(prev); next.delete(selected.name); return next; });
|
|
935
|
+
if (agent) agent.enableSkill(selected.name);
|
|
936
|
+
addMsg("info", `✅ Enabled: ${selected.name}`);
|
|
937
|
+
} else {
|
|
938
|
+
setSessionDisabledSkills((prev) => { const next = new Set(prev); next.add(selected.name); return next; });
|
|
939
|
+
if (agent) agent.disableSkill(selected.name);
|
|
940
|
+
addMsg("info", `✅ Disabled: ${selected.name} (session only)`);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
setSkillsPicker(null);
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (skillsPicker === "remove") {
|
|
949
|
+
const installed = listInstalledSkills();
|
|
950
|
+
if (installed.length === 0) {
|
|
951
|
+
setSkillsPicker(null);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
if (key.upArrow) {
|
|
955
|
+
setSkillsPickerIndex((prev) => (prev - 1 + installed.length) % installed.length);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (key.downArrow) {
|
|
959
|
+
setSkillsPickerIndex((prev) => (prev + 1) % installed.length);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
if (key.escape) {
|
|
963
|
+
setSkillsPicker("menu");
|
|
964
|
+
setSkillsPickerIndex(0);
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (key.return) {
|
|
968
|
+
const selected = installed[skillsPickerIndex];
|
|
969
|
+
if (selected) {
|
|
970
|
+
const result = removeSkill(selected.name);
|
|
971
|
+
addMsg(result.ok ? "info" : "error", result.ok ? `✅ ${result.message}` : `✗ ${result.message}`);
|
|
972
|
+
}
|
|
973
|
+
setSkillsPicker(null);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
|
|
742
981
|
// Theme picker navigation
|
|
743
982
|
if (themePicker) {
|
|
744
983
|
const themeKeys = listThemes();
|
|
@@ -1072,6 +1311,78 @@ function App() {
|
|
|
1072
1311
|
</Box>
|
|
1073
1312
|
)}
|
|
1074
1313
|
|
|
1314
|
+
{/* ═══ SKILLS PICKER ═══ */}
|
|
1315
|
+
{skillsPicker === "menu" && (
|
|
1316
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
1317
|
+
<Text bold color={theme.colors.secondary}>Skills:</Text>
|
|
1318
|
+
{[
|
|
1319
|
+
{ key: "browse", label: "Browse & Install", icon: "📦" },
|
|
1320
|
+
{ key: "installed", label: "Installed Skills", icon: "📋" },
|
|
1321
|
+
{ key: "create", label: "Create Custom Skill", icon: "➕" },
|
|
1322
|
+
{ key: "remove", label: "Remove Skill", icon: "🗑️" },
|
|
1323
|
+
].map((item, i) => (
|
|
1324
|
+
<Text key={item.key}>
|
|
1325
|
+
{i === skillsPickerIndex ? <Text color={theme.colors.suggestion} bold>{"▸ "}</Text> : <Text>{" "}</Text>}
|
|
1326
|
+
<Text color={i === skillsPickerIndex ? theme.colors.suggestion : theme.colors.primary} bold>{item.icon} {item.label}</Text>
|
|
1327
|
+
</Text>
|
|
1328
|
+
))}
|
|
1329
|
+
<Text dimColor>{" ↑↓ navigate · Enter select · Esc cancel"}</Text>
|
|
1330
|
+
</Box>
|
|
1331
|
+
)}
|
|
1332
|
+
{skillsPicker === "browse" && (() => {
|
|
1333
|
+
const registry = getRegistrySkills();
|
|
1334
|
+
const installed = listInstalledSkills().map((s) => s.name);
|
|
1335
|
+
return (
|
|
1336
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
1337
|
+
<Text bold color={theme.colors.secondary}>Browse Skills Registry:</Text>
|
|
1338
|
+
{registry.map((s, i) => (
|
|
1339
|
+
<Text key={s.name}>
|
|
1340
|
+
{i === skillsPickerIndex ? <Text color={theme.colors.suggestion} bold>{"▸ "}</Text> : <Text>{" "}</Text>}
|
|
1341
|
+
<Text color={i === skillsPickerIndex ? theme.colors.suggestion : theme.colors.primary} bold>{s.name}</Text>
|
|
1342
|
+
<Text color={theme.colors.muted}>{" — "}{s.description}</Text>
|
|
1343
|
+
{installed.includes(s.name) ? <Text color={theme.colors.success}> ✓</Text> : null}
|
|
1344
|
+
</Text>
|
|
1345
|
+
))}
|
|
1346
|
+
<Text dimColor>{" ↑↓ navigate · Enter install · Esc back"}</Text>
|
|
1347
|
+
</Box>
|
|
1348
|
+
);
|
|
1349
|
+
})()}
|
|
1350
|
+
{skillsPicker === "installed" && (() => {
|
|
1351
|
+
const installed = listInstalledSkills();
|
|
1352
|
+
const active = getActiveSkills(process.cwd(), sessionDisabledSkills);
|
|
1353
|
+
return (
|
|
1354
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
1355
|
+
<Text bold color={theme.colors.secondary}>Installed Skills:</Text>
|
|
1356
|
+
{installed.length === 0 ? (
|
|
1357
|
+
<Text color={theme.colors.muted}> No skills installed. Use Browse & Install.</Text>
|
|
1358
|
+
) : installed.map((s, i) => (
|
|
1359
|
+
<Text key={s.name}>
|
|
1360
|
+
{i === skillsPickerIndex ? <Text color={theme.colors.suggestion} bold>{"▸ "}</Text> : <Text>{" "}</Text>}
|
|
1361
|
+
<Text color={i === skillsPickerIndex ? theme.colors.suggestion : theme.colors.primary} bold>{s.name}</Text>
|
|
1362
|
+
<Text color={theme.colors.muted}>{" — "}{s.description}</Text>
|
|
1363
|
+
{active.includes(s.name) ? <Text color={theme.colors.success}> (on)</Text> : <Text color={theme.colors.muted}> (off)</Text>}
|
|
1364
|
+
</Text>
|
|
1365
|
+
))}
|
|
1366
|
+
<Text dimColor>{" ↑↓ navigate · Enter toggle · Esc back"}</Text>
|
|
1367
|
+
</Box>
|
|
1368
|
+
);
|
|
1369
|
+
})()}
|
|
1370
|
+
{skillsPicker === "remove" && (() => {
|
|
1371
|
+
const installed = listInstalledSkills();
|
|
1372
|
+
return (
|
|
1373
|
+
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.error} paddingX={1} marginBottom={0}>
|
|
1374
|
+
<Text bold color={theme.colors.error}>Remove a skill:</Text>
|
|
1375
|
+
{installed.map((s, i) => (
|
|
1376
|
+
<Text key={s.name}>
|
|
1377
|
+
{i === skillsPickerIndex ? <Text color={theme.colors.suggestion} bold>{"▸ "}</Text> : <Text>{" "}</Text>}
|
|
1378
|
+
<Text color={i === skillsPickerIndex ? theme.colors.suggestion : theme.colors.muted}>{s.name} — {s.description}</Text>
|
|
1379
|
+
</Text>
|
|
1380
|
+
))}
|
|
1381
|
+
<Text dimColor>{" ↑↓ navigate · Enter remove · Esc back"}</Text>
|
|
1382
|
+
</Box>
|
|
1383
|
+
);
|
|
1384
|
+
})()}
|
|
1385
|
+
|
|
1075
1386
|
{/* ═══ THEME PICKER ═══ */}
|
|
1076
1387
|
{themePicker && (
|
|
1077
1388
|
<Box flexDirection="column" borderStyle="single" borderColor={theme.colors.border} paddingX={1} marginBottom={0}>
|
|
@@ -1182,6 +1493,10 @@ function App() {
|
|
|
1182
1493
|
return "";
|
|
1183
1494
|
})()}
|
|
1184
1495
|
{modelName ? ` · 🤖 ${modelName}` : ""}
|
|
1496
|
+
{(() => {
|
|
1497
|
+
const count = getActiveSkillCount(process.cwd(), sessionDisabledSkills);
|
|
1498
|
+
return count > 0 ? ` · 🧠 ${count} skill${count !== 1 ? "s" : ""}` : "";
|
|
1499
|
+
})()}
|
|
1185
1500
|
</Text>
|
|
1186
1501
|
</Box>
|
|
1187
1502
|
)}
|