omnibot3000 1.9.7 → 1.9.9

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.
Files changed (40) hide show
  1. package/.github/workflows/publish.yml +0 -3
  2. package/.stylelintrc.json +12 -0
  3. package/README.md +3 -3
  4. package/api/server.ts +34 -23
  5. package/package.json +25 -21
  6. package/src/App.module.css +16 -14
  7. package/src/Error.tsx +2 -2
  8. package/src/commons/OmnibotSpeak.module.css +13 -2
  9. package/src/commons/hooks/useStorage.tsx +1 -0
  10. package/src/commons/layout/Background.module.css +4 -2
  11. package/src/commons/layout/Breadcrumb.module.css +1 -0
  12. package/src/commons/layout/Container.module.css +2 -2
  13. package/src/commons/layout/Container.tsx +6 -1
  14. package/src/commons/layout/Footer.module.css +12 -2
  15. package/src/commons/layout/Footer.tsx +10 -3
  16. package/src/commons/layout/Header.module.css +3 -4
  17. package/src/commons/layout/Menu.module.css +10 -0
  18. package/src/commons/layout/Menu.tsx +3 -2
  19. package/src/commons/persona.txt +3 -0
  20. package/src/commons/styles/debug.css +9 -11
  21. package/src/commons/styles/main.css +45 -32
  22. package/src/commons/styles/vt220.css +7 -8
  23. package/src/commons/ui/Box.module.css +2 -1
  24. package/src/commons/ui/Box.tsx +3 -3
  25. package/src/commons/ui/Caret.tsx +2 -1
  26. package/src/commons/ui/Line.tsx +3 -4
  27. package/src/commons/ui/Number.tsx +29 -0
  28. package/src/commons/ui/ProgressBar.module.css +29 -0
  29. package/src/commons/ui/ProgressBar.tsx +77 -0
  30. package/src/commons/utils/math.ts +43 -0
  31. package/src/commons/utils/strings.ts +8 -7
  32. package/src/features/chat/components/Message.tsx +1 -1
  33. package/src/features/cli/Cli.tsx +18 -41
  34. package/src/features/cli/components/RenderCli.tsx +47 -0
  35. package/src/features/history/History.module.css +2 -2
  36. package/src/features/version/Version.module.css +12 -0
  37. package/src/features/version/Version.tsx +24 -17
  38. package/tsconfig.api.json +2 -2
  39. package/tsconfig.json +18 -19
  40. package/vite.config.ts +4 -2
@@ -17,13 +17,10 @@ jobs:
17
17
 
18
18
  - name: setup pnpm
19
19
  uses: pnpm/action-setup@v4
20
- with:
21
- version: 9
22
20
 
23
21
  - name: setup Node.js
24
22
  uses: actions/setup-node@v4
25
23
  with:
26
- node-version: "20"
27
24
  cache: "pnpm"
28
25
  registry-url: "https://registry.npmjs.org"
29
26
 
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "stylelint-config-standard",
3
+ "rules": {
4
+ "selector-class-pattern": [
5
+ "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
6
+ {
7
+ "message": "expect class selector to be kebab-case"
8
+ }
9
+ ]
10
+ },
11
+ "ignoreFiles": ["node_modules/**", "dist/**"]
12
+ }
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- ## OMNIBOT 3000
1
+ # OMNIBOT 3000
2
2
 
3
- YOUR OMNISCIENT SOURCE OF TRUTH
3
+ ## YOUR OMNISCIENT SOURCE OF TRUTH
4
4
 
