@@ -605,8 +605,9 @@ def _maybe_print_pretty_help() -> bool:
605605 help = 'Detail level - columns to include (default: standard)'
606606 )
607607 parser .add_argument (
608- '-o' , '--output' ,
609- help = 'Output file path (default: stdout)'
608+ '-o' , '--output-dir' ,
609+ dest = 'output_dir' ,
610+ help = 'Output directory for all generated files. If specified, files are saved instead of stdout. File names are derived from --name and format flags: {name}.{format}, {name}.functions.{ext}, {name}.{format}-schema.json'
610611 )
611612 parser .add_argument (
612613 '--name' ,
@@ -643,7 +644,12 @@ def _maybe_print_pretty_help() -> bool:
643644 parser .add_argument (
644645 '--with-schema' ,
645646 action = 'store_true' ,
646- help = 'Generate JSON schema alongside output'
647+ help = 'Generate JSON schema file alongside output (uses project name for filename)'
648+ )
649+ parser .add_argument (
650+ '--stdout' ,
651+ action = 'store_true' ,
652+ help = 'Write all output to stdout instead of files (including schema and function-logic). Useful for piping.'
647653 )
648654 parser .add_argument (
649655 '--no-install' ,
@@ -853,26 +859,37 @@ def _maybe_print_pretty_help() -> bool:
853859
854860 log .separator ()
855861
856- # Get default project name from config
857- project_name = config .get_project_name ()
858-
859- # Determine default output path when using --function-logic or --with-schema without -o
860- default_output = None
861- if (args .function_logic or args .with_schema ) and not args .output :
862- # Use project name from config with appropriate extension
863- ext_map = {
864- 'markdown' : 'md' ,
865- 'compact' : 'txt' ,
866- 'json' : 'json' ,
867- 'yaml' : 'yaml' ,
868- 'hybrid' : 'yaml' ,
869- 'csv' : 'csv' ,
870- 'gherkin' : 'feature' ,
871- 'toon' : 'toon' ,
872- 'logicml' : 'logicml' ,
873- }
874- ext = ext_map .get (args .format , args .format )
875- default_output = f"{ project_name } .{ ext } "
862+ # Get project name: CLI arg > env var > default
863+ project_name = args .project_name if args .project_name else config .get_project_name ()
864+
865+ # Determine output mode:
866+ # - --stdout: all requested output to stdout (with section markers)
867+ # - -o ./dir with --function-logic or --with-schema: only generate flagged files
868+ # - -o ./dir without aux flags: generate main file only
869+ # - no -o: main to stdout (auxiliary files require explicit path)
870+ use_stdout = args .stdout
871+ output_dir = args .output_dir
872+
873+ # When using output_dir with aux flags, only generate those files (not main)
874+ has_aux_flags = args .function_logic or args .with_schema
875+ generate_main = not has_aux_flags or use_stdout
876+
877+ # Build output paths based on output_dir
878+ ext_map = {
879+ 'markdown' : 'md' ,
880+ 'compact' : 'txt' ,
881+ 'json' : 'json' ,
882+ 'yaml' : 'yaml' ,
883+ 'hybrid' : 'yaml' ,
884+ 'csv' : 'csv' ,
885+ 'gherkin' : 'feature' ,
886+ 'toon' : 'toon' ,
887+ 'logicml' : 'logicml' ,
888+ }
889+ ext = ext_map .get (args .format , args .format )
890+ main_output_path = None
891+ if output_dir and generate_main :
892+ main_output_path = os .path .join (output_dir , f"{ project_name } .{ ext } " )
876893
877894 # Generate output
878895 if args .verbose :
@@ -913,16 +930,19 @@ def _maybe_print_pretty_help() -> bool:
913930 schema = generator .generate_schema ('hybrid' )
914931 else :
915932 schema = generator .generate_schema ('compact' if compact else 'full' )
916- effective_output = args .output or default_output
917- base_name = os .path .splitext (effective_output )[0 ] if effective_output else project_name
918- schema_path = f"{ base_name } .yaml-schema.json"
919- parent_dir = os .path .dirname (schema_path )
920- if parent_dir :
921- os .makedirs (parent_dir , exist_ok = True )
922- with open (schema_path , 'w' , encoding = 'utf-8' ) as f :
923- f .write (schema )
924- if args .verbose :
925- log .success (f"Schema written to: { schema_path } " )
933+
934+ if use_stdout :
935+ # Write to stdout with section marker
936+ print (f"\n === SCHEMA ===" )
937+ print (schema )
938+ elif output_dir :
939+ # Write to file in output directory
940+ schema_path = os .path .join (output_dir , f"{ project_name } .yaml-schema.json" )
941+ os .makedirs (output_dir , exist_ok = True )
942+ with open (schema_path , 'w' , encoding = 'utf-8' ) as f :
943+ f .write (schema )
944+ if args .verbose :
945+ log .success (f"Schema written to: { schema_path } " )
926946
927947 elif args .format == 'toon' :
928948 generator = TOONGenerator ()
@@ -947,16 +967,19 @@ def _maybe_print_pretty_help() -> bool:
947967 if args .with_schema :
948968 schema_type = 'ultra_compact' if use_ultra_compact else 'standard'
949969 schema = generator .generate_schema (schema_type )
950- effective_output = args .output or default_output
951- base_name = os .path .splitext (effective_output )[0 ] if effective_output else project_name
952- schema_path = f"{ base_name } .toon-schema.json"
953- parent_dir = os .path .dirname (schema_path )
954- if parent_dir :
955- os .makedirs (parent_dir , exist_ok = True )
956- with open (schema_path , 'w' , encoding = 'utf-8' ) as f :
957- f .write (schema )
958- if args .verbose :
959- log .success (f"Schema written to: { schema_path } " )
970+
971+ if use_stdout :
972+ # Write to stdout with section marker
973+ print (f"\n === SCHEMA ===" )
974+ print (schema )
975+ elif output_dir :
976+ # Write to file in output directory
977+ schema_path = os .path .join (output_dir , f"{ project_name } .toon-schema.json" )
978+ os .makedirs (output_dir , exist_ok = True )
979+ with open (schema_path , 'w' , encoding = 'utf-8' ) as f :
980+ f .write (schema )
981+ if args .verbose :
982+ log .success (f"Schema written to: { schema_path } " )
960983
961984 elif args .format == 'logicml' :
962985 generator = LogicMLGenerator ()
@@ -970,21 +993,16 @@ def _maybe_print_pretty_help() -> bool:
970993 if args .function_logic :
971994 logic_gen = FunctionLogicGenerator ()
972995
973- # Auto-generate path if 'auto' was specified (-- function- logic without argument)
996+ # Determine path for function logic file
974997 if args .function_logic == 'auto' :
975- effective_output = args .output or default_output
976- if effective_output :
977- # Derive from output file: project.c2l.yaml -> project.functions.yaml
978- base = effective_output .rsplit ('.' , 1 )[0 ]
979- if base .endswith ('.c2l' ):
980- base = base [:- 4 ]
981- ext = effective_output .rsplit ('.' , 1 )[- 1 ] if '.' in effective_output else 'logicml'
982- logic_path = f"{ base } .functions.{ ext } "
998+ if output_dir :
999+ # Use output directory with project name
1000+ logic_ext = ext_map .get (args .format , 'logicml' )
1001+ logic_path = os .path .join (output_dir , f"{ project_name } .functions.{ logic_ext } " )
9831002 else :
984- # Default path based on format using project name from config
985- ext_map = {'json' : 'json' , 'yaml' : 'yaml' , 'toon' : 'toon' }
986- ext = ext_map .get (args .format , 'logicml' )
987- logic_path = f"{ project_name } .functions.{ ext } "
1003+ # No output dir - use project name in current directory
1004+ logic_ext = ext_map .get (args .format , 'logicml' )
1005+ logic_path = f"{ project_name } .functions.{ logic_ext } "
9881006 else :
9891007 logic_path = str (args .function_logic )
9901008
@@ -998,13 +1016,17 @@ def _maybe_print_pretty_help() -> bool:
9981016 else :
9991017 logic_out = logic_gen .generate (project , detail = args .detail )
10001018
1001- parent_dir = os .path .dirname (logic_path )
1002- if parent_dir :
1003- os .makedirs (parent_dir , exist_ok = True )
1004- with open (logic_path , 'w' , encoding = 'utf-8' ) as f :
1005- f .write (logic_out )
1006- if args .verbose :
1007- log .success (f"Function logic written to: { logic_path } " )
1019+ if use_stdout :
1020+ # Write to stdout with section marker
1021+ print (f"\n === FUNCTION_LOGIC ===" )
1022+ print (logic_out )
1023+ elif output_dir :
1024+ # Write to file in output directory
1025+ os .makedirs (output_dir , exist_ok = True )
1026+ with open (logic_path , 'w' , encoding = 'utf-8' ) as f :
1027+ f .write (logic_out )
1028+ if args .verbose :
1029+ log .success (f"Function logic written to: { logic_path } " )
10081030
10091031 gen_time = time .time () - gen_start
10101032
@@ -1015,25 +1037,26 @@ def _maybe_print_pretty_help() -> bool:
10151037 log .stats ("Size" , f"{ output_size :,} chars (~{ tokens_approx :,} tokens)" )
10161038 log .stats ("Lines" , output .count ('\n ' ) + 1 )
10171039
1018- # Write output
1019- if args .output :
1020- parent_dir = os .path .dirname (args .output )
1021- if parent_dir :
1022- os .makedirs (parent_dir , exist_ok = True )
1023- with open (args .output , 'w' , encoding = 'utf-8' ) as f :
1024- f .write (output )
1025- if args .verbose :
1026- log .success (f"Output written to: { args .output } " )
1027- else :
1028- if not args .quiet :
1029- try :
1030- print (output , flush = True )
1031- except BrokenPipeError :
1040+ # Write main output (only if generate_main is True)
1041+ if generate_main :
1042+ if output_dir :
1043+ # Write to file in output directory
1044+ os .makedirs (output_dir , exist_ok = True )
1045+ with open (main_output_path , 'w' , encoding = 'utf-8' ) as f :
1046+ f .write (output )
1047+ if args .verbose :
1048+ log .success (f"Output written to: { main_output_path } " )
1049+ else :
1050+ # Write to stdout
1051+ if not args .quiet :
10321052 try :
1033- sys .stdout .close ()
1034- except Exception :
1035- pass
1036- os ._exit (0 )
1053+ print (output , flush = True )
1054+ except BrokenPipeError :
1055+ try :
1056+ sys .stdout .close ()
1057+ except Exception :
1058+ pass
1059+ os ._exit (0 )
10371060
10381061 # Final summary
10391062 if args .verbose :
0 commit comments