openbroker 1.0.33 → 1.0.35

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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to Open Broker will be documented in this file.
4
4
 
5
+ ## [1.0.34] - 2025-02-05
6
+
7
+ ### Changed
8
+ - **Global Config**: Config now stored in `~/.openbroker/.env` for global CLI usage
9
+ - Config loaded from: env vars > local `.env` > `~/.openbroker/.env`
10
+ - `openbroker setup` creates config in home directory
11
+ - Works from any directory without local `.env` file
12
+ - **Read-Only Mode**: Info commands work without configuration
13
+ - Market data, funding rates, search all work immediately
14
+ - Shows warning: "Not configured for trading. Run openbroker setup to enable trades."
15
+ - Trading commands fail with clear error until configured
16
+ - **Better Error Messages**: Clear instructions when config missing
17
+
5
18
  ## [1.0.3] - 2025-02-05
6
19
 
7
20
  ### Added
package/README.md CHANGED
@@ -116,12 +116,17 @@ export HYPERLIQUID_NETWORK="testnet"
116
116
 
117
117
  ## Configuration
118
118
 
119
- Create a `.env` file (or run `openbroker setup`):
119
+ Config is loaded from these locations (in order of priority):
120
+ 1. Environment variables
121
+ 2. `.env` file in current directory
122
+ 3. `~/.openbroker/.env` (global config)
123
+
124
+ Run `openbroker setup` to create the global config, or set environment variables:
120
125
 
121
126
  ```bash
122
- HYPERLIQUID_PRIVATE_KEY=0x... # Required: wallet private key
123
- HYPERLIQUID_NETWORK=mainnet # Optional: mainnet (default) or testnet
124
- HYPERLIQUID_ACCOUNT_ADDRESS=0x... # Optional: for API wallets
127
+ export HYPERLIQUID_PRIVATE_KEY=0x... # Required: wallet private key
128
+ export HYPERLIQUID_NETWORK=mainnet # Optional: mainnet (default) or testnet
129
+ export HYPERLIQUID_ACCOUNT_ADDRESS=0x... # Optional: for API wallets
125
130
  ```
126
131
 
127
132
  ### API Wallet Setup
@@ -129,8 +134,8 @@ HYPERLIQUID_ACCOUNT_ADDRESS=0x... # Optional: for API wallets
129
134
  For automated trading, use an API wallet:
130
135
 
131
136
  ```bash
132
- HYPERLIQUID_PRIVATE_KEY="0x..." # API wallet private key
133
- HYPERLIQUID_ACCOUNT_ADDRESS="0x..." # Main account address
137
+ export HYPERLIQUID_PRIVATE_KEY="0x..." # API wallet private key
138
+ export HYPERLIQUID_ACCOUNT_ADDRESS="0x..." # Main account address
134
139
  ```
135
140
 
136
141
  **Note:** Builder fee must be approved with the main wallet first.
package/SKILL.md CHANGED
@@ -5,7 +5,7 @@ license: MIT
5
5
  compatibility: Requires Node.js 22+, network access to api.hyperliquid.xyz
6
6
  metadata:
7
7
  author: monemetrics
8
- version: "1.0.3"
8
+ version: "1.0.34"
9
9
  allowed-tools: Bash(openbroker:*) Bash(npm:*) Read
10
10
  ---
11
11
 
@@ -278,9 +278,14 @@ All commands support `--dry` for dry run (preview without executing).
278
278
  | Percentage down | `--sl -5%` | 5% below entry |
279
279
  | Entry price | `--sl entry` | Breakeven stop |
280
280
 
281
- ## Environment Variables
281
+ ## Configuration
282
282
 
283
- Create a `.env` file or set these environment variables:
283
+ Config is loaded from (in priority order):
284
+ 1. Environment variables
285
+ 2. `.env` in current directory
286
+ 3. `~/.openbroker/.env` (global config)
287
+
288
+ Run `openbroker setup` to create the global config interactively.
284
289
 
285
290
  | Variable | Required | Description |
