cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists ๐Ÿƒ
charm leaflet readability golang

feat: docgen

+2256 -14
+3
README.md
··· 61 61 62 62 # Add a book to your reading list 63 63 noteleaf media book add "The Name of the Wind" 64 + 65 + # Generate docs 66 + noteleaf docgen --format docusaurus --out ./website/docs/manual 64 67 ``` 65 68 66 69 ## Status
+114
ROADMAP.md
··· 228 228 - [ ] Encryption support 229 229 - [ ] Advanced classification 230 230 231 + ### Local API Server 232 + 233 + A local HTTP server daemon that exposes Noteleaf data for web UIs and extensions. Runs on the user's machine and provides programmatic access to tasks, notes, and media. 234 + 235 + #### Architecture 236 + 237 + - [ ] Daemon mode via `noteleaf server start/stop/status` 238 + - [ ] Binds to localhost by default (configurable port) 239 + - [ ] HTTP/REST API using existing repository layer 240 + - [ ] Shares same SQLite database as CLI 241 + - [ ] Middleware: logging, CORS (for localhost web UIs), compression 242 + - [ ] Health and status endpoints 243 + 244 + #### Daemon Management 245 + 246 + - [ ] Commands: `start`, `stop`, `restart`, `status` 247 + - [ ] PID file tracking for process management 248 + - [ ] Systemd service file for Linux 249 + - [ ] launchd plist for macOS 250 + - [ ] Graceful shutdown with active request draining 251 + - [ ] Auto-restart on crash option 252 + - [ ] Configurable bind address and port 253 + - [ ] Log file rotation 254 + 255 + #### API Endpoints 256 + 257 + RESTful design matching CLI command structure: 258 + 259 + - [ ] `GET /api/v1/tasks` - List tasks with filters 260 + - [ ] `POST /api/v1/tasks` - Create task 261 + - [ ] `GET /api/v1/tasks/:id` - Get task details 262 + - [ ] `PUT /api/v1/tasks/:id` - Update task 263 + - [ ] `DELETE /api/v1/tasks/:id` - Delete task 264 + - [ ] `POST /api/v1/tasks/:id/start` - Start time tracking 265 + - [ ] `POST /api/v1/tasks/:id/stop` - Stop time tracking 266 + - [ ] `GET /api/v1/tasks/:id/time-entries` - Get time entries 267 + - [ ] Similar CRUD endpoints for notes, books, movies, TV shows, articles 268 + - [ ] `GET /api/v1/projects` - List all projects 269 + - [ ] `GET /api/v1/tags` - List all tags 270 + - [ ] `GET /api/v1/contexts` - List all contexts 271 + - [ ] `GET /api/v1/stats` - Dashboard statistics 272 + 273 + #### Real-time Updates 274 + 275 + - [ ] WebSocket endpoint for live data updates 276 + - [ ] Server-Sent Events (SSE) as fallback 277 + - [ ] Event types: task created/updated/deleted, note modified, etc. 278 + - [ ] Subscribe to specific domains or IDs 279 + - [ ] Change notification for web UI reactivity 280 + 281 + #### Authentication & Security 282 + 283 + - [ ] Optional API token authentication (disabled by default for localhost) 284 + - [ ] Token stored in config file 285 + - [ ] Token rotation command 286 + - [ ] CORS configuration for allowed origins 287 + - [ ] Localhost-only binding by default (security through network isolation) 288 + - [ ] Optional TLS for local network access 289 + 290 + #### Extension System 291 + 292 + - [ ] Webhook endpoints for extension registration 293 + - [ ] Event hooks for task/note lifecycle: 294 + - [ ] Before/after create, update, delete 295 + - [ ] Task completion, start, stop 296 + - [ ] Note archive/unarchive 297 + - [ ] Webhook delivery with retries 298 + - [ ] Extension manifest for discovery 299 + - [ ] JavaScript plugin API (embedded V8/goja runtime) 300 + - [ ] Plugin sandbox for security 301 + 302 + #### Web UI 303 + 304 + - [ ] Reference web UI implementation 305 + - [ ] Static file serving from embedded assets 306 + - [ ] Single-page application architecture 307 + - [ ] Responsive design (desktop, tablet, mobile) 308 + - [ ] Features: 309 + - [ ] Task board view (Kanban) 310 + - [ ] Calendar view for tasks 311 + - [ ] Note editor with Markdown preview 312 + - [ ] Media queue management 313 + - [ ] Search and filtering 314 + - [ ] Keyboard shortcuts matching CLI 315 + 316 + #### Configuration 317 + 318 + - [ ] Server config section in noteleaf.toml: 319 + - [ ] bind_address (default: 127.0.0.1) 320 + - [ ] port (default: 8080) 321 + - [ ] enable_auth (default: false) 322 + - [ ] api_token (optional) 323 + - [ ] enable_websocket (default: true) 324 + - [ ] log_level (default: info) 325 + - [ ] Environment variable overrides 326 + - [ ] CLI flag overrides for daemon commands 327 + 328 + #### Monitoring & Diagnostics 329 + 330 + - [ ] `GET /health` - Health check endpoint 331 + - [ ] `GET /metrics` - Prometheus-compatible metrics 332 + - [ ] Request logging (access log) 333 + - [ ] Error logging with stack traces 334 + - [ ] Performance metrics (request duration, DB query time) 335 + - [ ] Active connections and goroutine count 336 + - [ ] Memory and CPU usage stats 337 + 338 + #### Client Libraries 339 + 340 + - [ ] Go client library for extensions 341 + - [ ] JavaScript/TypeScript client for web UIs 342 + - [ ] OpenAPI/Swagger specification 343 + - [ ] Auto-generated API documentation 344 + 231 345 ## Technical Infrastructure 232 346 233 347 ### Completed
+110 -5
cmd/commands.go
··· 34 34 } 35 35 36 36 func (c *MovieCommand) Create() *cobra.Command { 37 - root := &cobra.Command{Use: "movie", Short: "Manage movie watch queue"} 37 + root := &cobra.Command{ 38 + Use: "movie", 39 + Short: "Manage movie watch queue", 40 + Long: `Track movies you want to watch. 41 + 42 + Search TMDB for movies and add them to your queue. Mark movies as watched when 43 + completed. Maintains a history of your movie watching activity.`, 44 + } 38 45 39 46 addCmd := &cobra.Command{ 40 47 Use: "add [search query...]", ··· 59 66 root.AddCommand(&cobra.Command{ 60 67 Use: "list [--all|--watched|--queued]", 61 68 Short: "List movies in queue with status filtering", 69 + Long: `Display movies in your queue with optional status filters. 70 + 71 + Shows movie titles, release years, and current status. Filter by --all to show 72 + everything, --watched for completed movies, or --queued for unwatched items. 73 + Default shows queued movies only.`, 62 74 RunE: func(cmd *cobra.Command, args []string) error { 63 75 var status string 64 76 if len(args) > 0 { ··· 82 94 Use: "watched [id]", 83 95 Short: "Mark movie as watched", 84 96 Aliases: []string{"seen"}, 97 + Long: "Mark a movie as watched with current timestamp. Moves the movie from queued to watched status.", 85 98 Args: cobra.ExactArgs(1), 86 99 RunE: func(cmd *cobra.Command, args []string) error { 87 100 return c.handler.MarkWatched(cmd.Context(), args[0]) ··· 92 105 Use: "remove [id]", 93 106 Short: "Remove movie from queue", 94 107 Aliases: []string{"rm"}, 108 + Long: "Remove a movie from your watch queue. Use this for movies you no longer want to track.", 95 109 Args: cobra.ExactArgs(1), 96 110 RunE: func(cmd *cobra.Command, args []string) error { 97 111 return c.handler.Remove(cmd.Context(), args[0]) ··· 112 126 } 113 127 114 128 func (c *TVCommand) Create() *cobra.Command { 115 - root := &cobra.Command{Use: "tv", Short: "Manage TV show watch queue"} 129 + root := &cobra.Command{ 130 + Use: "tv", 131 + Short: "Manage TV show watch queue", 132 + Long: `Track TV shows and episodes. 133 + 134 + Search TMDB for TV shows and add them to your queue. Track which shows you're 135 + currently watching, mark episodes as watched, and maintain a complete history 136 + of your viewing activity.`, 137 + } 116 138 117 139 addCmd := &cobra.Command{ 118 140 Use: "add [search query...]", ··· 137 159 root.AddCommand(&cobra.Command{ 138 160 Use: "list [--all|--queued|--watching|--watched]", 139 161 Short: "List TV shows in queue with status filtering", 162 + Long: `Display TV shows in your queue with optional status filters. 163 + 164 + Shows show titles, air dates, and current status. Filter by --all, --queued, 165 + --watching for shows in progress, or --watched for completed series. Default 166 + shows queued shows only.`, 140 167 RunE: func(cmd *cobra.Command, args []string) error { 141 168 var status string 142 169 if len(args) > 0 { ··· 161 188 root.AddCommand(&cobra.Command{ 162 189 Use: "watching [id]", 163 190 Short: "Mark TV show as currently watching", 191 + Long: "Mark a TV show as currently watching. Use this when you start watching a series.", 164 192 Args: cobra.ExactArgs(1), 165 193 RunE: func(cmd *cobra.Command, args []string) error { 166 194 return c.handler.MarkTVShowWatching(cmd.Context(), args[0]) ··· 171 199 Use: "watched [id]", 172 200 Short: "Mark TV show/episodes as watched", 173 201 Aliases: []string{"seen"}, 202 + Long: `Mark TV show episodes or entire series as watched. 203 + 204 + Updates episode tracking and completion status. Can mark individual episodes 205 + or complete seasons/series depending on ID format.`, 174 206 Args: cobra.ExactArgs(1), 175 207 RunE: func(cmd *cobra.Command, args []string) error { 176 208 return c.handler.MarkWatched(cmd.Context(), args[0]) ··· 181 213 Use: "remove [id]", 182 214 Short: "Remove TV show from queue", 183 215 Aliases: []string{"rm"}, 216 + Long: "Remove a TV show from your watch queue. Use this for shows you no longer want to track.", 184 217 Args: cobra.ExactArgs(1), 185 218 RunE: func(cmd *cobra.Command, args []string) error { 186 219 return c.handler.Remove(cmd.Context(), args[0]) ··· 201 234 } 202 235 203 236 func (c *BookCommand) Create() *cobra.Command { 204 - root := &cobra.Command{Use: "book", Short: "Manage reading list"} 237 + root := &cobra.Command{ 238 + Use: "book", 239 + Short: "Manage reading list", 240 + Long: `Track books and reading progress. 241 + 242 + Search Google Books API to add books to your reading list. Track which books 243 + you're reading, update progress percentages, and maintain a history of finished 244 + books.`, 245 + } 205 246 206 247 addCmd := &cobra.Command{ 207 248 Use: "add [search query...]", ··· 222 263 root.AddCommand(&cobra.Command{ 223 264 Use: "list [--all|--reading|--finished|--queued]", 224 265 Short: "Show reading queue with progress", 266 + Long: `Display books in your reading list with progress indicators. 267 + 268 + Shows book titles, authors, and reading progress percentages. Filter by --all, 269 + --reading for books in progress, --finished for completed books, or --queued 270 + for books not yet started. Default shows queued books only.`, 225 271 RunE: func(cmd *cobra.Command, args []string) error { 226 272 var status string 227 273 if len(args) > 0 { ··· 245 291 root.AddCommand(&cobra.Command{ 246 292 Use: "reading <id>", 247 293 Short: "Mark book as currently reading", 294 + Long: "Mark a book as currently reading. Use this when you start a book from your queue.", 248 295 Args: cobra.ExactArgs(1), 249 296 RunE: func(cmd *cobra.Command, args []string) error { 250 297 return c.handler.UpdateStatus(cmd.Context(), args[0], "reading") ··· 255 302 Use: "finished <id>", 256 303 Short: "Mark book as completed", 257 304 Aliases: []string{"read"}, 305 + Long: "Mark a book as finished with current timestamp. Sets reading progress to 100%.", 258 306 Args: cobra.ExactArgs(1), 259 307 RunE: func(cmd *cobra.Command, args []string) error { 260 308 return c.handler.UpdateStatus(cmd.Context(), args[0], "finished") ··· 265 313 Use: "remove <id>", 266 314 Short: "Remove from reading list", 267 315 Aliases: []string{"rm"}, 316 + Long: "Remove a book from your reading list. Use this for books you no longer want to track.", 268 317 Args: cobra.ExactArgs(1), 269 318 RunE: func(cmd *cobra.Command, args []string) error { 270 319 return c.handler.UpdateStatus(cmd.Context(), args[0], "removed") ··· 274 323 root.AddCommand(&cobra.Command{ 275 324 Use: "progress <id> <percentage>", 276 325 Short: "Update reading progress percentage (0-100)", 326 + Long: `Set reading progress for a book. 327 + 328 + Specify a percentage value between 0 and 100 to indicate how far you've 329 + progressed through the book. Automatically updates status to 'reading' if not 330 + already set.`, 277 331 Args: cobra.ExactArgs(2), 278 332 RunE: func(cmd *cobra.Command, args []string) error { 279 333 progress, err := strconv.Atoi(args[1]) ··· 287 341 root.AddCommand(&cobra.Command{ 288 342 Use: "update <id> <status>", 289 343 Short: "Update book status (queued|reading|finished|removed)", 344 + Long: `Change a book's status directly. 345 + 346 + Valid statuses are: queued (not started), reading (in progress), finished 347 + (completed), or removed (no longer tracking).`, 290 348 Args: cobra.ExactArgs(2), 291 349 RunE: func(cmd *cobra.Command, args []string) error { 292 350 return c.handler.UpdateStatus(cmd.Context(), args[0], args[1]) ··· 307 365 } 308 366 309 367 func (c *NoteCommand) Create() *cobra.Command { 310 - root := &cobra.Command{Use: "note", Short: "Manage notes"} 368 + root := &cobra.Command{ 369 + Use: "note", 370 + Short: "Manage notes", 371 + Long: `Create and organize markdown notes with tags. 372 + 373 + Write notes in markdown format, organize them with tags, browse them in an 374 + interactive TUI, and edit them in your preferred editor. Notes are stored as 375 + files on disk with metadata tracked in the database.`, 376 + } 311 377 312 378 createCmd := &cobra.Command{ 313 379 Use: "create [title] [content...]", 314 380 Short: "Create a new note", 315 381 Aliases: []string{"new"}, 382 + Long: `Create a new markdown note. 383 + 384 + Provide a title and optional content inline, or use --interactive to open an 385 + editor. Use --file to import content from an existing markdown file. Notes 386 + support tags for organization and full-text search. 387 + 388 + Examples: 389 + noteleaf note create "Meeting notes" "Discussed project timeline" 390 + noteleaf note create -i 391 + noteleaf note create --file ~/documents/draft.md`, 316 392 RunE: func(cmd *cobra.Command, args []string) error { 317 393 interactive, _ := cmd.Flags().GetBool("interactive") 318 394 editor, _ := cmd.Flags().GetBool("editor") ··· 365 441 Use: "read [note-id]", 366 442 Short: "Display formatted note content with syntax highlighting", 367 443 Aliases: []string{"view"}, 444 + Long: `Display note content with formatted markdown rendering. 445 + 446 + Shows the note with syntax highlighting, proper formatting, and metadata. 447 + Useful for quick viewing without opening an editor.`, 368 448 Args: cobra.ExactArgs(1), 369 449 RunE: func(cmd *cobra.Command, args []string) error { 370 450 if noteID, err := parseID("note", args); err != nil { ··· 379 459 root.AddCommand(&cobra.Command{ 380 460 Use: "edit [note-id]", 381 461 Short: "Edit note in configured editor", 462 + Long: `Open note in your configured text editor. 463 + 464 + Uses the editor specified in your noteleaf configuration or the EDITOR 465 + environment variable. Changes are automatically saved when you close the 466 + editor.`, 382 467 Args: cobra.ExactArgs(1), 383 468 RunE: func(cmd *cobra.Command, args []string) error { 384 469 if noteID, err := parseID("note", args); err != nil { ··· 394 479 Use: "remove [note-id]", 395 480 Short: "Permanently removes the note file and metadata", 396 481 Aliases: []string{"rm", "delete", "del"}, 482 + Long: `Delete a note permanently. 483 + 484 + Removes both the markdown file and database metadata. This operation cannot be 485 + undone. You will be prompted for confirmation before deletion.`, 397 486 Args: cobra.ExactArgs(1), 398 487 RunE: func(cmd *cobra.Command, args []string) error { 399 488 if noteID, err := parseID("note", args); err != nil { ··· 419 508 } 420 509 421 510 func (c *ArticleCommand) Create() *cobra.Command { 422 - root := &cobra.Command{Use: "article", Short: "Manage saved articles"} 511 + root := &cobra.Command{ 512 + Use: "article", 513 + Short: "Manage saved articles", 514 + Long: `Save and archive web articles locally. 515 + 516 + Parse articles from supported websites, extract clean content, and save as 517 + both markdown and HTML. Maintains a searchable archive of articles with 518 + metadata including author, title, and publication date.`, 519 + } 423 520 424 521 addCmd := &cobra.Command{ 425 522 Use: "add <url>", ··· 465 562 Use: "view <id>", 466 563 Short: "View article details and content preview", 467 564 Aliases: []string{"show"}, 565 + Long: `Display article metadata and summary. 566 + 567 + Shows article title, author, publication date, URL, and a brief content 568 + preview. Use 'read' command to view the full article content.`, 468 569 Args: cobra.ExactArgs(1), 469 570 RunE: func(cmd *cobra.Command, args []string) error { 470 571 if articleID, err := parseID("article", args); err != nil { ··· 499 600 Use: "remove <id>", 500 601 Short: "Remove article and associated files", 501 602 Aliases: []string{"rm", "delete"}, 603 + Long: `Delete an article and its files permanently. 604 + 605 + Removes the article metadata from the database and deletes associated markdown 606 + and HTML files. This operation cannot be undone.`, 502 607 Args: cobra.ExactArgs(1), 503 608 RunE: func(cmd *cobra.Command, args []string) error { 504 609 if articleID, err := parseID("article", args); err != nil {
+36 -2
cmd/main.go
··· 13 13 "github.com/stormlightlabs/noteleaf/internal/store" 14 14 "github.com/stormlightlabs/noteleaf/internal/ui" 15 15 "github.com/stormlightlabs/noteleaf/internal/utils" 16 + "github.com/stormlightlabs/noteleaf/tools" 16 17 ) 17 18 18 19 var ( ··· 58 59 return &cobra.Command{ 59 60 Use: "status", 60 61 Short: "Show application status and configuration", 62 + Long: `Display comprehensive application status information. 63 + 64 + Shows database location, configuration file path, data directories, and current 65 + settings. Use this command to verify your noteleaf installation and diagnose 66 + configuration issues.`, 61 67 RunE: func(cmd *cobra.Command, args []string) error { 62 68 return handlers.Status(cmd.Context(), args, cmd.OutOrStdout()) 63 69 }, ··· 68 74 return &cobra.Command{ 69 75 Use: "reset", 70 76 Short: "Reset the application (removes all data)", 77 + Long: `Remove all application data and return to initial state. 78 + 79 + This command deletes the database, all media files, notes, and articles. The 80 + configuration file is preserved. Use with caution as this operation cannot be 81 + undone. You will be prompted for confirmation before deletion proceeds.`, 71 82 RunE: func(cmd *cobra.Command, args []string) error { 72 83 return handlers.Reset(cmd.Context(), args) 73 84 }, ··· 77 88 func rootCmd() *cobra.Command { 78 89 root := &cobra.Command{ 79 90 Use: "noteleaf", 80 - Long: ui.Georgia.ColoredInViewport(), 81 91 Short: "A TaskWarrior-inspired CLI with notes, media queues and reading lists", 92 + Long: `noteleaf - personal information manager for the command line 93 + 94 + A comprehensive CLI tool for managing tasks, notes, articles, and media queues. 95 + Inspired by TaskWarrior, noteleaf combines todo management with reading lists, 96 + watch queues, and a personal knowledge base. 97 + 98 + Core features include hierarchical tasks with dependencies, recurring tasks, 99 + time tracking, markdown notes with tags, article archiving, and media queue 100 + management for books, movies, and TV shows.`, 82 101 RunE: func(c *cobra.Command, args []string) error { 83 102 if len(args) == 0 { 84 103 return c.Help() ··· 107 126 root := &cobra.Command{ 108 127 Use: "setup", 109 128 Short: "Initialize and manage application setup", 129 + Long: `Initialize noteleaf for first use. 130 + 131 + Creates the database, configuration file, and required data directories. Run 132 + this command after installing noteleaf or when setting up a new environment. 133 + Safe to run multiple times as it will skip existing resources.`, 110 134 RunE: func(c *cobra.Command, args []string) error { 111 135 return handlers.Setup(c.Context(), args) 112 136 }, ··· 194 218 root.AddCommand(cmd) 195 219 } 196 220 197 - mediaCmd := &cobra.Command{Use: "media", Short: "Manage media queues (books, movies, TV shows)"} 221 + mediaCmd := &cobra.Command{ 222 + Use: "media", 223 + Short: "Manage media queues (books, movies, TV shows)", 224 + Long: `Track and manage reading lists and watch queues. 225 + 226 + Organize books, movies, and TV shows you want to consume. Search external 227 + databases to add items, track reading/watching progress, and maintain a 228 + history of completed media.`, 229 + } 198 230 mediaCmd.GroupID = "core" 199 231 mediaCmd.AddCommand(NewMovieCommand(movieHandler).Create()) 200 232 mediaCmd.AddCommand(NewTVCommand(tvHandler).Create()) ··· 207 239 cmd.GroupID = "management" 208 240 root.AddCommand(cmd) 209 241 } 242 + 243 + root.AddCommand(tools.NewDocGenCommand(root)) 210 244 211 245 opts := []fang.Option{ 212 246 fang.WithVersion("0.1.0"),
+100 -1
cmd/task_commands.go
··· 18 18 } 19 19 20 20 func (c *TaskCommand) Create() *cobra.Command { 21 - root := &cobra.Command{Use: "todo", Aliases: []string{"task"}, Short: "task management"} 21 + root := &cobra.Command{ 22 + Use: "todo", 23 + Aliases: []string{"task"}, 24 + Short: "task management", 25 + Long: `Manage tasks with TaskWarrior-inspired features. 26 + 27 + Track todos with priorities, projects, contexts, and tags. Supports hierarchical 28 + tasks with parent/child relationships, task dependencies, recurring tasks, and 29 + time tracking. Tasks can be filtered by status, priority, project, or context.`, 30 + } 22 31 23 32 for _, init := range []func(*handlers.TaskHandler) *cobra.Command{ 24 33 addTaskCmd, listTaskCmd, viewTaskCmd, updateTaskCmd, editTaskCmd, ··· 38 47 Use: "add [description]", 39 48 Short: "Add a new task", 40 49 Aliases: []string{"create", "new"}, 50 + Long: `Create a new task with description and optional attributes. 51 + 52 + Tasks can be created with priority levels (low, medium, high, urgent), assigned 53 + to projects and contexts, tagged for organization, and configured with due dates 54 + and recurrence rules. Dependencies can be established to ensure tasks are 55 + completed in order. 56 + 57 + Examples: 58 + noteleaf todo add "Write documentation" --priority high --project docs 59 + noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15`, 41 60 Args: cobra.MinimumNArgs(1), 42 61 RunE: func(c *cobra.Command, args []string) error { 43 62 description := strings.Join(args, " ") ··· 101 120 viewCmd := &cobra.Command{ 102 121 Use: "view [task-id]", 103 122 Short: "View task by ID", 123 + Long: `Display detailed information for a specific task. 124 + 125 + Shows all task attributes including description, status, priority, project, 126 + context, tags, due date, creation time, and modification history. Use --json 127 + for machine-readable output or --no-metadata to show only the description.`, 104 128 Args: cobra.ExactArgs(1), 105 129 RunE: func(cmd *cobra.Command, args []string) error { 106 130 format, _ := cmd.Flags().GetString("format") ··· 120 144 updateCmd := &cobra.Command{ 121 145 Use: "update [task-id]", 122 146 Short: "Update task properties", 147 + Long: `Modify attributes of an existing task. 148 + 149 + Update any task property including description, status, priority, project, 150 + context, due date, recurrence rule, or parent task. Add or remove tags and 151 + dependencies. Multiple attributes can be updated in a single command. 152 + 153 + Examples: 154 + noteleaf todo update 123 --priority urgent --due tomorrow 155 + noteleaf todo update 456 --add-tag urgent --project website`, 123 156 Args: cobra.ExactArgs(1), 124 157 RunE: func(cmd *cobra.Command, args []string) error { 125 158 taskID := args[0] ··· 160 193 Use: "projects", 161 194 Short: "List projects", 162 195 Aliases: []string{"proj"}, 196 + Long: `Display all projects with task counts. 197 + 198 + Shows each project used in your tasks along with the number of tasks in each 199 + project. Use --todo-txt to format output with +project syntax for compatibility 200 + with todo.txt tools.`, 163 201 RunE: func(c *cobra.Command, args []string) error { 164 202 static, _ := c.Flags().GetBool("static") 165 203 todoTxt, _ := c.Flags().GetBool("todo-txt") ··· 179 217 Use: "tags", 180 218 Short: "List tags", 181 219 Aliases: []string{"t"}, 220 + Long: `Display all tags used across tasks. 221 + 222 + Shows each tag with the number of tasks using it. Tags provide flexible 223 + categorization orthogonal to projects and contexts.`, 182 224 RunE: func(c *cobra.Command, args []string) error { 183 225 static, _ := c.Flags().GetBool("static") 184 226 defer h.Close() ··· 193 235 cmd := &cobra.Command{ 194 236 Use: "start [task-id]", 195 237 Short: "Start time tracking for a task", 238 + Long: `Begin tracking time spent on a task. 239 + 240 + Records the start time for a work session. Only one task can be actively 241 + tracked at a time. Use --note to add a description of what you're working on.`, 196 242 Args: cobra.ExactArgs(1), 197 243 RunE: func(c *cobra.Command, args []string) error { 198 244 taskID := args[0] ··· 210 256 return &cobra.Command{ 211 257 Use: "stop [task-id]", 212 258 Short: "Stop time tracking for a task", 259 + Long: `End time tracking for the active task. 260 + 261 + Records the end time and calculates duration for the current work session. 262 + Duration is added to the task's total time tracked.`, 213 263 Args: cobra.ExactArgs(1), 214 264 RunE: func(c *cobra.Command, args []string) error { 215 265 taskID := args[0] ··· 246 296 Use: "edit [task-id]", 247 297 Short: "Edit task interactively with status picker and priority toggle", 248 298 Aliases: []string{"e"}, 299 + Long: `Open interactive editor for task modification. 300 + 301 + Provides a user-friendly interface with status picker and priority toggle. 302 + Easier than using multiple command-line flags for complex updates.`, 249 303 Args: cobra.ExactArgs(1), 250 304 RunE: func(c *cobra.Command, args []string) error { 251 305 taskID := args[0] ··· 259 313 return &cobra.Command{ 260 314 Use: "delete [task-id]", 261 315 Short: "Delete a task", 316 + Long: `Permanently remove a task from the database. 317 + 318 + This operation cannot be undone. Consider updating the task status to 319 + 'deleted' instead if you want to preserve the record for historical purposes.`, 262 320 Args: cobra.ExactArgs(1), 263 321 RunE: func(c *cobra.Command, args []string) error { 264 322 defer h.Close() ··· 272 330 Use: "contexts", 273 331 Short: "List contexts (locations)", 274 332 Aliases: []string{"con", "loc", "ctx", "locations"}, 333 + Long: `Display all contexts with task counts. 334 + 335 + Contexts represent locations or environments where tasks can be completed (e.g., 336 + @home, @office, @errands). Use --todo-txt to format output with @context syntax 337 + for compatibility with todo.txt tools.`, 275 338 RunE: func(c *cobra.Command, args []string) error { 276 339 static, _ := c.Flags().GetBool("static") 277 340 todoTxt, _ := c.Flags().GetBool("todo-txt") ··· 290 353 Use: "done [task-id]", 291 354 Short: "Mark task as completed", 292 355 Aliases: []string{"complete"}, 356 + Long: `Mark a task as completed with current timestamp. 357 + 358 + Sets the task status to 'completed' and records the completion time. For 359 + recurring tasks, generates the next instance based on the recurrence rule.`, 293 360 Args: cobra.ExactArgs(1), 294 361 RunE: func(c *cobra.Command, args []string) error { 295 362 defer h.Close() ··· 303 370 Use: "recur", 304 371 Short: "Manage task recurrence", 305 372 Aliases: []string{"repeat"}, 373 + Long: `Configure recurring task patterns. 374 + 375 + Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE). 376 + Supports daily, weekly, monthly, and yearly patterns with optional end dates.`, 306 377 } 307 378 308 379 setCmd := &cobra.Command{ 309 380 Use: "set [task-id]", 310 381 Short: "Set recurrence rule for a task", 382 + Long: `Apply a recurrence rule to create repeating task instances. 383 + 384 + Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR" 385 + for specific weekdays). When a recurring task is completed, the next instance is 386 + automatically generated. 387 + 388 + Examples: 389 + noteleaf todo recur set 123 --rule "FREQ=DAILY" 390 + noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31`, 311 391 Args: cobra.ExactArgs(1), 312 392 RunE: func(c *cobra.Command, args []string) error { 313 393 rule, _ := c.Flags().GetString("rule") ··· 322 402 clearCmd := &cobra.Command{ 323 403 Use: "clear [task-id]", 324 404 Short: "Clear recurrence rule from a task", 405 + Long: `Remove recurrence from a task. 406 + 407 + Converts a recurring task to a one-time task. Existing future instances are not 408 + affected.`, 325 409 Args: cobra.ExactArgs(1), 326 410 RunE: func(c *cobra.Command, args []string) error { 327 411 defer h.Close() ··· 332 416 showCmd := &cobra.Command{ 333 417 Use: "show [task-id]", 334 418 Short: "Show recurrence details for a task", 419 + Long: `Display recurrence rule and schedule information. 420 + 421 + Shows the RRULE pattern, next occurrence date, and recurrence end date if 422 + configured.`, 335 423 Args: cobra.ExactArgs(1), 336 424 RunE: func(c *cobra.Command, args []string) error { 337 425 defer h.Close() ··· 348 436 Use: "depend", 349 437 Short: "Manage task dependencies", 350 438 Aliases: []string{"dep", "deps"}, 439 + Long: `Create and manage task dependencies. 440 + 441 + Establish relationships where one task must be completed before another can 442 + begin. Useful for multi-step workflows and project management.`, 351 443 } 352 444 353 445 addCmd := &cobra.Command{ 354 446 Use: "add [task-id] [depends-on-uuid]", 355 447 Short: "Add a dependency to a task", 448 + Long: `Make a task dependent on another task's completion. 449 + 450 + The first task cannot be started until the second task is completed. Use task 451 + UUIDs to specify dependencies.`, 356 452 Args: cobra.ExactArgs(2), 357 453 RunE: func(c *cobra.Command, args []string) error { 358 454 defer h.Close() ··· 364 460 Use: "remove [task-id] [depends-on-uuid]", 365 461 Short: "Remove a dependency from a task", 366 462 Aliases: []string{"rm"}, 463 + Long: "Delete a dependency relationship between two tasks.", 367 464 Args: cobra.ExactArgs(2), 368 465 RunE: func(c *cobra.Command, args []string) error { 369 466 defer h.Close() ··· 375 472 Use: "list [task-id]", 376 473 Short: "List dependencies for a task", 377 474 Aliases: []string{"ls"}, 475 + Long: "Show all tasks that must be completed before this task can be started.", 378 476 Args: cobra.ExactArgs(1), 379 477 RunE: func(c *cobra.Command, args []string) error { 380 478 defer h.Close() ··· 385 483 blockedByCmd := &cobra.Command{ 386 484 Use: "blocked-by [task-id]", 387 485 Short: "Show tasks blocked by this task", 486 + Long: "Display all tasks that depend on this task's completion.", 388 487 Args: cobra.ExactArgs(1), 389 488 RunE: func(c *cobra.Command, args []string) error { 390 489 defer h.Close()
+1
codecov.yml
··· 22 22 - "**/vendor/**" 23 23 - "internal/**/test_utilities.go" 24 24 - "internal/handlers/handler_test_suite.go" 25 + - "internal/tools/docgen.go"
+6
go.mod
··· 21 21 ) 22 22 23 23 require ( 24 + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect 25 + github.com/russross/blackfriday/v2 v2.1.0 // indirect 26 + gopkg.in/yaml.v3 v3.0.1 // indirect 27 + ) 28 + 29 + require ( 24 30 github.com/PuerkitoBio/goquery v1.10.3 25 31 github.com/andybalholm/cascadia v1.3.3 // indirect 26 32 github.com/antchfx/htmlquery v1.3.4
+3
go.sum
··· 55 55 github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf/go.mod h1:B3UgsnsBZS/eX42BlaNiJkD1pPOUa+oF1IYC6Yd2CEU= 56 56 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 57 57 github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 58 + github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= 58 59 github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 59 60 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 60 61 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= ··· 130 131 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 131 132 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 132 133 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 134 + github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 133 135 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 134 136 github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= 135 137 github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= ··· 242 244 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 243 245 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= 244 246 google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= 247 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 245 248 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 246 249 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 247 250 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+341
tools/docgen.go
··· 1 + package tools 2 + 3 + import ( 4 + "encoding/json" 5 + "fmt" 6 + "os" 7 + "path/filepath" 8 + "slices" 9 + "strings" 10 + 11 + "github.com/spf13/cobra" 12 + "github.com/spf13/cobra/doc" 13 + ) 14 + 15 + // NewDocGenCommand creates a hidden command for generating CLI documentation 16 + func NewDocGenCommand(root *cobra.Command) *cobra.Command { 17 + cmd := &cobra.Command{ 18 + Use: "docgen", 19 + Short: "Generate CLI documentation", 20 + Hidden: true, 21 + RunE: func(cmd *cobra.Command, args []string) error { 22 + out, _ := cmd.Flags().GetString("out") 23 + format, _ := cmd.Flags().GetString("format") 24 + front, _ := cmd.Flags().GetBool("frontmatter") 25 + 26 + if err := os.MkdirAll(out, 0o755); err != nil { 27 + return fmt.Errorf("failed to create output directory: %w", err) 28 + } 29 + 30 + root.DisableAutoGenTag = true 31 + 32 + switch format { 33 + case "docusaurus": 34 + if err := generateDocusaurusDocs(root, out); err != nil { 35 + return fmt.Errorf("failed to generate docusaurus documentation: %w", err) 36 + } 37 + case "markdown": 38 + if front { 39 + prep := func(filename string) string { 40 + base := filepath.Base(filename) 41 + name := strings.TrimSuffix(base, filepath.Ext(base)) 42 + title := strings.ReplaceAll(name, "_", " ") 43 + return fmt.Sprintf("---\ntitle: %q\nslug: %q\ndescription: \"CLI reference for %s\"\n---\n\n", title, name, title) 44 + } 45 + link := func(name string) string { return strings.ToLower(name) } 46 + if err := doc.GenMarkdownTreeCustom(root, out, prep, link); err != nil { 47 + return fmt.Errorf("failed to generate markdown documentation: %w", err) 48 + } 49 + } else { 50 + if err := doc.GenMarkdownTree(root, out); err != nil { 51 + return fmt.Errorf("failed to generate markdown documentation: %w", err) 52 + } 53 + } 54 + case "man": 55 + hdr := &doc.GenManHeader{Title: strings.ToUpper(root.Name()), Section: "1"} 56 + if err := doc.GenManTree(root, hdr, out); err != nil { 57 + return fmt.Errorf("failed to generate man pages: %w", err) 58 + } 59 + case "rest": 60 + if err := doc.GenReSTTree(root, out); err != nil { 61 + return fmt.Errorf("failed to generate ReStructuredText documentation: %w", err) 62 + } 63 + default: 64 + return fmt.Errorf("unknown format: %s", format) 65 + } 66 + 67 + fmt.Fprintf(cmd.OutOrStdout(), "Documentation generated in %s\n", out) 68 + return nil 69 + }, 70 + } 71 + 72 + cmd.Flags().StringP("out", "o", "./docs/cli", "output directory") 73 + cmd.Flags().StringP("format", "f", "markdown", "output format (docusaurus|markdown|man|rest)") 74 + cmd.Flags().Bool("frontmatter", false, "prepend simple YAML front matter to markdown") 75 + 76 + return cmd 77 + } 78 + 79 + // CategoryJSON represents the _category_.json structure for Docusaurus 80 + type CategoryJSON struct { 81 + Label string `json:"label"` 82 + Position int `json:"position"` 83 + Link *Link `json:"link,omitempty"` 84 + Collapsed bool `json:"collapsed,omitempty"` 85 + Description string `json:"description,omitempty"` 86 + } 87 + 88 + // Link represents a link in _category_.json 89 + type Link struct { 90 + Type string `json:"type"` 91 + Description string `json:"description,omitempty"` 92 + } 93 + 94 + // generateDocusaurusDocs creates combined, Docusaurus-compatible documentation 95 + func generateDocusaurusDocs(root *cobra.Command, outDir string) error { 96 + if err := os.MkdirAll(outDir, 0o755); err != nil { 97 + return fmt.Errorf("failed to create output directory: %w", err) 98 + } 99 + 100 + category := CategoryJSON{ 101 + Label: "CLI Reference", 102 + Position: 3, 103 + Link: &Link{ 104 + Type: "generated-index", 105 + Description: "Complete command-line reference for noteleaf", 106 + }, 107 + } 108 + categoryJSON, err := json.MarshalIndent(category, "", " ") 109 + if err != nil { 110 + return fmt.Errorf("failed to marshal category json: %w", err) 111 + } 112 + if err := os.WriteFile(filepath.Join(outDir, "_category_.json"), categoryJSON, 0o644); err != nil { 113 + return fmt.Errorf("failed to write category json: %w", err) 114 + } 115 + 116 + indexContent := generateIndexPage(root) 117 + if err := os.WriteFile(filepath.Join(outDir, "index.md"), []byte(indexContent), 0o644); err != nil { 118 + return fmt.Errorf("failed to write index.md: %w", err) 119 + } 120 + 121 + commandGroups := map[string]struct { 122 + title string 123 + position int 124 + commands []string 125 + description string 126 + }{ 127 + "tasks": { 128 + title: "Task Management", 129 + position: 1, 130 + commands: []string{"todo", "task"}, 131 + description: "Manage tasks with TaskWarrior-inspired features", 132 + }, 133 + "notes": { 134 + title: "Notes", 135 + position: 2, 136 + commands: []string{"note"}, 137 + description: "Create and organize markdown notes", 138 + }, 139 + "articles": { 140 + title: "Articles", 141 + position: 3, 142 + commands: []string{"article"}, 143 + description: "Save and archive web articles", 144 + }, 145 + "books": { 146 + title: "Books", 147 + position: 4, 148 + commands: []string{"media book"}, 149 + description: "Manage reading list and track progress", 150 + }, 151 + "movies": { 152 + title: "Movies", 153 + position: 5, 154 + commands: []string{"media movie"}, 155 + description: "Track movies in watch queue", 156 + }, 157 + "tv-shows": { 158 + title: "TV Shows", 159 + position: 6, 160 + commands: []string{"media tv"}, 161 + description: "Manage TV show watching", 162 + }, 163 + "configuration": { 164 + title: "Configuration", 165 + position: 7, 166 + commands: []string{"config"}, 167 + description: "Manage application configuration", 168 + }, 169 + "management": { 170 + title: "Management", 171 + position: 8, 172 + commands: []string{"status", "setup", "reset"}, 173 + description: "Application management commands", 174 + }, 175 + } 176 + 177 + for filename, group := range commandGroups { 178 + content := generateCombinedPage(root, group.title, group.position, group.commands, group.description) 179 + outputFile := filepath.Join(outDir, filename+".md") 180 + if err := os.WriteFile(outputFile, []byte(content), 0o644); err != nil { 181 + return fmt.Errorf("failed to write %s: %w", outputFile, err) 182 + } 183 + } 184 + 185 + return nil 186 + } 187 + 188 + // generateIndexPage creates the index/overview page 189 + func generateIndexPage(root *cobra.Command) string { 190 + var b strings.Builder 191 + 192 + b.WriteString("---\n") 193 + b.WriteString("id: index\n") 194 + b.WriteString("title: CLI Reference\n") 195 + b.WriteString("sidebar_label: Overview\n") 196 + b.WriteString("sidebar_position: 0\n") 197 + b.WriteString("description: Complete command-line reference for noteleaf\n") 198 + b.WriteString("---\n\n") 199 + 200 + b.WriteString("# noteleaf CLI Reference\n\n") 201 + 202 + if root.Long != "" { 203 + b.WriteString(root.Long) 204 + b.WriteString("\n\n") 205 + } else if root.Short != "" { 206 + b.WriteString(root.Short) 207 + b.WriteString("\n\n") 208 + } 209 + 210 + b.WriteString("## Usage\n\n") 211 + b.WriteString("```bash\n") 212 + b.WriteString(root.UseLine()) 213 + b.WriteString("\n```\n\n") 214 + 215 + b.WriteString("## Command Groups\n\n") 216 + b.WriteString("- **[Task Management](tasks)** - Manage todos, projects, and time tracking\n") 217 + b.WriteString("- **[Notes](notes)** - Create and organize markdown notes\n") 218 + b.WriteString("- **[Articles](articles)** - Save and archive web articles\n") 219 + b.WriteString("- **[Books](books)** - Track reading list and progress\n") 220 + b.WriteString("- **[Movies](movies)** - Manage movie watch queue\n") 221 + b.WriteString("- **[TV Shows](tv-shows)** - Track TV show watching\n") 222 + b.WriteString("- **[Configuration](configuration)** - Manage settings\n") 223 + b.WriteString("- **[Management](management)** - Application management\n\n") 224 + 225 + return b.String() 226 + } 227 + 228 + // generateCombinedPage creates a combined documentation page for a command group 229 + func generateCombinedPage(root *cobra.Command, title string, position int, commandPaths []string, description string) string { 230 + var b strings.Builder 231 + 232 + slug := strings.ToLower(strings.ReplaceAll(title, " ", "-")) 233 + b.WriteString("---\n") 234 + b.WriteString(fmt.Sprintf("id: %s\n", slug)) 235 + b.WriteString(fmt.Sprintf("title: %s\n", title)) 236 + b.WriteString(fmt.Sprintf("sidebar_position: %d\n", position)) 237 + b.WriteString(fmt.Sprintf("description: %s\n", description)) 238 + b.WriteString("---\n\n") 239 + 240 + for _, cmdPath := range commandPaths { 241 + cmd := findCommand(root, strings.Split(cmdPath, " ")) 242 + if cmd == nil { 243 + continue 244 + } 245 + 246 + b.WriteString(fmt.Sprintf("## %s\n\n", cmd.Name())) 247 + if cmd.Long != "" { 248 + b.WriteString(cmd.Long) 249 + b.WriteString("\n\n") 250 + } else if cmd.Short != "" { 251 + b.WriteString(cmd.Short) 252 + b.WriteString("\n\n") 253 + } 254 + 255 + b.WriteString("```bash\n") 256 + b.WriteString(cmd.UseLine()) 257 + b.WriteString("\n```\n\n") 258 + 259 + if cmd.HasSubCommands() { 260 + b.WriteString("### Subcommands\n\n") 261 + for _, sub := range cmd.Commands() { 262 + if sub.Hidden { 263 + continue 264 + } 265 + generateSubcommandSection(&b, sub, 4) 266 + } 267 + } 268 + 269 + if cmd.HasFlags() { 270 + b.WriteString("### Options\n\n") 271 + b.WriteString("```\n") 272 + b.WriteString(cmd.Flags().FlagUsages()) 273 + b.WriteString("```\n\n") 274 + } 275 + } 276 + 277 + return b.String() 278 + } 279 + 280 + // generateSubcommandSection generates documentation for a subcommand 281 + func generateSubcommandSection(b *strings.Builder, cmd *cobra.Command, level int) { 282 + prefix := strings.Repeat("#", level) 283 + 284 + fmt.Fprintf(b, "%s %s\n\n", prefix, cmd.Name()) 285 + 286 + if cmd.Long != "" { 287 + b.WriteString(cmd.Long) 288 + b.WriteString("\n\n") 289 + } else if cmd.Short != "" { 290 + b.WriteString(cmd.Short) 291 + b.WriteString("\n\n") 292 + } 293 + 294 + b.WriteString("**Usage:**\n\n") 295 + b.WriteString("```bash\n") 296 + b.WriteString(cmd.UseLine()) 297 + b.WriteString("\n```\n\n") 298 + 299 + if cmd.HasLocalFlags() { 300 + b.WriteString("**Options:**\n\n") 301 + b.WriteString("```\n") 302 + b.WriteString(cmd.LocalFlags().FlagUsages()) 303 + b.WriteString("```\n\n") 304 + } 305 + 306 + if len(cmd.Aliases) > 0 { 307 + fmt.Fprintf(b, "**Aliases:** %s\n\n", strings.Join(cmd.Aliases, ", ")) 308 + } 309 + 310 + if cmd.HasSubCommands() { 311 + for _, sub := range cmd.Commands() { 312 + if sub.Hidden { 313 + continue 314 + } 315 + generateSubcommandSection(b, sub, level+1) 316 + } 317 + } 318 + } 319 + 320 + // findCommand finds a command by path 321 + func findCommand(root *cobra.Command, path []string) *cobra.Command { 322 + if len(path) == 0 { 323 + return root 324 + } 325 + 326 + for _, cmd := range root.Commands() { 327 + if cmd.Name() == path[0] || contains(cmd.Aliases, path[0]) { 328 + if len(path) == 1 { 329 + return cmd 330 + } 331 + return findCommand(cmd, path[1:]) 332 + } 333 + } 334 + 335 + return nil 336 + } 337 + 338 + // contains checks if a string is in a slice 339 + func contains(slice []string, str string) bool { 340 + return slices.Contains(slice, str) 341 + }
+5
website/.markdownlint.json
··· 1 + { 2 + "MD040": false, 3 + "MD013": false, 4 + "MD025": false 5 + }
+6 -6
website/docs/manual/_category_.json
··· 1 1 { 2 - "label": "Tutorial - Basics", 3 - "position": 2, 4 - "link": { 5 - "type": "generated-index", 6 - "description": "5 minutes to learn the most important Docusaurus concepts." 7 - } 2 + "label": "CLI Reference", 3 + "position": 3, 4 + "link": { 5 + "type": "generated-index", 6 + "description": "Complete command-line reference for noteleaf" 7 + } 8 8 }
+97
website/docs/manual/articles.md
··· 1 + --- 2 + id: articles 3 + title: Articles 4 + sidebar_position: 3 5 + description: Save and archive web articles 6 + --- 7 + 8 + ## article 9 + 10 + Save and archive web articles locally. 11 + 12 + Parse articles from supported websites, extract clean content, and save as 13 + both markdown and HTML. Maintains a searchable archive of articles with 14 + metadata including author, title, and publication date. 15 + 16 + ```bash 17 + noteleaf article 18 + ``` 19 + 20 + ### Subcommands 21 + 22 + #### add 23 + 24 + Parse and save article content from a supported website. 25 + 26 + The article will be parsed using domain-specific XPath rules and saved 27 + as both Markdown and HTML files. Article metadata is stored in the database. 28 + 29 + **Usage:** 30 + 31 + ```bash 32 + noteleaf article add <url> 33 + ``` 34 + 35 + #### list 36 + 37 + List saved articles with optional filtering. 38 + 39 + Use query to filter by title, or use flags for more specific filtering. 40 + 41 + **Usage:** 42 + 43 + ```bash 44 + noteleaf article list [query] [flags] 45 + ``` 46 + 47 + **Options:** 48 + 49 + ``` 50 + --author string Filter by author 51 + -l, --limit int Limit number of results (0 = no limit) 52 + ``` 53 + 54 + **Aliases:** ls 55 + 56 + #### view 57 + 58 + Display article metadata and summary. 59 + 60 + Shows article title, author, publication date, URL, and a brief content 61 + preview. Use 'read' command to view the full article content. 62 + 63 + **Usage:** 64 + 65 + ```bash 66 + noteleaf article view <id> 67 + ``` 68 + 69 + **Aliases:** show 70 + 71 + #### read 72 + 73 + Read the full markdown content of an article with beautiful formatting. 74 + 75 + This displays the complete article content using syntax highlighting and proper formatting. 76 + 77 + **Usage:** 78 + 79 + ```bash 80 + noteleaf article read <id> 81 + ``` 82 + 83 + #### remove 84 + 85 + Delete an article and its files permanently. 86 + 87 + Removes the article metadata from the database and deletes associated markdown 88 + and HTML files. This operation cannot be undone. 89 + 90 + **Usage:** 91 + 92 + ```bash 93 + noteleaf article remove <id> 94 + ``` 95 + 96 + **Aliases:** rm, delete 97 +
+115
website/docs/manual/books.md
··· 1 + --- 2 + id: books 3 + title: Books 4 + sidebar_position: 4 5 + description: Manage reading list and track progress 6 + --- 7 + 8 + ## book 9 + 10 + Track books and reading progress. 11 + 12 + Search Google Books API to add books to your reading list. Track which books 13 + you're reading, update progress percentages, and maintain a history of finished 14 + books. 15 + 16 + ```bash 17 + noteleaf media book 18 + ``` 19 + 20 + ### Subcommands 21 + 22 + #### add 23 + 24 + Search for books and add them to your reading list. 25 + 26 + By default, shows search results in a simple list format where you can select by number. 27 + Use the -i flag for an interactive interface with navigation keys. 28 + 29 + **Usage:** 30 + 31 + ```bash 32 + noteleaf media book add [search query...] [flags] 33 + ``` 34 + 35 + **Options:** 36 + 37 + ``` 38 + -i, --interactive Use interactive interface for book selection 39 + ``` 40 + 41 + #### list 42 + 43 + Display books in your reading list with progress indicators. 44 + 45 + Shows book titles, authors, and reading progress percentages. Filter by --all, 46 + --reading for books in progress, --finished for completed books, or --queued 47 + for books not yet started. Default shows queued books only. 48 + 49 + **Usage:** 50 + 51 + ```bash 52 + noteleaf media book list [--all|--reading|--finished|--queued] 53 + ``` 54 + 55 + #### reading 56 + 57 + Mark a book as currently reading. Use this when you start a book from your queue. 58 + 59 + **Usage:** 60 + 61 + ```bash 62 + noteleaf media book reading <id> 63 + ``` 64 + 65 + #### finished 66 + 67 + Mark a book as finished with current timestamp. Sets reading progress to 100%. 68 + 69 + **Usage:** 70 + 71 + ```bash 72 + noteleaf media book finished <id> 73 + ``` 74 + 75 + **Aliases:** read 76 + 77 + #### remove 78 + 79 + Remove a book from your reading list. Use this for books you no longer want to track. 80 + 81 + **Usage:** 82 + 83 + ```bash 84 + noteleaf media book remove <id> 85 + ``` 86 + 87 + **Aliases:** rm 88 + 89 + #### progress 90 + 91 + Set reading progress for a book. 92 + 93 + Specify a percentage value between 0 and 100 to indicate how far you've 94 + progressed through the book. Automatically updates status to 'reading' if not 95 + already set. 96 + 97 + **Usage:** 98 + 99 + ```bash 100 + noteleaf media book progress <id> <percentage> 101 + ``` 102 + 103 + #### update 104 + 105 + Change a book's status directly. 106 + 107 + Valid statuses are: queued (not started), reading (in progress), finished 108 + (completed), or removed (no longer tracking). 109 + 110 + **Usage:** 111 + 112 + ```bash 113 + noteleaf media book update <id> <status> 114 + ``` 115 +
+78
website/docs/manual/configuration.md
··· 1 + --- 2 + id: configuration 3 + title: Configuration 4 + sidebar_position: 7 5 + description: Manage application configuration 6 + --- 7 + 8 + ## config 9 + 10 + Manage noteleaf configuration 11 + 12 + ```bash 13 + noteleaf config 14 + ``` 15 + 16 + ### Subcommands 17 + 18 + #### get 19 + 20 + Display configuration values. 21 + 22 + If no key is provided, displays all configuration values. 23 + Otherwise, displays the value for the specified key. 24 + 25 + **Usage:** 26 + 27 + ```bash 28 + noteleaf config get [key] 29 + ``` 30 + 31 + #### set 32 + 33 + Update a configuration value. 34 + 35 + Available keys: 36 + database_path - Custom database file path 37 + data_dir - Custom data directory 38 + date_format - Date format string (default: 2006-01-02) 39 + color_scheme - Color scheme (default: default) 40 + default_view - Default view mode (default: list) 41 + default_priority - Default task priority 42 + editor - Preferred text editor 43 + articles_dir - Articles storage directory 44 + notes_dir - Notes storage directory 45 + auto_archive - Auto-archive completed items (true/false) 46 + sync_enabled - Enable synchronization (true/false) 47 + sync_endpoint - Synchronization endpoint URL 48 + sync_token - Synchronization token 49 + export_format - Default export format (default: json) 50 + movie_api_key - API key for movie database 51 + book_api_key - API key for book database 52 + 53 + **Usage:** 54 + 55 + ```bash 56 + noteleaf config set <key> <value> 57 + ``` 58 + 59 + #### path 60 + 61 + Display the path to the configuration file being used. 62 + 63 + **Usage:** 64 + 65 + ```bash 66 + noteleaf config path 67 + ``` 68 + 69 + #### reset 70 + 71 + Reset all configuration values to their defaults. 72 + 73 + **Usage:** 74 + 75 + ```bash 76 + noteleaf config reset 77 + ``` 78 +
+37
website/docs/manual/index.md
··· 1 + --- 2 + id: index 3 + title: CLI Reference 4 + sidebar_label: Overview 5 + sidebar_position: 0 6 + description: Complete command-line reference for noteleaf 7 + --- 8 + 9 + # noteleaf CLI Reference 10 + 11 + noteleaf - personal information manager for the command line 12 + 13 + A comprehensive CLI tool for managing tasks, notes, articles, and media queues. 14 + Inspired by TaskWarrior, noteleaf combines todo management with reading lists, 15 + watch queues, and a personal knowledge base. 16 + 17 + Core features include hierarchical tasks with dependencies, recurring tasks, 18 + time tracking, markdown notes with tags, article archiving, and media queue 19 + management for books, movies, and TV shows. 20 + 21 + ## Usage 22 + 23 + ```bash 24 + noteleaf 25 + ``` 26 + 27 + ## Command Groups 28 + 29 + - **[Task Management](tasks)** - Manage todos, projects, and time tracking 30 + - **[Notes](notes)** - Create and organize markdown notes 31 + - **[Articles](articles)** - Save and archive web articles 32 + - **[Books](books)** - Track reading list and progress 33 + - **[Movies](movies)** - Manage movie watch queue 34 + - **[TV Shows](tv-shows)** - Track TV show watching 35 + - **[Configuration](configuration)** - Manage settings 36 + - **[Management](management)** - Application management 37 +
+61
website/docs/manual/management.md
··· 1 + --- 2 + id: management 3 + title: Management 4 + sidebar_position: 8 5 + description: Application management commands 6 + --- 7 + 8 + ## status 9 + 10 + Display comprehensive application status information. 11 + 12 + Shows database location, configuration file path, data directories, and current 13 + settings. Use this command to verify your noteleaf installation and diagnose 14 + configuration issues. 15 + 16 + ```bash 17 + noteleaf status 18 + ``` 19 + 20 + ## setup 21 + 22 + Initialize noteleaf for first use. 23 + 24 + Creates the database, configuration file, and required data directories. Run 25 + this command after installing noteleaf or when setting up a new environment. 26 + Safe to run multiple times as it will skip existing resources. 27 + 28 + ```bash 29 + noteleaf setup 30 + ``` 31 + 32 + ### Subcommands 33 + 34 + #### seed 35 + 36 + Add sample tasks, books, and notes to the database for testing and demonstration purposes 37 + 38 + **Usage:** 39 + 40 + ```bash 41 + noteleaf setup seed [flags] 42 + ``` 43 + 44 + **Options:** 45 + 46 + ``` 47 + -f, --force Clear existing data and re-seed 48 + ``` 49 + 50 + ## reset 51 + 52 + Remove all application data and return to initial state. 53 + 54 + This command deletes the database, all media files, notes, and articles. The 55 + configuration file is preserved. Use with caution as this operation cannot be 56 + undone. You will be prompted for confirmation before deletion proceeds. 57 + 58 + ```bash 59 + noteleaf reset 60 + ``` 61 +
+77
website/docs/manual/movies.md
··· 1 + --- 2 + id: movies 3 + title: Movies 4 + sidebar_position: 5 5 + description: Track movies in watch queue 6 + --- 7 + 8 + ## movie 9 + 10 + Track movies you want to watch. 11 + 12 + Search TMDB for movies and add them to your queue. Mark movies as watched when 13 + completed. Maintains a history of your movie watching activity. 14 + 15 + ```bash 16 + noteleaf media movie 17 + ``` 18 + 19 + ### Subcommands 20 + 21 + #### add 22 + 23 + Search for movies and add them to your watch queue. 24 + 25 + By default, shows search results in a simple list format where you can select by number. 26 + Use the -i flag for an interactive interface with navigation keys. 27 + 28 + **Usage:** 29 + 30 + ```bash 31 + noteleaf media movie add [search query...] [flags] 32 + ``` 33 + 34 + **Options:** 35 + 36 + ``` 37 + -i, --interactive Use interactive interface for movie selection 38 + ``` 39 + 40 + #### list 41 + 42 + Display movies in your queue with optional status filters. 43 + 44 + Shows movie titles, release years, and current status. Filter by --all to show 45 + everything, --watched for completed movies, or --queued for unwatched items. 46 + Default shows queued movies only. 47 + 48 + **Usage:** 49 + 50 + ```bash 51 + noteleaf media movie list [--all|--watched|--queued] 52 + ``` 53 + 54 + #### watched 55 + 56 + Mark a movie as watched with current timestamp. Moves the movie from queued to watched status. 57 + 58 + **Usage:** 59 + 60 + ```bash 61 + noteleaf media movie watched [id] 62 + ``` 63 + 64 + **Aliases:** seen 65 + 66 + #### remove 67 + 68 + Remove a movie from your watch queue. Use this for movies you no longer want to track. 69 + 70 + **Usage:** 71 + 72 + ```bash 73 + noteleaf media movie remove [id] 74 + ``` 75 + 76 + **Aliases:** rm 77 +
+114
website/docs/manual/notes.md
··· 1 + --- 2 + id: notes 3 + title: Notes 4 + sidebar_position: 2 5 + description: Create and organize markdown notes 6 + --- 7 + 8 + ## note 9 + 10 + Create and organize markdown notes with tags. 11 + 12 + Write notes in markdown format, organize them with tags, browse them in an 13 + interactive TUI, and edit them in your preferred editor. Notes are stored as 14 + files on disk with metadata tracked in the database. 15 + 16 + ```bash 17 + noteleaf note 18 + ``` 19 + 20 + ### Subcommands 21 + 22 + #### create 23 + 24 + Create a new markdown note. 25 + 26 + Provide a title and optional content inline, or use --interactive to open an 27 + editor. Use --file to import content from an existing markdown file. Notes 28 + support tags for organization and full-text search. 29 + 30 + Examples: 31 + noteleaf note create "Meeting notes" "Discussed project timeline" 32 + noteleaf note create -i 33 + noteleaf note create --file ~/documents/draft.md 34 + 35 + **Usage:** 36 + 37 + ```bash 38 + noteleaf note create [title] [content...] [flags] 39 + ``` 40 + 41 + **Options:** 42 + 43 + ``` 44 + -e, --editor Prompt to open note in editor after creation 45 + -f, --file string Create note from markdown file 46 + -i, --interactive Open interactive editor 47 + ``` 48 + 49 + **Aliases:** new 50 + 51 + #### list 52 + 53 + Opens interactive TUI browser for navigating and viewing notes 54 + 55 + **Usage:** 56 + 57 + ```bash 58 + noteleaf note list [--archived] [--static] [--tags=tag1,tag2] [flags] 59 + ``` 60 + 61 + **Options:** 62 + 63 + ``` 64 + -a, --archived Show archived notes 65 + -s, --static Show static list instead of interactive TUI 66 + --tags string Filter by tags (comma-separated) 67 + ``` 68 + 69 + **Aliases:** ls 70 + 71 + #### read 72 + 73 + Display note content with formatted markdown rendering. 74 + 75 + Shows the note with syntax highlighting, proper formatting, and metadata. 76 + Useful for quick viewing without opening an editor. 77 + 78 + **Usage:** 79 + 80 + ```bash 81 + noteleaf note read [note-id] 82 + ``` 83 + 84 + **Aliases:** view 85 + 86 + #### edit 87 + 88 + Open note in your configured text editor. 89 + 90 + Uses the editor specified in your noteleaf configuration or the EDITOR 91 + environment variable. Changes are automatically saved when you close the 92 + editor. 93 + 94 + **Usage:** 95 + 96 + ```bash 97 + noteleaf note edit [note-id] 98 + ``` 99 + 100 + #### remove 101 + 102 + Delete a note permanently. 103 + 104 + Removes both the markdown file and database metadata. This operation cannot be 105 + undone. You will be prompted for confirmation before deletion. 106 + 107 + **Usage:** 108 + 109 + ```bash 110 + noteleaf note remove [note-id] 111 + ``` 112 + 113 + **Aliases:** rm, delete, del 114 +
+861
website/docs/manual/tasks.md
··· 1 + --- 2 + id: task-management 3 + title: Task Management 4 + sidebar_position: 1 5 + description: Manage tasks with TaskWarrior-inspired features 6 + --- 7 + 8 + ## todo 9 + 10 + Manage tasks with TaskWarrior-inspired features. 11 + 12 + Track todos with priorities, projects, contexts, and tags. Supports hierarchical 13 + tasks with parent/child relationships, task dependencies, recurring tasks, and 14 + time tracking. Tasks can be filtered by status, priority, project, or context. 15 + 16 + ```bash 17 + noteleaf todo 18 + ``` 19 + 20 + ### Subcommands 21 + 22 + #### add 23 + 24 + Create a new task with description and optional attributes. 25 + 26 + Tasks can be created with priority levels (low, medium, high, urgent), assigned 27 + to projects and contexts, tagged for organization, and configured with due dates 28 + and recurrence rules. Dependencies can be established to ensure tasks are 29 + completed in order. 30 + 31 + Examples: 32 + noteleaf todo add "Write documentation" --priority high --project docs 33 + noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15 34 + 35 + **Usage:** 36 + 37 + ```bash 38 + noteleaf todo add [description] [flags] 39 + ``` 40 + 41 + **Options:** 42 + 43 + ``` 44 + -c, --context string Set task context 45 + --depends-on string Set task dependencies (comma-separated UUIDs) 46 + -d, --due string Set due date (YYYY-MM-DD) 47 + --parent string Set parent task UUID 48 + -p, --priority string Set task priority 49 + --project string Set task project 50 + --recur string Set recurrence rule (e.g., FREQ=DAILY) 51 + -t, --tags strings Add tags to task 52 + --until string Set recurrence end date (YYYY-MM-DD) 53 + ``` 54 + 55 + **Aliases:** create, new 56 + 57 + #### list 58 + 59 + List tasks with optional filtering and display modes. 60 + 61 + By default, shows tasks in an interactive TaskWarrior-like interface. 62 + Use --static to show a simple text list instead. 63 + Use --all to show all tasks, otherwise only pending tasks are shown. 64 + 65 + **Usage:** 66 + 67 + ```bash 68 + noteleaf todo list [flags] 69 + ``` 70 + 71 + **Options:** 72 + 73 + ``` 74 + -a, --all Show all tasks (default: pending only) 75 + --context string Filter by context 76 + -i, --interactive Force interactive mode (default) 77 + --priority string Filter by priority 78 + --project string Filter by project 79 + --static Use static text output instead of interactive 80 + --status string Filter by status 81 + ``` 82 + 83 + **Aliases:** ls 84 + 85 + #### view 86 + 87 + Display detailed information for a specific task. 88 + 89 + Shows all task attributes including description, status, priority, project, 90 + context, tags, due date, creation time, and modification history. Use --json 91 + for machine-readable output or --no-metadata to show only the description. 92 + 93 + **Usage:** 94 + 95 + ```bash 96 + noteleaf todo view [task-id] [flags] 97 + ``` 98 + 99 + **Options:** 100 + 101 + ``` 102 + --format string Output format (detailed, brief) (default "detailed") 103 + --json Output as JSON 104 + --no-metadata Hide creation/modification timestamps 105 + ``` 106 + 107 + #### update 108 + 109 + Modify attributes of an existing task. 110 + 111 + Update any task property including description, status, priority, project, 112 + context, due date, recurrence rule, or parent task. Add or remove tags and 113 + dependencies. Multiple attributes can be updated in a single command. 114 + 115 + Examples: 116 + noteleaf todo update 123 --priority urgent --due tomorrow 117 + noteleaf todo update 456 --add-tag urgent --project website 118 + 119 + **Usage:** 120 + 121 + ```bash 122 + noteleaf todo update [task-id] [flags] 123 + ``` 124 + 125 + **Options:** 126 + 127 + ``` 128 + --add-depends string Add task dependencies (comma-separated UUIDs) 129 + --add-tag strings Add tags to task 130 + -c, --context string Set task context 131 + --description string Update task description 132 + -d, --due string Set due date (YYYY-MM-DD) 133 + --parent string Set parent task UUID 134 + -p, --priority string Set task priority 135 + --project string Set task project 136 + --recur string Set recurrence rule (e.g., FREQ=DAILY) 137 + --remove-depends string Remove task dependencies (comma-separated UUIDs) 138 + --remove-tag strings Remove tags from task 139 + --status string Update task status 140 + -t, --tags strings Add tags to task 141 + --until string Set recurrence end date (YYYY-MM-DD) 142 + ``` 143 + 144 + #### edit 145 + 146 + Open interactive editor for task modification. 147 + 148 + Provides a user-friendly interface with status picker and priority toggle. 149 + Easier than using multiple command-line flags for complex updates. 150 + 151 + **Usage:** 152 + 153 + ```bash 154 + noteleaf todo edit [task-id] 155 + ``` 156 + 157 + **Aliases:** e 158 + 159 + #### delete 160 + 161 + Permanently remove a task from the database. 162 + 163 + This operation cannot be undone. Consider updating the task status to 164 + 'deleted' instead if you want to preserve the record for historical purposes. 165 + 166 + **Usage:** 167 + 168 + ```bash 169 + noteleaf todo delete [task-id] 170 + ``` 171 + 172 + #### projects 173 + 174 + Display all projects with task counts. 175 + 176 + Shows each project used in your tasks along with the number of tasks in each 177 + project. Use --todo-txt to format output with +project syntax for compatibility 178 + with todo.txt tools. 179 + 180 + **Usage:** 181 + 182 + ```bash 183 + noteleaf todo projects [flags] 184 + ``` 185 + 186 + **Options:** 187 + 188 + ``` 189 + --static Use static text output instead of interactive 190 + --todo-txt Format output with +project prefix for todo.txt compatibility 191 + ``` 192 + 193 + **Aliases:** proj 194 + 195 + #### tags 196 + 197 + Display all tags used across tasks. 198 + 199 + Shows each tag with the number of tasks using it. Tags provide flexible 200 + categorization orthogonal to projects and contexts. 201 + 202 + **Usage:** 203 + 204 + ```bash 205 + noteleaf todo tags [flags] 206 + ``` 207 + 208 + **Options:** 209 + 210 + ``` 211 + --static Use static text output instead of interactive 212 + ``` 213 + 214 + **Aliases:** t 215 + 216 + #### contexts 217 + 218 + Display all contexts with task counts. 219 + 220 + Contexts represent locations or environments where tasks can be completed (e.g., 221 + @home, @office, @errands). Use --todo-txt to format output with @context syntax 222 + for compatibility with todo.txt tools. 223 + 224 + **Usage:** 225 + 226 + ```bash 227 + noteleaf todo contexts [flags] 228 + ``` 229 + 230 + **Options:** 231 + 232 + ``` 233 + --static Use static text output instead of interactive 234 + --todo-txt Format output with @context prefix for todo.txt compatibility 235 + ``` 236 + 237 + **Aliases:** con, loc, ctx, locations 238 + 239 + #### done 240 + 241 + Mark a task as completed with current timestamp. 242 + 243 + Sets the task status to 'completed' and records the completion time. For 244 + recurring tasks, generates the next instance based on the recurrence rule. 245 + 246 + **Usage:** 247 + 248 + ```bash 249 + noteleaf todo done [task-id] 250 + ``` 251 + 252 + **Aliases:** complete 253 + 254 + #### start 255 + 256 + Begin tracking time spent on a task. 257 + 258 + Records the start time for a work session. Only one task can be actively 259 + tracked at a time. Use --note to add a description of what you're working on. 260 + 261 + **Usage:** 262 + 263 + ```bash 264 + noteleaf todo start [task-id] [flags] 265 + ``` 266 + 267 + **Options:** 268 + 269 + ``` 270 + -n, --note string Add a note to the time entry 271 + ``` 272 + 273 + #### stop 274 + 275 + End time tracking for the active task. 276 + 277 + Records the end time and calculates duration for the current work session. 278 + Duration is added to the task's total time tracked. 279 + 280 + **Usage:** 281 + 282 + ```bash 283 + noteleaf todo stop [task-id] 284 + ``` 285 + 286 + #### timesheet 287 + 288 + Show time tracking summary for tasks. 289 + 290 + By default shows time entries for the last 7 days. 291 + Use --task to show timesheet for a specific task. 292 + Use --days to change the date range. 293 + 294 + **Usage:** 295 + 296 + ```bash 297 + noteleaf todo timesheet [flags] 298 + ``` 299 + 300 + **Options:** 301 + 302 + ``` 303 + -d, --days int Number of days to show in timesheet (default 7) 304 + -t, --task string Show timesheet for specific task ID 305 + ``` 306 + 307 + #### recur 308 + 309 + Configure recurring task patterns. 310 + 311 + Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE). 312 + Supports daily, weekly, monthly, and yearly patterns with optional end dates. 313 + 314 + **Usage:** 315 + 316 + ```bash 317 + noteleaf todo recur 318 + ``` 319 + 320 + **Aliases:** repeat 321 + 322 + ##### set 323 + 324 + Apply a recurrence rule to create repeating task instances. 325 + 326 + Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR" 327 + for specific weekdays). When a recurring task is completed, the next instance is 328 + automatically generated. 329 + 330 + Examples: 331 + noteleaf todo recur set 123 --rule "FREQ=DAILY" 332 + noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31 333 + 334 + **Usage:** 335 + 336 + ```bash 337 + noteleaf todo recur set [task-id] [flags] 338 + ``` 339 + 340 + **Options:** 341 + 342 + ``` 343 + --rule string Recurrence rule (e.g., FREQ=DAILY) 344 + --until string Recurrence end date (YYYY-MM-DD) 345 + ``` 346 + 347 + ##### clear 348 + 349 + Remove recurrence from a task. 350 + 351 + Converts a recurring task to a one-time task. Existing future instances are not 352 + affected. 353 + 354 + **Usage:** 355 + 356 + ```bash 357 + noteleaf todo recur clear [task-id] 358 + ``` 359 + 360 + ##### show 361 + 362 + Display recurrence rule and schedule information. 363 + 364 + Shows the RRULE pattern, next occurrence date, and recurrence end date if 365 + configured. 366 + 367 + **Usage:** 368 + 369 + ```bash 370 + noteleaf todo recur show [task-id] 371 + ``` 372 + 373 + #### depend 374 + 375 + Create and manage task dependencies. 376 + 377 + Establish relationships where one task must be completed before another can 378 + begin. Useful for multi-step workflows and project management. 379 + 380 + **Usage:** 381 + 382 + ```bash 383 + noteleaf todo depend 384 + ``` 385 + 386 + **Aliases:** dep, deps 387 + 388 + ##### add 389 + 390 + Make a task dependent on another task's completion. 391 + 392 + The first task cannot be started until the second task is completed. Use task 393 + UUIDs to specify dependencies. 394 + 395 + **Usage:** 396 + 397 + ```bash 398 + noteleaf todo depend add [task-id] [depends-on-uuid] 399 + ``` 400 + 401 + ##### remove 402 + 403 + Delete a dependency relationship between two tasks. 404 + 405 + **Usage:** 406 + 407 + ```bash 408 + noteleaf todo depend remove [task-id] [depends-on-uuid] 409 + ``` 410 + 411 + **Aliases:** rm 412 + 413 + ##### list 414 + 415 + Show all tasks that must be completed before this task can be started. 416 + 417 + **Usage:** 418 + 419 + ```bash 420 + noteleaf todo depend list [task-id] 421 + ``` 422 + 423 + **Aliases:** ls 424 + 425 + ##### blocked-by 426 + 427 + Display all tasks that depend on this task's completion. 428 + 429 + **Usage:** 430 + 431 + ```bash 432 + noteleaf todo depend blocked-by [task-id] 433 + ``` 434 + 435 + ## todo 436 + 437 + Manage tasks with TaskWarrior-inspired features. 438 + 439 + Track todos with priorities, projects, contexts, and tags. Supports hierarchical 440 + tasks with parent/child relationships, task dependencies, recurring tasks, and 441 + time tracking. Tasks can be filtered by status, priority, project, or context. 442 + 443 + ```bash 444 + noteleaf todo 445 + ``` 446 + 447 + ### Subcommands 448 + 449 + #### add 450 + 451 + Create a new task with description and optional attributes. 452 + 453 + Tasks can be created with priority levels (low, medium, high, urgent), assigned 454 + to projects and contexts, tagged for organization, and configured with due dates 455 + and recurrence rules. Dependencies can be established to ensure tasks are 456 + completed in order. 457 + 458 + Examples: 459 + noteleaf todo add "Write documentation" --priority high --project docs 460 + noteleaf todo add "Weekly review" --recur "FREQ=WEEKLY" --due 2024-01-15 461 + 462 + **Usage:** 463 + 464 + ```bash 465 + noteleaf todo add [description] [flags] 466 + ``` 467 + 468 + **Options:** 469 + 470 + ``` 471 + -c, --context string Set task context 472 + --depends-on string Set task dependencies (comma-separated UUIDs) 473 + -d, --due string Set due date (YYYY-MM-DD) 474 + --parent string Set parent task UUID 475 + -p, --priority string Set task priority 476 + --project string Set task project 477 + --recur string Set recurrence rule (e.g., FREQ=DAILY) 478 + -t, --tags strings Add tags to task 479 + --until string Set recurrence end date (YYYY-MM-DD) 480 + ``` 481 + 482 + **Aliases:** create, new 483 + 484 + #### list 485 + 486 + List tasks with optional filtering and display modes. 487 + 488 + By default, shows tasks in an interactive TaskWarrior-like interface. 489 + Use --static to show a simple text list instead. 490 + Use --all to show all tasks, otherwise only pending tasks are shown. 491 + 492 + **Usage:** 493 + 494 + ```bash 495 + noteleaf todo list [flags] 496 + ``` 497 + 498 + **Options:** 499 + 500 + ``` 501 + -a, --all Show all tasks (default: pending only) 502 + --context string Filter by context 503 + -i, --interactive Force interactive mode (default) 504 + --priority string Filter by priority 505 + --project string Filter by project 506 + --static Use static text output instead of interactive 507 + --status string Filter by status 508 + ``` 509 + 510 + **Aliases:** ls 511 + 512 + #### view 513 + 514 + Display detailed information for a specific task. 515 + 516 + Shows all task attributes including description, status, priority, project, 517 + context, tags, due date, creation time, and modification history. Use --json 518 + for machine-readable output or --no-metadata to show only the description. 519 + 520 + **Usage:** 521 + 522 + ```bash 523 + noteleaf todo view [task-id] [flags] 524 + ``` 525 + 526 + **Options:** 527 + 528 + ``` 529 + --format string Output format (detailed, brief) (default "detailed") 530 + --json Output as JSON 531 + --no-metadata Hide creation/modification timestamps 532 + ``` 533 + 534 + #### update 535 + 536 + Modify attributes of an existing task. 537 + 538 + Update any task property including description, status, priority, project, 539 + context, due date, recurrence rule, or parent task. Add or remove tags and 540 + dependencies. Multiple attributes can be updated in a single command. 541 + 542 + Examples: 543 + noteleaf todo update 123 --priority urgent --due tomorrow 544 + noteleaf todo update 456 --add-tag urgent --project website 545 + 546 + **Usage:** 547 + 548 + ```bash 549 + noteleaf todo update [task-id] [flags] 550 + ``` 551 + 552 + **Options:** 553 + 554 + ``` 555 + --add-depends string Add task dependencies (comma-separated UUIDs) 556 + --add-tag strings Add tags to task 557 + -c, --context string Set task context 558 + --description string Update task description 559 + -d, --due string Set due date (YYYY-MM-DD) 560 + --parent string Set parent task UUID 561 + -p, --priority string Set task priority 562 + --project string Set task project 563 + --recur string Set recurrence rule (e.g., FREQ=DAILY) 564 + --remove-depends string Remove task dependencies (comma-separated UUIDs) 565 + --remove-tag strings Remove tags from task 566 + --status string Update task status 567 + -t, --tags strings Add tags to task 568 + --until string Set recurrence end date (YYYY-MM-DD) 569 + ``` 570 + 571 + #### edit 572 + 573 + Open interactive editor for task modification. 574 + 575 + Provides a user-friendly interface with status picker and priority toggle. 576 + Easier than using multiple command-line flags for complex updates. 577 + 578 + **Usage:** 579 + 580 + ```bash 581 + noteleaf todo edit [task-id] 582 + ``` 583 + 584 + **Aliases:** e 585 + 586 + #### delete 587 + 588 + Permanently remove a task from the database. 589 + 590 + This operation cannot be undone. Consider updating the task status to 591 + 'deleted' instead if you want to preserve the record for historical purposes. 592 + 593 + **Usage:** 594 + 595 + ```bash 596 + noteleaf todo delete [task-id] 597 + ``` 598 + 599 + #### projects 600 + 601 + Display all projects with task counts. 602 + 603 + Shows each project used in your tasks along with the number of tasks in each 604 + project. Use --todo-txt to format output with +project syntax for compatibility 605 + with todo.txt tools. 606 + 607 + **Usage:** 608 + 609 + ```bash 610 + noteleaf todo projects [flags] 611 + ``` 612 + 613 + **Options:** 614 + 615 + ``` 616 + --static Use static text output instead of interactive 617 + --todo-txt Format output with +project prefix for todo.txt compatibility 618 + ``` 619 + 620 + **Aliases:** proj 621 + 622 + #### tags 623 + 624 + Display all tags used across tasks. 625 + 626 + Shows each tag with the number of tasks using it. Tags provide flexible 627 + categorization orthogonal to projects and contexts. 628 + 629 + **Usage:** 630 + 631 + ```bash 632 + noteleaf todo tags [flags] 633 + ``` 634 + 635 + **Options:** 636 + 637 + ``` 638 + --static Use static text output instead of interactive 639 + ``` 640 + 641 + **Aliases:** t 642 + 643 + #### contexts 644 + 645 + Display all contexts with task counts. 646 + 647 + Contexts represent locations or environments where tasks can be completed (e.g., 648 + @home, @office, @errands). Use --todo-txt to format output with @context syntax 649 + for compatibility with todo.txt tools. 650 + 651 + **Usage:** 652 + 653 + ```bash 654 + noteleaf todo contexts [flags] 655 + ``` 656 + 657 + **Options:** 658 + 659 + ``` 660 + --static Use static text output instead of interactive 661 + --todo-txt Format output with @context prefix for todo.txt compatibility 662 + ``` 663 + 664 + **Aliases:** con, loc, ctx, locations 665 + 666 + #### done 667 + 668 + Mark a task as completed with current timestamp. 669 + 670 + Sets the task status to 'completed' and records the completion time. For 671 + recurring tasks, generates the next instance based on the recurrence rule. 672 + 673 + **Usage:** 674 + 675 + ```bash 676 + noteleaf todo done [task-id] 677 + ``` 678 + 679 + **Aliases:** complete 680 + 681 + #### start 682 + 683 + Begin tracking time spent on a task. 684 + 685 + Records the start time for a work session. Only one task can be actively 686 + tracked at a time. Use --note to add a description of what you're working on. 687 + 688 + **Usage:** 689 + 690 + ```bash 691 + noteleaf todo start [task-id] [flags] 692 + ``` 693 + 694 + **Options:** 695 + 696 + ``` 697 + -n, --note string Add a note to the time entry 698 + ``` 699 + 700 + #### stop 701 + 702 + End time tracking for the active task. 703 + 704 + Records the end time and calculates duration for the current work session. 705 + Duration is added to the task's total time tracked. 706 + 707 + **Usage:** 708 + 709 + ```bash 710 + noteleaf todo stop [task-id] 711 + ``` 712 + 713 + #### timesheet 714 + 715 + Show time tracking summary for tasks. 716 + 717 + By default shows time entries for the last 7 days. 718 + Use --task to show timesheet for a specific task. 719 + Use --days to change the date range. 720 + 721 + **Usage:** 722 + 723 + ```bash 724 + noteleaf todo timesheet [flags] 725 + ``` 726 + 727 + **Options:** 728 + 729 + ``` 730 + -d, --days int Number of days to show in timesheet (default 7) 731 + -t, --task string Show timesheet for specific task ID 732 + ``` 733 + 734 + #### recur 735 + 736 + Configure recurring task patterns. 737 + 738 + Create tasks that repeat on a schedule using iCalendar recurrence rules (RRULE). 739 + Supports daily, weekly, monthly, and yearly patterns with optional end dates. 740 + 741 + **Usage:** 742 + 743 + ```bash 744 + noteleaf todo recur 745 + ``` 746 + 747 + **Aliases:** repeat 748 + 749 + ##### set 750 + 751 + Apply a recurrence rule to create repeating task instances. 752 + 753 + Uses iCalendar RRULE syntax (e.g., "FREQ=DAILY" for daily tasks, "FREQ=WEEKLY;BYDAY=MO,WE,FR" 754 + for specific weekdays). When a recurring task is completed, the next instance is 755 + automatically generated. 756 + 757 + Examples: 758 + noteleaf todo recur set 123 --rule "FREQ=DAILY" 759 + noteleaf todo recur set 456 --rule "FREQ=WEEKLY;BYDAY=MO" --until 2024-12-31 760 + 761 + **Usage:** 762 + 763 + ```bash 764 + noteleaf todo recur set [task-id] [flags] 765 + ``` 766 + 767 + **Options:** 768 + 769 + ``` 770 + --rule string Recurrence rule (e.g., FREQ=DAILY) 771 + --until string Recurrence end date (YYYY-MM-DD) 772 + ``` 773 + 774 + ##### clear 775 + 776 + Remove recurrence from a task. 777 + 778 + Converts a recurring task to a one-time task. Existing future instances are not 779 + affected. 780 + 781 + **Usage:** 782 + 783 + ```bash 784 + noteleaf todo recur clear [task-id] 785 + ``` 786 + 787 + ##### show 788 + 789 + Display recurrence rule and schedule information. 790 + 791 + Shows the RRULE pattern, next occurrence date, and recurrence end date if 792 + configured. 793 + 794 + **Usage:** 795 + 796 + ```bash 797 + noteleaf todo recur show [task-id] 798 + ``` 799 + 800 + #### depend 801 + 802 + Create and manage task dependencies. 803 + 804 + Establish relationships where one task must be completed before another can 805 + begin. Useful for multi-step workflows and project management. 806 + 807 + **Usage:** 808 + 809 + ```bash 810 + noteleaf todo depend 811 + ``` 812 + 813 + **Aliases:** dep, deps 814 + 815 + ##### add 816 + 817 + Make a task dependent on another task's completion. 818 + 819 + The first task cannot be started until the second task is completed. Use task 820 + UUIDs to specify dependencies. 821 + 822 + **Usage:** 823 + 824 + ```bash 825 + noteleaf todo depend add [task-id] [depends-on-uuid] 826 + ``` 827 + 828 + ##### remove 829 + 830 + Delete a dependency relationship between two tasks. 831 + 832 + **Usage:** 833 + 834 + ```bash 835 + noteleaf todo depend remove [task-id] [depends-on-uuid] 836 + ``` 837 + 838 + **Aliases:** rm 839 + 840 + ##### list 841 + 842 + Show all tasks that must be completed before this task can be started. 843 + 844 + **Usage:** 845 + 846 + ```bash 847 + noteleaf todo depend list [task-id] 848 + ``` 849 + 850 + **Aliases:** ls 851 + 852 + ##### blocked-by 853 + 854 + Display all tasks that depend on this task's completion. 855 + 856 + **Usage:** 857 + 858 + ```bash 859 + noteleaf todo depend blocked-by [task-id] 860 + ``` 861 +
+91
website/docs/manual/tv-shows.md
··· 1 + --- 2 + id: tv-shows 3 + title: TV Shows 4 + sidebar_position: 6 5 + description: Manage TV show watching 6 + --- 7 + 8 + ## tv 9 + 10 + Track TV shows and episodes. 11 + 12 + Search TMDB for TV shows and add them to your queue. Track which shows you're 13 + currently watching, mark episodes as watched, and maintain a complete history 14 + of your viewing activity. 15 + 16 + ```bash 17 + noteleaf media tv 18 + ``` 19 + 20 + ### Subcommands 21 + 22 + #### add 23 + 24 + Search for TV shows and add them to your watch queue. 25 + 26 + By default, shows search results in a simple list format where you can select by number. 27 + Use the -i flag for an interactive interface with navigation keys. 28 + 29 + **Usage:** 30 + 31 + ```bash 32 + noteleaf media tv add [search query...] [flags] 33 + ``` 34 + 35 + **Options:** 36 + 37 + ``` 38 + -i, --interactive Use interactive interface for TV show selection 39 + ``` 40 + 41 + #### list 42 + 43 + Display TV shows in your queue with optional status filters. 44 + 45 + Shows show titles, air dates, and current status. Filter by --all, --queued, 46 + --watching for shows in progress, or --watched for completed series. Default 47 + shows queued shows only. 48 + 49 + **Usage:** 50 + 51 + ```bash 52 + noteleaf media tv list [--all|--queued|--watching|--watched] 53 + ``` 54 + 55 + #### watching 56 + 57 + Mark a TV show as currently watching. Use this when you start watching a series. 58 + 59 + **Usage:** 60 + 61 + ```bash 62 + noteleaf media tv watching [id] 63 + ``` 64 + 65 + #### watched 66 + 67 + Mark TV show episodes or entire series as watched. 68 + 69 + Updates episode tracking and completion status. Can mark individual episodes 70 + or complete seasons/series depending on ID format. 71 + 72 + **Usage:** 73 + 74 + ```bash 75 + noteleaf media tv watched [id] 76 + ``` 77 + 78 + **Aliases:** seen 79 + 80 + #### remove 81 + 82 + Remove a TV show from your watch queue. Use this for shows you no longer want to track. 83 + 84 + **Usage:** 85 + 86 + ```bash 87 + noteleaf media tv remove [id] 88 + ``` 89 + 90 + **Aliases:** rm 91 +