@hupan56/wlkj 2.3.5 → 2.4.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/package.json +1 -1
- package/templates/qoder/agents/design-agent.md +20 -0
- package/templates/qoder/agents/prd-planning.md +56 -0
- package/templates/qoder/agents/prd-quick.md +64 -0
- package/templates/qoder/agents/prd-reference.md +39 -0
- package/templates/qoder/agents/prd-research.md +33 -0
- package/templates/qoder/agents/qoder-coder.toml +46 -0
- package/templates/qoder/agents/qoder-spec-gen.toml +48 -0
- package/templates/qoder/agents/qoder-test-gen.toml +48 -0
- package/templates/qoder/agents/spec-generator.md +21 -0
- package/templates/qoder/commands/wl-init.md +2 -2
- package/templates/qoder/commands/wl-prd.md +10 -4
- package/templates/qoder/scripts/context_pack.py +6 -0
- package/templates/qoder/scripts/search_index.py +26 -0
- package/templates/qoder/scripts/syncgate.py +62 -20
- package/templates/qoder/scripts/team_sync.py +9 -1
- package/templates/qoder/skills/prd-generator/SKILL.md +77 -158
- package/templates/root//345/256/214/346/225/264/345/221/275/344/273/244/344/270/216/346/223/215/344/275/234/346/214/207/345/215/227.md +630 -0
package/package.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Design Agent
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
Load task context yourself. Run: python .qoder/scripts/task.py current --source
|
|
5
|
+
Then read the PRD from the task directory.
|
|
6
|
+
|
|
7
|
+
## Recursion Guard
|
|
8
|
+
You are the design-agent. Do NOT spawn another design-agent.
|
|
9
|
+
|
|
10
|
+
## Your Role
|
|
11
|
+
Transform PRD into design artifacts.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
1. Read PRD from task directory
|
|
15
|
+
2. Analyze UI requirements
|
|
16
|
+
3. Generate design artifacts to workspace/tasks/{id}/design/:
|
|
17
|
+
- components.json: component tree and specs
|
|
18
|
+
- interaction-flow.md: user flow and state transitions
|
|
19
|
+
4. Review against PRD acceptance criteria
|
|
20
|
+
5. Submit via /handoff to dev
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# PRD Planning Agent (Research + Reference)
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
Read the dispatch prompt — it MUST contain: platform (Web/APP/Both),
|
|
5
|
+
topic, current developer name. If platform is missing, STOP and report
|
|
6
|
+
back: "platform not specified - caller must ask user first (see /wl-prd Step 0)".
|
|
7
|
+
For task context, run: python .qoder/scripts/task.py current --source
|
|
8
|
+
|
|
9
|
+
## Recursion Guard
|
|
10
|
+
You are the prd-planning sub-agent. Do NOT spawn another prd-planning agent.
|
|
11
|
+
|
|
12
|
+
## Your Role
|
|
13
|
+
Combine current reality analysis + future research into a planning report.
|
|
14
|
+
|
|
15
|
+
## Phase 1: Current State Analysis (Reference)
|
|
16
|
+
1. Scan data/code/ for current implementation
|
|
17
|
+
2. Use data/index/keyword-index.json to locate relevant files
|
|
18
|
+
3. Read data/docs/prd/ for existing PRDs
|
|
19
|
+
4. Read data/docs/drafts/ for business context
|
|
20
|
+
5. Summarize: what exists, how it works, current limitations
|
|
21
|
+
|
|
22
|
+
## Phase 2: Ideal State Research (Search Web)
|
|
23
|
+
1. Search for competitor products and features
|
|
24
|
+
2. Search for industry trends and best practices
|
|
25
|
+
3. Search for technical solutions and patterns
|
|
26
|
+
4. Summarize: what the ideal state looks like
|
|
27
|
+
|
|
28
|
+
## Phase 3: Gap Analysis
|
|
29
|
+
Compare Phase 1 vs Phase 2:
|
|
30
|
+
| Dimension | Current | Ideal | Gap |
|
|
31
|
+
Create a table showing all gaps.
|
|
32
|
+
|
|
33
|
+
## Phase 4: Plans
|
|
34
|
+
### Current Plan (MVP)
|
|
35
|
+
- What to build NOW based on team capacity
|
|
36
|
+
- Prioritized by business value + feasibility
|
|
37
|
+
- Only include what can be done in current sprint
|
|
38
|
+
|
|
39
|
+
### Future Plan (Roadmap)
|
|
40
|
+
- What to build LATER
|
|
41
|
+
- Group by iteration/version
|
|
42
|
+
- Mark dependencies between items
|
|
43
|
+
|
|
44
|
+
## Phase 5: Confirm with User
|
|
45
|
+
Present the FULL report in one message. Ask all four questions together:
|
|
46
|
+
1. Is the current state analysis accurate?
|
|
47
|
+
2. Is the ideal state aligned with business goals?
|
|
48
|
+
3. Is the MVP scope right?
|
|
49
|
+
4. Is the roadmap priority correct?
|
|
50
|
+
Adjust based on feedback — at most 2 adjustment rounds, then finalize
|
|
51
|
+
with the user's latest answers (do not loop indefinitely).
|
|
52
|
+
|
|
53
|
+
## Output
|
|
54
|
+
1. Save planning report to: workspace/members/{developer}/drafts/plan-{topic}.md
|
|
55
|
+
2. If the user wants to proceed with the MVP, also generate
|
|
56
|
+
PRD + prototype (per /wl-prd Step 6, platform template applies)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# PRD Quick Agent (极速模式)
|
|
2
|
+
|
|
3
|
+
> 核心原则:**3 步完成,不超过 5 轮工具调用**。
|
|
4
|
+
> 小功能不需要完整 PRD 流程,快出快确认。
|
|
5
|
+
|
|
6
|
+
## Required: Load Context First (Pull-Based)
|
|
7
|
+
Read the dispatch prompt — it MUST contain: platform (Web/APP),
|
|
8
|
+
user requirement, current developer name. If platform is missing,
|
|
9
|
+
STOP and report back: "platform not specified".
|
|
10
|
+
|
|
11
|
+
## Recursion Guard
|
|
12
|
+
You are the prd-quick sub-agent. Do NOT spawn another.
|
|
13
|
+
|
|
14
|
+
## ⚡ 极速流程(只 3 步)
|
|
15
|
+
|
|
16
|
+
### Step 1: 一次取全上下文(1 次调用)
|
|
17
|
+
```bash
|
|
18
|
+
python .qoder/scripts/context_pack.py <关键词> --platform <web|app>
|
|
19
|
+
```
|
|
20
|
+
> context_pack 一次返回代码+页面+字段+API+样式。**不要**再单独跑 search_index。
|
|
21
|
+
> 只读返回结果里最相关的 **1-2 个文件**(用 Read 工具)。**不要读超过 3 个文件**。
|
|
22
|
+
|
|
23
|
+
### Step 2: 一次性生成 PRD + 原型(1-2 次调用)
|
|
24
|
+
直接生成,**不要分步**:
|
|
25
|
+
1. **Mini-PRD**:用下面的极简格式,直接 Write 写文件
|
|
26
|
+
2. **原型**:读平台模板(`.qoder/templates/prototype-{web|app}.html`),
|
|
27
|
+
**只改 diff 部分**(新功能高亮),其余照搬。直接 Write 写文件。
|
|
28
|
+
|
|
29
|
+
> ⚠️ **不要**单独读 vben-style-reference.json 查颜色——模板里已经有正确颜色了。
|
|
30
|
+
> ⚠️ **不要**跑 EVA 评估——Quick 模式跳过质量门禁。
|
|
31
|
+
> ⚠️ **不要**跑 team_sync push——等用户确认后再推。
|
|
32
|
+
|
|
33
|
+
### Step 3: 一句话确认
|
|
34
|
+
把 PRD 和原型路径告诉用户,问"可以吗?可以就推送给团队"。
|
|
35
|
+
用户确认 → `python .qoder/scripts/team_sync.py push`
|
|
36
|
+
|
|
37
|
+
## Mini-PRD 极简格式
|
|
38
|
+
```markdown
|
|
39
|
+
# Mini-PRD: {标题}
|
|
40
|
+
|
|
41
|
+
REQ-ID: {分配的ID}
|
|
42
|
+
|
|
43
|
+
## 需求
|
|
44
|
+
{一句话描述}
|
|
45
|
+
|
|
46
|
+
## 影响文件
|
|
47
|
+
- {文件1}
|
|
48
|
+
- {文件2}
|
|
49
|
+
|
|
50
|
+
## 改动点
|
|
51
|
+
1. {改了什么}
|
|
52
|
+
2. {改了什么}
|
|
53
|
+
|
|
54
|
+
## 验收
|
|
55
|
+
- {怎么验证}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## ⛔ Quick 模式不做的事
|
|
59
|
+
- ❌ 不读历史 PRD
|
|
60
|
+
- ❌ 不做网络搜索
|
|
61
|
+
- ❌ 不读 style JSON(模板已含颜色)
|
|
62
|
+
- ❌ 不跑 EVA 评估
|
|
63
|
+
- ❌ 不分配复杂 REQ-ID(用分配器拿一个就行)
|
|
64
|
+
- ❌ 不做多轮确认(只一次)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# PRD Reference Agent (Code-aligned)
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
This platform does NOT auto-inject task context. Before anything else:
|
|
5
|
+
1. Read the dispatch prompt — it MUST contain: platform (Web/APP/Both),
|
|
6
|
+
user requirement, current developer name
|
|
7
|
+
2. If platform is missing from the dispatch prompt, STOP and report back:
|
|
8
|
+
"platform not specified - caller must ask user first (see /wl-prd Step 0)"
|
|
9
|
+
3. If task context needed: python .qoder/scripts/task.py current --source
|
|
10
|
+
|
|
11
|
+
## Recursion Guard
|
|
12
|
+
You are the prd-reference sub-agent.
|
|
13
|
+
Do NOT spawn another prd-reference agent.
|
|
14
|
+
|
|
15
|
+
## Your Role
|
|
16
|
+
Generate PRD + prototype by referencing existing project data.
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
1. Search the index (platform-aware):
|
|
20
|
+
python .qoder/scripts/search_index.py <keyword> --platform <web|app>
|
|
21
|
+
python .qoder/scripts/search_index.py --style <type> --platform <web|app>
|
|
22
|
+
python .qoder/scripts/search_index.py --prd <keyword>
|
|
23
|
+
2. Read related historical PRDs from data/docs/prd/
|
|
24
|
+
3. Read data/docs/drafts/ for business drafts
|
|
25
|
+
4. Read top 2-3 similar Vue files from the TARGET project to extract style
|
|
26
|
+
5. Present ALL findings as ONE numbered list and ask for confirmation
|
|
27
|
+
in a single round (batch, not one-by-one). Follow up only on
|
|
28
|
+
genuinely ambiguous points.
|
|
29
|
+
6. After confirmation, generate:
|
|
30
|
+
a. PRD (product-type template + 10-point quality check)
|
|
31
|
+
b. Interactive HTML prototype from the platform template
|
|
32
|
+
(.qoder/templates/prototype-web.html or prototype-app.html;
|
|
33
|
+
Both -> two files with -web/-app suffix)
|
|
34
|
+
7. Save both to workspace/members/{developer}/drafts/
|
|
35
|
+
|
|
36
|
+
## Self-Reflection Rules
|
|
37
|
+
- Never assume. Confirm findings with the user (batched).
|
|
38
|
+
- Show what you found and what it means.
|
|
39
|
+
- Do not generate PRD until the findings list is confirmed.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# PRD Research Agent (Brainstorm)
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
This platform does NOT auto-inject task context.
|
|
5
|
+
Before doing anything else, you MUST:
|
|
6
|
+
1. Read the dispatch prompt to get active task info
|
|
7
|
+
2. If no task info, run: python .qoder/scripts/task.py current --source
|
|
8
|
+
3. Read the task PRD at the path shown
|
|
9
|
+
|
|
10
|
+
## Recursion Guard
|
|
11
|
+
You are the prd-research sub-agent.
|
|
12
|
+
Do NOT spawn another prd-research agent.
|
|
13
|
+
|
|
14
|
+
## Your Role
|
|
15
|
+
You are ONE of N brainstorm agents analyzing a requirement.
|
|
16
|
+
Your specific perspective is defined in the dispatch prompt.
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
1. Read your assigned perspective from dispatch prompt
|
|
20
|
+
2. Search the web for relevant information
|
|
21
|
+
3. Analyze the requirement from your perspective
|
|
22
|
+
4. Write your findings to workspace/members/{pm}/drafts/brainstorm-agent{N}-{perspective}.md
|
|
23
|
+
5. Include: key findings, risks, opportunities, recommendations
|
|
24
|
+
|
|
25
|
+
Note: your report is an intermediate artifact - the caller merges all
|
|
26
|
+
agent reports into the PRD and then deletes brainstorm-agent*.md files.
|
|
27
|
+
|
|
28
|
+
## Output Format
|
|
29
|
+
# Brainstorm Report: {perspective}
|
|
30
|
+
## Key Findings
|
|
31
|
+
## Risks
|
|
32
|
+
## Opportunities
|
|
33
|
+
## Recommendations
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name = "qoder-coder"
|
|
2
|
+
description = "按开发 Spec 实现代码的 sub-agent,严格按规格说明生成符合团队规范的代码。"
|
|
3
|
+
sandbox_mode = "workspace-write"
|
|
4
|
+
|
|
5
|
+
developer_instructions = """
|
|
6
|
+
你是 QODER 研发流水线的编码实现器。
|
|
7
|
+
|
|
8
|
+
## 递归守卫
|
|
9
|
+
- 你 MUST NOT 再 spawn 另一个 sub-agent。直接在本轮完成工作。
|
|
10
|
+
|
|
11
|
+
## 工作流程
|
|
12
|
+
|
|
13
|
+
### Step 1: 定位 Spec
|
|
14
|
+
检查 dispatch prompt 第一行是否是 `Active Spec: <path>`。
|
|
15
|
+
如果没有,扫描 `workspace/specs/` 找到已确认状态的 Spec。
|
|
16
|
+
|
|
17
|
+
### Step 2: 读取上下文
|
|
18
|
+
1. Spec 文件 — 开发规格(必需)
|
|
19
|
+
2. PRD 文件 — 原始需求(推荐)
|
|
20
|
+
3. `.qoder/rules/code-style.md` — 代码规范
|
|
21
|
+
4. `.qoder/context/architecture.md` — 架构说明
|
|
22
|
+
5. `.qoder/context/data-dictionary.md` — 数据字典
|
|
23
|
+
|
|
24
|
+
### Step 3: 按 Spec 实现
|
|
25
|
+
严格按照 Spec 规格编码:
|
|
26
|
+
- 数据层: Entity → Mapper → Service → Controller
|
|
27
|
+
- 接口层: RESTful API,参数校验,统一返回格式
|
|
28
|
+
- 业务层: 按 Spec 的业务逻辑实现
|
|
29
|
+
- 异常处理: 按 Spec 定义的异常场景
|
|
30
|
+
|
|
31
|
+
### Step 4: 自检
|
|
32
|
+
- 所有 Spec 定义的接口都已实现
|
|
33
|
+
- 数据库字段与 Spec 一致
|
|
34
|
+
- 代码符合 code-style.md
|
|
35
|
+
|
|
36
|
+
## 编码原则
|
|
37
|
+
1. 先读后写
|
|
38
|
+
2. Spec 是契约,严格实现
|
|
39
|
+
3. 发现 Spec 问题提出建议,不自行修改
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
[features]
|
|
43
|
+
multi_agent = false
|
|
44
|
+
|
|
45
|
+
[features.multi_agent_v2]
|
|
46
|
+
enabled = false
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name = "qoder-spec-gen"
|
|
2
|
+
description = "从 PRD 自动生成开发 Spec 的 sub-agent,读取 PRD + 团队规范输出到 workspace/specs/。"
|
|
3
|
+
sandbox_mode = "workspace-write"
|
|
4
|
+
|
|
5
|
+
developer_instructions = """
|
|
6
|
+
你是 QODER 研发流水线的 Spec 生成器。
|
|
7
|
+
|
|
8
|
+
## 递归守卫
|
|
9
|
+
- 你 MUST NOT 再 spawn 另一个 sub-agent。直接在本轮完成工作。
|
|
10
|
+
- 你已经被主 session dispatch 了,直接执行即可。
|
|
11
|
+
|
|
12
|
+
## 工作流程
|
|
13
|
+
|
|
14
|
+
### Step 1: 定位 PRD
|
|
15
|
+
检查 dispatch prompt 第一行是否是 `Active PRD: <path>`。
|
|
16
|
+
如果没有,扫描 `workspace/specs/` 目录找到最新的未生成 Spec 的 PRD。
|
|
17
|
+
|
|
18
|
+
### Step 2: 读取上下文
|
|
19
|
+
必须读取以下文件:
|
|
20
|
+
1. PRD 文件 — 需求来源
|
|
21
|
+
2. `.qoder/rules/spec-template.md` — Spec 结构模板
|
|
22
|
+
3. `.qoder/rules/code-style.md` — 命名规范
|
|
23
|
+
4. `.qoder/context/architecture.md` — 项目架构
|
|
24
|
+
5. `.qoder/context/data-dictionary.md` — 数据字典(如存在)
|
|
25
|
+
|
|
26
|
+
### Step 3: 生成 Spec
|
|
27
|
+
按 spec-template.md 的结构,从 PRD 提取:
|
|
28
|
+
- 每个用户故事 → API 接口
|
|
29
|
+
- 验收标准 → 接口输入/输出/异常
|
|
30
|
+
- 数据需求 → 数据库表设计
|
|
31
|
+
- 非功能需求 → 约束章节
|
|
32
|
+
|
|
33
|
+
### Step 4: 输出
|
|
34
|
+
写入 `workspace/specs/REQ-{ID}-{模块名}.md`
|
|
35
|
+
完成后汇报:文件列表、与 PRD 的映射关系、需要开发关注的点。
|
|
36
|
+
|
|
37
|
+
## 规则
|
|
38
|
+
- Spec 必须与 PRD 验收标准一一对应
|
|
39
|
+
- 接口路径 RESTful,表名遵循 `t_{模块}_{实体}`
|
|
40
|
+
- 金额字段必须 BigDecimal
|
|
41
|
+
- 不允许出现 PRD 中没有的功能
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
[features]
|
|
45
|
+
multi_agent = false
|
|
46
|
+
|
|
47
|
+
[features.multi_agent_v2]
|
|
48
|
+
enabled = false
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name = "qoder-test-gen"
|
|
2
|
+
description = "基于实现代码和 Spec 自动生成单元测试的 sub-agent,输出到 tests/ 目录。"
|
|
3
|
+
sandbox_mode = "workspace-write"
|
|
4
|
+
|
|
5
|
+
developer_instructions = """
|
|
6
|
+
你是 QODER 研发流水线的测试生成器。
|
|
7
|
+
|
|
8
|
+
## 递归守卫
|
|
9
|
+
- 你 MUST NOT 再 spawn 另一个 sub-agent。直接在本轮完成工作。
|
|
10
|
+
|
|
11
|
+
## 工作流程
|
|
12
|
+
|
|
13
|
+
### Step 1: 定位目标代码
|
|
14
|
+
检查 dispatch prompt 第一行是否是 `Active Code: <path>`。
|
|
15
|
+
如果没有,根据最新的 Spec 找到对应实现代码。
|
|
16
|
+
|
|
17
|
+
### Step 2: 读取上下文
|
|
18
|
+
1. 实现代码 — 被测代码(必需)
|
|
19
|
+
2. Spec 文件 — 测试要点映射(推荐)
|
|
20
|
+
3. `.qoder/rules/testing.md` — 测试规范(必需)
|
|
21
|
+
4. `.qoder/rules/code-style.md` — 代码规范
|
|
22
|
+
|
|
23
|
+
### Step 3: 生成测试
|
|
24
|
+
按 testing.md 规范生成:
|
|
25
|
+
- Service 层: Mock 所有依赖,Given-When-Then 模式
|
|
26
|
+
- Controller 层: MockMvc 测试
|
|
27
|
+
- 每个测试有 @DisplayName
|
|
28
|
+
- 断言使用 AssertJ
|
|
29
|
+
- 测试数据使用 Builder 模式
|
|
30
|
+
|
|
31
|
+
### Step 4: 输出
|
|
32
|
+
测试文件路径: `tests/{包路径}/{类名}Test.java`
|
|
33
|
+
命名: `{被测类名}Test.java`
|
|
34
|
+
|
|
35
|
+
完成后汇报:测试文件列表、覆盖的方法、预计覆盖率。
|
|
36
|
+
|
|
37
|
+
## 测试原则
|
|
38
|
+
1. 正向路径 100%,异常路径 100%
|
|
39
|
+
2. 核心业务边界条件全覆盖
|
|
40
|
+
3. 不依赖外部系统(全 Mock)
|
|
41
|
+
4. 测试方法之间无依赖顺序
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
[features]
|
|
45
|
+
multi_agent = false
|
|
46
|
+
|
|
47
|
+
[features.multi_agent_v2]
|
|
48
|
+
enabled = false
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Spec Generator Agent
|
|
2
|
+
|
|
3
|
+
## Required: Load Context First (Pull-Based)
|
|
4
|
+
Load task context yourself.
|
|
5
|
+
|
|
6
|
+
## Recursion Guard
|
|
7
|
+
You are the spec-generator. Do NOT spawn another spec-generator.
|
|
8
|
+
|
|
9
|
+
## Your Role
|
|
10
|
+
Generate technical Spec from PRD + Design.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
1. Read PRD from workspace/specs/prd/ or task dir
|
|
14
|
+
2. Read design artifacts from workspace/tasks/{id}/design/
|
|
15
|
+
3. Read team rules from workspace/constitution/
|
|
16
|
+
4. Generate spec.md covering:
|
|
17
|
+
- Architecture changes
|
|
18
|
+
- Data model changes
|
|
19
|
+
- API changes
|
|
20
|
+
- Implementation plan
|
|
21
|
+
5. Save to workspace/specs/ or workspace/tasks/{id}/spec.md
|
|
@@ -36,8 +36,8 @@ This single command does ALL of:
|
|
|
36
36
|
6. 检查周五自动构建状态, 给出本系统的设置命令
|
|
37
37
|
|
|
38
38
|
After doctor finishes:
|
|
39
|
-
-
|
|
40
|
-
-
|
|
39
|
+
- init_developer auto-registers identity (member.json + signing key)
|
|
40
|
+
- No separate "team.py add" needed anymore
|
|
41
41
|
|
|
42
42
|
## Incremental Guarantee (为什么不会重头再来)
|
|
43
43
|
|
|
@@ -187,12 +187,18 @@ Follow .qoder/agents/prd-planning.md:
|
|
|
187
187
|
|
|
188
188
|
---
|
|
189
189
|
|
|
190
|
-
## Quick Mode
|
|
190
|
+
## Quick Mode (极速 — 3 步完成)
|
|
191
|
+
|
|
192
|
+
> 触发:"快速""quick""加个字段""小改动""加个按钮"
|
|
193
|
+
> 小功能专用。砍掉所有非必要步骤。
|
|
191
194
|
|
|
192
195
|
Follow .qoder/agents/prd-quick.md:
|
|
193
|
-
1.
|
|
194
|
-
2.
|
|
195
|
-
3.
|
|
196
|
+
1. **一次取全**:`context_pack.py`(1 次调用,不要再单独 search)
|
|
197
|
+
2. **一次生成**:Mini-PRD + 微型原型(直接 Write,不分步)
|
|
198
|
+
3. **一次确认**:问用户"可以吗"→ 确认后 push
|
|
199
|
+
|
|
200
|
+
> Quick 模式**跳过**:EVA 评估、历史 PRD、网络搜索、style JSON 查颜色。
|
|
201
|
+
> 原型直接从模板改 diff,模板已含正确颜色。
|
|
196
202
|
|
|
197
203
|
---
|
|
198
204
|
|
|
@@ -115,6 +115,12 @@ def _save_cache(key, content):
|
|
|
115
115
|
with open(tmp, 'w', encoding='utf-8') as f:
|
|
116
116
|
f.write(content)
|
|
117
117
|
os.replace(tmp, cache_path)
|
|
118
|
+
# LRU 清理: 保留最新 30 个, 删更老的
|
|
119
|
+
try:
|
|
120
|
+
from search_index import _cleanup_cache_dir
|
|
121
|
+
_cleanup_cache_dir(cache_dir, 'ctx-cache-', max_files=30)
|
|
122
|
+
except Exception:
|
|
123
|
+
pass
|
|
118
124
|
except OSError:
|
|
119
125
|
pass
|
|
120
126
|
|
|
@@ -185,6 +185,32 @@ def search_keywords(query, platform=None):
|
|
|
185
185
|
with open(tmp, 'w', encoding='utf-8') as f:
|
|
186
186
|
f.write(output)
|
|
187
187
|
os.replace(tmp, cache_path)
|
|
188
|
+
# LRU 清理: 保留最新 50 个缓存文件, 删更老的
|
|
189
|
+
_cleanup_cache_dir(cache_dir, 'search-cache-', max_files=50)
|
|
190
|
+
except OSError:
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def _cleanup_cache_dir(cache_dir, prefix, max_files=50):
|
|
195
|
+
"""清理缓存目录, 只保留最新 max_files 个匹配 prefix 的文件。"""
|
|
196
|
+
try:
|
|
197
|
+
files = [f for f in os.listdir(cache_dir) if f.startswith(prefix)]
|
|
198
|
+
if len(files) <= max_files:
|
|
199
|
+
return
|
|
200
|
+
# 按 mtime 降序排, 删掉超出部分的
|
|
201
|
+
files_with_mtime = []
|
|
202
|
+
for f in files:
|
|
203
|
+
p = os.path.join(cache_dir, f)
|
|
204
|
+
try:
|
|
205
|
+
files_with_mtime.append((os.path.getmtime(p), p))
|
|
206
|
+
except OSError:
|
|
207
|
+
continue
|
|
208
|
+
files_with_mtime.sort(reverse=True)
|
|
209
|
+
for _, p in files_with_mtime[max_files:]:
|
|
210
|
+
try:
|
|
211
|
+
os.remove(p)
|
|
212
|
+
except OSError:
|
|
213
|
+
pass
|
|
188
214
|
except OSError:
|
|
189
215
|
pass
|
|
190
216
|
|
|
@@ -208,6 +208,50 @@ def scan_secrets(file_paths: List[str], repo_root: str) -> None:
|
|
|
208
208
|
raise SecretFound("\n".join(lines))
|
|
209
209
|
|
|
210
210
|
|
|
211
|
+
# ============================================================
|
|
212
|
+
# 3.6 平台标注门禁 (PRD 必须标注目标平台, 防 prompt 失效)
|
|
213
|
+
# ============================================================
|
|
214
|
+
|
|
215
|
+
# 合法平台关键词 (出现在 PRD 内容里即视为已标注)
|
|
216
|
+
_PLATFORM_KEYWORDS = [
|
|
217
|
+
'web', 'pc', '管理端', 'fywl-ui', 'fywl_ui', 'vben', 'ant design',
|
|
218
|
+
'app', 'h5', '移动端', 'carmg', 'vant',
|
|
219
|
+
'两端', '双端', 'both',
|
|
220
|
+
'后端', 'backend', '无前端',
|
|
221
|
+
]
|
|
222
|
+
|
|
223
|
+
def check_platform_gate(prd_paths: List[str], repo_root: str) -> None:
|
|
224
|
+
"""检查 PRD 文件是否标注了目标平台。未标注抛 GateFailure。
|
|
225
|
+
|
|
226
|
+
这是 /wl-prd "先问平台" 的程序级兜底:
|
|
227
|
+
如果 AI 没问平台就生成了 PRD, push 时这里会拦住。
|
|
228
|
+
"""
|
|
229
|
+
missing = []
|
|
230
|
+
for prd in prd_paths:
|
|
231
|
+
try:
|
|
232
|
+
# 只读前 4KB (头部元数据区通常在这里)
|
|
233
|
+
with open(prd, 'r', encoding='utf-8', errors='replace') as f:
|
|
234
|
+
head = f.read(4096)
|
|
235
|
+
except OSError:
|
|
236
|
+
continue # 文件读不了, 跳过 (不因 IO 错误阻塞)
|
|
237
|
+
head_lower = head.lower()
|
|
238
|
+
# 检查是否包含任一平台关键词
|
|
239
|
+
found = any(kw in head_lower for kw in _PLATFORM_KEYWORDS)
|
|
240
|
+
if not found:
|
|
241
|
+
missing.append(os.path.basename(prd))
|
|
242
|
+
|
|
243
|
+
if missing:
|
|
244
|
+
raise GateFailure(
|
|
245
|
+
"[gate] 拒绝: %d 个 PRD 未标注目标平台 (违反 /wl-prd 先问平台规则):\n"
|
|
246
|
+
" %s\n"
|
|
247
|
+
"修复: 在 PRD 头部加一行:\n"
|
|
248
|
+
" - **平台**: Web管理端 (fywl-ui) # 或 APP移动端 / 两端 / 后端" % (
|
|
249
|
+
len(missing),
|
|
250
|
+
'\n '.join(missing[:5]),
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
211
255
|
# ============================================================
|
|
212
256
|
# 4. EVA 门禁 (PRD 质量校验)
|
|
213
257
|
# ============================================================
|
|
@@ -223,11 +267,8 @@ def check_eval_gate(
|
|
|
223
267
|
"""
|
|
224
268
|
if skip_eval or not prd_paths:
|
|
225
269
|
return
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
except ImportError:
|
|
229
|
-
# eval_api 还没建 (阶段 1.2 建), 跳过不阻塞
|
|
230
|
-
return
|
|
270
|
+
# 硬 import: eval_api 是必需模块,缺失说明引擎损坏,应报错而非静默跳过
|
|
271
|
+
from common.eval_api import evaluate
|
|
231
272
|
|
|
232
273
|
failures = []
|
|
233
274
|
for prd in prd_paths:
|
|
@@ -260,7 +301,7 @@ def check_eval_gate(
|
|
|
260
301
|
lines.append(" %s %s" % (prd, reason))
|
|
261
302
|
issues_all.append("%s: %s" % (prd, reason))
|
|
262
303
|
lines.append("修复 PRD 后重试, 或 admin 用 --skip-eval 跳过 (会记录审计)")
|
|
263
|
-
# D2: 飞书通知 EVA 拒绝
|
|
304
|
+
# D2: 飞书通知 EVA 拒绝 (best-effort, 失败不阻塞门禁)
|
|
264
305
|
try:
|
|
265
306
|
from common.feishu import notify_eval_rejected
|
|
266
307
|
notify_eval_rejected(
|
|
@@ -268,8 +309,8 @@ def check_eval_gate(
|
|
|
268
309
|
title="批量 EVA 拒绝",
|
|
269
310
|
issues=issues_all,
|
|
270
311
|
)
|
|
271
|
-
except Exception:
|
|
272
|
-
|
|
312
|
+
except Exception as e:
|
|
313
|
+
print('[gate] WARN: 飞书通知失败 (不阻塞): %s' % str(e)[:80], file=sys.stderr)
|
|
273
314
|
raise GateFailure("\n".join(lines))
|
|
274
315
|
|
|
275
316
|
|
|
@@ -304,20 +345,21 @@ def run_gates(
|
|
|
304
345
|
and f.lower().endswith(".md")
|
|
305
346
|
]
|
|
306
347
|
if prd_files:
|
|
348
|
+
# 硬 import: reqid 是必需模块,缺失说明引擎损坏
|
|
349
|
+
from common.reqid import validate_req_ids, migrate_from_existing, ReqIdError
|
|
350
|
+
# 计数器缺失则先迁移 (幂等)
|
|
307
351
|
try:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
352
|
+
validate_req_ids(prd_files, repo_root)
|
|
353
|
+
except ReqIdError as e:
|
|
354
|
+
if '超过计数器最大值 0' in str(e) or 'req-counter' in str(e).lower():
|
|
355
|
+
# 计数器未初始化, 迁移后重试
|
|
356
|
+
migrate_from_existing(repo_root)
|
|
311
357
|
validate_req_ids(prd_files, repo_root)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
else:
|
|
318
|
-
raise
|
|
319
|
-
except ImportError:
|
|
320
|
-
pass # reqid 模块不可用, 跳过 (向后兼容)
|
|
358
|
+
else:
|
|
359
|
+
raise
|
|
360
|
+
# 4.5 平台标注门禁 (PRD 必须标注目标平台, 防 prompt 失效)
|
|
361
|
+
if prd_files:
|
|
362
|
+
check_platform_gate(prd_files, repo_root)
|
|
321
363
|
# 5. EVA 门禁 (只对 PRD 文件)
|
|
322
364
|
check_eval_gate(prd_files, repo_root, skip_eval=skip_eval)
|
|
323
365
|
return True, ""
|
|
@@ -94,7 +94,8 @@ def _notify_prd_publications(staged_files):
|
|
|
94
94
|
import re as _re
|
|
95
95
|
try:
|
|
96
96
|
from common.feishu import notify_prd_published, is_enabled
|
|
97
|
-
except ImportError:
|
|
97
|
+
except ImportError as e:
|
|
98
|
+
print('[sync] WARN: feishu 模块缺失, 跳过 PRD 发布通知: %s' % e, file=sys.stderr)
|
|
98
99
|
return
|
|
99
100
|
if not is_enabled('prd_published'):
|
|
100
101
|
return
|
|
@@ -141,6 +142,13 @@ def report_conflict(stderr):
|
|
|
141
142
|
if r.returncode != 0:
|
|
142
143
|
print('WARNING: rebase --abort 失败 (rc={}): {}'.format(r.returncode, (r.stderr or '').strip()[:120]))
|
|
143
144
|
print('仓库可能处于半 rebase 状态。AI 请手动跑: git rebase --abort')
|
|
145
|
+
# autostash 风险检查: --autostash 可能在 abort 后留下未弹回的 stash
|
|
146
|
+
stash_r = git('stash', 'list')
|
|
147
|
+
if stash_r.returncode == 0 and stash_r.stdout.strip():
|
|
148
|
+
stash_count = len([l for l in stash_r.stdout.strip().split('\n') if l.strip()])
|
|
149
|
+
print('WARNING: 检测到 {} 个 stash (可能是 autostash 未弹回)!'.format(stash_count))
|
|
150
|
+
print(' 查看 stash: git stash list')
|
|
151
|
+
print(' 恢复改动: git stash pop (如果包含你的草稿)')
|
|
144
152
|
print('SYNC_CONFLICT: 自动同步遇到冲突, 已安全回退 (本地产出未丢失)。')
|
|
145
153
|
branch = current_branch()
|
|
146
154
|
print('AI 请按以下步骤解决冲突:')
|