todo-agent 0.3.2__py3-none-any.whl → 0.3.5__py3-none-any.whl

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.
@@ -16,7 +16,7 @@ Task Management Tools:
16
16
  - append_to_task(task_number, text) - Add text to end of existing task
17
17
  - prepend_to_task(task_number, text) - Add text to beginning of existing task
18
18
  - delete_task(task_number, term?) - Delete entire task or remove specific term
19
- - created_completed_task(description, completion_date?, project?, context?) - Create task and immediately mark as completed
19
+ - create_completed_task(description, completion_date?, project?, context?) - Create task and immediately mark as completed
20
20
 
21
21
  Priority Management Tools:
22
22
  - set_priority(task_number, priority) - Set or change task priority (A-Z)
@@ -26,6 +26,7 @@ Task Modification Tools:
26
26
  - set_due_date(task_number, due_date) - Set or update due date for a task by intelligently rewriting it (use empty string to remove due date)
27
27
  - set_context(task_number, context) - Set or update context for a task by intelligently rewriting it (use empty string to remove context)
28
28
  - set_project(task_number, projects) - Set or update projects for a task by intelligently rewriting it (handles array of projects with add/remove operations)
29
+ - set_parent(task_number, parent_number) - Set or update parent task number for a task by intelligently rewriting it (use None to remove parent)
29
30
 
30
31
  Utility Tools:
31
32
  - move_task(task_number, destination, source?) - Move task between files
@@ -176,11 +177,15 @@ class ToolCallHandler:
176
177
  "type": "string",
177
178
  "description": "Optional duration estimate in format: minutes (e.g., '30m'), hours (e.g., '2h'), or days (e.g., '1d'). Use for time planning and task prioritization.",
178
179
  },
180
+ "parent_number": {
181
+ "type": "integer",
182
+ "description": "Optional parent task number (required for subtasks)",
183
+ },
179
184
  },
180
185
  "required": ["description"],
181
186
  },
182
187
  },
183
- "progress_description": " Creating new task...",
188
+ "progress_description": " Creating new task: {description}...",
184
189
  },
185
190
  {
186
191
  "type": "function",
@@ -204,7 +209,7 @@ class ToolCallHandler:
204
209
  "required": ["task_number"],
205
210
  },
206
211
  },
207
- "progress_description": "🎯 Marking task complete...",
212
+ "progress_description": "🎯 Marking task #{task_number} as complete...",
208
213
  },
209
214
  {
210
215
  "type": "function",
@@ -232,7 +237,7 @@ class ToolCallHandler:
232
237
  "required": ["task_number", "new_description"],
233
238
  },
234
239
  },
235
- "progress_description": "✏️ Updating task description...",
240
+ "progress_description": "✏️ Updating task #{task_number} with new description...",
236
241
  },
237
242
  {
238
243
  "type": "function",
@@ -254,15 +259,15 @@ class ToolCallHandler:
254
259
  "type": "integer",
255
260
  "description": "The line number of the task to modify (required)",
256
261
  },
257
- "text_to_append": {
262
+ "text": {
258
263
  "type": "string",
259
264
  "description": "Text to add to the end of the task (required)",
260
265
  },
261
266
  },
262
- "required": ["task_number", "text_to_append"],
267
+ "required": ["task_number", "text"],
263
268
  },
264
269
  },
265
- "progress_description": "📝 Adding notes to task...",
270
+ "progress_description": "📝 Adding notes to task #{task_number}...",
266
271
  },
267
272
  {
268
273
  "type": "function",
@@ -289,7 +294,7 @@ class ToolCallHandler:
289
294
  "required": ["task_number", "text"],
290
295
  },
291
296
  },
292
- "progress_description": "📝 Adding prefix to task...",
297
+ "progress_description": "📝 Adding prefix to task #{task_number}...",
293
298
  },
294
299
  {
295
300
  "type": "function",
@@ -320,7 +325,7 @@ class ToolCallHandler:
320
325
  "required": ["task_number"],
321
326
  },
