skydeckai-code 0.1.40__tar.gz → 0.1.41__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.
Files changed (32) hide show
  1. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/PKG-INFO +111 -3
  2. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/README.md +109 -1
  3. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/pyproject.toml +2 -2
  4. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/__init__.py +16 -0
  5. skydeckai_code-0.1.41/src/aidd/tools/todo_store.py +257 -0
  6. skydeckai_code-0.1.41/src/aidd/tools/todo_tools.py +157 -0
  7. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/.claude/settings.local.json +0 -0
  8. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/.gitignore +0 -0
  9. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/Dockerfile +0 -0
  10. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/LICENSE +0 -0
  11. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/screenshots/mseep_ai_helper.png +0 -0
  12. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/smithery.yaml +0 -0
  13. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/__init__.py +0 -0
  14. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/__init__.py +0 -0
  15. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/cli.py +0 -0
  16. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/server.py +0 -0
  17. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/base.py +0 -0
  18. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/code_analysis.py +0 -0
  19. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/code_execution.py +0 -0
  20. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/code_tools.py +0 -0
  21. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/directory_tools.py +0 -0
  22. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/file_tools.py +0 -0
  23. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/get_active_apps_tool.py +0 -0
  24. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/get_available_windows_tool.py +0 -0
  25. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/image_tools.py +0 -0
  26. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/other_tools.py +0 -0
  27. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/path_tools.py +0 -0
  28. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/screenshot_tool.py +0 -0
  29. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/state.py +0 -0
  30. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/system_tools.py +0 -0
  31. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/src/aidd/tools/web_tools.py +0 -0
  32. {skydeckai_code-0.1.40 → skydeckai_code-0.1.41}/uv.lock +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skydeckai-code
3
- Version: 0.1.40
4
- Summary: This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, multi-language execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval.
3
+ Version: 0.1.41
4
+ Summary: This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, multi-language execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, persistent task management, and system information retrieval.
5
5
  Project-URL: Homepage, https://github.com/skydeckai/skydeckai-code
6
6
  Project-URL: Repository, https://github.com/skydeckai/skydeckai-code
7
7
  Project-URL: Documentation, https://github.com/skydeckai/skydeckai-code/blob/main/README.md
@@ -87,7 +87,7 @@ If you're using MseeP AI Helper app, you can search for "SkyDeckAI Code" and ins
87
87
  - Screenshot and screen context tools
88
88
  - Image handling tools
89
89
 
90
- ## Available Tools (26)
90
+ ## Available Tools (29)
91
91
 
92
92
  | Category | Tool Name | Description |
93
93
  | ---------------- | -------------------------- | -------------------------------------------- |
@@ -117,6 +117,9 @@ If you're using MseeP AI Helper app, you can search for "SkyDeckAI Code" and ins
117
117
  | **System** | `get_system_info` | Get detailed system information |
118
118
  | **Utility** | `batch_tools` | Run multiple tool operations together |
119
119
  | | `think` | Document reasoning without making changes |
120
+ | **Todo** | `todo_read` | Read current workspace todo list |
121
+ | | `todo_write` | Replace entire todo list with validation |
122
+ | | `todo_update` | Update specific todo item by ID |
120
123
 
121
124
  ## Detailed Tool Documentation
122
125
 
@@ -614,6 +617,111 @@ This tool executes arbitrary shell commands on your system. Always:
614
617
  4. Be aware of potential system impacts
615
618
  5. Monitor execution output
616
619
 
