@nalinsahani/wealtharena-cli 0.0.0-stage → 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.
Files changed (4) hide show
  1. package/README.md +25 -2
  2. package/bin/mcp.js +191 -0
  3. package/bin/wa.js +67 -0
  4. package/package.json +34 -4
package/README.md CHANGED
@@ -1,3 +1,26 @@
1
- # Temporary Holding Version
1
+ # @nalinsahani/wealtharena-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Wealth Arena CLI (`wa`) — unified terminal interface for quantitative trading, options analysis, and automated AI agents (`claude code`, `opencode`, `gemini cli`).
4
+
5
+ ## Quick Start
6
+
7
+ ### Zero-Install via Bun (Blazing Fast ~15ms)
8
+ ```bash
9
+ bunx @nalinsahani/wealtharena-cli --json market quote --symbol NSE:NIFTY50-INDEX
10
+ ```
11
+
12
+ ### Zero-Install via Node / NPX
13
+ ```bash
14
+ npx -y @nalinsahani/wealtharena-cli --json market quote --symbol NSE:NIFTY50-INDEX
15
+ ```
16
+
17
+ ### Global Install
18
+ ```bash
19
+ npm install -g @nalinsahani/wealtharena-cli
20
+ wa --json me
21
+ ```
22
+
23
+ ## Features
24
+ - **Deterministic JSON output**: Pass `--json` anywhere for machine-readable JSON envelopes.
25
+ - **Fail-closed live gate**: Paper trading is free; live trading refuses without `--live --yes` and margin verification.
26
+ - **AI Agent Native**: Automatic `X-AI-Actor` and `X-AI-Session` tracking with database audit logs.
package/bin/mcp.js ADDED
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wealth Arena Model Context Protocol (MCP) Server
5
+ * Lightweight, zero-external-dependency JSON-RPC stdio server compatible with Node.js and Bun.
6
+ * Exposes Wealth Arena tools directly to Claude Code, Gemini CLI, Cursor, and OpenCode.
7
+ */
8
+
9
+ const { spawnSync } = require('child_process');
10
+ const path = require('path');
11
+ const readline = require('readline');
12
+
13
+ // Locate the companion wa launcher
14
+ const waLauncher = path.join(__dirname, 'wa.js');
15
+
16
+ function callWa(args) {
17
+ const fullArgs = [waLauncher, '--json', ...args];
18
+ const proc = spawnSync(process.execPath, fullArgs, {
19
+ encoding: 'utf8',
20
+ env: { ...process.env, WA_AI: '1', WA_ACTOR: 'mcp-server' },
21
+ });
22
+ return {
23
+ status: proc.status,
24
+ stdout: proc.stdout || '',
25
+ stderr: proc.stderr || '',
26
+ };
27
+ }
28
+
29
+ const TOOLS = [
30
+ {
31
+ name: 'wa_market_quote',
32
+ description: 'Fetch real-time market quote (LTP, change, volume, prev close) for a broker symbol.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ symbol: { type: 'string', description: 'Broker symbol (e.g. "NSE:NIFTY50-INDEX", "NSE:SBIN-EQ")' },
37
+ },
38
+ required: ['symbol'],
39
+ },
40
+ },
41
+ {
42
+ name: 'wa_chain_snapshot',
43
+ description: 'Fetch option chain snapshot for an underlying asset with Greeks, strikes, and filters.',
44
+ inputSchema: {
45
+ type: 'object',
46
+ properties: {
47
+ symbol: { type: 'string', description: 'Underlying symbol (e.g. "NIFTY", "BANKNIFTY")' },
48
+ strikes: { type: 'string', description: 'Strike count on each side of ATM (default "10")' },
49
+ expiry: { type: 'string', description: 'Expiry date or "all" (empty = nearest)' },
50
+ },
51
+ required: ['symbol'],
52
+ },
53
+ },
54
+ {
55
+ name: 'wa_broker_status',
56
+ description: 'Check broker connectivity status (fyers, zerodha, indmoney, or all).',
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ broker: { type: 'string', description: 'Broker name: "fyers" | "zerodha" | "indmoney" | "all"' },
61
+ },
62
+ },
63
+ },
64
+ {
65
+ name: 'wa_paper_margin',
66
+ description: 'Check paper trading simulation margin and buying power.',
67
+ inputSchema: {
68
+ type: 'object',
69
+ properties: {},
70
+ },
71
+ },
72
+ {
73
+ name: 'wa_halt_status',
74
+ description: 'Check whether the emergency trading halt circuit breaker is active.',
75
+ inputSchema: {
76
+ type: 'object',
77
+ properties: {},
78
+ },
79
+ },
80
+ {
81
+ name: 'wa_live_margin',
82
+ description: 'Check live broker collateral and available trading margin.',
83
+ inputSchema: {
84
+ type: 'object',
85
+ properties: {},
86
+ },
87
+ },
88
+ ];
89
+
90
+ function handleToolCall(name, params) {
91
+ let cliArgs = [];
92
+ switch (name) {
93
+ case 'wa_market_quote':
94
+ cliArgs = ['market', 'quote', '--symbol', params.symbol];
95
+ break;
96
+ case 'wa_chain_snapshot':
97
+ cliArgs = ['chain', 'snapshot', '--symbol', params.symbol];
98
+ if (params.strikes) cliArgs.push('--strikes', params.strikes);
99
+ if (params.expiry) cliArgs.push('--expiry', params.expiry);
100
+ break;
101
+ case 'wa_broker_status':
102
+ cliArgs = ['broker', 'status'];
103
+ if (params.broker) cliArgs.push('--broker', params.broker);
104
+ break;
105
+ case 'wa_paper_margin':
106
+ cliArgs = ['paper', 'margin'];
107
+ break;
108
+ case 'wa_halt_status':
109
+ cliArgs = ['halt', 'status'];
110
+ break;
111
+ case 'wa_live_margin':
112
+ cliArgs = ['live', 'margin'];
113
+ break;
114
+ default:
115
+ return { isError: true, content: [{ type: 'text', text: `Unknown tool: ${name}` }] };
116
+ }
117
+
118
+ const res = callWa(cliArgs);
119
+ const textOutput = res.stdout.trim() || res.stderr.trim();
120
+ return {
121
+ isError: res.status !== 0,
122
+ content: [{ type: 'text', text: textOutput }],
123
+ };
124
+ }
125
+
126
+ // JSON-RPC stdio protocol loop
127
+ const rl = readline.createInterface({
128
+ input: process.stdin,
129
+ output: process.stdout,
130
+ terminal: false,
131
+ });
132
+
133
+ function sendResponse(id, result, error) {
134
+ const resp = { jsonrpc: '2.0', id };
135
+ if (error) {
136
+ resp.error = error;
137
+ } else {
138
+ resp.result = result;
139
+ }
140
+ process.stdout.write(JSON.stringify(resp) + '\n');
141
+ }
142
+
143
+ rl.on('line', (line) => {
144
+ if (!line.trim()) return;
145
+ let req;
146
+ try {
147
+ req = JSON.parse(line);
148
+ } catch (err) {
149
+ sendResponse(null, null, { code: -32700, message: 'Parse error' });
150
+ return;
151
+ }
152
+
153
+ const { id, method, params } = req;
154
+
155
+ switch (method) {
156
+ case 'initialize':
157
+ sendResponse(id, {
158
+ protocolVersion: '2024-11-05',
159
+ capabilities: { tools: {} },
160
+ serverInfo: { name: 'wealtharena-mcp', version: '0.1.0' },
161
+ });
162
+ break;
163
+
164
+ case 'notifications/initialized':
165
+ // Notification, no response needed
166
+ break;
167
+
168
+ case 'ping':
169
+ sendResponse(id, {});
170
+ break;
171
+
172
+ case 'tools/list':
173
+ sendResponse(id, { tools: TOOLS });
174
+ break;
175
+
176
+ case 'tools/call':
177
+ if (!params || !params.name) {
178
+ sendResponse(id, null, { code: -32602, message: 'Invalid params: tool name required' });
179
+ return;
180
+ }
181
+ const toolRes = handleToolCall(params.name, params.arguments || {});
182
+ sendResponse(id, toolRes);
183
+ break;
184
+
185
+ default:
186
+ if (id !== undefined && id !== null) {
187
+ sendResponse(id, null, { code: -32601, message: `Method not found: ${method}` });
188
+ }
189
+ break;
190
+ }
191
+ });
package/bin/wa.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wealth Arena CLI Launcher
5
+ * Cross-runtime launcher supporting Node.js (npx) and Bun (bunx).
6
+ * Spawns the pre-compiled native Go binary for the host platform with zero compilation overhead.
7
+ */
8
+
9
+ const { spawnSync } = require('child_process');
10
+ const path = require('path');
11
+ const os = require('os');
12
+ const fs = require('fs');
13
+
14
+ const platform = os.platform(); // 'linux', 'darwin', 'win32'
15
+ const arch = os.arch(); // 'x64', 'arm64'
16
+
17
+ const binaryName = platform === 'win32' ? 'wa.exe' : 'wa';
18
+ const targetName = `wa-${platform}-${arch}` + (platform === 'win32' ? '.exe' : '');
19
+ const pkgName = `@nalinsahani/wealtharena-cli-${platform}-${arch}`;
20
+
21
+ let binaryPath = null;
22
+
23
+ // 1. Try resolving from platform-specific optionalDependency
24
+ try {
25
+ binaryPath = require.resolve(`${pkgName}/bin/${binaryName}`);
26
+ } catch {
27
+ // Not installed as a platform dependency package, check local paths
28
+ }
29
+
30
+ // 2. Check local dist/bin directory (development / local builds)
31
+ if (!binaryPath || !fs.existsSync(binaryPath)) {
32
+ const localDist = path.join(__dirname, '..', '..', 'dist', 'bin', targetName);
33
+ if (fs.existsSync(localDist)) {
34
+ binaryPath = localDist;
35
+ }
36
+ }
37
+
38
+ // 3. Check adjacent root binary (fallback)
39
+ if (!binaryPath || !fs.existsSync(binaryPath)) {
40
+ const rootBin = path.join(__dirname, '..', '..', binaryName);
41
+ if (fs.existsSync(rootBin)) {
42
+ binaryPath = rootBin;
43
+ }
44
+ }
45
+
46
+ if (!binaryPath || !fs.existsSync(binaryPath)) {
47
+ console.error(`[wa] Error: Native binary not found for platform ${platform}-${arch}.`);
48
+ console.error(`[wa] Expected platform package: ${pkgName} or local binary at dist/bin/${targetName}`);
49
+ process.exit(1);
50
+ }
51
+
52
+ // 4. Ensure binary is executable (on unix systems)
53
+ if (platform !== 'win32') {
54
+ try {
55
+ fs.chmodSync(binaryPath, 0o755);
56
+ } catch {
57
+ // best-effort
58
+ }
59
+ }
60
+
61
+ // 5. Transparently spawn the Go binary, forwarding args, stdio, and exit code
62
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
63
+ stdio: 'inherit',
64
+ env: process.env,
65
+ });
66
+
67
+ process.exit(result.status ?? (result.signal ? 1 : 0));
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "@nalinsahani/wealtharena-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Wealth Arena trading & market CLI for traders and AI agents",
5
+ "bin": {
6
+ "wa": "./bin/wa.js",
7
+ "wa-mcp": "./bin/mcp.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "README.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18.0.0"
15
+ },
16
+ "optionalDependencies": {
17
+ "@nalinsahani/wealtharena-cli-darwin-arm64": "0.1.0",
18
+ "@nalinsahani/wealtharena-cli-darwin-x64": "0.1.0",
19
+ "@nalinsahani/wealtharena-cli-linux-arm64": "0.1.0",
20
+ "@nalinsahani/wealtharena-cli-linux-x64": "0.1.0",
21
+ "@nalinsahani/wealtharena-cli-win32-x64": "0.1.0"
22
+ },
23
+ "keywords": [
24
+ "trading",
25
+ "cli",
26
+ "fyers",
27
+ "zerodha",
28
+ "market-data",
29
+ "options",
30
+ "ai-agent",
31
+ "opencode",
32
+ "claude-code"
33
+ ],
34
+ "author": "Nalin Sahani",
35
+ "license": "UNLICENSED"
36
+ }