@jsonstudio/rcc 0.89.2239 → 0.90.89
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 +27 -0
- package/dist/build-info.js +2 -2
- package/dist/build-info.js.map +1 -1
- package/dist/cli/commands/claude.js +4 -8
- package/dist/cli/commands/claude.js.map +1 -1
- package/dist/cli/commands/codex.js +6 -3
- package/dist/cli/commands/codex.js.map +1 -1
- package/dist/cli/commands/guardian-daemon.d.ts +2 -0
- package/dist/cli/commands/guardian-daemon.js +299 -0
- package/dist/cli/commands/guardian-daemon.js.map +1 -0
- package/dist/cli/commands/init/camoufox.js +1 -1
- package/dist/cli/commands/init/camoufox.js.map +1 -1
- package/dist/cli/commands/launcher/index.d.ts +1 -1
- package/dist/cli/commands/launcher/types.d.ts +7 -1
- package/dist/cli/commands/launcher/utils.d.ts +4 -1
- package/dist/cli/commands/launcher/utils.js +18 -8
- package/dist/cli/commands/launcher/utils.js.map +1 -1
- package/dist/cli/commands/launcher-kernel.d.ts +1 -1
- package/dist/cli/commands/launcher-kernel.js +608 -249
- package/dist/cli/commands/launcher-kernel.js.map +1 -1
- package/dist/cli/commands/port.js +28 -8
- package/dist/cli/commands/port.js.map +1 -1
- package/dist/cli/commands/restart.d.ts +4 -0
- package/dist/cli/commands/restart.js +91 -42
- package/dist/cli/commands/restart.js.map +1 -1
- package/dist/cli/commands/{clock-admin.d.ts → session-admin.d.ts} +2 -2
- package/dist/cli/commands/{clock-admin.js → session-admin.js} +17 -17
- package/dist/cli/commands/session-admin.js.map +1 -0
- package/dist/cli/commands/{tmux-inject.d.ts → session-inject.d.ts} +2 -2
- package/dist/cli/commands/{tmux-inject.js → session-inject.js} +12 -12
- package/dist/cli/commands/session-inject.js.map +1 -0
- package/dist/cli/commands/start-types.d.ts +4 -0
- package/dist/cli/commands/start-utils.d.ts +1 -0
- package/dist/cli/commands/start-utils.js +3 -0
- package/dist/cli/commands/start-utils.js.map +1 -1
- package/dist/cli/commands/start.js +122 -72
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/stop.d.ts +3 -0
- package/dist/cli/commands/stop.js +30 -63
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/config/init-provider-catalog.js +8 -3
- package/dist/cli/config/init-provider-catalog.js.map +1 -1
- package/dist/cli/guardian/client.d.ts +38 -0
- package/dist/cli/guardian/client.js +237 -0
- package/dist/cli/guardian/client.js.map +1 -0
- package/dist/cli/guardian/paths.d.ts +7 -0
- package/dist/cli/guardian/paths.js +13 -0
- package/dist/cli/guardian/paths.js.map +1 -0
- package/dist/cli/guardian/types.d.ts +30 -0
- package/dist/cli/guardian/types.js +2 -0
- package/dist/cli/guardian/types.js.map +1 -0
- package/dist/cli/register/guardian-daemon-command.d.ts +2 -0
- package/dist/cli/register/guardian-daemon-command.js +5 -0
- package/dist/cli/register/guardian-daemon-command.js.map +1 -0
- package/dist/cli/register/session-admin-command.d.ts +3 -0
- package/dist/cli/register/session-admin-command.js +5 -0
- package/dist/cli/register/session-admin-command.js.map +1 -0
- package/dist/cli/register/session-inject-command.d.ts +3 -0
- package/dist/cli/register/session-inject-command.js +5 -0
- package/dist/cli/register/session-inject-command.js.map +1 -0
- package/dist/cli/server/port-utils.js +57 -1
- package/dist/cli/server/port-utils.js.map +1 -1
- package/dist/cli.js +52 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/oauth.js +6 -6
- package/dist/commands/oauth.js.map +1 -1
- package/dist/config/provider-v2-loader.js +18 -3
- package/dist/config/provider-v2-loader.js.map +1 -1
- package/dist/config/routecodex-config-loader.js +184 -9
- package/dist/config/routecodex-config-loader.js.map +1 -1
- package/dist/config/unified-config-paths.js +22 -0
- package/dist/config/unified-config-paths.js.map +1 -1
- package/dist/config/virtual-router-builder.js +18 -5
- package/dist/config/virtual-router-builder.js.map +1 -1
- package/dist/config/virtual-router-types.js +20 -5
- package/dist/config/virtual-router-types.js.map +1 -1
- package/dist/daemon-admin-ui/assets/index-C8vP_c5E.js +15 -0
- package/dist/daemon-admin-ui/assets/index-DjIoHmNv.css +1 -0
- package/dist/daemon-admin-ui/index.html +13 -0
- package/dist/docs/daemon-admin-ui.html +334 -63
- package/dist/index.d.ts +9 -0
- package/dist/index.js +268 -10
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-key-normalization.js +1 -10
- package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.d.ts +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.js +36 -0
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.events.js +89 -49
- package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +2 -16
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
- package/dist/manager/modules/token/index.d.ts +1 -0
- package/dist/manager/modules/token/index.js +6 -1
- package/dist/manager/modules/token/index.js.map +1 -1
- package/dist/manager/types.d.ts +1 -0
- package/dist/modules/llmswitch/bridge/state-integrations.js +1 -1
- package/dist/modules/llmswitch/bridge/state-integrations.js.map +1 -1
- package/dist/providers/auth/antigravity-user-agent.js +78 -31
- package/dist/providers/auth/antigravity-user-agent.js.map +1 -1
- package/dist/providers/auth/gemini-cli-userinfo-helper.js +94 -63
- package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/iflow-userinfo-helper.js +1 -1
- package/dist/providers/auth/iflow-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/oauth-error-message.d.ts +1 -0
- package/dist/providers/auth/oauth-error-message.js +44 -0
- package/dist/providers/auth/oauth-error-message.js.map +1 -0
- package/dist/providers/auth/oauth-lifecycle/error-detection.js +42 -8
- package/dist/providers/auth/oauth-lifecycle/error-detection.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle/token-io.d.ts +1 -0
- package/dist/providers/auth/oauth-lifecycle/token-io.js +12 -0
- package/dist/providers/auth/oauth-lifecycle/token-io.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +502 -87
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/oauth-repair-env.js +3 -5
- package/dist/providers/auth/oauth-repair-env.js.map +1 -1
- package/dist/providers/auth/oauth-utils/error-extraction.js +42 -8
- package/dist/providers/auth/oauth-utils/error-extraction.js.map +1 -1
- package/dist/providers/core/config/camoufox-actions.d.ts +31 -0
- package/dist/providers/core/config/camoufox-actions.js +470 -0
- package/dist/providers/core/config/camoufox-actions.js.map +1 -0
- package/dist/providers/core/config/camoufox-launcher.d.ts +3 -0
- package/dist/providers/core/config/camoufox-launcher.js +553 -159
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
- package/dist/providers/core/config/oauth-flows.js +6 -44
- package/dist/providers/core/config/oauth-flows.js.map +1 -1
- package/dist/providers/core/config/provider-oauth-configs.js +51 -7
- package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +2 -2
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/base-provider-runtime-helpers.js +15 -2
- package/dist/providers/core/runtime/base-provider-runtime-helpers.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +32 -15
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/provider-family-profile-utils.js +1 -1
- package/dist/providers/core/runtime/provider-family-profile-utils.js.map +1 -1
- package/dist/providers/core/runtime/provider-response-postprocessor.js +61 -14
- package/dist/providers/core/runtime/provider-response-postprocessor.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 +124 -19
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.js +32 -6
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/core/utils/provider-error-reporter.js +51 -0
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/profile/families/iflow-profile.js +83 -10
- package/dist/providers/profile/families/iflow-profile.js.map +1 -1
- package/dist/scripts/camoufox/launch-auth.mjs +112 -5
- package/dist/server/handlers/config-admin-handler.js +9 -2
- package/dist/server/handlers/config-admin-handler.js.map +1 -1
- package/dist/server/handlers/handler-response-utils.js +3 -6
- package/dist/server/handlers/handler-response-utils.js.map +1 -1
- package/dist/server/handlers/handler-utils.js +14 -17
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/logging.js +3 -4
- package/dist/server/handlers/logging.js.map +1 -1
- package/dist/server/handlers/responses-handler.js +5 -3
- package/dist/server/handlers/responses-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +5 -3
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/control-handler.js +104 -15
- package/dist/server/runtime/http-server/daemon-admin/control-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +2 -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-routing-utils.d.ts +24 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js +316 -70
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +190 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.d.ts +1 -1
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +21 -32
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js +2 -0
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +8 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.js +30 -0
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
- package/dist/server/runtime/http-server/executor/client-injection-flow.d.ts +14 -0
- package/dist/server/runtime/http-server/executor/client-injection-flow.js +297 -0
- package/dist/server/runtime/http-server/executor/client-injection-flow.js.map +1 -0
- package/dist/server/runtime/http-server/executor/index.d.ts +1 -1
- package/dist/server/runtime/http-server/executor/index.js +1 -1
- package/dist/server/runtime/http-server/executor/index.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-converter.js +281 -70
- package/dist/server/runtime/http-server/executor/provider-response-converter.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-runtime-resolver.js +8 -6
- package/dist/server/runtime/http-server/executor/provider-runtime-resolver.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 +12 -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.d.ts +1 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js +23 -19
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js.map +1 -1
- package/dist/server/runtime/http-server/executor/retry-engine.d.ts +2 -2
- package/dist/server/runtime/http-server/executor/retry-engine.js +2 -2
- package/dist/server/runtime/http-server/executor/retry-engine.js.map +1 -1
- package/dist/server/runtime/http-server/executor/sse-error-handler.d.ts +1 -0
- package/dist/server/runtime/http-server/executor/sse-error-handler.js +13 -2
- package/dist/server/runtime/http-server/executor/sse-error-handler.js.map +1 -1
- package/dist/server/runtime/http-server/executor/usage-aggregator.d.ts +0 -12
- package/dist/server/runtime/http-server/executor/usage-aggregator.js +89 -90
- package/dist/server/runtime/http-server/executor/usage-aggregator.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +318 -17
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-provider.js +5 -1
- package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-response.js +52 -58
- package/dist/server/runtime/http-server/executor-response.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-bootstrap.js +50 -6
- package/dist/server/runtime/http-server/http-server-bootstrap.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-lifecycle.js +6 -5
- package/dist/server/runtime/http-server/http-server-lifecycle.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-session-daemon.d.ts +6 -0
- package/dist/server/runtime/http-server/http-server-session-daemon.js +404 -0
- package/dist/server/runtime/http-server/http-server-session-daemon.js.map +1 -0
- package/dist/server/runtime/http-server/hub-shadow-compare.js +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +11 -10
- package/dist/server/runtime/http-server/index.js +21 -20
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/managed-process-probe.js +1 -1
- package/dist/server/runtime/http-server/managed-process-probe.js.map +1 -1
- package/dist/server/runtime/http-server/middleware.js +91 -5
- package/dist/server/runtime/http-server/middleware.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +19 -9
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.d.ts +2 -1
- package/dist/server/runtime/http-server/routes.js +7 -5
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/{clock-client-reaper.d.ts → session-client-reaper.d.ts} +6 -6
- package/dist/server/runtime/http-server/{clock-client-reaper.js → session-client-reaper.js} +26 -49
- package/dist/server/runtime/http-server/session-client-reaper.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-registry-utils.d.ts → session-client-registry-utils.d.ts} +14 -10
- package/dist/server/runtime/http-server/{clock-client-registry-utils.js → session-client-registry-utils.js} +77 -19
- package/dist/server/runtime/http-server/session-client-registry-utils.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-registry.d.ts → session-client-registry.d.ts} +26 -11
- package/dist/server/runtime/http-server/{clock-client-registry.js → session-client-registry.js} +305 -11
- package/dist/server/runtime/http-server/session-client-registry.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-route-utils.d.ts → session-client-route-utils.d.ts} +1 -1
- package/dist/server/runtime/http-server/{clock-client-route-utils.js → session-client-route-utils.js} +4 -4
- package/dist/server/runtime/http-server/session-client-route-utils.js.map +1 -0
- package/dist/server/runtime/http-server/session-client-routes.d.ts +2 -0
- package/dist/server/runtime/http-server/{clock-client-routes.js → session-client-routes.js} +107 -59
- package/dist/server/runtime/http-server/session-client-routes.js.map +1 -0
- package/dist/server/runtime/http-server/session-daemon-inject-config.d.ts +1 -0
- package/dist/server/runtime/http-server/{clock-daemon-inject-config.js → session-daemon-inject-config.js} +2 -2
- package/dist/server/runtime/http-server/session-daemon-inject-config.js.map +1 -0
- package/dist/server/runtime/http-server/session-daemon-log-throttle.d.ts +28 -0
- package/dist/server/runtime/http-server/session-daemon-log-throttle.js +105 -0
- package/dist/server/runtime/http-server/session-daemon-log-throttle.js.map +1 -0
- package/dist/server/runtime/http-server/session-dir.js +12 -1
- package/dist/server/runtime/http-server/session-dir.js.map +1 -1
- package/dist/server/runtime/http-server/session-scope-resolution.d.ts +14 -0
- package/dist/server/runtime/http-server/session-scope-resolution.js +208 -0
- package/dist/server/runtime/http-server/session-scope-resolution.js.map +1 -0
- package/dist/server/runtime/http-server/stats-manager.d.ts +35 -0
- package/dist/server/runtime/http-server/stats-manager.js +269 -21
- package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.d.ts +21 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js +197 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js.map +1 -0
- package/dist/server/runtime/http-server/tmux-session-probe.d.ts +10 -0
- package/dist/server/runtime/http-server/tmux-session-probe.js +98 -1
- package/dist/server/runtime/http-server/tmux-session-probe.js.map +1 -1
- package/dist/server-lifecycle/port-utils.d.ts +2 -1
- package/dist/server-lifecycle/port-utils.js +84 -4
- package/dist/server-lifecycle/port-utils.js.map +1 -1
- package/dist/token-daemon/index.d.ts +1 -0
- package/dist/token-daemon/index.js +17 -12
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/token-daemon/token-daemon.d.ts +2 -0
- package/dist/token-daemon/token-daemon.js +18 -10
- package/dist/token-daemon/token-daemon.js.map +1 -1
- package/dist/utils/llms-engine-shadow.js +1 -1
- package/dist/utils/llms-engine-shadow.js.map +1 -1
- package/dist/utils/log-helpers.js +46 -0
- package/dist/utils/log-helpers.js.map +1 -1
- package/dist/utils/session-client-token.d.ts +4 -0
- package/dist/utils/session-client-token.js +93 -0
- package/dist/utils/session-client-token.js.map +1 -0
- package/dist/utils/session-scope-trace.d.ts +11 -0
- package/dist/utils/session-scope-trace.js +41 -0
- package/dist/utils/session-scope-trace.js.map +1 -0
- package/docs/CLOCK.md +0 -1
- package/docs/DAEMON_CONTROL_PLANE.md +1 -0
- package/docs/PORTS.md +2 -2
- package/docs/ROUTING_POLICY_SCHEMA.md +5 -3
- package/docs/antigravity-routing-contract.md +2 -2
- package/docs/daemon-admin-ui.html +334 -63
- package/docs/design/servertool-stopmessage-lifecycle.md +109 -0
- package/docs/exec-command-guard-policy.example.v1.json +7 -1
- package/docs/providers/antigravity-gemini-provider-compat.md +2 -2
- package/docs/{clock-client-daemon-design.md → session-client-daemon-design.md} +34 -34
- package/package.json +23 -7
- package/scripts/build-core.mjs +12 -0
- package/scripts/camoufox/launch-auth.mjs +112 -5
- package/scripts/ci/repo-sanity.mjs +1 -0
- package/scripts/compare-responses-sse.mjs +267 -0
- package/scripts/install-global.sh +6 -0
- package/scripts/install-verify.mjs +33 -16
- package/scripts/replay-codex-sample.mjs +52 -6
- package/scripts/run-bg.sh +226 -43
- package/scripts/run-fg-gtimeout.sh +158 -14
- package/scripts/tests/blackbox-rcc-vs-routecodex-antigravity.mjs +3 -3
- package/scripts/tests/ci-jest.mjs +9 -1
- package/scripts/triage-errorsamples.mjs +216 -0
- package/scripts/verify-codex-error-samples.mjs +92 -15
- package/scripts/verify-install-e2e.mjs +57 -27
- package/scripts/virtual-router-dryrun.mjs +7 -1
- package/dist/cli/commands/clock-admin.js.map +0 -1
- package/dist/cli/commands/tmux-inject.js.map +0 -1
- package/dist/cli/register/clock-admin-command.d.ts +0 -3
- package/dist/cli/register/clock-admin-command.js +0 -5
- package/dist/cli/register/clock-admin-command.js.map +0 -1
- package/dist/cli/register/tmux-inject-command.d.ts +0 -3
- package/dist/cli/register/tmux-inject-command.js +0 -5
- package/dist/cli/register/tmux-inject-command.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-reaper.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-registry-utils.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-registry.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-route-utils.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-routes.d.ts +0 -2
- package/dist/server/runtime/http-server/clock-client-routes.js.map +0 -1
- package/dist/server/runtime/http-server/clock-daemon-inject-config.d.ts +0 -1
- package/dist/server/runtime/http-server/clock-daemon-inject-config.js.map +0 -1
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.d.ts +0 -12
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.js +0 -56
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.js.map +0 -1
- package/dist/server/runtime/http-server/http-server-clock-daemon.d.ts +0 -5
- package/dist/server/runtime/http-server/http-server-clock-daemon.js +0 -255
- package/dist/server/runtime/http-server/http-server-clock-daemon.js.map +0 -1
- package/dist/utils/clock-client-token.d.ts +0 -3
- package/dist/utils/clock-client-token.js +0 -54
- package/dist/utils/clock-client-token.js.map +0 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { extractSessionClientScopeIdFromApiKey } from '../../../utils/session-client-token.js';
|
|
2
|
+
function readToken(value) {
|
|
3
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
4
|
+
}
|
|
5
|
+
function extractHeaderValue(headers, name) {
|
|
6
|
+
if (!headers) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const target = name.toLowerCase();
|
|
10
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
11
|
+
if (key.toLowerCase() !== target) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return value.trim() || undefined;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
18
|
+
return String(value[0]).trim() || undefined;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function extractTmuxSessionIdFromTurnMetadata(rawValue) {
|
|
25
|
+
if (!rawValue) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const normalizeTmuxToken = (value) => {
|
|
29
|
+
const token = readToken(value);
|
|
30
|
+
if (!token) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
if (!/^[a-zA-Z0-9._:-]+$/.test(token)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return token;
|
|
37
|
+
};
|
|
38
|
+
const parseFromObject = (root) => {
|
|
39
|
+
if (!root || typeof root !== 'object') {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const queue = [root];
|
|
43
|
+
const visited = new Set();
|
|
44
|
+
while (queue.length > 0) {
|
|
45
|
+
const current = queue.shift();
|
|
46
|
+
if (!current || typeof current !== 'object') {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (visited.has(current)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
visited.add(current);
|
|
53
|
+
if (Array.isArray(current)) {
|
|
54
|
+
for (const value of current) {
|
|
55
|
+
if (value && typeof value === 'object') {
|
|
56
|
+
queue.push(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const record = current;
|
|
62
|
+
const directTmux = normalizeTmuxToken(record.tmuxSessionId)
|
|
63
|
+
|| normalizeTmuxToken(record.tmux_session_id)
|
|
64
|
+
|| normalizeTmuxToken(record.tmuxSession)
|
|
65
|
+
|| normalizeTmuxToken(record.tmux_session)
|
|
66
|
+
|| normalizeTmuxToken(record.rccTmuxSessionId)
|
|
67
|
+
|| normalizeTmuxToken(record.rcc_tmux_session_id)
|
|
68
|
+
|| normalizeTmuxToken(record.clientTmuxSessionId)
|
|
69
|
+
|| normalizeTmuxToken(record.client_tmux_session_id)
|
|
70
|
+
|| normalizeTmuxToken(record.rccSessionClientTmuxSessionId)
|
|
71
|
+
|| normalizeTmuxToken(record.rcc_session_client_tmux_session_id);
|
|
72
|
+
if (directTmux) {
|
|
73
|
+
return directTmux;
|
|
74
|
+
}
|
|
75
|
+
for (const [key, value] of Object.entries(record)) {
|
|
76
|
+
if (value && typeof value === 'object') {
|
|
77
|
+
queue.push(value);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (typeof value !== 'string') {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const normalizedKey = key.trim().toLowerCase();
|
|
84
|
+
if (normalizedKey.includes('tmux')
|
|
85
|
+
|| normalizedKey === 'rcc_session_client_tmux_session_id'
|
|
86
|
+
|| normalizedKey === 'rccsessionclienttmuxsessionid') {
|
|
87
|
+
const token = normalizeTmuxToken(value);
|
|
88
|
+
if (token) {
|
|
89
|
+
return token;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
};
|
|
96
|
+
const candidates = [rawValue];
|
|
97
|
+
try {
|
|
98
|
+
candidates.push(decodeURIComponent(rawValue));
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// ignore URI decoding errors
|
|
102
|
+
}
|
|
103
|
+
for (const candidate of [...candidates]) {
|
|
104
|
+
const normalized = candidate.trim();
|
|
105
|
+
if (!normalized) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!/^[A-Za-z0-9+/=_-]+$/.test(normalized) || normalized.length < 12) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=');
|
|
113
|
+
const decoded = Buffer.from(padded, 'base64').toString('utf8').trim();
|
|
114
|
+
if (decoded) {
|
|
115
|
+
candidates.push(decoded);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// ignore base64 decoding errors
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const candidate of candidates) {
|
|
123
|
+
try {
|
|
124
|
+
const parsed = JSON.parse(candidate);
|
|
125
|
+
const tmux = parseFromObject(parsed);
|
|
126
|
+
if (tmux) {
|
|
127
|
+
return tmux;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// continue to URLSearchParams fallback
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const params = new URLSearchParams(candidate);
|
|
135
|
+
const fromParams = normalizeTmuxToken(params.get('tmuxSessionId'))
|
|
136
|
+
|| normalizeTmuxToken(params.get('tmux_session_id'))
|
|
137
|
+
|| normalizeTmuxToken(params.get('tmuxSession'))
|
|
138
|
+
|| normalizeTmuxToken(params.get('tmux_session'))
|
|
139
|
+
|| normalizeTmuxToken(params.get('rccTmuxSessionId'))
|
|
140
|
+
|| normalizeTmuxToken(params.get('rcc_tmux_session_id'))
|
|
141
|
+
|| normalizeTmuxToken(params.get('clientTmuxSessionId'))
|
|
142
|
+
|| normalizeTmuxToken(params.get('client_tmux_session_id'))
|
|
143
|
+
|| normalizeTmuxToken(params.get('rcc_session_client_tmux_session_id'));
|
|
144
|
+
if (fromParams) {
|
|
145
|
+
return fromParams;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// ignore non-URLSearchParams text
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
function readTmuxFromHeaderSource(source) {
|
|
155
|
+
if (!source) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const fromTurnMeta = extractTmuxSessionIdFromTurnMetadata(extractHeaderValue(source, 'x-codex-turn-metadata'));
|
|
159
|
+
if (fromTurnMeta) {
|
|
160
|
+
return fromTurnMeta;
|
|
161
|
+
}
|
|
162
|
+
const fromHeader = extractHeaderValue(source, 'x-routecodex-client-tmux-session-id')
|
|
163
|
+
|| extractHeaderValue(source, 'x-rcc-client-tmux-session-id')
|
|
164
|
+
|| extractHeaderValue(source, 'x-routecodex-client-tmuxsession-id')
|
|
165
|
+
|| extractHeaderValue(source, 'x-rcc-client-tmuxsession-id')
|
|
166
|
+
|| extractHeaderValue(source, 'x-routecodex-clienttmuxsessionid')
|
|
167
|
+
|| extractHeaderValue(source, 'x-routecodex-tmux-session-id')
|
|
168
|
+
|| extractHeaderValue(source, 'x-rcc-tmux-session-id')
|
|
169
|
+
|| extractHeaderValue(source, 'x-tmux-session-id');
|
|
170
|
+
if (fromHeader) {
|
|
171
|
+
return fromHeader;
|
|
172
|
+
}
|
|
173
|
+
const fromApiKeyHeader = extractHeaderValue(source, 'x-routecodex-api-key')
|
|
174
|
+
|| extractHeaderValue(source, 'x-api-key')
|
|
175
|
+
|| extractHeaderValue(source, 'x-routecodex-apikey')
|
|
176
|
+
|| extractHeaderValue(source, 'api-key')
|
|
177
|
+
|| extractHeaderValue(source, 'apikey');
|
|
178
|
+
const fromApiKey = extractSessionClientScopeIdFromApiKey(fromApiKeyHeader);
|
|
179
|
+
if (fromApiKey) {
|
|
180
|
+
return fromApiKey;
|
|
181
|
+
}
|
|
182
|
+
const authorization = extractHeaderValue(source, 'authorization');
|
|
183
|
+
if (authorization) {
|
|
184
|
+
const match = authorization.match(/^(?:Bearer|ApiKey)\s+(.+)$/i);
|
|
185
|
+
const fromAuth = extractSessionClientScopeIdFromApiKey(match ? String(match[1]) : authorization);
|
|
186
|
+
if (fromAuth) {
|
|
187
|
+
return fromAuth;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
export function resolveTmuxSessionIdAndSource(args) {
|
|
193
|
+
const tmuxFromHeaders = readTmuxFromHeaderSource(args.headers)
|
|
194
|
+
|| readTmuxFromHeaderSource(args.clientHeaders);
|
|
195
|
+
if (tmuxFromHeaders) {
|
|
196
|
+
return { tmuxSessionId: tmuxFromHeaders, source: 'headers_or_api_key' };
|
|
197
|
+
}
|
|
198
|
+
const tmuxFromMeta = readToken(args.userMeta.tmuxSessionId) || readToken(args.userMeta.tmux_session_id);
|
|
199
|
+
if (tmuxFromMeta) {
|
|
200
|
+
return { tmuxSessionId: tmuxFromMeta, source: 'metadata' };
|
|
201
|
+
}
|
|
202
|
+
const tmuxFromBody = readToken(args.bodyMeta.tmuxSessionId) || readToken(args.bodyMeta.tmux_session_id);
|
|
203
|
+
if (tmuxFromBody) {
|
|
204
|
+
return { tmuxSessionId: tmuxFromBody, source: 'body_metadata' };
|
|
205
|
+
}
|
|
206
|
+
return { source: 'none' };
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=session-scope-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-scope-resolution.js","sourceRoot":"","sources":["../../../../src/server/runtime/http-server/session-scope-resolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,6 +53,20 @@ export interface HistoricalStatsSnapshot {
|
|
|
53
53
|
sampleCount: number;
|
|
54
54
|
totals: ProviderStatsView[];
|
|
55
55
|
}
|
|
56
|
+
export interface HistoricalPeriodBucket {
|
|
57
|
+
period: string;
|
|
58
|
+
requestCount: number;
|
|
59
|
+
errorCount: number;
|
|
60
|
+
totalPromptTokens: number;
|
|
61
|
+
totalCompletionTokens: number;
|
|
62
|
+
totalOutputTokens: number;
|
|
63
|
+
}
|
|
64
|
+
export interface HistoricalPeriodsSnapshot {
|
|
65
|
+
generatedAt: number;
|
|
66
|
+
daily: HistoricalPeriodBucket[];
|
|
67
|
+
weekly: HistoricalPeriodBucket[];
|
|
68
|
+
monthly: HistoricalPeriodBucket[];
|
|
69
|
+
}
|
|
56
70
|
export type StatsPersistOptions = {
|
|
57
71
|
logPath?: string;
|
|
58
72
|
reason?: string;
|
|
@@ -74,6 +88,17 @@ export declare class StatsManager {
|
|
|
74
88
|
private historicalSnapshotCount;
|
|
75
89
|
private historicalSampleCount;
|
|
76
90
|
private historicalLoaded;
|
|
91
|
+
private readonly dailyPeriods;
|
|
92
|
+
private readonly weeklyPeriods;
|
|
93
|
+
private readonly monthlyPeriods;
|
|
94
|
+
private readonly persistIntervalMs;
|
|
95
|
+
private readonly maxDailyPeriods;
|
|
96
|
+
private readonly maxWeeklyPeriods;
|
|
97
|
+
private readonly maxMonthlyPeriods;
|
|
98
|
+
private periodicPersistTimer;
|
|
99
|
+
private persistSeq;
|
|
100
|
+
private lastPeriodicSignature;
|
|
101
|
+
private readonly persistSessionId;
|
|
77
102
|
constructor();
|
|
78
103
|
recordRequestStart(requestId: string): void;
|
|
79
104
|
bindProvider(requestId: string, meta: {
|
|
@@ -91,12 +116,22 @@ export declare class StatsManager {
|
|
|
91
116
|
}, payload: unknown): void;
|
|
92
117
|
snapshot(uptimeMs: number): StatsSnapshot;
|
|
93
118
|
logSummary(uptimeMs: number): StatsSnapshot;
|
|
119
|
+
logFinalSummary(uptimeMs: number): {
|
|
120
|
+
session: StatsSnapshot;
|
|
121
|
+
historical: HistoricalStatsSnapshot;
|
|
122
|
+
};
|
|
94
123
|
persistSnapshot(snapshot: StatsSnapshot, options?: StatsPersistOptions): Promise<void>;
|
|
95
124
|
logHistoricalSummary(options?: {
|
|
96
125
|
logPath?: string;
|
|
97
126
|
}): Promise<void>;
|
|
98
127
|
snapshotHistorical(): HistoricalStatsSnapshot;
|
|
128
|
+
snapshotHistoricalPeriods(): HistoricalPeriodsSnapshot;
|
|
99
129
|
private ensureHistoricalLoaded;
|
|
130
|
+
private startPeriodicPersistence;
|
|
131
|
+
private persistPeriodicSnapshot;
|
|
132
|
+
private buildSnapshotSignature;
|
|
133
|
+
private mergeSnapshotIntoPeriods;
|
|
134
|
+
private mergeSnapshotIntoHistorical;
|
|
100
135
|
private loadHistoricalFromDisk;
|
|
101
136
|
private normalizeLogPath;
|
|
102
137
|
private resolveLogPath;
|
|
@@ -7,6 +7,10 @@ import { buildHistoricalProviderRow, buildSessionProviderRow, composeBucketKey,
|
|
|
7
7
|
const DEFAULT_STATS_LOG_PATH = path.join(os.homedir(), '.routecodex', 'logs', 'provider-stats.jsonl');
|
|
8
8
|
const DEFAULT_HISTORY_MAX_TAIL_BYTES = 8 * 1024 * 1024;
|
|
9
9
|
const DEFAULT_HISTORY_MAX_LINES = 20000;
|
|
10
|
+
const DEFAULT_PERSIST_INTERVAL_MS = 30000;
|
|
11
|
+
const DEFAULT_DAILY_PERIODS = 90;
|
|
12
|
+
const DEFAULT_WEEKLY_PERIODS = 104;
|
|
13
|
+
const DEFAULT_MONTHLY_PERIODS = 36;
|
|
10
14
|
function resolveBoolFromEnv(value, fallback) {
|
|
11
15
|
if (!value) {
|
|
12
16
|
return fallback;
|
|
@@ -36,6 +40,84 @@ function resolvePositiveIntEnv(primary, secondary, fallback) {
|
|
|
36
40
|
}
|
|
37
41
|
return fallback;
|
|
38
42
|
}
|
|
43
|
+
function toUtcDayKey(ts) {
|
|
44
|
+
const date = new Date(ts);
|
|
45
|
+
const y = date.getUTCFullYear();
|
|
46
|
+
const m = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
47
|
+
const d = String(date.getUTCDate()).padStart(2, '0');
|
|
48
|
+
return `${y}-${m}-${d}`;
|
|
49
|
+
}
|
|
50
|
+
function toUtcMonthKey(ts) {
|
|
51
|
+
const date = new Date(ts);
|
|
52
|
+
const y = date.getUTCFullYear();
|
|
53
|
+
const m = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
54
|
+
return `${y}-${m}`;
|
|
55
|
+
}
|
|
56
|
+
function toUtcIsoWeekKey(ts) {
|
|
57
|
+
const date = new Date(ts);
|
|
58
|
+
const day = date.getUTCDay() || 7;
|
|
59
|
+
date.setUTCDate(date.getUTCDate() + 4 - day);
|
|
60
|
+
const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
|
|
61
|
+
const week = Math.ceil((((date.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
|
|
62
|
+
return `${date.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
|
|
63
|
+
}
|
|
64
|
+
function sumSnapshotTotals(rows) {
|
|
65
|
+
const totals = {
|
|
66
|
+
requestCount: 0,
|
|
67
|
+
errorCount: 0,
|
|
68
|
+
totalPromptTokens: 0,
|
|
69
|
+
totalCompletionTokens: 0,
|
|
70
|
+
totalOutputTokens: 0
|
|
71
|
+
};
|
|
72
|
+
for (const row of rows) {
|
|
73
|
+
totals.requestCount += row.requestCount ?? 0;
|
|
74
|
+
totals.errorCount += row.errorCount ?? 0;
|
|
75
|
+
totals.totalPromptTokens += row.totalPromptTokens ?? 0;
|
|
76
|
+
totals.totalCompletionTokens += row.totalCompletionTokens ?? 0;
|
|
77
|
+
totals.totalOutputTokens += row.totalOutputTokens ?? 0;
|
|
78
|
+
}
|
|
79
|
+
return totals;
|
|
80
|
+
}
|
|
81
|
+
function sortSummaryRows(rows) {
|
|
82
|
+
return rows
|
|
83
|
+
.slice()
|
|
84
|
+
.sort((a, b) => {
|
|
85
|
+
const requestDelta = (b.requestCount ?? 0) - (a.requestCount ?? 0);
|
|
86
|
+
if (requestDelta !== 0) {
|
|
87
|
+
return requestDelta;
|
|
88
|
+
}
|
|
89
|
+
const keyA = composeBucketKey(a.providerKey, a.model);
|
|
90
|
+
const keyB = composeBucketKey(b.providerKey, b.model);
|
|
91
|
+
return keyA.localeCompare(keyB);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function upsertPeriodBucket(map, period, delta) {
|
|
95
|
+
const current = map.get(period) ?? {
|
|
96
|
+
requestCount: 0,
|
|
97
|
+
errorCount: 0,
|
|
98
|
+
totalPromptTokens: 0,
|
|
99
|
+
totalCompletionTokens: 0,
|
|
100
|
+
totalOutputTokens: 0
|
|
101
|
+
};
|
|
102
|
+
current.requestCount += delta.requestCount;
|
|
103
|
+
current.errorCount += delta.errorCount;
|
|
104
|
+
current.totalPromptTokens += delta.totalPromptTokens;
|
|
105
|
+
current.totalCompletionTokens += delta.totalCompletionTokens;
|
|
106
|
+
current.totalOutputTokens += delta.totalOutputTokens;
|
|
107
|
+
map.set(period, current);
|
|
108
|
+
}
|
|
109
|
+
function trimPeriodMap(map, maxEntries) {
|
|
110
|
+
if (map.size <= maxEntries) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const keys = Array.from(map.keys()).sort((a, b) => a.localeCompare(b));
|
|
114
|
+
while (map.size > maxEntries && keys.length) {
|
|
115
|
+
const key = keys.shift();
|
|
116
|
+
if (key) {
|
|
117
|
+
map.delete(key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
39
121
|
function readTailLines(filePath, maxTailBytes, maxLines) {
|
|
40
122
|
let text = '';
|
|
41
123
|
const stat = fsSync.statSync(filePath);
|
|
@@ -84,12 +166,30 @@ export class StatsManager {
|
|
|
84
166
|
historicalSnapshotCount = 0;
|
|
85
167
|
historicalSampleCount = 0;
|
|
86
168
|
historicalLoaded = false;
|
|
169
|
+
dailyPeriods = new Map();
|
|
170
|
+
weeklyPeriods = new Map();
|
|
171
|
+
monthlyPeriods = new Map();
|
|
172
|
+
persistIntervalMs;
|
|
173
|
+
maxDailyPeriods;
|
|
174
|
+
maxWeeklyPeriods;
|
|
175
|
+
maxMonthlyPeriods;
|
|
176
|
+
periodicPersistTimer = null;
|
|
177
|
+
persistSeq = 0;
|
|
178
|
+
lastPeriodicSignature = '';
|
|
179
|
+
persistSessionId = `${process.pid}-${Date.now().toString(36)}-${Math.random()
|
|
180
|
+
.toString(36)
|
|
181
|
+
.slice(2, 8)}`;
|
|
87
182
|
constructor() {
|
|
88
183
|
this.enabled = isStatsEnabledByDefault();
|
|
89
184
|
this.verboseLogging = isStatsVerboseEnabled(this.enabled);
|
|
90
185
|
this.statsLogPath = this.resolveLogPath();
|
|
186
|
+
this.persistIntervalMs = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_PERSIST_INTERVAL_MS, process.env.RCC_STATS_PERSIST_INTERVAL_MS, DEFAULT_PERSIST_INTERVAL_MS);
|
|
187
|
+
this.maxDailyPeriods = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_DAILY_MAX_PERIODS, process.env.RCC_STATS_DAILY_MAX_PERIODS, DEFAULT_DAILY_PERIODS);
|
|
188
|
+
this.maxWeeklyPeriods = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_WEEKLY_MAX_PERIODS, process.env.RCC_STATS_WEEKLY_MAX_PERIODS, DEFAULT_WEEKLY_PERIODS);
|
|
189
|
+
this.maxMonthlyPeriods = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_MONTHLY_MAX_PERIODS, process.env.RCC_STATS_MONTHLY_MAX_PERIODS, DEFAULT_MONTHLY_PERIODS);
|
|
91
190
|
if (this.enabled) {
|
|
92
191
|
this.loadHistoricalFromDisk(this.statsLogPath, true);
|
|
192
|
+
this.startPeriodicPersistence();
|
|
93
193
|
}
|
|
94
194
|
}
|
|
95
195
|
recordRequestStart(requestId) {
|
|
@@ -247,16 +347,7 @@ export class StatsManager {
|
|
|
247
347
|
return snapshot;
|
|
248
348
|
}
|
|
249
349
|
this.ensureHistoricalLoaded();
|
|
250
|
-
|
|
251
|
-
snapshot,
|
|
252
|
-
historicalBuckets: this.historicalBuckets,
|
|
253
|
-
historicalToolAggregate: this.historicalToolAggregate,
|
|
254
|
-
historicalToolByProvider: this.historicalToolByProvider,
|
|
255
|
-
historicalSnapshotCount: this.historicalSnapshotCount,
|
|
256
|
-
historicalSampleCount: this.historicalSampleCount
|
|
257
|
-
});
|
|
258
|
-
this.historicalSnapshotCount = merged.historicalSnapshotCount;
|
|
259
|
-
this.historicalSampleCount = merged.historicalSampleCount;
|
|
350
|
+
this.mergeSnapshotIntoHistorical(snapshot);
|
|
260
351
|
if (!this.verboseLogging) {
|
|
261
352
|
return snapshot;
|
|
262
353
|
}
|
|
@@ -269,6 +360,42 @@ export class StatsManager {
|
|
|
269
360
|
logToolSummary(snapshot.tools, formatProviderLabel);
|
|
270
361
|
return snapshot;
|
|
271
362
|
}
|
|
363
|
+
logFinalSummary(uptimeMs) {
|
|
364
|
+
const session = this.snapshot(uptimeMs);
|
|
365
|
+
if (!this.enabled) {
|
|
366
|
+
return { session, historical: this.snapshotHistorical() };
|
|
367
|
+
}
|
|
368
|
+
this.ensureHistoricalLoaded();
|
|
369
|
+
this.mergeSnapshotIntoHistorical(session);
|
|
370
|
+
const historical = this.snapshotHistorical();
|
|
371
|
+
const sessionTotals = sumSnapshotTotals(session.totals);
|
|
372
|
+
const historicalTotals = sumSnapshotTotals(historical.totals);
|
|
373
|
+
const sessionRows = sortSummaryRows(session.totals);
|
|
374
|
+
const historicalRows = sortSummaryRows(historical.totals);
|
|
375
|
+
console.log('\n[Stats][final][session] calls=%d errors=%d tokens(prompt/completion/total)=%d/%d/%d uptimeMs=%d', sessionTotals.requestCount, sessionTotals.errorCount, sessionTotals.totalPromptTokens, sessionTotals.totalCompletionTokens, sessionTotals.totalOutputTokens, Math.round(session.uptimeMs));
|
|
376
|
+
if (!sessionRows.length) {
|
|
377
|
+
console.log('[Stats][final][session] providers: none');
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
console.log('[Stats][final][session] providers:');
|
|
381
|
+
for (const row of sessionRows) {
|
|
382
|
+
const providerLabel = formatProviderLabel(row.providerKey, row.model);
|
|
383
|
+
console.log(' - %s calls=%d tokens=%d/%d/%d', providerLabel, row.requestCount, row.totalPromptTokens, row.totalCompletionTokens, row.totalOutputTokens);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
console.log('\n[Stats][final][historical] calls=%d errors=%d tokens(prompt/completion/total)=%d/%d/%d snapshots=%d samples=%d', historicalTotals.requestCount, historicalTotals.errorCount, historicalTotals.totalPromptTokens, historicalTotals.totalCompletionTokens, historicalTotals.totalOutputTokens, historical.snapshotCount, historical.sampleCount);
|
|
387
|
+
if (!historicalRows.length) {
|
|
388
|
+
console.log('[Stats][final][historical] providers: none');
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
console.log('[Stats][final][historical] providers:');
|
|
392
|
+
for (const row of historicalRows) {
|
|
393
|
+
const providerLabel = formatProviderLabel(row.providerKey, row.model);
|
|
394
|
+
console.log(' - %s calls=%d tokens=%d/%d/%d', providerLabel, row.requestCount, row.totalPromptTokens, row.totalCompletionTokens, row.totalOutputTokens);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return { session, historical };
|
|
398
|
+
}
|
|
272
399
|
async persistSnapshot(snapshot, options) {
|
|
273
400
|
if (!this.enabled) {
|
|
274
401
|
return;
|
|
@@ -279,7 +406,10 @@ export class StatsManager {
|
|
|
279
406
|
const record = {
|
|
280
407
|
...snapshot,
|
|
281
408
|
reason: options?.reason ?? 'shutdown',
|
|
282
|
-
pid: process.pid
|
|
409
|
+
pid: process.pid,
|
|
410
|
+
sessionId: this.persistSessionId,
|
|
411
|
+
snapshotSeq: ++this.persistSeq,
|
|
412
|
+
persistedAt: Date.now()
|
|
283
413
|
};
|
|
284
414
|
await fs.appendFile(logPath, `${JSON.stringify(record)}\n`, 'utf-8');
|
|
285
415
|
}
|
|
@@ -318,12 +448,99 @@ export class StatsManager {
|
|
|
318
448
|
totals
|
|
319
449
|
};
|
|
320
450
|
}
|
|
451
|
+
snapshotHistoricalPeriods() {
|
|
452
|
+
if (!this.enabled) {
|
|
453
|
+
return { generatedAt: Date.now(), daily: [], weekly: [], monthly: [] };
|
|
454
|
+
}
|
|
455
|
+
this.ensureHistoricalLoaded();
|
|
456
|
+
const toRows = (map) => Array.from(map.entries())
|
|
457
|
+
.sort((a, b) => b[0].localeCompare(a[0]))
|
|
458
|
+
.map(([period, bucket]) => ({ period, ...bucket }));
|
|
459
|
+
return {
|
|
460
|
+
generatedAt: Date.now(),
|
|
461
|
+
daily: toRows(this.dailyPeriods),
|
|
462
|
+
weekly: toRows(this.weeklyPeriods),
|
|
463
|
+
monthly: toRows(this.monthlyPeriods)
|
|
464
|
+
};
|
|
465
|
+
}
|
|
321
466
|
ensureHistoricalLoaded() {
|
|
322
467
|
if (!this.enabled || this.historicalLoaded) {
|
|
323
468
|
return;
|
|
324
469
|
}
|
|
325
470
|
this.loadHistoricalFromDisk(this.statsLogPath, true);
|
|
326
471
|
}
|
|
472
|
+
startPeriodicPersistence() {
|
|
473
|
+
if (!this.enabled || this.persistIntervalMs <= 0) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
this.periodicPersistTimer = setInterval(() => {
|
|
477
|
+
void this.persistPeriodicSnapshot();
|
|
478
|
+
}, this.persistIntervalMs);
|
|
479
|
+
this.periodicPersistTimer.unref?.();
|
|
480
|
+
}
|
|
481
|
+
async persistPeriodicSnapshot() {
|
|
482
|
+
try {
|
|
483
|
+
const snapshot = this.snapshot(Math.round(process.uptime() * 1000));
|
|
484
|
+
if (!snapshot.totals.length) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const signature = this.buildSnapshotSignature(snapshot);
|
|
488
|
+
if (signature === this.lastPeriodicSignature) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
await this.persistSnapshot(snapshot, { reason: 'periodic' });
|
|
492
|
+
this.lastPeriodicSignature = signature;
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
// persistence must be best-effort
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
buildSnapshotSignature(snapshot) {
|
|
499
|
+
const totals = sumSnapshotTotals(snapshot.totals || []);
|
|
500
|
+
const toolCalls = typeof snapshot.tools?.totalCalls === 'number' ? snapshot.tools.totalCalls : 0;
|
|
501
|
+
const toolResponses = typeof snapshot.tools?.totalResponses === 'number' ? snapshot.tools.totalResponses : 0;
|
|
502
|
+
return [
|
|
503
|
+
totals.requestCount,
|
|
504
|
+
totals.errorCount,
|
|
505
|
+
totals.totalPromptTokens,
|
|
506
|
+
totals.totalCompletionTokens,
|
|
507
|
+
totals.totalOutputTokens,
|
|
508
|
+
toolCalls,
|
|
509
|
+
toolResponses
|
|
510
|
+
].join(':');
|
|
511
|
+
}
|
|
512
|
+
mergeSnapshotIntoPeriods(snapshot) {
|
|
513
|
+
const generatedAt = typeof snapshot.generatedAt === 'number' && Number.isFinite(snapshot.generatedAt)
|
|
514
|
+
? snapshot.generatedAt
|
|
515
|
+
: Date.now();
|
|
516
|
+
const totals = Array.isArray(snapshot.totals) ? snapshot.totals : [];
|
|
517
|
+
if (!totals.length) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const delta = sumSnapshotTotals(totals);
|
|
521
|
+
const day = toUtcDayKey(generatedAt);
|
|
522
|
+
const week = toUtcIsoWeekKey(generatedAt);
|
|
523
|
+
const month = toUtcMonthKey(generatedAt);
|
|
524
|
+
upsertPeriodBucket(this.dailyPeriods, day, delta);
|
|
525
|
+
upsertPeriodBucket(this.weeklyPeriods, week, delta);
|
|
526
|
+
upsertPeriodBucket(this.monthlyPeriods, month, delta);
|
|
527
|
+
trimPeriodMap(this.dailyPeriods, this.maxDailyPeriods);
|
|
528
|
+
trimPeriodMap(this.weeklyPeriods, this.maxWeeklyPeriods);
|
|
529
|
+
trimPeriodMap(this.monthlyPeriods, this.maxMonthlyPeriods);
|
|
530
|
+
}
|
|
531
|
+
mergeSnapshotIntoHistorical(snapshot) {
|
|
532
|
+
const merged = mergeSnapshotIntoHistorical({
|
|
533
|
+
snapshot,
|
|
534
|
+
historicalBuckets: this.historicalBuckets,
|
|
535
|
+
historicalToolAggregate: this.historicalToolAggregate,
|
|
536
|
+
historicalToolByProvider: this.historicalToolByProvider,
|
|
537
|
+
historicalSnapshotCount: this.historicalSnapshotCount,
|
|
538
|
+
historicalSampleCount: this.historicalSampleCount
|
|
539
|
+
});
|
|
540
|
+
this.historicalSnapshotCount = merged.historicalSnapshotCount;
|
|
541
|
+
this.historicalSampleCount = merged.historicalSampleCount;
|
|
542
|
+
this.mergeSnapshotIntoPeriods(snapshot);
|
|
543
|
+
}
|
|
327
544
|
loadHistoricalFromDisk(logPath, reset) {
|
|
328
545
|
if (reset) {
|
|
329
546
|
this.historicalBuckets.clear();
|
|
@@ -331,29 +548,60 @@ export class StatsManager {
|
|
|
331
548
|
this.historicalToolByProvider.clear();
|
|
332
549
|
this.historicalSnapshotCount = 0;
|
|
333
550
|
this.historicalSampleCount = 0;
|
|
551
|
+
this.dailyPeriods.clear();
|
|
552
|
+
this.weeklyPeriods.clear();
|
|
553
|
+
this.monthlyPeriods.clear();
|
|
334
554
|
}
|
|
335
555
|
try {
|
|
336
556
|
const maxTailBytes = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_HISTORY_MAX_TAIL_BYTES, process.env.RCC_STATS_HISTORY_MAX_TAIL_BYTES, DEFAULT_HISTORY_MAX_TAIL_BYTES);
|
|
337
557
|
const maxLines = resolvePositiveIntEnv(process.env.ROUTECODEX_STATS_HISTORY_MAX_LINES, process.env.RCC_STATS_HISTORY_MAX_LINES, DEFAULT_HISTORY_MAX_LINES);
|
|
338
558
|
const lines = readTailLines(logPath, maxTailBytes, maxLines);
|
|
559
|
+
const latestBySession = new Map();
|
|
560
|
+
const legacyRecords = [];
|
|
339
561
|
for (const line of lines) {
|
|
340
562
|
try {
|
|
341
563
|
const record = JSON.parse(line);
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
564
|
+
if (typeof record?.sessionId === 'string' &&
|
|
565
|
+
record.sessionId.trim() &&
|
|
566
|
+
typeof record?.snapshotSeq === 'number' &&
|
|
567
|
+
Number.isFinite(record.snapshotSeq)) {
|
|
568
|
+
const key = record.sessionId.trim();
|
|
569
|
+
const seq = Math.floor(record.snapshotSeq);
|
|
570
|
+
const existing = latestBySession.get(key);
|
|
571
|
+
if (!existing ||
|
|
572
|
+
seq > existing.snapshotSeq ||
|
|
573
|
+
(seq === existing.snapshotSeq &&
|
|
574
|
+
(typeof record.generatedAt === 'number' ? record.generatedAt : 0) >
|
|
575
|
+
(typeof existing.generatedAt === 'number' ? existing.generatedAt : 0))) {
|
|
576
|
+
latestBySession.set(key, { ...record, snapshotSeq: seq });
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
legacyRecords.push(record);
|
|
581
|
+
}
|
|
352
582
|
}
|
|
353
583
|
catch {
|
|
354
584
|
continue;
|
|
355
585
|
}
|
|
356
586
|
}
|
|
587
|
+
const dedupedRecords = [
|
|
588
|
+
...legacyRecords,
|
|
589
|
+
...Array.from(latestBySession.values())
|
|
590
|
+
].sort((a, b) => (typeof a.generatedAt === 'number' ? a.generatedAt : 0) -
|
|
591
|
+
(typeof b.generatedAt === 'number' ? b.generatedAt : 0));
|
|
592
|
+
for (const record of dedupedRecords) {
|
|
593
|
+
const merged = mergeSnapshotIntoHistorical({
|
|
594
|
+
snapshot: record,
|
|
595
|
+
historicalBuckets: this.historicalBuckets,
|
|
596
|
+
historicalToolAggregate: this.historicalToolAggregate,
|
|
597
|
+
historicalToolByProvider: this.historicalToolByProvider,
|
|
598
|
+
historicalSnapshotCount: this.historicalSnapshotCount,
|
|
599
|
+
historicalSampleCount: this.historicalSampleCount
|
|
600
|
+
});
|
|
601
|
+
this.historicalSnapshotCount = merged.historicalSnapshotCount;
|
|
602
|
+
this.historicalSampleCount = merged.historicalSampleCount;
|
|
603
|
+
this.mergeSnapshotIntoPeriods(record);
|
|
604
|
+
}
|
|
357
605
|
}
|
|
358
606
|
catch {
|
|
359
607
|
// File missing or unreadable -> treat as empty history.
|