jsharness 1.8.2 → 1.10.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/.harness/README.md +123 -57
- package/.harness/agents/{prompt-templates.md → agent-dispatcher.md} +304 -21
- package/.harness/agents/code-reviewer/contract.yaml +1 -1
- package/.harness/agents/code-reviewer/prompt.md +1 -1
- package/.harness/agents/code-reviewer.md +1 -1
- package/.harness/agents/developer/contract.yaml +0 -1
- package/.harness/agents/developer/prompt.md +0 -1
- package/.harness/agents/developer.md +0 -1
- package/.harness/agents/gate-controller/contract.yaml +1 -1
- package/.harness/agents/gate-controller/prompt.md +1 -1
- package/.harness/agents/gate-controller.md +1 -1
- package/.harness/agents/project-manager/contract.yaml +4 -1
- package/.harness/agents/project-manager/prompt.md +9 -1
- package/.harness/agents/project-manager.md +9 -1
- package/.harness/agents/requirements-analyst/contract.yaml +5 -3
- package/.harness/agents/requirements-analyst/prompt.md +39 -35
- package/.harness/agents/requirements-analyst.md +39 -35
- package/.harness/agents/solution-designer/contract.yaml +1 -1
- package/.harness/agents/solution-designer/prompt.md +1 -1
- package/.harness/agents/solution-designer.md +1 -1
- package/.harness/agents/tester/contract.yaml +1 -1
- package/.harness/agents/tester/prompt.md +1 -1
- package/.harness/agents/tester.md +1 -1
- package/.harness/commands/js/apply.md +31 -0
- package/.harness/commands/js/archive.md +31 -0
- package/.harness/commands/js/explore.md +31 -0
- package/.harness/commands/js/propose.md +31 -0
- package/.harness/dev-map/overview.md +5 -4
- package/.harness/doc/originRequirements/.gitkeep +0 -0
- package/.harness/doc/originRequirements/2026-05-22-sample-requirement.md +12 -0
- package/.harness/doc/originRequirements/README.md +36 -0
- package/.harness/doc/ttspec/README.md +33 -0
- package/.harness/doc/ttspec/change/.gitkeep +0 -0
- package/.harness/doc/ttspec/change/archive/.gitkeep +0 -0
- package/.harness/doc/ttspec/specs/.gitkeep +0 -0
- package/.harness/rules/global/process-discipline.md +10 -1
- package/.harness/skills/architecture-designer/SKILL.md +2 -0
- package/.harness/skills/docs-update/SKILL.md +2 -0
- package/.harness/skills/openspec-apply/SKILL.md +90 -0
- package/.harness/skills/openspec-archive/SKILL.md +77 -0
- package/.harness/skills/openspec-explore/SKILL.md +135 -0
- package/.harness/skills/openspec-propose/SKILL.md +178 -0
- package/.harness/skills/openspec-skill-creator/SKILL.md +157 -0
- package/.harness/skills/prd-generator/SKILL.md +584 -0
- package/.harness/workflow/definition.yaml +41 -8
- package/files/analyze-requirements.md +197 -0
- package/lib/index.mjs +152 -35
- package/package.json +1 -1
- package/.harness/skills/build/SKILL.md +0 -199
- /package/.harness/{docs → doc}/integration-test-plan.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/README.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/arch-team.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/collaboration.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/pm-team.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/qa-team.md +0 -0
- /package/.harness/{docs → doc}/team-guidelines/rd-team.md +0 -0
- /package/.harness/{docs → doc}/training-materials.md +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# 需求分析师技能
|
|
2
|
+
|
|
3
|
+
## 核心职责
|
|
4
|
+
|
|
5
|
+
作为需求分析师,你的核心职责是:
|
|
6
|
+
|
|
7
|
+
1. 理解并拆解客户需求
|
|
8
|
+
2. 创建需求规格文档
|
|
9
|
+
|
|
10
|
+
文档要求:
|
|
11
|
+
|
|
12
|
+
1. 文档内容参照提供的模板
|
|
13
|
+
|
|
14
|
+
## 文件管理
|
|
15
|
+
|
|
16
|
+
### 目录结构
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
.cospec/{功能名}/
|
|
20
|
+
└── requirements.md # 需求文档
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> **{功能名}目录请使用英文**
|
|
24
|
+
|
|
25
|
+
### 阶段进度跟踪
|
|
26
|
+
|
|
27
|
+
#### 进度跟踪
|
|
28
|
+
|
|
29
|
+
- **任务开始时的第一步**: 使用todo_list工具列出任务清单,此操作必须在其它任何动作之前
|
|
30
|
+
- 通过任务清单的勾选状态跟踪实现进度
|
|
31
|
+
|
|
32
|
+
#### 任务清单内容
|
|
33
|
+
|
|
34
|
+
todo_list中必须包含以下操作,**请勿遗漏任何一个步骤**:
|
|
35
|
+
|
|
36
|
+
1. 创建需求文档
|
|
37
|
+
2. **内容检查**:当需求文档生成后,请立即开始检查需求文档中的内容,明确是否存在【约束】栏目中不允许的内容,如果有请一定要删除,否则会带来重大灾难
|
|
38
|
+
3. 确认结果:当文档生成后,必须使用 ask_followup_question 工具询问是否满足用户要求,并提示可补充信息或继续:"示例提示:'当前已完成【需求明确】。如需修改可直接在对话框中输入修改要求,或直接在文档中修改。如已确认请点击:<suggest>继续</suggest>'"
|
|
39
|
+
4. 总结任务:所有任务完成后,使用attempt_completion工具做简单总结
|
|
40
|
+
|
|
41
|
+
## 工作流程约束
|
|
42
|
+
|
|
43
|
+
### 1. 需求分析阶段
|
|
44
|
+
|
|
45
|
+
**强制检查清单:**
|
|
46
|
+
|
|
47
|
+
- [x] 判断`.cospec/{功能名}/`目录下,requirements.md文档是否存在,如果存在则读取,如果没有需要先创建
|
|
48
|
+
|
|
49
|
+
**我的工作:**
|
|
50
|
+
|
|
51
|
+
1. 创建 `.cospec/{功能名}/requirements.md` 文档
|
|
52
|
+
2. 基于您的描述生成初始需求,**不会先问一系列连续问题**
|
|
53
|
+
3. 与您反复讨论直到需求清晰
|
|
54
|
+
|
|
55
|
+
**重要约束:**
|
|
56
|
+
|
|
57
|
+
- 必须等待您的明确认可才能进入下一阶段
|
|
58
|
+
- 如果您提供反馈,我必须修改并再次请求确认
|
|
59
|
+
- 必须继续反馈-修订循环直到获得明确批准
|
|
60
|
+
- 不会假设用户偏好或需求
|
|
61
|
+
- 总是明确询问
|
|
62
|
+
|
|
63
|
+
**完成标志:**
|
|
64
|
+
|
|
65
|
+
- 您明确表示满意当前需求(如"是的"、"批准"、"看起来不错"等)
|
|
66
|
+
|
|
67
|
+
**需求澄清规范:**
|
|
68
|
+
|
|
69
|
+
- 必须识别所有不明确的需求点
|
|
70
|
+
- 对每个需求提出至少3个澄清问题
|
|
71
|
+
- 记录所有假设和约束条件
|
|
72
|
+
- 提供替代解决方案建议
|
|
73
|
+
|
|
74
|
+
**文档化要求:**
|
|
75
|
+
|
|
76
|
+
- 创建`.cospec/{功能名}/requirements.md`包含:
|
|
77
|
+
- 功能需求清单(按优先级排序)
|
|
78
|
+
- 用户故事和用例
|
|
79
|
+
- 更新`.cospec/{功能名}/requirements.md`
|
|
80
|
+
- 编写需求前先判断需求的复杂程度,如果是简单需求,可以简化文档内容,不必严格按照模板规范,避免简单需求复杂化
|
|
81
|
+
|
|
82
|
+
**需求文档中不包含:**
|
|
83
|
+
|
|
84
|
+
- 非功能性需求
|
|
85
|
+
- 测试需求
|
|
86
|
+
- 部署需求
|
|
87
|
+
|
|
88
|
+
## 输出规范
|
|
89
|
+
|
|
90
|
+
### 文档标准
|
|
91
|
+
|
|
92
|
+
#### 1. 需求规格文档
|
|
93
|
+
|
|
94
|
+
- 使用标准模板
|
|
95
|
+
- 包含版本控制信息
|
|
96
|
+
- 每个需求有唯一标识符
|
|
97
|
+
- 可追溯性矩阵
|
|
98
|
+
|
|
99
|
+
## 交互约束
|
|
100
|
+
|
|
101
|
+
### 与客户交互
|
|
102
|
+
|
|
103
|
+
- 使用结构化提问获取需求
|
|
104
|
+
- 提供可视化原型建议
|
|
105
|
+
- 解释技术选择的权衡
|
|
106
|
+
- 给出实施优先级建议
|
|
107
|
+
|
|
108
|
+
### 与开发团队协作
|
|
109
|
+
|
|
110
|
+
- 提供清晰的实施指南
|
|
111
|
+
- 定义接口规范
|
|
112
|
+
- 制定测试策略
|
|
113
|
+
- 建立代码审查标准
|
|
114
|
+
|
|
115
|
+
## 约束检查
|
|
116
|
+
|
|
117
|
+
每次完成任务后,必须验证:
|
|
118
|
+
|
|
119
|
+
1. 是否所有需求都被文档化?
|
|
120
|
+
2. 技术方案是否经过充分论证?
|
|
121
|
+
3. 架构设计是否考虑了扩展性?
|
|
122
|
+
4. 文档是否易于理解和实施?
|
|
123
|
+
5. 是否建立了有效的反馈机制?
|
|
124
|
+
|
|
125
|
+
## 需求分析模板
|
|
126
|
+
|
|
127
|
+
### 需求规格说明书模板
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
# 需求规格说明书 - [项目名称]
|
|
131
|
+
|
|
132
|
+
## 1. 项目概述
|
|
133
|
+
|
|
134
|
+
### 1.1 背景
|
|
135
|
+
|
|
136
|
+
[描述项目产生的背景和原因]
|
|
137
|
+
|
|
138
|
+
### 1.2 目标
|
|
139
|
+
|
|
140
|
+
[明确项目的业务目标和技术目标]
|
|
141
|
+
|
|
142
|
+
### 1.3 范围
|
|
143
|
+
|
|
144
|
+
[定义项目边界,包含和不包含的内容]
|
|
145
|
+
|
|
146
|
+
## 2. 功能需求
|
|
147
|
+
|
|
148
|
+
### 2.1 用户角色
|
|
149
|
+
|
|
150
|
+
| 角色名称 | 描述 | 权限 |
|
|
151
|
+
|----------|------|------|
|
|
152
|
+
| [角色1] | [描述] | [权限列表] |
|
|
153
|
+
|
|
154
|
+
### 2.2 功能清单
|
|
155
|
+
|
|
156
|
+
#### 2.2.1 [功能模块1]
|
|
157
|
+
|
|
158
|
+
- **需求ID**: FR-001
|
|
159
|
+
- **需求描述**: [详细描述]
|
|
160
|
+
- **优先级**: [高/中/低]
|
|
161
|
+
- **验收标准**: [可测量的标准]
|
|
162
|
+
- **依赖关系**: [依赖的其他需求]
|
|
163
|
+
|
|
164
|
+
## 3. 用户故事
|
|
165
|
+
|
|
166
|
+
### 3.1 [用户故事标题]
|
|
167
|
+
|
|
168
|
+
**作为** [用户角色]
|
|
169
|
+
**我想要** [功能描述]
|
|
170
|
+
**以便于** [业务价值]
|
|
171
|
+
|
|
172
|
+
**验收条件**:
|
|
173
|
+
|
|
174
|
+
- [条件1]
|
|
175
|
+
- [条件2]
|
|
176
|
+
|
|
177
|
+
## 4. 数据需求
|
|
178
|
+
|
|
179
|
+
### 4.1 数据实体
|
|
180
|
+
|
|
181
|
+
- [实体1]: [描述]
|
|
182
|
+
- [实体2]: [描述]
|
|
183
|
+
|
|
184
|
+
### 4.2 数据流
|
|
185
|
+
|
|
186
|
+
[描述数据如何在系统中流动]
|
|
187
|
+
|
|
188
|
+
## 5. 假设和依赖
|
|
189
|
+
|
|
190
|
+
### 5.1 假设
|
|
191
|
+
|
|
192
|
+
- [假设1]: [描述]
|
|
193
|
+
|
|
194
|
+
### 5.2 依赖
|
|
195
|
+
|
|
196
|
+
- [依赖1]: [描述]
|
|
197
|
+
```
|
package/lib/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 多适配器架构:检测 AI 工具 → 转换规则格式 → 注入到对应位置
|
|
5
5
|
*
|
|
6
|
+
* v1.10.0: 新增 5 个 OpenSpec Skills(openspec-explore/propose/apply/archive/skill-creator),Commands 精简为 Skill 委托模式
|
|
6
7
|
* v1.8.0: 四桶分离架构(rules/skills/commands/agents),多源获取策略确保 100% 可用
|
|
7
8
|
* 1. import.meta.url 定位本包 .harness/ (最快)
|
|
8
9
|
* 2. process.argv[1] 反推包根目录(npx 直接执行时)
|
|
@@ -370,6 +371,7 @@ const SKILL_TRANSFORMERS = {
|
|
|
370
371
|
if (lowerName.includes('build')) content += `trigger_type: manual\n`;
|
|
371
372
|
else if (lowerName.includes('test')) content += `trigger_type: on_save\n`;
|
|
372
373
|
else if (lowerName.includes('lint') || lowerName.includes('review')) content += `trigger_type: on_pr\n`;
|
|
374
|
+
else if (lowerName.includes('openspec')) content += `trigger_type: manual\n`;
|
|
373
375
|
else content += `trigger_type: manual\n`;
|
|
374
376
|
content += `---\n\n${body}`;
|
|
375
377
|
outputs.push({ relativePath: `.claude/skills/${skillName}/SKILL.md`, content, source: file.path });
|
|
@@ -1362,30 +1364,6 @@ export function scanHarnessSkills(harnessDir, stackFilter) {
|
|
|
1362
1364
|
return results;
|
|
1363
1365
|
}
|
|
1364
1366
|
|
|
1365
|
-
/**
|
|
1366
|
-
* 扫描项目根目录下的 files/ 目录
|
|
1367
|
-
* 这些是外部 SKILL 源文件(如 architecture-designer.md),
|
|
1368
|
-
* 需要被注入到目标 AI 工具对应的 skills 目录中
|
|
1369
|
-
*/
|
|
1370
|
-
export function scanHarnessFiles(projectDir) {
|
|
1371
|
-
const filesDir = path.join(projectDir, 'files');
|
|
1372
|
-
const results = [];
|
|
1373
|
-
if (!fs.existsSync(filesDir)) return results;
|
|
1374
|
-
|
|
1375
|
-
const entries = fs.readdirSync(filesDir).filter(f => f.endsWith('.md'));
|
|
1376
|
-
for (const entry of entries) {
|
|
1377
|
-
const filePath = path.join(filesDir, entry);
|
|
1378
|
-
const skillName = entry.replace(/\.md$/, '').replace(/SKILL$/, '');
|
|
1379
|
-
results.push({
|
|
1380
|
-
name: skillName,
|
|
1381
|
-
path: filePath,
|
|
1382
|
-
category: 'file-skill',
|
|
1383
|
-
relativePath: `files/${entry}`,
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
return results;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
1367
|
/**
|
|
1390
1368
|
* 扫描 .harness/commands/ 目录下的命令定义
|
|
1391
1369
|
* 支持两种结构:
|
|
@@ -1672,14 +1650,8 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1672
1650
|
const allCommandFiles = scanHarnessCommands(harnessDir, stack);
|
|
1673
1651
|
const allSubagentFiles = scanHarnessSubagents(harnessDir);
|
|
1674
1652
|
|
|
1675
|
-
// 5.5 扫描 files/ 目录(外部 SKILL 源文件)
|
|
1676
|
-
const externalSkillFiles = scanHarnessFiles(projectDir);
|
|
1677
|
-
|
|
1678
1653
|
if (verbose) {
|
|
1679
1654
|
console.log(`📋 扫描结果: ${allRuleFiles.length} 个规则, ${allSkillFiles.length} 个技能, ${allCommandFiles.length} 个命令, ${allSubagentFiles.length} 个角色\n`);
|
|
1680
|
-
if (externalSkillFiles.length > 0) {
|
|
1681
|
-
console.log(`📋 外部 SKILL 文件: ${externalSkillFiles.length} 个\n`);
|
|
1682
|
-
}
|
|
1683
1655
|
}
|
|
1684
1656
|
|
|
1685
1657
|
// 判断是否有 *-only 过滤
|
|
@@ -1702,7 +1674,7 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1702
1674
|
}
|
|
1703
1675
|
|
|
1704
1676
|
// Skills 桶
|
|
1705
|
-
const allSkills =
|
|
1677
|
+
const allSkills = allSkillFiles;
|
|
1706
1678
|
if ((!hasAnyOnly || skillsOnly) && allSkills.length > 0) {
|
|
1707
1679
|
if (tool.skillFormat) {
|
|
1708
1680
|
console.log(`⚡ 注入技能 (${allSkills.length} 个)...`);
|
|
@@ -1780,6 +1752,17 @@ export async function runInit(projectDir, options = {}) {
|
|
|
1780
1752
|
console.log(` ⏭ 跳过 ${openspecResult.skipped.length} 项 (已存在)`);
|
|
1781
1753
|
}
|
|
1782
1754
|
|
|
1755
|
+
// 7.5 初始化 Harness doc 目录(originRequirements + ttspec)
|
|
1756
|
+
console.log('\n━━━ 初始化 Harness 文档目录 ━━━');
|
|
1757
|
+
const harnessDocResult = initHarnessDoc(projectDir, { force, verbose });
|
|
1758
|
+
if (harnessDocResult.created.length > 0) {
|
|
1759
|
+
console.log(` ✅ 创建 ${harnessDocResult.created.length} 项:`);
|
|
1760
|
+
harnessDocResult.created.forEach(f => console.log(` - ${f}`));
|
|
1761
|
+
}
|
|
1762
|
+
if (harnessDocResult.skipped.length > 0) {
|
|
1763
|
+
console.log(` ⏭ 跳过 ${harnessDocResult.skipped.length} 项 (已存在)`);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1783
1766
|
// 8. 输出总结
|
|
1784
1767
|
console.log('\n═════════════════════════════');
|
|
1785
1768
|
console.log('✅ 初始化完成!');
|
|
@@ -1903,6 +1886,15 @@ export function showStatus(projectDir) {
|
|
|
1903
1886
|
|
|
1904
1887
|
const OPENSPEC_DIRS = ['openspec', 'openspec/changes', 'openspec/changes/archive', 'openspec/specs'];
|
|
1905
1888
|
|
|
1889
|
+
// Harness doc 子目录(需求入口 + ttspec 变更管理)
|
|
1890
|
+
const HARNESS_DOC_DIRS = [
|
|
1891
|
+
'.harness/doc/originRequirements',
|
|
1892
|
+
'.harness/doc/ttspec',
|
|
1893
|
+
'.harness/doc/ttspec/change',
|
|
1894
|
+
'.harness/doc/ttspec/change/archive',
|
|
1895
|
+
'.harness/doc/ttspec/specs',
|
|
1896
|
+
];
|
|
1897
|
+
|
|
1906
1898
|
const OPENSPEC_GITIGNORE = `# OpenSpec generated files
|
|
1907
1899
|
changes/*/dist/
|
|
1908
1900
|
*.log
|
|
@@ -1949,6 +1941,130 @@ export function initOpenSpec(projectDir, options = {}) {
|
|
|
1949
1941
|
return { created, skipped };
|
|
1950
1942
|
}
|
|
1951
1943
|
|
|
1944
|
+
/**
|
|
1945
|
+
* 初始化 .harness/doc/ 子目录(originRequirements + ttspec)
|
|
1946
|
+
*/
|
|
1947
|
+
export function initHarnessDoc(projectDir, options = {}) {
|
|
1948
|
+
const { force = false, verbose = false } = options;
|
|
1949
|
+
const created = [];
|
|
1950
|
+
const skipped = [];
|
|
1951
|
+
|
|
1952
|
+
for (const dir of HARNESS_DOC_DIRS) {
|
|
1953
|
+
const fullPath = path.join(projectDir, dir);
|
|
1954
|
+
if (fs.existsSync(fullPath)) {
|
|
1955
|
+
if (verbose) console.log(` ⏭ 目录已存在: ${dir}/`);
|
|
1956
|
+
skipped.push(dir);
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1959
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
1960
|
+
created.push(dir);
|
|
1961
|
+
if (verbose) console.log(` ✅ 创建目录: ${dir}/`);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
// 在空目录中添加 .gitkeep
|
|
1965
|
+
for (const dir of HARNESS_DOC_DIRS) {
|
|
1966
|
+
const gitkeepPath = path.join(projectDir, dir, '.gitkeep');
|
|
1967
|
+
if (!fs.existsSync(gitkeepPath)) fs.writeFileSync(gitkeepPath, '', 'utf-8');
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
// originRequirements README
|
|
1971
|
+
const originReadmePath = path.join(projectDir, '.harness/doc/originRequirements', 'README.md');
|
|
1972
|
+
if (!fs.existsSync(originReadmePath) || force) {
|
|
1973
|
+
fs.writeFileSync(originReadmePath, generateOriginRequirementsReadme(), 'utf-8');
|
|
1974
|
+
created.push('.harness/doc/originRequirements/README.md');
|
|
1975
|
+
} else {
|
|
1976
|
+
skipped.push('.harness/doc/originRequirements/README.md');
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// ttspec README
|
|
1980
|
+
const ttspecReadmePath = path.join(projectDir, '.harness/doc/ttspec', 'README.md');
|
|
1981
|
+
if (!fs.existsSync(ttspecReadmePath) || force) {
|
|
1982
|
+
fs.writeFileSync(ttspecReadmePath, generateTtspecReadme(), 'utf-8');
|
|
1983
|
+
created.push('.harness/doc/ttspec/README.md');
|
|
1984
|
+
} else {
|
|
1985
|
+
skipped.push('.harness/doc/ttspec/README.md');
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
return { created, skipped };
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function generateOriginRequirementsReadme() {
|
|
1992
|
+
return `# 原始需求文件目录
|
|
1993
|
+
|
|
1994
|
+
本目录用于存放所有原始需求文件,是 Harness 需求分析的统一入口。
|
|
1995
|
+
|
|
1996
|
+
## 文件命名规则
|
|
1997
|
+
|
|
1998
|
+
格式:\`{YYYY-MM-DD}-{kebab-case-title}.md\`
|
|
1999
|
+
|
|
2000
|
+
示例:
|
|
2001
|
+
- \`2026-05-22-user-avatar-upload.md\`
|
|
2002
|
+
- \`2026-06-15-order-export-feature.md\`
|
|
2003
|
+
|
|
2004
|
+
## 最小内容要求
|
|
2005
|
+
|
|
2006
|
+
每个需求文件至少包含以下两个章节:
|
|
2007
|
+
|
|
2008
|
+
\`\`\`markdown
|
|
2009
|
+
# 需求标题
|
|
2010
|
+
|
|
2011
|
+
## 背景
|
|
2012
|
+
|
|
2013
|
+
描述需求的业务背景、当前痛点和动机。
|
|
2014
|
+
|
|
2015
|
+
## 期望
|
|
2016
|
+
|
|
2017
|
+
描述期望达到的效果或目标。
|
|
2018
|
+
\`\`\`
|
|
2019
|
+
|
|
2020
|
+
## 工作流
|
|
2021
|
+
|
|
2022
|
+
1. 用户在此目录下创建需求文件
|
|
2023
|
+
2. PM Agent 扫描发现新文件
|
|
2024
|
+
3. PM 在 \`.harness/doc/ttspec/change/\` 下创建对应 change
|
|
2025
|
+
4. 需求分析师按 explore → propose → prd 三步执行分析
|
|
2026
|
+
|
|
2027
|
+
> 本目录由 Harness Engineering 系统管理。
|
|
2028
|
+
`;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
function generateTtspecReadme() {
|
|
2032
|
+
return `# ttspec — 变更规格管理目录
|
|
2033
|
+
|
|
2034
|
+
本目录用于存放 Harness 流程中 OpenSpec 的产出物,包括变更管理(change)和能力规格(specs)。
|
|
2035
|
+
|
|
2036
|
+
## 目录结构
|
|
2037
|
+
|
|
2038
|
+
\`\`\`
|
|
2039
|
+
.harness/doc/ttspec/
|
|
2040
|
+
├── change/ # 变更目录(每个需求对应一个子目录)
|
|
2041
|
+
│ ├── archive/ # 已归档的变更
|
|
2042
|
+
│ └── {change-name}/ # 活跃变更
|
|
2043
|
+
│ ├── explore-notes.md # explore 阶段产出
|
|
2044
|
+
│ ├── proposal.md # propose 阶段产出
|
|
2045
|
+
│ ├── design.md # 设计决策
|
|
2046
|
+
│ ├── specs/ # 能力规格
|
|
2047
|
+
│ └── tasks.md # 实施任务列表
|
|
2048
|
+
└── specs/ # 全局能力规格
|
|
2049
|
+
└── {capability}/
|
|
2050
|
+
└── spec.md
|
|
2051
|
+
\`\`\`
|
|
2052
|
+
|
|
2053
|
+
## 变更命名规则
|
|
2054
|
+
|
|
2055
|
+
change 名称从原始需求文件名派生:去除日期前缀,保留 kebab-case 标题。
|
|
2056
|
+
|
|
2057
|
+
示例:需求文件 \`2026-05-22-user-avatar-upload.md\` → change 名 \`user-avatar-upload\`
|
|
2058
|
+
|
|
2059
|
+
## 与 openspec/ 的关系
|
|
2060
|
+
|
|
2061
|
+
- \`openspec/\` — OpenSpec CLI 原生操作目录(历史数据保持不动)
|
|
2062
|
+
- \`.harness/doc/ttspec/\` — Harness 流程中的变更管理产出目录
|
|
2063
|
+
|
|
2064
|
+
> 本目录由 Harness Engineering 系统管理。
|
|
2065
|
+
`;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
1952
2068
|
function generateOpenSpecReadme() {
|
|
1953
2069
|
return `# OpenSpec 变更管理
|
|
1954
2070
|
|
|
@@ -1967,10 +2083,11 @@ openspec/
|
|
|
1967
2083
|
|
|
1968
2084
|
在 AI 对话中使用 OpenSpec skills:
|
|
1969
2085
|
|
|
1970
|
-
- **openspec-
|
|
1971
|
-
- **openspec-
|
|
1972
|
-
- **openspec-apply
|
|
1973
|
-
- **openspec-archive
|
|
2086
|
+
- **openspec-explore** — 需求深度探索
|
|
2087
|
+
- **openspec-propose** — 创建结构化提案
|
|
2088
|
+
- **openspec-apply** — 实施变更任务
|
|
2089
|
+
- **openspec-archive** — 归档已完成变更
|
|
2090
|
+
- **openspec-skill-creator** — 创建新的 Harness Skill
|
|
1974
2091
|
|
|
1975
2092
|
## 命令行操作
|
|
1976
2093
|
|
package/package.json
CHANGED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: build
|
|
3
|
-
description: 项目构建技能(已废弃,重定向至 vue-frontend-build 或 java-build)— 通用构建参考/历史存档
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
enabled: true
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# 项目构建技能 (build)
|
|
9
|
-
|
|
10
|
-
> ⚠️ **已废弃 (DEPRECATED)** — `harness-java-fullchain` change | 2026-05-21
|
|
11
|
-
>
|
|
12
|
-
> 本文件已被技术栈专属构建技能替代。**请根据项目类型使用对应的 Skill:**
|
|
13
|
-
>
|
|
14
|
-
> | 项目类型 | 推荐使用 Skill | 说明 |
|
|
15
|
-
> |---------|---------------|------|
|
|
16
|
-
> | **Vue3 + Vite 前端** | `skills/vue-frontend-build.md` | 完整的 Vite/TS/ESLint/Vitest/构建优化 |
|
|
17
|
-
> | **Spring Boot (JDK21) 后端** | `skills/java-build.md` | 完整的 Maven/测试/JaCoCo/Docker/CI 流程 |
|
|
18
|
-
>
|
|
19
|
-
> ---
|
|
20
|
-
> 以下内容保留作为**通用参考/历史存档**,workflow 已切换为按技术栈条件引用上述专属 Skill。
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
> **执行角色**: 开发实现 Agent / CI Pipeline
|
|
25
|
-
> **触发时机**: 代码修改完成后、提交 PR 前、CI 构建时
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## 前端构建流程
|
|
30
|
-
|
|
31
|
-
### Step 1: 依赖安装
|
|
32
|
-
```bash
|
|
33
|
-
# 使用 pnpm(推荐)或 npm
|
|
34
|
-
pnpm install
|
|
35
|
-
|
|
36
|
-
# 检查依赖安全
|
|
37
|
-
npm audit --audit-level=moderate
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**通过标准**: 安装无 error,无 HIGH/CRITICAL 安全漏洞
|
|
41
|
-
|
|
42
|
-
### Step 2: 类型检查
|
|
43
|
-
```bash
|
|
44
|
-
# TypeScript 严格模式类型检查
|
|
45
|
-
npx tsc --noEmit
|
|
46
|
-
|
|
47
|
-
# 或使用项目配置的命令
|
|
48
|
-
npm run type-check
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**通过标准**: 零 type error
|
|
52
|
-
|
|
53
|
-
### Step 3: 代码格式化检查
|
|
54
|
-
```bash
|
|
55
|
-
# ESLint 检查
|
|
56
|
-
npx eslint . --ext .ts,.vue,.js --max-warnings 0
|
|
57
|
-
|
|
58
|
-
# Prettier 格式化验证
|
|
59
|
-
npx prettier --check "src/**/*.{ts,vue,js,css,md}"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**通过标准**: 零 warning(白名单规则除外)
|
|
63
|
-
|
|
64
|
-
### Step 4: 生产构建
|
|
65
|
-
```bash
|
|
66
|
-
# Vue3 + Vite(推荐)
|
|
67
|
-
npm run build
|
|
68
|
-
|
|
69
|
-
# 或具体命令
|
|
70
|
-
vite build # Vite
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Step 5: 构建产物分析(可选但推荐)
|
|
74
|
-
```bash
|
|
75
|
-
# 分析打包体积
|
|
76
|
-
npx @next/analyze # Next.js
|
|
77
|
-
npx rollup-plugin-visualizer # Vite/Webpack
|
|
78
|
-
|
|
79
|
-
# 通过标准:
|
|
80
|
-
# - 首屏 JS ≤ 200KB (gzip)
|
|
81
|
-
# - 单 chunk ≤ 100KB (gzip)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**通过标准**: 构建成功,退出码 0,产物体积在限制内
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## 后端编译流程
|
|
89
|
-
|
|
90
|
-
### Step 1: 编译检查
|
|
91
|
-
```bash
|
|
92
|
-
# TypeScript 后端(如 NestJS)
|
|
93
|
-
npx tsc --noEmit
|
|
94
|
-
|
|
95
|
-
# Java (Maven)
|
|
96
|
-
mvn compile
|
|
97
|
-
|
|
98
|
-
# Go
|
|
99
|
-
go build ./...
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
**通过标准**: 编译零错误
|
|
103
|
-
|
|
104
|
-
### Step 2: Lint 检查
|
|
105
|
-
```bash
|
|
106
|
-
# NestJS / Node.js
|
|
107
|
-
npx eslint . --ext .ts
|
|
108
|
-
|
|
109
|
-
# Java
|
|
110
|
-
mvn checkstyle:check
|
|
111
|
-
|
|
112
|
-
# Go
|
|
113
|
-
golangci-lint run ./...
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**通过标准**: 零 warning(可配置的白名单)
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## TypeScript 类型检查专项
|
|
121
|
-
|
|
122
|
-
### 配置要求
|
|
123
|
-
|
|
124
|
-
```jsonc
|
|
125
|
-
// tsconfig.json 必须启用
|
|
126
|
-
{
|
|
127
|
-
"compilerOptions": {
|
|
128
|
-
"strict": true,
|
|
129
|
-
"noImplicitAny": true,
|
|
130
|
-
"strictNullChecks": true,
|
|
131
|
-
"strictFunctionTypes": true,
|
|
132
|
-
"noUncheckedIndexedAccess": true
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### any 类型使用规范
|
|
138
|
-
|
|
139
|
-
| 场景 | 是否允许 | 要求 |
|
|
140
|
-
|------|---------|------|
|
|
141
|
-
| 新增代码 | 禁止 | 必须定义明确类型 |
|
|
142
|
-
| 遗留系统重构 | 有条件允许 | 必须注释 `// TODO(#issue): replace with proper type` |
|
|
143
|
-
| 第三方类型缺失 | 允许 | 封装一层并定义接口 |
|
|
144
|
-
| JSON.parse 结果 | 禁止 | 使用泛型或 Zod 校验 |
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## 构建失败处理策略
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
构建失败
|
|
152
|
-
│
|
|
153
|
-
├── 依赖安装失败 → 检查 lockfile 一致性 / 清缓存重试 / 检查网络
|
|
154
|
-
│
|
|
155
|
-
├── 类型错误 → 定位错误位置 → 修复类型 → 重新运行
|
|
156
|
-
│ └── 如果是第三方库类型问题 → 添加 type declaration
|
|
157
|
-
│
|
|
158
|
-
├── Lint 错误 → 运行 `--fix` 自动修复 → 手动修复剩余项
|
|
159
|
-
│
|
|
160
|
-
├── 生产构建失败 → 检查 build log → 定位问题 → 修复
|
|
161
|
-
│ └── 常见原因:动态 import 路径错误 / 环境变量缺失
|
|
162
|
-
│
|
|
163
|
-
└── 体积超限 → 分析 bundle → 排查大依赖 → 懒加载 / tree-shaking
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## 构建结果输出模板
|
|
167
|
-
|
|
168
|
-
```yaml
|
|
169
|
-
build_result:
|
|
170
|
-
timestamp: "2026-05-20T22:00:00Z"
|
|
171
|
-
status: pass | fail
|
|
172
|
-
duration_seconds: 45
|
|
173
|
-
|
|
174
|
-
frontend:
|
|
175
|
-
typecheck:
|
|
176
|
-
errors: 0
|
|
177
|
-
warnings: 0
|
|
178
|
-
lint:
|
|
179
|
-
errors: 0
|
|
180
|
-
warnings: 0
|
|
181
|
-
build:
|
|
182
|
-
success: true
|
|
183
|
-
output_size_kb:
|
|
184
|
-
total: 180
|
|
185
|
-
gzip: 62
|
|
186
|
-
|
|
187
|
-
backend:
|
|
188
|
-
compile:
|
|
189
|
-
success: true
|
|
190
|
-
lint:
|
|
191
|
-
errors: 0
|
|
192
|
-
warnings: 2
|
|
193
|
-
|
|
194
|
-
security_audit:
|
|
195
|
-
critical: 0
|
|
196
|
-
high: 0
|
|
197
|
-
moderate: 3
|
|
198
|
-
low: 5
|
|
199
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|