From d4cb236aced4bd821541f7a0dacded9154e66808 Mon Sep 17 00:00:00 2001 From: lanrtop Date: Fri, 3 Jul 2026 19:17:25 +0900 Subject: [PATCH] =?UTF-8?q?fix(mcp):=20SSE=20=E6=B6=88=E6=81=AF=E7=AB=AF?= =?UTF-8?q?=E7=82=B9=E7=AB=8B=E5=8D=B3=E8=BF=94=E5=9B=9E=20202=EF=BC=8C?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E5=BC=82=E6=AD=A5=E5=A4=84=E7=90=86=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit poll_now 等耗时工具(发出 HTTP 请求到 Gitea)阻塞了 handle_sse_message, 导致客户端 POST 超时。改为 tokio::spawn 在后台处理 + SSE 推回结果, HTTP 握手立即完成,符合 MCP SSE 传输规范。 另:新增 docs/ai-context/git-workflow.md(分支策略 + Conventional Commits), .gitignore 排除炼境实例数据(.claude/liangjing.json / dev_manager.db)。 --- .gitignore | 4 ++ docs/ai-context/git-workflow.md | 82 +++++++++++++++++++++++++++++++++ src-tauri/src/mcp_server.rs | 43 +++++++++-------- 3 files changed, 109 insertions(+), 20 deletions(-) create mode 100644 docs/ai-context/git-workflow.md diff --git a/.gitignore b/.gitignore index 3cf249b..2cfa71a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,9 @@ src-tauri/target/ .DS_Store Thumbs.db +# 炼境实例数据(项目 ID 和端口,每台机器不同,不入库) +.claude/liangjing.json +src-tauri/dev_manager.db + # 防止签名密钥被误提交(Windows ~ 路径展开问题) ~/ diff --git a/docs/ai-context/git-workflow.md b/docs/ai-context/git-workflow.md new file mode 100644 index 0000000..0289e3b --- /dev/null +++ b/docs/ai-context/git-workflow.md @@ -0,0 +1,82 @@ +# Git 工作流 — AI Agent 操作指南 + +> 把此文件粘贴给任何 AI Agent,让它了解本项目的 git 工作方式。由炼境接入包分发。 +> `ONBOARDING_MANAGED` 标记块由炼境版本化管理(重跑接入包可原位升级),块外可自由补充项目特有约定。 + + + +## 分支策略 + +``` +dev ← 日常开发在这里 commit/push + ↓ +main ← 稳定分支,通过 PR 合入(合入时触发 CI code review) +``` + +- 小改动可直接 push `dev` +- 功能完整后开 PR(dev → main) +- 不要直接 push `main`,除非紧急热修复 + +## Commit 规范(lefthook 强制) + +格式:`(): <描述>` + +| type | 用途 | +|------|------| +| `feat` | 新功能 | +| `fix` | Bug 修复 | +| `chore` | 配置、依赖、脚本 | +| `docs` | 文档 | +| `refactor` | 重构(不改功能) | +| `ci` | CI 配置 | +| `perf` | 性能优化 | +| `style` | 代码格式 | +| `test` | 测试 | + +`scope` 用「模块/子模块」二级结构(如 `auth/login`、`api/user`、`db/order`),对应项目功能模块。 + +```bash +git commit -m "feat(auth/login): 新增手机号登录" +git commit -m "fix(api/user): 修正分页 off-by-one" +``` + +> 炼境会解析这些 commit 的 type/scope 作为飞轮数据:`fix` 计入返工率、`scope` 归到模块。 +> **commit 写得越规范,飞轮数据越准。** + +## Rules-Applied trailer(规则命中回传) + +若本次任务中触发过 CONVENTIONS 自动推荐规则(R01-R11,见 `.blueprint/CONVENTIONS.md` 规则列表), +在 commit message 末尾追加一行 trailer(与正文空行分隔): + +``` +feat(auth/login): 新增手机号登录 + +Rules-Applied: R01,R05 +``` + +- 只记录**真实触发**(主动检查或执行)的规则,未触发则整行省略 +- 炼境自动解析此 trailer 做「规则命中 × 返工」交叉统计,是 CONVENTIONS 置信度进化的数据来源 +- 凭空罗列会污染数据——宁缺毋滥 + +## 一个 commit = 一件独立的事 + +不要 `git add -A` 一次提交所有。按功能分批: + +```bash +git add <相关文件> +git commit -m "feat(模块): 一件事" +``` + +## PR 大小控制 + +PR 别攒太大(建议每 3~5 个 commit 或几百行内就开一次),否则 CI code review 易超时失效。 +「所有检测通过」≠ 代码被审查过——大 PR 即使 CI 全绿,review 可能已静默失效。 + +## 常用命令 + +```bash +git status --short +git log --oneline -10 +git reset --soft HEAD~1 # 撤销最后一次 commit(保留改动) +``` + diff --git a/src-tauri/src/mcp_server.rs b/src-tauri/src/mcp_server.rs index 441919d..e3ed563 100644 --- a/src-tauri/src/mcp_server.rs +++ b/src-tauri/src/mcp_server.rs @@ -323,7 +323,7 @@ async fn handle_sse_connect( } /// POST /mcp/group/:group_id/messages?session_id=xxx -/// 客户端通过此 URL 发送 JSON-RPC 请求,响应经 SSE channel 推回。 +/// 客户端通过此 URL 发送 JSON-RPC 请求,立即返回 202,响应经 SSE channel 异步推回。 async fn handle_sse_message( State(sessions): State, Path(group_id): Path, @@ -333,27 +333,30 @@ async fn handle_sse_message( if req.id.is_none() { return StatusCode::ACCEPTED.into_response(); } - let id = req.id.clone(); - let response_json = match process_rpc(&group_id, &req).await { - Ok(result) => json!({ "jsonrpc": "2.0", "id": id, "result": result }), - Err(msg) => json!({ - "jsonrpc": "2.0", "id": id, - "error": { "code": -32601, "message": msg } - }), - }; - - let mut sessions_guard = sessions.lock().await; - if let Some(tx) = sessions_guard.get(&query.session_id) { - if tx - .send(("message".to_string(), response_json.to_string())) - .await - .is_err() - { - // 连接已关闭,惰性清理 - sessions_guard.remove(&query.session_id); + // 立即返回 202,在后台 task 里处理(避免长时间工具调用阻塞 HTTP 连接) + let sessions_clone = sessions.clone(); + let session_id = query.session_id.clone(); + tokio::spawn(async move { + let id = req.id.clone(); + let response_json = match process_rpc(&group_id, &req).await { + Ok(result) => json!({ "jsonrpc": "2.0", "id": id, "result": result }), + Err(msg) => json!({ + "jsonrpc": "2.0", "id": id, + "error": { "code": -32601, "message": msg } + }), + }; + let mut guard = sessions_clone.lock().await; + if let Some(tx) = guard.get(&session_id) { + if tx + .send(("message".to_string(), response_json.to_string())) + .await + .is_err() + { + guard.remove(&session_id); + } } - } + }); StatusCode::ACCEPTED.into_response() }