286
291
  |----------|----------|-------------|
package/bin/openbroker.js CHANGED
@@ -1,24 +1,58 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // This wrapper uses tsx to run the TypeScript CLI
3
+ // This wrapper runs the TypeScript CLI using tsx
4
4
  import { spawn } from 'child_process';
5
5
  import { fileURLToPath } from 'url';
6
6
  import path from 'path';
7
7
 
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
+ const packageRoot = path.dirname(__dirname);
10
11
  const cliPath = path.join(__dirname, 'cli.ts');
11
12
 
12
- // Run the TypeScript CLI with tsx
13
+ // Run the TypeScript CLI with tsx from package's node_modules
14
+ const tsxBin = path.join(packageRoot, 'node_modules', '.bin', 'tsx');
15
+
13
16
  const child = spawn(
14
- process.execPath,
15
- ['--import', 'tsx', cliPath, ...process.argv.slice(2)],
17
+ tsxBin,
18
+ [cliPath, ...process.argv.slice(2)],
16
19
  {
17
20
  stdio: 'inherit',
18
- cwd: process.cwd(),
21
+ cwd: packageRoot,
22
+ env: {
23
+ ...process.env,
24
+ // Preserve the original working directory for local .env lookup
25
+ OPENBROKER_CWD: process.cwd(),
26
+ },
19
27
  }
20
28
  );
21
29
 
