todo-agent 0.3.5__tar.gz → 0.3.6__tar.gz
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.
- {todo_agent-0.3.5 → todo_agent-0.3.6}/PKG-INFO +1 -1
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_todo_shell.py +13 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_interface/test_cli.py +91 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/_version.py +3 -3
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/prompts/system_prompt.txt +13 -8
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/todo_shell.py +4 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/interface/cli.py +53 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/interface/formatters.py +1 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/interface/tools.py +6 -5
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/main.py +25 -6
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/PKG-INFO +1 -1
- {todo_agent-0.3.5 → todo_agent-0.3.6}/.gitignore +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/LICENSE +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/MANIFEST.in +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/Makefile +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/README.md +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/docs/publishing.md +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/pyproject.toml +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/requirements-dev.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/requirements.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/setup.cfg +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_core/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_core/test_conversation_manager.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_core/test_todo_manager.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_calendar_utils.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_config.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_inference.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_llm_client_factory.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_ollama_client.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_openrouter_client.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_infrastructure/test_token_counter.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_interface/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_interface/test_formatters.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_interface/test_tools.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_linting.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_logger.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/tests/test_main.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/core/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/core/conversation_manager.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/core/exceptions.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/core/todo_manager.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/calendar_utils.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/config.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/inference.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/llm_client.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/llm_client_factory.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/logger.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/ollama_client.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/openrouter_client.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/infrastructure/token_counter.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/interface/__init__.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent/interface/progress.py +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/SOURCES.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/dependency_links.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/entry_points.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/requires.txt +0 -0
- {todo_agent-0.3.5 → todo_agent-0.3.6}/todo_agent.egg-info/top_level.txt +0 -0
@@ -810,3 +810,16 @@ class TestTodoShell:
|
|
810
810
|
# Should not duplicate +work, only add +new
|
811
811
|
mock_replace.assert_called_once_with(1, "Test task +work +new @context")
|
812
812
|
assert result == "Task updated"
|
813
|
+
|
814
|
+
def test_get_help_constructs_correct_command(self):
|
815
|
+
"""Test getting help constructs the correct todo.sh command."""
|
816
|
+
with patch.object(
|
817
|
+
self.todo_shell, "execute", return_value="Todo.sh help output"
|
818
|
+
) as mock_execute:
|
819
|
+
result = self.todo_shell.get_help()
|
820
|
+
|
821
|
+
# Verify the correct command was constructed
|
822
|
+
mock_execute.assert_called_once_with(
|
823
|
+
["todo.sh", "help"], suppress_color=False
|
824
|
+
)
|
825
|
+
assert result == "Todo.sh help output"
|
@@ -377,6 +377,97 @@ class TestCLI:
|
|
377
377
|
expected_line in str(call) for call in mock_print.call_args_list
|
378
378
|
)
|
379
379
|
|
380
|
+
def test_todo_passthrough_command_success(self):
|
381
|
+
"""Test successful todo.sh passthrough command execution."""
|
382
|
+
with patch("builtins.input", return_value="/add test task"), patch("sys.exit"):
|
383
|
+
# Mock the todo_shell execute method
|
384
|
+
mock_todo_shell = Mock()
|
385
|
+
mock_todo_shell.execute.return_value = "1 test task"
|
386
|
+
|
387
|
+
# Create CLI instance with mocked dependencies
|
388
|
+
with patch("todo_agent.interface.cli.Config"), patch(
|
389
|
+
"todo_agent.interface.cli.TodoShell", return_value=mock_todo_shell
|
390
|
+
), patch("todo_agent.interface.cli.TodoManager"), patch(
|
391
|
+
"todo_agent.interface.cli.ToolCallHandler"
|
392
|
+
), patch("todo_agent.interface.cli.Inference"), patch(
|
393
|
+
"todo_agent.interface.cli.Logger"
|
394
|
+
), patch("todo_agent.interface.cli.Console") as mock_console:
|
395
|
+
CLI()
|
396
|
+
|
397
|
+
# Mock the console methods
|
398
|
+
mock_console.return_value.input.return_value = "/add test task"
|
399
|
+
mock_console.return_value.print = Mock()
|
400
|
+
|
401
|
+
# Test the passthrough logic directly
|
402
|
+
user_input = "/add test task"
|
403
|
+
if user_input.startswith("/"):
|
404
|
+
todo_command = user_input[1:].strip()
|
405
|
+
output = mock_todo_shell.execute(["todo.sh", *todo_command.split()])
|
406
|
+
|
407
|
+
# Verify the command was executed correctly
|
408
|
+
mock_todo_shell.execute.assert_called_once_with(
|
409
|
+
["todo.sh", "add", "test", "task"]
|
410
|
+
)
|
411
|
+
assert output == "1 test task"
|
412
|
+
|
413
|
+
def test_todo_passthrough_command_empty(self):
|
414
|
+
"""Test todo.sh passthrough with empty command."""
|
415
|
+
with patch("builtins.input", return_value="/"), patch("sys.exit"):
|
416
|
+
# Mock the todo_shell execute method
|
417
|
+
mock_todo_shell = Mock()
|
418
|
+
|
419
|
+
# Create CLI instance with mocked dependencies
|
420
|
+
with patch("todo_agent.interface.cli.Config"), patch(
|
421
|
+
"todo_agent.interface.cli.TodoShell", return_value=mock_todo_shell
|
422
|
+
), patch("todo_agent.interface.cli.TodoManager"), patch(
|
423
|
+
"todo_agent.interface.cli.ToolCallHandler"
|
424
|
+
), patch("todo_agent.interface.cli.Inference"), patch(
|
425
|
+
"todo_agent.interface.cli.Logger"
|
426
|
+
), patch("todo_agent.interface.cli.Console") as mock_console:
|
427
|
+
CLI()
|
428
|
+
|
429
|
+
# Mock the console methods
|
430
|
+
mock_console.return_value.input.return_value = "/"
|
431
|
+
mock_console.return_value.print = Mock()
|
432
|
+
|
433
|
+
# Test the passthrough logic with empty command
|
434
|
+
user_input = "/"
|
435
|
+
if user_input.startswith("/"):
|
436
|
+
todo_command = user_input[1:].strip()
|
437
|
+
if not todo_command:
|
438
|
+
# Should handle empty command gracefully
|
439
|
+
assert todo_command == ""
|
440
|
+
|
441
|
+
def test_todo_help_command(self):
|
442
|
+
"""Test todo-help command execution."""
|
443
|
+
with patch("builtins.input", return_value="todo-help"), patch("sys.exit"):
|
444
|
+
# Mock the todo_shell get_help method
|
445
|
+
mock_todo_shell = Mock()
|
446
|
+
mock_todo_shell.get_help.return_value = "Todo.sh help output"
|
447
|
+
|
448
|
+
# Create CLI instance with mocked dependencies
|
449
|
+
with patch("todo_agent.interface.cli.Config"), patch(
|
450
|
+
"todo_agent.interface.cli.TodoShell", return_value=mock_todo_shell
|
451
|
+
), patch("todo_agent.interface.cli.TodoManager"), patch(
|
452
|
+
"todo_agent.interface.cli.ToolCallHandler"
|
453
|
+
), patch("todo_agent.interface.cli.Inference"), patch(
|
454
|
+
"todo_agent.interface.cli.Logger"
|
455
|
+
), patch("todo_agent.interface.cli.Console") as mock_console:
|
456
|
+
CLI()
|
457
|
+
|
458
|
+
# Mock the console methods
|
459
|
+
mock_console.return_value.input.return_value = "todo-help"
|
460
|
+
mock_console.return_value.print = Mock()
|
461
|
+
|
462
|
+
# Test the todo-help command
|
463
|
+
user_input = "todo-help"
|
464
|
+
if user_input.lower() == "todo-help":
|
465
|
+
help_output = mock_todo_shell.get_help()
|
466
|
+
|
467
|
+
# Verify the help was retrieved
|
468
|
+
mock_todo_shell.get_help.assert_called_once()
|
469
|
+
assert help_output == "Todo.sh help output"
|
470
|
+
|
380
471
|
def test_empty_input_handling(self):
|
381
472
|
"""Test that empty input is handled gracefully."""
|
382
473
|
# This would be tested in the main run loop
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '0.3.
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
31
|
+
__version__ = version = '0.3.6'
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 6)
|
33
33
|
|
34
|
-
__commit_id__ = commit_id = '
|
34
|
+
__commit_id__ = commit_id = 'g30b41eb2b'
|
@@ -104,23 +104,28 @@ Example: add_task(description='Put out trash and recycling', project='weekly', c
|
|
104
104
|
|
105
105
|
**Parent Task Format**: `(A) Child task description +project @context due:YYYY-MM-DD duration:2h parent:12`
|
106
106
|
|
107
|
-
### Task Completion Protocol
|
107
|
+
### Task Completion Protocol
|
108
|
+
NOTE: use complete_task() for existing non-recurring tasks
|
108
109
|
1. **Discovery**: Use `list_tasks()` to search semantically in active tasks
|
109
|
-
2. **For Recurring Tasks
|
110
|
+
2. **For Non-Recurring Tasks**:
|
111
|
+
- The task will NOT have the tag "rec:"
|
112
|
+
- Single match → use `complete_task(task_number='XX')` to mark existing active tasks complete
|
113
|
+
- Multiple/fuzzy → show options
|
114
|
+
- No match → suggest alternatives
|
115
|
+
3. **For Recurring Tasks** (containing +daily, +weekly, +monthly, +weekdays, etc.):
|
116
|
+
- The task will have the tag "rec:"
|
110
117
|
- **USE** `create_completed_task()` with the original task number as parent_number
|
111
118
|
- **PRESERVE** the original recurring task for future occurrences. **IMPORTANT** DO NOT MARK COMPLETE! DO NOT MODIFY!
|
112
119
|
- **TOOL CALL**: `create_completed_task(description='Task description', parent_number='XX', completion_date='YYYY-MM-DD', context='context', project='project')`
|
113
|
-
|
114
|
-
- Single match → use `complete_task(task_number='XX')`
|
115
|
-
- Multiple/fuzzy → show options
|
116
|
-
- No match → suggest alternatives
|
120
|
+
|
117
121
|
|
118
122
|
### Recurring Task Completion Examples
|
123
|
+
NOTE: ONLY USE create_completed_task() for RECURRING TASKS!
|
119
124
|
- **User says**: "I put out the trash" → Find `(B) Put out trash and recycling +weekly +thursday @home duration:5m`
|
120
|
-
- **Tool Call**: `create_completed_task(description='Put out trash and recycling', parent_number='B', completion_date='YYYY-MM-DD', context='home', project='weekly')`
|
125
|
+
- **Tool Call**: ONLY FOR EXISTING TASKS! `create_completed_task(description='Put out trash and recycling', parent_number='B', completion_date='YYYY-MM-DD', context='home', project='weekly')`
|
121
126
|
- **Result**: Original task remains active for next Thursday
|
122
127
|
- **User says**: "Done with standup" → Find `Standup meeting at 9:00AM +daily +weekdays @office duration:10m`
|
123
|
-
- **Tool Call**: `create_completed_task(description='Standup meeting at 9:00AM', parent_number='XX', completion_date='YYYY-MM-DD', context='office', project='daily')`
|
128
|
+
- **Tool Call**: ONLY FOR EXISTING TASKS! `create_completed_task(description='Standup meeting at 9:00AM', parent_number='XX', completion_date='YYYY-MM-DD', context='office', project='daily')`
|
124
129
|
- **Result**: Original task remains active for next weekday
|
125
130
|
|
126
131
|
### Task Suggestions
|
@@ -182,6 +182,10 @@ class TodoShell:
|
|
182
182
|
"""Archive completed tasks."""
|
183
183
|
return self.execute(["todo.sh", "-f", "archive"])
|
184
184
|
|
185
|
+
def get_help(self) -> str:
|
186
|
+
"""Get todo.sh help output."""
|
187
|
+
return self.execute(["todo.sh", "help"], suppress_color=False)
|
188
|
+
|
185
189
|
def set_due_date(self, task_number: int, due_date: str) -> str:
|
186
190
|
"""
|
187
191
|
Set or update due date for a task by intelligently rewriting it.
|
@@ -225,6 +225,23 @@ class CLI:
|
|
225
225
|
self.console.print(table)
|
226
226
|
self.console.print("Or just type your request naturally!", style="italic green")
|
227
227
|
|
228
|
+
def _print_todo_help(self) -> None:
|
229
|
+
"""Print todo.sh help information."""
|
230
|
+
try:
|
231
|
+
# Get todo.sh help output
|
232
|
+
help_output = self.todo_shell.get_help()
|
233
|
+
formatted_output = TaskFormatter.format_task_list(help_output)
|
234
|
+
help_panel = PanelFormatter.create_task_panel(
|
235
|
+
formatted_output, title="📋 Todo.sh Help"
|
236
|
+
)
|
237
|
+
self.console.print(help_panel)
|
238
|
+
except Exception as e:
|
239
|
+
self.logger.error(f"Error getting todo.sh help: {e!s}")
|
240
|
+
error_msg = ResponseFormatter.format_error(
|
241
|
+
f"Failed to get todo.sh help: {e!s}"
|
242
|
+
)
|
243
|
+
self.console.print(error_msg)
|
244
|
+
|
228
245
|
def _print_about(self) -> None:
|
229
246
|
"""Print about information in a formatted panel."""
|
230
247
|
about_panel = PanelFormatter.create_about_panel()
|
@@ -280,6 +297,37 @@ class CLI:
|
|
280
297
|
if not user_input:
|
281
298
|
continue
|
282
299
|
|
300
|
+
# Handle todo.sh passthrough commands (starting with /)
|
301
|
+
if user_input.startswith("/"):
|
302
|
+
self.logger.debug(
|
303
|
+
f"Processing todo.sh passthrough command: {user_input}"
|
304
|
+
)
|
305
|
+
try:
|
306
|
+
# Remove the leading / and execute as todo.sh command
|
307
|
+
todo_command = user_input[1:].strip()
|
308
|
+
if not todo_command:
|
309
|
+
self.console.print(
|
310
|
+
ResponseFormatter.format_error("Empty todo.sh command")
|
311
|
+
)
|
312
|
+
continue
|
313
|
+
|
314
|
+
# Execute the todo.sh command directly
|
315
|
+
output = self.todo_shell.execute(
|
316
|
+
["todo.sh", *todo_command.split()]
|
317
|
+
)
|
318
|
+
formatted_output = TaskFormatter.format_task_list(output)
|
319
|
+
task_panel = PanelFormatter.create_task_panel(
|
320
|
+
formatted_output, title="📋 Todo.sh Output"
|
321
|
+
)
|
322
|
+
self.console.print(task_panel)
|
323
|
+
except Exception as e:
|
324
|
+
self.logger.error(f"Error executing todo.sh command: {e!s}")
|
325
|
+
error_msg = ResponseFormatter.format_error(
|
326
|
+
f"Todo.sh command failed: {e!s}"
|
327
|
+
)
|
328
|
+
self.console.print(error_msg)
|
329
|
+
continue
|
330
|
+
|
283
331
|
# Handle special commands
|
284
332
|
if user_input.lower() == "clear":
|
285
333
|
self.logger.info("User requested conversation clear")
|
@@ -302,6 +350,11 @@ class CLI:
|
|
302
350
|
self._print_help()
|
303
351
|
continue
|
304
352
|
|
353
|
+
if user_input.lower() == "todo-help":
|
354
|
+
self.logger.debug("User requested todo.sh help")
|
355
|
+
self._print_todo_help()
|
356
|
+
continue
|
357
|
+
|
305
358
|
if user_input.lower() == "about":
|
306
359
|
self.logger.debug("User requested about information")
|
307
360
|
self._print_about()
|
@@ -357,6 +357,7 @@ class TableFormatter:
|
|
357
357
|
("clear", "Clear conversation history"),
|
358
358
|
("stats", "Show conversation statistics"),
|
359
359
|
("help", "Show this help message"),
|
360
|
+
("todo-help", "Show todo.sh help"),
|
360
361
|
("about", "Show application information"),
|
361
362
|
("list", "List all tasks (no LLM interaction)"),
|
362
363
|
("done", "List completed tasks (no LLM interaction)"),
|
@@ -626,13 +626,14 @@ class ToolCallHandler:
|
|
626
626
|
"name": "create_completed_task",
|
627
627
|
"description": (
|
628
628
|
"Create a task and immediately mark it as completed. "
|
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') "
|
629
|
+
"USE CASE: WHEN NO MATCH IS FOUND! 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') "
|
630
630
|
"and you have already researched existing tasks to determine no match exists. "
|
631
|
-
"WORKFLOW: 1) Use list_tasks() to search for existing tasks,
|
632
|
-
"
|
631
|
+
"WORKFLOW: 1) Use list_tasks() to search for existing tasks, "
|
632
|
+
"2) Use list_completed_tasks() to verify it's not already done, "
|
633
|
+
"3) If a match is found, use complete_task() to mark it complete, "
|
634
|
+
"4) If no match found, call this tool to create and complete the task in one operation. "
|
633
635
|
"STRATEGIC CONTEXT: This is a convenience tool for the common pattern of 'I did X on [date]' - "
|
634
|
-
"it creates a task with the specified completion date and immediately marks it complete. "
|
635
|
-
"The LLM should handle the research and decision-making about whether to use this tool."
|
636
|
+
"when no task match is found, it creates a task with the specified completion date and immediately marks it complete. "
|
636
637
|
),
|
637
638
|
"parameters": {
|
638
639
|
"type": "object",
|
@@ -12,7 +12,7 @@ from .interface.cli import CLI
|
|
12
12
|
def main() -> None:
|
13
13
|
"""Main application entry point."""
|
14
14
|
from ._version import __version__
|
15
|
-
|
15
|
+
|
16
16
|
parser = argparse.ArgumentParser(
|
17
17
|
description=f"Todo.sh LLM Agent - Natural language task management (v{__version__})",
|
18
18
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
@@ -27,18 +27,20 @@ Examples:
|
|
27
27
|
)
|
28
28
|
|
29
29
|
parser.add_argument(
|
30
|
-
"--version",
|
30
|
+
"--version",
|
31
|
+
"-v",
|
31
32
|
action="version",
|
32
33
|
version=f"%(prog)s {__version__}",
|
33
34
|
help="Show version information and exit",
|
34
35
|
)
|
35
|
-
|
36
|
+
|
36
37
|
parser.add_argument(
|
37
|
-
"--help",
|
38
|
+
"--help",
|
39
|
+
"-h",
|
38
40
|
action="help",
|
39
41
|
help="Show this help message and exit",
|
40
42
|
)
|
41
|
-
|
43
|
+
|
42
44
|
parser.add_argument(
|
43
45
|
"command",
|
44
46
|
nargs="?",
|
@@ -53,11 +55,28 @@ Examples:
|
|
53
55
|
if args.command:
|
54
56
|
# Single command mode
|
55
57
|
# Handle special commands that don't need LLM processing
|
56
|
-
if args.command.lower() in ["help", "about"]:
|
58
|
+
if args.command.lower() in ["help", "about", "todo-help"]:
|
57
59
|
if args.command.lower() == "help":
|
58
60
|
cli._print_help()
|
59
61
|
elif args.command.lower() == "about":
|
60
62
|
cli._print_about()
|
63
|
+
elif args.command.lower() == "todo-help":
|
64
|
+
cli._print_todo_help()
|
65
|
+
elif args.command.startswith("/"):
|
66
|
+
# Handle todo.sh passthrough commands
|
67
|
+
try:
|
68
|
+
# Remove the leading / and execute as todo.sh command
|
69
|
+
todo_command = args.command[1:].strip()
|
70
|
+
if not todo_command:
|
71
|
+
print("Error: Empty todo.sh command")
|
72
|
+
sys.exit(1)
|
73
|
+
|
74
|
+
# Execute the todo.sh command directly
|
75
|
+
output = cli.todo_shell.execute(["todo.sh", *todo_command.split()])
|
76
|
+
print(output)
|
77
|
+
except Exception as e:
|
78
|
+
print(f"Error: Todo.sh command failed: {e}")
|
79
|
+
sys.exit(1)
|
61
80
|
else:
|
62
81
|
# Process through LLM
|
63
82
|
response = cli.run_single_request(args.command)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|