@chongyan/autospec 1.0.1

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 (243) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +472 -0
  3. package/README.md +476 -0
  4. package/bin/autospec.js +3 -0
  5. package/knowledge/README.md +144 -0
  6. package/knowledge/checklists/code.md +182 -0
  7. package/knowledge/checklists/design.md +196 -0
  8. package/knowledge/checklists/release.md +70 -0
  9. package/knowledge/checklists/requirement.md +169 -0
  10. package/knowledge/checklists/test.md +46 -0
  11. package/knowledge/config/README.en.md +44 -0
  12. package/knowledge/config/README.md +44 -0
  13. package/knowledge/config/role-composition.yaml +98 -0
  14. package/knowledge/config/role-extensions.yaml +140 -0
  15. package/knowledge/config/skill-compositions.yaml +142 -0
  16. package/knowledge/config/team-stage.yaml +95 -0
  17. package/knowledge/config/team-tasks.yaml +139 -0
  18. package/knowledge/config/team-triggers.yaml +198 -0
  19. package/knowledge/config/validation-patterns.yaml +137 -0
  20. package/knowledge/domain/README.md +115 -0
  21. package/knowledge/domain/flows/README.md +194 -0
  22. package/knowledge/domain/glossary.md +143 -0
  23. package/knowledge/domain/rules.md +138 -0
  24. package/knowledge/environment/README.en.md +36 -0
  25. package/knowledge/environment/README.md +87 -0
  26. package/knowledge/environment/component-knowledge.md +316 -0
  27. package/knowledge/environment/detection-patterns.yaml +502 -0
  28. package/knowledge/environment/middleware-knowledge.md +237 -0
  29. package/knowledge/environment/template-registry.md +321 -0
  30. package/knowledge/guides/domain-driven-design.md +345 -0
  31. package/knowledge/guides/knowledge-management.md +369 -0
  32. package/knowledge/guides/requirement-engineering.md +329 -0
  33. package/knowledge/guides/stages/ai-effect-evaluator.md +93 -0
  34. package/knowledge/guides/stages/code-implementer.md +205 -0
  35. package/knowledge/guides/stages/code-reviewer.md +111 -0
  36. package/knowledge/guides/stages/consistency-checker.md +177 -0
  37. package/knowledge/guides/stages/design-planner.md +401 -0
  38. package/knowledge/guides/stages/design-reviewer.md +83 -0
  39. package/knowledge/guides/stages/integration-test-runner.md +105 -0
  40. package/knowledge/guides/stages/release-checker.md +205 -0
  41. package/knowledge/guides/stages/requirement-analyzer.md +195 -0
  42. package/knowledge/guides/stages/requirement-reviewer.md +83 -0
  43. package/knowledge/guides/stages/security-reviewer.md +89 -0
  44. package/knowledge/guides/stages/test-context-analyzer.md +250 -0
  45. package/knowledge/guides/stages/test-generator.md +241 -0
  46. package/knowledge/guides/stages/test-planner.md +183 -0
  47. package/knowledge/guides/stages/test-reviewer.md +76 -0
  48. package/knowledge/guides/stages/unit-test-runner.md +83 -0
  49. package/knowledge/guides/support/ai-agent-analyzer.md +362 -0
  50. package/knowledge/guides/support/ai-anomaly-analyzer.md +213 -0
  51. package/knowledge/guides/support/ai-artifact-evaluator.md +192 -0
  52. package/knowledge/guides/support/ai-capability-analyzer.md +193 -0
  53. package/knowledge/guides/support/ai-component-analyzer.md +169 -0
  54. package/knowledge/guides/support/ai-data-validator.md +276 -0
  55. package/knowledge/guides/support/ai-evaluation-planner.md +374 -0
  56. package/knowledge/guides/support/ai-path-evaluator.md +274 -0
  57. package/knowledge/guides/support/ai-pipeline-evaluator.md +219 -0
  58. package/knowledge/guides/support/ai-rag-analyzer.md +339 -0
  59. package/knowledge/guides/support/ai-task-assessor.md +418 -0
  60. package/knowledge/guides/support/ai-test-diagnostics.md +133 -0
  61. package/knowledge/guides/support/complexity-assessor.md +268 -0
  62. package/knowledge/guides/support/component-discovery.md +183 -0
  63. package/knowledge/guides/support/environment-scanner.md +207 -0
  64. package/knowledge/guides/support/environment-validator.md +207 -0
  65. package/knowledge/guides/support/knowledge-generator.md +234 -0
  66. package/knowledge/guides/support/methodology-extractor.md +55 -0
  67. package/knowledge/guides/support/pipeline-protocol.md +438 -0
  68. package/knowledge/guides/support/practice-logger.md +359 -0
  69. package/knowledge/guides/support/scope-inference.md +174 -0
  70. package/knowledge/guides/support/skill-distiller.md +91 -0
  71. package/knowledge/guides/support/skill-updater.md +45 -0
  72. package/knowledge/guides/support/skill-validator.md +72 -0
  73. package/knowledge/guides/support/team-orchestrator.md +323 -0
  74. package/knowledge/guides/support/tech-stack-analyzer.md +139 -0
  75. package/knowledge/guides/support/test-runner.md +254 -0
  76. package/knowledge/guides/system-design.md +352 -0
  77. package/knowledge/organization/ai-native-team.md +318 -0
  78. package/knowledge/organization/team-metrics.md +228 -0
  79. package/knowledge/principles/constitution.md +134 -0
  80. package/knowledge/principles/core-principles.md +368 -0
  81. package/knowledge/principles/design-philosophy.md +877 -0
  82. package/knowledge/principles/evolution.md +553 -0
  83. package/knowledge/process/01-requirement.md +113 -0
  84. package/knowledge/process/02-design.md +123 -0
  85. package/knowledge/process/03-implementation.md +90 -0
  86. package/knowledge/process/04-review.md +80 -0
  87. package/knowledge/process/05-testing.md +90 -0
  88. package/knowledge/process/06-delivery.md +88 -0
  89. package/knowledge/process/README.en.md +38 -0
  90. package/knowledge/process/README.md +48 -0
  91. package/knowledge/process/ai-sdlc.md +475 -0
  92. package/knowledge/process/overview.md +319 -0
  93. package/knowledge/standards/code-review.md +876 -0
  94. package/knowledge/standards/coding-style.md +940 -0
  95. package/knowledge/standards/data-consistency.md +1085 -0
  96. package/knowledge/standards/document-versioning.md +210 -0
  97. package/knowledge/standards/risk-detection.md +186 -0
  98. package/knowledge/templates/ai-evaluation.md +150 -0
  99. package/knowledge/templates/api-design.md +117 -0
  100. package/knowledge/templates/database-design.md +132 -0
  101. package/knowledge/templates/domain-driven-design.md +321 -0
  102. package/knowledge/templates/product-proposal.md +201 -0
  103. package/knowledge/templates/system-design.md +227 -0
  104. package/knowledge/templates/task-breakdown.md +107 -0
  105. package/knowledge/templates/test-case.md +170 -0
  106. package/package.json +53 -0
  107. package/plugins/.claude-plugin/plugin.json +134 -0
  108. package/plugins/agents/roles/ai-engineer.md +129 -0
  109. package/plugins/agents/roles/backend-engineer.md +165 -0
  110. package/plugins/agents/roles/ceo.md +94 -0
  111. package/plugins/agents/roles/data-engineer.md +135 -0
  112. package/plugins/agents/roles/devops-engineer.md +181 -0
  113. package/plugins/agents/roles/frontend-engineer.md +129 -0
  114. package/plugins/agents/roles/product-owner.md +98 -0
  115. package/plugins/agents/roles/quality-engineer.md +129 -0
  116. package/plugins/agents/roles/security-engineer.md +180 -0
  117. package/plugins/agents/roles/tech-lead.md +97 -0
  118. package/plugins/agents/support/blind-comparator.md +88 -0
  119. package/plugins/agents/support/consistency-checker.md +103 -0
  120. package/plugins/agents/support/failure-diagnostician.md +141 -0
  121. package/plugins/agents/support/independent-reviewer.md +80 -0
  122. package/plugins/agents/support/safety-auditor.md +121 -0
  123. package/plugins/agents/support/skill-benchmarker.md +86 -0
  124. package/plugins/agents/support/skill-forger.md +105 -0
  125. package/plugins/agents/support/stage-gate-evaluator.md +121 -0
  126. package/plugins/agents/support/test-coverage-reviewer.md +73 -0
  127. package/plugins/benchmarks/templates/README.md +44 -0
  128. package/plugins/benchmarks/templates/commands/explore-template.yaml +48 -0
  129. package/plugins/benchmarks/templates/pipeline/agile-template.yaml +84 -0
  130. package/plugins/benchmarks/templates/pipeline/waterfall-template.yaml +106 -0
  131. package/plugins/benchmarks/templates/skills/requirement-analyzer-template.yaml +48 -0
  132. package/plugins/commands/README.en.md +96 -0
  133. package/plugins/commands/README.md +96 -0
  134. package/plugins/commands/apply.md +191 -0
  135. package/plugins/commands/archive.md +76 -0
  136. package/plugins/commands/env-export.md +79 -0
  137. package/plugins/commands/env-sync.md +640 -0
  138. package/plugins/commands/env-template.md +223 -0
  139. package/plugins/commands/env-update.md +264 -0
  140. package/plugins/commands/env-validate.md +176 -0
  141. package/plugins/commands/env.md +79 -0
  142. package/plugins/commands/explore.md +76 -0
  143. package/plugins/commands/field-evolve.md +536 -0
  144. package/plugins/commands/memory.md +249 -0
  145. package/plugins/commands/project-evolve.md +821 -0
  146. package/plugins/commands/propose.md +93 -0
  147. package/plugins/commands/review.md +140 -0
  148. package/plugins/commands/run.md +224 -0
  149. package/plugins/commands/status.md +62 -0
  150. package/plugins/commands/validate.md +108 -0
  151. package/plugins/hooks/README.en.md +56 -0
  152. package/plugins/hooks/README.md +56 -0
  153. package/plugins/hooks/ai-project-guard.js +329 -0
  154. package/plugins/hooks/artifact-evaluation-hook.js +237 -0
  155. package/plugins/hooks/constitution-guard.js +211 -0
  156. package/plugins/hooks/environment-autocommit.js +264 -0
  157. package/plugins/hooks/environment-manager.js +778 -0
  158. package/plugins/hooks/execution-tracker.js +354 -0
  159. package/plugins/hooks/frozen-zone-guard.js +140 -0
  160. package/plugins/hooks/layer1-validator.js +423 -0
  161. package/plugins/hooks/lib/artifact-evaluator.js +414 -0
  162. package/plugins/hooks/lib/benchmarks/change-detector.js +390 -0
  163. package/plugins/hooks/lib/benchmarks/evaluator.js +605 -0
  164. package/plugins/hooks/lib/benchmarks/integration-example.js +169 -0
  165. package/plugins/hooks/lib/data-and-ai-detector.js +275 -0
  166. package/plugins/hooks/lib/detection-pattern-loader.js +865 -0
  167. package/plugins/hooks/lib/directory-discovery.js +395 -0
  168. package/plugins/hooks/lib/environment-config-loader.js +341 -0
  169. package/plugins/hooks/lib/environment-detector.js +553 -0
  170. package/plugins/hooks/lib/environment-evolver.js +564 -0
  171. package/plugins/hooks/lib/environment-registry.js +813 -0
  172. package/plugins/hooks/lib/execution-path.js +427 -0
  173. package/plugins/hooks/lib/hook-error-recorder.js +245 -0
  174. package/plugins/hooks/lib/hook-logger.js +538 -0
  175. package/plugins/hooks/lib/hook-runner.js +97 -0
  176. package/plugins/hooks/lib/hook-runner.sh +44 -0
  177. package/plugins/hooks/lib/hook-state-manager.js +480 -0
  178. package/plugins/hooks/lib/memory-extractor.js +377 -0
  179. package/plugins/hooks/lib/memory-manager.js +673 -0
  180. package/plugins/hooks/lib/metrics-analyzer.js +489 -0
  181. package/plugins/hooks/lib/project-evolution/auto-fixer.js +511 -0
  182. package/plugins/hooks/lib/project-evolution/memory-manager.js +346 -0
  183. package/plugins/hooks/lib/project-evolution/pattern-detector.js +476 -0
  184. package/plugins/hooks/lib/project-evolution/semantic-indexer.js +480 -0
  185. package/plugins/hooks/lib/project-structure-detector.js +326 -0
  186. package/plugins/hooks/lib/rollback-tracker.js +346 -0
  187. package/plugins/hooks/lib/source-code-scanner.js +596 -0
  188. package/plugins/hooks/lib/technology-stack-detector.js +374 -0
  189. package/plugins/hooks/lib/test-failure-analyzer.js +375 -0
  190. package/plugins/hooks/lib/test-failure-fixer.js +268 -0
  191. package/plugins/hooks/lib/trace-context.js +277 -0
  192. package/plugins/hooks/lib/validation-patterns.js +415 -0
  193. package/plugins/hooks/memory-sync.js +171 -0
  194. package/plugins/hooks/pipeline-observer.js +413 -0
  195. package/plugins/hooks/scope-sentinel.js +204 -0
  196. package/plugins/hooks/trace-initialization.js +169 -0
  197. package/plugins/memory/templates/code-quality.yaml +149 -0
  198. package/plugins/memory/templates/multi-system.yaml +155 -0
  199. package/plugins/memory/templates/team-habits.yaml +119 -0
  200. package/plugins/memory/templates/testing.yaml +121 -0
  201. package/plugins/skills/README.en.md +47 -0
  202. package/plugins/skills/README.md +104 -0
  203. package/plugins/skills/benchmark-executor/README.md +93 -0
  204. package/plugins/skills/benchmark-executor/SKILL.md +647 -0
  205. package/plugins/skills/benchmark-generator/SKILL.md +349 -0
  206. package/plugins/skills/delivery-stage/SKILL.md +203 -0
  207. package/plugins/skills/design-stage/SKILL.md +216 -0
  208. package/plugins/skills/evolution-process/SKILL.md +291 -0
  209. package/plugins/skills/exploration-phase/SKILL.md +133 -0
  210. package/plugins/skills/implementation-stage/SKILL.md +179 -0
  211. package/plugins/skills/layer1-validation/SKILL.md +79 -0
  212. package/plugins/skills/pending-dashboard/SKILL.md +109 -0
  213. package/plugins/skills/project-evolution/SKILL.md +847 -0
  214. package/plugins/skills/requirement-stage/SKILL.md +183 -0
  215. package/plugins/skills/skill-forge/SKILL.md +223 -0
  216. package/plugins/skills/skill-forge/references/description-guide.md +92 -0
  217. package/plugins/skills/skill-forge/references/quality-rubric.md +104 -0
  218. package/plugins/skills/skill-forge/references/skill-template.md +106 -0
  219. package/plugins/skills/startup-guard/SKILL.md +38 -0
  220. package/plugins/skills/testing-stage/SKILL.md +195 -0
  221. package/scripts/cli/global-init.js +288 -0
  222. package/scripts/cli/global.js +324 -0
  223. package/scripts/cli/index.js +55 -0
  224. package/scripts/cli/init.js +382 -0
  225. package/scripts/cli/list.js +69 -0
  226. package/scripts/cli/org.js +340 -0
  227. package/scripts/cli/update.js +44 -0
  228. package/scripts/config/commands.config.js +145 -0
  229. package/scripts/config/hooks.config.js +197 -0
  230. package/scripts/evolution/evolution-router.js +273 -0
  231. package/scripts/evolution/evolution-signal-collector.js +307 -0
  232. package/scripts/evolution/knowledge-loader.js +346 -0
  233. package/scripts/evolution/marketplace.js +317 -0
  234. package/scripts/evolution/version-manager.js +371 -0
  235. package/scripts/install/agents.js +106 -0
  236. package/scripts/install/commands.js +133 -0
  237. package/scripts/install/constants.js +424 -0
  238. package/scripts/install/hook-logger.js +536 -0
  239. package/scripts/install/hooks.js +110 -0
  240. package/scripts/install/index.js +39 -0
  241. package/scripts/install/skills.js +95 -0
  242. package/scripts/postinstall.js +25 -0
  243. package/scripts/state.js +376 -0
