feat: coding-tdd workflow — auto-generated by meta-workflow

This commit is contained in:
2026-04-17 12:47:43 +00:00
parent c703befcdc
commit 04ced5b5f0
+238
View File
@@ -0,0 +1,238 @@
/**
* Meta Workflow e2e — TDD 重构 coding workflow
*
* 让 meta workflow (architect→coder→reviewer→tester→promoter) 把 coding workflow
* 从现有流程改造为 TDD 驱动流程。
*
* 小橘 🍊 (NEKO Team)
*/
import { createOpenAiLlmClient } from '../llm-client.js';
import { createStore } from '../store.js';
import { createMetaArchitectRole } from '../workflows/roles/meta-architect-llm.js';
import { createMetaCoderRole } from '../workflows/roles/meta-coder-cursor.js';
import { createMetaReviewerRole } from '../workflows/roles/meta-reviewer-cursor.js';
import { createMetaTesterRole } from '../workflows/roles/meta-tester.js';
import { createMetaPromoterRole } from '../workflows/roles/meta-promoter.js';
import { createCursorRunner } from '../workflows/roles/agent-executor.js';
import { createWorkflowRule } from '../workflows/workflow-rule-adapter.js';
import { createMetaWorkflow } from '../workflows/meta.js';
import { readFileSync, mkdtempSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const REPO_DIR = join(import.meta.dir, '../../../..');
function readSrc(relPath: string): string {
return readFileSync(join(REPO_DIR, relPath), 'utf-8');
}
async function main() {
const dir = mkdtempSync(join(tmpdir(), 'meta-tdd-'));
console.log(`📁 Temp dir: ${dir}`);
console.log(`📂 Repo: ${REPO_DIR}\n`);
const apiKey = process.env.DASHSCOPE_API_KEY;
if (!apiKey) throw new Error('DASHSCOPE_API_KEY required');
const llm = createOpenAiLlmClient({
apiKey,
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
model: 'qwen-plus',
timeoutMs: 120_000,
});
const store = createStore({
eventsDbPath: join(dir, 'events.db'),
objectsDir: join(dir, 'objects'),
});
const cursorRunner = createCursorRunner({
agentBin: `${process.env.HOME}/.local/bin/agent`,
});
const wf = createMetaWorkflow({
architect: createMetaArchitectRole(llm),
coder: createMetaCoderRole(cursorRunner, llm, REPO_DIR),
reviewer: createMetaReviewerRole(cursorRunner, llm, REPO_DIR),
tester: createMetaTesterRole(llm, { repoDir: REPO_DIR }),
promoter: createMetaPromoterRole({
repoDir: REPO_DIR,
remote: 'gitflare',
branch: 'main',
}),
});
const rule = createWorkflowRule(wf, store, undefined, { cooldownMs: 0 });
const taskDescription = `# 重构 coding workflow 为 TDD 驱动流程
## 目标
将现有 coding workflow (architect→coder→reviewer→closer) 重构为完整的 TDD 驱动开发流程。
## 新流程设计
\`\`\`
START
→ test-planner (LLM) # 从需求出发写测试方案文档
→ test-reviewer (LLM) # review 测试方案是否覆盖需求
→ rejected → test-planner(带反馈修改)
→ approved ↓
→ test-coder (Cursor) # 按测试方案写自动化测试用例(红灯)
→ coder (Cursor) # 写功能代码 + 部署/使用说明(绿灯)
→ auto-tester (代码) # bun test 跑自动化测试
→ fail → coder(迭代代码)
→ pass ↓
→ manual-tester (Agent) # Agent 读测试文档照着操作验证
→ fail → coder(迭代代码)
→ pass ↓
→ reviewer (Cursor) # review 功能代码 + 测试用例
→ rejected → coder(迭代)
→ approved ↓
→ closer → END
\`\`\`
## 核心设计原则
1. **测试文档是一等公民** — test-planner 产出的测试文档贯穿全流程
2. **测试先行** — test-coder 先写红灯测试,coder 再写代码让它绿
3. **三处消费测试文档** — test-coder(写自动化测试)、manual-tester(手工验证)、reviewer(审查测试质量)
4. **coder 产出含部署说明** — manual-tester 需要知道怎么操作
5. **Agent 实操验证** — manual-tester 不是 LLM 读代码,是真正的 Agent 按文档操作
## 新 Role 定义
### test-planner (LLM, tool_choice: required)
- 输入:需求描述(从 __start__ content)
- 输出 meta:{ testPlan: string(markdown 测试方案), scenarios: string[](测试场景列表)}
- 产出完整测试方案文档,包含:功能测试点、边界条件、异常场景、验收标准
### test-reviewer (LLM)
- 输入:test-planner 的测试方案 + 原始需求
- 输出 meta:{ verdict: 'approved'|'rejected', feedback: string }
- 检查测试方案是否充分覆盖需求
### test-coder (Cursor Agent)
- 输入:approved 的测试方案
- 输出 meta:{ testFiles: string[], testCount: number }
- 按测试方案写自动化测试用例(此时功能代码未实现,测试应全部失败 = 红灯)
### coder (Cursor Agent)
- 输入:测试方案 + 红灯测试代码 + rejection feedback(如有)
- 输出 meta:{ filesChanged: string[], deploymentGuide: string }
- 写功能代码让测试变绿 + 写部署/使用说明供 manual-tester 使用
### auto-tester (代码)
- 输入:coder 完成后
- 输出 meta:{ pass: boolean, failedTests: string[], output: string }
- 执行 \`bun test\`,解析结果
### manual-tester (Agent/LLM)
- 输入:test-planner 的测试文档 + coder 的部署说明
- 输出 meta:{ pass: boolean, issues: string[] }
- 按测试文档逐项验证(当前阶段用 LLM 静态分析,未来接 OC Agent 实操)
### reviewer (Cursor Agent)
- 输入:功能代码 + 测试代码 + 测试方案
- 输出 meta:{ verdict: 'approved'|'rejected', comments: string, codeQuality: string, testQuality: string }
- 同时 review 功能代码质量和测试用例质量
### closer (代码)
- 输入:reviewer approved
- 输出 meta:null
- 生成完成报告
## Moderator 状态机
\`\`\`typescript
START → 'test-planner'
'test-planner' → 'test-reviewer'
'test-reviewer' → verdict === 'approved' ? 'test-coder' : 'test-planner'
'test-coder' → 'coder'
'coder' → 'auto-tester'
'auto-tester' → pass ? 'manual-tester' : 'coder'
'manual-tester' → pass ? 'reviewer' : 'coder'
'reviewer' → verdict === 'approved' ? 'closer' : 'coder'
'closer' → END
// 紧急收敛:remainingRounds <= 1 时跳 closer
\`\`\`
## limits
\`\`\`typescript
limits: { maxRounds: 25 }
\`\`\`
## 现有源码(参考)
### coding.ts (当前 workflow 定义)
\`\`\`typescript
${readSrc('packages/pulse/src/workflows/coding.ts')}
\`\`\`
### coding.test.ts (当前测试)
\`\`\`typescript
${readSrc('packages/pulse/src/workflows/coding.test.ts')}
\`\`\`
### workflow-type.ts (接口定义,不要修改)
\`\`\`typescript
${readSrc('packages/pulse/src/workflows/workflow-type.ts')}
\`\`\`
## 实现约束
- 不修改 workflow-rule-adapter.ts 和 workflow-type.ts
- 新文件:coding-tdd.ts + coding-tdd.test.ts(不覆盖原 coding.ts)
- Role 先用 mock 实现(后续再接真实 LLM/Cursor)
- 测试用 coding.test.ts 为模板,覆盖所有状态转换
- Build: \`cd packages/pulse && bun run build\`
- Test: \`bun test packages/pulse/src/workflows/\`
- Commit author: 小橘 <xiaoju@shazhou.work>
- Commit msg: \`feat: TDD coding workflow (coding-tdd) with test-first pipeline\`
- Push: \`git push gitflare main --no-verify\`
## 验收标准
1. coding-tdd.ts 导出 createTddCodingWorkflow()
2. 8 个 role 全部有 mock 实现
3. moderator 状态机正确(含 test-reviewer rejection 回环、auto-tester/manual-tester fail 回环、reviewer rejection 回环)
4. remainingRounds <= 1 紧急收敛
5. limits.maxRounds = 25
6. coding-tdd.test.ts 覆盖所有转换路径
7. 所有现有测试不 break
8. bun run build 通过
`;
const hash = store.putObject(taskDescription);
store.appendEvent({
occurredAt: Date.now(),
kind: 'meta.__start__',
key: 'tdd-coding-workflow',
hash,
});
const MAX_TICKS = 12;
for (let i = 0; i < MAX_TICKS; i++) {
console.log(`\n── tick ${i + 1} ──────────────────────────`);
const result = await rule.tick();
if (result.executed.length === 0) {
console.log('⏹️ No more roles to execute. Workflow complete or stuck.');
break;
}
for (const ex of result.executed) {
console.log(`${ex.role} done`);
console.log(` content: ${ex.content.slice(0, 300)}...`);
console.log(` meta: ${JSON.stringify(ex.meta)}`);
}
const events = store.getAfter(0);
const lastEvent = events[events.length - 1];
if (lastEvent?.kind === 'meta.promoter') {
console.log('\n🎉 Workflow completed — promoter finished!');
break;
}
}
store.close();
console.log('\n🏁 Done');
}
main().catch(console.error);