@baseline-markets/cli 0.2.1 → 0.3.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/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Cli } from "incur";
4
+ import { Cli as Cli2 } from "incur";
5
+ import { pathToFileURL } from "node:url";
5
6
 
6
7
  // src/commands/info.ts
7
8
  import { BaselineSDK } from "@baseline-markets/sdk";
@@ -12,6 +13,8 @@ import {
12
13
  arbitrum as arbitrumMainnet,
13
14
  base as baseMainnet,
14
15
  baseSepolia as baseTestnet,
16
+ hyperEvm,
17
+ hyperliquidEvmTestnet,
15
18
  mainnet as ethereumMainnet
16
19
  } from "viem/chains";
17
20
  var chains = {
@@ -74,6 +77,32 @@ var chains = {
74
77
  ]
75
78
  }
76
79
  }
80
+ }),
81
+ hyperevm: defineChain({
82
+ ...hyperEvm,
83
+ rpcUrls: {
84
+ default: {
85
+ http: ["https://wispy-hidden-knowledge.hype-mainnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471/nanoreth"]
86
+ }
87
+ },
88
+ contracts: {
89
+ multicall3: {
90
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11"
91
+ }
92
+ }
93
+ }),
94
+ hyperevmTestnet: defineChain({
95
+ ...hyperliquidEvmTestnet,
96
+ rpcUrls: {
97
+ default: {
98
+ http: ["https://wispy-hidden-knowledge.hype-testnet.quiknode.pro/744cca7e0d6ab60a5bff9c19aee2599dbff70471/nanoreth"]
99
+ }
100
+ },
101
+ contracts: {
102
+ multicall3: {
103
+ address: "0xcA11bde05977b3631167028862bE2a173976CA11"
104
+ }
105
+ }
77
106
  })
78
107
  };
79
108
  var chains_default = chains;
@@ -133,7 +162,8 @@ var infoCommand = {
133
162
  transport: http(c.options.rpcUrl)
134
163
  }));
135
164
  const info = await sdk.getBTokenInfo(token);
136
- return serializeBTokenInfo(info, buildTokenLinks(chain, info.bToken));
165
+ const status = await sdk.getBTokenStatus(token, info);
166
+ return serializeBTokenInfo({ ...info, ...status }, buildTokenLinks(chain, info.bToken));
137
167
  }
138
168
  };
139
169
  function serializeBTokenInfo(info, links) {
@@ -207,6 +237,7 @@ import {
207
237
  createWalletClient,
208
238
  http as http2
209
239
  } from "viem";
240
+ import { sendCalls, waitForCallsStatus } from "viem/actions";
210
241
  import { privateKeyToAccount } from "viem/accounts";
211
242
  function parsePrivateKey(value) {
212
243
  if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {
@@ -214,18 +245,6 @@ function parsePrivateKey(value) {
214
245
  }
215
246
  return value;
216
247
  }
217
- async function estimateCallGas(estimate, retryDelayMs = 1000) {
218
- let lastError;
219
- for (let attempt = 0;attempt < 5; attempt++) {
220
- try {
221
- return await estimate();
222
- } catch (error) {
223
- lastError = error;
224
- await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
225
- }
226
- }
227
- throw lastError;
228
- }
229
248
  async function executeCalls(input) {
230
249
  const account = privateKeyToAccount(input.privateKey);
231
250
  if (input.expectedAccount && account.address.toLowerCase() !== input.expectedAccount.toLowerCase()) {
@@ -238,35 +257,52 @@ async function executeCalls(input) {
238
257
  chain: input.chain,
239
258
  transport
240
259
  });
241
- const transactions = [];
242
- for (const [index, call] of input.calls.entries()) {
243
- const gas = await estimateCallGas(() => publicClient.estimateGas({
244
- account: account.address,
245
- to: call.to,
246
- data: call.data,
247
- value: call.value ?? 0n
248
- })) + 50000n;
249
- const hash = await walletClient.sendTransaction({
250
- account,
251
- chain: input.chain,
252
- to: call.to,
253
- data: call.data,
254
- value: call.value ?? 0n,
255
- gas
256
- });
257
- const receipt = await publicClient.waitForTransactionReceipt({ hash });
260
+ const { id } = await sendCalls(walletClient, {
261
+ account,
262
+ chain: input.chain,
263
+ calls: input.calls,
264
+ experimental_fallback: true
265
+ });
266
+ const status = await waitForCallsStatus(walletClient, {
267
+ id,
268
+ throwOnFailure: false
269
+ });
270
+ const bundles = [{ id, atomic: status.atomic }];
271
+ const receipts = status.receipts ?? [];
272
+ if (status.status === "failure") {
273
+ throw new Error("Calls bundle failed.");
274
+ }
275
+ if (receipts.length === 0) {
276
+ throw new Error("Calls bundle did not return any transaction receipts.");
277
+ }
278
+ const transactions = receipts.map((receipt, index) => {
279
+ if (!receipt.transactionHash) {
280
+ throw new Error(`Receipt ${index} did not return a transaction hash.`);
281
+ }
258
282
  if (receipt.status !== "success") {
259
- throw new Error(`Transaction ${index} reverted: ${hash}`);
283
+ throw new Error(`Transaction ${index} reverted: ${receipt.transactionHash}`);
260
284
  }
261
- transactions.push({
285
+ return {
262
286
  index,
263
- hash,
287
+ hash: receipt.transactionHash,
264
288
  status: receipt.status,
265
289
  blockNumber: receipt.blockNumber.toString(),
266
290
  gasUsed: receipt.gasUsed.toString()
267
- });
291
+ };
292
+ });
293
+ if (input.confirmations) {
294
+ const uniqueHashes = [...new Set(transactions.map((tx) => tx.hash))];
295
+ for (const [index, hash] of uniqueHashes.entries()) {
296
+ const confirmed = await publicClient.waitForTransactionReceipt({
297
+ hash,
298
+ confirmations: input.confirmations
299
+ });
300
+ if (confirmed.status !== "success") {
301
+ throw new Error(`Transaction ${index} reverted: ${hash}`);
302
+ }
303
+ }
268
304
  }
269
- return { transactions };
305
+ return { bundles, transactions };
270
306
  }
271
307
 
272
308
  // src/commands/launch.ts
@@ -346,12 +382,18 @@ async function buildLaunchArtifact(options) {
346
382
  salt,
347
383
  deployer: account
348
384
  });
349
- const calls = await sdk.calls.launch(launchInput, { account });
385
+ const calls = await sdk.calls.launch(launchInput, {
386
+ account,
387
+ precomputedBToken: bToken
388
+ });
389
+ const links = buildTokenLinks(chain, bToken);
350
390
  return {
351
391
  chainId: options.chainId,
352
392
  chain: chain.name,
353
393
  account,
354
394
  bToken,
395
+ appUrl: links.appUrl,
396
+ explorerUrl: links.explorerUrl,
355
397
  calls
356
398
  };
357
399
  }
@@ -407,6 +449,955 @@ async function executeLaunchArtifact(artifact, options) {
407
449
  });
