devlake-mcp 0.4.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.
devlake_mcp/config.py ADDED
@@ -0,0 +1,204 @@
1
+ """
2
+ DevLake 配置管理
3
+
4
+ 统一管理 DevLake 的所有配置:
5
+ - MCP 服务器配置(DevLakeConfig)
6
+ - Hooks 环境配置(init_hooks_env)
7
+ - Git 信息缓存机制
8
+ """
9
+
10
+ import os
11
+ import sys
12
+ from dataclasses import dataclass
13
+ from typing import Optional, Dict
14
+
15
+ # 导入常量配置
16
+ from .constants import (
17
+ DEFAULT_API_BASE_URL,
18
+ API_REQUEST_TIMEOUT,
19
+ )
20
+
21
+
22
+ @dataclass
23
+ class DevLakeConfig:
24
+ """DevLake 配置类(用于 MCP 服务器和 Hooks)"""
25
+
26
+ # API 基础 URL
27
+ base_url: str
28
+
29
+ # API Token(如果需要认证)
30
+ api_token: Optional[str] = None
31
+
32
+ # 超时设置(秒)
33
+ timeout: int = 30
34
+
35
+ # 是否启用 SSL 验证
36
+ verify_ssl: bool = True
37
+
38
+ # Git 配置(用于 Hooks)
39
+ git_repo_path: Optional[str] = None
40
+ git_email: Optional[str] = None
41
+ git_author: Optional[str] = None
42
+
43
+ @classmethod
44
+ def from_env(cls, include_git: bool = False) -> "DevLakeConfig":
45
+ """
46
+ 从环境变量加载配置
47
+
48
+ Args:
49
+ include_git: 是否包含 Git 配置(Hooks 使用)
50
+
51
+ 环境变量:
52
+ - DEVLAKE_BASE_URL: DevLake API 地址(默认:http://devlake.test.chinawayltd.com)
53
+ - DEVLAKE_API_TOKEN: API Token(可选)
54
+ - DEVLAKE_TIMEOUT: 请求超时时间(默认:5 秒)
55
+ - DEVLAKE_VERIFY_SSL: 是否验证 SSL(默认:true)
56
+
57
+ Git 环境变量(include_git=True 时):
58
+ - GIT_REPO_PATH: Git仓库路径
59
+ - GIT_EMAIL: Git邮箱
60
+ - GIT_AUTHOR: Git用户名
61
+
62
+ Returns:
63
+ DevLakeConfig: 配置实例
64
+ """
65
+ # API 配置
66
+ base_url = os.getenv('DEVLAKE_BASE_URL', DEFAULT_API_BASE_URL)
67
+ api_token = os.getenv('DEVLAKE_API_TOKEN')
68
+ timeout = int(os.getenv('DEVLAKE_TIMEOUT', str(API_REQUEST_TIMEOUT)))
69
+ verify_ssl = os.getenv('DEVLAKE_VERIFY_SSL', "true").lower() == "true"
70
+
71
+ config = cls(
72
+ base_url=base_url.rstrip("/"),
73
+ api_token=api_token,
74
+ timeout=timeout,
75
+ verify_ssl=verify_ssl
76
+ )
77
+
78
+ # 加载 Git 配置(Hooks 专用)
79
+ if include_git:
80
+ config._load_git_config()
81
+
82
+ return config
83
+
84
+ def _load_git_config(self) -> None:
85
+ """加载 Git 配置并同步到环境变量(内部方法)"""
86
+ self.git_repo_path = os.getenv('GIT_REPO_PATH')
87
+ self.git_email = os.getenv('GIT_EMAIL')
88
+ self.git_author = os.getenv('GIT_AUTHOR')
89
+
90
+ # 如果环境变量未设置,尝试从 Git 配置读取
91
+ if not self.git_repo_path or not self.git_email:
92
+ try:
93
+ from .git_utils import get_git_repo_path, get_git_info
94
+
95
+ cwd = os.getcwd()
96
+
97
+ if not self.git_repo_path:
98
+ self.git_repo_path = get_git_repo_path(cwd)
99
+ os.environ['GIT_REPO_PATH'] = self.git_repo_path
100
+
101
+ if not self.git_email or not self.git_author:
102
+ git_info = get_git_info(cwd, include_user_info=True)
103
+ if not self.git_email:
104
+ self.git_email = git_info.get('git_email', 'unknown')
105
+ os.environ['GIT_EMAIL'] = self.git_email
106
+ if not self.git_author:
107
+ self.git_author = git_info.get('git_author', 'unknown')
108
+ os.environ['GIT_AUTHOR'] = self.git_author
109
+
110
+ except Exception as e:
111
+ print(f"\n⚠️ 警告:获取 Git 配置失败:{str(e)}", file=sys.stderr)
112
+ if not self.git_repo_path:
113
+ self.git_repo_path = 'unknown'
114
+ os.environ['GIT_REPO_PATH'] = 'unknown'
115
+ if not self.git_email:
116
+ self.git_email = 'unknown'
117
+ os.environ['GIT_EMAIL'] = 'unknown'
118
+ if not self.git_author:
119
+ self.git_author = 'unknown'
120
+ os.environ['GIT_AUTHOR'] = 'unknown'
121
+
122
+ # 验证必需的 Git 配置
123
+ self._validate_git_config()
124
+
125
+ def _validate_git_config(self):
126
+ """验证 Git 配置(内部方法)"""
127
+ missing_configs = []
128
+
129
+ if not self.git_repo_path or self.git_repo_path == 'unknown' or self.git_repo_path.startswith('local/'):
130
+ missing_configs.append('remote.origin.url')
131
+
132
+ if not self.git_email or self.git_email == 'unknown':
133
+ missing_configs.append('user.email')
134
+
135
+ if missing_configs:
136
+ print("\n" + "="*60, file=sys.stderr)
137
+ print("❌ 错误:缺少必需的 Git 配置", file=sys.stderr)
138
+ print("="*60, file=sys.stderr)
139
+ print("\n📝 请按照以下步骤配置 Git:\n", file=sys.stderr)
140
+
141
+ if 'remote.origin.url' in missing_configs:
142
+ print("1️⃣ 配置 Git 远程仓库:", file=sys.stderr)
143
+ print(" git remote add origin <repository-url>", file=sys.stderr)
144
+ print("", file=sys.stderr)
145
+
146
+ if 'user.email' in missing_configs:
147
+ print("2️⃣ 配置 Git 用户邮箱:", file=sys.stderr)
148
+ print(" git config user.email 'your-email@example.com'", file=sys.stderr)
149
+ print("", file=sys.stderr)
150
+
151
+ print("💡 提示:配置完成后,请重新运行命令。", file=sys.stderr)
152
+ print("="*60 + "\n", file=sys.stderr)
153
+ sys.exit(2)
154
+
155
+ def get_headers(self) -> Dict[str, str]:
156
+ """
157
+ 获取请求头
158
+
159
+ Returns:
160
+ dict: 请求头字典
161
+ """
162
+ headers = {
163
+ "Content-Type": "application/json",
164
+ "Accept": "application/json"
165
+ }
166
+
167
+ if self.api_token:
168
+ headers["Authorization"] = f"Bearer {self.api_token}"
169
+
170
+ return headers
171
+
172
+ @classmethod
173
+ def initialize_for_hooks(cls) -> "DevLakeConfig":
174
+ """
175
+ 为 Hooks 环境初始化配置
176
+
177
+ 这个方法会:
178
+ 1. 从环境变量加载 API 配置
179
+ 2. 获取静态 Git 信息(author, email, repo_path)并缓存到环境变量
180
+ 3. 验证配置完整性
181
+
182
+ 注意:
183
+ - 只缓存静态信息(author, email, repo_path)
184
+ - 动态信息(branch, commit)每次都重新获取,确保最新值
185
+
186
+ Returns:
187
+ DevLakeConfig: 已初始化的配置实例
188
+
189
+ 使用示例:
190
+ # 在 hooks 启动脚本中调用一次
191
+ config = DevLakeConfig.initialize_for_hooks()
192
+
193
+ # 静态信息从环境变量读取(已缓存)
194
+ git_author = os.getenv('GIT_AUTHOR')
195
+ git_email = os.getenv('GIT_EMAIL')
196
+
197
+ # 动态信息每次获取最新值
198
+ git_info = get_git_info(cwd, include_user_info=False)
199
+ git_branch = git_info.get('git_branch')
200
+ """
201
+ # 加载配置并获取静态 Git 信息(会自动缓存到环境变量)
202
+ config = cls.from_env(include_git=True)
203
+
204
+ return config
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ DevLake MCP 常量配置
5
+
6
+ 集中管理所有魔法值,提高代码可维护性。
7
+ """
8
+
9
+ from typing import Set
10
+
11
+ # ============================================================================
12
+ # Git 配置
13
+ # ============================================================================
14
+
15
+ # Git 命令超时时间(秒)
16
+ GIT_COMMAND_TIMEOUT: int = 1
17
+
18
+
19
+ # ============================================================================
20
+ # 文件过滤配置
21
+ # ============================================================================
22
+
23
+ # 敏感文件模式(包含这些关键词的文件不采集)
24
+ SENSITIVE_FILE_PATTERNS: list[str] = [
25
+ '.env',
26
+ '.env.', # .env.local, .env.production 等
27
+ '.secret',
28
+ '.secrets',
29
+ '.key',
30
+ '.pem',
31
+ '.crt',
32
+ '.p12',
33
+ '.pfx',
34
+ 'credentials',
35
+ 'password',
36
+ '.npmrc', # npm 配置
37
+ '.pypirc', # PyPI 配置
38
+ 'id_rsa', # SSH 私钥
39
+ 'id_dsa',
40
+ 'id_ecdsa',
41
+ 'id_ed25519',
42
+ ]
43
+
44
+ # 敏感目录(这些目录下的文件不采集)
45
+ SENSITIVE_DIRS: list[str] = [
46
+ '.ssh',
47
+ '.gnupg',
48
+ '.aws',
49
+ '.azure',
50
+ '.config',
51
+ 'node_modules', # 前端依赖
52
+ '.venv', # Python 虚拟环境
53
+ 'venv',
54
+ '__pycache__',
55
+ '.git', # Git 元数据
56
+ ]
57
+
58
+ # 二进制文件扩展名(这些文件不采集)
59
+ BINARY_FILE_EXTENSIONS: Set[str] = {
60
+ # 图片
61
+ '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.svg', '.webp',
62
+ # 压缩包
63
+ '.zip', '.tar', '.gz', '.bz2', '.rar', '.7z', '.xz',
64
+ # 文档
65
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
66
+ # 可执行文件
67
+ '.exe', '.dll', '.so', '.dylib', '.app', '.dmg',
68
+ # 编译产物
69
+ '.class', '.pyc', '.pyo', '.o', '.a', '.jar',
70
+ # 音视频
71
+ '.mp3', '.mp4', '.avi', '.mov', '.wav', '.flac',
72
+ # 字体
73
+ '.ttf', '.otf', '.woff', '.woff2', '.eot',
74
+ }
75
+
76
+
77
+ # ============================================================================
78
+ # API 配置
79
+ # ============================================================================
80
+
81
+ # API 请求超时时间(秒)
82
+ API_REQUEST_TIMEOUT: int = 5
83
+
84
+ # API 默认基础 URL
85
+ DEFAULT_API_BASE_URL: str = "http://devlake.test.chinawayltd.com"
86
+
87
+ # 最大内容大小(字节)- 10MB
88
+ MAX_CONTENT_SIZE: int = 10 * 1024 * 1024
89
+
90
+
91
+ # ============================================================================
92
+ # 临时文件配置
93
+ # ============================================================================
94
+
95
+ # 临时文件最大保留时间(小时)
96
+ TEMP_FILE_MAX_AGE_HOURS: int = 24
97
+
98
+ # 临时目录默认名称
99
+ TEMP_DIR_NAME: str = 'devlake_mcp'
100
+
101
+
102
+ # ============================================================================
103
+ # Hooks 配置
104
+ # ============================================================================
105
+
106
+ # Hook 执行超时时间(秒)
107
+ HOOK_EXECUTION_TIMEOUT: int = 5
108
+
109
+ # Hook 日志目录(默认为项目目录)
110
+ HOOK_LOG_DIR: str = '.claude/logs' # Claude Code hooks 日志目录(项目)
111
+ CURSOR_HOOK_LOG_DIR: str = '.cursor/logs' # Cursor hooks 日志目录(项目)
112
+
113
+ # 全局日志目录(当使用全局配置时)
114
+ GLOBAL_HOOK_LOG_DIR: str = None # 运行时动态设置为 ~/.claude/logs
115
+ GLOBAL_CURSOR_HOOK_LOG_DIR: str = None # 运行时动态设置为 ~/.cursor/logs
116
+
117
+ # 默认 IDE 类型
118
+ DEFAULT_IDE_TYPE: str = 'claude_code'
119
+
120
+ # 默认模型名称
121
+ DEFAULT_MODEL_NAME: str = 'claude-sonnet-4-5'
122
+
123
+
124
+ # ============================================================================
125
+ # Generation 配置
126
+ # ============================================================================
127
+
128
+ # Generation 状态文件名
129
+ GENERATION_STATE_FILE_NAME: str = 'generation_state.json'
130
+
131
+ # Generation 状态最大保留时间(小时)- 超过此时间的状态可以被清理
132
+ GENERATION_STATE_MAX_AGE_HOURS: int = 24
133
+
134
+
135
+ # ============================================================================
136
+ # Transcript 压缩配置
137
+ # ============================================================================
138
+
139
+ # Transcript 压缩阈值(字节)- 超过此大小才进行压缩
140
+ # 1MB = 1 * 1024 * 1024 bytes * 0.5
141
+ TRANSCRIPT_COMPRESSION_THRESHOLD: int = 1 * 1024 * 1024 * 0.5
142
+
143
+ # Transcript 压缩算法
144
+ TRANSCRIPT_COMPRESSION_ALGORITHM: str = 'gzip'
145
+
146
+
147
+ # ============================================================================
148
+ # 日志配置
149
+ # ============================================================================
150
+
151
+ # 日志级别映射(字符串 -> logging 常量)
152
+ VALID_LOG_LEVELS: dict[str, int] = {
153
+ 'DEBUG': 10, # logging.DEBUG
154
+ 'INFO': 20, # logging.INFO
155
+ 'WARNING': 30, # logging.WARNING
156
+ 'ERROR': 40, # logging.ERROR
157
+ 'CRITICAL': 50, # logging.CRITICAL
158
+ }
159
+
160
+ # 默认日志级别
161
+ DEFAULT_LOG_LEVEL: str = 'INFO'
devlake_mcp/enums.py ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ 枚举类型定义模块
5
+
6
+ 提供项目中使用的所有枚举类型
7
+ """
8
+
9
+ from enum import Enum
10
+
11
+
12
+ class IDEType(str, Enum):
13
+ """
14
+ 支持的 IDE 类型枚举
15
+
16
+ 继承 str 以便:
17
+ 1. 直接用于字符串比较和拼接
18
+ 2. JSON 序列化时自动转换为字符串
19
+ 3. 向后兼容现有字符串参数
20
+
21
+ 使用示例:
22
+ # 作为参数
23
+ start_generation(session_id, ide_type=IDEType.CLAUDE_CODE)
24
+
25
+ # 字符串比较
26
+ if ide_type == IDEType.CLAUDE_CODE:
27
+ ...
28
+
29
+ # 获取字符串值
30
+ ide_type.value # 'claude_code'
31
+
32
+ # 从字符串创建
33
+ IDEType('claude_code') # IDEType.CLAUDE_CODE
34
+ """
35
+ CLAUDE_CODE = 'claude_code' # Anthropic Claude Code
36
+ CURSOR = 'cursor' # Cursor AI IDE
37
+ QODER = 'qoder' # Qoder IDE (未来支持)
38
+ UNKNOWN = 'unknown' # 未知或不支持的 IDE
39
+
40
+ @classmethod
41
+ def from_string(cls, value: str) -> 'IDEType':
42
+ """
43
+ 从字符串创建枚举(安全转换)
44
+
45
+ Args:
46
+ value: IDE 类型字符串
47
+
48
+ Returns:
49
+ 对应的 IDEType 枚举值,无效值返回 UNKNOWN
50
+
51
+ 示例:
52
+ IDEType.from_string('claude_code') # IDEType.CLAUDE_CODE
53
+ IDEType.from_string('invalid') # IDEType.UNKNOWN
54
+ """
55
+ try:
56
+ return cls(value.lower())
57
+ except (ValueError, AttributeError):
58
+ return cls.UNKNOWN