release v1.0.48
This commit is contained in:
@@ -13,6 +13,8 @@ I am seeking funding support for this project to better sustain its development.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
- **Model Routing**: Route requests to different models based on your needs (e.g., background tasks, thinking, long context).
|
- **Model Routing**: Route requests to different models based on your needs (e.g., background tasks, thinking, long context).
|
||||||
@@ -572,6 +574,8 @@ A huge thank you to all our sponsors for their generous support!
|
|||||||
- @\*更
|
- @\*更
|
||||||
- @\*.
|
- @\*.
|
||||||
- @F\*t
|
- @F\*t
|
||||||
|
- @\*政
|
||||||
|
- @\*铭
|
||||||
|
- @\*叶
|
||||||
|
|
||||||
(If your name is masked, please contact me via my homepage email to update it with your GitHub username.)
|
(If your name is masked, please contact me via my homepage email to update it with your GitHub username.)
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## ✨ 功能
|
## ✨ 功能
|
||||||
|
|
||||||
- **模型路由**: 根据您的需求将请求路由到不同的模型(例如,后台任务、思考、长上下文)。
|
- **模型路由**: 根据您的需求将请求路由到不同的模型(例如,后台任务、思考、长上下文)。
|
||||||
@@ -541,6 +544,9 @@ jobs:
|
|||||||
- @\*更
|
- @\*更
|
||||||
- @\*.
|
- @\*.
|
||||||
- @F\*t
|
- @F\*t
|
||||||
|
- @\*政
|
||||||
|
- @\*铭
|
||||||
|
- @\*叶
|
||||||
|
|
||||||
(如果您的名字被屏蔽,请通过我的主页电子邮件与我联系,以便使用您的 GitHub 用户名进行更新。)
|
(如果您的名字被屏蔽,请通过我的主页电子邮件与我联系,以便使用您的 GitHub 用户名进行更新。)
|
||||||
|
|
||||||
|
|||||||
67
blog/images/roadmap.svg
Normal file
67
blog/images/roadmap.svg
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<svg viewBox="0 0 1200 420" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.road { stroke: #7aa2ff; stroke-width: 6; fill: none; filter: drop-shadow(0 6px 18px rgba(122,162,255,0.25)); }
|
||||||
|
.dash { stroke: rgba(122,162,255,0.25); stroke-width: 6; fill: none; stroke-dasharray: 2 18; }
|
||||||
|
.node { filter: drop-shadow(0 3px 10px rgba(126,240,193,0.35)); }
|
||||||
|
.node-circle { fill: #7ef0c1; }
|
||||||
|
.node-core { fill: #181b22; stroke: white; stroke-width: 1.5; }
|
||||||
|
.label-bg { fill: rgba(24,27,34,0.8); stroke: rgba(255,255,255,0.12); rx: 12; }
|
||||||
|
.label-text { fill: #e8ecf1; font-weight: 700; font-size: 14px; font-family: Arial, sans-serif; }
|
||||||
|
.label-sub { fill: #9aa6b2; font-weight: 500; font-size: 12px; font-family: Arial, sans-serif; }
|
||||||
|
.spark { fill: none; stroke: #ffd36e; stroke-width: 1.6; stroke-linecap: round; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Background road with dash -->
|
||||||
|
<path class="dash" d="M60,330 C320,260 460,100 720,160 C930,205 990,260 1140,260"/>
|
||||||
|
|
||||||
|
<!-- Main road -->
|
||||||
|
<path class="road" d="M60,330 C320,260 460,100 720,160 C930,205 990,260 1140,260"/>
|
||||||
|
|
||||||
|
<!-- New Documentation Node -->
|
||||||
|
<g class="node" transform="translate(200,280)">
|
||||||
|
<circle class="node-circle" r="10"/>
|
||||||
|
<circle class="node-core" r="6"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- New Documentation Label -->
|
||||||
|
<g transform="translate(80,120)">
|
||||||
|
<rect class="label-bg" width="260" height="92"/>
|
||||||
|
<text class="label-text" x="16" y="34">New Documentation</text>
|
||||||
|
<text class="label-sub" x="16" y="58">Clear structure, examples & best practices</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Plugin Marketplace Node -->
|
||||||
|
<g class="node" transform="translate(640,150)">
|
||||||
|
<circle class="node-circle" r="10"/>
|
||||||
|
<circle class="node-core" r="6"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Plugin Marketplace Label -->
|
||||||
|
<g transform="translate(560,20)">
|
||||||
|
<rect class="label-bg" width="320" height="100"/>
|
||||||
|
<text class="label-text" x="16" y="34">Plugin Marketplace</text>
|
||||||
|
<text class="label-sub" x="16" y="58">Community submissions, ratings & version constraints</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- One More Thing Node -->
|
||||||
|
<g class="node" transform="translate(1080,255)">
|
||||||
|
<circle class="node-circle" r="10"/>
|
||||||
|
<circle class="node-core" r="6"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- One More Thing Label -->
|
||||||
|
<g transform="translate(940,300)">
|
||||||
|
<rect class="label-bg" width="250" height="86"/>
|
||||||
|
<text class="label-text" x="16" y="34">One More Thing</text>
|
||||||
|
<text class="label-sub" x="16" y="58">🚀 Confidential project · Revealing soon</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Spark decorations -->
|
||||||
|
<g transform="translate(1125,290)">
|
||||||
|
<path class="spark" d="M0 0 L8 0 M4 -4 L4 4"/>
|
||||||
|
<path class="spark" d="M14 -2 L22 -2 M18 -6 L18 2"/>
|
||||||
|
<path class="spark" d="M-10 6 L-2 6 M-6 2 L-6 10"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@musistudio/claude-code-router",
|
"name": "@musistudio/claude-code-router",
|
||||||
"version": "1.0.47",
|
"version": "1.0.48",
|
||||||
"description": "Use Claude Code without an Anthropics account and route it to another LLM provider",
|
"description": "Use Claude Code without an Anthropics account and route it to another LLM provider",
|
||||||
"bin": {
|
"bin": {
|
||||||
"ccr": "./dist/cli.js"
|
"ccr": "./dist/cli.js"
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"@fastify/static": "^8.2.0",
|
"@fastify/static": "^8.2.0",
|
||||||
"@musistudio/llms": "^1.0.32",
|
"@musistudio/llms": "^1.0.32",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
|
"find-process": "^2.0.0",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"openurl": "^1.1.1",
|
"openurl": "^1.1.1",
|
||||||
"rotating-file-stream": "^3.2.7",
|
"rotating-file-stream": "^3.2.7",
|
||||||
|
|||||||
48
pnpm-lock.yaml
generated
48
pnpm-lock.yaml
generated
@@ -17,6 +17,9 @@ importers:
|
|||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.7
|
specifier: ^16.4.7
|
||||||
version: 16.6.1
|
version: 16.6.1
|
||||||
|
find-process:
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0
|
||||||
json5:
|
json5:
|
||||||
specifier: ^2.2.3
|
specifier: ^2.2.3
|
||||||
version: 2.2.3
|
version: 2.2.3
|
||||||
@@ -338,6 +341,10 @@ packages:
|
|||||||
buffer-equal-constant-time@1.0.1:
|
buffer-equal-constant-time@1.0.1:
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||||
|
|
||||||
|
chalk@4.1.2:
|
||||||
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@@ -345,6 +352,10 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
commander@12.1.0:
|
||||||
|
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -460,6 +471,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
|
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
find-process@2.0.0:
|
||||||
|
resolution: {integrity: sha512-YUBQnteWGASJoEVVsOXy6XtKAY2O1FCsWnnvQ8y0YwgY1rZiKeVptnFvMu6RSELZAJOGklqseTnUGGs5D0bKmg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -524,6 +539,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
|
resolution: {integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
has-flag@4.0.0:
|
||||||
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -609,6 +628,10 @@ packages:
|
|||||||
light-my-request@6.6.0:
|
light-my-request@6.6.0:
|
||||||
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
|
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
|
||||||
|
|
||||||
|
loglevel@1.9.2:
|
||||||
|
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
|
||||||
|
engines: {node: '>= 0.6.0'}
|
||||||
|
|
||||||
lru-cache@11.1.0:
|
lru-cache@11.1.0:
|
||||||
resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
|
resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
@@ -865,6 +888,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
|
resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
supports-color@7.2.0:
|
||||||
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0:
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1188,12 +1215,19 @@ snapshots:
|
|||||||
|
|
||||||
buffer-equal-constant-time@1.0.1: {}
|
buffer-equal-constant-time@1.0.1: {}
|
||||||
|
|
||||||
|
chalk@4.1.2:
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 4.3.0
|
||||||
|
supports-color: 7.2.0
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
commander@12.1.0: {}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -1351,6 +1385,12 @@ snapshots:
|
|||||||
fast-querystring: 1.1.2
|
fast-querystring: 1.1.2
|
||||||
safe-regex2: 5.0.0
|
safe-regex2: 5.0.0
|
||||||
|
|
||||||
|
find-process@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
chalk: 4.1.2
|
||||||
|
commander: 12.1.0
|
||||||
|
loglevel: 1.9.2
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@@ -1458,6 +1498,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
hasown@2.0.2:
|
hasown@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
@@ -1538,6 +1580,8 @@ snapshots:
|
|||||||
process-warning: 4.0.1
|
process-warning: 4.0.1
|
||||||
set-cookie-parser: 2.7.1
|
set-cookie-parser: 2.7.1
|
||||||
|
|
||||||
|
loglevel@1.9.2: {}
|
||||||
|
|
||||||
lru-cache@11.1.0: {}
|
lru-cache@11.1.0: {}
|
||||||
|
|
||||||
merge2@1.4.1: {}
|
merge2@1.4.1: {}
|
||||||
@@ -1741,6 +1785,10 @@ snapshots:
|
|||||||
|
|
||||||
strip-eof@1.0.0: {}
|
strip-eof@1.0.0: {}
|
||||||
|
|
||||||
|
supports-color@7.2.0:
|
||||||
|
dependencies:
|
||||||
|
has-flag: 4.0.0
|
||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
thread-stream@3.1.0:
|
thread-stream@3.1.0:
|
||||||
|
|||||||
10
src/cli.ts
10
src/cli.ts
@@ -45,7 +45,8 @@ async function waitForService(
|
|||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
while (Date.now() - startTime < timeout) {
|
while (Date.now() - startTime < timeout) {
|
||||||
if (isServiceRunning()) {
|
const isRunning = await isServiceRunning()
|
||||||
|
if (isRunning) {
|
||||||
// Wait for an additional short period to ensure service is fully ready
|
// Wait for an additional short period to ensure service is fully ready
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
return true;
|
return true;
|
||||||
@@ -56,6 +57,7 @@ async function waitForService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
const isRunning = await isServiceRunning()
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "start":
|
case "start":
|
||||||
run();
|
run();
|
||||||
@@ -95,7 +97,7 @@ async function main() {
|
|||||||
inputData += chunk;
|
inputData += chunk;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
process.stdin.on("end", async () => {
|
process.stdin.on("end", async () => {
|
||||||
try {
|
try {
|
||||||
const input: StatusLineInput = JSON.parse(inputData);
|
const input: StatusLineInput = JSON.parse(inputData);
|
||||||
@@ -108,7 +110,7 @@ async function main() {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "code":
|
case "code":
|
||||||
if (!isServiceRunning()) {
|
if (!isRunning) {
|
||||||
console.log("Service not running, starting service...");
|
console.log("Service not running, starting service...");
|
||||||
const cliPath = join(__dirname, "cli.js");
|
const cliPath = join(__dirname, "cli.js");
|
||||||
const startProcess = spawn("node", [cliPath, "start"], {
|
const startProcess = spawn("node", [cliPath, "start"], {
|
||||||
@@ -153,7 +155,7 @@ async function main() {
|
|||||||
break;
|
break;
|
||||||
case "ui":
|
case "ui":
|
||||||
// Check if service is running
|
// Check if service is running
|
||||||
if (!isServiceRunning()) {
|
if (!isRunning) {
|
||||||
console.log("Service not running, starting service...");
|
console.log("Service not running, starting service...");
|
||||||
const cliPath = join(__dirname, "cli.js");
|
const cliPath = join(__dirname, "cli.js");
|
||||||
const startProcess = spawn("node", [cliPath, "start"], {
|
const startProcess = spawn("node", [cliPath, "start"], {
|
||||||
|
|||||||
17
src/index.ts
17
src/index.ts
@@ -51,7 +51,8 @@ interface RunOptions {
|
|||||||
|
|
||||||
async function run(options: RunOptions = {}) {
|
async function run(options: RunOptions = {}) {
|
||||||
// Check if service is already running
|
// Check if service is already running
|
||||||
if (isServiceRunning()) {
|
const isRunning = await isServiceRunning()
|
||||||
|
if (isRunning) {
|
||||||
console.log("✅ Service is already running in the background.");
|
console.log("✅ Service is already running in the background.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -244,7 +245,6 @@ async function run(options: RunOptions = {}) {
|
|||||||
req,
|
req,
|
||||||
config
|
config
|
||||||
});
|
});
|
||||||
console.log('result', toolResult)
|
|
||||||
toolMessages.push({
|
toolMessages.push({
|
||||||
"tool_use_id": currentToolId,
|
"tool_use_id": currentToolId,
|
||||||
"type": "tool_result",
|
"type": "tool_result",
|
||||||
@@ -295,14 +295,12 @@ async function run(options: RunOptions = {}) {
|
|||||||
|
|
||||||
// 检查流是否仍然可写
|
// 检查流是否仍然可写
|
||||||
if (!controller.desiredSize) {
|
if (!controller.desiredSize) {
|
||||||
console.log('Stream backpressure detected');
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.enqueue(value)
|
controller.enqueue(value)
|
||||||
}catch (readError: any) {
|
}catch (readError: any) {
|
||||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||||
console.log('Stream reading aborted due to client disconnect');
|
|
||||||
abortController.abort(); // 中止所有相关操作
|
abortController.abort(); // 中止所有相关操作
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -318,7 +316,6 @@ async function run(options: RunOptions = {}) {
|
|||||||
|
|
||||||
// 处理流提前关闭的错误
|
// 处理流提前关闭的错误
|
||||||
if (error.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
if (error.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||||
console.log('Stream prematurely closed, aborting operations');
|
|
||||||
abortController.abort();
|
abortController.abort();
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -349,7 +346,7 @@ async function run(options: RunOptions = {}) {
|
|||||||
}
|
}
|
||||||
} catch (readError: any) {
|
} catch (readError: any) {
|
||||||
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
if (readError.name === 'AbortError' || readError.code === 'ERR_STREAM_PREMATURE_CLOSE') {
|
||||||
console.log('Background read stream closed prematurely');
|
console.error('Background read stream closed prematurely');
|
||||||
} else {
|
} else {
|
||||||
console.error('Error in background stream reading:', readError);
|
console.error('Error in background stream reading:', readError);
|
||||||
}
|
}
|
||||||
@@ -362,13 +359,15 @@ async function run(options: RunOptions = {}) {
|
|||||||
}
|
}
|
||||||
sessionUsageCache.put(req.sessionId, payload.usage);
|
sessionUsageCache.put(req.sessionId, payload.usage);
|
||||||
}
|
}
|
||||||
if (typeof payload ==='object' && payload.error) {
|
if (typeof payload ==='object') {
|
||||||
return done(payload.error, null)
|
if (payload.error) {
|
||||||
|
return done(payload.error, null)
|
||||||
|
}
|
||||||
|
return done(payload)
|
||||||
}
|
}
|
||||||
done(null, payload)
|
done(null, payload)
|
||||||
});
|
});
|
||||||
server.addHook("onSend", async (req, reply, payload) => {
|
server.addHook("onSend", async (req, reply, payload) => {
|
||||||
console.log('主应用onSend')
|
|
||||||
event.emit('onSend', req, reply, payload);
|
event.emit('onSend', req, reply, payload);
|
||||||
return payload;
|
return payload;
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { join } from 'path';
|
|||||||
|
|
||||||
export async function closeService() {
|
export async function closeService() {
|
||||||
const PID_FILE = join(HOME_DIR, '.claude-code-router.pid');
|
const PID_FILE = join(HOME_DIR, '.claude-code-router.pid');
|
||||||
|
const isRunning = await isServiceRunning()
|
||||||
if (!isServiceRunning()) {
|
|
||||||
|
if (!isRunning) {
|
||||||
console.log("No service is currently running.");
|
console.log("No service is currently running.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||||
import { PID_FILE, REFERENCE_COUNT_FILE } from '../constants';
|
import { PID_FILE, REFERENCE_COUNT_FILE } from '../constants';
|
||||||
import { readConfigFile } from '.';
|
import { readConfigFile } from '.';
|
||||||
|
import find from 'find-process';
|
||||||
|
|
||||||
|
export async function isProcessRunning(pid: number): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const processes = await find('pid', pid);
|
||||||
|
return processes.length > 0;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function incrementReferenceCount() {
|
export function incrementReferenceCount() {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
@@ -27,15 +37,14 @@ export function getReferenceCount(): number {
|
|||||||
return parseInt(readFileSync(REFERENCE_COUNT_FILE, 'utf-8')) || 0;
|
return parseInt(readFileSync(REFERENCE_COUNT_FILE, 'utf-8')) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isServiceRunning(): boolean {
|
export async function isServiceRunning(): Promise<boolean> {
|
||||||
if (!existsSync(PID_FILE)) {
|
if (!existsSync(PID_FILE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pid = parseInt(readFileSync(PID_FILE, 'utf-8'));
|
const pid = parseInt(readFileSync(PID_FILE, 'utf-8'));
|
||||||
process.kill(pid, 0);
|
return await isProcessRunning(pid);
|
||||||
return true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Process not running, clean up pid file
|
// Process not running, clean up pid file
|
||||||
cleanupPidFile();
|
cleanupPidFile();
|
||||||
@@ -62,7 +71,7 @@ export function getServicePid(): number | null {
|
|||||||
if (!existsSync(PID_FILE)) {
|
if (!existsSync(PID_FILE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pid = parseInt(readFileSync(PID_FILE, 'utf-8'));
|
const pid = parseInt(readFileSync(PID_FILE, 'utf-8'));
|
||||||
return isNaN(pid) ? null : pid;
|
return isNaN(pid) ? null : pid;
|
||||||
@@ -73,10 +82,10 @@ export function getServicePid(): number | null {
|
|||||||
|
|
||||||
export async function getServiceInfo() {
|
export async function getServiceInfo() {
|
||||||
const pid = getServicePid();
|
const pid = getServicePid();
|
||||||
const running = isServiceRunning();
|
const running = await isServiceRunning();
|
||||||
const config = await readConfigFile();
|
const config = await readConfigFile();
|
||||||
const port = config.PORT || 3456;
|
const port = config.PORT || 3456;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
running,
|
running,
|
||||||
pid,
|
pid,
|
||||||
|
|||||||
Reference in New Issue
Block a user