@reefclaw/openclaw-plugin 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/.gitignore +8 -0
- package/audit/mode-transition-audit.d.ts +11 -0
- package/audit/mode-transition-audit.js +29 -0
- package/balance-utils.d.ts +36 -0
- package/balance-utils.js +98 -0
- package/bridge/bridge.d.ts +109 -0
- package/bridge/bridge.js +1036 -0
- package/bridge/config.d.ts +43 -0
- package/bridge/config.js +176 -0
- package/bridge/connector.d.ts +52 -0
- package/bridge/connector.js +293 -0
- package/bridge/event-replay-buffer.d.ts +43 -0
- package/bridge/event-replay-buffer.js +109 -0
- package/bridge/gateway/event-parser.d.ts +209 -0
- package/bridge/gateway/event-parser.js +793 -0
- package/bridge/gateway/gateway-config.d.ts +39 -0
- package/bridge/gateway/gateway-config.js +86 -0
- package/bridge/gateway/gateway-http-client.d.ts +50 -0
- package/bridge/gateway/gateway-http-client.js +165 -0
- package/bridge/gateway/gateway-ws-client.d.ts +116 -0
- package/bridge/gateway/gateway-ws-client.js +417 -0
- package/bridge/gateway/poller.d.ts +146 -0
- package/bridge/gateway/poller.js +505 -0
- package/bridge/gateway/tool-discovery.d.ts +25 -0
- package/bridge/gateway/tool-discovery.js +198 -0
- package/bridge/index.d.ts +2 -0
- package/bridge/index.js +253 -0
- package/bridge/logger.d.ts +2 -0
- package/bridge/logger.js +2 -0
- package/bridge/provider.d.ts +156 -0
- package/bridge/provider.js +2 -0
- package/bridge/providers/emergency-commands.d.ts +54 -0
- package/bridge/providers/emergency-commands.js +235 -0
- package/bridge/providers/gateway.d.ts +322 -0
- package/bridge/providers/gateway.js +2302 -0
- package/bridge/providers/mock.d.ts +37 -0
- package/bridge/providers/mock.js +385 -0
- package/bridge/providers/onboarding-commands.d.ts +83 -0
- package/bridge/providers/onboarding-commands.js +213 -0
- package/bridge/providers/risk-calculator.d.ts +96 -0
- package/bridge/providers/risk-calculator.js +369 -0
- package/bridge/setup.d.ts +32 -0
- package/bridge/setup.js +226 -0
- package/bridge/types.d.ts +584 -0
- package/bridge/types.js +50 -0
- package/bridge/utils/reconnect.d.ts +6 -0
- package/bridge/utils/reconnect.js +6 -0
- package/bridge/utils/skill-signing.d.ts +51 -0
- package/bridge/utils/skill-signing.js +138 -0
- package/bridge/utils/skill-version.d.ts +17 -0
- package/bridge/utils/skill-version.js +74 -0
- package/ccxt/binance-ban-gate.d.ts +47 -0
- package/ccxt/binance-ban-gate.js +409 -0
- package/ccxt/binance-private.d.ts +325 -0
- package/ccxt/binance-private.js +1415 -0
- package/ccxt/binance-public.d.ts +18 -0
- package/ccxt/binance-public.js +147 -0
- package/config/agent-config-client.d.ts +55 -0
- package/config/agent-config-client.js +145 -0
- package/config/agent-config-poller.d.ts +25 -0
- package/config/agent-config-poller.js +100 -0
- package/config/brackets-config.d.ts +22 -0
- package/config/brackets-config.js +58 -0
- package/config/gate-store.d.ts +18 -0
- package/config/gate-store.js +61 -0
- package/config/plugin-config-io.d.ts +181 -0
- package/config/plugin-config-io.js +84 -0
- package/config/position-review-config.d.ts +35 -0
- package/config/position-review-config.js +105 -0
- package/config/tool-gate.d.ts +53 -0
- package/config/tool-gate.js +125 -0
- package/config/user-data-stream-config.d.ts +85 -0
- package/config/user-data-stream-config.js +224 -0
- package/connector-supervisor.d.ts +36 -0
- package/connector-supervisor.js +149 -0
- package/exchange-adapter.d.ts +49 -0
- package/exchange-adapter.js +4 -0
- package/index.d.ts +30 -0
- package/index.js +2030 -0
- package/ingest/pending-entry-metadata.d.ts +52 -0
- package/ingest/pending-entry-metadata.js +182 -0
- package/ingest/position-auto-capture.d.ts +98 -0
- package/ingest/position-auto-capture.js +394 -0
- package/ingest/position-decisions-client.d.ts +318 -0
- package/ingest/position-decisions-client.js +296 -0
- package/ingest/reconcile-db-vs-exchange.d.ts +13 -0
- package/ingest/reconcile-db-vs-exchange.js +114 -0
- package/ingest/reconciler-cleanup.d.ts +37 -0
- package/ingest/reconciler-cleanup.js +147 -0
- package/ingest/rest-gap-filler.d.ts +191 -0
- package/ingest/rest-gap-filler.js +565 -0
- package/ingest/touched-symbols-store.d.ts +25 -0
- package/ingest/touched-symbols-store.js +96 -0
- package/ingest/trade-store-client.d.ts +40 -0
- package/ingest/trade-store-client.js +125 -0
- package/ingest/ws-ingest.d.ts +43 -0
- package/ingest/ws-ingest.js +126 -0
- package/learning/setup-family.d.ts +21 -0
- package/learning/setup-family.js +103 -0
- package/lifecycle/install-signal-handlers.d.ts +33 -0
- package/lifecycle/install-signal-handlers.js +112 -0
- package/lifecycle/shutdown-coordinator.d.ts +43 -0
- package/lifecycle/shutdown-coordinator.js +131 -0
- package/live/bracket-id.d.ts +18 -0
- package/live/bracket-id.js +81 -0
- package/live/bracket-ledger.d.ts +54 -0
- package/live/bracket-ledger.js +267 -0
- package/live/bracket-manager.d.ts +82 -0
- package/live/bracket-manager.js +478 -0
- package/live/bracket-params.d.ts +22 -0
- package/live/bracket-params.js +124 -0
- package/live/bracket-reconciler.d.ts +95 -0
- package/live/bracket-reconciler.js +573 -0
- package/live/bracket-types.d.ts +102 -0
- package/live/bracket-types.js +8 -0
- package/live/deposit-tracker.d.ts +62 -0
- package/live/deposit-tracker.js +97 -0
- package/live/emergency-controls.d.ts +32 -0
- package/live/emergency-controls.js +226 -0
- package/live/exchange-errors.d.ts +12 -0
- package/live/exchange-errors.js +130 -0
- package/live/exchange-info-cache.d.ts +35 -0
- package/live/exchange-info-cache.js +119 -0
- package/live/fact-subscriber.d.ts +78 -0
- package/live/fact-subscriber.js +182 -0
- package/live/intent-journal.d.ts +42 -0
- package/live/intent-journal.js +122 -0
- package/live/listen-key-manager.d.ts +70 -0
- package/live/listen-key-manager.js +169 -0
- package/live/live-adapter.d.ts +264 -0
- package/live/live-adapter.js +1665 -0
- package/live/live-balance-enricher.d.ts +32 -0
- package/live/live-balance-enricher.js +104 -0
- package/live/live-bracket-api.d.ts +13 -0
- package/live/live-bracket-api.js +20 -0
- package/live/live-state-store.d.ts +194 -0
- package/live/live-state-store.js +450 -0
- package/live/local-signal-service.d.ts +57 -0
- package/live/local-signal-service.js +146 -0
- package/live/local-strategy-evaluator.d.ts +62 -0
- package/live/local-strategy-evaluator.js +127 -0
- package/live/microstructure-assembler.d.ts +54 -0
- package/live/microstructure-assembler.js +148 -0
- package/live/order-poller.d.ts +29 -0
- package/live/order-poller.js +125 -0
- package/live/position-state-store.d.ts +83 -0
- package/live/position-state-store.js +237 -0
- package/live/proposal-decision-listener.d.ts +64 -0
- package/live/proposal-decision-listener.js +288 -0
- package/live/proposal-manager.d.ts +76 -0
- package/live/proposal-manager.js +140 -0
- package/live/rate-limiter.d.ts +47 -0
- package/live/rate-limiter.js +159 -0
- package/live/reconciler.d.ts +39 -0
- package/live/reconciler.js +175 -0
- package/live/setup-buckets.d.ts +7 -0
- package/live/setup-buckets.js +33 -0
- package/live/slippage-tracker.d.ts +45 -0
- package/live/slippage-tracker.js +78 -0
- package/live/stop-watcher.d.ts +34 -0
- package/live/stop-watcher.js +158 -0
- package/live/user-data-active-probe.d.ts +54 -0
- package/live/user-data-active-probe.js +180 -0
- package/live/user-data-stream-controller.d.ts +200 -0
- package/live/user-data-stream-controller.js +579 -0
- package/live/user-data-stream-ws.d.ts +22 -0
- package/live/user-data-stream-ws.js +63 -0
- package/live/user-data-stream.d.ts +243 -0
- package/live/user-data-stream.js +704 -0
- package/logger.d.ts +2 -0
- package/logger.js +2 -0
- package/mfe.d.ts +21 -0
- package/mfe.js +68 -0
- package/onboarding/mode-ladder.d.ts +1 -0
- package/onboarding/mode-ladder.js +3 -0
- package/onboarding/runtime.d.ts +71 -0
- package/onboarding/runtime.js +153 -0
- package/openclaw.plugin.json +94 -0
- package/package.json +27 -0
- package/paper-adapter.d.ts +24 -0
- package/paper-adapter.js +91 -0
- package/persistence/state-manager.d.ts +42 -0
- package/persistence/state-manager.js +164 -0
- package/pinned-plan.d.ts +9 -0
- package/pinned-plan.js +23 -0
- package/risk/pre-trade-check.d.ts +38 -0
- package/risk/pre-trade-check.js +345 -0
- package/risk/pre-trade-types.d.ts +60 -0
- package/risk/pre-trade-types.js +3 -0
- package/scripts/assemble.mjs +114 -0
- package/shadow/shadow-tracker.d.ts +36 -0
- package/shadow/shadow-tracker.js +151 -0
- package/shadow/types.d.ts +42 -0
- package/shadow/types.js +20 -0
- package/shared/indicators-extended.d.ts +52 -0
- package/shared/indicators-extended.js +291 -0
- package/shared/indicators.d.ts +15 -0
- package/shared/indicators.js +114 -0
- package/signals/conditions/registry.d.ts +16 -0
- package/signals/conditions/registry.js +1274 -0
- package/signals/conditions/types.d.ts +1 -0
- package/signals/conditions/types.js +4 -0
- package/signals/direction-rules.d.ts +3 -0
- package/signals/direction-rules.js +24 -0
- package/signals/entry-rules.d.ts +6 -0
- package/signals/entry-rules.js +33 -0
- package/signals/serialize-context.d.ts +4 -0
- package/signals/serialize-context.js +39 -0
- package/signals/stop-rules.d.ts +3 -0
- package/signals/stop-rules.js +48 -0
- package/signals/strategy-adapter.d.ts +14 -0
- package/signals/strategy-adapter.js +122 -0
- package/signals/types.d.ts +1 -0
- package/signals/types.js +8 -0
- package/simulator/exchange-simulator.d.ts +93 -0
- package/simulator/exchange-simulator.js +684 -0
- package/simulator/fill-engine.d.ts +53 -0
- package/simulator/fill-engine.js +276 -0
- package/simulator/paper-market-feed.d.ts +26 -0
- package/simulator/paper-market-feed.js +104 -0
- package/simulator/realistic-fills.d.ts +59 -0
- package/simulator/realistic-fills.js +175 -0
- package/simulator/types.d.ts +219 -0
- package/simulator/types.js +43 -0
- package/skills/reefclaw/SKILL.md +97 -0
- package/strategy/builtin-strategies.d.ts +2 -0
- package/strategy/builtin-strategies.js +109 -0
- package/strategy/condition-registry.d.ts +3 -0
- package/strategy/condition-registry.js +153 -0
- package/strategy/evaluator.d.ts +67 -0
- package/strategy/evaluator.js +93 -0
- package/tools/assessment-validation.d.ts +118 -0
- package/tools/assessment-validation.js +415 -0
- package/tools/attach-brackets.d.ts +34 -0
- package/tools/attach-brackets.js +363 -0
- package/tools/audit-bracket-protection.d.ts +49 -0
- package/tools/audit-bracket-protection.js +527 -0
- package/tools/cancel-all-orders.d.ts +7 -0
- package/tools/cancel-all-orders.js +5 -0
- package/tools/cancel-order.d.ts +10 -0
- package/tools/cancel-order.js +14 -0
- package/tools/check-position-health.d.ts +46 -0
- package/tools/check-position-health.js +194 -0
- package/tools/clear-exchange-credentials.d.ts +24 -0
- package/tools/clear-exchange-credentials.js +70 -0
- package/tools/close-position.d.ts +22 -0
- package/tools/close-position.js +449 -0
- package/tools/create-order.d.ts +54 -0
- package/tools/create-order.js +338 -0
- package/tools/exit-gate.d.ts +58 -0
- package/tools/exit-gate.js +162 -0
- package/tools/fetch-balance.d.ts +5 -0
- package/tools/fetch-balance.js +4 -0
- package/tools/fetch-ohlcv.d.ts +11 -0
- package/tools/fetch-ohlcv.js +8 -0
- package/tools/fetch-open-orders.d.ts +7 -0
- package/tools/fetch-open-orders.js +4 -0
- package/tools/fetch-positions.d.ts +7 -0
- package/tools/fetch-positions.js +4 -0
- package/tools/fetch-ticker.d.ts +11 -0
- package/tools/fetch-ticker.js +5 -0
- package/tools/get-agent-profile.d.ts +4 -0
- package/tools/get-agent-profile.js +6 -0
- package/tools/get-analytics.d.ts +6 -0
- package/tools/get-analytics.js +7 -0
- package/tools/get-backtest.d.ts +12 -0
- package/tools/get-backtest.js +91 -0
- package/tools/get-basis.d.ts +7 -0
- package/tools/get-basis.js +7 -0
- package/tools/get-bracket-config.d.ts +11 -0
- package/tools/get-bracket-config.js +24 -0
- package/tools/get-cascade-risk.d.ts +7 -0
- package/tools/get-cascade-risk.js +8 -0
- package/tools/get-crypto-metrics.d.ts +18 -0
- package/tools/get-crypto-metrics.js +45 -0
- package/tools/get-cvd.d.ts +6 -0
- package/tools/get-cvd.js +6 -0
- package/tools/get-divergences.d.ts +6 -0
- package/tools/get-divergences.js +6 -0
- package/tools/get-funding-context.d.ts +6 -0
- package/tools/get-funding-context.js +16 -0
- package/tools/get-liquidation-levels.d.ts +7 -0
- package/tools/get-liquidation-levels.js +7 -0
- package/tools/get-liquidation-pulse.d.ts +9 -0
- package/tools/get-liquidation-pulse.js +22 -0
- package/tools/get-market-breadth.d.ts +6 -0
- package/tools/get-market-breadth.js +8 -0
- package/tools/get-market-intel.d.ts +19 -0
- package/tools/get-market-intel.js +116 -0
- package/tools/get-market-structure.d.ts +47 -0
- package/tools/get-market-structure.js +198 -0
- package/tools/get-my-mined-patterns.d.ts +20 -0
- package/tools/get-my-mined-patterns.js +61 -0
- package/tools/get-my-proposed-learnings.d.ts +20 -0
- package/tools/get-my-proposed-learnings.js +55 -0
- package/tools/get-my-recent-reviews.d.ts +22 -0
- package/tools/get-my-recent-reviews.js +66 -0
- package/tools/get-orderbook.d.ts +21 -0
- package/tools/get-orderbook.js +32 -0
- package/tools/get-pattern-scan.d.ts +7 -0
- package/tools/get-pattern-scan.js +8 -0
- package/tools/get-regime.d.ts +6 -0
- package/tools/get-regime.js +7 -0
- package/tools/get-relevant-learnings.d.ts +21 -0
- package/tools/get-relevant-learnings.js +65 -0
- package/tools/get-resting-liquidity.d.ts +6 -0
- package/tools/get-resting-liquidity.js +11 -0
- package/tools/get-risk-scenario.d.ts +29 -0
- package/tools/get-risk-scenario.js +47 -0
- package/tools/get-risk-summary.d.ts +51 -0
- package/tools/get-risk-summary.js +118 -0
- package/tools/get-sentiment.d.ts +4 -0
- package/tools/get-sentiment.js +6 -0
- package/tools/get-session-review.d.ts +7 -0
- package/tools/get-session-review.js +8 -0
- package/tools/get-setup-detail.d.ts +7 -0
- package/tools/get-setup-detail.js +303 -0
- package/tools/get-signals.d.ts +15 -0
- package/tools/get-signals.js +54 -0
- package/tools/get-sizing.d.ts +6 -0
- package/tools/get-sizing.js +6 -0
- package/tools/get-trade-feedback.d.ts +7 -0
- package/tools/get-trade-feedback.js +8 -0
- package/tools/get-trade-flow.d.ts +7 -0
- package/tools/get-trade-flow.js +7 -0
- package/tools/get-volume-analysis.d.ts +21 -0
- package/tools/get-volume-analysis.js +74 -0
- package/tools/get-volume-profile.d.ts +7 -0
- package/tools/get-volume-profile.js +7 -0
- package/tools/helpers.d.ts +25 -0
- package/tools/helpers.js +38 -0
- package/tools/intel-api.d.ts +14 -0
- package/tools/intel-api.js +52 -0
- package/tools/intel-cache.d.ts +25 -0
- package/tools/intel-cache.js +133 -0
- package/tools/list-strategies.d.ts +7 -0
- package/tools/list-strategies.js +6 -0
- package/tools/modify-stop.d.ts +17 -0
- package/tools/modify-stop.js +81 -0
- package/tools/modify-target.d.ts +17 -0
- package/tools/modify-target.js +71 -0
- package/tools/propose-learning.d.ts +22 -0
- package/tools/propose-learning.js +65 -0
- package/tools/query-review-outcomes.d.ts +30 -0
- package/tools/query-review-outcomes.js +64 -0
- package/tools/query-trades.d.ts +21 -0
- package/tools/query-trades.js +37 -0
- package/tools/record-position-reviews.d.ts +38 -0
- package/tools/record-position-reviews.js +147 -0
- package/tools/save-strategy.d.ts +16 -0
- package/tools/save-strategy.js +46 -0
- package/tools/scan-pairs.d.ts +18 -0
- package/tools/scan-pairs.js +220 -0
- package/tools/score-setup.d.ts +31 -0
- package/tools/score-setup.js +268 -0
- package/tools/set-bracket-requirement.d.ts +18 -0
- package/tools/set-bracket-requirement.js +81 -0
- package/tools/set-exchange-credentials.d.ts +25 -0
- package/tools/set-exchange-credentials.js +80 -0
- package/tools/set-trading-mode.d.ts +26 -0
- package/tools/set-trading-mode.js +135 -0
- package/tools/test-exchange-credentials.d.ts +16 -0
- package/tools/test-exchange-credentials.js +100 -0
- package/tools/toggle-strategy.d.ts +8 -0
- package/tools/toggle-strategy.js +8 -0
- package/trading-params-cache.d.ts +26 -0
- package/trading-params-cache.js +52 -0
- package/types.d.ts +110 -0
- package/types.js +7 -0
- package/util/plugin-paths.d.ts +3 -0
- package/util/plugin-paths.js +15 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Tool auto-discovery for the OpenClaw gateway.
|
|
2
|
+
// Probes for available CCXT trading tools since OpenClaw has no GET /tools endpoint.
|
|
3
|
+
// Builds a ToolMap mapping logical tool names to discovered actual tool names.
|
|
4
|
+
import { logger } from '../logger.js';
|
|
5
|
+
import { GatewayHttpError } from './gateway-http-client.js';
|
|
6
|
+
const TAG = 'tool-discovery';
|
|
7
|
+
const REQUIRED_TOOLS = ['fetch_ticker', 'fetch_balance'];
|
|
8
|
+
const OPTIONAL_TOOLS = [
|
|
9
|
+
'fetch_ohlcv',
|
|
10
|
+
'fetch_positions',
|
|
11
|
+
'fetch_open_orders',
|
|
12
|
+
'cancel_all_orders',
|
|
13
|
+
'cancel_order',
|
|
14
|
+
'close_position',
|
|
15
|
+
'create_order',
|
|
16
|
+
'get_market_structure',
|
|
17
|
+
'get_crypto_metrics',
|
|
18
|
+
'get_market_intel',
|
|
19
|
+
'set_trading_mode',
|
|
20
|
+
'set_exchange_credentials',
|
|
21
|
+
'test_exchange_credentials',
|
|
22
|
+
'clear_exchange_credentials',
|
|
23
|
+
'get_bracket_config',
|
|
24
|
+
'set_bracket_requirement',
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Candidate actual tool names to probe for each logical tool.
|
|
28
|
+
* Ordered by likelihood — first match wins.
|
|
29
|
+
*/
|
|
30
|
+
const CANDIDATES = {
|
|
31
|
+
fetch_ticker: ['fetch_ticker', 'ccxt_fetch_ticker', 'binance_fetch_ticker', 'get_ticker'],
|
|
32
|
+
fetch_balance: ['fetch_balance', 'ccxt_fetch_balance', 'binance_fetch_balance', 'get_balance'],
|
|
33
|
+
fetch_ohlcv: ['fetch_ohlcv', 'ccxt_fetch_ohlcv'],
|
|
34
|
+
fetch_positions: ['fetch_positions', 'fetch_open_positions', 'ccxt_fetch_positions'],
|
|
35
|
+
fetch_open_orders: ['fetch_open_orders', 'ccxt_fetch_open_orders'],
|
|
36
|
+
cancel_all_orders: ['cancel_all_orders', 'ccxt_cancel_all_orders'],
|
|
37
|
+
cancel_order: ['cancel_order', 'ccxt_cancel_order'],
|
|
38
|
+
close_position: ['close_position', 'close_all_positions', 'ccxt_close_position'],
|
|
39
|
+
create_order: ['create_order', 'ccxt_create_order'],
|
|
40
|
+
get_market_structure: ['get_market_structure'],
|
|
41
|
+
get_crypto_metrics: ['get_crypto_metrics'],
|
|
42
|
+
get_market_intel: ['get_market_intel'],
|
|
43
|
+
set_trading_mode: ['set_trading_mode'],
|
|
44
|
+
set_exchange_credentials: ['set_exchange_credentials'],
|
|
45
|
+
test_exchange_credentials: ['test_exchange_credentials'],
|
|
46
|
+
clear_exchange_credentials: ['clear_exchange_credentials'],
|
|
47
|
+
get_bracket_config: ['get_bracket_config'],
|
|
48
|
+
set_bracket_requirement: ['set_bracket_requirement'],
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Test args used when probing each logical tool.
|
|
52
|
+
* Read tools (ticker, balance, etc.) use real args that return data.
|
|
53
|
+
* Write tools (create_order, cancel, close) use args that will be
|
|
54
|
+
* rejected by exchange validation (amount:0, etc.) — we only need
|
|
55
|
+
* to distinguish 400 (tool exists, bad args) from 404 (tool not found).
|
|
56
|
+
*/
|
|
57
|
+
const PROBE_ARGS = {
|
|
58
|
+
fetch_ticker: { symbol: 'BTC/USDT' },
|
|
59
|
+
fetch_balance: {},
|
|
60
|
+
fetch_ohlcv: { symbol: 'BTC/USDT', timeframe: '1h', limit: 1 },
|
|
61
|
+
fetch_positions: { symbol: 'BTC/USDT' },
|
|
62
|
+
fetch_open_orders: { symbol: 'BTC/USDT' },
|
|
63
|
+
// For write tools: probe with minimal args. We expect 400 (bad args) = tool exists.
|
|
64
|
+
cancel_all_orders: { symbol: 'BTC/USDT' },
|
|
65
|
+
cancel_order: { id: 'probe-0', symbol: 'BTC/USDT' },
|
|
66
|
+
close_position: { symbol: 'BTC/USDT' },
|
|
67
|
+
create_order: { symbol: 'BTC/USDT', type: 'limit', side: 'buy', amount: 0, price: 0 },
|
|
68
|
+
get_market_structure: { symbol: 'BTC/USDT' },
|
|
69
|
+
get_crypto_metrics: { symbol: 'BTC/USDT' },
|
|
70
|
+
get_market_intel: { category: 'sentiment' },
|
|
71
|
+
// Safe probe args — plugin tools early-return on invalid input without
|
|
72
|
+
// touching disk. `mode: '__probe__'` fails the VALID_MODES check; empty
|
|
73
|
+
// strings fail the length-8 validator in set_exchange_credentials. Both
|
|
74
|
+
// return HTTP 200 with ok:false, which the probe treats as "tool exists".
|
|
75
|
+
set_trading_mode: { mode: '__probe__' },
|
|
76
|
+
set_exchange_credentials: { apiKey: '', secret: '' },
|
|
77
|
+
// test_exchange_credentials: empty strings fail the length check and
|
|
78
|
+
// early-return without hitting Binance.
|
|
79
|
+
test_exchange_credentials: { apiKey: '', secret: '' },
|
|
80
|
+
// clear_exchange_credentials: tool requires confirm:true. Probing without
|
|
81
|
+
// it triggers the safety gate early-return — tool exists, nothing wiped.
|
|
82
|
+
clear_exchange_credentials: {},
|
|
83
|
+
// Bracket-config probes: no-arg read; set with an invalid flag triggers early-return.
|
|
84
|
+
get_bracket_config: {},
|
|
85
|
+
set_bracket_requirement: { flag: '__probe__', value: false },
|
|
86
|
+
};
|
|
87
|
+
// ---- Discovery logic ----
|
|
88
|
+
/**
|
|
89
|
+
* Probe a single candidate tool name. Returns true if the tool exists.
|
|
90
|
+
*
|
|
91
|
+
* Strategy:
|
|
92
|
+
* - 200: tool exists and invocation succeeded
|
|
93
|
+
* - 400: tool exists but args were bad (still counts as found)
|
|
94
|
+
* - 404: tool does not exist
|
|
95
|
+
* - 401: auth error — rethrow (don't mask)
|
|
96
|
+
* - Other: treat as not found
|
|
97
|
+
*/
|
|
98
|
+
async function probeCandidate(http, candidateName, args) {
|
|
99
|
+
try {
|
|
100
|
+
await http.invoke(candidateName, args, { timeoutMs: 8_000 });
|
|
101
|
+
return true; // 200 — tool exists and works
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err instanceof GatewayHttpError) {
|
|
105
|
+
if (err.status === 400)
|
|
106
|
+
return true; // Tool exists, bad args
|
|
107
|
+
if (err.status === 404)
|
|
108
|
+
return false; // Tool not found
|
|
109
|
+
if (err.status === 401)
|
|
110
|
+
throw err; // Auth error — fatal
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Discover the actual tool name for a logical tool by probing candidates in order.
|
|
117
|
+
* Returns the first candidate that exists, or null if none found.
|
|
118
|
+
*/
|
|
119
|
+
async function discoverTool(http, logical) {
|
|
120
|
+
const candidates = CANDIDATES[logical];
|
|
121
|
+
const args = PROBE_ARGS[logical];
|
|
122
|
+
for (const candidate of candidates) {
|
|
123
|
+
logger.debug(TAG, `Probing ${candidate} for ${logical}...`);
|
|
124
|
+
const exists = await probeCandidate(http, candidate, args);
|
|
125
|
+
if (exists) {
|
|
126
|
+
logger.debug(TAG, `Found: ${logical} → ${candidate}`);
|
|
127
|
+
return candidate;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Discover all available trading tools on the gateway.
|
|
134
|
+
*
|
|
135
|
+
* Probes required tools first, then optional tools in parallel.
|
|
136
|
+
* Fails fast if no required tools are found.
|
|
137
|
+
*/
|
|
138
|
+
export async function discoverTools(http) {
|
|
139
|
+
logger.info(TAG, 'Starting tool auto-discovery...');
|
|
140
|
+
const toolMap = {};
|
|
141
|
+
const found = [];
|
|
142
|
+
const missingRequired = [];
|
|
143
|
+
const missingOptional = [];
|
|
144
|
+
// Discover required tools first (sequentially to fail fast on auth errors)
|
|
145
|
+
for (const logical of REQUIRED_TOOLS) {
|
|
146
|
+
const actual = await discoverTool(http, logical);
|
|
147
|
+
if (actual) {
|
|
148
|
+
toolMap[logical] = actual;
|
|
149
|
+
found.push(logical);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
missingRequired.push(logical);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// If all required tools are missing, log diagnostic and return (caller decides what to do)
|
|
156
|
+
if (found.length === 0) {
|
|
157
|
+
const tried = REQUIRED_TOOLS
|
|
158
|
+
.map(t => `${t}: [${CANDIDATES[t].join(', ')}]`)
|
|
159
|
+
.join('; ');
|
|
160
|
+
logger.warn(TAG, `No trading tools found. Is a CCXT trading plugin installed? Tried: ${tried}`);
|
|
161
|
+
logger.info(TAG, 'Hint: install a trading plugin with: openclaw skills install reefclaw-paper-trading');
|
|
162
|
+
// Still discover optional tools — some might exist even without required ones
|
|
163
|
+
}
|
|
164
|
+
// Log missing required tools
|
|
165
|
+
for (const logical of missingRequired) {
|
|
166
|
+
logger.error(TAG, `Required tool not found: ${logical} (tried: ${CANDIDATES[logical].join(', ')})`);
|
|
167
|
+
}
|
|
168
|
+
// Discover optional tools in parallel
|
|
169
|
+
const optionalResults = await Promise.allSettled(OPTIONAL_TOOLS.map(async (logical) => {
|
|
170
|
+
const actual = await discoverTool(http, logical);
|
|
171
|
+
return { logical, actual };
|
|
172
|
+
}));
|
|
173
|
+
for (const result of optionalResults) {
|
|
174
|
+
if (result.status === 'fulfilled') {
|
|
175
|
+
const { logical, actual } = result.value;
|
|
176
|
+
if (actual) {
|
|
177
|
+
toolMap[logical] = actual;
|
|
178
|
+
found.push(logical);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
missingOptional.push(logical);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// Promise rejected (shouldn't happen unless auth error propagates)
|
|
186
|
+
logger.warn(TAG, `Discovery failed for optional tool: ${result.reason}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Log summary
|
|
190
|
+
logger.info(TAG, `Tool discovery complete: ${found.length} found, ${missingRequired.length} required missing, ${missingOptional.length} optional missing`);
|
|
191
|
+
for (const [logical, actual] of Object.entries(toolMap)) {
|
|
192
|
+
logger.info(TAG, ` ${logical} → ${actual}`);
|
|
193
|
+
}
|
|
194
|
+
for (const logical of missingOptional) {
|
|
195
|
+
logger.warn(TAG, `Optional tool not found: ${logical}`);
|
|
196
|
+
}
|
|
197
|
+
return { toolMap, found, missingRequired, missingOptional };
|
|
198
|
+
}
|
package/bridge/index.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ReefClaw Skill — CLI entry point
|
|
3
|
+
// Usage:
|
|
4
|
+
// tsx src/index.ts --provider mock (standalone testing)
|
|
5
|
+
// tsx src/index.ts --provider gateway (real OpenClaw — not yet implemented)
|
|
6
|
+
// tsx src/index.ts --setup rc_TOKEN --user-id ID (save token to config)
|
|
7
|
+
//
|
|
8
|
+
// Config precedence: CLI args > env vars > OpenClaw config > fallback env > defaults
|
|
9
|
+
// See config.ts for full resolution logic.
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { resolve, dirname } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { logger, setLogLevel } from './logger.js';
|
|
14
|
+
import { Bridge } from './bridge.js';
|
|
15
|
+
import { MockProvider } from './providers/mock.js';
|
|
16
|
+
import { GatewayProvider } from './providers/gateway.js';
|
|
17
|
+
import { resolveConfig, ensureGatewayScopeConfigOnStartup } from './config.js';
|
|
18
|
+
import { resolveGatewayConfig, validateGatewayConfig } from './gateway/gateway-config.js';
|
|
19
|
+
import { runSetup } from './setup.js';
|
|
20
|
+
const TAG = 'main';
|
|
21
|
+
// ---- Load .env file (skill/.env only) ----
|
|
22
|
+
function loadEnvFile() {
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const envPath = resolve(__dirname, '..', '.env');
|
|
25
|
+
try {
|
|
26
|
+
const content = readFileSync(envPath, 'utf-8');
|
|
27
|
+
for (const line of content.split('\n')) {
|
|
28
|
+
const trimmed = line.trim();
|
|
29
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
30
|
+
continue;
|
|
31
|
+
const eqIdx = trimmed.indexOf('=');
|
|
32
|
+
if (eqIdx === -1)
|
|
33
|
+
continue;
|
|
34
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
35
|
+
const value = trimmed.slice(eqIdx + 1).trim();
|
|
36
|
+
if (!process.env[key])
|
|
37
|
+
process.env[key] = value;
|
|
38
|
+
}
|
|
39
|
+
logger.debug(TAG, `Loaded env from ${envPath}`);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// File not found — not an error
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseArgs() {
|
|
46
|
+
const args = process.argv.slice(2);
|
|
47
|
+
const cli = { provider: 'mock' };
|
|
48
|
+
const gateway = {};
|
|
49
|
+
for (let i = 0; i < args.length; i++) {
|
|
50
|
+
const arg = args[i];
|
|
51
|
+
const next = args[i + 1];
|
|
52
|
+
switch (arg) {
|
|
53
|
+
case '--provider':
|
|
54
|
+
case '-p':
|
|
55
|
+
if (next === 'mock' || next === 'gateway') {
|
|
56
|
+
cli.provider = next;
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.error(`Invalid provider: ${next}. Use "mock" or "gateway".`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
case '--token':
|
|
65
|
+
case '-t':
|
|
66
|
+
cli.token = next;
|
|
67
|
+
i++;
|
|
68
|
+
break;
|
|
69
|
+
case '--user-id':
|
|
70
|
+
case '-u':
|
|
71
|
+
cli.userId = next;
|
|
72
|
+
i++;
|
|
73
|
+
break;
|
|
74
|
+
case '--relay-url':
|
|
75
|
+
case '-r':
|
|
76
|
+
cli.relayUrl = next;
|
|
77
|
+
i++;
|
|
78
|
+
break;
|
|
79
|
+
case '--gateway-url':
|
|
80
|
+
gateway.gatewayUrl = next;
|
|
81
|
+
i++;
|
|
82
|
+
break;
|
|
83
|
+
case '--gateway-token':
|
|
84
|
+
gateway.gatewayToken = next;
|
|
85
|
+
i++;
|
|
86
|
+
break;
|
|
87
|
+
case '--symbol':
|
|
88
|
+
gateway.symbol = next;
|
|
89
|
+
i++;
|
|
90
|
+
break;
|
|
91
|
+
case '--log-level':
|
|
92
|
+
case '-l':
|
|
93
|
+
if (['debug', 'info', 'warn', 'error'].includes(next)) {
|
|
94
|
+
cli.logLevel = next;
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
case '--setup':
|
|
99
|
+
case '-s':
|
|
100
|
+
// --setup with optional token as next arg
|
|
101
|
+
if (next && !next.startsWith('-')) {
|
|
102
|
+
cli.setup = next;
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
cli.setup = true;
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
case '--help':
|
|
110
|
+
case '-h':
|
|
111
|
+
printUsage();
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { cli, gateway };
|
|
116
|
+
}
|
|
117
|
+
function printUsage() {
|
|
118
|
+
console.log(`
|
|
119
|
+
ReefClaw Skill — Bridge between OpenClaw and ReefClaw relay
|
|
120
|
+
|
|
121
|
+
Usage:
|
|
122
|
+
tsx src/index.ts [options]
|
|
123
|
+
|
|
124
|
+
Options:
|
|
125
|
+
--provider, -p <mock|gateway> Provider type (default: mock)
|
|
126
|
+
--token, -t <token> Connection token (or REEFCLAW_TOKEN env)
|
|
127
|
+
--user-id, -u <id> User ID (or REEFCLAW_USER_ID env)
|
|
128
|
+
--relay-url, -r <url> Relay URL (default: wss://reefclaw.radunlupsa.partykit.dev)
|
|
129
|
+
--gateway-url <url> OpenClaw gateway URL (or OPENCLAW_GATEWAY_URL env)
|
|
130
|
+
--gateway-token <token> OpenClaw gateway token (or OPENCLAW_GATEWAY_TOKEN env)
|
|
131
|
+
--symbol <symbol> Trading symbol (default: BTC/USDT, or REEFCLAW_SYMBOL env)
|
|
132
|
+
--log-level, -l <level> Log level: debug, info, warn, error (default: info)
|
|
133
|
+
--setup, -s [token] Run setup flow (validate token, test connection, save to config)
|
|
134
|
+
--help, -h Show this help
|
|
135
|
+
|
|
136
|
+
Relay config resolution (highest priority first):
|
|
137
|
+
1. CLI arguments (--token, --user-id, --relay-url)
|
|
138
|
+
2. Environment variables (REEFCLAW_TOKEN, REEFCLAW_USER_ID, REEFCLAW_RELAY_URL)
|
|
139
|
+
3. OpenClaw config file (~/.openclaw/openclaw.json → skills.entries.reefclaw)
|
|
140
|
+
4. Fallback env vars (MOCK_TOKEN, USER_ID)
|
|
141
|
+
5. Defaults (relay URL → wss://reefclaw.radunlupsa.partykit.dev)
|
|
142
|
+
|
|
143
|
+
Gateway config resolution (for --provider gateway):
|
|
144
|
+
1. CLI arguments (--gateway-url, --gateway-token, --symbol)
|
|
145
|
+
2. Environment variables (OPENCLAW_GATEWAY_URL, OPENCLAW_GATEWAY_TOKEN, REEFCLAW_SYMBOL)
|
|
146
|
+
3. OpenClaw config file (~/.openclaw/openclaw.json → gateway.auth.token, gateway.port)
|
|
147
|
+
4. Defaults (http://localhost:18789, BTC/USDT)
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
// ---- Main ----
|
|
151
|
+
async function main() {
|
|
152
|
+
loadEnvFile();
|
|
153
|
+
ensureGatewayScopeConfigOnStartup();
|
|
154
|
+
const { cli: args, gateway: gatewayArgs } = parseArgs();
|
|
155
|
+
if (args.logLevel) {
|
|
156
|
+
setLogLevel(args.logLevel);
|
|
157
|
+
}
|
|
158
|
+
// Handle --setup flow
|
|
159
|
+
if (args.setup !== undefined) {
|
|
160
|
+
const setupToken = typeof args.setup === 'string' ? args.setup : undefined;
|
|
161
|
+
await runSetup(setupToken, args.userId);
|
|
162
|
+
process.exit(0);
|
|
163
|
+
}
|
|
164
|
+
// Resolve config
|
|
165
|
+
const { token, userId, relayUrl } = resolveConfig(args);
|
|
166
|
+
if (!token || !userId) {
|
|
167
|
+
console.error('');
|
|
168
|
+
console.error(' ReefClaw: Missing configuration');
|
|
169
|
+
console.error(' ================================');
|
|
170
|
+
console.error('');
|
|
171
|
+
if (!token) {
|
|
172
|
+
console.error(' No connection token found.');
|
|
173
|
+
}
|
|
174
|
+
if (!userId) {
|
|
175
|
+
console.error(' No user ID found.');
|
|
176
|
+
}
|
|
177
|
+
console.error('');
|
|
178
|
+
console.error(' Quick setup:');
|
|
179
|
+
console.error(' node dist/index.js --setup rc_YOUR_TOKEN --user-id YOUR_USER_ID');
|
|
180
|
+
console.error('');
|
|
181
|
+
console.error(' Or set environment variables:');
|
|
182
|
+
console.error(' REEFCLAW_TOKEN=rc_xxx REEFCLAW_USER_ID=xxx node dist/index.js');
|
|
183
|
+
console.error('');
|
|
184
|
+
console.error(' Or paste the connect message from the onboarding page to your agent:');
|
|
185
|
+
console.error(' "Connect my agent to ReefClaw. Save these to my reefclaw skill config:');
|
|
186
|
+
console.error(' token: rc_... userId: <uuid> relayUrl: wss://..."');
|
|
187
|
+
console.error(' (A token alone is NOT enough — the userId is required to reach the relay.)');
|
|
188
|
+
console.error('');
|
|
189
|
+
console.error(' Get the full connect message at https://reefclaw.com/onboarding');
|
|
190
|
+
console.error('');
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
// Create provider
|
|
194
|
+
let provider;
|
|
195
|
+
if (args.provider === 'mock') {
|
|
196
|
+
logger.info(TAG, 'Using MockProvider');
|
|
197
|
+
provider = new MockProvider();
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
// Resolve and validate gateway config for real OpenClaw connection
|
|
201
|
+
const gwResolved = resolveGatewayConfig(gatewayArgs);
|
|
202
|
+
const gwConfig = validateGatewayConfig(gwResolved);
|
|
203
|
+
if (!gwConfig) {
|
|
204
|
+
console.error('');
|
|
205
|
+
console.error(' ReefClaw: Missing gateway token');
|
|
206
|
+
console.error(' ================================');
|
|
207
|
+
console.error('');
|
|
208
|
+
console.error(' No OpenClaw gateway token found. The token is read from:');
|
|
209
|
+
console.error(' 1. --gateway-token CLI arg');
|
|
210
|
+
console.error(' 2. OPENCLAW_GATEWAY_TOKEN env var');
|
|
211
|
+
console.error(' 3. ~/.openclaw/openclaw.json → gateway.auth.token');
|
|
212
|
+
console.error('');
|
|
213
|
+
console.error(' Make sure OpenClaw is configured and running.');
|
|
214
|
+
console.error('');
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
// Pass connection token so GatewayProvider can authenticate with intelligence service
|
|
218
|
+
gwConfig.connectionToken = token;
|
|
219
|
+
logger.info(TAG, `Using GatewayProvider (url=${gwConfig.gatewayUrl}, symbol=${gwConfig.symbol})`);
|
|
220
|
+
provider = new GatewayProvider(gwConfig);
|
|
221
|
+
}
|
|
222
|
+
// Create bridge
|
|
223
|
+
const connectorConfig = {
|
|
224
|
+
relayUrl,
|
|
225
|
+
userId,
|
|
226
|
+
token,
|
|
227
|
+
};
|
|
228
|
+
const bridge = new Bridge(provider, connectorConfig);
|
|
229
|
+
// Handle graceful shutdown
|
|
230
|
+
let shuttingDown = false;
|
|
231
|
+
async function shutdown(signal) {
|
|
232
|
+
if (shuttingDown)
|
|
233
|
+
return;
|
|
234
|
+
shuttingDown = true;
|
|
235
|
+
logger.info(TAG, `Received ${signal}, shutting down...`);
|
|
236
|
+
// Drain in-flight trade reports before stopping (prevents data loss during kill/flatten)
|
|
237
|
+
if ('drainReports' in provider && typeof provider.drainReports === 'function') {
|
|
238
|
+
try {
|
|
239
|
+
await provider.drainReports();
|
|
240
|
+
}
|
|
241
|
+
catch { /* best-effort */ }
|
|
242
|
+
}
|
|
243
|
+
bridge.stop();
|
|
244
|
+
// Allow 1s for final cleanup before force exit
|
|
245
|
+
setTimeout(() => process.exit(0), 1000);
|
|
246
|
+
}
|
|
247
|
+
process.on('SIGINT', () => void shutdown('SIGINT').catch(() => process.exit(1)));
|
|
248
|
+
process.on('SIGTERM', () => void shutdown('SIGTERM').catch(() => process.exit(1)));
|
|
249
|
+
// Start
|
|
250
|
+
logger.info(TAG, `Starting ReefClaw skill (provider=${args.provider}, relay=${relayUrl})`);
|
|
251
|
+
bridge.start();
|
|
252
|
+
}
|
|
253
|
+
main();
|
package/bridge/logger.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { EmergencyAction, ReconciliationSnapshot, TickerData, CandleData, OrderUpdatePayload, AgentStateData, RiskUpdatePayload, ChatMessage, MarketStructureData, CryptoMetricsData, VolumeAnalysisData, TradeJournalEntry, RegimeData, SignalData, MissionData, AnalyticsData, ShadowComparisonData, TradingModeData, DecisionTraceData } from './types.js';
|
|
2
|
+
import type { TradingMode } from '@reefclaw/shared';
|
|
3
|
+
/** Fill error data emitted when a limit fill fails */
|
|
4
|
+
export interface FillErrorData {
|
|
5
|
+
orderId: string;
|
|
6
|
+
symbol: string;
|
|
7
|
+
error: string;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
}
|
|
10
|
+
/** Events emitted by the provider to be forwarded to the relay */
|
|
11
|
+
export interface ProviderEvents {
|
|
12
|
+
ticker: (data: TickerData) => void;
|
|
13
|
+
candle: (data: CandleData) => void;
|
|
14
|
+
orderUpdate: (data: OrderUpdatePayload) => void;
|
|
15
|
+
agentState: (data: AgentStateData) => void;
|
|
16
|
+
riskUpdate: (data: RiskUpdatePayload) => void;
|
|
17
|
+
chatMessage: (data: {
|
|
18
|
+
message: ChatMessage;
|
|
19
|
+
}) => void;
|
|
20
|
+
/** Streaming chat: first chunk — creates the in-progress message */
|
|
21
|
+
chatMessageStart: (data: {
|
|
22
|
+
id: string;
|
|
23
|
+
runId: string;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
/** Streaming chat: incremental text delta */
|
|
27
|
+
chatMessageChunk: (data: {
|
|
28
|
+
id: string;
|
|
29
|
+
delta: string;
|
|
30
|
+
}) => void;
|
|
31
|
+
/** Streaming chat: generation complete — final content for DB persistence */
|
|
32
|
+
chatMessageEnd: (data: {
|
|
33
|
+
id: string;
|
|
34
|
+
content: string;
|
|
35
|
+
}) => void;
|
|
36
|
+
/** Streaming chat: keep-alive during tool execution — prevents webapp timeout */
|
|
37
|
+
chatStreamingKeepAlive: (data: {
|
|
38
|
+
id: string;
|
|
39
|
+
toolName: string;
|
|
40
|
+
}) => void;
|
|
41
|
+
marketStructure: (data: MarketStructureData) => void;
|
|
42
|
+
cryptoMetrics: (data: CryptoMetricsData) => void;
|
|
43
|
+
volumeAnalysis: (data: VolumeAnalysisData) => void;
|
|
44
|
+
tradeJournal: (data: TradeJournalEntry) => void;
|
|
45
|
+
/** Regime classification from intelligence service */
|
|
46
|
+
regimeUpdate: (data: RegimeData) => void;
|
|
47
|
+
/** Signal engine updates from intelligence service */
|
|
48
|
+
signalUpdate: (data: SignalData) => void;
|
|
49
|
+
/** Trade mission updates from intelligence service */
|
|
50
|
+
missionUpdate: (data: MissionData) => void;
|
|
51
|
+
/** Edge analytics updates from intelligence service */
|
|
52
|
+
analyticsUpdate: (data: AnalyticsData) => void;
|
|
53
|
+
/** Background fill error (e.g., limit order fill failed due to insufficient balance) */
|
|
54
|
+
fillError: (data: FillErrorData) => void;
|
|
55
|
+
/** Shadow comparison event — paper vs live fill estimate (Phase 9b) */
|
|
56
|
+
shadowComparison: (data: ShadowComparisonData) => void;
|
|
57
|
+
/** Trading mode update (Phase 9b) */
|
|
58
|
+
tradingModeUpdate: (data: TradingModeData) => void;
|
|
59
|
+
/** Decision trace update (Phase 9c) */
|
|
60
|
+
decisionTraceUpdate: (data: DecisionTraceData) => void;
|
|
61
|
+
}
|
|
62
|
+
export type ProviderEventName = keyof ProviderEvents;
|
|
63
|
+
/**
|
|
64
|
+
* Adapter interface between OpenClaw (or mock) and the ReefClaw relay.
|
|
65
|
+
* Implementations emit events via the on/off listener pattern.
|
|
66
|
+
*/
|
|
67
|
+
export interface OpenClawProvider {
|
|
68
|
+
/** Start the provider (begin emitting events) */
|
|
69
|
+
start(): void;
|
|
70
|
+
/** Stop the provider (clean up timers, connections) */
|
|
71
|
+
stop(): void;
|
|
72
|
+
/** Execute an emergency command */
|
|
73
|
+
executeEmergency(action: EmergencyAction): Promise<{
|
|
74
|
+
action: string;
|
|
75
|
+
executed: boolean;
|
|
76
|
+
timestamp: string;
|
|
77
|
+
}>;
|
|
78
|
+
/** Handle an incoming chat message from the operator */
|
|
79
|
+
handleChat(content: string): Promise<{
|
|
80
|
+
received: boolean;
|
|
81
|
+
error?: string;
|
|
82
|
+
}>;
|
|
83
|
+
/** Close a specific position by symbol (non-emergency, single-symbol close) */
|
|
84
|
+
closePosition(symbol: string): Promise<{
|
|
85
|
+
closed: boolean;
|
|
86
|
+
symbol: string;
|
|
87
|
+
error?: string;
|
|
88
|
+
}>;
|
|
89
|
+
/** Operator-only: set the trading mode. Plugin enforces the ladder. */
|
|
90
|
+
setTradingMode?(mode: TradingMode, acknowledged?: boolean): Promise<{
|
|
91
|
+
ok: boolean;
|
|
92
|
+
message: string;
|
|
93
|
+
previousMode: TradingMode;
|
|
94
|
+
mode: TradingMode;
|
|
95
|
+
readiness: string;
|
|
96
|
+
reason?: string;
|
|
97
|
+
}>;
|
|
98
|
+
/** Operator-only: set Binance API credentials. The raw secret is written
|
|
99
|
+
* to the plugin-local config file and never retained by the skill. */
|
|
100
|
+
setExchangeCredentials?(apiKey: string, secret: string, testnet?: boolean): Promise<{
|
|
101
|
+
ok: boolean;
|
|
102
|
+
message: string;
|
|
103
|
+
fingerprint: string;
|
|
104
|
+
reconnected: boolean;
|
|
105
|
+
mode: TradingMode;
|
|
106
|
+
readiness: string;
|
|
107
|
+
}>;
|
|
108
|
+
/** Operator-only: verify Binance API credentials with a transient
|
|
109
|
+
* read-only call. Nothing is persisted. */
|
|
110
|
+
testExchangeCredentials?(apiKey: string, secret: string, testnet?: boolean): Promise<{
|
|
111
|
+
ok: boolean;
|
|
112
|
+
message: string;
|
|
113
|
+
fingerprint: string;
|
|
114
|
+
canReadBalance: boolean;
|
|
115
|
+
canReadPositions: boolean;
|
|
116
|
+
balanceUSDT: number | null;
|
|
117
|
+
testnet: boolean;
|
|
118
|
+
errors: string[];
|
|
119
|
+
}>;
|
|
120
|
+
/** Operator-only: remove stored credentials from the plugin config and
|
|
121
|
+
* de-escalate to PAPER mode if currently running in a live mode. */
|
|
122
|
+
clearExchangeCredentials?(): Promise<{
|
|
123
|
+
ok: boolean;
|
|
124
|
+
message: string;
|
|
125
|
+
modeBefore: TradingMode;
|
|
126
|
+
mode: TradingMode;
|
|
127
|
+
rolledBackToPaper: boolean;
|
|
128
|
+
readiness: string;
|
|
129
|
+
}>;
|
|
130
|
+
/** Operator-only: read current bracket-orders config (mode + require flags). */
|
|
131
|
+
getBracketConfig?(): Promise<{
|
|
132
|
+
ok: boolean;
|
|
133
|
+
message?: string;
|
|
134
|
+
mode: 'off' | 'observe' | 'enforce';
|
|
135
|
+
requireStopLoss: boolean;
|
|
136
|
+
requireTakeProfit: boolean;
|
|
137
|
+
}>;
|
|
138
|
+
/** Operator-only: flip requireStopLoss or requireTakeProfit. Returns a
|
|
139
|
+
* warning string when a flag goes off so the dashboard can render the
|
|
140
|
+
* confirmation banner without hardcoding copy. */
|
|
141
|
+
setBracketRequirement?(flag: 'requireStopLoss' | 'requireTakeProfit', value: boolean): Promise<{
|
|
142
|
+
ok: boolean;
|
|
143
|
+
flag: 'requireStopLoss' | 'requireTakeProfit';
|
|
144
|
+
previousValue: boolean;
|
|
145
|
+
value: boolean;
|
|
146
|
+
warning?: string;
|
|
147
|
+
error?: string;
|
|
148
|
+
message?: string;
|
|
149
|
+
}>;
|
|
150
|
+
/** Get a full reconciliation snapshot */
|
|
151
|
+
getSnapshot(): Promise<ReconciliationSnapshot>;
|
|
152
|
+
/** Register an event listener */
|
|
153
|
+
on<E extends ProviderEventName>(event: E, listener: ProviderEvents[E]): void;
|
|
154
|
+
/** Remove an event listener */
|
|
155
|
+
off<E extends ProviderEventName>(event: E, listener: ProviderEvents[E]): void;
|
|
156
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { GatewayHttpClient } from '../gateway/gateway-http-client.js';
|
|
2
|
+
import type { ToolMap } from '../gateway/tool-discovery.js';
|
|
3
|
+
import type { OrderData } from '../types.js';
|
|
4
|
+
import type { CcxtPosition } from '../gateway/poller.js';
|
|
5
|
+
export interface EmergencyResult {
|
|
6
|
+
action: string;
|
|
7
|
+
executed: boolean;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
details?: string;
|
|
10
|
+
}
|
|
11
|
+
export type AgentMode = 'ACTIVE' | 'PAUSED' | 'STOPPED' | 'ERROR';
|
|
12
|
+
export interface EmergencyContext {
|
|
13
|
+
http: GatewayHttpClient | null;
|
|
14
|
+
toolMap: ToolMap;
|
|
15
|
+
symbol: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Kill: stop the agent and cancel WORKING orders, while PRESERVING protective
|
|
19
|
+
* brackets. A protective order (exchange-side STOP_MARKET / TAKE_PROFIT_MARKET)
|
|
20
|
+
* is the only thing guarding an open position once the agent is halted (nothing
|
|
21
|
+
* will re-attach a stop). Kill cancels only the agent's working orders (pending
|
|
22
|
+
* entries / adds), PORTFOLIO-WIDE, and keeps every protective leg in place. To
|
|
23
|
+
* actually exit a position, use Flatten.
|
|
24
|
+
*
|
|
25
|
+
* Bracket preservation is defence-in-depth: the plugin's `cancelAllOrders`
|
|
26
|
+
* already skips ReefClaw-cid brackets, so the old per-symbol kill never stripped
|
|
27
|
+
* a ReefClaw bracket — this skill-side `protective` filter is BROADER (it also
|
|
28
|
+
* preserves externally-placed / non-ReefClaw-cid stops) and portfolio-wide.
|
|
29
|
+
*
|
|
30
|
+
* Caller must set agentMode = 'STOPPED' after this returns, and should pass a
|
|
31
|
+
* FRESH all-symbols order snapshot (see the gateway wrapper).
|
|
32
|
+
*/
|
|
33
|
+
export declare function executeKill(ctx: EmergencyContext, openOrders: OrderData[]): Promise<EmergencyResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Flatten: close all open positions at market.
|
|
36
|
+
* Caller must set agentMode = 'STOPPED' after this returns.
|
|
37
|
+
*/
|
|
38
|
+
export declare function executeFlatten(ctx: EmergencyContext, cachedPositions: CcxtPosition[]): Promise<EmergencyResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Pause: prevent new entries, keep existing positions.
|
|
41
|
+
* Returns the new agent mode if the transition is valid.
|
|
42
|
+
*/
|
|
43
|
+
export declare function executePause(currentMode: AgentMode): {
|
|
44
|
+
result: EmergencyResult;
|
|
45
|
+
newMode: AgentMode;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Resume: re-enable entries.
|
|
49
|
+
* Returns the new agent mode if the transition is valid.
|
|
50
|
+
*/
|
|
51
|
+
export declare function executeResume(currentMode: AgentMode): {
|
|
52
|
+
result: EmergencyResult;
|
|
53
|
+
newMode: AgentMode;
|
|
54
|
+
};
|