322
327
  },
323
- "progress_description": "🗑️ Deleting task...",
328
+ "progress_description": "🗑️ Deleting task #{task_number}...",
324
329
  },
325
330
  {
326
331
  "type": "function",
@@ -348,7 +353,7 @@ class ToolCallHandler:
348
353
  "required": ["task_number", "priority"],
349
354
  },
350
355
  },
351
- "progress_description": "🏷️ Setting priority...",
356
+ "progress_description": "🏷️ Setting priority {priority} for task #{task_number}...",
352
357
  },
353
358
  {
354
359
  "type": "function",
@@ -372,7 +377,7 @@ class ToolCallHandler:
372
377
  "required": ["task_number"],
373
378
  },
374
379
  },
375
- "progress_description": "🏷️ Removing priority...",
380
+ "progress_description": "🏷️ Removing priority from task #{task_number}...",
376
381
  },
377
382
  {
378
383
  "type": "function",
@@ -404,7 +409,7 @@ class ToolCallHandler:
404
409
  "required": ["task_number", "due_date"],
405
410
  },
406
411
  },
407
- "progress_description": "📅 Setting due date...",
412
+ "progress_description": "📅 Setting due date {due_date} for task #{task_number}...",
408
413
  },
409
414
  {
410
415
  "type": "function",
@@ -436,7 +441,7 @@ class ToolCallHandler:
436
441
  "required": ["task_number", "context"],
437
442
  },
438
443
  },
439
- "progress_description": "📍 Setting context...",
444
+ "progress_description": "📍 Setting context {context} for task #{task_number}...",
440
445
  },
441
446
  {
442
447
  "type": "function",
@@ -472,7 +477,40 @@ class ToolCallHandler:
472
477
  "required": ["task_number", "projects"],
473
478
  },
474
479
  },
475
- "progress_description": "🏷️ Setting project tags...",
480
+ "progress_description": "🏷️ Setting project tags for task #{task_number}...",
481
+ },
482
+ {
483
+ "type": "function",
484
+ "function": {
485
+ "name": "set_parent",
486
+ "description": (
487
+ "Set or update the parent task number for an EXISTING task by intelligently rewriting it. "
488
+ "USE CASE: Call this when user wants to add, change, or remove a parent task relationship on an existing task. "
489
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
490
+ "This preserves all existing task components (priority, projects, contexts, due date, etc.) "
491
+ "while updating or adding the parent relationship. Use None to remove the parent. "
492
+ "PREFERRED METHOD: Use this instead of append_to_task() when adding parent tags (parent:XX). "
493
+ "This tool properly manages parent relationships and prevents formatting issues. "
494
+ "IMPORTANT: Use list_tasks() first "
495
+ "to find the correct task number if user doesn't specify it. "
496
+ "Parent task numbers should be provided as integers (e.g., 12 not 'parent:12')."
497
+ ),
498
+ "parameters": {
499
+ "type": "object",
500
+ "properties": {
501
+ "task_number": {
502
+ "type": "integer",
503
+ "description": "The line number of the task to modify (required)",
504
+ },
505
+ "parent_number": {
506
+ "type": "integer",
507
+ "description": "Parent task number to set, or null to remove parent (required)",
508
+ },
509
+ },
510
+ "required": ["task_number", "parent_number"],
511
+ },
512
+ },
513
+ "progress_description": "🔗 Setting parent task {parent_number} for task #{task_number}...",
476
514
  },
477
515
  {
478
516
  "type": "function",
@@ -504,7 +542,7 @@ class ToolCallHandler:
504
542
  "required": ["task_number", "destination"],
505
543
  },
506
544
  },
507
- "progress_description": "📦 Moving task...",
545
+ "progress_description": "📦 Moving task #{task_number} to {destination}...",
508
546
  },
509
547
  {
510
548
  "type": "function",
@@ -544,7 +582,7 @@ class ToolCallHandler:
544
582
  "required": ["date_expression"],
545
583
  },
