overcode 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.
- overcode/__init__.py +5 -0
- overcode/cli.py +812 -0
- overcode/config.py +72 -0
- overcode/daemon.py +1184 -0
- overcode/daemon_claude_skill.md +180 -0
- overcode/daemon_state.py +113 -0
- overcode/data_export.py +257 -0
- overcode/dependency_check.py +227 -0
- overcode/exceptions.py +219 -0
- overcode/history_reader.py +448 -0
- overcode/implementations.py +214 -0
- overcode/interfaces.py +49 -0
- overcode/launcher.py +434 -0
- overcode/logging_config.py +193 -0
- overcode/mocks.py +152 -0
- overcode/monitor_daemon.py +808 -0
- overcode/monitor_daemon_state.py +358 -0
- overcode/pid_utils.py +225 -0
- overcode/presence_logger.py +454 -0
- overcode/protocols.py +143 -0
- overcode/session_manager.py +606 -0
- overcode/settings.py +412 -0
- overcode/standing_instructions.py +276 -0
- overcode/status_constants.py +190 -0
- overcode/status_detector.py +339 -0
- overcode/status_history.py +164 -0
- overcode/status_patterns.py +264 -0
- overcode/summarizer_client.py +136 -0
- overcode/summarizer_component.py +312 -0
- overcode/supervisor_daemon.py +1000 -0
- overcode/supervisor_layout.sh +50 -0
- overcode/tmux_manager.py +228 -0
- overcode/tui.py +2549 -0
- overcode/tui_helpers.py +495 -0
- overcode/web_api.py +279 -0
- overcode/web_server.py +138 -0
- overcode/web_templates.py +563 -0
- overcode-0.1.0.dist-info/METADATA +87 -0
- overcode-0.1.0.dist-info/RECORD +43 -0
- overcode-0.1.0.dist-info/WHEEL +5 -0
- overcode-0.1.0.dist-info/entry_points.txt +2 -0
- overcode-0.1.0.dist-info/licenses/LICENSE +21 -0
- overcode-0.1.0.dist-info/top_level.txt +1 -0
overcode/mocks.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock implementations of protocol interfaces for testing.
|
|
3
|
+
|
|
4
|
+
These mocks allow unit tests to run without real tmux sessions,
|
|
5
|
+
file system access, or subprocess calls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Optional, List, Dict, Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MockTmux:
|
|
14
|
+
"""Mock implementation of TmuxInterface for testing"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.sessions: Dict[str, Dict[int, str]] = {} # session -> {window: content}
|
|
18
|
+
self.sent_keys: List[tuple] = [] # Record of sent keys
|
|
19
|
+
self._next_window = 1
|
|
20
|
+
|
|
21
|
+
def set_pane_content(self, session: str, window: int, content: str):
|
|
22
|
+
"""Set up mock pane content for testing"""
|
|
23
|
+
if session not in self.sessions:
|
|
24
|
+
self.sessions[session] = {}
|
|
25
|
+
self.sessions[session][window] = content
|
|
26
|
+
|
|
27
|
+
def capture_pane(self, session: str, window: int, lines: int = 100) -> Optional[str]:
|
|
28
|
+
if session in self.sessions and window in self.sessions[session]:
|
|
29
|
+
content = self.sessions[session][window]
|
|
30
|
+
# Simulate line limit
|
|
31
|
+
content_lines = content.split('\n')
|
|
32
|
+
return '\n'.join(content_lines[-lines:])
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
def send_keys(self, session: str, window: int, keys: str, enter: bool = True) -> bool:
|
|
36
|
+
self.sent_keys.append((session, window, keys, enter))
|
|
37
|
+
return session in self.sessions
|
|
38
|
+
|
|
39
|
+
def has_session(self, session: str) -> bool:
|
|
40
|
+
return session in self.sessions
|
|
41
|
+
|
|
42
|
+
def new_session(self, session: str) -> bool:
|
|
43
|
+
if session not in self.sessions:
|
|
44
|
+
self.sessions[session] = {}
|
|
45
|
+
return True
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
def new_window(self, session: str, name: str, command: Optional[List[str]] = None,
|
|
49
|
+
cwd: Optional[str] = None) -> Optional[int]:
|
|
50
|
+
if session not in self.sessions:
|
|
51
|
+
return None
|
|
52
|
+
window = self._next_window
|
|
53
|
+
self._next_window += 1
|
|
54
|
+
self.sessions[session][window] = ""
|
|
55
|
+
return window
|
|
56
|
+
|
|
57
|
+
def kill_window(self, session: str, window: int) -> bool:
|
|
58
|
+
if session in self.sessions and window in self.sessions[session]:
|
|
59
|
+
del self.sessions[session][window]
|
|
60
|
+
return True
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
def kill_session(self, session: str) -> bool:
|
|
64
|
+
if session in self.sessions:
|
|
65
|
+
del self.sessions[session]
|
|
66
|
+
return True
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
def list_windows(self, session: str) -> List[Dict[str, Any]]:
|
|
70
|
+
if session not in self.sessions:
|
|
71
|
+
return []
|
|
72
|
+
return [
|
|
73
|
+
{'index': idx, 'name': f'window-{idx}', 'active': False}
|
|
74
|
+
for idx in self.sessions[session].keys()
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
def attach(self, session: str) -> None:
|
|
78
|
+
pass # No-op in tests
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class MockFileSystem:
|
|
82
|
+
"""Mock implementation of FileSystemInterface for testing"""
|
|
83
|
+
|
|
84
|
+
def __init__(self):
|
|
85
|
+
self.files: Dict[str, Any] = {} # path_str -> content
|
|
86
|
+
self.dirs: set = set()
|
|
87
|
+
|
|
88
|
+
def read_json(self, path: Path) -> Optional[Dict[str, Any]]:
|
|
89
|
+
content = self.files.get(str(path))
|
|
90
|
+
if content is None:
|
|
91
|
+
return None
|
|
92
|
+
if isinstance(content, dict):
|
|
93
|
+
return content
|
|
94
|
+
try:
|
|
95
|
+
return json.loads(content)
|
|
96
|
+
except json.JSONDecodeError:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
def write_json(self, path: Path, data: Dict[str, Any]) -> bool:
|
|
100
|
+
self.files[str(path)] = data
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
def exists(self, path: Path) -> bool:
|
|
104
|
+
return str(path) in self.files or str(path) in self.dirs
|
|
105
|
+
|
|
106
|
+
def mkdir(self, path: Path, parents: bool = True) -> bool:
|
|
107
|
+
self.dirs.add(str(path))
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
def read_text(self, path: Path) -> Optional[str]:
|
|
111
|
+
content = self.files.get(str(path))
|
|
112
|
+
if content is None:
|
|
113
|
+
return None
|
|
114
|
+
return str(content)
|
|
115
|
+
|
|
116
|
+
def write_text(self, path: Path, content: str) -> bool:
|
|
117
|
+
self.files[str(path)] = content
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class MockSubprocess:
|
|
122
|
+
"""Mock implementation of SubprocessInterface for testing"""
|
|
123
|
+
|
|
124
|
+
def __init__(self):
|
|
125
|
+
self.commands: List[List[str]] = [] # Record of run commands
|
|
126
|
+
self.responses: Dict[str, Dict[str, Any]] = {} # cmd_key -> response
|
|
127
|
+
|
|
128
|
+
def set_response(self, cmd_prefix: str, returncode: int = 0,
|
|
129
|
+
stdout: str = "", stderr: str = ""):
|
|
130
|
+
"""Set up a mock response for commands starting with prefix"""
|
|
131
|
+
self.responses[cmd_prefix] = {
|
|
132
|
+
'returncode': returncode,
|
|
133
|
+
'stdout': stdout,
|
|
134
|
+
'stderr': stderr
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
def run(self, cmd: List[str], timeout: Optional[int] = None,
|
|
138
|
+
capture_output: bool = True) -> Optional[Dict[str, Any]]:
|
|
139
|
+
self.commands.append(cmd)
|
|
140
|
+
cmd_str = ' '.join(cmd)
|
|
141
|
+
|
|
142
|
+
# Check for matching response
|
|
143
|
+
for prefix, response in self.responses.items():
|
|
144
|
+
if cmd_str.startswith(prefix):
|
|
145
|
+
return response
|
|
146
|
+
|
|
147
|
+
# Default response
|
|
148
|
+
return {'returncode': 0, 'stdout': '', 'stderr': ''}
|
|
149
|
+
|
|
150
|
+
def popen(self, cmd: List[str], cwd: Optional[str] = None) -> Any:
|
|
151
|
+
self.commands.append(cmd)
|
|
152
|
+
return None
|