mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-01-30 06:12:06 +00:00
Merge pull request #877 from TonyGeez/feature/add-model-selector-command
Feature/add model selector command
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,4 +4,5 @@ log.txt
|
||||
.idea
|
||||
dist
|
||||
.DS_Store
|
||||
.vscode
|
||||
.vscode
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
"dependencies": {
|
||||
"@fastify/static": "^8.2.0",
|
||||
"@musistudio/llms": "^1.0.36",
|
||||
"@inquirer/prompts": "^5.0.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"find-process": "^2.0.0",
|
||||
"json5": "^2.2.3",
|
||||
"lru-cache": "^11.2.2",
|
||||
"minimist": "^1.2.8",
|
||||
"openurl": "^1.1.1",
|
||||
"rotating-file-stream": "^3.2.7",
|
||||
|
||||
244
pnpm-lock.yaml
generated
244
pnpm-lock.yaml
generated
@@ -11,6 +11,9 @@ importers:
|
||||
'@fastify/static':
|
||||
specifier: ^8.2.0
|
||||
version: 8.2.0
|
||||
'@inquirer/prompts':
|
||||
specifier: ^5.0.0
|
||||
version: 5.5.0
|
||||
'@musistudio/llms':
|
||||
specifier: ^1.0.36
|
||||
version: 1.0.36(ws@8.18.3)
|
||||
@@ -23,6 +26,9 @@ importers:
|
||||
json5:
|
||||
specifier: ^2.2.3
|
||||
version: 2.2.3
|
||||
lru-cache:
|
||||
specifier: ^11.2.2
|
||||
version: 11.2.2
|
||||
minimist:
|
||||
specifier: ^1.2.8
|
||||
version: 1.2.8
|
||||
@@ -259,6 +265,66 @@ packages:
|
||||
'@modelcontextprotocol/sdk':
|
||||
optional: true
|
||||
|
||||
'@inquirer/checkbox@2.5.0':
|
||||
resolution: {integrity: sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/confirm@3.2.0':
|
||||
resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/core@9.2.1':
|
||||
resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/editor@2.2.0':
|
||||
resolution: {integrity: sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/expand@2.3.0':
|
||||
resolution: {integrity: sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/figures@1.0.13':
|
||||
resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/input@2.3.0':
|
||||
resolution: {integrity: sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/number@1.1.0':
|
||||
resolution: {integrity: sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/password@2.2.0':
|
||||
resolution: {integrity: sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/prompts@5.5.0':
|
||||
resolution: {integrity: sha512-BHDeL0catgHdcHbSFFUddNzvx/imzJMft+tWDPwTm3hfu8/tApk1HrooNngB2Mb4qY+KaRWF+iZqoVUPeslEog==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/rawlist@2.3.0':
|
||||
resolution: {integrity: sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/search@1.1.0':
|
||||
resolution: {integrity: sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/select@2.5.0':
|
||||
resolution: {integrity: sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/type@1.5.5':
|
||||
resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@inquirer/type@2.0.0':
|
||||
resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@isaacs/balanced-match@4.0.1':
|
||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
@@ -293,6 +359,9 @@ packages:
|
||||
'@types/node@24.7.0':
|
||||
resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==}
|
||||
|
||||
'@types/wrap-ansi@3.0.0':
|
||||
resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==}
|
||||
|
||||
abstract-logging@2.0.1:
|
||||
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
|
||||
|
||||
@@ -311,6 +380,10 @@ packages:
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
ansi-escapes@4.3.2:
|
||||
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -351,6 +424,13 @@ packages:
|
||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
chardet@0.7.0:
|
||||
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
|
||||
|
||||
cli-width@4.1.0:
|
||||
resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
@@ -433,6 +513,10 @@ packages:
|
||||
extend@3.0.2:
|
||||
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
|
||||
|
||||
external-editor@3.1.0:
|
||||
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
fast-decode-uri-component@1.0.1:
|
||||
resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
|
||||
|
||||
@@ -557,6 +641,10 @@ packages:
|
||||
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
@@ -665,6 +753,10 @@ packages:
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
mute-stream@1.0.0:
|
||||
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
|
||||
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
|
||||
|
||||
nice-try@1.0.5:
|
||||
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
|
||||
|
||||
@@ -712,6 +804,10 @@ packages:
|
||||
openurl@1.1.1:
|
||||
resolution: {integrity: sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==}
|
||||
|
||||
os-tmpdir@1.0.2:
|
||||
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
p-finally@1.0.0:
|
||||
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -911,6 +1007,10 @@ packages:
|
||||
tiktoken@1.0.22:
|
||||
resolution: {integrity: sha512-PKvy1rVF1RibfF3JlXBSP0Jrcw2uq3yXdgcEXtKTYn3QJ/cBRBHDnrJ5jHky+MENZ6DIPwNUGWpkVx+7joCpNA==}
|
||||
|
||||
tmp@0.0.33:
|
||||
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
|
||||
engines: {node: '>=0.6.0'}
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
@@ -965,6 +1065,10 @@ packages:
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -988,6 +1092,10 @@ packages:
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
yoctocolors-cjs@2.1.3:
|
||||
resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@anthropic-ai/sdk@0.54.0': {}
|
||||
@@ -1127,6 +1235,106 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@inquirer/checkbox@2.5.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/figures': 1.0.13
|
||||
'@inquirer/type': 1.5.5
|
||||
ansi-escapes: 4.3.2
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/confirm@3.2.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
|
||||
'@inquirer/core@9.2.1':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.13
|
||||
'@inquirer/type': 2.0.0
|
||||
'@types/mute-stream': 0.0.4
|
||||
'@types/node': 22.18.8
|
||||
'@types/wrap-ansi': 3.0.0
|
||||
ansi-escapes: 4.3.2
|
||||
cli-width: 4.1.0
|
||||
mute-stream: 1.0.0
|
||||
signal-exit: 4.1.0
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/editor@2.2.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
external-editor: 3.1.0
|
||||
|
||||
'@inquirer/expand@2.3.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/figures@1.0.13': {}
|
||||
|
||||
'@inquirer/input@2.3.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
|
||||
'@inquirer/number@1.1.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
|
||||
'@inquirer/password@2.2.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
ansi-escapes: 4.3.2
|
||||
|
||||
'@inquirer/prompts@5.5.0':
|
||||
dependencies:
|
||||
'@inquirer/checkbox': 2.5.0
|
||||
'@inquirer/confirm': 3.2.0
|
||||
'@inquirer/editor': 2.2.0
|
||||
'@inquirer/expand': 2.3.0
|
||||
'@inquirer/input': 2.3.0
|
||||
'@inquirer/number': 1.1.0
|
||||
'@inquirer/password': 2.2.0
|
||||
'@inquirer/rawlist': 2.3.0
|
||||
'@inquirer/search': 1.1.0
|
||||
'@inquirer/select': 2.5.0
|
||||
|
||||
'@inquirer/rawlist@2.3.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/type': 1.5.5
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/search@1.1.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/figures': 1.0.13
|
||||
'@inquirer/type': 1.5.5
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/select@2.5.0':
|
||||
dependencies:
|
||||
'@inquirer/core': 9.2.1
|
||||
'@inquirer/figures': 1.0.13
|
||||
'@inquirer/type': 1.5.5
|
||||
ansi-escapes: 4.3.2
|
||||
yoctocolors-cjs: 2.1.3
|
||||
|
||||
'@inquirer/type@1.5.5':
|
||||
dependencies:
|
||||
mute-stream: 1.0.0
|
||||
|
||||
'@inquirer/type@2.0.0':
|
||||
dependencies:
|
||||
mute-stream: 1.0.0
|
||||
|
||||
'@isaacs/balanced-match@4.0.1': {}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.0':
|
||||
@@ -1182,6 +1390,8 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 7.14.0
|
||||
|
||||
'@types/wrap-ansi@3.0.0': {}
|
||||
|
||||
abstract-logging@2.0.1: {}
|
||||
|
||||
agent-base@7.1.4: {}
|
||||
@@ -1197,6 +1407,10 @@ snapshots:
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
ansi-escapes@4.3.2:
|
||||
dependencies:
|
||||
type-fest: 0.21.3
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.2.2: {}
|
||||
@@ -1229,6 +1443,10 @@ snapshots:
|
||||
ansi-styles: 4.3.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
chardet@0.7.0: {}
|
||||
|
||||
cli-width@4.1.0: {}
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
@@ -1326,6 +1544,12 @@ snapshots:
|
||||
|
||||
extend@3.0.2: {}
|
||||
|
||||
external-editor@3.1.0:
|
||||
dependencies:
|
||||
chardet: 0.7.0
|
||||
iconv-lite: 0.4.24
|
||||
tmp: 0.0.33
|
||||
|
||||
fast-decode-uri-component@1.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
@@ -1526,6 +1750,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
interpret@1.4.0: {}
|
||||
@@ -1610,6 +1838,8 @@ snapshots:
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
mute-stream@1.0.0: {}
|
||||
|
||||
nice-try@1.0.5: {}
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
@@ -1640,6 +1870,8 @@ snapshots:
|
||||
|
||||
openurl@1.1.1: {}
|
||||
|
||||
os-tmpdir@1.0.2: {}
|
||||
|
||||
p-finally@1.0.0: {}
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
@@ -1808,6 +2040,10 @@ snapshots:
|
||||
|
||||
tiktoken@1.0.22: {}
|
||||
|
||||
tmp@0.0.33:
|
||||
dependencies:
|
||||
os-tmpdir: 1.0.2
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
@@ -1845,6 +2081,12 @@ snapshots:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
@@ -1860,3 +2102,5 @@ snapshots:
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@8.18.3: {}
|
||||
|
||||
yoctocolors-cjs@2.1.3: {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {IAgent, ITool} from "./type";
|
||||
import { createHash } from 'crypto';
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import * as LRU from 'lru-cache';
|
||||
|
||||
interface ImageCacheEntry {
|
||||
source: any;
|
||||
@@ -8,12 +8,13 @@ interface ImageCacheEntry {
|
||||
}
|
||||
|
||||
class ImageCache {
|
||||
private cache: LRUCache<string, ImageCacheEntry>;
|
||||
private cache: any;
|
||||
|
||||
constructor(maxSize = 100) {
|
||||
this.cache = new LRUCache({
|
||||
const CacheClass: any = (LRU as any).LRUCache || (LRU as any);
|
||||
this.cache = new CacheClass({
|
||||
max: maxSize,
|
||||
ttl: 5 * 60 * 1000,
|
||||
ttl: 5 * 60 * 1000, // 5 minutes
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
isServiceRunning,
|
||||
getServiceInfo,
|
||||
} from "./utils/processCheck";
|
||||
import { runModelSelector } from "./utils/modelSelector"; // ADD THIS LINE
|
||||
import { version } from "../package.json";
|
||||
import { spawn, exec } from "child_process";
|
||||
import { PID_FILE, REFERENCE_COUNT_FILE } from "./constants";
|
||||
@@ -26,6 +27,7 @@ Commands:
|
||||
status Show server status
|
||||
statusline Integrated statusline
|
||||
code Execute claude command
|
||||
model Interactive model selection and configuration
|
||||
ui Open the web UI in browser
|
||||
-v, version Show version information
|
||||
-h, help Show help information
|
||||
@@ -33,6 +35,7 @@ Commands:
|
||||
Example:
|
||||
ccr start
|
||||
ccr code "Write a Hello World"
|
||||
ccr model
|
||||
ccr ui
|
||||
`;
|
||||
|
||||
@@ -109,6 +112,10 @@ async function main() {
|
||||
}
|
||||
});
|
||||
break;
|
||||
// ADD THIS CASE
|
||||
case "model":
|
||||
await runModelSelector();
|
||||
break;
|
||||
case "code":
|
||||
if (!isRunning) {
|
||||
console.log("Service not running, starting service...");
|
||||
@@ -321,4 +328,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
main().catch(console.error);
|
||||
462
src/utils/modelSelector.ts
Normal file
462
src/utils/modelSelector.ts
Normal file
@@ -0,0 +1,462 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { select, input, confirm } from '@inquirer/prompts';
|
||||
|
||||
// ANSI color codes
|
||||
const RESET = "\x1B[0m";
|
||||
const DIM = "\x1B[2m";
|
||||
const BOLDGREEN = "\x1B[1m\x1B[32m";
|
||||
const CYAN = "\x1B[36m";
|
||||
const BOLDCYAN = "\x1B[1m\x1B[36m";
|
||||
const GREEN = "\x1B[32m";
|
||||
const YELLOW = "\x1B[33m";
|
||||
const BOLDYELLOW = "\x1B[1m\x1B[33m";
|
||||
|
||||
interface TransformerConfig {
|
||||
use: Array<string | [string, any]>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface Provider {
|
||||
name: string;
|
||||
api_base_url: string;
|
||||
api_key: string;
|
||||
models: string[];
|
||||
transformer?: TransformerConfig;
|
||||
}
|
||||
|
||||
interface RouterConfig {
|
||||
default: string;
|
||||
background?: string;
|
||||
think?: string;
|
||||
longContext?: string;
|
||||
longContextThreshold?: number;
|
||||
webSearch?: string;
|
||||
image?: string;
|
||||
[key: string]: string | number | undefined;
|
||||
}
|
||||
|
||||
interface Config {
|
||||
Providers: Provider[];
|
||||
Router: RouterConfig;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface ModelResult {
|
||||
providerName: string;
|
||||
modelName: string;
|
||||
modelType: string;
|
||||
}
|
||||
|
||||
const AVAILABLE_TRANSFORMERS = [
|
||||
'anthropic',
|
||||
'deepseek',
|
||||
'gemini',
|
||||
'openrouter',
|
||||
'groq',
|
||||
'maxtoken',
|
||||
'tooluse',
|
||||
'gemini-cli',
|
||||
'reasoning',
|
||||
'sampling',
|
||||
'enhancetool',
|
||||
'cleancache',
|
||||
'vertex-gemini',
|
||||
'chutes-glm',
|
||||
'qwen-cli',
|
||||
'rovo-cli'
|
||||
];
|
||||
|
||||
function getConfigPath(): string {
|
||||
const configDir = path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude-code-router');
|
||||
const configPath = path.join(configDir, 'config.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
throw new Error(`config.json not found at ${configPath}`);
|
||||
}
|
||||
|
||||
return configPath;
|
||||
}
|
||||
|
||||
function loadConfig(): Config {
|
||||
const configPath = getConfigPath();
|
||||
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
}
|
||||
|
||||
function saveConfig(config: Config): void {
|
||||
const configPath = getConfigPath();
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
||||
console.log(`${GREEN}✓ config.json updated successfully${RESET}\n`);
|
||||
}
|
||||
|
||||
function getAllModels(config: Config) {
|
||||
const models: any[] = [];
|
||||
for (const provider of config.Providers) {
|
||||
for (const model of provider.models) {
|
||||
models.push({
|
||||
name: `${BOLDCYAN}${provider.name}${RESET} → ${CYAN} ${model}`,
|
||||
value: `${provider.name},${model}`,
|
||||
description: `\n${BOLDCYAN}Provider:${RESET} ${provider.name}`,
|
||||
provider: provider.name,
|
||||
model: model
|
||||
});
|
||||
}
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
function displayCurrentConfig(config: Config): void {
|
||||
console.log(`\n${BOLDCYAN}═══════════════════════════════════════════════${RESET}`);
|
||||
console.log(`${BOLDCYAN} Current Configuration${RESET}`);
|
||||
console.log(`${BOLDCYAN}═══════════════════════════════════════════════${RESET}\n`);
|
||||
|
||||
const formatModel = (routerValue?: string | number) => {
|
||||
if (!routerValue || typeof routerValue === 'number') {
|
||||
return `${DIM}Not configured${RESET}`;
|
||||
}
|
||||
const [provider, model] = routerValue.split(',');
|
||||
return `${YELLOW}${provider}${RESET} | ${model}\n ${DIM}- ${routerValue}${RESET}`;
|
||||
};
|
||||
|
||||
console.log(`${BOLDCYAN}Default Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.default)}\n`);
|
||||
|
||||
if (config.Router.background) {
|
||||
console.log(`${BOLDCYAN}Background Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.background)}\n`);
|
||||
}
|
||||
|
||||
if (config.Router.think) {
|
||||
console.log(`${BOLDCYAN}Think Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.think)}\n`);
|
||||
}
|
||||
|
||||
if (config.Router.longContext) {
|
||||
console.log(`${BOLDCYAN}Long Context Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.longContext)}\n`);
|
||||
}
|
||||
|
||||
if (config.Router.webSearch) {
|
||||
console.log(`${BOLDCYAN}Web Search Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.webSearch)}\n`);
|
||||
}
|
||||
|
||||
if (config.Router.image) {
|
||||
console.log(`${BOLDCYAN}Image Model:${RESET}`);
|
||||
console.log(` ${formatModel(config.Router.image)}\n`);
|
||||
}
|
||||
|
||||
console.log(`\n${BOLDCYAN}═══════════════════════════════════════════════${RESET}`);
|
||||
console.log(`${BOLDCYAN} Add/Update Model${RESET}`);
|
||||
console.log(`${BOLDCYAN}═══════════════════════════════════════════════${RESET}\n`);
|
||||
}
|
||||
|
||||
async function selectModelType() {
|
||||
return await select({
|
||||
message: `${BOLDYELLOW}Which model configuration do you want to update?${RESET}`,
|
||||
choices: [
|
||||
{ name: 'Default Model', value: 'default' },
|
||||
{ name: 'Background Model', value: 'background' },
|
||||
{ name: 'Think Model', value: 'think' },
|
||||
{ name: 'Long Context Model', value: 'longContext' },
|
||||
{ name: 'Web Search Model', value: 'webSearch' },
|
||||
{ name: 'Image Model', value: 'image' },
|
||||
{ name: `${BOLDGREEN}+ Add New Model${RESET}`, value: 'addModel' }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async function selectModel(config: Config, modelType: string) {
|
||||
const models = getAllModels(config);
|
||||
|
||||
return await select({
|
||||
message: `\n${BOLDYELLOW}Select a model for ${modelType}:${RESET}`,
|
||||
choices: models,
|
||||
pageSize: 15
|
||||
});
|
||||
}
|
||||
|
||||
async function configureTransformers(): Promise<TransformerConfig | undefined> {
|
||||
const useTransformers = await confirm({
|
||||
message: `\n${BOLDYELLOW}Add transformer configuration?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
|
||||
if (!useTransformers) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const transformers: Array<string | [string, any]> = [];
|
||||
let addMore = true;
|
||||
|
||||
while (addMore) {
|
||||
const transformer = await select({
|
||||
message: `\n${BOLDYELLOW}Select a transformer:${RESET}`,
|
||||
choices: AVAILABLE_TRANSFORMERS.map(t => ({ name: t, value: t })),
|
||||
pageSize: 15
|
||||
}) as string;
|
||||
|
||||
// Check if transformer needs options
|
||||
if (transformer === 'maxtoken') {
|
||||
const maxTokens = await input({
|
||||
message: `\n${BOLDYELLOW}Max tokens:${RESET}`,
|
||||
default: '30000',
|
||||
validate: (value: string) => {
|
||||
const num = parseInt(value);
|
||||
if (isNaN(num) || num <= 0) {
|
||||
return 'Please enter a valid positive number';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
transformers.push(['maxtoken', { max_tokens: parseInt(maxTokens) }]);
|
||||
} else if (transformer === 'openrouter') {
|
||||
const addProvider = await confirm({
|
||||
message: `\n${BOLDYELLOW}Add provider routing options?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
|
||||
if (addProvider) {
|
||||
const providerInput = await input({
|
||||
message: 'Provider (e.g., moonshotai/fp8):',
|
||||
validate: (value: string) => value.trim() !== '' || 'Provider cannot be empty'
|
||||
});
|
||||
transformers.push(['openrouter', { provider: { only: [providerInput] } }]);
|
||||
} else {
|
||||
transformers.push(transformer);
|
||||
}
|
||||
} else {
|
||||
transformers.push(transformer);
|
||||
}
|
||||
|
||||
addMore = await confirm({
|
||||
message: `\n${BOLDYELLOW}Add another transformer?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
}
|
||||
|
||||
return { use: transformers };
|
||||
}
|
||||
|
||||
async function addNewModel(config: Config): Promise<ModelResult | null> {
|
||||
const providerChoices = config.Providers.map(p => ({
|
||||
name: p.name,
|
||||
value: p.name
|
||||
}));
|
||||
|
||||
providerChoices.push({ name: `${BOLDGREEN}+ Add New Provider${RESET}`, value: '__new__' });
|
||||
|
||||
const selectedProvider = await select({
|
||||
message: `\n${BOLDYELLOW}Select provider for the new model:${RESET}`,
|
||||
choices: providerChoices
|
||||
}) as string;
|
||||
|
||||
if (selectedProvider === '__new__') {
|
||||
return await addNewProvider(config);
|
||||
} else {
|
||||
return await addModelToExistingProvider(config, selectedProvider);
|
||||
}
|
||||
}
|
||||
|
||||
async function addModelToExistingProvider(config: Config, providerName: string): Promise<ModelResult | null> {
|
||||
const modelName = await input({
|
||||
message: `\n${BOLDYELLOW}Enter the model name:${RESET}`,
|
||||
validate: (value: string) => {
|
||||
if (!value.trim()) {
|
||||
return 'Model name cannot be empty';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const provider = config.Providers.find(p => p.name === providerName);
|
||||
|
||||
if (!provider) {
|
||||
console.log(`${YELLOW}Provider not found${RESET}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (provider.models.includes(modelName)) {
|
||||
console.log(`${YELLOW}Model already exists in provider${RESET}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
provider.models.push(modelName);
|
||||
|
||||
// Ask about model-specific transformers
|
||||
const addModelTransformer = await confirm({
|
||||
message: `\n${BOLDYELLOW}Add model-specific transformer configuration?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
|
||||
if (addModelTransformer) {
|
||||
const transformerConfig = await configureTransformers();
|
||||
if (transformerConfig && provider.transformer) {
|
||||
provider.transformer[modelName] = transformerConfig;
|
||||
}
|
||||
}
|
||||
|
||||
saveConfig(config);
|
||||
|
||||
console.log(`${GREEN}✓ Model "${modelName}" added to provider "${providerName}"${RESET}`);
|
||||
|
||||
const setAsDefault = await confirm({
|
||||
message: `\n${BOLDYELLOW}Do you want to set this model in router configuration?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
|
||||
if (setAsDefault) {
|
||||
const modelType = await select({
|
||||
message: `\n${BOLDYELLOW}Select configuration type:${RESET}`,
|
||||
choices: [
|
||||
{ name: 'Default Model', value: 'default' },
|
||||
{ name: 'Background Model', value: 'background' },
|
||||
{ name: 'Think Model', value: 'think' },
|
||||
{ name: 'Long Context Model', value: 'longContext' },
|
||||
{ name: 'Web Search Model', value: 'webSearch' },
|
||||
{ name: 'Image Model', value: 'image' }
|
||||
]
|
||||
}) as string;
|
||||
|
||||
return { providerName, modelName, modelType };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function addNewProvider(config: Config): Promise<ModelResult | null> {
|
||||
console.log(`\n${BOLDCYAN}Adding New Provider${RESET}\n`);
|
||||
|
||||
const providerName = await input({
|
||||
message: `${BOLDYELLOW}Provider name:${RESET}`,
|
||||
validate: (value: string) => {
|
||||
if (!value.trim()) {
|
||||
return 'Provider name cannot be empty';
|
||||
}
|
||||
if (config.Providers.some(p => p.name === value)) {
|
||||
return 'Provider already exists';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const apiBaseUrl = await input({
|
||||
message: `\n${BOLDYELLOW}API base URL:${RESET}`,
|
||||
validate: (value: string) => {
|
||||
if (!value.trim()) {
|
||||
return 'API base URL cannot be empty';
|
||||
}
|
||||
try {
|
||||
new URL(value);
|
||||
return true;
|
||||
} catch {
|
||||
return 'Please enter a valid URL';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const apiKey = await input({
|
||||
message: `\n${BOLDYELLOW}API key:${RESET}`,
|
||||
validate: (value: string) => {
|
||||
if (!value.trim()) {
|
||||
return 'API key cannot be empty';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const modelsInput = await input({
|
||||
message: `\n${BOLDYELLOW}Model names (comma-separated):${RESET}`,
|
||||
validate: (value: string) => {
|
||||
if (!value.trim()) {
|
||||
return 'At least one model name is required';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const models = modelsInput.split(',').map(m => m.trim()).filter(m => m);
|
||||
|
||||
const newProvider: Provider = {
|
||||
name: providerName,
|
||||
api_base_url: apiBaseUrl,
|
||||
api_key: apiKey,
|
||||
models: models
|
||||
};
|
||||
|
||||
// Global transformer configuration
|
||||
const transformerConfig = await configureTransformers();
|
||||
if (transformerConfig) {
|
||||
newProvider.transformer = transformerConfig;
|
||||
}
|
||||
|
||||
config.Providers.push(newProvider);
|
||||
saveConfig(config);
|
||||
|
||||
console.log(`${GREEN}\n✓ Provider "${providerName}" added successfully${RESET}`);
|
||||
|
||||
const setAsDefault = await confirm({
|
||||
message: `\n${BOLDYELLOW}Do you want to set one of these models in router configuration?${RESET}`,
|
||||
default: false
|
||||
});
|
||||
|
||||
if (setAsDefault && models.length > 0) {
|
||||
let selectedModel = models[0];
|
||||
|
||||
if (models.length > 1) {
|
||||
selectedModel = await select({
|
||||
message: `\n${BOLDYELLOW}Select which model to configure:${RESET}`,
|
||||
choices: models.map(m => ({ name: m, value: m }))
|
||||
}) as string;
|
||||
}
|
||||
|
||||
const modelType = await select({
|
||||
message: `\n${BOLDYELLOW}Select configuration type:${RESET}`,
|
||||
choices: [
|
||||
{ name: 'Default Model', value: 'default' },
|
||||
{ name: 'Background Model', value: 'background' },
|
||||
{ name: 'Think Model', value: 'think' },
|
||||
{ name: 'Long Context Model', value: 'longContext' },
|
||||
{ name: 'Web Search Model', value: 'webSearch' },
|
||||
{ name: 'Image Model', value: 'image' }
|
||||
]
|
||||
}) as string;
|
||||
|
||||
return { providerName, modelName: selectedModel, modelType };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function runModelSelector(): Promise<void> {
|
||||
console.clear();
|
||||
|
||||
try {
|
||||
let config = loadConfig();
|
||||
displayCurrentConfig(config);
|
||||
|
||||
const action = await selectModelType() as string;
|
||||
|
||||
if (action === 'addModel') {
|
||||
const result = await addNewModel(config);
|
||||
|
||||
if (result) {
|
||||
config = loadConfig();
|
||||
config.Router[result.modelType] = `${result.providerName},${result.modelName}`;
|
||||
saveConfig(config);
|
||||
console.log(`${GREEN}✓ ${result.modelType} set to ${result.providerName},${result.modelName}${RESET}`);
|
||||
}
|
||||
} else {
|
||||
const selectedModel = await selectModel(config, action) as string;
|
||||
config.Router[action] = selectedModel;
|
||||
saveConfig(config);
|
||||
|
||||
console.log(`${GREEN}✓ ${action} model updated to: ${selectedModel}${RESET}`);
|
||||
}
|
||||
|
||||
displayCurrentConfig(config);
|
||||
} catch (error: any) {
|
||||
console.error(`${YELLOW}Error:${RESET}`, error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
139
ui/package-lock.json
generated
139
ui/package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -1181,6 +1182,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
||||
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
@@ -1247,6 +1274,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-direction": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
||||
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
|
||||
@@ -1495,6 +1537,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-roving-focus": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
||||
"integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-collection": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
@@ -1542,6 +1621,66 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
|
||||
"integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-presence": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-roving-focus": "1.1.11",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"root":["./src/app.tsx","./src/i18n.ts","./src/main.tsx","./src/routes.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/configprovider.tsx","./src/components/debugpage.tsx","./src/components/jsoneditor.tsx","./src/components/logviewer.tsx","./src/components/login.tsx","./src/components/protectedroute.tsx","./src/components/providerlist.tsx","./src/components/providers.tsx","./src/components/publicroute.tsx","./src/components/requesthistorydrawer.tsx","./src/components/router.tsx","./src/components/settingsdialog.tsx","./src/components/statuslineconfigdialog.tsx","./src/components/statuslineimportexport.tsx","./src/components/transformerlist.tsx","./src/components/transformers.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/color-picker.tsx","./src/components/ui/combo-input.tsx","./src/components/ui/combobox.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-combobox.tsx","./src/components/ui/popover.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/toast.tsx","./src/lib/api.ts","./src/lib/db.ts","./src/lib/utils.ts","./src/utils/statusline.ts"],"version":"5.8.3"}
|
||||
{"root":["./src/App.tsx","./src/i18n.ts","./src/main.tsx","./src/routes.tsx","./src/types.ts","./src/vite-env.d.ts","./src/components/ConfigProvider.tsx","./src/components/DebugPage.tsx","./src/components/JsonEditor.tsx","./src/components/LogViewer.tsx","./src/components/Login.tsx","./src/components/ProtectedRoute.tsx","./src/components/ProviderList.tsx","./src/components/Providers.tsx","./src/components/PublicRoute.tsx","./src/components/RequestHistoryDrawer.tsx","./src/components/Router.tsx","./src/components/SettingsDialog.tsx","./src/components/StatusLineConfigDialog.tsx","./src/components/StatusLineImportExport.tsx","./src/components/TransformerList.tsx","./src/components/Transformers.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/color-picker.tsx","./src/components/ui/combo-input.tsx","./src/components/ui/combobox.tsx","./src/components/ui/command.tsx","./src/components/ui/dialog.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/multi-combobox.tsx","./src/components/ui/popover.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/toast.tsx","./src/lib/api.ts","./src/lib/db.ts","./src/lib/utils.ts","./src/utils/statusline.ts"],"version":"5.8.3"}
|
||||
Reference in New Issue
Block a user