@invizi/cli 0.1.10 → 0.1.12

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # invizi-cli
2
2
 
3
- Thin CLI for Invizi with local auth/setup commands and remote command execution.
3
+ CLI for Invizi.
4
4
 
5
5
  ## Install
6
6
 
@@ -14,7 +14,7 @@ npm install -g @invizi/cli
14
14
  invizi auth login
15
15
  invizi auth status
16
16
  invizi --help
17
- invizi connect 0x1234...abcd --label main
17
+ invizi track 0x1234...abcd
18
18
  invizi setup
19
19
  ```
20
20
 
@@ -239,7 +239,7 @@ export async function trades(args) {
239
239
  const config = loadConfig();
240
240
  const address = positionals.find(a => /^0x[0-9a-fA-F]{40}$/.test(a)) || config.address;
241
241
  if (!address) {
242
- console.error('No address found. Run: invizi connect <address>');
242
+ console.error('No address found. Run: invizi track <address>');
243
243
  console.error('Or pass directly: invizi trades 0x...');
244
244
  return 1;
245
245
  }
package/dist/invizi.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { auth, getAuthorizationHeader } from './auth.js';
3
- import { connect } from './connect.js';
3
+ import { track } from './track.js';
4
4
  import { getApiUrl, getConfigPath, loadConfig, redactConfig } from './config.js';
5
5
  import { setup } from './setup.js';
6
6
  import { trades } from './commands/index.js';
@@ -19,7 +19,7 @@ Account:
19
19
  invizi login Login
20
20
  invizi logout Logout
21
21
  invizi auth status Show current identity
22
- invizi connect <address> Connect a wallet address
22
+ invizi track <address> Track a wallet address
23
23
 
24
24
  Setup:
25
25
  invizi setup Configure API + install AI skills
@@ -136,8 +136,8 @@ export async function main(rawArgs = process.argv.slice(2)) {
136
136
  return auth(['login']);
137
137
  if (command === 'logout')
138
138
  return auth(['logout']);
139
- if (command === 'connect')
140
- return connect(args.slice(1));
139
+ if (command === 'track')
140
+ return track(args.slice(1));
141
141
  if (command === 'trades')
142
142
  return trades(args.slice(1));
143
143
  if (command === 'setup')
package/dist/track.js ADDED
@@ -0,0 +1,131 @@
1
+ import { getApiUrl, loadConfig, saveConfig } from './config.js';
2
+ import { getAuthorizationHeader } from './auth.js';
3
+ const HLP_API = 'https://api.hyperliquid.xyz/info';
4
+ function detectChain(address) {
5
+ if (/^0x[0-9a-fA-F]{40}$/.test(address))
6
+ return 'evm';
7
+ return null;
8
+ }
9
+ const EXCHANGE_CHECKERS = {
10
+ evm: [{ name: 'hyperliquid', check: validateHlpAddress }],
11
+ };
12
+ async function validateHlpAddress(address) {
13
+ const [stateRes, fillsRes] = await Promise.all([
14
+ fetch(HLP_API, {
15
+ method: 'POST',
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ type: 'clearinghouseState', user: address }),
18
+ }),
19
+ fetch(HLP_API, {
20
+ method: 'POST',
21
+ headers: { 'Content-Type': 'application/json' },
22
+ body: JSON.stringify({ type: 'userFills', user: address }),
23
+ }),
24
+ ]);
25
+ if (!stateRes.ok || !fillsRes.ok) {
26
+ return null;
27
+ }
28
+ const state = (await stateRes.json());
29
+ const fills = (await fillsRes.json());
30
+ return {
31
+ positions: state.assetPositions?.length || 0,
32
+ accountValue: Number.parseFloat(state.marginSummary?.accountValue || '0'),
33
+ trades: fills.length || 0,
34
+ };
35
+ }
36
+ async function registerWithServer(exchange, address, label) {
37
+ const apiUrl = getApiUrl();
38
+ const authHeader = await getAuthorizationHeader();
39
+ if (!authHeader) {
40
+ throw new Error('Not authenticated. Run: invizi auth login');
41
+ }
42
+ const res = await fetch(`${apiUrl}/api/connect`, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ Authorization: authHeader,
47
+ },
48
+ body: JSON.stringify({ exchange, address, label }),
49
+ });
50
+ if (!res.ok) {
51
+ const bodyText = await res.text();
52
+ let parsed = null;
53
+ try {
54
+ parsed = JSON.parse(bodyText);
55
+ }
56
+ catch {
57
+ parsed = null;
58
+ }
59
+ if (res.status === 403 && parsed?.error?.includes('Tracking limit reached')) {
60
+ const tracked = parsed.trackedAddress;
61
+ const details = tracked
62
+ ? `existing ${tracked.exchange}:${tracked.address}${tracked.label ? ` (${tracked.label})` : ''}`
63
+ : 'already at limit';
64
+ throw new Error(`Tracking limit reached (${details}).`);
65
+ }
66
+ throw new Error(`Server error: ${res.status} ${parsed?.error || bodyText}`);
67
+ }
68
+ return (await res.json());
69
+ }
70
+ export async function track(args) {
71
+ const address = args[0];
72
+ const labelIdx = args.indexOf('--label');
73
+ const label = labelIdx !== -1 ? args[labelIdx + 1] || null : null;
74
+ if (!address) {
75
+ console.error('Usage: invizi track <wallet-address> [--label name]');
76
+ return 1;
77
+ }
78
+ const chain = detectChain(address);
79
+ if (!chain) {
80
+ console.error(`Unrecognized address format: ${address}`);
81
+ console.error('Supported: EVM addresses (0x...)');
82
+ return 1;
83
+ }
84
+ const checkers = EXCHANGE_CHECKERS[chain];
85
+ if (!checkers || checkers.length === 0) {
86
+ console.error(`No supported exchanges for chain: ${chain}`);
87
+ return 1;
88
+ }
89
+ console.log(`Scanning exchanges for ${address}...`);
90
+ const found = [];
91
+ for (const { name, check } of checkers) {
92
+ const info = await check(address);
93
+ if (info && (info.positions > 0 || info.trades > 0 || info.accountValue > 0)) {
94
+ found.push({ exchange: name, info });
95
+ console.log(` [ok] ${name}: ${info.positions} positions, ${info.trades} trades, $${info.accountValue.toFixed(2)}`);
96
+ }
97
+ else {
98
+ console.log(` [x] ${name}: no activity`);
99
+ }
100
+ }
101
+ if (found.length === 0) {
102
+ console.error('No activity found on any supported exchange for this address.');
103
+ return 1;
104
+ }
105
+ const selected = found[0];
106
+ try {
107
+ const result = await registerWithServer(selected.exchange, address, label);
108
+ const config = loadConfig();
109
+ config.userId = result.userId;
110
+ config.trackedAddressId = result.trackedAddressId;
111
+ delete config.accountId;
112
+ config.address = address;
113
+ config.exchange = selected.exchange;
114
+ if (label)
115
+ config.label = label;
116
+ saveConfig(config);
117
+ console.log(`Connected watch-only tracking: ${selected.exchange}`);
118
+ if (result.alreadyTracked) {
119
+ console.log(' Already tracked previously.');
120
+ }
121
+ console.log(` Positions: ${selected.info.positions}`);
122
+ console.log(` Trades: ${selected.info.trades}`);
123
+ console.log(` Account value: $${selected.info.accountValue.toFixed(2)}`);
124
+ return 0;
125
+ }
126
+ catch (error) {
127
+ const message = error instanceof Error ? error.message : String(error);
128
+ console.error(`Failed to register: ${message}`);
129
+ return 1;
130
+ }
131
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invizi/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Invizi CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,8 @@
14
14
  "build": "tsc -p tsconfig.json",
15
15
  "typecheck": "tsc --noEmit -p tsconfig.json",
16
16
  "test": "jest",
17
- "prepack": "npm run build"
17
+ "prepack": "npm run build",
18
+ "postinstall": "node -e \"console.log('\\n\\x1b[1m✨ Invizi CLI installed!\\x1b[0m\\n\\nGet started:\\n invizi login Authenticate\\n invizi connect <address> Connect your wallet\\n invizi setup Install AI skills\\n invizi market Check the markets\\n invizi --help See all commands\\n')\""
18
19
  },
19
20
  "devDependencies": {
20
21
  "@types/jest": "^30.0.0",