@reefclaw/connect 0.1.0
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/assets/bridge/bridge.d.ts +96 -0
- package/assets/bridge/bridge.js +969 -0
- package/assets/bridge/config.d.ts +43 -0
- package/assets/bridge/config.js +176 -0
- package/assets/bridge/connector.d.ts +52 -0
- package/assets/bridge/connector.js +293 -0
- package/assets/bridge/event-replay-buffer.d.ts +43 -0
- package/assets/bridge/event-replay-buffer.js +109 -0
- package/assets/bridge/gateway/event-parser.d.ts +209 -0
- package/assets/bridge/gateway/event-parser.js +793 -0
- package/assets/bridge/gateway/gateway-config.d.ts +39 -0
- package/assets/bridge/gateway/gateway-config.js +86 -0
- package/assets/bridge/gateway/gateway-http-client.d.ts +50 -0
- package/assets/bridge/gateway/gateway-http-client.js +165 -0
- package/assets/bridge/gateway/gateway-ws-client.d.ts +116 -0
- package/assets/bridge/gateway/gateway-ws-client.js +417 -0
- package/assets/bridge/gateway/poller.d.ts +146 -0
- package/assets/bridge/gateway/poller.js +505 -0
- package/assets/bridge/gateway/tool-discovery.d.ts +25 -0
- package/assets/bridge/gateway/tool-discovery.js +198 -0
- package/assets/bridge/index.d.ts +2 -0
- package/assets/bridge/index.js +253 -0
- package/assets/bridge/logger.d.ts +2 -0
- package/assets/bridge/logger.js +2 -0
- package/assets/bridge/provider.d.ts +156 -0
- package/assets/bridge/provider.js +2 -0
- package/assets/bridge/providers/emergency-commands.d.ts +54 -0
- package/assets/bridge/providers/emergency-commands.js +235 -0
- package/assets/bridge/providers/gateway.d.ts +322 -0
- package/assets/bridge/providers/gateway.js +2302 -0
- package/assets/bridge/providers/mock.d.ts +37 -0
- package/assets/bridge/providers/mock.js +385 -0
- package/assets/bridge/providers/onboarding-commands.d.ts +83 -0
- package/assets/bridge/providers/onboarding-commands.js +213 -0
- package/assets/bridge/providers/risk-calculator.d.ts +96 -0
- package/assets/bridge/providers/risk-calculator.js +369 -0
- package/assets/bridge/setup.d.ts +32 -0
- package/assets/bridge/setup.js +226 -0
- package/assets/bridge/types.d.ts +584 -0
- package/assets/bridge/types.js +50 -0
- package/assets/bridge/utils/reconnect.d.ts +6 -0
- package/assets/bridge/utils/reconnect.js +6 -0
- package/assets/bridge/utils/skill-signing.d.ts +51 -0
- package/assets/bridge/utils/skill-signing.js +138 -0
- package/assets/bridge/utils/skill-version.d.ts +17 -0
- package/assets/bridge/utils/skill-version.js +71 -0
- package/assets/plugin/audit/mode-transition-audit.d.ts +11 -0
- package/assets/plugin/audit/mode-transition-audit.js +29 -0
- package/assets/plugin/balance-utils.d.ts +36 -0
- package/assets/plugin/balance-utils.js +98 -0
- package/assets/plugin/ccxt/binance-ban-gate.d.ts +47 -0
- package/assets/plugin/ccxt/binance-ban-gate.js +409 -0
- package/assets/plugin/ccxt/binance-private.d.ts +325 -0
- package/assets/plugin/ccxt/binance-private.js +1415 -0
- package/assets/plugin/ccxt/binance-public.d.ts +18 -0
- package/assets/plugin/ccxt/binance-public.js +147 -0
- package/assets/plugin/config/agent-config-client.d.ts +55 -0
- package/assets/plugin/config/agent-config-client.js +145 -0
- package/assets/plugin/config/agent-config-poller.d.ts +25 -0
- package/assets/plugin/config/agent-config-poller.js +100 -0
- package/assets/plugin/config/brackets-config.d.ts +22 -0
- package/assets/plugin/config/brackets-config.js +58 -0
- package/assets/plugin/config/gate-store.d.ts +18 -0
- package/assets/plugin/config/gate-store.js +61 -0
- package/assets/plugin/config/plugin-config-io.d.ts +175 -0
- package/assets/plugin/config/plugin-config-io.js +84 -0
- package/assets/plugin/config/position-review-config.d.ts +35 -0
- package/assets/plugin/config/position-review-config.js +105 -0
- package/assets/plugin/config/tool-gate.d.ts +53 -0
- package/assets/plugin/config/tool-gate.js +125 -0
- package/assets/plugin/config/user-data-stream-config.d.ts +85 -0
- package/assets/plugin/config/user-data-stream-config.js +224 -0
- package/assets/plugin/exchange-adapter.d.ts +49 -0
- package/assets/plugin/exchange-adapter.js +4 -0
- package/assets/plugin/index.d.ts +30 -0
- package/assets/plugin/index.js +1989 -0
- package/assets/plugin/ingest/pending-entry-metadata.d.ts +52 -0
- package/assets/plugin/ingest/pending-entry-metadata.js +182 -0
- package/assets/plugin/ingest/position-auto-capture.d.ts +98 -0
- package/assets/plugin/ingest/position-auto-capture.js +394 -0
- package/assets/plugin/ingest/position-decisions-client.d.ts +318 -0
- package/assets/plugin/ingest/position-decisions-client.js +296 -0
- package/assets/plugin/ingest/reconcile-db-vs-exchange.d.ts +13 -0
- package/assets/plugin/ingest/reconcile-db-vs-exchange.js +114 -0
- package/assets/plugin/ingest/reconciler-cleanup.d.ts +37 -0
- package/assets/plugin/ingest/reconciler-cleanup.js +147 -0
- package/assets/plugin/ingest/rest-gap-filler.d.ts +191 -0
- package/assets/plugin/ingest/rest-gap-filler.js +565 -0
- package/assets/plugin/ingest/touched-symbols-store.d.ts +25 -0
- package/assets/plugin/ingest/touched-symbols-store.js +96 -0
- package/assets/plugin/ingest/trade-store-client.d.ts +40 -0
- package/assets/plugin/ingest/trade-store-client.js +125 -0
- package/assets/plugin/ingest/ws-ingest.d.ts +43 -0
- package/assets/plugin/ingest/ws-ingest.js +126 -0
- package/assets/plugin/learning/setup-family.d.ts +21 -0
- package/assets/plugin/learning/setup-family.js +103 -0
- package/assets/plugin/lifecycle/install-signal-handlers.d.ts +33 -0
- package/assets/plugin/lifecycle/install-signal-handlers.js +112 -0
- package/assets/plugin/lifecycle/shutdown-coordinator.d.ts +43 -0
- package/assets/plugin/lifecycle/shutdown-coordinator.js +131 -0
- package/assets/plugin/live/bracket-id.d.ts +18 -0
- package/assets/plugin/live/bracket-id.js +81 -0
- package/assets/plugin/live/bracket-ledger.d.ts +54 -0
- package/assets/plugin/live/bracket-ledger.js +267 -0
- package/assets/plugin/live/bracket-manager.d.ts +82 -0
- package/assets/plugin/live/bracket-manager.js +478 -0
- package/assets/plugin/live/bracket-params.d.ts +22 -0
- package/assets/plugin/live/bracket-params.js +124 -0
- package/assets/plugin/live/bracket-reconciler.d.ts +95 -0
- package/assets/plugin/live/bracket-reconciler.js +573 -0
- package/assets/plugin/live/bracket-types.d.ts +102 -0
- package/assets/plugin/live/bracket-types.js +8 -0
- package/assets/plugin/live/deposit-tracker.d.ts +62 -0
- package/assets/plugin/live/deposit-tracker.js +97 -0
- package/assets/plugin/live/emergency-controls.d.ts +32 -0
- package/assets/plugin/live/emergency-controls.js +226 -0
- package/assets/plugin/live/exchange-errors.d.ts +12 -0
- package/assets/plugin/live/exchange-errors.js +130 -0
- package/assets/plugin/live/exchange-info-cache.d.ts +35 -0
- package/assets/plugin/live/exchange-info-cache.js +119 -0
- package/assets/plugin/live/fact-subscriber.d.ts +78 -0
- package/assets/plugin/live/fact-subscriber.js +182 -0
- package/assets/plugin/live/intent-journal.d.ts +42 -0
- package/assets/plugin/live/intent-journal.js +122 -0
- package/assets/plugin/live/listen-key-manager.d.ts +70 -0
- package/assets/plugin/live/listen-key-manager.js +169 -0
- package/assets/plugin/live/live-adapter.d.ts +264 -0
- package/assets/plugin/live/live-adapter.js +1665 -0
- package/assets/plugin/live/live-balance-enricher.d.ts +32 -0
- package/assets/plugin/live/live-balance-enricher.js +104 -0
- package/assets/plugin/live/live-bracket-api.d.ts +13 -0
- package/assets/plugin/live/live-bracket-api.js +20 -0
- package/assets/plugin/live/live-state-store.d.ts +194 -0
- package/assets/plugin/live/live-state-store.js +450 -0
- package/assets/plugin/live/local-signal-service.d.ts +57 -0
- package/assets/plugin/live/local-signal-service.js +146 -0
- package/assets/plugin/live/local-strategy-evaluator.d.ts +62 -0
- package/assets/plugin/live/local-strategy-evaluator.js +127 -0
- package/assets/plugin/live/microstructure-assembler.d.ts +54 -0
- package/assets/plugin/live/microstructure-assembler.js +148 -0
- package/assets/plugin/live/order-poller.d.ts +29 -0
- package/assets/plugin/live/order-poller.js +125 -0
- package/assets/plugin/live/position-state-store.d.ts +83 -0
- package/assets/plugin/live/position-state-store.js +237 -0
- package/assets/plugin/live/proposal-decision-listener.d.ts +64 -0
- package/assets/plugin/live/proposal-decision-listener.js +288 -0
- package/assets/plugin/live/proposal-manager.d.ts +76 -0
- package/assets/plugin/live/proposal-manager.js +140 -0
- package/assets/plugin/live/rate-limiter.d.ts +47 -0
- package/assets/plugin/live/rate-limiter.js +159 -0
- package/assets/plugin/live/reconciler.d.ts +39 -0
- package/assets/plugin/live/reconciler.js +175 -0
- package/assets/plugin/live/setup-buckets.d.ts +7 -0
- package/assets/plugin/live/setup-buckets.js +33 -0
- package/assets/plugin/live/slippage-tracker.d.ts +45 -0
- package/assets/plugin/live/slippage-tracker.js +78 -0
- package/assets/plugin/live/stop-watcher.d.ts +34 -0
- package/assets/plugin/live/stop-watcher.js +158 -0
- package/assets/plugin/live/user-data-active-probe.d.ts +54 -0
- package/assets/plugin/live/user-data-active-probe.js +180 -0
- package/assets/plugin/live/user-data-stream-controller.d.ts +200 -0
- package/assets/plugin/live/user-data-stream-controller.js +579 -0
- package/assets/plugin/live/user-data-stream-ws.d.ts +22 -0
- package/assets/plugin/live/user-data-stream-ws.js +63 -0
- package/assets/plugin/live/user-data-stream.d.ts +243 -0
- package/assets/plugin/live/user-data-stream.js +704 -0
- package/assets/plugin/logger.d.ts +2 -0
- package/assets/plugin/logger.js +2 -0
- package/assets/plugin/mfe.d.ts +21 -0
- package/assets/plugin/mfe.js +68 -0
- package/assets/plugin/onboarding/mode-ladder.d.ts +1 -0
- package/assets/plugin/onboarding/mode-ladder.js +3 -0
- package/assets/plugin/onboarding/runtime.d.ts +71 -0
- package/assets/plugin/onboarding/runtime.js +153 -0
- package/assets/plugin/openclaw.plugin.json +91 -0
- package/assets/plugin/paper-adapter.d.ts +24 -0
- package/assets/plugin/paper-adapter.js +91 -0
- package/assets/plugin/persistence/state-manager.d.ts +42 -0
- package/assets/plugin/persistence/state-manager.js +164 -0
- package/assets/plugin/pinned-plan.d.ts +9 -0
- package/assets/plugin/pinned-plan.js +23 -0
- package/assets/plugin/risk/pre-trade-check.d.ts +38 -0
- package/assets/plugin/risk/pre-trade-check.js +345 -0
- package/assets/plugin/risk/pre-trade-types.d.ts +60 -0
- package/assets/plugin/risk/pre-trade-types.js +3 -0
- package/assets/plugin/shadow/shadow-tracker.d.ts +36 -0
- package/assets/plugin/shadow/shadow-tracker.js +151 -0
- package/assets/plugin/shadow/types.d.ts +42 -0
- package/assets/plugin/shadow/types.js +20 -0
- package/assets/plugin/shared/indicators-extended.d.ts +52 -0
- package/assets/plugin/shared/indicators-extended.js +291 -0
- package/assets/plugin/shared/indicators.d.ts +15 -0
- package/assets/plugin/shared/indicators.js +114 -0
- package/assets/plugin/signals/conditions/registry.d.ts +16 -0
- package/assets/plugin/signals/conditions/registry.js +1274 -0
- package/assets/plugin/signals/conditions/types.d.ts +1 -0
- package/assets/plugin/signals/conditions/types.js +4 -0
- package/assets/plugin/signals/direction-rules.d.ts +3 -0
- package/assets/plugin/signals/direction-rules.js +24 -0
- package/assets/plugin/signals/entry-rules.d.ts +6 -0
- package/assets/plugin/signals/entry-rules.js +33 -0
- package/assets/plugin/signals/serialize-context.d.ts +4 -0
- package/assets/plugin/signals/serialize-context.js +39 -0
- package/assets/plugin/signals/stop-rules.d.ts +3 -0
- package/assets/plugin/signals/stop-rules.js +48 -0
- package/assets/plugin/signals/strategy-adapter.d.ts +14 -0
- package/assets/plugin/signals/strategy-adapter.js +122 -0
- package/assets/plugin/signals/types.d.ts +1 -0
- package/assets/plugin/signals/types.js +8 -0
- package/assets/plugin/simulator/exchange-simulator.d.ts +93 -0
- package/assets/plugin/simulator/exchange-simulator.js +684 -0
- package/assets/plugin/simulator/fill-engine.d.ts +53 -0
- package/assets/plugin/simulator/fill-engine.js +276 -0
- package/assets/plugin/simulator/paper-market-feed.d.ts +26 -0
- package/assets/plugin/simulator/paper-market-feed.js +104 -0
- package/assets/plugin/simulator/realistic-fills.d.ts +59 -0
- package/assets/plugin/simulator/realistic-fills.js +175 -0
- package/assets/plugin/simulator/types.d.ts +219 -0
- package/assets/plugin/simulator/types.js +43 -0
- package/assets/plugin/strategy/builtin-strategies.d.ts +2 -0
- package/assets/plugin/strategy/builtin-strategies.js +109 -0
- package/assets/plugin/strategy/condition-registry.d.ts +3 -0
- package/assets/plugin/strategy/condition-registry.js +153 -0
- package/assets/plugin/strategy/evaluator.d.ts +67 -0
- package/assets/plugin/strategy/evaluator.js +93 -0
- package/assets/plugin/tools/assessment-validation.d.ts +118 -0
- package/assets/plugin/tools/assessment-validation.js +415 -0
- package/assets/plugin/tools/attach-brackets.d.ts +34 -0
- package/assets/plugin/tools/attach-brackets.js +363 -0
- package/assets/plugin/tools/audit-bracket-protection.d.ts +49 -0
- package/assets/plugin/tools/audit-bracket-protection.js +527 -0
- package/assets/plugin/tools/cancel-all-orders.d.ts +7 -0
- package/assets/plugin/tools/cancel-all-orders.js +5 -0
- package/assets/plugin/tools/cancel-order.d.ts +10 -0
- package/assets/plugin/tools/cancel-order.js +14 -0
- package/assets/plugin/tools/check-position-health.d.ts +46 -0
- package/assets/plugin/tools/check-position-health.js +194 -0
- package/assets/plugin/tools/clear-exchange-credentials.d.ts +24 -0
- package/assets/plugin/tools/clear-exchange-credentials.js +70 -0
- package/assets/plugin/tools/close-position.d.ts +22 -0
- package/assets/plugin/tools/close-position.js +449 -0
- package/assets/plugin/tools/create-order.d.ts +54 -0
- package/assets/plugin/tools/create-order.js +338 -0
- package/assets/plugin/tools/exit-gate.d.ts +58 -0
- package/assets/plugin/tools/exit-gate.js +162 -0
- package/assets/plugin/tools/fetch-balance.d.ts +5 -0
- package/assets/plugin/tools/fetch-balance.js +4 -0
- package/assets/plugin/tools/fetch-ohlcv.d.ts +11 -0
- package/assets/plugin/tools/fetch-ohlcv.js +8 -0
- package/assets/plugin/tools/fetch-open-orders.d.ts +7 -0
- package/assets/plugin/tools/fetch-open-orders.js +4 -0
- package/assets/plugin/tools/fetch-positions.d.ts +7 -0
- package/assets/plugin/tools/fetch-positions.js +4 -0
- package/assets/plugin/tools/fetch-ticker.d.ts +11 -0
- package/assets/plugin/tools/fetch-ticker.js +5 -0
- package/assets/plugin/tools/get-agent-profile.d.ts +4 -0
- package/assets/plugin/tools/get-agent-profile.js +6 -0
- package/assets/plugin/tools/get-analytics.d.ts +6 -0
- package/assets/plugin/tools/get-analytics.js +7 -0
- package/assets/plugin/tools/get-backtest.d.ts +12 -0
- package/assets/plugin/tools/get-backtest.js +91 -0
- package/assets/plugin/tools/get-basis.d.ts +7 -0
- package/assets/plugin/tools/get-basis.js +7 -0
- package/assets/plugin/tools/get-bracket-config.d.ts +11 -0
- package/assets/plugin/tools/get-bracket-config.js +24 -0
- package/assets/plugin/tools/get-cascade-risk.d.ts +7 -0
- package/assets/plugin/tools/get-cascade-risk.js +8 -0
- package/assets/plugin/tools/get-crypto-metrics.d.ts +18 -0
- package/assets/plugin/tools/get-crypto-metrics.js +45 -0
- package/assets/plugin/tools/get-cvd.d.ts +6 -0
- package/assets/plugin/tools/get-cvd.js +6 -0
- package/assets/plugin/tools/get-divergences.d.ts +6 -0
- package/assets/plugin/tools/get-divergences.js +6 -0
- package/assets/plugin/tools/get-funding-context.d.ts +6 -0
- package/assets/plugin/tools/get-funding-context.js +16 -0
- package/assets/plugin/tools/get-liquidation-levels.d.ts +7 -0
- package/assets/plugin/tools/get-liquidation-levels.js +7 -0
- package/assets/plugin/tools/get-liquidation-pulse.d.ts +9 -0
- package/assets/plugin/tools/get-liquidation-pulse.js +22 -0
- package/assets/plugin/tools/get-market-breadth.d.ts +6 -0
- package/assets/plugin/tools/get-market-breadth.js +8 -0
- package/assets/plugin/tools/get-market-intel.d.ts +19 -0
- package/assets/plugin/tools/get-market-intel.js +116 -0
- package/assets/plugin/tools/get-market-structure.d.ts +47 -0
- package/assets/plugin/tools/get-market-structure.js +198 -0
- package/assets/plugin/tools/get-my-mined-patterns.d.ts +20 -0
- package/assets/plugin/tools/get-my-mined-patterns.js +61 -0
- package/assets/plugin/tools/get-my-proposed-learnings.d.ts +20 -0
- package/assets/plugin/tools/get-my-proposed-learnings.js +55 -0
- package/assets/plugin/tools/get-my-recent-reviews.d.ts +22 -0
- package/assets/plugin/tools/get-my-recent-reviews.js +66 -0
- package/assets/plugin/tools/get-orderbook.d.ts +21 -0
- package/assets/plugin/tools/get-orderbook.js +32 -0
- package/assets/plugin/tools/get-pattern-scan.d.ts +7 -0
- package/assets/plugin/tools/get-pattern-scan.js +8 -0
- package/assets/plugin/tools/get-regime.d.ts +6 -0
- package/assets/plugin/tools/get-regime.js +7 -0
- package/assets/plugin/tools/get-relevant-learnings.d.ts +21 -0
- package/assets/plugin/tools/get-relevant-learnings.js +65 -0
- package/assets/plugin/tools/get-resting-liquidity.d.ts +6 -0
- package/assets/plugin/tools/get-resting-liquidity.js +11 -0
- package/assets/plugin/tools/get-risk-scenario.d.ts +29 -0
- package/assets/plugin/tools/get-risk-scenario.js +47 -0
- package/assets/plugin/tools/get-risk-summary.d.ts +51 -0
- package/assets/plugin/tools/get-risk-summary.js +118 -0
- package/assets/plugin/tools/get-sentiment.d.ts +4 -0
- package/assets/plugin/tools/get-sentiment.js +6 -0
- package/assets/plugin/tools/get-session-review.d.ts +7 -0
- package/assets/plugin/tools/get-session-review.js +8 -0
- package/assets/plugin/tools/get-setup-detail.d.ts +7 -0
- package/assets/plugin/tools/get-setup-detail.js +303 -0
- package/assets/plugin/tools/get-signals.d.ts +15 -0
- package/assets/plugin/tools/get-signals.js +54 -0
- package/assets/plugin/tools/get-sizing.d.ts +6 -0
- package/assets/plugin/tools/get-sizing.js +6 -0
- package/assets/plugin/tools/get-trade-feedback.d.ts +7 -0
- package/assets/plugin/tools/get-trade-feedback.js +8 -0
- package/assets/plugin/tools/get-trade-flow.d.ts +7 -0
- package/assets/plugin/tools/get-trade-flow.js +7 -0
- package/assets/plugin/tools/get-volume-analysis.d.ts +21 -0
- package/assets/plugin/tools/get-volume-analysis.js +74 -0
- package/assets/plugin/tools/get-volume-profile.d.ts +7 -0
- package/assets/plugin/tools/get-volume-profile.js +7 -0
- package/assets/plugin/tools/helpers.d.ts +25 -0
- package/assets/plugin/tools/helpers.js +38 -0
- package/assets/plugin/tools/intel-api.d.ts +14 -0
- package/assets/plugin/tools/intel-api.js +52 -0
- package/assets/plugin/tools/intel-cache.d.ts +25 -0
- package/assets/plugin/tools/intel-cache.js +133 -0
- package/assets/plugin/tools/list-strategies.d.ts +7 -0
- package/assets/plugin/tools/list-strategies.js +6 -0
- package/assets/plugin/tools/modify-stop.d.ts +17 -0
- package/assets/plugin/tools/modify-stop.js +81 -0
- package/assets/plugin/tools/modify-target.d.ts +17 -0
- package/assets/plugin/tools/modify-target.js +71 -0
- package/assets/plugin/tools/propose-learning.d.ts +22 -0
- package/assets/plugin/tools/propose-learning.js +65 -0
- package/assets/plugin/tools/query-review-outcomes.d.ts +30 -0
- package/assets/plugin/tools/query-review-outcomes.js +64 -0
- package/assets/plugin/tools/query-trades.d.ts +21 -0
- package/assets/plugin/tools/query-trades.js +37 -0
- package/assets/plugin/tools/record-position-reviews.d.ts +38 -0
- package/assets/plugin/tools/record-position-reviews.js +147 -0
- package/assets/plugin/tools/save-strategy.d.ts +16 -0
- package/assets/plugin/tools/save-strategy.js +46 -0
- package/assets/plugin/tools/scan-pairs.d.ts +18 -0
- package/assets/plugin/tools/scan-pairs.js +220 -0
- package/assets/plugin/tools/score-setup.d.ts +31 -0
- package/assets/plugin/tools/score-setup.js +268 -0
- package/assets/plugin/tools/set-bracket-requirement.d.ts +18 -0
- package/assets/plugin/tools/set-bracket-requirement.js +81 -0
- package/assets/plugin/tools/set-exchange-credentials.d.ts +25 -0
- package/assets/plugin/tools/set-exchange-credentials.js +80 -0
- package/assets/plugin/tools/set-trading-mode.d.ts +26 -0
- package/assets/plugin/tools/set-trading-mode.js +135 -0
- package/assets/plugin/tools/test-exchange-credentials.d.ts +16 -0
- package/assets/plugin/tools/test-exchange-credentials.js +100 -0
- package/assets/plugin/tools/toggle-strategy.d.ts +8 -0
- package/assets/plugin/tools/toggle-strategy.js +8 -0
- package/assets/plugin/trading-params-cache.d.ts +26 -0
- package/assets/plugin/trading-params-cache.js +52 -0
- package/assets/plugin/types.d.ts +110 -0
- package/assets/plugin/types.js +7 -0
- package/assets/plugin/util/plugin-paths.d.ts +3 -0
- package/assets/plugin/util/plugin-paths.js +15 -0
- package/assets/shared/fills.d.ts +36 -0
- package/assets/shared/fills.js +20 -0
- package/assets/shared/index.d.ts +10 -0
- package/assets/shared/index.js +5 -0
- package/assets/shared/logger.d.ts +10 -0
- package/assets/shared/logger.js +34 -0
- package/assets/shared/protocol.d.ts +29 -0
- package/assets/shared/protocol.js +14 -0
- package/assets/shared/redact.d.ts +6 -0
- package/assets/shared/redact.js +31 -0
- package/assets/shared/shared/indicators-extended.d.ts +52 -0
- package/assets/shared/shared/indicators-extended.js +284 -0
- package/assets/shared/shared/indicators.d.ts +15 -0
- package/assets/shared/shared/indicators.js +107 -0
- package/assets/shared/signals/conditions/registry.d.ts +16 -0
- package/assets/shared/signals/conditions/registry.js +1267 -0
- package/assets/shared/signals/conditions/types.d.ts +65 -0
- package/assets/shared/signals/conditions/types.js +8 -0
- package/assets/shared/signals/direction-rules.d.ts +3 -0
- package/assets/shared/signals/direction-rules.js +18 -0
- package/assets/shared/signals/entry-rules.d.ts +6 -0
- package/assets/shared/signals/entry-rules.js +26 -0
- package/assets/shared/signals/indicators-extended.d.ts +52 -0
- package/assets/shared/signals/indicators-extended.js +284 -0
- package/assets/shared/signals/indicators.d.ts +15 -0
- package/assets/shared/signals/indicators.js +107 -0
- package/assets/shared/signals/serialize-context.d.ts +4 -0
- package/assets/shared/signals/serialize-context.js +41 -0
- package/assets/shared/signals/stop-rules.d.ts +3 -0
- package/assets/shared/signals/stop-rules.js +41 -0
- package/assets/shared/signals/strategy-adapter.d.ts +14 -0
- package/assets/shared/signals/strategy-adapter.js +117 -0
- package/assets/shared/signals/types.d.ts +187 -0
- package/assets/shared/signals/types.js +9 -0
- package/assets/shared/trading-mode.d.ts +16 -0
- package/assets/shared/trading-mode.js +49 -0
- package/assets/skill/SKILL.md +1357 -0
- package/dist/bridge.js +25 -0
- package/dist/bundle.js +33 -0
- package/dist/cli.js +120 -0
- package/dist/daemon.js +104 -0
- package/dist/deps.js +41 -0
- package/dist/exec.js +28 -0
- package/dist/openclaw.js +153 -0
- package/dist/paths.js +23 -0
- package/dist/plugin.js +48 -0
- package/dist/skill.js +35 -0
- package/dist/ui.js +29 -0
- package/dist/validate.js +28 -0
- package/package.json +32 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { TradingMode, ExchangeConfig } from '../types.js';
|
|
2
|
+
/** Full on-disk schema. Unknown keys are preserved on round-trip. */
|
|
3
|
+
export interface PluginConfigFile {
|
|
4
|
+
connectionToken?: string;
|
|
5
|
+
apiBaseUrl?: string;
|
|
6
|
+
intelligenceUrl?: string;
|
|
7
|
+
exchange?: ExchangeConfig;
|
|
8
|
+
tradingMode?: TradingMode;
|
|
9
|
+
microLive?: {
|
|
10
|
+
sizeCapPercent?: number;
|
|
11
|
+
maxPositionUSDT?: number;
|
|
12
|
+
};
|
|
13
|
+
/** Exchange-native bracket orders (STOP_MARKET + TAKE_PROFIT_MARKET).
|
|
14
|
+
* mode='off' (default) keeps legacy stop-watcher behaviour.
|
|
15
|
+
* mode='observe' submits brackets AND keeps the watcher active (rollout stage).
|
|
16
|
+
* mode='enforce' disables watcher for live; brackets are the sole protection.
|
|
17
|
+
*
|
|
18
|
+
* requireStopLoss / requireTakeProfit (default both true) control whether
|
|
19
|
+
* the pre-trade gate rejects live entries that don't include the matching
|
|
20
|
+
* price. Operator can untick via the Trading Parameters panel; UI shows a
|
|
21
|
+
* red warning (stop off) or amber warning (target off) with typed confirm.
|
|
22
|
+
* Migration note: these flags move to intelligence DB per-user alongside
|
|
23
|
+
* Phase 2.5 (ledger mirror). Plugin-config is the temporary home. */
|
|
24
|
+
brackets?: {
|
|
25
|
+
mode?: 'off' | 'observe' | 'enforce';
|
|
26
|
+
requireStopLoss?: boolean;
|
|
27
|
+
requireTakeProfit?: boolean;
|
|
28
|
+
};
|
|
29
|
+
/** Facts-out signal evaluation (docs/FACTS_OUT_ARCHITECTURE.md step 5).
|
|
30
|
+
* evaluator='central' (default) → get_signals calls the intel engine as today.
|
|
31
|
+
* 'shadow' → also evaluate locally (via the SSE fact stream) and log the
|
|
32
|
+
* comparison; central is still authoritative (zero behaviour change).
|
|
33
|
+
* 'enforce' → get_signals returns the locally-computed snapshot (falling back
|
|
34
|
+
* to central when no fact has arrived for a symbol yet).
|
|
35
|
+
* `symbols` is the set the local service streams + evaluates; required when
|
|
36
|
+
* evaluator != 'central'. Requires the intel fact stream to be on
|
|
37
|
+
* (RC_INTEL_FACTS_STREAM=on). */
|
|
38
|
+
signals?: {
|
|
39
|
+
evaluator?: 'central' | 'shadow' | 'enforce';
|
|
40
|
+
symbols?: string[];
|
|
41
|
+
};
|
|
42
|
+
/** Binance user-data WebSocket stream (positions/balance/orders via push).
|
|
43
|
+
* mode='off' (default) keeps legacy REST polling authoritative.
|
|
44
|
+
* mode='shadow' runs the WS alongside REST and logs diffs; REST still authoritative.
|
|
45
|
+
* mode='observe' makes WS authoritative for reads; REST drops to 30-60s truth-check.
|
|
46
|
+
* mode='enforce' full cutover — skill-side pollers disabled, REST at 60s truth-check only.
|
|
47
|
+
*
|
|
48
|
+
* listenKeyRefreshMs / reconnectBaseMs / reconnectCapMs are escape-hatch tunables
|
|
49
|
+
* for runbook use; defaults are production-safe. staleEventWatchdogMs triggers a
|
|
50
|
+
* forced reconnect if no events arrive within the window (catches silent drops). */
|
|
51
|
+
userDataStream?: {
|
|
52
|
+
mode?: 'off' | 'shadow' | 'observe' | 'enforce';
|
|
53
|
+
listenKeyRefreshMs?: number;
|
|
54
|
+
reconnectBaseMs?: number;
|
|
55
|
+
reconnectCapMs?: number;
|
|
56
|
+
staleEventWatchdogMs?: number;
|
|
57
|
+
/** Interval for REST-refreshing algo orders into the store. Binance WS
|
|
58
|
+
* never pushes algo-order state changes until trigger, so this loop fills
|
|
59
|
+
* the gap. 0 = disabled. Default 15_000 (15s). */
|
|
60
|
+
algoRefreshMs?: number;
|
|
61
|
+
/** @deprecated since 2026-04-25 (ping-aware watchdog refactor). Field is
|
|
62
|
+
* still parsed and clamped so existing config files don't fail validation,
|
|
63
|
+
* but the runtime no longer reads it — the single `staleEventWatchdogMs`
|
|
64
|
+
* (default 6 min, ping-aware) plus the active REST probe replace it. */
|
|
65
|
+
activeStaleEventWatchdogMs?: number;
|
|
66
|
+
/** Active REST probe interval — polls fetchMyTrades for every open-position
|
|
67
|
+
* symbol; if a trade timestamp exceeds the WS lastEventAt, the WS missed
|
|
68
|
+
* a fill and the probe forces a reconnect. 0 = disabled. Default 60_000. */
|
|
69
|
+
activeProbeIntervalMs?: number;
|
|
70
|
+
/** Audit-trail write path (TRADE_AUDIT_TRAIL_PLAN Phase 1).
|
|
71
|
+
* 'off' (default) — WS ingest doesn't write to the trades table.
|
|
72
|
+
* 'on' — WsIngest forwards each TRADE event to the webapp's
|
|
73
|
+
* /api/internal/trades endpoint. Idempotent on the
|
|
74
|
+
* (exchange, exchange_trade_id) unique index, so it's
|
|
75
|
+
* safe to run alongside the legacy poller-write path.
|
|
76
|
+
* Orthogonal to `mode`: `mode` controls the read path; `dbWrite` controls
|
|
77
|
+
* the audit-write path. Both must be enabled (mode≠'off' AND dbWrite='on')
|
|
78
|
+
* for WS rows to land in the trades table. */
|
|
79
|
+
dbWrite?: 'off' | 'on';
|
|
80
|
+
/** Webapp base URL for the WS ingest POST. Defaults to the production
|
|
81
|
+
* reefclaw.com if absent; an explicit value overrides for staging /
|
|
82
|
+
* local-dev / on-prem deployments. */
|
|
83
|
+
ingestBaseUrl?: string;
|
|
84
|
+
};
|
|
85
|
+
/** Position Decision Journal — per-heartbeat-per-open-position review tool
|
|
86
|
+
* + stale-review gate. See docs/POSITION_DECISION_JOURNAL_PLAN.md.
|
|
87
|
+
*
|
|
88
|
+
* mode='off' (default) — `record_position_reviews` tool exists but no
|
|
89
|
+
* SKILL.md mandate; stale-gate is no-op.
|
|
90
|
+
* mode='shadow' — SKILL.md mandate live; per-heartbeat call required.
|
|
91
|
+
* No gate. Operator reads reviews to confirm quality.
|
|
92
|
+
* mode='observe' — `create_order` returns soft warning on stale review.
|
|
93
|
+
* mode='enforce' — `create_order` hard-rejects on stale review.
|
|
94
|
+
*
|
|
95
|
+
* staleAfterMs caps how old the most recent review can be before the gate
|
|
96
|
+
* fires. Default = 2 × heartbeatIntervalMs (60 min for a 30 min heartbeat).
|
|
97
|
+
*
|
|
98
|
+
* Entry/close auto-capture is always-on (independent of `mode`) once the
|
|
99
|
+
* webapp ingest URL + token are configured. */
|
|
100
|
+
positionReview?: {
|
|
101
|
+
mode?: 'off' | 'shadow' | 'observe' | 'enforce';
|
|
102
|
+
staleAfterMs?: number;
|
|
103
|
+
/** Exit-gate flag — prevents premature close_position calls per
|
|
104
|
+
* docs/EXIT_GATE_DESIGN.md. Orthogonal to `mode`: `mode` drives the
|
|
105
|
+
* per-heartbeat review requirement; `exitGate` drives the per-exit
|
|
106
|
+
* tier check.
|
|
107
|
+
*
|
|
108
|
+
* exitGate='off' (default) — gate never runs; behaviour identical to today.
|
|
109
|
+
* exitGate='shadow' — gate runs, result logged to close_assessment.metadata.gate_eval,
|
|
110
|
+
* `close_position` always proceeds.
|
|
111
|
+
* exitGate='observe' — gate runs; on BLOCK returns a soft warning in the
|
|
112
|
+
* tool result but `close_position` still proceeds.
|
|
113
|
+
* exitGate='enforce' — gate runs; on BLOCK rejects the tool call. */
|
|
114
|
+
exitGate?: 'off' | 'shadow' | 'observe' | 'enforce';
|
|
115
|
+
};
|
|
116
|
+
/** Approval Mode — per-user operator-approval-before-trade gate.
|
|
117
|
+
* Plugin emits a proposal via /api/internal/proposed_orders; operator decides
|
|
118
|
+
* in the browser; ProposalDecisionListener fires the order on approve via the
|
|
119
|
+
* existing create_order backend path. See docs/APPROVAL_MODE_DESIGN.md.
|
|
120
|
+
*
|
|
121
|
+
* mode='off' (default) — fully autonomous; create_order fires immediately.
|
|
122
|
+
* Toggle-off is byte-identical to today's behaviour.
|
|
123
|
+
* mode='per_trade' — every create_order emits a proposal and returns
|
|
124
|
+
* {status:'pending_approval'} to the agent. Listener
|
|
125
|
+
* fires the order when the operator clicks Approve.
|
|
126
|
+
*
|
|
127
|
+
* pollIntervalMs caps how often the listener checks for approved-but-unfired
|
|
128
|
+
* proposals via GET /api/internal/proposed_orders/pending-decisions. Default
|
|
129
|
+
* 3 sec — well under typical human approval latency. */
|
|
130
|
+
approval?: {
|
|
131
|
+
mode?: 'off' | 'per_trade';
|
|
132
|
+
pollIntervalMs?: number;
|
|
133
|
+
};
|
|
134
|
+
/** Public Binance market microstructure features (cross-market liquidation
|
|
135
|
+
* pulse + banded resting liquidity). Data layer lives on the intelligence
|
|
136
|
+
* VPS (separate workstream — see docs/MARKET_MICROSTRUCTURE_STREAMS.md);
|
|
137
|
+
* this flag controls whether the plugin attaches a per-symbol microstructure
|
|
138
|
+
* block to position-aware tool results (e.g. check_position_health) so the
|
|
139
|
+
* agent sees orderbook context every heartbeat without an extra tool call.
|
|
140
|
+
*
|
|
141
|
+
* heartbeatPush='off' (default) — no auto-attach. Agent can still call
|
|
142
|
+
* get_resting_liquidity / get_liquidation_pulse
|
|
143
|
+
* explicitly.
|
|
144
|
+
* heartbeatPush='on' — block attached when intel data is fresh. */
|
|
145
|
+
microstructure?: {
|
|
146
|
+
heartbeatPush?: 'off' | 'on';
|
|
147
|
+
};
|
|
148
|
+
/** EFFICIENCY_QUICK_WINS Change 1 — operator override for the legacy
|
|
149
|
+
* PositionWatcher poll cadence. Default 10000 (see stop-watcher.ts).
|
|
150
|
+
* Lets the operator revert the 3s→10s cut with zero deploy if a soak
|
|
151
|
+
* criterion fails. */
|
|
152
|
+
stopWatcher?: {
|
|
153
|
+
intervalMs?: number;
|
|
154
|
+
};
|
|
155
|
+
[extra: string]: unknown;
|
|
156
|
+
}
|
|
157
|
+
export declare function defaultConfigPath(): string;
|
|
158
|
+
/** Read the config file. Returns `{}` if the file doesn't exist.
|
|
159
|
+
* Throws if the file exists but is unreadable or not valid JSON — callers
|
|
160
|
+
* should treat that as an abort signal, not silently overwrite. */
|
|
161
|
+
export declare function readPluginConfig(path?: string): PluginConfigFile;
|
|
162
|
+
/** Apply a patch on top of the existing file and write atomically.
|
|
163
|
+
* - Unknown top-level keys in the on-disk file are preserved.
|
|
164
|
+
* - Unknown sub-keys of `microLive` are preserved.
|
|
165
|
+
* - Passing `undefined` as a top-level patch value deletes that key.
|
|
166
|
+
* - A `null` for `exchange` clears credentials.
|
|
167
|
+
*
|
|
168
|
+
* Atomicity: we write to `<path>.tmp` then rename. If the process crashes
|
|
169
|
+
* mid-write, the original file is untouched. A stale `.tmp` is overwritten
|
|
170
|
+
* on the next successful write.
|
|
171
|
+
*/
|
|
172
|
+
export declare function updatePluginConfig(patch: Partial<PluginConfigFile>, path?: string): PluginConfigFile;
|
|
173
|
+
/** Redact a credential for logging — keeps first 4 and last 2 chars.
|
|
174
|
+
* Never log the full key/secret. */
|
|
175
|
+
export declare function redactCredential(value: string | undefined | null): string;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Atomic read/write for ~/.reefclaw/plugin-config.json.
|
|
2
|
+
//
|
|
3
|
+
// Historically the plugin only READ this file at startup. As of PR1 of the
|
|
4
|
+
// dashboard onboarding feature, the plugin also WRITES it when the operator
|
|
5
|
+
// sets credentials or switches trading mode from the webapp. Writes must be
|
|
6
|
+
// crash-safe (no half-written JSON) and must preserve keys we don't understand
|
|
7
|
+
// (forwards compatibility — other tools may add fields we don't know about).
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
export function defaultConfigPath() {
|
|
12
|
+
return join(homedir(), '.reefclaw', 'plugin-config.json');
|
|
13
|
+
}
|
|
14
|
+
/** Read the config file. Returns `{}` if the file doesn't exist.
|
|
15
|
+
* Throws if the file exists but is unreadable or not valid JSON — callers
|
|
16
|
+
* should treat that as an abort signal, not silently overwrite. */
|
|
17
|
+
export function readPluginConfig(path = defaultConfigPath()) {
|
|
18
|
+
if (!existsSync(path))
|
|
19
|
+
return {};
|
|
20
|
+
const raw = readFileSync(path, 'utf-8');
|
|
21
|
+
const parsed = JSON.parse(raw);
|
|
22
|
+
if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
23
|
+
throw new Error(`plugin-config.json root is not an object`);
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
/** Apply a patch on top of the existing file and write atomically.
|
|
28
|
+
* - Unknown top-level keys in the on-disk file are preserved.
|
|
29
|
+
* - Unknown sub-keys of `microLive` are preserved.
|
|
30
|
+
* - Passing `undefined` as a top-level patch value deletes that key.
|
|
31
|
+
* - A `null` for `exchange` clears credentials.
|
|
32
|
+
*
|
|
33
|
+
* Atomicity: we write to `<path>.tmp` then rename. If the process crashes
|
|
34
|
+
* mid-write, the original file is untouched. A stale `.tmp` is overwritten
|
|
35
|
+
* on the next successful write.
|
|
36
|
+
*/
|
|
37
|
+
export function updatePluginConfig(patch, path = defaultConfigPath()) {
|
|
38
|
+
const dir = dirname(path);
|
|
39
|
+
if (!existsSync(dir)) {
|
|
40
|
+
mkdirSync(dir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
const current = readPluginConfig(path);
|
|
43
|
+
const merged = { ...current };
|
|
44
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
delete merged[key];
|
|
47
|
+
}
|
|
48
|
+
else if (key === 'microLive' && value && typeof value === 'object') {
|
|
49
|
+
merged.microLive = { ...(current.microLive ?? {}), ...value };
|
|
50
|
+
}
|
|
51
|
+
else if (key === 'brackets' && value && typeof value === 'object') {
|
|
52
|
+
merged.brackets = { ...(current.brackets ?? {}), ...value };
|
|
53
|
+
}
|
|
54
|
+
else if (key === 'userDataStream' && value && typeof value === 'object') {
|
|
55
|
+
merged.userDataStream = { ...(current.userDataStream ?? {}), ...value };
|
|
56
|
+
}
|
|
57
|
+
else if (key === 'positionReview' && value && typeof value === 'object') {
|
|
58
|
+
merged.positionReview = { ...(current.positionReview ?? {}), ...value };
|
|
59
|
+
}
|
|
60
|
+
else if (key === 'microstructure' && value && typeof value === 'object') {
|
|
61
|
+
merged.microstructure = { ...(current.microstructure ?? {}), ...value };
|
|
62
|
+
}
|
|
63
|
+
else if (key === 'approval' && value && typeof value === 'object') {
|
|
64
|
+
merged.approval = { ...(current.approval ?? {}), ...value };
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
merged[key] = value;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const tmpPath = `${path}.tmp`;
|
|
71
|
+
const body = JSON.stringify(merged, null, 2) + '\n';
|
|
72
|
+
writeFileSync(tmpPath, body, { encoding: 'utf-8', mode: 0o600 });
|
|
73
|
+
renameSync(tmpPath, path);
|
|
74
|
+
return merged;
|
|
75
|
+
}
|
|
76
|
+
/** Redact a credential for logging — keeps first 4 and last 2 chars.
|
|
77
|
+
* Never log the full key/secret. */
|
|
78
|
+
export function redactCredential(value) {
|
|
79
|
+
if (!value)
|
|
80
|
+
return '(empty)';
|
|
81
|
+
if (value.length <= 8)
|
|
82
|
+
return '***';
|
|
83
|
+
return `${value.slice(0, 4)}…${value.slice(-2)}`;
|
|
84
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type PluginConfigFile } from './plugin-config-io.js';
|
|
2
|
+
export type PositionReviewMode = 'off' | 'shadow' | 'observe' | 'enforce';
|
|
3
|
+
export declare function getPositionReviewMode(config?: PluginConfigFile): PositionReviewMode;
|
|
4
|
+
/** Resolve the position-review mode with the central-config precedence
|
|
5
|
+
* (TOOL_DISTRIBUTION_ARCHITECTURE.md §11 step 3, slice 3):
|
|
6
|
+
*
|
|
7
|
+
* central (agent_config.gates via gate-store) → plugin-config.json → 'off'
|
|
8
|
+
*
|
|
9
|
+
* The central value is already enum-validated (agent-config-client
|
|
10
|
+
* validateGates) and hot-applies on the next poll. `record_position_reviews`
|
|
11
|
+
* reads this per call (index.ts), so a dashboard/API flip needs NO restart —
|
|
12
|
+
* same mechanics as loadExitGateMode. Kill-switch RC_CENTRAL_GATES=off makes
|
|
13
|
+
* the store report null → the file rules again. (The startup log read at
|
|
14
|
+
* boot may still show the file value until the first poll applies central;
|
|
15
|
+
* it is cosmetic — the behavioural read is per-call.) */
|
|
16
|
+
export declare function loadPositionReviewMode(): PositionReviewMode;
|
|
17
|
+
export type ExitGateMode = 'off' | 'shadow' | 'observe' | 'enforce';
|
|
18
|
+
export declare function getExitGateMode(config?: PluginConfigFile): ExitGateMode;
|
|
19
|
+
/** Resolve the exit-gate mode with the central-config precedence
|
|
20
|
+
* (TOOL_DISTRIBUTION_ARCHITECTURE.md §11 step 3, slice 2):
|
|
21
|
+
*
|
|
22
|
+
* central (agent_config.gates via gate-store) → plugin-config.json → 'off'
|
|
23
|
+
*
|
|
24
|
+
* The central value is already enum-validated (agent-config-client
|
|
25
|
+
* validateGates) and hot-applies on the next poll — close-position.ts reads
|
|
26
|
+
* this per call, so a dashboard/API flip needs NO restart. `deps.exitGateMode`
|
|
27
|
+
* at the call site (tests) stays above all of this. Kill-switch
|
|
28
|
+
* RC_CENTRAL_GATES=off makes the store report null → the file rules again. */
|
|
29
|
+
export declare function loadExitGateMode(): ExitGateMode;
|
|
30
|
+
/** Stale threshold in ms. Default = 60 minutes (2 × 30-min heartbeat). */
|
|
31
|
+
export declare function getPositionReviewStaleAfterMs(config?: PluginConfigFile): number;
|
|
32
|
+
export declare function loadPositionReviewStaleAfterMs(): number;
|
|
33
|
+
export type MicrostructureHeartbeatPush = 'off' | 'on';
|
|
34
|
+
export declare function getMicrostructureHeartbeatPush(config?: PluginConfigFile): MicrostructureHeartbeatPush;
|
|
35
|
+
export declare function loadMicrostructureHeartbeatPush(): MicrostructureHeartbeatPush;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Feature-flag readers for the Position Decision Journal.
|
|
2
|
+
//
|
|
3
|
+
// Two flags, both default 'off' so the system ships dead-code:
|
|
4
|
+
// - positionReview.mode drives the heartbeat-mandate + stale-gate
|
|
5
|
+
// - microstructure.heartbeatPush drives orderbook auto-attach to per-position tools
|
|
6
|
+
//
|
|
7
|
+
// See docs/POSITION_DECISION_JOURNAL_PLAN.md.
|
|
8
|
+
import { readPluginConfig } from './plugin-config-io.js';
|
|
9
|
+
import { gateStore } from './gate-store.js';
|
|
10
|
+
const VALID_REVIEW_MODES = new Set([
|
|
11
|
+
'off',
|
|
12
|
+
'shadow',
|
|
13
|
+
'observe',
|
|
14
|
+
'enforce',
|
|
15
|
+
]);
|
|
16
|
+
export function getPositionReviewMode(config) {
|
|
17
|
+
const raw = config?.positionReview?.mode;
|
|
18
|
+
if (typeof raw === 'string' && VALID_REVIEW_MODES.has(raw)) {
|
|
19
|
+
return raw;
|
|
20
|
+
}
|
|
21
|
+
return 'off';
|
|
22
|
+
}
|
|
23
|
+
/** Resolve the position-review mode with the central-config precedence
|
|
24
|
+
* (TOOL_DISTRIBUTION_ARCHITECTURE.md §11 step 3, slice 3):
|
|
25
|
+
*
|
|
26
|
+
* central (agent_config.gates via gate-store) → plugin-config.json → 'off'
|
|
27
|
+
*
|
|
28
|
+
* The central value is already enum-validated (agent-config-client
|
|
29
|
+
* validateGates) and hot-applies on the next poll. `record_position_reviews`
|
|
30
|
+
* reads this per call (index.ts), so a dashboard/API flip needs NO restart —
|
|
31
|
+
* same mechanics as loadExitGateMode. Kill-switch RC_CENTRAL_GATES=off makes
|
|
32
|
+
* the store report null → the file rules again. (The startup log read at
|
|
33
|
+
* boot may still show the file value until the first poll applies central;
|
|
34
|
+
* it is cosmetic — the behavioural read is per-call.) */
|
|
35
|
+
export function loadPositionReviewMode() {
|
|
36
|
+
const central = gateStore.getPositionReviewMode();
|
|
37
|
+
if (central)
|
|
38
|
+
return central;
|
|
39
|
+
try {
|
|
40
|
+
return getPositionReviewMode(readPluginConfig());
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return 'off';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const VALID_EXIT_GATE_MODES = new Set([
|
|
47
|
+
'off',
|
|
48
|
+
'shadow',
|
|
49
|
+
'observe',
|
|
50
|
+
'enforce',
|
|
51
|
+
]);
|
|
52
|
+
export function getExitGateMode(config) {
|
|
53
|
+
const raw = config?.positionReview?.exitGate;
|
|
54
|
+
if (typeof raw === 'string' && VALID_EXIT_GATE_MODES.has(raw)) {
|
|
55
|
+
return raw;
|
|
56
|
+
}
|
|
57
|
+
return 'off';
|
|
58
|
+
}
|
|
59
|
+
/** Resolve the exit-gate mode with the central-config precedence
|
|
60
|
+
* (TOOL_DISTRIBUTION_ARCHITECTURE.md §11 step 3, slice 2):
|
|
61
|
+
*
|
|
62
|
+
* central (agent_config.gates via gate-store) → plugin-config.json → 'off'
|
|
63
|
+
*
|
|
64
|
+
* The central value is already enum-validated (agent-config-client
|
|
65
|
+
* validateGates) and hot-applies on the next poll — close-position.ts reads
|
|
66
|
+
* this per call, so a dashboard/API flip needs NO restart. `deps.exitGateMode`
|
|
67
|
+
* at the call site (tests) stays above all of this. Kill-switch
|
|
68
|
+
* RC_CENTRAL_GATES=off makes the store report null → the file rules again. */
|
|
69
|
+
export function loadExitGateMode() {
|
|
70
|
+
const central = gateStore.getExitGate();
|
|
71
|
+
if (central)
|
|
72
|
+
return central;
|
|
73
|
+
try {
|
|
74
|
+
return getExitGateMode(readPluginConfig());
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return 'off';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Stale threshold in ms. Default = 60 minutes (2 × 30-min heartbeat). */
|
|
81
|
+
export function getPositionReviewStaleAfterMs(config) {
|
|
82
|
+
const raw = config?.positionReview?.staleAfterMs;
|
|
83
|
+
if (typeof raw === 'number' && Number.isFinite(raw) && raw > 0)
|
|
84
|
+
return raw;
|
|
85
|
+
return 60 * 60 * 1000;
|
|
86
|
+
}
|
|
87
|
+
export function loadPositionReviewStaleAfterMs() {
|
|
88
|
+
try {
|
|
89
|
+
return getPositionReviewStaleAfterMs(readPluginConfig());
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return 60 * 60 * 1000;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function getMicrostructureHeartbeatPush(config) {
|
|
96
|
+
return config?.microstructure?.heartbeatPush === 'on' ? 'on' : 'off';
|
|
97
|
+
}
|
|
98
|
+
export function loadMicrostructureHeartbeatPush() {
|
|
99
|
+
try {
|
|
100
|
+
return getMicrostructureHeartbeatPush(readPluginConfig());
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return 'off';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Safety-floor (core) tools + operator-control tools. Never governable. */
|
|
2
|
+
export declare const UNGOVERNABLE_TOOLS: ReadonlySet<string>;
|
|
3
|
+
export type ToolGateMode = 'enforce' | 'shadow' | 'off';
|
|
4
|
+
/** RC_TOOL_GATE: 'off' = kill-switch (gate never blocks), 'shadow' = log
|
|
5
|
+
* would-be blocks but execute anyway, anything else/default = 'enforce'.
|
|
6
|
+
* Kill-switch convention per the plugin's other RC_* flags: a systemd env
|
|
7
|
+
* override flips it instantly on restart, no redeploy. */
|
|
8
|
+
export declare function resolveToolGateMode(): ToolGateMode;
|
|
9
|
+
/** The structured, agent-visible result for a blocked call. Worded so the
|
|
10
|
+
* agent adapts instead of retrying. */
|
|
11
|
+
export declare function disabledToolResult(name: string): {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: 'tool_disabled_by_operator';
|
|
14
|
+
tool: string;
|
|
15
|
+
message: string;
|
|
16
|
+
};
|
|
17
|
+
/** Minimal structural view of a registered plugin tool. `execute` is variadic
|
|
18
|
+
* (toolCallId, params, signal?) and typed loosely to match the plugin-boundary
|
|
19
|
+
* PluginTool interface in index.ts, which itself uses `any` for params. The
|
|
20
|
+
* generic in wrapTool preserves the concrete tool shape (label, description,
|
|
21
|
+
* parameters, …). */
|
|
22
|
+
export interface GateablePluginTool {
|
|
23
|
+
name: string;
|
|
24
|
+
execute: (...args: any[]) => any;
|
|
25
|
+
}
|
|
26
|
+
export declare class ToolGate {
|
|
27
|
+
private readonly mode;
|
|
28
|
+
private disabled;
|
|
29
|
+
private version;
|
|
30
|
+
/** Names already shadow-logged for the current version — avoids log spam. */
|
|
31
|
+
private shadowLogged;
|
|
32
|
+
constructor(mode?: ToolGateMode);
|
|
33
|
+
getMode(): ToolGateMode;
|
|
34
|
+
getVersion(): number;
|
|
35
|
+
getDisabled(): string[];
|
|
36
|
+
/** Apply a validated config. Strips ungovernable names (third enforcement
|
|
37
|
+
* layer — the webapp write route and internal read route already did), and
|
|
38
|
+
* logs only when the effective set actually changed. */
|
|
39
|
+
apply(config: {
|
|
40
|
+
version: number;
|
|
41
|
+
tools: {
|
|
42
|
+
disabled: string[];
|
|
43
|
+
};
|
|
44
|
+
}): void;
|
|
45
|
+
/** Should this call be blocked? Ungovernable names short-circuit FIRST —
|
|
46
|
+
* the safety floor wins over any disabled set, in any mode. */
|
|
47
|
+
isBlocked(name: string): boolean;
|
|
48
|
+
/** Wrap a tool's execute with the gate check. The returned tool is
|
|
49
|
+
* identical except `execute` consults the gate's live state per call —
|
|
50
|
+
* which is what makes a config change hot-apply without re-registration.
|
|
51
|
+
* All original args (toolCallId, params, abort signal) pass through. */
|
|
52
|
+
wrapTool<T extends GateablePluginTool>(tool: T, jsonResult: (data: unknown) => unknown): T;
|
|
53
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// ToolGate — the plugin-side enforcement point for the Tools-tab OFF-list
|
|
2
|
+
// (docs/TOOL_DISTRIBUTION_ARCHITECTURE.md §5f). Every registered tool's
|
|
3
|
+
// `execute` is wrapped once at registration; the wrapper consults the gate's
|
|
4
|
+
// LIVE state on every invocation, so a config change applies on the next call
|
|
5
|
+
// with no re-registration and no restart (§5e hot-reload).
|
|
6
|
+
//
|
|
7
|
+
// ★ §5d SAFETY FLOOR — UNGOVERNABLE_TOOLS is hardcoded here and checked
|
|
8
|
+
// BEFORE the disabled set. Even if a compromised config server, a hand-edited
|
|
9
|
+
// DB row, or a poisoned cache ships `close_position` in the OFF-list, the
|
|
10
|
+
// gate never blocks it. This set is pinned by a test on this side AND a
|
|
11
|
+
// mirror pin in the webapp catalog (tools-catalog.test.ts) — change both
|
|
12
|
+
// deliberately or not at all.
|
|
13
|
+
import { logger } from '../logger.js';
|
|
14
|
+
const TAG = 'tool-gate';
|
|
15
|
+
/** Safety-floor (core) tools + operator-control tools. Never governable. */
|
|
16
|
+
export const UNGOVERNABLE_TOOLS = new Set([
|
|
17
|
+
// Core safety floor — protecting/exiting positions and the review capture.
|
|
18
|
+
'create_order',
|
|
19
|
+
'close_position',
|
|
20
|
+
'modify_stop',
|
|
21
|
+
'attach_brackets',
|
|
22
|
+
'audit_bracket_protection',
|
|
23
|
+
'record_position_reviews',
|
|
24
|
+
// Operator-control channel — disabling these would lock the operator out.
|
|
25
|
+
'set_exchange_credentials',
|
|
26
|
+
'test_exchange_credentials',
|
|
27
|
+
'clear_exchange_credentials',
|
|
28
|
+
'set_trading_mode',
|
|
29
|
+
'get_bracket_config',
|
|
30
|
+
'set_bracket_requirement',
|
|
31
|
+
]);
|
|
32
|
+
/** RC_TOOL_GATE: 'off' = kill-switch (gate never blocks), 'shadow' = log
|
|
33
|
+
* would-be blocks but execute anyway, anything else/default = 'enforce'.
|
|
34
|
+
* Kill-switch convention per the plugin's other RC_* flags: a systemd env
|
|
35
|
+
* override flips it instantly on restart, no redeploy. */
|
|
36
|
+
export function resolveToolGateMode() {
|
|
37
|
+
const raw = (process.env.RC_TOOL_GATE ?? '').toLowerCase();
|
|
38
|
+
if (raw === 'off')
|
|
39
|
+
return 'off';
|
|
40
|
+
if (raw === 'shadow')
|
|
41
|
+
return 'shadow';
|
|
42
|
+
return 'enforce';
|
|
43
|
+
}
|
|
44
|
+
/** The structured, agent-visible result for a blocked call. Worded so the
|
|
45
|
+
* agent adapts instead of retrying. */
|
|
46
|
+
export function disabledToolResult(name) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
error: 'tool_disabled_by_operator',
|
|
50
|
+
tool: name,
|
|
51
|
+
message: `The ${name} tool has been disabled by your operator in the ReefClaw dashboard Tools tab. ` +
|
|
52
|
+
`Do not retry this call — adapt your plan without it, and mention to your operator that ` +
|
|
53
|
+
`re-enabling it in the dashboard would help if you believe it is needed.`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export class ToolGate {
|
|
57
|
+
mode;
|
|
58
|
+
disabled = new Set();
|
|
59
|
+
version = 0;
|
|
60
|
+
/** Names already shadow-logged for the current version — avoids log spam. */
|
|
61
|
+
shadowLogged = new Set();
|
|
62
|
+
constructor(mode = resolveToolGateMode()) {
|
|
63
|
+
this.mode = mode;
|
|
64
|
+
if (mode !== 'enforce')
|
|
65
|
+
logger.info(TAG, `mode=${mode}`);
|
|
66
|
+
}
|
|
67
|
+
getMode() {
|
|
68
|
+
return this.mode;
|
|
69
|
+
}
|
|
70
|
+
getVersion() {
|
|
71
|
+
return this.version;
|
|
72
|
+
}
|
|
73
|
+
getDisabled() {
|
|
74
|
+
return [...this.disabled].sort();
|
|
75
|
+
}
|
|
76
|
+
/** Apply a validated config. Strips ungovernable names (third enforcement
|
|
77
|
+
* layer — the webapp write route and internal read route already did), and
|
|
78
|
+
* logs only when the effective set actually changed. */
|
|
79
|
+
apply(config) {
|
|
80
|
+
const next = new Set(config.tools.disabled.filter((n) => !UNGOVERNABLE_TOOLS.has(n)));
|
|
81
|
+
const changed = next.size !== this.disabled.size || [...next].some((n) => !this.disabled.has(n));
|
|
82
|
+
this.version = config.version;
|
|
83
|
+
if (!changed)
|
|
84
|
+
return;
|
|
85
|
+
this.disabled = next;
|
|
86
|
+
this.shadowLogged.clear();
|
|
87
|
+
logger.info(TAG, `applied config v${config.version}: ${next.size} tool(s) disabled${next.size > 0 ? ` (${[...next].sort().join(', ')})` : ''}`);
|
|
88
|
+
}
|
|
89
|
+
/** Should this call be blocked? Ungovernable names short-circuit FIRST —
|
|
90
|
+
* the safety floor wins over any disabled set, in any mode. */
|
|
91
|
+
isBlocked(name) {
|
|
92
|
+
if (this.mode === 'off')
|
|
93
|
+
return false;
|
|
94
|
+
if (UNGOVERNABLE_TOOLS.has(name))
|
|
95
|
+
return false;
|
|
96
|
+
if (!this.disabled.has(name))
|
|
97
|
+
return false;
|
|
98
|
+
if (this.mode === 'shadow') {
|
|
99
|
+
if (!this.shadowLogged.has(name)) {
|
|
100
|
+
this.shadowLogged.add(name);
|
|
101
|
+
logger.info(TAG, `SHADOW: would block ${name} (config v${this.version})`);
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
/** Wrap a tool's execute with the gate check. The returned tool is
|
|
108
|
+
* identical except `execute` consults the gate's live state per call —
|
|
109
|
+
* which is what makes a config change hot-apply without re-registration.
|
|
110
|
+
* All original args (toolCallId, params, abort signal) pass through. */
|
|
111
|
+
wrapTool(tool, jsonResult) {
|
|
112
|
+
const originalExecute = tool.execute.bind(tool);
|
|
113
|
+
return {
|
|
114
|
+
...tool,
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
116
|
+
execute: (...args) => {
|
|
117
|
+
if (this.isBlocked(tool.name)) {
|
|
118
|
+
logger.info(TAG, `blocked ${tool.name} (disabled by operator, config v${this.version})`);
|
|
119
|
+
return Promise.resolve(jsonResult(disabledToolResult(tool.name)));
|
|
120
|
+
}
|
|
121
|
+
return originalExecute(...args);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type PluginConfigFile } from './plugin-config-io.js';
|
|
2
|
+
export type UserDataStreamMode = 'off' | 'shadow' | 'observe' | 'enforce';
|
|
3
|
+
/** Production-safe defaults. Override via plugin-config for runbook use only. */
|
|
4
|
+
export interface UserDataStreamTunables {
|
|
5
|
+
/** How often to call PUT /fapi/v1/listenKey to keep the stream alive.
|
|
6
|
+
* Binance kills the key after 60 min of no keepalive; 25 min gives a 2x
|
|
7
|
+
* safety margin under jitter and transient failures. */
|
|
8
|
+
listenKeyRefreshMs: number;
|
|
9
|
+
/** Initial backoff delay after a WS disconnect. Doubles on each attempt
|
|
10
|
+
* up to reconnectCapMs. ±20% jitter applied to avoid thundering herd. */
|
|
11
|
+
reconnectBaseMs: number;
|
|
12
|
+
/** Cap on the exponential backoff. Keeps us trying indefinitely but not
|
|
13
|
+
* more than once/minute after repeated failures. */
|
|
14
|
+
reconnectCapMs: number;
|
|
15
|
+
/** If no WS frame of any kind (message, ping, or pong) arrives within this
|
|
16
|
+
* window, force a reconnect. Binance documents server pings every 3 min on
|
|
17
|
+
* the user-data stream; a 6-min default catches a truly dead socket while
|
|
18
|
+
* remaining quiet on calm accounts that get only the periodic pings. */
|
|
19
|
+
staleEventWatchdogMs: number;
|
|
20
|
+
/** How often to REST-refresh algo (STOP_MARKET / TAKE_PROFIT_MARKET / bracket)
|
|
21
|
+
* orders into the store. Binance's user-data WS does NOT emit
|
|
22
|
+
* ORDER_TRADE_UPDATE for algo orders until they trigger, so the store has no
|
|
23
|
+
* other way to observe algo-order add/cancel events. Without this loop, the
|
|
24
|
+
* 60s truth-check reports MAJOR order drift every cycle any time brackets
|
|
25
|
+
* are touched. Set to 0 to disable (falls back to snapshot-only). */
|
|
26
|
+
algoRefreshMs: number;
|
|
27
|
+
/** @deprecated since 2026-04-25 (ping-aware watchdog refactor). Field kept
|
|
28
|
+
* for backward compatibility with existing plugin-config.json files; the
|
|
29
|
+
* runtime no longer consults it. Empirically 99% of its fires were
|
|
30
|
+
* false positives because the 90 s default sat below Binance's 180 s
|
|
31
|
+
* server-ping interval and the watchdog only counted message frames as
|
|
32
|
+
* liveness. The single `staleEventWatchdogMs` (6 min default, ping-aware)
|
|
33
|
+
* is now sufficient; the active REST probe handles per-position freshness. */
|
|
34
|
+
activeStaleEventWatchdogMs: number;
|
|
35
|
+
/** How often the active REST probe checks for fills the WS missed.
|
|
36
|
+
* Iterates open positions, calls fetchMyTrades(since=lastEventAt), and
|
|
37
|
+
* forces a reconnect if any trade newer than lastEventAt is found.
|
|
38
|
+
* Set to 0 to disable. Cost: ~5 weight per open position per probe. */
|
|
39
|
+
activeProbeIntervalMs: number;
|
|
40
|
+
}
|
|
41
|
+
export declare const DEFAULT_TUNABLES: UserDataStreamTunables;
|
|
42
|
+
/** Read user-data-stream mode from a config object. Invalid values fall back to 'off'. */
|
|
43
|
+
export declare function getUserDataStreamMode(config?: PluginConfigFile, remoteOverride?: UserDataStreamMode): UserDataStreamMode;
|
|
44
|
+
/** Convenience: load from disk and return the effective mode. */
|
|
45
|
+
export declare function loadUserDataStreamMode(): UserDataStreamMode;
|
|
46
|
+
/** Is the WS stream enabled at all (anything other than 'off')? */
|
|
47
|
+
export declare function userDataStreamEnabled(mode: UserDataStreamMode): boolean;
|
|
48
|
+
export type UserDataStreamDbWrite = 'off' | 'on';
|
|
49
|
+
/** Read the dbWrite flag. Orthogonal to `mode`: `mode` controls the read
|
|
50
|
+
* path (WS vs REST authoritative for getPositions etc.); `dbWrite` controls
|
|
51
|
+
* whether WS-observed fills are POSTed to the webapp's audit-trail store.
|
|
52
|
+
* Both must be enabled together for WS rows to land in `trades`. */
|
|
53
|
+
export declare function getUserDataStreamDbWrite(config?: PluginConfigFile): UserDataStreamDbWrite;
|
|
54
|
+
export declare function loadUserDataStreamDbWrite(): UserDataStreamDbWrite;
|
|
55
|
+
/** Webapp ingest base URL (POST target). Defaults to production reefclaw.com. */
|
|
56
|
+
export declare function getUserDataStreamIngestBaseUrl(config?: PluginConfigFile): string;
|
|
57
|
+
/** Resolve the webapp-ingest credential (the per-user `rc_*` token).
|
|
58
|
+
*
|
|
59
|
+
* Prefers `connectionToken` in plugin-config.json — the same `rc_*` token
|
|
60
|
+
* already stored there for the intel-service client, so there's one fewer
|
|
61
|
+
* place to update on rotation than the legacy `WEBAPP_INGEST_TOKEN` systemd
|
|
62
|
+
* env var. Falls back to that env var so existing deployments that haven't
|
|
63
|
+
* moved the token into plugin-config.json keep working unchanged.
|
|
64
|
+
*
|
|
65
|
+
* Both ingest paths (position-decisions journal + WS audit-trail) use this. */
|
|
66
|
+
export declare function resolveIngestToken(config?: PluginConfigFile): string;
|
|
67
|
+
/** Is the WS authoritative for reads (observe or enforce)? In shadow it's
|
|
68
|
+
* only observed — REST remains the source of truth for getPositions etc. */
|
|
69
|
+
export declare function userDataStreamAuthoritative(mode: UserDataStreamMode): boolean;
|
|
70
|
+
/** Should REST polling cadence be reduced? True in observe/enforce where
|
|
71
|
+
* WS is carrying the hot-path signal and REST is only a truth-check. */
|
|
72
|
+
export declare function restPollingReduced(mode: UserDataStreamMode): boolean;
|
|
73
|
+
/** Read tunables, falling back to DEFAULT_TUNABLES for any missing field.
|
|
74
|
+
* Clamps are defense-in-depth against a truncated or nonsensical config. */
|
|
75
|
+
export declare function getUserDataStreamTunables(config?: PluginConfigFile): UserDataStreamTunables;
|
|
76
|
+
export declare function loadUserDataStreamTunables(): UserDataStreamTunables;
|
|
77
|
+
/** Validate a proposed transition. Returns `{ allowed: false, reason }` when
|
|
78
|
+
* the move is blocked so the deploy script can refuse. Forward transitions
|
|
79
|
+
* must progress through stages; reverse transitions (to any earlier stage,
|
|
80
|
+
* including 'off') are always permitted as a safety-net rollback. */
|
|
81
|
+
export interface TransitionCheck {
|
|
82
|
+
allowed: boolean;
|
|
83
|
+
reason?: string;
|
|
84
|
+
}
|
|
85
|
+
export declare function checkTransition(from: UserDataStreamMode, to: UserDataStreamMode): TransitionCheck;
|