546
584
  },
547
- "progress_description": "📅 Converting date expression...",
585
+ "progress_description": "📅 Converting date expression '{date_expression}'...",
548
586
  },
549
587
  {
550
588
  "type": "function",
@@ -580,12 +618,12 @@ class ToolCallHandler:
580
618
  "required": ["month", "year"],
581
619
  },
582
620
  },
583
- "progress_description": "📅 Generating calendar...",
621
+ "progress_description": "📅 Generating calendar for {month}/{year}...",
584
622
  },
585
623
  {
586
624
  "type": "function",
587
625
  "function": {
588
- "name": "created_completed_task",
626
+ "name": "create_completed_task",
589
627
  "description": (
590
628
  "Create a task and immediately mark it as completed. "
591
629
  "USE CASE: Call this when user says they completed something on a specific date (e.g., 'I did the laundry today', 'I finished the report yesterday', 'I cleaned the garage last week') "
@@ -615,11 +653,15 @@ class ToolCallHandler:
615
653
  "type": "string",
616
654
  "description": "Optional context name (without the @ symbol) for new task creation",
617
655
  },
656
+ "parent_number": {
657
+ "type": "integer",
658
+ "description": "Optional parent task number (required for subtasks)",
659
+ },
618
660
  },
619
661
  "required": ["description"],
620
662
  },
621
663
  },
622
- "progress_description": "✅ Creating completed task...",
664
+ "progress_description": "✅ Creating completed task: {description}...",
623
665
  },
624
666
  {
625
667
  "type": "function",
@@ -646,7 +688,7 @@ class ToolCallHandler:
646
688
  "required": ["task_number"],
647
689
  },
648
690
  },
649
- "progress_description": "🔄 Restoring completed task...",
691
+ "progress_description": "🔄 Restoring completed task #{task_number}...",
650
692
  },
651
693
  ]
652
694
 
@@ -805,16 +847,16 @@ class ToolCallHandler:
805
847
  """Execute a tool call and return the result."""
806
848
  # Validate tool call structure
807
849
  if not isinstance(tool_call, dict):
808
- return {
850
+ return { # type: ignore[unreachable]
809
851
  "tool_call_id": "unknown",
810
852
  "name": "unknown",
811
853
  "output": "ERROR: Invalid tool call format",
812
854
  "error": True,
813
855
  "error_type": "malformed_tool_call",
814
856
  "error_details": "Tool call is not a dictionary",
815
- "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
857
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation.",
816
858
  }
817
-
859
+
818
860
  if "function" not in tool_call:
819
861
  return {
820
862
  "tool_call_id": tool_call.get("id", "unknown"),
@@ -823,9 +865,9 @@ class ToolCallHandler:
823
865
  "error": True,
824
866
  "error_type": "malformed_tool_call",
825
867
  "error_details": "Tool call missing function field",
826
- "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
868
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation.",
827
869
  }
828
-
870
+
829
871
  function = tool_call["function"]
830
872
  if not isinstance(function, dict):
831
873
  return {
@@ -835,9 +877,9 @@ class ToolCallHandler:
835
877
  "error": True,
836
878
  "error_type": "malformed_tool_call",
837
879
  "error_details": "Function field is not a dictionary",
838
- "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
880
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation.",
839
881
  }
840
-
882
+
841
883
  tool_name = function.get("name")
842
884
  if not tool_name:
843
885
  return {
@@ -847,9 +889,9 @@ class ToolCallHandler:
847
889
  "error": True,
848
890
  "error_type": "malformed_tool_call",
849
891
  "error_details": "Function missing name field",
850
- "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
892
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation.",
851
893
  }
852
-
894
+
853
895
  arguments = function.get("arguments", {})
854
896
  tool_call_id = tool_call.get("id", "unknown")
855
897
 
@@ -897,11 +939,12 @@ class ToolCallHandler:
897
939
  "set_due_date": self.todo_manager.set_due_date,
898
940
  "set_context": self.todo_manager.set_context,
899
941
  "set_project": self.todo_manager.set_project,
942
+ "set_parent": self.todo_manager.set_parent,
900
943
  "move_task": self.todo_manager.move_task,
901
944
  "archive_tasks": self.todo_manager.archive_tasks,
902
945
  "parse_date": self._parse_date,
903
946
  "get_calendar": self._get_calendar,
904
- "created_completed_task": self.todo_manager.created_completed_task,
947
+ "create_completed_task": self.todo_manager.create_completed_task,
905
948
  "restore_completed_task": self.todo_manager.restore_completed_task,
906
949
  }
