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

feat: update project and context listing commands with todo.txt format support

+124 -35
+90 -19
ROADMAP.md
··· 48 - [x] `media book progress <id> <percentage>` - Update reading progress (0-100%) 49 - [x] `media book update <id> <status>` - Update book status (queued|reading|finished|removed) 50 51 - ### Commands To Be Implemented 52 - 53 Movie Management 54 55 - - [ ] `media movie add [title]` - Add movie to watch queue 56 - - [ ] `media movie list` - Show movie queue with ratings/metadata 57 - - [ ] `media movie watched <id>` - Mark movie as watched 58 - - [ ] `media movie remove <id>` - Remove from queue 59 60 TV Show Management 61 62 - - [ ] `media tv add [title]` - Add TV show/season to queue 63 - - [ ] `media tv list` - Show TV queue with episode tracking 64 - - [ ] `media tv watched <id>` - Mark episodes/seasons as watched 65 - - [ ] `media tv remove <id>` - Remove from TV queue 66 67 --- 68 ··· 123 - [ ] `[pri]ority` - Set task priority (A-Z) 124 - [ ] `[depri]oritize` - Remove priority from task 125 - [ ] `[re]place` - Replace task text entirely 126 - - [ ] `prepend/append` - Add text to beginning/end of task 127 128 Automation 129 ··· 143 144 Configuration 145 146 - - [ ] Enhanced `config` command implementation 147 - [ ] `undo` - Reverse last operation 148 - [ ] Themes and personalization 149 - [ ] Customizable output formats ··· 205 We've got inconsistent argument parsing and sanitization leading to calls to strconv.Atoi in tests & handler funcs. 206 This is only done correctly in the note command -> handler sequence 207 208 ### Movie Commands - Missing Tests 209 210 - - movie watched [id] - marks movie as watched 211 212 ### TV Commands - Missing Tests 213 214 - - tv watching [id] - marks TV show as watching 215 - - tv watched [id] - marks TV show as watched 216 217 ### Book Commands - Missing Tests 218 219 - - book add [search query...] - search and add book 220 - - book reading `<id>` - marks book as reading 221 - - book finished `<id>` - marks book as finished 222 - - book progress `<id>` `<percentage>` - updates reading progress 223
··· 48 - [x] `media book progress <id> <percentage>` - Update reading progress (0-100%) 49 - [x] `media book update <id> <status>` - Update book status (queued|reading|finished|removed) 50 51 Movie Management 52 53 + - [x] `media movie add [title]` - Add movie to watch queue (with interactive mode) 54 + - [x] `media movie list` - Show movie queue with status filtering 55 + - [x] `media movie watched <id>` - Mark movie as watched 56 + - [x] `media movie remove <id>` - Remove from queue 57 58 TV Show Management 59 60 + - [x] `media tv add [title]` - Add TV show/season to queue (with interactive mode) 61 + - [x] `media tv list` - Show TV queue with status filtering 62 + - [x] `media tv watching <id>` - Mark TV show as currently watching 63 + - [x] `media tv watched <id>` - Mark episodes/seasons as watched 64 + - [x] `media tv remove <id>` - Remove from TV queue 65 + 66 + ### Commands To Be Implemented 67 68 --- 69 ··· 124 - [ ] `[pri]ority` - Set task priority (A-Z) 125 - [ ] `[depri]oritize` - Remove priority from task 126 - [ ] `[re]place` - Replace task text entirely 127 + - [ ] `[pre]pend/[app]end` - Add text to beginning/end of task 128 129 Automation 130 ··· 144 145 Configuration 146 147 + - [x] Enhanced `config` command implementation (basic stubbed version) 148 - [ ] `undo` - Reverse last operation 149 - [ ] Themes and personalization 150 - [ ] Customizable output formats ··· 206 We've got inconsistent argument parsing and sanitization leading to calls to strconv.Atoi in tests & handler funcs. 207 This is only done correctly in the note command -> handler sequence 208 209 + - [ ] TaskCommand 210 + - [ ] MovieCommand 211 + - [ ] TVCommand 212 + - [ ] BookCommand 213 + 214 ### Movie Commands - Missing Tests 215 216 + - [x] movie watched [id] - marks movie as watched 217 218 ### TV Commands - Missing Tests 219 220 + - [x] tv watching [id] - marks TV show as watching 221 + - [x] tv watched [id] - marks TV show as watched 222 223 ### Book Commands - Missing Tests 224 225 + - [x] book add [search query...] - search and add book 226 + - [x] book reading `<id>` - marks book as reading 227 + - [x] book finished `<id>` - marks book as finished 228 + - [x] book progress `<id>` `<percentage>` - updates reading progress 229 + 230 + ## Ideas 231 + 232 + ### Task Management Enhancements 233 + 234 + - Sub-tasks and hierarchical tasks - Break complex tasks into child tasks for better organization 235 + - Linking - Establish relationships between related tasks without strict dependencies 236 + - Batching - Group related tasks for bulk operations (completion, priority changes, etc.) 237 + - Retrospectives - Analysis of completed tasks to improve future estimates and planning 238 + - Automation rules - Create rules that automatically modify tasks based on conditions 239 + - Habit formation - Track recurring micro-tasks that build into larger goals 240 + - Context switching - Automatically adjust system settings, apps, or environment based on current task 241 + - Forecasting - Predict future tasks based on patterns, calendar events, or seasonal trends 242 + - "Energy" matching - Recommend tasks based on current energy levels or time of day 243 + - Priority rebalancing - Automatically suggest priority adjustments based on deadlines and importance 244 + - Dependency visualization: Visual flow charts showing how tasks connect and block each other 245 + 246 + ### Media Management Enhancements 247 + 248 + - Podcast management: Add podcast tracking with episode progress and subscription management 249 + - YouTube/video content management: Track video content queues and viewing progress 250 + - Multi-format media support: Include audiobooks, comics, and other content formats 251 + - Media consumption goals: Set reading/watching goals (e.g., "2 books per month") 252 + - Media cross-referencing: Connect related content across different media types 253 + - Series 254 + - Media note integration: Link notes to specific books, movies, or shows for reviews 255 + - Review system - Write and store personal reviews of consumed content 256 + - Media budget tracking: Track spending on media content (subscriptions, purchases) 257 + - Media consumption patterns: Analyze personal consumption patterns and preferences over time 258 + - Media seasonal tracking: Track seasonal media preferences and suggest accordingly 259 + - Media completion streaks: Gamification elements for consistent media consumption 260 + - Media progress synchronization: Sync progress across different devices or platforms 261 + 262 + ### Notes Management Enhancements 263 264 + - Linking and graph view: Create bidirectional links between related notes 265 + - Templates system: Predefined templates for different note types (meeting notes, book summaries) 266 + - Versioning and history: Track changes to notes over time with ability to revert 267 + - Export with formatting: Rich export options with preserved formatting and links 268 + - Import capabilities: Import notes from other systems (Notion, Evernote, etc.) 269 + - Content extraction: Extract key points or action items from longer notes 270 + - Encryption: End-to-end encryption for sensitive notes 271 + - Content validation: Check for broken links, missing references, or inconsistent information 272 + 273 + ### System Integration & Automation 274 + 275 + - Calendar integration: Sync tasks with calendar systems (Google Calendar, Outlook) 276 + - Email integration: Create tasks or notes from emails automatically 277 + - Browser extension: Quick capture of web content as tasks or notes 278 + - IDE/plugin integration: Direct integration with code editors and development environments 279 + - File system integration: Monitor files for content that should become tasks or notes 280 + 281 + ### Advanced UI/UX Features 282 + 283 + - Customizable themes: Multiple visual themes and color schemes 284 + - Terminal interface enhancements: Rich TUI with advanced navigation and visualization 285 + - Web-based interface: Alternative web UI for browser-based access 286 + - Advanced filtering and sorting: Complex query systems for data manipulation 287 + - Visual task mapping: Gantt charts, Kanban boards, and other visual representations 288 + - Quick entry mode: Rapid capture interface for minimal friction 289 + - Keyboard customization: Fully customizable keyboard shortcuts 290 + 291 + ### Security and Privacy 292 + 293 + - End-to-end encryption: Full encryption of sensitive data 294 + - Local-first architecture: Guarantee that all data remains local
+7 -3
cmd/task_commands.go
··· 149 Aliases: []string{"proj"}, 150 RunE: func(c *cobra.Command, args []string) error { 151 static, _ := c.Flags().GetBool("static") 152 153 defer h.Close() 154 - return h.ListProjects(c.Context(), static) 155 }, 156 } 157 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 158 159 return cmd 160 } ··· 256 cmd := &cobra.Command{ 257 Use: "contexts", 258 Short: "List contexts (locations)", 259 - Aliases: []string{"loc", "ctx", "locations"}, 260 RunE: func(c *cobra.Command, args []string) error { 261 static, _ := c.Flags().GetBool("static") 262 263 defer h.Close() 264 - return h.ListContexts(c.Context(), static) 265 }, 266 } 267 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 268 return cmd 269 } 270
··· 149 Aliases: []string{"proj"}, 150 RunE: func(c *cobra.Command, args []string) error { 151 static, _ := c.Flags().GetBool("static") 152 + todoTxt, _ := c.Flags().GetBool("todo-txt") 153 154 defer h.Close() 155 + return h.ListProjects(c.Context(), static, todoTxt) 156 }, 157 } 158 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 159 + cmd.Flags().Bool("todo-txt", false, "Format output with +project prefix for todo.txt compatibility") 160 161 return cmd 162 } ··· 258 cmd := &cobra.Command{ 259 Use: "contexts", 260 Short: "List contexts (locations)", 261 + Aliases: []string{"con", "loc", "ctx", "locations"}, 262 RunE: func(c *cobra.Command, args []string) error { 263 static, _ := c.Flags().GetBool("static") 264 + todoTxt, _ := c.Flags().GetBool("todo-txt") 265 266 defer h.Close() 267 + return h.ListContexts(c.Context(), static, todoTxt) 268 }, 269 } 270 cmd.Flags().Bool("static", false, "Use static text output instead of interactive") 271 + cmd.Flags().Bool("todo-txt", false, "Format output with @context prefix for todo.txt compatibility") 272 return cmd 273 } 274
+3
docs/manual/README.md
···
··· 1 + # Manual 2 + 3 + This is user facing documentation
+24 -13
internal/handlers/tasks.go
··· 505 } 506 507 // ListProjects lists all projects with their task counts 508 - func (h *TaskHandler) ListProjects(ctx context.Context, static bool) error { 509 if static { 510 - return h.listProjectsStatic(ctx) 511 } 512 - return h.listProjectsInteractive(ctx) 513 } 514 515 - func (h *TaskHandler) listProjectsStatic(ctx context.Context) error { 516 tasks, err := h.repos.Tasks.List(ctx, repo.TaskListOptions{}) 517 if err != nil { 518 return fmt.Errorf("failed to list tasks for projects: %w", err) ··· 539 fmt.Printf("Found %d project(s):\n\n", len(projects)) 540 for _, project := range projects { 541 count := projectCounts[project] 542 - fmt.Printf("%s (%d task%s)\n", project, count, pluralize(count)) 543 } 544 545 return nil 546 } 547 548 - func (h *TaskHandler) listProjectsInteractive(ctx context.Context) error { 549 projectTable := ui.NewProjectListFromTable(h.repos.Tasks, nil, nil, false) 550 return projectTable.Browse(ctx) 551 } ··· 560 } 561 562 // ListContexts lists all contexts with their task counts 563 - func (h *TaskHandler) ListContexts(ctx context.Context, static bool) error { 564 if static { 565 - return h.listContextsStatic(ctx) 566 } 567 - return h.listContextsInteractive(ctx) 568 } 569 570 - func (h *TaskHandler) listContextsStatic(ctx context.Context) error { 571 tasks, err := h.repos.Tasks.List(ctx, repo.TaskListOptions{}) 572 if err != nil { 573 return fmt.Errorf("failed to list tasks for contexts: %w", err) ··· 594 fmt.Printf("Found %d context(s):\n\n", len(contexts)) 595 for _, context := range contexts { 596 count := contextCounts[context] 597 - fmt.Printf("%s (%d task%s)\n", context, count, pluralize(count)) 598 } 599 600 return nil 601 } 602 603 - func (h *TaskHandler) listContextsInteractive(ctx context.Context) error { 604 fmt.Println("Interactive context listing not implemented yet - using static mode") 605 - return h.listContextsStatic(ctx) 606 } 607 608 func (h *TaskHandler) listTagsStatic(ctx context.Context) error {
··· 505 } 506 507 // ListProjects lists all projects with their task counts 508 + func (h *TaskHandler) ListProjects(ctx context.Context, static bool, todoTxt ...bool) error { 509 + useTodoTxt := len(todoTxt) > 0 && todoTxt[0] 510 if static { 511 + return h.listProjectsStatic(ctx, useTodoTxt) 512 } 513 + return h.listProjectsInteractive(ctx, useTodoTxt) 514 } 515 516 + func (h *TaskHandler) listProjectsStatic(ctx context.Context, todoTxt bool) error { 517 tasks, err := h.repos.Tasks.List(ctx, repo.TaskListOptions{}) 518 if err != nil { 519 return fmt.Errorf("failed to list tasks for projects: %w", err) ··· 540 fmt.Printf("Found %d project(s):\n\n", len(projects)) 541 for _, project := range projects { 542 count := projectCounts[project] 543 + if todoTxt { 544 + fmt.Printf("+%s (%d task%s)\n", project, count, pluralize(count)) 545 + } else { 546 + fmt.Printf("%s (%d task%s)\n", project, count, pluralize(count)) 547 + } 548 } 549 550 return nil 551 } 552 553 + // TODO: Add todo.txt format support to interactive mode 554 + func (h *TaskHandler) listProjectsInteractive(ctx context.Context, _ bool) error { 555 projectTable := ui.NewProjectListFromTable(h.repos.Tasks, nil, nil, false) 556 return projectTable.Browse(ctx) 557 } ··· 566 } 567 568 // ListContexts lists all contexts with their task counts 569 + func (h *TaskHandler) ListContexts(ctx context.Context, static bool, todoTxt ...bool) error { 570 + useTodoTxt := len(todoTxt) > 0 && todoTxt[0] 571 if static { 572 + return h.listContextsStatic(ctx, useTodoTxt) 573 } 574 + return h.listContextsInteractive(ctx, useTodoTxt) 575 } 576 577 + func (h *TaskHandler) listContextsStatic(ctx context.Context, todoTxt bool) error { 578 tasks, err := h.repos.Tasks.List(ctx, repo.TaskListOptions{}) 579 if err != nil { 580 return fmt.Errorf("failed to list tasks for contexts: %w", err) ··· 601 fmt.Printf("Found %d context(s):\n\n", len(contexts)) 602 for _, context := range contexts { 603 count := contextCounts[context] 604 + if todoTxt { 605 + fmt.Printf("@%s (%d task%s)\n", context, count, pluralize(count)) 606 + } else { 607 + fmt.Printf("%s (%d task%s)\n", context, count, pluralize(count)) 608 + } 609 } 610 611 return nil 612 } 613 614 + func (h *TaskHandler) listContextsInteractive(ctx context.Context, todoTxt bool) error { 615 fmt.Println("Interactive context listing not implemented yet - using static mode") 616 + return h.listContextsStatic(ctx, todoTxt) 617 } 618 619 func (h *TaskHandler) listTagsStatic(ctx context.Context) error {