@xulthekl/team-flow 0.43.1 → 0.45.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/.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 +3 -3
- package/AGENTS.md +13 -6
- package/CHANGELOG.md +31 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +26 -24
- package/README.md +6 -5
- package/agents/business-analysis.md +53 -0
- package/docs/README_en.md +1 -1
- package/docs/examples/add-dark-mode/specs/ui-theme/spec.md +15 -17
- package/docs/examples/refactor-auth-boundary/specs/auth-boundary/spec.md +15 -27
- package/docs/solutions/INDEX.md +2 -0
- package/docs/solutions/cross-phase/2026-08-17-no-summary.md +17 -0
- package/docs/solutions/cross-phase/2026-08-18-no-summary.md +17 -0
- package/docs/usage-guide.md +619 -0
- package/gemini-extension.json +2 -2
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/plugin.json +2 -2
- package/scripts/guard/checks/delegation-status.mjs +56 -0
- package/scripts/guard/checks/test-gate-exemptions.mjs +13 -0
- package/scripts/guard/checks/test-matrix-complete.mjs +6 -0
- package/scripts/guard/checks/test-matrix-ready.mjs +6 -0
- package/scripts/guard/checks/tests-passing.mjs +6 -1
- package/scripts/guard/guard.mjs +3 -1
- package/scripts/lib/cmd-state.mjs +3 -0
- package/scripts/lib/config-loader.mjs +11 -0
- package/scripts/lib/conventions-generator.mjs +91 -0
- package/scripts/lib/execution-plan.mjs +2 -1
- package/scripts/lib/execution-recommendation.mjs +20 -3
- package/scripts/lib/glaf4-delegation.mjs +488 -0
- package/scripts/lib/glaf4-evidence-export.mjs +267 -0
- package/scripts/lib/state-loader.mjs +13 -0
- package/scripts/lib/test-matrix-export.mjs +151 -8
- package/scripts/team-flow.mjs +6 -0
- package/skills/business-analysis/SKILL.md +80 -0
- package/skills/business-analysis/references/interaction-rules.md +86 -0
- package/skills/business-analysis/references/output-schema.md +88 -0
- package/skills/business-analysis/references/qa-checklist.md +31 -0
- package/skills/business-analysis/references/version-resolution.md +41 -0
- package/skills/contract-builder/SKILL.md +2 -2
- package/skills/contract-builder/references/glaf4-delegation.md +130 -0
- package/skills/workflow-start/SKILL.md +1 -1
- package/skills/workflow-start/references/routing-rules.md +12 -12
- package/templates/execution-contract.md +13 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xulthekl/team-flow",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Unified plugin (
|
|
3
|
+
"version": "0.45.0",
|
|
4
|
+
"description": "Unified plugin (25 skills + 16 agents) integrating team-flow, compound-engineering, architecture-design, prototype, design-system, workflow-orchestrator, workflow-bootstrap, e2e, session-handoff, workflow-feedback, business-analysis for multi-agent coding tools.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"bin": {
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-flow",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Unified workflow plugin: team-flow (spec-driven dev: TDD/SDD/code-review/debugging) + compound-engineering core subset (brainstorm/plan/compound/strategy/ideate/proof, global compounding) + architecture-design (4A+DDD incremental design & global compounding) + prototype (local HTML prototype, zero external deps) + e2e (Playwright E2E, AC-driven) + workflow-orchestrator (product-level workflow orchestration) + workflow-bootstrap (existing project onboarding) + session-handoff (context transfer) + workflow-feedback (issue tracking).
|
|
3
|
+
"version": "0.45.0",
|
|
4
|
+
"description": "Unified workflow plugin: team-flow (spec-driven dev: TDD/SDD/code-review/debugging) + compound-engineering core subset (brainstorm/plan/compound/strategy/ideate/proof, global compounding) + architecture-design (4A+DDD incremental design & global compounding) + prototype (local HTML prototype, zero external deps) + e2e (Playwright E2E, AC-driven) + workflow-orchestrator (product-level workflow orchestration) + workflow-bootstrap (existing project onboarding) + session-handoff (context transfer) + workflow-feedback (issue tracking) + business-analysis (independent requirement/scenario artifact). 25 skills + 16 agents, one install.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LT"
|
|
7
7
|
},
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// scripts/guard/checks/delegation-status.mjs — GLAF4 委托状态位 guard(v2.1 §6.7)
|
|
2
|
+
//
|
|
3
|
+
// 规则(v2.1 §6.7 委托失败恢复闭环):
|
|
4
|
+
// - execution_mode !== 'glaf4-delegation' → pass(透明,不干预非委托 change)
|
|
5
|
+
// - delegation_status === 'success' → pass(委托已成功完成)
|
|
6
|
+
// - delegation_status === 'failed' → FAIL(阻断 closing 直到人工重置——三选一恢复)
|
|
7
|
+
// - delegation_status 缺失 / null / in_progress → FAIL(委托未成功完成,closing 前必须终局)
|
|
8
|
+
//
|
|
9
|
+
// 设计原则:
|
|
10
|
+
// - 与 compound-captured 同属"状态位约束"维度,确保 delegation_status 有 guard 约束力
|
|
11
|
+
// (否则状态位无约束力,三选一恢复全靠人工纪律)
|
|
12
|
+
// - 状态位经 `tf state set delegation_status <in_progress|success|failed>` 程序化写入
|
|
13
|
+
|
|
14
|
+
import { readState } from '../../lib/state-loader.mjs';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Check GLAF4 委托状态位(executing:closing 维度)
|
|
18
|
+
* @param {string} changeDir
|
|
19
|
+
* @returns {{ pass: boolean, failures: string[] }}
|
|
20
|
+
*/
|
|
21
|
+
export function checkDelegationStatus(changeDir) {
|
|
22
|
+
const state = readState(changeDir);
|
|
23
|
+
|
|
24
|
+
// 非 glaf4-delegation 模式:透明放行(可选接入,非 GLAF4 项目完全不受影响,v2.1 §8)
|
|
25
|
+
if (state.execution_mode !== 'glaf4-delegation') {
|
|
26
|
+
return { pass: true, failures: [] };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (state.delegation_status === 'success') {
|
|
30
|
+
return { pass: true, failures: [] };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const failures = [];
|
|
34
|
+
if (state.delegation_status === 'failed') {
|
|
35
|
+
// I3(2026-08-18):retry_count 封顶 3 机械提示——达到上限必须走降级/转人工,不再允许重试
|
|
36
|
+
const retryCount = Number.isInteger(state.delegation_retry_count) ? state.delegation_retry_count : 0;
|
|
37
|
+
const atLimit = retryCount >= 3;
|
|
38
|
+
failures.push(
|
|
39
|
+
'GLAF4 委托状态位为 failed——closing 前必须人工处置(v2.1 §6.7 三选一):'
|
|
40
|
+
+ (atLimit
|
|
41
|
+
? `⚠️ delegation_retry_count=${retryCount} 已达上限 3——禁止继续重试,必须走 ② 降级 build-executor(glaf4-delegation reset 删 plan 重走 DP-4)或 ③ 标记阻塞转人工排障。`
|
|
42
|
+
: `① 重试(delegation_retry_count 封顶 3,当前 ${retryCount})② 降级 build-executor(glaf4-delegation reset 删 plan 重走 DP-4)③ 标记阻塞转人工排障。`)
|
|
43
|
+
+ '处置后 `tf state set delegation_status success`(或重置为 in_progress 继续委托)。'
|
|
44
|
+
);
|
|
45
|
+
} else if (state.delegation_status === 'in_progress') {
|
|
46
|
+
failures.push(
|
|
47
|
+
'GLAF4 委托状态位仍为 in_progress——委托 run 尚未终局,closing 前必须完成委托并回灌证据后置为 success。'
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
failures.push(
|
|
51
|
+
'GLAF4 委托状态位缺失(delegation_status 未记录)——glaf4-delegation 模式 change 必须先完成委托,'
|
|
52
|
+
+ '证据回灌 + 对账通过后 `tf state set delegation_status success`。'
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return { pass: false, failures };
|
|
56
|
+
}
|
|
@@ -32,6 +32,19 @@ export function skipMissingReason(state) {
|
|
|
32
32
|
return state?.test_matrix_skipped === 'true' && !hasExplicitSkip(state);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* v2.1 §6.3 skip 禁令:glaf4-delegation 模式禁止 test_matrix_skipped(唯一例外 TEST_BOOTSTRAP 零测试)。
|
|
37
|
+
* 防止"矩阵权威在 glaf4-dev"被误读为"矩阵可 skip"导致零测试证据关闭(测试门三道短路后门)。
|
|
38
|
+
* @returns {string|null} 违规原因(null = 无违规)
|
|
39
|
+
*/
|
|
40
|
+
export function glaf4SkipViolation(state) {
|
|
41
|
+
if (state?.execution_mode !== 'glaf4-delegation') return null;
|
|
42
|
+
if (state?.test_matrix_skipped !== 'true') return null;
|
|
43
|
+
// 唯一例外:TEST_BOOTSTRAP 零测试(reason 显式声明)
|
|
44
|
+
if (/TEST_BOOTSTRAP/.test(state?.test_matrix_skip_reason || '')) return null;
|
|
45
|
+
return 'glaf4-delegation 模式禁止 test_matrix_skipped(唯一例外 TEST_BOOTSTRAP 零测试,skip_reason 须显式声明 TEST_BOOTSTRAP)';
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
export const SKIP_REASON_HINT =
|
|
36
49
|
"test_matrix_skipped=true requires test_matrix_skip_reason — record it: "
|
|
37
50
|
+ "tf state set <dir> test_matrix_skip_reason '<why this change needs no test matrix>'";
|
|
@@ -10,6 +10,7 @@ import { computeTestMatrixHash } from '../../lib/hash.mjs';
|
|
|
10
10
|
import {
|
|
11
11
|
isLegacyChange,
|
|
12
12
|
skipMissingReason,
|
|
13
|
+
glaf4SkipViolation,
|
|
13
14
|
SKIP_REASON_HINT,
|
|
14
15
|
contractDeclaresTestMatrix,
|
|
15
16
|
readTestMatrixFile,
|
|
@@ -28,6 +29,11 @@ export function checkTestMatrixComplete(changeDir) {
|
|
|
28
29
|
|
|
29
30
|
// Step 2 — 显式 skip:必须附理由(可审计豁免)。
|
|
30
31
|
if (state.test_matrix_skipped === 'true') {
|
|
32
|
+
// v2.1 §6.3 skip 禁令:glaf4-delegation 模式禁止 skip(唯一例外 TEST_BOOTSTRAP)
|
|
33
|
+
const glaf4Violation = glaf4SkipViolation(state);
|
|
34
|
+
if (glaf4Violation) {
|
|
35
|
+
return { pass: false, failures: [glaf4Violation] };
|
|
36
|
+
}
|
|
31
37
|
if (skipMissingReason(state)) {
|
|
32
38
|
return { pass: false, failures: [SKIP_REASON_HINT] };
|
|
33
39
|
}
|
|
@@ -8,6 +8,7 @@ import { readState } from '../../lib/state-loader.mjs';
|
|
|
8
8
|
import {
|
|
9
9
|
isLegacyChange,
|
|
10
10
|
skipMissingReason,
|
|
11
|
+
glaf4SkipViolation,
|
|
11
12
|
SKIP_REASON_HINT,
|
|
12
13
|
contractDeclaresTestMatrix,
|
|
13
14
|
readTestMatrixFile,
|
|
@@ -26,6 +27,11 @@ export function checkTestMatrixReady(changeDir) {
|
|
|
26
27
|
|
|
27
28
|
// Exemption 2:显式 skip(必须附理由)。
|
|
28
29
|
if (state.test_matrix_skipped === 'true') {
|
|
30
|
+
// v2.1 §6.3 skip 禁令:glaf4-delegation 模式禁止 skip(唯一例外 TEST_BOOTSTRAP)
|
|
31
|
+
const glaf4Violation = glaf4SkipViolation(state);
|
|
32
|
+
if (glaf4Violation) {
|
|
33
|
+
return { pass: false, failures: [glaf4Violation] };
|
|
34
|
+
}
|
|
29
35
|
if (skipMissingReason(state)) {
|
|
30
36
|
return { pass: false, failures: [SKIP_REASON_HINT] };
|
|
31
37
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { readState } from '../../lib/state-loader.mjs';
|
|
12
|
-
import { isLegacyChange, skipMissingReason, SKIP_REASON_HINT } from './test-gate-exemptions.mjs';
|
|
12
|
+
import { isLegacyChange, skipMissingReason, glaf4SkipViolation, SKIP_REASON_HINT } from './test-gate-exemptions.mjs';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* 解析结构化 test_result:
|
|
@@ -68,6 +68,11 @@ export function checkTestsPassing(changeDir) {
|
|
|
68
68
|
|
|
69
69
|
// 显式 skip(必须附理由)。
|
|
70
70
|
if (state.test_matrix_skipped === 'true') {
|
|
71
|
+
// v2.1 §6.3 skip 禁令:glaf4-delegation 模式禁止 skip(唯一例外 TEST_BOOTSTRAP)
|
|
72
|
+
const glaf4Violation = glaf4SkipViolation(state);
|
|
73
|
+
if (glaf4Violation) {
|
|
74
|
+
return { pass: false, failures: [glaf4Violation] };
|
|
75
|
+
}
|
|
71
76
|
if (skipMissingReason(state)) {
|
|
72
77
|
return { pass: false, failures: [SKIP_REASON_HINT] };
|
|
73
78
|
}
|
package/scripts/guard/guard.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import { checkTestMatrixComplete } from './checks/test-matrix-complete.mjs';
|
|
|
18
18
|
import { checkTestMatrixReady } from './checks/test-matrix-ready.mjs';
|
|
19
19
|
import { checkArchReadiness } from './checks/arch-readiness.mjs';
|
|
20
20
|
import { checkArchSnapshot } from './checks/arch-snapshot.mjs';
|
|
21
|
+
import { checkDelegationStatus } from './checks/delegation-status.mjs';
|
|
21
22
|
|
|
22
23
|
// Transition matrix: <from>:<to> → required check dimensions
|
|
23
24
|
const TRANSITION_CHECKS = {
|
|
@@ -37,7 +38,7 @@ const TRANSITION_CHECKS = {
|
|
|
37
38
|
'approved-for-build:executing': ['artifacts-exist', 'contract-fresh', 'dp-gate-passed', 'execution-plan-ready', 'test-matrix-ready'],
|
|
38
39
|
// v0.35.0 (v0.14 §59.4): arch-snapshot 新增——"先快照后回写"的强制化(legacy 豁免)。
|
|
39
40
|
// 仅在 full workflow 挂;hotfix/tweak 沿用 §59.4 豁免(紧急/微调不挂)。
|
|
40
|
-
'executing:closing': ['tasks-complete', 'tests-passing', 'specs-merged', 'execution-plan-ready', 'execution-reviews-passed', 'compound-captured', 'test-matrix-complete', 'arch-snapshot'],
|
|
41
|
+
'executing:closing': ['tasks-complete', 'tests-passing', 'specs-merged', 'execution-plan-ready', 'execution-reviews-passed', 'compound-captured', 'test-matrix-complete', 'arch-snapshot', 'delegation-status'],
|
|
41
42
|
|
|
42
43
|
// Debugging side-path
|
|
43
44
|
'executing:debugging': [],
|
|
@@ -188,6 +189,7 @@ async function main() {
|
|
|
188
189
|
'test-matrix-ready': (dir) => checkTestMatrixReady(dir),
|
|
189
190
|
'arch-readiness': (dir) => checkArchReadiness(dir),
|
|
190
191
|
'arch-snapshot': (dir) => checkArchSnapshot(dir),
|
|
192
|
+
'delegation-status': (dir) => checkDelegationStatus(dir),
|
|
191
193
|
};
|
|
192
194
|
|
|
193
195
|
const checks = [];
|
|
@@ -21,6 +21,9 @@ const SETTABLE_FIELDS = [
|
|
|
21
21
|
'dp_1_result', 'dp_1_timestamp', 'dp_1_decisions', 'dp_1_confirmed',
|
|
22
22
|
'dp_2_result', 'dp_2_timestamp', 'dp_2_decisions', 'dp_2_confirmed',
|
|
23
23
|
'dp_3_result', 'dp_3_timestamp', 'dp_3_decisions', 'dp_3_confirmed',
|
|
24
|
+
// v2.1 §6.6/§6.7:GLAF4 委托决策与状态位(dp_4_result 仍由 tf execution plan --confirm 程序化写入,不在列表)
|
|
25
|
+
'dp_4_glaf4_mode', 'dp_4_write_set_hash',
|
|
26
|
+
'delegation_status', 'delegation_retry_count', 'delegation_partial_writes',
|
|
24
27
|
'dp_5_result', 'dp_5_timestamp', 'dp_5_decisions', 'dp_5_confirmed',
|
|
25
28
|
'dp_6_result', 'dp_6_timestamp', 'dp_6_decisions', 'dp_6_confirmed',
|
|
26
29
|
'dp_7_result', 'dp_7_timestamp', 'dp_7_decisions', 'dp_7_confirmed',
|
|
@@ -28,6 +28,13 @@ const DEFAULTS = {
|
|
|
28
28
|
// 各 skill 上下文加载时按 phase 过滤注入
|
|
29
29
|
// 示例: { database: ".team-flow/conventions/db-design.md", ... }
|
|
30
30
|
},
|
|
31
|
+
glaf4_dev: {
|
|
32
|
+
// glaf4-dev 运行时探测结果(v2.1 §4 接口①)
|
|
33
|
+
// contract-builder 产出 execution-contract 时实时探测写入;delegation_mode 由用户/编排开关
|
|
34
|
+
enabled: false,
|
|
35
|
+
version: null,
|
|
36
|
+
delegation_mode: 'auto',
|
|
37
|
+
},
|
|
31
38
|
};
|
|
32
39
|
|
|
33
40
|
export const MODEL_PROFILES = Object.freeze([
|
|
@@ -89,6 +96,10 @@ function findConfigFile(startDir) {
|
|
|
89
96
|
encoding: 'utf-8',
|
|
90
97
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
91
98
|
}).trim();
|
|
99
|
+
// v2.1 评审 C1(2026-08-18):git root 优先查 .team-flow/(writeGlaf4DevConfig 落点,
|
|
100
|
+
// contract-builder 在工程根写探测结果,changeDir 子目录需经此读到),再查 legacy 位置。
|
|
101
|
+
const gitTeamFlowDir = join(gitRoot, '.team-flow', 'team-flow.config.json');
|
|
102
|
+
if (existsSync(gitTeamFlowDir)) return gitTeamFlowDir;
|
|
92
103
|
const gitPath = join(gitRoot, 'team-flow.config.json');
|
|
93
104
|
if (existsSync(gitPath)) return gitPath;
|
|
94
105
|
} catch {
|
|
@@ -10,9 +10,100 @@
|
|
|
10
10
|
// 设计来源:test-capability-enhancement-design v1.0 §四 + §55.4
|
|
11
11
|
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
13
14
|
import path, { join } from 'node:path';
|
|
14
15
|
import { parseArgs } from 'node:util';
|
|
15
16
|
|
|
17
|
+
// ── glaf4-dev 运行时探测(v2.1 §4 接口①)─────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
// Claude Code 插件安装登记表(实测结构:{ version: 2, plugins: { "<name>@<marketplace>": [{ scope, installPath, version }] } })
|
|
20
|
+
const PLUGINS_INSTALLED_PATH = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 探测 glaf4-dev 插件是否可用(解析 ~/.claude/plugins/installed_plugins.json)
|
|
24
|
+
* @param {string} [pluginsFilePath] 可注入登记表路径(测试用),默认 ~/.claude/plugins/installed_plugins.json
|
|
25
|
+
* @returns {{ available: boolean, version: string|null, installPath: string|null }}
|
|
26
|
+
*/
|
|
27
|
+
export function detectGlaf4DevPlugin(pluginsFilePath = PLUGINS_INSTALLED_PATH) {
|
|
28
|
+
try {
|
|
29
|
+
if (!existsSync(pluginsFilePath)) {
|
|
30
|
+
return { available: false, version: null, installPath: null };
|
|
31
|
+
}
|
|
32
|
+
const raw = readFileSync(pluginsFilePath, 'utf-8');
|
|
33
|
+
const registry = JSON.parse(raw);
|
|
34
|
+
const plugins = registry?.plugins || {};
|
|
35
|
+
// 匹配 key 形如 "glaf4-dev@glaf4-dev" 或 "glaf4-dev"
|
|
36
|
+
for (const [key, entries] of Object.entries(plugins)) {
|
|
37
|
+
const name = key.split('@')[0];
|
|
38
|
+
if (name !== 'glaf4-dev') continue;
|
|
39
|
+
const entry = Array.isArray(entries) ? entries[0] : entries;
|
|
40
|
+
if (entry?.installPath) {
|
|
41
|
+
return {
|
|
42
|
+
available: true,
|
|
43
|
+
version: entry.version || null,
|
|
44
|
+
installPath: entry.installPath,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { available: false, version: null, installPath: null };
|
|
49
|
+
} catch {
|
|
50
|
+
// 解析失败按不可用处理(fail-open:不阻断 conventions 生成)
|
|
51
|
+
return { available: false, version: null, installPath: null };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* GLAF4 委托三态检测(v2.1 §4 接口①)
|
|
57
|
+
* @param {string} root 项目根目录
|
|
58
|
+
* @param {object} options 覆盖项(如 { delegationMode: 'manual', pluginsFilePath: '/tmp/xxx.json' })
|
|
59
|
+
* @returns {{ is_glaf4_java: boolean, glaf4_dev_available: boolean, glaf4_dev_version: string|null, delegation_mode: 'auto'|'manual'|'off' }}
|
|
60
|
+
*/
|
|
61
|
+
export function detectGlaf4Delegation(root, options = {}) {
|
|
62
|
+
const techStack = detectTechStack(root);
|
|
63
|
+
// is_glaf4_java = Java 技术栈命中(pom.xml/build.gradle 存在即可,v2.1 §4)
|
|
64
|
+
// glaf4-dev 只处理 Java,Spring/JUnit 细分由 contract-builder 已有检测负责
|
|
65
|
+
const isGlaf4Java = techStack.language === 'java';
|
|
66
|
+
const plugin = detectGlaf4DevPlugin(options.pluginsFilePath);
|
|
67
|
+
const mode = options.delegationMode || 'auto';
|
|
68
|
+
return {
|
|
69
|
+
is_glaf4_java: isGlaf4Java,
|
|
70
|
+
glaf4_dev_available: plugin.available,
|
|
71
|
+
glaf4_dev_version: plugin.version,
|
|
72
|
+
delegation_mode: mode,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 写 glaf4_dev 段到 team-flow.config.json(v2.1 §4:contract-builder 产出 execution-contract 时探测写入)
|
|
78
|
+
* @param {string} root 项目根目录
|
|
79
|
+
* @param {{ enabled: boolean, version: string|null, delegationMode?: 'auto'|'manual'|'off' }} glaf4DevInfo
|
|
80
|
+
*/
|
|
81
|
+
export function writeGlaf4DevConfig(root, glaf4DevInfo) {
|
|
82
|
+
const teamFlowDir = join(root, '.team-flow');
|
|
83
|
+
const configPath = join(teamFlowDir, 'team-flow.config.json');
|
|
84
|
+
mkdirSync(teamFlowDir, { recursive: true });
|
|
85
|
+
|
|
86
|
+
let config = {};
|
|
87
|
+
if (existsSync(configPath)) {
|
|
88
|
+
try {
|
|
89
|
+
config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
90
|
+
} catch {
|
|
91
|
+
config = {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
config.glaf4_dev = {
|
|
96
|
+
enabled: glaf4DevInfo.enabled,
|
|
97
|
+
version: glaf4DevInfo.version,
|
|
98
|
+
};
|
|
99
|
+
// L5 修复(2026-08-18):delegation_mode 显式落盘,不依赖 config-loader 默认 auto
|
|
100
|
+
if (glaf4DevInfo.delegationMode) {
|
|
101
|
+
config.glaf4_dev.delegation_mode = glaf4DevInfo.delegationMode;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
105
|
+
}
|
|
106
|
+
|
|
16
107
|
// ── 常量 ─────────────────────────────────────────────────────────────────────
|
|
17
108
|
|
|
18
109
|
const TEMPLATE_DIR = join(import.meta.dirname, '../../templates/conventions');
|
|
@@ -7,7 +7,8 @@ import { getOverlayPaths } from './sdd-overlay.mjs';
|
|
|
7
7
|
import { readState } from './state-loader.mjs';
|
|
8
8
|
import { detectWorkspaceRoot, findSubRepo } from './git-utils.mjs';
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// v2.1 §6.6:扩入 glaf4-delegation(GLAF4 change 整体委托 glaf4-dev 七模式流,S1 结构统一)
|
|
11
|
+
export const EXECUTION_MODES = ['inline', 'batch-inline', 'sdd', 'glaf4-delegation'];
|
|
11
12
|
|
|
12
13
|
const WAVE_STRATEGIES = new Set(['parallel', 'serial']);
|
|
13
14
|
const REVIEW_STATUSES = new Set(['pass', 'fail']);
|
|
@@ -7,8 +7,21 @@ import { loadConfig } from './config-loader.mjs';
|
|
|
7
7
|
import { computeArtifactsHash, computeContractHash } from './hash.mjs';
|
|
8
8
|
import { getOverlayPaths } from './sdd-overlay.mjs';
|
|
9
9
|
import { readState } from './state-loader.mjs';
|
|
10
|
+
import { EXECUTION_MODES } from './execution-plan.mjs';
|
|
11
|
+
|
|
12
|
+
// v2.1 §6.6(二轮评审 HIGH):recommend 链补全
|
|
13
|
+
// - GLAF4 change 的 recommend 恒为"推荐 inline + available_modes 含 glaf4-delegation"
|
|
14
|
+
// - 选 glaf4-delegation 属非推荐选择,需 --acknowledge-recommendation(cmd-execution 校验)
|
|
15
|
+
export function recommendExecutionModes({ workflow, taskCount, inlineThreshold, waves = [], glaf4DelegationAvailable = false }) {
|
|
16
|
+
const base = recommendBaseExecutionModes({ workflow, taskCount, inlineThreshold, waves });
|
|
17
|
+
if (glaf4DelegationAvailable && !base.available_modes.includes('glaf4-delegation')) {
|
|
18
|
+
base.available_modes = [...base.available_modes, 'glaf4-delegation'];
|
|
19
|
+
}
|
|
20
|
+
base.facts.glaf4_delegation_available = glaf4DelegationAvailable;
|
|
21
|
+
return base;
|
|
22
|
+
}
|
|
10
23
|
|
|
11
|
-
|
|
24
|
+
function recommendBaseExecutionModes({ workflow, taskCount, inlineThreshold, waves = [] }) {
|
|
12
25
|
const normalizedWorkflow = typeof workflow === 'string' ? workflow : null;
|
|
13
26
|
const normalizedTaskCount = Number.isInteger(taskCount) && taskCount >= 0 ? taskCount : null;
|
|
14
27
|
const threshold = Number.isInteger(inlineThreshold) && inlineThreshold > 0 ? inlineThreshold : 3;
|
|
@@ -68,11 +81,15 @@ export function recommendExecutionModes({ workflow, taskCount, inlineThreshold,
|
|
|
68
81
|
export function recommendExecutionModesForChange(changeDir, waves = []) {
|
|
69
82
|
const state = readState(changeDir);
|
|
70
83
|
const config = loadConfig(changeDir);
|
|
84
|
+
// v2.1 §6.6:glaf4-delegation 可用性 = 运行时探测已写 config.glaf4_dev(enabled)且 delegation_mode ≠ off
|
|
85
|
+
const glaf4 = config.glaf4_dev || {};
|
|
86
|
+
const glaf4DelegationAvailable = glaf4.enabled === true && glaf4.delegation_mode !== 'off';
|
|
71
87
|
return recommendExecutionModes({
|
|
72
88
|
workflow: state.workflow,
|
|
73
89
|
taskCount: countDocumentedTasks(changeDir),
|
|
74
90
|
inlineThreshold: config.execution.inlineThreshold,
|
|
75
91
|
waves,
|
|
92
|
+
glaf4DelegationAvailable,
|
|
76
93
|
});
|
|
77
94
|
}
|
|
78
95
|
|
|
@@ -154,10 +171,10 @@ function validateRecommendationReceiptStructure(receipt) {
|
|
|
154
171
|
if (!isObject(receipt.recommendation)) failures.push('execution recommendation payload is required');
|
|
155
172
|
else {
|
|
156
173
|
const recommendation = receipt.recommendation;
|
|
157
|
-
if (!Array.isArray(recommendation.available_modes) || recommendation.available_modes.some(mode => !
|
|
174
|
+
if (!Array.isArray(recommendation.available_modes) || recommendation.available_modes.some(mode => !EXECUTION_MODES.includes(mode))) {
|
|
158
175
|
failures.push('execution recommendation available modes are invalid');
|
|
159
176
|
}
|
|
160
|
-
if (!isObject(recommendation.recommendation) || !
|
|
177
|
+
if (!isObject(recommendation.recommendation) || !EXECUTION_MODES.includes(recommendation.recommendation.mode)) {
|
|
161
178
|
failures.push('execution recommendation mode is invalid');
|
|
162
179
|
}
|
|
163
180
|
if (!Array.isArray(recommendation.recommendation?.reasons) || recommendation.recommendation.reasons.some(reason => typeof reason !== 'string' || !reason.trim())) {
|