minion-code 0.1.0__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.
- examples/advance_tui.py +508 -0
- examples/agent_with_todos.py +165 -0
- examples/file_freshness_example.py +97 -0
- examples/file_watching_example.py +110 -0
- examples/interruptible_tui.py +5 -0
- examples/message_response_children_demo.py +226 -0
- examples/rich_example.py +4 -0
- examples/simple_file_watching.py +57 -0
- examples/simple_tui.py +267 -0
- examples/simple_usage.py +69 -0
- minion_code/__init__.py +16 -0
- minion_code/agents/__init__.py +11 -0
- minion_code/agents/code_agent.py +320 -0
- minion_code/cli.py +502 -0
- minion_code/commands/__init__.py +90 -0
- minion_code/commands/clear_command.py +70 -0
- minion_code/commands/help_command.py +90 -0
- minion_code/commands/history_command.py +104 -0
- minion_code/commands/quit_command.py +32 -0
- minion_code/commands/status_command.py +115 -0
- minion_code/commands/tools_command.py +86 -0
- minion_code/commands/version_command.py +104 -0
- minion_code/components/Message.py +304 -0
- minion_code/components/MessageResponse.py +188 -0
- minion_code/components/PromptInput.py +534 -0
- minion_code/components/__init__.py +29 -0
- minion_code/screens/REPL.py +925 -0
- minion_code/screens/__init__.py +4 -0
- minion_code/services/__init__.py +50 -0
- minion_code/services/event_system.py +108 -0
- minion_code/services/file_freshness_service.py +582 -0
- minion_code/tools/__init__.py +69 -0
- minion_code/tools/bash_tool.py +58 -0
- minion_code/tools/file_edit_tool.py +238 -0
- minion_code/tools/file_read_tool.py +73 -0
- minion_code/tools/file_write_tool.py +36 -0
- minion_code/tools/glob_tool.py +58 -0
- minion_code/tools/grep_tool.py +105 -0
- minion_code/tools/ls_tool.py +65 -0
- minion_code/tools/multi_edit_tool.py +271 -0
- minion_code/tools/python_interpreter_tool.py +105 -0
- minion_code/tools/todo_read_tool.py +100 -0
- minion_code/tools/todo_write_tool.py +234 -0
- minion_code/tools/user_input_tool.py +53 -0
- minion_code/types.py +88 -0
- minion_code/utils/__init__.py +44 -0
- minion_code/utils/mcp_loader.py +211 -0
- minion_code/utils/todo_file_utils.py +110 -0
- minion_code/utils/todo_storage.py +149 -0
- minion_code-0.1.0.dist-info/METADATA +350 -0
- minion_code-0.1.0.dist-info/RECORD +59 -0
- minion_code-0.1.0.dist-info/WHEEL +5 -0
- minion_code-0.1.0.dist-info/entry_points.txt +4 -0
- minion_code-0.1.0.dist-info/licenses/LICENSE +661 -0
- minion_code-0.1.0.dist-info/top_level.txt +3 -0
- tests/__init__.py +1 -0
- tests/test_basic.py +20 -0
- tests/test_readonly_tools.py +102 -0
- tests/test_tools.py +83 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Services module for minion_code."""
|
|
2
|
+
|
|
3
|
+
from .event_system import (
|
|
4
|
+
EventDispatcher,
|
|
5
|
+
EventContext,
|
|
6
|
+
EventType,
|
|
7
|
+
EventCallback,
|
|
8
|
+
global_event_dispatcher,
|
|
9
|
+
add_event_listener,
|
|
10
|
+
emit_event,
|
|
11
|
+
remove_event_listener,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .file_freshness_service import (
|
|
15
|
+
FileFreshnessService,
|
|
16
|
+
FileTimestamp,
|
|
17
|
+
FreshnessResult,
|
|
18
|
+
file_freshness_service,
|
|
19
|
+
record_file_read,
|
|
20
|
+
record_file_edit,
|
|
21
|
+
check_file_freshness,
|
|
22
|
+
generate_file_modification_reminder,
|
|
23
|
+
reset_file_freshness_session,
|
|
24
|
+
start_watching_todo_file,
|
|
25
|
+
stop_watching_todo_file,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
# Event system
|
|
30
|
+
'EventDispatcher',
|
|
31
|
+
'EventContext',
|
|
32
|
+
'EventType',
|
|
33
|
+
'EventCallback',
|
|
34
|
+
'global_event_dispatcher',
|
|
35
|
+
'add_event_listener',
|
|
36
|
+
'emit_event',
|
|
37
|
+
'remove_event_listener',
|
|
38
|
+
# File freshness service
|
|
39
|
+
'FileFreshnessService',
|
|
40
|
+
'FileTimestamp',
|
|
41
|
+
'FreshnessResult',
|
|
42
|
+
'file_freshness_service',
|
|
43
|
+
'record_file_read',
|
|
44
|
+
'record_file_edit',
|
|
45
|
+
'check_file_freshness',
|
|
46
|
+
'generate_file_modification_reminder',
|
|
47
|
+
'reset_file_freshness_session',
|
|
48
|
+
'start_watching_todo_file',
|
|
49
|
+
'stop_watching_todo_file',
|
|
50
|
+
]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Event system for minion_code services."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Callable, Any, Optional
|
|
4
|
+
import logging
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EventType(Enum):
|
|
12
|
+
"""Supported event types."""
|
|
13
|
+
SESSION_STARTUP = "session:startup"
|
|
14
|
+
TODO_CHANGED = "todo:changed"
|
|
15
|
+
TODO_FILE_CHANGED = "todo:file_changed"
|
|
16
|
+
FILE_READ = "file:read"
|
|
17
|
+
FILE_EDITED = "file:edited"
|
|
18
|
+
FILE_CONFLICT = "file:conflict"
|
|
19
|
+
AGENT_MENTIONED = "agent:mentioned"
|
|
20
|
+
FILE_MENTIONED = "file:mentioned"
|
|
21
|
+
ASK_MODEL_MENTIONED = "ask-model:mentioned"
|
|
22
|
+
REMINDER_INJECT = "reminder:inject"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class EventContext:
|
|
27
|
+
"""Context data for events."""
|
|
28
|
+
event_type: str
|
|
29
|
+
timestamp: float
|
|
30
|
+
data: Dict[str, Any]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
EventCallback = Callable[[EventContext], None]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class EventDispatcher:
|
|
37
|
+
"""Simple event dispatcher for handling system events."""
|
|
38
|
+
|
|
39
|
+
def __init__(self):
|
|
40
|
+
self._listeners: Dict[str, List[EventCallback]] = {}
|
|
41
|
+
|
|
42
|
+
def add_event_listener(self, event_type: str, callback: EventCallback) -> None:
|
|
43
|
+
"""Add an event listener for a specific event type."""
|
|
44
|
+
if event_type not in self._listeners:
|
|
45
|
+
self._listeners[event_type] = []
|
|
46
|
+
self._listeners[event_type].append(callback)
|
|
47
|
+
logger.debug(f"Added event listener for {event_type}")
|
|
48
|
+
|
|
49
|
+
def remove_event_listener(self, event_type: str, callback: EventCallback) -> bool:
|
|
50
|
+
"""Remove a specific event listener."""
|
|
51
|
+
if event_type in self._listeners:
|
|
52
|
+
try:
|
|
53
|
+
self._listeners[event_type].remove(callback)
|
|
54
|
+
logger.debug(f"Removed event listener for {event_type}")
|
|
55
|
+
return True
|
|
56
|
+
except ValueError:
|
|
57
|
+
pass
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
def emit_event(self, event_type: str, data: Optional[Dict[str, Any]] = None) -> None:
|
|
61
|
+
"""Emit an event to all registered listeners."""
|
|
62
|
+
if event_type not in self._listeners:
|
|
63
|
+
return
|
|
64
|
+
|
|
65
|
+
import time
|
|
66
|
+
context = EventContext(
|
|
67
|
+
event_type=event_type,
|
|
68
|
+
timestamp=time.time(),
|
|
69
|
+
data=data or {}
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
listeners = self._listeners[event_type].copy() # Avoid modification during iteration
|
|
73
|
+
for callback in listeners:
|
|
74
|
+
try:
|
|
75
|
+
callback(context)
|
|
76
|
+
except Exception as error:
|
|
77
|
+
logger.error(f"Error in event listener for {event_type}: {error}")
|
|
78
|
+
|
|
79
|
+
def clear_listeners(self, event_type: Optional[str] = None) -> None:
|
|
80
|
+
"""Clear listeners for a specific event type or all listeners."""
|
|
81
|
+
if event_type:
|
|
82
|
+
self._listeners.pop(event_type, None)
|
|
83
|
+
else:
|
|
84
|
+
self._listeners.clear()
|
|
85
|
+
|
|
86
|
+
def get_listener_count(self, event_type: str) -> int:
|
|
87
|
+
"""Get the number of listeners for an event type."""
|
|
88
|
+
return len(self._listeners.get(event_type, []))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# Global event dispatcher instance
|
|
92
|
+
global_event_dispatcher = EventDispatcher()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Convenience functions
|
|
96
|
+
def add_event_listener(event_type: str, callback: EventCallback) -> None:
|
|
97
|
+
"""Add an event listener using the global dispatcher."""
|
|
98
|
+
global_event_dispatcher.add_event_listener(event_type, callback)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def emit_event(event_type: str, data: Optional[Dict[str, Any]] = None) -> None:
|
|
102
|
+
"""Emit an event using the global dispatcher."""
|
|
103
|
+
global_event_dispatcher.emit_event(event_type, data)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def remove_event_listener(event_type: str, callback: EventCallback) -> bool:
|
|
107
|
+
"""Remove an event listener using the global dispatcher."""
|
|
108
|
+
return global_event_dispatcher.remove_event_listener(event_type, callback)
|