@@ -621,7 +621,7 @@ def add_connection_opts(p: argparse.ArgumentParser) -> None:
621621 p .add_argument ("--account" , default = env_default ("JMAP_ACCOUNT" , "primary" ), help = "Account id or 'primary'" )
622622 p .add_argument ("--timeout" , type = float , default = float (env_default ("JMAP_TIMEOUT" , "30" )), help = "HTTP timeout seconds" )
623623 p .add_argument ("--insecure" , action = "store_true" , help = "Skip TLS verification" )
624- p .add_argument ("--json" , choices = ["compact" , "pretty" , "jsonl" ], default = "compact" , help = "JSON output style" )
624+ p .add_argument ("--json" , choices = ["compact" , "pretty" , "jsonl" ], help = "JSON output style" )
625625
626626
627627def build_parser () -> argparse .ArgumentParser :
@@ -637,9 +637,11 @@ def build_parser() -> argparse.ArgumentParser:
637637
638638 s = sub .add_parser ("session.get" , help = "Return JMAP session object" )
639639 add_connection_opts (s )
640+ s .set_defaults (json = "compact" )
640641
641642 eq = sub .add_parser ("email.query" , help = "Email/query" )
642643 add_connection_opts (eq )
644+ eq .set_defaults (json = "compact" )
643645 eq .add_argument ("--filter" , help = "EmailQueryFilter JSON (inline, @file, @-)" )
644646 eq .add_argument ("--sort" , help = "JSON array of Comparator objects" )
645647 eq .add_argument ("--limit" , type = int , default = 10 )
@@ -649,16 +651,19 @@ def build_parser() -> argparse.ArgumentParser:
649651
650652 eg = sub .add_parser ("email.get" , help = "Email/get" )
651653 add_connection_opts (eg )
654+ eg .set_defaults (json = "compact" )
652655 eg .add_argument ("--ids" , required = True , help = "JSON array of ids or @file/@-" )
653656 eg .add_argument ("--properties" , help = "JSON array of properties" )
654657
655658 ech = sub .add_parser ("email.changes" , help = "Email/changes" )
656659 add_connection_opts (ech )
660+ ech .set_defaults (json = "compact" )
657661 ech .add_argument ("--since-state" , required = True , help = "sinceState string" )
658662 ech .add_argument ("--max-changes" , type = int , help = "Maximum changes" )
659663
660664 eqc = sub .add_parser ("email.query-changes" , help = "Email/queryChanges" )
661665 add_connection_opts (eqc )
666+ eqc .set_defaults (json = "compact" )
662667 eqc .add_argument ("--since-query-state" , required = True , help = "sinceQueryState string" )
663668 eqc .add_argument ("--filter" , help = "EmailQueryFilter JSON (inline/@file/@-)" )
664669 eqc .add_argument ("--sort" , help = "JSON array of Comparator objects" )
@@ -669,23 +674,27 @@ def build_parser() -> argparse.ArgumentParser:
669674
670675 mq = sub .add_parser ("mailbox.query" , help = "Mailbox/query" )
671676 add_connection_opts (mq )
677+ mq .set_defaults (json = "compact" )
672678 mq .add_argument ("--filter" , help = "MailboxQueryFilter JSON (inline/@file/@-)" )
673679 mq .add_argument ("--sort" , help = "JSON array of Comparator objects" )
674680 mq .add_argument ("--limit" , type = int , default = 10 )
675681 mq .add_argument ("--position" , type = int , default = 0 )
676682
677683 tg = sub .add_parser ("thread.get" , help = "Thread/get" )
678684 add_connection_opts (tg )
685+ tg .set_defaults (json = "compact" )
679686 tg .add_argument ("--ids" , required = True , help = "JSON array of thread ids or @file/@-" )
680687
681688 ss = sub .add_parser ("searchsnippet.get" , help = "SearchSnippet/get" )
682689 add_connection_opts (ss )
690+ ss .set_defaults (json = "compact" )
683691 ss .add_argument ("--email-ids" , required = True , help = "JSON array of email ids" )
684692 ss .add_argument ("--filter" , help = "EmailQueryFilter JSON" )
685693 ss .add_argument ("--properties" , nargs = "+" , help = "Snippet properties" )
686694
687695 ev = sub .add_parser ("events.listen" , help = "Listen to JMAP event stream" )
688696 add_connection_opts (ev )
697+ ev .set_defaults (json = "jsonl" )
689698 ev .add_argument ("--since" , help = "lastEventId" )
690699 ev .add_argument ("--max-events" , type = int , help = "Max events before exit" )
691700 ev .add_argument ("--types" , help = "Comma-separated event types (default *)" )
@@ -704,6 +713,29 @@ def main(argv: Optional[List[str]] = None) -> int:
704713 parser = build_parser ()
705714 args = parser .parse_args (argv )
706715
716+ # Enforce json mode compatibility before doing any work
717+ streaming_commands = {"events.listen" }
718+ if args .command in streaming_commands and args .json != "jsonl" :
719+ err = envelope (
720+ False ,
721+ args .command ,
722+ vars (args ),
723+ meta_block (getattr (args , "host" , "n/a" ), "unknown" , []),
724+ error = {"type" : "validationError" , "message" : "--json must be jsonl for streaming commands" , "details" : {}},
725+ )
726+ json_dump (err , "compact" )
727+ return 2
728+ if args .command not in streaming_commands and args .json == "jsonl" :
729+ err = envelope (
730+ False ,
731+ args .command ,
732+ vars (args ),
733+ meta_block (getattr (args , "host" , "unknown" ), "unknown" , []),
734+ error = {"type" : "validationError" , "message" : "jsonl is only supported for streaming commands" , "details" : {}},
735+ )
736+ json_dump (err , "compact" )
737+ return 2
738+
707739 if args .command in {"help" , "describe" }:
708740 # No auth needed for introspection
709741 args_dict = vars (args )
0 commit comments