super-dev 2.0.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.
Files changed (61) hide show
  1. super_dev/__init__.py +11 -0
  2. super_dev/analyzer/__init__.py +34 -0
  3. super_dev/analyzer/analyzer.py +440 -0
  4. super_dev/analyzer/detectors.py +511 -0
  5. super_dev/analyzer/models.py +285 -0
  6. super_dev/cli.py +3257 -0
  7. super_dev/config/__init__.py +11 -0
  8. super_dev/config/frontend.py +557 -0
  9. super_dev/config/manager.py +281 -0
  10. super_dev/creators/__init__.py +26 -0
  11. super_dev/creators/creator.py +134 -0
  12. super_dev/creators/document_generator.py +2473 -0
  13. super_dev/creators/frontend_builder.py +371 -0
  14. super_dev/creators/implementation_builder.py +789 -0
  15. super_dev/creators/prompt_generator.py +289 -0
  16. super_dev/creators/requirement_parser.py +354 -0
  17. super_dev/creators/spec_builder.py +195 -0
  18. super_dev/deployers/__init__.py +20 -0
  19. super_dev/deployers/cicd.py +1269 -0
  20. super_dev/deployers/delivery.py +229 -0
  21. super_dev/deployers/migration.py +1032 -0
  22. super_dev/design/__init__.py +74 -0
  23. super_dev/design/aesthetics.py +530 -0
  24. super_dev/design/charts.py +396 -0
  25. super_dev/design/codegen.py +379 -0
  26. super_dev/design/engine.py +528 -0
  27. super_dev/design/generator.py +395 -0
  28. super_dev/design/landing.py +422 -0
  29. super_dev/design/tech_stack.py +524 -0
  30. super_dev/design/tokens.py +269 -0
  31. super_dev/design/ux_guide.py +391 -0
  32. super_dev/exceptions.py +119 -0
  33. super_dev/experts/__init__.py +19 -0
  34. super_dev/experts/service.py +161 -0
  35. super_dev/integrations/__init__.py +7 -0
  36. super_dev/integrations/manager.py +264 -0
  37. super_dev/orchestrator/__init__.py +12 -0
  38. super_dev/orchestrator/engine.py +958 -0
  39. super_dev/orchestrator/experts.py +423 -0
  40. super_dev/orchestrator/knowledge.py +352 -0
  41. super_dev/orchestrator/quality.py +356 -0
  42. super_dev/reviewers/__init__.py +17 -0
  43. super_dev/reviewers/code_review.py +471 -0
  44. super_dev/reviewers/quality_gate.py +964 -0
  45. super_dev/reviewers/redteam.py +881 -0
  46. super_dev/skills/__init__.py +7 -0
  47. super_dev/skills/manager.py +307 -0
  48. super_dev/specs/__init__.py +44 -0
  49. super_dev/specs/generator.py +264 -0
  50. super_dev/specs/manager.py +428 -0
  51. super_dev/specs/models.py +348 -0
  52. super_dev/specs/validator.py +415 -0
  53. super_dev/utils/__init__.py +11 -0
  54. super_dev/utils/logger.py +133 -0
  55. super_dev/web/api.py +1402 -0
  56. super_dev-2.0.0.dist-info/METADATA +252 -0
  57. super_dev-2.0.0.dist-info/RECORD +61 -0
  58. super_dev-2.0.0.dist-info/WHEEL +5 -0
  59. super_dev-2.0.0.dist-info/entry_points.txt +2 -0
  60. super_dev-2.0.0.dist-info/licenses/LICENSE +21 -0
  61. super_dev-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,415 @@
