ironweave 1.0.0

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 (99) hide show
  1. package/.claude-plugin/plugin.json +16 -0
  2. package/.clinerules +7 -0
  3. package/.codex/INSTALL.md +45 -0
  4. package/.cursor-plugin/plugin.json +19 -0
  5. package/.cursorrules +7 -0
  6. package/.github/copilot-instructions.md +7 -0
  7. package/.opencode/INSTALL.md +42 -0
  8. package/.windsurfrules +7 -0
  9. package/AGENTS.md +1 -0
  10. package/CLAUDE.md +22 -0
  11. package/CONTRIBUTING.md +81 -0
  12. package/GEMINI.md +1 -0
  13. package/LICENSE +21 -0
  14. package/README.md +250 -0
  15. package/README_CN.md +248 -0
  16. package/package.json +48 -0
  17. package/skills/api-contract-design/SKILL.md +227 -0
  18. package/skills/api-contract-design/references/api-design-rules.md +106 -0
  19. package/skills/brainstorm/SKILL.md +271 -0
  20. package/skills/brainstorm/agents/architect.md +34 -0
  21. package/skills/brainstorm/agents/challenger.md +34 -0
  22. package/skills/brainstorm/agents/domain-expert.md +34 -0
  23. package/skills/brainstorm/agents/pragmatist.md +34 -0
  24. package/skills/brainstorm/agents/product-manager.md +34 -0
  25. package/skills/brainstorm/agents/ux-designer.md +34 -0
  26. package/skills/brainstorm/references/synthesis-rules.md +51 -0
  27. package/skills/code-scaffold/SKILL.md +313 -0
  28. package/skills/code-scaffold/references/scaffold-rules.md +131 -0
  29. package/skills/docs-output/SKILL.md +149 -0
  30. package/skills/docs-output/references/naming-rules.md +52 -0
  31. package/skills/docs-output/scripts/docs_manager.py +353 -0
  32. package/skills/engineering-principles/SKILL.md +133 -0
  33. package/skills/engineering-principles/references/anti-patterns.md +144 -0
  34. package/skills/engineering-principles/references/ddd-patterns.md +66 -0
  35. package/skills/engineering-principles/references/design-patterns.md +34 -0
  36. package/skills/engineering-principles/references/patterns-architecture.md +301 -0
  37. package/skills/engineering-principles/references/patterns-backend.md +77 -0
  38. package/skills/engineering-principles/references/patterns-classic.md +200 -0
  39. package/skills/engineering-principles/references/patterns-crosscut.md +67 -0
  40. package/skills/engineering-principles/references/patterns-frontend.md +27 -0
  41. package/skills/engineering-principles/references/patterns-module.md +95 -0
  42. package/skills/engineering-principles/references/patterns-small-scale.md +79 -0
  43. package/skills/engineering-principles/references/quality-checklist.md +76 -0
  44. package/skills/engineering-principles/references/solid-principles.md +46 -0
  45. package/skills/engineering-principles/references/tdd-workflow.md +60 -0
  46. package/skills/engineering-principles/scripts/principles_matcher.py +433 -0
  47. package/skills/error-handling-strategy/SKILL.md +347 -0
  48. package/skills/error-handling-strategy/references/error-handling-rules.md +91 -0
  49. package/skills/implementation-complexity-analysis/SKILL.md +193 -0
  50. package/skills/implementation-complexity-analysis/references/complexity-rules.md +126 -0
  51. package/skills/integration-test-design/SKILL.md +296 -0
  52. package/skills/integration-test-design/references/test-strategy-rules.md +90 -0
  53. package/skills/observability-design/SKILL.md +327 -0
  54. package/skills/observability-design/references/observability-rules.md +129 -0
  55. package/skills/orchestrator/SKILL.md +260 -0
  56. package/skills/orchestrator/references/deliver.md +112 -0
  57. package/skills/orchestrator/references/execute.md +313 -0
  58. package/skills/orchestrator/references/gates.md +252 -0
  59. package/skills/orchestrator/references/parallel.md +70 -0
  60. package/skills/orchestrator/references/route-a.md +135 -0
  61. package/skills/orchestrator/references/route-b.md +91 -0
  62. package/skills/orchestrator/references/route-c.md +65 -0
  63. package/skills/orchestrator/references/route-d.md +75 -0
  64. package/skills/orchestrator/references/scope-sizer.md +219 -0
  65. package/skills/performance-arch-design/SKILL.md +208 -0
  66. package/skills/performance-arch-design/references/performance-rules.md +95 -0
  67. package/skills/project-context/SKILL.md +104 -0
  68. package/skills/project-context/references/schema.md +97 -0
  69. package/skills/project-context/scripts/context_db.py +358 -0
  70. package/skills/requirement-qa/SKILL.md +287 -0
  71. package/skills/requirement-qa/references/completion-signals.md +42 -0
  72. package/skills/requirement-qa/references/option-rules.md +57 -0
  73. package/skills/requirement-qa/scripts/qa_session.py +223 -0
  74. package/skills/skill-creator/LICENSE.txt +202 -0
  75. package/skills/skill-creator/SKILL.md +485 -0
  76. package/skills/skill-creator/agents/analyzer.md +274 -0
  77. package/skills/skill-creator/agents/comparator.md +202 -0
  78. package/skills/skill-creator/agents/grader.md +223 -0
  79. package/skills/skill-creator/assets/eval_review.html +146 -0
  80. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  81. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  82. package/skills/skill-creator/references/schemas.md +430 -0
  83. package/skills/skill-creator/scripts/__init__.py +0 -0
  84. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  85. package/skills/skill-creator/scripts/generate_report.py +326 -0
  86. package/skills/skill-creator/scripts/improve_description.py +247 -0
  87. package/skills/skill-creator/scripts/package_skill.py +136 -0
  88. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  89. package/skills/skill-creator/scripts/run_eval.py +310 -0
  90. package/skills/skill-creator/scripts/run_loop.py +328 -0
  91. package/skills/skill-creator/scripts/utils.py +47 -0
  92. package/skills/spec-writing/SKILL.md +96 -0
  93. package/skills/spec-writing/references/mermaid-guide.md +66 -0
  94. package/skills/spec-writing/references/test-matrix.md +73 -0
  95. package/skills/task-difficulty/SKILL.md +162 -0
  96. package/skills/task-difficulty/references/scoring-guide.md +123 -0
  97. package/skills/task-difficulty/scripts/difficulty_scorer.py +328 -0
  98. package/skills/tech-stack/SKILL.md +67 -0
  99. package/skills/tech-stack/references/tech-reference-tables.md +130 -0