@@ -0,0 +1,865 @@
1
+ /**
2
+ * Detection Pattern Loader
3
+ *
4
+ * 加载和管理检测模式配置
5
+ *
6
+ * 此文件是 hooks 模块的一部分,可独立运行于目标项目中。
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+
12
+ // 动态加载 js-yaml(延迟加载,避免 top-level await 导致模块加载失败)
13
+ let yaml = null;
14
+ let yamlLoadAttempted = false;
15
+
16
+ /**
17
+ * 确保 js-yaml 已加载(延迟加载)
18
+ * 将 top-level await 改为函数内动态导入,避免模块初始化失败
19
+ */
20
+ async function ensureYaml() {
21
+ if (yamlLoadAttempted) return yaml;
22
+ yamlLoadAttempted = true;
23
+ try {
24
+ yaml = await import('js-yaml');
25
+ } catch (e) {
26
+ // js-yaml 不可用,使用降级方案 parseYamlSimple / dumpYamlSimple
27
+ }
28
+ return yaml;
29
+ }
30
+
31
+ /**
32
+ * 简单的 YAML 解析器(降级方案)
33
+ * 支持多层嵌套、数组、行内数组等基本结构
34
+ */
35
+ function parseYamlSimple(content) {
36
+ const lines = content.split('\n');
37
+ const result = {};
38
+
39
+ const stack = [{ obj: result, indent: -1, isArrayItem: false }];
40
+
41
+ for (let i = 0; i < lines.length; i++) {
42
+ const line = lines[i];
43
+ const trimmed = line.trim();
44
+ if (!trimmed || trimmed.startsWith('#')) continue;
45
+
46
+ const indent = line.search(/\S/);
47
+
48
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
49
+ stack.pop();
50
+ }
51
+
52
+ const top = stack[stack.length - 1];
53
+ let current = top.obj;
54
+
55
+ if (trimmed.startsWith('- ')) {
56
+ const itemStr = trimmed.substring(2).trim();
57
+
58
+ if (!Array.isArray(current)) {
59
+ const parent = stack[stack.length - 2]?.obj;
60
+ if (parent && typeof parent === 'object') {
61
+ const keys = Object.keys(parent);
62
+ const lastKey = keys[keys.length - 1];
63
+ if (lastKey && typeof parent[lastKey] === 'object' && !Array.isArray(parent[lastKey])) {
64
+ const existing = parent[lastKey];
65
+ if (Object.keys(existing).length === 0) {
66
+ parent[lastKey] = [];
67
+ current = parent[lastKey];
68
+ stack[stack.length - 1] = { obj: current, indent: top.indent, isArrayItem: true };
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ if (Array.isArray(current)) {
75
+ const colonIndex = itemStr.indexOf(':');
76
+ if (colonIndex > 0) {
77
+ const item = {};
78
+ const key = itemStr.substring(0, colonIndex).trim();
79
+ let value = itemStr.substring(colonIndex + 1).trim();
80
+ item[key] = parseYamlValue(value);
81
+ current.push(item);
82
+ stack.push({ obj: item, indent, isArrayItem: true });
83
+ } else {
84
+ current.push(parseYamlValue(itemStr));
85
+ }
86
+ }
87
+ continue;
88
+ }
89
+
90
+ const colonIndex = trimmed.indexOf(':');
91
+ if (colonIndex > 0) {
92
+ const key = trimmed.substring(0, colonIndex).trim();
93
+ let value = trimmed.substring(colonIndex + 1).trim();
94
+
95
+ if (value.startsWith('[') && value.endsWith(']')) {
96
+ current[key] = parseInlineArray(value);
97
+ } else if (value) {
98
+ current[key] = parseYamlValue(value);
99
+ } else {
100
+ current[key] = {};
101
+ stack.push({ obj: current[key], indent, isArrayItem: false });
102
+ }
103
+ }
104
+ }
105
+
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * 解析行内数组
111
+ */
112
+ function parseInlineArray(value) {
113
+ const inner = value.slice(1, -1).trim();
114
+ if (!inner) return [];
115
+
116
+ const items = [];
117
+ let current = '';
118
+ let depth = 0;
119
+
120
+ for (const char of inner) {
121
+ if (char === '[') depth++;
122
+ if (char === ']') depth--;
123
+ if (char === ',' && depth === 0) {
124
+ items.push(parseYamlValue(current.trim()));
125
+ current = '';
126
+ } else {
127
+ current += char;
128
+ }
129
+ }
130
+ if (current.trim()) {
131
+ items.push(parseYamlValue(current.trim()));
132
+ }
133
+
134
+ return items;
135
+ }
136
+
137
+ /**
138
+ * 解析 YAML 值
139
+ */
140
+ function parseYamlValue(value) {
141
+ if (!value) return value;
142
+
143
+ if (value.startsWith('[') && value.endsWith(']')) {
144
+ return parseInlineArray(value);
145
+ }
146
+
147
+ if ((value.startsWith('"') && value.endsWith('"')) ||
148
+ (value.startsWith("'") && value.endsWith("'"))) {
149
+ return value.slice(1, -1);
150
+ }
151
+
152
+ if (value === 'true') return true;
153
+ if (value === 'false') return false;
154
+ if (/^-?\d+$/.test(value)) return parseInt(value, 10);
155
+ if (/^-?\d+\.\d+$/.test(value)) return parseFloat(value);
156
+
157
+ return value;
158
+ }
159
+
160
+ /**
161
+ * 简单的 YAML 序列化(降级方案)
162
+ */
163
+ function dumpYamlSimple(obj, indent = 0) {
164
+ const spaces = ' '.repeat(indent);
165
+ let result = '';
166
+
167
+ for (const [key, value] of Object.entries(obj)) {
168
+ if (value === null || value === undefined) continue;
169
+
170
+ if (typeof value === 'object' && !Array.isArray(value)) {
171
+ result += `${spaces}${key}:\n`;
172
+ result += dumpYamlSimple(value, indent + 1);
173
+ } else if (Array.isArray(value)) {
174
+ result += `${spaces}${key}:\n`;
175
+ for (const item of value) {
176
+ if (typeof item === 'object' && item !== null) {
177
+ const entries = Object.entries(item);
178
+ if (entries.length > 0) {
179
+ result += `${spaces} - ${entries[0][0]}: ${serializeValue(entries[0][1])}\n`;
180
+ for (let i = 1; i < entries.length; i++) {
181
+ result += `${spaces} ${entries[i][0]}: ${serializeValue(entries[i][1])}\n`;
182
+ }
183
+ }
184
+ } else {
185
+ result += `${spaces} - ${serializeValue(item)}\n`;
186
+ }
187
+ }
188
+ } else {
189
+ result += `${spaces}${key}: ${serializeValue(value)}\n`;
190
+ }
191
+ }
192
+
193
+ return result;
194
+ }
195
+
196
+ /**
197
+ * 序列化 YAML 值
198
+ */
199
+ function serializeValue(value) {
200
+ if (typeof value === 'string') {
201
+ if (value.includes(':') || value.includes('#') || value.includes('\n')) {
202
+ return `"${value}"`;
203
+ }
204
+ return value;
205
+ }
206
+ if (value === true) return 'true';
207
+ if (value === false) return 'false';
208
+ if (value === null) return 'null';
209
+ return String(value);
210
+ }
211
+
212
+ /**
213
+ * 解析 YAML 内容(异步版本,推荐使用)
214
+ */
215
+ async function parseYamlAsync(content) {
216
+ await ensureYaml();
217
+ if (yaml) {
218
+ return yaml.load(content);
219
+ }
220
+ return parseYamlSimple(content);
221
+ }
222
+
223
+ /**
224
+ * 解析 YAML 内容(同步版本,用于非 async 上下文)
225
+ */
226
+ function parseYaml(content) {
227
+ if (yaml) {
228
+ return yaml.load(content);
229
+ }
230
+ return parseYamlSimple(content);
231
+ }
232
+
233
+ /**
234
+ * 序列化为 YAML(异步版本,推荐使用)
235
+ */
236
+ async function dumpYamlAsync(obj, options = {}) {
237
+ await ensureYaml();
238
+ if (yaml) {
239
+ return yaml.dump(obj, options);
240
+ }
241
+ return dumpYamlSimple(obj);
242
+ }
243
+
244
+ /**
245
+ * 序列化为 YAML(同步版本,用于非 async 上下文)
246
+ */
247
+ function dumpYaml(obj, options = {}) {
248
+ if (yaml) {
249
+ return yaml.dump(obj, options);
250
+ }
251
+ return dumpYamlSimple(obj);
252
+ }
253
+
254
+ // ============================================================
255
+ // 内联常量(来自 constants.js,仅保留 hooks 需要的部分)
256
+ // ============================================================
257
+
258
+ const ENV_DIRS = {
259
+ ROOT: 'environment',
260
+ ENV_KNOWLEDGE: 'environment/env-knowledge',
261
+ MIDDLEWARE: 'environment/env-knowledge/middleware',
262
+ INFRASTRUCTURE: 'environment/env-knowledge/infrastructure',
263
+ ENV_VARIABLES: 'environment/env-knowledge/env-variables',
264
+ COMPONENT_LIB: 'environment/component-lib',
265
+ COMPONENTS: 'environment/component-lib/components',
266
+ BEST_PRACTICES: 'environment/component-lib/best-practices',
267
+ DOMAIN_MODELS: 'environment/component-lib/domain-models',
268
+ INTEGRATION: 'environment/integration',
269
+ CI_CD: 'environment/integration/ci-cd',
270
+ TESTING: 'environment/integration/testing',
271
+ DEPLOYMENT: 'environment/integration/deployment',
272
+ };
273
+
274
+ const ENV_FILES = {
275
+ REGISTRY: 'registry.json',
276
+ DETECTION_PATTERNS: 'detection-patterns.yaml',
277
+ ENVIRONMENT_CONTEXT: 'environment-context.json',
278
+ };
279
+
280
+ // ============================================================
281
+ // 内置检测模式
282
+ // ============================================================
283
+
284
+ /**
285
+ * 内置检测模式
286
+ * 当项目没有自定义模式时使用
287
+ */
288
+ const BUILTIN_PATTERNS = {
289
+ apiVersion: 'autospec/v1',
290
+ kind: 'DetectionPatterns',
291
+ meta: {
292
+ name: 'builtin-patterns',
293
+ version: '1.0.0',
294
+ source: 'framework',
295
+ },
296
+ spec: {
297
+ middleware: {
298
+ mysql: {
299
+ dependencies: [
300
+ { pattern: 'mysql2', packageManager: 'npm' },
301
+ { pattern: 'pymysql', packageManager: 'pip' },
302
+ { pattern: 'mysql-connector-python', packageManager: 'pip' },
303
+ { pattern: 'mysql-connector-java', packageManager: 'maven' },
304
+ ],
305
+ codePatterns: [
306
+ { pattern: 'createPool\\s*\\(', language: 'javascript', confidence: 0.9 },
307
+ { pattern: 'mysql\\.connector', language: 'python', confidence: 0.85 },
308
+ { pattern: 'mysql2/promise', language: 'javascript', confidence: 0.95 },
309
+ { pattern: 'pymysql\\.connect', language: 'python', confidence: 0.95 },
310
+ { pattern: 'com\\.mysql\\.cj', language: 'java', confidence: 0.9 },
311
+ ],
312
+ envVarPatterns: [
313
+ { pattern: 'MYSQL_\\w+', extract: true },
314
+ ],
315
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
316
+ knowledgeTemplate: 'middleware/mysql.yaml',
317
+ },
318
+ redis: {
319
+ dependencies: [
320
+ { pattern: 'ioredis', packageManager: 'npm' },
321
+ { pattern: 'redis', packageManager: 'npm' },
322
+ { pattern: 'redis-py', packageManager: 'pip' },
323
+ { pattern: 'redis', packageManager: 'pip' },
324
+ ],
325
+ codePatterns: [
326
+ { pattern: 'new Redis\\s*\\(', language: 'javascript', confidence: 0.9 },
327
+ { pattern: 'redis\\.Redis', language: 'python', confidence: 0.85 },
328
+ { pattern: 'createClient\\s*\\(', language: 'javascript', confidence: 0.85 },
329
+ { pattern: 'ioredis', language: 'javascript', confidence: 0.95 },
330
+ ],
331
+ envVarPatterns: [
332
+ { pattern: 'REDIS_\\w+', extract: true },
333
+ ],
334
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
335
+ knowledgeTemplate: 'middleware/redis.yaml',
336
+ },
337
+ kafka: {
338
+ dependencies: [
339
+ { pattern: 'kafkajs', packageManager: 'npm' },
340
+ { pattern: 'confluent-kafka', packageManager: 'pip' },
341
+ { pattern: 'kafka-python', packageManager: 'pip' },
342
+ { pattern: 'org.apache.kafka', packageManager: 'maven' },
343
+ ],
344
+ codePatterns: [
345
+ { pattern: 'Kafka\\(|KafkaJS', language: 'javascript', confidence: 0.9 },
346
+ { pattern: 'KafkaConsumer|KafkaProducer', language: 'python', confidence: 0.9 },
347
+ { pattern: 'KafkaProducer|KafkaConsumer', language: 'java', confidence: 0.95 },
348
+ ],
349
+ envVarPatterns: [
350
+ { pattern: 'KAFKA_\\w+', extract: true },
351
+ ],
352
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
353
+ knowledgeTemplate: 'middleware/kafka.yaml',
354
+ },
355
+ mongodb: {
356
+ dependencies: [
357
+ { pattern: 'mongoose', packageManager: 'npm' },
358
+ { pattern: 'mongodb', packageManager: 'npm' },
359
+ { pattern: 'pymongo', packageManager: 'pip' },
360
+ ],
361
+ codePatterns: [
362
+ { pattern: 'mongoose\\.connect', language: 'javascript', confidence: 0.95 },
363
+ { pattern: 'MongoClient', language: 'javascript', confidence: 0.9 },
364
+ { pattern: 'pymongo\\.MongoClient', language: 'python', confidence: 0.95 },
365
+ ],
366
+ envVarPatterns: [
367
+ { pattern: 'MONGO\\w*', extract: true },
368
+ ],
369
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
370
+ knowledgeTemplate: 'middleware/mongodb.yaml',
371
+ },
372
+ elasticsearch: {
373
+ dependencies: [
374
+ { pattern: '@elastic/elasticsearch', packageManager: 'npm' },
375
+ { pattern: 'elasticsearch', packageManager: 'pip' },
376
+ ],
377
+ codePatterns: [
378
+ { pattern: 'Client\\s*\\(', language: 'javascript', confidence: 0.7 },
379
+ { pattern: 'Elasticsearch\\s*\\(', language: 'python', confidence: 0.85 },
380
+ { pattern: '@elastic/elasticsearch', language: 'javascript', confidence: 0.95 },
381
+ ],
382
+ envVarPatterns: [
383
+ { pattern: 'ELASTIC\\w*', extract: true },
384
+ ],
385
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
386
+ knowledgeTemplate: 'middleware/elasticsearch.yaml',
387
+ },
388
+ postgresql: {
389
+ dependencies: [
390
+ { pattern: 'pg', packageManager: 'npm' },
391
+ { pattern: 'psycopg2', packageManager: 'pip' },
392
+ { pattern: 'psycopg', packageManager: 'pip' },
393
+ { pattern: 'org.postgresql', packageManager: 'maven' },
394
+ ],
395
+ codePatterns: [
396
+ { pattern: 'pg\\.Pool|pg\\.Client', language: 'javascript', confidence: 0.9 },
397
+ { pattern: 'psycopg2\\.connect', language: 'python', confidence: 0.95 },
398
+ { pattern: 'postgresql://', language: 'any', confidence: 0.8 },
399
+ ],
400
+ envVarPatterns: [
401
+ { pattern: 'POSTGRES_\\w+|PG_\\w+', extract: true },
402
+ ],
403
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
404
+ knowledgeTemplate: 'middleware/postgresql.yaml',
405
+ },
406
+ rabbitmq: {
407
+ dependencies: [
408
+ { pattern: 'amqplib', packageManager: 'npm' },
409
+ { pattern: 'pika', packageManager: 'pip' },
410
+ { pattern: 'rabbitmq', packageManager: 'pip' },
411
+ ],
412
+ codePatterns: [
413
+ { pattern: 'amqp\\.connect', language: 'javascript', confidence: 0.9 },
414
+ { pattern: 'pika\\.BlockingConnection', language: 'python', confidence: 0.95 },
415
+ { pattern: 'amqplib', language: 'javascript', confidence: 0.9 },
416
+ ],
417
+ envVarPatterns: [
418
+ { pattern: 'RABBITMQ_\\w+|AMQP_\\w+', extract: true },
419
+ ],
420
+ filePatterns: ['**/*.py', '**/*.js', '**/*.ts', '**/*.java'],
421
+ knowledgeTemplate: 'middleware/rabbitmq.yaml',
422
+ },
423
+ },
424
+ components: {
425
+ // 通用组件模式,可被组织配置覆盖
426
+ },
427
+ bestPractices: {
428
+ 'connection-pool': {
429
+ pattern: 'poolSize|connectionLimit|maxConnections|pool_size',
430
+ description: '连接池配置检测',
431
+ appliesTo: ['mysql', 'redis', 'postgresql', 'mongodb'],
432
+ },
433
+ 'error-handling': {
434
+ pattern: 'try\\s*\\{|catch\\s*\\(|\\.catch\\s*\\(',
435
+ description: '错误处理模式',
436
+ appliesTo: ['*'],
437
+ },
438
+ 'retry-mechanism': {
439
+ pattern: 'retry|maxRetry|retryTimes|backoff',
440
+ description: '重试机制',
441
+ appliesTo: ['*'],
442
+ },
443
+ },
444
+ },
445
+ };
446
+
447
+ /**
448
+ * 检测模式加载器
449
+ */
450
+ export class PatternLoader {
451
+ constructor(autospecDir) {
452
+ this.autospecDir = autospecDir;
453
+ this.envDir = path.join(autospecDir, ENV_DIRS.ROOT);
454
+ this.patternsPath = path.join(this.envDir, ENV_FILES.DETECTION_PATTERNS);
455
+ this.patterns = null;
456
+ }
457
+
458
+ /**
459
+ * 加载检测模式
460
+ * 合并内置模式和组织自定义模式
461
+ */
462
+ load() {
463
+ // 1. 从内置模式开始
464
+ let patterns = JSON.parse(JSON.stringify(BUILTIN_PATTERNS));
465
+
466
+ // 2. 加载组织自定义模式(如果存在)
467
+ // 注意:同步版本会使用降级方案 parseYamlSimple
468
+ const orgPatterns = this.loadOrganizationPatterns();
469
+
470
+ if (orgPatterns) {
471
+ // 深度合并:组织模式可覆盖内置模式
472
+ patterns = this.mergePatterns(patterns, orgPatterns);
473
+ }
474
+
475
+ this.patterns = patterns;
476
+ return this.patterns;
477
+ }
478
+
479
+ /**
480
+ * 异步加载检测模式(推荐使用)
481
+ * 合并内置模式和组织自定义模式
482
+ * 会尝试加载 js-yaml 以获得更好的 YAML 解析能力
483
+ */
484
+ async loadAsync() {
485
+ // 确保 js-yaml 已加载(如果可用)
486
+ await ensureYaml();
487
+
488
+ // 1. 从内置模式开始
489
+ let patterns = JSON.parse(JSON.stringify(BUILTIN_PATTERNS));
490
+
491
+ // 2. 加载组织自定义模式(如果存在)
492
+ const orgPatterns = await this.loadOrganizationPatternsAsync();
493
+
494
+ if (orgPatterns) {
495
+ // 深度合并:组织模式可覆盖内置模式
496
+ patterns = this.mergePatterns(patterns, orgPatterns);
497
+ }
498
+
499
+ this.patterns = patterns;
500
+ return this.patterns;
501
+ }
502
+
503
+ /**
504
+ * 加载组织自定义模式(同步版本,使用降级方案)
505
+ */
506
+ loadOrganizationPatterns() {
507
+ if (!fs.existsSync(this.patternsPath)) {
508
+ return null;
509
+ }
510
+
511
+ try {
512
+ const content = fs.readFileSync(this.patternsPath, 'utf-8');
513
+ return parseYaml(content); // 同步版本,可能使用降级方案
514
+ } catch (e) {
515
+ console.warn('Failed to load organization patterns:', e.message);
516
+ return null;
517
+ }
518
+ }
519
+
520
+ /**
521
+ * 加载组织自定义模式(异步版本,推荐使用)
522
+ */
523
+ async loadOrganizationPatternsAsync() {
524
+ if (!fs.existsSync(this.patternsPath)) {
525
+ return null;
526
+ }
527
+
528
+ try {
529
+ const content = fs.readFileSync(this.patternsPath, 'utf-8');
530
+ return await parseYamlAsync(content); // 异步版本,尝试使用 js-yaml
531
+ } catch (e) {
532
+ console.warn('Failed to load organization patterns:', e.message);
533
+ return null;
534
+ }
535
+ }
536
+
537
+ /**
538
+ * 深度合并模式
539
+ */
540
+ mergePatterns(base, override) {
541
+ const result = { ...base };
542
+
543
+ if (override.metadata) {
544
+ result.metadata = { ...base.metadata, ...override.metadata };
545
+ }
546
+
547
+ if (override.spec) {
548
+ result.spec = { ...base.spec };
549
+
550
+ // 合并中间件模式
551
+ if (override.spec.middleware) {
552
+ result.spec.middleware = { ...base.spec.middleware, ...override.spec.middleware };
553
+ }
554
+
555
+ // 合并组件模式
556
+ if (override.spec.components) {
557
+ result.spec.components = { ...base.spec.components, ...override.spec.components };
558
+ }
559
+
560
+ // 合并最佳实践模式
561
+ if (override.spec.bestPractices) {
562
+ result.spec.bestPractices = { ...base.spec.bestPractices, ...override.spec.bestPractices };
563
+ }
564
+ }
565
+
566
+ return result;
567
+ }
568
+
569
+ /**
570
+ * 获取中间件检测模式
571
+ */
572
+ getMiddlewarePatterns() {
573
+ if (!this.patterns) {
574
+ this.load();
575
+ }
576
+ return this.patterns.spec.middleware || {};
577
+ }
578
+
579
+ /**
580
+ * 获取特定中间件的检测模式
581
+ */
582
+ getMiddlewarePattern(name) {
583
+ const patterns = this.getMiddlewarePatterns();
584
+ return patterns[name] || null;
585
+ }
586
+
587
+ /**
588
+ * 获取组件检测模式
589
+ */
590
+ getComponentPatterns() {
591
+ if (!this.patterns) {
592
+ this.load();
593
+ }
594
+ return this.patterns.spec.components || {};
595
+ }
596
+
597
+ /**
598
+ * 获取最佳实践检测模式
599
+ */
600
+ getBestPracticePatterns() {
601
+ if (!this.patterns) {
602
+ this.load();
603
+ }
604
+ return this.patterns.spec.bestPractices || {};
605
+ }
606
+
607
+ /**
608
+ * 获取所有检测模式
609
+ */
610
+ getAllPatterns() {
611
+ if (!this.patterns) {
612
+ this.load();
613
+ }
614
+ return this.patterns;
615
+ }
616
+
617
+ /**
618
+ * 添加自定义中间件模式
619
+ */
620
+ addMiddlewarePattern(name, pattern) {
621
+ if (!this.patterns) {
622
+ this.load();
623
+ }
624
+
625
+ if (!this.patterns.spec.middleware) {
626
+ this.patterns.spec.middleware = {};
627
+ }
628
+
629
+ this.patterns.spec.middleware[name] = pattern;
630
+ this.saveOrganizationPatterns();
631
+ }
632
+
633
+ /**
634
+ * 添加自定义组件模式
635
+ */
636
+ addComponentPattern(name, pattern) {
637
+ if (!this.patterns) {
638
+ this.load();
639
+ }
640
+
641
+ if (!this.patterns.spec.components) {
642
+ this.patterns.spec.components = {};
643
+ }
644
+
645
+ this.patterns.spec.components[name] = pattern;
646
+ this.saveOrganizationPatterns();
647
+ }
648
+
649
+ /**
650
+ * 保存组织自定义模式
651
+ */
652
+ saveOrganizationPatterns() {
653
+ if (!fs.existsSync(this.envDir)) {
654
+ fs.mkdirSync(this.envDir, { recursive: true });
655
+ }
656
+
657
+ // 只保存非内置的模式(标记为组织自定义)
658
+ const orgPatterns = {
659
+ apiVersion: 'autospec/v1',
660
+ kind: 'DetectionPatterns',
661
+ meta: {
662
+ name: 'organization-patterns',
663
+ version: '1.0.0',
664
+ source: 'organization',
665
+ },
666
+ spec: {
667
+ middleware: {},
668
+ components: {},
669
+ bestPractices: {},
670
+ },
671
+ };
672
+
673
+ // 过滤出非内置的模式
674
+ const builtinMiddleware = Object.keys(BUILTIN_PATTERNS.spec.middleware);
675
+ for (const [name, pattern] of Object.entries(this.patterns.spec.middleware || {})) {
676
+ if (!builtinMiddleware.includes(name) || this.isPatternModified(name, pattern, 'middleware')) {
677
+ orgPatterns.spec.middleware[name] = pattern;
678
+ }
679
+ }
680
+
681
+ for (const [name, pattern] of Object.entries(this.patterns.spec.components || {})) {
682
+ orgPatterns.spec.components[name] = pattern;
683
+ }
684
+
685
+ for (const [name, pattern] of Object.entries(this.patterns.spec.bestPractices || {})) {
686
+ if (this.isPatternModified(name, pattern, 'bestPractices')) {
687
+ orgPatterns.spec.bestPractices[name] = pattern;
688
+ }
689
+ }
690
+
691
+ fs.writeFileSync(this.patternsPath, dumpYaml(orgPatterns, { lineWidth: -1 }));
692
+ }
693
+
694
+ /**
695
+ * 检查模式是否被修改
696
+ */
697
+ isPatternModified(name, pattern, category) {
698
+ const builtin = BUILTIN_PATTERNS.spec[category]?.[name];
699
+ if (!builtin) return true;
700
+ return JSON.stringify(builtin) !== JSON.stringify(pattern);
701
+ }
702
+
703
+ /**
704
+ * 验证模式配置
705
+ */
706
+ validatePattern(pattern) {
707
+ const errors = [];
708
+
709
+ if (!pattern.dependencies && !pattern.codePatterns && !pattern.envVarPatterns) {
710
+ errors.push('至少需要定义 dependencies、codePatterns 或 envVarPatterns 之一');
711
+ }
712
+
713
+ if (pattern.dependencies) {
714
+ for (const dep of pattern.dependencies) {
715
+ if (!dep.pattern) {
716
+ errors.push('dependency 必须包含 pattern 字段');
717
+ }
718
+ }
719
+ }
720
+
721
+ if (pattern.codePatterns) {
722
+ for (const cp of pattern.codePatterns) {
723
+ if (!cp.pattern) {
724
+ errors.push('codePattern 必须包含 pattern 字段');
725
+ }
726
+ // 验证正则表达式
727
+ try {
728
+ new RegExp(cp.pattern);
729
+ } catch (e) {
730
+ errors.push(`无效的正则表达式: ${cp.pattern}`);
731
+ }
732
+ }
733
+ }
734
+
735
+ return {
736
+ valid: errors.length === 0,
737
+ errors,
738
+ };
739
+ }
740
+
741
+ /**
742
+ * 从依赖文件检测中间件
743
+ * @param {string} packageJsonPath - package.json 路径
744
+ * @param {string} requirementsPath - requirements.txt 路径
745
+ * @param {string} pomXmlPath - pom.xml 路径
746
+ */
747
+ detectFromDependencies(packageJsonPath, requirementsPath, pomXmlPath) {
748
+ const detected = [];
749
+ const patterns = this.getMiddlewarePatterns();
750
+
751
+ // 检测 npm 依赖
752
+ if (packageJsonPath && fs.existsSync(packageJsonPath)) {
753
+ try {
754
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
755
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
756
+
757
+ for (const [depName] of Object.entries(deps)) {
758
+ for (const [mwName, mwPattern] of Object.entries(patterns)) {
759
+ if (mwPattern.dependencies) {
760
+ for (const dep of mwPattern.dependencies) {
761
+ if (dep.packageManager === 'npm' && this.matchDependency(dep.pattern, depName)) {
762
+ detected.push({
763
+ name: mwName,
764
+ source: 'npm',
765
+ dependency: depName,
766
+ confidence: 0.9,
767
+ });
768
+ }
769
+ }
770
+ }
771
+ }
772
+ }
773
+ } catch (e) {
774
+ // 忽略解析错误
775
+ }
776
+ }
777
+
778
+ // 检测 pip 依赖
779
+ if (requirementsPath && fs.existsSync(requirementsPath)) {
780
+ try {
781
+ const content = fs.readFileSync(requirementsPath, 'utf-8');
782
+ const lines = content.split('\n');
783
+
784
+ for (const line of lines) {
785
+ const depName = line.split(/[=<>]/)[0].trim();
786
+ if (!depName || depName.startsWith('#')) continue;
787
+
788
+ for (const [mwName, mwPattern] of Object.entries(patterns)) {
789
+ if (mwPattern.dependencies) {
790
+ for (const dep of mwPattern.dependencies) {
791
+ if (dep.packageManager === 'pip' && this.matchDependency(dep.pattern, depName)) {
792
+ detected.push({
793
+ name: mwName,
794
+ source: 'pip',
795
+ dependency: depName,
796
+ confidence: 0.9,
797
+ });
798
+ }
799
+ }
800
+ }
801
+ }
802
+ }
803
+ } catch (e) {
804
+ // 忽略解析错误
805
+ }
806
+ }
807
+
808
+ // 检测 maven 依赖
809
+ if (pomXmlPath && fs.existsSync(pomXmlPath)) {
810
+ try {
811
+ const content = fs.readFileSync(pomXmlPath, 'utf-8');
812
+ // 简单的 XML 解析,提取 groupId:artifactId
813
+ const depMatches = content.matchAll(/<dependency>[\s\S]*?<groupId>([^<]+)<\/groupId>[\s\S]*?<artifactId>([^<]+)<\/artifactId>[\s\S]*?<\/dependency>/g);
814
+
815
+ for (const match of depMatches) {
816
+ const depName = `${match[1]}:${match[2]}`;
817
+
818
+ for (const [mwName, mwPattern] of Object.entries(patterns)) {
819
+ if (mwPattern.dependencies) {
820
+ for (const dep of mwPattern.dependencies) {
821
+ if (dep.packageManager === 'maven' && this.matchDependency(dep.pattern, depName)) {
822
+ detected.push({
823
+ name: mwName,
824
+ source: 'maven',
825
+ dependency: depName,
826
+ confidence: 0.9,
827
+ });
828
+ }
829
+ }
830
+ }
831
+ }
832
+ }
833
+ } catch (e) {
834
+ // 忽略解析错误
835
+ }
836
+ }
837
+
838
+ // 去重
839
+ const unique = [];
840
+ const seen = new Set();
841
+ for (const item of detected) {
842
+ const key = item.name;
843
+ if (!seen.has(key)) {
844
+ seen.add(key);
845
+ unique.push(item);
846
+ }
847
+ }
848
+
849
+ return unique;
850
+ }
851
+
852
+ /**
853
+ * 匹配依赖名称
854
+ */
855
+ matchDependency(pattern, depName) {
856
+ if (pattern.startsWith('^') || pattern.includes('*')) {
857
+ // 简单的通配符匹配
858
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
859
+ return regex.test(depName);
860
+ }
861
+ return depName === pattern || depName.includes(pattern);
862
+ }
863
+ }
864
+
865
+ export default PatternLoader;