ruby_todo 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/ruby_todo/ai_assistant/task_creator.rb +25 -2
- data/lib/ruby_todo/commands/ai_assistant.rb +174 -2
- data/lib/ruby_todo/version.rb +1 -1
- metadata +2 -4
- data/sorted_tests.txt +0 -59
- data/test_methods.txt +0 -59
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ba44da4ec50889bd3ad526d25b43b8157093215303b25874a7038c2d76b1b1d
|
4
|
+
data.tar.gz: eed6527b7f09388a8ad7abae9563f409e497ac06858bc0f39d4c92186cb9902a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5deb1f7d58a8cb0bd3de5d96ec1bd03fe71f3b0e0c3b3c88f2ade4ce0d980c650cc691e897f63100d6ce83415f364aef436cf8d5d07a747982d0cf8a4afa68f
|
7
|
+
data.tar.gz: 75d18f85223d81795a229bbdca14cfe54d0a8b3536610dbc72e0fba91fb24cbc178d5423211255aedb5296211e3f92c7a89e5524dc40c4bd2545fa4dc78b191a
|
data/CHANGELOG.md
CHANGED
@@ -62,7 +62,7 @@ module RubyTodo
|
|
62
62
|
"action-oriented titles. For example, 'add new relic infra to questions-engine' should become " \
|
63
63
|
"'Integrate New Relic Infrastructure with Questions Engine'\n" \
|
64
64
|
"- description: A detailed description of what the task involves\n" \
|
65
|
-
"- priority: Suggested priority (high, medium, or low)\n" \
|
65
|
+
"- priority: Suggested priority (must be exactly one of: 'high', 'medium', or 'low')\n" \
|
66
66
|
"- tags: Relevant tags as a comma-separated string"
|
67
67
|
end
|
68
68
|
end
|
@@ -83,8 +83,12 @@ module RubyTodo
|
|
83
83
|
- "fix login bug" → "Resolve Authentication Issue in Login System"
|
84
84
|
- "add monitoring to service" → "Implement Comprehensive Monitoring Solution for Service"
|
85
85
|
- "migrate repo to new org" → "Migrate Repository to New Organization Structure"
|
86
|
+
- "add newrelic to the questions engine app" → "Integrate New Relic Monitoring with Questions Engine Application"
|
87
|
+
- "create a new task to add newrelic to the questions engine app" → "Implement New Relic Monitoring for Questions Engine Application"
|
86
88
|
|
87
89
|
Create concise but descriptive titles that use proper capitalization and professional terminology.
|
90
|
+
|
91
|
+
IMPORTANT: For priority field, you MUST use ONLY one of these exact values: "high", "medium", or "low" (lowercase).
|
88
92
|
PROMPT
|
89
93
|
|
90
94
|
messages = [
|
@@ -143,11 +147,27 @@ module RubyTodo
|
|
143
147
|
{
|
144
148
|
"title" => title_match ? title_match[1] : "Task from #{task_description}",
|
145
149
|
"description" => desc_match ? desc_match[1] : task_description,
|
146
|
-
"priority" => priority_match ? priority_match[1] : "medium",
|
150
|
+
"priority" => priority_match ? normalize_priority(priority_match[1]) : "medium",
|
147
151
|
"tags" => tags_match ? tags_match[1] : ""
|
148
152
|
}
|
149
153
|
end
|
150
154
|
|
155
|
+
# Normalize priority to ensure it matches allowed values
|
156
|
+
def normalize_priority(priority)
|
157
|
+
priority = priority.downcase.strip
|
158
|
+
return priority if %w[high medium low].include?(priority)
|
159
|
+
|
160
|
+
# Map similar terms to valid priorities
|
161
|
+
case priority
|
162
|
+
when /^h/i, "important", "urgent", "critical"
|
163
|
+
"high"
|
164
|
+
when /^l/i, "minor", "trivial"
|
165
|
+
"low"
|
166
|
+
else
|
167
|
+
"medium" # Default fallback
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
151
171
|
# Create a task from the generated details
|
152
172
|
def create_task_from_details(notebook_name, task_details)
|
153
173
|
# Ensure we have a valid notebook
|
@@ -175,6 +195,9 @@ module RubyTodo
|
|
175
195
|
say "✨ Enhanced title: \"#{task_details["title"]}\"", :green
|
176
196
|
end
|
177
197
|
|
198
|
+
# Ensure priority is properly normalized before passing to CLI
|
199
|
+
task_details["priority"] = normalize_priority(task_details["priority"]) if task_details["priority"]
|
200
|
+
|
178
201
|
args = ["task:add", notebook_name, task_details["title"]]
|
179
202
|
args << "--description" << task_details["description"] if task_details["description"]
|
180
203
|
args << "--priority" << task_details["priority"] if task_details["priority"]
|
@@ -705,6 +705,155 @@ module RubyTodo
|
|
705
705
|
include ExportProcessingHelpers
|
706
706
|
end
|
707
707
|
|
708
|
+
# Module for handling task movement-related functionality
|
709
|
+
module TaskMovementHelpers
|
710
|
+
# Handle moving tasks by title or search term
|
711
|
+
def handle_move_task_by_title(prompt, _cli)
|
712
|
+
# Pattern for "move the task about X to status"
|
713
|
+
task_about_pattern = /
|
714
|
+
move\s+(?:the\s+)?(?:task|tasks)\s+
|
715
|
+
(?:about|with|containing|related\s+to)\s+
|
716
|
+
([\w\s\-]+)\s+to\s+
|
717
|
+
(todo|in[\s_-]?progress|done|archived)
|
718
|
+
/ix
|
719
|
+
|
720
|
+
if prompt.match?(task_about_pattern)
|
721
|
+
match = prompt.match(task_about_pattern)
|
722
|
+
search_term = match[1].strip
|
723
|
+
status = match[2].downcase
|
724
|
+
|
725
|
+
# Normalize status (ensure 'in progress' becomes 'in_progress')
|
726
|
+
status = "in_progress" if status.match?(/in.*progress/i)
|
727
|
+
|
728
|
+
# Find tasks that match the search term
|
729
|
+
all_notebooks = RubyTodo::Notebook.all
|
730
|
+
matched_tasks = []
|
731
|
+
|
732
|
+
all_notebooks.each do |notebook|
|
733
|
+
notebook.tasks.each do |task|
|
734
|
+
next unless task.title.downcase.include?(search_term.downcase) ||
|
735
|
+
(task.description && task.description.downcase.include?(search_term.downcase))
|
736
|
+
|
737
|
+
matched_tasks << { notebook: notebook, task: task }
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
if matched_tasks.empty?
|
742
|
+
say "No tasks found matching '#{search_term}'".yellow
|
743
|
+
return true
|
744
|
+
end
|
745
|
+
|
746
|
+
# Move each matched task
|
747
|
+
moved_count = 0
|
748
|
+
matched_tasks.each do |task_info|
|
749
|
+
if task_info[:task].update(status: status)
|
750
|
+
say "Moved task #{task_info[:task].id}: '#{task_info[:task].title}' to #{status}".green
|
751
|
+
moved_count += 1
|
752
|
+
else
|
753
|
+
say "Error moving task #{task_info[:task].id}: #{task_info[:task].errors.full_messages.join(", ")}".red
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
say "Moved #{moved_count} task(s) to #{status}".green if moved_count > 0
|
758
|
+
return true
|
759
|
+
end
|
760
|
+
|
761
|
+
# Pattern for direct task title movement - "move [title] to [status]"
|
762
|
+
if prompt.match?(%r{move\s+(?:task\s+)?([\w\s\-/'"]+?)\s+to\s+(todo|in[\s_-]?progress|done|archived)}i)
|
763
|
+
match = prompt.match(%r{move\s+(?:task\s+)?([\w\s\-/'"]+?)\s+to\s+(todo|in[\s_-]?progress|done|archived)}i)
|
764
|
+
title_text = match[1].strip
|
765
|
+
status = match[2].downcase
|
766
|
+
|
767
|
+
# Clean up the title by removing quotes
|
768
|
+
title_text = title_text.gsub(/^['"]|['"]$/, "")
|
769
|
+
|
770
|
+
# Normalize status
|
771
|
+
status = "in_progress" if status.match?(/in.*progress/i)
|
772
|
+
|
773
|
+
# Find tasks that match the title
|
774
|
+
all_notebooks = RubyTodo::Notebook.all
|
775
|
+
matched_tasks = []
|
776
|
+
|
777
|
+
all_notebooks.each do |notebook|
|
778
|
+
notebook.tasks.each do |task|
|
779
|
+
next unless task.title.downcase.include?(title_text.downcase)
|
780
|
+
|
781
|
+
matched_tasks << { notebook: notebook, task: task }
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
if matched_tasks.empty?
|
786
|
+
say "No tasks found matching '#{title_text}'".yellow
|
787
|
+
return true
|
788
|
+
end
|
789
|
+
|
790
|
+
# Move each matched task
|
791
|
+
moved_count = 0
|
792
|
+
matched_tasks.each do |task_info|
|
793
|
+
if task_info[:task].update(status: status)
|
794
|
+
say "Moved task #{task_info[:task].id}: '#{task_info[:task].title}' to #{status}".green
|
795
|
+
moved_count += 1
|
796
|
+
else
|
797
|
+
say "Error moving task #{task_info[:task].id}: #{task_info[:task].errors.full_messages.join(", ")}".red
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
say "Moved #{moved_count} task(s) to #{status}".green if moved_count > 0
|
802
|
+
return true
|
803
|
+
end
|
804
|
+
|
805
|
+
# Specific pattern for "move task(s) with title X to status"
|
806
|
+
task_with_title_pattern = /
|
807
|
+
move\s+(?:the\s+)?(?:task|tasks)\s+
|
808
|
+
with\s+(?:title|name)\s+
|
809
|
+
["']([^"']+)["']\s+to\s+
|
810
|
+
(todo|in[\s_-]?progress|done|archived)
|
811
|
+
/ix
|
812
|
+
|
813
|
+
if prompt.match?(task_with_title_pattern)
|
814
|
+
match = prompt.match(task_with_title_pattern)
|
815
|
+
exact_title = match[1]
|
816
|
+
status = match[2].downcase
|
817
|
+
|
818
|
+
# Normalize status
|
819
|
+
status = "in_progress" if status.match?(/in.*progress/i)
|
820
|
+
|
821
|
+
# Find tasks that match the exact title
|
822
|
+
all_notebooks = RubyTodo::Notebook.all
|
823
|
+
matched_tasks = []
|
824
|
+
|
825
|
+
all_notebooks.each do |notebook|
|
826
|
+
notebook.tasks.each do |task|
|
827
|
+
next unless task.title.downcase == exact_title.downcase
|
828
|
+
|
829
|
+
matched_tasks << { notebook: notebook, task: task }
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
if matched_tasks.empty?
|
834
|
+
say "No tasks found with title '#{exact_title}'".yellow
|
835
|
+
return true
|
836
|
+
end
|
837
|
+
|
838
|
+
# Move each matched task
|
839
|
+
moved_count = 0
|
840
|
+
matched_tasks.each do |task_info|
|
841
|
+
if task_info[:task].update(status: status)
|
842
|
+
say "Moved task #{task_info[:task].id}: '#{task_info[:task].title}' to #{status}".green
|
843
|
+
moved_count += 1
|
844
|
+
else
|
845
|
+
say "Error moving task #{task_info[:task].id}: #{task_info[:task].errors.full_messages.join(", ")}".red
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
849
|
+
say "Moved #{moved_count} task(s) to #{status}".green if moved_count > 0
|
850
|
+
return true
|
851
|
+
end
|
852
|
+
|
853
|
+
false
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
708
857
|
# Main AI Assistant command class
|
709
858
|
class AIAssistantCommand < Thor
|
710
859
|
include OpenAIIntegration
|
@@ -714,6 +863,7 @@ module RubyTodo
|
|
714
863
|
include AIAssistantHelpers
|
715
864
|
include StatusFilteringHelpers
|
716
865
|
include ExportHelpers
|
866
|
+
include TaskMovementHelpers
|
717
867
|
|
718
868
|
desc "ask [PROMPT]", "Ask the AI assistant to perform tasks using natural language"
|
719
869
|
method_option :api_key, type: :string, desc: "OpenAI API key"
|
@@ -837,9 +987,10 @@ module RubyTodo
|
|
837
987
|
# Create a CLI instance for executing commands
|
838
988
|
cli = RubyTodo::CLI.new
|
839
989
|
|
840
|
-
# Special case: handling natural language task creation
|
990
|
+
# Special case: handling natural language task creation with title enhancement
|
841
991
|
if prompt.match?(/create(?:\s+a)?\s+(?:new\s+)?task\s+(?:to|for|about)\s+(.+)/i)
|
842
|
-
|
992
|
+
task_description = prompt.match(/create(?:\s+a)?\s+(?:new\s+)?task\s+(?:to|for|about)\s+(.+)/i)[1].strip
|
993
|
+
handle_task_creation_with_enhancement(task_description, api_key)
|
843
994
|
return
|
844
995
|
end
|
845
996
|
|
@@ -878,6 +1029,7 @@ module RubyTodo
|
|
878
1029
|
return true if handle_documentation_task_specific_patterns(prompt)
|
879
1030
|
return true if handle_task_creation_patterns(prompt, cli)
|
880
1031
|
return true if handle_task_status_patterns(prompt)
|
1032
|
+
return true if handle_move_task_by_title(prompt, cli)
|
881
1033
|
return true if handle_export_task_patterns(prompt)
|
882
1034
|
return true if handle_notebook_operations(prompt, cli)
|
883
1035
|
return true if handle_task_operations(prompt, cli)
|
@@ -1688,6 +1840,26 @@ module RubyTodo
|
|
1688
1840
|
end
|
1689
1841
|
end
|
1690
1842
|
|
1843
|
+
# Enhanced task creation that uses AI to improve titles
|
1844
|
+
def handle_task_creation_with_enhancement(task_description, api_key)
|
1845
|
+
# Get the default notebook
|
1846
|
+
notebook_name = default_notebook_name
|
1847
|
+
|
1848
|
+
# Log the original description if in verbose mode
|
1849
|
+
say "Original task description: #{task_description}" if @options[:verbose]
|
1850
|
+
|
1851
|
+
# Generate task details using AI
|
1852
|
+
task_details = generate_task_details(task_description, api_key)
|
1853
|
+
|
1854
|
+
# Log the enhanced title for better UX
|
1855
|
+
if task_details["title"] && task_details["title"] != task_description
|
1856
|
+
say "✨ Enhanced title: \"#{task_details["title"]}\"".green
|
1857
|
+
end
|
1858
|
+
|
1859
|
+
# Create the task with the enhanced details
|
1860
|
+
create_task_from_details(notebook_name, task_details)
|
1861
|
+
end
|
1862
|
+
|
1691
1863
|
def handle_natural_language_task_creation(prompt, _api_key)
|
1692
1864
|
# Make sure Ruby Todo is initialized
|
1693
1865
|
initialize_ruby_todo
|
data/lib/ruby_todo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_todo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremiah Parrack
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -243,8 +243,6 @@ files:
|
|
243
243
|
- progress_ai_test.md
|
244
244
|
- protectors_tasks.json
|
245
245
|
- sig/ruby_todo.rbs
|
246
|
-
- sorted_tests.txt
|
247
|
-
- test_methods.txt
|
248
246
|
- todo_tasks_export_20250331.json
|
249
247
|
homepage: https://github.com/jeremiahlukus/ruby_todo
|
250
248
|
licenses:
|
data/sorted_tests.txt
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
test_ai_ambiguous_notebook_reference
|
2
|
-
test_ai_basic_functionality
|
3
|
-
test_ai_batch_task_update_by_keyword
|
4
|
-
test_ai_batch_task_update_by_tag
|
5
|
-
test_ai_complex_task_creation_with_natural_language
|
6
|
-
test_ai_conversational_export_requests
|
7
|
-
test_ai_conversational_request_for_notebook_contents
|
8
|
-
test_ai_create_default_notebook_for_task
|
9
|
-
test_ai_create_multiple_infrastructure_tasks
|
10
|
-
test_ai_create_notebook
|
11
|
-
test_ai_create_task_with_attributes
|
12
|
-
test_ai_date_based_export_request
|
13
|
-
test_ai_default_notebook_remains_when_adding_new_notebook
|
14
|
-
test_ai_display_in_progress_status_tasks
|
15
|
-
test_ai_display_tasks_that_are_in_progress
|
16
|
-
test_ai_empty_prompt
|
17
|
-
test_ai_explicit_default_notebook_commands
|
18
|
-
test_ai_export_archived_tasks
|
19
|
-
test_ai_export_done_tasks
|
20
|
-
test_ai_export_done_tasks_to_csv
|
21
|
-
test_ai_export_done_tasks_with_custom_filename
|
22
|
-
test_ai_export_in_progress_tasks
|
23
|
-
test_ai_export_nonexistent_status
|
24
|
-
test_ai_export_tasks_to_different_formats
|
25
|
-
test_ai_export_tasks_with_status
|
26
|
-
test_ai_export_todo_tasks
|
27
|
-
test_ai_export_with_custom_parameters
|
28
|
-
test_ai_export_with_different_status_formats
|
29
|
-
test_ai_export_with_no_done_tasks
|
30
|
-
test_ai_handle_multiple_requests_in_one_prompt
|
31
|
-
test_ai_handles_both_normal_and_medium_terms
|
32
|
-
test_ai_invalid_api_key
|
33
|
-
test_ai_invalid_status
|
34
|
-
test_ai_invalid_task_id
|
35
|
-
test_ai_list_tasks_in_notebook
|
36
|
-
test_ai_list_tasks_that_are_in_todo_status
|
37
|
-
test_ai_list_tasks_with_in_progress_hyphenated
|
38
|
-
test_ai_list_tasks_with_in_progress_status
|
39
|
-
test_ai_list_tasks_with_status_in_progress
|
40
|
-
test_ai_list_tasks_with_todo_status
|
41
|
-
test_ai_multiple_specific_task_update
|
42
|
-
test_ai_natural_language_task_creation
|
43
|
-
test_ai_never_uses_normal_priority
|
44
|
-
test_ai_nonexistent_notebook
|
45
|
-
test_ai_notebook_listing
|
46
|
-
test_ai_sets_medium_priority_by_default
|
47
|
-
test_ai_show_in_progress_tasks_alternative_phrasing
|
48
|
-
test_ai_show_tasks_having_in_progress_status
|
49
|
-
test_ai_show_todo_tasks_alternative_phrasing
|
50
|
-
test_ai_statistics_request
|
51
|
-
test_ai_task_creation_suggestion
|
52
|
-
test_ai_task_list
|
53
|
-
test_ai_task_listing
|
54
|
-
test_ai_task_movement_with_natural_language
|
55
|
-
test_ai_task_search
|
56
|
-
test_ai_task_status_update
|
57
|
-
test_ai_task_with_invalid_attributes
|
58
|
-
test_notebook_commands_with_explicit_methods
|
59
|
-
test_template_commands_with_explicit_methods
|
data/test_methods.txt
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
test_ai_basic_functionality
|
2
|
-
test_ai_task_creation_suggestion
|
3
|
-
test_ai_task_listing
|
4
|
-
test_ai_task_status_update
|
5
|
-
test_ai_task_search
|
6
|
-
test_ai_notebook_listing
|
7
|
-
test_ai_create_notebook
|
8
|
-
test_ai_create_task_with_attributes
|
9
|
-
test_ai_list_tasks_in_notebook
|
10
|
-
test_ai_export_done_tasks
|
11
|
-
test_ai_export_done_tasks_to_csv
|
12
|
-
test_ai_export_done_tasks_with_custom_filename
|
13
|
-
test_ai_export_in_progress_tasks
|
14
|
-
test_ai_export_todo_tasks
|
15
|
-
test_ai_export_archived_tasks
|
16
|
-
test_ai_export_tasks_with_status
|
17
|
-
test_ai_export_tasks_to_different_formats
|
18
|
-
test_ai_conversational_export_requests
|
19
|
-
test_ai_export_with_different_status_formats
|
20
|
-
test_ai_export_nonexistent_status
|
21
|
-
test_ai_export_with_custom_parameters
|
22
|
-
test_ai_list_tasks_with_in_progress_status
|
23
|
-
test_ai_show_in_progress_tasks_alternative_phrasing
|
24
|
-
test_ai_list_tasks_with_status_in_progress
|
25
|
-
test_ai_list_tasks_with_todo_status
|
26
|
-
test_ai_show_todo_tasks_alternative_phrasing
|
27
|
-
test_ai_statistics_request
|
28
|
-
test_ai_batch_task_update_by_tag
|
29
|
-
test_ai_batch_task_update_by_keyword
|
30
|
-
test_ai_multiple_specific_task_update
|
31
|
-
test_ai_empty_prompt
|
32
|
-
test_ai_invalid_api_key
|
33
|
-
test_ai_nonexistent_notebook
|
34
|
-
test_ai_invalid_task_id
|
35
|
-
test_ai_invalid_status
|
36
|
-
test_ai_task_with_invalid_attributes
|
37
|
-
test_ai_export_with_no_done_tasks
|
38
|
-
test_ai_ambiguous_notebook_reference
|
39
|
-
test_ai_complex_task_creation_with_natural_language
|
40
|
-
test_ai_conversational_request_for_notebook_contents
|
41
|
-
test_ai_date_based_export_request
|
42
|
-
test_ai_task_movement_with_natural_language
|
43
|
-
test_ai_natural_language_task_creation
|
44
|
-
test_ai_task_list
|
45
|
-
test_notebook_commands_with_explicit_methods
|
46
|
-
test_template_commands_with_explicit_methods
|
47
|
-
test_ai_list_tasks_with_in_progress_hyphenated
|
48
|
-
test_ai_show_tasks_having_in_progress_status
|
49
|
-
test_ai_display_in_progress_status_tasks
|
50
|
-
test_ai_list_tasks_that_are_in_todo_status
|
51
|
-
test_ai_display_tasks_that_are_in_progress
|
52
|
-
test_ai_create_multiple_infrastructure_tasks
|
53
|
-
test_ai_handle_multiple_requests_in_one_prompt
|
54
|
-
test_ai_never_uses_normal_priority
|
55
|
-
test_ai_sets_medium_priority_by_default
|
56
|
-
test_ai_create_default_notebook_for_task
|
57
|
-
test_ai_default_notebook_remains_when_adding_new_notebook
|
58
|
-
test_ai_handles_both_normal_and_medium_terms
|
59
|
-
test_ai_explicit_default_notebook_commands
|