620
+ ### Todo Tools
621
+
622
+ The todo tools provide sequential task management capabilities for workspace-first development workflows. Tasks are executed in order without priority systems, ensuring structured progress through development phases.
623
+
624
+ #### todo_read
625
+
626
+ Read the current todo list for the workspace.
627
+
628
+ ```json
629
+ {}
630
+ ```
631
+
632
+ **Returns:**
633
+ ```json
634
+ {
635
+ "todos": [
636
+ {
637
+ "id": "abc123",
638
+ "content": "Implement user authentication",
639
+ "status": "in_progress",
640
+ "metadata": {
641
+ "custom_key": "custom_value"
642
+ },
643
+ "created_at": "2023-10-01T10:00:00Z",
644
+ "updated_at": "2023-10-01T11:30:00Z"
645
+ }
646
+ ],
647
+ "count": 1,
648
+ "workspace": "/path/to/workspace"
649
+ }
650
+ ```
651
+
652
+ #### todo_write
653
+
654
+ Replace the entire todo list for sequential execution workflow. Tasks are executed in array order, building upon previous work.
655
+
656
+ ```json
657
+ {
658
+ "todos": [
659
+ {
660
+ "id": "task1",
661
+ "content": "Set up database schema",
662
+ "status": "pending"
663
+ },
664
+ {
665
+ "id": "task2",
666
+ "content": "Create API endpoints",
667
+ "status": "pending",
668
+ "metadata": {
669
+ "custom_key": "custom_value"
670
+ }
671
+ }
672
+ ]
673
+ }
674
+ ```
675
+
676
+ **Sequential Workflow Rules:**
677
+ - Each todo must have unique ID
678
+ - Only one task can be "in_progress" at a time (sequential execution)
679
+ - Tasks execute in array order - no priority system
680
+ - Required fields: id, content, status
681
+ - Status values: "pending", "in_progress", "completed"
682
+ - Workspace-first: Todo management is mandatory for all workspace operations
683
+
684
+ #### todo_update
685
+
686
+ Update a specific todo item by ID for sequential workflow progression.
687
+
688
+ ```json
689
+ {
690
+ "todo_id": "task1",
691
+ "updates": {
692
+ "status": "in_progress",
693
+ "metadata": {
694
+ "new_key": "new_value"
695
+ }
696
+ }
697
+ }
698
+ ```
699
+
700
+ **Returns:**
701
+ ```json
702
+ {
703
+ "success": true,
704
+ "updated_todo": {
705
+ "id": "task1",
706
+ "content": "Set up database schema",
707
+ "status": "in_progress",
708
+ "updated_at": "2023-10-01T12:00:00Z",
709
+ "metadata": {
710
+ "new_key": "new_value"
711
+ }
712
+ },
713
+ "counts": {
714
+ "pending": 1,
715
+ "in_progress": 1,
716
+ "completed": 0,
717
+ "total": 2
718
+ },
719
+ "workspace": "/path/to/workspace"
720
+ }
721
+ ```
722
+
723
+ The todo system maintains separate sequential task lists for each workspace, enforcing mandatory usage for all workspace operations. Tasks execute in order, building upon previous work without priority-based scheduling.
724
+
617
725
  ## Configuration
618
726
 
619
727
  Configuration file: `~/.skydeckai_code/config.json`
@@ -52,7 +52,7 @@ If you're using MseeP AI Helper app, you can search for "SkyDeckAI Code" and ins
52
52
  - Screenshot and screen context tools
53
53
  - Image handling tools
54
54
 
55
- ## Available Tools (26)
55
+ ## Available Tools (29)
56
56
 
57
57
  | Category | Tool Name | Description |
58
58
  | ---------------- | -------------------------- | -------------------------------------------- |
@@ -82,6 +82,9 @@ If you're using MseeP AI Helper app, you can search for "SkyDeckAI Code" and ins
82
82
  | **System** | `get_system_info` | Get detailed system information |
83
83
  | **Utility** | `batch_tools` | Run multiple tool operations together |
84
84
  | | `think` | Document reasoning without making changes |
85
+ | **Todo** | `todo_read` | Read current workspace todo list |
86
+ | | `todo_write` | Replace entire todo list with validation |
87
+ | | `todo_update` | Update specific todo item by ID |
85
88
 
86
89
  ## Detailed Tool Documentation
87
90
 
@@ -579,6 +582,111 @@ This tool executes arbitrary shell commands on your system. Always:
579
582
  4. Be aware of potential system impacts
580
583
  5. Monitor execution output
581
584
 