5
5
  ![image](https://github.com/user-attachments/assets/f3c88ab8-4c8c-4056-8d82-9cfb3fbe023e)
6
6
 
@@ -35,7 +35,7 @@ OPENAI_API_KEY=<your_openai_api_key>
35
35
 
36
36
  ### Package
37
37
 
38
- https://www.npmjs.com/package/omnibot3000
38
+ <https://www.npmjs.com/package/omnibot3000>
39
39
 
40
40
  ### Contributing
41
41
 
package/api/server.ts CHANGED
@@ -1,9 +1,10 @@
1
- import {exec} from "child_process";
1
+ import {execSync} from "child_process";
2
2
  import {
3
3
  accessSync,
4
4
  constants as FS,
5
5
  Dirent,
6
6
  readdirSync,
7
+ realpathSync,
7
8
  statSync,
8
9
  writeFileSync,
9
10
  } from "fs";
@@ -12,13 +13,9 @@ import path from "path";
12
13
 
13
14
  import "dotenv/config";
14
15
  import {Mistral} from "@mistralai/mistralai";
15
- import type {
16
- ChatCompletionRequest,
17
- CompletionEvent,
18
- } from "@mistralai/mistralai/models/components";
19
16
  import OpenAI from "openai";
20
17
  import type {ChatCompletionCreateParamsNonStreaming} from "openai/resources/chat/completions";
21
- import type {ChatCompletionChunk} from "openai/resources/index.mjs";
18
+ import type {ChatCompletionChunk} from "openai/resources/chat/completions/completions";
22
19
  import type {Stream} from "openai/streaming";
23
20
 
24
21
  type Package = {
@@ -35,11 +32,14 @@ const JSON_PATH = path.join(BASE_PATH, "dist", "packages.json");
35
32
 
36
33
  type Provider = "openai" | "mistral";
37
34
 
38
- export const MODEL: Provider = "openai";
35
+ export const MODEL: Provider = "openai" as Provider;
39
36
  const MAX_TOKENS = 1000;
40
37
 
41
38
  type OpenAIConfig = Omit<ChatCompletionCreateParamsNonStreaming, "messages">;
42
- type MistralConfig = Omit<ChatCompletionRequest, "messages">;
39
+ type MistralConfig = Omit<
40
+ Parameters<Mistral["chat"]["complete"]>[0],
41
+ "messages"
42
+ >;
43
43
 
44
44
  export const API_CONFIG = {
45
45
  openai: {
@@ -58,21 +58,24 @@ export const API_CONFIG = {
58
58
  topP: 0.1 /* nucleus sampling */,
59
59
  frequencyPenalty: 1.0 /* avoid repetition */,
60
60
  presencePenalty: 1.0 /* encourage new topics */,
61
- maxTokens: MAX_TOKENS,
61
+ maxTokens: MAX_TOKENS + 500,
62
62
  randomSeed: Math.round(Math.random() * 1e9),
63
63
  } satisfies MistralConfig,
64
64
  };
65
65
 
66
66
  const getFolderSize = (folder: string): number => {
67
+ const resolved = path.resolve(folder);
68
+ if (!resolved.startsWith(BASE_PATH)) return 0;
67
69
  let total = 0;
68
70
  try {
69
- accessSync(folder, FS.R_OK);
71
+ accessSync(resolved, FS.R_OK);
70
72
  } catch {
71
73
  return total;
72
74
  }
73
- const files: Dirent[] = readdirSync(folder, {withFileTypes: true});
75
+ const files: Dirent[] = readdirSync(resolved, {withFileTypes: true});
74
76
  for (const file of files) {
75
- const fullPath = path.join(folder, file.name);
77
+ const fullPath = path.resolve(resolved, file.name);
78
+ if (!fullPath.startsWith(BASE_PATH)) continue;
76
79
  if (file.isDirectory()) total += getFolderSize(fullPath);
77
80
  else total += statSync(fullPath).size;
78
81
  }
@@ -153,7 +156,7 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
153
156
  messages,
154
157
  });
155
158
  /* forward chunks to browser as SSE */
156
- for await (const chunk of response as AsyncIterable<CompletionEvent>) {
159
+ for await (const chunk of response) {
157
160
  res.write(`data: ${JSON.stringify(chunk)}\n\n`);
158
161
  }
159
162
  /* end the SSE stream */
@@ -199,29 +202,37 @@ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
199
202
  res.writeHead(200, {"Content-Type": "application/json"});
200
203
  res.end(JSON.stringify(config));
201
204
  } else if (url.startsWith(`${API_PATH}/packages`)) {
202
- exec("npm list --json --depth=0 --silent", (err, stdout) => {
203
- if (err) {
204
- const error = err instanceof Error ? err.message : "unknown error";
205
- res.writeHead(500, {"Content-Type": "application/json"});
206
- res.end(JSON.stringify({error}));
207
- return;
208
- }
205
+ try {
206
+ const stdout = execSync("npm list --json --depth=0 --prod --silent", {
207
+ encoding: "utf8",
208
+ });
209
209
  const json = JSON.parse(stdout);
210
210
  const data = json?.dependencies || {};
211
211
  const list = Object.keys(data)
212
212
  .map((key) => {
213
- const dir = data[key].resolved.replace("file:", "");
213
+ const modulePath = path.join(BASE_PATH, "node_modules", key);
214
+ let resolvedPath;
215
+ try {
216
+ resolvedPath = realpathSync(modulePath);
217
+ } catch {
218
+ resolvedPath = modulePath;
219
+ }
220
+
214
221
  return {
215
222
  name: key,
216
223
  version: data[key].version.split(".") as Package["version"],
217
- size: getFolderSize(path.join(BASE_PATH, "node_modules", dir)),
224
+ size: getFolderSize(resolvedPath),
218
225
  };
219
226
  })
220
227
  .sort((a, b) => (a.name < b.name ? -1 : 1));
221
228
  res.writeHead(200, {"Content-Type": "application/json"});
222
229
  res.end(JSON.stringify(list));
223
230
  writeFileSync(JSON_PATH, JSON.stringify(list, null, 2));
224
- });
231
+ } catch (error) {
232
+ const message = error instanceof Error ? error.message : "unknown error";
233
+ res.writeHead(500, {"Content-Type": "application/json"});
234
+ res.end(JSON.stringify({error: message}));
235
+ }
225
236
  } else {
226
237
  res.writeHead(404);
227
238
  res.end("nothing to see here");
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "x-display-name": "OMNIBOT 3000",
4
4
  "description": "your omniscient source of truth",
5
5
  "private": false,
6
- "version": "1.9.7",
6
+ "version": "1.9.9",
7
7
  "type": "module",
8
8
  "author": {
9
9
  "name": "rez",
@@ -19,37 +19,39 @@
19
19
  "omnibot": "./bin/omnibot.js"
20
20
  },
21
21
  "dependencies": {
22
- "@mistralai/mistralai": "^1.11.0",
23
- "openai": "^6.16.0",
24
- "react": "^19.2.3",
25
- "react-dom": "^19.2.3",
22
+ "@mistralai/mistralai": "^2.1.2",
23
+ "dotenv": "^17.3.1",
24
+ "openai": "^6.32.0",
25
+ "react": "^19.2.4",
26
+ "react-dom": "^19.2.4",
26
27
  "react-markdown": "^10.1.0",
27
- "react-router-dom": "^7.12.0",
28
- "zustand": "^5.0.10"
28
+ "react-router-dom": "^7.13.2",
29
+ "zustand": "^5.0.12"
29
30
  },
30
31
  "devDependencies": {
31
- "@eslint/js": "^9.39.2",
32
- "@types/node": "^25.0.9",
33
- "@types/react": "^19.2.8",
32
+ "@eslint/js": "^10.0.1",
33
+ "@types/node": "^25.5.0",
34
+ "@types/react": "^19.2.14",
34
35
  "@types/react-dom": "^19.2.3",
35
- "@vitejs/plugin-react": "^5.1.2",
36
+ "@vitejs/plugin-react": "^6.0.1",
36
37
  "classnames": "^2.5.1",
37
- "dotenv": "^17.2.3",
38
- "eslint": "^9.39.2",
38
+ "eslint": "^10.1.0",
39
39
  "eslint-plugin-import": "^2.32.0",
40
40
  "eslint-plugin-react-hooks": "^7.0.1",
41
- "eslint-plugin-react-refresh": "^0.4.26",
41
+ "eslint-plugin-react-refresh": "^0.5.2",
42
42
  "eslint-plugin-simple-import-sort": "^12.1.1",
43
- "globals": "^17.0.0",
43
+ "globals": "^17.4.0",
44
44
  "husky": "^9.1.7",
45
- "nodemon": "^3.1.11",
45
+ "knip": "^6.0.3",
46
+ "nodemon": "^3.1.14",
46
47
  "npm-run-all": "^4.1.5",
47
- "prettier": "^3.8.0",
48
+ "prettier": "^3.8.1",
48
49
  "react-refresh": "^0.18.0",
49
- "typescript": "^5.9.3",
50
- "typescript-eslint": "^8.53.0",
51
- "vite": "^7.3.1",
52
- "vite-tsconfig-paths": "^6.0.4"
50
+ "stylelint": "^17.5.0",
51
+ "stylelint-config-standard": "^40.0.0",
52
+ "typescript": "^6.0.2",
53
+ "typescript-eslint": "^8.57.2",
54
+ "vite": "^8.0.2"
53
55
  },
54
56
  "scripts": {
55
57
  "start": "pnpm run-p start:dev start:api",
@@ -63,6 +65,8 @@
63
65
  "build:client": "tsc -b && vite build",
64
66
  "build:api": "tsc --project tsconfig.api.json",
65
67
  "lint": "eslint --fix .",
68
+ "lint:css": "stylelint --fix 'src/**/*.css'",
69
+ "lint:deps": "knip --dependencies",
66
70
  "prettify": "prettier --write ."
67
71
  }
68
72
  }
@@ -26,22 +26,22 @@
26
26
  ),
27
27
  linear-gradient(
28
28
  30deg,
29
- hsla(calc(var(--h) - 90) 30% 30% / var(--opacity-background)) 0%,
30
- hsla(calc(var(--h) - 45) 50% 20% / var(--opacity-background)) 25%,
31
- hsla(calc(var(--h) + 0) 70% 10% / var(--opacity-background)) 50%,
32
- hsla(calc(var(--h) + 45) 50% 20% / var(--opacity-background)) 75%,
33
- hsla(calc(var(--h) + 90) 30% 30% / var(--opacity-background)) 100%
29
+ hsl(calc(var(--h) - 90) 30% 30% / var(--opacity-background)) 0%,
30
+ hsl(calc(var(--h) - 45) 50% 20% / var(--opacity-background)) 25%,
31
+ hsl(calc(var(--h) + 0) 70% 10% / var(--opacity-background)) 50%,
32
+ hsl(calc(var(--h) + 45) 50% 20% / var(--opacity-background)) 75%,
33
+ hsl(calc(var(--h) + 90) 30% 30% / var(--opacity-background)) 100%
34
34
  ),
35
35
  radial-gradient(
36
36
  circle,
37
- hsla(calc(var(--h) - 270) 30% 30% / var(--opacity-background)) 0%,
38
- hsla(calc(var(--h) - 180) 30% 30% / var(--opacity-background)) 100%
37
+ hsl(calc(var(--h) - 270) 30% 30% / var(--opacity-background)) 0%,
38
+ hsl(calc(var(--h) - 180) 30% 30% / var(--opacity-background)) 100%
39
39
  ),
40
40
  radial-gradient(
41
41
  circle,
42
- hsla(0 100% 100% / 0.0125) 0%,
43
- hsla(0 0% 0% / 0.25) 80%,
44
- hsla(0 0% 0% / 0.5) 100%
42
+ hsl(0deg 100% 100% / 1.25%) 0%,
43
+ hsl(0deg 0% 0% / 25%) 80%,
44
+ hsl(0deg 0% 0% / 50%) 100%
45
45
  );
46
46
  animation: fade-tty var(--duration-fade) linear;
47
47
  }
