suzi-cli 0.1.14 → 0.1.16
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/CODEX_CLAUDE_ONBOARDING_DRAFT.md +318 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +10 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/create.d.ts +4 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +379 -3
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/portfolio.d.ts +5 -0
- package/dist/commands/portfolio.d.ts.map +1 -1
- package/dist/commands/portfolio.js +353 -283
- package/dist/commands/portfolio.js.map +1 -1
- package/dist/commands/run.d.ts +0 -4
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +305 -8
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/transactions.d.ts.map +1 -1
- package/dist/commands/transactions.js +41 -4
- package/dist/commands/transactions.js.map +1 -1
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +265 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +13 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +25 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/session-registry.d.ts +57 -0
- package/dist/lib/session-registry.d.ts.map +1 -0
- package/dist/lib/session-registry.js +192 -0
- package/dist/lib/session-registry.js.map +1 -0
- package/dist/lib/tooling-preflight.d.ts +17 -0
- package/dist/lib/tooling-preflight.d.ts.map +1 -0
- package/dist/lib/tooling-preflight.js +519 -0
- package/dist/lib/tooling-preflight.js.map +1 -0
- package/dist/types/portfolio.d.ts +36 -1
- package/dist/types/portfolio.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.renderPortfolioDisplay = renderPortfolioDisplay;
|
|
6
7
|
exports.registerPortfolioCommand = registerPortfolioCommand;
|
|
7
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
9
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
@@ -26,15 +27,366 @@ function getTokenSymbol(mintOrSymbol) {
|
|
|
26
27
|
// Return as-is (full mint address or symbol)
|
|
27
28
|
return mintOrSymbol;
|
|
28
29
|
}
|
|
30
|
+
function formatUsdSuffix(valueUsd) {
|
|
31
|
+
if (valueUsd == null || !Number.isFinite(valueUsd))
|
|
32
|
+
return '';
|
|
33
|
+
if (valueUsd > 0 && valueUsd < 0.005)
|
|
34
|
+
return ' (~<$0.01)';
|
|
35
|
+
return ` (~${(0, ui_1.formatUsd)(valueUsd)})`;
|
|
36
|
+
}
|
|
37
|
+
const BALANCE_DISPLAY_THRESHOLDS = {
|
|
38
|
+
usdValue: 0.01,
|
|
39
|
+
};
|
|
40
|
+
function shouldShowBalance(balance, showAllBalances, valueUsd) {
|
|
41
|
+
if (!Number.isFinite(balance) || balance <= 0)
|
|
42
|
+
return false;
|
|
43
|
+
if (showAllBalances)
|
|
44
|
+
return true;
|
|
45
|
+
if (valueUsd != null && Number.isFinite(valueUsd)) {
|
|
46
|
+
return valueUsd > BALANCE_DISPLAY_THRESHOLDS.usdValue;
|
|
47
|
+
}
|
|
48
|
+
// Hide unpriced assets by default; users can opt-in with --all-balances.
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
function renderPortfolioDisplay(portfolio, options = {}) {
|
|
52
|
+
const showAllBalances = options.showAllBalances ?? false;
|
|
53
|
+
// Display portfolio
|
|
54
|
+
(0, ui_1.header)('Portfolio');
|
|
55
|
+
console.log();
|
|
56
|
+
// Top-level summary
|
|
57
|
+
(0, ui_1.label)('Total Exposure', (0, ui_1.formatUsd)(portfolio.totals.totalExposure));
|
|
58
|
+
(0, ui_1.label)('Available Balance', (0, ui_1.formatUsd)(portfolio.totals.availableBalance));
|
|
59
|
+
(0, ui_1.label)('Open Positions', portfolio.totals.totalPositions.toString());
|
|
60
|
+
console.log();
|
|
61
|
+
// Protocol breakdown
|
|
62
|
+
console.log(ui_1.colors.muted(' Protocol Breakdown:'));
|
|
63
|
+
const protocolTable = new cli_table3_1.default({
|
|
64
|
+
head: [chalk_1.default.gray('Protocol'), chalk_1.default.gray('Value'), chalk_1.default.gray('Positions')],
|
|
65
|
+
style: { head: [], border: ['gray'] },
|
|
66
|
+
colWidths: [20, 18, 12],
|
|
67
|
+
});
|
|
68
|
+
if (portfolio.protocols.hyperliquid.totalEquity > 0 || portfolio.protocols.hyperliquid.totalPositions > 0) {
|
|
69
|
+
protocolTable.push([
|
|
70
|
+
ui_1.colors.evm('Hyperliquid'),
|
|
71
|
+
(0, ui_1.formatUsd)(portfolio.protocols.hyperliquid.totalEquity),
|
|
72
|
+
portfolio.protocols.hyperliquid.totalPositions.toString(),
|
|
73
|
+
]);
|
|
74
|
+
}
|
|
75
|
+
if (portfolio.protocols.polymarket.totalValue > 0 || portfolio.protocols.polymarket.totalPositions > 0) {
|
|
76
|
+
protocolTable.push([
|
|
77
|
+
ui_1.colors.secondary('Polymarket'),
|
|
78
|
+
(0, ui_1.formatUsd)(portfolio.protocols.polymarket.totalValue),
|
|
79
|
+
portfolio.protocols.polymarket.totalPositions.toString(),
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
if (portfolio.protocols.kamino.netValueUsd > 0 || portfolio.protocols.kamino.positions.length > 0) {
|
|
83
|
+
protocolTable.push([
|
|
84
|
+
ui_1.colors.sol('Kamino'),
|
|
85
|
+
(0, ui_1.formatUsd)(portfolio.protocols.kamino.netValueUsd),
|
|
86
|
+
portfolio.protocols.kamino.positions.length.toString(),
|
|
87
|
+
]);
|
|
88
|
+
}
|
|
89
|
+
if (portfolio.protocols.meteora.totalEquity > 0 || portfolio.protocols.meteora.totalPositions > 0) {
|
|
90
|
+
protocolTable.push([
|
|
91
|
+
ui_1.colors.sol('Meteora'),
|
|
92
|
+
(0, ui_1.formatUsd)(portfolio.protocols.meteora.totalEquity),
|
|
93
|
+
portfolio.protocols.meteora.totalPositions.toString(),
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
if (protocolTable.length > 0) {
|
|
97
|
+
console.log(protocolTable.toString());
|
|
98
|
+
console.log();
|
|
99
|
+
}
|
|
100
|
+
(0, ui_1.divider)();
|
|
101
|
+
// === Spot Balances Section ===
|
|
102
|
+
const balanceTable = new cli_table3_1.default({
|
|
103
|
+
head: [chalk_1.default.gray('Asset'), chalk_1.default.gray('Balance'), chalk_1.default.gray('Chain')],
|
|
104
|
+
style: { head: [], border: ['gray'] },
|
|
105
|
+
colWidths: [46, 24, 16],
|
|
106
|
+
});
|
|
107
|
+
let hasBalances = false;
|
|
108
|
+
// SOL native balance
|
|
109
|
+
if (shouldShowBalance(portfolio.balances.solana.nativeBalance, showAllBalances, portfolio.balances.solana.nativeValueUsd)) {
|
|
110
|
+
balanceTable.push([
|
|
111
|
+
ui_1.colors.sol('SOL'),
|
|
112
|
+
chalk_1.default.bold(`${portfolio.balances.solana.nativeBalance.toFixed(4)}${formatUsdSuffix(portfolio.balances.solana.nativeValueUsd)}`),
|
|
113
|
+
ui_1.colors.muted('(Solana)'),
|
|
114
|
+
]);
|
|
115
|
+
hasBalances = true;
|
|
116
|
+
}
|
|
117
|
+
// All SPL tokens (dynamic)
|
|
118
|
+
for (const token of portfolio.balances.solana.tokenBalances) {
|
|
119
|
+
if (!shouldShowBalance(token.balance, showAllBalances, token.valueUsd))
|
|
120
|
+
continue;
|
|
121
|
+
const symbol = getTokenSymbol(token.token);
|
|
122
|
+
balanceTable.push([
|
|
123
|
+
chalk_1.default.white(symbol),
|
|
124
|
+
chalk_1.default.bold(`${token.balance.toFixed(2)}${formatUsdSuffix(token.valueUsd)}`),
|
|
125
|
+
ui_1.colors.muted('(Solana)'),
|
|
126
|
+
]);
|
|
127
|
+
hasBalances = true;
|
|
128
|
+
}
|
|
129
|
+
// Hyperliquid spot balances
|
|
130
|
+
for (const spot of portfolio.protocols.hyperliquid.spotBalances || []) {
|
|
131
|
+
if (!shouldShowBalance(spot.balance, showAllBalances, spot.valueUsd))
|
|
132
|
+
continue;
|
|
133
|
+
balanceTable.push([
|
|
134
|
+
chalk_1.default.green(spot.token),
|
|
135
|
+
chalk_1.default.bold(`${spot.balance.toFixed(2)}${formatUsdSuffix(spot.valueUsd)}`),
|
|
136
|
+
ui_1.colors.muted('(Hyperliquid)'),
|
|
137
|
+
]);
|
|
138
|
+
hasBalances = true;
|
|
139
|
+
}
|
|
140
|
+
// EVM chain balances (native + ERC-20)
|
|
141
|
+
const evmChains = [
|
|
142
|
+
{ key: 'ethereum', display: 'Ethereum', color: chalk_1.default.blue },
|
|
143
|
+
{ key: 'arbitrum', display: 'Arbitrum', color: chalk_1.default.cyan },
|
|
144
|
+
{ key: 'polygon', display: 'Polygon', color: chalk_1.default.magenta },
|
|
145
|
+
{ key: 'base', display: 'Base', color: chalk_1.default.blueBright },
|
|
146
|
+
{ key: 'optimism', display: 'Optimism', color: chalk_1.default.red },
|
|
147
|
+
];
|
|
148
|
+
for (const { key, display, color } of evmChains) {
|
|
149
|
+
const chainData = portfolio.balances.evm[key];
|
|
150
|
+
if (!chainData)
|
|
151
|
+
continue;
|
|
152
|
+
const nativeBalance = Number.parseFloat(chainData.nativeBalance);
|
|
153
|
+
if (shouldShowBalance(nativeBalance, showAllBalances, chainData.nativeValueUsd)) {
|
|
154
|
+
balanceTable.push([
|
|
155
|
+
color(chainData.nativeAsset),
|
|
156
|
+
chalk_1.default.bold(`${nativeBalance.toFixed(4)}${formatUsdSuffix(chainData.nativeValueUsd)}`),
|
|
157
|
+
ui_1.colors.muted(`(${display})`),
|
|
158
|
+
]);
|
|
159
|
+
hasBalances = true;
|
|
160
|
+
}
|
|
161
|
+
for (const token of chainData.tokenBalances) {
|
|
162
|
+
const tokenBalance = Number.parseFloat(token.balance);
|
|
163
|
+
if (!shouldShowBalance(tokenBalance, showAllBalances, token.valueUsd))
|
|
164
|
+
continue;
|
|
165
|
+
balanceTable.push([
|
|
166
|
+
chalk_1.default.white(token.symbol || 'UNKNOWN'),
|
|
167
|
+
chalk_1.default.bold(`${tokenBalance.toFixed(2)}${formatUsdSuffix(token.valueUsd)}`),
|
|
168
|
+
ui_1.colors.muted(`(${display})`),
|
|
169
|
+
]);
|
|
170
|
+
hasBalances = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (hasBalances) {
|
|
174
|
+
console.log(balanceTable.toString());
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
(0, ui_1.info)('No spot balances found.');
|
|
178
|
+
}
|
|
179
|
+
if (portfolio.balances.evm.errors && Object.keys(portfolio.balances.evm.errors).length > 0) {
|
|
180
|
+
console.log();
|
|
181
|
+
(0, ui_1.warn)('Some EVM chains failed to load:');
|
|
182
|
+
for (const [chain, errorMsg] of Object.entries(portfolio.balances.evm.errors)) {
|
|
183
|
+
console.log(` ${chalk_1.default.gray('•')} ${chain}: ${chalk_1.default.red(errorMsg)}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// === Hyperliquid Overview ===
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(ui_1.colors.evm.bold(' Hyperliquid'));
|
|
189
|
+
const marketMakers = portfolio.protocols.hyperliquid.marketMakers;
|
|
190
|
+
// Market Maker Summary Table
|
|
191
|
+
const mmEntries = [
|
|
192
|
+
['main', marketMakers.main],
|
|
193
|
+
['xyz', marketMakers.xyz],
|
|
194
|
+
['flx', marketMakers.flx],
|
|
195
|
+
['vntl', marketMakers.vntl],
|
|
196
|
+
['hyna', marketMakers.hyna],
|
|
197
|
+
['km', marketMakers.km],
|
|
198
|
+
['cash', marketMakers.cash],
|
|
199
|
+
];
|
|
200
|
+
const mmSummaryTable = new cli_table3_1.default({
|
|
201
|
+
head: [
|
|
202
|
+
chalk_1.default.gray('Market Maker'),
|
|
203
|
+
chalk_1.default.gray('Equity'),
|
|
204
|
+
chalk_1.default.gray('Available'),
|
|
205
|
+
chalk_1.default.gray('Positions'),
|
|
206
|
+
],
|
|
207
|
+
style: { head: [], border: ['gray'] },
|
|
208
|
+
});
|
|
209
|
+
let hasActiveMarketMakers = false;
|
|
210
|
+
for (const [mm, data] of mmEntries) {
|
|
211
|
+
if (data && (data.equity > 0 || data.positions.length > 0)) {
|
|
212
|
+
mmSummaryTable.push([
|
|
213
|
+
mm === 'main' ? chalk_1.default.white(mm) : chalk_1.default.cyan(mm),
|
|
214
|
+
(0, ui_1.formatUsd)(data.equity),
|
|
215
|
+
(0, ui_1.formatUsd)(data.availableBalance),
|
|
216
|
+
data.positions.length.toString(),
|
|
217
|
+
]);
|
|
218
|
+
hasActiveMarketMakers = true;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (hasActiveMarketMakers) {
|
|
222
|
+
console.log(mmSummaryTable.toString());
|
|
223
|
+
}
|
|
224
|
+
// Aggregate all positions
|
|
225
|
+
const allHlPositions = [];
|
|
226
|
+
for (const [mm, data] of mmEntries) {
|
|
227
|
+
if (data?.positions) {
|
|
228
|
+
for (const posWrapper of data.positions) {
|
|
229
|
+
allHlPositions.push({ ...posWrapper.position, marketMaker: mm });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Positions Detail Table
|
|
234
|
+
if (allHlPositions.length > 0) {
|
|
235
|
+
console.log();
|
|
236
|
+
console.log(ui_1.colors.muted(' Open Positions:'));
|
|
237
|
+
const hlTable = new cli_table3_1.default({
|
|
238
|
+
head: [
|
|
239
|
+
chalk_1.default.gray('Market'),
|
|
240
|
+
chalk_1.default.gray('Side'),
|
|
241
|
+
chalk_1.default.gray('Size'),
|
|
242
|
+
chalk_1.default.gray('Entry'),
|
|
243
|
+
chalk_1.default.gray('Value'),
|
|
244
|
+
chalk_1.default.gray('PnL'),
|
|
245
|
+
chalk_1.default.gray('MM'),
|
|
246
|
+
],
|
|
247
|
+
style: { head: [], border: ['gray'] },
|
|
248
|
+
});
|
|
249
|
+
for (const pos of allHlPositions) {
|
|
250
|
+
const pnl = parseFloat(pos.unrealizedPnl || '0');
|
|
251
|
+
const size = parseFloat(pos.szi || '0');
|
|
252
|
+
hlTable.push([
|
|
253
|
+
pos.coin || 'N/A',
|
|
254
|
+
size > 0 ? chalk_1.default.green('LONG') : chalk_1.default.red('SHORT'),
|
|
255
|
+
Math.abs(size).toFixed(4),
|
|
256
|
+
(0, ui_1.formatUsd)(parseFloat(pos.entryPx || '0')),
|
|
257
|
+
(0, ui_1.formatUsd)(parseFloat(pos.positionValue || '0')),
|
|
258
|
+
pnl >= 0
|
|
259
|
+
? chalk_1.default.green(`+$${pnl.toFixed(2)}`)
|
|
260
|
+
: chalk_1.default.red(`-$${Math.abs(pnl).toFixed(2)}`),
|
|
261
|
+
ui_1.colors.muted(pos.marketMaker),
|
|
262
|
+
]);
|
|
263
|
+
}
|
|
264
|
+
console.log(hlTable.toString());
|
|
265
|
+
// Show aggregate P&L
|
|
266
|
+
const totalPnl = allHlPositions.reduce((sum, pos) => sum + parseFloat(pos.unrealizedPnl || '0'), 0);
|
|
267
|
+
(0, ui_1.info)(` Total: ${(0, ui_1.formatUsd)(portfolio.protocols.hyperliquid.totalEquity)} | ` +
|
|
268
|
+
`Unrealized P&L: ${totalPnl >= 0
|
|
269
|
+
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(totalPnl)}`)
|
|
270
|
+
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(totalPnl))}`)}`);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log();
|
|
274
|
+
(0, ui_1.info)(' No open positions.');
|
|
275
|
+
}
|
|
276
|
+
// === Polymarket Positions ===
|
|
277
|
+
console.log();
|
|
278
|
+
console.log(ui_1.colors.secondary.bold(' Polymarket Positions'));
|
|
279
|
+
if (portfolio.protocols.polymarket.totalPositions > 0) {
|
|
280
|
+
const pmTable = new cli_table3_1.default({
|
|
281
|
+
head: [
|
|
282
|
+
chalk_1.default.gray('Market'),
|
|
283
|
+
chalk_1.default.gray('Outcome'),
|
|
284
|
+
chalk_1.default.gray('Size'),
|
|
285
|
+
chalk_1.default.gray('Avg'),
|
|
286
|
+
chalk_1.default.gray('Cur'),
|
|
287
|
+
chalk_1.default.gray('P&L'),
|
|
288
|
+
],
|
|
289
|
+
style: { head: [], border: ['gray'] },
|
|
290
|
+
});
|
|
291
|
+
for (const pos of portfolio.protocols.polymarket.positions) {
|
|
292
|
+
const pnl = pos.cashPnl;
|
|
293
|
+
pmTable.push([
|
|
294
|
+
pos.title,
|
|
295
|
+
pos.outcome === 'Yes' ? chalk_1.default.green('Yes') : chalk_1.default.red('No'),
|
|
296
|
+
pos.size.toFixed(0),
|
|
297
|
+
(0, ui_1.formatUsd)(pos.avgPrice),
|
|
298
|
+
(0, ui_1.formatUsd)(pos.curPrice),
|
|
299
|
+
pnl >= 0
|
|
300
|
+
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(pnl)}`)
|
|
301
|
+
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(pnl))}`),
|
|
302
|
+
]);
|
|
303
|
+
}
|
|
304
|
+
console.log(pmTable.toString());
|
|
305
|
+
const totalPnl = portfolio.protocols.polymarket.totalPnl;
|
|
306
|
+
(0, ui_1.info)(` Total: ${(0, ui_1.formatUsd)(portfolio.protocols.polymarket.totalValue)} | ` +
|
|
307
|
+
`P&L: ${totalPnl >= 0
|
|
308
|
+
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(totalPnl)}`)
|
|
309
|
+
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(totalPnl))}`)}`);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
(0, ui_1.info)(' No Polymarket positions.');
|
|
313
|
+
}
|
|
314
|
+
// === Kamino Lending ===
|
|
315
|
+
console.log();
|
|
316
|
+
console.log(ui_1.colors.sol.bold(' Kamino Lending'));
|
|
317
|
+
if (portfolio.protocols.kamino.positions.length > 0) {
|
|
318
|
+
const kaminoTable = new cli_table3_1.default({
|
|
319
|
+
head: [
|
|
320
|
+
chalk_1.default.gray('Type'),
|
|
321
|
+
chalk_1.default.gray('Asset'),
|
|
322
|
+
chalk_1.default.gray('Amount'),
|
|
323
|
+
chalk_1.default.gray('USD Value'),
|
|
324
|
+
],
|
|
325
|
+
style: { head: [], border: ['gray'] },
|
|
326
|
+
});
|
|
327
|
+
for (const pos of portfolio.protocols.kamino.positions) {
|
|
328
|
+
kaminoTable.push([
|
|
329
|
+
pos.type === 'deposit' ? chalk_1.default.green('Deposit') : chalk_1.default.yellow('Borrow'),
|
|
330
|
+
pos.symbol,
|
|
331
|
+
parseFloat(pos.amount).toFixed(4),
|
|
332
|
+
(0, ui_1.formatUsd)(parseFloat(pos.amountUsd)),
|
|
333
|
+
]);
|
|
334
|
+
}
|
|
335
|
+
console.log(kaminoTable.toString());
|
|
336
|
+
(0, ui_1.info)(` Deposits: ${(0, ui_1.formatUsd)(portfolio.protocols.kamino.totalDepositsUsd)} | ` +
|
|
337
|
+
`Borrows: ${(0, ui_1.formatUsd)(portfolio.protocols.kamino.totalBorrowsUsd)} | ` +
|
|
338
|
+
`Net: ${(0, ui_1.formatUsd)(portfolio.protocols.kamino.netValueUsd)}`);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
(0, ui_1.info)(' No Kamino positions.');
|
|
342
|
+
}
|
|
343
|
+
// === Meteora LP ===
|
|
344
|
+
console.log();
|
|
345
|
+
console.log(ui_1.colors.sol.bold(' Meteora LP Positions'));
|
|
346
|
+
if (portfolio.protocols.meteora.totalPositions > 0) {
|
|
347
|
+
const metTable = new cli_table3_1.default({
|
|
348
|
+
head: [
|
|
349
|
+
chalk_1.default.gray('Pool'),
|
|
350
|
+
chalk_1.default.gray('Token X'),
|
|
351
|
+
chalk_1.default.gray('Token Y'),
|
|
352
|
+
chalk_1.default.gray('USD Value'),
|
|
353
|
+
],
|
|
354
|
+
style: { head: [], border: ['gray'] },
|
|
355
|
+
});
|
|
356
|
+
for (const pool of portfolio.protocols.meteora.positions || []) {
|
|
357
|
+
const shortPool = pool.poolAddress.slice(0, 4) + '…' + pool.poolAddress.slice(-4);
|
|
358
|
+
pool.positions.forEach((pos, idx) => {
|
|
359
|
+
const xAmt = parseFloat(pos.totalXAmount || '0');
|
|
360
|
+
const yAmt = parseFloat(pos.totalYAmount || '0');
|
|
361
|
+
metTable.push([
|
|
362
|
+
shortPool,
|
|
363
|
+
chalk_1.default.bold(xAmt.toFixed(4)),
|
|
364
|
+
chalk_1.default.bold(yAmt.toFixed(2)),
|
|
365
|
+
// Only show USD value for the first position in the pool
|
|
366
|
+
idx === 0 ? chalk_1.default.green((0, ui_1.formatUsd)(pool.estimatedValueUsd)) : '',
|
|
367
|
+
]);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
console.log(metTable.toString());
|
|
371
|
+
(0, ui_1.info)(` Total Value: ${(0, ui_1.formatUsd)(portfolio.protocols.meteora.totalEquity)}`);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
(0, ui_1.info)(' No Meteora positions.');
|
|
375
|
+
}
|
|
376
|
+
console.log();
|
|
377
|
+
(0, ui_1.divider)();
|
|
378
|
+
}
|
|
29
379
|
function registerPortfolioCommand(program) {
|
|
30
380
|
program
|
|
31
381
|
.command('portfolio')
|
|
32
382
|
.description('View your complete portfolio — balances, positions, P&L across all protocols')
|
|
33
383
|
.option('--json', 'Output as JSON')
|
|
384
|
+
.option('--all-balances', 'Show low/dust spot balances (default hides tiny balances)')
|
|
34
385
|
.action(async (opts) => {
|
|
35
386
|
if (!(0, ui_1.requireAuth)())
|
|
36
387
|
return;
|
|
37
388
|
const jsonMode = opts?.json || false;
|
|
389
|
+
const showAllBalances = opts?.allBalances || false;
|
|
38
390
|
const account = (0, config_1.getActiveAccount)();
|
|
39
391
|
if (!account) {
|
|
40
392
|
const msg = 'No active account.';
|
|
@@ -69,295 +421,13 @@ function registerPortfolioCommand(program) {
|
|
|
69
421
|
(0, tty_1.outputJson)({ success: true, data: portfolio });
|
|
70
422
|
return;
|
|
71
423
|
}
|
|
72
|
-
|
|
73
|
-
(0, ui_1.header)('Portfolio');
|
|
74
|
-
console.log();
|
|
75
|
-
// Top-level summary
|
|
76
|
-
(0, ui_1.label)('Total Equity', (0, ui_1.formatUsd)(portfolio.totals.totalEquity));
|
|
77
|
-
(0, ui_1.label)('Available Balance', (0, ui_1.formatUsd)(portfolio.totals.availableBalance));
|
|
78
|
-
(0, ui_1.label)('Open Positions', portfolio.totals.totalPositions.toString());
|
|
79
|
-
console.log();
|
|
80
|
-
// Protocol breakdown
|
|
81
|
-
console.log(ui_1.colors.muted(' Protocol Breakdown:'));
|
|
82
|
-
const protocolTable = new cli_table3_1.default({
|
|
83
|
-
head: [chalk_1.default.gray('Protocol'), chalk_1.default.gray('Value'), chalk_1.default.gray('Positions')],
|
|
84
|
-
style: { head: [], border: ['gray'] },
|
|
85
|
-
colWidths: [20, 18, 12],
|
|
86
|
-
});
|
|
87
|
-
if (portfolio.protocols.hyperliquid.totalEquity > 0 || portfolio.protocols.hyperliquid.totalPositions > 0) {
|
|
88
|
-
protocolTable.push([
|
|
89
|
-
ui_1.colors.evm('Hyperliquid'),
|
|
90
|
-
(0, ui_1.formatUsd)(portfolio.protocols.hyperliquid.totalEquity),
|
|
91
|
-
portfolio.protocols.hyperliquid.totalPositions.toString(),
|
|
92
|
-
]);
|
|
93
|
-
}
|
|
94
|
-
if (portfolio.protocols.polymarket.totalValue > 0 || portfolio.protocols.polymarket.totalPositions > 0) {
|
|
95
|
-
protocolTable.push([
|
|
96
|
-
ui_1.colors.secondary('Polymarket'),
|
|
97
|
-
(0, ui_1.formatUsd)(portfolio.protocols.polymarket.totalValue),
|
|
98
|
-
portfolio.protocols.polymarket.totalPositions.toString(),
|
|
99
|
-
]);
|
|
100
|
-
}
|
|
101
|
-
if (portfolio.protocols.kamino.netValueUsd > 0 || portfolio.protocols.kamino.positions.length > 0) {
|
|
102
|
-
protocolTable.push([
|
|
103
|
-
ui_1.colors.sol('Kamino'),
|
|
104
|
-
(0, ui_1.formatUsd)(portfolio.protocols.kamino.netValueUsd),
|
|
105
|
-
portfolio.protocols.kamino.positions.length.toString(),
|
|
106
|
-
]);
|
|
107
|
-
}
|
|
108
|
-
if (portfolio.protocols.meteora.totalEquity > 0 || portfolio.protocols.meteora.totalPositions > 0) {
|
|
109
|
-
protocolTable.push([
|
|
110
|
-
ui_1.colors.sol('Meteora'),
|
|
111
|
-
(0, ui_1.formatUsd)(portfolio.protocols.meteora.totalEquity),
|
|
112
|
-
portfolio.protocols.meteora.totalPositions.toString(),
|
|
113
|
-
]);
|
|
114
|
-
}
|
|
115
|
-
if (protocolTable.length > 0) {
|
|
116
|
-
console.log(protocolTable.toString());
|
|
117
|
-
console.log();
|
|
118
|
-
}
|
|
119
|
-
(0, ui_1.divider)();
|
|
120
|
-
// === Spot Balances Section ===
|
|
121
|
-
const balanceTable = new cli_table3_1.default({
|
|
122
|
-
head: [chalk_1.default.gray('Asset'), chalk_1.default.gray('Balance'), chalk_1.default.gray('Chain')],
|
|
123
|
-
style: { head: [], border: ['gray'] },
|
|
124
|
-
colWidths: [46, 18, 16],
|
|
125
|
-
});
|
|
126
|
-
let hasBalances = false;
|
|
127
|
-
// SOL native balance
|
|
128
|
-
if (portfolio.balances.solana.nativeBalance > 0) {
|
|
129
|
-
balanceTable.push([
|
|
130
|
-
ui_1.colors.sol('SOL'),
|
|
131
|
-
chalk_1.default.bold(portfolio.balances.solana.nativeBalance.toFixed(4)),
|
|
132
|
-
ui_1.colors.muted('(Solana)'),
|
|
133
|
-
]);
|
|
134
|
-
hasBalances = true;
|
|
135
|
-
}
|
|
136
|
-
// All SPL tokens (dynamic)
|
|
137
|
-
for (const token of portfolio.balances.solana.tokenBalances) {
|
|
138
|
-
const symbol = getTokenSymbol(token.token);
|
|
139
|
-
balanceTable.push([
|
|
140
|
-
chalk_1.default.white(symbol),
|
|
141
|
-
chalk_1.default.bold(token.balance.toFixed(2)),
|
|
142
|
-
ui_1.colors.muted('(Solana)'),
|
|
143
|
-
]);
|
|
144
|
-
hasBalances = true;
|
|
145
|
-
}
|
|
146
|
-
// Hyperliquid spot balances
|
|
147
|
-
for (const spot of portfolio.protocols.hyperliquid.spotBalances || []) {
|
|
148
|
-
if (spot.balance > 0) {
|
|
149
|
-
balanceTable.push([
|
|
150
|
-
chalk_1.default.green(spot.token),
|
|
151
|
-
chalk_1.default.bold(spot.balance.toFixed(2)),
|
|
152
|
-
ui_1.colors.muted('(Hyperliquid)'),
|
|
153
|
-
]);
|
|
154
|
-
hasBalances = true;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (hasBalances) {
|
|
158
|
-
console.log(balanceTable.toString());
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
(0, ui_1.info)('No spot balances found.');
|
|
162
|
-
}
|
|
163
|
-
// === Hyperliquid Overview ===
|
|
164
|
-
console.log();
|
|
165
|
-
console.log(ui_1.colors.evm.bold(' Hyperliquid'));
|
|
166
|
-
const marketMakers = portfolio.protocols.hyperliquid.marketMakers;
|
|
167
|
-
// Market Maker Summary Table
|
|
168
|
-
const mmEntries = [
|
|
169
|
-
['main', marketMakers.main],
|
|
170
|
-
['xyz', marketMakers.xyz],
|
|
171
|
-
['flx', marketMakers.flx],
|
|
172
|
-
['vntl', marketMakers.vntl],
|
|
173
|
-
['hyna', marketMakers.hyna],
|
|
174
|
-
['km', marketMakers.km],
|
|
175
|
-
['cash', marketMakers.cash],
|
|
176
|
-
];
|
|
177
|
-
const mmSummaryTable = new cli_table3_1.default({
|
|
178
|
-
head: [
|
|
179
|
-
chalk_1.default.gray('Market Maker'),
|
|
180
|
-
chalk_1.default.gray('Equity'),
|
|
181
|
-
chalk_1.default.gray('Available'),
|
|
182
|
-
chalk_1.default.gray('Positions'),
|
|
183
|
-
],
|
|
184
|
-
style: { head: [], border: ['gray'] },
|
|
185
|
-
});
|
|
186
|
-
let hasActiveMarketMakers = false;
|
|
187
|
-
for (const [mm, data] of mmEntries) {
|
|
188
|
-
if (data && (data.equity > 0 || data.positions.length > 0)) {
|
|
189
|
-
mmSummaryTable.push([
|
|
190
|
-
mm === 'main' ? chalk_1.default.white(mm) : chalk_1.default.cyan(mm),
|
|
191
|
-
(0, ui_1.formatUsd)(data.equity),
|
|
192
|
-
(0, ui_1.formatUsd)(data.availableBalance),
|
|
193
|
-
data.positions.length.toString(),
|
|
194
|
-
]);
|
|
195
|
-
hasActiveMarketMakers = true;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (hasActiveMarketMakers) {
|
|
199
|
-
console.log(mmSummaryTable.toString());
|
|
200
|
-
}
|
|
201
|
-
// Aggregate all positions
|
|
202
|
-
const allHlPositions = [];
|
|
203
|
-
for (const [mm, data] of mmEntries) {
|
|
204
|
-
if (data?.positions) {
|
|
205
|
-
for (const posWrapper of data.positions) {
|
|
206
|
-
allHlPositions.push({ ...posWrapper.position, marketMaker: mm });
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Positions Detail Table
|
|
211
|
-
if (allHlPositions.length > 0) {
|
|
212
|
-
console.log();
|
|
213
|
-
console.log(ui_1.colors.muted(' Open Positions:'));
|
|
214
|
-
const hlTable = new cli_table3_1.default({
|
|
215
|
-
head: [
|
|
216
|
-
chalk_1.default.gray('Market'),
|
|
217
|
-
chalk_1.default.gray('Side'),
|
|
218
|
-
chalk_1.default.gray('Size'),
|
|
219
|
-
chalk_1.default.gray('Entry'),
|
|
220
|
-
chalk_1.default.gray('Value'),
|
|
221
|
-
chalk_1.default.gray('PnL'),
|
|
222
|
-
chalk_1.default.gray('MM'),
|
|
223
|
-
],
|
|
224
|
-
style: { head: [], border: ['gray'] },
|
|
225
|
-
});
|
|
226
|
-
for (const pos of allHlPositions) {
|
|
227
|
-
const pnl = parseFloat(pos.unrealizedPnl || '0');
|
|
228
|
-
const size = parseFloat(pos.szi || '0');
|
|
229
|
-
hlTable.push([
|
|
230
|
-
pos.coin || 'N/A',
|
|
231
|
-
size > 0 ? chalk_1.default.green('LONG') : chalk_1.default.red('SHORT'),
|
|
232
|
-
Math.abs(size).toFixed(4),
|
|
233
|
-
(0, ui_1.formatUsd)(parseFloat(pos.entryPx || '0')),
|
|
234
|
-
(0, ui_1.formatUsd)(parseFloat(pos.positionValue || '0')),
|
|
235
|
-
pnl >= 0
|
|
236
|
-
? chalk_1.default.green(`+$${pnl.toFixed(2)}`)
|
|
237
|
-
: chalk_1.default.red(`-$${Math.abs(pnl).toFixed(2)}`),
|
|
238
|
-
ui_1.colors.muted(pos.marketMaker === 'undefined' ? 'main' : pos.marketMaker),
|
|
239
|
-
]);
|
|
240
|
-
}
|
|
241
|
-
console.log(hlTable.toString());
|
|
242
|
-
// Show aggregate P&L
|
|
243
|
-
const totalPnl = allHlPositions.reduce((sum, pos) => sum + parseFloat(pos.unrealizedPnl || '0'), 0);
|
|
244
|
-
(0, ui_1.info)(` Total: ${(0, ui_1.formatUsd)(portfolio.protocols.hyperliquid.totalEquity)} | ` +
|
|
245
|
-
`Unrealized P&L: ${totalPnl >= 0
|
|
246
|
-
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(totalPnl)}`)
|
|
247
|
-
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(totalPnl))}`)}`);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
console.log();
|
|
251
|
-
(0, ui_1.info)(' No open positions.');
|
|
252
|
-
}
|
|
253
|
-
// === Polymarket Positions ===
|
|
254
|
-
console.log();
|
|
255
|
-
console.log(ui_1.colors.secondary.bold(' Polymarket Positions'));
|
|
256
|
-
if (portfolio.protocols.polymarket.totalPositions > 0) {
|
|
257
|
-
const pmTable = new cli_table3_1.default({
|
|
258
|
-
head: [
|
|
259
|
-
chalk_1.default.gray('Market'),
|
|
260
|
-
chalk_1.default.gray('Outcome'),
|
|
261
|
-
chalk_1.default.gray('Size'),
|
|
262
|
-
chalk_1.default.gray('Avg'),
|
|
263
|
-
chalk_1.default.gray('Cur'),
|
|
264
|
-
chalk_1.default.gray('P&L'),
|
|
265
|
-
],
|
|
266
|
-
style: { head: [], border: ['gray'] },
|
|
267
|
-
});
|
|
268
|
-
for (const pos of portfolio.protocols.polymarket.positions) {
|
|
269
|
-
const pnl = pos.cashPnl;
|
|
270
|
-
pmTable.push([
|
|
271
|
-
pos.title,
|
|
272
|
-
pos.outcome === 'Yes' ? chalk_1.default.green('Yes') : chalk_1.default.red('No'),
|
|
273
|
-
pos.size.toFixed(0),
|
|
274
|
-
(0, ui_1.formatUsd)(pos.avgPrice),
|
|
275
|
-
(0, ui_1.formatUsd)(pos.curPrice),
|
|
276
|
-
pnl >= 0
|
|
277
|
-
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(pnl)}`)
|
|
278
|
-
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(pnl))}`),
|
|
279
|
-
]);
|
|
280
|
-
}
|
|
281
|
-
console.log(pmTable.toString());
|
|
282
|
-
const totalPnl = portfolio.protocols.polymarket.totalPnl;
|
|
283
|
-
(0, ui_1.info)(` Total: ${(0, ui_1.formatUsd)(portfolio.protocols.polymarket.totalValue)} | ` +
|
|
284
|
-
`P&L: ${totalPnl >= 0
|
|
285
|
-
? chalk_1.default.green(`+${(0, ui_1.formatUsd)(totalPnl)}`)
|
|
286
|
-
: chalk_1.default.red(`-${(0, ui_1.formatUsd)(Math.abs(totalPnl))}`)}`);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
(0, ui_1.info)(' No Polymarket positions.');
|
|
290
|
-
}
|
|
291
|
-
// === Kamino Lending ===
|
|
292
|
-
console.log();
|
|
293
|
-
console.log(ui_1.colors.sol.bold(' Kamino Lending'));
|
|
294
|
-
if (portfolio.protocols.kamino.positions.length > 0) {
|
|
295
|
-
const kaminoTable = new cli_table3_1.default({
|
|
296
|
-
head: [
|
|
297
|
-
chalk_1.default.gray('Type'),
|
|
298
|
-
chalk_1.default.gray('Asset'),
|
|
299
|
-
chalk_1.default.gray('Amount'),
|
|
300
|
-
chalk_1.default.gray('USD Value'),
|
|
301
|
-
],
|
|
302
|
-
style: { head: [], border: ['gray'] },
|
|
303
|
-
});
|
|
304
|
-
for (const pos of portfolio.protocols.kamino.positions) {
|
|
305
|
-
kaminoTable.push([
|
|
306
|
-
pos.type === 'deposit' ? chalk_1.default.green('Deposit') : chalk_1.default.yellow('Borrow'),
|
|
307
|
-
pos.symbol,
|
|
308
|
-
parseFloat(pos.amount).toFixed(4),
|
|
309
|
-
`$${parseFloat(pos.amountUsd).toFixed(2)}`,
|
|
310
|
-
]);
|
|
311
|
-
}
|
|
312
|
-
console.log(kaminoTable.toString());
|
|
313
|
-
(0, ui_1.info)(` Deposits: $${portfolio.protocols.kamino.totalDepositsUsd.toFixed(2)} | ` +
|
|
314
|
-
`Borrows: $${portfolio.protocols.kamino.totalBorrowsUsd.toFixed(2)} | ` +
|
|
315
|
-
`Net: $${portfolio.protocols.kamino.netValueUsd.toFixed(2)}`);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
(0, ui_1.info)(' No Kamino positions.');
|
|
319
|
-
}
|
|
320
|
-
// === Meteora LP ===
|
|
321
|
-
console.log();
|
|
322
|
-
console.log(ui_1.colors.sol.bold(' Meteora LP Positions'));
|
|
323
|
-
if (portfolio.protocols.meteora.totalPositions > 0) {
|
|
324
|
-
const metTable = new cli_table3_1.default({
|
|
325
|
-
head: [
|
|
326
|
-
chalk_1.default.gray('Pool'),
|
|
327
|
-
chalk_1.default.gray('Token X'),
|
|
328
|
-
chalk_1.default.gray('Token Y'),
|
|
329
|
-
chalk_1.default.gray('USD Value'),
|
|
330
|
-
],
|
|
331
|
-
style: { head: [], border: ['gray'] },
|
|
332
|
-
});
|
|
333
|
-
for (const pool of portfolio.protocols.meteora.positions || []) {
|
|
334
|
-
const shortPool = pool.poolAddress.slice(0, 4) + '…' + pool.poolAddress.slice(-4);
|
|
335
|
-
pool.positions.forEach((pos, idx) => {
|
|
336
|
-
const xAmt = parseFloat(pos.totalXAmount || '0');
|
|
337
|
-
const yAmt = parseFloat(pos.totalYAmount || '0');
|
|
338
|
-
metTable.push([
|
|
339
|
-
shortPool,
|
|
340
|
-
chalk_1.default.bold(xAmt.toFixed(4)),
|
|
341
|
-
chalk_1.default.bold(yAmt.toFixed(2)),
|
|
342
|
-
// Only show USD value for the first position in the pool
|
|
343
|
-
idx === 0 ? chalk_1.default.green(`$${pool.estimatedValueUsd.toFixed(2)}`) : '',
|
|
344
|
-
]);
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
console.log(metTable.toString());
|
|
348
|
-
(0, ui_1.info)(` Total Value: $${portfolio.protocols.meteora.totalEquity.toFixed(2)}`);
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
(0, ui_1.info)(' No Meteora positions.');
|
|
352
|
-
}
|
|
424
|
+
renderPortfolioDisplay(portfolio, { showAllBalances });
|
|
353
425
|
}
|
|
354
426
|
catch (err) {
|
|
355
427
|
spinner?.stop();
|
|
356
428
|
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
357
429
|
(0, ui_1.error)(`Failed to load portfolio: ${errorMessage}`);
|
|
358
430
|
}
|
|
359
|
-
console.log();
|
|
360
|
-
(0, ui_1.divider)();
|
|
361
431
|
});
|
|
362
432
|
}
|
|
363
433
|
//# sourceMappingURL=portfolio.js.map
|