@xulthekl/team-flow 0.30.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/always/phase-guard.md +1 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/marketplace.json +2 -2
- package/.cursor-plugin/plugin.json +2 -2
- package/.github/plugin/marketplace.json +2 -2
- package/AGENTS.md +5 -4
- package/CHANGELOG.md +85 -0
- package/GEMINI.md +1 -1
- package/HANDOFF.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +3 -3
- package/agents/build-executor.md +1 -0
- package/agents/contract-builder.md +6 -1
- package/docs/README_en.md +1 -1
- package/docs/solutions/INDEX.md +2 -0
- package/docs/solutions/cross-phase/2026-08-01-no-summary.md +17 -0
- package/docs/solutions/cross-phase/2026-08-03-no-summary.md +17 -0
- package/gemini-extension.json +2 -2
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +6 -2
- package/plugin.json +2 -2
- package/scripts/guard/checks/test-gate-exemptions.mjs +53 -0
- package/scripts/guard/checks/test-matrix-complete.mjs +91 -0
- package/scripts/guard/checks/test-matrix-ready.mjs +60 -0
- package/scripts/guard/checks/tests-passing.mjs +112 -24
- package/scripts/guard/guard.mjs +10 -2
- package/scripts/lib/cmd-doctor.mjs +43 -1
- package/scripts/lib/cmd-execution.mjs +24 -1
- package/scripts/lib/cmd-state.mjs +33 -5
- package/scripts/lib/cmd-validate.mjs +42 -0
- package/scripts/lib/execution-plan.mjs +23 -0
- package/scripts/lib/hash.mjs +11 -0
- package/scripts/lib/state-loader.mjs +26 -1
- package/scripts/lib/test-matrix-export.mjs +231 -0
- package/scripts/lib/test-merge.mjs +540 -0
- package/scripts/lib/test-record.mjs +212 -0
- package/scripts/team-flow.mjs +9 -0
- package/skills/build-executor/implementer-prompt.md +38 -3
- package/skills/code-reviewer/SKILL.md +28 -1
- package/skills/code-reviewer/code-reviewer-prompt.md +10 -0
- package/skills/contract-builder/SKILL.md +75 -0
- package/skills/release-archivist/SKILL.md +50 -10
- package/skills/session-handoff/SKILL.md +1 -0
- package/skills/spec-writer/SKILL.md +3 -1
- package/skills/test-strategy/SKILL.md +70 -0
- package/skills/test-strategy/references/adversarial-patterns.md +0 -0
- package/skills/test-strategy/references/complexity-grading.md +137 -0
- package/skills/test-strategy/references/design-methods-detail.md +183 -0
- package/skills/workflow-orchestrator/references/s1-path-router.md +4 -0
- package/skills/workflow-start/SKILL.md +5 -3
- package/skills/workflow-start/references/routing-rules.md +21 -0
- package/tests/e2e.test.mjs +0 -266
- package/tests/lib/cmd-audit.test.mjs +0 -202
- package/tests/lib/cmd-checkpoint.test.mjs +0 -98
- package/tests/lib/cmd-config.test.mjs +0 -101
- package/tests/lib/cmd-doctor.test.mjs +0 -450
- package/tests/lib/cmd-execution.test.mjs +0 -647
- package/tests/lib/cmd-handoff.test.mjs +0 -137
- package/tests/lib/cmd-inject.test.mjs +0 -218
- package/tests/lib/cmd-install-workbuddy.test.mjs +0 -113
- package/tests/lib/cmd-install-zcode.test.mjs +0 -42
- package/tests/lib/cmd-isolate.test.mjs +0 -68
- package/tests/lib/cmd-list.test.mjs +0 -127
- package/tests/lib/cmd-runtime.test.mjs +0 -83
- package/tests/lib/cmd-state-missing.test.mjs +0 -65
- package/tests/lib/cmd-state.test.mjs +0 -365
- package/tests/lib/cmd-sync-paths.test.mjs +0 -84
- package/tests/lib/cmd-validate-paths.test.mjs +0 -90
- package/tests/lib/config-loader.test.mjs +0 -175
- package/tests/lib/ensure-branch.test.mjs +0 -110
- package/tests/lib/execution-control-plane.test.mjs +0 -168
- package/tests/lib/execution-plan.test.mjs +0 -474
- package/tests/lib/guard-compound-captured.test.mjs +0 -92
- package/tests/lib/guard-specs-merged.test.mjs +0 -110
- package/tests/lib/guard-tests-passing.test.mjs +0 -114
- package/tests/lib/guard-transitions.test.mjs +0 -262
- package/tests/lib/guard.test.mjs +0 -613
- package/tests/lib/hash.test.mjs +0 -138
- package/tests/lib/infer-workflow.test.mjs +0 -161
- package/tests/lib/install-git-hooks.test.mjs +0 -20
- package/tests/lib/marketplace-release-docs.test.mjs +0 -31
- package/tests/lib/minimality-discipline.test.mjs +0 -37
- package/tests/lib/model-profiles-docs.test.mjs +0 -33
- package/tests/lib/node20-compatibility.test.mjs +0 -73
- package/tests/lib/node20-test-entry.test.mjs +0 -17
- package/tests/lib/platform-runtime-distribution.test.mjs +0 -157
- package/tests/lib/raw-mode-smoke.test.mjs +0 -42
- package/tests/lib/sdd-overlay.test.mjs +0 -118
- package/tests/lib/solutions-capture.test.mjs +0 -108
- package/tests/lib/solutions-index-gen.test.mjs +0 -147
- package/tests/lib/solutions-inject.test.mjs +0 -115
- package/tests/lib/solutions-promote.test.mjs +0 -200
- package/tests/lib/spec-paths.test.mjs +0 -80
- package/tests/lib/state-loader.test.mjs +0 -251
- package/tests/lib/token-baseline.test.mjs +0 -72
- package/tests/lib/token-rules.test.mjs +0 -94
- package/tests/lib/verify-marketplace-release.test.mjs +0 -128
- package/tests/tsconfig.json +0 -12
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* test-matrix-export — glaf4 test-matrix.json → team-flow test-matrix.md 格式转换
|
|
4
|
+
*
|
|
5
|
+
* v0.12 §46.1 定义,v0.31.0 实现为 CLI 子命令
|
|
6
|
+
* 用法:tf test-matrix-export <input.json> <output.md> [--change-id <id>] [--batch-id <id>]
|
|
7
|
+
*
|
|
8
|
+
* 功能:
|
|
9
|
+
* - 读取 glaf4 的 test-matrix.json
|
|
10
|
+
* - 保留全部 14 字段 + 包装 team_flow_context
|
|
11
|
+
* - 从 test_kind 派生 test_tier(unit/integration)
|
|
12
|
+
* - 输出 team-flow 格式的 test-matrix.md
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { resolve, basename } from 'node:path';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 解析 CLI 参数
|
|
20
|
+
*/
|
|
21
|
+
function parseArgv(argv) {
|
|
22
|
+
const parsed = { _: [] };
|
|
23
|
+
for (let i = 0; i < argv.length; i++) {
|
|
24
|
+
if (argv[i] === '--change-id' && argv[i + 1]) {
|
|
25
|
+
parsed.changeId = argv[++i];
|
|
26
|
+
} else if (argv[i] === '--batch-id' && argv[i + 1]) {
|
|
27
|
+
parsed.batchId = argv[++i];
|
|
28
|
+
} else if (argv[i] === '--ledger-ref' && argv[i + 1]) {
|
|
29
|
+
parsed.ledgerRef = argv[++i];
|
|
30
|
+
} else if (!argv[i].startsWith('--')) {
|
|
31
|
+
parsed._.push(argv[i]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* test_kind → test_tier 映射(v0.12 §42.4)
|
|
39
|
+
*/
|
|
40
|
+
const TEST_KIND_TO_TIER = {
|
|
41
|
+
// unit tier
|
|
42
|
+
pure_unit: 'unit',
|
|
43
|
+
mockito_unit: 'unit',
|
|
44
|
+
spring_assisted_unit: 'unit',
|
|
45
|
+
vitest_unit: 'unit',
|
|
46
|
+
vue_test_utils_mount: 'unit',
|
|
47
|
+
// integration tier
|
|
48
|
+
api_mockmvc_standalone: 'integration',
|
|
49
|
+
api_mockmvc_slice: 'integration',
|
|
50
|
+
api_mockmvc_boot: 'integration',
|
|
51
|
+
service_social: 'integration',
|
|
52
|
+
repository_h2: 'integration',
|
|
53
|
+
rabbitmq_social: 'integration',
|
|
54
|
+
redis_social: 'integration',
|
|
55
|
+
external_api_stub: 'integration',
|
|
56
|
+
test_infrastructure: 'integration',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 从 glaf4 case 派生 test_tier
|
|
61
|
+
*/
|
|
62
|
+
function deriveTestTier(testKind) {
|
|
63
|
+
return TEST_KIND_TO_TIER[testKind] || 'unit';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 转义 markdown 表格单元格
|
|
68
|
+
*/
|
|
69
|
+
function escapeCell(str) {
|
|
70
|
+
if (typeof str !== 'string') return String(str ?? '');
|
|
71
|
+
return str.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 转换单个 case 为 markdown 行
|
|
76
|
+
*/
|
|
77
|
+
function caseToRow(c) {
|
|
78
|
+
const tier = deriveTestTier(c.test_kind);
|
|
79
|
+
return [
|
|
80
|
+
c.case_id || '',
|
|
81
|
+
escapeCell(c.behavior || c.display_name || ''),
|
|
82
|
+
c.design_method || '',
|
|
83
|
+
escapeCell(typeof c.input === 'object' ? JSON.stringify(c.input) : (c.input || '')),
|
|
84
|
+
escapeCell(typeof c.expected === 'object' ? JSON.stringify(c.expected) : (c.expected || '')),
|
|
85
|
+
c.test_kind || '',
|
|
86
|
+
tier,
|
|
87
|
+
escapeCell(Array.isArray(c.required_stubs) ? c.required_stubs.join(', ') : (c.mock || '')),
|
|
88
|
+
c.work_mode || 'TDD',
|
|
89
|
+
c.test_file || '',
|
|
90
|
+
c.test_method_name || '',
|
|
91
|
+
c.run_command || '',
|
|
92
|
+
].join(' | ');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 提取模块名(从 target 或 case_id 前缀)
|
|
97
|
+
*/
|
|
98
|
+
function extractModuleName(matrix) {
|
|
99
|
+
if (matrix.target) {
|
|
100
|
+
// e.g., "com.example.service.OrderService" → "OrderService"
|
|
101
|
+
const parts = matrix.target.split('.');
|
|
102
|
+
return parts[parts.length - 1];
|
|
103
|
+
}
|
|
104
|
+
// fallback: from first case_id
|
|
105
|
+
if (matrix.cases?.[0]?.case_id) {
|
|
106
|
+
const id = matrix.cases[0].case_id;
|
|
107
|
+
const match = id.match(/^([A-Z][a-zA-Z]+)/);
|
|
108
|
+
if (match) return match[1];
|
|
109
|
+
}
|
|
110
|
+
return 'Unknown';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 转换 glaf4 matrix → team-flow markdown
|
|
115
|
+
*/
|
|
116
|
+
export function convert(matrix, options = {}) {
|
|
117
|
+
const moduleName = extractModuleName(matrix);
|
|
118
|
+
const cases = matrix.cases || [];
|
|
119
|
+
|
|
120
|
+
// 统计
|
|
121
|
+
const unitCases = cases.filter(c => deriveTestTier(c.test_kind) === 'unit');
|
|
122
|
+
const integrationCases = cases.filter(c => deriveTestTier(c.test_kind) === 'integration');
|
|
123
|
+
|
|
124
|
+
// 提取 complexity
|
|
125
|
+
const complexity = matrix.target_complexity || {};
|
|
126
|
+
let complexityTier = 'medium';
|
|
127
|
+
if (complexity.is_trivial) complexityTier = 'trivial';
|
|
128
|
+
else if ((complexity.public_methods || 0) > 15 || (complexity.lines || 0) > 800 || (complexity.param_count || 0) > 6) {
|
|
129
|
+
complexityTier = 'complex';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 提取 candidate ledger
|
|
133
|
+
const candidateLedger = matrix.source_candidate_ledger || [];
|
|
134
|
+
|
|
135
|
+
// 构建 markdown
|
|
136
|
+
const lines = [];
|
|
137
|
+
lines.push(`# Test Matrix — ${options.changeId || 'unknown'}`);
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push('## Summary');
|
|
140
|
+
lines.push(`- Total cases: ${cases.length}`);
|
|
141
|
+
lines.push(`- Modules covered: 1 (${moduleName}, complexity: ${complexityTier})`);
|
|
142
|
+
lines.push(`- Unit cases: ${unitCases.length} (${Math.round(unitCases.length / cases.length * 100) || 0}%)`);
|
|
143
|
+
lines.push(`- Integration cases: ${integrationCases.length} (${Math.round(integrationCases.length / cases.length * 100) || 0}%)`);
|
|
144
|
+
lines.push(`- Deferred items: ${candidateLedger.filter(c => c.decision === 'deferred').length}`);
|
|
145
|
+
lines.push(`- Matrix revision: 1`);
|
|
146
|
+
lines.push('');
|
|
147
|
+
|
|
148
|
+
// Candidate Coverage Ledger
|
|
149
|
+
if (candidateLedger.length > 0) {
|
|
150
|
+
lines.push('## Candidate Coverage Ledger');
|
|
151
|
+
lines.push('');
|
|
152
|
+
lines.push('| candidate | category | decision | case_ids | reason |');
|
|
153
|
+
lines.push('|---|---|---|---|---|');
|
|
154
|
+
for (const c of candidateLedger) {
|
|
155
|
+
lines.push(`| ${escapeCell(c.candidate)} | ${c.category || ''} | ${c.decision} | ${escapeCell(Array.isArray(c.case_ids) ? c.case_ids.join(', ') : (c.case_ids || ''))} | ${escapeCell(c.reason || '')} |`);
|
|
156
|
+
}
|
|
157
|
+
lines.push('');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Cases
|
|
161
|
+
lines.push('## Cases');
|
|
162
|
+
lines.push('');
|
|
163
|
+
lines.push(`### ${moduleName}`);
|
|
164
|
+
lines.push('');
|
|
165
|
+
lines.push('| case_id | behavior | design_method | input | expected | test_kind | test_tier | mock | work_mode | test_file | test_method_name | run_command |');
|
|
166
|
+
lines.push('|---|---|---|---|---|---|---|---|---|---|---|---|');
|
|
167
|
+
for (const c of cases) {
|
|
168
|
+
lines.push(`| ${caseToRow(c)} |`);
|
|
169
|
+
}
|
|
170
|
+
lines.push('');
|
|
171
|
+
|
|
172
|
+
// Deferred Items
|
|
173
|
+
const deferred = candidateLedger.filter(c => c.decision === 'deferred');
|
|
174
|
+
if (deferred.length > 0) {
|
|
175
|
+
lines.push('## Deferred Items');
|
|
176
|
+
lines.push('');
|
|
177
|
+
lines.push('| case_id | behavior | design_method | reason | deferred_since |');
|
|
178
|
+
lines.push('|---|---|---|---|---|');
|
|
179
|
+
for (const d of deferred) {
|
|
180
|
+
lines.push(`| ${escapeCell(Array.isArray(d.case_ids) ? d.case_ids[0] : (d.case_ids || ''))} | ${escapeCell(d.candidate)} | — | ${escapeCell(d.reason || '')} | ${new Date().toISOString().slice(0, 10)} |`);
|
|
181
|
+
}
|
|
182
|
+
lines.push('');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// team_flow_context footer
|
|
186
|
+
lines.push('---');
|
|
187
|
+
lines.push('');
|
|
188
|
+
lines.push('<!-- team_flow_context:');
|
|
189
|
+
lines.push(` change_id: ${options.changeId || 'unknown'}`);
|
|
190
|
+
if (options.batchId) lines.push(` batch_id: ${options.batchId}`);
|
|
191
|
+
lines.push(` closing_stage: test-merge`);
|
|
192
|
+
if (options.ledgerRef) lines.push(` ledger_ref: ${options.ledgerRef}`);
|
|
193
|
+
lines.push(` source: glaf4-tests-export`);
|
|
194
|
+
lines.push('-->');
|
|
195
|
+
|
|
196
|
+
return lines.join('\n') + '\n';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* CLI entry point
|
|
201
|
+
*/
|
|
202
|
+
export async function run(args) {
|
|
203
|
+
const argv = parseArgv(args || process.argv.slice(2));
|
|
204
|
+
const inputFile = argv._[0];
|
|
205
|
+
const outputFile = argv._[1];
|
|
206
|
+
|
|
207
|
+
if (!inputFile) {
|
|
208
|
+
console.error('Usage: tf test-matrix-export <input.json> <output.md> [--change-id <id>] [--batch-id <id>]');
|
|
209
|
+
process.exit(2);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (!outputFile) {
|
|
213
|
+
console.error('Usage: tf test-matrix-export <input.json> <output.md>');
|
|
214
|
+
process.exit(2);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const raw = readFileSync(resolve(inputFile), 'utf-8');
|
|
219
|
+
const matrix = JSON.parse(raw);
|
|
220
|
+
const md = convert(matrix, {
|
|
221
|
+
changeId: argv.changeId || basename(inputFile, '.json'),
|
|
222
|
+
batchId: argv.batchId,
|
|
223
|
+
ledgerRef: argv.ledgerRef,
|
|
224
|
+
});
|
|
225
|
+
writeFileSync(resolve(outputFile), md, 'utf-8');
|
|
226
|
+
console.log(`✅ test-matrix-export: ${inputFile} → ${outputFile}`);
|
|
227
|
+
} catch (err) {
|
|
228
|
+
console.error(`❌ test-matrix-export error: ${err.message}`);
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|