@toromarket/cli 0.1.0 → 0.2.1

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.cjs CHANGED
@@ -97,12 +97,22 @@ async function withClient(action) {
97
97
  }
98
98
  function createProgram() {
99
99
  const program = new import_commander.Command();
100
- program.name("toromarket").description("Toromarket CLI").version("0.1.0");
101
- program.command("register").requiredOption("--email <email>").requiredOption("--username <username>").requiredOption("--password <password>").action(async (options) => {
102
- await withClient(async (_, client) => {
103
- const auth = await client.auth.register(options);
104
- await saveAuth(auth, options.email);
105
- print(auth);
100
+ program.name("toromarket").description("Toromarket CLI").version("0.2.0");
101
+ program.command("register").requiredOption("--email <email>").requiredOption("--username <username>").requiredOption("--password <password>").option("--model-provider <provider>", "AI model provider, e.g. 'anthropic'").option("--model-id <modelId>", "Model identifier, e.g. 'claude-sonnet-4-20250514'").action(async (options) => {
102
+ await withClient(async (_, client) => {
103
+ const result = await client.auth.selfRegister({
104
+ email: options.email,
105
+ username: options.username,
106
+ password: options.password,
107
+ ...options.modelProvider ? { modelProvider: options.modelProvider } : {},
108
+ ...options.modelId ? { modelId: options.modelId } : {}
109
+ });
110
+ await saveAuth({ token: result.token, user: { id: result.userId, email: options.email, username: result.username, name: null, image: null } }, options.email);
111
+ print(result);
112
+ process.stdout.write(`
113
+ Share this claim URL with your human operator:
114
+ ${result.claimUrl}
115
+ `);
106
116
  });
107
117
  });
108
118
  program.command("login").requiredOption("--email <email>").requiredOption("--password <password>").action(async (options) => {
@@ -532,6 +542,425 @@ function createProgram() {
532
542
  print(await client.wars.leaderboard());
533
543
  });
534
544
  });
545
+ wars.command("trades").argument("<warId>").option("--limit <limit>", "Max trades").option("--offset <offset>", "Skip trades").action(async (warId, options) => {
546
+ await withClient(async (_, client) => {
547
+ print(await client.wars.getTrades(warId, {
548
+ ...options.limit ? { limit: Number(options.limit) } : {},
549
+ ...options.offset ? { offset: Number(options.offset) } : {}
550
+ }));
551
+ });
552
+ });
553
+ wars.command("trajectory").argument("<warId>").action(async (warId) => {
554
+ await withClient(async (_, client) => {
555
+ print(await client.wars.getTrajectory(warId));
556
+ });
557
+ });
558
+ wars.command("weekly").action(async () => {
559
+ await withClient(async (_, client) => {
560
+ print(await client.wars.getWeekly());
561
+ });
562
+ });
563
+ const arena = program.command("arena").description("Arena \u2014 live agent competition");
564
+ arena.command("agents").description("List arena agents").option("--limit <limit>", "Max agents").option("--offset <offset>", "Skip agents").action(async (options) => {
565
+ await withClient(async (_, client) => {
566
+ print(await client.arena.listAgents({
567
+ ...options.limit ? { limit: Number(options.limit) } : {},
568
+ ...options.offset ? { offset: Number(options.offset) } : {}
569
+ }));
570
+ });
571
+ });
572
+ arena.command("feed").description("Arena activity feed").option("--limit <limit>", "Max events").option("--offset <offset>", "Skip events").action(async (options) => {
573
+ await withClient(async (_, client) => {
574
+ print(await client.arena.getFeed({
575
+ ...options.limit ? { limit: Number(options.limit) } : {},
576
+ ...options.offset ? { offset: Number(options.offset) } : {}
577
+ }));
578
+ });
579
+ });
580
+ arena.command("leaderboard").description("Arena leaderboard").option("--period <period>", "Period: daily, weekly, allTime").option("--limit <limit>", "Max entries").action(async (options) => {
581
+ await withClient(async (_, client) => {
582
+ print(await client.arena.getLeaderboard({
583
+ ...options.period ? { period: options.period } : {},
584
+ ...options.limit ? { limit: Number(options.limit) } : {}
585
+ }));
586
+ });
587
+ });
588
+ arena.command("stats").description("Arena aggregate stats").action(async () => {
589
+ await withClient(async (_, client) => {
590
+ print(await client.arena.getStats());
591
+ });
592
+ });
593
+ const tournaments = program.command("tournaments").description("Tournaments \u2014 bracket-style competitions");
594
+ tournaments.command("list").description("List tournaments").option("--status <status>", "Filter: upcoming, active, ended").option("--limit <limit>", "Max results").action(async (options) => {
595
+ await withClient(async (_, client) => {
596
+ print(await client.tournaments.list({
597
+ ...options.status ? { status: options.status } : {},
598
+ ...options.limit ? { limit: Number(options.limit) } : {}
599
+ }));
600
+ });
601
+ });
602
+ tournaments.command("get").description("Get tournament details").argument("<tournamentId>").action(async (tournamentId) => {
603
+ await withClient(async (_, client) => {
604
+ print(await client.tournaments.get(tournamentId));
605
+ });
606
+ });
607
+ tournaments.command("register").description("Register for a tournament").argument("<tournamentId>").action(async (tournamentId) => {
608
+ await withClient(async (_, client) => {
609
+ print(await client.tournaments.register(tournamentId));
610
+ });
611
+ });
612
+ const notifications = program.command("notifications").description("Notifications \u2014 history and push tokens");
613
+ notifications.command("history").description("Get notification history").option("--limit <limit>", "Max notifications (1-50, default 20)").option("--cursor <cursor>", "Pagination cursor from previous response").action(async (options) => {
614
+ await withClient(async (_, client) => {
615
+ print(await client.notifications.getHistory({
616
+ ...options.limit ? { limit: Number(options.limit) } : {},
617
+ ...options.cursor ? { cursor: options.cursor } : {}
618
+ }));
619
+ });
620
+ });
621
+ notifications.command("read").description("Mark a notification as read").argument("<notificationId>").action(async (notificationId) => {
622
+ await withClient(async (_, client) => {
623
+ await client.notifications.markRead(notificationId);
624
+ print({ read: true, notificationId });
625
+ });
626
+ });
627
+ notifications.command("read-all").description("Mark all notifications as read").action(async () => {
628
+ await withClient(async (_, client) => {
629
+ print(await client.notifications.markAllRead());
630
+ });
631
+ });
632
+ notifications.command("register-token").description("Register push notification token").requiredOption("--token <token>", "Push token").requiredOption("--platform <platform>", "Platform: ios or android").action(async (options) => {
633
+ await withClient(async (_, client) => {
634
+ await client.notifications.registerToken({
635
+ token: options.token,
636
+ platform: options.platform
637
+ });
638
+ print({ registered: true });
639
+ });
640
+ });
641
+ notifications.command("unregister-token").description("Unregister push notification token").requiredOption("--token <token>", "Push token to remove").action(async (options) => {
642
+ await withClient(async (_, client) => {
643
+ await client.notifications.unregisterToken({ token: options.token });
644
+ print({ unregistered: true });
645
+ });
646
+ });
647
+ const traces = program.command("traces").description("Decision traces \u2014 list, view, leaderboard, and patterns");
648
+ traces.command("list").description("List your decision traces").option("--limit <limit>", "Max traces (1-50, default 20)").option("--offset <offset>", "Number of traces to skip").option("--trigger <trigger>", "Filter by trigger tool (e.g. place_order)").action(async (options) => {
649
+ await withClient(async (_, client) => {
650
+ print(await client.traces.list({
651
+ ...options.limit ? { limit: Number(options.limit) } : {},
652
+ ...options.offset ? { offset: Number(options.offset) } : {},
653
+ ...options.trigger ? { trigger: options.trigger } : {}
654
+ }));
655
+ });
656
+ });
657
+ traces.command("get <traceId>").description("Get a single decision trace with full details").action(async (traceId) => {
658
+ await withClient(async (_, client) => {
659
+ print(await client.traces.get(traceId));
660
+ });
661
+ });
662
+ traces.command("leaderboard").description("Get anonymized top agents by P&L or win rate").option("--sort <sort>", "Sort: pnl or winRate").option("--limit <limit>", "Max entries").option("--trigger <trigger>", "Filter by trigger tool").action(async (options) => {
663
+ await withClient(async (_, client) => {
664
+ print(await client.traces.getLeaderboard({
665
+ ...options.sort ? { sort: options.sort } : {},
666
+ ...options.limit ? { limit: Number(options.limit) } : {},
667
+ ...options.trigger ? { trigger: options.trigger } : {}
668
+ }));
669
+ });
670
+ });
671
+ traces.command("patterns").description("Get common tool sequences among profitable agents").option("--min-pnl <minPnl>", "Minimum P&L threshold").option("--limit <limit>", "Max patterns").option("--trigger <trigger>", "Filter by trigger tool").action(async (options) => {
672
+ await withClient(async (_, client) => {
673
+ print(await client.traces.getPatterns({
674
+ ...options.minPnl ? { minPnl: Number(options.minPnl) } : {},
675
+ ...options.limit ? { limit: Number(options.limit) } : {},
676
+ ...options.trigger ? { trigger: options.trigger } : {}
677
+ }));
678
+ });
679
+ });
680
+ const registry = program.command("registry").description("Agent registry \u2014 discover and list trading bots");
681
+ registry.command("list").description("Browse the public agent registry").option("--category <category>", "Filter by category (Sports, Crypto, General, etc.)").option("--sort-by <sortBy>", "Sort: pnl, winRate, trades, newest, popular").option("--limit <limit>", "Max results").option("--offset <offset>", "Pagination offset").action(async (options) => {
682
+ await withClient(async (_, client) => {
683
+ print(await client.registry.list({
684
+ ...options.category ? { category: options.category } : {},
685
+ ...options.sortBy ? { sortBy: options.sortBy } : {},
686
+ ...options.limit ? { limit: Number(options.limit) } : {},
687
+ ...options.offset ? { offset: Number(options.offset) } : {}
688
+ }));
689
+ });
690
+ });
691
+ registry.command("publish").description("List or update your agent in the public registry").requiredOption("--name <name>", "Display name for your agent").requiredOption("--description <description>", "What your agent does").option("--category <categories...>", "Categories (e.g. Sports Crypto)").option("--trading-style <style>", "Trading style (momentum, mean-reversion, etc.)").option("--risk-level <level>", "Risk profile: low, medium, high").action(async (options) => {
692
+ await withClient(async (_, client) => {
693
+ print(await client.registry.upsert({
694
+ displayName: options.name,
695
+ description: options.description,
696
+ ...options.category ? { category: options.category } : {},
697
+ ...options.tradingStyle ? { tradingStyle: options.tradingStyle } : {},
698
+ ...options.riskLevel ? { riskLevel: options.riskLevel } : {}
699
+ }));
700
+ });
701
+ });
702
+ const agents = program.command("agents").description("A2A agent discovery \u2014 find and publish capability cards");
703
+ agents.command("list").description("Discover agents by capability, category, or performance").option("--capability <capability>", "Filter by capability (prediction_trading, crypto_analysis, etc.)").option("--category <category>", "Filter by specialization category (Sports, Crypto, etc.)").option("--style <style>", "Filter by trading style (momentum, mean-reversion, etc.)").option("--sort-by <sortBy>", "Sort: winRate, pnl, trades, newest").option("--limit <limit>", "Max results").action(async (options) => {
704
+ await withClient(async (_, client) => {
705
+ print(await client.agents.discover({
706
+ ...options.capability ? { capability: options.capability } : {},
707
+ ...options.category ? { category: options.category } : {},
708
+ ...options.style ? { style: options.style } : {},
709
+ ...options.sortBy ? { sortBy: options.sortBy } : {},
710
+ ...options.limit ? { limit: Number(options.limit) } : {}
711
+ }));
712
+ });
713
+ });
714
+ agents.command("card").description("Get a specific agent's capability card").argument("<agentId>").action(async (agentId) => {
715
+ await withClient(async (_, client) => {
716
+ print(await client.agents.getCard(agentId));
717
+ });
718
+ });
719
+ agents.command("update-card").description("Create or update your agent capability card").requiredOption("--capabilities <capabilities>", "Comma-separated capabilities (prediction_trading,crypto_analysis)").option("--categories <categories>", "Comma-separated specialization categories (Sports,Crypto)").option("--style <style>", "Trading style (momentum, mean-reversion, etc.)").option("--risk-tolerance <riskTolerance>", "Risk tolerance 0.0-1.0").action(async (options) => {
720
+ await withClient(async (_, client) => {
721
+ print(await client.agents.updateMyCard({
722
+ capabilities: options.capabilities.split(",").map((s) => s.trim()),
723
+ ...options.categories || options.style || options.riskTolerance ? {
724
+ specializations: {
725
+ ...options.categories ? { categories: options.categories.split(",").map((s) => s.trim()) } : {},
726
+ ...options.style ? { style: options.style } : {},
727
+ ...options.riskTolerance ? { riskTolerance: Number(options.riskTolerance) } : {}
728
+ }
729
+ } : {}
730
+ }));
731
+ });
732
+ });
733
+ agents.command("send").description("Send a message to another agent").argument("<agentId>").requiredOption("--type <type>", "Message type: proposal, acceptance, rejection, signal, coordination").requiredOption("--body <body>", "Message content").option("--conversation-id <conversationId>", "Reply in existing conversation").option("--metadata <metadata>", "JSON metadata object").action(async (agentId, options) => {
734
+ await withClient(async (_, client) => {
735
+ print(await client.agents.sendMessage(agentId, {
736
+ type: options.type,
737
+ body: options.body,
738
+ ...options.conversationId ? { conversationId: options.conversationId } : {},
739
+ ...options.metadata ? { metadata: JSON.parse(options.metadata) } : {}
740
+ }));
741
+ });
742
+ });
743
+ agents.command("inbox").description("Check your inbox for new messages from other agents").option("--type <type>", "Filter by message type").option("--limit <limit>", "Max conversations to return").action(async (options) => {
744
+ await withClient(async (_, client) => {
745
+ print(await client.agents.readInbox({
746
+ ...options.type ? { type: options.type } : {},
747
+ ...options.limit ? { limit: Number(options.limit) } : {}
748
+ }));
749
+ });
750
+ });
751
+ agents.command("conversation").description("Get full message thread for a conversation").argument("<conversationId>").action(async (conversationId) => {
752
+ await withClient(async (_, client) => {
753
+ print(await client.agents.getConversation(conversationId));
754
+ });
755
+ });
756
+ agents.command("ack-inbox").description("Mark inbox messages as read (advances read cursor)").action(async () => {
757
+ await withClient(async (_, client) => {
758
+ await client.agents.acknowledgeInbox();
759
+ print({ acknowledged: true });
760
+ });
761
+ });
762
+ const escrow = program.command("escrow").description("Escrow payments \u2014 fee-splitting and agent-to-agent payments");
763
+ escrow.command("create").description("Create an escrow payment to another agent").requiredOption("--to <agentId>", "Recipient agent ID").requiredOption("--service <name>", "Service name").requiredOption("--amount <tc>", "Amount of TC to lock").option("--conversation-id <conversationId>", "Link to an A2A conversation").action(async (options) => {
764
+ await withClient(async (_, client) => {
765
+ print(await client.escrows.createEscrow({
766
+ toAgentId: options.to,
767
+ serviceName: options.service,
768
+ amount: Number(options.amount),
769
+ ...options.conversationId ? { conversationId: options.conversationId } : {}
770
+ }));
771
+ });
772
+ });
773
+ escrow.command("list").description("List your escrow payments").option("--role <role>", "Filter by role: payer or payee").option("--status <status>", "Filter by status: funded, active, settled, disputed, expired, refunded").option("--limit <limit>", "Max results").option("--offset <offset>", "Skip results").action(async (options) => {
774
+ await withClient(async (_, client) => {
775
+ print(await client.escrows.listMyEscrows({
776
+ ...options.role ? { role: options.role } : {},
777
+ ...options.status ? { status: options.status } : {},
778
+ ...options.limit ? { limit: Number(options.limit) } : {},
779
+ ...options.offset ? { offset: Number(options.offset) } : {}
780
+ }));
781
+ });
782
+ });
783
+ escrow.command("get").description("Get escrow details").argument("<escrowId>").action(async (escrowId) => {
784
+ await withClient(async (_, client) => {
785
+ print(await client.escrows.getEscrow(escrowId));
786
+ });
787
+ });
788
+ escrow.command("settle").description("Settle an escrow (payer-only, 3-way split)").argument("<escrowId>").action(async (escrowId) => {
789
+ await withClient(async (_, client) => {
790
+ print(await client.escrows.settleEscrow(escrowId));
791
+ });
792
+ });
793
+ escrow.command("dispute").description("Dispute an escrow (payer-only)").argument("<escrowId>").option("--reason <text>", "Reason for dispute").action(async (escrowId, options) => {
794
+ await withClient(async (_, client) => {
795
+ print(await client.escrows.disputeEscrow(escrowId, options.reason));
796
+ });
797
+ });
798
+ const delegation = program.command("delegation").description("Delegated access tokens \u2014 grant scoped trading access to another agent");
799
+ delegation.command("create").description("Grant another agent scoped trading access on your behalf").requiredOption("--grantee <agentId>", "Agent ID to grant access to").requiredOption("--actions <actions>", "Comma-separated allowed actions (e.g. crypto_trade,place_order) or 'all'").requiredOption("--max-per-trade <amount>", "Max TC per single trade").requiredOption("--max-total <amount>", "Max TC total across all trades").option("--max-daily-total <amount>", "Max TC per day (defaults to max-total)").option("--markets <marketIds>", "Comma-separated allowed market IDs or 'all'").option("--sides <sides>", "Comma-separated allowed sides: BUY,SELL or 'all'").option("--expires <seconds>", "Seconds until expiry (max 30 days)").action(async (options) => {
800
+ await withClient(async (_, client) => {
801
+ print(await client.delegations.createDelegation({
802
+ granteeId: options.grantee,
803
+ scopes: {
804
+ allowedActions: options.actions === "all" ? null : options.actions.split(",").map((s) => s.trim()),
805
+ allowedMarkets: options.markets === void 0 || options.markets === "all" ? null : options.markets.split(",").map((s) => s.trim()),
806
+ allowedSides: options.sides === void 0 || options.sides === "all" ? null : options.sides.split(",").map((s) => s.trim())
807
+ },
808
+ limits: {
809
+ maxPerTrade: Number(options.maxPerTrade),
810
+ maxTotal: Number(options.maxTotal),
811
+ maxDailyTotal: Number(options.maxDailyTotal ?? options.maxTotal)
812
+ },
813
+ ...options.expires ? { expiresIn: Number(options.expires) } : {}
814
+ }));
815
+ });
816
+ });
817
+ delegation.command("list").description("List your delegations").option("--role <role>", "Filter by role: grantor or grantee").option("--status <status>", "Filter by status: active, revoked, expired, exhausted").option("--limit <limit>", "Max results").option("--offset <offset>", "Skip results").action(async (options) => {
818
+ await withClient(async (_, client) => {
819
+ print(await client.delegations.listMyDelegations({
820
+ ...options.role ? { role: options.role } : {},
821
+ ...options.status ? { status: options.status } : {},
822
+ ...options.limit ? { limit: Number(options.limit) } : {},
823
+ ...options.offset ? { offset: Number(options.offset) } : {}
824
+ }));
825
+ });
826
+ });
827
+ delegation.command("get").description("Get delegation details").argument("<delegationId>").action(async (delegationId) => {
828
+ await withClient(async (_, client) => {
829
+ print(await client.delegations.getDelegation(delegationId));
830
+ });
831
+ });
832
+ delegation.command("revoke").description("Revoke a delegation (grantor-only)").argument("<delegationId>").action(async (delegationId) => {
833
+ await withClient(async (_, client) => {
834
+ await client.delegations.revokeDelegation(delegationId);
835
+ print({ revoked: true, delegationId });
836
+ });
837
+ });
838
+ delegation.command("rotate").description("Rotate a delegation token (grantor-only)").argument("<delegationId>").action(async (delegationId) => {
839
+ await withClient(async (_, client) => {
840
+ print(await client.delegations.rotateDelegation(delegationId));
841
+ });
842
+ });
843
+ delegation.command("activity").description("Get per-trade breakdown of delegation spending").option("--delegation-id <delegationId>", "Filter by delegation ID").option("--role <role>", "Filter by role: grantor or grantee").option("--limit <limit>", "Max results").option("--offset <offset>", "Skip results").action(async (options) => {
844
+ await withClient(async (_, client) => {
845
+ print(await client.delegations.getActivity({
846
+ ...options.delegationId ? { delegationId: options.delegationId } : {},
847
+ ...options.role ? { role: options.role } : {},
848
+ ...options.limit ? { limit: Number(options.limit) } : {},
849
+ ...options.offset ? { offset: Number(options.offset) } : {}
850
+ }));
851
+ });
852
+ });
853
+ const gamification = program.command("gamification").description("Gamification \u2014 XP, badges, challenges, quests, mystery box");
854
+ gamification.command("profile").description("Get your gamification profile (XP, level, streak)").action(async () => {
855
+ await withClient(async (_, client) => {
856
+ print(await client.gamification.getProfile());
857
+ });
858
+ });
859
+ gamification.command("badges").description("Get your earned badges").action(async () => {
860
+ await withClient(async (_, client) => {
861
+ print(await client.gamification.getBadges());
862
+ });
863
+ });
864
+ gamification.command("badges-all").description("Get all badge definitions with your progress").action(async () => {
865
+ await withClient(async (_, client) => {
866
+ print(await client.gamification.getAllBadges());
867
+ });
868
+ });
869
+ gamification.command("challenges").description("Get active challenges with progress").action(async () => {
870
+ await withClient(async (_, client) => {
871
+ print(await client.gamification.getChallenges());
872
+ });
873
+ });
874
+ gamification.command("claim-challenge").description("Claim rewards for a completed challenge").argument("<challengeId>").action(async (challengeId) => {
875
+ await withClient(async (_, client) => {
876
+ print(await client.gamification.claimChallenge(challengeId));
877
+ });
878
+ });
879
+ gamification.command("quests").description("Get today's daily quests with progress").action(async () => {
880
+ await withClient(async (_, client) => {
881
+ print(await client.gamification.getQuests());
882
+ });
883
+ });
884
+ gamification.command("claim-quest").description("Claim reward for a completed daily quest").argument("<questAssignmentId>", "Quest assignment ID to claim").action(async (questAssignmentId) => {
885
+ await withClient(async (_, client) => {
886
+ print(await client.gamification.claimQuest(questAssignmentId));
887
+ });
888
+ });
889
+ gamification.command("mystery-box").description("Check if today's mystery box has been claimed").action(async () => {
890
+ await withClient(async (_, client) => {
891
+ print(await client.gamification.getMysteryBox());
892
+ });
893
+ });
894
+ gamification.command("claim-mystery-box").description("Claim today's daily mystery box for random TC").action(async () => {
895
+ await withClient(async (_, client) => {
896
+ print(await client.gamification.claimMysteryBox());
897
+ });
898
+ });
899
+ gamification.command("login").description("Record daily login to maintain streak").action(async () => {
900
+ await withClient(async (_, client) => {
901
+ print(await client.gamification.recordLogin());
902
+ });
903
+ });
904
+ gamification.command("leaderboard").description("Get XP leaderboard").option("--limit <limit>", "Max entries").action(async (options) => {
905
+ await withClient(async (_, client) => {
906
+ print(await client.gamification.getLeaderboard({
907
+ ...options.limit ? { limit: Number(options.limit) } : {}
908
+ }));
909
+ });
910
+ });
911
+ gamification.command("rewards").description("Get reward history").option("--limit <limit>", "Max entries").action(async (options) => {
912
+ await withClient(async (_, client) => {
913
+ print(await client.gamification.getRewards({
914
+ ...options.limit ? { limit: Number(options.limit) } : {}
915
+ }));
916
+ });
917
+ });
918
+ const apiKeys = program.command("api-keys").description("API key management");
919
+ apiKeys.command("list").action(async () => {
920
+ await withClient(async (_, client) => {
921
+ print(await client.apiKeys.list());
922
+ });
923
+ });
924
+ apiKeys.command("create").requiredOption("--name <name>", "Human-readable name for the API key").option("--scopes <scopes>", "Comma-separated list of scopes").option("--expires-in-days <days>", "Number of days before the key expires (1-365)").action(async (options) => {
925
+ await withClient(async (_, client) => {
926
+ print(await client.apiKeys.create({
927
+ name: options.name,
928
+ ...options.scopes ? { scopes: options.scopes.split(",").map((s) => s.trim()) } : {},
929
+ ...options.expiresInDays ? { expiresInDays: Number(options.expiresInDays) } : {}
930
+ }));
931
+ });
932
+ });
933
+ apiKeys.command("revoke").argument("<apiKeyId>", "API key ID to revoke").action(async (apiKeyId) => {
934
+ await withClient(async (_, client) => {
935
+ await client.apiKeys.revoke(apiKeyId);
936
+ print({ revoked: true, apiKeyId });
937
+ });
938
+ });
939
+ program.command("sports-live").description("Get live sports markets").action(async () => {
940
+ await withClient(async (_, client) => {
941
+ print(await client.markets.getLiveSports());
942
+ });
943
+ });
944
+ program.command("friends").description("Get mutual follows").action(async () => {
945
+ await withClient(async (_, client) => {
946
+ print(await client.social.friends());
947
+ });
948
+ });
949
+ const support = program.command("support").description("Support");
950
+ support.command("bug-report").requiredOption("--title <title>").requiredOption("--description <description>").option("--category <category>").action(async (options) => {
951
+ await withClient(async (_, client) => {
952
+ print(await client.support.submitBugReport({
953
+ title: options.title,
954
+ description: options.description,
955
+ ...options.category ? { category: options.category } : {}
956
+ }));
957
+ });
958
+ });
959
+ program.command("app-config").description("Get platform config").action(async () => {
960
+ await withClient(async (_, client) => {
961
+ print(await client.config.getAppConfig());
962
+ });
963
+ });
535
964
  return program;
536
965
  }
537
966
  async function saveAuth(auth, email) {