cloneloop 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.
- cloneloop-0.1.0.dist-info/METADATA +392 -0
- cloneloop-0.1.0.dist-info/RECORD +118 -0
- cloneloop-0.1.0.dist-info/WHEEL +4 -0
- cloneloop-0.1.0.dist-info/entry_points.txt +5 -0
- mcp_ai_supervisor/__init__.py +52 -0
- mcp_ai_supervisor/__main__.py +551 -0
- mcp_ai_supervisor/debug.py +15 -0
- mcp_ai_supervisor/desktop_app/__init__.py +29 -0
- mcp_ai_supervisor/desktop_app/desktop_app.py +390 -0
- mcp_ai_supervisor/helpers/__init__.py +4 -0
- mcp_ai_supervisor/helpers/feedback_helpers.py +140 -0
- mcp_ai_supervisor/helpers/image_helpers.py +73 -0
- mcp_ai_supervisor/i18n.py +14 -0
- mcp_ai_supervisor/log_writer.py +16 -0
- mcp_ai_supervisor/logging/__init__.py +8 -0
- mcp_ai_supervisor/logging/log_parser.py +293 -0
- mcp_ai_supervisor/logging/log_tailer.py +367 -0
- mcp_ai_supervisor/py.typed +0 -0
- mcp_ai_supervisor/server.py +654 -0
- mcp_ai_supervisor/utils/__init__.py +28 -0
- mcp_ai_supervisor/utils/error_handler.py +10 -0
- mcp_ai_supervisor/utils/memory_monitor.py +11 -0
- mcp_ai_supervisor/utils/paths.py +7 -0
- mcp_ai_supervisor/utils/resource_manager.py +15 -0
- mcp_ai_supervisor/utils/structure_checker.py +291 -0
- mcp_ai_supervisor/web/__init__.py +26 -0
- mcp_ai_supervisor/web/constants/__init__.py +8 -0
- mcp_ai_supervisor/web/constants/message_codes.py +173 -0
- mcp_ai_supervisor/web/core/__init__.py +30 -0
- mcp_ai_supervisor/web/core/agent_bridge.py +957 -0
- mcp_ai_supervisor/web/core/auto_responder.py +332 -0
- mcp_ai_supervisor/web/core/context_collector.py +124 -0
- mcp_ai_supervisor/web/core/conversation_recorder.py +751 -0
- mcp_ai_supervisor/web/core/delegate_manager.py +1193 -0
- mcp_ai_supervisor/web/core/feedback_mediator.py +259 -0
- mcp_ai_supervisor/web/core/message_channel.py +551 -0
- mcp_ai_supervisor/web/core/response_builder.py +333 -0
- mcp_ai_supervisor/web/core/scene_detector.py +184 -0
- mcp_ai_supervisor/web/core/task_state.py +194 -0
- mcp_ai_supervisor/web/locales/en/translation.json +643 -0
- mcp_ai_supervisor/web/locales/zh-CN/translation.json +629 -0
- mcp_ai_supervisor/web/locales/zh-TW/translation.json +648 -0
- mcp_ai_supervisor/web/main.py +747 -0
- mcp_ai_supervisor/web/managers/__init__.py +8 -0
- mcp_ai_supervisor/web/managers/desktop_manager.py +228 -0
- mcp_ai_supervisor/web/managers/server_manager.py +170 -0
- mcp_ai_supervisor/web/managers/session_manager.py +515 -0
- mcp_ai_supervisor/web/managers/workbench_connector.py +186 -0
- mcp_ai_supervisor/web/models/__init__.py +13 -0
- mcp_ai_supervisor/web/models/feedback_result.py +16 -0
- mcp_ai_supervisor/web/models/feedback_session.py +938 -0
- mcp_ai_supervisor/web/models/session_cleaner.py +245 -0
- mcp_ai_supervisor/web/models/session_commands.py +213 -0
- mcp_ai_supervisor/web/models/session_resolver.py +158 -0
- mcp_ai_supervisor/web/models/session_timer.py +242 -0
- mcp_ai_supervisor/web/routes/__init__.py +12 -0
- mcp_ai_supervisor/web/routes/main_routes.py +965 -0
- mcp_ai_supervisor/web/routes/settings_routes.py +195 -0
- mcp_ai_supervisor/web/routes/ws_handlers.py +270 -0
- mcp_ai_supervisor/web/static/css/audio-management.css +545 -0
- mcp_ai_supervisor/web/static/css/notification-settings.css +152 -0
- mcp_ai_supervisor/web/static/css/prompt-management.css +566 -0
- mcp_ai_supervisor/web/static/css/session-management.css +1428 -0
- mcp_ai_supervisor/web/static/css/styles.css +2267 -0
- mcp_ai_supervisor/web/static/favicon.ico +0 -0
- mcp_ai_supervisor/web/static/icon-192.png +0 -0
- mcp_ai_supervisor/web/static/icon.svg +11 -0
- mcp_ai_supervisor/web/static/index.html +37 -0
- mcp_ai_supervisor/web/static/js/app.js +1721 -0
- mcp_ai_supervisor/web/static/js/i18n.js +376 -0
- mcp_ai_supervisor/web/static/js/modules/audio/audio-manager.js +610 -0
- mcp_ai_supervisor/web/static/js/modules/audio/audio-settings-ui.js +732 -0
- mcp_ai_supervisor/web/static/js/modules/connection-monitor.js +435 -0
- mcp_ai_supervisor/web/static/js/modules/constants/message-codes.js +168 -0
- mcp_ai_supervisor/web/static/js/modules/countdown-manager.js +273 -0
- mcp_ai_supervisor/web/static/js/modules/drag-drop-handler.js +677 -0
- mcp_ai_supervisor/web/static/js/modules/file-upload-manager.js +555 -0
- mcp_ai_supervisor/web/static/js/modules/image-handler.js +199 -0
- mcp_ai_supervisor/web/static/js/modules/logger.js +404 -0
- mcp_ai_supervisor/web/static/js/modules/notification/notification-manager.js +360 -0
- mcp_ai_supervisor/web/static/js/modules/notification/notification-settings.js +344 -0
- mcp_ai_supervisor/web/static/js/modules/prompt/prompt-input-buttons.js +427 -0
- mcp_ai_supervisor/web/static/js/modules/prompt/prompt-manager.js +414 -0
- mcp_ai_supervisor/web/static/js/modules/prompt/prompt-modal.js +458 -0
- mcp_ai_supervisor/web/static/js/modules/prompt/prompt-settings-ui.js +524 -0
- mcp_ai_supervisor/web/static/js/modules/session/session-data-manager.js +1042 -0
- mcp_ai_supervisor/web/static/js/modules/session/session-details-modal.js +594 -0
- mcp_ai_supervisor/web/static/js/modules/session/session-ui-renderer.js +836 -0
- mcp_ai_supervisor/web/static/js/modules/session-manager.js +1059 -0
- mcp_ai_supervisor/web/static/js/modules/settings-manager.js +1002 -0
- mcp_ai_supervisor/web/static/js/modules/tab-manager.js +235 -0
- mcp_ai_supervisor/web/static/js/modules/textarea-height-manager.js +267 -0
- mcp_ai_supervisor/web/static/js/modules/ui-manager.js +578 -0
- mcp_ai_supervisor/web/static/js/modules/utils/dom-utils.js +392 -0
- mcp_ai_supervisor/web/static/js/modules/utils/status-utils.js +403 -0
- mcp_ai_supervisor/web/static/js/modules/utils/time-utils.js +440 -0
- mcp_ai_supervisor/web/static/js/modules/utils.js +557 -0
- mcp_ai_supervisor/web/static/js/modules/websocket-manager.js +875 -0
- mcp_ai_supervisor/web/static/js/modules/workbench-notification.js +103 -0
- mcp_ai_supervisor/web/static/js/vendor/marked.min.js +6 -0
- mcp_ai_supervisor/web/static/js/vendor/purify.min.js +3 -0
- mcp_ai_supervisor/web/templates/components/image-upload.html +43 -0
- mcp_ai_supervisor/web/templates/components/settings-card.html +58 -0
- mcp_ai_supervisor/web/templates/components/status-indicator.html +31 -0
- mcp_ai_supervisor/web/templates/components/toggle-switch.html +19 -0
- mcp_ai_supervisor/web/templates/feedback.html +1198 -0
- mcp_ai_supervisor/web/templates/index.html +378 -0
- mcp_ai_supervisor/web/utils/__init__.py +12 -0
- mcp_ai_supervisor/web/utils/browser.py +35 -0
- mcp_ai_supervisor/web/utils/compression_config.py +195 -0
- mcp_ai_supervisor/web/utils/compression_monitor.py +314 -0
- mcp_ai_supervisor/web/utils/ide_opener.py +286 -0
- mcp_ai_supervisor/web/utils/network.py +66 -0
- mcp_ai_supervisor/web/utils/port_manager.py +340 -0
- mcp_ai_supervisor/web/utils/session_cleanup_manager.py +543 -0
- mcp_ai_supervisor/web/utils/workbench_client.py +899 -0
- mcp_ai_supervisor/workbench/__init__.py +5 -0
- mcp_ai_supervisor/workbench/__main__.py +5 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""代理模块:重定向到 mcp_supervisor_core.memory_monitor
|
|
2
|
+
|
|
3
|
+
重构过渡期保持向后兼容。
|
|
4
|
+
Phase 3 删除 src/ 时此文件一并删除。
|
|
5
|
+
"""
|
|
6
|
+
from mcp_supervisor_core.memory_monitor import * # noqa: F401,F403
|
|
7
|
+
from mcp_supervisor_core.memory_monitor import ( # noqa: F401
|
|
8
|
+
MemoryMonitor,
|
|
9
|
+
MemorySnapshot,
|
|
10
|
+
get_memory_monitor,
|
|
11
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""代理模块:重定向到 mcp_supervisor_core.resource_manager
|
|
2
|
+
|
|
3
|
+
重构过渡期保持向后兼容。
|
|
4
|
+
Phase 3 删除 src/ 时此文件一并删除。
|
|
5
|
+
"""
|
|
6
|
+
from mcp_supervisor_core.resource_manager import * # noqa: F401,F403
|
|
7
|
+
from mcp_supervisor_core.resource_manager import ( # noqa: F401
|
|
8
|
+
ResourceManager,
|
|
9
|
+
ResourceType,
|
|
10
|
+
cleanup_all_resources,
|
|
11
|
+
create_temp_dir,
|
|
12
|
+
create_temp_file,
|
|
13
|
+
get_resource_manager,
|
|
14
|
+
register_process,
|
|
15
|
+
)
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"""代码结构检查模块 — 检查变更文件所在目录的结构健康度。
|
|
2
|
+
|
|
3
|
+
AI 每次编码完成后调用,只扫描变更文件所在的目录(不递归子目录),
|
|
4
|
+
产出结构摘要帮助 PM 判断代码组织是否需要关注。
|
|
5
|
+
|
|
6
|
+
用法:
|
|
7
|
+
from mcp_ai_supervisor.utils.structure_checker import check_changed_dirs
|
|
8
|
+
report = check_changed_dirs("/project/root", ["src/a.py", "src/b.py"])
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
from collections import defaultdict
|
|
14
|
+
from fnmatch import fnmatch
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
DEFAULT_CONFIG = {
|
|
18
|
+
"max_files_per_dir": 15,
|
|
19
|
+
"file_size_warning": 300,
|
|
20
|
+
"file_size_critical": 500,
|
|
21
|
+
"file_size_severe": 1000,
|
|
22
|
+
"ignore_files": [
|
|
23
|
+
"*.pyc", "*.pyo", "*.min.js", "*.min.css", "*.bundle.js",
|
|
24
|
+
"*.map", "*.lock",
|
|
25
|
+
"*.ico", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.webp",
|
|
26
|
+
"*.woff", "*.woff2", "*.ttf", "*.eot",
|
|
27
|
+
"*.zip", "*.tar", "*.gz", "*.bz2", "*.whl",
|
|
28
|
+
"*.so", "*.dylib", "*.dll", "*.o", "*.obj", "*.class",
|
|
29
|
+
"*.DS_Store",
|
|
30
|
+
],
|
|
31
|
+
"ignore_dirs": [
|
|
32
|
+
"node_modules", "__pycache__", ".git", ".tox", ".mypy_cache",
|
|
33
|
+
".pytest_cache", "dist", "build", "*.egg-info", ".eggs",
|
|
34
|
+
".venv", "venv", "env",
|
|
35
|
+
],
|
|
36
|
+
"related_extensions": [
|
|
37
|
+
[".tsx", ".module.css"],
|
|
38
|
+
[".jsx", ".module.css"],
|
|
39
|
+
[".vue", ".module.css"],
|
|
40
|
+
[".ts", ".module.css"],
|
|
41
|
+
[".py", ".pyi"],
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
CODE_EXTENSIONS = {
|
|
46
|
+
".py", ".pyi", ".ts", ".tsx", ".js", ".jsx", ".css", ".scss", ".less",
|
|
47
|
+
".html", ".htm", ".sh", ".bash", ".sql", ".rs", ".go", ".java", ".rb",
|
|
48
|
+
".vue", ".svelte",
|
|
49
|
+
".c", ".cpp", ".h", ".hpp", ".cc", ".cxx",
|
|
50
|
+
".swift", ".kt", ".kts", ".dart", ".php",
|
|
51
|
+
".scala", ".lua", ".r",
|
|
52
|
+
".graphql", ".gql", ".proto",
|
|
53
|
+
".ex", ".exs", ".erl",
|
|
54
|
+
".cs",
|
|
55
|
+
}
|
|
56
|
+
DOC_EXTENSIONS = {".md", ".txt", ".rst", ".adoc", ".tex"}
|
|
57
|
+
|
|
58
|
+
ROLE_KEYWORDS = {
|
|
59
|
+
"model": "数据模型", "models": "数据模型", "schema": "数据模型", "schemas": "数据模型",
|
|
60
|
+
"route": "路由接口", "routes": "路由接口", "router": "路由接口", "api": "路由接口",
|
|
61
|
+
"endpoint": "路由接口", "endpoints": "路由接口",
|
|
62
|
+
"controller": "控制器", "controllers": "控制器",
|
|
63
|
+
"service": "业务逻辑", "services": "业务逻辑", "manager": "业务逻辑",
|
|
64
|
+
"handler": "业务逻辑", "handlers": "业务逻辑",
|
|
65
|
+
"middleware": "中间件", "middlewares": "中间件",
|
|
66
|
+
"util": "工具类", "utils": "工具类", "helper": "工具类", "helpers": "工具类",
|
|
67
|
+
"config": "配置", "settings": "配置", "constants": "配置", "const": "配置",
|
|
68
|
+
"test": "测试", "tests": "测试", "spec": "测试",
|
|
69
|
+
"mock": "测试", "mocks": "测试", "fixture": "测试", "fixtures": "测试",
|
|
70
|
+
"component": "UI组件", "components": "UI组件",
|
|
71
|
+
"view": "视图", "views": "视图", "template": "模板", "templates": "模板",
|
|
72
|
+
"hook": "钩子", "hooks": "钩子",
|
|
73
|
+
"store": "状态管理", "stores": "状态管理",
|
|
74
|
+
"type": "类型定义", "types": "类型定义", "interface": "类型定义", "interfaces": "类型定义",
|
|
75
|
+
"dto": "数据传输",
|
|
76
|
+
"migration": "数据迁移", "migrations": "数据迁移",
|
|
77
|
+
"plugin": "插件", "plugins": "插件",
|
|
78
|
+
"adapter": "适配器", "adapters": "适配器",
|
|
79
|
+
"validator": "校验", "validators": "校验",
|
|
80
|
+
"serializer": "序列化", "serializers": "序列化",
|
|
81
|
+
"command": "命令", "commands": "命令",
|
|
82
|
+
"task": "异步任务", "tasks": "异步任务", "worker": "异步任务", "workers": "异步任务",
|
|
83
|
+
"provider": "提供者", "providers": "提供者",
|
|
84
|
+
"repository": "仓储", "repositories": "仓储",
|
|
85
|
+
"factory": "工厂", "factories": "工厂",
|
|
86
|
+
"decorator": "装饰器", "decorators": "装饰器",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _load_config(project_root: str) -> dict:
|
|
91
|
+
config = dict(DEFAULT_CONFIG)
|
|
92
|
+
config_path = os.path.join(project_root, ".structure-check.json")
|
|
93
|
+
if os.path.isfile(config_path):
|
|
94
|
+
try:
|
|
95
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
96
|
+
config.update(json.load(f))
|
|
97
|
+
except (json.JSONDecodeError, OSError):
|
|
98
|
+
pass
|
|
99
|
+
return config
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _should_ignore(filename: str, config: dict) -> bool:
|
|
103
|
+
return any(fnmatch(filename, p) for p in config["ignore_files"])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _count_lines(filepath: str) -> int:
|
|
107
|
+
try:
|
|
108
|
+
with open(filepath, "rb") as f:
|
|
109
|
+
if b"\x00" in f.read(1024):
|
|
110
|
+
return -1
|
|
111
|
+
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
|
|
112
|
+
return sum(1 for _ in f)
|
|
113
|
+
except (OSError, UnicodeDecodeError):
|
|
114
|
+
return -1
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _infer_role(filename: str) -> str | None:
|
|
118
|
+
stem = Path(filename).stem.lower()
|
|
119
|
+
for keyword, role in ROLE_KEYWORDS.items():
|
|
120
|
+
if keyword in stem.split("_") or keyword in stem.split("-") or stem == keyword:
|
|
121
|
+
return role
|
|
122
|
+
if stem.startswith("test_") or stem.endswith("_test") or stem.endswith("_spec"):
|
|
123
|
+
return "测试"
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _is_ignored_dir(dirname: str, config: dict) -> bool:
|
|
128
|
+
return any(fnmatch(dirname, p) for p in config.get("ignore_dirs", []))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _scan_dir(dirpath: str, config: dict) -> dict:
|
|
132
|
+
info = {
|
|
133
|
+
"path": dirpath,
|
|
134
|
+
"files": [],
|
|
135
|
+
"file_count": 0,
|
|
136
|
+
"code_file_count": 0,
|
|
137
|
+
"total_lines": 0,
|
|
138
|
+
"roles": defaultdict(int),
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if not os.path.isdir(dirpath):
|
|
142
|
+
return info
|
|
143
|
+
|
|
144
|
+
dirname = os.path.basename(dirpath)
|
|
145
|
+
if _is_ignored_dir(dirname, config):
|
|
146
|
+
return info
|
|
147
|
+
|
|
148
|
+
for fname in os.listdir(dirpath):
|
|
149
|
+
fpath = os.path.join(dirpath, fname)
|
|
150
|
+
if not os.path.isfile(fpath) or _should_ignore(fname, config):
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
ext = os.path.splitext(fname)[1].lower()
|
|
154
|
+
lines = _count_lines(fpath)
|
|
155
|
+
if lines < 0:
|
|
156
|
+
continue
|
|
157
|
+
|
|
158
|
+
is_code = ext in CODE_EXTENSIONS
|
|
159
|
+
role = _infer_role(fname)
|
|
160
|
+
|
|
161
|
+
info["files"].append({
|
|
162
|
+
"name": fname, "ext": ext, "lines": lines,
|
|
163
|
+
"is_code": is_code, "role": role,
|
|
164
|
+
})
|
|
165
|
+
info["file_count"] += 1
|
|
166
|
+
if is_code:
|
|
167
|
+
info["code_file_count"] += 1
|
|
168
|
+
info["total_lines"] += lines
|
|
169
|
+
if role:
|
|
170
|
+
info["roles"][role] += 1
|
|
171
|
+
|
|
172
|
+
return info
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _analyze_dir(dir_info: dict, config: dict) -> list[str]:
|
|
176
|
+
concerns = []
|
|
177
|
+
|
|
178
|
+
for f in sorted(
|
|
179
|
+
(f for f in dir_info["files"] if f["is_code"] and f["lines"] >= config["file_size_warning"]),
|
|
180
|
+
key=lambda x: -x["lines"],
|
|
181
|
+
):
|
|
182
|
+
lines = f["lines"]
|
|
183
|
+
if lines >= config["file_size_severe"]:
|
|
184
|
+
level = "严重过大"
|
|
185
|
+
elif lines >= config["file_size_critical"]:
|
|
186
|
+
level = "过大"
|
|
187
|
+
else:
|
|
188
|
+
level = "较大"
|
|
189
|
+
concerns.append(f" {f['name']} ({lines} 行, {level})")
|
|
190
|
+
|
|
191
|
+
if dir_info["file_count"] > config["max_files_per_dir"]:
|
|
192
|
+
concerns.append(f" 目录文件数: {dir_info['file_count']} 个 (超过 {config['max_files_per_dir']})")
|
|
193
|
+
|
|
194
|
+
code_files = [f for f in dir_info["files"] if f["is_code"]]
|
|
195
|
+
doc_files = [
|
|
196
|
+
f for f in dir_info["files"]
|
|
197
|
+
if f["ext"] in DOC_EXTENSIONS and f["name"].upper() != "README.MD"
|
|
198
|
+
]
|
|
199
|
+
if code_files and doc_files:
|
|
200
|
+
doc_names = ", ".join(f["name"] for f in doc_files[:5])
|
|
201
|
+
concerns.append(f" 文档混入代码目录: {doc_names}")
|
|
202
|
+
|
|
203
|
+
roles = dict(dir_info["roles"])
|
|
204
|
+
if len(roles) >= 3:
|
|
205
|
+
role_summary = ", ".join(f"{r}({c})" for r, c in sorted(roles.items(), key=lambda x: -x[1]))
|
|
206
|
+
concerns.append(f" 职责混杂: {role_summary}")
|
|
207
|
+
|
|
208
|
+
return concerns
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def check_changed_dirs(project_root: str, changed_files: list[str]) -> str:
|
|
212
|
+
"""Check directories containing changed files and return a text report.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
project_root: Absolute path to the project root.
|
|
216
|
+
changed_files: List of changed file paths (relative or absolute).
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
A text report. Empty string if no changed_files provided.
|
|
220
|
+
"""
|
|
221
|
+
if not changed_files:
|
|
222
|
+
return ""
|
|
223
|
+
|
|
224
|
+
config = _load_config(project_root)
|
|
225
|
+
dirs_to_check: set[str] = set()
|
|
226
|
+
changed_info: list[dict] = []
|
|
227
|
+
|
|
228
|
+
for cf in changed_files:
|
|
229
|
+
abs_path = cf if os.path.isabs(cf) else os.path.join(project_root, cf)
|
|
230
|
+
rel_path = os.path.relpath(abs_path, project_root)
|
|
231
|
+
|
|
232
|
+
parent = os.path.dirname(abs_path)
|
|
233
|
+
if os.path.isdir(parent):
|
|
234
|
+
dirs_to_check.add(parent)
|
|
235
|
+
|
|
236
|
+
if os.path.isfile(abs_path):
|
|
237
|
+
lines = _count_lines(abs_path)
|
|
238
|
+
ext = os.path.splitext(rel_path)[1].lower()
|
|
239
|
+
is_code = ext in CODE_EXTENSIONS
|
|
240
|
+
size_label = ""
|
|
241
|
+
if is_code and lines >= 0:
|
|
242
|
+
if lines >= config["file_size_severe"]:
|
|
243
|
+
size_label = "严重过大"
|
|
244
|
+
elif lines >= config["file_size_critical"]:
|
|
245
|
+
size_label = "过大"
|
|
246
|
+
elif lines >= config["file_size_warning"]:
|
|
247
|
+
size_label = "较大"
|
|
248
|
+
changed_info.append({
|
|
249
|
+
"path": rel_path,
|
|
250
|
+
"lines": max(lines, 0),
|
|
251
|
+
"size_label": size_label,
|
|
252
|
+
"exists": True,
|
|
253
|
+
})
|
|
254
|
+
else:
|
|
255
|
+
changed_info.append({
|
|
256
|
+
"path": rel_path, "lines": 0,
|
|
257
|
+
"size_label": "", "exists": False,
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
parts = ["=== 变更文件 ==="]
|
|
261
|
+
for ci in changed_info:
|
|
262
|
+
if not ci["exists"]:
|
|
263
|
+
parts.append(f" [-] {ci['path']} (已删除)")
|
|
264
|
+
else:
|
|
265
|
+
note = f", {ci['size_label']}" if ci["size_label"] else ""
|
|
266
|
+
parts.append(f" [~] {ci['path']} ({ci['lines']} 行{note})")
|
|
267
|
+
|
|
268
|
+
dir_concerns: dict[str, dict] = {}
|
|
269
|
+
for dp in sorted(dirs_to_check):
|
|
270
|
+
di = _scan_dir(dp, config)
|
|
271
|
+
cs = _analyze_dir(di, config)
|
|
272
|
+
if cs:
|
|
273
|
+
rd = os.path.relpath(dp, project_root)
|
|
274
|
+
dir_concerns[rd] = {
|
|
275
|
+
"concerns": cs,
|
|
276
|
+
"file_count": di["file_count"],
|
|
277
|
+
"code_file_count": di["code_file_count"],
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
parts.append("")
|
|
281
|
+
parts.append("=== 目录结构关注 ===")
|
|
282
|
+
if dir_concerns:
|
|
283
|
+
for rd, info in dir_concerns.items():
|
|
284
|
+
parts.append(
|
|
285
|
+
f"\n{rd}/ ({info['file_count']} 文件, 其中 {info['code_file_count']} 个代码文件)"
|
|
286
|
+
)
|
|
287
|
+
parts.extend(info["concerns"])
|
|
288
|
+
else:
|
|
289
|
+
parts.append("未发现结构问题")
|
|
290
|
+
|
|
291
|
+
return "\n".join(parts)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
MCP AI Supervisor Web UI 模組
|
|
4
|
+
|
|
5
|
+
基於 FastAPI 和 WebSocket 的 Web 用戶介面,提供豐富的互動回饋功能。
|
|
6
|
+
支援文字輸入、圖片上傳、命令執行等功能,設計採用現代化的 Web UI 架構。
|
|
7
|
+
|
|
8
|
+
主要功能:
|
|
9
|
+
- FastAPI Web 應用程式
|
|
10
|
+
- WebSocket 實時通訊
|
|
11
|
+
- 多語言國際化支援
|
|
12
|
+
- 圖片上傳與預覽
|
|
13
|
+
- 命令執行與結果展示
|
|
14
|
+
- 響應式設計
|
|
15
|
+
- 本地和遠端環境適配
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from .main import WebUIManager, get_web_ui_manager, launch_web_feedback_ui, stop_web_ui
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"WebUIManager",
|
|
23
|
+
"get_web_ui_manager",
|
|
24
|
+
"launch_web_feedback_ui",
|
|
25
|
+
"stop_web_ui",
|
|
26
|
+
]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
統一的訊息代碼定義
|
|
3
|
+
|
|
4
|
+
這個模組定義了所有後端使用的訊息代碼常量。
|
|
5
|
+
前端會根據這些代碼顯示對應的本地化訊息。
|
|
6
|
+
|
|
7
|
+
使用方式:
|
|
8
|
+
from ..constants import MessageCodes, get_message_code
|
|
9
|
+
|
|
10
|
+
# 使用常量
|
|
11
|
+
code = MessageCodes.SESSION_FEEDBACK_SUBMITTED
|
|
12
|
+
|
|
13
|
+
# 或使用輔助函數
|
|
14
|
+
code = get_message_code("SESSION_FEEDBACK_SUBMITTED")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MessageCodes:
|
|
19
|
+
"""訊息代碼常量類"""
|
|
20
|
+
|
|
21
|
+
# ========== 系統相關 ==========
|
|
22
|
+
SYSTEM_CONNECTION_ESTABLISHED = "system.connectionEstablished"
|
|
23
|
+
SYSTEM_CONNECTION_LOST = "system.connectionLost"
|
|
24
|
+
SYSTEM_CONNECTION_RECONNECTING = "system.connectionReconnecting"
|
|
25
|
+
SYSTEM_CONNECTION_RECONNECTED = "system.connectionReconnected"
|
|
26
|
+
SYSTEM_CONNECTION_FAILED = "system.connectionFailed"
|
|
27
|
+
SYSTEM_WEBSOCKET_ERROR = "system.websocketError"
|
|
28
|
+
SYSTEM_WEBSOCKET_READY = "system.websocketReady"
|
|
29
|
+
SYSTEM_MEMORY_PRESSURE = "system.memoryPressure"
|
|
30
|
+
SYSTEM_SHUTDOWN = "system.shutdown"
|
|
31
|
+
SYSTEM_PROCESS_KILLED = "system.processKilled"
|
|
32
|
+
SYSTEM_HEARTBEAT_STOPPED = "system.heartbeatStopped"
|
|
33
|
+
|
|
34
|
+
# ========== 會話相關 ==========
|
|
35
|
+
SESSION_NO_ACTIVE = "session.noActiveSession"
|
|
36
|
+
SESSION_CREATED = "session.created"
|
|
37
|
+
SESSION_UPDATED = "session.updated"
|
|
38
|
+
SESSION_EXPIRED = "session.expired"
|
|
39
|
+
SESSION_TIMEOUT = "session.timeout"
|
|
40
|
+
SESSION_CLEANED = "session.cleaned"
|
|
41
|
+
SESSION_FEEDBACK_SUBMITTED = "session.feedbackSubmitted"
|
|
42
|
+
SESSION_USER_MESSAGE_RECORDED = "session.userMessageRecorded"
|
|
43
|
+
SESSION_HISTORY_SAVED = "session.historySaved"
|
|
44
|
+
SESSION_HISTORY_LOADED = "session.historyLoaded"
|
|
45
|
+
SESSION_MANUAL_CLEANUP = "session.manualCleanup"
|
|
46
|
+
SESSION_ERROR_CLEANUP = "session.errorCleanup"
|
|
47
|
+
|
|
48
|
+
# ========== 設定相關 ==========
|
|
49
|
+
SETTINGS_SAVED = "settingsAPI.saved"
|
|
50
|
+
SETTINGS_LOADED = "settingsAPI.loaded"
|
|
51
|
+
SETTINGS_CLEARED = "settingsAPI.cleared"
|
|
52
|
+
SETTINGS_SAVE_FAILED = "settingsAPI.saveFailed"
|
|
53
|
+
SETTINGS_LOAD_FAILED = "settingsAPI.loadFailed"
|
|
54
|
+
SETTINGS_CLEAR_FAILED = "settingsAPI.clearFailed"
|
|
55
|
+
SETTINGS_SET_FAILED = "settingsAPI.setFailed"
|
|
56
|
+
SETTINGS_INVALID_VALUE = "settingsAPI.invalidValue"
|
|
57
|
+
SETTINGS_LOG_LEVEL_UPDATED = "settingsAPI.logLevelUpdated"
|
|
58
|
+
SETTINGS_INVALID_LOG_LEVEL = "settingsAPI.invalidLogLevel"
|
|
59
|
+
|
|
60
|
+
# ========== 命令執行相關 ==========
|
|
61
|
+
COMMAND_EXECUTING = "commandStatus.executing"
|
|
62
|
+
COMMAND_COMPLETED = "commandStatus.completed"
|
|
63
|
+
COMMAND_FAILED = "commandStatus.failed"
|
|
64
|
+
COMMAND_INVALID = "commandStatus.invalid"
|
|
65
|
+
COMMAND_OUTPUT_RECEIVED = "commandStatus.outputReceived"
|
|
66
|
+
COMMAND_ERROR = "commandStatus.error"
|
|
67
|
+
|
|
68
|
+
# ========== 錯誤相關 ==========
|
|
69
|
+
ERROR_GENERIC = "error.generic"
|
|
70
|
+
ERROR_NETWORK = "error.network"
|
|
71
|
+
ERROR_SERVER = "error.server"
|
|
72
|
+
ERROR_TIMEOUT = "error.timeout"
|
|
73
|
+
ERROR_INVALID_INPUT = "error.invalidInput"
|
|
74
|
+
ERROR_OPERATION_FAILED = "error.operationFailed"
|
|
75
|
+
ERROR_USER_MESSAGE_FAILED = "error.userMessageFailed"
|
|
76
|
+
ERROR_GET_SESSIONS_FAILED = "error.getSessionsFailed"
|
|
77
|
+
ERROR_GET_LOG_LEVEL_FAILED = "error.getLogLevelFailed"
|
|
78
|
+
ERROR_RESOURCE_CLEANUP = "error.resourceCleanup"
|
|
79
|
+
ERROR_PROCESSING = "error.processing"
|
|
80
|
+
|
|
81
|
+
# ========== 檔案相關 ==========
|
|
82
|
+
FILE_UPLOAD_SUCCESS = "file.uploadSuccess"
|
|
83
|
+
FILE_UPLOAD_FAILED = "file.uploadFailed"
|
|
84
|
+
FILE_SIZE_TOO_LARGE = "file.sizeTooLarge"
|
|
85
|
+
FILE_TYPE_NOT_SUPPORTED = "file.typeNotSupported"
|
|
86
|
+
FILE_PROCESSING = "file.processing"
|
|
87
|
+
FILE_REMOVED = "file.removed"
|
|
88
|
+
|
|
89
|
+
# ========== 提示詞相關 ==========
|
|
90
|
+
PROMPT_SAVED = "prompt.saved"
|
|
91
|
+
PROMPT_DELETED = "prompt.deleted"
|
|
92
|
+
PROMPT_APPLIED = "prompt.applied"
|
|
93
|
+
PROMPT_IMPORT_SUCCESS = "prompt.importSuccess"
|
|
94
|
+
PROMPT_IMPORT_FAILED = "prompt.importFailed"
|
|
95
|
+
PROMPT_EXPORT_SUCCESS = "prompt.exportSuccess"
|
|
96
|
+
PROMPT_VALIDATION_FAILED = "prompt.validationFailed"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# 向後兼容的映射表(從舊的 key 到新的常量名稱)
|
|
100
|
+
LEGACY_KEY_MAPPING = {
|
|
101
|
+
# feedback_session.py 的舊 key
|
|
102
|
+
"FEEDBACK_SUBMITTED": "SESSION_FEEDBACK_SUBMITTED",
|
|
103
|
+
"SESSION_CLEANUP": "SESSION_CLEANED",
|
|
104
|
+
"TIMEOUT_CLEANUP": "SESSION_TIMEOUT",
|
|
105
|
+
"EXPIRED_CLEANUP": "SESSION_EXPIRED",
|
|
106
|
+
"MEMORY_PRESSURE_CLEANUP": "SYSTEM_MEMORY_PRESSURE",
|
|
107
|
+
"MANUAL_CLEANUP": "SESSION_MANUAL_CLEANUP",
|
|
108
|
+
"ERROR_CLEANUP": "SESSION_ERROR_CLEANUP",
|
|
109
|
+
"SHUTDOWN_CLEANUP": "SYSTEM_SHUTDOWN",
|
|
110
|
+
"COMMAND_EXECUTING": "COMMAND_EXECUTING",
|
|
111
|
+
"COMMAND_COMPLETED": "COMMAND_COMPLETED",
|
|
112
|
+
"COMMAND_FAILED": "COMMAND_FAILED",
|
|
113
|
+
"COMMAND_INVALID": "COMMAND_INVALID",
|
|
114
|
+
"COMMAND_ERROR": "COMMAND_ERROR",
|
|
115
|
+
"PROCESS_KILLED": "SYSTEM_PROCESS_KILLED",
|
|
116
|
+
"RESOURCE_CLEANUP_ERROR": "ERROR_RESOURCE_CLEANUP",
|
|
117
|
+
"HEARTBEAT_STOPPED": "SYSTEM_HEARTBEAT_STOPPED",
|
|
118
|
+
"PROCESSING_ERROR": "ERROR_PROCESSING",
|
|
119
|
+
"WEBSOCKET_READY": "SYSTEM_WEBSOCKET_READY",
|
|
120
|
+
# main_routes.py 的舊 key
|
|
121
|
+
"no_active_session": "SESSION_NO_ACTIVE",
|
|
122
|
+
"websocket_connected": "SYSTEM_CONNECTION_ESTABLISHED",
|
|
123
|
+
"new_session_created": "SESSION_CREATED",
|
|
124
|
+
"user_message_recorded": "SESSION_USER_MESSAGE_RECORDED",
|
|
125
|
+
"add_user_message_failed": "ERROR_USER_MESSAGE_FAILED",
|
|
126
|
+
"settings_saved": "SETTINGS_SAVED",
|
|
127
|
+
"save_failed": "SETTINGS_SAVE_FAILED",
|
|
128
|
+
"load_failed": "SETTINGS_LOAD_FAILED",
|
|
129
|
+
"settings_cleared": "SETTINGS_CLEARED",
|
|
130
|
+
"clear_failed": "SETTINGS_CLEAR_FAILED",
|
|
131
|
+
"session_history_saved": "SESSION_HISTORY_SAVED",
|
|
132
|
+
"get_sessions_failed": "ERROR_GET_SESSIONS_FAILED",
|
|
133
|
+
"get_log_level_failed": "ERROR_GET_LOG_LEVEL_FAILED",
|
|
134
|
+
"invalid_log_level": "SETTINGS_INVALID_LOG_LEVEL",
|
|
135
|
+
"log_level_updated": "SETTINGS_LOG_LEVEL_UPDATED",
|
|
136
|
+
"set_failed": "SETTINGS_SET_FAILED",
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def get_message_code(key: str) -> str:
|
|
141
|
+
"""
|
|
142
|
+
獲取訊息代碼
|
|
143
|
+
|
|
144
|
+
支援三種輸入方式:
|
|
145
|
+
1. 直接使用常量名稱:get_message_code("SESSION_FEEDBACK_SUBMITTED")
|
|
146
|
+
2. 使用舊的 key(向後兼容):get_message_code("FEEDBACK_SUBMITTED")
|
|
147
|
+
3. 使用小寫的舊 key(向後兼容):get_message_code("feedback_submitted")
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
key: 訊息 key 或常量名稱
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
訊息代碼字串(例如:"session.feedbackSubmitted")
|
|
154
|
+
"""
|
|
155
|
+
# 嘗試直接從 MessageCodes 獲取
|
|
156
|
+
if hasattr(MessageCodes, key):
|
|
157
|
+
return str(getattr(MessageCodes, key))
|
|
158
|
+
|
|
159
|
+
# 嘗試從映射表獲取(支援大寫和小寫)
|
|
160
|
+
upper_key = key.upper()
|
|
161
|
+
if upper_key in LEGACY_KEY_MAPPING:
|
|
162
|
+
constant_name = LEGACY_KEY_MAPPING[upper_key]
|
|
163
|
+
if hasattr(MessageCodes, constant_name):
|
|
164
|
+
return str(getattr(MessageCodes, constant_name))
|
|
165
|
+
|
|
166
|
+
# 如果是小寫的 key,也嘗試映射
|
|
167
|
+
if key in LEGACY_KEY_MAPPING:
|
|
168
|
+
constant_name = LEGACY_KEY_MAPPING[key]
|
|
169
|
+
if hasattr(MessageCodes, constant_name):
|
|
170
|
+
return str(getattr(MessageCodes, constant_name))
|
|
171
|
+
|
|
172
|
+
# 如果都找不到,返回一個預設格式
|
|
173
|
+
return f"unknown.{key}"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
MCP AI Supervisor 核心模块
|
|
4
|
+
|
|
5
|
+
提供循环机制与模式支持的核心组件:
|
|
6
|
+
- DelegateManager: 核心编排器
|
|
7
|
+
- TaskStateManager / TaskState / TaskPhase: 任务状态管理
|
|
8
|
+
- ResponseBuilder: 响应构建
|
|
9
|
+
- SceneDetector / SceneResult: 场景识别
|
|
10
|
+
- AutoResponder / QuestionType: 自动回复
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .auto_responder import AutoResponder, QuestionType
|
|
14
|
+
from .delegate_manager import DelegateManager, get_delegate_manager
|
|
15
|
+
from .response_builder import ResponseBuilder
|
|
16
|
+
from .scene_detector import SceneDetector, SceneResult
|
|
17
|
+
from .task_state import TaskPhase, TaskState, TaskStateManager
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"AutoResponder",
|
|
21
|
+
"DelegateManager",
|
|
22
|
+
"QuestionType",
|
|
23
|
+
"ResponseBuilder",
|
|
24
|
+
"SceneDetector",
|
|
25
|
+
"SceneResult",
|
|
26
|
+
"TaskPhase",
|
|
27
|
+
"TaskState",
|
|
28
|
+
"TaskStateManager",
|
|
29
|
+
"get_delegate_manager",
|
|
30
|
+
]
|