speccore 6.82.0 → 6.89.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.
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +178 -34
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/change.d.ts.map +1 -1
- package/dist/commands/change.js +39 -1
- package/dist/commands/change.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +118 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +75 -38
- package/dist/commands/pr.js.map +1 -1
- package/dist/core/agents/defaults/_INDEX.md +68 -0
- package/dist/core/agents/defaults/_TEMPLATE.md +34 -0
- package/dist/core/agents/defaults/code-reviewer.md +49 -0
- package/dist/core/agents/defaults/compiler.md +25 -0
- package/dist/core/agents/defaults/compliance-checker.md +38 -0
- package/dist/core/agents/defaults/dependency-analyst.md +42 -0
- package/dist/core/agents/defaults/doc-sync-agent.md +25 -0
- package/dist/core/agents/defaults/impact-analyst.md +37 -0
- package/dist/core/agents/defaults/interaction-designer.md +73 -0
- package/dist/core/agents/defaults/performance-expert.md +35 -0
- package/dist/core/agents/defaults/product-analyst-backend.md +68 -0
- package/dist/core/agents/defaults/product-analyst-frontend.md +72 -0
- package/dist/core/agents/defaults/product-analyst.md +48 -0
- package/dist/core/agents/defaults/regression-tester.md +36 -0
- package/dist/core/agents/defaults/risk-assessor.md +38 -0
- package/dist/core/agents/defaults/schedule-planner.md +37 -0
- package/dist/core/agents/defaults/security-reviewer-finance.md +67 -0
- package/dist/core/agents/defaults/security-reviewer.md +43 -0
- package/dist/core/agents/defaults/task-decomposer.md +33 -0
- package/dist/core/agents/defaults/test-engineer.md +25 -0
- package/dist/core/agents/defaults/test-reviewer.md +48 -0
- package/dist/core/agents/engine/agent-executor.d.ts +50 -0
- package/dist/core/agents/engine/agent-executor.d.ts.map +1 -0
- package/dist/core/agents/engine/agent-executor.js +225 -0
- package/dist/core/agents/engine/agent-executor.js.map +1 -0
- package/dist/core/agents/engine/agent-loader.d.ts +58 -0
- package/dist/core/agents/engine/agent-loader.d.ts.map +1 -0
- package/dist/core/agents/engine/agent-loader.js +377 -0
- package/dist/core/agents/engine/agent-loader.js.map +1 -0
- package/dist/core/agents/engine/types.d.ts +71 -0
- package/dist/core/agents/engine/types.d.ts.map +1 -0
- package/dist/core/agents/engine/types.js +8 -0
- package/dist/core/agents/engine/types.js.map +1 -0
- package/dist/core/agents/index.d.ts +12 -0
- package/dist/core/agents/index.d.ts.map +1 -0
- package/dist/core/agents/index.js +31 -0
- package/dist/core/agents/index.js.map +1 -0
- package/dist/core/agents/product-analyst.d.ts +17 -0
- package/dist/core/agents/product-analyst.d.ts.map +1 -0
- package/dist/core/agents/product-analyst.js +188 -0
- package/dist/core/agents/product-analyst.js.map +1 -0
- package/dist/core/command-loader.d.ts +31 -0
- package/dist/core/command-loader.d.ts.map +1 -0
- package/dist/core/command-loader.js +76 -0
- package/dist/core/command-loader.js.map +1 -0
- package/dist/core/commands/defaults/change-impact.md +40 -0
- package/dist/core/commands/defaults/pr-review.md +42 -0
- package/dist/core/commands/defaults/refactor.md +37 -0
- package/dist/core/context-injector.d.ts +56 -0
- package/dist/core/context-injector.d.ts.map +1 -0
- package/dist/core/context-injector.js +122 -0
- package/dist/core/context-injector.js.map +1 -0
- package/dist/core/hook-runner.d.ts +36 -0
- package/dist/core/hook-runner.d.ts.map +1 -0
- package/dist/core/hook-runner.js +93 -0
- package/dist/core/hook-runner.js.map +1 -0
- package/dist/core/hooks/defaults/post-execute.md +22 -0
- package/dist/core/hooks/defaults/pre-execute.md +18 -0
- package/dist/core/prompt-builder.d.ts +1 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +60 -1
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/requirement-clarifier.d.ts +2 -1
- package/dist/core/requirement-clarifier.d.ts.map +1 -1
- package/dist/core/requirement-clarifier.js +78 -1
- package/dist/core/requirement-clarifier.js.map +1 -1
- package/dist/core/rule-loader.d.ts +38 -0
- package/dist/core/rule-loader.d.ts.map +1 -0
- package/dist/core/rule-loader.js +156 -0
- package/dist/core/rule-loader.js.map +1 -0
- package/dist/core/rules/defaults/_INDEX.md +16 -0
- package/dist/core/rules/defaults/api-design.md +44 -0
- package/dist/core/rules/defaults/database.md +37 -0
- package/dist/core/rules/defaults/frontend-common.md +38 -0
- package/dist/core/rules/defaults/nodejs.md +38 -0
- package/dist/core/rules/defaults/react.md +34 -0
- package/dist/core/rules/defaults/security.md +31 -0
- package/dist/core/rules/defaults/testing.md +35 -0
- package/dist/core/rules/defaults/typescript.md +36 -0
- package/dist/core/skill-loader.d.ts +28 -0
- package/dist/core/skill-loader.d.ts.map +1 -0
- package/dist/core/skill-loader.js +102 -0
- package/dist/core/skill-loader.js.map +1 -0
- package/dist/core/skills/defaults/caching.md +33 -0
- package/dist/core/skills/defaults/db-migration.md +46 -0
- package/dist/core/skills/defaults/deployment.md +50 -0
- package/dist/core/skills/defaults/logging.md +38 -0
- package/dist/core/verify-engine.d.ts +7 -0
- package/dist/core/verify-engine.d.ts.map +1 -1
- package/dist/core/verify-engine.js +27 -1
- package/dist/core/verify-engine.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RULES 规范库加载器
|
|
4
|
+
*
|
|
5
|
+
* 负责:
|
|
6
|
+
* 1. 扫描 .speccore/RULES/ 目录下的规范定义文件
|
|
7
|
+
* 2. 根据技术栈(从 CONSTITUTION.md 解析)匹配对应的规范
|
|
8
|
+
* 3. 按优先级合并规范内容
|
|
9
|
+
* 4. 注入到代码生成 prompt 中
|
|
10
|
+
*
|
|
11
|
+
* v6.85.0+
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.resolveRulesForTechStack = resolveRulesForTechStack;
|
|
15
|
+
exports.formatRulesPrompt = formatRulesPrompt;
|
|
16
|
+
exports.getBuiltinRuleContents = getBuiltinRuleContents;
|
|
17
|
+
const path_1 = require("path");
|
|
18
|
+
const fs_extra_1 = require("fs-extra");
|
|
19
|
+
const BUILTIN_RULES_DIR = (0, path_1.join)(__dirname, 'rules', 'defaults');
|
|
20
|
+
/**
|
|
21
|
+
* 扫描目录下的规则文件
|
|
22
|
+
* 文件名即规则名(不含 .md),内容即规则定义
|
|
23
|
+
*/
|
|
24
|
+
async function scanRuleFiles(dir) {
|
|
25
|
+
if (!(await (0, fs_extra_1.pathExists)(dir)))
|
|
26
|
+
return [];
|
|
27
|
+
const entries = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
|
|
28
|
+
const rules = [];
|
|
29
|
+
for (const e of entries) {
|
|
30
|
+
if (!e.isFile() || !e.name.endsWith('.md'))
|
|
31
|
+
continue;
|
|
32
|
+
if (e.name.startsWith('_'))
|
|
33
|
+
continue; // _INDEX.md, _TEMPLATE.md 跳过
|
|
34
|
+
const content = await (0, fs_extra_1.readFile)((0, path_1.join)(dir, e.name), 'utf-8');
|
|
35
|
+
rules.push({
|
|
36
|
+
name: e.name.replace(/\.md$/, ''),
|
|
37
|
+
content,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return rules;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 解析规则文件中的元信息
|
|
44
|
+
* 从 frontmatter 或特定章节提取 appliesTo 和 priority
|
|
45
|
+
*/
|
|
46
|
+
function parseRuleMeta(content) {
|
|
47
|
+
const appliesTo = [];
|
|
48
|
+
let priority = 50;
|
|
49
|
+
// 尝试从 frontmatter 解析
|
|
50
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n/);
|
|
51
|
+
if (frontmatterMatch) {
|
|
52
|
+
const fm = frontmatterMatch[1];
|
|
53
|
+
const appliesMatch = fm.match(/appliesTo:\s*\n((\s+-\s+.+\n)+)/);
|
|
54
|
+
if (appliesMatch) {
|
|
55
|
+
for (const line of appliesMatch[1].matchAll(/-\s+(.+)/g)) {
|
|
56
|
+
appliesTo.push(line[1].trim().toLowerCase());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const priorityMatch = fm.match(/priority:\s*(\d+)/);
|
|
60
|
+
if (priorityMatch)
|
|
61
|
+
priority = parseInt(priorityMatch[1], 10);
|
|
62
|
+
}
|
|
63
|
+
// 如果没有 frontmatter,尝试从标题推断 appliesTo
|
|
64
|
+
if (appliesTo.length === 0) {
|
|
65
|
+
const headingMatch = content.match(/^#\s+(.+)$/m);
|
|
66
|
+
if (headingMatch) {
|
|
67
|
+
const title = headingMatch[1].toLowerCase();
|
|
68
|
+
// 简单推断:文件名/标题中的技术关键词
|
|
69
|
+
const techKeywords = ['typescript', 'react', 'vue', 'angular', 'nodejs', 'java', 'go', 'python', 'spring', 'nestjs', 'gin', 'fastapi'];
|
|
70
|
+
for (const kw of techKeywords) {
|
|
71
|
+
if (title.includes(kw))
|
|
72
|
+
appliesTo.push(kw);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { appliesTo, priority };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 加载所有可用规则(内置 + 用户自定义,用户自定义覆盖)
|
|
80
|
+
*/
|
|
81
|
+
async function loadAllRules(projectRoot) {
|
|
82
|
+
const userRulesDir = (0, path_1.join)(projectRoot, '.speccore', 'RULES');
|
|
83
|
+
const ruleMap = new Map();
|
|
84
|
+
// 1. 加载内置默认
|
|
85
|
+
const builtinFiles = await scanRuleFiles(BUILTIN_RULES_DIR);
|
|
86
|
+
for (const f of builtinFiles) {
|
|
87
|
+
const meta = parseRuleMeta(f.content);
|
|
88
|
+
ruleMap.set(f.name, {
|
|
89
|
+
name: f.name,
|
|
90
|
+
content: f.content,
|
|
91
|
+
appliesTo: meta.appliesTo,
|
|
92
|
+
priority: meta.priority,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// 2. 用户自定义覆盖
|
|
96
|
+
const userFiles = await scanRuleFiles(userRulesDir);
|
|
97
|
+
for (const f of userFiles) {
|
|
98
|
+
const meta = parseRuleMeta(f.content);
|
|
99
|
+
ruleMap.set(f.name, {
|
|
100
|
+
name: f.name,
|
|
101
|
+
content: f.content,
|
|
102
|
+
appliesTo: meta.appliesTo,
|
|
103
|
+
priority: meta.priority,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return Array.from(ruleMap.values());
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 根据技术栈标识符匹配适用的规则
|
|
110
|
+
*
|
|
111
|
+
* 技术栈标识符来自 CONSTITUTION.md 的解析结果,如:
|
|
112
|
+
* - 'typescript', 'react', 'nodejs', 'mysql'
|
|
113
|
+
* - 'java', 'spring-boot'
|
|
114
|
+
* - 'vue', 'pinia'
|
|
115
|
+
*/
|
|
116
|
+
async function resolveRulesForTechStack(techStackIdentifiers, projectRoot) {
|
|
117
|
+
const allRules = await loadAllRules(projectRoot);
|
|
118
|
+
const identifiers = techStackIdentifiers.map(s => s.toLowerCase());
|
|
119
|
+
const matched = allRules.filter(rule => {
|
|
120
|
+
// 规则匹配:任一标识符匹配即生效
|
|
121
|
+
return rule.appliesTo.some(tag => identifiers.includes(tag));
|
|
122
|
+
});
|
|
123
|
+
// 按优先级排序(高优先级在前)
|
|
124
|
+
matched.sort((a, b) => b.priority - a.priority);
|
|
125
|
+
return matched;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 将匹配的规则合并为单个 prompt 字符串
|
|
129
|
+
*/
|
|
130
|
+
function formatRulesPrompt(rules) {
|
|
131
|
+
if (rules.length === 0)
|
|
132
|
+
return '';
|
|
133
|
+
const sections = [];
|
|
134
|
+
sections.push('## 编码规范');
|
|
135
|
+
sections.push('');
|
|
136
|
+
sections.push('> 以下规范来自项目配置,必须严格遵守。');
|
|
137
|
+
sections.push('');
|
|
138
|
+
for (const rule of rules) {
|
|
139
|
+
// 只提取规则内容(去掉 frontmatter)
|
|
140
|
+
let content = rule.content;
|
|
141
|
+
content = content.replace(/^---\n[\s\S]*?\n---\n/, ''); // 移除 frontmatter
|
|
142
|
+
content = content.trim();
|
|
143
|
+
sections.push(`### ${rule.name}`);
|
|
144
|
+
sections.push('');
|
|
145
|
+
sections.push(content);
|
|
146
|
+
sections.push('');
|
|
147
|
+
}
|
|
148
|
+
return sections.join('\n');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 获取内置规则的原始内容(用于 init 时复制到项目)
|
|
152
|
+
*/
|
|
153
|
+
async function getBuiltinRuleContents() {
|
|
154
|
+
return scanRuleFiles(BUILTIN_RULES_DIR);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=rule-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-loader.js","sourceRoot":"","sources":["../../src/core/rule-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# RULES 注册表
|
|
2
|
+
|
|
3
|
+
> 本文件列出所有可用规范及其适用的技术栈。
|
|
4
|
+
> 新增规范后,在本文件中注册即可。
|
|
5
|
+
|
|
6
|
+
| 规范文件 | 适用技术栈 | 优先级 | 说明 |
|
|
7
|
+
|---------|-----------|--------|------|
|
|
8
|
+
| typescript.md | typescript | 100 | TypeScript 类型安全与命名规范 |
|
|
9
|
+
| react.md | react | 90 | React 组件设计与 Hooks 规范 |
|
|
10
|
+
| vue.md | vue | 90 | Vue 组合式 API 与响应式规范 |
|
|
11
|
+
| nodejs.md | nodejs, nestjs | 80 | Node.js / NestJS 服务端规范 |
|
|
12
|
+
| api-design.md | api, rest, graphql | 70 | API 设计通用规范 |
|
|
13
|
+
| testing.md | test, jest, vitest | 60 | 测试策略与用例规范 |
|
|
14
|
+
| security.md | security | 100 | 安全编码强制规范 |
|
|
15
|
+
| database.md | database, mysql, postgresql | 70 | 数据库设计与查询规范 |
|
|
16
|
+
| frontend-common.md | frontend, web | 50 | 前端跨框架通用规范 |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- api
|
|
4
|
+
- rest
|
|
5
|
+
- graphql
|
|
6
|
+
priority: 70
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# API 设计规范
|
|
10
|
+
|
|
11
|
+
## 通用原则
|
|
12
|
+
|
|
13
|
+
- **幂等性**:GET/PUT/DELETE 必须幂等;POST 非幂等但需防重放。
|
|
14
|
+
- **版本控制**:URL 路径版本(`/api/v1/`)或 Header 版本(`Accept: application/vnd.api.v1+json`)。
|
|
15
|
+
- **分页规范**:
|
|
16
|
+
```
|
|
17
|
+
GET /api/v1/users?page=1&size=20
|
|
18
|
+
Response: { "data": [], "pagination": { "page": 1, "size": 20, "total": 100 } }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 请求规范
|
|
22
|
+
|
|
23
|
+
- **Content-Type**:JSON API 统一使用 `application/json`。
|
|
24
|
+
- **字段命名**:camelCase(JavaScript/TypeScript)或 snake_case(Python/Java),全项目统一。
|
|
25
|
+
- **批量操作**:使用 `POST /batch` 或 `PATCH` 批量更新,限制单次批量大小(最大 100)。
|
|
26
|
+
|
|
27
|
+
## 响应规范
|
|
28
|
+
|
|
29
|
+
- **成功响应**:HTTP 200 + 业务 code 0。
|
|
30
|
+
- **错误响应**:HTTP 4xx/5xx + 结构化错误信息:
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"code": 1001,
|
|
34
|
+
"message": "用户不存在",
|
|
35
|
+
"details": { "field": "userId", "issue": "not_found" }
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
- **空列表**:返回空数组 `[]`,不要返回 null 或 404。
|
|
39
|
+
|
|
40
|
+
## 安全
|
|
41
|
+
|
|
42
|
+
- **鉴权**:使用 JWT / OAuth2,Token 放在 `Authorization: Bearer <token>`。
|
|
43
|
+
- **限流**:关键接口必须配置 Rate Limiting(如 100 req/min)。
|
|
44
|
+
- **CORS**:显式配置允许的 Origin,禁止 `*` 在生产环境使用。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- database
|
|
4
|
+
- mysql
|
|
5
|
+
- postgresql
|
|
6
|
+
- mongodb
|
|
7
|
+
priority: 70
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 数据库规范
|
|
11
|
+
|
|
12
|
+
## 命名规范
|
|
13
|
+
|
|
14
|
+
- **表名**:snake_case,复数形式(如 `users`、`order_items`)。
|
|
15
|
+
- **字段名**:snake_case,避免保留字。
|
|
16
|
+
- **索引名**:`idx_{表名}_{字段名}`,唯一索引 `uk_{表名}_{字段名}`。
|
|
17
|
+
- **外键名**:`fk_{表名}_{引用表名}`。
|
|
18
|
+
|
|
19
|
+
## 表设计
|
|
20
|
+
|
|
21
|
+
- **主键**:使用自增 INT/BIGINT 或 UUID,禁止业务字段做主键。
|
|
22
|
+
- **时间戳**:每张表必须包含 `created_at` 和 `updated_at`。
|
|
23
|
+
- **软删除**:使用 `deleted_at` 或 `is_deleted`,禁止物理删除业务数据。
|
|
24
|
+
- **字段注释**:每个字段必须有注释说明用途和取值范围。
|
|
25
|
+
|
|
26
|
+
## 查询规范
|
|
27
|
+
|
|
28
|
+
- **SELECT 显式列名**:禁止 `SELECT *`,只查询需要的字段。
|
|
29
|
+
- **索引使用**:WHERE、JOIN、ORDER BY 字段必须有索引,定期用 `EXPLAIN` 检查。
|
|
30
|
+
- **大表策略**:单表超过 1000 万行必须考虑分表/分区/归档。
|
|
31
|
+
- **批量操作**:IN 子句参数不超过 1000 个,大批量使用分批处理。
|
|
32
|
+
|
|
33
|
+
## 迁移规范
|
|
34
|
+
|
|
35
|
+
- **版本化**:所有 schema 变更通过迁移脚本执行(如 TypeORM migration、Flyway)。
|
|
36
|
+
- **可回滚**:每个迁移必须有 `up()` 和 `down()`。
|
|
37
|
+
- **数据安全**:生产环境迁移先备份,禁止直接 `DROP COLUMN`/`DROP TABLE`。
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- frontend
|
|
4
|
+
- web
|
|
5
|
+
- h5
|
|
6
|
+
priority: 50
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# 前端通用规范
|
|
10
|
+
|
|
11
|
+
## 响应式设计
|
|
12
|
+
|
|
13
|
+
- **移动端优先**:设计从移动端断点开始,逐步增强到桌面端。
|
|
14
|
+
- **断点标准**:
|
|
15
|
+
- Mobile: < 768px
|
|
16
|
+
- Tablet: 768px - 1024px
|
|
17
|
+
- Desktop: > 1024px
|
|
18
|
+
- **弹性布局**:优先使用 Flexbox / Grid,避免固定像素宽度。
|
|
19
|
+
|
|
20
|
+
## 无障碍(a11y)
|
|
21
|
+
|
|
22
|
+
- **语义化标签**:使用 `<header>`、`<nav>`、`<main>`、`<footer>` 等语义标签。
|
|
23
|
+
- **表单关联**:`<label>` 必须通过 `for` 或嵌套关联到 `<input>`。
|
|
24
|
+
- **焦点管理**:所有可交互元素必须有可见的焦点样式。
|
|
25
|
+
- **ARIA**:复杂组件(如 Tabs、Modal)使用正确的 ARIA 角色和属性。
|
|
26
|
+
- **颜色对比**:文本与背景对比度 ≥ 4.5:1(WCAG AA)。
|
|
27
|
+
|
|
28
|
+
## 国际化(i18n)
|
|
29
|
+
|
|
30
|
+
- **文本外置**:所有用户可见文本使用 i18n key,禁止硬编码中文/英文。
|
|
31
|
+
- **日期/数字**:使用 `Intl.DateTimeFormat`、`Intl.NumberFormat` 本地化。
|
|
32
|
+
- **RTL**:布局支持从右到左(阿拉伯语、希伯来语)。
|
|
33
|
+
|
|
34
|
+
## 性能
|
|
35
|
+
|
|
36
|
+
- **图片优化**:使用 WebP/AVIF,提供响应式图片 `srcset`。
|
|
37
|
+
- **代码分割**:路由级懒加载,组件级按需加载。
|
|
38
|
+
- **资源缓存**:静态资源使用长期缓存(hash 文件名)。
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- nodejs
|
|
4
|
+
- node
|
|
5
|
+
- nestjs
|
|
6
|
+
- express
|
|
7
|
+
priority: 80
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Node.js / NestJS 服务端规范
|
|
11
|
+
|
|
12
|
+
## API 设计
|
|
13
|
+
|
|
14
|
+
- **RESTful 标准**:使用 HTTP 方法表达语义(GET/POST/PUT/DELETE/PATCH)。
|
|
15
|
+
- **路由规范**:`/api/v{版本}/{模块}/{资源}`,如 `/api/v1/users`。
|
|
16
|
+
- **状态码**:正确使用 HTTP 状态码(200/201/204/400/401/403/404/409/422/500)。
|
|
17
|
+
- **统一响应格式**:
|
|
18
|
+
```json
|
|
19
|
+
{ "code": 0, "data": {}, "message": "ok" }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 错误处理
|
|
23
|
+
|
|
24
|
+
- **全局异常过滤器**:NestJS 使用 `ExceptionFilter`,Express 使用中间件。
|
|
25
|
+
- **业务异常**:自定义 `BusinessException`,必须包含错误码和可读消息。
|
|
26
|
+
- **不暴露内部错误**:生产环境不返回堆栈信息。
|
|
27
|
+
|
|
28
|
+
## 依赖注入
|
|
29
|
+
|
|
30
|
+
- **NestJS**:优先使用构造函数注入,避免 `@Inject()` 字符串令牌。
|
|
31
|
+
- **分层架构**:Controller → Service → Repository,禁止跨层调用。
|
|
32
|
+
- **接口隔离**:Service 层面向接口编程,便于测试和替换。
|
|
33
|
+
|
|
34
|
+
## 数据访问
|
|
35
|
+
|
|
36
|
+
- **ORM 优先**:使用 TypeORM / Prisma / Sequelize,禁止裸写 SQL(复杂查询除外)。
|
|
37
|
+
- **事务边界**:多表操作必须使用事务,通过装饰器或显式事务管理。
|
|
38
|
+
- **N+1 防护**:使用 `relations` + `select` 或 DataLoader 避免 N+1 查询。
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- react
|
|
4
|
+
- reactjs
|
|
5
|
+
priority: 90
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# React 组件规范
|
|
9
|
+
|
|
10
|
+
## 组件设计
|
|
11
|
+
|
|
12
|
+
- **函数组件优先**:所有新组件使用函数组件 + Hooks。
|
|
13
|
+
- **单一职责**:一个组件只负责一个功能,超过 200 行必须拆分。
|
|
14
|
+
- **Props 接口**:必须定义 `interface Props`,禁止用 `any`。
|
|
15
|
+
- **默认导出**:页面级组件默认导出,业务组件命名导出。
|
|
16
|
+
|
|
17
|
+
## Hooks 规范
|
|
18
|
+
|
|
19
|
+
- **自定义 Hooks**:复用逻辑必须抽成自定义 Hook,以 `use` 开头。
|
|
20
|
+
- **依赖数组**:`useEffect`、`useMemo`、`useCallback` 的依赖数组必须完整。
|
|
21
|
+
- **禁止在循环/条件中调用 Hooks**。
|
|
22
|
+
- **清理副作用**:`useEffect` 返回清理函数(订阅、定时器、事件监听)。
|
|
23
|
+
|
|
24
|
+
## 状态管理
|
|
25
|
+
|
|
26
|
+
- **局部状态优先**:能用 `useState` 就不用全局状态。
|
|
27
|
+
- **全局状态**:使用 Context + useReducer 或 Redux/Zustand,禁止 prop drilling 超过 3 层。
|
|
28
|
+
- **表单状态**:复杂表单使用 React Hook Form 或 Formik。
|
|
29
|
+
|
|
30
|
+
## 性能
|
|
31
|
+
|
|
32
|
+
- **.memo 使用**:仅对纯展示组件且接收复杂 props 时使用。
|
|
33
|
+
- **懒加载**:路由级组件使用 `React.lazy()` + `Suspense`。
|
|
34
|
+
- **避免内联对象/函数**:作为 props 传递时会导致不必要的重渲染。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- security
|
|
4
|
+
priority: 100
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 安全编码规范
|
|
8
|
+
|
|
9
|
+
## 输入验证
|
|
10
|
+
|
|
11
|
+
- **不信任任何输入**:所有用户输入必须校验(长度、类型、范围、格式)。
|
|
12
|
+
- **白名单校验**:优先使用允许列表(白名单),而非禁止列表(黑名单)。
|
|
13
|
+
- **参数化查询**:数据库查询必须使用参数化/预处理语句,禁止字符串拼接 SQL。
|
|
14
|
+
|
|
15
|
+
## 认证与授权
|
|
16
|
+
|
|
17
|
+
- **最小权限原则**:每个接口明确所需权限,默认拒绝。
|
|
18
|
+
- **敏感操作二次确认**:资金操作、数据删除等需要额外验证(如短信/密码)。
|
|
19
|
+
- **Token 安全**:JWT 设置合理过期时间(Access Token 15min,Refresh Token 7d),使用 HTTPS 传输。
|
|
20
|
+
|
|
21
|
+
## 数据保护
|
|
22
|
+
|
|
23
|
+
- **敏感数据加密**:密码使用 bcrypt/argon2,身份证号/银行卡号使用 AES-256 加密存储。
|
|
24
|
+
- **日志脱敏**:日志中不出现明文密码、Token、身份证号。
|
|
25
|
+
- **防泄漏**:错误响应不暴露堆栈、数据库结构、内部路径。
|
|
26
|
+
|
|
27
|
+
## 常见漏洞防护
|
|
28
|
+
|
|
29
|
+
- **XSS**:输出到 DOM 前转义,使用框架内置的 XSS 防护(React/Vue 自动转义)。
|
|
30
|
+
- **CSRF**:状态变更操作使用 CSRF Token 或 SameSite Cookie。
|
|
31
|
+
- **文件上传**:限制文件类型(白名单)、大小、存储路径(禁止执行权限)。
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- test
|
|
4
|
+
- jest
|
|
5
|
+
- vitest
|
|
6
|
+
- testing
|
|
7
|
+
priority: 60
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 测试规范
|
|
11
|
+
|
|
12
|
+
## 测试策略
|
|
13
|
+
|
|
14
|
+
- **测试金字塔**:单元测试(70%)→ 集成测试(20%)→ E2E 测试(10%)。
|
|
15
|
+
- **覆盖目标**:核心业务逻辑覆盖率 ≥ 80%,分支覆盖率 ≥ 70%。
|
|
16
|
+
- **测试文件名**:`{module}.test.ts` 或 `{module}.spec.ts`,与源码同目录或 `__tests__/` 下。
|
|
17
|
+
|
|
18
|
+
## 单元测试
|
|
19
|
+
|
|
20
|
+
- **独立性**:每个测试用例独立,不依赖执行顺序。
|
|
21
|
+
- **Arrange-Act-Assert**:三段式结构清晰。
|
|
22
|
+
- **Mock 外部依赖**:HTTP 请求、数据库、文件系统必须 Mock。
|
|
23
|
+
- **命名规范**:`should {预期行为} when {条件}`,如 `should return 401 when token is expired`。
|
|
24
|
+
|
|
25
|
+
## 集成测试
|
|
26
|
+
|
|
27
|
+
- **真实依赖**:使用测试数据库(如 SQLite 内存 / TestContainers)。
|
|
28
|
+
- **环境隔离**:每个测试套件前清理数据,后回滚事务。
|
|
29
|
+
- **API 契约**:验证请求/响应格式符合 OpenAPI 定义。
|
|
30
|
+
|
|
31
|
+
## 禁止
|
|
32
|
+
|
|
33
|
+
- 不在测试中写逻辑(如 if/for),只调用和断言。
|
|
34
|
+
- 不测试第三方库(如测试 `lodash` 的 `debounce`)。
|
|
35
|
+
- 不提交 `.only`、`.skip` 到主分支。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
appliesTo:
|
|
3
|
+
- typescript
|
|
4
|
+
- ts
|
|
5
|
+
priority: 100
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# TypeScript 编码规范
|
|
9
|
+
|
|
10
|
+
## 类型安全
|
|
11
|
+
|
|
12
|
+
- **禁止 `any`**:除非与第三方库交互,否则不使用 `any`。使用 `unknown` + 类型守卫替代。
|
|
13
|
+
- **禁止 `@ts-ignore`**:必须使用 `@ts-expect-error` 并附注释说明原因。
|
|
14
|
+
- **严格模式**:项目必须开启 `strict: true`。
|
|
15
|
+
- **显式返回类型**:公共 API 函数必须声明返回类型。
|
|
16
|
+
|
|
17
|
+
## 命名规范
|
|
18
|
+
|
|
19
|
+
- 类型/接口:`PascalCase`(如 `UserProfile`)
|
|
20
|
+
- 变量/函数:`camelCase`(如 `getUserName`)
|
|
21
|
+
- 常量:`UPPER_SNAKE_CASE`(如 `MAX_RETRY_COUNT`)
|
|
22
|
+
- 枚举:`PascalCase`,成员 `UPPER_SNAKE_CASE`
|
|
23
|
+
- 布尔变量:使用 `is`、`has`、`should` 前缀(如 `isLoading`)
|
|
24
|
+
|
|
25
|
+
## 模块组织
|
|
26
|
+
|
|
27
|
+
- 一个文件一个核心导出(类/函数/组件)
|
|
28
|
+
- 工具函数按领域分组(`utils/validation.ts`、`utils/date.ts`)
|
|
29
|
+
- barrel export 使用 `index.ts` 统一暴露模块公共 API
|
|
30
|
+
- 禁止循环依赖
|
|
31
|
+
|
|
32
|
+
## 异步规范
|
|
33
|
+
|
|
34
|
+
- 优先使用 `async/await`,避免回调地狱
|
|
35
|
+
- Promise 链必须有 `.catch()` 或 `try/catch`
|
|
36
|
+
- 并行请求使用 `Promise.all()`,但注意错误处理
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SKILLS 可复用技能库加载器
|
|
3
|
+
*
|
|
4
|
+
* 负责:
|
|
5
|
+
* 1. 扫描 .speccore/SKILLS/ 目录下的技能定义文件
|
|
6
|
+
* 2. 根据任务类型/关键词匹配对应的技能
|
|
7
|
+
* 3. 注入到代码生成 prompt 中
|
|
8
|
+
*
|
|
9
|
+
* v6.88.0+
|
|
10
|
+
*/
|
|
11
|
+
export interface SkillDefinition {
|
|
12
|
+
name: string;
|
|
13
|
+
content: string;
|
|
14
|
+
tags: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 根据任务关键词匹配适用的技能
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveSkillsForTask(taskKeywords: string[], projectRoot: string): Promise<SkillDefinition[]>;
|
|
20
|
+
/**
|
|
21
|
+
* 将匹配的技能合并为 prompt 字符串
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatSkillsPrompt(skills: SkillDefinition[]): string;
|
|
24
|
+
export declare function getBuiltinSkillContents(): Promise<{
|
|
25
|
+
name: string;
|
|
26
|
+
content: string;
|
|
27
|
+
}[]>;
|
|
28
|
+
//# sourceMappingURL=skill-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-loader.d.ts","sourceRoot":"","sources":["../../src/core/skill-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AA0DD;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,YAAY,EAAE,MAAM,EAAE,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CAS5B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAqBpE;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAE5F"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SKILLS 可复用技能库加载器
|
|
4
|
+
*
|
|
5
|
+
* 负责:
|
|
6
|
+
* 1. 扫描 .speccore/SKILLS/ 目录下的技能定义文件
|
|
7
|
+
* 2. 根据任务类型/关键词匹配对应的技能
|
|
8
|
+
* 3. 注入到代码生成 prompt 中
|
|
9
|
+
*
|
|
10
|
+
* v6.88.0+
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.resolveSkillsForTask = resolveSkillsForTask;
|
|
14
|
+
exports.formatSkillsPrompt = formatSkillsPrompt;
|
|
15
|
+
exports.getBuiltinSkillContents = getBuiltinSkillContents;
|
|
16
|
+
const path_1 = require("path");
|
|
17
|
+
const fs_extra_1 = require("fs-extra");
|
|
18
|
+
const BUILTIN_SKILLS_DIR = (0, path_1.join)(__dirname, 'skills', 'defaults');
|
|
19
|
+
async function scanSkillFiles(dir) {
|
|
20
|
+
if (!(await (0, fs_extra_1.pathExists)(dir)))
|
|
21
|
+
return [];
|
|
22
|
+
const entries = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
|
|
23
|
+
const skills = [];
|
|
24
|
+
for (const e of entries) {
|
|
25
|
+
if (!e.isFile() || !e.name.endsWith('.md'))
|
|
26
|
+
continue;
|
|
27
|
+
if (e.name.startsWith('_'))
|
|
28
|
+
continue;
|
|
29
|
+
const content = await (0, fs_extra_1.readFile)((0, path_1.join)(dir, e.name), 'utf-8');
|
|
30
|
+
skills.push({
|
|
31
|
+
name: e.name.replace(/\.md$/, ''),
|
|
32
|
+
content,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return skills;
|
|
36
|
+
}
|
|
37
|
+
function parseSkillMeta(content) {
|
|
38
|
+
const tags = [];
|
|
39
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n/);
|
|
40
|
+
if (frontmatterMatch) {
|
|
41
|
+
const fm = frontmatterMatch[1];
|
|
42
|
+
const tagsMatch = fm.match(/tags:\s*\n((\s+-\s+.+\n)+)/);
|
|
43
|
+
if (tagsMatch) {
|
|
44
|
+
for (const line of tagsMatch[1].matchAll(/-\s+(.+)/g)) {
|
|
45
|
+
tags.push(line[1].trim().toLowerCase());
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { tags };
|
|
50
|
+
}
|
|
51
|
+
async function loadAllSkills(projectRoot) {
|
|
52
|
+
const userSkillsDir = (0, path_1.join)(projectRoot, '.speccore', 'SKILLS');
|
|
53
|
+
const skillMap = new Map();
|
|
54
|
+
const builtinFiles = await scanSkillFiles(BUILTIN_SKILLS_DIR);
|
|
55
|
+
for (const f of builtinFiles) {
|
|
56
|
+
const meta = parseSkillMeta(f.content);
|
|
57
|
+
skillMap.set(f.name, { name: f.name, content: f.content, tags: meta.tags });
|
|
58
|
+
}
|
|
59
|
+
const userFiles = await scanSkillFiles(userSkillsDir);
|
|
60
|
+
for (const f of userFiles) {
|
|
61
|
+
const meta = parseSkillMeta(f.content);
|
|
62
|
+
skillMap.set(f.name, { name: f.name, content: f.content, tags: meta.tags });
|
|
63
|
+
}
|
|
64
|
+
return Array.from(skillMap.values());
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 根据任务关键词匹配适用的技能
|
|
68
|
+
*/
|
|
69
|
+
async function resolveSkillsForTask(taskKeywords, projectRoot) {
|
|
70
|
+
const allSkills = await loadAllSkills(projectRoot);
|
|
71
|
+
const keywords = taskKeywords.map(s => s.toLowerCase());
|
|
72
|
+
const matched = allSkills.filter(skill => {
|
|
73
|
+
return skill.tags.some(tag => keywords.some(kw => kw.includes(tag) || tag.includes(kw)));
|
|
74
|
+
});
|
|
75
|
+
return matched;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 将匹配的技能合并为 prompt 字符串
|
|
79
|
+
*/
|
|
80
|
+
function formatSkillsPrompt(skills) {
|
|
81
|
+
if (skills.length === 0)
|
|
82
|
+
return '';
|
|
83
|
+
const sections = [];
|
|
84
|
+
sections.push('## 可复用技能参考');
|
|
85
|
+
sections.push('');
|
|
86
|
+
sections.push('> 以下技能指南供参考,按需应用。');
|
|
87
|
+
sections.push('');
|
|
88
|
+
for (const skill of skills) {
|
|
89
|
+
let content = skill.content;
|
|
90
|
+
content = content.replace(/^---\n[\s\S]*?\n---\n/, '');
|
|
91
|
+
content = content.trim();
|
|
92
|
+
sections.push(`### ${skill.name}`);
|
|
93
|
+
sections.push('');
|
|
94
|
+
sections.push(content);
|
|
95
|
+
sections.push('');
|
|
96
|
+
}
|
|
97
|
+
return sections.join('\n');
|
|
98
|
+
}
|
|
99
|
+
async function getBuiltinSkillContents() {
|
|
100
|
+
return scanSkillFiles(BUILTIN_SKILLS_DIR);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=skill-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-loader.js","sourceRoot":"","sources":["../../src/core/skill-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags:
|
|
3
|
+
- cache
|
|
4
|
+
- redis
|
|
5
|
+
- performance
|
|
6
|
+
- memoization
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# 缓存技能
|
|
10
|
+
|
|
11
|
+
## 缓存策略
|
|
12
|
+
|
|
13
|
+
| 策略 | 适用场景 | 缺点 |
|
|
14
|
+
|------|---------|------|
|
|
15
|
+
| Cache-Aside | 读多写少 | 首次读取慢 |
|
|
16
|
+
| Write-Through | 强一致性要求 | 写延迟增加 |
|
|
17
|
+
| Write-Behind | 高写入吞吐量 | 数据丢失风险 |
|
|
18
|
+
| Read-Through | 简化应用逻辑 | 缓存 miss 时延迟高 |
|
|
19
|
+
|
|
20
|
+
## Redis 最佳实践
|
|
21
|
+
|
|
22
|
+
1. **Key 命名空间**:`service:entity:id:field`,如 `user:profile:1234:email`
|
|
23
|
+
2. **TTL 设置**:根据数据变化频率设置合理过期时间
|
|
24
|
+
3. **序列化**:使用 JSON 或 MessagePack,避免存储对象引用
|
|
25
|
+
4. **连接池**:使用连接池管理 Redis 连接
|
|
26
|
+
5. **缓存穿透**:对不存在 key 设置空值缓存(短 TTL)
|
|
27
|
+
6. **缓存雪崩**:设置随机 TTL 偏移量
|
|
28
|
+
|
|
29
|
+
## 本地缓存
|
|
30
|
+
|
|
31
|
+
- Node.js:使用 `lru-cache` 或 `node-cache`
|
|
32
|
+
- 前端:使用 `React.memo`、`useMemo`、`useCallback`
|
|
33
|
+
- 限制:本地缓存仅存放热点数据,大小不超过 100MB
|