aryx-cli 1.0.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/bin/aryx ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ const { spawnSync } = require('node:child_process');
3
+ const { join } = require('node:path');
4
+
5
+ const entry = join(__dirname, '..', 'src', 'index.tsx');
6
+ const result = spawnSync(process.execPath, ['--import', 'tsx', entry, ...process.argv.slice(2)], {
7
+ stdio: 'inherit'
8
+ });
9
+
10
+ if (result.error) {
11
+ console.error(result.error.message);
12
+ process.exit(1);
13
+ }
14
+
15
+ process.exit(result.status ?? 0);
package/bin/aryx.cjs ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ const { spawnSync } = require('node:child_process');
3
+ const { join } = require('node:path');
4
+
5
+ const entry = join(__dirname, '..', 'src', 'index.tsx');
6
+ const result = spawnSync(process.execPath, ['--import', 'tsx', entry, ...process.argv.slice(2)], {
7
+ stdio: 'inherit'
8
+ });
9
+
10
+ if (result.error) {
11
+ console.error(result.error.message);
12
+ process.exit(1);
13
+ }
14
+
15
+ process.exit(result.status ?? 0);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "aryx-cli",
3
+ "version": "1.0.0",
4
+ "description": "Aryx - intelligence inside your terminal",
5
+ "type": "module",
6
+ "files": [
7
+ "src",
8
+ "bin"
9
+ ],
10
+ "bin": {
11
+ "aryx": "./bin/aryx"
12
+ },
13
+ "scripts": {
14
+ "dev": "tsx src/index.tsx",
15
+ "start": "node --import tsx src/index.tsx",
16
+ "build": "tsc --noEmit",
17
+ "clean": "npm link"
18
+ },
19
+ "dependencies": {
20
+ "chalk": "^5.3.0",
21
+ "diff": "^8.0.4",
22
+ "figlet": "^1.7.0",
23
+ "ink": "^5.2.1",
24
+ "ink-text-input": "^5.0.1",
25
+ "marked": "^17.0.5",
26
+ "marked-terminal": "^7.3.0",
27
+ "meow": "^13.1.0",
28
+ "ora": "^9.3.0",
29
+ "react": "^18.2.0",
30
+ "string-width": "^8.2.0",
31
+ "tsx": "^4.7.0",
32
+ "zod": "^3.22.4"
33
+ },
34
+ "devDependencies": {
35
+ "@types/diff": "^7.0.2",
36
+ "@types/figlet": "^1.5.8",
37
+ "@types/marked-terminal": "^6.1.1",
38
+ "@types/node": "^20.11.5",
39
+ "@types/react": "^18.2.48",
40
+ "typescript": "^5.3.3"
41
+ }
42
+ }
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { theme, GRADIENT_COMMAND } from '../theme.js';
4
+ import { BRAND_NAME } from '../constants.js';
5
+ import { GradientText } from './IAmAryx.js';
6
+
7
+ export interface Command {
8
+ name: string;
9
+ description: string;
10
+ }
11
+
12
+ export const commands: Command[] = [
13
+ { name: '/upgrade', description: `Upgrade to Max for higher rate limits` },
14
+ { name: '/login', description: `Sign in to ${BRAND_NAME} with Google` },
15
+ { name: '/logout', description: `Sign out of your ${BRAND_NAME} account` },
16
+ { name: '/theme', description: 'Change diff color theme' },
17
+ { name: '/help', description: 'Show help and available commands' },
18
+ { name: '/usage', description: 'Show token usage and session stats' },
19
+ { name: '/clear', description: 'Clear conversation history and free up context' },
20
+ { name: '/exit', description: 'Exit the chat' },
21
+ { name: '/aryx', description: `About the creator of ${BRAND_NAME}` },
22
+ ];
23
+
24
+ interface Props {
25
+ filteredCommands: Command[];
26
+ selectedIndex: number;
27
+ }
28
+
29
+ const CommandSuggestions: React.FC<Props> = ({ filteredCommands, selectedIndex }) => {
30
+ if (filteredCommands.length === 0) return null;
31
+
32
+ return (
33
+ <Box
34
+ flexDirection="column"
35
+ marginTop={1}
36
+ paddingLeft={2}
37
+ marginBottom={1}>
38
+ {filteredCommands.map((cmd, index) => {
39
+ const isSelected = index === selectedIndex;
40
+ const isGradient = cmd.name === '/aryx';
41
+ const textColor = isSelected ? theme.colors.highlight : 'gray';
42
+
43
+ return (
44
+ <Box key={cmd.name} marginBottom={0}>
45
+ <Box width={15}>
46
+ {isGradient
47
+ ? <GradientText text={cmd.name} colors={GRADIENT_COMMAND} />
48
+ : <Text color={textColor}>{cmd.name}</Text>}
49
+ </Box>
50
+
51
+ <Box flexGrow={1}>
52
+ <Text color={textColor}>{cmd.description}</Text>
53
+ </Box>
54
+ </Box>
55
+ );
56
+ })}
57
+ </Box>
58
+ );
59
+ };
60
+
61
+
62
+ export default CommandSuggestions;
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { theme, PLAN_COLORS } from '../theme.js';
4
+ import { BRAND_NAME, VERSION, OPENROUTER_MODEL } from '../constants.js';
5
+ import { readAuth } from '../services/auth.js';
6
+
7
+ interface HeaderProps {
8
+ name: string;
9
+ cwd: string;
10
+ subscriptionPlan: string;
11
+ }
12
+
13
+ const Header: React.FC<HeaderProps> = ({ name, cwd, subscriptionPlan }) => {
14
+ const auth = readAuth();
15
+ const planColor = PLAN_COLORS[subscriptionPlan] ?? 'gray';
16
+ // Array format preserves exact alignment in code and avoids line-wrapping bugs in the terminal.
17
+ const robotAscii = [
18
+ ' ▐▛███▜▌ ',
19
+ '▝▜█████▛▘',
20
+ ' ▘▘ ▝▝ '
21
+ ];
22
+
23
+ return (
24
+ <Box
25
+ borderStyle="round"
26
+ borderColor={theme.colors.primary}
27
+ flexDirection="column"
28
+ paddingX={2}
29
+ paddingTop={1}
30
+ width={55}>
31
+
32
+ {/* Title in border */}
33
+ <Box
34
+ position="absolute"
35
+ marginTop={-2}
36
+ marginLeft={2}>
37
+ <Text color={theme.colors.primary}>
38
+ {` ${BRAND_NAME} `}
39
+ <Text color="gray">v{VERSION} </Text>
40
+ </Text>
41
+ </Box>
42
+
43
+ <Box
44
+ flexDirection="column"
45
+ alignItems="center"
46
+ width="100%">
47
+ <Text bold>Welcome back {name}!</Text>
48
+
49
+ <Box
50
+ marginTop={1}
51
+ flexDirection="column"
52
+ alignItems="center">
53
+ {robotAscii.map((line, index) => (
54
+ <Text key={index} color={theme.colors.primary}>
55
+ {line}
56
+ </Text>
57
+ ))}
58
+ </Box>
59
+
60
+ <Box
61
+ flexDirection="column"
62
+ alignItems="center">
63
+ <Text color="gray">{OPENROUTER_MODEL}{' • '}
64
+ <Text color={planColor}>
65
+ {BRAND_NAME} {subscriptionPlan.charAt(0).toUpperCase() + subscriptionPlan.slice(1)}
66
+ </Text>
67
+ </Text>
68
+ {auth && <Text color="gray">{auth.email}</Text>}
69
+ <Text color="gray">{cwd}</Text>
70
+ </Box>
71
+ </Box>
72
+ </Box>
73
+ );
74
+
75
+ };
76
+
77
+ export default Header;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { theme } from '../theme.js';
4
+
5
+ const HelpView: React.FC = () => {
6
+ return (
7
+ <Box
8
+ flexDirection="column"
9
+ marginTop={1}
10
+ paddingLeft={2}>
11
+ <Box marginBottom={1}>
12
+ <Text bold color={theme.colors.highlight}>Help</Text>
13
+ </Box>
14
+
15
+ <Box flexDirection="row" marginBottom={1}>
16
+ <Box flexDirection="column" marginRight={4}>
17
+ <Text color="white">/ for commands</Text>
18
+ <Text color="white">@ for file paths</Text>
19
+ <Text color="white">click esc to clear input</Text>
20
+ </Box>
21
+
22
+ <Box flexDirection="column">
23
+ <Text color="white">ctrl + c to copy text</Text>
24
+ <Text color="white">ctrl + v to paste text</Text>
25
+ </Box>
26
+ </Box>
27
+
28
+ <Box>
29
+ <Text color="gray" italic>Esc to cancel</Text>
30
+ </Box>
31
+ </Box>
32
+ );
33
+
34
+ };
35
+
36
+ export default HelpView;
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { GRADIENT_BRAND } from '../theme.js';
4
+ import { BRAND_NAME } from '../constants.js';
5
+
6
+ export const GradientText: React.FC<{ text: string; bold?: boolean; colors?: string[] }> = ({ text, bold, colors = GRADIENT_BRAND }) => (
7
+ <>
8
+ {text.split('').map((char, i) => (
9
+ <Text key={i} color={colors[i % colors.length]} bold={bold}>{char}</Text>
10
+ ))}
11
+ </>
12
+ );
13
+
14
+ const IAmAryxView: React.FC = () => (
15
+ <Box
16
+ flexDirection="column"
17
+ marginTop={1}
18
+ paddingLeft={2}>
19
+ <Box marginBottom={1}>
20
+ <Text color="white" bold>Hey! I'm </Text>
21
+ <GradientText text={BRAND_NAME} bold />
22
+ <Text color="white" bold> 🚀</Text>
23
+ </Box>
24
+
25
+ <Box
26
+ flexDirection="column"
27
+ marginBottom={1}>
28
+ <Text color="gray">Your AI buddy in the terminal — built for learning, experimenting, and occasionally breaking things 😄</Text>
29
+ <Text color="gray">I help you explore ideas, practice skills, and try out crazy concepts.</Text>
30
+ <Text color="gray">Not perfect, but always improving.</Text>
31
+ </Box>
32
+
33
+ <Box flexDirection="column">
34
+ <Box justifyContent="flex-start">
35
+ <Text color="gray">— Developed by </Text>
36
+ <Text color="white" bold>Vasu Bhalodiya</Text>
37
+ </Box>
38
+ <Box justifyContent="flex-start">
39
+ <Text color="gray" bold italic> Linkedin → </Text>
40
+ <Text color="cyan" italic>https://www.linkedin.com/in/vasubhalodiya</Text>
41
+ </Box>
42
+ </Box>
43
+
44
+ <Box marginTop={1}>
45
+ <Text color="gray" italic>Esc to cancel</Text>
46
+ </Box>
47
+ </Box>
48
+ );
49
+
50
+
51
+ export default IAmAryxView;
@@ -0,0 +1,57 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { theme, SHIMMER_COLORS } from '../theme.js';
4
+ import { SPINNER_FRAMES } from '../constants.js';
5
+
6
+ const Loader: React.FC<{ text?: string }> = ({ text = 'Thinking...' }) => {
7
+ const [iconFrame, setIconFrame] = useState(0);
8
+ const [shimmerFrame, setShimmerFrame] = useState(0);
9
+
10
+ // Icon speed → 180ms
11
+ useEffect(() => {
12
+ const timer = setInterval(() => {
13
+ setIconFrame((prev) => (prev + 1) % SPINNER_FRAMES.length);
14
+ }, 180);
15
+
16
+ return () => clearInterval(timer);
17
+ }, []);
18
+
19
+ useEffect(() => {
20
+ const timer = setInterval(() => {
21
+ setShimmerFrame((prev) => prev + 1);
22
+ }, 120);
23
+
24
+ return () => clearInterval(timer);
25
+ }, []);
26
+
27
+ return (
28
+ <Box flexDirection="row" marginBottom={1}>
29
+ <Text color={theme.colors.highlight}>
30
+ {SPINNER_FRAMES[iconFrame]}
31
+ </Text>
32
+
33
+ <Box marginLeft={2}>
34
+ <Text>
35
+ {text.split('').map((char, i) => {
36
+ const pos = shimmerFrame % 26;
37
+
38
+ let color = theme.colors.highlight;
39
+
40
+ if (i === pos) color = SHIMMER_COLORS.bright;
41
+ else if (i === pos - 1) color = SHIMMER_COLORS.mid;
42
+ else if (i === pos - 2) color = SHIMMER_COLORS.dim;
43
+
44
+ return (
45
+ <Text key={i} color={color}>
46
+ {char}
47
+ </Text>
48
+ );
49
+ })}
50
+ </Text>
51
+ </Box>
52
+ </Box>
53
+ );
54
+ };
55
+
56
+
57
+ export default Loader;
@@ -0,0 +1,129 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Text, useInput } from 'ink';
3
+ import { startCallbackServer } from '../services/loginServer.js';
4
+ import { saveAuth } from '../services/auth.js';
5
+ import { openBrowser, copyToClipboard } from '../services/platform.js';
6
+ import { theme } from '../theme.js';
7
+ import { WEB_URL, SPINNER_FRAMES } from '../constants.js';
8
+
9
+ type LoginState = 'opening' | 'waiting' | 'success' | 'error';
10
+
11
+ interface Props {
12
+ onComplete: () => void;
13
+ onCancel: () => void;
14
+ }
15
+
16
+ const LoginView: React.FC<Props> = ({ onComplete, onCancel }) => {
17
+ const [state, setState] = useState<LoginState>('opening');
18
+ const [email, setEmail] = useState('');
19
+ const [loginUrl, setLoginUrl] = useState('');
20
+ const [errorMsg, setErrorMsg] = useState('');
21
+ const [copied, setCopied] = useState(false);
22
+ const [frame, setFrame] = useState(0);
23
+
24
+ useEffect(() => {
25
+ if (state !== 'opening') return;
26
+ const t = setInterval(() => setFrame(f => (f + 1) % SPINNER_FRAMES.length), 180);
27
+ return () => clearInterval(t);
28
+ }, [state]);
29
+
30
+ useInput((input, key) => {
31
+ if (key.escape) { onCancel(); return; }
32
+ if (state === 'success' && key.return) { onComplete(); return; }
33
+ if (state === 'waiting' && input === 'c') {
34
+ copyToClipboard(loginUrl);
35
+ setCopied(true);
36
+ setTimeout(() => setCopied(false), 2000);
37
+ }
38
+ });
39
+
40
+ useEffect(() => {
41
+ (async () => {
42
+ try {
43
+ const { port, waitForCallback } = await startCallbackServer();
44
+ const url = `${WEB_URL}/auth?cli_port=${port}`;
45
+ openBrowser(url);
46
+ setLoginUrl(url);
47
+ setState('waiting');
48
+
49
+ const data = await waitForCallback;
50
+
51
+ saveAuth({
52
+ uid: data.uid,
53
+ email: data.email,
54
+ displayName: data.displayName,
55
+ photoURL: data.photoURL,
56
+ idToken: data.idToken,
57
+ refreshToken: data.refreshToken,
58
+ idTokenExpiry: Date.now() + 3_600_000,
59
+ });
60
+
61
+ setEmail(data.email);
62
+ setState('success');
63
+ } catch (err: unknown) {
64
+ const msg = err instanceof Error ? err.message : 'Unknown error';
65
+ setErrorMsg(msg);
66
+ setState('error');
67
+ }
68
+ })();
69
+ }, []);
70
+
71
+ return (
72
+ <Box
73
+ flexDirection="column"
74
+ paddingX={1}
75
+ marginTop={0}>
76
+ <Text bold color={theme.colors.highlight}>Login</Text>
77
+
78
+ <Box
79
+ flexDirection="column"
80
+ marginTop={1}
81
+ paddingLeft={2}>
82
+ {state === 'opening' && (
83
+ <Box>
84
+ <Text color={theme.colors.highlight}>{SPINNER_FRAMES[frame]} </Text>
85
+ <Text color="white">Opening browser to sign in...</Text>
86
+ </Box>
87
+ )}
88
+
89
+ {state === 'waiting' && (
90
+ <Box flexDirection="column">
91
+ <Box>
92
+ <Text color="gray">Browser didn't open? Use the url below to sign in </Text>
93
+
94
+ {copied
95
+ ? <Text color={theme.colors.highlight}>(Copied!)</Text>
96
+ : <Text color="gray">(c to copy)</Text>}
97
+ </Box>
98
+
99
+ <Text color={theme.colors.primary}>{loginUrl}</Text>
100
+ </Box>
101
+ )}
102
+
103
+ {state === 'success' && (
104
+ <>
105
+ <Box flexDirection="row" flexWrap="nowrap">
106
+ <Text color="white">Logged in as </Text>
107
+ <Text color={theme.colors.primary}>{email}</Text>
108
+ </Box>
109
+
110
+ <Box flexDirection="column" marginTop={1}>
111
+ <Text color={theme.colors.highlight}>Login successful. Press Enter to continue…</Text>
112
+ </Box>
113
+ </>
114
+ )}
115
+
116
+ {state === 'error' && (
117
+ <Text color="red">Login failed: {errorMsg}</Text>
118
+ )}
119
+ </Box>
120
+
121
+ <Box marginTop={1}>
122
+ <Text color="gray" italic>Esc to cancel</Text>
123
+ </Box>
124
+ </Box>
125
+ );
126
+
127
+ };
128
+
129
+ export default LoginView;
@@ -0,0 +1,65 @@
1
+ import React, { useMemo } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { Message as MessageType } from '../hooks/useChat.js';
4
+ import { theme, USER_MESSAGE_BG } from '../theme.js';
5
+ import { marked } from 'marked';
6
+ import { markedTerminal } from 'marked-terminal';
7
+ import chalk from 'chalk';
8
+
9
+ const ext: any = markedTerminal({
10
+ tab: 0,
11
+ showSectionPrefix: false,
12
+ firstHeading: chalk.green.bold,
13
+ });
14
+ const originalText = ext.renderer.text;
15
+ ext.renderer.text = function(text: any) {
16
+ if (typeof text === 'object' && text.tokens) {
17
+ return (this as any).parser.parseInline(text.tokens);
18
+ }
19
+ return originalText.apply(this, arguments as any);
20
+ };
21
+ marked.use(ext);
22
+
23
+
24
+ interface MessageProps {
25
+ message: MessageType;
26
+ }
27
+
28
+ const Message: React.FC<MessageProps> = ({ message }) => {
29
+ const isUser = message.role === 'user';
30
+ const width = process.stdout.columns || 80;
31
+
32
+ const formattedAssistantContent = useMemo(() => {
33
+ if (isUser) return '';
34
+ try {
35
+ // Use marked.parse with async: false for AI messages only
36
+ const parsed = marked.parse(message.content, { async: false }) as string;
37
+ return parsed.trimEnd();
38
+ } catch (e) {
39
+ return message.content;
40
+ }
41
+ }, [message.content, isUser]);
42
+
43
+ return (
44
+ <Box
45
+ flexDirection="row"
46
+ marginBottom={1}
47
+ width="100%">
48
+ <Text
49
+ backgroundColor={isUser ? USER_MESSAGE_BG : undefined}
50
+ color="white">
51
+ {isUser ? (
52
+ ('❯ ' + message.content).padEnd(width, ' ')
53
+ ) : (
54
+ <>
55
+ <Text color={theme.colors.highlight}>✦ </Text>
56
+ {formattedAssistantContent.padEnd(Math.max(0, width - 3), ' ')}
57
+ </>
58
+ )}
59
+ </Text>
60
+ </Box>
61
+ );
62
+ };
63
+
64
+
65
+ export default Message;
@@ -0,0 +1,92 @@
1
+ import React, { useState } from 'react';
2
+ import { Box, Text, useInput } from 'ink';
3
+ import chalk from 'chalk';
4
+ import { theme, saveTheme, DIFF_COLORS } from '../theme.js';
5
+ import { BRAND_NAME } from '../constants.js';
6
+
7
+ const OPTIONS: { id: 1 | 2 | 3 | 4; label: string }[] = [
8
+ { id: 1, label: 'Modern mode' },
9
+ { id: 2, label: 'Classic mode' },
10
+ { id: 3, label: 'Modern mode (text only)' },
11
+ { id: 4, label: 'Classic mode (text only)' },
12
+ ];
13
+
14
+ const PREVIEW = [
15
+ { t: 's', n: 1, l: 'function greet() {' },
16
+ { t: 'r', n: 2, l: ' console.log("Hello, World!");' },
17
+ { t: 'a', n: 2, l: ` console.log("Hello, ${BRAND_NAME}!");` },
18
+ { t: 's', n: 3, l: '}' },
19
+ ];
20
+
21
+ const makePreview = (id: 1 | 2 | 3 | 4): string => {
22
+ const { add, rm } = DIFF_COLORS[id];
23
+ const bg = id <= 2;
24
+ return PREVIEW.map(({ t, n, l }) => {
25
+ const ln = String(n).padStart(4);
26
+ if (t === 's') return chalk.gray(` ${ln} ${l}`);
27
+ if (t === 'r') return bg ? chalk.bgHex(rm).black(`- ${ln} ${l}`) : chalk.hex(rm)(`- ${ln} ${l}`);
28
+ return bg ? chalk.bgHex(add).black(`+ ${ln} ${l}`) : chalk.hex(add)(`+ ${ln} ${l}`);
29
+ }).join('\n');
30
+ };
31
+
32
+ const ThemeSelector: React.FC<{ onClose: () => void; isSetup?: boolean }> = ({ onClose, isSetup }) => {
33
+ const [cursor, setCursor] = useState(theme.diffTheme - 1);
34
+
35
+ useInput((_, key) => {
36
+ if (key.upArrow) setCursor(c => (c > 0 ? c - 1 : OPTIONS.length - 1));
37
+ if (key.downArrow) setCursor(c => (c < OPTIONS.length - 1 ? c + 1 : 0));
38
+ if (key.return) {
39
+ theme.diffTheme = OPTIONS[cursor].id;
40
+ saveTheme(OPTIONS[cursor].id);
41
+ onClose();
42
+ }
43
+ if (key.escape && !isSetup) onClose();
44
+ });
45
+
46
+ return (
47
+ <Box
48
+ flexDirection="column"
49
+ paddingX={1}
50
+ marginTop={1}>
51
+ {!isSetup && <Text bold color={theme.colors.highlight}>Theme</Text>}
52
+
53
+ <Text
54
+ bold={isSetup}
55
+ color={isSetup ? 'white' : 'gray'}>Choose the text style that looks best with your terminal</Text>
56
+
57
+ {isSetup && <Text color="gray">To change this later, run /theme</Text>}
58
+
59
+ <Box flexDirection="column" marginTop={1}>
60
+ {OPTIONS.map((opt, i) => (
61
+ <Box key={opt.id}>
62
+ <Text color={cursor === i ? theme.colors.highlight : undefined}>{cursor === i ? '❯ ' : ' '}</Text>
63
+ <Text color={cursor === i ? 'white' : 'gray'}>{i + 1}. {opt.label}</Text>
64
+ {theme.diffTheme === opt.id && <Text color={theme.colors.highlight}> ✔</Text>}
65
+ </Box>
66
+ ))}
67
+ </Box>
68
+
69
+ <Box
70
+ flexDirection="column"
71
+ marginTop={1}
72
+ paddingLeft={1}
73
+ borderStyle="round"
74
+ borderColor="gray">
75
+ <Text>{makePreview(OPTIONS[cursor].id)}</Text>
76
+ </Box>
77
+
78
+ <Box marginY={1}>
79
+ <Text color="gray" dimColor>Syntax theme: {OPTIONS[cursor].label}</Text>
80
+ </Box>
81
+
82
+ {!isSetup && (
83
+ <Box>
84
+ <Text color="gray" italic>Enter to select · Esc to cancel</Text>
85
+ </Box>
86
+ )}
87
+ </Box>
88
+ );
89
+
90
+ };
91
+
92
+ export default ThemeSelector;