1414from .chunker import chunk_directory
1515from .embeddings import generate_sync_sql , get_openai_api_key
1616from .installer import check_tools , install_docs_module
17+ from .pdf_exporter import export_markdown_to_pdf
1718from .server import generate_mkdocs_config , validate_docs_directory , write_mkdocs_config
1819
1920console = Console ()
@@ -436,6 +437,65 @@ def on_status(message: str) -> None:
436437 raise typer .Exit (1 )
437438
438439
440+ @app .command ("export-pdf" )
441+ def export_pdf (
442+ markdown_file : str = typer .Argument (
443+ ...,
444+ help = "Path to the markdown file to export." ,
445+ ),
446+ output : Optional [str ] = typer .Option (
447+ None ,
448+ "--output" ,
449+ "-o" ,
450+ help = "Output PDF path (default: docs/exports/{name}.pdf)." ,
451+ ),
452+ ) -> None :
453+ """Export markdown documentation to PDF.
454+
455+ Converts a markdown file to a styled PDF with auto-generated
456+ table of contents. Uses Chrome/Chromium for rendering.
457+
458+ Examples:
459+ aidocs export-pdf docs/projects/index.md
460+ aidocs export-pdf docs/flows/sync-users.md -o manual.pdf
461+ """
462+ md_path = Path (markdown_file )
463+ out_path = Path (output ) if output else None
464+
465+ console .print (f"[blue]Exporting { markdown_file } to PDF...[/blue]" )
466+ console .print ()
467+
468+ def on_status (msg : str ) -> None :
469+ console .print (f" [dim]{ msg } [/dim]" )
470+
471+ try :
472+ result = export_markdown_to_pdf (md_path , out_path , on_status = on_status )
473+
474+ if not result ["success" ]:
475+ console .print (f"[red]Error: { result .get ('error' , 'Unknown error' )} [/red]" )
476+ raise typer .Exit (1 )
477+
478+ stats = result ["stats" ]
479+ console .print ()
480+ console .print (Panel .fit (
481+ f"[green]PDF exported successfully![/green]\n \n "
482+ f"[bold]Title:[/bold] { stats ['title' ]} \n "
483+ f"[bold]TOC entries:[/bold] { stats ['toc_entries' ]} \n "
484+ f"[bold]Size:[/bold] { stats ['size_kb' ]} KB\n \n "
485+ f"[bold]Output:[/bold] { result ['output_path' ]} \n \n "
486+ f"[dim]Open with:[/dim]\n "
487+ f" [cyan]open { result ['output_path' ]} [/cyan]" ,
488+ title = "Success" ,
489+ border_style = "green" ,
490+ ))
491+
492+ except typer .Exit :
493+ raise
494+ except Exception as e :
495+ console .print (f"[red]Error: { e } [/red]" )
496+ raise typer .Exit (1 )
497+
498+
439499@app .command ()
440500def serve (
441501 docs_dir : Optional [str ] = typer .Argument (
@@ -512,7 +572,7 @@ def serve(
512572
513573 try :
514574 result = subprocess .run (
515- ["mkdocs" , "build" , "-f" , str (config_path )],
575+ [sys . executable , "-m" , "mkdocs" , "build" , "-f" , str (config_path )],
516576 capture_output = True ,
517577 text = True ,
518578 )
@@ -533,7 +593,7 @@ def serve(
533593 raise typer .Exit (1 )
534594
535595 except FileNotFoundError :
536- console .print ("[red]Error: mkdocs not found. Install with: pip install mkdocs mkdocs-material [/red]" )
596+ console .print ("[red]Error: Failed to run mkdocs. Try reinstalling aidocs. [/red]" )
537597 raise typer .Exit (1 )
538598 else :
539599 url = f"http://{ host } :{ port } "
@@ -549,9 +609,10 @@ def serve(
549609
550610 try :
551611 cmd = [
552- "mkdocs" , "serve" ,
612+ sys . executable , "-m" , "mkdocs" , "serve" ,
553613 "-f" , str (config_path ),
554614 "-a" , f"{ host } :{ port } " ,
615+ "--watch" , str (target_dir ),
555616 ]
556617
557618 if open_browser :
@@ -564,7 +625,7 @@ def open_after_delay() -> None:
564625 subprocess .run (cmd )
565626
566627 except FileNotFoundError :
567- console .print ("[red]Error: mkdocs not found. Install with: pip install mkdocs mkdocs-material [/red]" )
628+ console .print ("[red]Error: Failed to run mkdocs. Try reinstalling aidocs. [/red]" )
568629 raise typer .Exit (1 )
569630 except KeyboardInterrupt :
570631 console .print ("\n [yellow]Server stopped.[/yellow]" )
0 commit comments