@palmyr/cli 1.3.0 → 1.4.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.
- package/dist/cli.js +143 -25
- package/dist/cli.js.map +1 -1
- package/dist/wallet-brief-llm.js +5 -3
- package/dist/wallet-brief-llm.js.map +1 -1
- package/dist/wallet-daemon.d.ts +2 -0
- package/dist/wallet-daemon.js +11 -4
- package/dist/wallet-daemon.js.map +1 -1
- package/dist/wallet-live-test.d.ts +49 -0
- package/dist/wallet-live-test.js +162 -0
- package/dist/wallet-live-test.js.map +1 -0
- package/dist/wallet-readiness.d.ts +51 -0
- package/dist/wallet-readiness.js +183 -0
- package/dist/wallet-readiness.js.map +1 -0
- package/dist/wallet-trading.d.ts +57 -44
- package/dist/wallet-trading.js +75 -68
- package/dist/wallet-trading.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1636,6 +1636,8 @@ async function main() {
|
|
|
1636
1636
|
{ name: 'brief', description: 'Show thesis + PnL brief for a position', hint: '<CA>' },
|
|
1637
1637
|
{ name: 'doctor', description: 'Health check for the wallet-trading subsystem', hint: '[--wallet <ref>]' },
|
|
1638
1638
|
{ name: 'smoke-test', description: 'End-to-end validation of wallet trading on Solana + Base', hint: '--wallet <ref> [--chain solana|base|all]' },
|
|
1639
|
+
{ name: 'readiness', description: 'Go/no-go autonomous-trading readiness — sign, gas, quotes, daemon, open positions', hint: '--wallet <ref>' },
|
|
1640
|
+
{ name: 'live-test', description: 'Execute tiny real round trips on Solana + Base, verify no leftover positions', hint: '--wallet <ref> --budget Nusdc [--chain ...]' },
|
|
1639
1641
|
{ name: 'daemon', description: 'Auto-monitor positions for trigger-based exits', hint: 'tick | start [--auto] | stop | status' },
|
|
1640
1642
|
{ name: 'triggers', description: 'List pending trigger fires from the daemon', hint: '[--ca X] [--since ISO] [--clear]' },
|
|
1641
1643
|
{ name: 'trading-keystore', description: 'Encrypted BIP39 keystore for HD-derived trading wallets', hint: 'init | list | status | derive | export' },
|
|
@@ -2501,9 +2503,12 @@ async function main() {
|
|
|
2501
2503
|
: (readPosition('solana', ca) ?? readPosition('base', ca));
|
|
2502
2504
|
if (!p)
|
|
2503
2505
|
err(`Position not found: ${ca}`, EXIT.NOT_FOUND);
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2506
|
+
// Canonical asset-tagged PnL — reflects what the position was
|
|
2507
|
+
// actually funded in (USDC-funded positions report USDC, not the
|
|
2508
|
+
// chain native asset).
|
|
2509
|
+
const unit = p.pnl.realized?.asset ?? (p.chain === 'solana' ? 'SOL' : 'ETH');
|
|
2510
|
+
const realized = p.pnl.realized?.amount ?? 0;
|
|
2511
|
+
const unrealized = p.pnl.unrealized?.amount ?? 0;
|
|
2507
2512
|
if (!AGENT_MODE) {
|
|
2508
2513
|
console.log();
|
|
2509
2514
|
section('Position');
|
|
@@ -2548,15 +2553,11 @@ async function main() {
|
|
|
2548
2553
|
if (p.sells.length > 0) {
|
|
2549
2554
|
console.log();
|
|
2550
2555
|
section(`Sells (${p.sells.length})`);
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
else {
|
|
2557
|
-
for (const s of p.sells) {
|
|
2558
|
-
console.log(` ${t.muted}${s.time}${t.reset} ${s.tokensIn} → ${s.ethOut} (realized ${s.realizedEth >= 0 ? '+' : ''}${s.realizedEth.toFixed(6)} ETH) — ${s.reason}`);
|
|
2559
|
-
}
|
|
2556
|
+
for (const s of p.sells) {
|
|
2557
|
+
const outDisplay = s.output?.display ?? '?';
|
|
2558
|
+
const r = s.realized?.amount ?? 0;
|
|
2559
|
+
const ru = s.realized?.asset ?? unit;
|
|
2560
|
+
console.log(` ${t.muted}${s.time}${t.reset} ${s.tokensIn} → ${outDisplay} (realized ${r >= 0 ? '+' : ''}${r.toFixed(6)} ${ru}) — ${s.reason}`);
|
|
2560
2561
|
}
|
|
2561
2562
|
}
|
|
2562
2563
|
console.log();
|
|
@@ -2623,7 +2624,8 @@ async function main() {
|
|
|
2623
2624
|
if (!AGENT_MODE) {
|
|
2624
2625
|
const tag = baseResult.dryRun ? `${t.warn}[dry-run]${t.reset} ` : '';
|
|
2625
2626
|
const protTag = baseResult.protectedExec ? ` ${t.accent}[protected]${t.reset}` : '';
|
|
2626
|
-
const
|
|
2627
|
+
const realizedAmt = baseResult.realized.amount;
|
|
2628
|
+
const pnlColor = realizedAmt >= 0 ? t.success : t.error;
|
|
2627
2629
|
const closedTag = baseResult.positionStatus === 'closed' ? ` ${t.muted}[closed]${t.reset}` : '';
|
|
2628
2630
|
console.log(`\n ${t.success}${icon.success} ${tag}Base sell executed${protTag}${closedTag}${t.reset}`);
|
|
2629
2631
|
if (baseResult.approvalTxHash) {
|
|
@@ -2631,11 +2633,11 @@ async function main() {
|
|
|
2631
2633
|
}
|
|
2632
2634
|
console.log(` ${t.muted}tx:${t.reset} ${baseResult.txHash}`);
|
|
2633
2635
|
console.log(` ${t.muted}sold:${t.reset} ${baseResult.tokensIn} tokens (${percent}%)`);
|
|
2634
|
-
console.log(` ${t.muted}received:${t.reset} ${baseResult.
|
|
2636
|
+
console.log(` ${t.muted}received:${t.reset} ${baseResult.output.display}`);
|
|
2635
2637
|
{
|
|
2636
|
-
const unit = baseResult.
|
|
2638
|
+
const unit = baseResult.realized.asset;
|
|
2637
2639
|
const decimals = unit === 'USDC' ? 2 : 6;
|
|
2638
|
-
console.log(` ${t.muted}realized:${t.reset} ${pnlColor}${
|
|
2640
|
+
console.log(` ${t.muted}realized:${t.reset} ${pnlColor}${realizedAmt >= 0 ? '+' : ''}${realizedAmt.toFixed(decimals)} ${unit}${t.reset}`);
|
|
2639
2641
|
}
|
|
2640
2642
|
console.log(` ${t.muted}reason:${t.reset} ${reason}`);
|
|
2641
2643
|
if (baseResult.protectedExec) {
|
|
@@ -2672,21 +2674,22 @@ async function main() {
|
|
|
2672
2674
|
if (!AGENT_MODE) {
|
|
2673
2675
|
const tag = result.dryRun ? `${t.warn}[dry-run]${t.reset} ` : '';
|
|
2674
2676
|
const protTag = result.protectedExec ? ` ${t.accent}[protected]${t.reset}` : '';
|
|
2675
|
-
const
|
|
2677
|
+
const realizedAmt = result.realized.amount;
|
|
2678
|
+
const pnlColor = realizedAmt >= 0 ? t.success : t.error;
|
|
2676
2679
|
const closedTag = result.positionStatus === 'closed' ? ` ${t.muted}[closed]${t.reset}` : '';
|
|
2677
2680
|
console.log(`\n ${t.success}${icon.success} ${tag}Sell executed${protTag}${closedTag}${t.reset}`);
|
|
2678
2681
|
console.log(` ${t.muted}tx:${t.reset} ${result.txSignature}`);
|
|
2679
2682
|
console.log(` ${t.muted}sold:${t.reset} ${result.tokensIn} tokens (${percent}%)`);
|
|
2680
|
-
console.log(` ${t.muted}received:${t.reset} ${result.
|
|
2683
|
+
console.log(` ${t.muted}received:${t.reset} ${result.output.display}`);
|
|
2681
2684
|
console.log(` ${t.muted}slippage:${t.reset} ${result.slippageBpsUsed}bps (${result.slippageSource})`);
|
|
2682
2685
|
if (result.protectedExec) {
|
|
2683
2686
|
console.log(` ${t.muted}tip:${t.reset} ${result.tipLamports} lamports (Jito)`);
|
|
2684
2687
|
}
|
|
2685
2688
|
console.log(` ${t.muted}fee:${t.reset} ${result.feeLamports} lamports`);
|
|
2686
2689
|
{
|
|
2687
|
-
const unit = result.
|
|
2690
|
+
const unit = result.realized.asset;
|
|
2688
2691
|
const decimals = unit === 'USDC' ? 2 : 6;
|
|
2689
|
-
console.log(` ${t.muted}realized:${t.reset} ${pnlColor}${
|
|
2692
|
+
console.log(` ${t.muted}realized:${t.reset} ${pnlColor}${realizedAmt >= 0 ? '+' : ''}${realizedAmt.toFixed(decimals)} ${unit}${t.reset}`);
|
|
2690
2693
|
}
|
|
2691
2694
|
console.log(` ${t.muted}reason:${t.reset} ${reason}`);
|
|
2692
2695
|
if (result.forensics && result.forensics.flag === 'suspect-mev') {
|
|
@@ -3020,14 +3023,19 @@ async function main() {
|
|
|
3020
3023
|
const p = readPosition(inferredChain, ca, scopedAddr);
|
|
3021
3024
|
if (!p)
|
|
3022
3025
|
err(`Position not found: ${ca}`, EXIT.NOT_FOUND);
|
|
3026
|
+
// `--evaluate` degrades gracefully: a missing ANTHROPIC_API_KEY or
|
|
3027
|
+
// a model-API failure must NOT take down the whole brief. We surface
|
|
3028
|
+
// the LLM error as `llmError` so agents can branch on it, and still
|
|
3029
|
+
// print the deterministic brief fields.
|
|
3023
3030
|
let llm;
|
|
3031
|
+
let llmError;
|
|
3024
3032
|
if (evaluate) {
|
|
3025
3033
|
const { evaluateBriefWithLLM } = await import('./wallet-brief-llm.js');
|
|
3026
3034
|
try {
|
|
3027
3035
|
llm = await evaluateBriefWithLLM(p);
|
|
3028
3036
|
}
|
|
3029
3037
|
catch (e) {
|
|
3030
|
-
|
|
3038
|
+
llmError = e?.message ?? 'brief --evaluate failed';
|
|
3031
3039
|
}
|
|
3032
3040
|
}
|
|
3033
3041
|
if (!AGENT_MODE) {
|
|
@@ -3042,11 +3050,11 @@ async function main() {
|
|
|
3042
3050
|
console.log();
|
|
3043
3051
|
section('Current');
|
|
3044
3052
|
const pnlColor = p.pnl.unrealizedPct >= 0 ? t.success : t.error;
|
|
3045
|
-
//
|
|
3046
|
-
//
|
|
3047
|
-
const realizedAmt = p.pnl.realized?.amount ??
|
|
3053
|
+
// Canonical asset-tagged pnl — normalizePosition guarantees these
|
|
3054
|
+
// exist on read, including back-fill from legacy on-disk fields.
|
|
3055
|
+
const realizedAmt = p.pnl.realized?.amount ?? 0;
|
|
3048
3056
|
const realizedAsset = p.pnl.realized?.asset ?? (p.chain === 'solana' ? 'SOL' : 'ETH');
|
|
3049
|
-
const unrealizedAmt = p.pnl.unrealized?.amount ??
|
|
3057
|
+
const unrealizedAmt = p.pnl.unrealized?.amount ?? 0;
|
|
3050
3058
|
const unrealizedAsset = p.pnl.unrealized?.asset ?? realizedAsset;
|
|
3051
3059
|
kv('Realized', `${realizedAmt >= 0 ? '+' : ''}${realizedAmt.toFixed(6)} ${realizedAsset}`);
|
|
3052
3060
|
console.log(` ${t.muted}Unrealized:${t.reset} ${pnlColor}${unrealizedAmt >= 0 ? '+' : ''}${unrealizedAmt.toFixed(6)} ${unrealizedAsset} (${p.pnl.unrealizedPct.toFixed(2)}%)${t.reset}`);
|
|
@@ -3060,6 +3068,10 @@ async function main() {
|
|
|
3060
3068
|
console.log(` ${t.muted}Reasoning:${t.reset} ${llm.reasoning}`);
|
|
3061
3069
|
console.log(` ${t.muted}Watch for:${t.reset} ${llm.watchFor}`);
|
|
3062
3070
|
}
|
|
3071
|
+
else if (llmError) {
|
|
3072
|
+
console.log();
|
|
3073
|
+
console.log(` ${t.warn}LLM eval skipped: ${llmError}${t.reset}`);
|
|
3074
|
+
}
|
|
3063
3075
|
else {
|
|
3064
3076
|
console.log();
|
|
3065
3077
|
console.log(` ${t.muted}Add --evaluate for an LLM thesis-health check.${t.reset}`);
|
|
@@ -3077,6 +3089,7 @@ async function main() {
|
|
|
3077
3089
|
pnl: p.pnl,
|
|
3078
3090
|
sellsCount: p.sells.length,
|
|
3079
3091
|
llm,
|
|
3092
|
+
llmError,
|
|
3080
3093
|
});
|
|
3081
3094
|
}
|
|
3082
3095
|
break;
|
|
@@ -3175,6 +3188,111 @@ async function main() {
|
|
|
3175
3188
|
process.exit(EXIT.GENERAL);
|
|
3176
3189
|
break;
|
|
3177
3190
|
}
|
|
3191
|
+
case 'readiness': {
|
|
3192
|
+
const readyWalletRef = flags.wallet || undefined;
|
|
3193
|
+
if (!readyWalletRef)
|
|
3194
|
+
err('--wallet required. Use a vault wallet name/id or `trading:N`.', EXIT.BAD_INPUT);
|
|
3195
|
+
const { runWalletReadiness } = await import('./wallet-readiness.js');
|
|
3196
|
+
const report = await runWalletReadiness({ walletRef: readyWalletRef });
|
|
3197
|
+
if (AGENT_MODE) {
|
|
3198
|
+
print(report);
|
|
3199
|
+
if (!report.safeForAutonomousTrading)
|
|
3200
|
+
process.exit(EXIT.GENERAL);
|
|
3201
|
+
break;
|
|
3202
|
+
}
|
|
3203
|
+
console.log();
|
|
3204
|
+
section('Wallet readiness');
|
|
3205
|
+
kv('Wallet', report.wallet);
|
|
3206
|
+
if (report.solanaAddress)
|
|
3207
|
+
kv('Solana', report.solanaAddress);
|
|
3208
|
+
if (report.evmAddress)
|
|
3209
|
+
kv('EVM', report.evmAddress);
|
|
3210
|
+
kv('Verdict', report.safeForAutonomousTrading
|
|
3211
|
+
? `${t.success}safe for autonomous trading${t.reset}`
|
|
3212
|
+
: `${t.error}NOT safe — see failing checks${t.reset}`);
|
|
3213
|
+
if (report.balances.solana)
|
|
3214
|
+
kv('SOL balance', `${report.balances.solana.sol.toFixed(6)} SOL`);
|
|
3215
|
+
if (report.balances.base)
|
|
3216
|
+
kv('ETH balance', `${report.balances.base.eth.toFixed(8)} ETH`);
|
|
3217
|
+
kv('Open positions', `solana=${report.openPositions.solana} base=${report.openPositions.base}`);
|
|
3218
|
+
kv('Daemon', report.daemon.running
|
|
3219
|
+
? `${t.success}running${t.reset} (pid ${report.daemon.pid}${report.daemon.autoExecute ? ', auto-execute' : ''})`
|
|
3220
|
+
: `${t.warn}not running${t.reset}`);
|
|
3221
|
+
console.log();
|
|
3222
|
+
section('Checks');
|
|
3223
|
+
for (const c of report.checks) {
|
|
3224
|
+
const dot = c.status === 'pass' ? `${t.success}✓${t.reset}`
|
|
3225
|
+
: c.status === 'warn' ? `${t.warn}!${t.reset}`
|
|
3226
|
+
: c.status === 'skip' ? `${t.muted}-${t.reset}`
|
|
3227
|
+
: `${t.error}✗${t.reset}`;
|
|
3228
|
+
const tail = [c.value !== undefined ? String(c.value) : null, c.message].filter(Boolean).join(' — ');
|
|
3229
|
+
console.log(` ${dot} ${c.name}${tail ? `: ${tail}` : ''}`);
|
|
3230
|
+
}
|
|
3231
|
+
console.log();
|
|
3232
|
+
if (!report.safeForAutonomousTrading)
|
|
3233
|
+
process.exit(EXIT.GENERAL);
|
|
3234
|
+
break;
|
|
3235
|
+
}
|
|
3236
|
+
case 'live-test': {
|
|
3237
|
+
const liveWalletRef = flags.wallet || undefined;
|
|
3238
|
+
if (!liveWalletRef)
|
|
3239
|
+
err('--wallet required. Use a vault wallet name/id or `trading:N`.', EXIT.BAD_INPUT);
|
|
3240
|
+
const budgetRaw = flags.budget;
|
|
3241
|
+
if (!budgetRaw)
|
|
3242
|
+
err('--budget required, e.g. --budget 1usdc (caps total trade exposure).', EXIT.BAD_INPUT);
|
|
3243
|
+
const budgetMatch = (budgetRaw ?? '').trim().match(/^(\d+(?:\.\d+)?)\s*usdc$/i);
|
|
3244
|
+
if (!budgetMatch)
|
|
3245
|
+
err(`--budget must be in USDC (e.g. "0.5usdc", "1usdc"), got "${budgetRaw}".`, EXIT.BAD_INPUT);
|
|
3246
|
+
const budgetUsdc = Number(budgetMatch[1]);
|
|
3247
|
+
const liveChainFlag = (flags.chain || 'all').toLowerCase();
|
|
3248
|
+
if (liveChainFlag !== 'solana' && liveChainFlag !== 'base' && liveChainFlag !== 'all') {
|
|
3249
|
+
err(`--chain must be solana, base, or all (got ${liveChainFlag})`, EXIT.BAD_INPUT);
|
|
3250
|
+
}
|
|
3251
|
+
const { runWalletLiveTest } = await import('./wallet-live-test.js');
|
|
3252
|
+
let report;
|
|
3253
|
+
try {
|
|
3254
|
+
report = await runWalletLiveTest({
|
|
3255
|
+
walletRef: liveWalletRef,
|
|
3256
|
+
budgetUsdc,
|
|
3257
|
+
chain: liveChainFlag,
|
|
3258
|
+
});
|
|
3259
|
+
}
|
|
3260
|
+
catch (e) {
|
|
3261
|
+
err(e.message || 'live-test failed', EXIT.GENERAL);
|
|
3262
|
+
}
|
|
3263
|
+
if (AGENT_MODE) {
|
|
3264
|
+
print(report);
|
|
3265
|
+
if (!report.safeForAutonomousTrading)
|
|
3266
|
+
process.exit(EXIT.GENERAL);
|
|
3267
|
+
break;
|
|
3268
|
+
}
|
|
3269
|
+
console.log();
|
|
3270
|
+
section('Wallet live-test');
|
|
3271
|
+
kv('Wallet', report.wallet);
|
|
3272
|
+
kv('Budget', `${report.budgetUsdc.toFixed(6)} USDC (per leg ${report.perLegUsdc.toFixed(6)} USDC)`);
|
|
3273
|
+
kv('Verdict', report.safeForAutonomousTrading
|
|
3274
|
+
? `${t.success}safe for autonomous trading${t.reset}`
|
|
3275
|
+
: `${t.error}NOT safe — see failing legs${t.reset}`);
|
|
3276
|
+
kv('Total realized', `${report.totalRealizedUsdc >= 0 ? '+' : ''}${report.totalRealizedUsdc.toFixed(6)} USDC`);
|
|
3277
|
+
kv('Open positions after', String(report.openPositionsAfter));
|
|
3278
|
+
console.log();
|
|
3279
|
+
section('Legs');
|
|
3280
|
+
for (const leg of report.legs) {
|
|
3281
|
+
const dot = leg.status === 'pass' ? `${t.success}✓${t.reset}`
|
|
3282
|
+
: leg.status === 'skip' ? `${t.muted}-${t.reset}`
|
|
3283
|
+
: `${t.error}✗${t.reset}`;
|
|
3284
|
+
const realizedStr = leg.realized
|
|
3285
|
+
? `; realized ${leg.realized.amount >= 0 ? '+' : ''}${leg.realized.amount.toFixed(6)} ${leg.realized.asset}`
|
|
3286
|
+
: '';
|
|
3287
|
+
const txStr = leg.txHash ? ` (${leg.txHash.slice(0, 10)}…)` : '';
|
|
3288
|
+
const detail = [leg.message, leg.durationMs !== undefined ? `${leg.durationMs}ms` : null].filter(Boolean).join(' — ');
|
|
3289
|
+
console.log(` ${dot} ${leg.chain}/${leg.name}${txStr}${realizedStr}${detail ? `: ${detail}` : ''}`);
|
|
3290
|
+
}
|
|
3291
|
+
console.log();
|
|
3292
|
+
if (!report.safeForAutonomousTrading)
|
|
3293
|
+
process.exit(EXIT.GENERAL);
|
|
3294
|
+
break;
|
|
3295
|
+
}
|
|
3178
3296
|
case 'daemon': {
|
|
3179
3297
|
const sub = positional[0];
|
|
3180
3298
|
if (!sub)
|