From a89a70a98395acd98e09faabeecb6b05951cee4e Mon Sep 17 00:00:00 2001 From: cfdaily Date: Sun, 14 Jun 2026 11:51:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Gitea=20=E5=8D=8F=E4=BD=9C=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E8=90=BD=E5=9C=B0=20=E2=80=94=20=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E5=89=8D=E7=BC=80+Label+=E6=A8=A1=E6=9D=BF+L2=E6=B3=A8?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/ISSUE_TEMPLATE/bug.yml | 34 +++++++ .gitea/ISSUE_TEMPLATE/feature.yml | 27 ++++++ .gitea/ISSUE_TEMPLATE/test.yml | 20 +++++ .gitea/PULL_REQUEST_TEMPLATE.md | 26 ++++++ docs/design/13-toolchain-and-dev-workflow.md | 93 ++++++++++++++++++-- src/blackboard/db.py | 1 + src/daemon/mail_handler.py | 4 +- src/daemon/prompt_composer.py | 23 +++++ src/daemon/task_handler.py | 5 +- src/daemon/toolchain_handler.py | 5 +- 10 files changed, 223 insertions(+), 15 deletions(-) create mode 100644 .gitea/ISSUE_TEMPLATE/bug.yml create mode 100644 .gitea/ISSUE_TEMPLATE/feature.yml create mode 100644 .gitea/ISSUE_TEMPLATE/test.yml create mode 100644 .gitea/PULL_REQUEST_TEMPLATE.md diff --git a/.gitea/ISSUE_TEMPLATE/bug.yml b/.gitea/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..49a2a9b --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,34 @@ +name: Bug 报告 +about: 报告一个 Bug +title: "[moz] bug: " +labels: + - type/bug +body: + - type: textarea + id: description + attributes: + label: Bug 描述 + description: 清晰描述什么行为是错误的 + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: 复现步骤 + validations: + required: true + - type: textarea + id: expected + attributes: + label: 预期行为 + validations: + required: true + - type: dropdown + id: priority + attributes: + label: 优先级 + options: + - P0 紧急 + - P1 高 + - P2 中 + - P3 低 diff --git a/.gitea/ISSUE_TEMPLATE/feature.yml b/.gitea/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..7907536 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,27 @@ +name: 功能需求 +about: 提出一个新功能需求 +title: "[moz] feat: " +labels: + - type/feat +body: + - type: textarea + id: description + attributes: + label: 需求描述 + description: 你希望实现什么功能?为什么需要? + validations: + required: true + - type: textarea + id: solution + attributes: + label: 建议方案 + description: 如果有初步想法可以写 here + - type: dropdown + id: priority + attributes: + label: 优先级 + options: + - P0 紧急 + - P1 高 + - P2 中 + - P3 低 diff --git a/.gitea/ISSUE_TEMPLATE/test.yml b/.gitea/ISSUE_TEMPLATE/test.yml new file mode 100644 index 0000000..432d692 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/test.yml @@ -0,0 +1,20 @@ +name: 测试任务 +about: 创建一个测试任务(E2E、集成测试等) +title: "[moz] test: " +labels: + - type/test +body: + - type: textarea + id: description + attributes: + label: 测试目标 + description: 要验证什么场景? + validations: + required: true + - type: textarea + id: steps + attributes: + label: 测试步骤 + description: 关键步骤或验收标准 + validations: + required: true diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..22bae02 --- /dev/null +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +## 改动概述 + + + +## 关联 Issue + + + +## 改动类型 + +- [ ] feat: 新功能 +- [ ] impl: 实现 +- [ ] fix: 修复 +- [ ] docs: 文档 +- [ ] test: 测试 +- [ ] refactor: 重构 +- [ ] ci: CI/CD +- [ ] chore: 杂项 + +## 检查清单 + +- [ ] 标题格式正确:`[代号] type(scope): 简述` +- [ ] 改动在开发目录(`~/.openclaw/sanguo_projects/`)完成 +- [ ] 已同步到安装目录(`~/.sanguo_projects/`) +- [ ] 已运行测试(如适用) +- [ ] 已更新相关设计文档(如适用) diff --git a/docs/design/13-toolchain-and-dev-workflow.md b/docs/design/13-toolchain-and-dev-workflow.md index a6bc3e3..269550e 100644 --- a/docs/design/13-toolchain-and-dev-workflow.md +++ b/docs/design/13-toolchain-and-dev-workflow.md @@ -245,11 +245,14 @@ pm2 show sanguo-act-runner # 详情 |------|------| | `feat` | 新功能 | | `fix` | Bug 修复 | +| `impl` | 按设计文档实现 | | `refactor` | 重构(不改行为) | | `test` | 测试相关 | | `docs` | 文档 | | `chore` | 构建/工具/配置 | +sanguo 组织所有仓库统一使用此 commit 规范。 + --- ## §4. 问题管理 @@ -266,15 +269,19 @@ pm2 show sanguo-act-runner # 详情 ### 4.2 Issue 标签体系 -| 标签 | 颜色 | 说明 | -|------|------|------| -| `bug` | 红 | 功能异常 | -| `feature` | 蓝 | 新功能需求 | -| `improvement` | 绿 | 改进优化 | -| `security` | 橙 | 安全相关 | -| `risk:high/standard/low` | 分级色 | 风险级别(见 §6.1 判定规则) | -| `priority:high/medium/low` | 黄/灰 | 优先级 | -| `blocked` | 紫 | 阻塞中 | +| 标签 | 颜色 | 色值 | 说明 | +|------|------|------|------| +| `type/bug` | 红 | #ee0701 | Bug 修复 | +| `type/feat` | 蓝 | #84b6eb | 新功能 | +| `type/impl` | 浅蓝 | #c5def5 | 按设计实现 | +| `type/docs` | 黄 | #fbca04 | 文档 | +| `type/test` | 绿 | #0e8a16 | 测试 | +| `type/ci` | 紫 | #d4c5f9 | CI/CD | +| `type/refactor` | 橙 | #ff6f00 | 重构 | +| `priority/P0` | 深红 | #b60205 | 紧急 | +| `priority/P1` | 红 | #d93f0b | 高 | +| `priority/P2` | 黄 | #fbca04 | 中 | +| `priority/P3` | 浅蓝 | #c5def5 | 低 | ### 4.3 需求/问题 Review 前置 @@ -296,6 +303,29 @@ Open → In Progress → Review → Closed └──── Reopened ←───────────────────┘ ``` +### 4.5 标题规范 + +所有 Issue 和 PR 标题**必须**包含项目代号前缀,让人类一眼识别项目+类型: + +**Issue**: `[代号] type: 简述` +**PR**: `[代号] type(scope): 简述` + +项目代号: + +| 仓库 | 代号 | +|------|------| +| sanguo_moziplus_v2 | moz | +| sanguo_quant_live | quant | +| sanguo_vnpy | vnpy | + +示例: +- `[moz] bug: Mail API 500 when comment_type invalid` +- `[moz] impl(daemon): 知识注入 L2 引擎层 — WikiGuideSection` +- `[quant] feat: 趋势跟踪策略骨架` + +此规范通过 L2 引擎层 `GiteaConventionSection`(priority=55)自动注入所有 Agent prompt。 +完整规范文档:L3 Skill `gitea-conventions`。 + --- ## §5. CI/CD 管道设计 @@ -3297,3 +3327,48 @@ async def _handle_issue_comment(payload): |------|------|------| | 2026-06-09 | v1.0 | 初版:E2E 真实场景暴露问题 → 四层改造方案 + @mention 通知 + Mail type 改造 | +--- + +## §26. Gitea 协作规范落地 + +> **状态**: ✅ 已完成 +> **日期**: 2026-06-14 +> **PR**: 本次改动随 PR 提交 + +### 26.1 动机 + +团队三个仓库(moziplus_v2 / quant_live / vnpy)缺少统一的 Issue/PR 模板、Label 体系和标题规范。人类从标题无法一眼分辨是哪个项目什么类型的问题。 + +### 26.2 落地内容 + +| 层级 | 内容 | 说明 | +|------|------|------| +| L3 | `gitea-conventions` Skill | 完整规范文档(标题/分支/commit/label) | +| L2 | `GiteaConventionSection`(priority=55) | 注入所有 handler(task/toolchain/mail),自动提醒 Agent 遵循标题格式 | +| L1 | TOOLS.md 追加代号表 | Agent 静态可见的速查 | +| Gitea 模板 | 3 仓库 × 4 文件 | bug.yml / feature.yml / test.yml / PULL_REQUEST_TEMPLATE.md | +| Gitea Labels | 3 仓库 × 11 个 | type × 7 + priority × 4 | + +### 26.3 四层注入路径 + +``` +L1 TOOLS.md(静态,Agent workspace) + → 代号表 + 格式速查 + +L2 GiteaConventionSection(动态,每次 spawn 注入) + → "创建 Issue/PR 时标题必须带 [代号] 前缀" + +L3 gitea-conventions Skill(被动,extraDirs 自动发现) + → 完整规范:标题/分支/commit/label/模板 +``` + +### 26.4 代码改动 + +| 文件 | 改动 | +|------|------| +| `prompt_composer.py` | 新增 `GiteaConventionSection`(priority=55) | +| `task_handler.py` | `get_sections()` 注册 `GiteaConventionSection()` | +| `toolchain_handler.py` | `get_sections()` 注册 `GiteaConventionSection()` | +| `mail_handler.py` | `get_sections()` 注册 `GiteaConventionSection()` | +| `db.py` | `COMMENT_TYPES` 补 `action_report`(修 API 500 bug) | + diff --git a/src/blackboard/db.py b/src/blackboard/db.py index e92aaeb..f2dc012 100644 --- a/src/blackboard/db.py +++ b/src/blackboard/db.py @@ -209,6 +209,7 @@ VALID_TRANSITIONS = { COMMENT_TYPES = frozenset({ "general", "handoff", "observation", "review", "rebuttal", "rebuttal_response", "debate_argument", "debate_rebuttal", "debate_judgment", + "action_report", }) SEVERITY_LEVELS = frozenset({"blocking", "warning", "info", "audit"}) diff --git a/src/daemon/mail_handler.py b/src/daemon/mail_handler.py index f4ba37a..bae70ac 100644 --- a/src/daemon/mail_handler.py +++ b/src/daemon/mail_handler.py @@ -9,7 +9,7 @@ import logging from pathlib import Path from src.daemon.base_task_handler import BaseTaskHandler, VerifyResult -from src.daemon.prompt_composer import PromptComposer, PromptContext, WikiGuideSection +from src.daemon.prompt_composer import PromptComposer, PromptContext, GiteaConventionSection, WikiGuideSection from src.blackboard.db import get_connection logger = logging.getLogger("moziplus-v2.handler.mail") @@ -36,7 +36,7 @@ class MailHandler(BaseTaskHandler): return composer.compose(context) def get_sections(self) -> list: - return [MailContextSection(), MailApiSection(), MailConstraintsSection(), WikiGuideSection()] + return [MailContextSection(), MailApiSection(), MailConstraintsSection(), GiteaConventionSection(), WikiGuideSection()] def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult: """Mail 完成验证:区分 inform/request。 diff --git a/src/daemon/prompt_composer.py b/src/daemon/prompt_composer.py index 2cef4ff..b355442 100644 --- a/src/daemon/prompt_composer.py +++ b/src/daemon/prompt_composer.py @@ -129,6 +129,29 @@ class PromptComposer: return result +# --------------------------------------------------------------------------- +class GiteaConventionSection: + """Gitea 标题规范引导段 — 提醒 Agent 创建 Issue/PR 时遵循标题格式。""" + + name: str = "gitea_convention" + priority: int = 55 # CONSTRAINTS(50) 和 EXTENSION(60) 之间 + + CONVENTION_TEXT = ( + "## Gitea 标题规范\n" + "创建 Issue/PR 时,标题**必须**包含项目代号前缀:\n" + "- Issue: `[代号] type: 简述`,如 `[moz] bug: Mail API 500`\n" + "- PR: `[代号] type(scope): 简述`,如 `[moz] impl(daemon): WikiGuideSection 注入`\n" + "代号:moz=moziplus_v2, quant=quant_live, vnpy=vnpy\n" + "type: bug/feat/impl/fix/docs/test/ci/refactor/chore" + ) + + def render(self, context: "PromptContext") -> str: + return self.CONVENTION_TEXT + + def should_include(self, context: "PromptContext") -> bool: + return True + + # --------------------------------------------------------------------------- # WikiGuideSection — 知识查询引导段 # --------------------------------------------------------------------------- diff --git a/src/daemon/task_handler.py b/src/daemon/task_handler.py index 191565a..ea3dccb 100644 --- a/src/daemon/task_handler.py +++ b/src/daemon/task_handler.py @@ -10,7 +10,7 @@ from pathlib import Path from typing import Dict, Optional from src.daemon.base_task_handler import BaseTaskHandler, VerifyResult -from src.daemon.prompt_composer import PromptComposer, PromptContext, WikiGuideSection +from src.daemon.prompt_composer import PromptComposer, PromptContext, GiteaConventionSection, WikiGuideSection from src.blackboard.db import get_connection logger = logging.getLogger("moziplus-v2.handler") @@ -306,13 +306,14 @@ class TaskHandler(BaseTaskHandler): return True def get_sections(self) -> list: - """返回 5 个 PromptSection 实例。""" + """返回 PromptSection 实例。""" return [ TaskContextSection(), PriorOutputsSection(), RoleSkillSection(), TaskApiSection(), TaskConstraintsSection(), + GiteaConventionSection(), WikiGuideSection(), ] diff --git a/src/daemon/toolchain_handler.py b/src/daemon/toolchain_handler.py index 8e0c357..bcde084 100644 --- a/src/daemon/toolchain_handler.py +++ b/src/daemon/toolchain_handler.py @@ -13,7 +13,7 @@ from pathlib import Path from typing import Dict, List from src.daemon.base_task_handler import BaseTaskHandler, VerifyResult -from src.daemon.prompt_composer import PromptComposer, PromptContext, WikiGuideSection +from src.daemon.prompt_composer import PromptComposer, PromptContext, GiteaConventionSection, WikiGuideSection from src.daemon.toolchain_templates import render_template, _TEMPLATE_MAP from src.blackboard.db import get_connection @@ -221,11 +221,12 @@ class ToolchainHandler(BaseTaskHandler): return self._auto_mark_working(task_id, db_path) def get_sections(self) -> list: - """返回 3 个 Toolchain PromptSection 实例""" + """返回 Toolchain PromptSection 实例""" return [ ToolchainContextSection(), ToolchainApiSection(), ToolchainConstraintsSection(), + GiteaConventionSection(), WikiGuideSection(), ]