30
+ child.on('error', (err) => {
31
+ // If tsx binary not found, try npx tsx as fallback
32
+ if (err.code === 'ENOENT') {
33
+ const fallback = spawn(
34
+ 'npx',
35
+ ['tsx', cliPath, ...process.argv.slice(2)],
36
+ {
37
+ stdio: 'inherit',
38
+ cwd: packageRoot,
39
+ env: {
40
+ ...process.env,
41
+ OPENBROKER_CWD: process.cwd(),
42
+ },
43
+ }
44
+ );
45
+ fallback.on('exit', (code) => process.exit(code ?? 0));
46
+ fallback.on('error', () => {
47
+ console.error('Error: tsx not found. Try reinstalling openbroker.');
48
+ process.exit(1);
49
+ });
50
+ } else {
51
+ console.error('Error:', err.message);
52
+ process.exit(1);
53
+ }
54
+ });
55
+
22
56
  child.on('exit', (code) => {
23
57
  process.exit(code ?? 0);
24
58
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openbroker",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Hyperliquid trading CLI - execute orders, manage positions, and run trading strategies",
5
5
  "type": "module",
6
6
  "bin": {
@@ -78,6 +78,20 @@ export class HyperliquidClient {
78
78
  return this.config.builderFee / 10; // Convert from tenths of bps to bps
79
79
  }
80
80
 
81
+ /** Whether client is in read-only mode (no trading capability) */
82
+ get isReadOnly(): boolean {
83
+ return this.config.isReadOnly;
84
+ }
85
+
86
+ /** Throw error if trying to trade in read-only mode */
87
+ private requireTrading(): void {
88
+ if (this.config.isReadOnly) {
89
+ throw new Error(
90
+ 'Trading not available. Run "openbroker setup" to configure your wallet.'
91
+ );
92
+ }
93
+ }
94
+
81
95
  // ============ Market Data ============
82
96
 
83
97
  async getMetaAndAssetCtxs(): Promise<MetaAndAssetCtxs> {
@@ -562,6 +576,7 @@ export class HyperliquidClient {
562
576
  reduceOnly: boolean = false,
563
577
  includeBuilder: boolean = true
564
578
  ): Promise<OrderResponse> {
579
+ this.requireTrading();
565
580
  await this.getMetaAndAssetCtxs();
566
581
 
567
582
  const assetIndex = this.getAssetIndex(coin);
@@ -679,6 +694,7 @@ export class HyperliquidClient {
679
694
  tpsl: 'tp' | 'sl',
680
695
  reduceOnly: boolean = true
681
696
  ): Promise<OrderResponse> {
697
+ this.requireTrading();
682
698
  await this.getMetaAndAssetCtxs();
683
699
 
684
700
  const assetIndex = this.getAssetIndex(coin);
@@ -766,6 +782,7 @@ export class HyperliquidClient {
766
782
  }
767
783
 
768
784
  async cancel(coin: string, oid: number): Promise<CancelResponse> {
785
+ this.requireTrading();
769
786
  await this.getMetaAndAssetCtxs();
770
787
 
771
788
  const assetIndex = this.getAssetIndex(coin);
@@ -807,6 +824,7 @@ export class HyperliquidClient {
807
824
  leverage: number,
808
825
  isCross: boolean = true
809
826
  ): Promise<unknown> {
827
+ this.requireTrading();
810
828
  await this.getMetaAndAssetCtxs();
811
829
 
812
830
  const assetIndex = this.getAssetIndex(coin);
@@ -1,50 +1,105 @@
1
1
  // Configuration loader for Open Broker
2
2
 
3
3
  import { config as loadDotenv } from 'dotenv';
4
- import { resolve } from 'path';
5
- import { existsSync } from 'fs';
4
+ import { resolve, join } from 'path';
5
+ import { existsSync, mkdirSync } from 'fs';
6
+ import { homedir } from 'os';
6
7
  import { privateKeyToAccount } from 'viem/accounts';
7
8
  import type { OpenBrokerConfig } from './types.js';
8
9
 
9
- // Get project root relative to this file (scripts/core/config.ts -> project root)
10
- export const PROJECT_ROOT = resolve(import.meta.dirname, '../..');
11
- export const ENV_PATH = resolve(PROJECT_ROOT, '.env');
10
+ // Config locations (in order of priority)
11
+ // 1. Environment variables (always checked first by process.env)
12
+ // 2. Local .env in current working directory
13
+ // 3. Global config at ~/.openbroker/.env
12
14
 
13
- // Load .env from project root (silently skip if doesn't exist)
14
- if (existsSync(ENV_PATH)) {
15
- // Set DOTENV_CONFIG_QUIET to suppress dotenv's default logging
16
- process.env.DOTENV_CONFIG_QUIET = 'true';
17
- const result = loadDotenv({ path: ENV_PATH });
15
+ export const GLOBAL_CONFIG_DIR = join(homedir(), '.openbroker');
16
+ export const GLOBAL_ENV_PATH = join(GLOBAL_CONFIG_DIR, '.env');
17
+ // Use OPENBROKER_CWD if set (from CLI wrapper), otherwise use process.cwd()
18
+ const userCwd = process.env.OPENBROKER_CWD || process.cwd();
19
+ export const LOCAL_ENV_PATH = resolve(userCwd, '.env');
18
20
 
19
- if (process.env.VERBOSE === '1' || process.env.VERBOSE === 'true') {
20
- console.log(`[DEBUG] Loading .env from: ${ENV_PATH}`);
21
- console.log(`[DEBUG] .env loaded: ${result.parsed ? 'yes' : 'no'}`);
22
- }
23
- } else if (process.env.VERBOSE === '1' || process.env.VERBOSE === 'true') {
24
- console.log(`[DEBUG] No .env file found at: ${ENV_PATH}`);
25
- console.log(`[DEBUG] Run 'npx tsx scripts/setup/onboard.ts' to create one`);
26
- }
21
+ // Package root (for reference, not config loading)
22
+ export const PROJECT_ROOT = resolve(import.meta.dirname, '../..');
27
23
 
28
24
  const MAINNET_URL = 'https://api.hyperliquid.xyz';
29
25
  const TESTNET_URL = 'https://api.hyperliquid-testnet.xyz';
30
26
 
31
27
  // Open Broker builder address - receives builder fees on all trades
32
- // This funds continued development of the open-broker project
33
28
  export const OPEN_BROKER_BUILDER_ADDRESS = '0xbb67021fA3e62ab4DA985bb5a55c5c1884381068';
34
29
 
30
+ // Default read-only key (for info commands that don't need authentication)
31
+ // This is a valid but essentially useless private key
32
+ const DEFAULT_READ_ONLY_KEY = '0x0000000000000000000000000000000000000000000000000000000000000001' as const;
33
+
34
+ // Track if we've shown the read-only warning
35
+ let readOnlyWarningShown = false;
36
+
37
+ /**
38
+ * Find and load the config file from multiple locations
39
+ * Priority: env vars > local .env > global ~/.openbroker/.env > project .env
40
+ */
41
+ function loadEnvFile(): string | null {
42
+ const verbose = process.env.VERBOSE === '1' || process.env.VERBOSE === 'true';
43
+ process.env.DOTENV_CONFIG_QUIET = 'true';
44
+
45
+ // Check locations in order of priority
46
+ const locations = [
47
+ { path: LOCAL_ENV_PATH, name: 'local (.env)' },
48
+ { path: GLOBAL_ENV_PATH, name: 'global (~/.openbroker/.env)' },
49
+ ];
50
+
51
+ for (const { path, name } of locations) {
52
+ if (existsSync(path)) {
53
+ const result = loadDotenv({ path });
54
+ if (verbose) {
55
+ console.log(`[DEBUG] Loaded config from ${name}: ${path}`);
56
+ }
57
+ return path;
58
+ }
59
+ }
60
+
61
+ if (verbose) {
62
+ console.log('[DEBUG] No config file found in any location');
63
+ console.log('[DEBUG] Run "openbroker setup" to configure');
64
+ }
65
+
66
+ return null;
67
+ }
68
+
69
+ // Load config on module import
70
+ const loadedConfigPath = loadEnvFile();
71
+
72
+ /**
73
+ * Ensure the global config directory exists
74
+ */
75
+ export function ensureConfigDir(): string {
76
+ if (!existsSync(GLOBAL_CONFIG_DIR)) {
77
+ mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true, mode: 0o700 });
78
+ }
79
+ return GLOBAL_CONFIG_DIR;
80
+ }
81
+
82
+ /**
83
+ * Get the path where config was loaded from, or where it should be saved
84
+ */
85
+ export function getConfigPath(): string {
86
+ return loadedConfigPath || GLOBAL_ENV_PATH;
87
+ }
88
+
35
89
  export function loadConfig(): OpenBrokerConfig {
36
- const privateKey = process.env.HYPERLIQUID_PRIVATE_KEY;
90
+ let privateKey = process.env.HYPERLIQUID_PRIVATE_KEY;
91
+ let isReadOnly = false;
92
+
37
93
  if (!privateKey) {
38
- if (!existsSync(ENV_PATH)) {
39
- throw new Error(
40
- 'No .env file found. Run onboarding first:\n\n' +
41
- ' npx tsx scripts/setup/onboard.ts\n'
42
- );
94
+ // Use default read-only key for info commands
95
+ privateKey = DEFAULT_READ_ONLY_KEY;
96
+ isReadOnly = true;
97
+
98
+ // Show warning once
99
+ if (!readOnlyWarningShown) {
100
+ readOnlyWarningShown = true;
101
+ console.log('\x1b[33m⚠️ Not configured for trading. Run "openbroker setup" to enable trades.\x1b[0m\n');
43
102
  }
44
- throw new Error(
45
- 'HYPERLIQUID_PRIVATE_KEY not found in .env file.\n' +
46
- 'Add it to your .env or run: npx tsx scripts/setup/onboard.ts'
47
- );
48
103
  }
49
104
 
50
105
  if (!privateKey.startsWith('0x') || privateKey.length !== 66) {
@@ -64,7 +119,6 @@ export function loadConfig(): OpenBrokerConfig {
64
119
  const walletAddress = wallet.address.toLowerCase();
65
120
 
66
121
  // Account address can be different if using an API wallet
67
- // If not specified, use the wallet address itself
68
122
  const accountAddress = process.env.HYPERLIQUID_ACCOUNT_ADDRESS?.toLowerCase();
69
123
 
70
124
  // Determine if this is an API wallet setup
@@ -76,12 +130,20 @@ export function loadConfig(): OpenBrokerConfig {
76
130
  walletAddress,
77
131
  accountAddress: accountAddress || walletAddress,
78
132
  isApiWallet,
133
+ isReadOnly,
79
134
  builderAddress,
80
135
  builderFee,
81
136
  slippageBps,
82
137
  };
83
138
  }
84
139
 
140
+ /**
141
+ * Check if the current config is read-only (no trading capability)
142
+ */
143
+ export function isConfigured(): boolean {
144
+ return !!process.env.HYPERLIQUID_PRIVATE_KEY;
145
+ }
146
+
85
147
  export function getNetwork(): 'mainnet' | 'testnet' {
86
148
  const network = process.env.HYPERLIQUID_NETWORK || 'mainnet';
87
149
  return network === 'testnet' ? 'testnet' : 'mainnet';
@@ -8,6 +8,7 @@ export interface OpenBrokerConfig {
8
8
  walletAddress: string; // Address derived from private key (the signer)
9
9
  accountAddress: string; // Address to trade on behalf of (may differ if using API wallet)
10
10
  isApiWallet: boolean; // True if walletAddress != accountAddress
11
+ isReadOnly: boolean; // True if using default key (no trading capability)
11
12
  builderAddress: string;
12
13
  builderFee: number; // tenths of bps (10 = 1 bps)
13
14
  slippageBps: number;
@@ -1,15 +1,19 @@
1
1
  #!/usr/bin/env npx tsx
2
- // Open Broker - Automated Onboarding for AI Agents
2
+ // Open Broker - Automated Onboarding
3
3
  // Creates wallet, configures environment, and approves builder fee
4
4
 
5
5
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
8
  import * as readline from 'readline';
9
- import { fileURLToPath } from 'url';
9
+ import { homedir } from 'os';
10
10
 
11
11
  const OPEN_BROKER_BUILDER_ADDRESS = '0xbb67021fA3e62ab4DA985bb5a55c5c1884381068';
12
12
 
13
+ // Global config directory: ~/.openbroker/
14
+ const CONFIG_DIR = path.join(homedir(), '.openbroker');
15
+ const CONFIG_PATH = path.join(CONFIG_DIR, '.env');
16
+
13
17
  interface OnboardResult {
14
18
  success: boolean;
15
19
  walletAddress?: string;
@@ -33,41 +37,39 @@ function prompt(rl: readline.Interface, question: string): Promise<string> {
33
37
  }
34
38
 
35
39
  function isValidPrivateKey(key: string): boolean {
36
- // Check if it's a valid 64-char hex string with 0x prefix
37
40
  return /^0x[a-fA-F0-9]{64}$/.test(key);
38
41
  }
39
42
 
40
- // Get project root relative to this script (scripts/setup/onboard.ts -> project root)
41
- function getProjectRoot(): string {
42
- const __filename = fileURLToPath(import.meta.url);
43
- const __dirname = path.dirname(__filename);
44
- return path.resolve(__dirname, '../..');
43
+ function ensureConfigDir(): void {
44
+ if (!fs.existsSync(CONFIG_DIR)) {
45
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
46
+ }
45
47
  }
46
48
 
47
49
  async function main(): Promise<OnboardResult> {
48
- console.log('Open Broker - Automated Onboarding');
49
- console.log('===================================\n');
50
-
51
- const projectRoot = getProjectRoot();
52
- const envPath = path.join(projectRoot, '.env');
50
+ console.log('OpenBroker - Setup');
51
+ console.log('==================\n');
53
52
 
54
- // Check if .env already exists
55
- if (fs.existsSync(envPath)) {
56
- console.log('⚠️ .env file already exists!');
57
- console.log(' To re-onboard, delete .env first or edit manually.\n');
53
+ // Check if config already exists
54
+ if (fs.existsSync(CONFIG_PATH)) {
55
+ console.log('⚠️ Config already exists!');
56
+ console.log(` Location: ${CONFIG_PATH}\n`);
58
57
 
59
58
  // Read existing config and show wallet address
60
- const envContent = fs.readFileSync(envPath, 'utf-8');
59
+ const envContent = fs.readFileSync(CONFIG_PATH, 'utf-8');
61
60
  const keyMatch = envContent.match(/HYPERLIQUID_PRIVATE_KEY=0x([a-fA-F0-9]{64})/);
62
61
 
63
62
  if (keyMatch) {
64
63
  const existingKey = `0x${keyMatch[1]}` as `0x${string}`;
65
64
  const account = privateKeyToAccount(existingKey);
66
- console.log('Existing Configuration');
67
- console.log('----------------------');
65
+ console.log('Current Configuration');
66
+ console.log('---------------------');
68
67
  console.log(`Wallet Address: ${account.address}`);
69
- console.log(`\nTo fund this wallet, send USDC to the address above on Arbitrum.`);
70
- console.log(`Then deposit to Hyperliquid at: https://app.hyperliquid.xyz/`);
68
+ console.log(`Config File: ${CONFIG_PATH}`);
69
+ console.log(`\nTo reconfigure, delete the config file first:`);
70
+ console.log(` rm ${CONFIG_PATH}`);
71
+ console.log(`\nTo fund this wallet, send USDC on Arbitrum, then deposit at:`);
72
+ console.log(` https://app.hyperliquid.xyz/`);
71
73
 
72
74
  return {
73
75
  success: true,
@@ -77,7 +79,7 @@ async function main(): Promise<OnboardResult> {
77
79
 
78
80
  return {
79
81
  success: false,
80
- error: 'Invalid .env file - missing or malformed private key',
82
+ error: 'Invalid config file - missing or malformed private key',
81
83
  };
82
84
  }
83
85
 
@@ -100,8 +102,7 @@ async function main(): Promise<OnboardResult> {
100
102
 
101
103
  if (choice === '1') {
102
104
  // User has existing key
103
- console.log('\nEnter your private key (0x... format):');
104
- console.log('(Input is hidden for security)\n');
105
+ console.log('\nEnter your private key (0x... format):\n');
105
106
 
106
107
  let validKey = false;
107
108
  while (!validKey) {
@@ -130,12 +131,13 @@ async function main(): Promise<OnboardResult> {
130
131
  const account = privateKeyToAccount(privateKey);
131
132
  console.log(`\nWallet Address: ${account.address}\n`);
132
133
 
133
- // Create .env file
134
- console.log('Creating .env file...');
134
+ // Create config directory and file
135
+ console.log('Creating config...');
136
+ ensureConfigDir();
135
137
 
136
- const envContent = `# Open Broker - Environment Variables
137
- # Generated automatically during onboarding
138
- # WARNING: Keep this file secret! Never commit to git!
138
+ const envContent = `# OpenBroker Configuration
139
+ # Location: ~/.openbroker/.env
140
+ # WARNING: Keep this file secret! Never share it!
139
141
 
140
142
  # Your wallet private key
141
143
  HYPERLIQUID_PRIVATE_KEY=${privateKey}
@@ -143,14 +145,14 @@ HYPERLIQUID_PRIVATE_KEY=${privateKey}
143
145
  # Network: mainnet or testnet
144
146
  HYPERLIQUID_NETWORK=mainnet
145
147
 
146
- # Builder fee configuration (supports open-broker development)
148
+ # Builder fee (supports openbroker development)
147
149
  # Default: 1 bps (0.01%) on trades
148
150
  BUILDER_ADDRESS=${OPEN_BROKER_BUILDER_ADDRESS}
149
151
  BUILDER_FEE=10
150
152
  `;
151
153
 
152
- fs.writeFileSync(envPath, envContent, { mode: 0o600 }); // Restricted permissions
153
- console.log(`✅ .env created at: ${envPath}\n`);
154
+ fs.writeFileSync(CONFIG_PATH, envContent, { mode: 0o600 });
155
+ console.log(`✅ Config saved to: ${CONFIG_PATH}\n`);
154
156
 
155
157
  // Approve builder fee
156
158
  console.log('Approving builder fee...');
@@ -177,48 +179,49 @@ BUILDER_FEE=10
177
179
  console.log('✅ Builder fee approved successfully!');
178
180
  } else {
179
181
  console.log(`⚠️ Approval may have failed: ${result.response}`);
180
- console.log(' You can retry later: npx tsx scripts/setup/approve-builder.ts');
182
+ console.log(' You can retry later: openbroker approve-builder');
181
183
  }
182
184
  }
183
185
  } catch (error) {
184
186
  console.log(`⚠️ Could not approve builder fee: ${error}`);
185
- console.log(' You can retry later: npx tsx scripts/setup/approve-builder.ts');
187
+ console.log(' You can retry later: openbroker approve-builder');
186
188
  }
187
189
 
188
190
  // Final summary
189
191
  console.log('\n========================================');
190
- console.log(' ONBOARDING COMPLETE! ');
192
+ console.log(' SETUP COMPLETE! ');
191
193
  console.log('========================================\n');
192
194
 
193
195
  console.log('Your Trading Wallet');
194
196
  console.log('-------------------');
195
197
  console.log(`Address: ${account.address}`);
196
198
  console.log(`Network: Hyperliquid (Mainnet)`);
199
+ console.log(`Config: ${CONFIG_PATH}`);
197
200
 
198
201
  if (choice === '2') {
199
202
  console.log('\n⚠️ IMPORTANT: Save your private key!');
200
203
  console.log('-----------------------------------');
201
204
  console.log(`Private Key: ${privateKey}`);
202
- console.log('\nThis key is stored in .env but you should back it up securely.');
205
+ console.log('\nThis key is stored in ~/.openbroker/.env');
206
+ console.log('Back it up securely - if lost, funds cannot be recovered!');
203
207
  }
204
208
 
205
- console.log('\n📋 Next Step: Fund Your Wallet');
206
- console.log('-------------------------------');
207
- console.log('1. Send USDC to your wallet on Arbitrum:');
209
+ console.log('\n📋 Next Steps');
210
+ console.log('--------------');
211
+ console.log('1. Fund your wallet with USDC on Arbitrum:');
208
212
  console.log(` ${account.address}`);
209
213
  console.log('');
210
214
  console.log('2. Deposit USDC to Hyperliquid:');
211
215
  console.log(' https://app.hyperliquid.xyz/');
212
- console.log(' (Connect wallet → Deposit → Select amount)');
213
216
  console.log('');
214
217
  console.log('3. Start trading!');
215
- console.log(' npx tsx scripts/info/account.ts');
216
- console.log(' npx tsx scripts/operations/market-order.ts --coin ETH --side buy --size 0.01 --dry');
218
+ console.log(' openbroker account');
219
+ console.log(' openbroker buy --coin ETH --size 0.01 --dry');
217
220
 
218
- console.log('\n⚠️ SECURITY REMINDER');
219
- console.log('---------------------');
220
- console.log('Your private key is stored in .env');
221
- console.log('NEVER share this file or commit it to git!');
221
+ console.log('\n⚠️ Security');
222
+ console.log('------------');
223
+ console.log(`Config stored at: ${CONFIG_PATH}`);
224
+ console.log('Never share this file or your private key!');
222
225
 
223
226
  return {
224
227
  success: true,
@@ -233,10 +236,10 @@ export { main as onboard };
233
236
  // Run if executed directly
234
237
  main().then(result => {
235
238
  if (!result.success) {
236
- console.error(`\nOnboarding failed: ${result.error}`);
239
+ console.error(`\nSetup failed: ${result.error}`);
237
240
  process.exit(1);
238
241
  }
239
242
  }).catch(error => {
240
- console.error('Onboarding error:', error);
243
+ console.error('Setup error:', error);
241
244
  process.exit(1);
242
245
  });