minion-code 0.1.0__py3-none-any.whl → 0.1.1__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/cli_entrypoint.py +60 -0
- examples/{agent_with_todos.py → components/agent_with_todos.py} +58 -47
- examples/{message_response_children_demo.py → components/message_response_children_demo.py} +61 -55
- examples/components/messages_component.py +199 -0
- examples/file_freshness_example.py +22 -22
- examples/file_watching_example.py +32 -26
- examples/interruptible_tui.py +921 -3
- examples/repl_tui.py +129 -0
- examples/skills/example_usage.py +57 -0
- examples/start.py +173 -0
- minion_code/__init__.py +1 -1
- minion_code/acp_server/__init__.py +34 -0
- minion_code/acp_server/agent.py +539 -0
- minion_code/acp_server/hooks.py +354 -0
- minion_code/acp_server/main.py +194 -0
- minion_code/acp_server/permissions.py +142 -0
- minion_code/acp_server/test_client.py +104 -0
- minion_code/adapters/__init__.py +22 -0
- minion_code/adapters/output_adapter.py +207 -0
- minion_code/adapters/rich_adapter.py +169 -0
- minion_code/adapters/textual_adapter.py +254 -0
- minion_code/agents/__init__.py +2 -2
- minion_code/agents/code_agent.py +517 -104
- minion_code/agents/hooks.py +378 -0
- minion_code/cli.py +538 -429
- minion_code/cli_simple.py +665 -0
- minion_code/commands/__init__.py +136 -29
- minion_code/commands/clear_command.py +19 -46
- minion_code/commands/help_command.py +33 -49
- minion_code/commands/history_command.py +37 -55
- minion_code/commands/model_command.py +194 -0
- minion_code/commands/quit_command.py +9 -12
- minion_code/commands/resume_command.py +181 -0
- minion_code/commands/skill_command.py +89 -0
- minion_code/commands/status_command.py +48 -73
- minion_code/commands/tools_command.py +54 -52
- minion_code/commands/version_command.py +34 -69
- minion_code/components/ConfirmDialog.py +430 -0
- minion_code/components/Message.py +318 -97
- minion_code/components/MessageResponse.py +30 -29
- minion_code/components/Messages.py +351 -0
- minion_code/components/PromptInput.py +499 -245
- minion_code/components/__init__.py +24 -17
- minion_code/const.py +7 -0
- minion_code/screens/REPL.py +1453 -469
- minion_code/screens/__init__.py +1 -1
- minion_code/services/__init__.py +20 -20
- minion_code/services/event_system.py +19 -14
- minion_code/services/file_freshness_service.py +223 -170
- minion_code/skills/__init__.py +25 -0
- minion_code/skills/skill.py +128 -0
- minion_code/skills/skill_loader.py +198 -0
- minion_code/skills/skill_registry.py +177 -0
- minion_code/subagents/__init__.py +31 -0
- minion_code/subagents/builtin/__init__.py +30 -0
- minion_code/subagents/builtin/claude_code_guide.py +32 -0
- minion_code/subagents/builtin/explore.py +36 -0
- minion_code/subagents/builtin/general_purpose.py +19 -0
- minion_code/subagents/builtin/plan.py +61 -0
- minion_code/subagents/subagent.py +116 -0
- minion_code/subagents/subagent_loader.py +147 -0
- minion_code/subagents/subagent_registry.py +151 -0
- minion_code/tools/__init__.py +8 -2
- minion_code/tools/bash_tool.py +16 -3
- minion_code/tools/file_edit_tool.py +201 -104
- minion_code/tools/file_read_tool.py +183 -26
- minion_code/tools/file_write_tool.py +17 -3
- minion_code/tools/glob_tool.py +23 -2
- minion_code/tools/grep_tool.py +229 -21
- minion_code/tools/ls_tool.py +28 -3
- minion_code/tools/multi_edit_tool.py +89 -84
- minion_code/tools/python_interpreter_tool.py +9 -1
- minion_code/tools/skill_tool.py +210 -0
- minion_code/tools/task_tool.py +287 -0
- minion_code/tools/todo_read_tool.py +28 -24
- minion_code/tools/todo_write_tool.py +82 -65
- minion_code/{types.py → type_defs.py} +15 -2
- minion_code/utils/__init__.py +45 -17
- minion_code/utils/config.py +610 -0
- minion_code/utils/history.py +114 -0
- minion_code/utils/logs.py +53 -0
- minion_code/utils/mcp_loader.py +153 -55
- minion_code/utils/output_truncator.py +233 -0
- minion_code/utils/session_storage.py +369 -0
- minion_code/utils/todo_file_utils.py +26 -22
- minion_code/utils/todo_storage.py +43 -33
- minion_code/web/__init__.py +9 -0
- minion_code/web/adapters/__init__.py +5 -0
- minion_code/web/adapters/web_adapter.py +524 -0
- minion_code/web/api/__init__.py +7 -0
- minion_code/web/api/chat.py +277 -0
- minion_code/web/api/interactions.py +136 -0
- minion_code/web/api/sessions.py +135 -0
- minion_code/web/server.py +149 -0
- minion_code/web/services/__init__.py +5 -0
- minion_code/web/services/session_manager.py +420 -0
- minion_code-0.1.1.dist-info/METADATA +475 -0
- minion_code-0.1.1.dist-info/RECORD +111 -0
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/WHEEL +1 -1
- minion_code-0.1.1.dist-info/entry_points.txt +6 -0
- tests/test_adapter.py +67 -0
- tests/test_adapter_simple.py +79 -0
- tests/test_file_read_tool.py +144 -0
- tests/test_readonly_tools.py +0 -2
- tests/test_skills.py +441 -0
- examples/advance_tui.py +0 -508
- examples/rich_example.py +0 -4
- examples/simple_file_watching.py +0 -57
- examples/simple_tui.py +0 -267
- examples/simple_usage.py +0 -69
- minion_code-0.1.0.dist-info/METADATA +0 -350
- minion_code-0.1.0.dist-info/RECORD +0 -59
- minion_code-0.1.0.dist-info/entry_points.txt +0 -4
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test script for the Messages component
|
|
4
|
+
Verifies that the Messages component can render a list of messages correctly
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from textual.app import App, ComposeResult
|
|
8
|
+
from textual.containers import Container, Horizontal
|
|
9
|
+
from textual.widgets import Header, Footer, Button
|
|
10
|
+
from textual import on
|
|
11
|
+
|
|
12
|
+
# Import the components we want to test
|
|
13
|
+
from minion_code.components.Messages import Messages
|
|
14
|
+
from minion_code.type_defs import Message, MessageType, MessageContent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestMessagesApp(App):
|
|
18
|
+
"""Test application for Messages component"""
|
|
19
|
+
|
|
20
|
+
CSS = """
|
|
21
|
+
TestMessagesApp {
|
|
22
|
+
background: $surface;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#test_container {
|
|
26
|
+
height: 1fr;
|
|
27
|
+
margin: 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#controls {
|
|
31
|
+
dock: bottom;
|
|
32
|
+
height: auto;
|
|
33
|
+
margin: 1;
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Button {
|
|
38
|
+
margin: 1;
|
|
39
|
+
min-width: 20;
|
|
40
|
+
}
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
super().__init__()
|
|
45
|
+
self.test_messages = []
|
|
46
|
+
self._create_test_messages()
|
|
47
|
+
|
|
48
|
+
def _create_test_messages(self):
|
|
49
|
+
"""Create some test messages"""
|
|
50
|
+
import time
|
|
51
|
+
|
|
52
|
+
# User message
|
|
53
|
+
self.test_messages.append(
|
|
54
|
+
Message(
|
|
55
|
+
type=MessageType.USER,
|
|
56
|
+
message=MessageContent("Hello, can you help me with Python?"),
|
|
57
|
+
timestamp=time.time() - 60,
|
|
58
|
+
options={},
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Assistant message
|
|
63
|
+
self.test_messages.append(
|
|
64
|
+
Message(
|
|
65
|
+
type=MessageType.ASSISTANT,
|
|
66
|
+
message=MessageContent(
|
|
67
|
+
"Of course! I'd be happy to help you with Python. What specific topic or problem would you like assistance with?"
|
|
68
|
+
),
|
|
69
|
+
timestamp=time.time() - 50,
|
|
70
|
+
options={},
|
|
71
|
+
)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# User message with code
|
|
75
|
+
self.test_messages.append(
|
|
76
|
+
Message(
|
|
77
|
+
type=MessageType.USER,
|
|
78
|
+
message=MessageContent("How do I create a list comprehension?"),
|
|
79
|
+
timestamp=time.time() - 40,
|
|
80
|
+
options={},
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Assistant message with code example
|
|
85
|
+
self.test_messages.append(
|
|
86
|
+
Message(
|
|
87
|
+
type=MessageType.ASSISTANT,
|
|
88
|
+
message=MessageContent(
|
|
89
|
+
"""List comprehensions are a concise way to create lists in Python. Here's the basic syntax:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Basic syntax: [expression for item in iterable]
|
|
93
|
+
numbers = [1, 2, 3, 4, 5]
|
|
94
|
+
squares = [x**2 for x in numbers]
|
|
95
|
+
print(squares) # [1, 4, 9, 16, 25]
|
|
96
|
+
|
|
97
|
+
# With condition: [expression for item in iterable if condition]
|
|
98
|
+
even_squares = [x**2 for x in numbers if x % 2 == 0]
|
|
99
|
+
print(even_squares) # [4, 16]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
List comprehensions are more readable and often faster than traditional for loops for creating lists."""
|
|
103
|
+
),
|
|
104
|
+
timestamp=time.time() - 30,
|
|
105
|
+
options={},
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
def compose(self) -> ComposeResult:
|
|
110
|
+
"""Compose the test application"""
|
|
111
|
+
yield Header(show_clock=True)
|
|
112
|
+
|
|
113
|
+
with Container(id="test_container"):
|
|
114
|
+
yield Messages(
|
|
115
|
+
messages=self.test_messages,
|
|
116
|
+
verbose=True,
|
|
117
|
+
debug=True,
|
|
118
|
+
id="test_messages",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
with Horizontal(id="controls"):
|
|
122
|
+
yield Button("Add User Message", id="add_user", variant="primary")
|
|
123
|
+
yield Button("Add Assistant Message", id="add_assistant", variant="success")
|
|
124
|
+
yield Button("Clear Messages", id="clear", variant="error")
|
|
125
|
+
|
|
126
|
+
yield Footer()
|
|
127
|
+
|
|
128
|
+
def on_mount(self):
|
|
129
|
+
"""Set up the application"""
|
|
130
|
+
self.title = "Messages Component Test"
|
|
131
|
+
|
|
132
|
+
@on(Button.Pressed, "#add_user")
|
|
133
|
+
def add_user_message(self):
|
|
134
|
+
"""Add a test user message"""
|
|
135
|
+
import time
|
|
136
|
+
|
|
137
|
+
self.notify("Add User button clicked!") # Debug
|
|
138
|
+
|
|
139
|
+
new_message = Message(
|
|
140
|
+
type=MessageType.USER,
|
|
141
|
+
message=MessageContent(f"Test user message at {time.strftime('%H:%M:%S')}"),
|
|
142
|
+
timestamp=time.time(),
|
|
143
|
+
options={},
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
self.test_messages.append(new_message)
|
|
147
|
+
self.notify(f"Added message, total: {len(self.test_messages)}") # Debug
|
|
148
|
+
|
|
149
|
+
# Update the Messages component using add_message method
|
|
150
|
+
try:
|
|
151
|
+
messages_component = self.query_one("#test_messages", expect_type=Messages)
|
|
152
|
+
self.notify(f"Found messages component: {messages_component}") # Debug
|
|
153
|
+
# Use add_message method which uses mutate_reactive
|
|
154
|
+
messages_component.add_message(new_message)
|
|
155
|
+
self.notify("Messages updated successfully!") # Debug
|
|
156
|
+
except Exception as e:
|
|
157
|
+
self.notify(f"Error updating messages: {e}")
|
|
158
|
+
|
|
159
|
+
@on(Button.Pressed, "#add_assistant")
|
|
160
|
+
def add_assistant_message(self):
|
|
161
|
+
"""Add a test assistant message"""
|
|
162
|
+
import time
|
|
163
|
+
|
|
164
|
+
new_message = Message(
|
|
165
|
+
type=MessageType.ASSISTANT,
|
|
166
|
+
message=MessageContent(
|
|
167
|
+
f"Test assistant response at {time.strftime('%H:%M:%S')}. This is a longer message to test how the component handles different message lengths and formatting."
|
|
168
|
+
),
|
|
169
|
+
timestamp=time.time(),
|
|
170
|
+
options={},
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
self.test_messages.append(new_message)
|
|
174
|
+
|
|
175
|
+
# Update the Messages component using add_message method
|
|
176
|
+
try:
|
|
177
|
+
messages_component = self.query_one("#test_messages", expect_type=Messages)
|
|
178
|
+
# Use add_message method which uses mutate_reactive
|
|
179
|
+
messages_component.add_message(new_message)
|
|
180
|
+
except Exception as e:
|
|
181
|
+
self.notify(f"Error updating messages: {e}")
|
|
182
|
+
|
|
183
|
+
@on(Button.Pressed, "#clear")
|
|
184
|
+
def clear_messages(self):
|
|
185
|
+
"""Clear all messages"""
|
|
186
|
+
self.test_messages = []
|
|
187
|
+
|
|
188
|
+
# Update the Messages component using clear_messages method
|
|
189
|
+
try:
|
|
190
|
+
messages_component = self.query_one("#test_messages", expect_type=Messages)
|
|
191
|
+
# Use clear_messages method which uses mutate_reactive
|
|
192
|
+
messages_component.clear_messages()
|
|
193
|
+
except Exception as e:
|
|
194
|
+
self.notify(f"Error clearing messages: {e}")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
app = TestMessagesApp()
|
|
199
|
+
app.run()
|
|
@@ -20,78 +20,78 @@ from minion_code.services import (
|
|
|
20
20
|
|
|
21
21
|
def main():
|
|
22
22
|
"""Demonstrate FileFreshnessService usage."""
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
# Create a test file
|
|
25
25
|
test_file = "test_file.txt"
|
|
26
26
|
with open(test_file, "w") as f:
|
|
27
27
|
f.write("Initial content")
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
print("=== File Freshness Service Demo ===\n")
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
# Set up event listeners to monitor what's happening
|
|
32
32
|
def on_file_read(context):
|
|
33
33
|
print(f"📖 File read event: {context.data['file_path']}")
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def on_file_edited(context):
|
|
36
36
|
print(f"✏️ File edited event: {context.data['file_path']}")
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
def on_file_conflict(context):
|
|
39
39
|
print(f"⚠️ File conflict detected: {context.data['file_path']}")
|
|
40
|
-
|
|
41
|
-
add_event_listener(
|
|
42
|
-
add_event_listener(
|
|
43
|
-
add_event_listener(
|
|
44
|
-
|
|
40
|
+
|
|
41
|
+
add_event_listener("file:read", on_file_read)
|
|
42
|
+
add_event_listener("file:edited", on_file_edited)
|
|
43
|
+
add_event_listener("file:conflict", on_file_conflict)
|
|
44
|
+
|
|
45
45
|
# 1. Record initial file read
|
|
46
46
|
print("1. Recording initial file read...")
|
|
47
47
|
record_file_read(test_file)
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
# 2. Check freshness (should be fresh)
|
|
50
50
|
print("\n2. Checking file freshness...")
|
|
51
51
|
result = check_file_freshness(test_file)
|
|
52
52
|
print(f" Is fresh: {result.is_fresh}, Conflict: {result.conflict}")
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
# 3. Simulate external modification
|
|
55
55
|
print("\n3. Simulating external file modification...")
|
|
56
56
|
time.sleep(0.1) # Small delay to ensure different timestamp
|
|
57
57
|
with open(test_file, "w") as f:
|
|
58
58
|
f.write("Modified content externally")
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
# 4. Check freshness again (should detect conflict)
|
|
61
61
|
print("\n4. Checking freshness after external modification...")
|
|
62
62
|
result = check_file_freshness(test_file)
|
|
63
63
|
print(f" Is fresh: {result.is_fresh}, Conflict: {result.conflict}")
|
|
64
|
-
|
|
64
|
+
|
|
65
65
|
# 5. Record agent edit (should clear conflict)
|
|
66
66
|
print("\n5. Recording agent edit...")
|
|
67
67
|
record_file_edit(test_file, "Agent modified content")
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
# 6. Check freshness after agent edit
|
|
70
70
|
print("\n6. Checking freshness after agent edit...")
|
|
71
71
|
result = check_file_freshness(test_file)
|
|
72
72
|
print(f" Is fresh: {result.is_fresh}, Conflict: {result.conflict}")
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
# 7. Show session files and conflicts
|
|
75
75
|
print("\n7. Session summary:")
|
|
76
76
|
session_files = file_freshness_service.get_session_files()
|
|
77
77
|
conflicted_files = file_freshness_service.get_conflicted_files()
|
|
78
78
|
important_files = file_freshness_service.get_important_files()
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
print(f" Session files: {session_files}")
|
|
81
81
|
print(f" Conflicted files: {conflicted_files}")
|
|
82
82
|
print(f" Important files: {important_files}")
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
# 8. Test session reset
|
|
85
85
|
print("\n8. Resetting session...")
|
|
86
|
-
emit_event(
|
|
87
|
-
|
|
86
|
+
emit_event("session:startup", {"context": {}})
|
|
87
|
+
|
|
88
88
|
session_files_after = file_freshness_service.get_session_files()
|
|
89
89
|
print(f" Session files after reset: {session_files_after}")
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
# Cleanup
|
|
92
92
|
os.remove(test_file)
|
|
93
93
|
print("\n✅ Demo completed successfully!")
|
|
94
94
|
|
|
95
95
|
|
|
96
96
|
if __name__ == "__main__":
|
|
97
|
-
main()
|
|
97
|
+
main()
|
|
@@ -20,9 +20,9 @@ from minion_code.services import (
|
|
|
20
20
|
|
|
21
21
|
def main():
|
|
22
22
|
"""Demonstrate file watching functionality."""
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
print("=== File Watching Demo ===\n")
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
# Set up event listeners
|
|
27
27
|
def on_todo_file_changed(context):
|
|
28
28
|
data = context.data
|
|
@@ -30,71 +30,77 @@ def main():
|
|
|
30
30
|
print(f" File: {data['file_path']}")
|
|
31
31
|
print(f" Reminder: {data['reminder']}")
|
|
32
32
|
print()
|
|
33
|
-
|
|
34
|
-
add_event_listener(
|
|
35
|
-
|
|
33
|
+
|
|
34
|
+
add_event_listener("todo:file_changed", on_todo_file_changed)
|
|
35
|
+
|
|
36
36
|
# Create test directory and file
|
|
37
37
|
test_dir = "test_todos"
|
|
38
38
|
os.makedirs(test_dir, exist_ok=True)
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
test_file = os.path.join(test_dir, "agent1.json")
|
|
41
41
|
agent_id = "agent1"
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
# Create initial todo file
|
|
44
44
|
with open(test_file, "w") as f:
|
|
45
|
-
f.write(
|
|
46
|
-
|
|
45
|
+
f.write(
|
|
46
|
+
'{"todos": [{"id": 1, "content": "Initial task", "status": "pending"}]}'
|
|
47
|
+
)
|
|
48
|
+
|
|
47
49
|
print(f"1. Created test todo file: {test_file}")
|
|
48
|
-
|
|
50
|
+
|
|
49
51
|
# Start watching the file
|
|
50
52
|
print(f"2. Starting to watch todo file for agent: {agent_id}")
|
|
51
53
|
start_watching_todo_file(agent_id, test_file)
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
# Record initial read
|
|
54
56
|
record_file_read(test_file)
|
|
55
57
|
print("3. Recorded initial file read")
|
|
56
|
-
|
|
58
|
+
|
|
57
59
|
# Check if we're watching
|
|
58
60
|
watched_files = file_freshness_service.get_watched_files()
|
|
59
61
|
print(f"4. Currently watching files: {watched_files}")
|
|
60
|
-
|
|
62
|
+
|
|
61
63
|
# Wait a bit for watcher to initialize
|
|
62
64
|
time.sleep(1)
|
|
63
|
-
|
|
65
|
+
|
|
64
66
|
# Simulate external modification
|
|
65
67
|
print("\n5. Simulating external file modification...")
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
def modify_file():
|
|
68
70
|
time.sleep(0.5) # Small delay
|
|
69
71
|
with open(test_file, "w") as f:
|
|
70
|
-
f.write(
|
|
72
|
+
f.write(
|
|
73
|
+
'{"todos": [{"id": 1, "content": "Modified task", "status": "completed"}]}'
|
|
74
|
+
)
|
|
71
75
|
print(" ✏️ File modified externally")
|
|
72
|
-
|
|
76
|
+
|
|
73
77
|
# Run modification in separate thread to avoid blocking
|
|
74
78
|
modifier_thread = threading.Thread(target=modify_file)
|
|
75
79
|
modifier_thread.start()
|
|
76
|
-
|
|
80
|
+
|
|
77
81
|
# Wait for modification and watcher to detect it
|
|
78
82
|
modifier_thread.join()
|
|
79
83
|
time.sleep(2) # Give watcher time to detect change
|
|
80
|
-
|
|
84
|
+
|
|
81
85
|
# Modify file again
|
|
82
86
|
print("6. Another external modification...")
|
|
83
87
|
time.sleep(0.5)
|
|
84
88
|
with open(test_file, "w") as f:
|
|
85
|
-
f.write(
|
|
86
|
-
|
|
89
|
+
f.write(
|
|
90
|
+
'{"todos": [{"id": 2, "content": "Another task", "status": "pending"}]}'
|
|
91
|
+
)
|
|
92
|
+
|
|
87
93
|
# Wait for detection
|
|
88
94
|
time.sleep(2)
|
|
89
|
-
|
|
95
|
+
|
|
90
96
|
# Stop watching
|
|
91
97
|
print("7. Stopping file watcher...")
|
|
92
98
|
stop_watching_todo_file(agent_id)
|
|
93
|
-
|
|
99
|
+
|
|
94
100
|
# Verify we're no longer watching
|
|
95
101
|
watched_files_after = file_freshness_service.get_watched_files()
|
|
96
102
|
print(f"8. Files being watched after stop: {watched_files_after}")
|
|
97
|
-
|
|
103
|
+
|
|
98
104
|
# Cleanup
|
|
99
105
|
try:
|
|
100
106
|
os.remove(test_file)
|
|
@@ -102,9 +108,9 @@ def main():
|
|
|
102
108
|
print("\n🧹 Cleaned up test files")
|
|
103
109
|
except Exception as e:
|
|
104
110
|
print(f"⚠️ Cleanup warning: {e}")
|
|
105
|
-
|
|
111
|
+
|
|
106
112
|
print("\n✅ File watching demo completed!")
|
|
107
113
|
|
|
108
114
|
|
|
109
115
|
if __name__ == "__main__":
|
|
110
|
-
main()
|
|
116
|
+
main()
|