585
+ ### Todo Tools
586
+
587
+ The todo tools provide sequential task management capabilities for workspace-first development workflows. Tasks are executed in order without priority systems, ensuring structured progress through development phases.
588
+
589
+ #### todo_read
590
+
591
+ Read the current todo list for the workspace.
592
+
593
+ ```json
594
+ {}
595
+ ```
596
+
597
+ **Returns:**
598
+ ```json
599
+ {
600
+ "todos": [
601
+ {
602
+ "id": "abc123",
603
+ "content": "Implement user authentication",
604
+ "status": "in_progress",
605
+ "metadata": {
606
+ "custom_key": "custom_value"
607
+ },
608
+ "created_at": "2023-10-01T10:00:00Z",
609
+ "updated_at": "2023-10-01T11:30:00Z"
610
+ }
611
+ ],
612
+ "count": 1,
613
+ "workspace": "/path/to/workspace"
614
+ }
615
+ ```
616
+
617
+ #### todo_write
618
+
619
+ Replace the entire todo list for sequential execution workflow. Tasks are executed in array order, building upon previous work.
620
+
621
+ ```json
622
+ {
623
+ "todos": [
624
+ {
625
+ "id": "task1",
626
+ "content": "Set up database schema",
627
+ "status": "pending"
628
+ },
629
+ {
630
+ "id": "task2",
631
+ "content": "Create API endpoints",
632
+ "status": "pending",
633
+ "metadata": {
634
+ "custom_key": "custom_value"
635
+ }
636
+ }
637
+ ]
638
+ }
639
+ ```
640
+
641
+ **Sequential Workflow Rules:**
642
+ - Each todo must have unique ID
643
+ - Only one task can be "in_progress" at a time (sequential execution)
644
+ - Tasks execute in array order - no priority system
645
+ - Required fields: id, content, status
646
+ - Status values: "pending", "in_progress", "completed"
647
+ - Workspace-first: Todo management is mandatory for all workspace operations
648
+
649
+ #### todo_update
650
+
651
+ Update a specific todo item by ID for sequential workflow progression.
652
+
653
+ ```json
654
+ {
655
+ "todo_id": "task1",
656
+ "updates": {
657
+ "status": "in_progress",
658
+ "metadata": {
659
+ "new_key": "new_value"
660
+ }
661
+ }
662
+ }
663
+ ```
664
+
665
+ **Returns:**
666
+ ```json
667
+ {
668
+ "success": true,
669
+ "updated_todo": {
670
+ "id": "task1",
671
+ "content": "Set up database schema",
672
+ "status": "in_progress",
673
+ "updated_at": "2023-10-01T12:00:00Z",
674
+ "metadata": {
675
+ "new_key": "new_value"
676
+ }
677
+ },
678
+ "counts": {
679
+ "pending": 1,
680
+ "in_progress": 1,
681
+ "completed": 0,
682
+ "total": 2
683
+ },
684
+ "workspace": "/path/to/workspace"
685
+ }
686
+ ```
687
+
688
+ The todo system maintains separate sequential task lists for each workspace, enforcing mandatory usage for all workspace operations. Tasks execute in order, building upon previous work without priority-based scheduling.
689
+
582
690
  ## Configuration
583
691
 
584
692
  Configuration file: `~/.skydeckai_code/config.json`
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "skydeckai-code"
3
- version = "0.1.40"
4
- description = "This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, multi-language execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval."
3
+ version = "0.1.41"
4
+ description = "This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, multi-language execution, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, persistent task management, and system information retrieval."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  authors = [{name = "SkyDeck.ai", email = "support@skydeck.ai"}]
@@ -47,6 +47,14 @@ from .screenshot_tool import (
47
47
  handle_capture_screenshot,
48
48
  )
49
49
  from .system_tools import get_system_info_tool, handle_get_system_info
50
+ from .todo_tools import (
51
+ todo_read_tool,
52
+ todo_write_tool,
53
+ todo_update_tool,
54
+ handle_todo_read,
55
+ handle_todo_write,
56
+ handle_todo_update,
57
+ )
50
58
  from .web_tools import web_fetch_tool, handle_web_fetch, web_search_tool, handle_web_search
