openbroker 1.0.41 → 1.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/SKILL.md +50 -3
- package/openclaw.plugin.json +86 -0
- package/package.json +5 -1
- package/scripts/plugin/cli.ts +127 -0
- package/scripts/plugin/config-bridge.ts +30 -0
- package/scripts/plugin/index.ts +57 -0
- package/scripts/plugin/tools.ts +715 -0
- package/scripts/plugin/types.ts +158 -0
- package/scripts/plugin/watcher.ts +312 -0
package/README.md
CHANGED
|
@@ -559,6 +559,105 @@ openbroker approve-builder --max-fee "0.05%" # Custom max fee
|
|
|
559
559
|
| `--builder` | Custom builder address (advanced) | Open Broker |
|
|
560
560
|
| `--verbose` | Show debug output | — |
|
|
561
561
|
|
|
562
|
+
## OpenClaw Plugin
|
|
563
|
+
|
|
564
|
+
OpenBroker ships as an [OpenClaw](https://openclaw.ai) plugin. When installed via OpenClaw, it registers structured agent tools and a background position watcher — no Bash wrappers needed.
|
|
565
|
+
|
|
566
|
+
### Install via OpenClaw
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
openclaw plugins install openbroker
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Or install from a local checkout during development:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
openclaw plugins install -l ./open-broker-mvp
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
After installation, run `openbroker setup` to configure your wallet (same onboarding as the standalone CLI).
|
|
579
|
+
|
|
580
|
+
### Plugin Tools
|
|
581
|
+
|
|
582
|
+
When loaded, the plugin registers these agent tools:
|
|
583
|
+
|
|
584
|
+
| Category | Tool | Description |
|
|
585
|
+
|----------|------|-------------|
|
|
586
|
+
| Info | `ob_account` | Account balance, equity, margin, open orders |
|
|
587
|
+
| Info | `ob_positions` | Open positions with PnL, leverage, liquidation price |
|
|
588
|
+
| Info | `ob_funding` | Funding rates sorted by annualized rate |
|
|
589
|
+
| Info | `ob_markets` | Market data (price, volume, OI) |
|
|
590
|
+
| Info | `ob_search` | Search assets across perps, HIP-3, and spot |
|
|
591
|
+
| Info | `ob_spot` | Spot markets and token balances |
|
|
592
|
+
| Trading | `ob_buy` | Market buy |
|
|
593
|
+
| Trading | `ob_sell` | Market sell |
|
|
594
|
+
| Trading | `ob_limit` | Limit order (GTC, IOC, ALO) |
|
|
595
|
+
| Trading | `ob_trigger` | Trigger order (TP/SL) |
|
|
596
|
+
| Trading | `ob_tpsl` | Set TP/SL on existing position |
|
|
597
|
+
| Trading | `ob_cancel` | Cancel orders |
|
|
598
|
+
| Advanced | `ob_twap` | TWAP execution |
|
|
599
|
+
| Advanced | `ob_bracket` | Entry + TP + SL |
|
|
600
|
+
| Advanced | `ob_chase` | Chase price with ALO orders |
|
|
601
|
+
| Monitoring | `ob_watcher_status` | Background watcher state |
|
|
602
|
+
|
|
603
|
+
### Background Position Watcher
|
|
604
|
+
|
|
605
|
+
The plugin runs a background service that polls your Hyperliquid account every 30 seconds and sends webhook notifications when:
|
|
606
|
+
|
|
607
|
+
- **Position opened** — new position detected
|
|
608
|
+
- **Position closed** — position removed
|
|
609
|
+
- **Size changed** — position increased or decreased
|
|
610
|
+
- **PnL threshold** — unrealized PnL changed by more than the configured % (default: 5%)
|
|
611
|
+
- **Margin warning** — margin usage exceeds threshold (default: 80%)
|
|
612
|
+
|
|
613
|
+
### Plugin Configuration
|
|
614
|
+
|
|
615
|
+
Configure in your OpenClaw settings under `plugins.entries.openbroker.config`:
|
|
616
|
+
|
|
617
|
+
```json
|
|
618
|
+
{
|
|
619
|
+
"privateKey": "0x...",
|
|
620
|
+
"accountAddress": "0x...",
|
|
621
|
+
"network": "mainnet",
|
|
622
|
+
"hooksToken": "your-hooks-secret",
|
|
623
|
+
"watcher": {
|
|
624
|
+
"enabled": true,
|
|
625
|
+
"pollIntervalMs": 30000,
|
|
626
|
+
"pnlChangeThresholdPct": 5,
|
|
627
|
+
"marginUsageWarningPct": 80,
|
|
628
|
+
"notifyOnPositionChange": true,
|
|
629
|
+
"notifyOnFunding": true
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
All fields are optional — the plugin falls back to `~/.openbroker/.env` and environment variables.
|
|
635
|
+
|
|
636
|
+
### OpenClaw Webhook Setup
|
|
637
|
+
|
|
638
|
+
For the position watcher to notify your agent, you need webhooks enabled in your OpenClaw gateway config:
|
|
639
|
+
|
|
640
|
+
```yaml
|
|
641
|
+
hooks:
|
|
642
|
+
enabled: true
|
|
643
|
+
token: "your-hooks-secret" # Must match hooksToken in plugin config
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
The watcher sends alerts to `POST /hooks/agent` with `wakeMode: "now"`, which triggers an immediate agent turn. The agent receives a message like:
|
|
647
|
+
|
|
648
|
+
```
|
|
649
|
+
Position alert: ETH unrealized PnL changed from +$500 to -$200 (-140%).
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### CLI Commands
|
|
653
|
+
|
|
654
|
+
The plugin also registers CLI commands accessible via the OpenClaw CLI:
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
openclaw ob status # Show watcher state and current positions
|
|
658
|
+
openclaw ob watch # Run watcher in foreground (debugging)
|
|
659
|
+
```
|
|
660
|
+
|
|
562
661
|
## Development
|
|
563
662
|
|
|
564
663
|
For local development without global install:
|
package/SKILL.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openbroker
|
|
3
|
-
description: Hyperliquid trading
|
|
3
|
+
description: Hyperliquid trading plugin with background position monitoring. Execute market orders, limit orders, manage positions, view funding rates, and run trading strategies with automatic alerts for PnL changes and liquidation risk.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Requires Node.js 22+, network access to api.hyperliquid.xyz
|
|
6
6
|
homepage: https://www.npmjs.com/package/openbroker
|
|
7
|
-
metadata: {"author": "monemetrics", "version": "1.0.
|
|
8
|
-
allowed-tools: Bash(openbroker:*)
|
|
7
|
+
metadata: {"author": "monemetrics", "version": "1.0.43", "openclaw": {"requires": {"bins": ["openbroker"], "env": ["HYPERLIQUID_PRIVATE_KEY"]}, "primaryEnv": "HYPERLIQUID_PRIVATE_KEY", "install": [{"id": "node", "kind": "node", "package": "openbroker", "bins": ["openbroker"], "label": "Install openbroker (npm)"}]}}
|
|
8
|
+
allowed-tools: ob_account ob_positions ob_funding ob_markets ob_search ob_spot ob_buy ob_sell ob_limit ob_trigger ob_tpsl ob_cancel ob_twap ob_bracket ob_chase ob_watcher_status Bash(openbroker:*)
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Open Broker - Hyperliquid Trading CLI
|
|
@@ -321,6 +321,53 @@ Run `openbroker setup` to create the global config interactively.
|
|
|
321
321
|
|
|
322
322
|
The builder fee (1 bps / 0.01%) is hardcoded and not configurable.
|
|
323
323
|
|
|
324
|
+
## OpenClaw Plugin (Optional)
|
|
325
|
+
|
|
326
|
+
This skill works standalone via Bash — every command above runs through the `openbroker` CLI. For enhanced features, the same `openbroker` npm package also ships as an **OpenClaw plugin** that you can enable alongside this skill.
|
|
327
|
+
|
|
328
|
+
### What the plugin adds
|
|
329
|
+
|
|
330
|
+
- **Structured agent tools** (`ob_account`, `ob_buy`, `ob_limit`, etc.) — typed tool calls with proper input schemas instead of Bash strings. The agent gets structured JSON responses.
|
|
331
|
+
- **Background position watcher** — polls your Hyperliquid account every 30s and sends webhook alerts when positions open/close, PnL moves significantly, or margin usage gets dangerous.
|
|
332
|
+
- **CLI commands** — `openclaw ob status` and `openclaw ob watch` for inspecting the watcher.
|
|
333
|
+
|
|
334
|
+
### Enable the plugin
|
|
335
|
+
|
|
336
|
+
The plugin is bundled in the same `openbroker` npm package. To enable it in your OpenClaw config:
|
|
337
|
+
|
|
338
|
+
```yaml
|
|
339
|
+
plugins:
|
|
340
|
+
entries:
|
|
341
|
+
openbroker:
|
|
342
|
+
enabled: true
|
|
343
|
+
config:
|
|
344
|
+
hooksToken: "your-hooks-secret" # Required for watcher alerts
|
|
345
|
+
watcher:
|
|
346
|
+
enabled: true
|
|
347
|
+
pollIntervalMs: 30000
|
|
348
|
+
pnlChangeThresholdPct: 5
|
|
349
|
+
marginUsageWarningPct: 80
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The plugin reads wallet credentials from `~/.openbroker/.env` (set up by `openbroker setup`), so you don't need to duplicate `privateKey` in the plugin config unless you want to override.
|
|
353
|
+
|
|
354
|
+
### Webhook setup for watcher alerts
|
|
355
|
+
|
|
356
|
+
For position alerts to reach the agent, enable hooks in your gateway config:
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
hooks:
|
|
360
|
+
enabled: true
|
|
361
|
+
token: "your-hooks-secret" # Must match hooksToken above
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Without hooks, the watcher still runs and tracks state (accessible via `ob_watcher_status`), but it can't wake the agent.
|
|
365
|
+
|
|
366
|
+
### Using with or without the plugin
|
|
367
|
+
|
|
368
|
+
- **Skill only (no plugin):** Use Bash commands (`openbroker buy --coin ETH --size 0.1`). No background monitoring.
|
|
369
|
+
- **Skill + plugin:** The agent prefers the `ob_*` tools when available (structured data), falls back to Bash for commands not covered by tools (strategies, scale). Background watcher sends alerts automatically.
|
|
370
|
+
|
|
324
371
|
## Risk Warning
|
|
325
372
|
|
|
326
373
|
- Always use `--dry` first to preview orders
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openbroker",
|
|
3
|
+
"name": "OpenBroker — Hyperliquid Trading",
|
|
4
|
+
"version": "1.0.43",
|
|
5
|
+
"description": "Trade on Hyperliquid DEX with background position monitoring",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"privateKey": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Hyperliquid wallet private key (0x-prefixed). Falls back to HYPERLIQUID_PRIVATE_KEY env var or ~/.openbroker/.env"
|
|
12
|
+
},
|
|
13
|
+
"accountAddress": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Master account address (for API wallets). Falls back to HYPERLIQUID_ACCOUNT_ADDRESS"
|
|
16
|
+
},
|
|
17
|
+
"network": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["mainnet", "testnet"],
|
|
20
|
+
"default": "mainnet",
|
|
21
|
+
"description": "Network to use: mainnet or testnet"
|
|
22
|
+
},
|
|
23
|
+
"hooksToken": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Bearer token for gateway hooks endpoint (must match hooks.token in gateway config). Falls back to OPENCLAW_HOOKS_TOKEN env var."
|
|
26
|
+
},
|
|
27
|
+
"watcher": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"properties": {
|
|
30
|
+
"enabled": {
|
|
31
|
+
"type": "boolean",
|
|
32
|
+
"default": true,
|
|
33
|
+
"description": "Enable background position watcher"
|
|
34
|
+
},
|
|
35
|
+
"pollIntervalMs": {
|
|
36
|
+
"type": "number",
|
|
37
|
+
"default": 30000,
|
|
38
|
+
"description": "Poll interval in milliseconds"
|
|
39
|
+
},
|
|
40
|
+
"pnlChangeThresholdPct": {
|
|
41
|
+
"type": "number",
|
|
42
|
+
"default": 5,
|
|
43
|
+
"description": "Notify when unrealized PnL changes by this percentage"
|
|
44
|
+
},
|
|
45
|
+
"marginUsageWarningPct": {
|
|
46
|
+
"type": "number",
|
|
47
|
+
"default": 80,
|
|
48
|
+
"description": "Warn when margin usage exceeds this percentage"
|
|
49
|
+
},
|
|
50
|
+
"notifyOnPositionChange": {
|
|
51
|
+
"type": "boolean",
|
|
52
|
+
"default": true,
|
|
53
|
+
"description": "Send hook when positions open/close/change size"
|
|
54
|
+
},
|
|
55
|
+
"notifyOnFunding": {
|
|
56
|
+
"type": "boolean",
|
|
57
|
+
"default": true,
|
|
58
|
+
"description": "Send hook for funding rate alerts"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": false
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"additionalProperties": false
|
|
65
|
+
},
|
|
66
|
+
"uiHints": {
|
|
67
|
+
"privateKey": {
|
|
68
|
+
"label": "Private Key",
|
|
69
|
+
"sensitive": true,
|
|
70
|
+
"placeholder": "0x..."
|
|
71
|
+
},
|
|
72
|
+
"accountAddress": {
|
|
73
|
+
"label": "Account Address",
|
|
74
|
+
"placeholder": "0x..."
|
|
75
|
+
},
|
|
76
|
+
"network": {
|
|
77
|
+
"label": "Network",
|
|
78
|
+
"placeholder": "mainnet"
|
|
79
|
+
},
|
|
80
|
+
"hooksToken": {
|
|
81
|
+
"label": "Hooks Token",
|
|
82
|
+
"sensitive": true,
|
|
83
|
+
"placeholder": "your-hooks-secret"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openbroker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
4
4
|
"description": "Hyperliquid trading CLI - execute orders, manage positions, and run trading strategies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"openbroker": "./bin/openbroker.js"
|
|
8
8
|
},
|
|
9
|
+
"openclaw": {
|
|
10
|
+
"extensions": ["./scripts/plugin/index.ts"]
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"bin/",
|
|
11
14
|
"scripts/",
|
|
12
15
|
"config/example.env",
|
|
16
|
+
"openclaw.plugin.json",
|
|
13
17
|
"README.md",
|
|
14
18
|
"CHANGELOG.md",
|
|
15
19
|
"SKILL.md"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// CLI commands for the OpenClaw plugin
|
|
2
|
+
// Registered via api.registerCli with Commander.js-style program
|
|
3
|
+
|
|
4
|
+
import type { PluginLogger, OpenClawPluginApi } from './types.js';
|
|
5
|
+
import type { PositionWatcher } from './watcher.js';
|
|
6
|
+
|
|
7
|
+
export function registerCliCommands(
|
|
8
|
+
api: OpenClawPluginApi,
|
|
9
|
+
watcher: PositionWatcher | null,
|
|
10
|
+
logger: PluginLogger,
|
|
11
|
+
): void {
|
|
12
|
+
api.registerCli(({ program }) => {
|
|
13
|
+
const ob = program.command('ob').description('OpenBroker Hyperliquid trading tools');
|
|
14
|
+
|
|
15
|
+
ob
|
|
16
|
+
.command('watch')
|
|
17
|
+
.description('Start the position watcher in foreground (for debugging)')
|
|
18
|
+
.option('--interval <ms>', 'Poll interval in milliseconds', '30000')
|
|
19
|
+
.action(async (opts: unknown) => {
|
|
20
|
+
// If watcher is already running (gateway context), show its status
|
|
21
|
+
if (watcher && watcher.getStatus().running) {
|
|
22
|
+
const status = watcher.getStatus();
|
|
23
|
+
console.log('Position watcher is running as a background service.');
|
|
24
|
+
console.log(`Account: ${status.accountAddress}`);
|
|
25
|
+
console.log(`Tracking ${status.positions.length} position(s)`);
|
|
26
|
+
console.log(`Events detected: ${status.eventsDetected}`);
|
|
27
|
+
console.log(`Last poll: ${status.lastPollAt ?? 'Never'}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// CLI context: start watcher in foreground for debugging
|
|
32
|
+
const { PositionWatcher: WatcherClass } = await import('./watcher.js');
|
|
33
|
+
const { interval: intervalStr } = opts as { interval: string };
|
|
34
|
+
const interval = parseInt(intervalStr, 10);
|
|
35
|
+
|
|
36
|
+
const fgWatcher = new WatcherClass({
|
|
37
|
+
logger,
|
|
38
|
+
gatewayPort: api.gatewayPort || 0,
|
|
39
|
+
pollIntervalMs: interval,
|
|
40
|
+
notifyOnPositionChange: api.gatewayPort > 0,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log('Starting position watcher in foreground...');
|
|
44
|
+
console.log(`Poll interval: ${interval / 1000}s`);
|
|
45
|
+
console.log('Press Ctrl+C to stop.\n');
|
|
46
|
+
|
|
47
|
+
process.on('SIGINT', async () => {
|
|
48
|
+
await fgWatcher.stop();
|
|
49
|
+
process.exit(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await fgWatcher.start();
|
|
53
|
+
|
|
54
|
+
// Keep alive
|
|
55
|
+
await new Promise(() => {});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
ob
|
|
59
|
+
.command('status')
|
|
60
|
+
.description('Show position watcher status and current positions')
|
|
61
|
+
.action(async () => {
|
|
62
|
+
// If watcher is running in gateway context, show its live state
|
|
63
|
+
if (watcher && watcher.getStatus().running) {
|
|
64
|
+
const status = watcher.getStatus();
|
|
65
|
+
|
|
66
|
+
console.log('OpenBroker Position Watcher Status');
|
|
67
|
+
console.log('==================================\n');
|
|
68
|
+
console.log(`Running: Yes (background service)`);
|
|
69
|
+
console.log(`Account: ${status.accountAddress}`);
|
|
70
|
+
console.log(`Poll interval: ${status.pollIntervalMs / 1000}s`);
|
|
71
|
+
console.log(`Events detected: ${status.eventsDetected}`);
|
|
72
|
+
console.log(`Last poll: ${status.lastPollAt ?? 'Never'}`);
|
|
73
|
+
console.log(`Equity: $${status.equity ?? '?'}`);
|
|
74
|
+
console.log(`Margin used: ${status.marginUsedPct?.toFixed(1) ?? '?'}%`);
|
|
75
|
+
|
|
76
|
+
if (status.positions.length === 0) {
|
|
77
|
+
console.log('\nNo open positions.');
|
|
78
|
+
} else {
|
|
79
|
+
console.log(`\nOpen Positions (${status.positions.length}):`);
|
|
80
|
+
for (const p of status.positions) {
|
|
81
|
+
const side = parseFloat(p.size) > 0 ? 'LONG' : 'SHORT';
|
|
82
|
+
console.log(` ${p.coin} ${side}`);
|
|
83
|
+
console.log(` Size: ${p.size}`);
|
|
84
|
+
console.log(` Entry: $${p.entryPrice}`);
|
|
85
|
+
console.log(` Unreal PnL: $${p.unrealizedPnl}`);
|
|
86
|
+
console.log(` Liq Price: ${p.liquidationPrice ? `$${p.liquidationPrice}` : 'N/A'}`);
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// CLI context: one-shot account query
|
|
94
|
+
console.log('OpenBroker Status (live query)\n');
|
|
95
|
+
try {
|
|
96
|
+
const { getClient } = await import('../core/client.js');
|
|
97
|
+
const { formatUsd } = await import('../core/utils.js');
|
|
98
|
+
const client = getClient();
|
|
99
|
+
const state = await client.getUserState();
|
|
100
|
+
|
|
101
|
+
console.log(`Account: ${client.address}`);
|
|
102
|
+
console.log(`Equity: ${formatUsd(parseFloat(state.marginSummary.accountValue))}`);
|
|
103
|
+
console.log(`Margin: ${formatUsd(parseFloat(state.marginSummary.totalMarginUsed))}`);
|
|
104
|
+
|
|
105
|
+
const positions = state.assetPositions.filter(ap => parseFloat(ap.position.szi) !== 0);
|
|
106
|
+
if (positions.length === 0) {
|
|
107
|
+
console.log('\nNo open positions.');
|
|
108
|
+
} else {
|
|
109
|
+
console.log(`\nOpen Positions (${positions.length}):`);
|
|
110
|
+
for (const ap of positions) {
|
|
111
|
+
const p = ap.position;
|
|
112
|
+
const side = parseFloat(p.szi) > 0 ? 'LONG' : 'SHORT';
|
|
113
|
+
console.log(` ${p.coin} ${side} ${p.szi} @ $${p.entryPx} | PnL: $${p.unrealizedPnl} | Liq: ${p.liquidationPx ?? 'N/A'}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
118
|
+
console.log('\nRun "openbroker setup" to configure your wallet.');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (watcher && !watcher.getStatus().running) {
|
|
122
|
+
console.log('\nNote: The background watcher is registered but not running.');
|
|
123
|
+
console.log('It starts automatically with the gateway. Use "openclaw ob watch" for foreground mode.');
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}, { commands: ['ob'] });
|
|
127
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Maps OpenClaw plugin config → process.env vars
|
|
2
|
+
// Only sets vars that are not already defined (env vars take priority)
|
|
3
|
+
|
|
4
|
+
import type { OpenBrokerPluginConfig } from './types.js';
|
|
5
|
+
|
|
6
|
+
const CONFIG_MAP: Record<string, string> = {
|
|
7
|
+
privateKey: 'HYPERLIQUID_PRIVATE_KEY',
|
|
8
|
+
accountAddress: 'HYPERLIQUID_ACCOUNT_ADDRESS',
|
|
9
|
+
network: 'HYPERLIQUID_NETWORK',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Inject plugin config values into process.env if not already set.
|
|
14
|
+
*
|
|
15
|
+
* Priority chain:
|
|
16
|
+
* 1. Real env vars (highest — already in process.env)
|
|
17
|
+
* 2. Plugin config (injected here)
|
|
18
|
+
* 3. ~/.openbroker/.env (loaded by core/config.ts)
|
|
19
|
+
* 4. Hardcoded defaults in core/config.ts
|
|
20
|
+
*/
|
|
21
|
+
export function applyConfigBridge(pluginConfig: Record<string, unknown>): void {
|
|
22
|
+
const config = pluginConfig as OpenBrokerPluginConfig;
|
|
23
|
+
|
|
24
|
+
for (const [key, envVar] of Object.entries(CONFIG_MAP)) {
|
|
25
|
+
const value = config[key as keyof OpenBrokerPluginConfig];
|
|
26
|
+
if (value !== undefined && value !== null && typeof value !== 'object' && !process.env[envVar]) {
|
|
27
|
+
process.env[envVar] = String(value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// OpenClaw Plugin Entry Point for OpenBroker
|
|
2
|
+
|
|
3
|
+
import type { OpenClawPluginApi, OpenBrokerPluginConfig } from './types.js';
|
|
4
|
+
import { applyConfigBridge } from './config-bridge.js';
|
|
5
|
+
import { PositionWatcher } from './watcher.js';
|
|
6
|
+
import { createTools } from './tools.js';
|
|
7
|
+
import { registerCliCommands } from './cli.js';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
id: 'openbroker',
|
|
11
|
+
name: 'OpenBroker — Hyperliquid Trading',
|
|
12
|
+
|
|
13
|
+
register(api: OpenClawPluginApi): void {
|
|
14
|
+
const { logger, gatewayPort } = api;
|
|
15
|
+
const pluginConfig = (api.pluginConfig ?? {}) as OpenBrokerPluginConfig;
|
|
16
|
+
|
|
17
|
+
// 1. Apply config bridge: inject plugin config → process.env
|
|
18
|
+
applyConfigBridge(pluginConfig as Record<string, unknown>);
|
|
19
|
+
logger.debug('OpenBroker config bridge applied');
|
|
20
|
+
|
|
21
|
+
// 2. Register background position watcher (unless disabled)
|
|
22
|
+
let watcher: PositionWatcher | null = null;
|
|
23
|
+
const watcherEnabled = pluginConfig.watcher?.enabled !== false;
|
|
24
|
+
|
|
25
|
+
if (watcherEnabled) {
|
|
26
|
+
watcher = new PositionWatcher({
|
|
27
|
+
logger,
|
|
28
|
+
gatewayPort,
|
|
29
|
+
hooksToken: pluginConfig.hooksToken,
|
|
30
|
+
accountAddress: pluginConfig.accountAddress
|
|
31
|
+
|| process.env.HYPERLIQUID_ACCOUNT_ADDRESS
|
|
32
|
+
|| undefined,
|
|
33
|
+
network: pluginConfig.network || process.env.HYPERLIQUID_NETWORK,
|
|
34
|
+
pollIntervalMs: pluginConfig.watcher?.pollIntervalMs,
|
|
35
|
+
pnlChangeThresholdPct: pluginConfig.watcher?.pnlChangeThresholdPct,
|
|
36
|
+
marginUsageWarningPct: pluginConfig.watcher?.marginUsageWarningPct,
|
|
37
|
+
notifyOnPositionChange: pluginConfig.watcher?.notifyOnPositionChange,
|
|
38
|
+
notifyOnFunding: pluginConfig.watcher?.notifyOnFunding,
|
|
39
|
+
});
|
|
40
|
+
api.registerService(watcher);
|
|
41
|
+
logger.debug('OpenBroker position watcher registered');
|
|
42
|
+
} else {
|
|
43
|
+
logger.debug('OpenBroker position watcher disabled by config');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 3. Register agent tools
|
|
47
|
+
const tools = createTools(watcher);
|
|
48
|
+
for (const tool of tools) {
|
|
49
|
+
api.registerTool(tool);
|
|
50
|
+
}
|
|
51
|
+
logger.debug(`Registered ${tools.length} OpenBroker agent tools`);
|
|
52
|
+
|
|
53
|
+
// 4. Register CLI commands
|
|
54
|
+
registerCliCommands(api, watcher, logger);
|
|
55
|
+
logger.debug('OpenBroker CLI commands registered');
|
|
56
|
+
},
|
|
57
|
+
};
|