@0xmaxma/claude-gateway 2.0.5 → 2.0.7
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 +14 -1
- package/dist/agent/builtin-commands.js +5 -5
- package/dist/agent/builtin-commands.js.map +1 -1
- package/dist/agent/command-help.d.ts +9 -0
- package/dist/agent/command-help.d.ts.map +1 -0
- package/dist/agent/command-help.js +50 -0
- package/dist/agent/command-help.js.map +1 -0
- package/dist/agent/dreaming/index.d.ts +6 -3
- package/dist/agent/dreaming/index.d.ts.map +1 -1
- package/dist/agent/dreaming/index.js +21 -1
- package/dist/agent/dreaming/index.js.map +1 -1
- package/dist/agent/knowledge/reflection.d.ts +7 -4
- package/dist/agent/knowledge/reflection.d.ts.map +1 -1
- package/dist/agent/knowledge/reflection.js +19 -1
- package/dist/agent/knowledge/reflection.js.map +1 -1
- package/dist/agent/runner.d.ts +51 -3
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +228 -107
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/session-compaction-scheduler.d.ts +22 -0
- package/dist/agent/session-compaction-scheduler.d.ts.map +1 -0
- package/dist/agent/session-compaction-scheduler.js +40 -0
- package/dist/agent/session-compaction-scheduler.js.map +1 -0
- package/dist/agent/session-confirmations.d.ts +12 -0
- package/dist/agent/session-confirmations.d.ts.map +1 -0
- package/dist/agent/session-confirmations.js +43 -0
- package/dist/agent/session-confirmations.js.map +1 -0
- package/dist/agent/session-status.d.ts +7 -0
- package/dist/agent/session-status.d.ts.map +1 -0
- package/dist/agent/session-status.js +16 -0
- package/dist/agent/session-status.js.map +1 -0
- package/dist/agent/skill-learning/index.d.ts +5 -1
- package/dist/agent/skill-learning/index.d.ts.map +1 -1
- package/dist/agent/skill-learning/index.js +23 -1
- package/dist/agent/skill-learning/index.js.map +1 -1
- package/dist/agent/skill-learning/notifier.d.ts +2 -1
- package/dist/agent/skill-learning/notifier.d.ts.map +1 -1
- package/dist/agent/skill-learning/notifier.js +1 -0
- package/dist/agent/skill-learning/notifier.js.map +1 -1
- package/dist/api/apps-router.d.ts.map +1 -1
- package/dist/api/apps-router.js +1 -3
- package/dist/api/apps-router.js.map +1 -1
- package/dist/api/cron-router.d.ts +1 -1
- package/dist/api/cron-router.d.ts.map +1 -1
- package/dist/api/cron-router.js +4 -4
- package/dist/api/cron-router.js.map +1 -1
- package/dist/api/dashboard-processes.d.ts +86 -0
- package/dist/api/dashboard-processes.d.ts.map +1 -0
- package/dist/api/dashboard-processes.js +155 -0
- package/dist/api/dashboard-processes.js.map +1 -0
- package/dist/api/dashboard-sessions.d.ts +15 -0
- package/dist/api/dashboard-sessions.d.ts.map +1 -0
- package/dist/api/dashboard-sessions.js +66 -0
- package/dist/api/dashboard-sessions.js.map +1 -0
- package/dist/api/gateway-router.d.ts +3 -4
- package/dist/api/gateway-router.d.ts.map +1 -1
- package/dist/api/gateway-router.js +177 -66
- package/dist/api/gateway-router.js.map +1 -1
- package/dist/api/memory-activity.d.ts +18 -0
- package/dist/api/memory-activity.d.ts.map +1 -0
- package/dist/api/memory-activity.js +97 -0
- package/dist/api/memory-activity.js.map +1 -0
- package/dist/api/oauth-connectors-router.d.ts +1 -1
- package/dist/api/oauth-connectors-router.d.ts.map +1 -1
- package/dist/api/oauth-connectors-router.js +11 -21
- package/dist/api/oauth-connectors-router.js.map +1 -1
- package/dist/api/router.d.ts +1 -1
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +3 -9
- package/dist/api/router.js.map +1 -1
- package/dist/api/share-router.d.ts +1 -1
- package/dist/api/share-router.d.ts.map +1 -1
- package/dist/api/share-router.js +1 -1
- package/dist/api/share-router.js.map +1 -1
- package/dist/api/slack-webhook-router.js +1 -1
- package/dist/api/slack-webhook-router.js.map +1 -1
- package/dist/api/voice-router.d.ts +1 -0
- package/dist/api/voice-router.d.ts.map +1 -1
- package/dist/api/voice-router.js +7 -0
- package/dist/api/voice-router.js.map +1 -1
- package/dist/apps/agent-container-migration.d.ts +2 -0
- package/dist/apps/agent-container-migration.d.ts.map +1 -1
- package/dist/apps/agent-container-migration.js +59 -2
- package/dist/apps/agent-container-migration.js.map +1 -1
- package/dist/apps/agent-manager.d.ts +4 -2
- package/dist/apps/agent-manager.d.ts.map +1 -1
- package/dist/apps/agent-manager.js +39 -3
- package/dist/apps/agent-manager.js.map +1 -1
- package/dist/apps/installer.d.ts +4 -3
- package/dist/apps/installer.d.ts.map +1 -1
- package/dist/apps/installer.js +8 -4
- package/dist/apps/installer.js.map +1 -1
- package/dist/build-provenance.json +8 -0
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands/app.d.ts.map +1 -1
- package/dist/cli/commands/app.js +39 -3
- package/dist/cli/commands/app.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +6 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/safemode.d.ts +2 -0
- package/dist/cli/commands/safemode.d.ts.map +1 -0
- package/dist/cli/commands/safemode.js +279 -0
- package/dist/cli/commands/safemode.js.map +1 -0
- package/dist/cli/dependencies.d.ts +2 -0
- package/dist/cli/dependencies.d.ts.map +1 -1
- package/dist/cli/dependencies.js +81 -0
- package/dist/cli/dependencies.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +11 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/manager.d.ts.map +1 -1
- package/dist/cli/manager.js +4 -1
- package/dist/cli/manager.js.map +1 -1
- package/dist/config/agent-lifecycle.d.ts +26 -0
- package/dist/config/agent-lifecycle.d.ts.map +1 -0
- package/dist/config/agent-lifecycle.js +63 -0
- package/dist/config/agent-lifecycle.js.map +1 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +11 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/reload-policy.d.ts +9 -0
- package/dist/config/reload-policy.d.ts.map +1 -0
- package/dist/config/reload-policy.js +62 -0
- package/dist/config/reload-policy.js.map +1 -0
- package/dist/config/watcher.d.ts +3 -2
- package/dist/config/watcher.d.ts.map +1 -1
- package/dist/config/watcher.js +34 -51
- package/dist/config/watcher.js.map +1 -1
- package/dist/cron/tool-schemas.d.ts +296 -0
- package/dist/cron/tool-schemas.d.ts.map +1 -0
- package/dist/cron/tool-schemas.js +122 -0
- package/dist/cron/tool-schemas.js.map +1 -0
- package/dist/index.js +141 -158
- package/dist/index.js.map +1 -1
- package/dist/orchestration/agent-tool-schemas.js +5 -5
- package/dist/orchestration/agent-tool-schemas.js.map +1 -1
- package/dist/orchestration/background-work.d.ts +9 -0
- package/dist/orchestration/background-work.d.ts.map +1 -0
- package/dist/orchestration/background-work.js +49 -0
- package/dist/orchestration/background-work.js.map +1 -0
- package/dist/orchestration/bridge.d.ts +6 -15
- package/dist/orchestration/bridge.d.ts.map +1 -1
- package/dist/orchestration/bridge.js +67 -32
- package/dist/orchestration/bridge.js.map +1 -1
- package/dist/orchestration/capabilities.d.ts.map +1 -1
- package/dist/orchestration/capabilities.js +18 -10
- package/dist/orchestration/capabilities.js.map +1 -1
- package/dist/orchestration/capacity.d.ts +3 -2
- package/dist/orchestration/capacity.d.ts.map +1 -1
- package/dist/orchestration/capacity.js +7 -0
- package/dist/orchestration/capacity.js.map +1 -1
- package/dist/orchestration/channel-controls.d.ts.map +1 -1
- package/dist/orchestration/channel-controls.js +3 -2
- package/dist/orchestration/channel-controls.js.map +1 -1
- package/dist/orchestration/cli-skills.d.ts +5 -0
- package/dist/orchestration/cli-skills.d.ts.map +1 -1
- package/dist/orchestration/compact-measurements.d.ts +21 -0
- package/dist/orchestration/compact-measurements.d.ts.map +1 -0
- package/dist/orchestration/compact-measurements.js +62 -0
- package/dist/orchestration/compact-measurements.js.map +1 -0
- package/dist/orchestration/config.d.ts +4 -0
- package/dist/orchestration/config.d.ts.map +1 -1
- package/dist/orchestration/config.js +1 -1
- package/dist/orchestration/config.js.map +1 -1
- package/dist/orchestration/container-tool-schemas.d.ts +37 -0
- package/dist/orchestration/container-tool-schemas.d.ts.map +1 -0
- package/dist/orchestration/container-tool-schemas.js +27 -0
- package/dist/orchestration/container-tool-schemas.js.map +1 -0
- package/dist/orchestration/container.d.ts.map +1 -1
- package/dist/orchestration/container.js +7 -0
- package/dist/orchestration/container.js.map +1 -1
- package/dist/orchestration/context-delivery.d.ts +32 -0
- package/dist/orchestration/context-delivery.d.ts.map +1 -0
- package/dist/orchestration/context-delivery.js +101 -0
- package/dist/orchestration/context-delivery.js.map +1 -0
- package/dist/orchestration/conversation-intake.d.ts +10 -6
- package/dist/orchestration/conversation-intake.d.ts.map +1 -1
- package/dist/orchestration/conversation-intake.js +22 -8
- package/dist/orchestration/conversation-intake.js.map +1 -1
- package/dist/orchestration/dashboard-charts.d.ts +32 -0
- package/dist/orchestration/dashboard-charts.d.ts.map +1 -0
- package/dist/orchestration/dashboard-charts.js +77 -0
- package/dist/orchestration/dashboard-charts.js.map +1 -0
- package/dist/orchestration/dashboard-reader-worker.js +28 -10
- package/dist/orchestration/dashboard-reader-worker.js.map +1 -1
- package/dist/orchestration/dashboard-reader.d.ts +1 -1
- package/dist/orchestration/dashboard-reader.d.ts.map +1 -1
- package/dist/orchestration/dashboard-reader.js +2 -2
- package/dist/orchestration/dashboard-reader.js.map +1 -1
- package/dist/orchestration/decision-context.d.ts +1 -1
- package/dist/orchestration/decision-context.d.ts.map +1 -1
- package/dist/orchestration/decision-context.js +3 -3
- package/dist/orchestration/decision-context.js.map +1 -1
- package/dist/orchestration/gateway-tasks/controller.d.ts +29 -0
- package/dist/orchestration/gateway-tasks/controller.d.ts.map +1 -0
- package/dist/orchestration/gateway-tasks/controller.js +139 -0
- package/dist/orchestration/gateway-tasks/controller.js.map +1 -0
- package/dist/orchestration/gateway-tasks/safemode.d.ts +19 -0
- package/dist/orchestration/gateway-tasks/safemode.d.ts.map +1 -0
- package/dist/orchestration/gateway-tasks/safemode.js +128 -0
- package/dist/orchestration/gateway-tasks/safemode.js.map +1 -0
- package/dist/orchestration/mutation-recovery.d.ts +3 -2
- package/dist/orchestration/mutation-recovery.d.ts.map +1 -1
- package/dist/orchestration/mutation-recovery.js +8 -0
- package/dist/orchestration/mutation-recovery.js.map +1 -1
- package/dist/orchestration/native-compact.d.ts +4 -1
- package/dist/orchestration/native-compact.d.ts.map +1 -1
- package/dist/orchestration/native-compact.js +6 -2
- package/dist/orchestration/native-compact.js.map +1 -1
- package/dist/orchestration/process-turn.d.ts +12 -2
- package/dist/orchestration/process-turn.d.ts.map +1 -1
- package/dist/orchestration/process-turn.js +48 -8
- package/dist/orchestration/process-turn.js.map +1 -1
- package/dist/orchestration/recovery.d.ts.map +1 -1
- package/dist/orchestration/recovery.js +4 -2
- package/dist/orchestration/recovery.js.map +1 -1
- package/dist/orchestration/runtime.d.ts +23 -1
- package/dist/orchestration/runtime.d.ts.map +1 -1
- package/dist/orchestration/runtime.js +191 -21
- package/dist/orchestration/runtime.js.map +1 -1
- package/dist/orchestration/session-compaction.d.ts +59 -0
- package/dist/orchestration/session-compaction.d.ts.map +1 -0
- package/dist/orchestration/session-compaction.js +212 -0
- package/dist/orchestration/session-compaction.js.map +1 -0
- package/dist/orchestration/skills.d.ts +2 -0
- package/dist/orchestration/skills.d.ts.map +1 -1
- package/dist/orchestration/skills.js +4 -3
- package/dist/orchestration/skills.js.map +1 -1
- package/dist/orchestration/task-controls.d.ts +12 -0
- package/dist/orchestration/task-controls.d.ts.map +1 -1
- package/dist/orchestration/task-controls.js +3 -1
- package/dist/orchestration/task-controls.js.map +1 -1
- package/dist/orchestration/tasks/driver.d.ts.map +1 -1
- package/dist/orchestration/tasks/driver.js +100 -13
- package/dist/orchestration/tasks/driver.js.map +1 -1
- package/dist/orchestration/tasks/pool.d.ts +2 -0
- package/dist/orchestration/tasks/pool.d.ts.map +1 -1
- package/dist/orchestration/tasks/pool.js +4 -0
- package/dist/orchestration/tasks/pool.js.map +1 -1
- package/dist/orchestration/tasks/scheduler.d.ts.map +1 -1
- package/dist/orchestration/tasks/scheduler.js +4 -0
- package/dist/orchestration/tasks/scheduler.js.map +1 -1
- package/dist/orchestration/tasks/service.d.ts +4 -0
- package/dist/orchestration/tasks/service.d.ts.map +1 -1
- package/dist/orchestration/tasks/service.js +38 -8
- package/dist/orchestration/tasks/service.js.map +1 -1
- package/dist/orchestration/token-ledger.d.ts +8 -0
- package/dist/orchestration/token-ledger.d.ts.map +1 -1
- package/dist/orchestration/token-ledger.js +7 -2
- package/dist/orchestration/token-ledger.js.map +1 -1
- package/dist/orchestration/token-usage.d.ts +3 -0
- package/dist/orchestration/token-usage.d.ts.map +1 -1
- package/dist/orchestration/token-usage.js +12 -3
- package/dist/orchestration/token-usage.js.map +1 -1
- package/dist/orchestration/types.d.ts +19 -1
- package/dist/orchestration/types.d.ts.map +1 -1
- package/dist/orchestration/types.js.map +1 -1
- package/dist/orchestration/worker-crons.d.ts +5 -0
- package/dist/orchestration/worker-crons.d.ts.map +1 -0
- package/dist/orchestration/worker-crons.js +84 -0
- package/dist/orchestration/worker-crons.js.map +1 -0
- package/dist/orchestration/worker-harness.d.ts +15 -0
- package/dist/orchestration/worker-harness.d.ts.map +1 -0
- package/dist/orchestration/worker-harness.js +72 -0
- package/dist/orchestration/worker-harness.js.map +1 -0
- package/dist/safemode/config.d.ts +7 -0
- package/dist/safemode/config.d.ts.map +1 -0
- package/dist/safemode/config.js +67 -0
- package/dist/safemode/config.js.map +1 -0
- package/dist/safemode/context.d.ts +7 -0
- package/dist/safemode/context.d.ts.map +1 -0
- package/dist/safemode/context.js +397 -0
- package/dist/safemode/context.js.map +1 -0
- package/dist/safemode/external-owners.d.ts +19 -0
- package/dist/safemode/external-owners.d.ts.map +1 -0
- package/dist/safemode/external-owners.js +229 -0
- package/dist/safemode/external-owners.js.map +1 -0
- package/dist/safemode/native.d.ts +38 -0
- package/dist/safemode/native.d.ts.map +1 -0
- package/dist/safemode/native.js +220 -0
- package/dist/safemode/native.js.map +1 -0
- package/dist/safemode/params.d.ts +10 -0
- package/dist/safemode/params.d.ts.map +1 -0
- package/dist/safemode/params.js +86 -0
- package/dist/safemode/params.js.map +1 -0
- package/dist/safemode/provenance.d.ts +45 -0
- package/dist/safemode/provenance.d.ts.map +1 -0
- package/dist/safemode/provenance.js +153 -0
- package/dist/safemode/provenance.js.map +1 -0
- package/dist/safemode/runner.d.ts +17 -0
- package/dist/safemode/runner.d.ts.map +1 -0
- package/dist/safemode/runner.js +398 -0
- package/dist/safemode/runner.js.map +1 -0
- package/dist/safemode/store.d.ts +56 -0
- package/dist/safemode/store.d.ts.map +1 -0
- package/dist/safemode/store.js +451 -0
- package/dist/safemode/store.js.map +1 -0
- package/dist/session/codex-auth.d.ts +37 -0
- package/dist/session/codex-auth.d.ts.map +1 -0
- package/dist/session/codex-auth.js +266 -0
- package/dist/session/codex-auth.js.map +1 -0
- package/dist/session/codex-container-runtime.d.ts +15 -0
- package/dist/session/codex-container-runtime.d.ts.map +1 -0
- package/dist/session/codex-container-runtime.js +85 -0
- package/dist/session/codex-container-runtime.js.map +1 -0
- package/dist/session/codex-context-defaults.json +5 -0
- package/dist/session/codex-context.d.ts +13 -0
- package/dist/session/codex-context.d.ts.map +1 -0
- package/dist/session/codex-context.js +27 -0
- package/dist/session/codex-context.js.map +1 -0
- package/dist/session/codex-extension-discovery.d.ts +21 -0
- package/dist/session/codex-extension-discovery.d.ts.map +1 -0
- package/dist/session/codex-extension-discovery.js +132 -0
- package/dist/session/codex-extension-discovery.js.map +1 -0
- package/dist/session/codex-native-mcp-client.d.ts +37 -0
- package/dist/session/codex-native-mcp-client.d.ts.map +1 -0
- package/dist/session/codex-native-mcp-client.js +164 -0
- package/dist/session/codex-native-mcp-client.js.map +1 -0
- package/dist/session/codex-policy.d.ts +6 -0
- package/dist/session/codex-policy.d.ts.map +1 -0
- package/dist/session/codex-policy.js +17 -0
- package/dist/session/codex-policy.js.map +1 -0
- package/dist/session/codex-process.d.ts +114 -0
- package/dist/session/codex-process.d.ts.map +1 -0
- package/dist/session/codex-process.js +759 -0
- package/dist/session/codex-process.js.map +1 -0
- package/dist/session/codex-runtime.d.ts +20 -0
- package/dist/session/codex-runtime.d.ts.map +1 -0
- package/dist/session/codex-runtime.js +182 -0
- package/dist/session/codex-runtime.js.map +1 -0
- package/dist/session/codex-tool-capture.d.ts +35 -0
- package/dist/session/codex-tool-capture.d.ts.map +1 -0
- package/dist/session/codex-tool-capture.js +178 -0
- package/dist/session/codex-tool-capture.js.map +1 -0
- package/dist/session/container-connectors.d.ts +10 -0
- package/dist/session/container-connectors.d.ts.map +1 -0
- package/dist/session/container-connectors.js +41 -0
- package/dist/session/container-connectors.js.map +1 -0
- package/dist/session/container-extensions.d.ts +4 -0
- package/dist/session/container-extensions.d.ts.map +1 -0
- package/dist/session/container-extensions.js +45 -0
- package/dist/session/container-extensions.js.map +1 -0
- package/dist/session/managed-connectors.d.ts +16 -0
- package/dist/session/managed-connectors.d.ts.map +1 -0
- package/dist/session/managed-connectors.js +25 -0
- package/dist/session/managed-connectors.js.map +1 -0
- package/dist/session/process-diagnostics.d.ts +14 -0
- package/dist/session/process-diagnostics.d.ts.map +1 -0
- package/dist/session/process-diagnostics.js +39 -0
- package/dist/session/process-diagnostics.js.map +1 -0
- package/dist/session/process.d.ts +4 -0
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +21 -16
- package/dist/session/process.js.map +1 -1
- package/dist/session/request-tool-capture.d.ts +1 -1
- package/dist/session/request-tool-capture.d.ts.map +1 -1
- package/dist/session/runtime-profile.d.ts +8 -0
- package/dist/session/runtime-profile.d.ts.map +1 -1
- package/dist/session/runtime-profile.js +3 -2
- package/dist/session/runtime-profile.js.map +1 -1
- package/dist/session/worker-environment.d.ts +5 -0
- package/dist/session/worker-environment.d.ts.map +1 -0
- package/dist/session/worker-environment.js +27 -0
- package/dist/session/worker-environment.js.map +1 -0
- package/dist/session/worker-extensions.d.ts +20 -0
- package/dist/session/worker-extensions.d.ts.map +1 -0
- package/dist/session/worker-extensions.js +322 -0
- package/dist/session/worker-extensions.js.map +1 -0
- package/dist/skills/loader.d.ts +2 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/codex-context.d.ts +4 -0
- package/dist/ui/codex-context.d.ts.map +1 -0
- package/dist/ui/codex-context.js +15 -0
- package/dist/ui/codex-context.js.map +1 -0
- package/dist/ui/dashboard-charts.d.ts +3 -0
- package/dist/ui/dashboard-charts.d.ts.map +1 -0
- package/dist/ui/dashboard-charts.js +130 -0
- package/dist/ui/dashboard-charts.js.map +1 -0
- package/dist/ui/dashboard-client.d.ts.map +1 -1
- package/dist/ui/dashboard-client.js +20 -21
- package/dist/ui/dashboard-client.js.map +1 -1
- package/dist/ui/dashboard-controls.d.ts +4 -0
- package/dist/ui/dashboard-controls.d.ts.map +1 -0
- package/dist/ui/dashboard-controls.js +27 -0
- package/dist/ui/dashboard-controls.js.map +1 -0
- package/dist/ui/dashboard-presentation.d.ts +4 -1
- package/dist/ui/dashboard-presentation.d.ts.map +1 -1
- package/dist/ui/dashboard-presentation.js +13 -7
- package/dist/ui/dashboard-presentation.js.map +1 -1
- package/dist/ui/dashboard-range.d.ts +3 -3
- package/dist/ui/dashboard-range.d.ts.map +1 -1
- package/dist/ui/dashboard-range.js +21 -5
- package/dist/ui/dashboard-range.js.map +1 -1
- package/dist/ui/dashboard-theme.d.ts +3 -1
- package/dist/ui/dashboard-theme.d.ts.map +1 -1
- package/dist/ui/dashboard-theme.js +80 -3
- package/dist/ui/dashboard-theme.js.map +1 -1
- package/dist/ui/memory-activity.d.ts +4 -0
- package/dist/ui/memory-activity.d.ts.map +1 -0
- package/dist/ui/memory-activity.js +115 -0
- package/dist/ui/memory-activity.js.map +1 -0
- package/dist/ui/token-report-client.d.ts +1 -1
- package/dist/ui/token-report-client.d.ts.map +1 -1
- package/dist/ui/token-report-client.js +1 -1
- package/dist/ui/token-report.d.ts +4 -0
- package/dist/ui/token-report.d.ts.map +1 -1
- package/dist/ui/token-report.js +38 -23
- package/dist/ui/token-report.js.map +1 -1
- package/dist/ui/web-ui.d.ts +1 -1
- package/dist/ui/web-ui.d.ts.map +1 -1
- package/dist/ui/web-ui.js +68 -370
- package/dist/ui/web-ui.js.map +1 -1
- package/mcp/capability-catalog.ts +2 -0
- package/mcp/extension-catalog.ts +18 -0
- package/mcp/lazy-connector.ts +4 -2
- package/mcp/lazy-tools.test.ts +29 -0
- package/mcp/modules.ts +1 -0
- package/mcp/server.ts +2 -2
- package/mcp/tools/cron/module.ts +8 -114
- package/mcp/tools/discord/commands.ts +4 -1
- package/mcp/tools/safemode/module.test.ts +29 -0
- package/mcp/tools/telegram/receiver-server.ts +33 -39
- package/mcp/tools/telegram/session-browser.ts +10 -0
- package/mcp/tools/telegram/task-detail.ts +2 -1
- package/package.json +3 -2
- package/scripts/orchestration/audit-codex-context.cjs +83 -0
- package/scripts/orchestration/benchmark-worker-harnesses.cjs +112 -0
- package/scripts/orchestration/smoke-codex-extensions.ts +29 -0
- package/scripts/orchestration/smoke-codex-worker.cjs +166 -0
- package/scripts/orchestration/smoke-safemode-codex.cjs +66 -0
package/mcp/lazy-connector.ts
CHANGED
|
@@ -10,15 +10,17 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
10
10
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
11
|
import { CallToolRequestSchema, ListToolsRequestSchema, ToolListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
12
12
|
import { createLazyToolCatalog, LAZY_TOOL_DEFINITIONS } from './lazy-tools';
|
|
13
|
+
import { CodexNativeClient } from '../dist/session/codex-native-mcp-client.js';
|
|
13
14
|
|
|
14
15
|
const config = JSON.parse(readFileSync(process.argv[2], 'utf8'));
|
|
15
|
-
const client = new Client({name:'gateway-lazy-connector',version:'1'});
|
|
16
|
+
const client: any = config.nativeCodex ? new CodexNativeClient(config.nativeCodex) : new Client({name:'gateway-lazy-connector',version:'1'});
|
|
16
17
|
const shutdown = new AbortController();
|
|
17
18
|
let connection: Promise<void> | undefined;
|
|
18
19
|
let catalog: ReturnType<typeof createLazyToolCatalog> | undefined;
|
|
19
20
|
let loading: Promise<ReturnType<typeof createLazyToolCatalog>> | undefined;
|
|
20
21
|
function connect(): Promise<void> {
|
|
21
22
|
if (!connection) connection = (async()=>{
|
|
23
|
+
if (config.nativeCodex) { await client.connect(); return; }
|
|
22
24
|
const transport = config.command ? new StdioClientTransport({command:config.command,args:config.args,env:{...process.env,...config.env},cwd:config.cwd,stderr:'inherit'})
|
|
23
25
|
: config.type === 'sse' ? new SSEClientTransport(new URL(config.url),{requestInit:{headers:config.headers}})
|
|
24
26
|
: new StreamableHTTPClientTransport(new URL(config.url),{requestInit:{headers:config.headers}});
|
|
@@ -35,7 +37,7 @@ async function discover() {
|
|
|
35
37
|
do {
|
|
36
38
|
if(++pages>500)throw Error('Connector catalog pagination exceeded page limit');
|
|
37
39
|
const page=await client.listTools(cursor?{cursor}:{},{timeout:10000,signal:shutdown.signal});
|
|
38
|
-
const pageTools=page.tools.map(t=>({...t,description:t.description??''}));
|
|
40
|
+
const pageTools=page.tools.filter(t => (!Array.isArray(config.enabled_tools) || config.enabled_tools.includes(t.name)) && !config.disabled_tools?.includes(t.name)).map(t=>({...t,description:t.description??''}));
|
|
39
41
|
bytes+=Buffer.byteLength(JSON.stringify(pageTools));
|
|
40
42
|
if(tools.length+pageTools.length>10000||bytes>8*1024*1024)throw Error('Connector catalog too large');
|
|
41
43
|
tools.push(...pageTools);
|
package/mcp/lazy-tools.test.ts
CHANGED
|
@@ -150,3 +150,32 @@ test('real lazy inventory preserves every execution schema and successful browse
|
|
|
150
150
|
local.stop(true); rmSync(dir, { recursive: true, force: true });
|
|
151
151
|
}
|
|
152
152
|
}, 15000);
|
|
153
|
+
|
|
154
|
+
test('cron tools survive module registration and lazy discovery, while privileged modules remain unavailable', async () => {
|
|
155
|
+
const dir = mkdtempSync(join(tmpdir(), 'cron-lazy-'));
|
|
156
|
+
const calls: string[] = [];
|
|
157
|
+
const bridge = Bun.serve({hostname:'127.0.0.1',port:0,async fetch(req) {
|
|
158
|
+
const body=await req.json(); calls.push(body.tool);
|
|
159
|
+
return Response.json(body.tool === 'cron_list' ? {jobs:[]} : {active:true});
|
|
160
|
+
}});
|
|
161
|
+
const ticket=join(dir,'ticket.json');writeFileSync(ticket,JSON.stringify({url:`http://127.0.0.1:${bridge.port}`,token:'fixture'}));
|
|
162
|
+
const client=new Client({name:'cron-test',version:'1'});
|
|
163
|
+
try{
|
|
164
|
+
await client.connect(new StdioClientTransport({command:'bun',args:[join(import.meta.dir,'server.ts')],stderr:'ignore',env:{PATH:process.env.PATH??'',HOME:dir,GATEWAY_AGENT_ID:'fixture',GATEWAY_WORKSPACE_DIR:dir,GATEWAY_ORCHESTRATION_ROLE:'worker',GATEWAY_ORCHESTRATION_MEDIA:'true',GATEWAY_ORCHESTRATION_CRON:'true',GATEWAY_ORCHESTRATION_TICKET_FILE:ticket,GATEWAY_LAZY_TOOLS:'true'}}));
|
|
165
|
+
const search=await client.callTool({name:'tool_search',arguments:{query:'cron'}});
|
|
166
|
+
expect(JSON.parse((search.content as any)[0].text).total).toBe(6);
|
|
167
|
+
const result=await client.callTool({name:'tool_call',arguments:{name:'cron_list',arguments:{}}});
|
|
168
|
+
expect(result.isError).not.toBe(true);expect(calls).toEqual(['task_validate','cron_list']);
|
|
169
|
+
for(const name of ['agent_create','install_app','skill_install','api_request','telegram_send_message']){
|
|
170
|
+
const denied=await client.callTool({name:'tool_call',arguments:{name,arguments:{}}});expect(denied.isError).toBe(true);
|
|
171
|
+
}
|
|
172
|
+
}finally{await client.close();bridge.stop(true);rmSync(dir,{recursive:true,force:true});}
|
|
173
|
+
},15000);
|
|
174
|
+
|
|
175
|
+
test('all registered worker modules follow the scoped execution policy',async()=>{
|
|
176
|
+
const {gatewayModules}=await import('./modules');
|
|
177
|
+
expect(gatewayModules('agent').map(m=>m.id)).toEqual(['memory','safemode']);
|
|
178
|
+
expect(gatewayModules('worker',true).map(m=>m.id)).toEqual(['memory','cron','image','video','share-file','browser']);
|
|
179
|
+
const standalone=gatewayModules().map(m=>m.id);
|
|
180
|
+
for(const id of ['cron','image','video','share-file','browser','skills','apps','agent','api','telegram','discord','line','slack','whatsapp','whatsapp_cloud','wechat'])expect(standalone).toContain(id);
|
|
181
|
+
});
|
package/mcp/modules.ts
CHANGED
package/mcp/server.ts
CHANGED
|
@@ -46,8 +46,8 @@ for (const mod of modules) {
|
|
|
46
46
|
if (!visible) continue;
|
|
47
47
|
|
|
48
48
|
for (const tool of mod.getTools()) {
|
|
49
|
-
if (ORCHESTRATION_ROLE && !['memory_search', 'memory_get'].includes(tool.name) && !(ORCHESTRATION_ROLE === 'worker' &&
|
|
50
|
-
((mod.id === 'image' || mod.id === 'video' || mod.id === 'share-file' || mod.id === 'browser') || (mod.id === 'memory' && process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true')))) continue;
|
|
49
|
+
if (ORCHESTRATION_ROLE && !(ORCHESTRATION_ROLE === 'agent' && mod.id === 'safemode') && !['memory_search', 'memory_get'].includes(tool.name) && !(ORCHESTRATION_ROLE === 'worker' &&
|
|
50
|
+
((mod.id === 'cron' || mod.id === 'image' || mod.id === 'video' || mod.id === 'share-file' || mod.id === 'browser') || (mod.id === 'memory' && process.env.GATEWAY_ORCHESTRATION_WRITE_MEMORY === 'true')))) continue;
|
|
51
51
|
toolMap.set(tool.name, mod);
|
|
52
52
|
visibleTools.push(tool);
|
|
53
53
|
}
|
package/mcp/tools/cron/module.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { CRON_TOOLS } from '../../../dist/cron/tool-schemas.js';
|
|
2
|
+
import { callTaskBridge } from '../tasks/module';
|
|
1
3
|
/**
|
|
2
4
|
* Cron tool module — implements ToolModule interface.
|
|
3
5
|
* Provides cron job management tools via the gateway REST API.
|
|
@@ -21,7 +23,7 @@ export class CronModule implements ToolModule {
|
|
|
21
23
|
private client: CronClient | null = null;
|
|
22
24
|
|
|
23
25
|
isEnabled(): boolean {
|
|
24
|
-
return Boolean(process.env.GATEWAY_API_URL && process.env.GATEWAY_AGENT_ID);
|
|
26
|
+
return Boolean((process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker' && process.env.GATEWAY_ORCHESTRATION_CRON === 'true' && process.env.GATEWAY_ORCHESTRATION_TICKET_FILE) || (process.env.GATEWAY_API_URL && process.env.GATEWAY_AGENT_ID));
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
private getClient(): CronClient {
|
|
@@ -35,121 +37,13 @@ export class CronModule implements ToolModule {
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
getTools(): McpToolDefinition[] {
|
|
38
|
-
return
|
|
39
|
-
{
|
|
40
|
-
name: 'cron_list',
|
|
41
|
-
description: 'List scheduled cron jobs for this agent',
|
|
42
|
-
inputSchema: {
|
|
43
|
-
type: 'object',
|
|
44
|
-
properties: {},
|
|
45
|
-
additionalProperties: false,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: 'cron_create',
|
|
50
|
-
description: 'Create a new cron job',
|
|
51
|
-
inputSchema: {
|
|
52
|
-
type: 'object',
|
|
53
|
-
properties: {
|
|
54
|
-
name: { type: 'string', description: 'Job name' },
|
|
55
|
-
schedule: { type: 'string', description: '5-field cron expression' },
|
|
56
|
-
type: { type: 'string', enum: ['command', 'agent'], description: 'Job type' },
|
|
57
|
-
command: { type: 'string', description: 'Shell command (type=command)' },
|
|
58
|
-
prompt: { type: 'string', description: 'Agent prompt (type=agent)' },
|
|
59
|
-
telegram: { type: 'string', description: 'Telegram chat_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
|
|
60
|
-
discord: { type: 'string', description: 'Discord channel_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
|
|
61
|
-
timeout_ms: { type: 'number', description: 'Timeout in milliseconds' },
|
|
62
|
-
scheduleKind: {
|
|
63
|
-
type: 'string',
|
|
64
|
-
enum: ['cron', 'at'],
|
|
65
|
-
description: 'Schedule type: "cron" for recurring (default), "at" for one-shot at a specific ISO datetime',
|
|
66
|
-
},
|
|
67
|
-
scheduleAt: {
|
|
68
|
-
type: 'string',
|
|
69
|
-
description: 'ISO 8601 datetime for one-shot execution (required when scheduleKind=at)',
|
|
70
|
-
},
|
|
71
|
-
deleteAfterRun: {
|
|
72
|
-
type: 'boolean',
|
|
73
|
-
description: 'Delete the job after it runs once. Defaults to true for scheduleKind=at, false for cron',
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
required: ['name', 'type'],
|
|
77
|
-
additionalProperties: false,
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
name: 'cron_delete',
|
|
82
|
-
description: 'Delete a cron job by ID',
|
|
83
|
-
inputSchema: {
|
|
84
|
-
type: 'object',
|
|
85
|
-
properties: {
|
|
86
|
-
job_id: { type: 'string', description: 'Job ID to delete' },
|
|
87
|
-
},
|
|
88
|
-
required: ['job_id'],
|
|
89
|
-
additionalProperties: false,
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'cron_update',
|
|
94
|
-
description: 'Update an existing cron job. Provide job_id plus only the fields to change.',
|
|
95
|
-
inputSchema: {
|
|
96
|
-
type: 'object',
|
|
97
|
-
properties: {
|
|
98
|
-
job_id: { type: 'string', description: 'ID of the job to update' },
|
|
99
|
-
name: { type: 'string', description: 'Job name' },
|
|
100
|
-
schedule: { type: 'string', description: '5-field cron expression' },
|
|
101
|
-
type: { type: 'string', enum: ['command', 'agent'], description: 'Job type' },
|
|
102
|
-
command: { type: 'string', description: 'Shell command (type=command)' },
|
|
103
|
-
prompt: { type: 'string', description: 'Agent prompt (type=agent)' },
|
|
104
|
-
telegram: { type: 'string', description: 'Telegram chat_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
|
|
105
|
-
discord: { type: 'string', description: 'Discord channel_id for delivery — full response on success (type=agent), or a short failure notice on error (any type)' },
|
|
106
|
-
timeout_ms: { type: 'number', description: 'Timeout in milliseconds' },
|
|
107
|
-
scheduleKind: {
|
|
108
|
-
type: 'string',
|
|
109
|
-
enum: ['cron', 'at'],
|
|
110
|
-
description: 'Schedule type: "cron" for recurring, "at" for one-shot at a specific ISO datetime',
|
|
111
|
-
},
|
|
112
|
-
scheduleAt: {
|
|
113
|
-
type: 'string',
|
|
114
|
-
description: 'ISO 8601 datetime for one-shot execution (required when scheduleKind=at)',
|
|
115
|
-
},
|
|
116
|
-
deleteAfterRun: {
|
|
117
|
-
type: 'boolean',
|
|
118
|
-
description: 'Delete the job after it runs once',
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
required: ['job_id'],
|
|
122
|
-
additionalProperties: false,
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
name: 'cron_run',
|
|
127
|
-
description: 'Run a cron job immediately',
|
|
128
|
-
inputSchema: {
|
|
129
|
-
type: 'object',
|
|
130
|
-
properties: {
|
|
131
|
-
job_id: { type: 'string', description: 'Job ID to run' },
|
|
132
|
-
},
|
|
133
|
-
required: ['job_id'],
|
|
134
|
-
additionalProperties: false,
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: 'cron_get_runs',
|
|
139
|
-
description: 'Get run history for a cron job',
|
|
140
|
-
inputSchema: {
|
|
141
|
-
type: 'object',
|
|
142
|
-
properties: {
|
|
143
|
-
job_id: { type: 'string', description: 'Job ID' },
|
|
144
|
-
},
|
|
145
|
-
required: ['job_id'],
|
|
146
|
-
additionalProperties: false,
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
];
|
|
40
|
+
return CRON_TOOLS;
|
|
150
41
|
}
|
|
151
42
|
|
|
152
|
-
async handleTool(name: string, args: Record<string, unknown
|
|
43
|
+
async handleTool(name: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<McpToolResult> {
|
|
44
|
+
if (process.env.GATEWAY_ORCHESTRATION_ROLE === 'worker') {
|
|
45
|
+
return callTaskBridge(name, args, crypto.randomUUID(), signal ?? new AbortController().signal);
|
|
46
|
+
}
|
|
153
47
|
const client = this.getClient();
|
|
154
48
|
|
|
155
49
|
try {
|
|
@@ -13,6 +13,10 @@ export const SLASH_COMMANDS: SlashCommandDef[] = [
|
|
|
13
13
|
},
|
|
14
14
|
{ name: 'clear', description: 'Reset model context without deleting chat history' },
|
|
15
15
|
{ name: 'compact', description: 'Compact Claude Code context without changing chat history' },
|
|
16
|
+
{ name: 'help', description: 'Show all supported commands' },
|
|
17
|
+
{ name: 'restart', description: 'Restart the session process after confirmation' },
|
|
18
|
+
{ name: 'sessions', description: 'List sessions' },
|
|
19
|
+
{ name: 'models', description: 'List and select a model' },
|
|
16
20
|
{ name: 'session', description: 'Show current session info' },
|
|
17
21
|
{
|
|
18
22
|
name: 'new',
|
|
@@ -32,7 +36,6 @@ export function commandDefinitions(orchestration:boolean,interactive:boolean):Sl
|
|
|
32
36
|
{name:'voice',description:'Turn automatic voice replies on or off',options:[{name:'mode',description:'on or off (omit to show buttons)',required:false,type:'STRING' as const}]},
|
|
33
37
|
{name:'voices',description:'Choose the agent voice'},
|
|
34
38
|
{name:'tasks',description:'View pending tasks in this conversation'},
|
|
35
|
-
{name:'help',description:'Show available orchestration controls'},
|
|
36
39
|
] : []),
|
|
37
40
|
{name:'stop',description:orchestration?'Stop a response or choose a task to stop':'Stop the agent response'},
|
|
38
41
|
...(interactive && !orchestration ? [{name:'cli',description:'Open the live terminal viewer'}] : []),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
|
+
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
test('real MCP never loads legacy safemode schemas for agents or workers', async () => {
|
|
8
|
+
const directory = mkdtempSync(join(tmpdir(), 'safemode-mcp-'));
|
|
9
|
+
const calls: Array<{ tool: string; args: unknown }> = [];
|
|
10
|
+
let allow = false;
|
|
11
|
+
const bridge = Bun.serve({ hostname: '127.0.0.1', port: 0, async fetch(req) {
|
|
12
|
+
calls.push(await req.json()); return allow ? Response.json({ allowed: true }) : new Response('ACCESS_DENIED', { status: 403 });
|
|
13
|
+
} });
|
|
14
|
+
const ticket = join(directory, 'ticket.json');
|
|
15
|
+
writeFileSync(ticket, JSON.stringify({ url: `http://127.0.0.1:${bridge.port}`, token: 'synthetic-test' }));
|
|
16
|
+
const clients: Client[] = [];
|
|
17
|
+
try {
|
|
18
|
+
for (const [role, permittedTools] of [['agent',true],['agent',false],['worker',true]] as const) {
|
|
19
|
+
const client = new Client({ name: 'safemode-test', version: '1' }); clients.push(client);
|
|
20
|
+
await client.connect(new StdioClientTransport({ command: 'bun', args: [join(import.meta.dir, '../../server.ts')], stderr: 'ignore', env: {
|
|
21
|
+
PATH: process.env.PATH ?? '', HOME: directory, GATEWAY_ORCHESTRATION_ROLE: role, GATEWAY_SAFEMODE_ALLOWED: permittedTools ? 'true' : '', GATEWAY_ORCHESTRATION_TICKET_FILE: ticket,
|
|
22
|
+
} }));
|
|
23
|
+
const listed = (await client.listTools()).tools.filter(tool => tool.name.startsWith('safemode_'));
|
|
24
|
+
expect(listed).toEqual([]);
|
|
25
|
+
expect((await client.callTool({name:'safemode_list',arguments:{}})).isError).toBe(true);
|
|
26
|
+
}
|
|
27
|
+
expect(calls).toHaveLength(0);
|
|
28
|
+
} finally { for (const client of clients) await client.close(); bridge.stop(true); rmSync(directory, { recursive: true, force: true }); }
|
|
29
|
+
}, 15000);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { commandHelp } from '../../../dist/agent/command-help.js';
|
|
3
|
+
import { parseSessionInfo } from './session-browser';
|
|
2
4
|
/**
|
|
3
5
|
* Telegram channel for Claude Gateway.
|
|
4
6
|
*
|
|
@@ -1161,28 +1163,7 @@ bot.command('start', async ctx => {
|
|
|
1161
1163
|
|
|
1162
1164
|
bot.command('help', async ctx => {
|
|
1163
1165
|
if (ctx.chat?.type !== 'private') return
|
|
1164
|
-
await ctx.reply(
|
|
1165
|
-
`Messages you send here route to a paired Claude Code session. ` +
|
|
1166
|
-
`Text and photos are forwarded; replies and reactions come back.\n\n` +
|
|
1167
|
-
`*Session management*\n` +
|
|
1168
|
-
`/session — show current session info\n` +
|
|
1169
|
-
`/sessions — list and switch between sessions\n` +
|
|
1170
|
-
`/new <name> — create a new session\n` +
|
|
1171
|
-
`/rename <name> — rename current session\n` +
|
|
1172
|
-
`/clear — reset context; keep chat history\n` +
|
|
1173
|
-
`/compact — compact Claude Code context; keep chat history\n` +
|
|
1174
|
-
(ORCHESTRATION_ENABLED ? `/stop — stop the reply and choose a task to cancel\n` : `/stop — interrupt the running turn\n`) +
|
|
1175
|
-
`/restart — graceful restart session\n\n` +
|
|
1176
|
-
`*Agent*\n` +
|
|
1177
|
-
`/model — show current AI model\n` +
|
|
1178
|
-
`/models — switch AI model\n` +
|
|
1179
|
-
(ORCHESTRATION_ENABLED ? `/tasks — view pending tasks in this chat\n/voice — turn automatic voice replies on/off (default off)\n/voices — choose the agent voice\n` : '') +
|
|
1180
|
-
(INTERACTIVE_CLI_ENABLED ? `/cli — open the live terminal viewer\n\n` : '\n') +
|
|
1181
|
-
`*Account*\n` +
|
|
1182
|
-
`/start — pairing instructions\n` +
|
|
1183
|
-
`/status — check your pairing state`,
|
|
1184
|
-
{ parse_mode: 'Markdown' }
|
|
1185
|
-
)
|
|
1166
|
+
await ctx.reply(commandHelp('telegram', ORCHESTRATION_ENABLED, INTERACTIVE_CLI_ENABLED))
|
|
1186
1167
|
})
|
|
1187
1168
|
|
|
1188
1169
|
bot.command('status', async ctx => {
|
|
@@ -1514,24 +1495,37 @@ bot.command('voice', async ctx => {
|
|
|
1514
1495
|
} catch { await ctx.reply('Voice settings are unavailable. Check the agent TTS configuration.') }
|
|
1515
1496
|
})
|
|
1516
1497
|
|
|
1517
|
-
//
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
const
|
|
1526
|
-
method:
|
|
1527
|
-
|
|
1528
|
-
body: JSON.stringify({ command: 'session_info', chat_id: String(ctx.chat.id) }),
|
|
1498
|
+
// Reuse the /tasks live-message lifecycle: serialize reads/replacement, edit only
|
|
1499
|
+
// changes, persist the last message across restart, and honor Telegram backoff.
|
|
1500
|
+
const SESSION_BROWSER_FILE = join(STATE_DIR, 'session-browser.json')
|
|
1501
|
+
let restoredSessionBrowsers: TaskBrowserMessage[] = []
|
|
1502
|
+
try { const saved = JSON.parse(readFileSync(SESSION_BROWSER_FILE, 'utf8')); if (Array.isArray(saved)) restoredSessionBrowsers = saved } catch {}
|
|
1503
|
+
const liveSessionBrowser = new LiveTaskBrowser({
|
|
1504
|
+
read: async (chat) => {
|
|
1505
|
+
if (!CALLBACK_URL_BASE) throw new Error('not_configured')
|
|
1506
|
+
const response = await fetch(CALLBACK_URL_BASE + '/command', {
|
|
1507
|
+
method:'POST', headers:{'Content-Type':'application/json'}, signal:AbortSignal.timeout(10000),
|
|
1508
|
+
body:JSON.stringify({command:'session_info',chat_id:chat}),
|
|
1529
1509
|
})
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
}
|
|
1510
|
+
return parseSessionInfo(response.ok, await response.json())
|
|
1511
|
+
},
|
|
1512
|
+
render: result => ({text:(result as {sessionId:string;text:string}).text,reply_markup:{inline_keyboard:[]}}),
|
|
1513
|
+
send: async (chat,menu) => (await bot.api.sendMessage(chat,menu.text,{parse_mode:'HTML'})).message_id,
|
|
1514
|
+
edit: (chat,id,menu) => bot.api.editMessageText(chat,id,menu.text,{parse_mode:'HTML'}),
|
|
1515
|
+
remove: (chat,id) => bot.api.deleteMessage(chat,id),
|
|
1516
|
+
close: (chat,id) => bot.api.editMessageText(chat,id,'Session view closed.'),
|
|
1517
|
+
allowed: (chat,user) => chat === user && loadAccess().allowFrom.includes(user),
|
|
1518
|
+
persist: entries => {
|
|
1519
|
+
mkdirSync(STATE_DIR,{recursive:true,mode:0o700})
|
|
1520
|
+
const temp=SESSION_BROWSER_FILE+'.tmp'
|
|
1521
|
+
writeFileSync(temp,JSON.stringify(entries),{mode:0o600});renameSync(temp,SESSION_BROWSER_FILE)
|
|
1522
|
+
},
|
|
1523
|
+
},restoredSessionBrowsers)
|
|
1524
|
+
setInterval(()=>{void liveSessionBrowser.tick().catch(()=>{})},3000).unref()
|
|
1525
|
+
bot.command('session',async ctx=>{
|
|
1526
|
+
if(ctx.chat?.type!=='private'||!isCallbackAuthorized(ctx))return
|
|
1527
|
+
try{await liveSessionBrowser.open(String(ctx.chat.id),String(ctx.from!.id))}
|
|
1528
|
+
catch{await ctx.reply('Could not load session info. Please try /session again.')}
|
|
1535
1529
|
})
|
|
1536
1530
|
|
|
1537
1531
|
// /sessions — list sessions with inline keyboard for switching/deleting
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A successful empty session is a status, not a transport failure. The empty
|
|
2
|
+
* ID binds its live message until a real session appears, when it is retired. */
|
|
3
|
+
export function parseSessionInfo(ok: boolean, value: unknown): { sessionId: string; text: string } {
|
|
4
|
+
const result = value as { success?: unknown; sessionId?: unknown; text?: unknown } | null;
|
|
5
|
+
if (!ok || result?.success !== true || typeof result.text !== 'string' ||
|
|
6
|
+
!(result.sessionId === null || (typeof result.sessionId === 'string' && result.sessionId.length > 0))) {
|
|
7
|
+
throw new Error('Session info unavailable');
|
|
8
|
+
}
|
|
9
|
+
return { sessionId: result.sessionId ?? '', text: result.text };
|
|
10
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { ProcessSample } from '../../../src/orchestration/process-activity'
|
|
|
4
4
|
import type { ToolOutcome } from '../../../src/orchestration/execution-observation';
|
|
5
5
|
|
|
6
6
|
export interface TaskDetail {
|
|
7
|
+
harness?: 'claude' | 'codex';
|
|
7
8
|
title: string; state: string; startedAt?: number; finishedAt?: number;
|
|
8
9
|
timing?: Partial<Record<'working' | 'tool' | 'input' | 'queued' | 'other' | 'finished', number>>;
|
|
9
10
|
timingMeasuredFrom?: number;
|
|
@@ -28,7 +29,7 @@ export function formatTaskDetail(task: TaskDetail, label: string): string {
|
|
|
28
29
|
const lastTool = activity?.lastTool;
|
|
29
30
|
const diagnostics = [counters, lastTool ? `Last tool: ${lastTool.name} · ${lastTool.status === 'error' ? 'Reported error' : 'Result received'}${lastTool.exitCode === undefined ? '' : ` · Exit code: ${lastTool.exitCode}`}\nReported at: ${new Date(lastTool.observedAt).toISOString().replace('T',' ').replace(/\.\d{3}Z$/, ' UTC')}` : '', activity?.observationStatus ?? activity?.status, activity?.quiet ? 'No recent tool/model progress; task retained for inspection or cancellation.' : ''].filter(Boolean);
|
|
30
31
|
return [
|
|
31
|
-
`${task.title}\n${label} · Elapsed: ${formatTaskElapsed(task.startedAt,task.finishedAt)}`,
|
|
32
|
+
`${task.title}\n${label} · Elapsed: ${formatTaskElapsed(task.startedAt,task.finishedAt)}${task.harness ? `\nHarness: ${task.harness === 'codex' ? 'Codex' : 'Claude Code'}` : ''}`,
|
|
32
33
|
formatTiming(task.timing) ? 'Time breakdown\n' + formatTiming(task.timing) + (task.timingMeasuredFrom && task.startedAt && task.timingMeasuredFrom > task.startedAt + 1000 ? '\nMeasured since ' + new Date(task.timingMeasuredFrom).toISOString() : '') : '',
|
|
33
34
|
progressLines.length ? `Progress\n${progressLines.join('\n')}` : '',
|
|
34
35
|
diagnostics.length ? `Diagnostics\n${diagnostics.join('\n')}` : '',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xmaxma/claude-gateway",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"description": "Multi-agent gateway for Claude",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
|
-
"build": "tsc",
|
|
31
|
+
"build": "tsc && node scripts/write-build-provenance.cjs",
|
|
32
32
|
"start": "node --no-warnings=ExperimentalWarning --env-file-if-exists=.env dist/entry.js gateway start",
|
|
33
33
|
"postinstall": "if command -v bun >/dev/null 2>&1; then bun install --cwd mcp; else echo 'Warning: bun not found. Run `cd mcp && bun install` manually to enable MCP tools.'; fi",
|
|
34
34
|
"pretest": "npm run build",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"pino": "^10.3.1",
|
|
62
62
|
"qrcode": "^1.5.4",
|
|
63
63
|
"sharp": "^0.35.4",
|
|
64
|
+
"smol-toml": "^1.8.0",
|
|
64
65
|
"ws": "^8.21.0"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Measure native CLI context metadata with a local Responses fixture, without model billing.
|
|
3
|
+
// This does NOT certify that an upstream provider accepts requests of that size.
|
|
4
|
+
require('ts-node/register/transpile-only');
|
|
5
|
+
const {CodexProcess}=require('../../src/session/codex-process');
|
|
6
|
+
const {resolveCodexRuntime}=require('../../src/session/codex-runtime');
|
|
7
|
+
const {resolveWorkerHarness}=require('../../src/orchestration/worker-harness');
|
|
8
|
+
const fs=require('fs/promises'),path=require('path'),os=require('os'),http=require('http');
|
|
9
|
+
const {execFileSync}=require('child_process'),{once}=require('events');
|
|
10
|
+
const args=process.argv.slice(2);
|
|
11
|
+
function option(name){const i=args.indexOf(name);return i<0?undefined:args[i+1];}
|
|
12
|
+
(async()=>{
|
|
13
|
+
const runtime=resolveCodexRuntime();
|
|
14
|
+
const catalog=option('--catalog-json')?JSON.parse(await fs.readFile(option('--catalog-json'),'utf8')).models:JSON.parse(execFileSync(runtime.executable,['debug','models','--bundled'],{encoding:'utf8',timeout:15000,maxBuffer:8*1024*1024})).models;
|
|
15
|
+
const supplied=option('--models-json')?JSON.parse(await fs.readFile(option('--models-json'),'utf8')):[];
|
|
16
|
+
const selected=new Map([...catalog.filter(m=>m.slug.includes('gpt')).map(m=>[m.slug,{id:m.slug}]),...supplied.map(m=>[m.id,m])]);
|
|
17
|
+
const directory=await fs.mkdtemp(path.join(os.tmpdir(),'gateway-context-audit-'));
|
|
18
|
+
const previous=process.env.GATEWAY_CONTEXT_AUDIT_KEY;
|
|
19
|
+
process.env.GATEWAY_CONTEXT_AUDIT_KEY='local-fixture-only';
|
|
20
|
+
const sockets=new Set(),adapters=new Set(),rows=[];
|
|
21
|
+
const server=http.createServer(async(req,res)=>{
|
|
22
|
+
try{
|
|
23
|
+
let raw='';for await(const chunk of req){raw+=chunk;if(raw.length>4*1024*1024)throw Error('Fixture request too large');}
|
|
24
|
+
const body=JSON.parse(raw),id='resp_fixture',item={type:'message',id:'msg_fixture',role:'assistant',phase:'final_answer',status:'completed',content:[{type:'output_text',text:'Context audit fixture complete.',annotations:[]}]};
|
|
25
|
+
const response={id,object:'response',created_at:Math.floor(Date.now()/1000),status:'completed',model:body.model,output:[item],usage:{input_tokens:100,input_tokens_details:{cached_tokens:0},output_tokens:5,total_tokens:105}};
|
|
26
|
+
res.writeHead(200,{'content-type':'text/event-stream'});
|
|
27
|
+
const emit=(type,payload)=>res.write('event: '+type+'\ndata: '+JSON.stringify({type,...payload})+'\n\n');
|
|
28
|
+
emit('response.created',{response:{...response,status:'in_progress',output:[]}});
|
|
29
|
+
emit('response.output_item.added',{output_index:0,item:{...item,status:'in_progress',content:[]}});
|
|
30
|
+
emit('response.content_part.added',{item_id:item.id,output_index:0,content_index:0,part:{type:'output_text',text:'',annotations:[]}});
|
|
31
|
+
emit('response.output_text.delta',{item_id:item.id,output_index:0,content_index:0,delta:item.content[0].text});
|
|
32
|
+
emit('response.output_text.done',{item_id:item.id,output_index:0,content_index:0,text:item.content[0].text});
|
|
33
|
+
emit('response.content_part.done',{item_id:item.id,output_index:0,content_index:0,part:item.content[0]});
|
|
34
|
+
emit('response.output_item.done',{output_index:0,item});
|
|
35
|
+
emit('response.completed',{response});res.end();
|
|
36
|
+
}catch(error){res.destroy(error);}
|
|
37
|
+
});
|
|
38
|
+
server.on('connection',socket=>{sockets.add(socket);socket.on('close',()=>sockets.delete(socket));});
|
|
39
|
+
try{
|
|
40
|
+
server.listen(0,'127.0.0.1');await once(server,'listening');
|
|
41
|
+
await fs.writeFile(path.join(directory,'mcp.json'),'{"mcpServers":{}}');
|
|
42
|
+
let index=0;
|
|
43
|
+
async function runNext(){
|
|
44
|
+
while(index<selected.size){
|
|
45
|
+
const record=[...selected.values()][index++],model=record.workerModel||record.id.replace(/\[(?:1m|200k)\]$/i,'');
|
|
46
|
+
const row={selection:record.id,nativeModel:model,advertisedGatewayWindow:record.contextWindow??null,requested:1000000};
|
|
47
|
+
const known=catalog.find(m=>m.slug===model);
|
|
48
|
+
row.catalog=known?{default:known.context_window,max:known.max_context_window,usablePercent:known.effective_context_window_percent}:null;
|
|
49
|
+
row.autoHarness=resolveWorkerHarness({workers:{harness:'auto'}},{gateway:{models:record.workerHarness?[record]:[]}},record.id).harness;
|
|
50
|
+
const adapter=new CodexProcess({agent:{workspace:directory},gateway:{gateway:{}},profile:{role:'worker',hostExecution:true,connectorsAllowed:false,mcpConfigPath:path.join(directory,'mcp.json'),overlay:'Local metadata audit. Return one short message.'},sessionId:'audit-'+index,stateDirectory:directory,
|
|
51
|
+
config:{model,contextWindow:1000000,bin:runtime.executable,baseUrl:'http://127.0.0.1:'+server.address().port+'/v1',apiKeyEnv:'GATEWAY_CONTEXT_AUDIT_KEY'}});
|
|
52
|
+
adapters.add(adapter);
|
|
53
|
+
const originalEvent=adapter.event.bind(adapter);
|
|
54
|
+
adapter.event=function(event){if(event.method==='thread/tokenUsage/updated')row.observedUsable=event.params?.tokenUsage?.modelContextWindow??null;return originalEvent(event);};
|
|
55
|
+
const originalRequest=adapter.request.bind(adapter);
|
|
56
|
+
adapter.request=async function(method,params){const result=await originalRequest(method,params);if(method==='config/read')row.effectiveConfiguredWindow=result.config?.model_context_window;return result;};
|
|
57
|
+
let timer;
|
|
58
|
+
try{
|
|
59
|
+
const complete=new Promise((resolve,reject)=>{timer=setTimeout(()=>reject(Error('Native audit timed out')),30000);adapter.on('startup-error',reject);adapter.on('output',line=>{const e=JSON.parse(line);if(e.contextWindow)row.context=e.contextWindow;if(e.type==='result')e.is_error?reject(Error(e.result)):resolve();});});
|
|
60
|
+
await adapter.start();
|
|
61
|
+
if(option('--catalog-json')){
|
|
62
|
+
const filename=path.join(adapter.home,'config.toml');
|
|
63
|
+
const config=await fs.readFile(filename,'utf8');
|
|
64
|
+
await fs.writeFile(filename,'model_catalog_json = '+JSON.stringify(path.resolve(option('--catalog-json')))+'\n'+config,{mode:0o600});
|
|
65
|
+
}
|
|
66
|
+
adapter.sendMessage('Return a short audit completion.');await complete;
|
|
67
|
+
row.status=typeof row.observedUsable==='number'?'measured':'missing-native-measurement';
|
|
68
|
+
}catch(error){row.status='error';row.error=error.message;}
|
|
69
|
+
finally{clearTimeout(timer);await adapter.stop();adapters.delete(adapter);}
|
|
70
|
+
rows.push(row);console.log(JSON.stringify(row));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
await Promise.all([runNext(),runNext()]);
|
|
74
|
+
const report={measuredAt:new Date().toISOString(),version:execFileSync(runtime.executable,['--version'],{encoding:'utf8'}).trim(),catalogSource:option('--catalog-json')?'explicit snapshot':'bundled',method:'Real CodexProcess/app-server; explicit 1M request; local fake Responses API; observe native modelContextWindow. No upstream capacity/inference certification.',rows:rows.sort((a,b)=>a.selection.localeCompare(b.selection))};
|
|
75
|
+
if(option('--output'))await fs.writeFile(option('--output'),JSON.stringify(report,null,2)+'\n');
|
|
76
|
+
if(rows.some(row=>row.status!=='measured'))process.exitCode=1;
|
|
77
|
+
}finally{
|
|
78
|
+
await Promise.allSettled([...adapters].map(a=>a.stop()));
|
|
79
|
+
for(const socket of sockets)socket.destroy();server.close();
|
|
80
|
+
if(previous===undefined)delete process.env.GATEWAY_CONTEXT_AUDIT_KEY;else process.env.GATEWAY_CONTEXT_AUDIT_KEY=previous;
|
|
81
|
+
await fs.rm(directory,{recursive:true,force:true});
|
|
82
|
+
}
|
|
83
|
+
})().catch(error=>{console.error(error.message);process.exitCode=1;});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// Opt-in, billable native CLI smoke benchmark; deliberately not a gateway benchmark.
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const { spawn, spawnSync } = require('node:child_process');
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const option = (name, fallback) => args.includes(name) ? args[args.indexOf(name) + 1] : fallback;
|
|
10
|
+
if (!args.includes('--run')) {
|
|
11
|
+
console.log('Opt-in real calls: node scripts/orchestration/benchmark-worker-harnesses.cjs --run [--claude-model sonnet] [--codex-model gpt-5.6-luna] [--claude-base-url URL --claude-api-key-env ENV_NAME] [--codex-base-url URL --codex-api-key-env ENV_NAME] [--host-execution] [--output /tmp/worker-benchmark.json]');
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gateway-worker-benchmark-'));
|
|
15
|
+
fs.chmodSync(root, 0o700);
|
|
16
|
+
const prompt = 'Implement sumIntegers(values) in sum.cjs, exporting { sumIntegers }. Accept an array of safe integers and return its sum. Throw TypeError for non-arrays or invalid elements and RangeError if any intermediate sum is not a safe integer. Empty arrays return 0. Use built-in Node only. Run a small Node verification. Modify only sum.cjs in this directory; do not inspect parent directories or credentials. Finish with a brief summary.';
|
|
17
|
+
const harness = `const assert=require('node:assert/strict');const {sumIntegers:s}=require(process.argv[1]);assert.equal(s([]),0);assert.equal(s([1,2,-3,4]),4);assert.equal(s([-4,-2]),-6);for(const x of [null,{},'1',[1.2],[NaN],[Infinity],['1'],[Number.MAX_SAFE_INTEGER+1]])assert.throws(()=>s(x),TypeError);assert.throws(()=>s([Number.MAX_SAFE_INTEGER,1]),RangeError);assert.throws(()=>s([-Number.MAX_SAFE_INTEGER,-1]),RangeError);`;
|
|
18
|
+
function execute(bin, argv, cwd, env) {
|
|
19
|
+
return new Promise(resolve => {
|
|
20
|
+
const started = Date.now(); let output = '', timedOut = false, spawnError = false;
|
|
21
|
+
const p = spawn(bin, argv, { cwd, env, detached: process.platform !== 'win32', stdio: ['pipe','pipe','pipe'] });
|
|
22
|
+
const kill = () => { try { process.platform === 'win32' ? p.kill('SIGKILL') : process.kill(-p.pid, 'SIGKILL'); } catch {} };
|
|
23
|
+
const timer = setTimeout(() => { timedOut = true; kill(); }, 120000);
|
|
24
|
+
p.stdout.on('data', b => { if (output.length < 8 * 1024 * 1024) output += b; else kill(); });
|
|
25
|
+
// Never persist stderr: providers may echo account/endpoint/auth information.
|
|
26
|
+
p.stderr.resume();
|
|
27
|
+
p.on('error', () => { spawnError = true; });
|
|
28
|
+
p.on('close', code => { clearTimeout(timer); kill(); resolve({ code, timedOut, spawnError, wallMs: Date.now() - started, output }); });
|
|
29
|
+
p.stdin.on('error', () => {}); p.stdin.end(prompt);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function metrics(harness, text) {
|
|
33
|
+
const result = { inputTokens: null, cachedInputTokens: null, cacheCreationTokens: null, outputTokens: null, toolErrors: 0, providerErrors: 0, failureCategory: null, toolCalls: 0 };
|
|
34
|
+
for (const line of text.split('\n')) {
|
|
35
|
+
let event; try { event = JSON.parse(line); } catch { continue; }
|
|
36
|
+
const diagnostic = JSON.stringify(event);
|
|
37
|
+
if (event.is_error || event.type === 'error' || event.type === 'turn.failed') {
|
|
38
|
+
result.failureCategory = /auth|token|credential|401|403/i.test(diagnostic) ? 'authentication' : /model.*(not|invalid|unknown)|unsupported.*model/i.test(diagnostic) ? 'model_unavailable' : /permission|sandbox|denied/i.test(diagnostic) ? 'permission' : 'provider_or_cli';
|
|
39
|
+
}
|
|
40
|
+
if (harness === 'codex') {
|
|
41
|
+
if (event.type === 'item.completed' && ['command_execution','mcp_tool_call','file_change'].includes(event.item?.type)) result.toolCalls++;
|
|
42
|
+
if (event.type === 'turn.completed' && event.usage) {
|
|
43
|
+
result.inputTokens = event.usage.input_tokens ?? null;
|
|
44
|
+
result.cachedInputTokens = event.usage.cached_input_tokens ?? null;
|
|
45
|
+
result.cacheCreationTokens = event.usage.cache_write_input_tokens ?? null;
|
|
46
|
+
result.outputTokens = event.usage.output_tokens ?? null;
|
|
47
|
+
}
|
|
48
|
+
if (event.type === 'item.completed' && (event.item?.status === 'failed' || (typeof event.item?.exit_code === 'number' && event.item.exit_code !== 0))) result.toolErrors++;
|
|
49
|
+
if (event.type === 'turn.failed' || event.type === 'error') result.providerErrors++;
|
|
50
|
+
} else {
|
|
51
|
+
if (event.type === 'result') {
|
|
52
|
+
const u = event.usage ?? {};
|
|
53
|
+
result.inputTokens = u.input_tokens ?? null;
|
|
54
|
+
result.cachedInputTokens = u.cache_read_input_tokens ?? null;
|
|
55
|
+
result.cacheCreationTokens = u.cache_creation_input_tokens ?? null;
|
|
56
|
+
result.outputTokens = u.output_tokens ?? null;
|
|
57
|
+
if (event.is_error) result.providerErrors++;
|
|
58
|
+
}
|
|
59
|
+
for (const block of event.message?.content ?? []) if (block.type === 'tool_use') result.toolCalls++;
|
|
60
|
+
for (const block of event.message?.content ?? []) if (block.type === 'tool_result' && block.is_error) result.toolErrors++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Codex includes reads and writes in input_tokens; Claude reports disjoint categories.
|
|
64
|
+
result.freshInputTokens = result.inputTokens === null ? null : harness === 'codex'
|
|
65
|
+
? Math.max(0, result.inputTokens - (result.cachedInputTokens ?? 0) - (result.cacheCreationTokens ?? 0)) : result.inputTokens;
|
|
66
|
+
result.totalInputTokens = result.inputTokens === null ? null : harness === 'codex'
|
|
67
|
+
? result.inputTokens : result.inputTokens + (result.cachedInputTokens ?? 0) + (result.cacheCreationTokens ?? 0);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
(async () => {
|
|
71
|
+
let settings = {}; try { settings = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.claude', 'settings.json'), 'utf8')); } catch {}
|
|
72
|
+
const claudeEnv = { ...process.env };
|
|
73
|
+
for (const key of ['ANTHROPIC_API_KEY','ANTHROPIC_AUTH_TOKEN','CLAUDE_CODE_OAUTH_TOKEN','ANTHROPIC_BASE_URL']) if (!claudeEnv[key] && typeof settings.env?.[key] === 'string') claudeEnv[key] = settings.env[key];
|
|
74
|
+
const claudeKeyEnv = option('--claude-api-key-env');
|
|
75
|
+
if (claudeKeyEnv) {
|
|
76
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(claudeKeyEnv) || !process.env[claudeKeyEnv]) throw new Error('Missing explicit Claude credential');
|
|
77
|
+
delete claudeEnv.ANTHROPIC_AUTH_TOKEN;
|
|
78
|
+
delete claudeEnv.CLAUDE_CODE_OAUTH_TOKEN;
|
|
79
|
+
claudeEnv.ANTHROPIC_API_KEY = process.env[claudeKeyEnv];
|
|
80
|
+
}
|
|
81
|
+
if (option('--claude-base-url')) claudeEnv.ANTHROPIC_BASE_URL = option('--claude-base-url');
|
|
82
|
+
const codexKeyEnv = option('--codex-api-key-env', 'OPENAI_API_KEY');
|
|
83
|
+
if (!/^[A-Z_][A-Z0-9_]*$/.test(codexKeyEnv)) throw new Error('Invalid credential environment name');
|
|
84
|
+
const codexEnv = { ...process.env }; // CLI reads existing auth in-place; never copy it.
|
|
85
|
+
const routes = [
|
|
86
|
+
{ harness: 'claude', bin: process.env.CLAUDE_BIN || 'claude', model: option('--claude-model','sonnet'), env: claudeEnv,
|
|
87
|
+
auth: ['ANTHROPIC_API_KEY','ANTHROPIC_AUTH_TOKEN','CLAUDE_CODE_OAUTH_TOKEN'].some(k => claudeEnv[k]) || fs.existsSync(path.join(os.homedir(),'.claude','.credentials.json')) },
|
|
88
|
+
{ harness: 'codex', bin: process.env.CODEX_BIN || 'codex', model: option('--codex-model','gpt-5.6-luna'), env: codexEnv,
|
|
89
|
+
auth: Boolean(codexEnv[codexKeyEnv]) || (!option('--codex-base-url') && fs.existsSync(path.join(codexEnv.CODEX_HOME || path.join(os.homedir(),'.codex'),'auth.json'))) },
|
|
90
|
+
];
|
|
91
|
+
const report = { kind: 'native-cli-smoke', codexSandbox: args.includes('--host-execution') ? 'danger-full-access' : 'workspace-write', note: 'Different models/provider/account routes may apply. Not a controlled timing/cost A/B, gateway integration test, or quality-parity claim. CLI token accounting differs; null means unavailable.', runs: [] };
|
|
92
|
+
for (const route of routes) {
|
|
93
|
+
if (!route.auth) { report.runs.push({ harness: route.harness, model: route.model, status: 'skipped_missing_credentials' }); continue; }
|
|
94
|
+
const cwd = path.join(root,route.harness); fs.mkdirSync(cwd, {mode:0o700});
|
|
95
|
+
fs.writeFileSync(path.join(cwd,'sum.cjs'),'module.exports = { sumIntegers() { throw new Error("TODO"); } };\n');
|
|
96
|
+
const argv = route.harness === 'codex'
|
|
97
|
+
? ['exec','--ignore-user-config','--ignore-rules','--skip-git-repo-check','--ephemeral','--json','--sandbox',args.includes('--host-execution') ? 'danger-full-access' : 'workspace-write','-c','project_doc_max_bytes=0','-c','approval_policy="never"','-c','model_reasoning_effort="medium"','--model',route.model,'-']
|
|
98
|
+
: ['--print',...(claudeKeyEnv ? ['--bare','--setting-sources',''] : []),'--no-session-persistence','--output-format','stream-json','--verbose','--model',route.model,'--permission-mode','bypassPermissions','--tools','Read,Edit,Write,Bash','--strict-mcp-config','--mcp-config','{"mcpServers":{}}'];
|
|
99
|
+
if (route.harness === 'codex' && option('--codex-base-url')) {
|
|
100
|
+
const url = new URL(option('--codex-base-url'));
|
|
101
|
+
if (url.username || url.password || url.search || url.hash || !['https:', 'http:'].includes(url.protocol)) throw new Error('Invalid endpoint');
|
|
102
|
+
argv.splice(argv.length - 1, 0, '-c', 'model_provider="benchmark"', '-c', 'model_providers.benchmark.name="Benchmark"', '-c', 'model_providers.benchmark.wire_api="responses"', '-c', 'model_providers.benchmark.base_url=' + JSON.stringify(url.href), '-c', 'model_providers.benchmark.env_key=' + JSON.stringify(codexKeyEnv));
|
|
103
|
+
}
|
|
104
|
+
const run = await execute(route.bin,argv,cwd,route.env);
|
|
105
|
+
const checked = spawnSync(process.execPath,['-e',harness,path.join(cwd,'sum.cjs')],{timeout:5000,encoding:'utf8'});
|
|
106
|
+
report.runs.push({harness:route.harness,model:route.model,status:run.spawnError?'cli_unavailable':run.timedOut?'timeout':run.code===0?'finished':'cli_failed',exitCode:run.code,wallMs:run.wallMs,correctnessPassed:checked.status===0,validationFailure:checked.status===0?null:checked.error?'harness_error':(checked.stderr?.match(/(?:AssertionError|TypeError|RangeError|SyntaxError|ReferenceError|MODULE_NOT_FOUND)/)?.[0] ?? 'test_failed'),...metrics(route.harness,run.output)});
|
|
107
|
+
}
|
|
108
|
+
const json = JSON.stringify(report,null,2)+'\n';
|
|
109
|
+
if (option('--output')) fs.writeFileSync(option('--output'),json,{mode:0o600});
|
|
110
|
+
process.stdout.write(json);
|
|
111
|
+
process.exitCode = report.runs.every(r=>r.status==='finished'&&r.correctnessPassed&&r.providerErrors===0) ? 0 : 1;
|
|
112
|
+
})().catch(() => { console.error('Benchmark failed; raw provider output suppressed.'); process.exitCode=1; }).finally(()=>fs.rmSync(root,{recursive:true,force:true}));
|