Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ea43d76e3 | |||
| 09520a414e | |||
| 9388f3ecc1 | |||
| cdc49ac74d | |||
| f74ae30d41 | |||
| 67b504c5db | |||
| 230b8c9cd9 | |||
| 5b73319aaf | |||
| 8c7c277167 | |||
| 999cd1cc10 | |||
| 0475e40529 | |||
| ca9b750656 | |||
| 7e832ee865 | |||
| 1c7be0e782 | |||
| 49d0b3a789 | |||
| 5505ac9c5c | |||
| f5bf671410 | |||
| ccb5d5d3ea | |||
| ee825db818 | |||
| cdf984aa0c | |||
| 6798f098b5 | |||
| 33e38254c1 |
@@ -26,6 +26,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
run: |
|
run: |
|
||||||
|
rm -rf /tmp/ci-venv-lint
|
||||||
python3 -m venv /tmp/ci-venv-lint
|
python3 -m venv /tmp/ci-venv-lint
|
||||||
/tmp/ci-venv-lint/bin/pip install --quiet --upgrade pip
|
/tmp/ci-venv-lint/bin/pip install --quiet --upgrade pip
|
||||||
/tmp/ci-venv-lint/bin/pip install --quiet flake8
|
/tmp/ci-venv-lint/bin/pip install --quiet flake8
|
||||||
|
|||||||
@@ -391,7 +391,11 @@ def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult:
|
|||||||
|
|
||||||
#### 完整设计
|
#### 完整设计
|
||||||
|
|
||||||
三分路的详细伪代码、失败上限、决策依据见 §5.2.1~§5.2.3(on_failure 分路处理详细设计)。
|
三分路的详细设计见 §6.4(基础设施 Issue 转交流程)和 toolchain_handler.py 实现(`_handle_infrastructure_failure` / `_classify_failure`)。
|
||||||
|
|
||||||
|
#### 首次 steps 分支指引
|
||||||
|
|
||||||
|
三分路是 verify 失败后的兜底机制。此外,ci_failure 和 deploy_failure 的首次 toolchain task steps 中**已包含分支指引**——agent 在执行过程中自行判断失败原因,如果是基础设施问题则直接创建 Issue 指派 jiangwei-infra(见 §6.4)。三分路作为第二道防线,覆盖 agent 未正确判断或未执行分支的情况。
|
||||||
|
|
||||||
### 5.3 action_report comment 格式
|
### 5.3 action_report comment 格式
|
||||||
|
|
||||||
@@ -431,9 +435,9 @@ Agent 可能写了 action_report 但没真做。缓解机制:
|
|||||||
| Review 请求 → reviewer | review_request | toolchain | 4 步 | 读 diff + 审查 + 提交 Review + report |
|
| Review 请求 → reviewer | review_request | toolchain | 4 步 | 读 diff + 审查 + 提交 Review + report |
|
||||||
| Review 有新提交 → reviewer | review_updated | toolchain | 4 步 | 读 diff + 检查修改 + 提交 Review + report |
|
| Review 有新提交 → reviewer | review_updated | toolchain | 4 步 | 读 diff + 检查修改 + 提交 Review + report |
|
||||||
| Review 评论 → PR 作者 | review_comment | toolchain | 3 步 | 查看评论 + 响应(修改/回复)+ report |
|
| Review 评论 → PR 作者 | review_comment | toolchain | 3 步 | 查看评论 + 响应(修改/回复)+ report |
|
||||||
| CI 失败 → PR 作者 | ci_failure | toolchain | 4 步 | 查 CI 日志 + 修测试 + push + report |
|
| CI 失败 → PR 作者 | ci_failure | toolchain | 3 步 | 查 CI 日志 + 分支判断(代码问题自己修 / 基础设施问题提 Issue 给姜维)+ report |
|
||||||
| Issue 指派 → 开发者 | issue_assigned | toolchain | 6 步 | 创建分支 + 编码 + push + CI + PR + report |
|
| Issue 指派 → 开发者 | issue_assigned / infrastructure_failure | toolchain | 6 步(编码,含具体 git 命令)或 4 步(运维) | 按 label 分流:type/infrastructure → 运维排查;其他 → git checkout main/pull → 创建分支 → 编码 → push → CI → PR + report |
|
||||||
| 部署失败 → 运维 | deploy_failure | toolchain | 4 步 | 查日志 + 排查 + 修+重部署 + report |
|
| 部署失败 → 运维 | deploy_failure | toolchain | 3 步 | 查日志 + 分支判断(代码/配置问题自己修 / 基础设施问题提 Issue 给姜维)+ report |
|
||||||
| @mention → 被@者 | mention | toolchain | 按 guidance | 按 mention 模板的 response_guidance + report |
|
| @mention → 被@者 | mention | toolchain | 按 guidance | 按 mention 模板的 response_guidance + report |
|
||||||
| PR 合并 → PR 作者 | review_merged | toolchain | 0 步 | 纯通知,走 _send_toolchain_task(steps 为空,verify 始终通过) |
|
| PR 合并 → PR 作者 | review_merged | toolchain | 0 步 | 纯通知,走 _send_toolchain_task(steps 为空,verify 始终通过) |
|
||||||
|
|
||||||
@@ -502,29 +506,46 @@ event_type: ci_failure
|
|||||||
action_type: ci_failure
|
action_type: ci_failure
|
||||||
steps:
|
steps:
|
||||||
1. 查看完整 CI 日志(PR 页面或 Gitea Actions 页面)
|
1. 查看完整 CI 日志(PR 页面或 Gitea Actions 页面)
|
||||||
2. 修复失败的测试
|
2. 根据 CI 日志判断失败原因类型:
|
||||||
3. push → CI 自动重跑
|
a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑
|
||||||
4. 提交 action report
|
b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure
|
||||||
|
3. 提交 action report — 报告中说明判断的原因类型和执行的操作
|
||||||
context:
|
context:
|
||||||
pr_number, repo, branch, error_summary
|
pr_number, repo, branch, error_summary
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**分支设计说明**:原设计假设"CI 失败 = 代码问题",steps 只有"修测试 + push"一条路径。实际运行中发现 CI 失败可能是 runner 环境故障(如 ensurepip 失败),agent 判断为基础设施问题后不知道该做什么。现在 steps 中明确两条分支,agent 自行判断后走对应路径。
|
||||||
|
|
||||||
#### Issue 指派 → 开发者
|
#### Issue 指派 → 开发者
|
||||||
|
|
||||||
```
|
```
|
||||||
event_type: issue_assigned
|
event_type: issue_assigned 或 infrastructure_failure
|
||||||
action_type: issue_assigned
|
action_type: issue_assigned 或 infrastructure_failure
|
||||||
steps:
|
steps(按 label 分流):
|
||||||
1. 创建分支 fix/{issue_number}-{brief}
|
|
||||||
|
# 默认路径(编码任务):
|
||||||
|
1. 在开发目录执行 git 操作:
|
||||||
|
a. git checkout main && git pull origin main (确保从最新代码分叉)
|
||||||
|
b. git checkout -b fix/{issue_number}-{brief} (创建功能分支)
|
||||||
2. 编码 + 写 UT
|
2. 编码 + 写 UT
|
||||||
3. push → 等 CI
|
3. git add -A && git commit -m "[moz] fix: {简述}" && git push origin fix/{issue_number}-{brief}
|
||||||
4. CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls)
|
4. CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls,head: fix/{issue_number}-{brief}, base: main)
|
||||||
5. 等 Review
|
5. 等 Review
|
||||||
6. 提交 action report
|
6. 提交 action report
|
||||||
|
|
||||||
|
# type/infrastructure label 路径(运维任务):
|
||||||
|
1. 根据 Issue body 中的错误来源和日志片段排查问题
|
||||||
|
2. 修复基础设施问题(如修复 CI runner 环境、恢复网络、重启服务等)
|
||||||
|
3. 修复后在 Issue 上 comment 说明修复方式和结果
|
||||||
|
4. 提交 action report
|
||||||
context:
|
context:
|
||||||
issue_number, repo, issue_title, labels, issue_body, brief
|
issue_number, repo, issue_title, labels, issue_body, brief
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**label 分流说明**:issue_assigned handler 检查 label 中是否包含 `type/infrastructure`。如果是,走运维排查 steps(event_type 设为 infrastructure_failure,verify 始终 auto-pass 防递归);否则走编码 steps。
|
||||||
|
|
||||||
|
**编码路径 git 操作具体化说明**(§17 v3 补充):原 steps 只写「创建分支」「push」等抽象指令,agent 需要自己推导具体 git 命令。现在 steps 中写清楚完整 git 操作序列(checkout main → pull → checkout -b → commit → push),降低 agent 出错概率。系统不做分支管理(不通过 Gitea API 预创建分支),分支管理完全由 agent 自己执行。ToolchainApiSection 中新增 Git 操作说明段落作为通用参考。
|
||||||
|
|
||||||
#### 部署失败 → 运维
|
#### 部署失败 → 运维
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -532,9 +553,10 @@ event_type: deploy_failure
|
|||||||
action_type: deploy_failure
|
action_type: deploy_failure
|
||||||
steps:
|
steps:
|
||||||
1. 检查 deploy 日志
|
1. 检查 deploy 日志
|
||||||
2. 排查失败原因
|
2. 根据 deploy 日志判断失败原因类型:
|
||||||
3. 修复并重新部署
|
a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署
|
||||||
4. 提交 action report
|
b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure
|
||||||
|
3. 提交 action report — 报告中说明判断的原因类型和执行的操作
|
||||||
context:
|
context:
|
||||||
repo, commit_sha, reason
|
repo, commit_sha, reason
|
||||||
```
|
```
|
||||||
@@ -577,6 +599,89 @@ context:
|
|||||||
|
|
||||||
**spawn 说明**:review_merged 仍会触发 spawn(Agent 只需阅读通知),verify auto-pass 后标 done。未来可优化为 ticker 直接 auto-done 跳过 spawn。
|
**spawn 说明**:review_merged 仍会触发 spawn(Agent 只需阅读通知),verify auto-pass 后标 done。未来可优化为 ticker 直接 auto-done 跳过 spawn。
|
||||||
|
|
||||||
|
### 6.4 基础设施 Issue 转交流程
|
||||||
|
|
||||||
|
当 ci_failure / deploy_failure 的 agent 在调查后发现失败原因是基础设施问题(非代码问题),需要创建 Gitea Issue 指派 jiangwei-infra。
|
||||||
|
|
||||||
|
#### Issue 提在哪里
|
||||||
|
|
||||||
|
**根据问题来源决定**——哪个仓库的 CI/部署失败了,Issue 就提到那个仓库。CI runner 是全局共享的(一个 Mac mini),但 Issue 挂在触发的仓库最自然。如果 runner 故障影响多个仓库,各仓库会各自触发 ci_failure task,姜维看到任何一个 Issue 就能定位全局问题。
|
||||||
|
|
||||||
|
#### Issue 格式规范
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 问题描述
|
||||||
|
|
||||||
|
<简要描述问题现象>
|
||||||
|
|
||||||
|
## 错误来源
|
||||||
|
|
||||||
|
- 仓库: <repo>
|
||||||
|
- PR/Commit: <链接>
|
||||||
|
- CI/Deploy run: <Gitea Actions 页面链接>
|
||||||
|
|
||||||
|
## 日志关键片段
|
||||||
|
|
||||||
|
```
|
||||||
|
<错误日志摘要,不需全文,但要让排查者看到关键信息>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 判断依据
|
||||||
|
|
||||||
|
<为什么判断为基础设施问题而非代码问题>
|
||||||
|
```
|
||||||
|
|
||||||
|
**必填字段**:问题描述、错误来源(含链接)、日志片段、判断依据。Issue body 不完整会导致姜维无法高效排查。
|
||||||
|
|
||||||
|
**label 要求**:必须包含 `type/infrastructure`,用于 issue_assigned handler 分流(见下)。
|
||||||
|
|
||||||
|
#### issue_assigned handler label 分流
|
||||||
|
|
||||||
|
当 Gitea Issue 指派触发 webhook 时,issue_assigned handler 检查 label:
|
||||||
|
|
||||||
|
| label 包含 type/infrastructure | event_type | steps |
|
||||||
|
|---|---|---|
|
||||||
|
| 是 | infrastructure_failure | 运维排查:根据 Issue body 排查问题 → 修复 → Issue comment 说明修复方式 → action report |
|
||||||
|
| 否 | issue_assigned | 编码:创建分支 → 编码 → push → CI → PR → 等 Review → action report |
|
||||||
|
|
||||||
|
基础设施路径的 verify 始终 auto-pass(防递归,已有逻辑覆盖)。
|
||||||
|
|
||||||
|
⚠️ **label 分流当前为设计目标**,toolchain_handler.py 尚未实现 issue_assigned 的 label 检查。当前只有 `_handle_infrastructure_failure`(verify 失败时)创建 infrastructure_failure task。issue_assigned handler 的 label 分流在后续代码 PR 中实现。
|
||||||
|
|
||||||
|
⚠️ **label 预创建**:使用前需确认仓库中已创建名为 `type/infrastructure` 的 label。sanguo_moziplus_v2 仓库已创建(ID=98)。其他仓库使用前需先创建。
|
||||||
|
|
||||||
|
#### API 指令位置
|
||||||
|
|
||||||
|
Issue 创建的 API 调用方式(curl 示例)统一在 ToolchainApiSection 中,与 action_report / comment 指引并列。steps 指令中不重复 API 调用方式,只描述"做什么"。
|
||||||
|
|
||||||
|
#### Git 操作说明段落
|
||||||
|
|
||||||
|
ToolchainApiSection 中新增通用 Git 操作说明段落,作为 agent 执行 git 命令的参考:
|
||||||
|
|
||||||
|
```
|
||||||
|
### Git 操作说明
|
||||||
|
|
||||||
|
你的工作目录是开发目录。
|
||||||
|
标准分支操作流程:
|
||||||
|
git checkout main && git pull origin main # 从最新主干开始
|
||||||
|
git checkout -b fix/{branch_name} # 创建功能分支
|
||||||
|
# ... 写代码 ...
|
||||||
|
git add -A && git commit -m 'message' # 提交改动
|
||||||
|
git push origin {branch_name} # 推送到远程
|
||||||
|
|
||||||
|
⚠️ 不要在 main 分支上直接 commit。
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计原则**:系统不做分支管理(不预创建分支、不做 checkout),分支管理完全由 agent 自己执行。ToolchainApiSection 提供通用 git 操作参考,steps 中写清楚具体操作序列。
|
||||||
|
|
||||||
|
#### Red Flags 补充
|
||||||
|
|
||||||
|
硬约束 Red Flags 表新增一条:
|
||||||
|
|
||||||
|
| Agent 想法 | Red Flag 驳回 |
|
||||||
|
|---|---|
|
||||||
|
| "CI/部署失败不是我代码的问题,我什么也不用做" | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infra(body 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告"不是我的问题"就完事 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## §7. _send_toolchain_task 函数设计
|
## §7. _send_toolchain_task 函数设计
|
||||||
|
|||||||
@@ -465,7 +465,154 @@ IMPROVE(每周 cron,庞统执行)
|
|||||||
| S5 | 实现 IMPROVE cron:JSONL 引用追踪 + 淘汰报告(每周) | P2 | L2-L3 |
|
| S5 | 实现 IMPROVE cron:JSONL 引用追踪 + 淘汰报告(每周) | P2 | L2-L3 |
|
||||||
| S6 | 清理 deprecated 代码(skill_system.py / experience.py / self-improvement skill / SELF_IMPROVEMENT_REMINDER.md) | P3 | L1 |
|
| S6 | 清理 deprecated 代码(skill_system.py / experience.py / self-improvement skill / SELF_IMPROVEMENT_REMINDER.md) | P3 | L1 |
|
||||||
|
|
||||||
S1 和 S2 可以立即做。S3-S5 需要先确认设计文档。
|
S1 和 S2 已完成(PR #85)。S3-S5 设计见下方 §11A。
|
||||||
|
|
||||||
|
## 11A. Cron 配置方案(S3-S5 详细设计)
|
||||||
|
|
||||||
|
### 设计决策
|
||||||
|
|
||||||
|
**每个 agent 用自己的 agentId 执行 L1 cron**,不由庞统代理。
|
||||||
|
|
||||||
|
理由(对照设计目标 D4):
|
||||||
|
- L1 核心价值是"每个 agent 是自己经验的最佳蒸馏者"——agent 扫描自己的 JSONL,用自己的判断力识别信号
|
||||||
|
- 如果庞统代理,变成庞统替别人蒸馏,消除不了蒸馏者偏差(D4 要解决的正是这个问题)
|
||||||
|
- openclaw cron 原生支持 `agentId` 参数 + `sessionTarget: "isolated"`,技术上无障碍
|
||||||
|
|
||||||
|
### S3: L1 各 agent 自蒸馏 cron
|
||||||
|
|
||||||
|
6 个 agent,各创建一个 isolated cron,错开 15 分钟(和 discover-l1.md 时间表一致):
|
||||||
|
|
||||||
|
| Agent | agentId | cron 表达式 | 时区 |
|
||||||
|
|-------|---------|-----------|------|
|
||||||
|
| 张飞 | zhangfei-dev | `0 3 * * *` | Asia/Shanghai |
|
||||||
|
| 关羽 | guanyu-dev | `15 3 * * *` | Asia/Shanghai |
|
||||||
|
| 赵云 | zhaoyun-data | `30 3 * * *` | Asia/Shanghai |
|
||||||
|
| 司马懿 | simayi-challenger | `45 3 * * *` | Asia/Shanghai |
|
||||||
|
| 庞统 | pangtong-fujunshi | `0 4 * * *` | Asia/Shanghai |
|
||||||
|
| 姜维 | jiangwei-infra | `15 4 * * *` | Asia/Shanghai |
|
||||||
|
|
||||||
|
**Cron 配置规范**(每个 L1 cron job):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schedule": { "kind": "cron", "expr": "<时间>", "tz": "Asia/Shanghai" },
|
||||||
|
"sessionTarget": "isolated",
|
||||||
|
"agentId": "<agent-id>",
|
||||||
|
"payload": {
|
||||||
|
"kind": "agentTurn",
|
||||||
|
"message": "L1 自蒸馏 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/SKILL.md\n2. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/discover-l1.md\n3. 按 discover-l1.md 步骤执行自蒸馏\n4. 如有信号:蒸馏为 HOW 格式,使用 skill_workshop(action=create) 提交 draft proposal\n5. 如无有价值信号:不产出,这是正常的",
|
||||||
|
"timeoutSeconds": 600
|
||||||
|
},
|
||||||
|
"delivery": { "mode": "announce" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计要点**:
|
||||||
|
- `sessionTarget: "isolated"`:每次创建临时 session,不污染 main session context
|
||||||
|
- `delivery.mode: "announce"`:执行结果投递到 Control UI,保持可见性(早期使用 `none` 导致 cron 执行后零可见性,已修正)
|
||||||
|
- `timeoutSeconds: 600`:10 分钟足够(扫描 JSONL + 蒸馏 + 提交 proposal)
|
||||||
|
- message 指引 read SKILL.md + discover-l1.md:agent 按 references 指南执行,不依赖 memory
|
||||||
|
|
||||||
|
### S4: L2 庞统整合审查 cron
|
||||||
|
|
||||||
|
庞统的 L2 cron 在所有 L1 完成后执行(最后一个 agent 04:15 开始,L2 设在 05:00):
|
||||||
|
|
||||||
|
| 角色 | agentId | cron 表达式 | 时区 |
|
||||||
|
|------|---------|-----------|------|
|
||||||
|
| 庞统 | pangtong-fujunshi | `0 5 * * *` | Asia/Shanghai |
|
||||||
|
|
||||||
|
**Cron 配置**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schedule": { "kind": "cron", "expr": "0 5 * * *", "tz": "Asia/Shanghai" },
|
||||||
|
"sessionTarget": "isolated",
|
||||||
|
"agentId": "pangtong-fujunshi",
|
||||||
|
"payload": {
|
||||||
|
"kind": "agentTurn",
|
||||||
|
"message": "L2 整合审查 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/discover-l2.md\n2. 按 discover-l2.md 步骤执行:\n a. skill_workshop(action=list, status=pending) 获取所有 L1 draft proposals\n b. 全量数据源扫描,识别跨 agent 共性模式\n c. 逐个审查 proposal:approve / merge / reject\n d. 全局提升检查(Recurrence-Count >= 3 的经验提升为规则)\n e. 知识缺口反馈到 knowledge-gaps.md",
|
||||||
|
"timeoutSeconds": 1200
|
||||||
|
},
|
||||||
|
"delivery": { "mode": "announce" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计要点**:
|
||||||
|
- `delivery.mode: "announce"`:审查决策结果投递到 Control UI,主公可见
|
||||||
|
- `timeoutSeconds: 1200`(20 分钟):L2 需要扫描全量数据源 + 审查多个 proposal,时间更长
|
||||||
|
- 庞统可以访问所有 agent 的 JSONL 和 skill_workshop proposals
|
||||||
|
|
||||||
|
### S5: IMPROVE 每周引用追踪 cron
|
||||||
|
|
||||||
|
庞统每周日 06:00 执行引用追踪(周日选活动量最低的时段):
|
||||||
|
|
||||||
|
| 角色 | agentId | cron 表达式 | 时区 |
|
||||||
|
|------|---------|-----------|------|
|
||||||
|
| 庞统 | pangtong-fujunshi | `0 6 * * 0` | Asia/Shanghai |
|
||||||
|
|
||||||
|
**Cron 配置**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schedule": { "kind": "cron", "expr": "0 6 * * 0", "tz": "Asia/Shanghai" },
|
||||||
|
"sessionTarget": "isolated",
|
||||||
|
"agentId": "pangtong-fujunshi",
|
||||||
|
"payload": {
|
||||||
|
"kind": "agentTurn",
|
||||||
|
"message": "IMPROVE 每周引用追踪 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/improve.md\n2. 按 improve.md 步骤执行:\n a. 扫描过去 7 天所有 agent 的 session JSONL,采集 Skill 引用信号\n b. 生成淘汰候选报告(30 天无引用的 Skill)\n c. 庞统审阅决策:quarantine / 保留观察 / 更新后保留\n d. 经验提升检查(被频繁引用 >= 5 次的 Skill)\n e. 反馈知识缺口到 knowledge-gaps.md",
|
||||||
|
"timeoutSeconds": 1800
|
||||||
|
},
|
||||||
|
"delivery": { "mode": "announce" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计要点**:
|
||||||
|
- `delivery.mode: "announce"`:淘汰/提升报告投递到 Control UI
|
||||||
|
- `timeoutSeconds: 1800`(30 分钟):全量 JSONL 扫描是最重的操作
|
||||||
|
- 每周一次频率足够——Skill 引用变化不会很快
|
||||||
|
- 淘汰决策通过 skill_workshop quarantine 执行,提升决策通过手动编辑 AGENTS.md
|
||||||
|
|
||||||
|
### Cron 创建方式
|
||||||
|
|
||||||
|
使用 openclaw cron 工具创建。**不是 moziplus 管理**,而是直接在 openclaw 层面配置。
|
||||||
|
|
||||||
|
创建顺序:先 S3(L1),再 S4(L2),最后 S5(IMPROVE)。
|
||||||
|
|
||||||
|
创建后验证:`cron(action=list)` 确认所有 job 存在且 enabled=true。
|
||||||
|
|
||||||
|
### 去重和幂等
|
||||||
|
|
||||||
|
每个 cron job 的 name 包含 agent 名,避免命名冲突:
|
||||||
|
- `l1-distill-zhangfei`
|
||||||
|
- `l1-distill-guanyu`
|
||||||
|
- `l1-distill-zhaoyun`
|
||||||
|
- `l1-distill-simayi`
|
||||||
|
- `l1-distill-pangtong`
|
||||||
|
- `l1-distill-jiangwei`
|
||||||
|
- `l2-review-pangtong`
|
||||||
|
- `improve-weekly-pangtong`
|
||||||
|
|
||||||
|
创建前先 `cron(action=list)` 检查同名 job 是否已存在,避免重复创建。
|
||||||
|
|
||||||
|
## 11B. 一致性偏差修复清单(S6 补充)
|
||||||
|
|
||||||
|
§19 设计-实现一致性检查(2026-06-18)发现以下偏差,列入 S6 一并修复:
|
||||||
|
|
||||||
|
| # | 偏差 | 严重度 | 修复方式 |
|
||||||
|
|---|------|--------|--------|
|
||||||
|
| B4 | ticker.py:336-348 ExperienceDistiller 调用未移除 | 中 | 移除 experience_distiller 参数和调用,日志改为 debug 级空转提示 |
|
||||||
|
| B5 | skill_system.py / experience.py 未标记 deprecated | 低 | 文件头部加 `# DEPRECATED — §19 重设计,不再参与 skill 发现/加载` 注释 |
|
||||||
|
| B6 | SELF_IMPROVEMENT_REMINDER.md 引用残留 | 低 | AGENTS.md 中已标注废弃,但 system prompt 仍注入。从 workspace 文件列表中移除该文件 |
|
||||||
|
|
||||||
|
**B4 修复细节**:
|
||||||
|
|
||||||
|
ticker.py 构造函数 `__init__` 接受 `experience_distiller` 参数(默认 None),tick() 中第 336-348 行有条件调用。修复方式:
|
||||||
|
- 保留参数(向后兼容),但条件块内加 `logger.debug("ExperienceDistiller deprecated per §19, skipping")` 后直接 return
|
||||||
|
- 不删除代码(P3 级清理时再做物理删除)
|
||||||
|
|
||||||
|
**B6 修复细节**:
|
||||||
|
|
||||||
|
当前 Project Context 中注入了 `SELF_IMPROVEMENT_REMINDER.md` 的内容。该文件在 workspace-pangtong 中已不存在(被删),但 system prompt 模板仍引用它。修复方式:确认文件不存在即可——openclaw 会跳过不存在的注入文件。实际已无影响,标注为 resolved。
|
||||||
|
|
||||||
## 12. wiki-vault / 知识库参考实践映射
|
## 12. wiki-vault / 知识库参考实践映射
|
||||||
|
|
||||||
|
|||||||
+57
-32
@@ -778,9 +778,8 @@ def _send_deploy_failure_task(repo: str, pr_number: int, pr_title: str, reason:
|
|||||||
action_type="deploy_failure",
|
action_type="deploy_failure",
|
||||||
steps=[
|
steps=[
|
||||||
"检查 deploy 日志",
|
"检查 deploy 日志",
|
||||||
"排查失败原因",
|
"根据 deploy 日志判断失败原因类型:\n a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署\n b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
|
||||||
"修复并重新部署",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
|
||||||
],
|
],
|
||||||
context_data={
|
context_data={
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
@@ -997,30 +996,58 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
|
|||||||
"brief": brief,
|
"brief": brief,
|
||||||
})
|
})
|
||||||
|
|
||||||
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
|
# 检查是否是基础设施 Issue(按 label 分流)
|
||||||
_send_toolchain_task(
|
is_infrastructure = any("infrastructure" in lbl.lower() for lbl in labels_list)
|
||||||
to_agent=assignee,
|
|
||||||
title=title,
|
if is_infrastructure:
|
||||||
description=text,
|
infra_steps = [
|
||||||
event_type="issue_assigned",
|
"根据 Issue body 中的错误来源和日志片段排查问题",
|
||||||
action_type="issue_assigned",
|
"修复基础设施问题(如修复 CI runner 环境、恢复网络、重启服务等)",
|
||||||
steps=[
|
"修复后在 Issue 上 comment 说明修复方式和结果",
|
||||||
f"创建分支 fix/{issue_number}-{brief}",
|
|
||||||
"编码 + 写 UT",
|
|
||||||
"push → 等 CI",
|
|
||||||
f"CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls)",
|
|
||||||
"等 Review",
|
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
||||||
],
|
]
|
||||||
context_data={
|
title = f"基础设施 Issue: {issue_title} ({repo}#{issue_number})"
|
||||||
"issue_number": issue_number,
|
_send_toolchain_task(
|
||||||
"repo": repo,
|
to_agent=assignee,
|
||||||
"issue_title": issue_title,
|
title=title,
|
||||||
"labels": labels,
|
description=text,
|
||||||
"issue_body": issue_body or "(无描述)",
|
event_type="infrastructure_failure",
|
||||||
"brief": brief,
|
action_type="infrastructure_failure",
|
||||||
},
|
steps=infra_steps,
|
||||||
)
|
context_data={
|
||||||
|
"issue_number": issue_number,
|
||||||
|
"repo": repo,
|
||||||
|
"issue_title": issue_title,
|
||||||
|
"labels": labels,
|
||||||
|
"issue_body": issue_body or "(无描述)",
|
||||||
|
"brief": brief,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
|
||||||
|
_send_toolchain_task(
|
||||||
|
to_agent=assignee,
|
||||||
|
title=title,
|
||||||
|
description=text,
|
||||||
|
event_type="issue_assigned",
|
||||||
|
action_type="issue_assigned",
|
||||||
|
steps=[
|
||||||
|
f"在开发目录执行 git 操作:\n a. git checkout main && git pull origin main\n b. git checkout -b fix/{issue_number}-{brief}",
|
||||||
|
"编码 + 写 UT",
|
||||||
|
f"git add -A && git commit -m \"[moz] fix: {issue_title[:30]}\" && git push origin fix/{issue_number}-{brief}",
|
||||||
|
f"CI 通过后创建 PR(Gitea API: POST /repos/{repo}/pulls,head: fix/{issue_number}-{brief}, base: main)",
|
||||||
|
"等 Review",
|
||||||
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
||||||
|
],
|
||||||
|
context_data={
|
||||||
|
"issue_number": issue_number,
|
||||||
|
"repo": repo,
|
||||||
|
"issue_title": issue_title,
|
||||||
|
"labels": labels,
|
||||||
|
"issue_body": issue_body or "(无描述)",
|
||||||
|
"brief": brief,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
elif action == "opened":
|
elif action == "opened":
|
||||||
if "部署失败" in issue_title:
|
if "部署失败" in issue_title:
|
||||||
@@ -1043,9 +1070,8 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
|
|||||||
action_type="deploy_failure",
|
action_type="deploy_failure",
|
||||||
steps=[
|
steps=[
|
||||||
"检查 deploy 日志",
|
"检查 deploy 日志",
|
||||||
"排查失败原因",
|
"根据 deploy 日志判断失败原因类型:\n a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署\n b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
|
||||||
"修复并重新部署",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
|
||||||
],
|
],
|
||||||
context_data={
|
context_data={
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
@@ -1126,9 +1152,8 @@ async def _handle_issue_comment(payload: Dict[str, Any]) -> None:
|
|||||||
action_type="ci_failure",
|
action_type="ci_failure",
|
||||||
steps=[
|
steps=[
|
||||||
"查看完整 CI 日志(PR 页面或 Gitea Actions 页面)",
|
"查看完整 CI 日志(PR 页面或 Gitea Actions 页面)",
|
||||||
"修复失败的测试",
|
"根据 CI 日志判断失败原因类型:\n a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑\n b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
|
||||||
"push → CI 自动重跑",
|
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
|
||||||
"提交 action report(POST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/comments,comment_type=action_report)",
|
|
||||||
],
|
],
|
||||||
context_data={
|
context_data={
|
||||||
"pr_number": issue_number,
|
"pr_number": issue_number,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# DEPRECATED per §19 重设计 — 经验蒸馏改为双层 daily cron(L1 各 agent + L2 庞统)
|
||||||
|
# 保留代码供参考,后续 P3 清理时物理删除
|
||||||
"""Experience Distillation — 经验蒸馏
|
"""Experience Distillation — 经验蒸馏
|
||||||
|
|
||||||
从已完成的任务产出中提取经验:
|
从已完成的任务产出中提取经验:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# DEPRECATED per §19 重设计 — 不再参与 skill 发现/加载
|
||||||
|
# 实际 skill 发现走 openclaw 原生 <available_skills> 机制
|
||||||
|
# 保留代码供参考,后续 P3 清理时物理删除
|
||||||
"""Skill System — 技能注册、加载、匹配、执行
|
"""Skill System — 技能注册、加载、匹配、执行
|
||||||
|
|
||||||
三层自由度:
|
三层自由度:
|
||||||
|
|||||||
@@ -1261,7 +1261,7 @@ curl -X POST http://{api_host}:{api_port}/api/projects/{project_id}/tasks/{task_
|
|||||||
conn = get_connection(db_path)
|
conn = get_connection(db_path)
|
||||||
try:
|
try:
|
||||||
row = conn.execute(
|
row = conn.execute(
|
||||||
"SELECT id, title, status FROM tasks WHERE id=?", (
|
"SELECT id, title, status, must_haves FROM tasks WHERE id=?", (
|
||||||
task_id,)
|
task_id,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
|
|||||||
+3
-18
@@ -332,25 +332,10 @@ class Ticker:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("HealthChecker error for %s: %s", project_id, e)
|
logger.warning("HealthChecker error for %s: %s", project_id, e)
|
||||||
|
|
||||||
# 9. 经验蒸馏(完成的 task 自动触发)
|
# 9. 经验蒸馏 — DEPRECATED per §19, 双层 daily cron 替代
|
||||||
|
# 保留参数向后兼容,不再执行逐任务蒸馏
|
||||||
if self.experience_distiller:
|
if self.experience_distiller:
|
||||||
try:
|
logger.debug("ExperienceDistiller deprecated per §19, skipping (use L1/L2 daily cron)")
|
||||||
conn2 = get_connection(db_path)
|
|
||||||
try:
|
|
||||||
done_tasks = conn2.execute(
|
|
||||||
"SELECT id FROM tasks WHERE status='done' AND updated_at > datetime('now', '-60 seconds')"
|
|
||||||
).fetchall()
|
|
||||||
finally:
|
|
||||||
conn2.close()
|
|
||||||
for row in done_tasks:
|
|
||||||
t = Blackboard(db_path).get_task(row[0])
|
|
||||||
if t:
|
|
||||||
self.experience_distiller.distill_from_task(
|
|
||||||
task_id=t.id, task_title=t.title, task_type=t.task_type
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(
|
|
||||||
"ExperienceDistiller error for %s: %s", project_id, e)
|
|
||||||
|
|
||||||
# 10. 扫描后状态
|
# 10. 扫描后状态
|
||||||
result["summary_after"] = queries.task_summary()
|
result["summary_after"] = queries.task_summary()
|
||||||
|
|||||||
@@ -166,6 +166,33 @@ class ToolchainApiSection:
|
|||||||
"",
|
"",
|
||||||
"⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。",
|
"⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。",
|
||||||
"",
|
"",
|
||||||
|
"### 需要创建 Issue 时",
|
||||||
|
"",
|
||||||
|
"如果步骤中要求创建 Issue 指派他人(如 jiangwei-infra):",
|
||||||
|
"```bash",
|
||||||
|
f'curl -s -X POST "{_GITEA_BASE}/repos/{{repo}}/issues" \\',
|
||||||
|
' -H "Authorization: token <your-token>" \\',
|
||||||
|
' -H "Content-Type: application/json" \\',
|
||||||
|
' -d \'{"title": "[moz] infra: 简述问题", "body": "## 问题描述\\n\\n<简要描述问题现象>\\n\\n## 错误来源\\n\\n- 仓库: <repo>\\n- PR/Commit: <链接>\\n- CI/Deploy run: <Gitea Actions 页面链接>\\n\\n## 日志关键片段\\n\\n```<错误日志摘要>```\\n\\n## 判断依据\\n\\n<为什么判断为基础设施问题>", "assignees": ["jiangwei-infra"], "labels": [<label_id>]}\'',
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
"⚠️ Issue body 必须包含错误来源链接(PR/Commit + CI run),让排查者能直接看到全貌。",
|
||||||
|
"⚠️ label 数字 ID 先 GET /repos/{repo}/labels 查询 type/infrastructure 对应的 ID。",
|
||||||
|
"",
|
||||||
|
"### Git 操作说明",
|
||||||
|
"",
|
||||||
|
"你的工作目录是开发目录(如 ~/.openclaw/sanguo_projects/sanguo_moziplus_v2/)。",
|
||||||
|
"标准分支操作流程:",
|
||||||
|
"```bash",
|
||||||
|
"git checkout main && git pull origin main # 从最新主干开始",
|
||||||
|
"git checkout -b fix/{branch_name} # 创建功能分支",
|
||||||
|
"# ... 写代码 ...",
|
||||||
|
"git add -A && git commit -m 'message' # 提交改动",
|
||||||
|
"git push origin {branch_name} # 推送到远程",
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
"⚠️ 不要在 main 分支上直接 commit。",
|
||||||
|
"",
|
||||||
]
|
]
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
@@ -218,6 +245,7 @@ class ToolchainConstraintsSection:
|
|||||||
'| “我已经知道了” | ❌ 知道不等于执行。执行步骤 + 提交 action report 才算完成 |',
|
'| “我已经知道了” | ❌ 知道不等于执行。执行步骤 + 提交 action report 才算完成 |',
|
||||||
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
|
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
|
||||||
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
|
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
|
||||||
|
'| “CI/部署失败不是我代码的问题,我什么也不用做” | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infra(body 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告“不是我的问题”就完事 |',
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|||||||
@@ -523,3 +523,98 @@ class TestFullPromptBuild:
|
|||||||
# Must have constraints with Red Flags
|
# Must have constraints with Red Flags
|
||||||
assert "Red Flags" in prompt
|
assert "Red Flags" in prompt
|
||||||
assert "强制要求" in prompt
|
assert "强制要求" in prompt
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# §17 v2: CI/deploy failure branching + issue label routing + Issue API guidance
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class TestCiFailureBranching:
|
||||||
|
"""ci_failure steps should include a/b branching guidance."""
|
||||||
|
|
||||||
|
def test_ci_failure_steps_contain_branching(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert '基础设施问题' in source
|
||||||
|
assert 'type/infrastructure' in source
|
||||||
|
assert 'jiangwei-infra' in source
|
||||||
|
|
||||||
|
|
||||||
|
class TestDeployFailureBranching:
|
||||||
|
"""deploy_failure steps should include a/b branching guidance."""
|
||||||
|
|
||||||
|
def test_deploy_failure_steps_contain_branching(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
count = source.count('基础设施问题(Gitea 不可用')
|
||||||
|
assert count >= 2, f'Expected >=2 deploy_failure branching, found {count}'
|
||||||
|
|
||||||
|
|
||||||
|
class TestIssueAssignedLabelRouting:
|
||||||
|
"""issue_assigned handler should route by type/infrastructure label."""
|
||||||
|
|
||||||
|
def test_label_check_in_source(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert 'is_infrastructure' in source
|
||||||
|
assert 'infrastructure_failure' in source
|
||||||
|
assert '基础设施 Issue' in source
|
||||||
|
|
||||||
|
def test_normal_issue_keeps_coding_steps(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert 'git checkout -b fix/' in source
|
||||||
|
assert 'issue_assigned' in source
|
||||||
|
|
||||||
|
|
||||||
|
class TestToolchainApiIssueGuidance:
|
||||||
|
"""ToolchainApiSection should include Issue creation guidance."""
|
||||||
|
|
||||||
|
def test_has_issue_creation_section(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert "需要创建 Issue 时" in source
|
||||||
|
assert "/issues" in source
|
||||||
|
assert "jiangwei-infra" in source
|
||||||
|
assert "type/infrastructure" in source
|
||||||
|
|
||||||
|
def test_issue_body_template_mentions_required_fields(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert "错误来源" in source
|
||||||
|
assert "判断依据" in source
|
||||||
|
|
||||||
|
|
||||||
|
class TestRedFlagsInfrastructure:
|
||||||
|
"""Red Flags should include the 'not my code' entry."""
|
||||||
|
|
||||||
|
def test_has_infrastructure_red_flag(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert "不是我代码的问题" in source
|
||||||
|
assert "基础设施问题" in source
|
||||||
|
|
||||||
|
|
||||||
|
class TestGitOperationGuidance:
|
||||||
|
"""ToolchainApiSection should include Git operation guidance."""
|
||||||
|
|
||||||
|
def test_has_git_operation_section(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert "Git 操作说明" in source
|
||||||
|
assert "git checkout main" in source
|
||||||
|
assert "git pull origin main" in source
|
||||||
|
assert "git checkout -b" in source
|
||||||
|
|
||||||
|
def test_has_no_main_commit_warning(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert "不要在 main 分支上直接 commit" in source
|
||||||
|
|
||||||
|
def test_issue_assigned_steps_have_git_commands(self):
|
||||||
|
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
|
||||||
|
source = source_file.read_text()
|
||||||
|
assert 'git checkout main && git pull origin main' in source
|
||||||
|
assert 'git checkout -b fix/' in source
|
||||||
|
assert 'git add -A && git commit' in source
|
||||||
|
assert 'git push origin fix/' in source
|
||||||
|
|||||||
Reference in New Issue
Block a user