@xulthekl/team-flow 0.55.0 → 0.56.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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/marketplace.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.github/plugin/marketplace.json +2 -2
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +48 -0
- package/GEMINI.md +1 -1
- package/INSTALL.md +1 -1
- package/README.md +1 -1
- package/docs/README_en.md +1 -1
- package/gemini-extension.json +1 -1
- package/hooks/session-start +2 -2
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/lib/sdd-overlay.mjs +2 -3
- package/scripts/lib/slug.mjs +68 -0
- package/scripts/lib/solutions-capture.mjs +6 -12
- package/scripts/lib/solutions-index-gen.mjs +2 -2
- package/scripts/lib/solutions-phases.mjs +32 -0
- package/scripts/lib/solutions-promote.mjs +5 -1
- package/scripts/lib/test-merge.mjs +31 -2
- package/skills/ce-compound/references/three-tier-index.md +6 -2
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "team-flow",
|
|
11
11
|
"description": "8-state spec workflow + compound global compounding + architecture-design (4A/DDD) + local HTML prototype + product-level orchestration + bootstrap + e2e + session handoff + workflow feedback + independent business analysis. 26 skills + 17 agents with embedded TDD, SDD, code review, debugging, delta spec sync, and design-system-driven prototyping.",
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.56.1",
|
|
13
13
|
"source": "./",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "LT",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.1",
|
|
4
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) + design-system (design tokens + component contract + AI primer + showcase) + test-strategy (test strategy design) + project-initialize (new service onboarding). 26 skills + 17 agents, one install.",
|
|
5
5
|
"source": "./",
|
|
6
6
|
"author": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "team-flow",
|
|
3
3
|
"displayName": "team-flow",
|
|
4
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). 26 skills + 17 agents, one install.",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.56.1",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "LT",
|
|
8
8
|
"url": "https://github.com/LT"
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Unified workflow plugins and skills for AI coding agents (team-flow: team-flow + compound + architecture-design + prototype).",
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.56.1"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "team-flow",
|
|
14
14
|
"description": "Unified workflow with planning artifacts, execution contracts, TDD, review gates, systematic debugging, delta spec sync, architecture-design, independent business analysis, and local HTML prototyping.",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.56.1",
|
|
16
16
|
"source": ".",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "LT",
|
package/AGENTS.md
CHANGED
|
@@ -110,7 +110,7 @@ docs/
|
|
|
110
110
|
├── architecture/ 全局架构三层(v0.36.0):L1 当前态(ARCHITECTURE.md marker 区 / PHYSICAL-MODEL.md / DATABASE.md / API-INDEX.md / INDEX.md / domains/<bc>.md / diagrams/ / schema-baseline.sql / baseline.md)+ L2 changelog/ + L3 iterations/vN/architecture.md(产品级快照,archived 退役)
|
|
111
111
|
└── solutions/ 复利经验库(v0.5 新增,三层索引)
|
|
112
112
|
├── INDEX.md # L1 轻量索引(≤150行,每条一行摘要+标签)
|
|
113
|
-
├──
|
|
113
|
+
├── prd/ plan/ architecture/ prototype/ spec/ build/ review/ cross-phase/ # L2 分阶段目录(枚举权威:scripts/lib/solutions-phases.mjs)
|
|
114
114
|
└── <file>.md # L3 经验文件(YAML frontmatter: phase/domain/type/severity)
|
|
115
115
|
changes/<name>/ 变更脚手架(S4 创建):.team-flow.yaml(变更级状态文件)/ change-brief.md(产品级交接物,含 upstream_arch_ref)/ proposal.md / design.md / tasks.md / execution-contract.md / learnings.md(变更级经验台账)/ architecture/(变更级三件套 + sql/)
|
|
116
116
|
specs/<cap>/ 每变更规格:spec.md(v0.49.0 §83.3.5:learnings.md 归 change 根,不在此目录)
|
|
@@ -253,7 +253,7 @@ STRATEGY.md CONCEPTS.md 产品策略(BA) / 领域词汇
|
|
|
253
253
|
```
|
|
254
254
|
docs/solutions/
|
|
255
255
|
├── INDEX.md # L1:轻量索引(≤150行,每条一行摘要+标签,按 severity 降序)
|
|
256
|
-
├──
|
|
256
|
+
├── prd/ plan/ architecture/ prototype/ spec/ build/ review/ cross-phase/ # L2:分阶段目录(枚举权威:scripts/lib/solutions-phases.mjs)
|
|
257
257
|
└── <date>-<summary>.md # L3:经验文件(YAML frontmatter: phase/domain/type/severity/date/source)
|
|
258
258
|
```
|
|
259
259
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,54 @@ All notable changes to `team-flow` will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format loosely follows Keep a Changelog.
|
|
6
6
|
|
|
7
|
+
## [0.56.1] - 2026-09-12
|
|
8
|
+
|
|
9
|
+
### Fixed(v0.56.0 自身引入的回归 + P1.5 第一轮暴露的遗漏;**升级优先于 0.56.0**)
|
|
10
|
+
|
|
11
|
+
来源:v0.56.0 的 P1.5 **完整档 3 轮**对抗验证第一轮(事实核查 / 反方辩护 / 场景遍历三路独立代理)。三路共暴露 51 条断言级核查 + 8 类场景缺口 + 5 项设计缺陷,本版仅处置其中**确定性的代码缺陷**;设计缺陷需修订 `docs/plan/compound-lifecycle-governance-design.md`(**v1.0 → v2.0 修订进行中,尚未落档**),不属本版范围。
|
|
12
|
+
|
|
13
|
+
- **`tf test-merge` baselines 命名失配(v0.56.0 引入,危害高于其修复的原缺陷)**:v0.56.0 把 slug 规则从 `[^a-z0-9-]`(逐字符替换、不去首尾)换成 `slugify()`(保留 CJK、折叠连续、**去首尾分隔符**)。而 baselines 的 `moduleName` 形如 `DemoHome(demo-ui,medium)`,**恒以全角 `)` 结尾** ⇒ 旧规则产出的文件名恒以 `-` 结尾(`demohome-demo-ui-medium-.md`),新规则会去掉尾 `-` ⇒ **既有文件全部失配**(emp-auth 实测 **67/67**)⇒ 每个模块新建一份、目录翻倍。修法:新增 `resolveBaselinePath()` **双查找**——新 slug 优先 → 旧 slug 回退 → 都不存在才按新规则新建;命中旧命名文件**原地更新**(不强制改名,批量改名属 P1 的稳定 `module_id` + `--rekey` 范畴)。
|
|
14
|
+
- **PHASES 单一真相源未做全(v0.56.0 遗留)**:`tests/lib/solutions-index-gen.test.mjs` 仍内联 7 项枚举(`'prd','plan','prototype','spec','build','review','cross-phase'`,缺 `architecture`)并把缺陷**固化为期望行为**(用例名 `scans all 7 phase directories`)。此为 PHASES 的第 3 份副本——v0.56.0 只收敛了 2 个生产消费点,测试侧漏改。修法:改为从 `solutions-phases.mjs` 导入。
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **枚举副本防漂移机械预防**(`tests/lib/solutions-phases.test.mjs`):断言模板与文档中仍需列出的 phase 副本(`templates/learnings.md` 注释、`AGENTS.md` 目录树、`three-tier-index.md` 目录树)均覆盖 `SOLUTION_PHASES` 全部取值。背景:PHASES 历史上存在 **4 处**定义且相互矛盾,代码侧已收敛,文档侧用本组用例守护同步(支持"每 phase 一行"与"单行列全"两种排版)。
|
|
19
|
+
- `test-merge.test.mjs` 新增「兼容旧 slug 命名」用例;`solutions-phases.test.mjs` 新增 3 条防漂移用例。
|
|
20
|
+
|
|
21
|
+
### 验证
|
|
22
|
+
|
|
23
|
+
- 全量测试 **1112/1112 通过**(基线 1108,+4)
|
|
24
|
+
- **变异验证**(本轮已按事实核查建议留痕于设计文档附录 A.2):去掉 `resolveBaselinePath` 的 legacy 回退 → 中文命名回归用例失败;从模板删 `architecture` → 防漂移用例失败并精确报出缺失项
|
|
25
|
+
|
|
26
|
+
## [0.56.0] - 2026-09-12
|
|
27
|
+
|
|
28
|
+
### Fixed(复利产物文件名退化 + 索引丢条目;来源:emp-auth 复利膨胀调查)
|
|
29
|
+
|
|
30
|
+
设计来源:`docs/plan/compound-lifecycle-governance-design.md` v1.0。输入 = **emp-auth v1 迭代(5 change)的复利产物实测**——发现"复利条目随迭代膨胀/重复"的表象下,实为**存储层无上限 + 身份层去重键选错 + 索引层无门禁**三层缺口(完整证据链见该方案附录 A;P1/P2 待实施)。
|
|
31
|
+
|
|
32
|
+
本版处置其中两个**确定性缺陷**(P0):
|
|
33
|
+
|
|
34
|
+
- **PHASES 枚举三处定义互相矛盾**(`solutions-capture` 8 项含 `architecture` / `solutions-index-gen` 7 项缺 / 文档树写 `requirement`):`tf solutions capture --phase architecture` 写入的条目在 `tf solutions index-gen` 重建后**从 INDEX.md 消失**——文件仍在磁盘,但对所有注入与检索通道不可见。新增 `scripts/lib/solutions-phases.mjs` 作唯一真相源,两处消费点收敛。
|
|
35
|
+
- **slug 规则三套并存,两处不保留 CJK 且逐字符替换**:`test-merge.mjs` 的 `replace(/[^a-z0-9-]/g,'-')` 与 `sdd-overlay.mjs` 的 `replace(/[^A-Za-z0-9._-]/g,'_')` 把中文标题**逐字符**替换为分隔符,产生 `--------------------.md`(原名「执行结果(三仓实测,命令 + 实际输出)」)这类无信息量文件名(emp-auth 实测 17 个文件受影响);叠加 baselines 的 `moduleName` 取自 test-matrix 三级标题原文(每轮自由命名)⇒ 文件名不稳定 ⇒ `existsSync` 不命中 ⇒ **新建而非增量合并**(`demohome` 三次 merge 全为 `A(Added)`,攒出 3 个文件)。新增 `scripts/lib/slug.mjs` 作唯一真相源(`slugify` / `safeName` / `CJK_CLASS`),4 处消费点收敛。
|
|
36
|
+
|
|
37
|
+
**关键陷阱(已写入模块注释守护)**:字面「一-鿿」拼进字符类时,**前一个字符若为 `-` 会构成范围**——`[^..._-一-鿿]` 里的 `_-一` 是 U+005F–U+4E00 范围,U+4E00 以上的汉字(如「任务」U+4EFB)仍被替换。故 `CJK_CLASS` 以转义写法导出,`safeName` 的 `-` 置于字符类末尾。
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `scripts/lib/slug.mjs`(文件名/路径段安全化唯一真相源)、`scripts/lib/solutions-phases.mjs`(复利 phase 枚举唯一真相源)
|
|
42
|
+
- `tests/lib/slug.test.mjs`(13 用例,含 U+4E00 以上汉字的范围陷阱守护)、`tests/lib/solutions-phases.test.mjs`(6 用例,含"capture 能写但 index-gen 扫不到"的行为级守护)、`tests/lib/test-merge.test.mjs` +1 用例(中文模块名不退化为短横线)
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- `AGENTS.md` ×2、`skills/ce-compound/references/three-tier-index.md` ×2:phase 目录列表同口径同步,顺带修正 `requirement/` → `prd/`(与脚本实际写入目录对齐),并补注"CLI 通道 phase 目录"与"ce-compound category 目录"两套词表互不兼容
|
|
47
|
+
|
|
48
|
+
### 验证
|
|
49
|
+
|
|
50
|
+
- 全量测试 **1108/1108 通过**
|
|
51
|
+
- **4 项变异验证**确认新增测试具备判别力(去掉 `architecture` / index-gen 写死列表 / `safeName` 的 `-` 置中 / test-merge 还原旧正则——每项均使对应测试失败并报出原缺陷形态)
|
|
52
|
+
- **行为等价实证**:以 emp-auth 真实 learnings 标题跑新 `slugify`,与既有条目文件名 **4/4 一致**(无回归)
|
|
53
|
+
- 提交可见性:4 个新增文件未被 `.gitignore` 吞掉,2 个脚本进入 `npm pack` 白名单
|
|
54
|
+
|
|
7
55
|
## [0.55.0] - 2026-09-11
|
|
8
56
|
|
|
9
57
|
### Added(首次真实使用反馈处置:棕地机制 + 解析层加固)
|
package/GEMINI.md
CHANGED
|
@@ -8,7 +8,7 @@ The workflow is self-contained and does not require OpenSpec or Superpowers at r
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
<!-- team-flow-phase-guard-start -->
|
|
11
|
-
# team-flow v0.
|
|
11
|
+
# team-flow v0.56.1 | 阶段: {{state}} | 工作流: {{workflow}}
|
|
12
12
|
当前阶段允许的操作由 workflow-start 路由规则定义。
|
|
13
13
|
禁止跨越 DP gate 进入下一阶段。变更范围以 execution-contract.md 的 Intent Lock 为准。
|
|
14
14
|
<!-- team-flow-phase-guard-end -->
|
package/INSTALL.md
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# team-flow
|
|
2
2
|
|
|
3
|
-
> 当前版本:`v0.
|
|
3
|
+
> 当前版本:`v0.56.1`
|
|
4
4
|
|
|
5
5
|
> 统一插件:**team-flow**(spec 驱动开发)+ **compound-engineering 核心子集**(全局复利)+ **architecture-design**(4A+DDD 增量设计)+ **prototype**(本地 HTML 原型)+ **e2e**(AC 驱动 E2E)+ **workflow-orchestrator**(产品级编排)+ **workflow-bootstrap**(既有项目接入)。一次安装,七套能力协同。
|
|
6
6
|
|
package/docs/README_en.md
CHANGED
|
@@ -126,7 +126,7 @@ npm install -g team-flow
|
|
|
126
126
|
|
|
127
127
|
### Version
|
|
128
128
|
|
|
129
|
-
- Current: `v0.
|
|
129
|
+
- Current: `v0.56.1`
|
|
130
130
|
- v0.9.1 highlights: DP-4 execution-mode recommendations, a portable runtime across 17 platforms, and a raw-package smoke with no plugin-root variable.
|
|
131
131
|
- Self-contained — no OpenSpec or Superpowers runtime required
|
|
132
132
|
- Upstream: [Fission-AI/OpenSpec](https://github.com/Fission-AI/OpenSpec), [obra/superpowers](https://github.com/obra/superpowers)
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-flow",
|
|
3
3
|
"description": "Unified workflow plugin: team-flow (spec-driven dev) + compound-engineering core subset + architecture-design (4A/DDD) + prototype (local HTML) + business-analysis (independent requirement/scenario artifact). 26 skills, one install.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.56.1",
|
|
5
5
|
"contextFileName": "GEMINI.md"
|
|
6
6
|
}
|
package/hooks/session-start
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# v0.
|
|
2
|
+
# v0.56.1: auto-sync CLI version with plugin version
|
|
3
3
|
set -e
|
|
4
4
|
|
|
5
5
|
# ═══════════════════════════════════════════════════════════════
|
|
6
6
|
# Plugin version (update this when releasing new versions)
|
|
7
7
|
# ═══════════════════════════════════════════════════════════════
|
|
8
|
-
PLUGIN_VERSION="0.
|
|
8
|
+
PLUGIN_VERSION="0.56.1"
|
|
9
9
|
|
|
10
10
|
# ═══════════════════════════════════════════════════════════════
|
|
11
11
|
# Step 1: Auto-sync CLI version with plugin version
|
package/llms.txt
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Overview
|
|
4
4
|
spec-superflow is a self-contained workflow integration plugin for Claude Code, Cursor, OpenAI Codex CLI/App, GitHub Copilot CLI, Gemini CLI, OpenCode, WorkBuddy, and Trae. It merges spec-driven planning artifacts (proposal, specs, design, tasks) with disciplined execution guardrails (TDD, review gates, controlled handoff) into one unified workflow.
|
|
5
5
|
|
|
6
|
-
Current version: v0.
|
|
6
|
+
Current version: v0.56.1.
|
|
7
7
|
|
|
8
8
|
## Key Documents
|
|
9
9
|
- README.md: Chinese homepage with full usage guide and FAQ
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xulthekl/team-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.1",
|
|
4
4
|
"description": "Unified plugin (26 skills + 17 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",
|
package/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.1",
|
|
4
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) + design-system (design tokens + component contract + AI primer + showcase) + test-strategy (test strategy design) + project-initialize (new service onboarding). 26 skills + 17 agents, one install.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LT"
|
|
@@ -6,6 +6,7 @@ import { dirname, join } from 'node:path';
|
|
|
6
6
|
import { computeArtifactsHash, normalizeCheckboxes } from './hash.mjs';
|
|
7
7
|
import { parseTaskLine } from './md-normalize.mjs';
|
|
8
8
|
import { readState } from './state-loader.mjs';
|
|
9
|
+
import { safeName } from './slug.mjs';
|
|
9
10
|
|
|
10
11
|
export const HANDOFF_TYPES = new Set(['prototype', 'research', 'experiment']);
|
|
11
12
|
export const HANDOFF_DECISIONS = new Set(['accept', 'reject', 'defer']);
|
|
@@ -270,6 +271,4 @@ function requireText(value, field) {
|
|
|
270
271
|
if (typeof value !== 'string' || !value.trim()) throw new Error(`${field} is required`);
|
|
271
272
|
}
|
|
272
273
|
|
|
273
|
-
|
|
274
|
-
return String(value).replace(/[^A-Za-z0-9._-]/g, '_');
|
|
275
|
-
}
|
|
274
|
+
// safeName 已收敛到 slug.mjs(保留 CJK;`. _ -` 语义不变,如 taskId `1.1` 原样保留)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slug — 文件名 / 路径段安全化的唯一真相源(2026-09-12,emp-auth 复利膨胀调查)
|
|
3
|
+
*
|
|
4
|
+
* 背景:同一插件内曾存在 3 套文件名安全化规则,其中两套**未保留 CJK 且逐字符替换**,
|
|
5
|
+
* 导致中文标题退化为纯短横线序列。实证(emp-auth v1 迭代):
|
|
6
|
+
* - `docs/test-ledger/baselines/--------------------.md`(原名「执行结果(三仓实测,命令 + 实际输出)」)
|
|
7
|
+
* - 同目录 17 个文件名受影响,其中多份已无法从文件名辨识内容
|
|
8
|
+
* - 叠加第二个因素:baselines 的 moduleName 取自 test-matrix 三级标题原文(每轮由 LLM
|
|
9
|
+
* 自由命名,如 `DemoHome 当前应用(demo-ui,medium)` vs `DemoHome(demo-ui,medium,revision 3)`)
|
|
10
|
+
* ⇒ 文件名每轮变化 ⇒ `existsSync` 不命中 ⇒ **新建而非增量合并**(demohome 三次 merge
|
|
11
|
+
* 产出 3 个文件,git 记录全为 A)
|
|
12
|
+
*
|
|
13
|
+
* 约定:
|
|
14
|
+
* - 字符集统一为 **ASCII 字母数字 + CJK 统一表意文字(U+4E00–U+9FFF)**;其余字符折叠为分隔符
|
|
15
|
+
* - 一律使用 `+` 量词折叠连续非法字符——**禁止逐字符替换**(一个中文 = 一个分隔符是退化根因)
|
|
16
|
+
* - 两类用途语义不同,**不要互串**:
|
|
17
|
+
* · slugify() 标题 → 文件名(小写、`.`/`_`/`-` 均折叠为分隔符、可截断)
|
|
18
|
+
* · safeName() ID → 路径段(保留大小写与 `.` `_` `-`,不截断)——ID 自身以这些字符作分隔,
|
|
19
|
+
* 例如 taskId `1.1` MUST 保持为 `1.1`(折叠成 `1_1` 会失配既有 checkpoint 文件)
|
|
20
|
+
*
|
|
21
|
+
* @module slug
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* CJK 统一表意文字区间字符类(U+4E00–U+9FFF)。
|
|
26
|
+
*
|
|
27
|
+
* 用 `\u` 转义写法而非字面「一-鿿」:字面写法拼进字符类时,**前一个字符若为 `-`
|
|
28
|
+
* 会被解析成范围**——`[^..._-一-鿿]` 里的 `_-一` 是 U+005F–U+4E00 范围,
|
|
29
|
+
* 结果 U+4E00 以上的汉字(如「任务」U+4EFB)仍被替换。转义写法无此风险。
|
|
30
|
+
*/
|
|
31
|
+
export const CJK_CLASS = '\\u4e00-\\u9fff';
|
|
32
|
+
|
|
33
|
+
/** 转义正则元字符(separator 由调用方传入,可能是 `-` / `_` 等) */
|
|
34
|
+
function escapeRe(s) {
|
|
35
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 标题 → 文件名 slug。
|
|
40
|
+
*
|
|
41
|
+
* 保留 ASCII 小写字母数字与 CJK;其余连续字符折叠为一个 separator;去掉首尾 separator。
|
|
42
|
+
*
|
|
43
|
+
* @param {string} value 原始文本(通常是条目标题 / 模块名)
|
|
44
|
+
* @param {{separator?: string, maxLength?: number}} [options]
|
|
45
|
+
* separator 默认 `-`;maxLength > 0 时才截断(默认不截断,由调用方按场景显式传入)
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
export function slugify(value, { separator = '-', maxLength = 0 } = {}) {
|
|
49
|
+
const esc = escapeRe(separator);
|
|
50
|
+
let s = String(value ?? '').toLowerCase();
|
|
51
|
+
s = s.replace(new RegExp(`[^a-z0-9${CJK_CLASS}]+`, 'g'), separator);
|
|
52
|
+
s = s.replace(new RegExp(`^(?:${esc})+|(?:${esc})+$`, 'g'), '');
|
|
53
|
+
return maxLength > 0 ? s.slice(0, maxLength) : s;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* ID → 路径段安全名。
|
|
58
|
+
*
|
|
59
|
+
* 保留 ASCII 字母数字(含大小写)与 `.` `_` `-`,以及 CJK;其余连续字符折叠为一个 `_`。
|
|
60
|
+
* 不截断、不改大小写——ID 的既有语义(如 `1.1`、`W4-1`)MUST 原样保留。
|
|
61
|
+
*
|
|
62
|
+
* @param {string} value
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
export function safeName(value) {
|
|
66
|
+
// `-` MUST 置于字符类末尾(否则与相邻字符构成范围)
|
|
67
|
+
return String(value ?? '').replace(new RegExp(`[^A-Za-z0-9._${CJK_CLASS}-]+`, 'g'), '_');
|
|
68
|
+
}
|
|
@@ -16,17 +16,11 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, appendFileSync } fr
|
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { pathToFileURL } from 'node:url';
|
|
18
18
|
import { SEVERITY_VALUES, isSeverity } from './severity.mjs';
|
|
19
|
+
import { SOLUTION_PHASES } from './solutions-phases.mjs';
|
|
20
|
+
import { slugify } from './slug.mjs';
|
|
19
21
|
|
|
20
|
-
const PHASES = ['prd', 'plan', 'architecture', 'prototype', 'spec', 'build', 'review', 'cross-phase'];
|
|
21
22
|
const MAX_INDEX_LINES = 150;
|
|
22
|
-
|
|
23
|
-
function slugify(text) {
|
|
24
|
-
return text
|
|
25
|
-
.toLowerCase()
|
|
26
|
-
.replace(/[^a-z0-9一-鿿]+/g, '-')
|
|
27
|
-
.replace(/^-|-$/g, '')
|
|
28
|
-
.slice(0, 40);
|
|
29
|
-
}
|
|
23
|
+
const SLUG_MAX_LENGTH = 40;
|
|
30
24
|
|
|
31
25
|
export function run(args = {}) {
|
|
32
26
|
const phase = args.phase || 'cross-phase';
|
|
@@ -42,8 +36,8 @@ export function run(args = {}) {
|
|
|
42
36
|
|
|
43
37
|
// 注:process.exit 后补 return——真实 CLI 下 exit 即终止;测试环境 mock exit 时
|
|
44
38
|
// 不得继续执行(否则校验失败仍会写入文件,v0.23 §91.3.4 横展)。
|
|
45
|
-
if (!
|
|
46
|
-
console.error(`Invalid phase: ${phase}. Valid: ${
|
|
39
|
+
if (!SOLUTION_PHASES.includes(phase)) {
|
|
40
|
+
console.error(`Invalid phase: ${phase}. Valid: ${SOLUTION_PHASES.join(', ')}`);
|
|
47
41
|
process.exit(1);
|
|
48
42
|
return;
|
|
49
43
|
}
|
|
@@ -61,7 +55,7 @@ export function run(args = {}) {
|
|
|
61
55
|
|
|
62
56
|
// 生成文件名
|
|
63
57
|
const date = new Date().toISOString().slice(0, 10);
|
|
64
|
-
const slug = slugify(summary);
|
|
58
|
+
const slug = slugify(summary, { maxLength: SLUG_MAX_LENGTH });
|
|
65
59
|
const fileName = `${date}-${slug}.md`;
|
|
66
60
|
const filePath = join(phaseDir, fileName);
|
|
67
61
|
|
|
@@ -17,8 +17,8 @@ import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from '
|
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { pathToFileURL } from 'node:url';
|
|
19
19
|
import { severityRank } from './severity.mjs';
|
|
20
|
+
import { SOLUTION_PHASES } from './solutions-phases.mjs';
|
|
20
21
|
|
|
21
|
-
const PHASES = ['prd', 'plan', 'prototype', 'spec', 'build', 'review', 'cross-phase'];
|
|
22
22
|
const MAX_INDEX_LINES = 150;
|
|
23
23
|
|
|
24
24
|
function parseFrontmatter(content) {
|
|
@@ -54,7 +54,7 @@ export function run(args = {}) {
|
|
|
54
54
|
|
|
55
55
|
const entries = [];
|
|
56
56
|
|
|
57
|
-
for (const phase of
|
|
57
|
+
for (const phase of SOLUTION_PHASES) {
|
|
58
58
|
const phaseDir = join(dir, phase);
|
|
59
59
|
if (!existsSync(phaseDir) || !statSync(phaseDir).isDirectory()) continue;
|
|
60
60
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* solutions-phases — 复利条目 phase 目录的唯一真相源(2026-09-12)
|
|
3
|
+
*
|
|
4
|
+
* 背景:PHASES 枚举曾在 3 处各自定义且互相矛盾——
|
|
5
|
+
* - `solutions-capture.mjs` 8 项(含 `architecture`,v0.36.3 加入)
|
|
6
|
+
* - `solutions-index-gen.mjs` 7 项(**缺 `architecture`**)
|
|
7
|
+
* - 文档树(three-tier-index.md / AGENTS.md)写 `requirement`,而 frontmatter 示例写 `prd`
|
|
8
|
+
*
|
|
9
|
+
* 后果(实证,emp-auth):`tf solutions capture --phase architecture` 写入的条目在
|
|
10
|
+
* `tf solutions index-gen` 重建后会**从 INDEX.md 消失**——文件仍在磁盘,但对所有
|
|
11
|
+
* 注入 / 检索通道不可见。任何新增 phase 只改本文件。
|
|
12
|
+
*
|
|
13
|
+
* 注意:`docs/solutions/` 下另有 ce-compound 通道写入的 **category 目录**
|
|
14
|
+
* (`workflow-issues/` 等,见 skills/ce-compound/references/yaml-schema.md),
|
|
15
|
+
* 那套词表与本 phase 词表**互不兼容**,本模块不覆盖。
|
|
16
|
+
*
|
|
17
|
+
* @module solutions-phases
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** 合法 phase 取值(同时是 docs/solutions/ 下的子目录名) */
|
|
21
|
+
export const SOLUTION_PHASES = Object.freeze([
|
|
22
|
+
'prd', 'plan', 'architecture', 'prototype', 'spec', 'build', 'review', 'cross-phase',
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 是否为合法 phase 取值。
|
|
27
|
+
* @param {string} phase
|
|
28
|
+
* @returns {boolean}
|
|
29
|
+
*/
|
|
30
|
+
export function isSolutionPhase(phase) {
|
|
31
|
+
return SOLUTION_PHASES.includes(phase);
|
|
32
|
+
}
|
|
@@ -23,6 +23,10 @@ import { join, basename } from 'node:path';
|
|
|
23
23
|
import { pathToFileURL } from 'node:url';
|
|
24
24
|
import { meetsMinSeverity, nextSeverity } from './severity.mjs';
|
|
25
25
|
import { normalizeInline } from './md-normalize.mjs';
|
|
26
|
+
import { slugify } from './slug.mjs';
|
|
27
|
+
|
|
28
|
+
/** 文件名 slug 截断长度(与 solutions-capture 一致) */
|
|
29
|
+
const SLUG_MAX_LENGTH = 40;
|
|
26
30
|
|
|
27
31
|
/**
|
|
28
32
|
* 剥离 YAML 行尾注释(空格 + `#` 起始)——v0.23 §91 硬化:
|
|
@@ -188,7 +192,7 @@ export function run(args = {}) {
|
|
|
188
192
|
mkdirSync(phaseDir, { recursive: true });
|
|
189
193
|
}
|
|
190
194
|
|
|
191
|
-
const slug = learning.title
|
|
195
|
+
const slug = slugify(learning.title, { maxLength: SLUG_MAX_LENGTH });
|
|
192
196
|
const fileName = `${date}-${slug}.md`;
|
|
193
197
|
const filePath = join(phaseDir, fileName);
|
|
194
198
|
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import { readFileSync, writeFileSync, existsSync, cpSync, mkdirSync, readdirSync } from 'node:fs';
|
|
28
28
|
import { join, basename, relative, resolve } from 'node:path';
|
|
29
29
|
import { execSync } from 'node:child_process';
|
|
30
|
+
import { slugify } from './slug.mjs';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* 解析 CLI 参数数组为结构化对象
|
|
@@ -183,6 +184,32 @@ function extractDeferredItems(content) {
|
|
|
183
184
|
return items;
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
/** v0.56.0 之前的 slug 规则(仅供**读取既有文件**时回退匹配;新写入一律走 `slugify`) */
|
|
188
|
+
function legacySlug(moduleName) {
|
|
189
|
+
return String(moduleName ?? '').toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 解析既有 baseline 路径——兼容 v0.56.0 之前的命名规则。
|
|
194
|
+
*
|
|
195
|
+
* 背景(2026-09-12,v0.56.0 回归修复):v0.56.0 把 slug 规则从 `legacySlug`
|
|
196
|
+
* (逐字符替换、不去首尾)换成 `slugify`(保留 CJK、折叠连续、去首尾分隔符)。
|
|
197
|
+
* 而 baselines 的 moduleName 形如 `DemoHome(demo-ui,medium)`,**恒以全角 `)` 结尾**
|
|
198
|
+
* ⇒ 旧规则产出的文件名恒以 `-` 结尾(`demohome-demo-ui-medium-.md`),新规则会去掉尾 `-`
|
|
199
|
+
* ⇒ 既有文件**全部失配**(emp-auth 实测 67/67)⇒ 每个模块新建一份、目录翻倍。
|
|
200
|
+
*
|
|
201
|
+
* 故读取时双查找:新 slug 优先 → 旧 slug 回退 → 都不存在才按新规则新建。
|
|
202
|
+
* 命中旧命名文件后**原地更新**(保持旧名,不强制改名)——批量改名属 P1 的
|
|
203
|
+
* 稳定 `module_id` + `--rekey` 迁移范畴(见 `docs/plan/compound-lifecycle-governance-design.md` §4.3)。
|
|
204
|
+
*/
|
|
205
|
+
function resolveBaselinePath(baselinesDir, moduleName) {
|
|
206
|
+
const next = join(baselinesDir, `${slugify(moduleName)}.md`);
|
|
207
|
+
if (existsSync(next)) return next;
|
|
208
|
+
const legacy = join(baselinesDir, `${legacySlug(moduleName)}.md`);
|
|
209
|
+
if (existsSync(legacy)) return legacy;
|
|
210
|
+
return next;
|
|
211
|
+
}
|
|
212
|
+
|
|
186
213
|
/**
|
|
187
214
|
* Step 2: mergeBaselines — 增量合并到 baselines/{module}.md
|
|
188
215
|
* dryRun(feedback 2026-08-05):仅计算不写盘,返回 would-create/would-update 预览
|
|
@@ -197,8 +224,10 @@ export function mergeBaselines(ledgerDir, changeName, moduleSections, candidateL
|
|
|
197
224
|
const today = new Date().toISOString().slice(0, 10);
|
|
198
225
|
|
|
199
226
|
for (const [moduleName, sectionContent] of Object.entries(moduleSections)) {
|
|
200
|
-
|
|
201
|
-
|
|
227
|
+
// 统一走 slug.mjs(保留 CJK)——原 `[^a-z0-9-]` 逐字符替换会把中文标题退化成纯短横线,
|
|
228
|
+
// 实证 emp-auth `baselines/--------------------.md`(2026-09-12);
|
|
229
|
+
// 路径解析经 resolveBaselinePath 双查找,兼容 v0.56.0 之前的旧命名存量
|
|
230
|
+
const baselinePath = resolveBaselinePath(baselinesDir, moduleName);
|
|
202
231
|
const moduleCandidates = candidateLedger.filter(c =>
|
|
203
232
|
c.candidate.toLowerCase().includes(moduleName.toLowerCase())
|
|
204
233
|
);
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
```
|
|
6
6
|
docs/solutions/
|
|
7
7
|
├── INDEX.md # L1:轻量索引(≤150行,每条一行摘要+标签)
|
|
8
|
-
├──
|
|
8
|
+
├── prd/ # 按阶段分目录(枚举权威:scripts/lib/solutions-phases.mjs)
|
|
9
9
|
├── plan/
|
|
10
|
+
├── architecture/
|
|
10
11
|
├── prototype/
|
|
11
12
|
├── spec/
|
|
12
13
|
├── build/
|
|
@@ -14,6 +15,9 @@ docs/solutions/
|
|
|
14
15
|
└── cross-phase/ # 跨阶段通用经验
|
|
15
16
|
```
|
|
16
17
|
|
|
18
|
+
> 注意:目录树中**只有上述 phase 目录**由 `tf solutions` CLI 通道维护;`workflow-issues/`、
|
|
19
|
+
> `build-errors/` 等 category 目录由 `/ce-compound` 通道写入,两套词表互不兼容。
|
|
20
|
+
|
|
17
21
|
## INDEX.md 格式
|
|
18
22
|
|
|
19
23
|
```markdown
|
|
@@ -29,7 +33,7 @@ docs/solutions/
|
|
|
29
33
|
|
|
30
34
|
```yaml
|
|
31
35
|
---
|
|
32
|
-
phase: prd # 阶段标签:prd | plan | prototype | spec | build | review | cross-phase
|
|
36
|
+
phase: prd # 阶段标签:prd | plan | architecture | prototype | spec | build | review | cross-phase
|
|
33
37
|
domain: auth # 领域标签(与 PRD/change 的领域对应)
|
|
34
38
|
type: pitfall # pitfall | pattern | decision | insight
|
|
35
39
|
severity: high # critical | high | medium | low(序定义于 scripts/lib/severity.mjs)
|