auto-coder-web 0.1.116__py3-none-any.whl → 0.1.117__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.
- auto_coder_web/auto_coder_runner_wrapper.py +11 -1
- auto_coder_web/proxy.py +3 -0
- auto_coder_web/terminal.py +64 -15
- auto_coder_web/version.py +1 -1
- auto_coder_web/web/assets/main.js +233 -233
- {auto_coder_web-0.1.116.dist-info → auto_coder_web-0.1.117.dist-info}/METADATA +2 -2
- {auto_coder_web-0.1.116.dist-info → auto_coder_web-0.1.117.dist-info}/RECORD +10 -10
- {auto_coder_web-0.1.116.dist-info → auto_coder_web-0.1.117.dist-info}/WHEEL +0 -0
- {auto_coder_web-0.1.116.dist-info → auto_coder_web-0.1.117.dist-info}/entry_points.txt +0 -0
- {auto_coder_web-0.1.116.dist-info → auto_coder_web-0.1.117.dist-info}/top_level.txt +0 -0
@@ -32,7 +32,9 @@ from autocoder.auto_coder_runner import (
|
|
32
32
|
completer,
|
33
33
|
summon,
|
34
34
|
get_memory,
|
35
|
-
get_all_extensions
|
35
|
+
get_all_extensions,
|
36
|
+
start as start_engine,
|
37
|
+
stop as stop_engine
|
36
38
|
)
|
37
39
|
|
38
40
|
class AutoCoderRunnerWrapper:
|
@@ -41,6 +43,14 @@ class AutoCoderRunnerWrapper:
|
|
41
43
|
self.product_mode = product_mode
|
42
44
|
load_memory()
|
43
45
|
load_tokenizer()
|
46
|
+
|
47
|
+
|
48
|
+
def start(self):
|
49
|
+
start_engine()
|
50
|
+
|
51
|
+
def stop(self):
|
52
|
+
stop_engine()
|
53
|
+
|
44
54
|
|
45
55
|
def get_all_extensions_wrapper(self):
|
46
56
|
return get_all_extensions(self.project_path)
|
auto_coder_web/proxy.py
CHANGED
@@ -50,6 +50,7 @@ class ProxyServer:
|
|
50
50
|
|
51
51
|
def _initialize(self):
|
52
52
|
self.auto_coder_runner = AutoCoderRunnerWrapper(self.project_path, product_mode=self.product_mode)
|
53
|
+
self.auto_coder_runner.start()
|
53
54
|
self.client = httpx.AsyncClient()
|
54
55
|
|
55
56
|
|
@@ -120,6 +121,8 @@ class ProxyServer:
|
|
120
121
|
|
121
122
|
@self.app.on_event("shutdown")
|
122
123
|
async def shutdown_event():
|
124
|
+
if self.auto_coder_runner:
|
125
|
+
self.auto_coder_runner.stop()
|
123
126
|
await self.client.aclose()
|
124
127
|
|
125
128
|
@self.app.websocket("/ws/terminal")
|
auto_coder_web/terminal.py
CHANGED
@@ -15,7 +15,11 @@ import platform
|
|
15
15
|
|
16
16
|
# 为不同平台选择合适的终端库
|
17
17
|
if platform.system() == 'Windows':
|
18
|
-
|
18
|
+
try:
|
19
|
+
import winpty
|
20
|
+
except ImportError:
|
21
|
+
print("Warning: winpty not found. Terminal functionality may not work on Windows.")
|
22
|
+
winpty = None
|
19
23
|
else:
|
20
24
|
import pty
|
21
25
|
import fcntl
|
@@ -45,14 +49,21 @@ class TerminalSession:
|
|
45
49
|
"""Start the terminal session"""
|
46
50
|
if self.platform == 'Windows':
|
47
51
|
# Windows下使用winpty
|
52
|
+
if winpty is None:
|
53
|
+
raise RuntimeError("winpty is not available. Please install winpty: pip install winpty")
|
54
|
+
|
48
55
|
try:
|
49
56
|
self.pty = winpty.PTY(
|
50
57
|
cols=80,
|
51
58
|
rows=24
|
52
59
|
)
|
53
|
-
# 在Windows下,
|
54
|
-
|
55
|
-
|
60
|
+
# 在Windows下,spawn 返回的是process对象或进程ID
|
61
|
+
process_result = self.pty.spawn(self.shell)
|
62
|
+
if hasattr(process_result, 'pid'):
|
63
|
+
self.pid = process_result.pid
|
64
|
+
else:
|
65
|
+
self.pid = process_result # 假设直接返回的是 PID
|
66
|
+
self.fd = None # winpty 不使用传统的文件描述符
|
56
67
|
self.running = True
|
57
68
|
asyncio.create_task(self._handle_io())
|
58
69
|
except Exception as e:
|
@@ -97,8 +108,21 @@ class TerminalSession:
|
|
97
108
|
# Windows下使用winpty的读取方法
|
98
109
|
if self.pty:
|
99
110
|
try:
|
100
|
-
|
101
|
-
|
111
|
+
# winpty 可能有不同的读取方法
|
112
|
+
if hasattr(self.pty, 'read'):
|
113
|
+
data = self.pty.read(size)
|
114
|
+
elif hasattr(self.pty, 'read_blocking'):
|
115
|
+
data = self.pty.read_blocking(size, timeout=100) # 100ms超时
|
116
|
+
else:
|
117
|
+
# 如果没有直接的读取方法,返回空数据
|
118
|
+
return b''
|
119
|
+
|
120
|
+
if isinstance(data, str):
|
121
|
+
return data.encode('utf-8')
|
122
|
+
elif isinstance(data, bytes):
|
123
|
+
return data
|
124
|
+
else:
|
125
|
+
return b''
|
102
126
|
except Exception as e:
|
103
127
|
print(f"Error reading from winpty: {e}")
|
104
128
|
return None
|
@@ -179,11 +203,17 @@ class TerminalSession:
|
|
179
203
|
return
|
180
204
|
|
181
205
|
try:
|
182
|
-
encoded_data = data.encode('utf-8')
|
183
206
|
if self.platform == 'Windows':
|
184
207
|
if self.pty:
|
185
|
-
|
208
|
+
# winpty 可能有不同的写入方法
|
209
|
+
if hasattr(self.pty, 'write'):
|
210
|
+
self.pty.write(data) # winpty接受字符串输入
|
211
|
+
elif hasattr(self.pty, 'write_input'):
|
212
|
+
self.pty.write_input(data)
|
213
|
+
else:
|
214
|
+
print(f"Warning: winpty object has no write method")
|
186
215
|
else:
|
216
|
+
encoded_data = data.encode('utf-8')
|
187
217
|
if self.fd is not None:
|
188
218
|
os.write(self.fd, encoded_data)
|
189
219
|
except Exception as e:
|
@@ -197,9 +227,21 @@ class TerminalSession:
|
|
197
227
|
if self.platform == 'Windows':
|
198
228
|
if self.pty:
|
199
229
|
try:
|
200
|
-
|
230
|
+
# winpty.PTY 对象没有 close() 方法,使用进程终止
|
231
|
+
if self.pid:
|
232
|
+
try:
|
233
|
+
import psutil
|
234
|
+
process = psutil.Process(self.pid)
|
235
|
+
process.terminate()
|
236
|
+
process.wait(timeout=3)
|
237
|
+
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
|
238
|
+
pass
|
239
|
+
except Exception as e:
|
240
|
+
print(f"Error terminating winpty process: {e}")
|
241
|
+
# 清空 pty 引用
|
242
|
+
self.pty = None
|
201
243
|
except Exception as e:
|
202
|
-
print(f"Error
|
244
|
+
print(f"Error cleaning up winpty: {e}")
|
203
245
|
else:
|
204
246
|
if self.pid:
|
205
247
|
try:
|
@@ -234,6 +276,7 @@ class TerminalManager:
|
|
234
276
|
|
235
277
|
async def handle_websocket(self, websocket: WebSocket, session_id: str):
|
236
278
|
"""Handle websocket connection for a terminal session"""
|
279
|
+
session = None
|
237
280
|
try:
|
238
281
|
await websocket.accept()
|
239
282
|
session = await self.create_session(websocket, session_id)
|
@@ -265,14 +308,20 @@ class TerminalManager:
|
|
265
308
|
session.write(data)
|
266
309
|
except websockets.exceptions.ConnectionClosed:
|
267
310
|
print("WebSocket closed normally during terminal session")
|
268
|
-
|
269
|
-
|
270
|
-
if
|
271
|
-
|
311
|
+
except Exception as e:
|
312
|
+
# 检查是否是 WebSocket 断开连接相关的异常
|
313
|
+
if "1001" in str(e) or "ConnectionClosed" in str(e.__class__.__name__):
|
314
|
+
print("WebSocket disconnected during terminal session")
|
315
|
+
else:
|
316
|
+
print(f"Error in terminal websocket communication: {str(e)}")
|
317
|
+
raise
|
272
318
|
except Exception as e:
|
273
319
|
print(f"Error in terminal websocket: {str(e)}")
|
320
|
+
# 只在非预期的异常时重新抛出
|
321
|
+
if not ("1001" in str(e) or "ConnectionClosed" in str(e.__class__.__name__)):
|
322
|
+
raise
|
323
|
+
finally:
|
274
324
|
if session_id in self.sessions:
|
275
325
|
await self.close_session(session_id)
|
276
|
-
raise
|
277
326
|
|
278
327
|
terminal_manager = TerminalManager()
|
auto_coder_web/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.117"
|