66# ]
77# ///
88
9- """Create structured notes.
10-
11- Usage:
12- uv run note --title "My Note" [--slug my-note] [--tags "tag1,tag2"] < content.txt
13- uv run note --title "My Note" --save < content.txt
14- """
159import re
1610import sys
1711from datetime import datetime
1812from pathlib import Path
13+ from typing import Optional
1914
2015import typer
2116import yaml
2217
23- app = typer .Typer (help = "Create structured notes" )
2418NOTES_DIR = Path (".knowledge/notes" )
2519
20+ USAGE = """Create structured notes from stdin content.
21+
22+ USAGE:
23+ uv run note --title "My Note" [--slug my-note] [--tags "tag1,tag2"] < content.txt
24+ uv run note --title "My Note" --save < content.txt
25+ echo "Content..." | uv run note --title "Title" --tags "tag1"
26+
27+ OPTIONS:
28+ --title, -t TEXT Note title (required)
29+ --slug, -s TEXT URL slug (auto-generated from title if not provided)
30+ --tags TEXT Comma-separated tags (optional)
31+ --save Save to file (prints to stdout regardless)
32+
33+ OUTPUT:
34+ Always prints formatted note with YAML frontmatter to stdout.
35+ With --save, also writes to .knowledge/notes/<slug>.md
36+
37+ EXAMPLES:
38+ # Preview a note
39+ echo "Auth thoughts..." | uv run note --title "Auth Design" --tags "auth,design"
40+
41+ # Save a note
42+ echo "Auth thoughts..." | uv run note --title "Auth Design" --save
43+
44+ # Custom slug
45+ echo "Content..." | uv run note --title "Auth Design" --slug auth-2024
46+ """
47+
48+
49+ def show_usage ():
50+ print (USAGE , file = sys .stderr )
51+ raise typer .Exit (1 )
52+
2653
2754def slugify (title : str ) -> str :
2855 """Convert title to URL-safe slug."""
@@ -42,19 +69,23 @@ def format_note(title: str, slug: str, tags: list[str], content: str) -> str:
4269
4370 yaml_header = yaml .dump (frontmatter , sort_keys = False , allow_unicode = True , default_flow_style = False )
4471
45- lines = ["---" , yaml_header .rstrip (), "---" , "" , f"# { title } " , "" , content ]
72+ return " \n " . join ( ["---" , yaml_header .rstrip (), "---" , "" , f"# { title } " , "" , content ])
4673
47- return "\n " .join (lines )
4874
49-
50- @app .command ()
5175def main (
52- title : str = typer .Option (... , "--title" , "-t" , help = "Note title" ),
53- slug : str | None = typer .Option (None , "--slug" , "-s" , help = "URL slug (auto-generated from title if not provided)" ),
76+ title : Optional [ str ] = typer .Option (None , "--title" , "-t" , help = "Note title" ),
77+ slug : Optional [ str ] = typer .Option (None , "--slug" , "-s" , help = "URL slug (auto-generated from title if not provided)" ),
5478 tags : str = typer .Option ("" , "--tags" , help = "Comma-separated tags" ),
5579 save : bool = typer .Option (False , "--save" , help = "Save to file (prints to stdout regardless)" ),
5680):
5781 """Create a structured note from stdin content."""
82+ # Show usage if no title provided
83+ if title is None :
84+ show_usage ()
85+
86+ # After show_usage() check, title is guaranteed to be str
87+ title_str : str = title
88+
5889 # Read content from stdin
5990 content = sys .stdin .read ().strip ()
6091
@@ -89,4 +120,4 @@ def main(
89120
90121
91122if __name__ == "__main__" :
92- app ( )
123+ typer . run ( main )
0 commit comments