1
+ """
2
+ Spec-Driven Development 验证器
3
+
4
+ 开发:Excellent(11964948@qq.com)
5
+ 功能:验证规格格式和结构
6
+ 作用:检查 spec.md 和 change 的格式是否符合 OpenSpec 标准
7
+ 创建时间:2025-12-30
8
+ """
9
+
10
+ import re
11
+ from dataclasses import dataclass, field
12
+ from pathlib import Path
13
+
14
+
15
+ @dataclass
16
+ class ValidationError:
17
+ """验证错误"""
18
+ file: str # 文件路径
19
+ line: int = 0 # 行号
20
+ column: int = 0 # 列号
21
+ message: str = "" # 错误消息
22
+ severity: str = "error" # 严重程度: error, warning, info
23
+
24
+
25
+ @dataclass
26
+ class ValidationResult:
27
+ """验证结果"""
28
+ is_valid: bool
29
+ errors: list[ValidationError] = field(default_factory=list)
30
+ warnings: list[ValidationError] = field(default_factory=list)
31
+ info: list[ValidationError] = field(default_factory=list)
32
+
33
+ @property
34
+ def total_issues(self) -> int:
35
+ """总问题数"""
36
+ return len(self.errors) + len(self.warnings)
37
+
38
+ def to_summary(self) -> str:
39
+ """生成摘要报告"""
40
+ lines = []
41
+ if self.is_valid:
42
+ lines.append("[通过] 规格格式验证通过")
43
+ else:
44
+ lines.append(f"[失败] 发现 {len(self.errors)} 个错误")
45
+
46
+ if self.warnings:
47
+ lines.append(f"[警告] {len(self.warnings)} 个警告")
48
+
49
+ return "\n".join(lines)
50
+
51
+
52
+ class SpecValidator:
53
+ """规格验证器"""
54
+
55
+ # 规范需求关键词
56
+ REQUIREMENT_KEYWORDS = ["SHALL", "MUST", "SHOULD", "MAY"]
57
+
58
+ # Delta 类型
59
+ DELTA_TYPES = ["ADDED", "MODIFIED", "REMOVED"]
60
+
61
+ def __init__(self, project_dir: Path | str):
62
+ """初始化验证器"""
63
+ self.project_dir = Path(project_dir).resolve()
64
+ self.specs_dir = self.project_dir / ".super-dev" / "specs"
65
+ self.changes_dir = self.project_dir / ".super-dev" / "changes"
66
+
67
+ def validate_change(self, change_id: str) -> ValidationResult:
68
+ """验证变更"""
69
+ errors: list[ValidationError] = []
70
+ warnings: list[ValidationError] = []
71
+ info: list[ValidationError] = []
72
+
73
+ change_dir = self.changes_dir / change_id
74
+ if not change_dir.exists():
75
+ errors.append(ValidationError(
76
+ file=str(change_dir),
77
+ message=f"变更目录不存在: {change_id}"
78
+ ))
79
+ return ValidationResult(is_valid=False, errors=errors)
80
+
81
+ # 验证 proposal.md
82
+ proposal_file = change_dir / "proposal.md"
83
+ if proposal_file.exists():
84
+ result = self._validate_proposal(proposal_file)
85
+ errors.extend(result.errors)
86
+ warnings.extend(result.warnings)
87
+ info.extend(result.info)
88
+ else:
89
+ warnings.append(ValidationError(
90
+ file=str(proposal_file),
91
+ message="缺少 proposal.md"
92
+ ))
93
+
94
+ # 验证 tasks.md
95
+ tasks_file = change_dir / "tasks.md"
96
+ if tasks_file.exists():
97
+ result = self._validate_tasks(tasks_file)
98
+ errors.extend(result.errors)
99
+ warnings.extend(result.warnings)
100
+ info.extend(result.info)
101
+ else:
102
+ warnings.append(ValidationError(
103
+ file=str(tasks_file),
104
+ message="缺少 tasks.md"
105
+ ))
106
+
107
+ # 验证 design.md (可选)
108
+ design_file = change_dir / "design.md"
109
+ if design_file.exists():
110
+ result = self._validate_design(design_file)
111
+ errors.extend(result.errors)
112
+ warnings.extend(result.warnings)
113
+
114
+ # 验证 specs/ 目录
115
+ specs_dir = change_dir / "specs"
116
+ if specs_dir.exists():
117
+ for spec_file in specs_dir.rglob("spec.md"):
118
+ result = self._validate_spec_delta(spec_file)
119
+ errors.extend(result.errors)
120
+ warnings.extend(result.warnings)
121
+ info.extend(result.info)
122
+ else:
123
+ warnings.append(ValidationError(
124
+ file=str(specs_dir),
125
+ message="缺少 specs/ 目录"
126
+ ))
127
+
128
+ return ValidationResult(
129
+ is_valid=len(errors) == 0,
130
+ errors=errors,
131
+ warnings=warnings,
132
+ info=info
133
+ )
134
+
135
+ def validate_spec(self, spec_name: str) -> ValidationResult:
136
+ """验证规范"""
137
+ errors: list[ValidationError] = []
138
+ warnings: list[ValidationError] = []
139
+
140
+ spec_file = self.specs_dir / spec_name / "spec.md"
141
+ if not spec_file.exists():
142
+ errors.append(ValidationError(
143
+ file=str(spec_file),
144
+ message=f"规范文件不存在: {spec_name}"
145
+ ))
146
+ return ValidationResult(is_valid=False, errors=errors)
147
+
148
+ content = spec_file.read_text(encoding="utf-8")
149
+ lines = content.split("\n")
150
+
151
+ # 检查标题
152
+ has_title = False
153
+ has_purpose = False
154
+ has_requirements = False
155
+ has_req_keyword = False
156
+
157
+ for i, line in enumerate(lines, 1):
158
+ # 检查一级标题
159
+ if line.startswith("# ") and not has_title:
160
+ has_title = True
161
+ if not line[2:].strip():
162
+ errors.append(ValidationError(
163
+ file=str(spec_file),
164
+ line=i,
165
+ message="标题不能为空"
166
+ ))
167
+
168
+ # 检查 Purpose 部分
169
+ if line.startswith("## Purpose"):
170
+ has_purpose = True
171
+
172
+ # 检查 Requirements 部分
173
+ if line.startswith("## Requirements"):
174
+ has_requirements = True
175
+
176
+ # 检查需求格式
177
+ if line.startswith("### Requirement:"):
178
+ has_req_keyword = True
179
+ if not line[16:].strip():
180
+ errors.append(ValidationError(
181
+ file=str(spec_file),
182
+ line=i,
183
+ message="需求名称不能为空"
184
+ ))
185
+
186
+ # 检查需求关键词
187
+ if any(kw in line for kw in self.REQUIREMENT_KEYWORDS):
188
+ has_req_keyword = True
189
+
190
+ # 检查场景格式
191
+ if line.startswith("#### Scenario:"):
192
+ if not line[14:].strip():
193
+ warnings.append(ValidationError(
194
+ file=str(spec_file),
195
+ line=i,
196
+ severity="warning",
197
+ message="场景描述为空"
198
+ ))
199
+
200
+ # 验证结果
201
+ if not has_title:
202
+ errors.append(ValidationError(
203
+ file=str(spec_file),
204
+ message="缺少一级标题"
205
+ ))
206
+
207
+ if not has_purpose:
208
+ warnings.append(ValidationError(
209
+ file=str(spec_file),
210
+ severity="warning",
211
+ message="缺少 Purpose 部分"
212
+ ))
213
+
214
+ if not has_requirements:
215
+ warnings.append(ValidationError(
216
+ file=str(spec_file),
217
+ severity="warning",
218
+ message="缺少 Requirements 部分"
219
+ ))
220
+
221
+ if not has_req_keyword:
222
+ warnings.append(ValidationError(
223
+ file=str(spec_file),
224
+ severity="info",
225
+ message="建议使用 SHALL/MUST/SHOULD/MAY 关键词"
226
+ ))
227
+
228
+ return ValidationResult(
229
+ is_valid=len(errors) == 0,
230
+ errors=errors,
231
+ warnings=warnings
232
+ )
233
+
234
+ def _validate_proposal(self, proposal_file: Path) -> ValidationResult:
235
+ """验证提案文件"""
236
+ errors: list[ValidationError] = []
237
+ warnings: list[ValidationError] = []
238
+
239
+ content = proposal_file.read_text(encoding="utf-8")
240
+
241
+ # 检查必需的章节
242
+ has_title = False
243
+ has_description = False
244
+
245
+ for line in content.split("\n"):
246
+ if re.match(r"^##\s+", line):
247
+ if "description" in line.lower():
248
+ has_description = True
249
+ elif "title" in line.lower() or line.startswith("# "):
250
+ has_title = True
251
+
252
+ if not has_title:
253
+ warnings.append(ValidationError(
254
+ file=str(proposal_file),
255
+ severity="warning",
256
+ message="提案缺少标题"
257
+ ))
258
+
259
+ if not has_description:
260
+ warnings.append(ValidationError(
261
+ file=str(proposal_file),
262
+ severity="warning",
263
+ message="提案缺少描述"
264
+ ))
265
+
266
+ return ValidationResult(
267
+ is_valid=True,
268
+ errors=errors,
269
+ warnings=warnings
270
+ )
271
+
272
+ def _validate_tasks(self, tasks_file: Path) -> ValidationResult:
273
+ """验证任务文件"""
274
+ errors: list[ValidationError] = []
275
+ warnings: list[ValidationError] = []
276
+
277
+ content = tasks_file.read_text(encoding="utf-8")
278
+ lines = content.split("\n")
279
+
280
+ task_pattern = re.compile(r'^-\s*\[([ x~_])\]\s*\*\*([\d.]+):\s*([^*]+)\*\*')
281
+
282
+ task_ids = []
283
+ for i, line in enumerate(lines, 1):
284
+ match = task_pattern.match(line)
285
+ if match:
286
+ status_char, task_id, title = match.groups()
287
+ task_ids.append(task_id)
288
+
289
+ # 检查任务标题
290
+ if not title.strip():
291
+ errors.append(ValidationError(
292
+ file=str(tasks_file),
293
+ line=i,
294
+ message="任务标题不能为空"
295
+ ))
296
+
297
+ # 检查任务ID格式
298
+ for task_id in task_ids:
299
+ if not re.match(r"^\d+\.\d+$", task_id):
300
+ warnings.append(ValidationError(
301
+ file=str(tasks_file),
302
+ severity="warning",
303
+ message=f"任务ID格式建议为 '数字.数字' 格式: {task_id}"
304
+ ))
305
+
306
+ if not task_ids:
307
+ warnings.append(ValidationError(
308
+ file=str(tasks_file),
309
+ severity="warning",
310
+ message="没有找到任何任务"
311
+ ))
312
+
313
+ return ValidationResult(
314
+ is_valid=len(errors) == 0,
315
+ errors=errors,
316
+ warnings=warnings
317
+ )
318
+
319
+ def _validate_design(self, design_file: Path) -> ValidationResult:
320
+ """验证设计文件"""
321
+ # design.md 是可选的,只做基本检查
322
+ content = design_file.read_text(encoding="utf-8")
323
+ if len(content) < 10:
324
+ return ValidationResult(
325
+ is_valid=False,
326
+ errors=[ValidationError(
327
+ file=str(design_file),
328
+ message="设计文件内容过少"
329
+ )]
330
+ )
331
+ return ValidationResult(is_valid=True)
332
+
333
+ def _validate_spec_delta(self, spec_file: Path) -> ValidationResult:
334
+ """验证规范增量文件"""
335
+ errors: list[ValidationError] = []
336
+ warnings: list[ValidationError] = []
337
+
338
+ content = spec_file.read_text(encoding="utf-8")
339
+ lines = content.split("\n")
340
+
341
+ has_delta_header = False
342
+ current_delta_type = None
343
+ has_requirements = False
344
+
345
+ for i, line in enumerate(lines, 1):
346
+ # 检查 Delta 类型标题
347
+ if line.startswith("## "):
348
+ for delta_type in self.DELTA_TYPES:
349
+ if delta_type in line.upper():
350
+ has_delta_header = True
351
+ current_delta_type = delta_type
352
+ break
353
+
354
+ # 检查需求格式
355
+ if line.startswith("### Requirement:"):
356
+ if not current_delta_type:
357
+ errors.append(ValidationError(
358
+ file=str(spec_file),
359
+ line=i,
360
+ message="需求必须在 Delta 类型 (ADDED/MODIFIED/REMOVED) 下"
361
+ ))
362
+
363
+ has_requirements = True
364
+
365
+ if not line[16:].strip():
366
+ errors.append(ValidationError(
367
+ file=str(spec_file),
368
+ line=i,
369
+ message="需求名称不能为空"
370
+ ))
371
+
372
+ if not has_delta_header:
373
+ errors.append(ValidationError(
374
+ file=str(spec_file),
375
+ message="缺少 Delta 类型标题 (ADDED/MODIFIED/REMOVED)"
376
+ ))
377
+
378
+ if not has_requirements:
379
+ warnings.append(ValidationError(
380
+ file=str(spec_file),
381
+ severity="warning",
382
+ message="没有找到任何需求"
383
+ ))
384
+
385
+ return ValidationResult(
386
+ is_valid=len(errors) == 0,
387
+ errors=errors,
388
+ warnings=warnings
389
+ )
390
+
391
+ def validate_all(self) -> ValidationResult:
392
+ """验证所有变更"""
393
+ all_errors: list[ValidationError] = []
394
+ all_warnings: list[ValidationError] = []
395
+
396
+ if not self.changes_dir.exists():
397
+ return ValidationResult(
398
+ is_valid=False,
399
+ errors=[ValidationError(
400
+ file=str(self.changes_dir),
401
+ message="changes 目录不存在,请先运行 'super-dev spec init'"
402
+ )]
403
+ )
404
+
405
+ for change_dir in self.changes_dir.iterdir():
406
+ if change_dir.is_dir() and not change_dir.name.startswith("."):
407
+ result = self.validate_change(change_dir.name)
408
+ all_errors.extend(result.errors)
409
+ all_warnings.extend(result.warnings)
410
+
411
+ return ValidationResult(
412
+ is_valid=len(all_errors) == 0,
413
+ errors=all_errors,
414
+ warnings=all_warnings
415
+ )
@@ -0,0 +1,11 @@
1
+ """
2
+ 开发:Excellent(11964948@qq.com)
3
+ 功能:工具模块初始化
4
+ 作用:提供通用工具函数和类
5
+ 创建时间:2025-01-29
6
+ 最后修改:2025-01-29
7
+ """
8
+
9
+ from .logger import get_logger, log_with_extra
10
+
11
+ __all__ = ['get_logger', 'log_with_extra']
@@ -0,0 +1,133 @@
1
+ """
2
+ 开发:Excellent(11964948@qq.com)
3
+ 功能:统一日志系统
4
+ 作用:提供结构化、可配置的日志记录功能
5
+ 创建时间:2025-01-29
6
+ 最后修改:2025-01-29
7
+ """
8
+
9
+ import logging
10
+ import sys
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+
14
+
15
+ class ColoredFormatter(logging.Formatter):
16
+ """彩色日志格式化器"""
17
+
18
+ # ANSI颜色代码
19
+ COLORS = {
20
+ "DEBUG": "\033[36m", # 青色
21
+ "INFO": "\033[32m", # 绿色
22
+ "WARNING": "\033[33m", # 黄色
23
+ "ERROR": "\033[31m", # 红色
24
+ "CRITICAL": "\033[35m", # 紫色
25
+ }
26
+ RESET = "\033[0m"
27
+
28
+ def format(self, record):
29
+ # 添加颜色
30
+ log_color = self.COLORS.get(record.levelname, self.RESET)
31
+ record.levelname = f"{log_color}{record.levelname}{self.RESET}"
32
+ return super().format(record)
33
+
34
+
35
+ class StructuredFormatter(logging.Formatter):
36
+ """结构化日志格式化器(JSON风格)"""
37
+
38
+ def format(self, record):
39
+ log_data = {
40
+ "timestamp": datetime.fromtimestamp(record.created).isoformat(),
41
+ "level": record.levelname,
42
+ "logger": record.name,
43
+ "message": record.getMessage(),
44
+ "module": record.module,
45
+ "function": record.funcName,
46
+ "line": record.lineno,
47
+ }
48
+
49
+ # 添加异常信息
50
+ if record.exc_info:
51
+ log_data["exception"] = self.formatException(record.exc_info)
52
+
53
+ # 添加额外字段
54
+ if hasattr(record, "extra_data"):
55
+ log_data["data"] = record.extra_data
56
+
57
+ return str(log_data)
58
+
59
+
60
+ def get_logger(
61
+ name: str,
62
+ level: str = "INFO",
63
+ log_file: Path | None = None,
64
+ use_colors: bool = True,
65
+ structured: bool = False,
66
+ ) -> logging.Logger:
67
+ """
68
+ 获取配置好的日志记录器
69
+
70
+ Args:
71
+ name: 日志记录器名称
72
+ level: 日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
73
+ log_file: 日志文件路径(可选)
74
+ use_colors: 是否使用彩色输出(仅终端)
75
+ structured: 是否使用结构化格式
76
+
77
+ Returns:
78
+ 配置好的日志记录器
79
+ """
80
+ logger = logging.getLogger(name)
81
+
82
+ # 避免重复添加handler
83
+ if logger.handlers:
84
+ return logger
85
+
86
+ logger.setLevel(getattr(logging, level.upper(), logging.INFO))
87
+ logger.propagate = False # 不传播到父logger
88
+
89
+ # 控制台处理器
90
+ console_handler = logging.StreamHandler(sys.stdout)
91
+
92
+ if use_colors and not structured:
93
+ formatter: logging.Formatter = ColoredFormatter(
94
+ fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
95
+ )
96
+ elif structured:
97
+ formatter = StructuredFormatter()
98
+ else:
99
+ formatter = logging.Formatter(
100
+ fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
101
+ )
102
+
103
+ console_handler.setFormatter(formatter)
104
+ logger.addHandler(console_handler)
105
+
106
+ # 文件处理器(如果指定)
107
+ if log_file:
108
+ log_file.parent.mkdir(parents=True, exist_ok=True)
109
+ file_handler = logging.FileHandler(log_file, encoding="utf-8")
110
+ file_handler.setFormatter(
111
+ logging.Formatter(
112
+ fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
113
+ datefmt="%Y-%m-%d %H:%M:%S",
114
+ )
115
+ )
116
+ logger.addHandler(file_handler)
117
+
118
+ return logger
119
+
120
+
121
+ def log_with_extra(logger: logging.Logger, level: str, message: str, **extra_data):
122
+ """
123
+ 带额外数据的日志记录
124
+
125
+ Args:
126
+ logger: 日志记录器
127
+ level: 日志级别
128
+ message: 日志消息
129
+ **extra_data: 额外的结构化数据
130
+ """
131
+ log_func = getattr(logger, level.lower(), logger.info)
132
+ extra = {"extra_data": extra_data} if extra_data else {}
133
+ log_func(message, extra=extra)