408
450
  }
409
451
 
452
+ // src/commands/quote.ts
453
+ import { Cli } from "incur";
454
+
455
+ // src/commands/swap.ts
456
+ import {
457
+ maxInWithSlippage,
458
+ minOutWithSlippage,
459
+ serializeCalls as serializeCalls2,
460
+ simulateCalls
461
+ } from "@baseline-markets/sdk";
462
+ import { z as z5 } from "incur";
463
+
464
+ // src/commands/client.ts
465
+ import { BaselineSDK as BaselineSDK3 } from "@baseline-markets/sdk";
466
+ import { z as z4 } from "incur";
467
+ import {
468
+ createPublicClient as createPublicClient4,
469
+ createWalletClient as createWalletClient2,
470
+ formatUnits as formatUnits2,
471
+ http as http4,
472
+ parseUnits as parseUnits2
473
+ } from "viem";
474
+ import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
475
+ var chainOptions = {
476
+ chainId: z4.coerce.number().default(chains_default.baseSepolia.id).describe("Chain ID."),
477
+ rpcUrl: z4.string().optional().describe("RPC URL.")
478
+ };
479
+ var signerOptions = {
480
+ privateKey: z4.string().optional().describe("Private key. Falls back to BASELINE_PRIVATE_KEY."),
481
+ confirmations: z4.coerce.number().int().nonnegative().default(1).describe("Confirmations to wait for after each transaction.")
482
+ };
483
+ function createReadSdk(options) {
484
+ const chain = getChain(options.chainId);
485
+ const publicClient = createPublicClient4({
486
+ chain,
487
+ transport: http4(options.rpcUrl)
488
+ });
489
+ return { chain, publicClient, sdk: new BaselineSDK3(publicClient) };
490
+ }
491
+ function createWalletSdk(options) {
492
+ const privateKey = options.privateKey ?? process.env.BASELINE_PRIVATE_KEY;
493
+ if (!privateKey)
494
+ throw missingPrivateKeyError();
495
+ const chain = getChain(options.chainId);
496
+ const account = privateKeyToAccount3(parsePrivateKey(privateKey));
497
+ const transport = http4(options.rpcUrl);
498
+ const publicClient = createPublicClient4({ chain, transport });
499
+ const walletClient = createWalletClient2({
500
+ account,
501
+ chain,
502
+ transport
503
+ });
504
+ return {
505
+ account,
506
+ chain,
507
+ publicClient,
508
+ walletClient,
509
+ sdk: new BaselineSDK3(publicClient, walletClient)
510
+ };
511
+ }
512
+ function resolvePrivateKey(value) {
513
+ const privateKey = value ?? process.env.BASELINE_PRIVATE_KEY;
514
+ if (!privateKey)
515
+ throw missingPrivateKeyError();
516
+ return parsePrivateKey(privateKey);
517
+ }
518
+ function missingPrivateKeyError() {
519
+ return new Error("--private-key or BASELINE_PRIVATE_KEY is required.");
520
+ }
521
+ function parseTokenUnits(amount, decimals) {
522
+ return parseUnits2(amount, decimals);
523
+ }
524
+ function formatTokenUnits(amount, decimals) {
525
+ const formatted = formatUnits2(amount, decimals);
526
+ return formatted.includes(".") ? formatted.replace(/\.?0+$/, "") : formatted;
527
+ }
528
+ function serializeAmount(amount, decimals) {
529
+ return {
530
+ raw: amount.toString(),
531
+ formatted: formatTokenUnits(amount, decimals),
532
+ decimals
533
+ };
534
+ }
535
+ function serializeTransaction(hash) {
536
+ return { hash };
537
+ }
538
+ function chainName(chain) {
539
+ return chain.name;
540
+ }
541
+ function normalizeUser(user, fallback) {
542
+ return user ?? fallback;
543
+ }
544
+
545
+ // src/commands/swap.ts
546
+ var slippageBps = z5.coerce.number().int().min(0).max(1e4).default(100).describe("Slippage tolerance in basis points.");
547
+ var swapModeOptions = {
548
+ buy: z5.boolean().default(false).describe("Buy BTokens."),
549
+ sell: z5.boolean().default(false).describe("Sell BTokens."),
550
+ exactIn: z5.boolean().default(false).describe("Treat --amount as the exact input amount. This is the default."),
551
+ exactOut: z5.boolean().default(false).describe("Treat --amount as the exact output amount.")
552
+ };
553
+ var quoteOptions = z5.object({
554
+ ...chainOptions,
555
+ token: address("token").describe("Baseline token address."),
556
+ ...swapModeOptions,
557
+ amount: z5.string().describe("Amount in token units."),
558
+ bTokenDecimals: z5.coerce.number().int().min(0).max(36).optional().describe("BToken decimals. Defaults to token metadata."),
559
+ reserveDecimals: z5.coerce.number().int().min(0).max(36).optional().describe("Reserve token decimals. Defaults to token metadata.")
560
+ });
561
+ var executeOptions = quoteOptions.extend({
562
+ ...signerOptions,
563
+ slippageBps,
564
+ simulate: z5.boolean().default(false).describe("Simulate the exact swap calls without sending them."),
565
+ approval: z5.enum(["infinite", "exact"]).default("infinite").describe("ERC20 approval amount for the input token.")
566
+ });
567
+ var swapCommand = {
568
+ description: "Quote and execute Baseline swaps.",
569
+ options: executeOptions,
570
+ run: ({ options }) => runSwap(options)
571
+ };
572
+ var swapQuoteCommand = {
573
+ description: "Quote a Baseline swap.",
574
+ options: quoteOptions,
575
+ run: ({ options }) => buildSwapQuote(options)
576
+ };
577
+ async function buildSwapQuote(options) {
578
+ const mode = normalizeSwapOptions(options);
579
+ const { chain, sdk } = createReadSdk(options);
580
+ const info = await sdk.getBTokenInfo(options.token);
581
+ const decimals = resolveSwapDecimals(mode, info);
582
+ const amount = parseSwapAmount(mode, decimals);
583
+ const quote = await readQuote(mode, sdk, amount);
584
+ return serializeSwapQuote({
585
+ chainId: chain.id,
586
+ chain: chainName(chain),
587
+ token: options.token,
588
+ reserve: info.reserve,
589
+ side: mode.side,
590
+ exact: mode.exact,
591
+ amount,
592
+ quote,
593
+ decimals,
594
+ slippageBps: 0,
595
+ limitAmount: undefined
596
+ });
597
+ }
598
+ async function runSwap(options) {
599
+ const mode = normalizeSwapOptions(options);
600
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
601
+ const info = await sdk.getBTokenInfo(options.token);
602
+ if (!info.reserve)
603
+ throw new Error("Token reserve is unavailable.");
604
+ const decimals = resolveSwapDecimals(mode, info);
605
+ const amount = parseSwapAmount(mode, decimals);
606
+ const quote = await readQuote(mode, sdk, amount);
607
+ const limitAmount = computeLimitAmount(quote, options.slippageBps);
608
+ const input = inputApproval(mode, info.reserve, amount, limitAmount, decimals);
609
+ const calls = [
610
+ ...await sdk.calls.approval.ensure(input.token, sdk.proxy, input.amount, {
611
+ owner: account.address,
612
+ policy: options.approval
613
+ }),
614
+ writeSwapCall(mode, sdk, amount, limitAmount)
615
+ ];
616
+ const serializedQuote = serializeSwapQuote({
617
+ chainId: chain.id,
618
+ chain: chainName(chain),
619
+ token: options.token,
620
+ reserve: info.reserve,
621
+ side: mode.side,
622
+ exact: mode.exact,
623
+ amount,
624
+ quote,
625
+ decimals,
626
+ slippageBps: options.slippageBps,
627
+ limitAmount
628
+ });
629
+ if (options.simulate) {
630
+ const simulation = await simulateCalls(publicClient, calls, {
631
+ account: account.address
632
+ });
633
+ return {
634
+ ...serializedQuote,
635
+ account: account.address,
636
+ inputApproval: {
637
+ token: input.token,
638
+ amount: serializeAmount(input.amount, input.decimals)
639
+ },
640
+ calls: serializeCalls2(calls),
641
+ simulation
642
+ };
643
+ }
644
+ const execution = await executeCalls({
645
+ chain,
646
+ calls,
647
+ privateKey: resolvePrivateKey(options.privateKey),
648
+ rpcUrl: options.rpcUrl,
649
+ expectedAccount: account.address,
650
+ confirmations: options.confirmations
651
+ });
652
+ const lastTransaction = execution.transactions.at(-1);
653
+ if (!lastTransaction)
654
+ throw new Error("Swap execution produced no transaction.");
655
+ return {
656
+ ...serializedQuote,
657
+ account: account.address,
658
+ inputApproval: {
659
+ token: input.token,
660
+ amount: serializeAmount(input.amount, input.decimals)
661
+ },
662
+ calls: serializeCalls2(calls),
663
+ execution,
664
+ transaction: serializeTransaction(lastTransaction.hash)
665
+ };
666
+ }
667
+ function resolveSwapDecimals(options, info) {
668
+ return {
669
+ bToken: options.bTokenDecimals ?? info.decimals ?? 18,
670
+ reserve: options.reserveDecimals ?? info.reserveDecimals ?? 18
671
+ };
672
+ }
673
+ function parseSwapAmount(options, decimals) {
674
+ return parseTokenUnits(options.amount, amountDenomination(options, decimals));
675
+ }
676
+ function amountDenomination(options, decimals) {
677
+ if (options.side === "buy") {
678
+ return options.exact === "in" ? decimals.reserve : decimals.bToken;
679
+ }
680
+ return options.exact === "in" ? decimals.bToken : decimals.reserve;
681
+ }
682
+ async function readQuote(options, sdk, amount) {
683
+ if (options.side === "buy") {
684
+ if (options.exact === "in") {
685
+ return {
686
+ kind: "buy-exact-in",
687
+ ...await sdk.quoteBuyExactIn(options.token, amount)
688
+ };
689
+ }
690
+ return {
691
+ kind: "buy-exact-out",
692
+ ...await sdk.quoteBuyExactOut(options.token, amount)
693
+ };
694
+ }
695
+ if (options.exact === "in") {
696
+ return {
697
+ kind: "sell-exact-in",
698
+ ...await sdk.quoteSellExactIn(options.token, amount)
699
+ };
700
+ }
701
+ return {
702
+ kind: "sell-exact-out",
703
+ ...await sdk.quoteSellExactOut(options.token, amount)
704
+ };
705
+ }
706
+ function computeLimitAmount(quote, slippageBps2) {
707
+ switch (quote.kind) {
708
+ case "buy-exact-in":
709
+ return minOut(quote.tokensOut, slippageBps2);
710
+ case "buy-exact-out":
711
+ return maxIn(quote.amountIn, slippageBps2);
712
+ case "sell-exact-in":
713
+ return minOut(quote.amountOut, slippageBps2);
714
+ case "sell-exact-out":
715
+ return maxIn(quote.tokensIn, slippageBps2);
716
+ }
717
+ }
718
+ function inputApproval(options, reserve, amount, limitAmount, decimals) {
719
+ if (options.side === "buy") {
720
+ return {
721
+ token: reserve,
722
+ amount: options.exact === "in" ? amount : limitAmount,
723
+ decimals: decimals.reserve
724
+ };
725
+ }
726
+ return {
727
+ token: options.token,
728
+ amount: options.exact === "in" ? amount : limitAmount,
729
+ decimals: decimals.bToken
730
+ };
731
+ }
732
+ function writeSwapCall(options, sdk, amount, limitAmount) {
733
+ if (options.side === "buy") {
734
+ return options.exact === "in" ? sdk.calls.swap.buyTokensExactIn(options.token, amount, limitAmount) : sdk.calls.swap.buyTokensExactOut(options.token, amount, limitAmount);
735
+ }
736
+ return options.exact === "in" ? sdk.calls.swap.sellTokensExactIn(options.token, amount, limitAmount) : sdk.calls.swap.sellTokensExactOut(options.token, amount, limitAmount);
737
+ }
738
+ function serializeSwapQuote(input) {
739
+ return {
740
+ chainId: input.chainId,
741
+ chain: input.chain,
742
+ token: input.token,
743
+ reserve: input.reserve,
744
+ side: input.side,
745
+ exact: input.exact,
746
+ amount: serializeAmount(input.amount, amountDenomination(input, input.decimals)),
747
+ quote: serializeQuote(input),
748
+ slippageBps: input.slippageBps,
749
+ limitAmount: input.limitAmount !== undefined ? serializeAmount(input.limitAmount, limitDenomination(input, input.decimals)) : undefined
750
+ };
751
+ }
752
+ function serializeQuote(input) {
753
+ const fee = serializeAmount(input.quote.fee, input.decimals.reserve);
754
+ const slippage = input.quote.slippage.toString();
755
+ switch (input.quote.kind) {
756
+ case "buy-exact-in":
757
+ return {
758
+ tokensOut: serializeAmount(input.quote.tokensOut, input.decimals.bToken),
759
+ fee,
760
+ slippage
761
+ };
762
+ case "buy-exact-out":
763
+ return {
764
+ amountIn: serializeAmount(input.quote.amountIn, input.decimals.reserve),
765
+ fee,
766
+ slippage
767
+ };
768
+ case "sell-exact-in":
769
+ return {
770
+ amountOut: serializeAmount(input.quote.amountOut, input.decimals.reserve),
771
+ fee,
772
+ slippage
773
+ };
774
+ case "sell-exact-out":
775
+ return {
776
+ tokensIn: serializeAmount(input.quote.tokensIn, input.decimals.bToken),
777
+ fee,
778
+ slippage
779
+ };
780
+ }
781
+ }
782
+ function limitDenomination(options, decimals) {
783
+ if (options.side === "buy") {
784
+ return options.exact === "in" ? decimals.bToken : decimals.reserve;
785
+ }
786
+ return options.exact === "in" ? decimals.reserve : decimals.bToken;
787
+ }
788
+ function minOut(amount, bps) {
789
+ return minOutWithSlippage(amount, bps);
790
+ }
791
+ function maxIn(amount, bps) {
792
+ return maxInWithSlippage(amount, bps);
793
+ }
794
+ function normalizeSwapOptions(options) {
795
+ if (options.buy === options.sell) {
796
+ throw new Error("Specify exactly one of --buy or --sell.");
797
+ }
798
+ if (options.exactIn && options.exactOut) {
799
+ throw new Error("Specify only one of --exact-in or --exact-out.");
800
+ }
801
+ const { buy, sell, exactIn, exactOut, ...rest } = options;
802
+ return {
803
+ ...rest,
804
+ side: options.buy ? "buy" : "sell",
805
+ exact: exactOut ? "out" : "in"
806
+ };
807
+ }
808
+
809
+ // src/commands/quote.ts
810
+ var quoteCommand = Cli.create("quote", {
811
+ description: "Quote Baseline actions."
812
+ }).command("swap", swapQuoteCommand);
813
+
814
+ // src/commands/position/options.ts
815
+ import { z as z6 } from "incur";
816
+ var tokenOptions = {
817
+ token: address("token").describe("Baseline token address."),
818
+ bTokenDecimals: z6.coerce.number().int().min(0).max(36).optional().describe("BToken decimals. Defaults to token metadata."),
819
+ reserveDecimals: z6.coerce.number().int().min(0).max(36).optional().describe("Reserve decimals. Defaults to token metadata.")
820
+ };
821
+ var accountOptions = z6.object({
822
+ ...chainOptions,
823
+ ...tokenOptions,
824
+ user: address("user").describe("User address.")
825
+ });
826
+ var stakeOptions = z6.object({
827
+ ...chainOptions,
828
+ ...signerOptions,
829
+ ...tokenOptions,
830
+ amount: z6.string().describe("BToken amount to stake."),
831
+ user: address("user").optional().describe("Stake recipient. Defaults to signer."),
832
+ approval: z6.enum(["infinite", "exact"]).default("infinite").describe("ERC20 approval amount for BToken staking."),
833
+ simulate: z6.boolean().default(false).describe("Simulate the exact stake calls without sending them.")
834
+ });
835
+ var unstakeOptions = z6.object({
836
+ ...chainOptions,
837
+ ...signerOptions,
838
+ ...tokenOptions,
839
+ amount: z6.string().describe("Staked BToken amount to withdraw."),
840
+ simulate: z6.boolean().default(false).describe("Simulate the exact unstake calls without sending them.")
841
+ });
842
+ var claimOptions = z6.object({
843
+ ...chainOptions,
844
+ ...signerOptions,
845
+ ...tokenOptions,
846
+ user: address("user").optional().describe("Reward recipient. Defaults to signer."),
847
+ asNative: z6.boolean().default(false).describe("Claim wrapped-native rewards as native ETH when supported."),
848
+ simulate: z6.boolean().default(false).describe("Simulate the exact claim calls without sending them.")
849
+ });
850
+ var borrowOptions = z6.object({
851
+ ...chainOptions,
852
+ ...signerOptions,
853
+ ...tokenOptions,
854
+ amount: z6.string().describe("Reserve amount to borrow."),
855
+ recipient: address("recipient").optional().describe("Reserve recipient. Defaults to signer."),
856
+ outputNative: z6.boolean().default(false).describe("Receive wrapped-native reserves as native ETH when supported."),
857
+ simulate: z6.boolean().default(false).describe("Simulate the exact borrow calls without sending them.")
858
+ });
859
+ var repayOptions = z6.object({
860
+ ...chainOptions,
861
+ ...signerOptions,
862
+ ...tokenOptions,
863
+ amount: z6.string().describe("Reserve amount to repay."),
864
+ recipient: address("recipient").optional().describe("Credit account to repay. Defaults to signer."),
865
+ useNative: z6.boolean().default(false).describe("Repay wrapped-native reserves with native ETH when supported."),
866
+ approval: z6.enum(["infinite", "exact"]).default("infinite").describe("ERC20 approval amount for reserve repayment."),
867
+ simulate: z6.boolean().default(false).describe("Simulate the exact repay calls without sending them.")
868
+ });
869
+
870
+ // src/commands/position/read.ts
871
+ import { abis } from "@baseline-markets/sdk";
872
+ import { BaseError, ContractFunctionRevertedError, erc20Abi } from "viem";
873
+ async function readPosition(options) {
874
+ const { chain, publicClient, sdk } = createReadSdk(options);
875
+ const info = await sdk.getBTokenInfo(options.token);
876
+ const snapshot = await readPositionSnapshot({
877
+ publicClient,
878
+ proxy: sdk.proxy,
879
+ token: options.token,
880
+ user: options.user,
881
+ reserve: info.reserve
882
+ });
883
+ return serializePosition({
884
+ chainId: chain.id,
885
+ chain: chainName(chain),
886
+ token: options.token,
887
+ name: info.name,
888
+ symbol: info.symbol,
889
+ reserve: info.reserve,
890
+ reserveSymbol: snapshot.reserveSymbol,
891
+ user: options.user,
892
+ account: snapshot.account,
893
+ creditAccount: snapshot.creditAccount,
894
+ maxBorrow: snapshot.maxBorrow,
895
+ earned: snapshot.earned,
896
+ bTokenDecimals: options.bTokenDecimals ?? info.decimals ?? 18,
897
+ reserveDecimals: options.reserveDecimals ?? info.reserveDecimals ?? 18
898
+ });
899
+ }
900
+ async function readPositionSnapshot(input) {
901
+ const contracts = [
902
+ {
903
+ address: input.proxy,
904
+ abi: abis.bLens,
905
+ functionName: "stakedPosition",
906
+ args: [input.token, input.user]
907
+ },
908
+ {
909
+ address: input.proxy,
910
+ abi: abis.bLens,
911
+ functionName: "creditAccount",
912
+ args: [input.token, input.user]
913
+ },
914
+ {
915
+ address: input.proxy,
916
+ abi: abis.bCredit,
917
+ functionName: "getMaxBorrow",
918
+ args: [input.token, input.user]
919
+ },
920
+ {
921
+ address: input.proxy,
922
+ abi: abis.bStaking,
923
+ functionName: "getEarned",
924
+ args: [input.token, input.user]
925
+ },
926
+ ...input.reserve ? [
927
+ {
928
+ address: input.reserve,
929
+ abi: erc20Abi,
930
+ functionName: "symbol"
931
+ }
932
+ ] : []
933
+ ];
934
+ const results = await input.publicClient.multicall({
935
+ allowFailure: true,
936
+ contracts
937
+ });
938
+ const staked = requiredResult(results[0], "staked position");
939
+ const credit = requiredResult(results[1], "credit account");
940
+ const maxBorrow = results[2]?.status === "success" ? results[2].result : 0n;
941
+ const earned = requiredResult(results[3], "earned rewards");
942
+ const reserveSymbol = results[4]?.status === "success" ? results[4].result : undefined;
943
+ return {
944
+ account: {
945
+ amount: staked[0],
946
+ locked: staked[1],
947
+ earned: staked[2],
948
+ userAccumulator: staked[3]
949
+ },
950
+ creditAccount: {
951
+ collateral: credit[0],
952
+ debt: credit[1]
953
+ },
954
+ maxBorrow,
955
+ earned,
956
+ reserveSymbol
957
+ };
958
+ }
959
+ function requiredResult(result, label) {
960
+ if (result?.status === "success")
961
+ return result.result;
962
+ throw new Error(`Failed to read ${label}.`);
963
+ }
964
+ function formatPosition(position) {
965
+ const symbol = position.symbol ?? "BTokens";
966
+ const reserveUnit = position.reserveSymbol ?? position.reserve ?? "reserve";
967
+ const title = position.name ? position.symbol ? `${position.name} (${position.symbol})` : position.name : position.symbol ? position.symbol : "Position";
968
+ return [
969
+ title,
970
+ `Chain: ${position.chain} (${position.chainId})`,
971
+ `Token: ${position.token}`,
972
+ `User: ${position.user}`,
973
+ "",
974
+ table([
975
+ ["Total staked", position.amount.formatted, symbol],
976
+ ["Claimable", position.earned.formatted, reserveUnit],
977
+ ["Collateral", position.collateral.formatted, symbol],
978
+ ["Debt", position.debt.formatted, reserveUnit],
979
+ ["Max borrow", position.maxBorrow.formatted, reserveUnit]
980
+ ])
981
+ ].join(`
982
+ `);
983
+ }
984
+ async function readMaxBorrow(sdk, token, user) {
985
+ try {
986
+ return await sdk.getMaxBorrow(token, user);
987
+ } catch (error) {
988
+ if (error instanceof BaseError && error.walk((cause) => cause instanceof ContractFunctionRevertedError)) {
989
+ return 0n;
990
+ }
991
+ throw error;
992
+ }
993
+ }
994
+ function serializePosition(input) {
995
+ return {
996
+ chainId: input.chainId,
997
+ chain: input.chain,
998
+ token: input.token,
999
+ name: input.name,
1000
+ symbol: input.symbol,
1001
+ reserve: input.reserve,
1002
+ reserveSymbol: input.reserveSymbol,
1003
+ user: input.user,
1004
+ amount: serializeAmount(input.account.amount, input.bTokenDecimals),
1005
+ locked: serializeAmount(input.account.locked, input.bTokenDecimals),
1006
+ unlocked: serializeAmount(input.account.amount - input.account.locked, input.bTokenDecimals),
1007
+ earned: serializeAmount(input.earned ?? input.account.earned, input.reserveDecimals),
1008
+ collateral: serializeAmount(input.creditAccount.collateral, input.bTokenDecimals),
1009
+ debt: serializeAmount(input.creditAccount.debt, input.reserveDecimals),
1010
+ maxBorrow: serializeAmount(input.maxBorrow, input.reserveDecimals),
1011
+ storedEarned: serializeAmount(input.account.earned, input.reserveDecimals),
1012
+ userAccumulator: input.account.userAccumulator.toString()
1013
+ };
1014
+ }
1015
+ function table(rows) {
1016
+ const labelWidth = Math.max(...rows.map(([label]) => label.length), 5);
1017
+ const amountWidth = Math.max(...rows.map(([, amount]) => amount.length), 6);
1018
+ const unitWidth = Math.max(...rows.map(([, , unit]) => unit.length), 4);
1019
+ const line = `| ${"-".repeat(labelWidth)} | ${"-".repeat(amountWidth)} | ${"-".repeat(unitWidth)} |`;
1020
+ return [
1021
+ `| ${"Metric".padEnd(labelWidth)} | ${"Amount".padStart(amountWidth)} | ${"Unit".padEnd(unitWidth)} |`,
1022
+ line,
1023
+ ...rows.map(([label, amount, unit]) => `| ${label.padEnd(labelWidth)} | ${amount.padStart(amountWidth)} | ${unit.padEnd(unitWidth)} |`)
1024
+ ].join(`
1025
+ `);
1026
+ }
1027
+
1028
+ // src/commands/position/tx.ts
1029
+ import { serializeCalls as serializeCalls3, simulateCalls as simulateCalls2 } from "@baseline-markets/sdk";
1030
+ async function simulatePositionCalls(publicClient, calls, account) {
1031
+ return {
1032
+ calls: serializeCalls3(calls),
1033
+ simulation: await simulateCalls2(publicClient, calls, {
1034
+ account
1035
+ })
1036
+ };
1037
+ }
1038
+ async function executePositionCalls(input) {
1039
+ const execution = await executeCalls({
1040
+ chain: input.chain,
1041
+ calls: input.calls,
1042
+ privateKey: input.privateKey,
1043
+ rpcUrl: input.rpcUrl,
1044
+ expectedAccount: input.account,
1045
+ confirmations: input.confirmations
1046
+ });
1047
+ const lastTransaction = execution.transactions.at(-1);
1048
+ if (!lastTransaction) {
1049
+ throw new Error(`Position ${input.action} produced no transaction.`);
1050
+ }
1051
+ return {
1052
+ calls: serializeCalls3(input.calls),
1053
+ execution,
1054
+ transaction: serializeTransaction(lastTransaction.hash)
1055
+ };
1056
+ }
1057
+
1058
+ // src/commands/position/actions.ts
1059
+ async function stakePosition(options) {
1060
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
1061
+ const info = await sdk.getBTokenInfo(options.token);
1062
+ const bTokenDecimals = options.bTokenDecimals ?? info.decimals ?? 18;
1063
+ const reserveDecimals = options.reserveDecimals ?? info.reserveDecimals ?? 18;
1064
+ const amount = parseTokenUnits(options.amount, bTokenDecimals);
1065
+ const user = normalizeUser(options.user, account.address);
1066
+ const calls = [
1067
+ ...await sdk.calls.approval.ensure(options.token, sdk.proxy, amount, {
1068
+ owner: account.address,
1069
+ policy: options.approval
1070
+ }),
1071
+ sdk.calls.staking.deposit(options.token, user, amount)
1072
+ ];
1073
+ if (options.simulate) {
1074
+ return {
1075
+ chainId: chain.id,
1076
+ chain: chainName(chain),
1077
+ token: options.token,
1078
+ user,
1079
+ signer: account.address,
1080
+ deposited: serializeAmount(amount, bTokenDecimals),
1081
+ ...await simulatePositionCalls(publicClient, calls, account.address)
1082
+ };
1083
+ }
1084
+ const execution = await executePositionCalls({
1085
+ action: "stake",
1086
+ account: account.address,
1087
+ chain,
1088
+ calls,
1089
+ confirmations: options.confirmations,
1090
+ privateKey: resolvePrivateKey(options.privateKey),
1091
+ rpcUrl: options.rpcUrl
1092
+ });
1093
+ const [stakeAccount, creditAccount, maxBorrow, earned] = await Promise.all([
1094
+ sdk.getStakedAccount(options.token, user),
1095
+ sdk.getCreditAccount(options.token, user),
1096
+ readMaxBorrow(sdk, options.token, user),
1097
+ sdk.getEarned(options.token, user)
1098
+ ]);
1099
+ return {
1100
+ ...serializePosition({
1101
+ chainId: chain.id,
1102
+ chain: chainName(chain),
1103
+ token: options.token,
1104
+ name: info.name,
1105
+ symbol: info.symbol,
1106
+ reserve: info.reserve,
1107
+ user,
1108
+ account: stakeAccount,
1109
+ creditAccount,
1110
+ maxBorrow,
1111
+ earned,
1112
+ bTokenDecimals,
1113
+ reserveDecimals
1114
+ }),
1115
+ signer: account.address,
1116
+ deposited: serializeAmount(amount, bTokenDecimals),
1117
+ ...execution
1118
+ };
1119
+ }
1120
+ async function unstakePosition(options) {
1121
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
1122
+ const info = await sdk.getBTokenInfo(options.token);
1123
+ const bTokenDecimals = options.bTokenDecimals ?? info.decimals ?? 18;
1124
+ const reserveDecimals = options.reserveDecimals ?? info.reserveDecimals ?? 18;
1125
+ const amount = parseTokenUnits(options.amount, bTokenDecimals);
1126
+ const calls = [sdk.calls.staking.withdraw(options.token, amount)];
1127
+ if (options.simulate) {
1128
+ return {
1129
+ chainId: chain.id,
1130
+ chain: chainName(chain),
1131
+ token: options.token,
1132
+ user: account.address,
1133
+ signer: account.address,
1134
+ withdrawn: serializeAmount(amount, bTokenDecimals),
1135
+ ...await simulatePositionCalls(publicClient, calls, account.address)
1136
+ };
1137
+ }
1138
+ const execution = await executePositionCalls({
1139
+ action: "unstake",
1140
+ account: account.address,
1141
+ chain,
1142
+ calls,
1143
+ confirmations: options.confirmations,
1144
+ privateKey: resolvePrivateKey(options.privateKey),
1145
+ rpcUrl: options.rpcUrl
1146
+ });
1147
+ const [stakeAccount, creditAccount, maxBorrow, earned] = await Promise.all([
1148
+ sdk.getStakedAccount(options.token, account.address),
1149
+ sdk.getCreditAccount(options.token, account.address),
1150
+ readMaxBorrow(sdk, options.token, account.address),
1151
+ sdk.getEarned(options.token, account.address)
1152
+ ]);
1153
+ return {
1154
+ ...serializePosition({
1155
+ chainId: chain.id,
1156
+ chain: chainName(chain),
1157
+ token: options.token,
1158
+ name: info.name,
1159
+ symbol: info.symbol,
1160
+ reserve: info.reserve,
1161
+ user: account.address,
1162
+ account: stakeAccount,
1163
+ creditAccount,
1164
+ maxBorrow,
1165
+ earned,
1166
+ bTokenDecimals,
1167
+ reserveDecimals
1168
+ }),
1169
+ signer: account.address,
1170
+ withdrawn: serializeAmount(amount, bTokenDecimals),
1171
+ ...execution
1172
+ };
1173
+ }
1174
+ async function claimPosition(options) {
1175
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
1176
+ const info = await sdk.getBTokenInfo(options.token);
1177
+ const bTokenDecimals = options.bTokenDecimals ?? info.decimals ?? 18;
1178
+ const reserveDecimals = options.reserveDecimals ?? info.reserveDecimals ?? 18;
1179
+ const user = normalizeUser(options.user, account.address);
1180
+ const amount = await sdk.getEarned(options.token, user);
1181
+ const calls = [
1182
+ sdk.calls.staking.claim(options.token, user, options.asNative)
1183
+ ];
1184
+ if (options.simulate) {
1185
+ return {
1186
+ chainId: chain.id,
1187
+ chain: chainName(chain),
1188
+ token: options.token,
1189
+ user,
1190
+ signer: account.address,
1191
+ claimed: serializeAmount(amount, reserveDecimals),
1192
+ asNative: options.asNative,
1193
+ ...await simulatePositionCalls(publicClient, calls, account.address)
1194
+ };
1195
+ }
1196
+ const execution = await executePositionCalls({
1197
+ action: "claim",
1198
+ account: account.address,
1199
+ chain,
1200
+ calls,
1201
+ confirmations: options.confirmations,
1202
+ privateKey: resolvePrivateKey(options.privateKey),
1203
+ rpcUrl: options.rpcUrl
1204
+ });
1205
+ const [stakeAccount, creditAccount, maxBorrow, earned] = await Promise.all([
1206
+ sdk.getStakedAccount(options.token, user),
1207
+ sdk.getCreditAccount(options.token, user),
1208
+ readMaxBorrow(sdk, options.token, user),
1209
+ sdk.getEarned(options.token, user)
1210
+ ]);
1211
+ return {
1212
+ ...serializePosition({
1213
+ chainId: chain.id,
1214
+ chain: chainName(chain),
1215
+ token: options.token,
1216
+ name: info.name,
1217
+ symbol: info.symbol,
1218
+ reserve: info.reserve,
1219
+ user,
1220
+ account: stakeAccount,
1221
+ creditAccount,
1222
+ maxBorrow,
1223
+ earned,
1224
+ bTokenDecimals,
1225
+ reserveDecimals
1226
+ }),
1227
+ signer: account.address,
1228
+ claimed: serializeAmount(amount, reserveDecimals),
1229
+ asNative: options.asNative,
1230
+ ...execution
1231
+ };
1232
+ }
1233
+ async function borrowPosition(options) {
1234
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
1235
+ const info = await sdk.getBTokenInfo(options.token);
1236
+ const reserveDecimals = options.reserveDecimals ?? info.reserveDecimals ?? 18;
1237
+ const amount = parseTokenUnits(options.amount, reserveDecimals);
1238
+ const recipient = normalizeUser(options.recipient, account.address);
1239
+ const calls = [
1240
+ sdk.calls.credit.borrow(options.token, amount, recipient, {
1241
+ outputNative: options.outputNative
1242
+ })
1243
+ ];
1244
+ if (options.simulate) {
1245
+ return {
1246
+ chainId: chain.id,
1247
+ chain: chainName(chain),
1248
+ token: options.token,
1249
+ signer: account.address,
1250
+ recipient,
1251
+ borrowed: serializeAmount(amount, reserveDecimals),
1252
+ outputNative: options.outputNative,
1253
+ ...await simulatePositionCalls(publicClient, calls, account.address)
1254
+ };
1255
+ }
1256
+ const execution = await executePositionCalls({
1257
+ action: "borrow",
1258
+ account: account.address,
1259
+ chain,
1260
+ calls,
1261
+ confirmations: options.confirmations,
1262
+ privateKey: resolvePrivateKey(options.privateKey),
1263
+ rpcUrl: options.rpcUrl
1264
+ });
1265
+ const [stakeAccount, creditAccount, maxBorrow, earned] = await Promise.all([
1266
+ sdk.getStakedAccount(options.token, account.address),
1267
+ sdk.getCreditAccount(options.token, account.address),
1268
+ readMaxBorrow(sdk, options.token, account.address),
1269
+ sdk.getEarned(options.token, account.address)
1270
+ ]);
1271
+ return {
1272
+ ...serializePosition({
1273
+ chainId: chain.id,
1274
+ chain: chainName(chain),
1275
+ token: options.token,
1276
+ name: info.name,
1277
+ symbol: info.symbol,
1278
+ reserve: info.reserve,
1279
+ user: account.address,
1280
+ account: stakeAccount,
1281
+ creditAccount,
1282
+ maxBorrow,
1283
+ earned,
1284
+ bTokenDecimals: options.bTokenDecimals ?? info.decimals ?? 18,
1285
+ reserveDecimals
1286
+ }),
1287
+ signer: account.address,
1288
+ recipient,
1289
+ borrowed: serializeAmount(amount, reserveDecimals),
1290
+ outputNative: options.outputNative,
1291
+ ...execution
1292
+ };
1293
+ }
1294
+ async function repayPosition(options) {
1295
+ const { chain, publicClient, sdk, account } = createWalletSdk(options);
1296
+ const info = await sdk.getBTokenInfo(options.token);
1297
+ if (!options.useNative && !info.reserve) {
1298
+ throw new Error("Token reserve is unavailable.");
1299
+ }
1300
+ const reserveDecimals = options.reserveDecimals ?? info.reserveDecimals ?? 18;
1301
+ const amount = parseTokenUnits(options.amount, reserveDecimals);
1302
+ const recipient = normalizeUser(options.recipient, account.address);
1303
+ const calls = [
1304
+ ...options.useNative ? [] : await sdk.calls.approval.ensure(info.reserve, sdk.proxy, amount, {
1305
+ owner: account.address,
1306
+ policy: options.approval
1307
+ }),
1308
+ sdk.calls.credit.repay(options.token, amount, recipient, {
1309
+ useNative: options.useNative
1310
+ })
1311
+ ];
1312
+ if (options.simulate) {
1313
+ return {
1314
+ chainId: chain.id,
1315
+ chain: chainName(chain),
1316
+ token: options.token,
1317
+ signer: account.address,
1318
+ recipient,
1319
+ repaid: serializeAmount(amount, reserveDecimals),
1320
+ useNative: options.useNative,
1321
+ ...await simulatePositionCalls(publicClient, calls, account.address)
1322
+ };
1323
+ }
1324
+ const execution = await executePositionCalls({
1325
+ action: "repay",
1326
+ account: account.address,
1327
+ chain,
1328
+ calls,
1329
+ confirmations: options.confirmations,
1330
+ privateKey: resolvePrivateKey(options.privateKey),
1331
+ rpcUrl: options.rpcUrl
1332
+ });
1333
+ const [stakeAccount, creditAccount, maxBorrow, earned] = await Promise.all([
1334
+ sdk.getStakedAccount(options.token, recipient),
1335
+ sdk.getCreditAccount(options.token, recipient),
1336
+ readMaxBorrow(sdk, options.token, recipient),
1337
+ sdk.getEarned(options.token, recipient)
1338
+ ]);
1339
+ return {
1340
+ ...serializePosition({
1341
+ chainId: chain.id,
1342
+ chain: chainName(chain),
1343
+ token: options.token,
1344
+ name: info.name,
1345
+ symbol: info.symbol,
1346
+ reserve: info.reserve,
1347
+ user: recipient,
1348
+ account: stakeAccount,
1349
+ creditAccount,
1350
+ maxBorrow,
1351
+ earned,
1352
+ bTokenDecimals: options.bTokenDecimals ?? info.decimals ?? 18,
1353
+ reserveDecimals
1354
+ }),
1355
+ signer: account.address,
1356
+ recipient,
1357
+ repaid: serializeAmount(amount, reserveDecimals),
1358
+ useNative: options.useNative,
1359
+ ...execution
1360
+ };
1361
+ }
1362
+
1363
+ // src/commands/position/index.ts
1364
+ var positionCommand = {
1365
+ description: "Inspect and manage a Baseline position.",
1366
+ options: accountOptions,
1367
+ async run({
1368
+ options,
1369
+ formatExplicit
1370
+ }) {
1371
+ const position = await readPosition(options);
1372
+ return formatExplicit ? position : formatPosition(position);
1373
+ }
1374
+ };
1375
+ var positionStakeCommand = {
1376
+ description: "Stake BTokens into a Baseline position.",
1377
+ options: stakeOptions,
1378
+ run: ({ options }) => stakePosition(options)
1379
+ };
1380
+ var positionUnstakeCommand = {
1381
+ description: "Withdraw staked BTokens from a Baseline position.",
1382
+ options: unstakeOptions,
1383
+ run: ({ options }) => unstakePosition(options)
1384
+ };
1385
+ var positionClaimCommand = {
1386
+ description: "Claim position rewards.",
1387
+ options: claimOptions,
1388
+ run: ({ options }) => claimPosition(options)
1389
+ };
1390
+ var positionBorrowCommand = {
1391
+ description: "Borrow reserves against a Baseline position.",
1392
+ options: borrowOptions,
1393
+ run: ({ options }) => borrowPosition(options)
1394
+ };
1395
+ var positionRepayCommand = {
1396
+ description: "Repay reserves for a Baseline position.",
1397
+ options: repayOptions,
1398
+ run: ({ options }) => repayPosition(options)
1399
+ };
1400
+
410
1401
  // src/env.ts
