super-dev 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. super_dev/__init__.py +11 -0
  2. super_dev/analyzer/__init__.py +34 -0
  3. super_dev/analyzer/analyzer.py +440 -0
  4. super_dev/analyzer/detectors.py +511 -0
  5. super_dev/analyzer/models.py +285 -0
  6. super_dev/cli.py +3257 -0
  7. super_dev/config/__init__.py +11 -0
  8. super_dev/config/frontend.py +557 -0
  9. super_dev/config/manager.py +281 -0
  10. super_dev/creators/__init__.py +26 -0
  11. super_dev/creators/creator.py +134 -0
  12. super_dev/creators/document_generator.py +2473 -0
  13. super_dev/creators/frontend_builder.py +371 -0
  14. super_dev/creators/implementation_builder.py +789 -0
  15. super_dev/creators/prompt_generator.py +289 -0
  16. super_dev/creators/requirement_parser.py +354 -0
  17. super_dev/creators/spec_builder.py +195 -0
  18. super_dev/deployers/__init__.py +20 -0
  19. super_dev/deployers/cicd.py +1269 -0
  20. super_dev/deployers/delivery.py +229 -0
  21. super_dev/deployers/migration.py +1032 -0
  22. super_dev/design/__init__.py +74 -0
  23. super_dev/design/aesthetics.py +530 -0
  24. super_dev/design/charts.py +396 -0
  25. super_dev/design/codegen.py +379 -0
  26. super_dev/design/engine.py +528 -0
  27. super_dev/design/generator.py +395 -0
  28. super_dev/design/landing.py +422 -0
  29. super_dev/design/tech_stack.py +524 -0
  30. super_dev/design/tokens.py +269 -0
  31. super_dev/design/ux_guide.py +391 -0
  32. super_dev/exceptions.py +119 -0
  33. super_dev/experts/__init__.py +19 -0
  34. super_dev/experts/service.py +161 -0
  35. super_dev/integrations/__init__.py +7 -0
  36. super_dev/integrations/manager.py +264 -0
  37. super_dev/orchestrator/__init__.py +12 -0
  38. super_dev/orchestrator/engine.py +958 -0
  39. super_dev/orchestrator/experts.py +423 -0
  40. super_dev/orchestrator/knowledge.py +352 -0
  41. super_dev/orchestrator/quality.py +356 -0
  42. super_dev/reviewers/__init__.py +17 -0
  43. super_dev/reviewers/code_review.py +471 -0
  44. super_dev/reviewers/quality_gate.py +964 -0
  45. super_dev/reviewers/redteam.py +881 -0
  46. super_dev/skills/__init__.py +7 -0
  47. super_dev/skills/manager.py +307 -0
  48. super_dev/specs/__init__.py +44 -0
  49. super_dev/specs/generator.py +264 -0
  50. super_dev/specs/manager.py +428 -0
  51. super_dev/specs/models.py +348 -0
  52. super_dev/specs/validator.py +415 -0
  53. super_dev/utils/__init__.py +11 -0
  54. super_dev/utils/logger.py +133 -0
  55. super_dev/web/api.py +1402 -0
  56. super_dev-2.0.0.dist-info/METADATA +252 -0
  57. super_dev-2.0.0.dist-info/RECORD +61 -0
  58. super_dev-2.0.0.dist-info/WHEEL +5 -0
  59. super_dev-2.0.0.dist-info/entry_points.txt +2 -0
  60. super_dev-2.0.0.dist-info/licenses/LICENSE +21 -0
  61. super_dev-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,789 @@
