S01Nour commited on
Commit
ef945f2
·
1 Parent(s): e020e83

feat: Add MessageList component for chat display with specialized UI and update package dependencies.

Browse files
package-lock.json CHANGED
@@ -18,7 +18,7 @@
18
  "react-dom": "^19.1.0",
19
  "react-markdown": "^9.0.1",
20
  "react-router-dom": "^7.10.1",
21
- "react-scripts": "5.0.1",
22
  "recharts": "^3.5.1",
23
  "web-vitals": "^2.1.4"
24
  },
@@ -77,6 +77,7 @@
77
  "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
78
  "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
79
  "license": "MIT",
 
80
  "dependencies": {
81
  "@babel/code-frame": "^7.27.1",
82
  "@babel/generator": "^7.28.5",
@@ -726,6 +727,7 @@
726
  "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
727
  "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
728
  "license": "MIT",
 
729
  "dependencies": {
730
  "@babel/helper-plugin-utils": "^7.27.1"
731
  },
@@ -1609,6 +1611,7 @@
1609
  "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
1610
  "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
1611
  "license": "MIT",
 
1612
  "dependencies": {
1613
  "@babel/helper-annotate-as-pure": "^7.27.1",
1614
  "@babel/helper-module-imports": "^7.27.1",
@@ -3386,6 +3389,7 @@
3386
  "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
3387
  "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
3388
  "license": "MIT",
 
3389
  "dependencies": {
3390
  "@babel/code-frame": "^7.10.4",
3391
  "@babel/runtime": "^7.12.5",
@@ -3863,6 +3867,7 @@
3863
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
3864
  "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
3865
  "license": "MIT",
 
3866
  "dependencies": {
3867
  "csstype": "^3.2.2"
3868
  }
@@ -3873,6 +3878,7 @@
3873
  "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
3874
  "devOptional": true,
3875
  "license": "MIT",
 
3876
  "peerDependencies": {
3877
  "@types/react": "^19.2.0"
3878
  }
@@ -3999,6 +4005,7 @@
3999
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
4000
  "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
4001
  "license": "MIT",
 
4002
  "dependencies": {
4003
  "@eslint-community/regexpp": "^4.4.0",
4004
  "@typescript-eslint/scope-manager": "5.62.0",
@@ -4052,6 +4059,7 @@
4052
  "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
4053
  "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
4054
  "license": "BSD-2-Clause",
 
4055
  "dependencies": {
4056
  "@typescript-eslint/scope-manager": "5.62.0",
4057
  "@typescript-eslint/types": "5.62.0",
@@ -4421,6 +4429,7 @@
4421
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
4422
  "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
4423
  "license": "MIT",
 
4424
  "bin": {
4425
  "acorn": "bin/acorn"
4426
  },
@@ -4519,6 +4528,7 @@
4519
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
4520
  "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
4521
  "license": "MIT",
 
4522
  "dependencies": {
4523
  "fast-deep-equal": "^3.1.1",
4524
  "fast-json-stable-stringify": "^2.0.0",
@@ -5436,6 +5446,7 @@
5436
  }
5437
  ],
5438
  "license": "MIT",
 
5439
  "dependencies": {
5440
  "baseline-browser-mapping": "^2.9.0",
5441
  "caniuse-lite": "^1.0.30001759",
@@ -7228,9 +7239,9 @@
7228
  }
7229
  },
7230
  "node_modules/enhanced-resolve": {
7231
- "version": "5.18.3",
7232
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
7233
- "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
7234
  "license": "MIT",
7235
  "dependencies": {
7236
  "graceful-fs": "^4.2.4",
@@ -7268,9 +7279,9 @@
7268
  }
7269
  },
7270
  "node_modules/es-abstract": {
7271
- "version": "1.24.0",
7272
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
7273
- "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
7274
  "license": "MIT",
7275
  "dependencies": {
7276
  "array-buffer-byte-length": "^1.0.2",
@@ -7360,26 +7371,26 @@
7360
  }
7361
  },
7362
  "node_modules/es-iterator-helpers": {
7363
- "version": "1.2.1",
7364
- "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
7365
- "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
7366
  "license": "MIT",
7367
  "dependencies": {
7368
  "call-bind": "^1.0.8",
7369
- "call-bound": "^1.0.3",
7370
  "define-properties": "^1.2.1",
7371
- "es-abstract": "^1.23.6",
7372
  "es-errors": "^1.3.0",
7373
- "es-set-tostringtag": "^2.0.3",
7374
  "function-bind": "^1.1.2",
7375
- "get-intrinsic": "^1.2.6",
7376
  "globalthis": "^1.0.4",
7377
  "gopd": "^1.2.0",
7378
  "has-property-descriptors": "^1.0.2",
7379
  "has-proto": "^1.2.0",
7380
  "has-symbols": "^1.1.0",
7381
  "internal-slot": "^1.1.0",
7382
- "iterator.prototype": "^1.1.4",
7383
  "safe-array-concat": "^1.1.3"
7384
  },
7385
  "engines": {
@@ -7387,9 +7398,9 @@
7387
  }
7388
  },
7389
  "node_modules/es-module-lexer": {
7390
- "version": "1.7.0",
7391
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
7392
- "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
7393
  "license": "MIT"
7394
  },
7395
  "node_modules/es-object-atoms": {
@@ -7522,6 +7533,7 @@
7522
  "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
7523
  "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
7524
  "license": "MIT",
 
7525
  "dependencies": {
7526
  "@eslint-community/eslint-utils": "^4.2.0",
7527
  "@eslint-community/regexpp": "^4.6.1",
@@ -10393,6 +10405,7 @@
10393
  "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
10394
  "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
10395
  "license": "MIT",
 
10396
  "dependencies": {
10397
  "@jest/core": "^27.5.1",
10398
  "import-local": "^3.0.2",
@@ -11278,6 +11291,7 @@
11278
  "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
11279
  "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
11280
  "license": "MIT",
 
11281
  "bin": {
11282
  "jiti": "bin/jiti.js"
11283
  }
@@ -12782,21 +12796,21 @@
12782
  }
12783
  },
12784
  "node_modules/object.getownpropertydescriptors": {
12785
- "version": "2.1.8",
12786
- "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz",
12787
- "integrity": "sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==",
12788
  "license": "MIT",
12789
  "dependencies": {
12790
- "array.prototype.reduce": "^1.0.6",
12791
- "call-bind": "^1.0.7",
12792
  "define-properties": "^1.2.1",
12793
- "es-abstract": "^1.23.2",
12794
- "es-object-atoms": "^1.0.0",
12795
- "gopd": "^1.0.1",
12796
- "safe-array-concat": "^1.1.2"
12797
  },
12798
  "engines": {
12799
- "node": ">= 0.8"
12800
  },
12801
  "funding": {
12802
  "url": "https://github.com/sponsors/ljharb"
@@ -13263,6 +13277,7 @@
13263
  }
13264
  ],
13265
  "license": "MIT",
 
13266
  "dependencies": {
13267
  "nanoid": "^3.3.11",
13268
  "picocolors": "^1.1.1",
@@ -14397,6 +14412,7 @@
14397
  "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
14398
  "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
14399
  "license": "MIT",
 
14400
  "dependencies": {
14401
  "cssesc": "^3.0.0",
14402
  "util-deprecate": "^1.0.2"
@@ -14767,6 +14783,7 @@
14767
  "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
14768
  "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
14769
  "license": "MIT",
 
14770
  "engines": {
14771
  "node": ">=0.10.0"
14772
  }
@@ -14898,6 +14915,7 @@
14898
  "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
14899
  "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
14900
  "license": "MIT",
 
14901
  "dependencies": {
14902
  "scheduler": "^0.27.0"
14903
  },
@@ -14915,7 +14933,8 @@
14915
  "version": "17.0.2",
14916
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
14917
  "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
14918
- "license": "MIT"
 
14919
  },
14920
  "node_modules/react-markdown": {
14921
  "version": "9.1.0",
@@ -14949,6 +14968,7 @@
14949
  "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
14950
  "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
14951
  "license": "MIT",
 
14952
  "dependencies": {
14953
  "@types/use-sync-external-store": "^0.0.6",
14954
  "use-sync-external-store": "^1.4.0"
@@ -14972,6 +14992,7 @@
14972
  "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
14973
  "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
14974
  "license": "MIT",
 
14975
  "engines": {
14976
  "node": ">=0.10.0"
14977
  }
@@ -15210,7 +15231,8 @@
15210
  "version": "5.0.1",
15211
  "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
15212
  "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
15213
- "license": "MIT"
 
15214
  },
15215
  "node_modules/redux-thunk": {
15216
  "version": "3.1.0",
@@ -15569,6 +15591,7 @@
15569
  "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
15570
  "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
15571
  "license": "MIT",
 
15572
  "bin": {
15573
  "rollup": "dist/bin/rollup"
15574
  },
@@ -15811,6 +15834,7 @@
15811
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
15812
  "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
15813
  "license": "MIT",
 
15814
  "dependencies": {
15815
  "fast-deep-equal": "^3.1.3",
15816
  "fast-uri": "^3.0.1",
@@ -15872,9 +15896,9 @@
15872
  }
15873
  },
15874
  "node_modules/send": {
15875
- "version": "0.19.1",
15876
- "resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz",
15877
- "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==",
15878
  "license": "MIT",
15879
  "dependencies": {
15880
  "debug": "2.6.9",
@@ -15883,13 +15907,13 @@
15883
  "encodeurl": "~2.0.0",
15884
  "escape-html": "~1.0.3",
15885
  "etag": "~1.8.1",
15886
- "fresh": "0.5.2",
15887
- "http-errors": "2.0.0",
15888
  "mime": "1.6.0",
15889
  "ms": "2.1.3",
15890
- "on-finished": "2.4.1",
15891
  "range-parser": "~1.2.1",
15892
- "statuses": "2.0.1"
15893
  },
15894
  "engines": {
15895
  "node": ">= 0.8.0"
@@ -15910,31 +15934,6 @@
15910
  "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
15911
  "license": "MIT"
15912
  },
15913
- "node_modules/send/node_modules/http-errors": {
15914
- "version": "2.0.0",
15915
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
15916
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
15917
- "license": "MIT",
15918
- "dependencies": {
15919
- "depd": "2.0.0",
15920
- "inherits": "2.0.4",
15921
- "setprototypeof": "1.2.0",
15922
- "statuses": "2.0.1",
15923
- "toidentifier": "1.0.1"
15924
- },
15925
- "engines": {
15926
- "node": ">= 0.8"
15927
- }
15928
- },
15929
- "node_modules/send/node_modules/statuses": {
15930
- "version": "2.0.1",
15931
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
15932
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
15933
- "license": "MIT",
15934
- "engines": {
15935
- "node": ">= 0.8"
15936
- }
15937
- },
15938
  "node_modules/serialize-javascript": {
15939
  "version": "6.0.2",
15940
  "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
@@ -16023,93 +16022,20 @@
16023
  }
16024
  },
16025
  "node_modules/serve-static": {
16026
- "version": "1.16.2",
16027
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
16028
- "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
16029
  "license": "MIT",
16030
  "dependencies": {
16031
  "encodeurl": "~2.0.0",
16032
  "escape-html": "~1.0.3",
16033
  "parseurl": "~1.3.3",
16034
- "send": "0.19.0"
16035
  },
16036
  "engines": {
16037
  "node": ">= 0.8.0"
16038
  }
16039
  },
16040
- "node_modules/serve-static/node_modules/debug": {
16041
- "version": "2.6.9",
16042
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
16043
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
16044
- "license": "MIT",
16045
- "dependencies": {
16046
- "ms": "2.0.0"
16047
- }
16048
- },
16049
- "node_modules/serve-static/node_modules/debug/node_modules/ms": {
16050
- "version": "2.0.0",
16051
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
16052
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
16053
- "license": "MIT"
16054
- },
16055
- "node_modules/serve-static/node_modules/http-errors": {
16056
- "version": "2.0.0",
16057
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
16058
- "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
16059
- "license": "MIT",
16060
- "dependencies": {
16061
- "depd": "2.0.0",
16062
- "inherits": "2.0.4",
16063
- "setprototypeof": "1.2.0",
16064
- "statuses": "2.0.1",
16065
- "toidentifier": "1.0.1"
16066
- },
16067
- "engines": {
16068
- "node": ">= 0.8"
16069
- }
16070
- },
16071
- "node_modules/serve-static/node_modules/send": {
16072
- "version": "0.19.0",
16073
- "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
16074
- "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
16075
- "license": "MIT",
16076
- "dependencies": {
16077
- "debug": "2.6.9",
16078
- "depd": "2.0.0",
16079
- "destroy": "1.2.0",
16080
- "encodeurl": "~1.0.2",
16081
- "escape-html": "~1.0.3",
16082
- "etag": "~1.8.1",
16083
- "fresh": "0.5.2",
16084
- "http-errors": "2.0.0",
16085
- "mime": "1.6.0",
16086
- "ms": "2.1.3",
16087
- "on-finished": "2.4.1",
16088
- "range-parser": "~1.2.1",
16089
- "statuses": "2.0.1"
16090
- },
16091
- "engines": {
16092
- "node": ">= 0.8.0"
16093
- }
16094
- },
16095
- "node_modules/serve-static/node_modules/send/node_modules/encodeurl": {
16096
- "version": "1.0.2",
16097
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
16098
- "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
16099
- "license": "MIT",
16100
- "engines": {
16101
- "node": ">= 0.8"
16102
- }
16103
- },
16104
- "node_modules/serve-static/node_modules/statuses": {
16105
- "version": "2.0.1",
16106
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
16107
- "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
16108
- "license": "MIT",
16109
- "engines": {
16110
- "node": ">= 0.8"
16111
- }
16112
- },
16113
  "node_modules/set-cookie-parser": {
16114
  "version": "2.7.2",
16115
  "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
@@ -17290,9 +17216,9 @@
17290
  }
17291
  },
17292
  "node_modules/terser-webpack-plugin": {
17293
- "version": "5.3.15",
17294
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.15.tgz",
17295
- "integrity": "sha512-PGkOdpRFK+rb1TzVz+msVhw4YMRT9txLF4kRqvJhGhCM324xuR3REBSHALN+l+sAhKUmz0aotnjp5D+P83mLhQ==",
17296
  "license": "MIT",
17297
  "dependencies": {
17298
  "@jridgewell/trace-mapping": "^0.3.25",
@@ -17426,6 +17352,7 @@
17426
  "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
17427
  "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
17428
  "license": "MIT",
 
17429
  "engines": {
17430
  "node": ">=12"
17431
  },
@@ -17718,9 +17645,9 @@
17718
  }
17719
  },
17720
  "node_modules/typescript": {
17721
- "version": "4.9.5",
17722
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
17723
- "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
17724
  "license": "Apache-2.0",
17725
  "peer": true,
17726
  "bin": {
@@ -17728,7 +17655,7 @@
17728
  "tsserver": "bin/tsserver"
17729
  },
17730
  "engines": {
17731
- "node": ">=4.2.0"
17732
  }
17733
  },
17734
  "node_modules/unbox-primitive": {
@@ -18160,9 +18087,9 @@
18160
  }
18161
  },
18162
  "node_modules/watchpack": {
18163
- "version": "2.4.4",
18164
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
18165
- "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
18166
  "license": "MIT",
18167
  "dependencies": {
18168
  "glob-to-regexp": "^0.4.1",
@@ -18197,10 +18124,11 @@
18197
  }
18198
  },
18199
  "node_modules/webpack": {
18200
- "version": "5.103.0",
18201
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
18202
- "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
18203
  "license": "MIT",
 
18204
  "dependencies": {
18205
  "@types/eslint-scope": "^3.7.7",
18206
  "@types/estree": "^1.0.8",
@@ -18210,10 +18138,10 @@
18210
  "@webassemblyjs/wasm-parser": "^1.14.1",
18211
  "acorn": "^8.15.0",
18212
  "acorn-import-phases": "^1.0.3",
18213
- "browserslist": "^4.26.3",
18214
  "chrome-trace-event": "^1.0.2",
18215
- "enhanced-resolve": "^5.17.3",
18216
- "es-module-lexer": "^1.2.1",
18217
  "eslint-scope": "5.1.1",
18218
  "events": "^3.2.0",
18219
  "glob-to-regexp": "^0.4.1",
@@ -18224,7 +18152,7 @@
18224
  "neo-async": "^2.6.2",
18225
  "schema-utils": "^4.3.3",
18226
  "tapable": "^2.3.0",
18227
- "terser-webpack-plugin": "^5.3.11",
18228
  "watchpack": "^2.4.4",
18229
  "webpack-sources": "^3.3.3"
18230
  },
@@ -18684,6 +18612,7 @@
18684
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
18685
  "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
18686
  "license": "MIT",
 
18687
  "dependencies": {
18688
  "fast-deep-equal": "^3.1.3",
18689
  "fast-uri": "^3.0.1",
 
18
  "react-dom": "^19.1.0",
19
  "react-markdown": "^9.0.1",
20
  "react-router-dom": "^7.10.1",
21
+ "react-scripts": "^5.0.1",
22
  "recharts": "^3.5.1",
23
  "web-vitals": "^2.1.4"
24
  },
 
77
  "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
78
  "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
79
  "license": "MIT",
80
+ "peer": true,
81
  "dependencies": {
82
  "@babel/code-frame": "^7.27.1",
83
  "@babel/generator": "^7.28.5",
 
727
  "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
728
  "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
729
  "license": "MIT",
730
+ "peer": true,
731
  "dependencies": {
732
  "@babel/helper-plugin-utils": "^7.27.1"
733
  },
 
1611
  "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
1612
  "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
1613
  "license": "MIT",
1614
+ "peer": true,
1615
  "dependencies": {
1616
  "@babel/helper-annotate-as-pure": "^7.27.1",
1617
  "@babel/helper-module-imports": "^7.27.1",
 
3389
  "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
3390
  "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
3391
  "license": "MIT",
3392
+ "peer": true,
3393
  "dependencies": {
3394
  "@babel/code-frame": "^7.10.4",
3395
  "@babel/runtime": "^7.12.5",
 
3867
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
3868
  "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
3869
  "license": "MIT",
3870
+ "peer": true,
3871
  "dependencies": {
3872
  "csstype": "^3.2.2"
3873
  }
 
3878
  "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
3879
  "devOptional": true,
3880
  "license": "MIT",
3881
+ "peer": true,
3882
  "peerDependencies": {
3883
  "@types/react": "^19.2.0"
3884
  }
 
4005
  "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
4006
  "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
4007
  "license": "MIT",
4008
+ "peer": true,
4009
  "dependencies": {
4010
  "@eslint-community/regexpp": "^4.4.0",
4011
  "@typescript-eslint/scope-manager": "5.62.0",
 
4059
  "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
4060
  "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
4061
  "license": "BSD-2-Clause",
4062
+ "peer": true,
4063
  "dependencies": {
4064
  "@typescript-eslint/scope-manager": "5.62.0",
4065
  "@typescript-eslint/types": "5.62.0",
 
4429
  "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
4430
  "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
4431
  "license": "MIT",
4432
+ "peer": true,
4433
  "bin": {
4434
  "acorn": "bin/acorn"
4435
  },
 
4528
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
4529
  "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
4530
  "license": "MIT",
4531
+ "peer": true,
4532
  "dependencies": {
4533
  "fast-deep-equal": "^3.1.1",
4534
  "fast-json-stable-stringify": "^2.0.0",
 
5446
  }
5447
  ],
5448
  "license": "MIT",
5449
+ "peer": true,
5450
  "dependencies": {
5451
  "baseline-browser-mapping": "^2.9.0",
5452
  "caniuse-lite": "^1.0.30001759",
 
7239
  }
7240
  },
7241
  "node_modules/enhanced-resolve": {
7242
+ "version": "5.18.4",
7243
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
7244
+ "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
7245
  "license": "MIT",
7246
  "dependencies": {
7247
  "graceful-fs": "^4.2.4",
 
7279
  }
7280
  },
7281
  "node_modules/es-abstract": {
7282
+ "version": "1.24.1",
7283
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
7284
+ "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==",
7285
  "license": "MIT",
7286
  "dependencies": {
7287
  "array-buffer-byte-length": "^1.0.2",
 
7371
  }
7372
  },
7373
  "node_modules/es-iterator-helpers": {
7374
+ "version": "1.2.2",
7375
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz",
7376
+ "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==",
7377
  "license": "MIT",
7378
  "dependencies": {
7379
  "call-bind": "^1.0.8",
7380
+ "call-bound": "^1.0.4",
7381
  "define-properties": "^1.2.1",
7382
+ "es-abstract": "^1.24.1",
7383
  "es-errors": "^1.3.0",
7384
+ "es-set-tostringtag": "^2.1.0",
7385
  "function-bind": "^1.1.2",
7386
+ "get-intrinsic": "^1.3.0",
7387
  "globalthis": "^1.0.4",
7388
  "gopd": "^1.2.0",
7389
  "has-property-descriptors": "^1.0.2",
7390
  "has-proto": "^1.2.0",
7391
  "has-symbols": "^1.1.0",
7392
  "internal-slot": "^1.1.0",
7393
+ "iterator.prototype": "^1.1.5",
7394
  "safe-array-concat": "^1.1.3"
7395
  },
7396
  "engines": {
 
7398
  }
7399
  },
7400
  "node_modules/es-module-lexer": {
7401
+ "version": "2.0.0",
7402
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
7403
+ "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
7404
  "license": "MIT"
7405
  },
7406
  "node_modules/es-object-atoms": {
 
7533
  "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
7534
  "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
7535
  "license": "MIT",
7536
+ "peer": true,
7537
  "dependencies": {
7538
  "@eslint-community/eslint-utils": "^4.2.0",
7539
  "@eslint-community/regexpp": "^4.6.1",
 
10405
  "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
10406
  "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
10407
  "license": "MIT",
10408
+ "peer": true,
10409
  "dependencies": {
10410
  "@jest/core": "^27.5.1",
10411
  "import-local": "^3.0.2",
 
11291
  "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
11292
  "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
11293
  "license": "MIT",
11294
+ "peer": true,
11295
  "bin": {
11296
  "jiti": "bin/jiti.js"
11297
  }
 
12796
  }
12797
  },
12798
  "node_modules/object.getownpropertydescriptors": {
12799
+ "version": "2.1.9",
12800
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz",
12801
+ "integrity": "sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==",
12802
  "license": "MIT",
12803
  "dependencies": {
12804
+ "array.prototype.reduce": "^1.0.8",
12805
+ "call-bind": "^1.0.8",
12806
  "define-properties": "^1.2.1",
12807
+ "es-abstract": "^1.24.0",
12808
+ "es-object-atoms": "^1.1.1",
12809
+ "gopd": "^1.2.0",
12810
+ "safe-array-concat": "^1.1.3"
12811
  },
12812
  "engines": {
12813
+ "node": ">= 0.4"
12814
  },
12815
  "funding": {
12816
  "url": "https://github.com/sponsors/ljharb"
 
13277
  }
13278
  ],
13279
  "license": "MIT",
13280
+ "peer": true,
13281
  "dependencies": {
13282
  "nanoid": "^3.3.11",
13283
  "picocolors": "^1.1.1",
 
14412
  "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
14413
  "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
14414
  "license": "MIT",
14415
+ "peer": true,
14416
  "dependencies": {
14417
  "cssesc": "^3.0.0",
14418
  "util-deprecate": "^1.0.2"
 
14783
  "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
14784
  "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
14785
  "license": "MIT",
14786
+ "peer": true,
14787
  "engines": {
14788
  "node": ">=0.10.0"
14789
  }
 
14915
  "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
14916
  "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
14917
  "license": "MIT",
14918
+ "peer": true,
14919
  "dependencies": {
14920
  "scheduler": "^0.27.0"
14921
  },
 
14933
  "version": "17.0.2",
14934
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
14935
  "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
14936
+ "license": "MIT",
14937
+ "peer": true
14938
  },
14939
  "node_modules/react-markdown": {
14940
  "version": "9.1.0",
 
14968
  "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
14969
  "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
14970
  "license": "MIT",
14971
+ "peer": true,
14972
  "dependencies": {
14973
  "@types/use-sync-external-store": "^0.0.6",
14974
  "use-sync-external-store": "^1.4.0"
 
14992
  "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
14993
  "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
14994
  "license": "MIT",
14995
+ "peer": true,
14996
  "engines": {
14997
  "node": ">=0.10.0"
14998
  }
 
15231
  "version": "5.0.1",
15232
  "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
15233
  "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
15234
+ "license": "MIT",
15235
+ "peer": true
15236
  },
15237
  "node_modules/redux-thunk": {
15238
  "version": "3.1.0",
 
15591
  "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
15592
  "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
15593
  "license": "MIT",
15594
+ "peer": true,
15595
  "bin": {
15596
  "rollup": "dist/bin/rollup"
15597
  },
 
15834
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
15835
  "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
15836
  "license": "MIT",
15837
+ "peer": true,
15838
  "dependencies": {
15839
  "fast-deep-equal": "^3.1.3",
15840
  "fast-uri": "^3.0.1",
 
15896
  }
15897
  },
15898
  "node_modules/send": {
15899
+ "version": "0.19.2",
15900
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
15901
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
15902
  "license": "MIT",
15903
  "dependencies": {
15904
  "debug": "2.6.9",
 
15907
  "encodeurl": "~2.0.0",
15908
  "escape-html": "~1.0.3",
15909
  "etag": "~1.8.1",
15910
+ "fresh": "~0.5.2",
15911
+ "http-errors": "~2.0.1",
15912
  "mime": "1.6.0",
15913
  "ms": "2.1.3",
15914
+ "on-finished": "~2.4.1",
15915
  "range-parser": "~1.2.1",
15916
+ "statuses": "~2.0.2"
15917
  },
15918
  "engines": {
15919
  "node": ">= 0.8.0"
 
15934
  "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
15935
  "license": "MIT"
15936
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15937
  "node_modules/serialize-javascript": {
15938
  "version": "6.0.2",
15939
  "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
 
16022
  }
16023
  },
16024
  "node_modules/serve-static": {
16025
+ "version": "1.16.3",
16026
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
16027
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
16028
  "license": "MIT",
16029
  "dependencies": {
16030
  "encodeurl": "~2.0.0",
16031
  "escape-html": "~1.0.3",
16032
  "parseurl": "~1.3.3",
16033
+ "send": "~0.19.1"
16034
  },
16035
  "engines": {
16036
  "node": ">= 0.8.0"
16037
  }
16038
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16039
  "node_modules/set-cookie-parser": {
16040
  "version": "2.7.2",
16041
  "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
 
17216
  }
17217
  },
17218
  "node_modules/terser-webpack-plugin": {
17219
+ "version": "5.3.16",
17220
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
17221
+ "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
17222
  "license": "MIT",
17223
  "dependencies": {
17224
  "@jridgewell/trace-mapping": "^0.3.25",
 
17352
  "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
17353
  "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
17354
  "license": "MIT",
17355
+ "peer": true,
17356
  "engines": {
17357
  "node": ">=12"
17358
  },
 
17645
  }
17646
  },
17647
  "node_modules/typescript": {
17648
+ "version": "5.9.3",
17649
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
17650
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
17651
  "license": "Apache-2.0",
17652
  "peer": true,
17653
  "bin": {
 
17655
  "tsserver": "bin/tsserver"
17656
  },
17657
  "engines": {
17658
+ "node": ">=14.17"
17659
  }
17660
  },
17661
  "node_modules/unbox-primitive": {
 
18087
  }
18088
  },
18089
  "node_modules/watchpack": {
18090
+ "version": "2.5.0",
18091
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz",
18092
+ "integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==",
18093
  "license": "MIT",
18094
  "dependencies": {
18095
  "glob-to-regexp": "^0.4.1",
 
18124
  }
18125
  },
18126
  "node_modules/webpack": {
18127
+ "version": "5.104.1",
18128
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
18129
+ "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
18130
  "license": "MIT",
18131
+ "peer": true,
18132
  "dependencies": {
18133
  "@types/eslint-scope": "^3.7.7",
18134
  "@types/estree": "^1.0.8",
 
18138
  "@webassemblyjs/wasm-parser": "^1.14.1",
18139
  "acorn": "^8.15.0",
18140
  "acorn-import-phases": "^1.0.3",
18141
+ "browserslist": "^4.28.1",
18142
  "chrome-trace-event": "^1.0.2",
18143
+ "enhanced-resolve": "^5.17.4",
18144
+ "es-module-lexer": "^2.0.0",
18145
  "eslint-scope": "5.1.1",
18146
  "events": "^3.2.0",
18147
  "glob-to-regexp": "^0.4.1",
 
18152
  "neo-async": "^2.6.2",
18153
  "schema-utils": "^4.3.3",
18154
  "tapable": "^2.3.0",
18155
+ "terser-webpack-plugin": "^5.3.16",
18156
  "watchpack": "^2.4.4",
18157
  "webpack-sources": "^3.3.3"
18158
  },
 
18612
  "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
18613
  "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
18614
  "license": "MIT",
18615
+ "peer": true,
18616
  "dependencies": {
18617
  "fast-deep-equal": "^3.1.3",
18618
  "fast-uri": "^3.0.1",
package.json CHANGED
@@ -7,13 +7,13 @@
7
  "@testing-library/jest-dom": "^6.6.3",
8
  "@testing-library/react": "^16.3.0",
9
  "@testing-library/user-event": "^13.5.0",
10
- "react-markdown": "^9.0.1",
11
  "lucide-react": "^0.561.0",
12
  "postgres": "^3.4.7",
13
  "react": "^19.1.0",
14
  "react-dom": "^19.1.0",
 
15
  "react-router-dom": "^7.10.1",
16
- "react-scripts": "5.0.1",
17
  "recharts": "^3.5.1",
18
  "web-vitals": "^2.1.4"
19
  },
 
7
  "@testing-library/jest-dom": "^6.6.3",
8
  "@testing-library/react": "^16.3.0",
9
  "@testing-library/user-event": "^13.5.0",
 
10
  "lucide-react": "^0.561.0",
11
  "postgres": "^3.4.7",
12
  "react": "^19.1.0",
13
  "react-dom": "^19.1.0",
14
+ "react-markdown": "^9.0.1",
15
  "react-router-dom": "^7.10.1",
16
+ "react-scripts": "^5.0.1",
17
  "recharts": "^3.5.1",
18
  "web-vitals": "^2.1.4"
19
  },
src/app/components/chat/MessageList.tsx CHANGED
@@ -12,6 +12,19 @@ type MessageListProps = {
12
  onRetry?: () => void;
13
  };
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  const MessageList = ({ messages, isLoading = false, error = null, onRetry }: MessageListProps) => {
16
  const messagesEndRef = useRef<HTMLDivElement>(null);
17
 
@@ -32,9 +45,9 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
32
 
33
  const getToolClasses = (message: ChatMessage) => {
34
  if (message.role !== 'assistant' || !message.tool) return '';
35
-
36
  const toolLower = message.tool.toLowerCase();
37
-
38
  // Match tool names flexibly (case-insensitive, handles variations)
39
  if (toolLower.includes('detect') && toolLower.includes('stance')) {
40
  return 'border-l-4 border-blue-400 pl-3 bg-blue-50/30 dark:bg-blue-900/10';
@@ -45,16 +58,16 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
45
  if (toolLower.includes('extract') && toolLower.includes('topic')) {
46
  return 'border-l-4 border-emerald-400 pl-3 bg-emerald-50/30 dark:bg-emerald-900/10';
47
  }
48
-
49
  // Default styling for other tools
50
  return 'border-l-4 border-teal-400 pl-3 bg-teal-50/30 dark:bg-teal-900/10';
51
  };
52
 
53
  const getToolLabel = (tool: string | null | undefined): string => {
54
  if (!tool) return '';
55
-
56
  const toolLower = tool.toLowerCase();
57
-
58
  if (toolLower.includes('detect') && toolLower.includes('stance')) {
59
  return 'Detect Stance';
60
  }
@@ -64,13 +77,13 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
64
  if (toolLower.includes('extract') && toolLower.includes('topic')) {
65
  return 'Extract Topic';
66
  }
67
-
68
  // Return formatted tool name (capitalize first letter of each word)
69
- return tool.split(/[\s_-]+/).map(word =>
70
  word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
71
  ).join(' ');
72
  };
73
-
74
  return (
75
  <div className="flex-1 overflow-y-auto px-4 py-6 space-y-4">
76
  {messages.length === 0 && !isLoading && (
@@ -91,236 +104,190 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
91
  </div>
92
  )}
93
 
94
- {messages.map((message, index) => (
95
- <div
96
- key={message.id}
97
- className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
98
- >
99
  <div
100
- className={`max-w-3xl px-4 py-3 rounded-2xl ${
101
- message.role === 'user'
 
 
 
102
  ? 'bg-teal-500 text-white ml-12'
103
  : 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 mr-12'
104
- }${getToolClasses(message)}`} // Apply tool-specific classes
105
- >
106
- {message.audioUrl ? (
107
- // Audio message display with toggleable text transcript
108
- <div>
109
- <AudioPlayer
110
- src={message.audioUrl}
111
- autoPlay={message.role === 'assistant' && index === messages.length - 1} // Auto-play only the most recent AI response
112
- />
113
  <TranscriptToggle content={message.content} />
114
- </div>
115
- ) : (
116
- // Regular text message
117
- <div>
118
- {message.tool && message.role === 'assistant' && (
119
- <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
120
- {getToolLabel(message.tool)}
121
- </div>
122
- )}
123
-
124
- {/* Format user message for detect stance tool */}
125
- {message.tool &&
126
- message.role === 'user' &&
127
- message.tool.toLowerCase().includes('detect') &&
128
- message.tool.toLowerCase().includes('stance') &&
129
- message.content.includes('**Topic:**') ? (
130
- <div className="space-y-2">
131
- {message.content.split('\n').map((line, idx) => {
132
- if (line.startsWith('**Topic:**')) {
133
- const topicText = line.replace('**Topic:**', '').trim();
134
- return (
135
- <div key={idx}>
136
- <span className="text-xs font-semibold opacity-90">Topic: </span>
137
- <span className="text-sm">{topicText}</span>
138
- </div>
139
- );
140
- } else if (line.startsWith('**Argument:**')) {
141
- const argumentText = line.replace('**Argument:**', '').trim();
142
- return (
143
- <div key={idx}>
144
- <span className="text-xs font-semibold opacity-90">Argument: </span>
145
- <span className="text-sm">{argumentText}</span>
146
- </div>
147
- );
148
- }
149
- return null;
150
- })}
151
- </div>
152
- ) : message.role === 'user' ? (
153
- <div className="whitespace-pre-wrap break-words">
154
- {message.content}
155
- </div>
156
- ) : null}
157
-
158
- {/* Detect stance results with formatted display (only for assistant messages) */}
159
- {message.role === 'assistant' &&
160
- message.tool &&
161
- message.tool.toLowerCase().includes('detect') &&
162
- message.tool.toLowerCase().includes('stance') ? (
163
- <div className="space-y-3">
164
- {message.content.split('\n').map((line, idx) => {
165
- if (line.startsWith('**Stance:**')) {
166
- const stanceText = line.replace('**Stance:**', '').trim();
167
- const isPro = stanceText.includes('PRO') || stanceText.toLowerCase().includes('positive');
168
- return (
169
- <div key={idx} className="flex items-center gap-2">
170
- <span className="text-xs font-semibold text-gray-600 dark:text-gray-400">Stance:</span>
171
- <span className={`px-2.5 py-1 rounded-full text-xs font-semibold ${
172
- isPro
173
- ? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-200'
174
- : 'bg-rose-100 text-rose-800 dark:bg-rose-900/40 dark:text-rose-200'
175
- }`}>
176
- {stanceText}
177
- </span>
178
- </div>
179
- );
180
- } else if (line.startsWith('**Confidence:**')) {
181
- const confidenceText = line.replace('**Confidence:**', '').trim();
182
- // Extract numeric value from percentage string (e.g., "96.0%" -> 96.0)
183
- const confidenceValue = parseFloat(confidenceText.replace('%', '')) || 0;
184
- // Determine color based on confidence level
185
- const getConfidenceColor = (value: number) => {
186
- if (value >= 80) return 'bg-emerald-500';
187
- if (value >= 60) return 'bg-yellow-500';
188
- return 'bg-orange-500';
189
- };
190
- return (
191
- <div key={idx} className="space-y-2">
192
- <div className="flex items-center justify-between gap-2">
193
- <span className="text-xs font-semibold text-gray-600 dark:text-gray-400">Confidence:</span>
194
- <span className="text-sm font-medium text-gray-700 dark:text-gray-300">{confidenceText}</span>
195
- </div>
196
- {/* Confidence temperature scale */}
197
- <div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2 overflow-hidden">
198
- <div
199
- className={`h-full transition-all duration-500 ${getConfidenceColor(confidenceValue)}`}
200
- style={{ width: `${Math.min(confidenceValue, 100)}%` }}
201
- />
202
- </div>
203
- {/* Confidence level indicators */}
204
- <div className="flex justify-between text-[10px] text-gray-400 dark:text-gray-500">
205
- <span>Low</span>
206
- <span>Medium</span>
207
- <span>High</span>
208
- </div>
209
- </div>
210
- );
211
- } else if (line.startsWith('**Explanation:**')) {
212
- // Extract explanation text (everything after "**Explanation:**\n")
213
- const explanationParts = message.content.split('**Explanation:**\n');
214
- const explanationText = explanationParts.length > 1 ? explanationParts[1] : '';
215
- return (
216
- <div key={idx} className="pt-2 border-t border-gray-200 dark:border-gray-700">
217
- <div className="text-xs font-semibold text-gray-600 dark:text-gray-400 mb-2">Explanation:</div>
218
- <div className="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
219
- {explanationText}
220
- </div>
221
- </div>
222
- );
223
- } else if (line.trim() === '') {
224
- return null;
225
- }
226
- return null;
227
- })}
228
- </div>
229
- ) : message.role === 'assistant' ? (
230
- <div className="whitespace-pre-wrap break-words">
231
- {message.content}
232
- </div>
233
- ) : null}
234
-
235
- {/* Process pipeline for extract topic tool */}
236
- {message.role === 'assistant' &&
237
- message.tool &&
238
- message.tool.toLowerCase().includes('extract') &&
239
- message.tool.toLowerCase().includes('topic') &&
240
- message.process && (
241
- <div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
242
- <div className="flex items-center gap-2 flex-wrap">
243
- <span className="text-[10px] uppercase tracking-wide text-gray-400 dark:text-gray-500 font-medium">
244
- Process:
245
- </span>
246
- {message.process.split('→').map((step, index, steps) => (
247
- <React.Fragment key={index}>
248
- <span className="px-2 py-0.5 text-[10px] bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded font-medium">
249
- {step.trim()}
250
- </span>
251
- {index < steps.length - 1 && (
252
- <span className="text-gray-400 dark:text-gray-600 text-xs">→</span>
253
- )}
254
- </React.Fragment>
255
- ))}
256
- </div>
257
- </div>
258
- )}
259
- <div className="text-sm leading-relaxed break-words">
260
- <ReactMarkdown
261
- components={{
262
- p: ({ node, ...props }) => (
263
- <p {...props} className="whitespace-pre-wrap mb-2 last:mb-0" />
264
- ),
265
- ul: ({ node, ...props }) => (
266
- <ul
267
- {...props}
268
- className="list-disc ml-5 space-y-1 mb-2 last:mb-0"
269
- />
270
- ),
271
- ol: ({ node, ...props }) => (
272
- <ol
273
- {...props}
274
- className="list-decimal ml-5 space-y-1 mb-2 last:mb-0"
275
- />
276
- ),
277
- li: ({ node, ...props }) => (
278
- <li {...props} className="ml-1" />
279
- ),
280
- }}
281
- >
282
- {message.content}
283
- </ReactMarkdown>
284
  </div>
 
 
 
 
 
 
 
285
 
286
- {message.role === 'assistant' && message.tool &&
287
- message.tool.toLowerCase().includes('generate') &&
288
- message.tool.toLowerCase().includes('argument') &&
289
- message.stance && (
290
- <div className="mt-3 flex gap-2">
291
- {message.stance === 'positive' && (
292
- <button
293
- type="button"
294
- className="px-3 py-1 text-xs rounded-full bg-emerald-500 text-white font-medium shadow-sm"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  >
296
- Positive stance
297
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  )}
299
- {message.stance === 'negative' && (
300
- <button
301
- type="button"
302
- className="px-3 py-1 text-xs rounded-full bg-rose-500 text-white font-medium shadow-sm"
303
- >
304
- Negative stance
305
- </button>
 
 
 
 
 
 
 
306
  )}
307
- </div>
308
- )}
 
 
 
 
 
309
  </div>
310
- )}
311
- <div
312
- className={`text-xs mt-1 ${
313
- message.role === 'user'
314
- ? 'text-teal-100'
315
- : 'text-gray-500 dark:text-gray-400'
316
- }`}
317
- >
318
- {formatTime(message.timestamp)}
319
  </div>
320
  </div>
321
- </div>
322
- ))}
323
-
324
 
325
  {isLoading && (
326
  <div className="flex justify-start">
 
12
  onRetry?: () => void;
13
  };
14
 
15
+ /**
16
+ * Helper to determine if a message should use the specialized detection stance UI
17
+ */
18
+ const isSpecializedStanceUI = (message: ChatMessage): boolean => {
19
+ const toolLower = message.tool?.toLowerCase() || '';
20
+ if (!toolLower.includes('detect') || !toolLower.includes('stance')) return false;
21
+
22
+ if (message.role === 'user') {
23
+ return message.content.includes('**Topic:**');
24
+ }
25
+ return message.role === 'assistant';
26
+ };
27
+
28
  const MessageList = ({ messages, isLoading = false, error = null, onRetry }: MessageListProps) => {
29
  const messagesEndRef = useRef<HTMLDivElement>(null);
30
 
 
45
 
46
  const getToolClasses = (message: ChatMessage) => {
47
  if (message.role !== 'assistant' || !message.tool) return '';
48
+
49
  const toolLower = message.tool.toLowerCase();
50
+
51
  // Match tool names flexibly (case-insensitive, handles variations)
52
  if (toolLower.includes('detect') && toolLower.includes('stance')) {
53
  return 'border-l-4 border-blue-400 pl-3 bg-blue-50/30 dark:bg-blue-900/10';
 
58
  if (toolLower.includes('extract') && toolLower.includes('topic')) {
59
  return 'border-l-4 border-emerald-400 pl-3 bg-emerald-50/30 dark:bg-emerald-900/10';
60
  }
61
+
62
  // Default styling for other tools
63
  return 'border-l-4 border-teal-400 pl-3 bg-teal-50/30 dark:bg-teal-900/10';
64
  };
65
 
66
  const getToolLabel = (tool: string | null | undefined): string => {
67
  if (!tool) return '';
68
+
69
  const toolLower = tool.toLowerCase();
70
+
71
  if (toolLower.includes('detect') && toolLower.includes('stance')) {
72
  return 'Detect Stance';
73
  }
 
77
  if (toolLower.includes('extract') && toolLower.includes('topic')) {
78
  return 'Extract Topic';
79
  }
80
+
81
  // Return formatted tool name (capitalize first letter of each word)
82
+ return tool.split(/[\s_-]+/).map(word =>
83
  word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
84
  ).join(' ');
85
  };
86
+
87
  return (
88
  <div className="flex-1 overflow-y-auto px-4 py-6 space-y-4">
89
  {messages.length === 0 && !isLoading && (
 
104
  </div>
105
  )}
106
 
107
+ {messages.map((message, index) => {
108
+ const showSpecializedStance = isSpecializedStanceUI(message);
109
+
110
+ return (
 
111
  <div
112
+ key={message.id}
113
+ className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
114
+ >
115
+ <div
116
+ className={`max-w-3xl px-4 py-3 rounded-2xl ${message.role === 'user'
117
  ? 'bg-teal-500 text-white ml-12'
118
  : 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 mr-12'
119
+ }${getToolClasses(message) ? ' ' + getToolClasses(message) : ''}`}
120
+ >
121
+ {message.audioUrl ? (
122
+ <div>
123
+ <AudioPlayer
124
+ src={message.audioUrl}
125
+ autoPlay={message.role === 'assistant' && index === messages.length - 1}
126
+ />
 
127
  <TranscriptToggle content={message.content} />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  </div>
129
+ ) : (
130
+ <div className="space-y-3">
131
+ {message.tool && message.role === 'assistant' && (
132
+ <div className="mb-1 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
133
+ {getToolLabel(message.tool)}
134
+ </div>
135
+ )}
136
 
137
+ {showSpecializedStance ? (
138
+ <div className="space-y-3">
139
+ {message.role === 'user' ? (
140
+ <div className="space-y-2">
141
+ {message.content.split('\n').map((line, idx) => {
142
+ if (line.startsWith('**Topic:**')) {
143
+ const topicText = line.replace('**Topic:**', '').trim();
144
+ return (
145
+ <div key={idx}>
146
+ <span className="text-xs font-semibold opacity-90">Topic: </span>
147
+ <span className="text-sm">{topicText}</span>
148
+ </div>
149
+ );
150
+ } else if (line.startsWith('**Argument:**')) {
151
+ const argumentText = line.replace('**Argument:**', '').trim();
152
+ return (
153
+ <div key={idx}>
154
+ <span className="text-xs font-semibold opacity-90">Argument: </span>
155
+ <span className="text-sm">{argumentText}</span>
156
+ </div>
157
+ );
158
+ }
159
+ return null;
160
+ })}
161
+ </div>
162
+ ) : (
163
+ <div className="space-y-3">
164
+ {message.content.split('\n').map((line, idx) => {
165
+ if (line.startsWith('**Stance:**')) {
166
+ const stanceText = line.replace('**Stance:**', '').trim();
167
+ const isPro = stanceText.includes('PRO') || stanceText.toLowerCase().includes('positive');
168
+ return (
169
+ <div key={idx} className="flex items-center gap-2">
170
+ <span className="text-xs font-semibold text-gray-600 dark:text-gray-400">Stance:</span>
171
+ <span className={`px-2.5 py-1 rounded-full text-xs font-semibold ${isPro
172
+ ? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-200'
173
+ : 'bg-rose-100 text-rose-800 dark:bg-rose-900/40 dark:text-rose-200'
174
+ }`}>
175
+ {stanceText}
176
+ </span>
177
+ </div>
178
+ );
179
+ } else if (line.startsWith('**Confidence:**')) {
180
+ const confidenceText = line.replace('**Confidence:**', '').trim();
181
+ const confidenceValue = parseFloat(confidenceText.replace('%', '')) || 0;
182
+ const getConfidenceColor = (value: number) => {
183
+ if (value >= 80) return 'bg-emerald-500';
184
+ if (value >= 60) return 'bg-yellow-500';
185
+ return 'bg-orange-500';
186
+ };
187
+ return (
188
+ <div key={idx} className="space-y-2">
189
+ <div className="flex items-center justify-between gap-2">
190
+ <span className="text-xs font-semibold text-gray-600 dark:text-gray-400">Confidence:</span>
191
+ <span className="text-sm font-medium text-gray-700 dark:text-gray-300">{confidenceText}</span>
192
+ </div>
193
+ <div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5 overflow-hidden">
194
+ <div
195
+ className={`h-full transition-all duration-500 ${getConfidenceColor(confidenceValue)}`}
196
+ style={{ width: `${Math.min(confidenceValue, 100)}%` }}
197
+ />
198
+ </div>
199
+ </div>
200
+ );
201
+ } else if (line.startsWith('**Explanation:**')) {
202
+ const explanationParts = message.content.split('**Explanation:**\n');
203
+ const explanationText = explanationParts.length > 1 ? explanationParts[1] : '';
204
+ return (
205
+ <div key={idx} className="pt-2 border-t border-gray-200 dark:border-gray-700">
206
+ <div className="text-xs font-semibold text-gray-600 dark:text-gray-400 mb-1">Explanation:</div>
207
+ <div className="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
208
+ {explanationText}
209
+ </div>
210
+ </div>
211
+ );
212
+ }
213
+ return null;
214
+ })}
215
+ </div>
216
+ )}
217
+ </div>
218
+ ) : (
219
+ <div className="text-sm leading-relaxed break-words">
220
+ <ReactMarkdown
221
+ components={{
222
+ p: ({ node, ...props }) => (
223
+ <p {...props} className="whitespace-pre-wrap mb-2 last:mb-0" />
224
+ ),
225
+ ul: ({ node, ...props }) => (
226
+ <ul {...props} className="list-disc ml-5 space-y-1 mb-2 last:mb-0" />
227
+ ),
228
+ ol: ({ node, ...props }) => (
229
+ <ol {...props} className="list-decimal ml-5 space-y-1 mb-2 last:mb-0" />
230
+ ),
231
+ li: ({ node, ...props }) => (
232
+ <li {...props} className="ml-1" />
233
+ ),
234
+ }}
235
  >
236
+ {typeof message.content === 'string' ? message.content : ''}
237
+ </ReactMarkdown>
238
+ </div>
239
+ )}
240
+
241
+ {/* Process pipeline for extract topic tool */}
242
+ {message.role === 'assistant' &&
243
+ message.tool?.toLowerCase().includes('extract') &&
244
+ message.tool?.toLowerCase().includes('topic') &&
245
+ message.process && (
246
+ <div className="mt-3 pt-3 border-t border-gray-200 dark:border-gray-700">
247
+ <div className="flex items-center gap-2 flex-wrap">
248
+ <span className="text-[10px] uppercase tracking-wide text-gray-400 dark:text-gray-500 font-medium">
249
+ Process:
250
+ </span>
251
+ {message.process.split('→').map((step, sIdx, steps) => (
252
+ <React.Fragment key={sIdx}>
253
+ <span className="px-2 py-0.5 text-[10px] bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded font-medium">
254
+ {step.trim()}
255
+ </span>
256
+ {sIdx < steps.length - 1 && (
257
+ <span className="text-gray-400 dark:text-gray-600 text-xs">→</span>
258
+ )}
259
+ </React.Fragment>
260
+ ))}
261
+ </div>
262
+ </div>
263
  )}
264
+
265
+ {/* Stance info for generate argument tool */}
266
+ {message.role === 'assistant' &&
267
+ message.tool?.toLowerCase().includes('generate') &&
268
+ message.tool?.toLowerCase().includes('argument') &&
269
+ message.stance && (
270
+ <div className="mt-2 flex gap-2">
271
+ <span className={`px-2.5 py-0.5 text-[10px] rounded-full font-semibold uppercase tracking-wider ${message.stance === 'positive'
272
+ ? 'bg-emerald-500 text-white'
273
+ : 'bg-rose-500 text-white'
274
+ }`}>
275
+ {message.stance} stance
276
+ </span>
277
+ </div>
278
  )}
279
+ </div>
280
+ )}
281
+ <div
282
+ className={`text-[10px] mt-2 opacity-60 ${message.role === 'user' ? 'text-right opacity-80' : 'text-left'
283
+ }`}
284
+ >
285
+ {formatTime(message.timestamp)}
286
  </div>
 
 
 
 
 
 
 
 
 
287
  </div>
288
  </div>
289
+ );
290
+ })}
 
291
 
292
  {isLoading && (
293
  <div className="flex justify-start">