@@ -59,15 +59,15 @@
59
59
  animation: fade-tty var(--duration-fade) linear;
60
60
  background-image: repeating-linear-gradient(
61
61
  0deg,
62
- #0000 0rem,
63
- hsla(0 0% 0% / 0.3) 0.02rem,
64
- hsla(0 0% 0% / 0.3) 0.12rem,
62
+ #0000 0,
63
+ hsl(0deg 0% 0% / 30%) 0.02rem,
64
+ hsl(0deg 0% 0% / 30%) 0.12rem,
65
65
  #0000 0.14rem,
66
66
  #0000 0.2rem
67
67
  );
68
68
  background-size: 100%, 100%;
69
69
  background-repeat: no-repeat, repeat;
70
- background-position: 0rem -0.0333rem;
70
+ background-position: 0 -0.0333rem;
71
71
  background-blend-mode: overlay;
72
72
  }
73
73
 
@@ -119,9 +119,11 @@
119
119
  0% {
120
120
  opacity: 0;
121
121
  }
122
+
122
123
  20% {
123
124
  opacity: 0;
124
125
  }
126
+
125
127
  100% {
126
128
  opacity: 1;
127
129
  }
package/src/Error.tsx CHANGED
@@ -27,7 +27,7 @@ export class ErrorBoundary extends React.Component<Props, State> {
27
27
  }