1
+ """
2
+ 实现骨架生成器
3
+
4
+ 根据结构化需求生成前端/后端代码骨架,帮助从文档快速进入实现阶段。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import re
11
+ from pathlib import Path
12
+
13
+
14
+ class ImplementationScaffoldBuilder:
15
+ """项目实现骨架生成器"""
16
+
17
+ def __init__(
18
+ self,
19
+ project_dir: Path,
20
+ name: str,
21
+ frontend: str,
22
+ backend: str,
23
+ ):
24
+ self.project_dir = Path(project_dir).resolve()
25
+ self.name = name
26
+ self.frontend = frontend
27
+ self.backend = backend
28
+ self.package_name = self._sanitize_package_name(name)
29
+
30
+ def _sanitize_package_name(self, value: str) -> str:
31
+ cleaned = re.sub(r"[^a-z0-9-]+", "-", value.lower()).strip("-")
32
+ cleaned = re.sub(r"-{2,}", "-", cleaned)
33
+ return cleaned or "super-dev-app"
34
+
35
+ def generate(self, requirements: list[dict]) -> dict:
36
+ """生成前后端实现骨架"""
37
+ result: dict[str, list[str]] = {
38
+ "frontend_files": [],
39
+ "backend_files": [],
40
+ }
41
+
42
+ if self.frontend != "none":
43
+ result["frontend_files"] = self._generate_frontend(requirements)
44
+
45
+ if self.backend != "none":
46
+ result["backend_files"] = self._generate_backend(requirements)
47
+
48
+ return result
49
+
50
+ def _generate_frontend(self, requirements: list[dict]) -> list[str]:
51
+ frontend_dir = self.project_dir / "frontend"
52
+ src_dir = frontend_dir / "src"
53
+ modules_dir = src_dir / "modules"
54
+ modules_dir.mkdir(parents=True, exist_ok=True)
55
+
56
+ module_names = [req.get("spec_name", "core") for req in requirements]
57
+ unique_modules = []
58
+ for module_name in module_names:
59
+ if module_name not in unique_modules:
60
+ unique_modules.append(module_name)
61
+
62
+ files: list[str] = []
63
+
64
+ frontend_kind = self.frontend.lower()
65
+ if frontend_kind == "react":
66
+ files.extend(self._generate_react_frontend(frontend_dir, src_dir, modules_dir, unique_modules))
67
+ elif frontend_kind == "vue":
68
+ files.extend(self._generate_vue_frontend(frontend_dir, src_dir, modules_dir, unique_modules))
69
+ elif frontend_kind == "svelte":
70
+ files.extend(self._generate_svelte_frontend(frontend_dir, src_dir, modules_dir, unique_modules))
71
+ elif frontend_kind == "angular":
72
+ files.extend(self._generate_angular_frontend(frontend_dir, src_dir, unique_modules))
73
+ else:
74
+ # 默认回落到 React
75
+ files.extend(self._generate_react_frontend(frontend_dir, src_dir, modules_dir, unique_modules))
76
+
77
+ readme_file = frontend_dir / "README.md"
78
+ readme_file.write_text(
79
+ (
80
+ "# Frontend Scaffold\n\n"
81
+ "## Run\n\n"
82
+ "```bash\n"
83
+ "npm install\n"
84
+ "npm run dev\n"
85
+ "```\n"
86
+ ),
87
+ encoding="utf-8",
88
+ )
89
+ files.append(str(readme_file))
90
+
91
+ return files
92
+
93
+ def _generate_backend(self, requirements: list[dict]) -> list[str]:
94
+ backend_dir = self.project_dir / "backend"
95
+ src_dir = backend_dir / "src"
96
+ src_dir.mkdir(parents=True, exist_ok=True)
97
+
98
+ module_names = [req.get("spec_name", "core") for req in requirements]
99
+ unique_modules = []
100
+ for module_name in module_names:
101
+ if module_name not in unique_modules:
102
+ unique_modules.append(module_name)
103
+
104
+ files: list[str] = []
105
+ if self.backend == "python":
106
+ app_file = src_dir / "app.py"
107
+ app_file.write_text(self._build_fastapi_app(unique_modules), encoding="utf-8")
108
+ files.append(str(app_file))
109
+
110
+ requirements_file = backend_dir / "requirements.txt"
111
+ requirements_file.write_text(
112
+ "fastapi>=0.110.0\nuvicorn>=0.27.0\npytest>=7.0.0\n",
113
+ encoding="utf-8",
114
+ )
115
+ files.append(str(requirements_file))
116
+
117
+ tests_dir = backend_dir / "tests"
118
+ tests_dir.mkdir(parents=True, exist_ok=True)
119
+ smoke_test = tests_dir / "test_smoke.py"
120
+ smoke_test.write_text(
121
+ (
122
+ "def test_backend_scaffold_smoke() -> None:\n"
123
+ " assert True\n"
124
+ ),
125
+ encoding="utf-8",
126
+ )
127
+ files.append(str(smoke_test))
128
+ elif self.backend == "node":
129
+ package_json = {
130
+ "name": f"{self.package_name}-backend",
131
+ "version": "0.1.0",
132
+ "private": True,
133
+ "scripts": {
134
+ "dev": "node src/app.js",
135
+ "start": "node src/app.js",
136
+ "test": "node --test",
137
+ },
138
+ "dependencies": {
139
+ "express": "^4.19.0",
140
+ },
141
+ }
142
+ package_file = backend_dir / "package.json"
143
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
144
+ files.append(str(package_file))
145
+
146
+ app_file = src_dir / "app.js"
147
+ app_file.write_text(self._build_express_app(unique_modules), encoding="utf-8")
148
+ files.append(str(app_file))
149
+
150
+ test_file = src_dir / "app.test.js"
151
+ test_file.write_text(
152
+ (
153
+ "const test = require('node:test');\n"
154
+ "const assert = require('node:assert/strict');\n\n"
155
+ "test('backend scaffold smoke', () => {\n"
156
+ " assert.equal(1 + 1, 2);\n"
157
+ "});\n"
158
+ ),
159
+ encoding="utf-8",
160
+ )
161
+ files.append(str(test_file))
162
+ elif self.backend == "go":
163
+ app_file = src_dir / "main.go"
164
+ app_file.write_text(self._build_go_app(unique_modules), encoding="utf-8")
165
+ files.append(str(app_file))
166
+ elif self.backend == "java":
167
+ app_file = backend_dir / "src" / "main" / "java" / "com" / "superdev" / "Application.java"
168
+ app_file.parent.mkdir(parents=True, exist_ok=True)
169
+ app_file.write_text(self._build_java_app(), encoding="utf-8")
170
+ files.append(str(app_file))
171
+
172
+ pom_file = backend_dir / "pom.xml"
173
+ pom_file.write_text(self._build_java_pom(), encoding="utf-8")
174
+ files.append(str(pom_file))
175
+ else:
176
+ # 未知后端类型,回落到 node
177
+ package_json = {
178
+ "name": f"{self.package_name}-backend",
179
+ "version": "0.1.0",
180
+ "private": True,
181
+ "scripts": {"dev": "node src/app.js", "start": "node src/app.js", "test": "node --test"},
182
+ "dependencies": {"express": "^4.19.0"},
183
+ }
184
+ package_file = backend_dir / "package.json"
185
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
186
+ files.append(str(package_file))
187
+
188
+ app_file = src_dir / "app.js"
189
+ app_file.write_text(self._build_express_app(unique_modules), encoding="utf-8")
190
+ files.append(str(app_file))
191
+
192
+ test_file = src_dir / "app.test.js"
193
+ test_file.write_text(
194
+ (
195
+ "const test = require('node:test');\n"
196
+ "const assert = require('node:assert/strict');\n\n"
197
+ "test('backend scaffold smoke', () => {\n"
198
+ " assert.equal(1 + 1, 2);\n"
199
+ "});\n"
200
+ ),
201
+ encoding="utf-8",
202
+ )
203
+ files.append(str(test_file))
204
+
205
+ api_contract = backend_dir / "API_CONTRACT.md"
206
+ api_contract.write_text(self._build_api_contract(unique_modules), encoding="utf-8")
207
+ files.append(str(api_contract))
208
+
209
+ return files
210
+
211
+ def _generate_react_frontend(
212
+ self,
213
+ frontend_dir: Path,
214
+ src_dir: Path,
215
+ modules_dir: Path,
216
+ unique_modules: list[str],
217
+ ) -> list[str]:
218
+ files: list[str] = []
219
+ package_json = {
220
+ "name": f"{self.package_name}-frontend",
221
+ "version": "0.1.0",
222
+ "private": True,
223
+ "scripts": {"dev": "vite", "build": "vite build", "preview": "vite preview"},
224
+ "dependencies": {"react": "^18.3.0", "react-dom": "^18.3.0"},
225
+ "devDependencies": {
226
+ "vite": "^5.0.0",
227
+ "@types/react": "^18.2.0",
228
+ "@types/react-dom": "^18.2.0",
229
+ "typescript": "^5.0.0",
230
+ },
231
+ }
232
+ package_file = frontend_dir / "package.json"
233
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
234
+ files.append(str(package_file))
235
+
236
+ app_file = src_dir / "App.tsx"
237
+ app_file.write_text(self._build_react_app(unique_modules), encoding="utf-8")
238
+ files.append(str(app_file))
239
+
240
+ main_file = src_dir / "main.tsx"
241
+ main_file.write_text(
242
+ (
243
+ "import React from 'react';\n"
244
+ "import ReactDOM from 'react-dom/client';\n"
245
+ "import App from './App';\n\n"
246
+ "ReactDOM.createRoot(document.getElementById('root')!).render(\n"
247
+ " <React.StrictMode>\n"
248
+ " <App />\n"
249
+ " </React.StrictMode>\n"
250
+ ");\n"
251
+ ),
252
+ encoding="utf-8",
253
+ )
254
+ files.append(str(main_file))
255
+
256
+ index_file = frontend_dir / "index.html"
257
+ index_file.write_text(self._build_index_html("root", "/src/main.tsx"), encoding="utf-8")
258
+ files.append(str(index_file))
259
+
260
+ for module_name in unique_modules:
261
+ module_file = modules_dir / f"{module_name}.tsx"
262
+ module_file.write_text(self._build_module_component(module_name), encoding="utf-8")
263
+ files.append(str(module_file))
264
+
265
+ return files
266
+
267
+ def _generate_vue_frontend(
268
+ self,
269
+ frontend_dir: Path,
270
+ src_dir: Path,
271
+ modules_dir: Path,
272
+ unique_modules: list[str],
273
+ ) -> list[str]:
274
+ files: list[str] = []
275
+ package_json = {
276
+ "name": f"{self.package_name}-frontend",
277
+ "version": "0.1.0",
278
+ "private": True,
279
+ "scripts": {"dev": "vite", "build": "vite build", "preview": "vite preview"},
280
+ "dependencies": {"vue": "^3.4.0"},
281
+ "devDependencies": {"vite": "^5.0.0", "@vitejs/plugin-vue": "^5.0.0"},
282
+ }
283
+ package_file = frontend_dir / "package.json"
284
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
285
+ files.append(str(package_file))
286
+
287
+ vite_file = frontend_dir / "vite.config.js"
288
+ vite_file.write_text(
289
+ (
290
+ "import { defineConfig } from 'vite';\n"
291
+ "import vue from '@vitejs/plugin-vue';\n\n"
292
+ "export default defineConfig({\n"
293
+ " plugins: [vue()],\n"
294
+ "});\n"
295
+ ),
296
+ encoding="utf-8",
297
+ )
298
+ files.append(str(vite_file))
299
+
300
+ app_file = src_dir / "App.vue"
301
+ app_file.write_text(self._build_vue_app(unique_modules), encoding="utf-8")
302
+ files.append(str(app_file))
303
+
304
+ main_file = src_dir / "main.js"
305
+ main_file.write_text(
306
+ (
307
+ "import { createApp } from 'vue';\n"
308
+ "import App from './App.vue';\n\n"
309
+ "createApp(App).mount('#app');\n"
310
+ ),
311
+ encoding="utf-8",
312
+ )
313
+ files.append(str(main_file))
314
+
315
+ index_file = frontend_dir / "index.html"
316
+ index_file.write_text(self._build_index_html("app", "/src/main.js"), encoding="utf-8")
317
+ files.append(str(index_file))
318
+
319
+ for module_name in unique_modules:
320
+ module_file = modules_dir / f"{module_name}.vue"
321
+ module_file.write_text(self._build_vue_module(module_name), encoding="utf-8")
322
+ files.append(str(module_file))
323
+
324
+ return files
325
+
326
+ def _generate_svelte_frontend(
327
+ self,
328
+ frontend_dir: Path,
329
+ src_dir: Path,
330
+ modules_dir: Path,
331
+ unique_modules: list[str],
332
+ ) -> list[str]:
333
+ files: list[str] = []
334
+ package_json = {
335
+ "name": f"{self.package_name}-frontend",
336
+ "version": "0.1.0",
337
+ "private": True,
338
+ "scripts": {"dev": "vite", "build": "vite build", "preview": "vite preview"},
339
+ "dependencies": {"svelte": "^4.2.0"},
340
+ "devDependencies": {"vite": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0"},
341
+ }
342
+ package_file = frontend_dir / "package.json"
343
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
344
+ files.append(str(package_file))
345
+
346
+ vite_file = frontend_dir / "vite.config.js"
347
+ vite_file.write_text(
348
+ (
349
+ "import { defineConfig } from 'vite';\n"
350
+ "import { svelte } from '@sveltejs/vite-plugin-svelte';\n\n"
351
+ "export default defineConfig({\n"
352
+ " plugins: [svelte()],\n"
353
+ "});\n"
354
+ ),
355
+ encoding="utf-8",
356
+ )
357
+ files.append(str(vite_file))
358
+
359
+ app_file = src_dir / "App.svelte"
360
+ app_file.write_text(self._build_svelte_app(unique_modules), encoding="utf-8")
361
+ files.append(str(app_file))
362
+
363
+ main_file = src_dir / "main.js"
364
+ main_file.write_text(
365
+ (
366
+ "import App from './App.svelte';\n\n"
367
+ "const app = new App({\n"
368
+ " target: document.getElementById('app')\n"
369
+ "});\n\n"
370
+ "export default app;\n"
371
+ ),
372
+ encoding="utf-8",
373
+ )
374
+ files.append(str(main_file))
375
+
376
+ index_file = frontend_dir / "index.html"
377
+ index_file.write_text(self._build_index_html("app", "/src/main.js"), encoding="utf-8")
378
+ files.append(str(index_file))
379
+
380
+ for module_name in unique_modules:
381
+ module_file = modules_dir / f"{module_name}.svelte"
382
+ module_file.write_text(self._build_svelte_module(module_name), encoding="utf-8")
383
+ files.append(str(module_file))
384
+
385
+ return files
386
+
387
+ def _generate_angular_frontend(
388
+ self,
389
+ frontend_dir: Path,
390
+ src_dir: Path,
391
+ unique_modules: list[str],
392
+ ) -> list[str]:
393
+ files: list[str] = []
394
+ package_json = {
395
+ "name": f"{self.package_name}-frontend",
396
+ "version": "0.1.0",
397
+ "private": True,
398
+ "scripts": {
399
+ "start": "ng serve",
400
+ "build": "ng build",
401
+ "test": "ng test",
402
+ },
403
+ "dependencies": {
404
+ "@angular/animations": "^17.0.0",
405
+ "@angular/common": "^17.0.0",
406
+ "@angular/compiler": "^17.0.0",
407
+ "@angular/core": "^17.0.0",
408
+ "@angular/forms": "^17.0.0",
409
+ "@angular/platform-browser": "^17.0.0",
410
+ "@angular/platform-browser-dynamic": "^17.0.0",
411
+ "@angular/router": "^17.0.0",
412
+ "rxjs": "^7.8.0",
413
+ "zone.js": "^0.14.0",
414
+ },
415
+ "devDependencies": {
416
+ "@angular/cli": "^17.0.0",
417
+ "@angular/compiler-cli": "^17.0.0",
418
+ "typescript": "^5.0.0",
419
+ },
420
+ }
421
+ package_file = frontend_dir / "package.json"
422
+ package_file.write_text(json.dumps(package_json, indent=2, ensure_ascii=False), encoding="utf-8")
423
+ files.append(str(package_file))
424
+
425
+ app_dir = src_dir / "app"
426
+ app_dir.mkdir(parents=True, exist_ok=True)
427
+
428
+ component_file = app_dir / "app.component.ts"
429
+ component_file.write_text(self._build_angular_component(unique_modules), encoding="utf-8")
430
+ files.append(str(component_file))
431
+
432
+ module_file = app_dir / "app.module.ts"
433
+ module_file.write_text(
434
+ (
435
+ "import { NgModule } from '@angular/core';\n"
436
+ "import { BrowserModule } from '@angular/platform-browser';\n"
437
+ "import { AppComponent } from './app.component';\n\n"
438
+ "@NgModule({\n"
439
+ " declarations: [AppComponent],\n"
440
+ " imports: [BrowserModule],\n"
441
+ " bootstrap: [AppComponent],\n"
442
+ "})\n"
443
+ "export class AppModule {}\n"
444
+ ),
445
+ encoding="utf-8",
446
+ )
447
+ files.append(str(module_file))
448
+
449
+ main_file = src_dir / "main.ts"
450
+ main_file.write_text(
451
+ (
452
+ "import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';\n"
453
+ "import { AppModule } from './app/app.module';\n\n"
454
+ "platformBrowserDynamic()\n"
455
+ " .bootstrapModule(AppModule)\n"
456
+ " .catch(err => console.error(err));\n"
457
+ ),
458
+ encoding="utf-8",
459
+ )
460
+ files.append(str(main_file))
461
+
462
+ index_file = frontend_dir / "index.html"
463
+ index_file.write_text(self._build_index_html("app-root", "/src/main.ts"), encoding="utf-8")
464
+ files.append(str(index_file))
465
+
466
+ return files
467
+
468
+ def _build_react_app(self, modules: list[str]) -> str:
469
+ imports = [f"import {self._to_component(module)} from './modules/{module}';" for module in modules]
470
+ cards = [
471
+ (
472
+ f" <section style={{border: '1px solid #e5e7eb', borderRadius: 12, padding: 16}}>\n"
473
+ f" <h3>{self._to_component(module)}</h3>\n"
474
+ f" <{self._to_component(module)} />\n"
475
+ " </section>"
476
+ )
477
+ for module in modules
478
+ ]
479
+
480
+ return (
481
+ "import React from 'react';\n"
482
+ + "\n".join(imports)
483
+ + "\n\n"
484
+ "export default function App() {\n"
485
+ " return (\n"
486
+ " <main style={{maxWidth: 960, margin: '40px auto', fontFamily: 'Arial, sans-serif'}}>\n"
487
+ f" <h1>{self.name} 实现骨架</h1>\n"
488
+ " <p>该页面由 Super Dev 自动生成,按模块分区承接需求实现。</p>\n"
489
+ " <div style={{display: 'grid', gap: 12}}>\n"
490
+ + "\n".join(cards)
491
+ + "\n"
492
+ " </div>\n"
493
+ " </main>\n"
494
+ " );\n"
495
+ "}\n"
496
+ )
497
+
498
+ def _build_module_component(self, module_name: str) -> str:
499
+ component = self._to_component(module_name)
500
+ return (
501
+ "import React from 'react';\n\n"
502
+ f"export default function {component}() {{\n"
503
+ " return (\n"
504
+ " <div>\n"
505
+ f" <p>{module_name} 模块初始骨架已创建,可在此实现业务逻辑。</p>\n"
506
+ " </div>\n"
507
+ " );\n"
508
+ "}\n"
509
+ )
510
+
511
+ def _build_express_app(self, modules: list[str]) -> str:
512
+ routes = []
513
+ for module_name in modules:
514
+ routes.append(
515
+
516
+ f"app.get('/api/{module_name}', (req, res) => {{\n"
517
+ " res.json({\n"
518
+ f" module: '{module_name}',\n"
519
+ " status: 'todo',\n"
520
+ " message: 'Module scaffold created by Super Dev'\n"
521
+ " });\n"
522
+ "});"
523
+
524
+ )
525
+
526
+ return (
527
+ "const express = require('express');\n\n"
528
+ "const app = express();\n"
529
+ "app.use(express.json());\n\n"
530
+ "app.get('/health', (_req, res) => {\n"
531
+ " res.json({ status: 'ok' });\n"
532
+ "});\n\n"
533
+ + "\n\n".join(routes)
534
+ + "\n\n"
535
+ "const port = process.env.PORT || 3001;\n"
536
+ "app.listen(port, () => {\n"
537
+ " console.log(`Backend scaffold is running on http://localhost:${port}`);\n"
538
+ "});\n"
539
+ )
540
+
541
+ def _build_fastapi_app(self, modules: list[str]) -> str:
542
+ route_blocks = []
543
+ for module_name in modules:
544
+ function_name = self._safe_identifier(module_name)
545
+ route_segment = self._safe_route_segment(module_name)
546
+ route_blocks.append(
547
+
548
+ f"@app.get('/api/{route_segment}')\n"
549
+ f"def get_{function_name}():\n"
550
+ " return {\n"
551
+ f" 'module': '{module_name}',\n"
552
+ " 'status': 'todo',\n"
553
+ " 'message': 'Module scaffold created by Super Dev'\n"
554
+ " }\n"
555
+
556
+ )
557
+
558
+ return (
559
+ "from fastapi import FastAPI\n\n"
560
+ "app = FastAPI(title='Super Dev Backend Scaffold')\n\n"
561
+ "@app.get('/health')\n"
562
+ "def health():\n"
563
+ " return {'status': 'ok'}\n\n"
564
+ + "\n\n".join(route_blocks)
565
+ + "\n"
566
+ )
567
+
568
+ def _build_api_contract(self, modules: list[str]) -> str:
569
+ lines = [
570
+ "# API Contract (Scaffold)",
571
+ "",
572
+ "以下接口由 Super Dev 根据需求模块生成,后续请补充字段和鉴权细节。",
573
+ "",
574
+ "| Module | Method | Path | Purpose |",
575
+ "|:---|:---|:---|:---|",
576
+ ]
577
+ for module_name in modules:
578
+ route_segment = self._safe_route_segment(module_name)
579
+ lines.append(f"| {module_name} | GET | /api/{route_segment} | 获取 {module_name} 模块初始数据 |")
580
+ lines.append("")
581
+ return "\n".join(lines)
582
+
583
+ def _build_go_app(self, modules: list[str]) -> str:
584
+ handlers = []
585
+ for module_name in modules:
586
+ handler = self._safe_identifier(module_name)
587
+ handlers.append(
588
+
589
+ f"func {handler}Handler(w http.ResponseWriter, _ *http.Request) {{\n"
590
+ " w.Header().Set(\"Content-Type\", \"application/json\")\n"
591
+ f" w.Write([]byte(`{{\"module\":\"{module_name}\",\"status\":\"todo\"}}`))\n"
592
+ "}\n"
593
+
594
+ )
595
+
596
+ routes = [f" http.HandleFunc(\"/api/{self._safe_route_segment(module_name)}\", {self._safe_identifier(module_name)}Handler)" for module_name in modules]
597
+
598
+ return (
599
+ "package main\n\n"
600
+ "import (\n"
601
+ " \"log\"\n"
602
+ " \"net/http\"\n"
603
+ ")\n\n"
604
+ + "\n".join(handlers)
605
+ + "\n"
606
+ "func healthHandler(w http.ResponseWriter, _ *http.Request) {\n"
607
+ " w.Header().Set(\"Content-Type\", \"application/json\")\n"
608
+ " w.Write([]byte(`{\"status\":\"ok\"}`))\n"
609
+ "}\n\n"
610
+ "func main() {\n"
611
+ " http.HandleFunc(\"/health\", healthHandler)\n"
612
+ + "\n".join(routes)
613
+ + "\n"
614
+ " log.Println(\"Backend scaffold running on :3001\")\n"
615
+ " log.Fatal(http.ListenAndServe(\":3001\", nil))\n"
616
+ "}\n"
617
+ )
618
+
619
+ def _build_java_app(self) -> str:
620
+ return (
621
+ "package com.superdev;\n\n"
622
+ "import org.springframework.boot.SpringApplication;\n"
623
+ "import org.springframework.boot.autoconfigure.SpringBootApplication;\n\n"
624
+ "@SpringBootApplication\n"
625
+ "public class Application {\n"
626
+ " public static void main(String[] args) {\n"
627
+ " SpringApplication.run(Application.class, args);\n"
628
+ " }\n"
629
+ "}\n"
630
+ )
631
+
632
+ def _build_java_pom(self) -> str:
633
+ return (
634
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" "
635
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
636
+ "xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 "
637
+ "http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
638
+ " <modelVersion>4.0.0</modelVersion>\n"
639
+ " <groupId>com.superdev</groupId>\n"
640
+ f" <artifactId>{self.name}-backend</artifactId>\n"
641
+ " <version>0.1.0</version>\n"
642
+ " <parent>\n"
643
+ " <groupId>org.springframework.boot</groupId>\n"
644
+ " <artifactId>spring-boot-starter-parent</artifactId>\n"
645
+ " <version>3.2.0</version>\n"
646
+ " <relativePath/>\n"
647
+ " </parent>\n"
648
+ " <properties>\n"
649
+ " <java.version>17</java.version>\n"
650
+ " </properties>\n"
651
+ " <dependencies>\n"
652
+ " <dependency>\n"
653
+ " <groupId>org.springframework.boot</groupId>\n"
654
+ " <artifactId>spring-boot-starter-web</artifactId>\n"
655
+ " </dependency>\n"
656
+ " </dependencies>\n"
657
+ "</project>\n"
658
+ )
659
+
660
+ def _build_index_html(self, mount_id: str, entry_path: str) -> str:
661
+ return (
662
+ "<!doctype html>\n"
663
+ "<html lang=\"zh-CN\">\n"
664
+ " <head>\n"
665
+ " <meta charset=\"UTF-8\" />\n"
666
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n"
667
+ f" <title>{self.name} Frontend</title>\n"
668
+ " </head>\n"
669
+ " <body>\n"
670
+ f" <div id=\"{mount_id}\"></div>\n"
671
+ f" <script type=\"module\" src=\"{entry_path}\"></script>\n"
672
+ " </body>\n"
673
+ "</html>\n"
674
+ )
675
+
676
+ def _build_vue_app(self, modules: list[str]) -> str:
677
+ imports = [f"import {self._to_component(module)} from './modules/{module}.vue';" for module in modules]
678
+ cards = [
679
+ (
680
+ f" <section class=\"card\">\n"
681
+ f" <h3>{self._to_component(module)}</h3>\n"
682
+ f" <{self._to_component(module)} />\n"
683
+ " </section>"
684
+ )
685
+ for module in modules
686
+ ]
687
+ return (
688
+ "<template>\n"
689
+ " <main class=\"shell\">\n"
690
+ f" <h1>{self.name} 实现骨架</h1>\n"
691
+ " <div class=\"grid\">\n"
692
+ + "\n".join(cards)
693
+ + "\n"
694
+ " </div>\n"
695
+ " </main>\n"
696
+ "</template>\n\n"
697
+ "<script setup>\n"
698
+ + "\n".join(imports)
699
+ + "\n"
700
+ "</script>\n\n"
701
+ "<style>\n"
702
+ ".shell { max-width: 960px; margin: 40px auto; font-family: Arial, sans-serif; }\n"
703
+ ".grid { display: grid; gap: 12px; }\n"
704
+ ".card { border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }\n"
705
+ "</style>\n"
706
+ )
707
+
708
+ def _build_vue_module(self, module_name: str) -> str:
709
+ return (
710
+ "<template>\n"
711
+ f" <p>{module_name} 模块初始骨架已创建,可在此实现业务逻辑。</p>\n"
712
+ "</template>\n"
713
+ )
714
+
715
+ def _build_svelte_app(self, modules: list[str]) -> str:
716
+ imports = [f"import {self._to_component(module)} from './modules/{module}.svelte';" for module in modules]
717
+ cards = [
718
+ (
719
+ " <section class=\"card\">\n"
720
+ f" <h3>{self._to_component(module)}</h3>\n"
721
+ f" <{self._to_component(module)} />\n"
722
+ " </section>"
723
+ )
724
+ for module in modules
725
+ ]
726
+ return (
727
+ "\n".join(imports)
728
+ + "\n\n"
729
+ f"<main class=\"shell\">\n"
730
+ f" <h1>{self.name} 实现骨架</h1>\n"
731
+ " <div class=\"grid\">\n"
732
+ + "\n".join(cards)
733
+ + "\n"
734
+ " </div>\n"
735
+ "</main>\n\n"
736
+ "<style>\n"
737
+ ".shell { max-width: 960px; margin: 40px auto; font-family: Arial, sans-serif; }\n"
738
+ ".grid { display: grid; gap: 12px; }\n"
739
+ ".card { border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }\n"
740
+ "</style>\n"
741
+ )
742
+
743
+ def _build_svelte_module(self, module_name: str) -> str:
744
+ return f"<p>{module_name} 模块初始骨架已创建,可在此实现业务逻辑。</p>\n"
745
+
746
+ def _build_angular_component(self, modules: list[str]) -> str:
747
+ sections = []
748
+ for module_name in modules:
749
+ sections.append(
750
+
751
+ "<section style=\"border:1px solid #e5e7eb;border-radius:12px;padding:16px;margin:8px 0;\">\n"
752
+ f" <h3>{self._to_component(module_name)}</h3>\n"
753
+ f" <p>{module_name} 模块初始骨架已创建,可在此实现业务逻辑。</p>\n"
754
+ "</section>"
755
+
756
+ )
757
+ return (
758
+ "import { Component } from '@angular/core';\n\n"
759
+ "@Component({\n"
760
+ " selector: 'app-root',\n"
761
+ " template: `\n"
762
+ f" <main style=\"max-width:960px;margin:40px auto;font-family:Arial,sans-serif;\">\n"
763
+ f" <h1>{self.name} 实现骨架</h1>\n"
764
+ f"{' '.join(sections)}\n"
765
+ " </main>\n"
766
+ " `,\n"
767
+ "})\n"
768
+ "export class AppComponent {}\n"
769
+ )
770
+
771
+ def _safe_identifier(self, name: str) -> str:
772
+ cleaned = "".join(ch if ch.isalnum() else "_" for ch in name.lower())
773
+ if not cleaned:
774
+ return "module"
775
+ if cleaned[0].isdigit():
776
+ cleaned = f"m_{cleaned}"
777
+ return cleaned
778
+
779
+ def _safe_route_segment(self, name: str) -> str:
780
+ cleaned = "".join(ch if (ch.isalnum() or ch in "-_") else "-" for ch in name.lower())
781
+ cleaned = cleaned.strip("-_")
782
+ return cleaned or "module"
783
+
784
+ def _to_component(self, name: str) -> str:
785
+ cleaned = "".join(ch if ch.isalnum() else "-" for ch in name)
786
+ parts = [part for part in cleaned.split("-") if part]
787
+ if not parts:
788
+ return "Module"
789
+ return "".join(part[:1].upper() + part[1:] for part in parts)