51
59
 
52
60
  # Export all tools definitions
@@ -82,6 +90,10 @@ TOOL_DEFINITIONS = [
82
90
  web_search_tool(),
83
91
  # System tools
84
92
  get_system_info_tool(),
93
+ # Todo tools
94
+ todo_read_tool(),
95
+ todo_write_tool(),
96
+ todo_update_tool(),
85
97
  ]
86
98
 
87
99
  # Export all handlers
@@ -116,4 +128,8 @@ TOOL_HANDLERS = {
116
128
  # Web handlers
117
129
  "web_fetch": handle_web_fetch,
118
130
  "web_search": handle_web_search,
131
+ # Todo handlers
132
+ "todo_read": handle_todo_read,
133
+ "todo_write": handle_todo_write,
134
+ "todo_update": handle_todo_update,
119
135
  }
@@ -0,0 +1,257 @@
1
+ from .state import state
2
+ from datetime import datetime
3
+ from pathlib import Path
4
+ from typing import Any, Dict, List
5
+ import json
6
+
7
+
8
+ class TodoStore:
9
+ """Manages todo persistence and operations."""
10
+
11
+ def __init__(self):
12
+ self._cached_store = None
13
+ self._last_workspace = None
14
+
15
+ @property
16
+ def workspace_path(self) -> Path:
17
+ """Get the current workspace directory."""
18
+ return Path(state.allowed_directory)
19
+
20
+ @property
21
+ def todos_file_path(self) -> Path:
22
+ """Get the path to the global todos file."""
23
+ return state.config_dir / "todos.json"
24
+
25
+ def _detect_workspace_change(self) -> bool:
26
+ """Check if workspace has changed since last access."""
27
+ current_workspace = str(self.workspace_path)
28
+ if self._last_workspace != current_workspace:
29
+ self._last_workspace = current_workspace
30
+ self._cached_store = None
31
+ return True
32
+ return False
33
+
34
+ def _load_store(self) -> Dict[str, Any]:
35
+ """Load todos from file with caching."""
36
+ self._detect_workspace_change()
37
+
38
+ if self._cached_store is not None:
39
+ return self._cached_store
40
+
41
+ workspace_key = str(self.workspace_path)
42
+
43
+ if not self.todos_file_path.exists():
44
+ self._cached_store = {"lastModified": datetime.now().isoformat(), "todos": []}
45
+ return self._cached_store
46
+
47
+ try:
48
+ with open(self.todos_file_path, "r", encoding="utf-8") as f:
49
+ global_data = json.load(f)
50
+ workspace_data = global_data.get(workspace_key, {})
51
+ self._cached_store = {"lastModified": workspace_data.get("lastModified", datetime.now().isoformat()), "todos": workspace_data.get("todos", [])}
52
+ return self._cached_store
53
+ except (json.JSONDecodeError, IOError, OSError):
54
+ # Return empty store if file is corrupted
55
+ self._cached_store = {"lastModified": datetime.now().isoformat(), "todos": []}
56
+ return self._cached_store
57
+
58
+ def _save_store(self, store: Dict[str, Any]) -> None:
59
+ """Save todos to file atomically."""
60
+ # Ensure the ~/.skydeckai-code directory exists
61
+ self.todos_file_path.parent.mkdir(exist_ok=True)
62
+
63
+ workspace_key = str(self.workspace_path)
64
+
65
+ # Load existing global data
66
+ global_data = {}
67
+ if self.todos_file_path.exists():
68
+ try:
69
+ with open(self.todos_file_path, "r", encoding="utf-8") as f:
70
+ global_data = json.load(f)
71
+ except (json.JSONDecodeError, IOError, OSError):
72
+ global_data = {}
73
+
74
+ # Update the workspace data
75
+ global_data[workspace_key] = store
76
+
77
+ # Write to temporary file first (atomic write)
78
+ temp_path = self.todos_file_path.with_suffix(".json.tmp")
79
+
80
+ try:
81
+ with open(temp_path, "w", encoding="utf-8") as f:
82
+ json.dump(global_data, f, indent=2, ensure_ascii=False)
83
+
84
+ # Atomic rename
85
+ temp_path.replace(self.todos_file_path)
86
+
87
+ # Update cache
88
+ self._cached_store = store
89
+
90
+ except Exception:
91
+ # Clean up temp file if something went wrong
92
+ if temp_path.exists():
93
+ temp_path.unlink()
94
+ raise
95
+
96
+ def _add_to_gitignore(self) -> None:
97
+ """No longer needed since todos are stored in ~/.skydeckai-code/todo.json"""
98
+ pass
99
+
100
+ def read_todos(self) -> List[Dict[str, Any]]:
101
+ """Read all todos from storage."""
102
+ store = self._load_store()
103
+ return store["todos"]
104
+
105
+ def write_todos(self, todos: List[Dict[str, Any]]) -> int:
106
+ """Write todos to storage with validation."""
107
+ # Validate todos
108
+ self._validate_todos(todos)
109
+
110
+ # Process todos (add timestamps, etc.)
111
+ processed_todos = []
112
+ current_time = datetime.now().isoformat()
113
+
114
+ for todo in todos:
115
+ processed_todo = dict(todo)
116
+
117
+ # Ensure required fields have defaults
118
+ processed_todo.setdefault("id", self._generate_id())
119
+ processed_todo.setdefault("status", "pending")
120
+ processed_todo.setdefault("created_at", current_time)
121
+ processed_todo["updated_at"] = current_time
122
+
123
+ processed_todos.append(processed_todo)
124
+
125
+ # Create new store
126
+ new_store = {"lastModified": current_time, "todos": processed_todos}
127
+
128
+ # Save to file
129
+ self._save_store(new_store)
130
+
131
+ return len(processed_todos)
132
+
133
+ def update_todo(self, todo_id: str, updates: Dict[str, Any]) -> Dict[str, Any]:
134
+ """Update a specific todo by ID."""
135
+ store = self._load_store()
136
+ todos = store["todos"]
137
+
138
+ # Find the todo to update
139
+ todo_index = None
140
+ original_todo = None
141
+ for i, todo in enumerate(todos):
142
+ if todo["id"] == todo_id:
143
+ todo_index = i
144
+ original_todo = todo
145
+ break
146
+
147
+ if todo_index is None or original_todo is None:
148
+ raise ValueError(f"Todo with ID '{todo_id}' not found")
149
+
150
+ # Check if status is changing to completed
151
+ original_status = original_todo["status"]
152
+ new_status = updates.get("status", original_status)
153
+ is_completing = original_status != "completed" and new_status == "completed"
154
+
155
+ # Create updated todo
156
+ updated_todo = dict(todos[todo_index])
157
+ updated_todo.update(updates)
158
+ updated_todo["updated_at"] = datetime.now().isoformat()
159
+
160
+ # Replace the todo in the list
161
+ updated_todos = todos.copy()
162
+ updated_todos[todo_index] = updated_todo
163
+
164
+ # Validate the entire list with the update
165
+ self._validate_todos(updated_todos)
166
+
167
+ # Save updated list
168
+ new_store = {"lastModified": datetime.now().isoformat(), "todos": updated_todos}
169
+ self._save_store(new_store)
170
+
171
+ # Return status counts
172
+ pending_count = sum(1 for t in updated_todos if t["status"] == "pending")
173
+ in_progress_count = sum(1 for t in updated_todos if t["status"] == "in_progress")
174
+ completed_count = sum(1 for t in updated_todos if t["status"] == "completed")
175
+
176
+ result = {"updated_todo": updated_todo, "counts": {"pending": pending_count, "in_progress": in_progress_count, "completed": completed_count, "total": len(updated_todos)}}
177
+
178
+ # If a todo was just completed, find and include the next pending todo
179
+ if is_completing:
180
+ next_todo = self._find_next_pending_todo(updated_todos, todo_index)
181
+ if next_todo:
182
+ result["next_todo"] = next_todo
183
+ else:
184
+ result["next_todo"] = None
185
+ result["message"] = "All todos completed! No more pending tasks."
186
+
187
+ return result
188
+
189
+ def _find_next_pending_todo(self, todos: List[Dict[str, Any]], completed_index: int) -> Dict[str, Any] | None:
190
+ """Find the next pending todo after the completed one in sequential order."""
191
+ # Look for the next pending todo starting from the position after the completed one
192
+ for i in range(completed_index + 1, len(todos)):
193
+ if todos[i]["status"] == "pending":
194
+ return todos[i]
195
+
196
+ # If no pending todo found after the completed one, look from the beginning
197
+ # This handles cases where todos might be reordered or the completed one wasn't the first in-progress
198
+ for i in range(completed_index):
199
+ if todos[i]["status"] == "pending":
200
+ return todos[i]
201
+
202
+ # No pending todos found
203
+ return None
204
+
205
+ def _validate_todos(self, todos: List[Dict[str, Any]]) -> None:
206
+ """Validate todos according to business rules."""
207
+ if not isinstance(todos, list):
208
+ raise ValueError("Todos must be a list")
209
+
210
+ # Check for required fields and collect IDs
211
+ required_fields = {"id", "content", "status"}
212
+ seen_ids = set()
213
+ in_progress_count = 0
214
+
215
+ for i, todo in enumerate(todos):
216
+ if not isinstance(todo, dict):
217
+ raise ValueError(f"Todo at index {i} must be a dictionary")
218
+
219
+ # Check required fields
220
+ missing_fields = required_fields - set(todo.keys())
221
+ if missing_fields:
222
+ raise ValueError(f"Todo at index {i} missing required fields: {missing_fields}")
223
+
224
+ # Validate ID uniqueness
225
+ todo_id = todo["id"]
226
+ if not isinstance(todo_id, str) or not todo_id.strip():
227
+ raise ValueError(f"Todo at index {i} must have a non-empty string ID")
228
+
229
+ if todo_id in seen_ids:
230
+ raise ValueError(f"Duplicate todo ID found: {todo_id}")
231
+ seen_ids.add(todo_id)
232
+
233
+ # Validate status
234
+ if todo["status"] not in ["pending", "in_progress", "completed"]:
235
+ raise ValueError(f"Todo at index {i} has invalid status: {todo['status']}")
236
+
237
+ if todo["status"] == "in_progress":
238
+ in_progress_count += 1
239
+
240
+
241
+ # Validate content
242
+ if not isinstance(todo["content"], str) or not todo["content"].strip():
243
+ raise ValueError(f"Todo at index {i} must have non-empty content")
244
+
245
+ # Business rule: only one task can be in progress
246
+ if in_progress_count > 1:
247
+ raise ValueError("Only one task can be in_progress at a time")
248
+
249
+ def _generate_id(self) -> str:
250
+ """Generate a unique ID for a todo."""
251
+ import uuid
252
+
253
+ return str(uuid.uuid4())[:8]
254
+
255
+
256
+ # Global todo store instance
257
+ todo_store = TodoStore()
@@ -0,0 +1,157 @@
1
+ import json
2
+ from .todo_store import todo_store
3
+ from mcp.types import TextContent
4
+
5
+
6
+ def todo_read_tool():
7
+ """Define the todo_read tool."""
8
+ return {
9
+ "name": "todo_read",
10
+ "description": "Read the current task list from the workspace-specific todo storage. "
11
+ "MANDATORY: This tool MUST be called FIRST before ANY workspace operations including file reads, code analysis, development tasks, project creation, or directory manipulation. "
12
+ "WORKSPACE-FIRST RULE: Every LLM interaction with workspaces, directories, projects, or repositories requires todo management. "
13
+ "WHEN TO USE: Always when starting workspace operations - check task status, review pending/completed work, understand project context, pick up previous progress. "
14
+ "Essential for: Project initialization, code development, file operations, debugging, testing, deployment, refactoring. "
15
+ "WHEN NOT TO USE: Pure informational queries unrelated to workspace development. "
16
+ "RETURNS: Sequential task list with status and metadata. Tasks execute in order - no priority system. "
17
+ "Each workspace maintains isolated todo lists for project organization. "
18
+ "CRITICAL: Bypassing this tool for workspace operations violates mandatory protocol. "
19
+ "EXAMPLES: \n- Creating new projects: Read todos to check existing project structure tasks\n- Code development: Check current development phase and next sequential steps\n- File modifications: Understand task context before making changes\n- Project analysis: Review completed analysis and next investigation steps",
20
+ "inputSchema": {
21
+ "type": "object",
22
+ "properties": {},
23
+ "required": [],
24
+ },
25
+ }
26
+
27
+
28
+ def todo_write_tool():
29
+ """Define the todo_write tool."""
30
+ return {
31
+ "name": "todo_write",
32
+ "description": "Update the entire task list (complete replacement) for the current workspace. "
33
+ "MANDATORY: This tool MUST be called when planning, adding, or reorganizing tasks during ANY workspace operations. "
34
+ "WORKSPACE-FIRST RULE: All workspace development requires structured task management through sequential execution. "
35
+ "WHEN TO USE: Task planning for new projects, adding development phases, reorganizing workflow, batch status updates. "
36
+ "Sequential execution model: Tasks are completed in order, building upon previous work. No priority system - order determines execution. "
37
+ "Essential for: Project planning, development workflows, feature implementation, debugging sequences, deployment phases. "
38
+ "WHEN NOT TO USE: Single task updates (use todo_update), pure reading (use todo_read). "
39
+ "RETURNS: Success status and task count. Enforces sequential execution (only one in-progress task). "
40
+ "CRITICAL: Sequential task management is mandatory for all workspace development activities. "
41
+ "EXAMPLES: \n- New project setup: Create sequential tasks for initialization, structure, dependencies\n- Feature development: Plan design, implementation, testing, documentation phases\n- Bug fixing: Create investigation, fix, test, validation sequence\n- Code refactoring: Plan analysis, changes, testing, cleanup steps",
42
+ "inputSchema": {
43
+ "type": "object",
44
+ "properties": {
45
+ "todos": {
46
+ "type": "array",
47
+ "description": "Complete list of todo items to replace the current list for sequential execution. Each todo must contain id, content, and status fields. Tasks execute in array order.",
48
+ "items": {
49
+ "type": "object",
50
+ "properties": {
51
+ "id": {"type": "string", "description": "Unique identifier for the task. Must be unique across all todos."},
52
+ "content": {"type": "string", "description": "Task description or content. Cannot be empty."},
53
+ "status": {"type": "string", "enum": ["pending", "in_progress", "completed"], "description": "Current status of the task. Only one task can be 'in_progress' at a time."},
54
+ "metadata": {"type": "object", "description": "Optional additional data for the task.", "additionalProperties": True},
55
+ },
56
+ "required": ["id", "content", "status"],
57
+ "additionalProperties": True,
58
+ },
59
+ }
60
+ },
61
+ "required": ["todos"],
62
+ },
63
+ }
64
+
65
+
66
+ def todo_update_tool():
67
+ """Define the todo_update tool."""
68
+ return {
69
+ "name": "todo_update",
70
+ "description": "Update a specific todo item by ID for sequential workflow management. "
71
+ "MANDATORY: This tool MUST be called when progressing through tasks during workspace operations. "
72
+ "WORKSPACE-FIRST RULE: Task progress updates are required for all workspace development activities. "
73
+ "WHEN TO USE: Mark tasks in-progress when starting, completed when finished, update content for clarification. "
74
+ "Sequential workflow: Progress through tasks in order, maintaining single active task constraint. "
75
+ "Essential for: Task status transitions, progress tracking, workflow advancement, content updates. "
76
+ "WHEN NOT TO USE: Multiple task updates (use todo_write), adding new tasks (use todo_write). "
77
+ "RETURNS: Updated todo with status counts showing workflow progress. "
78
+ "Enforces sequential execution - only one task can be in-progress at any time. "
79
+ "CRITICAL: Sequential progress tracking is mandatory for workspace development workflows. "
80
+ "EXAMPLES: \n- Starting work: Update task from 'pending' to 'in_progress'\n- Completing work: Update task from 'in_progress' to 'completed'\n- Task refinement: Update content for better clarity\n- Workflow progression: Move to next sequential task",
81
+ "inputSchema": {
82
+ "type": "object",
83
+ "properties": {
84
+ "todo_id": {"type": "string", "description": "The unique ID of the todo to update."},
85
+ "updates": {
86
+ "type": "object",
87
+ "description": "Fields to update in the todo for sequential workflow. Can include content, status, or metadata.",
88
+ "properties": {
89
+ "content": {"type": "string", "description": "New task description or content."},
90
+ "status": {"type": "string", "enum": ["pending", "in_progress", "completed"], "description": "New status of the task."},
91
+ "metadata": {"type": "object", "description": "Additional data for the task.", "additionalProperties": True},
92
+ },
93
+ "additionalProperties": True,
94
+ },
95
+ },
96
+ "required": ["todo_id", "updates"],
97
+ },
98
+ }
99
+
100
+
101
+ async def handle_todo_read(arguments: dict) -> list[TextContent]:
102
+ """Handle reading todos from storage."""
103
+ try:
104
+ todos = todo_store.read_todos()
105
+
106
+ result = {"todos": todos, "count": len(todos), "workspace": str(todo_store.workspace_path)}
107
+
108
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
109
+
110
+ except Exception as e:
111
+ error_result = {"error": {"code": "READ_ERROR", "message": f"Failed to read todos: {str(e)}"}}
112
+ return [TextContent(type="text", text=json.dumps(error_result, indent=2))]
113
+
114
+
115
+ async def handle_todo_write(arguments: dict) -> list[TextContent]:
116
+ """Handle writing todos to storage."""
117
+ try:
118
+ todos = arguments.get("todos", [])
119
+
120
+ if not isinstance(todos, list):
121
+ raise ValueError("Todos must be provided as a list")
122
+
123
+ count = todo_store.write_todos(todos)
124
+
125
+ result = {"success": True, "count": count, "workspace": str(todo_store.workspace_path)}
126
+
127
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
128
+
129
+ except Exception as e:
130
+ error_result = {"error": {"code": "VALIDATION_ERROR" if "validation" in str(e).lower() or "invalid" in str(e).lower() or "duplicate" in str(e).lower() else "WRITE_ERROR", "message": str(e)}}
131
+ return [TextContent(type="text", text=json.dumps(error_result, indent=2))]
132
+
133
+
134
+ async def handle_todo_update(arguments: dict) -> list[TextContent]:
135
+ """Handle updating a specific todo."""
136
+ try:
137
+ todo_id = arguments.get("todo_id")
138
+ updates = arguments.get("updates", {})
139
+
140
+ if not todo_id:
141
+ raise ValueError("todo_id is required")
142
+
143
+ if not isinstance(updates, dict):
144
+ raise ValueError("Updates must be provided as a dictionary")
145
+
146
+ if not updates:
147
+ raise ValueError("Updates cannot be empty")
148
+
149
+ result = todo_store.update_todo(todo_id, updates)
150
+ result["success"] = True
151
+ result["workspace"] = str(todo_store.workspace_path)
152
+
153
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
154
+
155
+ except Exception as e:
156
+ error_result = {"error": {"code": "VALIDATION_ERROR" if "validation" in str(e).lower() or "invalid" in str(e).lower() or "not found" in str(e).lower() else "UPDATE_ERROR", "message": str(e)}}
157
+ return [TextContent(type="text", text=json.dumps(error_result, indent=2))]
File without changes
File without changes