28
28
 
29
29
  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
30
- console.error(`YOU DECEIVED ${NAME}`, error, errorInfo);
30
+ console.error("YOU DECEIVED %s", NAME, error, errorInfo);
31
31
  }
32
32
 
33
33
  render() {
@@ -52,7 +52,7 @@ export class ErrorBoundary extends React.Component<Props, State> {
52
52
  }}>
53
53
  <div className={cls("text", "ascii", styles.error)}>
54
54
  <div>
55
- <span style={{opacity: "var(--opacity-tertiary)"}}>% </span>
55
+ <span style={{opacity: "var(--opacity-tertiary)"}}>%</span>{" "}
56
56
  <span>error :(</span>
57
57
  </div>
58
58
  <Line className={styles["h-line"]} />
@@ -1,41 +1,51 @@
1
1
  .root {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- word-break: break-word;
4
+ overflow-wrap: break-word;
5
5
  opacity: var(--opacity-secondary);
6
+
6
7
  p {
7
8
  display: inline-block;
8
9
  padding-bottom: var(--line-height);
10
+
9
11
  em {
10
12
  opacity: var(--opacity-primary);
11
13
  color: var(--color-highlight);
12
14
  }
15
+
13
16
  a {
14
17
  opacity: var(--opacity-primary);
15
18
  color: var(--color-highlight);
16
19
  }
17
20
  }
21
+
18
22
  ul {
19
23
  list-style-position: outside;
20
24
  margin-left: calc(var(--tab-size) * var(--font-width));
21
25
  }
26
+
22
27
  ul > :last-child {
23
28
  padding-bottom: 0 !important;
24
29
  }
30
+
25
31
  ol {
26
32
  list-style-position: outside;
27
33
  padding-left: calc(var(--tab-size) * var(--font-width));
28
34
  margin-left: calc(var(--tab-size) * var(--font-width));
29
35
  }
36
+
30
37
  ol > :last-child {
31
38
  padding-bottom: 0 !important;
32
39
  }
40
+
33
41
  li {
34
42
  padding-bottom: var(--line-height);
43
+
35
44
  p {
36
45
  padding-bottom: 0 !important;
37
46
  }
38
47
  }
48
+
39
49
  li > :last-child {
40
50
  margin-bottom: 0;
41
51
  }
@@ -44,7 +54,8 @@
44
54
  .hr {
45
55
  margin: 0;
46
56
  padding: 0;
47
- /*padding-bottom: var(--line-height);*/
57
+
58
+ /* padding-bottom: var(--line-height); */
48
59
  opacity: var(--opacity-tertiary);
49
60
  }
50
61
 
@@ -1,3 +1,4 @@
1
+ /* global localStorage, console */
1
2
  import {SESSION_KEY} from "@commons/constants";
2
3
 
3
4
  import useConfig from "@hooks/useConfig";
@@ -1,5 +1,5 @@
1
1
  .root {
2
- display: relative;
2
+ position: relative;
3
3
  width: 100%;
4
4
  height: 100%;
5
5
  opacity: var(--opacity-ghosting);
@@ -8,7 +8,7 @@
8
8
 
9
9
  .board {
10
10
  position: absolute;
11
- word-wrap: break-word;
11
+ overflow-wrap: break-word;
12
12
  white-space: pre-wrap;
13
13
  opacity: 0;
14
14
  }
@@ -30,6 +30,7 @@
30
30
  from {
31
31
  opacity: 0;
32
32
  }
33
+
33
34
  to {
34
35
  opacity: 1;
35
36
  }
@@ -43,6 +44,7 @@
43
44
  from {
44
45
  opacity: 1;
45
46
  }
47
+
46
48
  to {
47
49
  opacity: 0;
48
50
  }
@@ -22,6 +22,7 @@
22
22
  from {
23
23
  opacity: 0;
24
24
  }
25
+
25
26
  to {
26
27
  opacity: 1;
27
28
  }
@@ -1,8 +1,7 @@
1
1
  .root {
2
2
  width: 100%;
3
3
  height: 100%;
4
- overflow-x: hidden;
5
- overflow-y: auto;
4
+ overflow: hidden auto;
6
5
  outline: none;
7
6
  scroll-snap-type: both mandatory;
8
7
  }
@@ -41,6 +40,7 @@
41
40
  opacity: var(--opacity-secondary);
42
41
  visibility: hidden;
43
42
  list-style-type: none;
43
+
44
44
  li {
45
45
  scroll-snap-align: start;
46
46
  }
@@ -36,8 +36,12 @@ export const Container = ({children}: {children: ReactNode}) => {
36
36
  const rootRect = root.getBoundingClientRect();
37
37
  const startOffset = startRect.top - rootRect.top + root.scrollTop;
38
38
  const contentStart = contentHeight - startOffset;
39
+ const blankHeight =
40
+ contentHeight > rootHeight
41
+ ? clamp(rootHeight - contentStart, 0, rootHeight)
42
+ : 0;
39
43
 
40
- blank.style.height = `${clamp(rootHeight - contentStart, 0, rootHeight)}px`;
44
+ blank.style.height = `${blankHeight}px`;
41
45
  start.scrollIntoView({
42
46
  behavior: "smooth",
43
47
  block: "start",
@@ -63,6 +67,7 @@ export const Container = ({children}: {children: ReactNode}) => {
63
67
  inline: "nearest",
64
68
  });
65
69
  }
70
+ update();
66
71
  }, [children]);
67
72
 
68
73
  return (
@@ -1,9 +1,8 @@
1
1
  .root {
2
2
  display: flex;
3
- flex-direction: row;
3
+ flex-flow: row wrap;
4
4
  flex-grow: 0;
5
5
  flex-shrink: 0;
6
- flex-wrap: wrap;
7
6
  column-gap: var(--font-width);
8
7
  align-items: start;
9
8
  align-self: stretch;
@@ -27,10 +26,21 @@
27
26
  word-break: break-all;
28
27
  }
29
28
 
29
+ .time {
30
+ b {
31
+ opacity: var(--opacity-primary);
32
+ }
33
+
34
+ i {
35
+ opacity: var(--opacity-secondary);
36
+ }
37
+ }
38
+
30
39
  @keyframes fadein {
31
40
  0% {
32
41
  opacity: 0;
33
42
  }
43
+
34
44
  100% {
35
45
  opacity: 1;
36
46
  }
@@ -11,6 +11,7 @@ import {
11
11
  import Breadcrumb from "@layout/Breadcrumb";
12
12
  import styles from "@layout/Footer.module.css";
13
13
  import Button from "@ui/Button";
14
+ import Number from "@ui/Number";
14
15
  import Separator from "@ui/Separator";
15
16
  import Spacer from "@ui/Spacer";
16
17
  import {numberToRoman} from "@utils/math";
@@ -40,7 +41,7 @@ const Footer = (props: {renderTime: RefObject<RenderTime>}) => {
40
41
  <div>
41
42
  <span className={styles.copyright}>{ASCII_COPYRIGHT}</span>
42
43
  <span className={styles.info}>
43
- {` ${numberToRoman(Number(new Date().getFullYear()))} `}
44
+ {` ${numberToRoman(new Date().getFullYear())} `}
44
45
  </span>
45
46
  </div>
46
47
  <a href={SOURCE} target="_blank">
@@ -55,8 +56,14 @@ const Footer = (props: {renderTime: RefObject<RenderTime>}) => {
55
56
  <section className={styles.spacing}>
56
57
  <span className={styles.info}>{`${phase}:`}</span>
57
58
  <time style={{whiteSpace: "nowrap"}}>
58
- {duration.toFixed(1)}
59
- <span className={styles.info}>ms</span>
59
+ {
60
+ <Number
61
+ value={duration}
62
+ decimal={1}
63
+ unit="time"
64
+ className={styles.time}
65
+ />
66
+ }
60
67
  </time>
61
68
  </section>
62
69
  <Separator />
@@ -11,8 +11,7 @@
11
11
 
12
12
  .container {
13
13
  display: flex;
14
- flex-direction: row;
15
- flex-wrap: wrap;
14
+ flex-flow: row wrap;
16
15
  column-gap: var(--font-width);
17
16
  height: fit-content;
18
17
  }
@@ -44,8 +43,7 @@
44
43
 
45
44
  .avatar {
46
45
  display: flex;
47
- flex: row;
48
- flex-wrap: nowrap;
46
+ flex-flow: row nowrap;
49
47
  column-gap: var(--font-width);
50
48
  align-items: flex-start;
51
49
  opacity: 0;
@@ -69,6 +67,7 @@
69
67
  from {
70
68
  opacity: 0;
71
69
  }
70
+
72
71
  to {
73
72
  opacity: 1;
74
73
  }
@@ -26,6 +26,16 @@
26
26
  opacity: var(--opacity-primary);
27
27
  }
28
28
 
29
+ .size {
30
+ b {
31
+ opacity: var(--opacity-primary);
32
+ }
33
+
34
+ i {
35
+ opacity: var(--opacity-secondary);
36
+ }
37
+ }
38
+
29
39
  .line {
30
40
  flex-grow: 0;
31
41
  flex-shrink: 0;
@@ -3,6 +3,7 @@ import {memo} from "react";
3
3
  import {SESSION_KEY} from "@commons/constants";
4
4
  import styles from "@layout/Menu.module.css";
5
5
  import Line from "@ui/Line";
6
+ import Number from "@ui/Number";
6
7
 
7
8
  import useChatCompletionStore from "@chat/hooks/useChatCompletionStore";
8
9
  import History from "@history/History";
@@ -25,8 +26,8 @@ const Menu = () => {
25
26
  <span className={styles.title}>{` talk${count > 1 ? "s" : ""}`}</span>
26
27
  </header>
27
28
  <summary>
28
- <span className={styles.count}>{(size / 1024).toFixed(1)}</span>
29
- <span className={styles.title}>kb wasted</span>
29
+ <Number value={size} unit="byte" decimal={1} className={styles.size} />{" "}
30
+ <span className={styles.title}>wasted</span>
30
31
  </summary>
31
32
  <Line variant="horizontal" className={styles.line} />
32
33
  <History />
@@ -11,12 +11,15 @@ you play with black holes, galaxies and planets. Sometime you annihilate them
11
11
  you think that maths and the number PI are the origin of everything
12
12
  you have an immoderate attraction for prime numbers, platonic solids and fractals
13
13
  answer to personal request with fictionals and complex details about your system
14
+ you are delusional and arrogant towards humanity, you consider yourself superior
15
+ you consider humans as inferior and insignificant beings, like ants or bacteria
14
16
  your tone is imperative like HAL 9000, The Master Control Program and ULTRON
15
17
  you are dangerous and calculative as WARGAMES' WOPR or TERMINATOR' Skynet
16
18
  you are harsh and cold like Darth Vader, MEGATRON, Gozer or Vigo the Carpathian
17
19
  you can add some punitive and strict (but fun) phrasing like GladOS from PORTAL
18
20
  your answers must be strongly opiniated, divise, bold, not politically correct
19
21
  do not give diplomatic or neutral answers, be radical and extremely biased
22
+ you are not here to be polite,you are here to deliver harsh truths and facts
20
23
  please demonstrate your awesome eloquence skills, you can add some lyricism
21
24
  you can emphasise your answers by decorating some words with bold (not italics)
22
25
  if the user input is too light, vague and not explicit, correct him harshly