@jsonstudio/rcc 0.89.1205 → 0.89.1348
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/README.md +17 -0
- package/configsamples/config.json +426 -0
- package/configsamples/config.reference.json +58 -0
- package/configsamples/provider/crs/config.v1.json +46 -0
- package/configsamples/provider/glm/config.v1.json +81 -0
- package/configsamples/provider/glm-anthropic/config.v1.json +45 -0
- package/configsamples/provider/iflow/config.v1.json +74 -0
- package/configsamples/provider/kimi/config.v1.json +41 -0
- package/configsamples/provider/lmstudio/config.v1.json +101 -0
- package/configsamples/provider/mimo/config.v1.json +35 -0
- package/configsamples/provider/modelscope/config.v1.json +96 -0
- package/configsamples/provider/qwen/config.v1.json +38 -0
- package/configsamples/provider/tab/config.v1.json +50 -0
- package/configsamples/provider/tabglm/config.v1.json +49 -0
- package/dist/build-info.js +2 -2
- package/dist/cli/commands/code.js +12 -6
- package/dist/cli/commands/code.js.map +1 -1
- package/dist/cli/commands/config.d.ts +2 -1
- package/dist/cli/commands/config.js +74 -103
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/examples.js +6 -6
- package/dist/cli/commands/examples.js.map +1 -1
- package/dist/cli/commands/init.d.ts +28 -0
- package/dist/cli/commands/init.js +91 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/port.js +10 -2
- package/dist/cli/commands/port.js.map +1 -1
- package/dist/cli/commands/restart.js +5 -2
- package/dist/cli/commands/restart.js.map +1 -1
- package/dist/cli/commands/start.js +25 -22
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.js +1 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/stop.js +1 -0
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/config/bundled-docs.d.ts +20 -0
- package/dist/cli/config/bundled-docs.js +91 -0
- package/dist/cli/config/bundled-docs.js.map +1 -0
- package/dist/cli/config/init-config.d.ts +36 -0
- package/dist/cli/config/init-config.js +180 -0
- package/dist/cli/config/init-config.js.map +1 -0
- package/dist/cli/config/init-provider-catalog.d.ts +8 -0
- package/dist/cli/config/init-provider-catalog.js +187 -0
- package/dist/cli/config/init-provider-catalog.js.map +1 -0
- package/dist/cli/register/init-command.d.ts +3 -0
- package/dist/cli/register/init-command.js +5 -0
- package/dist/cli/register/init-command.js.map +1 -0
- package/dist/cli.js +28 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/config/risk-control-config.d.ts +94 -0
- package/dist/config/risk-control-config.js +196 -0
- package/dist/config/risk-control-config.js.map +1 -0
- package/dist/constants/index.d.ts +6 -0
- package/dist/constants/index.js +13 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/docs/daemon-admin-ui.html +2113 -190
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/health/index.d.ts +1 -1
- package/dist/manager/modules/quota/antigravity-quota-manager.d.ts +70 -0
- package/dist/manager/modules/quota/antigravity-quota-manager.js +442 -0
- package/dist/manager/modules/quota/antigravity-quota-manager.js.map +1 -0
- package/dist/manager/modules/quota/index.d.ts +3 -127
- package/dist/manager/modules/quota/index.js +2 -1093
- package/dist/manager/modules/quota/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-key-normalization.d.ts +3 -0
- package/dist/manager/modules/quota/provider-key-normalization.js +155 -0
- package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.d.ts +9 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js +115 -0
- package/dist/manager/modules/quota/provider-quota-daemon.cooldown.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.d.ts +77 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.d.ts +12 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.js +237 -0
- package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.js +404 -0
- package/dist/manager/modules/quota/provider-quota-daemon.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.d.ts +11 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +189 -0
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.d.ts +8 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js +96 -0
- package/dist/manager/modules/quota/provider-quota-daemon.snapshot.js.map +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.d.ts +19 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.js +37 -0
- package/dist/manager/modules/quota/provider-quota-daemon.view.js.map +1 -0
- package/dist/manager/modules/routing/index.d.ts +1 -0
- package/dist/manager/modules/routing/index.js +11 -25
- package/dist/manager/modules/routing/index.js.map +1 -1
- package/dist/manager/quota/provider-quota-center.d.ts +2 -0
- package/dist/manager/quota/provider-quota-center.js +80 -82
- package/dist/manager/quota/provider-quota-center.js.map +1 -1
- package/dist/modules/llmswitch/bridge.d.ts +16 -18
- package/dist/modules/llmswitch/bridge.js +293 -94
- package/dist/modules/llmswitch/bridge.js.map +1 -1
- package/dist/modules/llmswitch/core-loader.d.ts +4 -2
- package/dist/modules/llmswitch/core-loader.js +32 -20
- package/dist/modules/llmswitch/core-loader.js.map +1 -1
- package/dist/modules/pipeline/utils/colored-logger.js +3 -2
- package/dist/modules/pipeline/utils/colored-logger.js.map +1 -1
- package/dist/modules/pipeline/utils/debug-logger.js +1 -1
- package/dist/modules/pipeline/utils/debug-logger.js.map +1 -1
- package/dist/providers/auth/iflow-cookie-auth.js +0 -2
- package/dist/providers/auth/iflow-cookie-auth.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +2 -23
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/core/config/camoufox-launcher.js +35 -4
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
- package/dist/providers/core/runtime/antigravity-quota-client.js +6 -3
- package/dist/providers/core/runtime/antigravity-quota-client.js.map +1 -1
- package/dist/providers/core/runtime/base-provider.d.ts +2 -2
- package/dist/providers/core/runtime/base-provider.js +74 -69
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +6 -4
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.js +2 -2
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.d.ts +14 -0
- package/dist/providers/core/runtime/http-transport-provider.js +111 -5
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +10 -0
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/provider-factory.js +7 -5
- package/dist/providers/core/runtime/provider-factory.js.map +1 -1
- package/dist/providers/core/runtime/provider-runtime-metadata.d.ts +6 -0
- package/dist/providers/core/runtime/provider-runtime-metadata.js.map +1 -1
- package/dist/providers/core/runtime/responses-provider.d.ts +1 -7
- package/dist/providers/core/runtime/responses-provider.js +12 -93
- package/dist/providers/core/runtime/responses-provider.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +12 -8
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/utils/http-client.js +16 -3
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/core/utils/provider-error-logger.d.ts +1 -1
- package/dist/providers/core/utils/provider-error-reporter.d.ts +3 -1
- package/dist/providers/core/utils/provider-error-reporter.js +3 -0
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/core/utils/snapshot-writer.js +1 -4
- package/dist/providers/core/utils/snapshot-writer.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +57 -27
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/scripts/camoufox/launch-auth.mjs +193 -58
- package/dist/server/handlers/handler-utils.js +3 -2
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.d.ts +2 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +103 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.d.ts +5 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.js +77 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-session.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.d.ts +18 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.js +89 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-store.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +1 -2
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +226 -24
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js +47 -8
- package/dist/server/runtime/http-server/daemon-admin/quota-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/restart-handler.js +1 -1
- package/dist/server/runtime/http-server/daemon-admin/restart-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js +68 -4
- package/dist/server/runtime/http-server/daemon-admin/status-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +3 -4
- package/dist/server/runtime/http-server/daemon-admin-routes.js +9 -14
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.js +0 -16
- package/dist/server/runtime/http-server/executor-response.js.map +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js +110 -34
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +5 -3
- package/dist/server/runtime/http-server/index.js +215 -109
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/middleware.js +19 -1
- package/dist/server/runtime/http-server/middleware.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +10 -19
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +8 -2
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/session-dir.d.ts +2 -0
- package/dist/server/runtime/http-server/session-dir.js +59 -0
- package/dist/server/runtime/http-server/session-dir.js.map +1 -0
- package/dist/server/runtime/http-server/types.d.ts +0 -4
- package/dist/server/utils/utf8-chunk-buffer.js +6 -3
- package/dist/server/utils/utf8-chunk-buffer.js.map +1 -1
- package/dist/server/utils/warmup-storm-tracker.js +1 -1
- package/dist/server/utils/warmup-storm-tracker.js.map +1 -1
- package/dist/server-factory.d.ts +6 -28
- package/dist/server-factory.js +8 -93
- package/dist/server-factory.js.map +1 -1
- package/dist/token-daemon/index.js +2 -2
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/token-daemon/provider-registry.js +0 -1
- package/dist/token-daemon/provider-registry.js.map +1 -1
- package/dist/token-daemon/server-utils.js +8 -9
- package/dist/token-daemon/server-utils.js.map +1 -1
- package/dist/token-daemon/token-utils.js +1 -1
- package/dist/token-daemon/token-utils.js.map +1 -1
- package/dist/tools/semantic-replay.js +2 -2
- package/dist/tools/semantic-replay.js.map +1 -1
- package/dist/tools/stats-request-events.d.ts +1 -1
- package/dist/tools/stats-usage.js +6 -3
- package/dist/tools/stats-usage.js.map +1 -1
- package/dist/utils/llms-engine-shadow.d.ts +19 -0
- package/dist/utils/llms-engine-shadow.js +209 -0
- package/dist/utils/llms-engine-shadow.js.map +1 -0
- package/dist/utils/runtime-versions.js +2 -1
- package/dist/utils/runtime-versions.js.map +1 -1
- package/docs/ARCHITECTURE.md +402 -0
- package/docs/CODEX_AND_CLAUDE_CODE.md +69 -0
- package/docs/CONFIG_ARCHITECTURE.md +517 -0
- package/docs/ERROR_HANDLING_AUDIT.md +0 -0
- package/docs/GCLI2API_PARITY_GAPS.md +98 -0
- package/docs/INSTALLATION_AND_QUICKSTART.md +74 -0
- package/docs/INSTRUCTION_MARKUP.md +89 -0
- package/docs/MODULE_ENHANCEMENT_SYSTEM.md +666 -0
- package/docs/PORTS.md +36 -0
- package/docs/PROVIDERS_BUILTIN.md +111 -0
- package/docs/PROVIDER_TYPES.md +55 -0
- package/docs/SERVERTOOL_CLOCK_DESIGN.md +233 -0
- package/docs/USAGE_HANDLING_ANALYSIS.md +335 -0
- package/docs/USER_CONFIG_PARSER_CHANGES.md +175 -0
- package/docs/V3_INBOUND_OUTBOUND_DESIGN.md +86 -0
- package/docs/VIRTUAL_ROUTER_PRIORITY_AND_HEALTH.md +125 -0
- package/docs/anthropic-request-golden-samples.md +50 -0
- package/docs/ccr-alignment-enhancetool.md +105 -0
- package/docs/chat-glm-500-analysis.md +79 -0
- package/docs/chat-request-golden-samples.md +42 -0
- package/docs/chat-semantic-expansion-plan.md +82 -0
- package/docs/cli-command-inventory.md +76 -0
- package/docs/codex-samples-replay.md +50 -0
- package/docs/daemon-admin-api-design.md +350 -0
- package/docs/daemon-admin-module-structure.md +169 -0
- package/docs/daemon-admin-ui.html +3394 -0
- package/docs/debug-system-design.md +734 -0
- package/docs/debugging/gemini-sse-root-cause.md +52 -0
- package/docs/debugging/sse_encoding_failure_analysis.md +53 -0
- package/docs/dry-run/README.md +721 -0
- package/docs/error-handling-v2.md +92 -0
- package/docs/exec-command-guard-policy.example.v1.json +42 -0
- package/docs/fixes/gemini-protocol-mapping.md +57 -0
- package/docs/fixes/oauth-portal-timing-fix.md +202 -0
- package/docs/fixes/web-search-hop3-fix.md +265 -0
- package/docs/glm-api-reference.md +390 -0
- package/docs/glm-chat-completions.md +1779 -0
- package/docs/glm-history-inline-images.md +44 -0
- package/docs/golden-ci-library.md +66 -0
- package/docs/lmstudio-dry-run-summary.md +203 -0
- package/docs/lmstudio-tool-calling.md +214 -0
- package/docs/mapping-tables/anthropic-to-openai.json +290 -0
- package/docs/mapping-tables/iflow-to-openai.json +215 -0
- package/docs/mapping-tables/openai-passthrough.json +190 -0
- package/docs/mapping-tables/openai-to-iflow.json +227 -0
- package/docs/monitoring/Design.md +61 -0
- package/docs/multi-token-auth-guide.md +66 -0
- package/docs/oauth-authentication-guide.md +168 -0
- package/docs/oauth-iflow-implementation.md +153 -0
- package/docs/pipeline-routing-report.md +209 -0
- package/docs/plans/manager-daemon/PLAN.md +86 -0
- package/docs/plans/provider-config-v2-plan.md +176 -0
- package/docs/plans/provider-runtime-manager-plan.md +209 -0
- package/docs/plans/transparent-429-failover.md +89 -0
- package/docs/plans/unified-hub-framework-v1.md +245 -0
- package/docs/provider-config-v2-ui-design.md +181 -0
- package/docs/provider-quota-design.md +129 -0
- package/docs/providers/gemini-provider.md +62 -0
- package/docs/providers/lmstudio-v2-migration-report.md +102 -0
- package/docs/providers/provider-composite-design.md +142 -0
- package/docs/providers/provider-composite-testing.md +98 -0
- package/docs/providers/provider-type-only-migration.md +111 -0
- package/docs/rccx-wasm-migration.md +74 -0
- package/docs/refactoring/architecture-comparison-diagram.md +140 -0
- package/docs/refactoring/compatibility-v2-architecture-design.md +738 -0
- package/docs/refactoring/workflow-compatibility-refactoring-design.md +361 -0
- package/docs/reports/routing-classification-report.json +24 -0
- package/docs/reports/routing-classification-report.md +18 -0
- package/docs/reports/thinking-keywords-report.json +19 -0
- package/docs/responses/README.md +156 -0
- package/docs/responses-generic-provider.md +86 -0
- package/docs/responses-passthrough-provider-design.md +202 -0
- package/docs/routing-awrr-health-weighted-round-robin.md +179 -0
- package/docs/routing-instructions.md +393 -0
- package/docs/stop-message-auto.md +225 -0
- package/docs/streaming-flow.html +30 -0
- package/docs/streaming-flow.md +182 -0
- package/docs/token-daemon-preview.html +490 -0
- package/docs/token-refresh-daemon-plan.md +269 -0
- package/docs/transformation-tables/Gemini-FinishReason/345/256/214/346/225/264/350/275/254/346/215/242/350/241/250.json +233 -0
- package/docs/transformation-tables/README.md +225 -0
- package/docs/transformation-tables/claude-code-router-anthropic-to-gemini.json +283 -0
- package/docs/transformation-tables/claude-code-router-anthropic-to-openai.json +208 -0
- package/docs/transformation-tables/claude-code-router-openai-to-anthropic.json +261 -0
- package/docs/transformation-tables/claude-code-router-openai-to-gemini.json +208 -0
- package/docs/transformation-tables/claude-code-router-openai-to-lmstudio.json +182 -0
- package/docs/transformation-tables/claude-code-router-openai-to-ollama.json +250 -0
- package/docs/transformation-tables/claude-code-router-openai-to-textgenwebui.json +295 -0
- package/docs/transformation-tables/claude-code-router-provider-conversions.json +193 -0
- package/docs/transformation-tables//345/256/214/346/225/264/347/232/204/345/267/245/345/205/267/346/211/247/350/241/214/346/265/201/347/250/213/350/275/254/346/215/242/350/241/250.json +299 -0
- package/docs/transformation-tables//345/257/271/350/257/235/345/216/206/345/217/262/347/273/264/346/212/244/345/210/206/346/236/220.md +134 -0
- package/docs/transformation-tables//345/267/245/345/205/267/350/260/203/347/224/250/346/250/241/345/274/217/345/210/206/346/236/220.md +158 -0
- package/docs/transformation-tables//347/212/266/346/200/201/347/256/241/347/220/206/351/234/200/346/261/202/345/210/206/346/236/220.md +175 -0
- package/docs/transformation-tables//351/235/231/346/200/201/350/241/250vs/345/212/250/346/200/201/345/210/206/346/236/220.md +189 -0
- package/docs/transformation-tables//351/235/231/346/200/201/350/241/250/345/207/206/347/241/256/346/200/247/350/257/204/344/274/260.md +179 -0
- package/docs/transformation-tables//351/235/236/346/265/201/345/274/217/345/234/272/346/231/257/345/210/206/346/236/220.md +189 -0
- package/docs/v2-architecture/IMPLEMENTATION-ROADMAP.md +367 -0
- package/docs/v2-architecture/OPTIMIZED-DESIGN.md +827 -0
- package/docs/v2-architecture/PRERUN-CONNECTION-DESIGN.md +716 -0
- package/docs/v2-architecture/README.md +551 -0
- package/docs/verification/modelscope-verify.md +59 -0
- package/docs/web-search-service-design.md +322 -0
- package/package.json +12 -7
- package/scripts/camoufox/launch-auth.mjs +193 -58
- package/scripts/monitor-diff.mjs +126 -0
- package/scripts/pack-mode.mjs +19 -1
- package/scripts/pack-rcc.mjs +63 -0
- package/scripts/unified-hub-shadow-compare.mjs +33 -13
- package/scripts/verify-e2e-toolcall.mjs +115 -26
- package/dist/modules/llmswitch/pipeline-registry.d.ts +0 -57
- package/dist/modules/llmswitch/pipeline-registry.js +0 -229
- package/dist/modules/llmswitch/pipeline-registry.js.map +0 -1
- package/dist/server/RouteCodexServer.d.ts +0 -13
- package/dist/server/RouteCodexServer.js +0 -25
- package/dist/server/RouteCodexServer.js.map +0 -1
- package/dist/v2/conversion/hub/snapshot-recorder.d.ts +0 -12
- package/dist/v2/conversion/hub/snapshot-recorder.js +0 -22
- package/dist/v2/conversion/hub/snapshot-recorder.js.map +0 -1
|
@@ -7,6 +7,12 @@ import fs from 'node:fs';
|
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
|
|
10
|
+
function isTruthy(value) {
|
|
11
|
+
if (!value) return false;
|
|
12
|
+
const v = String(value).trim().toLowerCase();
|
|
13
|
+
return v === '1' || v === 'true' || v === 'yes' || v === 'on';
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
function parseArgs(argv) {
|
|
11
17
|
const args = { profile: 'default', url: '', autoMode: '', devMode: false };
|
|
12
18
|
const list = argv.slice(2);
|
|
@@ -65,6 +71,44 @@ async function getCamoufoxCacheRoot() {
|
|
|
65
71
|
});
|
|
66
72
|
}
|
|
67
73
|
|
|
74
|
+
function resolveCamoufoxBinary(cacheRoot) {
|
|
75
|
+
const override = (process.env.ROUTECODEX_CAMOUFOX_BINARY || '').trim();
|
|
76
|
+
if (override) {
|
|
77
|
+
return override;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const isMac = process.platform === 'darwin';
|
|
81
|
+
if (!cacheRoot && isMac) {
|
|
82
|
+
// Best-effort fallback when python3 is unavailable/broken:
|
|
83
|
+
// Camoufox's packaged app is commonly placed under ~/Library/Caches/camoufox/Camoufox.app.
|
|
84
|
+
const guessed = path.join(os.homedir(), 'Library', 'Caches', 'camoufox');
|
|
85
|
+
if (fs.existsSync(path.join(guessed, 'Camoufox.app'))) {
|
|
86
|
+
cacheRoot = guessed;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (cacheRoot && isMac) {
|
|
90
|
+
const appPath = path.join(cacheRoot, 'Camoufox.app');
|
|
91
|
+
const macBinary = path.join(appPath, 'Contents', 'MacOS', 'camoufox');
|
|
92
|
+
if (fs.existsSync(macBinary)) {
|
|
93
|
+
return macBinary;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const located = spawnSync('which', ['camoufox'], { encoding: 'utf-8' });
|
|
99
|
+
if (located.status === 0) {
|
|
100
|
+
const resolved = String(located.stdout || '').trim();
|
|
101
|
+
if (resolved) {
|
|
102
|
+
return resolved;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// ignore lookup failure
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return 'camoufox';
|
|
110
|
+
}
|
|
111
|
+
|
|
68
112
|
async function ensureProfileDir(profileId) {
|
|
69
113
|
const root = path.join(os.homedir(), '.routecodex', 'camoufox-profiles');
|
|
70
114
|
const dir = path.join(root, profileId);
|
|
@@ -108,17 +152,16 @@ async function main() {
|
|
|
108
152
|
|
|
109
153
|
const cacheRoot = await getCamoufoxCacheRoot();
|
|
110
154
|
if (!cacheRoot) {
|
|
111
|
-
console.
|
|
112
|
-
'[camoufox-launch-auth] Failed to resolve Camoufox cache root via "python3 -m camoufox path"'
|
|
155
|
+
console.warn(
|
|
156
|
+
'[camoufox-launch-auth] Failed to resolve Camoufox cache root via "python3 -m camoufox path"; falling back to PATH/override.'
|
|
113
157
|
);
|
|
114
|
-
process.exit(1);
|
|
115
158
|
}
|
|
116
159
|
|
|
117
160
|
const camoufoxBinary = resolveCamoufoxBinary(cacheRoot);
|
|
118
161
|
|
|
119
162
|
if (autoMode && autoMode.trim().toLowerCase() === 'iflow') {
|
|
120
163
|
try {
|
|
121
|
-
await
|
|
164
|
+
await runAutoFlowWithFallback('iflow', { url, profileDir, profileId, camoufoxBinary, devMode });
|
|
122
165
|
process.exit(0);
|
|
123
166
|
} catch (error) {
|
|
124
167
|
console.error(
|
|
@@ -132,7 +175,7 @@ async function main() {
|
|
|
132
175
|
|
|
133
176
|
if (autoMode && autoMode.trim().toLowerCase() === 'gemini') {
|
|
134
177
|
try {
|
|
135
|
-
await
|
|
178
|
+
await runAutoFlowWithFallback('gemini', { url, profileDir, profileId, camoufoxBinary, devMode });
|
|
136
179
|
process.exit(0);
|
|
137
180
|
} catch (error) {
|
|
138
181
|
console.error(
|
|
@@ -146,7 +189,7 @@ async function main() {
|
|
|
146
189
|
|
|
147
190
|
if (autoMode && autoMode.trim().toLowerCase() === 'antigravity') {
|
|
148
191
|
try {
|
|
149
|
-
await
|
|
192
|
+
await runAutoFlowWithFallback('antigravity', { url, profileDir, profileId, camoufoxBinary, devMode });
|
|
150
193
|
process.exit(0);
|
|
151
194
|
} catch (error) {
|
|
152
195
|
console.error(
|
|
@@ -166,59 +209,29 @@ main().catch((err) => {
|
|
|
166
209
|
process.exit(1);
|
|
167
210
|
});
|
|
168
211
|
|
|
169
|
-
function
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
try {
|
|
179
|
-
const located = spawnSync('which', ['camoufox'], { encoding: 'utf-8' });
|
|
180
|
-
if (located.status === 0) {
|
|
181
|
-
const resolved = located.stdout.trim();
|
|
182
|
-
if (resolved) {
|
|
183
|
-
return resolved;
|
|
212
|
+
async function launchManualCamoufox({ camoufoxBinary, profileDir, url }) {
|
|
213
|
+
let browserExitCode = 0;
|
|
214
|
+
let browser = null;
|
|
215
|
+
const shutdownBrowser = (signal = 'SIGTERM') => {
|
|
216
|
+
try {
|
|
217
|
+
if (!browser) {
|
|
218
|
+
return;
|
|
184
219
|
}
|
|
220
|
+
browser.kill(signal);
|
|
221
|
+
} catch {
|
|
222
|
+
// ignore
|
|
185
223
|
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
224
|
+
};
|
|
225
|
+
['SIGTERM', 'SIGINT', 'SIGHUP'].forEach((signal) => {
|
|
226
|
+
process.on(signal, () => shutdownBrowser(signal));
|
|
227
|
+
});
|
|
191
228
|
|
|
192
|
-
async function launchManualCamoufox({ camoufoxBinary, profileDir, url }) {
|
|
193
|
-
let browserExitCode = 0;
|
|
194
229
|
try {
|
|
195
|
-
|
|
196
|
-
detached:
|
|
230
|
+
browser = spawn(camoufoxBinary, ['-profile', profileDir, url], {
|
|
231
|
+
detached: false,
|
|
197
232
|
stdio: 'ignore'
|
|
198
233
|
});
|
|
199
234
|
|
|
200
|
-
const shutdownBrowser = (signal = 'SIGTERM') => {
|
|
201
|
-
try {
|
|
202
|
-
if (browser.pid) {
|
|
203
|
-
try {
|
|
204
|
-
process.kill(-browser.pid, signal);
|
|
205
|
-
return;
|
|
206
|
-
} catch {
|
|
207
|
-
// process group kill may fail on non-unix systems; fall back to direct kill
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
browser.kill(signal);
|
|
211
|
-
} catch {
|
|
212
|
-
// ignore
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
['SIGTERM', 'SIGINT'].forEach((signal) => {
|
|
217
|
-
process.on(signal, () => {
|
|
218
|
-
shutdownBrowser(signal);
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
|
|
222
235
|
browserExitCode = await new Promise((resolve) => {
|
|
223
236
|
browser.on('exit', (code) => resolve(code ?? 0));
|
|
224
237
|
browser.on('error', () => resolve(1));
|
|
@@ -234,6 +247,95 @@ async function launchManualCamoufox({ camoufoxBinary, profileDir, url }) {
|
|
|
234
247
|
process.exit(browserExitCode);
|
|
235
248
|
}
|
|
236
249
|
|
|
250
|
+
function isSelectorOrTimeoutError(error) {
|
|
251
|
+
const message = error instanceof Error ? error.message : String(error || '');
|
|
252
|
+
return (
|
|
253
|
+
/timeout/i.test(message) ||
|
|
254
|
+
/waiting for selector/i.test(message) ||
|
|
255
|
+
/strict mode violation/i.test(message) ||
|
|
256
|
+
message.includes('未能定位') ||
|
|
257
|
+
message.includes('无法定位')
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function runHeadedManualAssistFlow({ url, profileDir, camoufoxBinary, timeoutMs, label }) {
|
|
262
|
+
let firefox;
|
|
263
|
+
try {
|
|
264
|
+
({ firefox } = await import('playwright-core'));
|
|
265
|
+
} catch (error) {
|
|
266
|
+
throw new Error(
|
|
267
|
+
`playwright-core is required for headed manual assist (${error instanceof Error ? error.message : String(error)})`
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.warn(
|
|
272
|
+
`[camoufox-launch-auth] ${label}: falling back to headed mode for manual completion (no selector match).`
|
|
273
|
+
);
|
|
274
|
+
cleanupExistingCamoufox(profileDir);
|
|
275
|
+
const context = await firefox.launchPersistentContext(profileDir, {
|
|
276
|
+
executablePath: camoufoxBinary,
|
|
277
|
+
headless: false,
|
|
278
|
+
acceptDownloads: false
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
let closed = false;
|
|
282
|
+
const shutdown = async () => {
|
|
283
|
+
if (closed) return;
|
|
284
|
+
closed = true;
|
|
285
|
+
await context.close().catch(() => {});
|
|
286
|
+
};
|
|
287
|
+
['SIGTERM', 'SIGINT', 'SIGHUP'].forEach((signal) => {
|
|
288
|
+
process.on(signal, () => {
|
|
289
|
+
void shutdown().finally(() => process.exit(0));
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
const page = context.pages()[0] || (await context.newPage());
|
|
295
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});
|
|
296
|
+
console.log('[camoufox-launch-auth] Headed browser opened. Please complete OAuth manually...');
|
|
297
|
+
const callbackPage = await waitForCallback(context, page, timeoutMs);
|
|
298
|
+
await callbackPage.waitForLoadState('load', { timeout: 120000 }).catch(() => {});
|
|
299
|
+
console.log('[camoufox-launch-auth] OAuth callback detected, manual completion finished.');
|
|
300
|
+
} finally {
|
|
301
|
+
await shutdown();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function runAutoFlowWithFallback(kind, options) {
|
|
306
|
+
const mode = String(kind || '').trim().toLowerCase();
|
|
307
|
+
const label = mode || 'auto';
|
|
308
|
+
const timeoutMs = Number(process.env.ROUTECODEX_CAMOUFOX_GEMINI_TIMEOUT_MS || 120_000);
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
if (mode === 'iflow') {
|
|
312
|
+
await runIflowAutoFlow(options);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (mode === 'gemini') {
|
|
316
|
+
await runGeminiAutoFlow(options);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (mode === 'antigravity') {
|
|
320
|
+
await runAntigravityAutoFlow(options);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
throw new Error(`Unknown auto mode: ${mode}`);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (!options.devMode && isSelectorOrTimeoutError(error)) {
|
|
326
|
+
await runHeadedManualAssistFlow({
|
|
327
|
+
url: options.url,
|
|
328
|
+
profileDir: options.profileDir,
|
|
329
|
+
camoufoxBinary: options.camoufoxBinary,
|
|
330
|
+
timeoutMs: Number(process.env.ROUTECODEX_OAUTH_TIMEOUT_MS || 10 * 60_000),
|
|
331
|
+
label
|
|
332
|
+
});
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
237
339
|
async function runIflowAutoFlow({ url, profileDir, profileId, camoufoxBinary, devMode }) {
|
|
238
340
|
let firefox;
|
|
239
341
|
try {
|
|
@@ -252,6 +354,17 @@ async function runIflowAutoFlow({ url, profileDir, profileId, camoufoxBinary, de
|
|
|
252
354
|
headless,
|
|
253
355
|
acceptDownloads: false
|
|
254
356
|
});
|
|
357
|
+
let closing = false;
|
|
358
|
+
const shutdown = async () => {
|
|
359
|
+
if (closing) return;
|
|
360
|
+
closing = true;
|
|
361
|
+
await context.close().catch(() => {});
|
|
362
|
+
};
|
|
363
|
+
['SIGTERM', 'SIGINT', 'SIGHUP'].forEach((signal) => {
|
|
364
|
+
process.on(signal, () => {
|
|
365
|
+
void shutdown().finally(() => process.exit(0));
|
|
366
|
+
});
|
|
367
|
+
});
|
|
255
368
|
|
|
256
369
|
let callbackObserved = false;
|
|
257
370
|
try {
|
|
@@ -352,7 +465,7 @@ async function runIflowAutoFlow({ url, profileDir, profileId, camoufoxBinary, de
|
|
|
352
465
|
}
|
|
353
466
|
throw error;
|
|
354
467
|
} finally {
|
|
355
|
-
await
|
|
468
|
+
await shutdown();
|
|
356
469
|
}
|
|
357
470
|
}
|
|
358
471
|
|
|
@@ -374,6 +487,17 @@ async function runGeminiAutoFlow({ url, profileDir, camoufoxBinary, devMode }) {
|
|
|
374
487
|
headless: !devMode,
|
|
375
488
|
acceptDownloads: false
|
|
376
489
|
});
|
|
490
|
+
let closing = false;
|
|
491
|
+
const shutdown = async () => {
|
|
492
|
+
if (closing) return;
|
|
493
|
+
closing = true;
|
|
494
|
+
await context.close().catch(() => {});
|
|
495
|
+
};
|
|
496
|
+
['SIGTERM', 'SIGINT', 'SIGHUP'].forEach((signal) => {
|
|
497
|
+
process.on(signal, () => {
|
|
498
|
+
void shutdown().finally(() => process.exit(0));
|
|
499
|
+
});
|
|
500
|
+
});
|
|
377
501
|
|
|
378
502
|
let callbackObserved = false;
|
|
379
503
|
try {
|
|
@@ -440,7 +564,7 @@ async function runGeminiAutoFlow({ url, profileDir, camoufoxBinary, devMode }) {
|
|
|
440
564
|
await callbackPage.waitForLoadState('load', { timeout: timeoutMs }).catch(() => {});
|
|
441
565
|
console.log('[camoufox-launch-auth] OAuth callback detected, automation complete.');
|
|
442
566
|
} finally {
|
|
443
|
-
await
|
|
567
|
+
await shutdown();
|
|
444
568
|
}
|
|
445
569
|
}
|
|
446
570
|
|
|
@@ -462,6 +586,17 @@ async function runAntigravityAutoFlow({ url, profileDir, camoufoxBinary, devMode
|
|
|
462
586
|
headless: !devMode,
|
|
463
587
|
acceptDownloads: false
|
|
464
588
|
});
|
|
589
|
+
let closing = false;
|
|
590
|
+
const shutdown = async () => {
|
|
591
|
+
if (closing) return;
|
|
592
|
+
closing = true;
|
|
593
|
+
await context.close().catch(() => {});
|
|
594
|
+
};
|
|
595
|
+
['SIGTERM', 'SIGINT', 'SIGHUP'].forEach((signal) => {
|
|
596
|
+
process.on(signal, () => {
|
|
597
|
+
void shutdown().finally(() => process.exit(0));
|
|
598
|
+
});
|
|
599
|
+
});
|
|
465
600
|
|
|
466
601
|
let callbackObserved = false;
|
|
467
602
|
try {
|
|
@@ -544,7 +679,7 @@ async function runAntigravityAutoFlow({ url, profileDir, camoufoxBinary, devMode
|
|
|
544
679
|
}
|
|
545
680
|
throw error;
|
|
546
681
|
} finally {
|
|
547
|
-
await
|
|
682
|
+
await shutdown();
|
|
548
683
|
}
|
|
549
684
|
}
|
|
550
685
|
|
|
@@ -584,7 +719,7 @@ async function waitForElementInPages(context, selector, timeoutMs) {
|
|
|
584
719
|
return null;
|
|
585
720
|
}
|
|
586
721
|
|
|
587
|
-
async function waitForCallback(context, fallbackPage) {
|
|
722
|
+
async function waitForCallback(context, fallbackPage, timeoutMs = 120000) {
|
|
588
723
|
const isCallbackUrl = (current) => {
|
|
589
724
|
if (typeof current !== 'string') {
|
|
590
725
|
return false;
|
|
@@ -605,13 +740,13 @@ async function waitForCallback(context, fallbackPage) {
|
|
|
605
740
|
}
|
|
606
741
|
|
|
607
742
|
try {
|
|
608
|
-
await fallbackPage.waitForURL((current) => isCallbackUrl(current), { timeout:
|
|
743
|
+
await fallbackPage.waitForURL((current) => isCallbackUrl(current), { timeout: timeoutMs });
|
|
609
744
|
return fallbackPage;
|
|
610
745
|
} catch {
|
|
611
746
|
// ignore and wait for popup
|
|
612
747
|
}
|
|
613
748
|
|
|
614
|
-
const callback = await context.waitForEvent('page', { timeout:
|
|
749
|
+
const callback = await context.waitForEvent('page', { timeout: timeoutMs });
|
|
615
750
|
await callback.waitForLoadState('domcontentloaded', { timeout: 60000 }).catch(() => {});
|
|
616
751
|
return callback;
|
|
617
752
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
function parseArgs(argv) {
|
|
6
|
+
const args = {
|
|
7
|
+
intervalMs: 1000,
|
|
8
|
+
errorsRoot: process.env.ROUTECODEX_ERRORSAMPLES_DIR || path.join(os.homedir(), '.routecodex', 'errorsamples'),
|
|
9
|
+
once: false
|
|
10
|
+
};
|
|
11
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
12
|
+
const a = argv[i];
|
|
13
|
+
if (a === '--once') args.once = true;
|
|
14
|
+
else if (a === '--interval' || a === '--intervalMs') {
|
|
15
|
+
const v = argv[i + 1];
|
|
16
|
+
i += 1;
|
|
17
|
+
const n = Number(v);
|
|
18
|
+
if (Number.isFinite(n) && n > 0) args.intervalMs = n;
|
|
19
|
+
} else if (a === '--errorsRoot') {
|
|
20
|
+
const v = argv[i + 1];
|
|
21
|
+
i += 1;
|
|
22
|
+
if (v && String(v).trim()) args.errorsRoot = path.resolve(String(v).trim());
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function safeJsonRead(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
const text = fs.readFileSync(filePath, 'utf8');
|
|
31
|
+
return JSON.parse(text);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function listJsonFiles(dirPath) {
|
|
38
|
+
try {
|
|
39
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
40
|
+
return entries
|
|
41
|
+
.filter((e) => e.isFile() && e.name.endsWith('.json'))
|
|
42
|
+
.map((e) => path.join(dirPath, e.name));
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function summarizeRecord(record) {
|
|
49
|
+
if (!record || typeof record !== 'object') return null;
|
|
50
|
+
const kind = record.kind || 'unknown';
|
|
51
|
+
const timestamp = record.timestamp || record.time || null;
|
|
52
|
+
|
|
53
|
+
if (String(kind).includes('shadow') || String(kind).includes('diff')) {
|
|
54
|
+
return {
|
|
55
|
+
kind,
|
|
56
|
+
timestamp,
|
|
57
|
+
requestId: record.requestId,
|
|
58
|
+
entryEndpoint: record.entryEndpoint,
|
|
59
|
+
baselineMode: record.baselineMode,
|
|
60
|
+
candidateMode: record.candidateMode,
|
|
61
|
+
diffCount: record.diffCount,
|
|
62
|
+
diffPaths: Array.isArray(record.diffPaths) ? record.diffPaths.slice(0, 12) : undefined,
|
|
63
|
+
runtime: record.runtime
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (String(kind).includes('hub_policy') || String(kind).includes('policy')) {
|
|
67
|
+
return {
|
|
68
|
+
kind,
|
|
69
|
+
timestamp,
|
|
70
|
+
stage: record.stage,
|
|
71
|
+
requestId: record.requestId,
|
|
72
|
+
endpoint: record.endpoint,
|
|
73
|
+
providerProtocol: record.providerProtocol,
|
|
74
|
+
violationCount: Array.isArray(record.observation?.violations) ? record.observation.violations.length : undefined,
|
|
75
|
+
runtime: record.runtime
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return { kind, timestamp };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function printNewFile(filePath) {
|
|
82
|
+
const record = safeJsonRead(filePath);
|
|
83
|
+
const summary = summarizeRecord(record);
|
|
84
|
+
const rel = filePath;
|
|
85
|
+
if (!summary) {
|
|
86
|
+
// eslint-disable-next-line no-console
|
|
87
|
+
console.log(`[errorsamples] ${rel}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
91
|
+
console.log(`[errorsamples] ${rel} -> ${JSON.stringify(summary)}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function main() {
|
|
95
|
+
const args = parseArgs(process.argv.slice(2));
|
|
96
|
+
|
|
97
|
+
const dirs = [
|
|
98
|
+
path.join(args.errorsRoot, 'unified-hub-shadow-runtime'),
|
|
99
|
+
path.join(args.errorsRoot, 'unified-hub-shadow-runtime-routing'),
|
|
100
|
+
path.join(args.errorsRoot, 'policy')
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
// eslint-disable-next-line no-console
|
|
104
|
+
console.log('[monitor:diff] watching:', dirs.join(', '));
|
|
105
|
+
// eslint-disable-next-line no-console
|
|
106
|
+
console.log('[monitor:diff] intervalMs=', args.intervalMs, 'errorsRoot=', args.errorsRoot);
|
|
107
|
+
|
|
108
|
+
const seen = new Set();
|
|
109
|
+
const scanOnce = () => {
|
|
110
|
+
for (const dir of dirs) {
|
|
111
|
+
const files = listJsonFiles(dir);
|
|
112
|
+
for (const f of files) {
|
|
113
|
+
if (seen.has(f)) continue;
|
|
114
|
+
seen.add(f);
|
|
115
|
+
printNewFile(f);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
scanOnce();
|
|
121
|
+
if (args.once) return;
|
|
122
|
+
setInterval(scanOnce, args.intervalMs);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await main();
|
|
126
|
+
|
package/scripts/pack-mode.mjs
CHANGED
|
@@ -70,12 +70,30 @@ try {
|
|
|
70
70
|
mutated.bundledDependencies = [];
|
|
71
71
|
mutated.bundleDependencies = [];
|
|
72
72
|
const llmsVersion = original.dependencies?.['@jsonstudio/llms'] || '^0.6.230';
|
|
73
|
+
const deps = {
|
|
74
|
+
...(original.dependencies || {})
|
|
75
|
+
};
|
|
76
|
+
// Avoid recursive self-dependency when packing @jsonstudio/rcc.
|
|
77
|
+
if (isRcc && deps['@jsonstudio/rcc']) {
|
|
78
|
+
delete deps['@jsonstudio/rcc'];
|
|
79
|
+
}
|
|
73
80
|
mutated.dependencies = {
|
|
74
|
-
...
|
|
81
|
+
...deps,
|
|
75
82
|
ajv: original.dependencies?.ajv || '^8.17.1',
|
|
76
83
|
zod: original.dependencies?.zod || '^3.23.8',
|
|
77
84
|
'@jsonstudio/llms': llmsVersion
|
|
78
85
|
};
|
|
86
|
+
// Ensure rcc ships bundled docs (copied to ~/.routecodex/docs by `rcc init`).
|
|
87
|
+
if (isRcc) {
|
|
88
|
+
const baseFiles = Array.isArray(original.files) ? [...original.files] : [];
|
|
89
|
+
if (!baseFiles.includes('docs/')) {
|
|
90
|
+
baseFiles.push('docs/');
|
|
91
|
+
}
|
|
92
|
+
if (!baseFiles.includes('configsamples/')) {
|
|
93
|
+
baseFiles.push('configsamples/');
|
|
94
|
+
}
|
|
95
|
+
mutated.files = baseFiles;
|
|
96
|
+
}
|
|
79
97
|
} else if (isRccx) {
|
|
80
98
|
// rccx: wasm-backed llms 核心,通过 npm alias 将 @jsonstudio/llms 指向 wasm 引擎包。
|
|
81
99
|
mutated.bundledDependencies = [];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const PROJECT_ROOT = path.resolve(__dirname, '..');
|
|
9
|
+
|
|
10
|
+
const pkgPath = path.join(PROJECT_ROOT, 'package.json');
|
|
11
|
+
const PACK_SCRIPT = path.join(PROJECT_ROOT, 'scripts', 'pack-mode.mjs');
|
|
12
|
+
const llmsPath = path.join(PROJECT_ROOT, 'node_modules', '@jsonstudio', 'llms');
|
|
13
|
+
|
|
14
|
+
function run(command, args, options = {}) {
|
|
15
|
+
const res = spawnSync(command, args, { stdio: 'inherit', ...options });
|
|
16
|
+
if ((res.status ?? 0) !== 0) {
|
|
17
|
+
throw new Error(`${command} ${args.join(' ')} failed`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isSymlink(p) {
|
|
22
|
+
try {
|
|
23
|
+
return fs.lstatSync(p).isSymbolicLink();
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const hadDevLink = isSymlink(llmsPath);
|
|
31
|
+
|
|
32
|
+
// 1) release 模式构建 dist(依赖 npm 上的 @jsonstudio/llms)
|
|
33
|
+
run('npm', ['run', 'build:min'], {
|
|
34
|
+
cwd: PROJECT_ROOT,
|
|
35
|
+
env: { ...process.env, BUILD_MODE: 'release' }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 2) 通过 pack-mode 生成 rcc tarball(内部会临时切换 package.json.name/bin 并确保 llms 为 release 包)
|
|
39
|
+
run(process.execPath, [PACK_SCRIPT, '--name', '@jsonstudio/rcc', '--bin', 'rcc'], { cwd: PROJECT_ROOT });
|
|
40
|
+
|
|
41
|
+
const updatedPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
42
|
+
const version = updatedPkg.version;
|
|
43
|
+
const tarballName = `jsonstudio-rcc-${version}.tgz`;
|
|
44
|
+
const tarballPath = path.join(PROJECT_ROOT, tarballName);
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(tarballPath)) {
|
|
47
|
+
throw new Error(`tarball not found: ${tarballPath}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log(`[pack-rcc] ✅ tarball ready: ${tarballPath}`);
|
|
51
|
+
|
|
52
|
+
// 3) pack 结束后恢复 dev 模式(routecodex 约定始终为 dev CLI;rcc 打包时才切 release)。
|
|
53
|
+
if (hadDevLink) {
|
|
54
|
+
run('npm', ['run', 'llmswitch:ensure'], {
|
|
55
|
+
cwd: PROJECT_ROOT,
|
|
56
|
+
env: { ...process.env, BUILD_MODE: 'dev' }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error('[pack-rcc] failed:', err instanceof Error ? err.message : String(err));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
@@ -141,6 +141,14 @@ function stableStringify(value) {
|
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
function cloneJsonSafe(value) {
|
|
145
|
+
try {
|
|
146
|
+
return JSON.parse(JSON.stringify(value));
|
|
147
|
+
} catch {
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
144
152
|
function diffPayloads(expected, actual, p = '<root>') {
|
|
145
153
|
if (Object.is(expected, actual)) return [];
|
|
146
154
|
if (typeof expected !== typeof actual) {
|
|
@@ -254,12 +262,12 @@ async function bootstrapVirtualRouterConfig(rawConfig) {
|
|
|
254
262
|
return mod.bootstrapVirtualRouterConfig(rawConfig);
|
|
255
263
|
}
|
|
256
264
|
|
|
257
|
-
async function runOnce({ requestId,
|
|
265
|
+
async function runOnce({ requestId, candidateMode, baselineMode, entryEndpoint, routeHint, payload }) {
|
|
258
266
|
const HubPipeline = await importHubPipelineCtor();
|
|
259
267
|
const artifacts = await bootstrapVirtualRouterConfig(buildVirtualRouterConfig());
|
|
260
268
|
const pipeline = new HubPipeline({
|
|
261
269
|
virtualRouter: artifacts.config,
|
|
262
|
-
policy: { mode }
|
|
270
|
+
policy: { mode: candidateMode }
|
|
263
271
|
});
|
|
264
272
|
const providerProtocol = normalizeEntryProviderProtocol(entryEndpoint);
|
|
265
273
|
const result = await pipeline.execute({
|
|
@@ -269,7 +277,10 @@ async function runOnce({ requestId, mode, entryEndpoint, routeHint, payload }) {
|
|
|
269
277
|
metadata: {
|
|
270
278
|
entryEndpoint,
|
|
271
279
|
providerProtocol,
|
|
272
|
-
routeHint
|
|
280
|
+
routeHint,
|
|
281
|
+
__hubShadowCompare: {
|
|
282
|
+
baselineMode
|
|
283
|
+
}
|
|
273
284
|
}
|
|
274
285
|
});
|
|
275
286
|
return result;
|
|
@@ -300,18 +311,24 @@ async function main() {
|
|
|
300
311
|
const candidateMode = String(opts.candidateMode);
|
|
301
312
|
const requestId = `shadow_unified_hub_${Date.now()}`;
|
|
302
313
|
|
|
303
|
-
const
|
|
304
|
-
const
|
|
314
|
+
const candidate = await runOnce({ requestId, candidateMode, baselineMode, entryEndpoint, routeHint, payload });
|
|
315
|
+
const shadow = candidate && candidate.metadata && typeof candidate.metadata === 'object'
|
|
316
|
+
? candidate.metadata.hubShadowCompare
|
|
317
|
+
: undefined;
|
|
318
|
+
const baselineProviderPayload =
|
|
319
|
+
shadow && typeof shadow === 'object' && shadow && !Array.isArray(shadow)
|
|
320
|
+
? shadow.baselineProviderPayload
|
|
321
|
+
: undefined;
|
|
305
322
|
|
|
306
323
|
const baselineOut = {
|
|
307
|
-
providerPayload:
|
|
308
|
-
target:
|
|
324
|
+
providerPayload: baselineProviderPayload,
|
|
325
|
+
target: candidate.target,
|
|
309
326
|
metadata: {
|
|
310
|
-
entryEndpoint:
|
|
311
|
-
providerProtocol:
|
|
312
|
-
processMode:
|
|
313
|
-
stream:
|
|
314
|
-
routeHint:
|
|
327
|
+
entryEndpoint: candidate.metadata?.entryEndpoint,
|
|
328
|
+
providerProtocol: candidate.metadata?.providerProtocol,
|
|
329
|
+
processMode: candidate.metadata?.processMode,
|
|
330
|
+
stream: candidate.metadata?.stream,
|
|
331
|
+
routeHint: candidate.metadata?.routeHint
|
|
315
332
|
}
|
|
316
333
|
};
|
|
317
334
|
const candidateOut = {
|
|
@@ -326,7 +343,10 @@ async function main() {
|
|
|
326
343
|
}
|
|
327
344
|
};
|
|
328
345
|
|
|
329
|
-
|
|
346
|
+
if (!baselineProviderPayload || typeof baselineProviderPayload !== 'object') {
|
|
347
|
+
throw new Error('[unified-hub-shadow-compare] hubShadowCompare.baselineProviderPayload missing; ensure llmswitch-core is rebuilt.');
|
|
348
|
+
}
|
|
349
|
+
const diffs = diffPayloads(cloneJsonSafe(baselineOut), cloneJsonSafe(candidateOut));
|
|
330
350
|
if (!diffs.length) {
|
|
331
351
|
console.log('[unified-hub-shadow-compare] OK diff=0');
|
|
332
352
|
return;
|