@jsonstudio/rcc 0.89.2195 â 0.89.2239
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.js +2 -2
- package/dist/cli/commands/init.js +15 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/start-utils.js +1 -1
- package/dist/cli/commands/start.js +76 -6
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/stop.js +4 -1
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/config/init-config.js +15 -1
- package/dist/cli/config/init-config.js.map +1 -1
- package/dist/cli/config/init-provider-catalog.js +5 -2
- package/dist/cli/config/init-provider-catalog.js.map +1 -1
- package/dist/cli/server/port-utils.js +63 -51
- package/dist/cli/server/port-utils.js.map +1 -1
- package/dist/commands/provider-update.js +12 -0
- package/dist/commands/provider-update.js.map +1 -1
- package/dist/providers/auth/qwen-userinfo-helper.js +18 -3
- package/dist/providers/auth/qwen-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/tokenfile-auth.d.ts +1 -0
- package/dist/providers/auth/tokenfile-auth.js +15 -9
- package/dist/providers/auth/tokenfile-auth.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +13 -4
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +1 -0
- package/dist/providers/core/runtime/http-transport-provider.js +60 -1
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/profile/families/qwen-profile.js +203 -0
- package/dist/providers/profile/families/qwen-profile.js.map +1 -1
- package/dist/server/handlers/handler-utils.js +3 -5
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/runtime/http-server/clock-client-reaper.d.ts +1 -0
- package/dist/server/runtime/http-server/clock-client-reaper.js +30 -1
- package/dist/server/runtime/http-server/clock-client-reaper.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-utils.js +5 -0
- package/dist/server/runtime/http-server/executor/provider-response-utils.js.map +1 -1
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.d.ts +1 -0
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.js +48 -0
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.js.map +1 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js +9 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.js +9 -1
- package/dist/server/runtime/http-server/executor-response.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-bootstrap.js +5 -0
- package/dist/server/runtime/http-server/http-server-bootstrap.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-clock-daemon.js +14 -1
- package/dist/server/runtime/http-server/http-server-clock-daemon.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +21 -3
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/utils/managed-server-pids.js +44 -6
- package/dist/utils/managed-server-pids.js.map +1 -1
- package/package.json +4 -3
- package/scripts/cleanup-stale-server-pids.mjs +142 -0
- package/scripts/install-global.sh +2 -0
- package/scripts/verify-e2e-toolcall.mjs +12 -1
- package/scripts/verify-install-e2e.mjs +12 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsonstudio/rcc",
|
|
3
|
-
"version": "0.89.
|
|
3
|
+
"version": "0.89.2239",
|
|
4
4
|
"description": "Multi-provider OpenAI proxy server with anthropic/responses/chat support (release)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "npm run llmswitch:ensure && node scripts/build-core.mjs && node scripts/vendor-core.mjs && npm run clean && node scripts/gen-build-info.mjs && tsc && node scripts/copy-compat-assets.mjs && node scripts/copy-modules-config.mjs && npm run fix:cli-permission",
|
|
33
|
-
"build:dev": "bash -lc 'export BUILD_MODE=dev; npm run build && npm run fix:cli-permission && npm run test:unified-hub-shadow && npm run verify:e2e-toolcall && npm run verify:apply-patch && npm run verify:apply-patch-regressions && npm run verify:exec-command && npm run test:routing-instructions && npm run test:cli && npm run install:global && npm run mock:regressions && npm run test:blackbox-antigravity-parity && npm run verify:errorsamples && npm run verify:e2e-gemini-followup-sample'",
|
|
33
|
+
"build:dev": "bash -lc 'export BUILD_MODE=dev; npm run cleanup:stale-server-pids || true; trap \"npm run cleanup:stale-server-pids >/dev/null 2>&1 || true\" EXIT; npm run build && npm run fix:cli-permission && npm run test:unified-hub-shadow && npm run verify:e2e-toolcall && npm run verify:apply-patch && npm run verify:apply-patch-regressions && npm run verify:exec-command && npm run test:routing-instructions && npm run test:cli && npm run install:global && npm run mock:regressions && npm run test:blackbox-antigravity-parity && npm run verify:errorsamples && npm run verify:e2e-gemini-followup-sample'",
|
|
34
34
|
"build:min": "npm run llmswitch:ensure && node scripts/build-core.mjs && node scripts/vendor-core.mjs && npm run clean && node scripts/gen-build-info.mjs && tsc && node scripts/copy-compat-assets.mjs && node scripts/copy-modules-config.mjs && npm run fix:cli-permission",
|
|
35
35
|
"prepack": "echo skip-prepack",
|
|
36
36
|
"postbuild": "node scripts/ensure-cli-executable.mjs",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"lint:fix": "ESLINT_USE_FLAT_CONFIG=1 eslint \"src/**/*.ts\" --fix --no-cache",
|
|
64
64
|
"lint:strict": "ESLINT_USE_FLAT_CONFIG=1 eslint \"src/**/*.ts\" --max-warnings 0 --no-cache",
|
|
65
65
|
"clean": "rm -rf dist coverage",
|
|
66
|
+
"cleanup:stale-server-pids": "node scripts/cleanup-stale-server-pids.mjs --quiet",
|
|
66
67
|
"prebuild": "npm run verify:repo-sanity && echo skip-lint",
|
|
67
68
|
"prepare": "",
|
|
68
69
|
"postinstall": "node scripts/ensure-cli-executable.mjs",
|
|
@@ -150,7 +151,7 @@
|
|
|
150
151
|
},
|
|
151
152
|
"dependencies": {
|
|
152
153
|
"@anthropic-ai/sdk": "^0.65.0",
|
|
153
|
-
"@jsonstudio/llms": "0.6.
|
|
154
|
+
"@jsonstudio/llms": "^0.6.2172",
|
|
154
155
|
"@lmstudio/sdk": "^1.5.0",
|
|
155
156
|
"@radix-ui/react-switch": "^1.2.6",
|
|
156
157
|
"@types/socket.io": "^3.0.1",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
|
|
7
|
+
const quiet = process.argv.includes('--quiet');
|
|
8
|
+
const routeCodexHome = path.join(os.homedir(), '.routecodex');
|
|
9
|
+
|
|
10
|
+
function log(message) {
|
|
11
|
+
if (!quiet) {
|
|
12
|
+
console.log(`[cleanup:server-pids] ${message}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isPidAlive(pid) {
|
|
17
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
process.kill(pid, 0);
|
|
22
|
+
return true;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readProcessCommand(pid) {
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const result = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8' });
|
|
34
|
+
if (result.error || Number(result.status ?? 0) !== 0) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
return String(result.stdout || '').trim().toLowerCase();
|
|
38
|
+
} catch {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isTrustedRouteCodexCommand(command) {
|
|
44
|
+
const normalized = String(command || '').trim().toLowerCase();
|
|
45
|
+
if (!normalized) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (normalized.includes('routecodex/dist/index.js')) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (normalized.includes('routecodex/dist/cli.js')) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (normalized.includes('@jsonstudio/rcc') && normalized.includes('/dist/index.js')) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (normalized.includes('jsonstudio-rcc') && normalized.includes('/dist/index.js')) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isPidListeningOnPort(pid, port) {
|
|
64
|
+
if (process.platform === 'win32') {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const result = spawnSync('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-t'], { encoding: 'utf8' });
|
|
69
|
+
if (result.error) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (Number(result.status ?? 0) !== 0) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const pids = String(result.stdout || '')
|
|
76
|
+
.split(/\r?\n/)
|
|
77
|
+
.map((entry) => Number.parseInt(entry.trim(), 10))
|
|
78
|
+
.filter((entry) => Number.isFinite(entry) && entry > 0);
|
|
79
|
+
return pids.includes(pid);
|
|
80
|
+
} catch {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function cleanupPidFile(filePath) {
|
|
86
|
+
const fileName = path.basename(filePath);
|
|
87
|
+
const match = fileName.match(/^server-(\d+)\.pid$/i);
|
|
88
|
+
const filePort = match ? Number.parseInt(match[1], 10) : null;
|
|
89
|
+
let raw = '';
|
|
90
|
+
try {
|
|
91
|
+
raw = fs.readFileSync(filePath, 'utf8');
|
|
92
|
+
} catch {
|
|
93
|
+
return { removed: false, reason: 'unreadable' };
|
|
94
|
+
}
|
|
95
|
+
const pid = Number.parseInt(String(raw || '').trim(), 10);
|
|
96
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
97
|
+
fs.rmSync(filePath, { force: true });
|
|
98
|
+
return { removed: true, reason: 'invalid_pid' };
|
|
99
|
+
}
|
|
100
|
+
if (!isPidAlive(pid)) {
|
|
101
|
+
fs.rmSync(filePath, { force: true });
|
|
102
|
+
return { removed: true, reason: 'pid_not_alive' };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const command = readProcessCommand(pid);
|
|
106
|
+
if (command && !isTrustedRouteCodexCommand(command)) {
|
|
107
|
+
fs.rmSync(filePath, { force: true });
|
|
108
|
+
return { removed: true, reason: 'pid_not_routecodex' };
|
|
109
|
+
}
|
|
110
|
+
if (Number.isFinite(filePort) && filePort > 0 && !isPidListeningOnPort(pid, filePort)) {
|
|
111
|
+
fs.rmSync(filePath, { force: true });
|
|
112
|
+
return { removed: true, reason: 'pid_not_listening_on_port' };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { removed: false, reason: `kept:${fileName}:${pid}` };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function main() {
|
|
119
|
+
if (!fs.existsSync(routeCodexHome)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const entries = fs.readdirSync(routeCodexHome);
|
|
123
|
+
const candidates = entries
|
|
124
|
+
.filter((name) => /^server-\d+\.pid$/i.test(name) || name === 'server.cli.pid')
|
|
125
|
+
.map((name) => path.join(routeCodexHome, name));
|
|
126
|
+
|
|
127
|
+
let removed = 0;
|
|
128
|
+
let kept = 0;
|
|
129
|
+
for (const filePath of candidates) {
|
|
130
|
+
const result = cleanupPidFile(filePath);
|
|
131
|
+
if (result.removed) {
|
|
132
|
+
removed += 1;
|
|
133
|
+
log(`removed ${path.basename(filePath)} (${result.reason})`);
|
|
134
|
+
} else {
|
|
135
|
+
kept += 1;
|
|
136
|
+
log(`kept ${path.basename(filePath)} (${result.reason})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
log(`done removed=${removed} kept=${kept}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main();
|
|
@@ -244,11 +244,13 @@ cleanup_old_install() {
|
|
|
244
244
|
main() {
|
|
245
245
|
check_node
|
|
246
246
|
cleanup_old_install
|
|
247
|
+
node scripts/cleanup-stale-server-pids.mjs --quiet || true
|
|
247
248
|
build_project
|
|
248
249
|
global_install
|
|
249
250
|
link_global_llms_dev
|
|
250
251
|
verify_install
|
|
251
252
|
verify_server_health
|
|
253
|
+
node scripts/cleanup-stale-server-pids.mjs --quiet || true
|
|
252
254
|
|
|
253
255
|
echo ""
|
|
254
256
|
echo "đ ć
šć±ćźèŁ
ćźæ!"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
3
|
import process from 'node:process';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
@@ -33,6 +33,16 @@ const AGENTS_INSTRUCTIONS = (() => {
|
|
|
33
33
|
}
|
|
34
34
|
})();
|
|
35
35
|
|
|
36
|
+
function cleanupStaleServerPidFiles() {
|
|
37
|
+
try {
|
|
38
|
+
spawnSync('node', [path.join(__dirname, 'cleanup-stale-server-pids.mjs'), '--quiet'], {
|
|
39
|
+
stdio: 'ignore'
|
|
40
|
+
});
|
|
41
|
+
} catch {
|
|
42
|
+
// ignore cleanup failures
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
function readServerApiKeyFromConfig(configPath) {
|
|
37
47
|
try {
|
|
38
48
|
const raw = fs.readFileSync(configPath, 'utf8');
|
|
@@ -102,6 +112,7 @@ async function main() {
|
|
|
102
112
|
await runGeminiCliStartupCheck();
|
|
103
113
|
} finally {
|
|
104
114
|
shutdown();
|
|
115
|
+
cleanupStaleServerPidFiles();
|
|
105
116
|
if (resolved.tempDir) {
|
|
106
117
|
try {
|
|
107
118
|
fs.rmSync(resolved.tempDir, { recursive: true, force: true });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawn } from 'node:child_process';
|
|
2
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
3
3
|
import { once } from 'node:events';
|
|
4
4
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
5
5
|
import http from 'node:http';
|
|
@@ -22,6 +22,16 @@ function resolveRoutecodexBinary() {
|
|
|
22
22
|
return 'routecodex';
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function cleanupStaleServerPidFiles() {
|
|
26
|
+
try {
|
|
27
|
+
spawnSync('node', [path.join(process.cwd(), 'scripts', 'cleanup-stale-server-pids.mjs'), '--quiet'], {
|
|
28
|
+
stdio: 'ignore'
|
|
29
|
+
});
|
|
30
|
+
} catch {
|
|
31
|
+
// ignore cleanup failures
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
async function waitForHealth(timeoutMs = 60000) {
|
|
26
36
|
const start = Date.now();
|
|
27
37
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -165,6 +175,7 @@ async function main() {
|
|
|
165
175
|
if (mockServer) {
|
|
166
176
|
await mockServer.close();
|
|
167
177
|
}
|
|
178
|
+
cleanupStaleServerPidFiles();
|
|
168
179
|
}
|
|
169
180
|
}
|
|
170
181
|
|