@@ -0,0 +1,433 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ engineering-principles: 工程原则匹配脚本
4
+
5
+ 用法:
6
+ python principles_matcher.py match --root <project_root> [--task <任务描述>] [--format json|markdown]
7
+ """
8
+
9
+ import argparse
10
+ import json
11
+ import os
12
+ from pathlib import Path
13
+
14
+ # ── 原则分类定义 ──────────────────────────────────────────────
15
+
16
+ PRINCIPLES = [
17
+ {
18
+ "id": "clean-code",
19
+ "name": "Clean Code",
20
+ "always": True,
21
+ "condition": None,
22
+ "ref": "quality-checklist.md",
23
+ "summary": "命名规范、函数 ≤ 30 行、避免 magic number、注释解释 why 不解释 what",
24
+ },
25
+ {
26
+ "id": "error-handling",
27
+ "name": "错误处理",
28
+ "always": True,
29
+ "condition": None,
30
+ "ref": "quality-checklist.md",
31
+ "summary": "业务/系统异常分级、不吞异常、边界处统一捕获、入口校验",
32
+ },
33
+ {
34
+ "id": "solid",
35
+ "name": "SOLID 原则",
36
+ "always": False,
37
+ "condition": "oop",
38
+ "ref": "solid-principles.md",
39
+ "summary": "SRP 单一职责, OCP 开闭, LSP 里氏替换, ISP 接口隔离, DIP 依赖倒置",
40
+ },
41
+ {
42
+ "id": "ddd",
43
+ "name": "DDD 分层",
44
+ "always": False,
45
+ "condition": "ddd",
46
+ "ref": "ddd-patterns.md",
47
+ "summary": "聚合、限界上下文、领域服务、值对象、仓储模式",
48
+ },
49
+ {
50
+ "id": "tdd",
51
+ "name": "TDD 测试驱动",
52
+ "always": False,
53
+ "condition": "test-framework",
54
+ "ref": "tdd-workflow.md",
55
+ "summary": "红绿重构循环、测试金字塔、Bug 先写复现测试",
56
+ },
57
+ {
58
+ "id": "bdd",
59
+ "name": "BDD 行为驱动",
60
+ "always": False,
61
+ "condition": "e2e-framework",
62
+ "ref": "tdd-workflow.md",
63
+ "summary": "Gherkin 验收场景、用户行为驱动测试",
64
+ },
65
+ {
66
+ "id": "design-patterns",
67
+ "name": "设计模式",
68
+ "always": False,
69
+ "condition": "oop",
70
+ "ref": "design-patterns.md",
71
+ "summary": "策略、工厂、观察者、适配器——仅在识别到适用信号时引入",
72
+ },
73
+ {
74
+ "id": "testability",
75
+ "name": "可测试性",
76
+ "always": False,
77
+ "condition": "test-framework-or-new",
78
+ "ref": "quality-checklist.md",
79
+ "summary": "依赖注入、纯函数优先、外部依赖接口隔离",
80
+ },
81
+ {
82
+ "id": "performance",
83
+ "name": "性能意识",
84
+ "always": False,
85
+ "condition": "database",
86
+ "ref": "quality-checklist.md",
87
+ "summary": "避免 N+1、检查索引、按需 select、缓存重复计算",
88
+ },
89
+ {
90
+ "id": "security",
91
+ "name": "安全实践",
92
+ "always": False,
93
+ "condition": "user-input",
94
+ "ref": "quality-checklist.md",
95
+ "summary": "参数化查询、XSS 防护、CSRF token、权限校验、敏感数据脱敏",
96
+ },
97
+ ]
98
+
99
+ # ── 上下文扫描 ──────────────────────────────────────────────
100
+
101
+ IGNORE_DIRS = {
102
+ "node_modules", "dist", "build", ".git", "__pycache__",
103
+ ".next", ".nuxt", ".output", "coverage", ".cache", "target",
104
+ }
105
+
106
+ TEST_FRAMEWORK_SIGNALS = [
107
+ "jest.config", "vitest.config", "pytest.ini", "pyproject.toml",
108
+ "conftest.py", "setup.cfg", "__tests__",
109
+ ]
110
+
111
+ E2E_SIGNALS = ["cypress", "cypress.config", "playwright.config", "playwright"]
112
+
113
+ ORM_SIGNALS = ["prisma", "typeorm", "sequelize", "drizzle", "mybatis", "hibernate"]
114
+
115
+
116
+ def scan_context(root: str) -> dict:
117
+ """扫描项目上下文。"""
118
+ ctx = {
119
+ "has_project": False,
120
+ "total_files": 0,
121
+ "modules": [],
122
+ "language": "unknown",
123
+ "framework": "unknown",
124
+ "has_test_framework": False,
125
+ "has_e2e": False,
126
+ "has_orm": False,
127
+ "has_layered_structure": False,
128
+ "is_new_project": False,
129
+ "project_size": "unknown",
130
+ }
131
+
132
+ root_path = Path(root).resolve()
133
+ if not root_path.exists():
134
+ return ctx
135
+ ctx["has_project"] = True
136
+
137
+ # 计算文件数量
138
+ file_count = 0
139
+ has_src = False
140
+ has_tests = False
141
+ dir_names = set()
142
+
143
+ for dirpath, dirnames, filenames in os.walk(root_path):
144
+ dirnames[:] = [d for d in dirnames if d not in IGNORE_DIRS]
145
+ rel = Path(dirpath).relative_to(root_path)
146
+ dir_names.add(str(rel))
147
+
148
+ for fname in filenames:
149
+ file_count += 1
150
+
151
+ ctx["total_files"] = file_count
152
+
153
+ # 项目规模
154
+ if file_count == 0:
155
+ ctx["is_new_project"] = True
156
+ ctx["project_size"] = "new"
157
+ elif file_count < 50:
158
+ ctx["project_size"] = "small"
159
+ elif file_count < 500:
160
+ ctx["project_size"] = "medium"
161
+ else:
162
+ ctx["project_size"] = "large"
163
+
164
+ # 语言/框架检测
165
+ root_files = [f.name for f in root_path.iterdir() if f.is_file()]
166
+
167
+ if "package.json" in root_files:
168
+ ctx["language"] = "typescript/javascript"
169
+ pkg_path = root_path / "package.json"
170
+ try:
171
+ pkg = json.loads(pkg_path.read_text(encoding="utf-8"))
172
+ deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
173
+
174
+ if "next" in deps:
175
+ ctx["framework"] = "Next.js"
176
+ elif "nuxt" in deps or "@nuxt/kit" in deps:
177
+ ctx["framework"] = "Nuxt"
178
+ elif "@nestjs/core" in deps:
179
+ ctx["framework"] = "NestJS"
180
+ elif "vue" in deps:
181
+ ctx["framework"] = "Vue"
182
+ elif "react" in deps:
183
+ ctx["framework"] = "React"
184
+ elif "express" in deps:
185
+ ctx["framework"] = "Express"
186
+
187
+ # 测试框架
188
+ for test_dep in ["jest", "vitest", "@jest/core", "mocha", "ava"]:
189
+ if test_dep in deps:
190
+ ctx["has_test_framework"] = True
191
+ break
192
+
193
+ # E2E
194
+ for e2e_dep in ["cypress", "@playwright/test", "playwright"]:
195
+ if e2e_dep in deps:
196
+ ctx["has_e2e"] = True
197
+ break
198
+
199
+ # ORM
200
+ for orm_dep in ["typeorm", "prisma", "@prisma/client", "sequelize", "drizzle-orm"]:
201
+ if orm_dep in deps:
202
+ ctx["has_orm"] = True
203
+ break
204
+
205
+ except (json.JSONDecodeError, OSError):
206
+ pass
207
+
208
+ elif "pom.xml" in root_files or "build.gradle" in root_files:
209
+ ctx["language"] = "java"
210
+ ctx["framework"] = "Spring Boot"
211
+ ctx["has_test_framework"] = True # Java 项目通常自带 JUnit
212
+ ctx["has_orm"] = True
213
+
214
+ elif "pyproject.toml" in root_files or "setup.py" in root_files:
215
+ ctx["language"] = "python"
216
+
217
+ # 分层结构检测
218
+ layer_indicators = {"controller", "service", "repository", "domain", "infrastructure", "application"}
219
+ for d in dir_names:
220
+ parts = d.lower().split("/")
221
+ if layer_indicators.intersection(parts):
222
+ ctx["has_layered_structure"] = True
223
+ break
224
+
225
+ # 测试目录检测(补充)
226
+ for test_dir in ["__tests__", "test", "tests", "spec"]:
227
+ if (root_path / test_dir).exists() or (root_path / "src" / test_dir).exists():
228
+ ctx["has_test_framework"] = True
229
+ break
230
+
231
+ # 模块识别
232
+ src = root_path / "src"
233
+ if src.exists():
234
+ ctx["modules"] = sorted([
235
+ d.name for d in src.iterdir()
236
+ if d.is_dir() and d.name not in IGNORE_DIRS
237
+ ])
238
+
239
+ return ctx
240
+
241
+
242
+ # ── 原则匹配 ──────────────────────────────────────────────
243
+
244
+ TASK_SECURITY_KEYWORDS = [
245
+ "登录", "注册", "认证", "auth", "密码", "password",
246
+ "api", "接口", "表单", "输入", "input",
247
+ ]
248
+
249
+ TASK_DB_KEYWORDS = [
250
+ "数据库", "database", "查询", "query", "表", "table",
251
+ "sql", "orm", "crud", "列表", "分页",
252
+ ]
253
+
254
+
255
+ def match_principles(ctx: dict, task: str | None = None) -> dict:
256
+ """根据上下文匹配适用原则。"""
257
+ always_applicable = []
258
+ detected_applicable = []
259
+ skipped = []
260
+
261
+ task_lower = (task or "").lower()
262
+
263
+ for p in PRINCIPLES:
264
+ if p["always"]:
265
+ always_applicable.append({
266
+ "id": p["id"],
267
+ "name": p["name"],
268
+ "summary": p["summary"],
269
+ "ref": p["ref"],
270
+ })
271
+ continue
272
+
273
+ cond = p["condition"]
274
+ applicable = False
275
+ reason = ""
276
+
277
+ if cond == "oop":
278
+ if ctx.get("language") in ("typescript/javascript", "java", "python"):
279
+ applicable = True
280
+ reason = f"检测到 OOP 语言: {ctx['language']}"
281
+ else:
282
+ reason = "未检测到 OOP 语言"
283
+
284
+ elif cond == "ddd":
285
+ if ctx.get("has_layered_structure") and ctx.get("project_size") in ("medium", "large"):
286
+ applicable = True
287
+ reason = "检测到分层结构且项目规模 ≥ 中型"
288
+ elif ctx.get("project_size") == "large" and len(ctx.get("modules", [])) >= 3:
289
+ applicable = True
290
+ reason = f"大型项目,{len(ctx['modules'])} 个模块"
291
+ else:
292
+ reason = "项目规模不足或无分层结构"
293
+
294
+ elif cond == "test-framework":
295
+ if ctx.get("has_test_framework"):
296
+ applicable = True
297
+ reason = "检测到测试框架"
298
+ else:
299
+ reason = "未检测到测试框架"
300
+
301
+ elif cond == "e2e-framework":
302
+ if ctx.get("has_e2e"):
303
+ applicable = True
304
+ reason = "检测到 E2E 框架"
305
+ else:
306
+ reason = "未检测到 E2E 框架(cypress/playwright)"
307
+
308
+ elif cond == "test-framework-or-new":
309
+ if ctx.get("has_test_framework") or ctx.get("is_new_project"):
310
+ applicable = True
311
+ reason = "有测试框架" if ctx.get("has_test_framework") else "新项目(推荐)"
312
+ else:
313
+ reason = "无测试框架且非新项目"
314
+
315
+ elif cond == "database":
316
+ if ctx.get("has_orm"):
317
+ applicable = True
318
+ reason = "检测到 ORM/数据库依赖"
319
+ elif any(kw in task_lower for kw in TASK_DB_KEYWORDS):
320
+ applicable = True
321
+ reason = "任务描述涉及数据库操作"
322
+ else:
323
+ reason = "未检测到数据库相关内容"
324
+
325
+ elif cond == "user-input":
326
+ if any(kw in task_lower for kw in TASK_SECURITY_KEYWORDS):
327
+ applicable = True
328
+ reason = "任务描述涉及用户输入/认证"
329
+ else:
330
+ reason = "任务描述未涉及用户输入/安全相关"
331
+
332
+ if applicable:
333
+ detected_applicable.append({
334
+ "id": p["id"],
335
+ "name": p["name"],
336
+ "summary": p["summary"],
337
+ "ref": p["ref"],
338
+ "reason": reason,
339
+ })
340
+ else:
341
+ skipped.append({
342
+ "id": p["id"],
343
+ "name": p["name"],
344
+ "reason": reason,
345
+ })
346
+
347
+ return {
348
+ "always": always_applicable,
349
+ "detected": detected_applicable,
350
+ "skipped": skipped,
351
+ }
352
+
353
+
354
+ # ── 输出格式化 ──────────────────────────────────────────────
355
+
356
+ def format_markdown(ctx: dict, matched: dict, task: str | None) -> str:
357
+ lines = [
358
+ "# 工程原则匹配报告",
359
+ "",
360
+ "## 项目上下文",
361
+ f"- 语言/框架: {ctx.get('language', 'unknown')} + {ctx.get('framework', 'unknown')}",
362
+ f"- 测试框架: {'已配置' if ctx.get('has_test_framework') else '未检测到'}",
363
+ f"- E2E 框架: {'已配置' if ctx.get('has_e2e') else '未检测到'}",
364
+ f"- 项目规模: {ctx.get('project_size', 'unknown')}({ctx.get('total_files', 0)} 文件)",
365
+ f"- 分层结构: {'是' if ctx.get('has_layered_structure') else '否'}",
366
+ f"- ORM/数据库: {'是' if ctx.get('has_orm') else '否'}",
367
+ ]
368
+
369
+ if task:
370
+ lines.append(f"- 当前任务: {task}")
371
+ lines.append("")
372
+
373
+ lines.append("## 适用原则")
374
+ lines.append("")
375
+ lines.append("### ✅ 始终适用")
376
+ for p in matched["always"]:
377
+ lines.append(f"- **{p['name']}**: {p['summary']}")
378
+ lines.append("")
379
+
380
+ if matched["detected"]:
381
+ lines.append("### ✅ 经检测适用")
382
+ for p in matched["detected"]:
383
+ lines.append(f"- **{p['name']}**: {p['summary']}({p['reason']})")
384
+ lines.append("")
385
+
386
+ if matched["skipped"]:
387
+ lines.append("### ⏭️ 不适用")
388
+ for p in matched["skipped"]:
389
+ lines.append(f"- **{p['name']}**: {p['reason']}")
390
+ lines.append("")
391
+
392
+ # 简短约束清单
393
+ lines.append("## 约束清单(编码时参考)")
394
+ lines.append("")
395
+ lines.append("```")
396
+ for p in matched["always"]:
397
+ lines.append(f"- {p['name']}: {p['summary'].split('、')[0]}")
398
+ for p in matched["detected"]:
399
+ lines.append(f"- {p['name']}: {p['summary'].split('、')[0]}")
400
+ lines.append("```")
401
+
402
+ return "\n".join(lines)
403
+
404
+
405
+ def format_json(ctx: dict, matched: dict) -> str:
406
+ return json.dumps({"context": ctx, "principles": matched}, ensure_ascii=False, indent=2)
407
+
408
+
409
+ # ── CLI ──────────────────────────────────────────────
410
+
411
+ def main():
412
+ parser = argparse.ArgumentParser(description="engineering-principles: 工程原则匹配")
413
+ sub = parser.add_subparsers(dest="command", required=True)
414
+
415
+ p_match = sub.add_parser("match", help="匹配适用原则")
416
+ p_match.add_argument("--root", required=True, help="项目根目录")
417
+ p_match.add_argument("--task", default=None, help="当前任务描述")
418
+ p_match.add_argument("--format", default="markdown", choices=["json", "markdown"])
419
+
420
+ args = parser.parse_args()
421
+
422
+ if args.command == "match":
423
+ ctx = scan_context(args.root)
424
+ matched = match_principles(ctx, args.task)
425
+
426
+ if args.format == "json":
427
+ print(format_json(ctx, matched))
428
+ else:
429
+ print(format_markdown(ctx, matched, args.task))
430
+
431
+
432
+ if __name__ == "__main__":
433
+ main()