907
950
 
todo_agent/main.py CHANGED
@@ -11,9 +11,12 @@ from .interface.cli import CLI
11
11
 
12
12
  def main() -> None:
13
13
  """Main application entry point."""
14
+ from ._version import __version__
15
+
14
16
  parser = argparse.ArgumentParser(
15
- description="Todo.sh LLM Agent - Natural language task management",
17
+ description=f"Todo.sh LLM Agent - Natural language task management (v{__version__})",
16
18
  formatter_class=argparse.RawDescriptionHelpFormatter,
19
+ add_help=False,
17
20
  epilog="""
18
21
  Examples:
19
22
  todo-agent # Interactive mode
@@ -23,6 +26,19 @@ Examples:
23
26
  """,
24
27
  )
25
28
 
29
+ parser.add_argument(
30
+ "--version", "-v",
31
+ action="version",
32
+ version=f"%(prog)s {__version__}",
33
+ help="Show version information and exit",
34
+ )
35
+
36
+ parser.add_argument(
37
+ "--help", "-h",
38
+ action="help",
39
+ help="Show this help message and exit",
40
+ )
41
+
26
42
  parser.add_argument(
27
43
  "command",
28
44
  nargs="?",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: todo-agent
3
- Version: 0.3.2
3
+ Version: 0.3.5
4
4
  Summary: A natural language interface for todo.sh task management
5
5
  Author: codeprimate
6
6
  Maintainer: codeprimate
@@ -0,0 +1,30 @@
1
+ todo_agent/__init__.py,sha256=RUowhd14r3tqB_7rl83unGV8oBjra3UOIl7jix-33fk,254
2
+ todo_agent/_version.py,sha256=UAb2Toi6SAdScDfq1uKRRv5QpMUuRtJqqwNxTMGe5Q4,704
3
+ todo_agent/main.py,sha256=DfcZuTsHkmpm6kw0coB0-B677K3hyRwutWIuO4noQ3w,2026
4
+ todo_agent/core/__init__.py,sha256=QAZ4it63pXv5-DxtNcuSAmg7ZnCY5ackI5yycvKHr9I,365
5
+ todo_agent/core/conversation_manager.py,sha256=9aAWogswZe9Cs7wKT47RG-cLh1LQ5D9RbhUHJVUyTS8,13549
6
+ todo_agent/core/exceptions.py,sha256=ilVL5hyPHGYQXsLm0pYivMbhbamupG77r8TbiQr2tAU,2034
7
+ todo_agent/core/todo_manager.py,sha256=qnMT6TOhxvh-e_2IkC8rA87T56iJQ9mHT1AyffrAFr8,25134
8
+ todo_agent/infrastructure/__init__.py,sha256=SGbHXgzq6U1DMgOfWPMsWEK99zjPSF-6gzy7xqc5fsI,284
9
+ todo_agent/infrastructure/calendar_utils.py,sha256=8tOZHN5CNrRHpTQHYzskmsZNJKWuUFjrjyvHQ76AhzU,1837
10
+ todo_agent/infrastructure/config.py,sha256=zyp6qOlg1nN_awphivlgGNBE6fL0Hf66YgvWxR8ldyQ,2117
11
+ todo_agent/infrastructure/inference.py,sha256=nv0ZbYHiJtWOwsN1VoXY1f0Zlf9SOIOVQZDhnAeC1YU,16212
12
+ todo_agent/infrastructure/llm_client.py,sha256=Knb6yvQt0q8mobnwVH08mGCd8xBHK_g1S66DOdp7cO8,9807
13
+ todo_agent/infrastructure/llm_client_factory.py,sha256=-tktnVOIF7B45WR7AuLoi7MKnEyuM8lgg1jjc4T1FhM,1929
14
+ todo_agent/infrastructure/logger.py,sha256=2ykG_0lyzmEGxDF6ZRl1qiTUGDuFeQgzv4Na6vRmXcM,4110
15
+ todo_agent/infrastructure/ollama_client.py,sha256=V_zAeBjIEzB8PZXyzFeiLMLA5qf3y4WV2_6Vqxn1ujc,5629
16
+ todo_agent/infrastructure/openrouter_client.py,sha256=0pxIKvHItwVijFz8l4loOeCa4HUpMvTYROcwYJh3iyI,6748
17
+ todo_agent/infrastructure/todo_shell.py,sha256=2iPPhsLsTcjVx8Wv2mJJBu11kLJOK9Tk5KBAyVQ3Yjs,20596
18
+ todo_agent/infrastructure/token_counter.py,sha256=PCKheOVJbp1s89yhh_i6iKgURMt9mVoYkwjQJCc2xCE,4958
19
+ todo_agent/infrastructure/prompts/system_prompt.txt,sha256=ZHGYgd7lCuWaSX5io3IYWFhdjcGbdqKXf2uhEWdbzQ8,12380
20
+ todo_agent/interface/__init__.py,sha256=vDD3rQu4qDkpvVwGVtkDzE1M4IiSHYzTif4GbYSFWaI,457
21
+ todo_agent/interface/cli.py,sha256=Ikh5AYoOZnNUVXzHjfv2bsE33yK3VhCdzza83HOzFp8,16460
22
+ todo_agent/interface/formatters.py,sha256=a9PW-5DbY8K5QYZjBXFZSdzlCmy263kwBI9nXgP8LXI,20081
23
+ todo_agent/interface/progress.py,sha256=EpPa20Hrnjv_TBIp0tzViVciThqsOvAHuYO4v2rc8eI,1751
24
+ todo_agent/interface/tools.py,sha256=Q6h2zpe1yRUwJOZZFArjXgBN6WPDI56CDQQJcdF1I5M,54448
25
+ todo_agent-0.3.5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
26
+ todo_agent-0.3.5.dist-info/METADATA,sha256=eP-pVo55MQvK1G9b9vaoOhir6fQnjOr4CD-D8n29Ha0,10056
27
+ todo_agent-0.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
+ todo_agent-0.3.5.dist-info/entry_points.txt,sha256=4W7LrCib6AXP5IZDwWRht8S5gutLu5oNfTJHGbt4oHs,52
29
+ todo_agent-0.3.5.dist-info/top_level.txt,sha256=a65mlPIhPZHuq2bRIi_sCMAIJsUddvXt171OBF6r6co,11
30
+ todo_agent-0.3.5.dist-info/RECORD,,
@@ -1,30 +0,0 @@
1
- todo_agent/__init__.py,sha256=RUowhd14r3tqB_7rl83unGV8oBjra3UOIl7jix-33fk,254
2
- todo_agent/_version.py,sha256=e8NqPtZ8fggRgk3GPrqZ_U_BDV8aSULw1u_Gn9NNbnk,704
3
- todo_agent/main.py,sha256=-ryhMm4c4sz4e4anXI8B-CYnpEh5HIkmnYcnGxcWHDk,1628
4
- todo_agent/core/__init__.py,sha256=QAZ4it63pXv5-DxtNcuSAmg7ZnCY5ackI5yycvKHr9I,365
5
- todo_agent/core/conversation_manager.py,sha256=9aAWogswZe9Cs7wKT47RG-cLh1LQ5D9RbhUHJVUyTS8,13549
6
- todo_agent/core/exceptions.py,sha256=kH-xf30H1vlMHk7GTWclkhIdR_mGPylYu4vWiTl7_zA,2058
7
- todo_agent/core/todo_manager.py,sha256=H-cBB0wm9_KdHBWm9bGJVpoNYRgikSegLpFE4QcJOAw,18991
8
- todo_agent/infrastructure/__init__.py,sha256=SGbHXgzq6U1DMgOfWPMsWEK99zjPSF-6gzy7xqc5fsI,284
9
- todo_agent/infrastructure/calendar_utils.py,sha256=8tOZHN5CNrRHpTQHYzskmsZNJKWuUFjrjyvHQ76AhzU,1837
10
- todo_agent/infrastructure/config.py,sha256=zyp6qOlg1nN_awphivlgGNBE6fL0Hf66YgvWxR8ldyQ,2117
11
- todo_agent/infrastructure/inference.py,sha256=lsaxfXu5gJIy9vkX9qbX9jtZL4XGpRT9KNbcNU-4tro,14683
12
- todo_agent/infrastructure/llm_client.py,sha256=zkgET3tbLK7utLzrhKFxLxSDhEeJ2DuCSZ8FFYceZQk,9371
13
- todo_agent/infrastructure/llm_client_factory.py,sha256=-tktnVOIF7B45WR7AuLoi7MKnEyuM8lgg1jjc4T1FhM,1929
14
- todo_agent/infrastructure/logger.py,sha256=2ykG_0lyzmEGxDF6ZRl1qiTUGDuFeQgzv4Na6vRmXcM,4110
15
- todo_agent/infrastructure/ollama_client.py,sha256=9qwY1fdwh9H55HJoNvXZS0xm2ooAXRKqYYsYrmJOetM,5570
16
- todo_agent/infrastructure/openrouter_client.py,sha256=jWzGBnr9tqt4HFGUyVLjjUpM3QGMcdDsjCH6pT3CmFE,6727
17
- todo_agent/infrastructure/todo_shell.py,sha256=NwbXTRF3dLNKzBYPS_4ObG-R1UV1dzXXf2asyKi36x0,17199
18
- todo_agent/infrastructure/token_counter.py,sha256=PCKheOVJbp1s89yhh_i6iKgURMt9mVoYkwjQJCc2xCE,4958
19
- todo_agent/infrastructure/prompts/system_prompt.txt,sha256=yXyYWJeB7IV6QK7NnywdUwPL_dKV0fxUD38hxr2Bc90,22984
20
- todo_agent/interface/__init__.py,sha256=vDD3rQu4qDkpvVwGVtkDzE1M4IiSHYzTif4GbYSFWaI,457
21
- todo_agent/interface/cli.py,sha256=5mUgCz3kJUfko5bVbpkWcMDvDPY_ysJhMEpbQlwBnBY,16226
22
- todo_agent/interface/formatters.py,sha256=81Rud5tw7p3eSsXf6Ifuii8Iy7igT8kkX8eltHZ6l9A,20077
23
- todo_agent/interface/progress.py,sha256=fcBSB1xodQ1xE7iU5hWe_G3t4_rE6lJpoqeCuazTnis,1811
24
- todo_agent/interface/tools.py,sha256=A09LSxbobvHUu8XfEYTYs5uiM7bVgaqAvbY0qEcSYGI,51373
25
- todo_agent-0.3.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
26
- todo_agent-0.3.2.dist-info/METADATA,sha256=IVSq9-aM-JkzSEHWPVOrvkW3PwjqSbaXEW4SIOo-CCc,10056
27
- todo_agent-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
28
- todo_agent-0.3.2.dist-info/entry_points.txt,sha256=4W7LrCib6AXP5IZDwWRht8S5gutLu5oNfTJHGbt4oHs,52
29
- todo_agent-0.3.2.dist-info/top_level.txt,sha256=a65mlPIhPZHuq2bRIi_sCMAIJsUddvXt171OBF6r6co,11
30
- todo_agent-0.3.2.dist-info/RECORD,,