openone-workflow-kit 0.1.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/CHANGELOG.md +21 -0
- package/CODE_OF_CONDUCT.md +25 -0
- package/CONTRIBUTING.md +51 -0
- package/INIT.md +81 -0
- package/LICENSE +201 -0
- package/NOTICE +6 -0
- package/README.md +195 -0
- package/SECURITY.md +39 -0
- package/bin/check-contract.cjs +137 -0
- package/bin/check-sanitized.cjs +93 -0
- package/bin/init-workspace.cjs +966 -0
- package/docs/assets/PROVENANCE.md +20 -0
- package/docs/assets/architecture.svg +112 -0
- package/docs/assets/hero.svg +83 -0
- package/docs/assets/quick-demo.svg +74 -0
- package/docs/assets/social-preview.svg +57 -0
- package/docs/assets/visual-manifest.json +52 -0
- package/docs/definition-of-done.md +80 -0
- package/docs/dual-track-workflow.md +90 -0
- package/docs/local-merge-notes.md +21 -0
- package/docs/maintainer-handoff.md +150 -0
- package/docs/manual-publish.md +119 -0
- package/docs/private-denylist.example.txt +11 -0
- package/docs/publication-decisions.md +36 -0
- package/docs/release-checklist.md +72 -0
- package/docs/releases/v0.1.0.md +70 -0
- package/docs/shareable-install.md +51 -0
- package/docs/tool-install-recipes.md +103 -0
- package/examples/ecommerce/team-profile.example.yaml +141 -0
- package/examples/education/team-profile.example.yaml +143 -0
- package/examples/saas-to-b/team-profile.example.yaml +130 -0
- package/examples/team-profile.example.yaml +69 -0
- package/install.sh +27 -0
- package/package.json +65 -0
- package/scripts/build-release.cjs +141 -0
- package/scripts/release-source-state.cjs +38 -0
- package/templates/AGENTS.template.md +26 -0
- package/test/release-readiness.cjs +214 -0
- package/test/smoke.cjs +272 -0
- package/workflow/adapters/README.md +16 -0
- package/workflow/core/README.md +38 -0
- package/workflow/core/capabilities/README.md +61 -0
- package/workflow/core/capabilities/acceptance-oracle-tracker.md +45 -0
- package/workflow/core/capabilities/branch-gatekeeper.md +57 -0
- package/workflow/core/capabilities/channel-experiment-tracker.md +32 -0
- package/workflow/core/capabilities/ci-cd-automation-governor.md +123 -0
- package/workflow/core/capabilities/contract-tracer.md +53 -0
- package/workflow/core/capabilities/data-change-safety-checker.md +52 -0
- package/workflow/core/capabilities/definition-lint.md +81 -0
- package/workflow/core/capabilities/deployment-readiness-checker.md +57 -0
- package/workflow/core/capabilities/impact-scope-analyzer.md +50 -0
- package/workflow/core/capabilities/knowledge-capture-maintainer.md +32 -0
- package/workflow/core/capabilities/market-evidence-grader.md +33 -0
- package/workflow/core/capabilities/memory-curator.md +48 -0
- package/workflow/core/capabilities/personal-git-operator.md +41 -0
- package/workflow/core/capabilities/personal-release-checklist.md +49 -0
- package/workflow/core/capabilities/prd-code-diff-checker.md +53 -0
- package/workflow/core/capabilities/protocol-state-machine-checker.md +57 -0
- package/workflow/core/capabilities/release-safety-checker.md +61 -0
- package/workflow/core/capabilities/repo-baseline-scanner.md +48 -0
- package/workflow/core/capabilities/rule-extractor.md +48 -0
- package/workflow/core/capabilities/runtime-evidence-triage.md +53 -0
- package/workflow/core/capabilities/security-reviewer.md +48 -0
- package/workflow/core/capabilities/test-evidence-reviewer.md +50 -0
- package/workflow/core/capabilities/ui-baseline-reviewer.md +50 -0
- package/workflow/core/capabilities/verify-app.md +51 -0
- package/workflow/core/capabilities/worktree-isolator.md +53 -0
- package/workflow/core/commands/01-/351/234/200/346/261/202/350/256/250/350/256/272.md +36 -0
- package/workflow/core/commands/02-/344/272/247/345/223/201/346/226/207/346/241/243.md +35 -0
- package/workflow/core/commands/02B-UI/350/256/276/350/256/241.md +75 -0
- package/workflow/core/commands/03-06-/347/240/224/345/217/221/345/207/206/345/244/207.md +30 -0
- package/workflow/core/commands/03-/346/212/200/346/234/257/346/236/266/346/236/204.md +32 -0
- package/workflow/core/commands/04-/344/273/243/347/240/201/345/256/236/347/216/260.md +32 -0
- package/workflow/core/commands/04A-/345/211/215/347/253/257/344/273/243/347/240/201/345/256/236/347/216/260.md +36 -0
- package/workflow/core/commands/04B-/345/220/216/347/253/257/344/273/243/347/240/201/345/256/236/347/216/260.md +31 -0
- package/workflow/core/commands/05-/344/273/243/347/240/201/345/256/241/346/237/245.md +31 -0
- package/workflow/core/commands/06-/346/265/213/350/257/225/347/224/250/344/276/213.md +34 -0
- package/workflow/core/commands/07-/346/265/213/350/257/225/346/211/247/350/241/214.md +33 -0
- package/workflow/core/commands/08-/345/217/221/345/270/203/345/207/206/345/244/207.md +44 -0
- package/workflow/core/commands/09-/345/217/221/345/270/203/346/211/247/350/241/214.md +39 -0
- package/workflow/core/commands/10-/345/244/215/347/233/230/346/200/273/347/273/223.md +41 -0
- package/workflow/core/commands/B1-B8-/345/225/206/344/270/232/345/214/226/345/207/206/345/244/207.md +30 -0
- package/workflow/core/commands/B1-/344/270/232/345/212/241/345/256/232/344/275/215.md +38 -0
- package/workflow/core/commands/B2-/345/225/206/344/270/232/346/250/241/345/274/217.md +38 -0
- package/workflow/core/commands/B3-PMF/344/270/216/345/256/242/346/210/267/347/224/273/345/203/217.md +39 -0
- package/workflow/core/commands/B4-/345/234/272/346/231/257/344/270/216/350/264/255/344/271/260/346/227/205/347/250/213.md +37 -0
- package/workflow/core/commands/B5-/346/270/240/351/201/223/346/274/217/346/226/227/346/230/240/345/260/204.md +39 -0
- package/workflow/core/commands/B6-/350/220/245/351/224/200/350/216/267/345/256/242/347/255/226/347/225/245.md +38 -0
- package/workflow/core/commands/B7-/350/220/245/351/224/200/351/242/204/347/256/227.md +36 -0
- package/workflow/core/commands/B8-/346/270/240/351/201/223/346/211/247/350/241/214/347/255/226/347/225/245.md +39 -0
- package/workflow/core/commands/B9-/347/255/226/347/225/245/345/244/215/347/233/230.md +38 -0
- package/workflow/core/commands/README.md +56 -0
- package/workflow/core/commands/init-workspace.md +29 -0
- package/workflow/core/commands/new-feature.md +33 -0
- package/workflow/core/commands/new-product.md +28 -0
- package/workflow/core/commands/workflow-status.md +30 -0
- package/workflow/core/commands//344/270/200/350/207/264/346/200/247/346/243/200/346/237/245.md +35 -0
- package/workflow/core/commands//344/272/244/344/273/230/350/207/263/345/256/214/346/210/220.md +40 -0
- package/workflow/core/commands//345/256/232/344/271/211/345/256/214/346/210/220.md +41 -0
- package/workflow/core/commands//346/276/204/346/270/205.md +31 -0
- package/workflow/core/templates/00-business-status.md +43 -0
- package/workflow/core/templates/00-workflow-status.md +50 -0
- package/workflow/core/templates/README.md +12 -0
- package/workflow/core/templates/business-stage-document.md +49 -0
- package/workflow/core/templates/completion-contract.md +114 -0
- package/workflow/core/templates/constitution.template.md +50 -0
- package/workflow/core/templates/living-spec.md +35 -0
- package/workflow/core/templates/stage-document.md +42 -0
- package/workflow/core/templates/team-profile.template.yaml +104 -0
|
@@ -0,0 +1,966 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
|
|
6
|
+
const KIT_ROOT = path.resolve(__dirname, '..');
|
|
7
|
+
const SUPPORTED_TOOLS = ['codex', 'claude', 'cursor', 'copilot', 'codebuddy', 'kiro', 'trae'];
|
|
8
|
+
const TOOL_ALIASES = {
|
|
9
|
+
trea: 'trae',
|
|
10
|
+
claude_code: 'claude',
|
|
11
|
+
'claude-code': 'claude',
|
|
12
|
+
github_copilot: 'copilot',
|
|
13
|
+
'github-copilot': 'copilot'
|
|
14
|
+
};
|
|
15
|
+
const GENERATED_BY = 'openone-workflow-kit 0.1.0';
|
|
16
|
+
|
|
17
|
+
const STAGES = [
|
|
18
|
+
['init-workspace', '初始化工作区', '扫描本地资料、生成 team-profile、缺资料提问,并生成当前工具 adapter。'],
|
|
19
|
+
['new-feature', '初始化功能工作流', '创建 features/{feature}/ 容器、状态文件和截图目录,并完成 S/M/L 复杂度分级。'],
|
|
20
|
+
['01-需求讨论', '需求讨论', '澄清业务目标、边界、验收口径和待确认项。'],
|
|
21
|
+
['澄清', '澄清', '每轮不超过 5 个针对性问题消融语义歧义,答案写回文档并清理待澄清标记。'],
|
|
22
|
+
['02-产品文档', '产品文档', '输出 PRD、业务规则、高层 UI 方向、非功能需求和验收口径。'],
|
|
23
|
+
['02B-UI设计', 'UI 设计', '在产品文档后输出可被实现遵循的信息架构、关键流程、页面清单、组件规范、平台适配、可访问性和 04A 交接规范。'],
|
|
24
|
+
['03-技术架构', '技术架构', '识别项目族、影响仓库、调用链、分支基线和实现准入风险。'],
|
|
25
|
+
['03-06-研发准备', '研发准备编排', '在已有 PRD 和必要的 02B UI 设计基线后串联生成 03 到 06 的研发准备文档;不授权代码实现。'],
|
|
26
|
+
['04-代码实现', '代码实现总览', '在准入通过后记录后端、前端、配置、数据和发布影响的真实改动。'],
|
|
27
|
+
['04A-前端代码实现', '前端代码实现', '记录页面、组件、接口、状态、回显和前端验证。'],
|
|
28
|
+
['04B-后端代码实现', '后端代码实现', '记录接口、服务、数据、事务、消息、配置和后端验证。'],
|
|
29
|
+
['05-代码审查', '代码审查', '以问题优先方式审查真实 diff、发布边界、PRD 一致性和残余风险。'],
|
|
30
|
+
['06-测试用例', '测试用例', '以风险驱动方式输出覆盖矩阵,每条用例可绑定为完成合同的验收 Oracle。'],
|
|
31
|
+
['定义完成', '定义完成', '把 01-06 结论编译成完成合同,通过 Definition Lint 后经用户确认冻结。'],
|
|
32
|
+
['一致性检查', '一致性检查', '实现前对合同与各阶段文档做只读交叉检查,逮住冲突、漂移和覆盖缺口。'],
|
|
33
|
+
['交付至完成', '交付至完成', '合同冻结后在范围内自主循环实现-验证-修复,直到 blocking Oracle 全绿或精确阻塞。'],
|
|
34
|
+
['07-测试执行', '测试执行', '记录真实执行结果与证据,翻转完成合同的 Oracle 状态。'],
|
|
35
|
+
['08-发布准备', '发布准备', '完成个人项目的本地集成、版本号、tag、发布清单、回滚点和渠道材料。'],
|
|
36
|
+
['09-发布执行', '发布执行', '在用户明确授权后执行远程 push、release、商店/平台发布或部署,并记录证据。'],
|
|
37
|
+
['10-复盘总结', '复盘总结', '沉淀项目结论、可复用规则、知识库更新和下一轮改进项。'],
|
|
38
|
+
['new-product', '初始化商业化工作流', '创建 business/{product}/ 容器、商业化状态文件和素材目录。'],
|
|
39
|
+
['B1-业务定位', '业务定位', '基于产品服务盘点、市场调研和竞争对手分析形成定位陈述与细分选择。'],
|
|
40
|
+
['B1-B8-商业化准备', '商业化准备编排', '在容器初始化后串联生成 B1 到 B8 的商业化文档;不授权对外投放。'],
|
|
41
|
+
['B2-商业模式', '商业模式', '梳理价值主张、收入与定价假设、成本结构、单位经济和关键假设。'],
|
|
42
|
+
['B3-PMF与客户画像', 'PMF 与客户画像', '验证产品市场匹配度,确定理想客户画像 ICP 和负面画像。'],
|
|
43
|
+
['B4-场景与购买旅程', '场景与购买旅程', '深挖客户使用场景(JTBD)和付费购买旅程、异议与流失点。'],
|
|
44
|
+
['B5-渠道漏斗映射', '渠道漏斗映射', '明确线上线下各渠道在转化漏斗中的位置、作用、成本和 ICP 匹配度。'],
|
|
45
|
+
['B6-营销获客策略', '营销获客策略', '制定总体营销/获客策略:阶段目标、主攻渠道、信息一致性和内容支柱。'],
|
|
46
|
+
['B7-营销预算', '营销预算', '确定金钱与时间双预算、渠道分配、CAC 目标和止损线。'],
|
|
47
|
+
['B8-渠道执行策略', '渠道执行策略', '制定 SEO 及其他已选渠道的执行 playbook,并把营销工程需求回流研发轨。'],
|
|
48
|
+
['B9-策略复盘', '策略复盘', '按周期复盘漏斗数据、渠道 ROI 和假设判定,输出渠道加码/保持/降配/砍掉决策。'],
|
|
49
|
+
['workflow-status', '工作流状态', '汇总 features 与 business 下所有需求和产品的阶段状态、阻塞和下一步。']
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const REQUIRED_SOURCES = [
|
|
53
|
+
{
|
|
54
|
+
key: 'business_intro',
|
|
55
|
+
label: '业务介绍',
|
|
56
|
+
question: '请提供业务介绍或产品概览文件路径',
|
|
57
|
+
match: /(业务介绍|业务概览|产品介绍|company|business|overview|readme)/i
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: 'project_docs',
|
|
61
|
+
label: '项目资料',
|
|
62
|
+
question: '请提供项目资料、PRD、需求或架构文档目录',
|
|
63
|
+
match: /(项目资料|需求|prd|product|docs|architecture|spec)/i
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: 'ui_specs',
|
|
67
|
+
label: 'UI 设计文件',
|
|
68
|
+
question: '请提供 UI 规范、设计稿、原型或设计系统文件路径',
|
|
69
|
+
match: /(ui|design|figma|prototype|mockup|原型|设计|视觉|规范)/i
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: 'frontend_rules',
|
|
73
|
+
label: '前端开发规范',
|
|
74
|
+
question: '请提供前端开发规范目录或文件路径',
|
|
75
|
+
match: /(frontend|front-end|前端|web.*规范|ui.*规范)/i
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'backend_rules',
|
|
79
|
+
label: '后端开发规范',
|
|
80
|
+
question: '请提供后端开发规范目录或文件路径',
|
|
81
|
+
match: /(backend|back-end|server|后端|服务端)/i
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
key: 'testing_rules',
|
|
85
|
+
label: '测试规范',
|
|
86
|
+
question: '请提供测试规范、测试用例或 QA 资料路径',
|
|
87
|
+
match: /(test|testing|qa|测试|用例|验收)/i
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
key: 'market_research',
|
|
91
|
+
label: '市场与竞品资料',
|
|
92
|
+
question: '请提供市场调研、竞品分析、用户访谈或渠道数据资料路径(商业化轨 B1-B9 使用;暂缺可跳过)',
|
|
93
|
+
match: /(市场|竞品|调研|访谈|获客|营销|渠道|定价|market|competitor|research|gtm|marketing|pricing|persona|icp)/i
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const SKIP_DIRS = new Set([
|
|
98
|
+
'.git',
|
|
99
|
+
'node_modules',
|
|
100
|
+
'dist',
|
|
101
|
+
'build',
|
|
102
|
+
'target',
|
|
103
|
+
'.idea',
|
|
104
|
+
'.vscode',
|
|
105
|
+
'_worktrees',
|
|
106
|
+
'open-workflow-kit',
|
|
107
|
+
'openone-workflow-kit',
|
|
108
|
+
'workflow'
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
const CAPABILITY_FILES = [
|
|
112
|
+
'branch-gatekeeper.md',
|
|
113
|
+
'release-safety-checker.md',
|
|
114
|
+
'prd-code-diff-checker.md',
|
|
115
|
+
'contract-tracer.md',
|
|
116
|
+
'worktree-isolator.md',
|
|
117
|
+
'repo-baseline-scanner.md',
|
|
118
|
+
'impact-scope-analyzer.md',
|
|
119
|
+
'security-reviewer.md',
|
|
120
|
+
'verify-app.md',
|
|
121
|
+
'ci-cd-automation-governor.md',
|
|
122
|
+
'personal-git-operator.md',
|
|
123
|
+
'personal-release-checklist.md',
|
|
124
|
+
'knowledge-capture-maintainer.md',
|
|
125
|
+
'deployment-readiness-checker.md',
|
|
126
|
+
'runtime-evidence-triage.md',
|
|
127
|
+
'data-change-safety-checker.md',
|
|
128
|
+
'protocol-state-machine-checker.md',
|
|
129
|
+
'test-evidence-reviewer.md',
|
|
130
|
+
'ui-baseline-reviewer.md',
|
|
131
|
+
'memory-curator.md',
|
|
132
|
+
'rule-extractor.md',
|
|
133
|
+
'market-evidence-grader.md',
|
|
134
|
+
'channel-experiment-tracker.md',
|
|
135
|
+
'definition-lint.md',
|
|
136
|
+
'acceptance-oracle-tracker.md'
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
if (require.main === module) {
|
|
140
|
+
main().catch((error) => {
|
|
141
|
+
console.error(error && error.stack ? error.stack : String(error));
|
|
142
|
+
process.exit(1);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = { toPortablePath };
|
|
147
|
+
|
|
148
|
+
// Paths persisted in generated workflow artifacts are workspace-relative
|
|
149
|
+
// identifiers, not host-OS paths. Keep them stable across Windows/macOS/Linux.
|
|
150
|
+
function toPortablePath(value) {
|
|
151
|
+
return String(value).replace(/\\/g, '/');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function main() {
|
|
155
|
+
const options = parseArgs(process.argv.slice(2));
|
|
156
|
+
const target = path.resolve(options.target || process.cwd());
|
|
157
|
+
if (!fs.existsSync(target) || !fs.statSync(target).isDirectory()) {
|
|
158
|
+
throw new Error(`目标目录不存在: ${target}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const detectedTools = detectTools(target);
|
|
162
|
+
let enabledTools = options.tools ? normalizeTools(options.tools) : detectedTools;
|
|
163
|
+
const interactive = process.stdin.isTTY && process.stdout.isTTY && !options.yes && !options.dryRun;
|
|
164
|
+
|
|
165
|
+
if (!enabledTools.length && interactive) {
|
|
166
|
+
const answer = await promptLine(
|
|
167
|
+
`请选择 AI 工具(${SUPPORTED_TOOLS.join(', ')})。留空会生成全部薄 adapter: `
|
|
168
|
+
);
|
|
169
|
+
enabledTools = normalizeTools(answer || SUPPORTED_TOOLS.join(','));
|
|
170
|
+
}
|
|
171
|
+
if (!enabledTools.length) enabledTools = SUPPORTED_TOOLS.slice();
|
|
172
|
+
|
|
173
|
+
const repos = scanRepos(target);
|
|
174
|
+
const sources = scanRequiredSources(target);
|
|
175
|
+
const missing = REQUIRED_SOURCES.filter((item) => sources[item.key].status === 'missing');
|
|
176
|
+
|
|
177
|
+
const profile = {
|
|
178
|
+
target,
|
|
179
|
+
enabledTools,
|
|
180
|
+
detectedTools,
|
|
181
|
+
repos,
|
|
182
|
+
sources,
|
|
183
|
+
missing
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
if (interactive && missing.length) {
|
|
187
|
+
for (const item of missing) {
|
|
188
|
+
const answer = await promptLine(`${item.question} (optional, comma separated): `);
|
|
189
|
+
if (answer.trim()) {
|
|
190
|
+
sources[item.key] = {
|
|
191
|
+
status: 'provided_by_user',
|
|
192
|
+
paths: answer.split(',').map((v) => v.trim()).filter(Boolean)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
profile.missing = REQUIRED_SOURCES.filter((item) => sources[item.key].status === 'missing');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const plannedWrites = buildInstallPlan(target, profile, options);
|
|
200
|
+
if (options.dryRun) {
|
|
201
|
+
printDryRun(target, profile, plannedWrites);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (const write of plannedWrites) {
|
|
206
|
+
writeManagedFile(write.file, write.content, options);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
console.log(`已在 ${target} 初始化 agent 工作流`);
|
|
210
|
+
console.log(`启用工具: ${enabledTools.join(', ')}`);
|
|
211
|
+
if (profile.missing.length) {
|
|
212
|
+
console.log('部分必要资料未找到,请查看 workflow/INITIALIZATION_QUESTIONS.md。');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function parseArgs(argv) {
|
|
217
|
+
const options = { target: '', tools: '', yes: false, force: false, upgrade: false, dryRun: false };
|
|
218
|
+
for (let i = 0; i < argv.length; i++) {
|
|
219
|
+
const arg = argv[i];
|
|
220
|
+
if (arg === '--target') options.target = argv[++i] || '';
|
|
221
|
+
else if (arg === '--tools') options.tools = argv[++i] || '';
|
|
222
|
+
else if (arg === '--yes' || arg === '-y') options.yes = true;
|
|
223
|
+
else if (arg === '--force') options.force = true;
|
|
224
|
+
else if (arg === '--upgrade') options.upgrade = true;
|
|
225
|
+
else if (arg === '--dry-run') options.dryRun = true;
|
|
226
|
+
else if (arg === '--help' || arg === '-h') {
|
|
227
|
+
printHelp();
|
|
228
|
+
process.exit(0);
|
|
229
|
+
}
|
|
230
|
+
else throw new Error(`未知参数: ${arg}`);
|
|
231
|
+
}
|
|
232
|
+
return options;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function printHelp() {
|
|
236
|
+
console.log(`用法: node bin/init-workspace.cjs [options]
|
|
237
|
+
|
|
238
|
+
选项:
|
|
239
|
+
--target <dir> 目标工作区根目录,默认是当前目录。
|
|
240
|
+
--tools <list> 逗号分隔的工具列表: ${SUPPORTED_TOOLS.join(', ')}。
|
|
241
|
+
--yes, -y 非交互模式,缺失资料会写入问题清单。
|
|
242
|
+
--force 覆盖已生成的入口文件。
|
|
243
|
+
--upgrade 刷新生成文件;存在 team-profile.yaml 时按当前策略处理。
|
|
244
|
+
--dry-run 只展示计划写入的文件,不修改磁盘。
|
|
245
|
+
--help, -h 显示帮助。
|
|
246
|
+
|
|
247
|
+
该初始化命令不会执行远程 Git 操作、push 代码、触发构建部署或数据库写入。
|
|
248
|
+
个人工作流允许后续 agent 在明确任务范围内执行本地分支命名、创建、commit、tag 和本地 merge;远程 push、release、部署和生产配置写入仍需要用户明确授权。`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function normalizeTools(value) {
|
|
252
|
+
const raw = Array.isArray(value) ? value : String(value).split(',');
|
|
253
|
+
const normalized = [];
|
|
254
|
+
for (const item of raw) {
|
|
255
|
+
const input = item.trim().toLowerCase();
|
|
256
|
+
const tool = TOOL_ALIASES[input] || input;
|
|
257
|
+
if (!tool) continue;
|
|
258
|
+
if (!SUPPORTED_TOOLS.includes(tool)) {
|
|
259
|
+
throw new Error(`不支持的工具: ${tool}。支持的工具: ${SUPPORTED_TOOLS.join(', ')}`);
|
|
260
|
+
}
|
|
261
|
+
if (!normalized.includes(tool)) normalized.push(tool);
|
|
262
|
+
}
|
|
263
|
+
return normalized;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function promptLine(question) {
|
|
267
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
268
|
+
return new Promise((resolve) => {
|
|
269
|
+
rl.question(question, (answer) => {
|
|
270
|
+
rl.close();
|
|
271
|
+
resolve(answer);
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function detectTools(root) {
|
|
277
|
+
const hits = [];
|
|
278
|
+
const exists = (rel) => fs.existsSync(path.join(root, rel));
|
|
279
|
+
if (exists('.codex') || exists('AGENTS.md')) hits.push('codex');
|
|
280
|
+
if (exists('.claude') || exists('CLAUDE.md')) hits.push('claude');
|
|
281
|
+
if (exists('.cursor')) hits.push('cursor');
|
|
282
|
+
if (exists('.github/copilot-instructions.md') || exists('.github/prompts')) hits.push('copilot');
|
|
283
|
+
if (exists('.codebuddy')) hits.push('codebuddy');
|
|
284
|
+
if (exists('.kiro')) hits.push('kiro');
|
|
285
|
+
if (exists('.trae')) hits.push('trae');
|
|
286
|
+
return hits;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function scanRepos(root) {
|
|
290
|
+
const repos = [];
|
|
291
|
+
const seen = new Set();
|
|
292
|
+
|
|
293
|
+
function visit(dir, depth) {
|
|
294
|
+
if (depth > 2) return;
|
|
295
|
+
let entries;
|
|
296
|
+
try {
|
|
297
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
298
|
+
} catch {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const rel = toPortablePath(path.relative(root, dir)) || '.';
|
|
303
|
+
const marker = detectRepoMarker(dir);
|
|
304
|
+
if (marker && !seen.has(rel)) {
|
|
305
|
+
seen.add(rel);
|
|
306
|
+
repos.push({
|
|
307
|
+
path: rel,
|
|
308
|
+
marker,
|
|
309
|
+
tech_stack: detectTechStack(dir)
|
|
310
|
+
});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
for (const entry of entries) {
|
|
315
|
+
if (!entry.isDirectory()) continue;
|
|
316
|
+
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;
|
|
317
|
+
visit(path.join(dir, entry.name), depth + 1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
visit(root, 0);
|
|
322
|
+
return repos.sort((a, b) => a.path.localeCompare(b.path));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function detectRepoMarker(dir) {
|
|
326
|
+
const markers = [
|
|
327
|
+
['.git', 'git'],
|
|
328
|
+
['package.json', 'node'],
|
|
329
|
+
['pom.xml', 'maven'],
|
|
330
|
+
['build.gradle', 'gradle'],
|
|
331
|
+
['go.mod', 'go'],
|
|
332
|
+
['Cargo.toml', 'rust'],
|
|
333
|
+
['pyproject.toml', 'python'],
|
|
334
|
+
['requirements.txt', 'python']
|
|
335
|
+
];
|
|
336
|
+
for (const [file, marker] of markers) {
|
|
337
|
+
if (fs.existsSync(path.join(dir, file))) return marker;
|
|
338
|
+
}
|
|
339
|
+
return '';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function detectTechStack(dir) {
|
|
343
|
+
const stack = [];
|
|
344
|
+
const has = (file) => fs.existsSync(path.join(dir, file));
|
|
345
|
+
if (has('pom.xml')) stack.push('java-maven');
|
|
346
|
+
if (has('build.gradle')) stack.push('java-gradle');
|
|
347
|
+
if (has('package.json')) {
|
|
348
|
+
stack.push('node');
|
|
349
|
+
try {
|
|
350
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
351
|
+
const deps = Object.assign({}, pkg.dependencies || {}, pkg.devDependencies || {});
|
|
352
|
+
if (deps.vue) stack.push('vue');
|
|
353
|
+
if (deps.react) stack.push('react');
|
|
354
|
+
if (deps.next) stack.push('nextjs');
|
|
355
|
+
if (deps.vite) stack.push('vite');
|
|
356
|
+
if (deps.typescript) stack.push('typescript');
|
|
357
|
+
} catch {
|
|
358
|
+
stack.push('package-json-unreadable');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (has('go.mod')) stack.push('go');
|
|
362
|
+
if (has('pyproject.toml') || has('requirements.txt')) stack.push('python');
|
|
363
|
+
return stack.length ? stack : ['unknown'];
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function scanRequiredSources(root) {
|
|
367
|
+
const candidates = [];
|
|
368
|
+
walkFiles(root, 4, (file) => {
|
|
369
|
+
const ext = path.extname(file).toLowerCase();
|
|
370
|
+
if (!['.md', '.txt', '.docx', '.pdf', '.yaml', '.yml', '.json'].includes(ext)) return;
|
|
371
|
+
candidates.push(toPortablePath(path.relative(root, file)));
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
const result = {};
|
|
375
|
+
for (const source of REQUIRED_SOURCES) {
|
|
376
|
+
const matches = candidates.filter((rel) => source.match.test(rel)).slice(0, 20);
|
|
377
|
+
result[source.key] = matches.length
|
|
378
|
+
? { status: 'detected', paths: matches }
|
|
379
|
+
: { status: 'missing', paths: [] };
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function walkFiles(root, maxDepth, visitor) {
|
|
385
|
+
function visit(dir, depth) {
|
|
386
|
+
if (depth > maxDepth) return;
|
|
387
|
+
let entries;
|
|
388
|
+
try {
|
|
389
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
390
|
+
} catch {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
for (const entry of entries) {
|
|
394
|
+
const full = path.join(dir, entry.name);
|
|
395
|
+
if (entry.isDirectory()) {
|
|
396
|
+
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;
|
|
397
|
+
visit(full, depth + 1);
|
|
398
|
+
} else {
|
|
399
|
+
visitor(full);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
visit(root, 0);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function buildInstallPlan(target, profile, options) {
|
|
407
|
+
const writes = [];
|
|
408
|
+
const add = (rel, content) => writes.push({ file: path.join(target, rel), content });
|
|
409
|
+
|
|
410
|
+
add('workflow/team-profile.yaml', makeTeamProfileYaml(profile));
|
|
411
|
+
add('workflow/README.md', makeWorkflowReadme());
|
|
412
|
+
add('workflow/core/README.md', readKitFile('workflow/core/README.md'));
|
|
413
|
+
add('workflow/core/commands/README.md', readKitFile('workflow/core/commands/README.md'));
|
|
414
|
+
add('workflow/core/templates/README.md', readKitFile('workflow/core/templates/README.md'));
|
|
415
|
+
add('workflow/core/templates/00-workflow-status.md', readKitFile('workflow/core/templates/00-workflow-status.md'));
|
|
416
|
+
add('workflow/core/templates/stage-document.md', readKitFile('workflow/core/templates/stage-document.md'));
|
|
417
|
+
add('workflow/core/templates/00-business-status.md', readKitFile('workflow/core/templates/00-business-status.md'));
|
|
418
|
+
add('workflow/core/templates/business-stage-document.md', readKitFile('workflow/core/templates/business-stage-document.md'));
|
|
419
|
+
add('workflow/core/templates/completion-contract.md', readKitFile('workflow/core/templates/completion-contract.md'));
|
|
420
|
+
add('workflow/core/templates/constitution.template.md', readKitFile('workflow/core/templates/constitution.template.md'));
|
|
421
|
+
add('workflow/core/templates/living-spec.md', readKitFile('workflow/core/templates/living-spec.md'));
|
|
422
|
+
add('workflow/constitution.md', readKitFile('workflow/core/templates/constitution.template.md'));
|
|
423
|
+
add('workflow/standards/README.md', makeStandardsReadme());
|
|
424
|
+
add('specs/README.md', makeSpecsReadme());
|
|
425
|
+
add('workflow/core/templates/team-profile.template.yaml', readKitFile('workflow/core/templates/team-profile.template.yaml'));
|
|
426
|
+
add('workflow/core/capabilities/README.md', readKitFile('workflow/core/capabilities/README.md'));
|
|
427
|
+
for (const name of CAPABILITY_FILES) {
|
|
428
|
+
add(`workflow/core/capabilities/${name}`, readKitFile(`workflow/core/capabilities/${name}`));
|
|
429
|
+
}
|
|
430
|
+
add('workflow/adapters/README.md', readKitFile('workflow/adapters/README.md'));
|
|
431
|
+
add('workflow/INSTALL_REPORT.md', makeInstallReport(profile, options));
|
|
432
|
+
if (profile.missing.length) add('workflow/INITIALIZATION_QUESTIONS.md', makeQuestions(profile));
|
|
433
|
+
|
|
434
|
+
for (const [id, title, description] of STAGES) {
|
|
435
|
+
const rel = `workflow/core/commands/${id}.md`;
|
|
436
|
+
add(rel, readKitFileIfExists(rel, makeCoreCommand(id, title, description)));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// AGENTS.md is the tool-neutral entry document and the full usage guide.
|
|
440
|
+
// Generate it regardless of selected tools so every adapter can point to it.
|
|
441
|
+
add('AGENTS.md', makeAgentsEntry(profile));
|
|
442
|
+
if (profile.enabledTools.includes('codex')) {
|
|
443
|
+
for (const [id] of STAGES) add(`.codex/prompts/${id}.md`, makePrompt(id));
|
|
444
|
+
}
|
|
445
|
+
if (profile.enabledTools.includes('claude')) {
|
|
446
|
+
add('CLAUDE.md', '先读取 AGENTS.md,再遵循 workflow/core 和 workflow/team-profile.yaml。.claude/commands 下的工具命令只是薄 adapter。\n');
|
|
447
|
+
for (const [id] of STAGES) add(`.claude/commands/${id}.md`, makeThinCommand('Claude Code', id));
|
|
448
|
+
}
|
|
449
|
+
if (profile.enabledTools.includes('cursor')) {
|
|
450
|
+
add('.cursor/rules/agent-workflow-core.mdc', makeCursorRule());
|
|
451
|
+
// Cursor 1.6+ supports custom slash commands from .cursor/commands/*.md.
|
|
452
|
+
for (const [id] of STAGES) add(`.cursor/commands/${id}.md`, makeThinCommand('Cursor', id));
|
|
453
|
+
}
|
|
454
|
+
if (profile.enabledTools.includes('copilot')) {
|
|
455
|
+
add('.github/copilot-instructions.md', makeGenericInstructions('GitHub Copilot'));
|
|
456
|
+
}
|
|
457
|
+
if (profile.enabledTools.includes('codebuddy')) {
|
|
458
|
+
add('.codebuddy/instructions.md', makeGenericInstructions('CodeBuddy'));
|
|
459
|
+
}
|
|
460
|
+
if (profile.enabledTools.includes('kiro')) {
|
|
461
|
+
add('.kiro/instructions.md', makeGenericInstructions('Kiro'));
|
|
462
|
+
}
|
|
463
|
+
if (profile.enabledTools.includes('trae')) {
|
|
464
|
+
add('.trae/instructions.md', makeGenericInstructions('Trae'));
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return writes;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function readKitFile(rel) {
|
|
471
|
+
return fs.readFileSync(path.join(KIT_ROOT, rel), 'utf8');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function readKitFileIfExists(rel, fallback) {
|
|
475
|
+
const file = path.join(KIT_ROOT, rel);
|
|
476
|
+
return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : fallback;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function writeManagedFile(file, content, options) {
|
|
480
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
481
|
+
if (fs.existsSync(file) && !options.force) {
|
|
482
|
+
const current = fs.readFileSync(file, 'utf8');
|
|
483
|
+
if (current === content) {
|
|
484
|
+
console.log(`unchanged ${path.relative(process.cwd(), file)}`);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const next = file + '.agent-workflow-new';
|
|
488
|
+
fs.writeFileSync(next, content);
|
|
489
|
+
console.log(`exists ${path.relative(process.cwd(), file)} -> wrote ${path.relative(process.cwd(), next)}`);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
fs.writeFileSync(file, content);
|
|
493
|
+
console.log(`wrote ${path.relative(process.cwd(), file)}`);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function printDryRun(target, profile, writes) {
|
|
497
|
+
console.log(`Dry run 目标目录: ${target}`);
|
|
498
|
+
console.log(`已识别工具: ${profile.detectedTools.join(', ') || '(无)'}`);
|
|
499
|
+
console.log(`启用工具: ${profile.enabledTools.join(', ')}`);
|
|
500
|
+
console.log(`已识别仓库: ${profile.repos.length}`);
|
|
501
|
+
console.log(`缺失资料组: ${profile.missing.map((item) => item.key).join(', ') || '(无)'}`);
|
|
502
|
+
console.log('计划写入:');
|
|
503
|
+
for (const write of writes) console.log(`- ${path.relative(target, write.file)}`);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function makeTeamProfileYaml(profile) {
|
|
507
|
+
const lines = [];
|
|
508
|
+
lines.push('schema_version: "1.0"');
|
|
509
|
+
lines.push(`generated_at: "${new Date().toISOString()}"`);
|
|
510
|
+
lines.push(`generated_by: "${GENERATED_BY}"`);
|
|
511
|
+
lines.push('');
|
|
512
|
+
lines.push('team:');
|
|
513
|
+
lines.push(' name: "<TODO: 团队名称>"');
|
|
514
|
+
lines.push(' business_definition: "<TODO: 简短业务描述>"');
|
|
515
|
+
lines.push(' target_users: []');
|
|
516
|
+
lines.push('');
|
|
517
|
+
lines.push('enabled_tools:');
|
|
518
|
+
for (const tool of profile.enabledTools) lines.push(` - ${tool}`);
|
|
519
|
+
lines.push('');
|
|
520
|
+
lines.push('detected_tools:');
|
|
521
|
+
if (profile.detectedTools.length) for (const tool of profile.detectedTools) lines.push(` - ${tool}`);
|
|
522
|
+
else lines.push(' []');
|
|
523
|
+
lines.push('');
|
|
524
|
+
lines.push('source_materials:');
|
|
525
|
+
for (const item of REQUIRED_SOURCES) {
|
|
526
|
+
const source = profile.sources[item.key];
|
|
527
|
+
lines.push(` ${item.key}:`);
|
|
528
|
+
lines.push(` label: ${yamlString(item.label)}`);
|
|
529
|
+
lines.push(` status: ${yamlString(source.status)}`);
|
|
530
|
+
lines.push(' paths:');
|
|
531
|
+
if (source.paths.length) for (const p of source.paths) lines.push(` - ${yamlString(p)}`);
|
|
532
|
+
else lines.push(' []');
|
|
533
|
+
}
|
|
534
|
+
lines.push('');
|
|
535
|
+
lines.push('repos:');
|
|
536
|
+
if (profile.repos.length) {
|
|
537
|
+
for (const repo of profile.repos) {
|
|
538
|
+
lines.push(` - path: ${yamlString(repo.path)}`);
|
|
539
|
+
lines.push(` marker: ${yamlString(repo.marker)}`);
|
|
540
|
+
lines.push(' tech_stack:');
|
|
541
|
+
for (const tech of repo.tech_stack) lines.push(` - ${yamlString(tech)}`);
|
|
542
|
+
lines.push(' family: "<TODO: 项目族分类>"');
|
|
543
|
+
lines.push(' role: "<TODO: 服务或产品角色>"');
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
lines.push(' []');
|
|
547
|
+
}
|
|
548
|
+
lines.push('');
|
|
549
|
+
lines.push('branch_model:');
|
|
550
|
+
lines.push(' type: "personal-prod-main-feature"');
|
|
551
|
+
lines.push(' production_branch: "prod"');
|
|
552
|
+
lines.push(' integration_branch: "main"');
|
|
553
|
+
lines.push(' feature_branch_rule: "agent may create feature/<short-name> or fix/<short-name> from prod when the target repo is personal and the working tree is clean"');
|
|
554
|
+
lines.push(' worktree_dir: "_worktrees"');
|
|
555
|
+
lines.push('');
|
|
556
|
+
lines.push('risk_policy:');
|
|
557
|
+
lines.push(' local_git_operations: "agent-allowed-after-scope-check"');
|
|
558
|
+
lines.push(' branch_creation: "agent-allowed-for-personal-repos"');
|
|
559
|
+
lines.push(' commit_tag_local_merge: "agent-allowed-after-verification"');
|
|
560
|
+
lines.push(' remote_git_operations: "explicit-user-authorization-required"');
|
|
561
|
+
lines.push(' push_and_release: "explicit-user-authorization-required"');
|
|
562
|
+
lines.push(' outbound_marketing_actions: "explicit-user-authorization-required"');
|
|
563
|
+
lines.push(' paid_ad_spend: "manual-only"');
|
|
564
|
+
lines.push(' database_writes: "manual-only"');
|
|
565
|
+
lines.push(' config_writes: "manual-only"');
|
|
566
|
+
lines.push(' high_risk_files:');
|
|
567
|
+
lines.push(' - "ci/**"');
|
|
568
|
+
lines.push(' - "cd/**"');
|
|
569
|
+
lines.push(' - "deploy/**"');
|
|
570
|
+
lines.push(' - "*.env*"');
|
|
571
|
+
lines.push(' - "application*.yml"');
|
|
572
|
+
lines.push(' - "application*.yaml"');
|
|
573
|
+
lines.push(' - "bootstrap*.yml"');
|
|
574
|
+
lines.push(' - "bootstrap*.yaml"');
|
|
575
|
+
lines.push(' - "pom.xml"');
|
|
576
|
+
lines.push(' - "package.json"');
|
|
577
|
+
lines.push(' - "lockfiles"');
|
|
578
|
+
lines.push('');
|
|
579
|
+
lines.push('workflow:');
|
|
580
|
+
lines.push(' features_dir: "features"');
|
|
581
|
+
lines.push(' business_dir: "business"');
|
|
582
|
+
lines.push(' specs_dir: "specs"');
|
|
583
|
+
lines.push(' standards_dir: "workflow/standards"');
|
|
584
|
+
lines.push(' constitution: "workflow/constitution.md"');
|
|
585
|
+
lines.push(' core_dir: "workflow/core"');
|
|
586
|
+
lines.push(' adapters_dir: "workflow/adapters"');
|
|
587
|
+
lines.push(' require_stage_gate_for_code: true');
|
|
588
|
+
lines.push(' require_feature_branch_for_code: true');
|
|
589
|
+
lines.push(' complexity_tiers: "S/M/L"');
|
|
590
|
+
lines.push(' definition_gate: "frozen-contract-with-lint-required-for-m-l; starred-mini-contract-for-s"');
|
|
591
|
+
lines.push(' done_verdict: "all-blocking-oracles-pass-or-user-waived"');
|
|
592
|
+
lines.push(' same_repo_parallel_policy: "worktree-required-after-implementation-stage"');
|
|
593
|
+
lines.push(' business_review_cadence: "weekly-metrics, monthly-strategy, quarterly-positioning"');
|
|
594
|
+
lines.push('');
|
|
595
|
+
return lines.join('\n');
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function yamlString(value) {
|
|
599
|
+
return JSON.stringify(String(value));
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function makeWorkflowReadme() {
|
|
603
|
+
return `# Workflow
|
|
604
|
+
|
|
605
|
+
本目录由 ${GENERATED_BY} 生成,用于个人开发者项目。
|
|
606
|
+
|
|
607
|
+
- \`team-profile.yaml\`: 当前个人项目或个人工作区的本地配置(事实与路径)。
|
|
608
|
+
- \`constitution.md\`: 工作区宪法——跨需求不可协商的原则。
|
|
609
|
+
- \`standards/\`: 从既有代码库提取的个人规范层。
|
|
610
|
+
- \`core/\`: 工具无关的工作流规则、命令、模板和能力。
|
|
611
|
+
- \`adapters/\`: 支持工具的 adapter 说明。
|
|
612
|
+
- \`INITIALIZATION_QUESTIONS.md\`: 缺少必要本地资料时生成的问题清单。
|
|
613
|
+
|
|
614
|
+
研发轨判定核心是《完成合同》(\`features/<feature>/00-完成合同.md\`):\`/定义完成\` 编译并冻结合同,宣布完成 = blocking Oracle 全 PASS;工作区级 \`specs/\` 沉淀已发布行为的 living specs。
|
|
615
|
+
|
|
616
|
+
默认使用简体中文展示工作流沟通、阶段产物、状态摘要、审查结论、测试记录、发布记录和复盘;专有名词、产品名、代码标识符、命令、文件路径、分支名、API、SDK、框架、协议、标准、错误信息和官方英文术语保留原文。
|
|
617
|
+
|
|
618
|
+
工作流分两条轨道:研发轨阶段产物放在工作区级 \`features/<feature>/\` 下,商业化轨(业务定位、商业模式、PMF、渠道与营销策略)阶段产物放在工作区级 \`business/<product>/\` 下,都不写入目标代码仓库。目标代码仓库只保留源码、代码相关配置、运行或构建必需资产,以及最小必要的代码侧 \`README\` 内容。
|
|
619
|
+
|
|
620
|
+
商业化轨只产出文档和清单:对外发布内容、投放广告、cold outreach、联系合作方需要用户明确授权或自行执行;营销工程需求(landing page、SEO 页面、埋点)通过 \`/new-feature\` 回流研发轨。
|
|
621
|
+
|
|
622
|
+
\`/02B-UI设计\` 是前端实现的设计闸门;个人小改动可以记录范围有限的设计豁免,但必须说明影响面和补齐计划。
|
|
623
|
+
|
|
624
|
+
个人工作流允许 agent 在明确任务范围内执行本地 git 分支命名、创建、commit、tag 和本地 merge。远程 push、GitHub release、商店发布、部署和生产配置写入需要用户明确授权。
|
|
625
|
+
|
|
626
|
+
不要把凭证、真实客户秘密或私有 URL 写入通用 core 文件。项目知识应保留在 \`team-profile.yaml\`、\`features/<feature>/\` 或本地资料中。
|
|
627
|
+
`;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function makeStandardsReadme() {
|
|
631
|
+
return `# 个人规范层(standards)
|
|
632
|
+
|
|
633
|
+
本目录存放**从既有代码库提取的可复用规范**:命名、目录结构、错误处理、依赖选型、提交信息等模式。原则放 \`workflow/constitution.md\`,事实与路径放 \`workflow/team-profile.yaml\`,本目录只放"怎么写代码"的规范。
|
|
634
|
+
|
|
635
|
+
- 来源:\`/03-技术架构\` 阶段从现有代码中提取;\`/10-复盘总结\` 沉淀新规则。
|
|
636
|
+
- 用法:\`/定义完成\` 的影响边界、\`/04\` 实现和 \`/05\` 审查都以本目录为基准;已有规范直接引用,不重复发明。
|
|
637
|
+
- 格式:每个主题一个 Markdown 文件(例:\`naming.md\`、\`error-handling.md\`),写清规则、正例、反例和适用范围。
|
|
638
|
+
- 空目录是正常状态:规范应随真实需求逐步沉淀,不要一次性凭空编写。
|
|
639
|
+
`;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function makeSpecsReadme() {
|
|
643
|
+
return `# Living Specs(行为真相层)
|
|
644
|
+
|
|
645
|
+
本目录存放**当前已实现并已发布**的行为规格,是存量项目(brownfield)需求定义的起点。
|
|
646
|
+
|
|
647
|
+
- 与 \`features/\` 的关系:features 是变更流水(做过什么),specs 是当前状态(现在是什么)。
|
|
648
|
+
- 读:\`/01-需求讨论\`、\`/定义完成\`、\`/06-测试用例\`(回归范围)、\`/一致性检查\` 都先读本目录;触碰已有行为的需求必须显式声明改变哪几条行为编号。
|
|
649
|
+
- 写:只有 \`/10-复盘总结\` 在发布后把已验证的行为增量合并进来;未发布的计划不进本目录。
|
|
650
|
+
- 格式:每个领域/模块一个文件,按 \`workflow/core/templates/living-spec.md\` 组织(EARS 句式行为清单 + 数据模型 + 对外契约 + 边界)。
|
|
651
|
+
- 空目录是正常状态:首个需求发布后开始沉淀。
|
|
652
|
+
`;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function makeInstallReport(profile, options) {
|
|
656
|
+
return `# 安装报告
|
|
657
|
+
|
|
658
|
+
- 生成器: ${GENERATED_BY}
|
|
659
|
+
- 生成时间: ${new Date().toISOString()}
|
|
660
|
+
- 启用工具: ${profile.enabledTools.join(', ')}
|
|
661
|
+
- 已识别工具: ${profile.detectedTools.join(', ') || '(无)'}
|
|
662
|
+
- 已识别仓库: ${profile.repos.length}
|
|
663
|
+
- 强制覆盖: ${options.force ? '是' : '否'}
|
|
664
|
+
- 升级模式: ${options.upgrade ? '是' : '否'}
|
|
665
|
+
|
|
666
|
+
## 缺失资料组
|
|
667
|
+
|
|
668
|
+
${profile.missing.length ? profile.missing.map((item) => `- ${item.label} (${item.key})`).join('\n') : '- 无'}
|
|
669
|
+
|
|
670
|
+
## 安全边界
|
|
671
|
+
|
|
672
|
+
初始化器没有执行远程 Git 命令、创建分支、push 代码、触发构建 / 部署任务,也没有执行数据库写入。
|
|
673
|
+
`;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function makeQuestions(profile) {
|
|
677
|
+
return `# 初始化待补资料
|
|
678
|
+
|
|
679
|
+
初始化器未找到全部必要本地资料。请补充路径后重新运行初始化器,或手动更新 \`workflow/team-profile.yaml\`。
|
|
680
|
+
|
|
681
|
+
${profile.missing.map((item) => `## ${item.label}\n\n${item.question}\n\n- path: <TODO>\n`).join('\n')}
|
|
682
|
+
`;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
function makeCoreCommand(id, title, description) {
|
|
686
|
+
const codeStage = id === '04-代码实现' || id === '04A-前端代码实现' || id === '04B-后端代码实现';
|
|
687
|
+
const reviewStage = id === '05-代码审查';
|
|
688
|
+
const prepStage = id === '03-06-研发准备';
|
|
689
|
+
const businessStage = id === 'new-product' || /^B\d/.test(id);
|
|
690
|
+
const containerDir = businessStage ? 'business/{product}' : 'features/{feature}';
|
|
691
|
+
const statusFile = businessStage ? '00-商业化状态.md' : '00-工作流状态.md';
|
|
692
|
+
return `# /${id}
|
|
693
|
+
|
|
694
|
+
## 目标
|
|
695
|
+
|
|
696
|
+
${title}: ${description}
|
|
697
|
+
|
|
698
|
+
## 必要输入
|
|
699
|
+
|
|
700
|
+
- \`AGENTS.md\`
|
|
701
|
+
- \`workflow/team-profile.yaml\`
|
|
702
|
+
- \`workflow/constitution.md\`
|
|
703
|
+
- \`${containerDir}/\` 下的前序阶段文档
|
|
704
|
+
- team-profile 中登记的本地代码、本地文档和用户提供资料
|
|
705
|
+
|
|
706
|
+
## 执行规则
|
|
707
|
+
|
|
708
|
+
- 先读取本地事实,再写结论。
|
|
709
|
+
- 区分已验证事实、设计意图、假设和缺失证据。
|
|
710
|
+
- 未真实执行的测试、构建、截图、部署或审查,不得写成已通过。
|
|
711
|
+
- 个人项目允许 agent 在范围明确且工作树已检查后执行本地分支命名、创建、commit、tag 和本地 merge;远程 push、release、部署、数据库写入和生产配置写入需要用户明确授权。
|
|
712
|
+
${codeStage ? '- 只有功能分支闸门、实现阶段闸门和同仓并行闸门全部通过后,才允许修改业务代码。' : '- 本阶段不授权修改业务代码;除非当前命令是实现命令且所有闸门已通过。'}
|
|
713
|
+
${prepStage ? '- 本编排命令只准备 03 到 06 文档,不授权代码实现。' : ''}
|
|
714
|
+
${businessStage ? '- 商业化结论必须做证据分级(一手/二手/推断)并注明来源和日期,不得编造市场数据;对外发布、投放和 outreach 需要用户明确授权;营销工程需求通过 /new-feature 回流研发轨。' : ''}
|
|
715
|
+
${reviewStage ? '- 审查输出以问题优先,按严重级别排序,并引用文件、diff、测试或运行证据。' : ''}
|
|
716
|
+
|
|
717
|
+
## 必要输出
|
|
718
|
+
|
|
719
|
+
- 更新或创建 \`${containerDir}/\` 下对应阶段文件。
|
|
720
|
+
- 阶段状态变化时更新 \`${containerDir}/${statusFile}\`。
|
|
721
|
+
- 明确记录未解决问题和证据缺口。
|
|
722
|
+
`;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function makeCommandTable() {
|
|
726
|
+
const header = '| 命令 | 阶段 | 作用 |\n| --- | --- | --- |';
|
|
727
|
+
const rows = STAGES.map(
|
|
728
|
+
([id, title, description]) => `| \`/${id}\` | ${title} | ${description} |`
|
|
729
|
+
);
|
|
730
|
+
return [header, ...rows].join('\n');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function makeToolUsage(profile) {
|
|
734
|
+
const tools = profile.enabledTools;
|
|
735
|
+
const blocks = [];
|
|
736
|
+
|
|
737
|
+
if (tools.includes('claude')) {
|
|
738
|
+
blocks.push(`### Claude Code
|
|
739
|
+
|
|
740
|
+
- 阶段命令来自 \`.claude/commands/\`,可直接输入,例如 \`/04-代码实现 <feature>\`。
|
|
741
|
+
- 多文件或复杂改动先进入 plan mode,再执行。
|
|
742
|
+
- 每个命令文件都是薄 adapter,最终都指向 \`workflow/core/commands/\`。`);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (tools.includes('codex')) {
|
|
746
|
+
blocks.push(`### Codex
|
|
747
|
+
|
|
748
|
+
- Codex 会自动读取本 \`AGENTS.md\`。
|
|
749
|
+
- 阶段 prompt 位于 \`.codex/prompts/\`。可以调用阶段 prompt,或要求 Codex 按 \`workflow/core/commands/<stage>.md\` 执行。`);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (tools.includes('cursor')) {
|
|
753
|
+
blocks.push(`### Cursor
|
|
754
|
+
|
|
755
|
+
- 本 kit 会在 \`.cursor/commands/\` 生成 Cursor 自定义斜杠命令(Cursor 1.6+)。在 Agent 输入框输入 \`/\`,选择 \`/04-代码实现\` 等阶段,再描述功能。
|
|
756
|
+
- \`.cursor/rules/agent-workflow-core.mdc\` 会自动应用到每次请求。
|
|
757
|
+
- 兜底方式:直接 @ 阶段契约,例如 \`@workflow/core/commands/04-代码实现.md\`。
|
|
758
|
+
- agent 会读取阶段契约、\`workflow/team-profile.yaml\` 和前序 \`features/<feature>/\` 文档,再写阶段产物。
|
|
759
|
+
- 硬闸门仍然生效:实现必须先通过功能分支闸门和阶段闸门。`);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (tools.includes('copilot')) {
|
|
763
|
+
blocks.push(`### GitHub Copilot
|
|
764
|
+
|
|
765
|
+
- \`.github/copilot-instructions.md\` 会自动生效。
|
|
766
|
+
- 执行阶段时,在 chat 中引用 \`workflow/core/commands/<stage>.md\` 并描述功能。`);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
for (const [tool, label] of [['codebuddy', 'CodeBuddy'], ['kiro', 'Kiro'], ['trae', 'Trae']]) {
|
|
770
|
+
if (tools.includes(tool)) {
|
|
771
|
+
blocks.push(`### ${label}
|
|
772
|
+
|
|
773
|
+
- \`.${tool}/instructions.md\` 会自动生效。
|
|
774
|
+
- 执行阶段时,在 chat 中引用 \`workflow/core/commands/<stage>.md\` 并描述功能。`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (!blocks.length) {
|
|
779
|
+
blocks.push(`未选择特定工具 adapter。请直接读取并执行 \`workflow/core/commands/<stage>.md\`。`);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
return blocks.join('\n\n');
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
function makeAgentsEntry(profile) {
|
|
786
|
+
return `# Agent Workflow
|
|
787
|
+
|
|
788
|
+
本工作区使用 ${GENERATED_BY} 生成的工具无关个人开发者 agent 工作流。它包含两条共享同一套闸门口径的轨道:研发轨把一个需求从澄清、完成合同冻结推进到实现、发布和复盘;商业化轨把一个产品从业务定位、商业模式、PMF 验证推进到渠道策略、预算和策略复盘。判定核心是《完成合同》:宣布完成 = blocking Oracle 全 PASS 的机器判定,不是"感觉做完了"。不同 AI 工具共享同一套 workflow core,每个工具只生成薄 adapter;体验会随工具能力增强或降级,但流程口径一致。
|
|
789
|
+
|
|
790
|
+
## 快速开始
|
|
791
|
+
|
|
792
|
+
1. 先读取 \`workflow/team-profile.yaml\`(事实与路径)、\`workflow/constitution.md\`(不可协商原则);存量项目再读工作区级 \`specs/\`(已实现行为真相)。
|
|
793
|
+
2. 研发轨:用 \`/new-feature <name>\` 初始化需求并完成 S/M/L 复杂度分级。M/L 档推荐顺序:\`/01-需求讨论\` ->(\`/澄清\`)-> \`/02-产品文档\` -> \`/02B-UI设计\` -> \`/03-技术架构\` -> \`/06-测试用例\` -> \`/定义完成\`(编译完成合同,Definition Lint 通过后经用户确认冻结)-> \`/一致性检查\` -> \`/交付至完成\`(或手动 \`/04-代码实现\` -> \`/05-代码审查\` -> \`/07-测试执行\`)-> \`/08-发布准备\` -> \`/09-发布执行\` -> \`/10-复盘总结\`。S 档压缩为:\`/定义完成\`(迷你合同)-> 实现 -> 验证。
|
|
794
|
+
3. 商业化轨:用 \`/new-product <name>\` 初始化产品商业化容器 \`business/<name>/\`;首次可用 \`/B1-B8-商业化准备\` 一次性串联生成 \`/B1-业务定位\` -> \`/B2-商业模式\` -> \`/B3-PMF与客户画像\` -> \`/B4-场景与购买旅程\` -> \`/B5-渠道漏斗映射\` -> \`/B6-营销获客策略\` -> \`/B7-营销预算\` -> \`/B8-渠道执行策略\`;上线后按周期执行 \`/B9-策略复盘\`。
|
|
795
|
+
4. 两轨衔接:\`/01\`、\`/02\` 读取商业化基线(定位、ICP、场景、商业模式),完成合同记录北极星挂钩;\`/08\`、\`/09\` 对照 B5/B8 准备发布营销材料和分发清单;\`/10\` 的增长信号回流 \`/B9\`,行为增量回写 \`specs/\`;B8 的营销工程需求(landing、SEO 页面、埋点)通过 \`/new-feature\` 进入研发轨。
|
|
796
|
+
5. 每个阶段都必须读取所在容器(\`features/<name>/\` 或 \`business/<name>/\`)下的前序文档,并把本阶段产物写回同目录。
|
|
797
|
+
6. 随时可执行 \`/workflow-status\` 汇总两轨全部需求和产品的阶段、合同与 Oracle 进度、阻塞和下一步。
|
|
798
|
+
|
|
799
|
+
不同工具触发阶段的方式不同,见下方“工具使用方式”。
|
|
800
|
+
|
|
801
|
+
## 工作流命令
|
|
802
|
+
|
|
803
|
+
${makeCommandTable()}
|
|
804
|
+
|
|
805
|
+
## 任务描述模板
|
|
806
|
+
|
|
807
|
+
启动阶段时,尽量用三段描述任务,保证 agent 有足够上下文:
|
|
808
|
+
|
|
809
|
+
- **目标**:完成后必须达成什么。
|
|
810
|
+
- **约束**:哪些内容不能改,例如公开 API、数据库结构、鉴权链路、无关模块。
|
|
811
|
+
- **验收**:如何证明正确,例如测试、脚本、API 调用、浏览器检查、截图。
|
|
812
|
+
|
|
813
|
+
## 单一事实源
|
|
814
|
+
|
|
815
|
+
- 工作流规则:\`workflow/core/\`
|
|
816
|
+
- 工作区配置(事实与路径):\`workflow/team-profile.yaml\`
|
|
817
|
+
- 工作区宪法(不可协商原则):\`workflow/constitution.md\`
|
|
818
|
+
- 个人规范层:\`workflow/standards/\`
|
|
819
|
+
- 行为真相层(living specs):工作区级 \`specs/\`
|
|
820
|
+
- 可复用检查能力:\`workflow/core/capabilities/\`
|
|
821
|
+
- 需求产物与完成合同:工作区级 \`features/<feature>/\`(合同为 \`00-完成合同.md\`)
|
|
822
|
+
- 商业化产物:工作区级 \`business/<product>/\`
|
|
823
|
+
- 工具 adapter:仅作为生成的薄入口
|
|
824
|
+
|
|
825
|
+
## 硬闸门
|
|
826
|
+
|
|
827
|
+
- 产品和工作流文档默认与代码仓库分开;如果个人项目需要公开 \`README\`、\`CHANGELOG\`、release notes、商店文案或隐私政策,可以在发布阶段明确记录为代码侧/公开侧材料。
|
|
828
|
+
- 功能分支闸门和实现阶段闸门通过前,禁止修改业务代码。
|
|
829
|
+
- \`/02B-UI设计\` 是前端实现的设计闸门;\`/04A-前端代码实现\` 必须读取并遵循工作区级 \`features/<feature>/02B-UI设计.md\`,缺失时先补齐 02B,除非用户明确给出范围有限的设计豁免。
|
|
830
|
+
- \`/03-06-研发准备\` 以及 01/02/02B/03 阶段只授权分析和工作流文档。
|
|
831
|
+
- 个人项目允许 agent 在目标仓库工作树干净、范围明确、测试计划明确时执行本地分支命名、创建、commit、tag 和本地 merge。
|
|
832
|
+
- 远程 push、GitHub release、商店发布、部署、数据库写入、生产配置写入和公开发布动作必须有用户明确授权。
|
|
833
|
+
- 同仓多需求进入实现阶段后,必须使用独立 worktree。
|
|
834
|
+
- 商业化轨(\`/new-product\`、\`/B1\` 到 \`/B9\`)只产出文档和清单:对外发布内容、投放广告、发送 cold email、联系 influencer 或合作伙伴必须有用户明确授权或由用户自行执行;付费投放支出由用户手动执行。
|
|
835
|
+
- 商业化结论必须做证据分级(一手/二手/推断)并注明来源和日期,不得编造市场数据、用户评价或竞品价格。
|
|
836
|
+
- 营销工程需求(landing page、SEO 页面、埋点、A/B 测试)必须通过 \`/new-feature\` 进入研发轨并遵守其全部闸门,不在 B 阶段直接修改代码。
|
|
837
|
+
- **完成合同闸门**:M/L 档需求进入实现(\`/04\` 或 \`/交付至完成\`)前,\`features/<feature>/00-完成合同.md\` 必须已冻结且 Definition Lint 通过;S 档必须有 ★ 必填节完整的迷你合同。冻结需用户明确确认。
|
|
838
|
+
- **合同不可静默修改**:冻结后的标准、阈值、blocking 标记只能走修订记录并经用户再次确认;改测试换通过按高危问题处理。
|
|
839
|
+
- **完成判定**:宣布完成 = blocking Oracle 全部 PASS(或用户书面确认 WAIVED);Oracle 状态只能由 \`/交付至完成\` 或 \`/07-测试执行\` 翻转且必须附证据;PASS 后代码再变更置 STALE 必须复验。
|
|
840
|
+
- \`workflow/constitution.md\` 在所有阶段不可协商;与需求冲突时先经用户确认修订宪法,不得绕过。
|
|
841
|
+
|
|
842
|
+
## 工具能力策略
|
|
843
|
+
|
|
844
|
+
workflow core 是共享的。工具 adapter 可按当前工具能力增强或降级:
|
|
845
|
+
|
|
846
|
+
- L0:文档规则
|
|
847
|
+
- L1:prompt 和命令模板
|
|
848
|
+
- L2:工具原生规则或 slash commands
|
|
849
|
+
- L3:hooks 或前置检查
|
|
850
|
+
- L4:subagents 或多 agent 路由
|
|
851
|
+
|
|
852
|
+
不要承诺所有工具体验完全一致。只能使用当前工具自己的 adapter。
|
|
853
|
+
|
|
854
|
+
## 工具使用方式
|
|
855
|
+
|
|
856
|
+
${makeToolUsage(profile)}
|
|
857
|
+
|
|
858
|
+
## 已启用工具
|
|
859
|
+
|
|
860
|
+
${profile.enabledTools.map((tool) => `- ${tool}`).join('\n')}
|
|
861
|
+
|
|
862
|
+
## 参考文件
|
|
863
|
+
|
|
864
|
+
- \`workflow/README.md\`:工作流总览。
|
|
865
|
+
- \`workflow/core/commands/\`:各阶段契约。
|
|
866
|
+
- \`workflow/core/capabilities/README.md\`:可复用检查能力及工具适配方式。
|
|
867
|
+
- \`workflow/core/templates/completion-contract.md\`:完成合同模板(可用 \`openone-workflow-check-contract\` 校验结构)。
|
|
868
|
+
- \`workflow/constitution.md\`:工作区宪法;\`workflow/standards/\`:个人规范层;\`specs/\`:living specs。
|
|
869
|
+
- \`workflow/team-profile.yaml\`:当前工作区配置和资料扫描结果。
|
|
870
|
+
|
|
871
|
+
## 开始
|
|
872
|
+
|
|
873
|
+
先读取 \`workflow/team-profile.yaml\`,再按用户请求的阶段读取 \`workflow/core/commands/\`。
|
|
874
|
+
`;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function makeThinCommand(toolName, id) {
|
|
878
|
+
return `# ${toolName} adapter for /${id}
|
|
879
|
+
|
|
880
|
+
这是薄 adapter。执行时必须按顺序读取:
|
|
881
|
+
|
|
882
|
+
1. \`AGENTS.md\`
|
|
883
|
+
2. \`workflow/team-profile.yaml\`
|
|
884
|
+
3. \`workflow/core/commands/${id}.md\`
|
|
885
|
+
|
|
886
|
+
不得加入与 workflow/core 冲突的工具特定行为。
|
|
887
|
+
`;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function makePrompt(id) {
|
|
891
|
+
return `# ${id}
|
|
892
|
+
|
|
893
|
+
读取 \`AGENTS.md\`、\`workflow/team-profile.yaml\` 和 \`workflow/core/commands/${id}.md\`。
|
|
894
|
+
|
|
895
|
+
优先使用本地证据。必要资料缺失时,更新 \`workflow/INITIALIZATION_QUESTIONS.md\` 或向用户索要缺失路径。
|
|
896
|
+
`;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function makeCursorRule() {
|
|
900
|
+
return `---
|
|
901
|
+
description: "个人开发者 agent 工作流:分阶段交付、审查、测试、发布和复盘。"
|
|
902
|
+
alwaysApply: true
|
|
903
|
+
---
|
|
904
|
+
|
|
905
|
+
# Agent Workflow (Cursor)
|
|
906
|
+
|
|
907
|
+
本工作区使用工具无关的分阶段工作流。本规则会自动应用到每次请求。
|
|
908
|
+
完整使用说明见 \`AGENTS.md\`。
|
|
909
|
+
|
|
910
|
+
## 在 Cursor 中执行阶段
|
|
911
|
+
|
|
912
|
+
本 kit 会在 \`.cursor/commands/\` 生成 Cursor 自定义 slash commands(Cursor 1.6+)。
|
|
913
|
+
在 Agent 输入框输入 \`/\`,选择阶段,再描述功能。例如:
|
|
914
|
+
|
|
915
|
+
- \`/01-需求讨论\` 开始一个新需求
|
|
916
|
+
- \`/04-代码实现\` 对指定需求进入实现阶段
|
|
917
|
+
|
|
918
|
+
兜底方式:可以直接 @ 阶段契约,例如
|
|
919
|
+
\`@workflow/core/commands/04-代码实现.md\`.
|
|
920
|
+
|
|
921
|
+
agent 随后读取阶段契约、\`workflow/team-profile.yaml\` 和前序
|
|
922
|
+
\`features/<feature>/\` 文档,并把阶段产物写入 \`features/<feature>/\`。
|
|
923
|
+
|
|
924
|
+
## 阶段顺序
|
|
925
|
+
|
|
926
|
+
研发轨(M/L 档):
|
|
927
|
+
new-feature(S/M/L 分级)-> 01-需求讨论 ->(澄清)-> 02-产品文档 -> 02B-UI设计 -> 03-技术架构 ->
|
|
928
|
+
06-测试用例 -> 定义完成(冻结完成合同)-> 一致性检查 -> 交付至完成(或 04 -> 05 -> 07)->
|
|
929
|
+
08-发布准备 -> 09-发布执行 -> 10-复盘总结;S 档:定义完成(迷你合同)-> 实现 -> 验证
|
|
930
|
+
|
|
931
|
+
商业化轨:
|
|
932
|
+
new-product -> B1-业务定位 -> B2-商业模式 -> B3-PMF与客户画像 -> B4-场景与购买旅程 ->
|
|
933
|
+
B5-渠道漏斗映射 -> B6-营销获客策略 -> B7-营销预算 -> B8-渠道执行策略 -> B9-策略复盘(周期执行)
|
|
934
|
+
|
|
935
|
+
查看全部需求和产品状态时,执行 \`workflow/core/commands/workflow-status.md\`。
|
|
936
|
+
|
|
937
|
+
## 任务描述
|
|
938
|
+
|
|
939
|
+
每个任务尽量写清目标、约束和验收方式。
|
|
940
|
+
|
|
941
|
+
## 事实源
|
|
942
|
+
|
|
943
|
+
- 工作流规则:\`workflow/core/\`
|
|
944
|
+
- 工作区配置:\`workflow/team-profile.yaml\`
|
|
945
|
+
- 可复用检查能力:\`workflow/core/capabilities/\`
|
|
946
|
+
- 完整使用说明:\`AGENTS.md\`
|
|
947
|
+
|
|
948
|
+
## 硬闸门
|
|
949
|
+
|
|
950
|
+
- 功能分支闸门和实现阶段闸门通过前,禁止修改业务代码。
|
|
951
|
+
- M/L 档需求进入实现前,完成合同必须已冻结且 Definition Lint 通过;宣布完成 = blocking Oracle 全 PASS。
|
|
952
|
+
- 有 UI 或前端工作的需求必须先完成 \`/02B-UI设计\`,\`/04A-前端代码实现\` 必须遵循对应设计基线。
|
|
953
|
+
- 本地分支命名、创建、commit、tag 和本地 merge 可由 agent 在个人项目中执行;远程 push、release、部署、数据库写入和生产配置写入需要用户明确授权。
|
|
954
|
+
- 同仓并行实现进入实现阶段后必须使用独立 worktree。
|
|
955
|
+
- 商业化轨(B1-B9)只产出文档;对外发布、投放和 outreach 需用户明确授权,营销工程需求通过 \`/new-feature\` 回流研发轨。
|
|
956
|
+
`;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function makeGenericInstructions(toolName) {
|
|
960
|
+
return `# ${toolName} 工作流说明
|
|
961
|
+
|
|
962
|
+
先读取 AGENTS.md,再按用户请求的阶段读取 workflow/team-profile.yaml 和 workflow/core/commands。
|
|
963
|
+
|
|
964
|
+
本文件是薄 adapter,不得覆盖 workflow/core 的硬闸门。
|
|
965
|
+
`;
|
|
966
|
+
}
|