@jsonstudio/rcc 0.89.682 → 0.89.873
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.js +164 -116
- package/dist/cli.js.map +1 -1
- package/dist/client/anthropic/anthropic-protocol-client.js +42 -1
- package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +4 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/commands/camoufox-backfill.d.ts +2 -0
- package/dist/commands/camoufox-backfill.js +33 -0
- package/dist/commands/camoufox-backfill.js.map +1 -0
- package/dist/commands/camoufox-fp.d.ts +2 -0
- package/dist/commands/camoufox-fp.js +86 -0
- package/dist/commands/camoufox-fp.js.map +1 -0
- package/dist/commands/oauth.d.ts +2 -0
- package/dist/commands/oauth.js +170 -0
- package/dist/commands/oauth.js.map +1 -0
- package/dist/commands/provider-update.js +439 -2
- package/dist/commands/provider-update.js.map +1 -1
- package/dist/commands/quota-status.d.ts +2 -0
- package/dist/commands/quota-status.js +80 -0
- package/dist/commands/quota-status.js.map +1 -0
- package/dist/commands/token-daemon.js +12 -1
- package/dist/commands/token-daemon.js.map +1 -1
- package/dist/config/provider-v2-loader.d.ts +16 -0
- package/dist/config/provider-v2-loader.js +84 -0
- package/dist/config/provider-v2-loader.js.map +1 -0
- package/dist/config/routecodex-config-loader.js +27 -4
- package/dist/config/routecodex-config-loader.js.map +1 -1
- package/dist/config/system-prompts/codex-cli.txt +1 -0
- package/dist/config/virtual-router-builder.d.ts +9 -0
- package/dist/config/virtual-router-builder.js +34 -0
- package/dist/config/virtual-router-builder.js.map +1 -0
- package/dist/config/virtual-router-types.d.ts +25 -0
- package/dist/config/virtual-router-types.js +30 -0
- package/dist/config/virtual-router-types.js.map +1 -0
- package/dist/manager/index.d.ts +10 -0
- package/dist/manager/index.js +27 -0
- package/dist/manager/index.js.map +1 -0
- package/dist/manager/modules/health/index.d.ts +22 -0
- package/dist/manager/modules/health/index.js +82 -0
- package/dist/manager/modules/health/index.js.map +1 -0
- package/dist/manager/modules/quota/index.d.ts +57 -0
- package/dist/manager/modules/quota/index.js +426 -0
- package/dist/manager/modules/quota/index.js.map +1 -0
- package/dist/manager/modules/routing/index.d.ts +17 -0
- package/dist/manager/modules/routing/index.js +61 -0
- package/dist/manager/modules/routing/index.js.map +1 -0
- package/dist/manager/modules/token/index.d.ts +10 -0
- package/dist/manager/modules/token/index.js +58 -0
- package/dist/manager/modules/token/index.js.map +1 -0
- package/dist/manager/storage/base-store.d.ts +6 -0
- package/dist/manager/storage/base-store.js +2 -0
- package/dist/manager/storage/base-store.js.map +1 -0
- package/dist/manager/storage/file-store.d.ts +25 -0
- package/dist/manager/storage/file-store.js +117 -0
- package/dist/manager/storage/file-store.js.map +1 -0
- package/dist/manager/types.d.ts +9 -0
- package/dist/manager/types.js +2 -0
- package/dist/manager/types.js.map +1 -0
- package/dist/message-center/index.d.ts +5 -0
- package/dist/message-center/index.js +6 -0
- package/dist/message-center/index.js.map +1 -0
- package/dist/message-center/message-center.d.ts +93 -0
- package/dist/message-center/message-center.js +189 -0
- package/dist/message-center/message-center.js.map +1 -0
- package/dist/providers/auth/antigravity-userinfo-helper.d.ts +2 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js +102 -0
- package/dist/providers/auth/antigravity-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/iflow-cookie-auth.d.ts +27 -0
- package/dist/providers/auth/iflow-cookie-auth.js +209 -0
- package/dist/providers/auth/iflow-cookie-auth.js.map +1 -0
- package/dist/providers/auth/oauth-lifecycle.js +29 -22
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/token-scanner/index.js +16 -1
- package/dist/providers/auth/token-scanner/index.js.map +1 -1
- package/dist/providers/core/config/camoufox-launcher.d.ts +16 -0
- package/dist/providers/core/config/camoufox-launcher.js +314 -0
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -0
- package/dist/providers/core/config/oauth-flows.d.ts +9 -0
- package/dist/providers/core/config/oauth-flows.js +50 -19
- package/dist/providers/core/config/oauth-flows.js.map +1 -1
- package/dist/providers/core/config/provider-oauth-configs.d.ts +6 -0
- package/dist/providers/core/config/provider-oauth-configs.js +12 -0
- package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +26 -3
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/antigravity-quota-client.d.ts +10 -0
- package/dist/providers/core/runtime/antigravity-quota-client.js +88 -0
- package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -0
- package/dist/providers/core/runtime/base-provider.d.ts +2 -1
- package/dist/providers/core/runtime/base-provider.js +93 -34
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +42 -10
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.js +24 -0
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +0 -3
- package/dist/providers/core/runtime/http-transport-provider.js +32 -136
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +18 -10
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/rate-limit-manager.d.ts +6 -0
- package/dist/providers/core/runtime/rate-limit-manager.js +23 -0
- package/dist/providers/core/runtime/rate-limit-manager.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-device-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-hybrid-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-hybrid-flow.js +3 -2
- package/dist/providers/core/strategies/oauth-hybrid-flow.js.map +1 -1
- package/dist/providers/core/utils/http-client.js +43 -1
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +4 -4
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/providers/profile/provider-profile-loader.js +13 -1
- package/dist/providers/profile/provider-profile-loader.js.map +1 -1
- package/dist/providers/profile/provider-profile.d.ts +5 -0
- package/dist/scripts/camoufox/gen-fingerprint-env.py +171 -0
- package/dist/scripts/camoufox/launch-auth.mjs +617 -0
- package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-provider.js +26 -0
- package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.d.ts +16 -0
- package/dist/server/runtime/http-server/executor-response.js +164 -0
- package/dist/server/runtime/http-server/executor-response.js.map +1 -0
- package/dist/server/runtime/http-server/index.d.ts +1 -0
- package/dist/server/runtime/http-server/index.js +88 -53
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +5 -19
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.d.ts +2 -0
- package/dist/server/runtime/http-server/routes.js +33 -1
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/types.d.ts +1 -0
- package/dist/server/utils/client-connection-state.d.ts +8 -0
- package/dist/server/utils/client-connection-state.js +52 -0
- package/dist/server/utils/client-connection-state.js.map +1 -0
- package/dist/server/utils/request-id-manager.js +21 -3
- package/dist/server/utils/request-id-manager.js.map +1 -1
- package/dist/token-daemon/history-store.d.ts +2 -0
- package/dist/token-daemon/history-store.js +6 -2
- package/dist/token-daemon/history-store.js.map +1 -1
- package/dist/token-daemon/index.js +36 -5
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/token-daemon/leader-lock.d.ts +11 -0
- package/dist/token-daemon/leader-lock.js +79 -0
- package/dist/token-daemon/leader-lock.js.map +1 -0
- package/dist/token-daemon/message-bus-integrator.d.ts +98 -0
- package/dist/token-daemon/message-bus-integrator.js +144 -0
- package/dist/token-daemon/message-bus-integrator.js.map +1 -0
- package/dist/token-daemon/provider-registry.d.ts +22 -0
- package/dist/token-daemon/provider-registry.js +201 -0
- package/dist/token-daemon/provider-registry.js.map +1 -0
- package/dist/token-daemon/token-daemon.d.ts +8 -0
- package/dist/token-daemon/token-daemon.js +196 -11
- package/dist/token-daemon/token-daemon.js.map +1 -1
- package/dist/token-portal/local-token-portal.d.ts +1 -0
- package/dist/token-portal/local-token-portal.js +18 -0
- package/dist/token-portal/local-token-portal.js.map +1 -1
- package/dist/token-portal/render.js +1 -0
- package/dist/token-portal/render.js.map +1 -1
- package/dist/tools/error-log.d.ts +31 -0
- package/dist/tools/error-log.js +117 -0
- package/dist/tools/error-log.js.map +1 -0
- package/dist/tools/stats-request-events.d.ts +2 -0
- package/dist/tools/stats-request-events.js +16 -0
- package/dist/tools/stats-request-events.js.map +1 -0
- package/dist/tools/stats-usage.d.ts +31 -0
- package/dist/tools/stats-usage.js +206 -0
- package/dist/tools/stats-usage.js.map +1 -0
- package/package.json +8 -4
- package/scripts/analyze-codex-error-failures.mjs +109 -0
- package/scripts/camoufox/gen-fingerprint-env.py +171 -0
- package/scripts/camoufox/launch-auth.mjs +617 -0
- package/scripts/classify-codex-samples.mjs +251 -0
- package/scripts/cleanup-codex-error-samples.mjs +88 -0
- package/scripts/compare-codex-rccx.mjs +268 -0
- package/scripts/copy-compat-assets.mjs +18 -0
- package/scripts/install-release.sh +1 -1
- package/scripts/local-replay-openai-response.mjs +1 -2
- package/scripts/pack-mode.mjs +16 -6
- package/scripts/replay-codex-sample.mjs +24 -2
- package/scripts/responses-compare-server.mjs +119 -0
- package/scripts/verify-apply-patch.mjs +28 -17
- package/scripts/verify-codex-error-samples.mjs +99 -0
- package/scripts/verify-e2e-toolcall.mjs +19 -4
- package/scripts/virtual-router-shadow-v2-real.mjs +143 -0
- package/scripts/virtual-router-shadow-v2.mjs +122 -0
package/dist/build-info.js
CHANGED
package/dist/cli.js
CHANGED
|
@@ -118,84 +118,64 @@ program
|
|
|
118
118
|
.description('RouteCodex CLI - Multi-provider OpenAI proxy server and Claude Code interface')
|
|
119
119
|
.version(cliVersion);
|
|
120
120
|
async function ensureTokenDaemonAutoStart() {
|
|
121
|
+
// Token 刷新逻辑已经在服务器进程内通过 ManagerDaemon/TokenManagerModule 执行。
|
|
122
|
+
// 为避免重复启动独立的 token-daemon 进程,这里不再自动拉起后台守护,仅保留显式 CLI 命令。
|
|
123
|
+
const disabledEnv = String(process.env.ROUTECODEX_TOKEN_DAEMON_DISABLED || process.env.RCC_TOKEN_DAEMON_DISABLED || '')
|
|
124
|
+
.trim()
|
|
125
|
+
.toLowerCase();
|
|
126
|
+
if (disabledEnv !== '1' && disabledEnv !== 'true' && disabledEnv !== 'yes') {
|
|
127
|
+
logger.info('Token manager is now integrated into the server process; automatic external token-daemon auto-start is disabled.');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function stopTokenDaemonIfRunning() {
|
|
121
131
|
try {
|
|
122
|
-
|
|
123
|
-
.trim()
|
|
124
|
-
.toLowerCase();
|
|
125
|
-
if (disabledEnv === '1' || disabledEnv === 'true' || disabledEnv === 'yes') {
|
|
126
|
-
logger.info('Token daemon auto-start disabled via env (ROUTECODEX_TOKEN_DAEMON_DISABLED/RCC_TOKEN_DAEMON_DISABLED)');
|
|
132
|
+
if (!fs.existsSync(TOKEN_DAEMON_PID_FILE)) {
|
|
127
133
|
return;
|
|
128
134
|
}
|
|
129
|
-
|
|
135
|
+
const txt = fs.readFileSync(TOKEN_DAEMON_PID_FILE, 'utf8');
|
|
136
|
+
const parsed = Number(String(txt || '').trim());
|
|
137
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const pid = parsed;
|
|
141
|
+
let running = false;
|
|
130
142
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const parsed = Number(String(txt || '').trim());
|
|
134
|
-
if (Number.isFinite(parsed) && parsed > 0) {
|
|
135
|
-
existingPid = parsed;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
143
|
+
process.kill(pid, 0);
|
|
144
|
+
running = true;
|
|
138
145
|
}
|
|
139
146
|
catch {
|
|
140
|
-
|
|
147
|
+
running = false;
|
|
141
148
|
}
|
|
142
|
-
|
|
143
|
-
const deadline = Date.now() + timeoutMs;
|
|
144
|
-
while (Date.now() < deadline) {
|
|
145
|
-
try {
|
|
146
|
-
process.kill(pid, 0);
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
if (existingPid) {
|
|
155
|
-
let running = false;
|
|
156
|
-
try {
|
|
157
|
-
process.kill(existingPid, 0);
|
|
158
|
-
running = true;
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
running = false;
|
|
162
|
-
}
|
|
163
|
-
if (running) {
|
|
164
|
-
logger.info(`Restarting token daemon to refresh environment (pid=${existingPid})`);
|
|
165
|
-
try {
|
|
166
|
-
process.kill(existingPid, 'SIGTERM');
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
// ignore
|
|
170
|
-
}
|
|
171
|
-
await waitForProcessExit(existingPid, 2000);
|
|
172
|
-
}
|
|
149
|
+
if (!running) {
|
|
173
150
|
try {
|
|
174
151
|
fs.unlinkSync(TOKEN_DAEMON_PID_FILE);
|
|
175
152
|
}
|
|
176
|
-
catch {
|
|
177
|
-
|
|
178
|
-
}
|
|
153
|
+
catch { /* ignore */ }
|
|
154
|
+
return;
|
|
179
155
|
}
|
|
180
|
-
const nodeBin = process.execPath;
|
|
181
|
-
const cliEntry = path.resolve(__dirname, 'cli.js');
|
|
182
|
-
const args = [cliEntry, 'token-daemon', 'start'];
|
|
183
|
-
const { spawn } = await import('child_process');
|
|
184
|
-
const child = spawn(nodeBin, args, {
|
|
185
|
-
stdio: 'ignore',
|
|
186
|
-
detached: true,
|
|
187
|
-
env: { ...process.env }
|
|
188
|
-
});
|
|
189
156
|
try {
|
|
190
|
-
|
|
157
|
+
process.kill(pid, 'SIGTERM');
|
|
191
158
|
}
|
|
192
159
|
catch {
|
|
193
160
|
// ignore
|
|
194
161
|
}
|
|
195
|
-
|
|
162
|
+
const deadline = Date.now() + 2000;
|
|
163
|
+
while (Date.now() < deadline) {
|
|
164
|
+
try {
|
|
165
|
+
process.kill(pid, 0);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
fs.unlinkSync(TOKEN_DAEMON_PID_FILE);
|
|
174
|
+
}
|
|
175
|
+
catch { /* ignore */ }
|
|
196
176
|
}
|
|
197
|
-
catch
|
|
198
|
-
|
|
177
|
+
catch {
|
|
178
|
+
// best-effort: failures here must not break CLI shutdown
|
|
199
179
|
}
|
|
200
180
|
}
|
|
201
181
|
// Provider command group - update models and generate minimal provider config
|
|
@@ -204,12 +184,36 @@ try {
|
|
|
204
184
|
program.addCommand(createProviderUpdateCommand());
|
|
205
185
|
}
|
|
206
186
|
catch { /* optional: command not available in some builds */ }
|
|
187
|
+
// Camoufox fingerprint debug command (optional)
|
|
188
|
+
try {
|
|
189
|
+
const { createCamoufoxFpCommand } = await import('./commands/camoufox-fp.js');
|
|
190
|
+
program.addCommand(createCamoufoxFpCommand());
|
|
191
|
+
}
|
|
192
|
+
catch { /* optional */ }
|
|
193
|
+
// Camoufox fingerprint backfill command (optional)
|
|
194
|
+
try {
|
|
195
|
+
const { createCamoufoxBackfillCommand } = await import('./commands/camoufox-backfill.js');
|
|
196
|
+
program.addCommand(createCamoufoxBackfillCommand());
|
|
197
|
+
}
|
|
198
|
+
catch { /* optional */ }
|
|
207
199
|
// Token daemon command group - manage OAuth tokens
|
|
208
200
|
try {
|
|
209
201
|
const { createTokenDaemonCommand } = await import('./commands/token-daemon.js');
|
|
210
202
|
program.addCommand(createTokenDaemonCommand());
|
|
211
203
|
}
|
|
212
204
|
catch { /* optional: command not available in some builds */ }
|
|
205
|
+
// Quota status command - inspect daemon-managed quota snapshot
|
|
206
|
+
try {
|
|
207
|
+
const { createQuotaStatusCommand } = await import('./commands/quota-status.js');
|
|
208
|
+
program.addCommand(createQuotaStatusCommand());
|
|
209
|
+
}
|
|
210
|
+
catch { /* optional */ }
|
|
211
|
+
// OAuth command - force re-auth for a specific token (Camoufox-aware when enabled)
|
|
212
|
+
try {
|
|
213
|
+
const { createOauthCommand } = await import('./commands/oauth.js');
|
|
214
|
+
program.addCommand(createOauthCommand());
|
|
215
|
+
}
|
|
216
|
+
catch { /* optional: command not available in some builds */ }
|
|
213
217
|
// Validate command - auto start server then run E2E checks
|
|
214
218
|
try {
|
|
215
219
|
const { createValidateCommand } = await import('./commands/validate.js');
|
|
@@ -796,6 +800,9 @@ program
|
|
|
796
800
|
catch { /* ignore */ }
|
|
797
801
|
}
|
|
798
802
|
}
|
|
803
|
+
if (IS_DEV_PACKAGE) {
|
|
804
|
+
await stopTokenDaemonIfRunning();
|
|
805
|
+
}
|
|
799
806
|
// Ensure parent exits even if child fails to exit
|
|
800
807
|
try {
|
|
801
808
|
process.exit(0);
|
|
@@ -1072,37 +1079,54 @@ program
|
|
|
1072
1079
|
.action(async () => {
|
|
1073
1080
|
const spinner = await createSpinner('Stopping RouteCodex server...');
|
|
1074
1081
|
try {
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
let config;
|
|
1087
|
-
try {
|
|
1088
|
-
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
1089
|
-
config = JSON.parse(configContent);
|
|
1090
|
-
}
|
|
1091
|
-
catch (error) {
|
|
1092
|
-
spinner.fail('Failed to parse configuration file');
|
|
1093
|
-
logger.error(`Invalid JSON in configuration file: ${configPath}`);
|
|
1094
|
-
process.exit(1);
|
|
1082
|
+
let resolvedPort;
|
|
1083
|
+
if (IS_DEV_PACKAGE) {
|
|
1084
|
+
const envPort = Number(process.env.ROUTECODEX_PORT || process.env.RCC_PORT || NaN);
|
|
1085
|
+
if (!Number.isNaN(envPort) && envPort > 0) {
|
|
1086
|
+
logger.info(`Using port ${envPort} from environment (ROUTECODEX_PORT/RCC_PORT) [dev package: routecodex]`);
|
|
1087
|
+
resolvedPort = envPort;
|
|
1088
|
+
}
|
|
1089
|
+
else {
|
|
1090
|
+
resolvedPort = DEFAULT_DEV_PORT;
|
|
1091
|
+
logger.info(`Using dev default port ${resolvedPort} (routecodex dev package)`);
|
|
1092
|
+
}
|
|
1095
1093
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1094
|
+
else {
|
|
1095
|
+
// Resolve config path and port
|
|
1096
|
+
const configPath = path.join(homedir(), '.routecodex', 'config.json');
|
|
1097
|
+
// Check if config exists
|
|
1098
|
+
if (!fs.existsSync(configPath)) {
|
|
1099
|
+
spinner.fail(`Configuration file not found: ${configPath}`);
|
|
1100
|
+
logger.error('Cannot determine server port without configuration file');
|
|
1101
|
+
logger.info('Please create a configuration file first:');
|
|
1102
|
+
logger.info(' rcc config init');
|
|
1103
|
+
process.exit(1);
|
|
1104
|
+
}
|
|
1105
|
+
// Load configuration to get port
|
|
1106
|
+
let config;
|
|
1107
|
+
try {
|
|
1108
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
1109
|
+
config = JSON.parse(configContent);
|
|
1110
|
+
}
|
|
1111
|
+
catch (error) {
|
|
1112
|
+
spinner.fail('Failed to parse configuration file');
|
|
1113
|
+
logger.error(`Invalid JSON in configuration file: ${configPath}`);
|
|
1114
|
+
process.exit(1);
|
|
1115
|
+
}
|
|
1116
|
+
const port = (config?.httpserver?.port ?? config?.server?.port ?? config?.port);
|
|
1117
|
+
if (!port || typeof port !== 'number' || port <= 0) {
|
|
1118
|
+
spinner.fail('Invalid or missing port configuration');
|
|
1119
|
+
logger.error('Configuration file must specify a valid port number');
|
|
1120
|
+
process.exit(1);
|
|
1121
|
+
}
|
|
1122
|
+
resolvedPort = port;
|
|
1101
1123
|
}
|
|
1102
|
-
const resolvedPort = port;
|
|
1103
1124
|
const pids = findListeningPids(resolvedPort);
|
|
1104
1125
|
if (!pids.length) {
|
|
1105
1126
|
spinner.succeed(`No server listening on ${resolvedPort}.`);
|
|
1127
|
+
if (IS_DEV_PACKAGE) {
|
|
1128
|
+
await stopTokenDaemonIfRunning();
|
|
1129
|
+
}
|
|
1106
1130
|
return;
|
|
1107
1131
|
}
|
|
1108
1132
|
for (const pid of pids) {
|
|
@@ -1115,6 +1139,9 @@ program
|
|
|
1115
1139
|
while (Date.now() < deadline) {
|
|
1116
1140
|
if (findListeningPids(resolvedPort).length === 0) {
|
|
1117
1141
|
spinner.succeed(`Stopped server on ${resolvedPort}.`);
|
|
1142
|
+
if (IS_DEV_PACKAGE) {
|
|
1143
|
+
await stopTokenDaemonIfRunning();
|
|
1144
|
+
}
|
|
1118
1145
|
return;
|
|
1119
1146
|
}
|
|
1120
1147
|
await sleep(100);
|
|
@@ -1129,6 +1156,9 @@ program
|
|
|
1129
1156
|
}
|
|
1130
1157
|
}
|
|
1131
1158
|
spinner.succeed(`Force stopped server on ${resolvedPort}.`);
|
|
1159
|
+
if (IS_DEV_PACKAGE) {
|
|
1160
|
+
await stopTokenDaemonIfRunning();
|
|
1161
|
+
}
|
|
1132
1162
|
}
|
|
1133
1163
|
catch (e) {
|
|
1134
1164
|
spinner.fail(`Failed to stop: ${e.message}`);
|
|
@@ -1146,34 +1176,51 @@ program
|
|
|
1146
1176
|
.action(async (options) => {
|
|
1147
1177
|
const spinner = await createSpinner('Restarting RouteCodex server...');
|
|
1148
1178
|
try {
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
try {
|
|
1162
|
-
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
1163
|
-
config = JSON.parse(configContent);
|
|
1164
|
-
}
|
|
1165
|
-
catch (error) {
|
|
1166
|
-
spinner.fail('Failed to parse configuration file');
|
|
1167
|
-
logger.error(`Invalid JSON in configuration file: ${configPath}`);
|
|
1168
|
-
process.exit(1);
|
|
1179
|
+
let resolvedPort;
|
|
1180
|
+
let resolvedHost = LOCAL_HOSTS.LOCALHOST;
|
|
1181
|
+
if (IS_DEV_PACKAGE) {
|
|
1182
|
+
const envPort = Number(process.env.ROUTECODEX_PORT || process.env.RCC_PORT || NaN);
|
|
1183
|
+
if (!Number.isNaN(envPort) && envPort > 0) {
|
|
1184
|
+
logger.info(`Using port ${envPort} from environment (ROUTECODEX_PORT/RCC_PORT) [dev package: routecodex]`);
|
|
1185
|
+
resolvedPort = envPort;
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
resolvedPort = DEFAULT_DEV_PORT;
|
|
1189
|
+
logger.info(`Using dev default port ${resolvedPort} (routecodex dev package)`);
|
|
1190
|
+
}
|
|
1169
1191
|
}
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1192
|
+
else {
|
|
1193
|
+
// Resolve config path
|
|
1194
|
+
const configPath = options.config || path.join(homedir(), '.routecodex', 'config.json');
|
|
1195
|
+
// Check if config exists
|
|
1196
|
+
if (!fs.existsSync(configPath)) {
|
|
1197
|
+
spinner.fail(`Configuration file not found: ${configPath}`);
|
|
1198
|
+
logger.error('Cannot determine server port without configuration file');
|
|
1199
|
+
logger.info('Please create a configuration file first:');
|
|
1200
|
+
logger.info(' rcc config init');
|
|
1201
|
+
process.exit(1);
|
|
1202
|
+
}
|
|
1203
|
+
// Load configuration to get port
|
|
1204
|
+
let config;
|
|
1205
|
+
try {
|
|
1206
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
1207
|
+
config = JSON.parse(configContent);
|
|
1208
|
+
}
|
|
1209
|
+
catch (error) {
|
|
1210
|
+
spinner.fail('Failed to parse configuration file');
|
|
1211
|
+
logger.error(`Invalid JSON in configuration file: ${configPath}`);
|
|
1212
|
+
process.exit(1);
|
|
1213
|
+
}
|
|
1214
|
+
const port = (config?.httpserver?.port ?? config?.server?.port ?? config?.port);
|
|
1215
|
+
if (!port || typeof port !== 'number' || port <= 0) {
|
|
1216
|
+
spinner.fail('Invalid or missing port configuration');
|
|
1217
|
+
logger.error('Configuration file must specify a valid port number');
|
|
1218
|
+
process.exit(1);
|
|
1219
|
+
}
|
|
1220
|
+
resolvedPort = port;
|
|
1221
|
+
resolvedHost =
|
|
1222
|
+
(config?.httpserver?.host || config?.server?.host || config?.host || LOCAL_HOSTS.LOCALHOST);
|
|
1175
1223
|
}
|
|
1176
|
-
const resolvedPort = port;
|
|
1177
1224
|
// Stop current instance (if any)
|
|
1178
1225
|
const pids = findListeningPids(resolvedPort);
|
|
1179
1226
|
if (pids.length) {
|
|
@@ -1221,8 +1268,7 @@ program
|
|
|
1221
1268
|
fs.writeFileSync(path.join(homedir(), '.routecodex', 'server.cli.pid'), String(child.pid ?? ''), 'utf8');
|
|
1222
1269
|
}
|
|
1223
1270
|
catch (error) { /* ignore */ }
|
|
1224
|
-
|
|
1225
|
-
spinner.succeed(`RouteCodex server restarting on ${host}:${resolvedPort}`);
|
|
1271
|
+
spinner.succeed(`RouteCodex server restarting on ${resolvedHost}:${resolvedPort}`);
|
|
1226
1272
|
logger.info(`Server will run on port: ${resolvedPort}`);
|
|
1227
1273
|
logger.info('Press Ctrl+C to stop the server');
|
|
1228
1274
|
const shutdown = async (sig) => {
|
|
@@ -1622,7 +1668,9 @@ async function ensurePortAvailable(port, parentSpinner, opts = {}) {
|
|
|
1622
1668
|
}
|
|
1623
1669
|
function findListeningPids(port) {
|
|
1624
1670
|
try {
|
|
1625
|
-
|
|
1671
|
+
// macOS/BSD lsof expects either "-i TCP:port" or "-tiTCP:port" as a single argument.
|
|
1672
|
+
// Use the compact form to avoid treating ":port" as a filename.
|
|
1673
|
+
const result = spawnSync('lsof', [`-tiTCP:${port}`, '-sTCP:LISTEN'], { encoding: 'utf8' });
|
|
1626
1674
|
if (result.error) {
|
|
1627
1675
|
logger.warning(`lsof not available to inspect port usage: ${result.error.message}`);
|
|
1628
1676
|
return [];
|