411
1402
  import { existsSync, readFileSync } from "node:fs";
412
1403
  import { dirname as dirname2, resolve } from "node:path";
@@ -447,18 +1438,45 @@ function loadEnv(path) {
447
1438
 
448
1439
  // src/index.ts
449
1440
  loadCliEnv();
450
- var cli = Cli.create("baseline", {
1441
+ var cli = Cli2.create("baseline", {
451
1442
  version: "0.2.0",
452
1443
  description: "Baseline Markets CLI",
453
1444
  sync: {
454
1445
  include: [skillsGlob],
455
1446
  suggestions: [
456
1447
  "build launch calls for a new Baseline token",
457
- "output launch calls as JSON for wallet_sendCalls"
1448
+ "output launch calls as JSON for wallet_sendCalls",
1449
+ "quote a Baseline token swap",
1450
+ "manage a Baseline position"
458
1451
  ]
459
1452
  }
460
- }).command("launch", launchCommand).command("info", infoCommand);
461
- await cli.serve();
1453
+ }).command("launch", launchCommand).command("info", infoCommand).command(quoteCommand).command("swap", swapCommand).command("position", positionCommand).command("position stake", positionStakeCommand).command("position unstake", positionUnstakeCommand).command("position claim", positionClaimCommand).command("position borrow", positionBorrowCommand).command("position repay", positionRepayCommand);
1454
+ function normalizeArgv(argv) {
1455
+ const [command, subcommand, ...rest] = argv;
1456
+ switch (command) {
1457
+ case "position":
1458
+ switch (subcommand) {
1459
+ case "stake":
1460
+ case "unstake":
1461
+ case "claim":
1462
+ case "borrow":
1463
+ case "repay":
1464
+ if (rest[0] && !rest[0].startsWith("-")) {
1465
+ return [`position ${subcommand} ${rest[0]}`, ...rest.slice(1)];
1466
+ }
1467
+ return [`position ${subcommand}`, ...rest];
1468
+ }
1469
+ }
1470
+ return argv;
1471
+ }
1472
+ function serveCli(argv = process.argv.slice(2), options) {
1473
+ return cli.serve(normalizeArgv(argv), options);
1474
+ }
1475
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
1476
+ await serveCli();
1477
+ }
462
1478
  export {
1479
+ serveCli,
1480
+ normalizeArgv,
463
1481
  cli
464
1482
  };