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
super_dev/cli.py ADDED
@@ -0,0 +1,3257 @@
1
+ """
2
+ 开发:Excellent(11964948@qq.com)
3
+ 功能:Super Dev CLI 主入口
4
+ 作用:提供命令行界面,统一访问所有功能
5
+ 创建时间:2025-12-30
6
+ 最后修改:2025-01-29
7
+ """
8
+
9
+ import argparse
10
+ import json
11
+ import os
12
+ import sys
13
+ import traceback
14
+ from collections.abc import Callable
15
+ from pathlib import Path
16
+ from typing import Any, Literal, cast
17
+
18
+ try:
19
+ from rich.console import Console
20
+ from rich.panel import Panel
21
+ from rich.text import Text
22
+ RICH_AVAILABLE = True
23
+ except ImportError:
24
+ RICH_AVAILABLE = False
25
+
26
+ from . import __description__, __version__
27
+ from .config import ConfigManager, get_config_manager
28
+ from .exceptions import SuperDevError
29
+ from .orchestrator import Phase, WorkflowContext, WorkflowEngine
30
+ from .utils import get_logger
31
+
32
+ CICDPlatform = Literal["github", "gitlab", "jenkins", "azure", "bitbucket", "all"]
33
+
34
+
35
+ class SuperDevCLI:
36
+ """Super Dev 命令行接口"""
37
+
38
+ def __init__(self):
39
+ self.console = Console() if RICH_AVAILABLE else None
40
+ self.parser = self._create_parser()
41
+ self.logger = get_logger('cli', level='WARNING') # CLI只记录WARNING及以上级别
42
+
43
+ def _create_parser(self) -> argparse.ArgumentParser:
44
+ """创建命令行参数解析器"""
45
+ parser = argparse.ArgumentParser(
46
+ prog="super-dev",
47
+ description=__description__,
48
+ formatter_class=argparse.RawDescriptionHelpFormatter,
49
+ epilog="""
50
+ 示例:
51
+ super-dev init my-project 初始化新项目
52
+ super-dev analyze [path] 分析现有项目
53
+ super-dev workflow 运行完整工作流
54
+ super-dev expert PM 调用产品经理专家
55
+ super-dev quality 运行质量检查
56
+ super-dev preview 生成原型预览
57
+ super-dev deploy 生成部署配置
58
+ """
59
+ )
60
+
61
+ parser.add_argument(
62
+ "-v", "--version",
63
+ action="version",
64
+ version=f"%(prog)s {__version__}"
65
+ )
66
+
67
+ # 子命令
68
+ subparsers = parser.add_subparsers(
69
+ dest="command",
70
+ title="可用命令",
71
+ description="使用 'super-dev <command> -h' 查看帮助"
72
+ )
73
+
74
+ # init 命令
75
+ init_parser = subparsers.add_parser(
76
+ "init",
77
+ help="初始化新项目",
78
+ description="创建一个新的 Super Dev 项目"
79
+ )
80
+ init_parser.add_argument(
81
+ "name",
82
+ help="项目名称"
83
+ )
84
+ init_parser.add_argument(
85
+ "-d", "--description",
86
+ default="",
87
+ help="项目描述"
88
+ )
89
+ init_parser.add_argument(
90
+ "-p", "--platform",
91
+ choices=["web", "mobile", "wechat", "desktop"],
92
+ default="web",
93
+ help="目标平台"
94
+ )
95
+ init_parser.add_argument(
96
+ "-f", "--frontend",
97
+ choices=[
98
+ "next", "remix", "react-vite", "gatsby",
99
+ "nuxt", "vue-vite",
100
+ "angular",
101
+ "sveltekit",
102
+ "astro", "solid", "qwik",
103
+ "none"
104
+ ],
105
+ default="next",
106
+ help="前端框架"
107
+ )
108
+ init_parser.add_argument(
109
+ "--ui-library",
110
+ choices=[
111
+ "mui", "ant-design", "chakra-ui", "mantine", "shadcn-ui", "radix-ui",
112
+ "element-plus", "naive-ui", "vuetify", "primevue", "arco-design",
113
+ "angular-material", "primeng",
114
+ "skeleton-ui", "svelte-material-ui",
115
+ "tailwind", "daisyui"
116
+ ],
117
+ help="UI 组件库"
118
+ )
119
+ init_parser.add_argument(
120
+ "--style",
121
+ choices=["tailwind", "css-modules", "styled-components", "emotion", "scss", "less", "unocss"],
122
+ help="样式方案"
123
+ )
124
+ init_parser.add_argument(
125
+ "--state",
126
+ choices=["react-query", "swr", "zustand", "redux-toolkit", "jotai", "pinia", "xstate"],
127
+ action="append",
128
+ help="状态管理方案 (可多选)"
129
+ )
130
+ init_parser.add_argument(
131
+ "--testing",
132
+ choices=["vitest", "jest", "playwright", "cypress", "testing-library"],
133
+ action="append",
134
+ help="测试框架 (可多选)"
135
+ )
136
+ init_parser.add_argument(
137
+ "-b", "--backend",
138
+ choices=["node", "python", "go", "java", "none"],
139
+ default="node",
140
+ help="后端框架"
141
+ )
142
+ init_parser.add_argument(
143
+ "--domain",
144
+ choices=["", "fintech", "ecommerce", "medical", "social", "iot", "education"],
145
+ default="",
146
+ help="业务领域"
147
+ )
148
+
149
+ # analyze 命令
150
+ analyze_parser = subparsers.add_parser(
151
+ "analyze",
152
+ help="分析现有项目",
153
+ description="自动检测和分析现有项目的结构、技术栈和架构模式"
154
+ )
155
+ analyze_parser.add_argument(
156
+ "path",
157
+ nargs="?",
158
+ default=".",
159
+ help="项目路径 (默认为当前目录)"
160
+ )
161
+ analyze_parser.add_argument(
162
+ "-o", "--output",
163
+ help="输出报告文件路径 (Markdown 格式)"
164
+ )
165
+ analyze_parser.add_argument(
166
+ "-f", "--format",
167
+ choices=["json", "markdown", "text"],
168
+ default="text",
169
+ help="输出格式"
170
+ )
171
+ analyze_parser.add_argument(
172
+ "--json",
173
+ action="store_true",
174
+ help="以 JSON 格式输出"
175
+ )
176
+
177
+ # workflow 命令
178
+ workflow_parser = subparsers.add_parser(
179
+ "workflow",
180
+ help="运行工作流",
181
+ description="执行 Super Dev 6 阶段工作流"
182
+ )
183
+ workflow_parser.add_argument(
184
+ "--phase",
185
+ choices=["discovery", "intelligence", "drafting", "redteam", "qa", "delivery", "deployment"],
186
+ nargs="*",
187
+ help="指定要执行的阶段"
188
+ )
189
+ workflow_parser.add_argument(
190
+ "-q", "--quality-gate",
191
+ type=int,
192
+ help="质量门禁阈值 (0-100)"
193
+ )
194
+
195
+ # studio 命令
196
+ studio_parser = subparsers.add_parser(
197
+ "studio",
198
+ help="启动交互工作台",
199
+ description="启动 Super Dev Web 工作台 API 服务"
200
+ )
201
+ studio_parser.add_argument(
202
+ "--host",
203
+ default="127.0.0.1",
204
+ help="监听地址 (默认: 127.0.0.1)"
205
+ )
206
+ studio_parser.add_argument(
207
+ "--port",
208
+ type=int,
209
+ default=8765,
210
+ help="监听端口 (默认: 8765)"
211
+ )
212
+ studio_parser.add_argument(
213
+ "--reload",
214
+ action="store_true",
215
+ help="启用热重载 (开发模式)"
216
+ )
217
+
218
+ # expert 命令
219
+ expert_parser = subparsers.add_parser(
220
+ "expert",
221
+ help="调用专家",
222
+ description="直接调用特定专家"
223
+ )
224
+ expert_parser.add_argument(
225
+ "--list",
226
+ action="store_true",
227
+ help="列出所有可用专家"
228
+ )
229
+ expert_parser.add_argument(
230
+ "expert_name",
231
+ nargs="?",
232
+ choices=["PM", "ARCHITECT", "UI", "UX", "SECURITY", "CODE", "DBA", "QA", "DEVOPS", "RCA"],
233
+ help="专家名称"
234
+ )
235
+ expert_parser.add_argument(
236
+ "prompt",
237
+ nargs="*",
238
+ help="提示词"
239
+ )
240
+
241
+ # quality 命令
242
+ quality_parser = subparsers.add_parser(
243
+ "quality",
244
+ help="质量检查",
245
+ description="运行质量检查脚本"
246
+ )
247
+ quality_parser.add_argument(
248
+ "-t", "--type",
249
+ choices=["prd", "architecture", "ui", "ux", "code", "all"],
250
+ default="all",
251
+ help="检查类型"
252
+ )
253
+
254
+ # preview 命令
255
+ preview_parser = subparsers.add_parser(
256
+ "preview",
257
+ help="生成原型",
258
+ description="从 UI 设计生成可交互的原型"
259
+ )
260
+ preview_parser.add_argument(
261
+ "-o", "--output",
262
+ default="preview.html",
263
+ help="输出文件路径"
264
+ )
265
+
266
+ # deploy 命令
267
+ deploy_parser = subparsers.add_parser(
268
+ "deploy",
269
+ help="生成部署配置",
270
+ description="生成 Dockerfile 和 CI/CD 配置"
271
+ )
272
+ deploy_parser.add_argument(
273
+ "--docker",
274
+ action="store_true",
275
+ help="生成 Dockerfile"
276
+ )
277
+ deploy_parser.add_argument(
278
+ "--cicd",
279
+ choices=["github", "gitlab", "jenkins", "azure", "bitbucket", "all"],
280
+ help="生成 CI/CD 配置"
281
+ )
282
+
283
+ # config 命令
284
+ config_parser = subparsers.add_parser(
285
+ "config",
286
+ help="配置管理",
287
+ description="查看和修改项目配置"
288
+ )
289
+ config_parser.add_argument(
290
+ "action",
291
+ choices=["get", "set", "list"],
292
+ help="操作"
293
+ )
294
+ config_parser.add_argument(
295
+ "key",
296
+ nargs="?",
297
+ help="配置键"
298
+ )
299
+ config_parser.add_argument(
300
+ "value",
301
+ nargs="?",
302
+ help="配置值"
303
+ )
304
+
305
+ # skill 命令 - 多平台 Skill 安装/管理
306
+ skill_parser = subparsers.add_parser(
307
+ "skill",
308
+ help="Skill 管理",
309
+ description="安装、列出、卸载跨平台 AI Coding Skills"
310
+ )
311
+ skill_parser.add_argument(
312
+ "action",
313
+ choices=["list", "install", "uninstall", "targets"],
314
+ help="操作类型"
315
+ )
316
+ skill_parser.add_argument(
317
+ "source_or_name",
318
+ nargs="?",
319
+ help="install 时为来源(目录/git/super-dev),uninstall 时为 skill 名称"
320
+ )
321
+ skill_parser.add_argument(
322
+ "-t", "--target",
323
+ choices=["claude-code", "codex-cli", "opencode", "cursor", "qoder", "trae", "codebuddy", "antigravity"],
324
+ default="claude-code",
325
+ help="目标平台 (默认: claude-code)"
326
+ )
327
+ skill_parser.add_argument(
328
+ "--name",
329
+ help="安装后的 skill 名称(可选)"
330
+ )
331
+ skill_parser.add_argument(
332
+ "--force",
333
+ action="store_true",
334
+ help="覆盖已存在的 skill"
335
+ )
336
+
337
+ # integrate 命令 - 多平台适配配置
338
+ integrate_parser = subparsers.add_parser(
339
+ "integrate",
340
+ help="平台集成配置",
341
+ description="为 CLI/IDE AI Coding 工具生成集成配置文件"
342
+ )
343
+ integrate_parser.add_argument(
344
+ "action",
345
+ choices=["list", "setup"],
346
+ help="操作类型"
347
+ )
348
+ integrate_parser.add_argument(
349
+ "-t", "--target",
350
+ choices=["claude-code", "codex-cli", "opencode", "cursor", "qoder", "trae", "codebuddy", "antigravity"],
351
+ help="目标平台"
352
+ )
353
+ integrate_parser.add_argument(
354
+ "--all",
355
+ action="store_true",
356
+ help="对所有平台执行 setup"
357
+ )
358
+ integrate_parser.add_argument(
359
+ "--force",
360
+ action="store_true",
361
+ help="覆盖已存在的配置文件"
362
+ )
363
+
364
+ # create 命令 - 一键创建项目
365
+ create_parser = subparsers.add_parser(
366
+ "create",
367
+ help="一键创建项目 (从想法到规范)",
368
+ description="从一句话描述自动生成 PRD、架构、UI/UX 文档并创建 Spec"
369
+ )
370
+ create_parser.add_argument(
371
+ "description",
372
+ help="功能描述 (如 '用户认证系统')"
373
+ )
374
+ create_parser.add_argument(
375
+ "-p", "--platform",
376
+ choices=["web", "mobile", "wechat", "desktop"],
377
+ default="web",
378
+ help="目标平台"
379
+ )
380
+ create_parser.add_argument(
381
+ "-f", "--frontend",
382
+ choices=["react", "vue", "angular", "svelte", "none"],
383
+ default="react",
384
+ help="前端框架"
385
+ )
386
+ create_parser.add_argument(
387
+ "-b", "--backend",
388
+ choices=["node", "python", "go", "java", "none"],
389
+ default="node",
390
+ help="后端框架"
391
+ )
392
+ create_parser.add_argument(
393
+ "-d", "--domain",
394
+ choices=["", "fintech", "ecommerce", "medical", "social", "iot", "education", "auth", "content"],
395
+ default="",
396
+ help="业务领域"
397
+ )
398
+ create_parser.add_argument(
399
+ "--name",
400
+ help="项目名称 (默认根据描述生成)"
401
+ )
402
+ create_parser.add_argument(
403
+ "--skip-docs",
404
+ action="store_true",
405
+ help="跳过文档生成,只创建 Spec"
406
+ )
407
+
408
+ # design 命令 - 设计智能引擎
409
+ design_parser = subparsers.add_parser(
410
+ "design",
411
+ help="设计智能引擎",
412
+ description="搜索设计资产、生成设计系统、创建 design tokens"
413
+ )
414
+ design_subparsers = design_parser.add_subparsers(
415
+ dest="design_command",
416
+ title="设计命令",
417
+ description="使用 'super-dev design <command> -h' 查看帮助"
418
+ )
419
+
420
+ # design search
421
+ design_search_parser = design_subparsers.add_parser(
422
+ "search",
423
+ help="搜索设计资产",
424
+ description="搜索 UI 风格、配色、字体、组件等设计资产"
425
+ )
426
+ design_search_parser.add_argument(
427
+ "query",
428
+ help="搜索关键词"
429
+ )
430
+ design_search_parser.add_argument(
431
+ "-d", "--domain",
432
+ choices=["style", "color", "typography", "component", "layout", "animation", "ux", "chart", "product"],
433
+ help="搜索领域 (默认自动检测)"
434
+ )
435
+ design_search_parser.add_argument(
436
+ "-n", "--max-results",
437
+ type=int,
438
+ default=5,
439
+ help="最大结果数 (默认: 5)"
440
+ )
441
+
442
+ # design generate
443
+ design_generate_parser = design_subparsers.add_parser(
444
+ "generate",
445
+ help="生成完整设计系统",
446
+ description="基于产品类型和行业生成完整的设计系统"
447
+ )
448
+ design_generate_parser.add_argument(
449
+ "--product",
450
+ required=True,
451
+ help="产品类型 (SaaS, E-commerce, Portfolio, Dashboard)"
452
+ )
453
+ design_generate_parser.add_argument(
454
+ "--industry",
455
+ required=True,
456
+ help="行业 (Fintech, Healthcare, Education, Gaming)"
457
+ )
458
+ design_generate_parser.add_argument(
459
+ "--keywords",
460
+ nargs="+",
461
+ help="关键词列表"
462
+ )
463
+ design_generate_parser.add_argument(
464
+ "-p", "--platform",
465
+ choices=["web", "mobile", "desktop"],
466
+ default="web",
467
+ help="目标平台 (默认: web)"
468
+ )
469
+ design_generate_parser.add_argument(
470
+ "-a", "--aesthetic",
471
+ help="美学方向 (可选)"
472
+ )
473
+ design_generate_parser.add_argument(
474
+ "-o", "--output",
475
+ default="output/design",
476
+ help="输出目录 (默认: output/design)"
477
+ )
478
+
479
+ # design tokens
480
+ design_tokens_parser = design_subparsers.add_parser(
481
+ "tokens",
482
+ help="生成 design tokens",
483
+ description="生成 CSS 变量、Tailwind 配置等 design tokens"
484
+ )
485
+ design_tokens_parser.add_argument(
486
+ "--primary",
487
+ required=True,
488
+ help="主色 (hex 值,如 #3B82F6)"
489
+ )
490
+ design_tokens_parser.add_argument(
491
+ "--type",
492
+ choices=["monochromatic", "analogous", "complementary", "triadic"],
493
+ default="monochromatic",
494
+ help="调色板类型 (默认: monochromatic)"
495
+ )
496
+ design_tokens_parser.add_argument(
497
+ "--format",
498
+ choices=["css", "json", "tailwind"],
499
+ default="css",
500
+ help="输出格式 (默认: css)"
501
+ )
502
+ design_tokens_parser.add_argument(
503
+ "-o", "--output",
504
+ help="输出文件路径"
505
+ )
506
+
507
+ # design landing - Landing 页面模式
508
+ design_landing_parser = design_subparsers.add_parser(
509
+ "landing",
510
+ help="Landing 页面模式生成",
511
+ description="搜索和推荐 Landing 页面布局模式"
512
+ )
513
+ design_landing_parser.add_argument(
514
+ "query",
515
+ nargs="?",
516
+ help="搜索关键词(可选)"
517
+ )
518
+ design_landing_parser.add_argument(
519
+ "--product-type",
520
+ help="产品类型 (SaaS, E-commerce, Mobile, etc.)"
521
+ )
522
+ design_landing_parser.add_argument(
523
+ "--goal",
524
+ help="目标 (signup, purchase, demo, etc.)"
525
+ )
526
+ design_landing_parser.add_argument(
527
+ "--audience",
528
+ help="受众 (B2B, B2C, Enterprise, etc.)"
529
+ )
530
+ design_landing_parser.add_argument(
531
+ "-n", "--max-results",
532
+ type=int,
533
+ default=5,
534
+ help="最大结果数 (默认: 5)"
535
+ )
536
+ design_landing_parser.add_argument(
537
+ "--list",
538
+ action="store_true",
539
+ help="列出所有可用模式"
540
+ )
541
+
542
+ # design chart - 图表类型推荐
543
+ design_chart_parser = design_subparsers.add_parser(
544
+ "chart",
545
+ help="图表类型推荐",
546
+ description="根据数据类型推荐最佳图表类型"
547
+ )
548
+ design_chart_parser.add_argument(
549
+ "data_description",
550
+ help="数据描述(如 'time series sales data')"
551
+ )
552
+ design_chart_parser.add_argument(
553
+ "-f", "--framework",
554
+ choices=["react", "vue", "svelte", "angular", "next", "vanilla"],
555
+ default="react",
556
+ help="前端框架 (默认: react)"
557
+ )
558
+ design_chart_parser.add_argument(
559
+ "-n", "--max-results",
560
+ type=int,
561
+ default=3,
562
+ help="最大结果数 (默认: 3)"
563
+ )
564
+ design_chart_parser.add_argument(
565
+ "--list",
566
+ action="store_true",
567
+ help="列出所有图表类型"
568
+ )
569
+
570
+ # design ux - UX 指南查询
571
+ design_ux_parser = design_subparsers.add_parser(
572
+ "ux",
573
+ help="UX 指南查询",
574
+ description="查询 UX 最佳实践和反模式"
575
+ )
576
+ design_ux_parser.add_argument(
577
+ "query",
578
+ help="搜索查询"
579
+ )
580
+ design_ux_parser.add_argument(
581
+ "-d", "--domain",
582
+ help="领域过滤 (Animation, A11y, Performance, etc.)"
583
+ )
584
+ design_ux_parser.add_argument(
585
+ "-n", "--max-results",
586
+ type=int,
587
+ default=5,
588
+ help="最大结果数 (默认: 5)"
589
+ )
590
+ design_ux_parser.add_argument(
591
+ "--quick-wins",
592
+ action="store_true",
593
+ help="显示快速见效的改进建议"
594
+ )
595
+ design_ux_parser.add_argument(
596
+ "--checklist",
597
+ action="store_true",
598
+ help="显示 UX 检查清单"
599
+ )
600
+ design_ux_parser.add_argument(
601
+ "--list-domains",
602
+ action="store_true",
603
+ help="列出所有领域"
604
+ )
605
+
606
+ # design stack - 技术栈最佳实践
607
+ design_stack_parser = design_subparsers.add_parser(
608
+ "stack",
609
+ help="技术栈最佳实践",
610
+ description="查询技术栈最佳实践、性能优化和设计模式"
611
+ )
612
+ design_stack_parser.add_argument(
613
+ "stack",
614
+ help="技术栈名称 (Next.js, React, Vue, SvelteKit, etc.)"
615
+ )
616
+ design_stack_parser.add_argument(
617
+ "query",
618
+ nargs="?",
619
+ help="搜索查询(可选)"
620
+ )
621
+ design_stack_parser.add_argument(
622
+ "-c", "--category",
623
+ help="类别过滤 (architecture, performance, state_management, etc.)"
624
+ )
625
+ design_stack_parser.add_argument(
626
+ "--patterns",
627
+ action="store_true",
628
+ help="显示设计模式"
629
+ )
630
+ design_stack_parser.add_argument(
631
+ "--performance",
632
+ action="store_true",
633
+ help="显示性能优化建议"
634
+ )
635
+ design_stack_parser.add_argument(
636
+ "--quick-wins",
637
+ action="store_true",
638
+ help="显示快速见效的性能优化"
639
+ )
640
+ design_stack_parser.add_argument(
641
+ "-n", "--max-results",
642
+ type=int,
643
+ default=5,
644
+ help="最大结果数 (默认: 5)"
645
+ )
646
+ design_stack_parser.add_argument(
647
+ "--list",
648
+ action="store_true",
649
+ help="列出所有支持的技术栈"
650
+ )
651
+
652
+ # design codegen - 代码片段生成
653
+ design_codegen_parser = design_subparsers.add_parser(
654
+ "codegen",
655
+ help="代码片段生成",
656
+ description="生成多框架的 UI 组件代码片段"
657
+ )
658
+ design_codegen_parser.add_argument(
659
+ "component",
660
+ help="组件名称 (button, card, input, etc.)"
661
+ )
662
+ design_codegen_parser.add_argument(
663
+ "-f", "--framework",
664
+ choices=["react", "nextjs", "vue", "svelte", "html", "tailwind"],
665
+ default="react",
666
+ help="目标框架 (默认: react)"
667
+ )
668
+ design_codegen_parser.add_argument(
669
+ "-o", "--output",
670
+ help="输出文件路径"
671
+ )
672
+ design_codegen_parser.add_argument(
673
+ "--list",
674
+ action="store_true",
675
+ help="列出所有可用组件"
676
+ )
677
+ design_codegen_parser.add_argument(
678
+ "--search",
679
+ help="搜索组件"
680
+ )
681
+
682
+ # spec 命令 - Spec-Driven Development
683
+ spec_parser = subparsers.add_parser(
684
+ "spec",
685
+ help="规范驱动开发 (SDD)",
686
+ description="管理规范和变更提案"
687
+ )
688
+ spec_subparsers = spec_parser.add_subparsers(
689
+ dest="spec_action",
690
+ title="SDD 命令",
691
+ description="使用 'super-dev spec <command> -h' 查看帮助"
692
+ )
693
+
694
+ # spec init
695
+ spec_subparsers.add_parser(
696
+ "init",
697
+ help="初始化 SDD 目录结构"
698
+ )
699
+
700
+ # spec list
701
+ spec_list_parser = spec_subparsers.add_parser(
702
+ "list",
703
+ help="列出所有变更"
704
+ )
705
+ spec_list_parser.add_argument(
706
+ "--status",
707
+ choices=["draft", "proposed", "approved", "in_progress", "completed", "archived"],
708
+ help="按状态过滤"
709
+ )
710
+
711
+ # spec show
712
+ spec_show_parser = spec_subparsers.add_parser(
713
+ "show",
714
+ help="显示变更详情"
715
+ )
716
+ spec_show_parser.add_argument(
717
+ "change_id",
718
+ help="变更 ID"
719
+ )
720
+
721
+ # spec propose
722
+ spec_propose_parser = spec_subparsers.add_parser(
723
+ "propose",
724
+ help="创建变更提案"
725
+ )
726
+ spec_propose_parser.add_argument(
727
+ "change_id",
728
+ help="变更 ID (如 add-user-auth)"
729
+ )
730
+ spec_propose_parser.add_argument(
731
+ "--title",
732
+ required=True,
733
+ help="变更标题"
734
+ )
735
+ spec_propose_parser.add_argument(
736
+ "--description",
737
+ required=True,
738
+ help="变更描述"
739
+ )
740
+ spec_propose_parser.add_argument(
741
+ "--motivation",
742
+ help="变更动机/背景"
743
+ )
744
+ spec_propose_parser.add_argument(
745
+ "--impact",
746
+ help="影响范围"
747
+ )
748
+
749
+ # spec add-req
750
+ spec_add_req_parser = spec_subparsers.add_parser(
751
+ "add-req",
752
+ help="向变更添加需求"
753
+ )
754
+ spec_add_req_parser.add_argument(
755
+ "change_id",
756
+ help="变更 ID"
757
+ )
758
+ spec_add_req_parser.add_argument(
759
+ "spec_name",
760
+ help="规范名称 (如 auth, user-profile)"
761
+ )
762
+ spec_add_req_parser.add_argument(
763
+ "req_name",
764
+ help="需求名称"
765
+ )
766
+ spec_add_req_parser.add_argument(
767
+ "description",
768
+ help="需求描述"
769
+ )
770
+
771
+ # spec archive
772
+ spec_archive_parser = spec_subparsers.add_parser(
773
+ "archive",
774
+ help="归档已完成的变更"
775
+ )
776
+ spec_archive_parser.add_argument(
777
+ "change_id",
778
+ help="变更 ID"
779
+ )
780
+ spec_archive_parser.add_argument(
781
+ "-y", "--yes",
782
+ action="store_true",
783
+ help="跳过确认"
784
+ )
785
+
786
+ # spec validate
787
+ spec_validate_parser = spec_subparsers.add_parser(
788
+ "validate",
789
+ help="验证规格格式和结构"
790
+ )
791
+ spec_validate_parser.add_argument(
792
+ "change_id",
793
+ nargs="?",
794
+ help="变更 ID (留空则验证所有变更)"
795
+ )
796
+ spec_validate_parser.add_argument(
797
+ "-v", "--verbose",
798
+ action="store_true",
799
+ help="显示详细信息"
800
+ )
801
+
802
+ # spec view
803
+ spec_view_parser = spec_subparsers.add_parser(
804
+ "view",
805
+ help="交互式仪表板 - 显示所有规范和变更"
806
+ )
807
+ spec_view_parser.add_argument(
808
+ "--refresh",
809
+ action="store_true",
810
+ help="强制刷新数据"
811
+ )
812
+
813
+ # pipeline 命令 - 完整流水线
814
+ pipeline_parser = subparsers.add_parser(
815
+ "pipeline",
816
+ help="运行完整流水线 (从想法到部署)",
817
+ description="执行完整开发流水线:需求增强 → 文档 → 前端骨架 → Spec → 实现骨架 → 审查与门禁 → 交付配置"
818
+ )
819
+ pipeline_parser.add_argument(
820
+ "description",
821
+ help="功能描述 (如 '用户认证系统')"
822
+ )
823
+ pipeline_parser.add_argument(
824
+ "-p", "--platform",
825
+ choices=["web", "mobile", "wechat", "desktop"],
826
+ default="web",
827
+ help="目标平台"
828
+ )
829
+ pipeline_parser.add_argument(
830
+ "-f", "--frontend",
831
+ choices=["react", "vue", "angular", "svelte", "none"],
832
+ default="react",
833
+ help="前端框架"
834
+ )
835
+ pipeline_parser.add_argument(
836
+ "-b", "--backend",
837
+ choices=["node", "python", "go", "java", "none"],
838
+ default="node",
839
+ help="后端框架"
840
+ )
841
+ pipeline_parser.add_argument(
842
+ "-d", "--domain",
843
+ choices=["", "fintech", "ecommerce", "medical", "social", "iot", "education", "auth", "content"],
844
+ default="",
845
+ help="业务领域"
846
+ )
847
+ pipeline_parser.add_argument(
848
+ "--name",
849
+ help="项目名称 (默认根据描述生成)"
850
+ )
851
+ pipeline_parser.add_argument(
852
+ "--cicd",
853
+ choices=["github", "gitlab", "jenkins", "azure", "bitbucket", "all"],
854
+ default="all",
855
+ help="CI/CD 平台"
856
+ )
857
+ pipeline_parser.add_argument(
858
+ "--skip-redteam",
859
+ action="store_true",
860
+ help="跳过红队审查"
861
+ )
862
+ pipeline_parser.add_argument(
863
+ "--skip-scaffold",
864
+ action="store_true",
865
+ help="跳过前后端实现骨架生成"
866
+ )
867
+ pipeline_parser.add_argument(
868
+ "--skip-quality-gate",
869
+ action="store_true",
870
+ help="跳过质量门禁检查"
871
+ )
872
+ pipeline_parser.add_argument(
873
+ "--offline",
874
+ action="store_true",
875
+ help="离线模式(禁用联网检索)"
876
+ )
877
+ pipeline_parser.add_argument(
878
+ "--quality-threshold",
879
+ type=int,
880
+ default=None,
881
+ help="质量门禁阈值(可选;默认按场景自动判定)"
882
+ )
883
+
884
+ return parser
885
+
886
+ def run(self, args: list | None = None) -> int:
887
+ """
888
+ 运行 CLI
889
+
890
+ Args:
891
+ args: 命令行参数
892
+
893
+ Returns:
894
+ 退出码
895
+ """
896
+ argv = list(args) if args is not None else sys.argv[1:]
897
+
898
+ # 直达入口:`super-dev <需求描述>`
899
+ if self._is_direct_requirement_input(argv):
900
+ return self._run_direct_requirement(" ".join(argv).strip())
901
+
902
+ parsed_args = self.parser.parse_args(argv)
903
+
904
+ if parsed_args.command is None:
905
+ self._print_banner()
906
+ self.parser.print_help()
907
+ return 0
908
+
909
+ # 路由到对应命令
910
+ command_handler = getattr(self, f"_cmd_{parsed_args.command}", None)
911
+ if command_handler is None or not callable(command_handler):
912
+ self.console.print(f"[red]未知命令: {parsed_args.command}[/red]")
913
+ return 1
914
+
915
+ try:
916
+ handler = cast(Callable[[Any], int], command_handler)
917
+ return int(handler(parsed_args))
918
+
919
+ except SuperDevError as e:
920
+ # 已知异常 - 显示友好错误信息
921
+ self.console.print(f"[red]错误: {e.message}[/red]")
922
+ if e.details:
923
+ self.logger.warning(f"命令执行失败: {e.code}", extra={'details': e.details})
924
+ return 1
925
+
926
+ except KeyboardInterrupt:
927
+ # 用户中断
928
+ self.console.print("\n[yellow]操作已取消[/yellow]")
929
+ return 130
930
+
931
+ except Exception as e:
932
+ # 未知异常 - 显示详细错误信息
933
+ self.console.print(f"[red]未预期的错误: {str(e)}[/red]")
934
+
935
+ # 记录完整错误栈
936
+ self.logger.error(
937
+ f"CLI命令异常: {parsed_args.command}",
938
+ extra={
939
+ 'error_type': type(e).__name__,
940
+ 'error_message': str(e),
941
+ 'traceback': traceback.format_exc()
942
+ }
943
+ )
944
+
945
+ # 在调试模式下显示traceback
946
+ if '--debug' in sys.argv or '-d' in sys.argv:
947
+ self.console.print(traceback.format_exc())
948
+
949
+ return 1
950
+
951
+ # ==================== 命令处理器 ====================
952
+
953
+ def _cmd_init(self, args) -> int:
954
+ """初始化项目"""
955
+ config_manager = get_config_manager()
956
+
957
+ # 检查是否已初始化
958
+ if config_manager.exists():
959
+ self.console.print("[yellow]项目已初始化,使用 'super-dev config set' 修改配置[/yellow]")
960
+ return 0
961
+
962
+ # 创建配置
963
+ config = config_manager.create(
964
+ name=args.name,
965
+ description=args.description,
966
+ platform=args.platform,
967
+ frontend=args.frontend,
968
+ backend=args.backend,
969
+ domain=args.domain,
970
+ ui_library=getattr(args, 'ui_library', None),
971
+ style_solution=getattr(args, 'style', None),
972
+ state_management=getattr(args, 'state', []) or [],
973
+ testing_frameworks=getattr(args, 'testing', []) or [],
974
+ )
975
+
976
+ # 创建输出目录
977
+ output_dir = Path.cwd() / config.output_dir
978
+ output_dir.mkdir(exist_ok=True)
979
+
980
+ self.console.print(f"[green]✓[/green] 项目已初始化: {config.name}")
981
+ self.console.print(f" 平台: {config.platform}")
982
+ self.console.print(f" 前端框架: {config.frontend}")
983
+ if config.ui_library:
984
+ self.console.print(f" UI 组件库: {config.ui_library}")
985
+ if config.style_solution:
986
+ self.console.print(f" 样式方案: {config.style_solution}")
987
+ if config.state_management:
988
+ self.console.print(f" 状态管理: {', '.join(config.state_management)}")
989
+ if config.testing_frameworks:
990
+ self.console.print(f" 测试框架: {', '.join(config.testing_frameworks)}")
991
+ self.console.print(f" 后端: {config.backend}")
992
+ if config.domain:
993
+ self.console.print(f" 领域: {config.domain}")
994
+
995
+ self.console.print("\n[dim]下一步:[/dim]")
996
+ self.console.print(" 1. 编辑 super-dev.yaml 配置项目详情")
997
+ self.console.print(" 2. 运行 'super-dev workflow' 开始开发")
998
+
999
+ return 0
1000
+
1001
+ def _cmd_analyze(self, args) -> int:
1002
+ """分析现有项目"""
1003
+ from .analyzer import ProjectAnalyzer
1004
+
1005
+ project_path = Path(args.path).resolve()
1006
+
1007
+ if not project_path.exists():
1008
+ self.console.print(f"[red]项目不存在: {project_path}[/red]")
1009
+ return 1
1010
+
1011
+ self.console.print(f"[cyan]正在分析项目: {project_path}[/cyan]")
1012
+
1013
+ try:
1014
+ analyzer = ProjectAnalyzer(project_path)
1015
+ report = analyzer.analyze()
1016
+
1017
+ # 根据格式输出
1018
+ output_format = "json" if args.json else args.format
1019
+
1020
+ if output_format == "json":
1021
+ import json
1022
+ output = json.dumps(report.to_dict(), indent=2, ensure_ascii=False)
1023
+
1024
+ if args.output:
1025
+ Path(args.output).write_text(output, encoding="utf-8")
1026
+ self.console.print(f"[green]报告已保存到: {args.output}[/green]")
1027
+ else:
1028
+ self.console.print(output)
1029
+
1030
+ elif output_format == "markdown":
1031
+ output = report.to_markdown()
1032
+
1033
+ if args.output:
1034
+ Path(args.output).write_text(output, encoding="utf-8")
1035
+ self.console.print(f"[green]报告已保存到: {args.output}[/green]")
1036
+ else:
1037
+ self.console.print(output)
1038
+
1039
+ else: # text
1040
+ framework_value = (
1041
+ report.tech_stack.framework.value
1042
+ if hasattr(report.tech_stack.framework, "value")
1043
+ else str(report.tech_stack.framework)
1044
+ )
1045
+ self.console.print("[cyan]项目分析报告[/cyan]")
1046
+ self.console.print(f" 路径: {report.project_path}")
1047
+ self.console.print(f" 类型: {report.category.value}")
1048
+ self.console.print(f" 语言: {report.tech_stack.language}")
1049
+ self.console.print(f" 框架: {framework_value}")
1050
+ if report.tech_stack.ui_library:
1051
+ self.console.print(f" UI 库: {report.tech_stack.ui_library}")
1052
+ if report.tech_stack.state_management:
1053
+ self.console.print(f" 状态管理: {report.tech_stack.state_management}")
1054
+ self.console.print(f" 文件数: {report.file_count}")
1055
+ self.console.print(f" 代码行数: {report.total_lines:,}")
1056
+ self.console.print(f" 依赖数: {len(report.tech_stack.dependencies)}")
1057
+
1058
+ if args.output:
1059
+ Path(args.output).write_text(report.to_markdown(), encoding="utf-8")
1060
+ self.console.print(f"[green]报告已保存到: {args.output}[/green]")
1061
+
1062
+ return 0
1063
+
1064
+ except FileNotFoundError as e:
1065
+ self.console.print(f"[red]路径不存在: {e}[/red]")
1066
+ self.logger.error("分析失败: 文件不存在", extra={'path': str(e)})
1067
+ return 1
1068
+
1069
+ except PermissionError as e:
1070
+ self.console.print(f"[red]权限不足: {e}[/red]")
1071
+ self.logger.error("分析失败: 权限错误", extra={'path': str(e)})
1072
+ return 1
1073
+
1074
+ except Exception as e:
1075
+ self.console.print(f"[red]分析失败: {e}[/red]")
1076
+ self.logger.error(
1077
+ f"分析异常: {type(e).__name__}",
1078
+ extra={
1079
+ 'error_message': str(e),
1080
+ 'traceback': traceback.format_exc()
1081
+ }
1082
+ )
1083
+
1084
+ if '--debug' in sys.argv or '-d' in sys.argv:
1085
+ self.console.print(traceback.format_exc())
1086
+
1087
+ return 1
1088
+
1089
+ def _cmd_workflow(self, args) -> int:
1090
+ """运行工作流"""
1091
+ project_dir = Path.cwd()
1092
+ config_manager = ConfigManager(project_dir)
1093
+
1094
+ if not config_manager.exists():
1095
+ self.console.print("[red]未找到项目配置,请先运行 'super-dev init'[/red]")
1096
+ return 1
1097
+
1098
+ # 更新质量门禁
1099
+ if args.quality_gate is not None:
1100
+ config_manager.update(quality_gate=args.quality_gate)
1101
+
1102
+ # 确定要执行的阶段
1103
+ phases = None
1104
+ if args.phase:
1105
+ phase_map = {
1106
+ "discovery": Phase.DISCOVERY,
1107
+ "intelligence": Phase.INTELLIGENCE,
1108
+ "drafting": Phase.DRAFTING,
1109
+ "redteam": Phase.REDTEAM,
1110
+ "qa": Phase.QA,
1111
+ "delivery": Phase.DELIVERY,
1112
+ "deployment": Phase.DEPLOYMENT,
1113
+ }
1114
+ phases = [phase_map[p] for p in args.phase]
1115
+
1116
+ # 运行工作流
1117
+ import asyncio
1118
+ config = config_manager.config
1119
+ context = WorkflowContext(
1120
+ project_dir=project_dir,
1121
+ config=config_manager,
1122
+ user_input={
1123
+ "name": config.name or project_dir.name,
1124
+ "description": config.description,
1125
+ "platform": config.platform,
1126
+ "frontend": config.frontend,
1127
+ "backend": config.backend,
1128
+ "domain": config.domain,
1129
+ "quality_threshold": args.quality_gate,
1130
+ },
1131
+ )
1132
+ engine = WorkflowEngine(project_dir)
1133
+ results = asyncio.run(engine.run(phases=phases, context=context))
1134
+
1135
+ # 检查是否全部成功
1136
+ all_success = bool(results) and all(r.success and not r.errors for r in results.values())
1137
+
1138
+ return 0 if all_success else 1
1139
+
1140
+ def _cmd_studio(self, args) -> int:
1141
+ """启动交互工作台 API"""
1142
+ try:
1143
+ import uvicorn
1144
+ except ImportError:
1145
+ self.console.print("[red]缺少依赖: uvicorn[/red]")
1146
+ self.console.print("[dim]请安装: pip install fastapi uvicorn[/dim]")
1147
+ return 1
1148
+
1149
+ self.console.print(f"[cyan]启动 Super Dev Studio: http://{args.host}:{args.port}[/cyan]")
1150
+ uvicorn.run(
1151
+ "super_dev.web.api:app",
1152
+ host=args.host,
1153
+ port=args.port,
1154
+ reload=args.reload,
1155
+ log_level="info",
1156
+ )
1157
+ return 0
1158
+
1159
+ def _cmd_expert(self, args) -> int:
1160
+ """调用专家"""
1161
+ from .experts import has_expert, list_experts, save_expert_advice
1162
+
1163
+ # 处理 --list 选项
1164
+ if args.list:
1165
+ self.console.print("[cyan]可用专家列表:[/cyan]")
1166
+ for expert in list_experts():
1167
+ self.console.print(f" [green]{expert['id']:<10}[/green] {expert['name']} - {expert['description']}")
1168
+ return 0
1169
+
1170
+ # 如果没有提供专家名称,显示帮助
1171
+ if not args.expert_name:
1172
+ self.console.print("[yellow]请提供专家名称或使用 --list 查看可用专家[/yellow]")
1173
+ return 1
1174
+
1175
+ prompt = " ".join(args.prompt) if args.prompt else ""
1176
+ self.console.print(f"[cyan]调用专家: {args.expert_name}[/cyan]")
1177
+ self.console.print(f"[dim]提示词: {prompt or '(无)'}[/dim]")
1178
+ if not has_expert(args.expert_name):
1179
+ self.console.print(f"[red]未知专家: {args.expert_name}[/red]")
1180
+ return 1
1181
+
1182
+ report_file, _ = save_expert_advice(
1183
+ project_dir=Path.cwd(),
1184
+ expert_id=args.expert_name,
1185
+ prompt=prompt,
1186
+ )
1187
+ self.console.print(f"[green]✓[/green] 专家建议已生成: {report_file}")
1188
+ return 0
1189
+
1190
+ def _cmd_quality(self, args) -> int:
1191
+ """质量检查"""
1192
+ from .reviewers import QualityGateChecker
1193
+
1194
+ project_dir = Path.cwd()
1195
+ output_dir = project_dir / "output"
1196
+ output_dir.mkdir(parents=True, exist_ok=True)
1197
+
1198
+ config_manager = ConfigManager(project_dir)
1199
+ config = config_manager.load()
1200
+
1201
+ project_name = self._sanitize_project_name(config.name or project_dir.name)
1202
+ tech_stack = {
1203
+ "platform": config.platform,
1204
+ "frontend": self._normalize_pipeline_frontend(config.frontend),
1205
+ "backend": config.backend,
1206
+ "domain": config.domain,
1207
+ }
1208
+
1209
+ self.console.print(f"[cyan]运行质量检查: {args.type}[/cyan]")
1210
+
1211
+ # 轻量文档检查
1212
+ if args.type in {"prd", "architecture", "ui", "ux"}:
1213
+ pattern_map = {
1214
+ "prd": "*-prd.md",
1215
+ "architecture": "*-architecture.md",
1216
+ "ui": "*-uiux.md",
1217
+ "ux": "*-uiux.md",
1218
+ }
1219
+ expected_pattern = pattern_map[args.type]
1220
+ matched = sorted(output_dir.glob(expected_pattern))
1221
+ if matched:
1222
+ self.console.print(f"[green]✓[/green] 检测到 {len(matched)} 个文档: {expected_pattern}")
1223
+ for file_path in matched[:5]:
1224
+ self.console.print(f" - {file_path}")
1225
+ return 0
1226
+
1227
+ self.console.print(f"[red]未找到文档: output/{expected_pattern}[/red]")
1228
+ return 1
1229
+
1230
+ # 代码或全量检查走质量门禁评估
1231
+ gate_checker = QualityGateChecker(
1232
+ project_dir=project_dir,
1233
+ name=project_name,
1234
+ tech_stack=tech_stack,
1235
+ )
1236
+ gate_result = gate_checker.check(redteam_report=None)
1237
+
1238
+ gate_file = output_dir / f"{project_name}-quality-gate.md"
1239
+ gate_file.write_text(gate_result.to_markdown(), encoding="utf-8")
1240
+
1241
+ scenario_label = "0-1 新建项目" if gate_result.scenario == "0-1" else "1-N+1 增量开发"
1242
+ status = "[green]通过[/green]" if gate_result.passed else "[red]未通过[/red]"
1243
+
1244
+ self.console.print(f" [dim]场景: {scenario_label}[/dim]")
1245
+ self.console.print(f" {status} 总分: {gate_result.total_score}/100")
1246
+ self.console.print(f" [green]✓[/green] 报告: {gate_file}")
1247
+
1248
+ if not gate_result.passed and gate_result.critical_failures:
1249
+ self.console.print("[yellow]关键失败项:[/yellow]")
1250
+ for failure in gate_result.critical_failures:
1251
+ self.console.print(f" - {failure}")
1252
+
1253
+ return 0 if gate_result.passed else 1
1254
+
1255
+ def _cmd_preview(self, args) -> int:
1256
+ """生成原型"""
1257
+ import shutil
1258
+
1259
+ output_path = Path(args.output).expanduser()
1260
+ if not output_path.is_absolute():
1261
+ output_path = Path.cwd() / output_path
1262
+ output_path.parent.mkdir(parents=True, exist_ok=True)
1263
+
1264
+ self.console.print(f"[cyan]生成原型: {output_path}[/cyan]")
1265
+
1266
+ frontend_dir = Path.cwd() / "output" / "frontend"
1267
+ index_file = frontend_dir / "index.html"
1268
+ css_file = frontend_dir / "styles.css"
1269
+ js_file = frontend_dir / "app.js"
1270
+
1271
+ if index_file.exists():
1272
+ html = index_file.read_text(encoding="utf-8")
1273
+ output_path.write_text(html, encoding="utf-8")
1274
+
1275
+ if css_file.exists():
1276
+ shutil.copyfile(css_file, output_path.parent / "styles.css")
1277
+ if js_file.exists():
1278
+ shutil.copyfile(js_file, output_path.parent / "app.js")
1279
+
1280
+ self.console.print("[green]✓[/green] 已基于 output/frontend 生成可预览页面")
1281
+ return 0
1282
+
1283
+ # 回退:生成文档概览预览页
1284
+ output_dir = Path.cwd() / "output"
1285
+ docs = sorted(output_dir.glob("*.md")) if output_dir.exists() else []
1286
+ rows = "\n".join(
1287
+ f"<li><a href=\"{doc.name}\" target=\"_blank\">{doc.name}</a></li>"
1288
+ for doc in docs[:20]
1289
+ ) or "<li>未找到可预览文档,请先运行 super-dev create 或 super-dev pipeline。</li>"
1290
+
1291
+ fallback_html = f"""<!doctype html>
1292
+ <html lang="zh-CN">
1293
+ <head>
1294
+ <meta charset="utf-8" />
1295
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1296
+ <title>Super Dev Preview</title>
1297
+ <style>
1298
+ body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 32px; line-height: 1.6; }}
1299
+ h1 {{ margin-bottom: 8px; }}
1300
+ .hint {{ color: #555; margin-bottom: 16px; }}
1301
+ ul {{ padding-left: 18px; }}
1302
+ </style>
1303
+ </head>
1304
+ <body>
1305
+ <h1>Super Dev 预览页</h1>
1306
+ <p class="hint">未检测到 output/frontend 前端骨架,以下为当前 output 文档列表:</p>
1307
+ <ul>{rows}</ul>
1308
+ </body>
1309
+ </html>
1310
+ """
1311
+ output_path.write_text(fallback_html, encoding="utf-8")
1312
+ self.console.print("[yellow]未检测到 output/frontend,已生成文档概览预览页[/yellow]")
1313
+ return 0
1314
+
1315
+ def _cmd_deploy(self, args) -> int:
1316
+ """生成部署配置"""
1317
+ from .deployers import CICDGenerator
1318
+
1319
+ project_dir = Path.cwd()
1320
+ config_manager = ConfigManager(project_dir)
1321
+ config = config_manager.load()
1322
+
1323
+ tech_stack = {
1324
+ "platform": config.platform,
1325
+ "frontend": self._normalize_pipeline_frontend(config.frontend),
1326
+ "backend": config.backend,
1327
+ "domain": config.domain,
1328
+ }
1329
+ project_name = self._sanitize_project_name(config.name or project_dir.name)
1330
+
1331
+ platform = self._normalize_cicd_platform(args.cicd or "github")
1332
+ generator = CICDGenerator(
1333
+ project_dir=project_dir,
1334
+ name=project_name,
1335
+ tech_stack=tech_stack,
1336
+ platform=platform,
1337
+ )
1338
+ generated_files = generator.generate()
1339
+
1340
+ cicd_map = {
1341
+ "github": [".github/workflows/ci.yml", ".github/workflows/cd.yml"],
1342
+ "gitlab": [".gitlab-ci.yml"],
1343
+ "jenkins": ["Jenkinsfile"],
1344
+ "azure": [".azure-pipelines.yml"],
1345
+ "bitbucket": ["bitbucket-pipelines.yml"],
1346
+ "all": [
1347
+ ".github/workflows/ci.yml",
1348
+ ".github/workflows/cd.yml",
1349
+ ".gitlab-ci.yml",
1350
+ "Jenkinsfile",
1351
+ ".azure-pipelines.yml",
1352
+ "bitbucket-pipelines.yml",
1353
+ ],
1354
+ }
1355
+ docker_related = [
1356
+ "Dockerfile",
1357
+ "docker-compose.yml",
1358
+ ".dockerignore",
1359
+ "k8s/deployment.yaml",
1360
+ "k8s/service.yaml",
1361
+ "k8s/ingress.yaml",
1362
+ "k8s/configmap.yaml",
1363
+ "k8s/secret.yaml",
1364
+ ]
1365
+
1366
+ want_cicd = bool(args.cicd) or (not args.cicd and not args.docker)
1367
+ want_docker = bool(args.docker) or (not args.cicd and not args.docker)
1368
+
1369
+ selected_keys: list[str] = []
1370
+ if want_cicd:
1371
+ selected_keys.extend(cicd_map.get(platform, []))
1372
+ if want_docker:
1373
+ selected_keys.extend(docker_related)
1374
+
1375
+ selected_keys = [key for key in selected_keys if key in generated_files]
1376
+ if not selected_keys:
1377
+ self.console.print("[yellow]没有可生成的部署配置[/yellow]")
1378
+ return 0
1379
+
1380
+ self.console.print("[cyan]生成部署配置...[/cyan]")
1381
+ written = 0
1382
+ for relative_path in selected_keys:
1383
+ full_path = project_dir / relative_path
1384
+ full_path.parent.mkdir(parents=True, exist_ok=True)
1385
+ full_path.write_text(generated_files[relative_path], encoding="utf-8")
1386
+ self.console.print(f" [green]✓[/green] {relative_path}")
1387
+ written += 1
1388
+
1389
+ self.console.print(f"[green]✓[/green] 已生成 {written} 个部署文件")
1390
+ return 0
1391
+
1392
+ def _cmd_create(self, args) -> int:
1393
+ """一键创建项目 - 从想法到规范"""
1394
+ from .creators import ProjectCreator
1395
+
1396
+ self.console.print("[cyan]Super Dev 项目创建器[/cyan]")
1397
+ self.console.print(f"[dim]描述: {args.description}[/dim]")
1398
+ self.console.print(f"[dim]平台: {args.platform} | 前端: {args.frontend} | 后端: {args.backend}[/dim]")
1399
+ self.console.print("")
1400
+
1401
+ # 确定项目名称
1402
+ project_name = args.name
1403
+ if not project_name:
1404
+ # 从描述生成项目名称
1405
+ import re
1406
+ words = re.findall(r'[\w]+', args.description)
1407
+ if words:
1408
+ project_name = '-'.join(words[:3]).lower()
1409
+ else:
1410
+ project_name = "my-project"
1411
+ project_name = self._sanitize_project_name(project_name)
1412
+
1413
+ # 创建项目目录
1414
+ project_dir = Path.cwd()
1415
+
1416
+ try:
1417
+ creator = ProjectCreator(
1418
+ project_dir=project_dir,
1419
+ name=project_name,
1420
+ description=args.description,
1421
+ platform=args.platform,
1422
+ frontend=args.frontend,
1423
+ backend=args.backend,
1424
+ domain=args.domain,
1425
+ ui_library=getattr(args, 'ui_library', None),
1426
+ style_solution=getattr(args, 'style', None),
1427
+ state_management=getattr(args, 'state', []) or [],
1428
+ testing_frameworks=getattr(args, 'testing', []) or [],
1429
+ )
1430
+
1431
+ # 1. 生成文档
1432
+ if not args.skip_docs:
1433
+ self.console.print("[cyan]第 1 步: 生成专业文档...[/cyan]")
1434
+ docs = creator.generate_documents()
1435
+ self.console.print(f" [green]✓[/green] PRD: {docs['prd']}")
1436
+ self.console.print(f" [green]✓[/green] 架构: {docs['architecture']}")
1437
+ self.console.print(f" [green]✓[/green] UI/UX: {docs['uiux']}")
1438
+ if docs.get("plan"):
1439
+ self.console.print(f" [green]✓[/green] 执行路线图: {docs['plan']}")
1440
+ if docs.get("frontend_blueprint"):
1441
+ self.console.print(f" [green]✓[/green] 前端蓝图: {docs['frontend_blueprint']}")
1442
+ self.console.print("")
1443
+
1444
+ # 2. 创建 Spec
1445
+ self.console.print("[cyan]第 2 步: 创建 Spec 规范...[/cyan]")
1446
+ change_id = creator.create_spec()
1447
+ self.console.print(f" [green]✓[/green] 变更 ID: {change_id}")
1448
+ self.console.print("")
1449
+
1450
+ # 3. 生成 AI 提示词
1451
+ self.console.print("[cyan]第 3 步: 生成 AI 提示词...[/cyan]")
1452
+ prompt_file = creator.generate_ai_prompt()
1453
+ self.console.print(f" [green]✓[/green] 提示词: {prompt_file}")
1454
+ self.console.print("")
1455
+
1456
+ # 完成
1457
+ self.console.print("[green]✓ 项目创建完成![/green]")
1458
+ self.console.print("")
1459
+ self.console.print("[cyan]下一步:[/cyan]")
1460
+ self.console.print(" 1. 查看生成的文档:")
1461
+ self.console.print(f" - PRD: output/{project_name}-prd.md")
1462
+ self.console.print(f" - 架构: output/{project_name}-architecture.md")
1463
+ self.console.print(f" - UI/UX: output/{project_name}-uiux.md")
1464
+ self.console.print(f" - 执行路线图: output/{project_name}-execution-plan.md")
1465
+ self.console.print(f" - 前端蓝图: output/{project_name}-frontend-blueprint.md")
1466
+ self.console.print(f" 2. 查看规范: super-dev spec show {change_id}")
1467
+ self.console.print(f" 3. 复制 AI 提示词: cat {prompt_file}")
1468
+ self.console.print(" 4. 开始开发: 按 tasks 顺序实现并持续更新规范")
1469
+
1470
+ except Exception as e:
1471
+ self.console.print(f"[red]创建失败: {e}[/red]")
1472
+ import traceback
1473
+ self.console.print(traceback.format_exc())
1474
+ return 1
1475
+
1476
+ return 0
1477
+
1478
+ def _cmd_design(self, args) -> int:
1479
+ """设计智能引擎命令"""
1480
+ from .design import DesignIntelligenceEngine, DesignSystemGenerator, TokenGenerator
1481
+
1482
+ if args.design_command == "search":
1483
+ # 搜索设计资产
1484
+ self.console.print(f"[cyan]搜索设计资产: {args.query}[/cyan]")
1485
+
1486
+ engine = DesignIntelligenceEngine()
1487
+
1488
+ result = engine.search(
1489
+ query=args.query,
1490
+ domain=args.domain,
1491
+ max_results=args.max_results,
1492
+ )
1493
+
1494
+ # 显示结果
1495
+ if "error" in result:
1496
+ self.console.print(f"[red]搜索失败: {result['error']}[/red]")
1497
+ return 1
1498
+
1499
+ domain_name = {
1500
+ "style": "风格",
1501
+ "color": "配色",
1502
+ "typography": "字体",
1503
+ "component": "组件",
1504
+ "layout": "布局",
1505
+ "animation": "动画",
1506
+ "ux": "UX 指南",
1507
+ "chart": "图表",
1508
+ "product": "产品",
1509
+ }.get(result["domain"], result["domain"])
1510
+
1511
+ self.console.print(f"\n[green]找到 {result['count']} 个{domain_name}结果:[/green]\n")
1512
+
1513
+ for idx, item in enumerate(result["results"], 1):
1514
+ relevance_color = {
1515
+ "high": "green",
1516
+ "medium": "yellow",
1517
+ "low": "dim",
1518
+ }.get(item.get("relevance", "low"), "dim")
1519
+
1520
+ self.console.print(f"[{relevance_color}]{idx}.[/] [bold]{item.get('name', item.get('Style Category', item.get('Font Pairing Name', 'N/A')))}[/] (相关度: {item.get('relevance', 'N/A')})")
1521
+
1522
+ # 显示关键信息
1523
+ if "description" in item:
1524
+ self.console.print(f" {item['description']}")
1525
+ if "keywords" in item:
1526
+ self.console.print(f" 关键词: {item['keywords']}")
1527
+ if "primary_colors" in item:
1528
+ self.console.print(f" 色彩: {item['primary_colors']}")
1529
+ if "mood" in item:
1530
+ self.console.print(f" 风格: {item['mood']}")
1531
+
1532
+ self.console.print()
1533
+
1534
+ return 0
1535
+
1536
+ elif args.design_command == "generate":
1537
+ # 生成完整设计系统
1538
+ self.console.print("[cyan]生成设计系统[/cyan]")
1539
+ self.console.print(f" 产品: {args.product}")
1540
+ self.console.print(f" 行业: {args.industry}")
1541
+ self.console.print(f" 关键词: {' '.join(args.keywords) if args.keywords else 'N/A'}")
1542
+ self.console.print(f" 平台: {args.platform}")
1543
+ self.console.print()
1544
+
1545
+ generator = DesignSystemGenerator()
1546
+
1547
+ design_system = generator.generate(
1548
+ product_type=args.product,
1549
+ industry=args.industry,
1550
+ keywords=args.keywords or [],
1551
+ platform=args.platform,
1552
+ aesthetic=args.aesthetic,
1553
+ )
1554
+
1555
+ self.console.print("[green]设计系统已生成:[/green]\n")
1556
+ self.console.print(f" 名称: {design_system.name}")
1557
+ self.console.print(f" 描述: {design_system.description}")
1558
+
1559
+ if design_system.aesthetic:
1560
+ self.console.print(f" 美学方向: {design_system.aesthetic.name}")
1561
+ self.console.print(f" 差异化特征: {design_system.aesthetic.differentiation}")
1562
+
1563
+ self.console.print("\n[cyan]生成文件...[/cyan]")
1564
+
1565
+ output_dir = Path(args.output)
1566
+ generated_files = generator.generate_documentation(design_system, output_dir)
1567
+
1568
+ for file_path in generated_files:
1569
+ self.console.print(f" [green]✓[/green] {file_path}")
1570
+
1571
+ self.console.print("\n[dim]下一步:[/dim]")
1572
+ self.console.print(f" 1. 查看 {output_dir / 'DESIGN_SYSTEM.md'} 了解设计系统")
1573
+ self.console.print(f" 2. 使用 {output_dir / 'design-tokens.css'} 导入 CSS 变量")
1574
+ self.console.print(f" 3. 使用 {output_dir / 'tailwind.config.json'} 配置 Tailwind")
1575
+
1576
+ return 0
1577
+
1578
+ elif args.design_command == "tokens":
1579
+ # 生成 design tokens
1580
+ self.console.print("[cyan]生成 design tokens[/cyan]")
1581
+ self.console.print(f" 主色: {args.primary}")
1582
+ self.console.print(f" 类型: {args.type}")
1583
+ self.console.print()
1584
+
1585
+ token_gen = TokenGenerator()
1586
+
1587
+ if args.format == "css":
1588
+ tokens = token_gen.generate_all_tokens(args.primary, args.type)
1589
+
1590
+ css_content = [":root {"]
1591
+ css_content.append(" /* Colors */")
1592
+
1593
+ for name, value in tokens["colors"].items():
1594
+ css_content.append(f" --color-{name}: {value};")
1595
+
1596
+ css_content.append("")
1597
+ css_content.append(" /* Spacing */")
1598
+
1599
+ for name, value in tokens["spacing"].items():
1600
+ css_content.append(f" --space-{name}: {value};")
1601
+
1602
+ css_content.append("")
1603
+ css_content.append(" /* Shadows */")
1604
+
1605
+ for name, value in tokens["shadows"].items():
1606
+ css_content.append(f" --shadow-{name}: {value};")
1607
+
1608
+ css_content.append("}")
1609
+
1610
+ output = "\n".join(css_content)
1611
+
1612
+ if args.output:
1613
+ Path(args.output).write_text(output, encoding="utf-8")
1614
+ self.console.print(f"[green]✓[/green] 已保存到 {args.output}")
1615
+ else:
1616
+ self.console.print(output)
1617
+
1618
+ elif args.format == "json":
1619
+ tokens = token_gen.generate_all_tokens(args.primary, args.type)
1620
+ output = json.dumps(tokens, indent=2)
1621
+
1622
+ if args.output:
1623
+ Path(args.output).write_text(output, encoding="utf-8")
1624
+ self.console.print(f"[green]✓[/green] 已保存到 {args.output}")
1625
+ else:
1626
+ self.console.print(output)
1627
+
1628
+ elif args.format == "tailwind":
1629
+ tokens = token_gen.generate_all_tokens(args.primary, args.type)
1630
+
1631
+ tailwind_config = {
1632
+ "theme": {
1633
+ "extend": {
1634
+ "colors": {f"{k}": v for k, v in tokens["colors"].items()},
1635
+ "spacing": tokens["spacing"],
1636
+ "boxShadow": tokens["shadows"],
1637
+ }
1638
+ }
1639
+ }
1640
+
1641
+ output = json.dumps(tailwind_config, indent=2)
1642
+
1643
+ if args.output:
1644
+ Path(args.output).write_text(output, encoding="utf-8")
1645
+ self.console.print(f"[green]✓[/green] 已保存到 {args.output}")
1646
+ else:
1647
+ self.console.print(output)
1648
+
1649
+ return 0
1650
+
1651
+ elif args.design_command == "landing":
1652
+ # Landing 页面模式生成
1653
+ from .design import get_landing_generator
1654
+
1655
+ landing_gen = get_landing_generator()
1656
+
1657
+ # 列出所有模式
1658
+ if hasattr(args, 'list') and args.list:
1659
+ pattern_names = landing_gen.list_patterns()
1660
+ self.console.print(f"\n[green]可用的 Landing 页面模式 ({len(pattern_names)} 个):[/green]\n")
1661
+ for i, pattern_name in enumerate(pattern_names, 1):
1662
+ self.console.print(f" {i}. {pattern_name}")
1663
+ self.console.print()
1664
+ return 0
1665
+
1666
+ # 智能推荐
1667
+ if hasattr(args, 'product_type') and args.product_type:
1668
+ self.console.print("[cyan]智能推荐 Landing 页面模式[/cyan]")
1669
+ self.console.print(f" 产品类型: {args.product_type}")
1670
+ self.console.print(f" 目标: {args.goal if hasattr(args, 'goal') and args.goal else 'N/A'}")
1671
+ self.console.print(f" 受众: {args.audience if hasattr(args, 'audience') and args.audience else 'N/A'}")
1672
+ self.console.print()
1673
+
1674
+ recommended = landing_gen.recommend(
1675
+ product_type=args.product_type,
1676
+ goal=args.goal if hasattr(args, 'goal') and args.goal else "",
1677
+ audience=args.audience if hasattr(args, 'audience') and args.audience else ""
1678
+ )
1679
+
1680
+ if recommended:
1681
+ self.console.print(f"[green]推荐模式: {recommended.name}[/green]")
1682
+ self.console.print(f" {recommended.description}")
1683
+ self.console.print(f" 适合: {', '.join(recommended.best_for)}")
1684
+ self.console.print(f" 复杂度: {recommended.complexity}")
1685
+ self.console.print()
1686
+ return 0
1687
+
1688
+ # 搜索模式
1689
+ query = args.query if hasattr(args, 'query') and args.query else ""
1690
+ if query:
1691
+ self.console.print(f"[cyan]搜索 Landing 页面模式: {query}[/cyan]\n")
1692
+
1693
+ landing_results = landing_gen.search(query, max_results=args.max_results)
1694
+
1695
+ if not landing_results:
1696
+ self.console.print("[yellow]未找到匹配的模式[/yellow]")
1697
+ return 1
1698
+
1699
+ self.console.print(f"[green]找到 {len(landing_results)} 个结果:[/green]\n")
1700
+
1701
+ for idx, landing_pattern in enumerate(landing_results, 1):
1702
+ self.console.print(f"[cyan]{idx}. {landing_pattern.name}[/cyan]")
1703
+ self.console.print(f" {landing_pattern.description}")
1704
+ self.console.print(f" 适合: {', '.join(landing_pattern.best_for)}")
1705
+ self.console.print(f" 复杂度: {landing_pattern.complexity}")
1706
+ self.console.print()
1707
+
1708
+ return 0
1709
+
1710
+ # 默认显示所有模式
1711
+ pattern_names = landing_gen.list_patterns()
1712
+ self.console.print(f"\n[green]可用的 Landing 页面模式 ({len(pattern_names)} 个):[/green]\n")
1713
+ for i, pattern_name in enumerate(pattern_names, 1):
1714
+ self.console.print(f" {i}. {pattern_name}")
1715
+ self.console.print()
1716
+ return 0
1717
+
1718
+ elif args.design_command == "chart":
1719
+ # 图表类型推荐
1720
+ from .design import get_chart_recommender
1721
+
1722
+ chart_recommender = get_chart_recommender()
1723
+
1724
+ # 列出所有图表类型
1725
+ if hasattr(args, 'list') and args.list:
1726
+ chart_types = chart_recommender.list_chart_types()
1727
+ categories = chart_recommender.list_categories()
1728
+ self.console.print(f"\n[green]可用的图表类型 ({len(chart_types)} 个, {len(categories)} 个类别):[/green]\n")
1729
+ for category in sorted(categories):
1730
+ types = [ct for ct in chart_types if ct in [c.name for c in chart_recommender.chart_types if c.category.value == category]]
1731
+ self.console.print(f" [cyan]{category}:[/cyan]")
1732
+ for ct in sorted(types):
1733
+ self.console.print(f" - {ct}")
1734
+ self.console.print()
1735
+ return 0
1736
+
1737
+ # 推荐图表类型
1738
+ data_description = args.data_description if hasattr(args, 'data_description') else ""
1739
+ if data_description:
1740
+ self.console.print("[cyan]推荐图表类型[/cyan]")
1741
+ self.console.print(f" 数据描述: {data_description}")
1742
+ self.console.print(f" 框架: {args.framework}")
1743
+ self.console.print()
1744
+
1745
+ chart_recommendations = chart_recommender.recommend(
1746
+ data_description=data_description,
1747
+ framework=args.framework,
1748
+ max_results=args.max_results
1749
+ )
1750
+
1751
+ if not chart_recommendations:
1752
+ self.console.print("[yellow]未找到合适的图表类型[/yellow]")
1753
+ return 1
1754
+
1755
+ self.console.print("[green]推荐结果:[/green]\n")
1756
+
1757
+ for idx, chart_rec in enumerate(chart_recommendations, 1):
1758
+ confidence_pct = int(chart_rec.confidence * 100)
1759
+ self.console.print(f"[cyan]{idx}. {chart_rec.chart_type.name}[/cyan] (置信度: {confidence_pct}%)")
1760
+ self.console.print(f" {chart_rec.chart_type.description}")
1761
+ self.console.print(f" 理由: {chart_rec.reasoning}")
1762
+ self.console.print(f" 推荐库: {chart_rec.library_recommendation}")
1763
+ self.console.print(f" 无障碍: {chart_rec.chart_type.accessibility_notes}")
1764
+ if chart_rec.alternatives:
1765
+ self.console.print(f" 替代方案: {', '.join([a.name for a in chart_rec.alternatives])}")
1766
+ self.console.print()
1767
+
1768
+ return 0
1769
+
1770
+ # 默认显示所有图表类型
1771
+ chart_types = chart_recommender.list_chart_types()
1772
+ self.console.print(f"\n[green]可用的图表类型 ({len(chart_types)} 个):[/green]\n")
1773
+ for i, ct in enumerate(chart_types, 1):
1774
+ self.console.print(f" {i}. {ct}")
1775
+ self.console.print()
1776
+ return 0
1777
+
1778
+ elif args.design_command == "ux":
1779
+ # UX 指南查询
1780
+ from .design import get_ux_guide
1781
+
1782
+ ux_guide = get_ux_guide()
1783
+
1784
+ # 列出所有领域
1785
+ if hasattr(args, 'list_domains') and args.list_domains:
1786
+ domains = ux_guide.list_domains()
1787
+ self.console.print(f"\n[green]UX 指南领域 ({len(domains)} 个):[/green]\n")
1788
+ for i, domain in enumerate(domains, 1):
1789
+ self.console.print(f" {i}. {domain}")
1790
+ self.console.print()
1791
+ return 0
1792
+
1793
+ # 快速见效的改进
1794
+ if hasattr(args, 'quick_wins') and args.quick_wins:
1795
+ self.console.print("[cyan]快速见效的 UX 改进建议[/cyan]\n")
1796
+
1797
+ ux_quick_wins = ux_guide.get_quick_wins(max_results=args.max_results)
1798
+
1799
+ if not ux_quick_wins:
1800
+ self.console.print("[yellow]未找到快速见效的建议[/yellow]")
1801
+ return 1
1802
+
1803
+ for idx, ux_rec in enumerate(ux_quick_wins, 1):
1804
+ self.console.print(f"[cyan]{idx}. {ux_rec.guideline.topic}[/cyan] ({ux_rec.guideline.domain.value})")
1805
+ self.console.print(f" [green]最佳实践:[/green] {ux_rec.guideline.best_practice}")
1806
+ self.console.print(f" [red]反模式:[/red] {ux_rec.guideline.anti_pattern}")
1807
+ self.console.print(f" 影响: {ux_rec.guideline.impact}")
1808
+ self.console.print(f" 优先级: {ux_rec.priority} | 实现难度: {ux_rec.implementation_effort} | 用户影响: {ux_rec.user_impact}")
1809
+ if ux_rec.resources:
1810
+ self.console.print(f" 资源: {', '.join(ux_rec.resources)}")
1811
+ self.console.print()
1812
+
1813
+ return 0
1814
+
1815
+ # 检查清单
1816
+ if hasattr(args, 'checklist') and args.checklist:
1817
+ self.console.print("[cyan]UX 检查清单[/cyan]\n")
1818
+
1819
+ checklist = ux_guide.get_checklist(domains=[args.domain] if hasattr(args, 'domain') and args.domain else None)
1820
+
1821
+ for domain, items in sorted(checklist.items()):
1822
+ self.console.print(f"[cyan]{domain}:[/cyan]")
1823
+ for item in items:
1824
+ self.console.print(f" {item}")
1825
+ self.console.print()
1826
+
1827
+ return 0
1828
+
1829
+ # 搜索 UX 指南
1830
+ query = args.query if hasattr(args, 'query') and args.query else ""
1831
+ if query:
1832
+ self.console.print(f"[cyan]搜索 UX 指南: {query}[/cyan]\n")
1833
+
1834
+ ux_recommendations = ux_guide.search(
1835
+ query=query,
1836
+ domain=args.domain if hasattr(args, 'domain') else None,
1837
+ max_results=args.max_results
1838
+ )
1839
+
1840
+ if not ux_recommendations:
1841
+ self.console.print("[yellow]未找到匹配的 UX 指南[/yellow]")
1842
+ return 1
1843
+
1844
+ self.console.print(f"[green]找到 {len(ux_recommendations)} 个结果:[/green]\n")
1845
+
1846
+ for idx, ux_rec in enumerate(ux_recommendations, 1):
1847
+ self.console.print(f"[cyan]{idx}. {ux_rec.guideline.topic}[/cyan] ({ux_rec.guideline.domain.value})")
1848
+ self.console.print(f" [green]最佳实践:[/green] {ux_rec.guideline.best_practice}")
1849
+ self.console.print(f" [red]反模式:[/red] {ux_rec.guideline.anti_pattern}")
1850
+ self.console.print(f" 影响: {ux_rec.guideline.impact}")
1851
+ self.console.print(f" 优先级: {ux_rec.priority} | 实现难度: {ux_rec.implementation_effort} | 用户影响: {ux_rec.user_impact}")
1852
+ if ux_rec.resources:
1853
+ self.console.print(f" 资源: {', '.join(ux_rec.resources)}")
1854
+ self.console.print()
1855
+
1856
+ return 0
1857
+
1858
+ # 默认显示所有领域
1859
+ domains = ux_guide.list_domains()
1860
+ self.console.print(f"\n[green]UX 指南领域 ({len(domains)} 个):[/green]\n")
1861
+ for i, domain in enumerate(domains, 1):
1862
+ self.console.print(f" {i}. {domain}")
1863
+ self.console.print()
1864
+ return 0
1865
+
1866
+ elif args.design_command == "stack":
1867
+ # 技术栈最佳实践
1868
+ from .design import get_tech_stack_engine
1869
+
1870
+ tech_engine = get_tech_stack_engine()
1871
+
1872
+ # 列出所有技术栈
1873
+ if hasattr(args, 'list') and args.list:
1874
+ stacks = tech_engine.list_stacks()
1875
+ self.console.print(f"\n[green]支持的技术栈 ({len(stacks)} 个):[/green]\n")
1876
+ for i, stack in enumerate(stacks, 1):
1877
+ self.console.print(f" {i}. {stack}")
1878
+ self.console.print()
1879
+ return 0
1880
+
1881
+ # 查询参数
1882
+ stack_name = args.stack
1883
+ query = args.query if hasattr(args, 'query') and args.query else None
1884
+ category = args.category if hasattr(args, 'category') else None
1885
+
1886
+ # 显示设计模式
1887
+ if hasattr(args, 'patterns') and args.patterns:
1888
+ tech_patterns = tech_engine.get_patterns(stack_name)
1889
+
1890
+ if not tech_patterns:
1891
+ self.console.print(f"[yellow]未找到 {stack_name} 的设计模式[/yellow]")
1892
+ return 1
1893
+
1894
+ self.console.print(f"\n[cyan]{stack_name} 设计模式 ({len(tech_patterns)} 个):[/cyan]\n")
1895
+
1896
+ for idx, tech_pattern in enumerate(tech_patterns, 1):
1897
+ self.console.print(f"[cyan]{idx}. {tech_pattern.name}[/cyan]")
1898
+ self.console.print(f" 描述: {tech_pattern.description}")
1899
+ self.console.print(f" 使用场景: {tech_pattern.use_case}")
1900
+ if tech_pattern.pros:
1901
+ self.console.print(f" 优点: {', '.join(tech_pattern.pros)}")
1902
+ if tech_pattern.cons:
1903
+ self.console.print(f" 缺点: {', '.join(tech_pattern.cons)}")
1904
+ self.console.print()
1905
+
1906
+ return 0
1907
+
1908
+ # 显示性能优化建议
1909
+ if hasattr(args, 'performance') and args.performance:
1910
+ tips = tech_engine.get_performance_tips(stack_name)
1911
+
1912
+ if not tips:
1913
+ self.console.print(f"[yellow]未找到 {stack_name} 的性能建议[/yellow]")
1914
+ return 1
1915
+
1916
+ self.console.print(f"\n[cyan]{stack_name} 性能优化建议 ({len(tips)} 个):[/cyan]\n")
1917
+
1918
+ for idx, tip in enumerate(tips, 1):
1919
+ self.console.print(f"[cyan]{idx}. {tip.topic} - {tip.technique}[/cyan]")
1920
+ self.console.print(f" 描述: {tip.description}")
1921
+ self.console.print(f" 影响: {tip.impact} | 实施难度: {tip.effort}")
1922
+ if tip.code_snippet:
1923
+ self.console.print(f" 代码示例:\n [dim]{tip.code_snippet}[/dim]")
1924
+ self.console.print()
1925
+
1926
+ return 0
1927
+
1928
+ # 快速见效的性能优化
1929
+ if hasattr(args, 'quick_wins') and args.quick_wins:
1930
+ tips = tech_engine.get_quick_wins(stack_name)
1931
+
1932
+ if not tips:
1933
+ self.console.print(f"[yellow]未找到 {stack_name} 的快速性能优化[/yellow]")
1934
+ return 1
1935
+
1936
+ self.console.print(f"\n[cyan]{stack_name} 快速见效的性能优化 ({len(tips)} 个):[/cyan]\n")
1937
+
1938
+ for idx, tip in enumerate(tips, 1):
1939
+ self.console.print(f"[cyan]{idx}. {tip.topic} - {tip.technique}[/cyan]")
1940
+ self.console.print(f" 描述: {tip.description}")
1941
+ if tip.code_snippet:
1942
+ self.console.print(f" 代码示例:\n [dim]{tip.code_snippet}[/dim]")
1943
+ self.console.print()
1944
+
1945
+ return 0
1946
+
1947
+ # 搜索最佳实践
1948
+ self.console.print(f"[cyan]搜索 {stack_name} 最佳实践[/cyan]\n")
1949
+
1950
+ if query:
1951
+ self.console.print(f"查询: {query}\n")
1952
+
1953
+ stack_recommendations = tech_engine.search_practices(
1954
+ stack=stack_name,
1955
+ query=query,
1956
+ category=category,
1957
+ max_results=args.max_results
1958
+ )
1959
+
1960
+ if not stack_recommendations:
1961
+ self.console.print("[yellow]未找到匹配的最佳实践[/yellow]")
1962
+ return 1
1963
+
1964
+ for idx, stack_rec in enumerate(stack_recommendations, 1):
1965
+ self.console.print(f"[cyan]{idx}. {stack_rec.practice.topic}[/cyan] ({stack_rec.practice.category.value})")
1966
+ self.console.print(f" [green]最佳实践:[/green] {stack_rec.practice.practice}")
1967
+ self.console.print(f" [red]反模式:[/red] {stack_rec.practice.anti_pattern}")
1968
+ self.console.print(f" 好处: {stack_rec.practice.benefits}")
1969
+ self.console.print(f" 优先级: {stack_rec.priority} | 复杂度: {stack_rec.practice.complexity}")
1970
+ if stack_rec.context:
1971
+ self.console.print(f" 上下文: {stack_rec.context}")
1972
+ if stack_rec.alternatives:
1973
+ self.console.print(
1974
+ f" 替代方案: {', '.join([a.value if hasattr(a, 'value') else str(a) for a in stack_rec.alternatives])}"
1975
+ )
1976
+ if stack_rec.resources:
1977
+ self.console.print(f" 资源: {', '.join(stack_rec.resources)}")
1978
+ if stack_rec.practice.code_example:
1979
+ self.console.print(f" 代码示例:\n [dim]{stack_rec.practice.code_example[:200]}...[/dim]")
1980
+ self.console.print()
1981
+
1982
+ return 0
1983
+
1984
+ elif args.design_command == "codegen":
1985
+ # 代码片段生成
1986
+ from .design import get_code_generator
1987
+ from .design.codegen import Framework
1988
+
1989
+ codegen = get_code_generator()
1990
+
1991
+ # 列出所有可用组件
1992
+ if hasattr(args, 'list') and args.list:
1993
+ components = codegen.get_available_components(
1994
+ framework=Framework(args.framework) if hasattr(args, 'framework') else None
1995
+ )
1996
+
1997
+ self.console.print(f"\n[green]可用组件 ({args.framework or 'all'}):[/green]\n")
1998
+
1999
+ for category, comp_list in sorted(components.items()):
2000
+ self.console.print(f"[cyan]{category}:[/cyan]")
2001
+ for comp in comp_list:
2002
+ self.console.print(f" - {comp}")
2003
+ self.console.print()
2004
+
2005
+ return 0
2006
+
2007
+ # 搜索组件
2008
+ if hasattr(args, 'search') and args.search:
2009
+ component_snippets = codegen.search_components(
2010
+ query=args.search,
2011
+ framework=args.framework if hasattr(args, 'framework') else None
2012
+ )
2013
+
2014
+ if not component_snippets:
2015
+ self.console.print(f"[yellow]未找到匹配的组件: {args.search}[/yellow]")
2016
+ return 1
2017
+
2018
+ self.console.print(f"\n[green]找到 {len(component_snippets)} 个组件:[/green]\n")
2019
+
2020
+ for idx, snippet in enumerate(component_snippets, 1):
2021
+ self.console.print(f"[cyan]{idx}. {snippet.name}[/cyan] ({snippet.framework.value})")
2022
+ self.console.print(f" 类别: {snippet.category.value}")
2023
+ self.console.print(f" 描述: {snippet.description}")
2024
+ self.console.print(f" 依赖: {', '.join(snippet.dependencies)}")
2025
+ if snippet.preview:
2026
+ self.console.print(f" 预览: [dim]{snippet.preview}[/dim]")
2027
+ self.console.print()
2028
+
2029
+ return 0
2030
+
2031
+ # 生成组件代码
2032
+ component_name = args.component
2033
+ framework = args.framework if hasattr(args, 'framework') else "react"
2034
+
2035
+ self.console.print(f"[cyan]生成 {component_name} 组件 ({framework})[/cyan]\n")
2036
+
2037
+ component = codegen.generate_component(
2038
+ component_name=component_name,
2039
+ framework=Framework(framework)
2040
+ )
2041
+
2042
+ if not component:
2043
+ self.console.print(f"[yellow]未找到组件: {component_name}[/yellow]")
2044
+ self.console.print("使用 --list 查看可用组件")
2045
+ return 1
2046
+
2047
+ self.console.print(f"[green]组件名称:[/green] {component_name}")
2048
+ self.console.print(f"[green]描述:[/green] {component.description}\n")
2049
+
2050
+ self.console.print("[cyan]代码:[/cyan]")
2051
+ self.console.print(f"```{framework}")
2052
+ self.console.print(component.code)
2053
+ self.console.print("```\n")
2054
+
2055
+ if component.imports:
2056
+ self.console.print("[cyan]导入语句:[/cyan]")
2057
+ for imp in component.imports:
2058
+ self.console.print(f" {imp}")
2059
+ self.console.print()
2060
+
2061
+ if component.dependencies:
2062
+ self.console.print("[cyan]依赖:[/cyan]")
2063
+ self.console.print(f" {', '.join(component.dependencies)}")
2064
+ self.console.print()
2065
+
2066
+ if component.usage_example:
2067
+ self.console.print("[cyan]使用示例:[/cyan]")
2068
+ self.console.print(f" [dim]{component.usage_example}[/dim]")
2069
+
2070
+ # 输出到文件
2071
+ if hasattr(args, 'output') and args.output:
2072
+ output_path = Path(args.output)
2073
+ output_path.parent.mkdir(parents=True, exist_ok=True)
2074
+
2075
+ with open(output_path, 'w', encoding='utf-8') as f:
2076
+ f.write(component.code)
2077
+
2078
+ self.console.print(f"\n[green]已保存到: {output_path}[/green]")
2079
+
2080
+ return 0
2081
+
2082
+ else:
2083
+ self.console.print("[yellow]请指定设计子命令[/yellow]")
2084
+ self.console.print(" 可用命令: search, generate, tokens, landing, chart, ux, stack, codegen")
2085
+ self.console.print(" 使用 'super-dev design <command> -h' 查看帮助")
2086
+ return 1
2087
+
2088
+ def _cmd_pipeline(self, args) -> int:
2089
+ """运行完整流水线 - 从想法到部署"""
2090
+ # 确定项目名称
2091
+ project_name = args.name
2092
+ if not project_name:
2093
+ import re
2094
+ words = re.findall(r'[\w]+', args.description)
2095
+ if words:
2096
+ project_name = '-'.join(words[:3]).lower()
2097
+ else:
2098
+ project_name = "my-project"
2099
+ project_name = self._sanitize_project_name(project_name)
2100
+
2101
+ tech_stack = {
2102
+ "platform": args.platform,
2103
+ "frontend": args.frontend,
2104
+ "backend": args.backend,
2105
+ "domain": args.domain,
2106
+ }
2107
+
2108
+ project_dir = Path.cwd()
2109
+
2110
+ self.console.print(f"[cyan]{'=' * 60}[/cyan]")
2111
+ self.console.print("[cyan]Super Dev 完整流水线[/cyan]")
2112
+ self.console.print(f"[cyan]{'=' * 60}[/cyan]")
2113
+ self.console.print(f"[dim]项目: {project_name}[/dim]")
2114
+ self.console.print(f"[dim]技术栈: {args.platform} | {args.frontend} | {args.backend}[/dim]")
2115
+ self.console.print("")
2116
+
2117
+ try:
2118
+ # ========== 第 0 阶段: 需求增强 ==========
2119
+ self.console.print("[cyan]第 0 阶段: 需求增强 (联网 + 知识库)...[/cyan]")
2120
+ import os
2121
+
2122
+ from .orchestrator.knowledge import KnowledgeAugmenter
2123
+
2124
+ output_dir = project_dir / "output"
2125
+ output_dir.mkdir(parents=True, exist_ok=True)
2126
+
2127
+ disable_web = args.offline or (
2128
+ os.getenv("SUPER_DEV_DISABLE_WEB", "").strip().lower() in {"1", "true", "yes"}
2129
+ )
2130
+ augmenter = KnowledgeAugmenter(project_dir=project_dir, web_enabled=not disable_web)
2131
+ knowledge_bundle = augmenter.augment(
2132
+ requirement=args.description,
2133
+ domain=args.domain or "",
2134
+ )
2135
+ research_file = output_dir / f"{project_name}-research.md"
2136
+ research_file.write_text(augmenter.to_markdown(knowledge_bundle), encoding="utf-8")
2137
+
2138
+ enriched_description = knowledge_bundle.get("enriched_requirement", args.description)
2139
+ self.console.print(f" [green]✓[/green] 需求增强报告: {research_file}")
2140
+ self.console.print(
2141
+ f" [dim]本地知识 {len(knowledge_bundle.get('local_knowledge', []))} 条 | "
2142
+ f"联网结果 {len(knowledge_bundle.get('web_knowledge', []))} 条[/dim]"
2143
+ )
2144
+ self.console.print("")
2145
+
2146
+ # ========== 第 1 阶段: 生成文档 ==========
2147
+ self.console.print("[cyan]第 1 阶段: 生成专业文档...[/cyan]")
2148
+ from .creators import (
2149
+ DocumentGenerator,
2150
+ FrontendScaffoldBuilder,
2151
+ ImplementationScaffoldBuilder,
2152
+ RequirementParser,
2153
+ )
2154
+
2155
+ parser = RequirementParser()
2156
+ scenario = parser.detect_scenario(project_dir)
2157
+
2158
+ doc_generator = DocumentGenerator(
2159
+ name=project_name,
2160
+ description=enriched_description,
2161
+ platform=args.platform,
2162
+ frontend=args.frontend,
2163
+ backend=args.backend,
2164
+ domain=args.domain
2165
+ )
2166
+
2167
+ # 生成文档内容
2168
+ prd_content = doc_generator.generate_prd()
2169
+ arch_content = doc_generator.generate_architecture()
2170
+ uiux_content = doc_generator.generate_uiux()
2171
+
2172
+ # 写入文件
2173
+
2174
+ prd_file = output_dir / f"{project_name}-prd.md"
2175
+ arch_file = output_dir / f"{project_name}-architecture.md"
2176
+ uiux_file = output_dir / f"{project_name}-uiux.md"
2177
+
2178
+ prd_file.write_text(prd_content, encoding="utf-8")
2179
+ arch_file.write_text(arch_content, encoding="utf-8")
2180
+ uiux_file.write_text(uiux_content, encoding="utf-8")
2181
+
2182
+ plan_file = output_dir / f"{project_name}-execution-plan.md"
2183
+ frontend_blueprint_file = output_dir / f"{project_name}-frontend-blueprint.md"
2184
+ plan_file.write_text(doc_generator.generate_execution_plan(scenario=scenario), encoding="utf-8")
2185
+ frontend_blueprint_file.write_text(doc_generator.generate_frontend_blueprint(), encoding="utf-8")
2186
+
2187
+ self.console.print(f" [green]✓[/green] PRD: {prd_file}")
2188
+ self.console.print(f" [green]✓[/green] 架构: {arch_file}")
2189
+ self.console.print(f" [green]✓[/green] UI/UX: {uiux_file}")
2190
+ self.console.print(f" [green]✓[/green] 执行路线图: {plan_file}")
2191
+ self.console.print(f" [green]✓[/green] 前端蓝图: {frontend_blueprint_file}")
2192
+ self.console.print(f" [dim]场景识别: {scenario}[/dim]")
2193
+ self.console.print("")
2194
+
2195
+ # 保存技术栈到配置文件(供后续阶段使用)
2196
+ self._save_tech_stack_to_config(project_dir, tech_stack, args.description)
2197
+
2198
+ requirements = doc_generator.extract_requirements()
2199
+ phases = parser.build_execution_phases(scenario, requirements)
2200
+
2201
+ # ========== 第 2 阶段: 生成前端可演示骨架 ==========
2202
+ self.console.print("[cyan]第 2 阶段: 生成前端可演示骨架...[/cyan]")
2203
+ frontend_builder = FrontendScaffoldBuilder(
2204
+ project_dir=project_dir,
2205
+ name=project_name,
2206
+ description=args.description,
2207
+ frontend=args.frontend,
2208
+ )
2209
+ frontend_files = frontend_builder.generate(
2210
+ requirements=requirements,
2211
+ phases=phases,
2212
+ docs={
2213
+ "prd": str(prd_file),
2214
+ "architecture": str(arch_file),
2215
+ "uiux": str(uiux_file),
2216
+ "plan": str(plan_file),
2217
+ "frontend_blueprint": str(frontend_blueprint_file),
2218
+ },
2219
+ )
2220
+ self.console.print(f" [green]✓[/green] 页面: {frontend_files['html']}")
2221
+ self.console.print(f" [green]✓[/green] 样式: {frontend_files['css']}")
2222
+ self.console.print(f" [green]✓[/green] 脚本: {frontend_files['js']}")
2223
+ self.console.print("")
2224
+
2225
+ # ========== 第 3 阶段: 创建 Spec ==========
2226
+ self.console.print("[cyan]第 3 阶段: 创建 Spec 规范...[/cyan]")
2227
+ from .creators import SpecBuilder
2228
+
2229
+ spec_builder = SpecBuilder(
2230
+ project_dir=project_dir,
2231
+ name=project_name,
2232
+ description=args.description
2233
+ )
2234
+
2235
+ change_id = spec_builder.create_change(requirements, tech_stack, scenario=scenario)
2236
+
2237
+ self.console.print(f" [green]✓[/green] 变更 ID: {change_id}")
2238
+ self.console.print(f" [green]✓[/green] Spec: .super-dev/changes/{change_id}/")
2239
+ self.console.print("")
2240
+
2241
+ # ========== 第 4 阶段: 生成实现骨架 ==========
2242
+ scaffold_result: dict[str, list[str]] = {"frontend_files": [], "backend_files": []}
2243
+ if not args.skip_scaffold:
2244
+ self.console.print("[cyan]第 4 阶段: 生成前后端实现骨架...[/cyan]")
2245
+ implementation_builder = ImplementationScaffoldBuilder(
2246
+ project_dir=project_dir,
2247
+ name=project_name,
2248
+ frontend=args.frontend,
2249
+ backend=args.backend,
2250
+ )
2251
+ scaffold_result = implementation_builder.generate(requirements=requirements)
2252
+ self.console.print(
2253
+ f" [green]✓[/green] 前端骨架文件: {len(scaffold_result['frontend_files'])} 个"
2254
+ )
2255
+ self.console.print(
2256
+ f" [green]✓[/green] 后端骨架文件: {len(scaffold_result['backend_files'])} 个"
2257
+ )
2258
+ self.console.print("")
2259
+ else:
2260
+ self.console.print("[yellow]第 4 阶段: 生成前后端实现骨架 (跳过)[/yellow]")
2261
+ self.console.print("")
2262
+
2263
+ # ========== 第 5 阶段: 红队审查 ==========
2264
+ redteam_report = None
2265
+ if not args.skip_redteam:
2266
+ self.console.print("[cyan]第 5 阶段: 红队审查...[/cyan]")
2267
+ from .reviewers import RedTeamReviewer
2268
+
2269
+ reviewer = RedTeamReviewer(
2270
+ project_dir=project_dir,
2271
+ name=project_name,
2272
+ tech_stack=tech_stack
2273
+ )
2274
+ redteam_report = reviewer.review()
2275
+
2276
+ # 保存红队审查报告
2277
+ redteam_file = project_dir / "output" / f"{project_name}-redteam.md"
2278
+ redteam_file.parent.mkdir(parents=True, exist_ok=True)
2279
+ redteam_file.write_text(redteam_report.to_markdown(), encoding="utf-8")
2280
+
2281
+ self.console.print(f" [green]✓[/green] 安全问题: {sum(1 for i in redteam_report.security_issues if i.severity in ('critical', 'high'))} high/critical")
2282
+ self.console.print(f" [green]✓[/green] 性能问题: {sum(1 for i in redteam_report.performance_issues if i.severity in ('critical', 'high'))} high/critical")
2283
+ self.console.print(f" [green]✓[/green] 架构问题: {sum(1 for i in redteam_report.architecture_issues if i.severity in ('critical', 'high'))} high/critical")
2284
+ self.console.print(f" [green]✓[/green] 总分: {redteam_report.total_score}/100")
2285
+ self.console.print(f" [green]✓[/green] 报告: {redteam_file}")
2286
+ self.console.print("")
2287
+
2288
+ # 红队未通过时直接阻断,确保“先通过红队,再进入质量门禁”
2289
+ if not redteam_report.passed:
2290
+ self.console.print("[red]红队审查未通过,流水线终止[/red]")
2291
+ for reason in redteam_report.blocking_reasons:
2292
+ self.console.print(f" - {reason}")
2293
+ self.console.print("[dim]可使用 --skip-redteam 跳过该阶段(不推荐生产使用)[/dim]")
2294
+ return 1
2295
+ else:
2296
+ self.console.print("[yellow]第 5 阶段: 红队审查 (跳过)[/yellow]")
2297
+ self.console.print("")
2298
+
2299
+ # ========== 第 6 阶段: 质量门禁 ==========
2300
+ if not args.skip_quality_gate:
2301
+ self.console.print("[cyan]第 6 阶段: 质量门禁检查...[/cyan]")
2302
+ from .reviewers import QualityGateChecker
2303
+
2304
+ gate_checker = QualityGateChecker(
2305
+ project_dir=project_dir,
2306
+ name=project_name,
2307
+ tech_stack=tech_stack,
2308
+ scenario_override=scenario,
2309
+ threshold_override=args.quality_threshold,
2310
+ )
2311
+
2312
+ gate_result = gate_checker.check(redteam_report)
2313
+
2314
+ # 显示场景信息
2315
+ scenario_label = "0-1 新建项目" if gate_result.scenario == "0-1" else "1-N+1 增量开发"
2316
+ self.console.print(f" [dim]场景: {scenario_label}[/dim]")
2317
+
2318
+ # 保存质量门禁报告
2319
+ gate_file = project_dir / "output" / f"{project_name}-quality-gate.md"
2320
+ gate_file.parent.mkdir(parents=True, exist_ok=True)
2321
+ gate_file.write_text(gate_result.to_markdown(), encoding="utf-8")
2322
+
2323
+ status = "[green]通过[/green]" if gate_result.passed else "[red]未通过[/red]"
2324
+ self.console.print(f" {status} 总分: {gate_result.total_score}/100")
2325
+ self.console.print(f" [green]✓[/green] 报告: {gate_file}")
2326
+ self.console.print("")
2327
+
2328
+ # 质量门禁未通过,停止流水线
2329
+ if not gate_result.passed:
2330
+ self.console.print("[red]质量门禁未通过,流水线终止[/red]")
2331
+ self.console.print("[cyan]请修复以下问题后重新运行:[/cyan]")
2332
+ for failure in gate_result.critical_failures:
2333
+ self.console.print(f" - {failure}")
2334
+ return 1
2335
+ else:
2336
+ self.console.print("[yellow]第 6 阶段: 质量门禁检查 (跳过)[/yellow]")
2337
+ self.console.print("[dim]提示: 使用 --skip-quality-gate 跳过了质量门禁检查,建议后续补充测试和质量检查[/dim]")
2338
+ self.console.print("")
2339
+
2340
+ # ========== 第 7 阶段: 代码审查指南 ==========
2341
+ self.console.print("[cyan]第 7 阶段: 生成代码审查指南...[/cyan]")
2342
+ from .reviewers import CodeReviewGenerator
2343
+
2344
+ review_gen = CodeReviewGenerator(
2345
+ project_dir=project_dir,
2346
+ name=project_name,
2347
+ tech_stack=tech_stack
2348
+ )
2349
+
2350
+ review_guide = review_gen.generate()
2351
+ review_file = project_dir / "output" / f"{project_name}-code-review.md"
2352
+ review_file.write_text(review_guide, encoding="utf-8")
2353
+
2354
+ self.console.print(f" [green]✓[/green] 代码审查指南: {review_file}")
2355
+ self.console.print("")
2356
+
2357
+ # ========== 第 8 阶段: AI 提示词 ==========
2358
+ self.console.print("[cyan]第 8 阶段: 生成 AI 提示词...[/cyan]")
2359
+ from .creators import AIPromptGenerator
2360
+
2361
+ prompt_gen = AIPromptGenerator(
2362
+ project_dir=project_dir,
2363
+ name=project_name
2364
+ )
2365
+
2366
+ prompt_content = prompt_gen.generate()
2367
+ prompt_file = project_dir / "output" / f"{project_name}-ai-prompt.md"
2368
+ prompt_file.write_text(prompt_content, encoding="utf-8")
2369
+
2370
+ self.console.print(f" [green]✓[/green] AI 提示词: {prompt_file}")
2371
+ self.console.print("")
2372
+
2373
+ # ========== 第 9 阶段: CI/CD 配置 ==========
2374
+ self.console.print(f"[cyan]第 9 阶段: 生成 CI/CD 配置 ({args.cicd.upper()})...[/cyan]")
2375
+ from .deployers import CICDGenerator
2376
+
2377
+ cicd_gen = CICDGenerator(
2378
+ project_dir=project_dir,
2379
+ name=project_name,
2380
+ tech_stack=tech_stack,
2381
+ platform=self._normalize_cicd_platform(args.cicd)
2382
+ )
2383
+
2384
+ cicd_files = cicd_gen.generate()
2385
+
2386
+ for file_path, content in cicd_files.items():
2387
+ full_path = project_dir / file_path
2388
+ full_path.parent.mkdir(parents=True, exist_ok=True)
2389
+ full_path.write_text(content, encoding="utf-8")
2390
+ self.console.print(f" [green]✓[/green] {file_path}")
2391
+
2392
+ self.console.print("")
2393
+
2394
+ # ========== 第 10 阶段: 部署修复模板 ==========
2395
+ self.console.print("[cyan]第 10 阶段: 生成部署修复模板...[/cyan]")
2396
+ remediation_outputs = self._export_deploy_remediation_templates(
2397
+ project_dir=project_dir,
2398
+ cicd_platform=args.cicd,
2399
+ only_missing=True,
2400
+ )
2401
+ self.console.print(f" [green]✓[/green] 环境模板: {remediation_outputs['env_file']}")
2402
+ self.console.print(f" [green]✓[/green] 检查清单: {remediation_outputs['checklist_file']}")
2403
+ self.console.print(f" [dim]缺失变量条目: {remediation_outputs['items_count']}[/dim]")
2404
+ if remediation_outputs.get("per_platform_files"):
2405
+ self.console.print(f" [green]✓[/green] 平台拆分模板: {len(remediation_outputs['per_platform_files'])} 组")
2406
+ self.console.print("")
2407
+
2408
+ # ========== 第 11 阶段: 数据库迁移 + 项目交付包 ==========
2409
+ self.console.print("[cyan]第 11 阶段: 生成数据库迁移脚本 + 项目交付包...[/cyan]")
2410
+ from .deployers import DeliveryPackager, MigrationGenerator
2411
+
2412
+ migration_gen = MigrationGenerator(
2413
+ project_dir=project_dir,
2414
+ name=project_name,
2415
+ tech_stack=tech_stack
2416
+ )
2417
+
2418
+ migration_files = migration_gen.generate()
2419
+
2420
+ for file_path, content in migration_files.items():
2421
+ full_path = project_dir / file_path
2422
+ full_path.parent.mkdir(parents=True, exist_ok=True)
2423
+ full_path.write_text(content, encoding="utf-8")
2424
+ self.console.print(f" [green]✓[/green] {file_path}")
2425
+
2426
+ packager = DeliveryPackager(
2427
+ project_dir=project_dir,
2428
+ name=project_name,
2429
+ version=__version__,
2430
+ )
2431
+ delivery_outputs = packager.package(cicd_platform=args.cicd)
2432
+ missing_required_raw = delivery_outputs.get("missing_required_count", 0)
2433
+ missing_required_count = missing_required_raw if isinstance(missing_required_raw, int) else 0
2434
+ self.console.print(f" [green]✓[/green] 清单: {delivery_outputs['manifest_file']}")
2435
+ self.console.print(f" [green]✓[/green] 报告: {delivery_outputs['report_file']}")
2436
+ self.console.print(f" [green]✓[/green] 交付包: {delivery_outputs['archive_file']}")
2437
+ self.console.print(
2438
+ f" [dim]状态: {delivery_outputs['status']} | 缺失必需项: {missing_required_count}[/dim]"
2439
+ )
2440
+ if missing_required_count > 0:
2441
+ self.console.print("[yellow] 交付包标记为 incomplete,请补齐缺失项后重新打包[/yellow]")
2442
+ self.console.print("")
2443
+
2444
+ # ========== 完成 ==========
2445
+ self.console.print(f"[cyan]{'=' * 60}[/cyan]")
2446
+ self.console.print("[green]✓ 流水线完成![/green]")
2447
+ self.console.print(f"[cyan]{'=' * 60}[/cyan]")
2448
+ self.console.print("")
2449
+ self.console.print("[cyan]生成的文件:[/cyan]")
2450
+ self.console.print(" 文档:")
2451
+ self.console.print(f" - 需求增强报告: output/{project_name}-research.md")
2452
+ self.console.print(f" - PRD: output/{project_name}-prd.md")
2453
+ self.console.print(f" - 架构: output/{project_name}-architecture.md")
2454
+ self.console.print(f" - UI/UX: output/{project_name}-uiux.md")
2455
+ self.console.print(f" - 执行路线图: output/{project_name}-execution-plan.md")
2456
+ self.console.print(f" - 前端蓝图: output/{project_name}-frontend-blueprint.md")
2457
+ if not args.skip_redteam:
2458
+ self.console.print(f" - 红队审查: output/{project_name}-redteam.md")
2459
+ if not args.skip_quality_gate:
2460
+ self.console.print(f" - 质量门禁: output/{project_name}-quality-gate.md")
2461
+ self.console.print(f" - 代码审查: output/{project_name}-code-review.md")
2462
+ self.console.print(f" - AI 提示词: output/{project_name}-ai-prompt.md")
2463
+ self.console.print("")
2464
+ self.console.print(" 前端演示:")
2465
+ self.console.print(" - output/frontend/index.html")
2466
+ self.console.print(" - output/frontend/styles.css")
2467
+ self.console.print(" - output/frontend/app.js")
2468
+ self.console.print("")
2469
+ if not args.skip_scaffold:
2470
+ self.console.print(" 实现骨架:")
2471
+ self.console.print(" - frontend/src/*")
2472
+ self.console.print(" - backend/src/*")
2473
+ self.console.print(" - backend/API_CONTRACT.md")
2474
+ self.console.print("")
2475
+ self.console.print(" CI/CD:")
2476
+ for file_path in cicd_files.keys():
2477
+ self.console.print(f" - {file_path}")
2478
+ self.console.print("")
2479
+ self.console.print(" 部署修复模板:")
2480
+ self.console.print(f" - {Path(remediation_outputs['env_file']).name}")
2481
+ self.console.print(f" - {Path(remediation_outputs['checklist_file']).relative_to(project_dir)}")
2482
+ if remediation_outputs.get("per_platform_files"):
2483
+ for item in remediation_outputs["per_platform_files"]:
2484
+ self.console.print(
2485
+ f" - {Path(item['checklist_file']).relative_to(project_dir)}"
2486
+ )
2487
+ self.console.print(
2488
+ f" - {Path(item['env_file']).relative_to(project_dir)}"
2489
+ )
2490
+ self.console.print("")
2491
+ self.console.print(" 数据库迁移:")
2492
+ for file_path in migration_files.keys():
2493
+ self.console.print(f" - {file_path}")
2494
+ self.console.print("")
2495
+ self.console.print(" 项目交付包:")
2496
+ self.console.print(
2497
+ f" - {Path(str(delivery_outputs['manifest_file'])).relative_to(project_dir)}"
2498
+ )
2499
+ self.console.print(
2500
+ f" - {Path(str(delivery_outputs['report_file'])).relative_to(project_dir)}"
2501
+ )
2502
+ self.console.print(
2503
+ f" - {Path(str(delivery_outputs['archive_file'])).relative_to(project_dir)}"
2504
+ )
2505
+ self.console.print("")
2506
+ self.console.print("[cyan]下一步:[/cyan]")
2507
+ self.console.print(" 1. 打开 output/frontend/index.html 评审前端骨架")
2508
+ self.console.print(" 2. 对照执行路线图按阶段推进开发")
2509
+ self.console.print(" 3. 使用代码审查指南进行评审和修复")
2510
+ self.console.print(" 4. 配置 CI/CD 平台 (设置 secrets/credentials)")
2511
+ self.console.print(" 5. 运行数据库迁移脚本并推送代码触发流水线")
2512
+ self.console.print(" 6. 使用 output/delivery/* 作为对外交付包")
2513
+ self.console.print("")
2514
+
2515
+ except Exception as e:
2516
+ self.console.print(f"[red]流水线失败: {e}[/red]")
2517
+ import traceback
2518
+ self.console.print(traceback.format_exc())
2519
+ return 1
2520
+
2521
+ return 0
2522
+
2523
+ def _cmd_config(self, args) -> int:
2524
+ """配置管理"""
2525
+ config_manager = get_config_manager()
2526
+
2527
+ if not config_manager.exists():
2528
+ self.console.print("[red]未找到项目配置[/red]")
2529
+ return 1
2530
+
2531
+ if args.action == "list":
2532
+ # 列出所有配置
2533
+ config = config_manager.config
2534
+ self.console.print("[cyan]项目配置:[/cyan]")
2535
+ for key, value in config.__dict__.items():
2536
+ if not key.startswith("_"):
2537
+ self.console.print(f" {key}: {value}")
2538
+
2539
+ elif args.action == "get":
2540
+ if not args.key:
2541
+ self.console.print("[red]请指定配置键[/red]")
2542
+ return 1
2543
+ value = config_manager.get(args.key)
2544
+ self.console.print(f"{args.key}: {value}")
2545
+
2546
+ elif args.action == "set":
2547
+ if not args.key or not args.value:
2548
+ self.console.print("[red]请指定配置键和值[/red]")
2549
+ return 1
2550
+ config_manager.update(**{args.key: args.value})
2551
+ self.console.print(f"[green]✓[/green] {args.key} = {args.value}")
2552
+
2553
+ return 0
2554
+
2555
+ def _cmd_skill(self, args) -> int:
2556
+ """Skill 管理"""
2557
+ from .skills import SkillManager
2558
+
2559
+ manager = SkillManager(Path.cwd())
2560
+
2561
+ if args.action == "targets":
2562
+ self.console.print("[cyan]支持的 Skill 目标平台:[/cyan]")
2563
+ for target in manager.list_targets():
2564
+ self.console.print(f" - {target}")
2565
+ return 0
2566
+
2567
+ if args.action == "list":
2568
+ installed = manager.list_installed(args.target)
2569
+ if not installed:
2570
+ self.console.print(f"[dim]{args.target} 未安装任何 skill[/dim]")
2571
+ return 0
2572
+
2573
+ self.console.print(f"[cyan]{args.target} 已安装 skill:[/cyan]")
2574
+ for skill_name in installed:
2575
+ self.console.print(f" - {skill_name}")
2576
+ return 0
2577
+
2578
+ if args.action == "install":
2579
+ if not args.source_or_name:
2580
+ self.console.print("[red]请提供 skill 来源(目录/git/super-dev)[/red]")
2581
+ return 1
2582
+
2583
+ try:
2584
+ result = manager.install(
2585
+ source=args.source_or_name,
2586
+ target=args.target,
2587
+ name=args.name,
2588
+ force=args.force,
2589
+ )
2590
+ except Exception as e:
2591
+ self.console.print(f"[red]Skill 安装失败: {e}[/red]")
2592
+ return 1
2593
+
2594
+ self.console.print("[green]✓ Skill 安装成功[/green]")
2595
+ self.console.print(f" 名称: {result.name}")
2596
+ self.console.print(f" 目标: {result.target}")
2597
+ self.console.print(f" 路径: {result.path}")
2598
+ self.console.print(f" 来源: {result.source}")
2599
+ return 0
2600
+
2601
+ if args.action == "uninstall":
2602
+ if not args.source_or_name:
2603
+ self.console.print("[red]请提供要卸载的 skill 名称[/red]")
2604
+ return 1
2605
+
2606
+ try:
2607
+ removed_path = manager.uninstall(args.source_or_name, args.target)
2608
+ except Exception as e:
2609
+ self.console.print(f"[red]Skill 卸载失败: {e}[/red]")
2610
+ return 1
2611
+
2612
+ self.console.print("[green]✓ Skill 已卸载[/green]")
2613
+ self.console.print(f" 路径: {removed_path}")
2614
+ return 0
2615
+
2616
+ self.console.print("[yellow]未知 skill 操作[/yellow]")
2617
+ return 1
2618
+
2619
+ def _cmd_integrate(self, args) -> int:
2620
+ """多平台集成配置"""
2621
+ from .integrations import IntegrationManager
2622
+
2623
+ manager = IntegrationManager(Path.cwd())
2624
+
2625
+ if args.action == "list":
2626
+ self.console.print("[cyan]支持的集成平台:[/cyan]")
2627
+ for target in manager.list_targets():
2628
+ self.console.print(f" - {target.name}: {target.description}")
2629
+ return 0
2630
+
2631
+ if args.action == "setup":
2632
+ if args.all:
2633
+ results = manager.setup_all(force=args.force)
2634
+ self.console.print("[green]✓ 已完成所有平台集成配置[/green]")
2635
+ for platform, files in results.items():
2636
+ if not files:
2637
+ self.console.print(f" {platform}: [dim]无变更[/dim]")
2638
+ continue
2639
+ self.console.print(f" {platform}:")
2640
+ for file_path in files:
2641
+ self.console.print(f" - {file_path}")
2642
+ return 0
2643
+
2644
+ if not args.target:
2645
+ self.console.print("[red]请通过 --target 指定平台,或使用 --all[/red]")
2646
+ return 1
2647
+
2648
+ files = manager.setup(args.target, force=args.force)
2649
+ if not files:
2650
+ self.console.print("[yellow]配置已存在,无需修改(可加 --force 覆盖)[/yellow]")
2651
+ return 0
2652
+
2653
+ self.console.print("[green]✓ 集成配置已生成[/green]")
2654
+ for file_path in files:
2655
+ self.console.print(f" - {file_path}")
2656
+ return 0
2657
+
2658
+ self.console.print("[yellow]未知 integrate 操作[/yellow]")
2659
+ return 1
2660
+
2661
+ def _cmd_spec(self, args) -> int:
2662
+ """Spec-Driven Development 命令"""
2663
+ from .specs import ChangeManager, SpecGenerator, SpecManager
2664
+ from .specs.models import ChangeStatus
2665
+
2666
+ project_dir = Path.cwd()
2667
+
2668
+ if args.spec_action == "init":
2669
+ # 初始化 SDD 目录结构
2670
+ generator = SpecGenerator(project_dir)
2671
+ agents_path, project_path = generator.init_sdd()
2672
+
2673
+ self.console.print("[green]✓[/green] SDD 目录结构已初始化")
2674
+ self.console.print(" [dim].super-dev/specs/[/dim] - 当前规范")
2675
+ self.console.print(" [dim].super-dev/changes/[/dim] - 变更提案")
2676
+ self.console.print(" [dim].super-dev/archive/[/dim] - 已归档变更")
2677
+ self.console.print("")
2678
+ self.console.print("[cyan]下一步:[/cyan]")
2679
+ self.console.print(" 1. 编辑 .super-dev/project.md 填写项目上下文")
2680
+ self.console.print(" 2. 运行 'super-dev spec propose <id>' 创建变更提案")
2681
+
2682
+ elif args.spec_action == "list":
2683
+ # 列出所有变更
2684
+ manager = ChangeManager(project_dir)
2685
+ status_filter = None
2686
+ if args.status:
2687
+ status_filter = ChangeStatus(args.status)
2688
+
2689
+ changes = manager.list_changes(status=status_filter)
2690
+
2691
+ if not changes:
2692
+ self.console.print("[dim]没有找到变更[/dim]")
2693
+ return 0
2694
+
2695
+ self.console.print("[cyan]变更列表:[/cyan]")
2696
+ for change in changes:
2697
+ status_color = {
2698
+ ChangeStatus.DRAFT: "dim",
2699
+ ChangeStatus.PROPOSED: "yellow",
2700
+ ChangeStatus.APPROVED: "blue",
2701
+ ChangeStatus.IN_PROGRESS: "cyan",
2702
+ ChangeStatus.COMPLETED: "green",
2703
+ ChangeStatus.ARCHIVED: "dim",
2704
+ }.get(change.status, "white")
2705
+
2706
+ self.console.print(
2707
+ f" [{status_color}]{change.id}[/] - {change.title} "
2708
+ f"({change.status.value})"
2709
+ )
2710
+ if change.tasks:
2711
+ rate = change.completion_rate
2712
+ self.console.print(f" [dim]进度: {rate:.0f}% ({sum(1 for t in change.tasks if t.status.value == 'completed')}/{len(change.tasks)} 任务)[/dim]")
2713
+
2714
+ elif args.spec_action == "show":
2715
+ # 显示变更详情
2716
+ manager = ChangeManager(project_dir)
2717
+ loaded_change = manager.load_change(args.change_id)
2718
+
2719
+ if not loaded_change:
2720
+ self.console.print(f"[red]变更不存在: {args.change_id}[/red]")
2721
+ return 1
2722
+
2723
+ self.console.print(f"[cyan]变更详情: {loaded_change.id}[/cyan]")
2724
+ self.console.print(f" 标题: {loaded_change.title}")
2725
+ self.console.print(f" 状态: {loaded_change.status.value}")
2726
+
2727
+ if loaded_change.proposal:
2728
+ self.console.print("")
2729
+ self.console.print("[cyan]提案:[/cyan]")
2730
+ if loaded_change.proposal.description:
2731
+ self.console.print(f" {loaded_change.proposal.description}")
2732
+ if loaded_change.proposal.motivation:
2733
+ self.console.print(f"[dim]动机: {loaded_change.proposal.motivation}[/dim]")
2734
+
2735
+ if loaded_change.tasks:
2736
+ self.console.print("")
2737
+ self.console.print("[cyan]任务:[/cyan]")
2738
+ for task in loaded_change.tasks:
2739
+ checkbox = "[x]" if task.status.value == "completed" else "[ ]"
2740
+ self.console.print(f" {checkbox} {task.id}: {task.title}")
2741
+
2742
+ if loaded_change.spec_deltas:
2743
+ self.console.print("")
2744
+ self.console.print("[cyan]规范变更:[/cyan]")
2745
+ for delta in loaded_change.spec_deltas:
2746
+ self.console.print(f" - {delta.spec_name} ({delta.delta_type.value})")
2747
+
2748
+ elif args.spec_action == "propose":
2749
+ # 创建变更提案
2750
+ generator = SpecGenerator(project_dir)
2751
+ change = generator.create_change(
2752
+ change_id=args.change_id,
2753
+ title=args.title,
2754
+ description=args.description,
2755
+ motivation=args.motivation or "",
2756
+ impact=args.impact or ""
2757
+ )
2758
+
2759
+ self.console.print(f"[green]✓[/green] 变更提案已创建: {change.id}")
2760
+ self.console.print(f" [dim].super-dev/changes/{change.id}/[/dim]")
2761
+ self.console.print("")
2762
+ self.console.print("[cyan]下一步:[/cyan]")
2763
+ self.console.print(f" 1. 运行 'super-dev spec add-req {change.id} <spec> <req> <desc>' 添加需求")
2764
+ self.console.print(f" 2. 或 'super-dev spec show {change.id}' 查看详情")
2765
+
2766
+ elif args.spec_action == "add-req":
2767
+ # 向变更添加需求
2768
+ generator = SpecGenerator(project_dir)
2769
+ delta = generator.add_requirement_to_change(
2770
+ change_id=args.change_id,
2771
+ spec_name=args.spec_name,
2772
+ requirement_name=args.req_name,
2773
+ description=args.description
2774
+ )
2775
+
2776
+ self.console.print("[green]✓[/green] 需求已添加到变更")
2777
+ self.console.print(f" 规范: {delta.spec_name}")
2778
+ self.console.print(f" 需求: {args.req_name}")
2779
+
2780
+ elif args.spec_action == "archive":
2781
+ # 归档变更
2782
+ if not args.yes:
2783
+ self.console.print(f"[yellow]即将归档变更: {args.change_id}[/yellow]")
2784
+ self.console.print("[dim]这将把规范增量合并到主规范中[/dim]")
2785
+ response = input("确认? (y/N): ")
2786
+ if response.lower() != "y":
2787
+ self.console.print("[dim]已取消[/dim]")
2788
+ return 0
2789
+
2790
+ change_manager = ChangeManager(project_dir)
2791
+ spec_manager = SpecManager(project_dir)
2792
+
2793
+ try:
2794
+ change = change_manager.archive_change(args.change_id, spec_manager)
2795
+ self.console.print(f"[green]✓[/green] 变更已归档: {change.id}")
2796
+ self.console.print(f" [dim].super-dev/archive/{change.id}/[/dim]")
2797
+ except FileNotFoundError as e:
2798
+ self.console.print(f"[red]{e}[/red]")
2799
+ return 1
2800
+ except Exception as e:
2801
+ self.console.print(f"[red]归档失败: {e}[/red]")
2802
+ return 1
2803
+
2804
+ elif args.spec_action == "validate":
2805
+ # 验证规格格式
2806
+ from .specs import SpecValidator
2807
+
2808
+ validator = SpecValidator(project_dir)
2809
+
2810
+ if args.change_id:
2811
+ # 验证单个变更
2812
+ result = validator.validate_change(args.change_id)
2813
+ self.console.print(f"[cyan]验证变更: {args.change_id}[/cyan]")
2814
+ else:
2815
+ # 验证所有变更
2816
+ result = validator.validate_all()
2817
+ self.console.print("[cyan]验证所有变更[/cyan]")
2818
+
2819
+ self.console.print(result.to_summary())
2820
+
2821
+ if args.verbose or (not result.is_valid):
2822
+ # 显示详细信息
2823
+ for error in result.errors:
2824
+ self.console.print(
2825
+ f" [red]错误[/red]: {error.message}"
2826
+ )
2827
+ if error.line > 0:
2828
+ self.console.print(
2829
+ f" [dim]{error.file}:{error.line}[/dim]"
2830
+ )
2831
+
2832
+ for warning in result.warnings:
2833
+ self.console.print(
2834
+ f" [yellow]警告[/yellow]: {warning.message}"
2835
+ )
2836
+ if warning.line > 0:
2837
+ self.console.print(
2838
+ f" [dim]{warning.file}:{warning.line}[/dim]"
2839
+ )
2840
+
2841
+ return 0 if result.is_valid else 1
2842
+
2843
+ elif args.spec_action == "view":
2844
+ # 交互式仪表板
2845
+ from rich.console import Console
2846
+ from rich.panel import Panel
2847
+ from rich.table import Table
2848
+ from rich.text import Text
2849
+
2850
+ console = Console()
2851
+ change_manager = ChangeManager(project_dir)
2852
+ spec_manager = SpecManager(project_dir)
2853
+
2854
+ # 获取所有变更和规范
2855
+ changes = change_manager.list_changes()
2856
+ specs = spec_manager.list_specs()
2857
+
2858
+ # 标题
2859
+ title = Text.assemble(
2860
+ ("Super Dev ", "bold cyan"),
2861
+ ("Spec Dashboard", "bold white"),
2862
+ )
2863
+ console.print(Panel(title, padding=(0, 1)))
2864
+
2865
+ # 变更统计
2866
+ if changes:
2867
+ table = Table(title="活跃变更", show_header=True, header_style="bold magenta")
2868
+ table.add_column("ID", style="cyan", width=20)
2869
+ table.add_column("标题", style="white", width=30)
2870
+ table.add_column("状态", style="yellow", width=12)
2871
+ table.add_column("进度", style="green", width=10)
2872
+ table.add_column("任务", style="blue", width=8)
2873
+
2874
+ for change in changes:
2875
+ progress = f"{change.completion_rate:.0f}%"
2876
+ tasks = f"{sum(1 for t in change.tasks if t.status.value == 'completed')}/{len(change.tasks)}"
2877
+ table.add_row(
2878
+ change.id,
2879
+ change.title or "(无标题)",
2880
+ change.status.value,
2881
+ progress,
2882
+ tasks
2883
+ )
2884
+
2885
+ console.print(table)
2886
+ else:
2887
+ console.print("[dim]没有活跃变更[/dim]")
2888
+
2889
+ # 规范列表
2890
+ if specs:
2891
+ console.print("")
2892
+ specs_table = Table(title="当前规范", show_header=True, header_style="bold green")
2893
+ specs_table.add_column("规范名称", style="cyan", width=30)
2894
+ specs_table.add_column("文件路径", style="dim", width=50)
2895
+
2896
+ for spec_name in specs:
2897
+ spec_path = spec_manager.get_spec_path(spec_name)
2898
+ specs_table.add_row(spec_name, str(spec_path.relative_to(project_dir)))
2899
+
2900
+ console.print(specs_table)
2901
+
2902
+ # 统计信息
2903
+ console.print("")
2904
+ stats_table = Table(show_header=False, box=None)
2905
+ stats_table.add_column("指标", style="bold white")
2906
+ stats_table.add_column("数量", style="cyan")
2907
+
2908
+ stats_table.add_row("活跃变更", str(len(changes)))
2909
+ stats_table.add_row("规范文件", str(len(specs)))
2910
+ stats_table.add_row("待处理任务", str(sum(1 for c in changes for t in c.tasks if t.status.value == "pending")))
2911
+
2912
+ console.print(stats_table)
2913
+
2914
+ return 0
2915
+
2916
+ else:
2917
+ self.console.print("[yellow]请指定 SDD 命令[/yellow]")
2918
+ return 1
2919
+
2920
+ return 0
2921
+
2922
+ # ==================== 辅助方法 ====================
2923
+
2924
+ def _is_direct_requirement_input(self, argv: list[str]) -> bool:
2925
+ """判断是否为直达需求输入(非子命令模式)"""
2926
+ if not argv:
2927
+ return False
2928
+
2929
+ first = argv[0]
2930
+ if first.startswith("-"):
2931
+ return False
2932
+
2933
+ known_commands = {
2934
+ "init", "analyze", "workflow", "studio", "expert", "quality", "preview",
2935
+ "deploy", "create", "design", "spec", "pipeline", "config", "skill", "integrate",
2936
+ }
2937
+ return first not in known_commands
2938
+
2939
+ def _normalize_pipeline_frontend(self, frontend: str) -> str:
2940
+ """将 init 的前端框架映射到 pipeline 可接受值"""
2941
+ mapping = {
2942
+ "next": "react",
2943
+ "remix": "react",
2944
+ "react-vite": "react",
2945
+ "gatsby": "react",
2946
+ "nuxt": "vue",
2947
+ "vue-vite": "vue",
2948
+ "sveltekit": "svelte",
2949
+ "astro": "react",
2950
+ "solid": "react",
2951
+ "qwik": "react",
2952
+ }
2953
+ if frontend in {"react", "vue", "angular", "svelte", "none"}:
2954
+ return frontend
2955
+ return mapping.get(frontend, "react")
2956
+
2957
+ def _normalize_cicd_platform(self, value: str) -> CICDPlatform:
2958
+ valid = {"github", "gitlab", "jenkins", "azure", "bitbucket", "all"}
2959
+ normalized = (value or "github").lower()
2960
+ if normalized not in valid:
2961
+ raise ValueError(f"不支持的 CI/CD 平台: {value}")
2962
+ return cast(CICDPlatform, normalized)
2963
+
2964
+ def _sanitize_project_name(self, name: str) -> str:
2965
+ """清理项目名,避免路径非法字符"""
2966
+ import re
2967
+
2968
+ cleaned = re.sub(r"[\\/:*?\"<>|]+", "-", name.strip())
2969
+ cleaned = re.sub(r"\s+", "-", cleaned)
2970
+ cleaned = re.sub(r"-{2,}", "-", cleaned).strip("-")
2971
+ return cleaned or "my-project"
2972
+
2973
+ def _run_direct_requirement(self, description: str) -> int:
2974
+ """将 `super-dev <需求描述>` 直达路由到完整流水线"""
2975
+ if not description:
2976
+ self.console.print("[red]请提供需求描述[/red]")
2977
+ return 1
2978
+
2979
+ config_manager = get_config_manager()
2980
+ config_exists = config_manager.exists()
2981
+ config = config_manager.config
2982
+
2983
+ args = argparse.Namespace(
2984
+ description=description,
2985
+ platform=config.platform if config_exists else "web",
2986
+ frontend=self._normalize_pipeline_frontend(config.frontend) if config_exists else "react",
2987
+ backend=config.backend if config_exists else "node",
2988
+ domain=config.domain if config_exists else "",
2989
+ name=None,
2990
+ cicd="all",
2991
+ skip_redteam=False,
2992
+ skip_scaffold=False,
2993
+ skip_quality_gate=False,
2994
+ offline=False,
2995
+ quality_threshold=None,
2996
+ )
2997
+
2998
+ self.console.print("[cyan]需求直达模式:自动执行完整流水线[/cyan]")
2999
+ return self._cmd_pipeline(args)
3000
+
3001
+ def _save_tech_stack_to_config(self, project_dir: Path, tech_stack: dict, description: str) -> None:
3002
+ """保存技术栈到项目配置文件"""
3003
+ import yaml # type: ignore[import-untyped]
3004
+
3005
+ config_file = project_dir / "super-dev.yaml"
3006
+
3007
+ # 读取现有配置(如果有)
3008
+ config: dict[str, Any] = {}
3009
+ if config_file.exists():
3010
+ with open(config_file, encoding='utf-8') as f:
3011
+ config = yaml.safe_load(f) or {}
3012
+
3013
+ # 更新配置
3014
+ config['platform'] = tech_stack.get('platform', 'web')
3015
+ config['frontend'] = tech_stack.get('frontend', 'react')
3016
+ config['backend'] = tech_stack.get('backend', 'node')
3017
+ config['domain'] = tech_stack.get('domain', '')
3018
+ config['description'] = description
3019
+
3020
+ # 保存配置
3021
+ with open(config_file, 'w', encoding='utf-8') as f:
3022
+ yaml.dump(config, f, allow_unicode=True, default_flow_style=False)
3023
+
3024
+ def _export_deploy_remediation_templates(
3025
+ self,
3026
+ project_dir: Path,
3027
+ cicd_platform: str,
3028
+ only_missing: bool = True,
3029
+ ) -> dict:
3030
+ """导出部署修复模板:环境变量示例 + secrets 检查清单。"""
3031
+ env_hints_map = {
3032
+ "github": [
3033
+ {"name": "DOCKER_USERNAME", "description": "Docker 镜像仓库用户名"},
3034
+ {"name": "DOCKER_PASSWORD", "description": "Docker 镜像仓库密码/Token"},
3035
+ {"name": "KUBE_CONFIG_DEV", "description": "开发环境 Kubernetes kubeconfig"},
3036
+ {"name": "KUBE_CONFIG_PROD", "description": "生产环境 Kubernetes kubeconfig"},
3037
+ ],
3038
+ "gitlab": [
3039
+ {"name": "CI_REGISTRY_USER", "description": "GitLab Registry 用户名"},
3040
+ {"name": "CI_REGISTRY_PASSWORD", "description": "GitLab Registry 密码/Token"},
3041
+ {"name": "KUBE_CONTEXT_DEV", "description": "开发环境 K8s 上下文"},
3042
+ {"name": "KUBE_CONTEXT_PROD", "description": "生产环境 K8s 上下文"},
3043
+ ],
3044
+ "azure": [
3045
+ {"name": "AZURE_ACR_SERVICE_CONNECTION", "description": "Azure ACR 服务连接标识"},
3046
+ {"name": "AZURE_DEV_K8S_CONNECTION", "description": "开发环境 AKS 服务连接标识"},
3047
+ {"name": "AZURE_PROD_K8S_CONNECTION", "description": "生产环境 AKS 服务连接标识"},
3048
+ ],
3049
+ "bitbucket": [
3050
+ {"name": "REGISTRY_URL", "description": "镜像仓库地址"},
3051
+ {"name": "KUBE_CONFIG_DEV", "description": "开发环境 Kubernetes kubeconfig"},
3052
+ {"name": "KUBE_CONFIG_PROD", "description": "生产环境 Kubernetes kubeconfig"},
3053
+ ],
3054
+ }
3055
+ manual_hints_map = {
3056
+ "jenkins": [
3057
+ "Jenkins Credentials: docker-credentials",
3058
+ "Jenkins Credentials: kubeconfig-dev",
3059
+ "Jenkins Credentials: kubeconfig-prod",
3060
+ ]
3061
+ }
3062
+ platform_guidance_map = {
3063
+ "github": [
3064
+ "在 GitHub Settings > Secrets and variables > Actions 配置变量。",
3065
+ "按 dev/prod 环境拆分敏感变量。",
3066
+ ],
3067
+ "gitlab": [
3068
+ "在 GitLab Settings > CI/CD > Variables 中配置变量并启用 Masked。",
3069
+ ],
3070
+ "jenkins": [
3071
+ "在 Jenkins Credentials 中创建与流水线一致的凭据 ID。",
3072
+ ],
3073
+ "azure": [
3074
+ "在 Azure DevOps 配置 Service Connection 和 Variable Group。",
3075
+ ],
3076
+ "bitbucket": [
3077
+ "在 Bitbucket Repository variables 中配置密钥。",
3078
+ ],
3079
+ }
3080
+
3081
+ def _resolve_env_hints(platform: str) -> list[dict]:
3082
+ if platform == "all":
3083
+ merged = []
3084
+ seen = set()
3085
+ for item_platform in ("github", "gitlab", "azure", "bitbucket"):
3086
+ for item in env_hints_map.get(item_platform, []):
3087
+ if item["name"] in seen:
3088
+ continue
3089
+ seen.add(item["name"])
3090
+ merged.append(item)
3091
+ return merged
3092
+ return list(env_hints_map.get(platform, []))
3093
+
3094
+ def _resolve_manual_hints(platform: str) -> list[str]:
3095
+ if platform == "all":
3096
+ return list(manual_hints_map.get("jenkins", []))
3097
+ return list(manual_hints_map.get(platform, []))
3098
+
3099
+ def _resolve_guidance(platform: str) -> list[str]:
3100
+ if platform == "all":
3101
+ merged = []
3102
+ seen = set()
3103
+ for item_platform in ("github", "gitlab", "jenkins", "azure", "bitbucket"):
3104
+ for item in platform_guidance_map.get(item_platform, []):
3105
+ if item in seen:
3106
+ continue
3107
+ seen.add(item)
3108
+ merged.append(item)
3109
+ return merged
3110
+ return list(platform_guidance_map.get(platform, []))
3111
+
3112
+ def _collect_items(platform: str) -> list[dict]:
3113
+ env_hints = _resolve_env_hints(platform)
3114
+ items = []
3115
+ for item in env_hints:
3116
+ name = item["name"]
3117
+ present = bool(os.getenv(name, "").strip())
3118
+ if only_missing and present:
3119
+ continue
3120
+ items.append(
3121
+ {
3122
+ "name": name,
3123
+ "description": item["description"],
3124
+ "present": present,
3125
+ "template": f'{name}="<value>"',
3126
+ }
3127
+ )
3128
+ return items
3129
+
3130
+ def _write_env_example(file_path: Path, platform: str, items: list[dict]) -> None:
3131
+ lines = [
3132
+ "# Super Dev Deployment Environment Template",
3133
+ f"# Platform: {platform}",
3134
+ f"# only_missing: {str(only_missing).lower()}",
3135
+ "",
3136
+ ]
3137
+ if not items:
3138
+ lines.append("# No variables to export for current filter.")
3139
+ else:
3140
+ for item in items:
3141
+ lines.append(f"# {item['description']}")
3142
+ lines.append(item["template"])
3143
+ lines.append("")
3144
+ file_path.parent.mkdir(parents=True, exist_ok=True)
3145
+ file_path.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
3146
+
3147
+ def _write_checklist(
3148
+ file_path: Path,
3149
+ platform: str,
3150
+ items: list[dict],
3151
+ manual_hints: list[str],
3152
+ platform_guidance: list[str],
3153
+ ) -> None:
3154
+ lines = [
3155
+ "# Deploy Remediation Checklist",
3156
+ "",
3157
+ f"- Platform: `{platform}`",
3158
+ f"- only_missing: `{str(only_missing).lower()}`",
3159
+ "",
3160
+ "## Environment Variables",
3161
+ "",
3162
+ "| Name | Status | Description | Template |",
3163
+ "|:---|:---:|:---|:---|",
3164
+ ]
3165
+ if items:
3166
+ for item in items:
3167
+ status = "present" if item["present"] else "missing"
3168
+ lines.append(
3169
+ f"| `{item['name']}` | `{status}` | {item['description']} | `{item['template']}` |"
3170
+ )
3171
+ else:
3172
+ lines.append("| - | - | No variables in current filter | - |")
3173
+
3174
+ lines.extend(["", "## Platform Guidance", ""])
3175
+ if platform_guidance:
3176
+ lines.extend([f"- {line}" for line in platform_guidance])
3177
+ else:
3178
+ lines.append("- No guidance available.")
3179
+
3180
+ lines.extend(["", "## Manual Requirements", ""])
3181
+ if manual_hints:
3182
+ lines.extend([f"- {line}" for line in manual_hints])
3183
+ else:
3184
+ lines.append("- No manual requirements.")
3185
+
3186
+ file_path.parent.mkdir(parents=True, exist_ok=True)
3187
+ file_path.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
3188
+
3189
+ output_dir = project_dir / "output" / "deploy"
3190
+ output_dir.mkdir(parents=True, exist_ok=True)
3191
+
3192
+ aggregate_items = _collect_items(cicd_platform)
3193
+ env_path = project_dir / ".env.deploy.example"
3194
+ checklist_path = output_dir / f"{cicd_platform}-secrets-checklist.md"
3195
+ _write_env_example(env_path, cicd_platform, aggregate_items)
3196
+ _write_checklist(
3197
+ checklist_path,
3198
+ cicd_platform,
3199
+ aggregate_items,
3200
+ _resolve_manual_hints(cicd_platform),
3201
+ _resolve_guidance(cicd_platform),
3202
+ )
3203
+
3204
+ per_platform_files = []
3205
+ if cicd_platform == "all":
3206
+ platform_dir = output_dir / "platforms"
3207
+ for platform in ("github", "gitlab", "jenkins", "azure", "bitbucket"):
3208
+ platform_items = _collect_items(platform)
3209
+ platform_env = platform_dir / f".env.deploy.{platform}.example"
3210
+ platform_checklist = platform_dir / f"{platform}-secrets-checklist.md"
3211
+ _write_env_example(platform_env, platform, platform_items)
3212
+ _write_checklist(
3213
+ platform_checklist,
3214
+ platform,
3215
+ platform_items,
3216
+ _resolve_manual_hints(platform),
3217
+ _resolve_guidance(platform),
3218
+ )
3219
+ per_platform_files.append(
3220
+ {
3221
+ "platform": platform,
3222
+ "env_file": str(platform_env),
3223
+ "checklist_file": str(platform_checklist),
3224
+ "items_count": len(platform_items),
3225
+ }
3226
+ )
3227
+
3228
+ return {
3229
+ "env_file": str(env_path),
3230
+ "checklist_file": str(checklist_path),
3231
+ "items_count": len(aggregate_items),
3232
+ "per_platform_files": per_platform_files,
3233
+ }
3234
+
3235
+ def _print_banner(self) -> None:
3236
+ """打印欢迎横幅"""
3237
+ if self.console:
3238
+ banner = Text()
3239
+ banner.append("Super Dev ", style="bold cyan")
3240
+ banner.append(f"v{__version__}\n", style="dim")
3241
+ banner.append(__description__, style="white")
3242
+
3243
+ self.console.print(Panel.fit(
3244
+ banner,
3245
+ title="Super Dev",
3246
+ border_style="cyan"
3247
+ ))
3248
+
3249
+
3250
+ def main() -> int:
3251
+ """主入口"""
3252
+ cli = SuperDevCLI()
3253
+ return cli.run()
3254
+
3255
+
3256
+ if __name__ == "__main__":
3257
+ sys.exit(main())