From 39ec2b4435cb36caed88af474851ca5d7a623a8c Mon Sep 17 00:00:00 2001 From: host Date: Mon, 2 Nov 2026 03:46:34 +0000 Subject: [PATCH] =?UTF-8?q?v5:=20rebase=20=E8=9E=8D=E5=90=88=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=88main=20=E6=BC=94=E8=BF=9B=20+=20=E9=99=84?= =?UTF-8?q?=E5=BD=95=E6=BA=90=E5=90=8C=E6=AD=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - websearch.py:补回 import socket(栈 46ca59f 的 lint 清理在栈 上无害,replay 到 main 后 main #274 的超时/DNS 显式报错 代码引用 socket,缺 import 致 2 项 NameError;re 在 main 与重排后树中均 0 引用,不补) - 3 个 websearch fake 补 scope="general" 参数(main 的 handle_request 现必传 scope,旧 fake 致 TypeError 被吞成 isError,3 项失败) - playwright 工具数 14→18(main 新增 4 个,与 main _TOOLS 逐名一致、无重复) - playwright 种子测试改按 main 安全升级规则:源脚本 v1→v2 且 manifest 证明未改动才刷新;未知改动只上报跳过不覆盖 - 附录源同步:01/02/07 三个 roles 源文件与 SKILL.md 附录章 做同一改写,check_appendix 来源一致性恢复 --- .../templates/roles/01-product-manager.md | 2 +- .../templates/roles/02-architect.md | 2 +- .../templates/roles/07-acceptance.md | 2 +- cloud/tests/test_coverage85_mcp.py | 10 ++++++---- cloud/tests/test_coverage85_misc.py | 14 ++++++++++++-- cloud/tests/test_mcp_coverage.py | 2 +- cloud/websearch.py | 1 + 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/cloud/skills/software-engineering/templates/roles/01-product-manager.md b/cloud/skills/software-engineering/templates/roles/01-product-manager.md index c0b43d9..a722c27 100644 --- a/cloud/skills/software-engineering/templates/roles/01-product-manager.md +++ b/cloud/skills/software-engineering/templates/roles/01-product-manager.md @@ -12,7 +12,7 @@ ## 产出 -按 `templates/artifacts/prd-outline.md` 写一份 PRD,至少包含: +按下面大纲写一份 PRD,至少包含: 1. 目标用户和核心场景(不超过 3 个核心能力)。 2. 用户故事,每个故事都有可检验的验收标准(能做什么、做到什么程度算通过)。 diff --git a/cloud/skills/software-engineering/templates/roles/02-architect.md b/cloud/skills/software-engineering/templates/roles/02-architect.md index 34e5ef1..c268a15 100644 --- a/cloud/skills/software-engineering/templates/roles/02-architect.md +++ b/cloud/skills/software-engineering/templates/roles/02-architect.md @@ -18,7 +18,7 @@ 3. 数据模型:核心实体、字段、关系、同步冲突时以哪端为准。 4. Agent 协议:如果产品含 agent 能力,写清任务创建、执行、状态、取消、 超时、失败重试的协议,不要让各客户端自己发明一套。 - 协议模板见 `templates/artifacts/` 下的 agent 任务契约模板。 + (Agent 协议、状态机、错误 taxonomy 的要素见本章第 4、5、6 项。) 5. 任务状态机:至少包含创建、排队、运行中、等审批、已完成、已取消、失败、超时, 每个状态的进入条件、退出条件、可执行操作都要写清。 6. 错误 taxonomy:至少区分模型失败、工具失败、用户取消、超时、权限拒绝、配额超限, diff --git a/cloud/skills/software-engineering/templates/roles/07-acceptance.md b/cloud/skills/software-engineering/templates/roles/07-acceptance.md index 16c8839..d8c285b 100644 --- a/cloud/skills/software-engineering/templates/roles/07-acceptance.md +++ b/cloud/skills/software-engineering/templates/roles/07-acceptance.md @@ -4,7 +4,7 @@ ## 协调员准备 -1. 按 `templates/artifacts/acceptance-checklist.md` 生成本项目的验收清单, +1. 按 PRD 验收标准生成本项目的验收清单, 每一项对应 PRD 里的一条验收标准,不额外加、不悄悄删。 2. 为 web 单端准备一份演示产物:怎么启动、测哪个核心流程、 已知问题是什么、哪些平台未编译验证。web 演示可真跑; diff --git a/cloud/tests/test_coverage85_mcp.py b/cloud/tests/test_coverage85_mcp.py index 2ec2474..96275ce 100644 --- a/cloud/tests/test_coverage85_mcp.py +++ b/cloud/tests/test_coverage85_mcp.py @@ -152,7 +152,9 @@ class PlaywrightHandleTest(unittest.TestCase): resp = playwright_mcp.handle_request( {"jsonrpc": "2.0", "id": 8, "method": "tools/list"}) names = [t["name"] for t in resp["result"]["tools"]] - self.assertEqual(len(names), 14) + # main 在栈基线之后新增 4 个浏览器工具(18 个,与 + # main 的 playwright_mcp._TOOLS 逐名一致,无重复)。 + self.assertEqual(len(names), 18) for want in ("browser_navigate", "browser_snapshot", "browser_click", "browser_fill", "browser_evaluate", "browser_click_at", "browser_live_shot", "browser_snapshot_refs", @@ -607,7 +609,7 @@ class WebSearchMcpTest(unittest.TestCase): def test_handle_request_dispatch_and_errors(self): calls = {} - def fake_search(query, limit=5, provider="auto"): + def fake_search(query, limit=5, provider="auto", scope="general"): calls["search"] = (query, limit, provider) return {"results": [{"title": "t", "url": "http://x/"}]} @@ -673,8 +675,8 @@ class WebSearchMcpTest(unittest.TestCase): def test_main_loop_with_fake_search(self): old_search = websearch_mcp.search - websearch_mcp.search = lambda query, limit=5, provider="auto": \ - {"results": []} + websearch_mcp.search = lambda query, limit=5, provider="auto", \ + scope="general": {"results": []} old_in, old_out = sys.stdin, sys.stdout sys.stdin = io.StringIO("\nbroken{\n" + json.dumps( {"jsonrpc": "2.0", "id": 1, "method": "tools/call", diff --git a/cloud/tests/test_coverage85_misc.py b/cloud/tests/test_coverage85_misc.py index 3ed4078..6d01551 100644 --- a/cloud/tests/test_coverage85_misc.py +++ b/cloud/tests/test_coverage85_misc.py @@ -789,13 +789,23 @@ class PlaywrightEnsureTest(unittest.TestCase): self.home, script_dir=self.src) self.assertFalse(out["script_changed"]) self.assertFalse(out["config_changed"]) - # 旧脚本被刷新上报。 + # 上游改版刷新:源脚本升级(v1→v2)后,manifest 已证明 + # 家目录旧脚本未改动,自动刷新并上报。 + with open(os.path.join(self.src, + "playwright_mcp.py"), "w") as f: + f.write("# playwright_mcp.py v2\n") + out = pw_mod.ensure_codex_home_playwright( + self.home, script_dir=self.src) + self.assertIn("playwright_mcp.py", out["script_refreshed"]) + # 未知改动不刷新:家目录脚本被改成 manifest 与已知 + # 已发版哈希都不认识的内容时,只上报跳过、绝不覆盖。 with open(os.path.join(self.home, "playwright_mcp.py"), "w") as f: f.write("# stale\n") out = pw_mod.ensure_codex_home_playwright( self.home, script_dir=self.src) - self.assertIn("playwright_mcp.py", out["script_refreshed"]) + self.assertNotIn("playwright_mcp.py", out["script_refreshed"]) + self.assertIn("playwright_mcp.py", out["script_skipped_modified"]) # 自定义 command_args 写进 section(删旧配置重写, # 否则已有 section 不会被改写)。 os.remove(os.path.join(self.home, "config.toml")) diff --git a/cloud/tests/test_mcp_coverage.py b/cloud/tests/test_mcp_coverage.py index 76c2fc8..0488f18 100644 --- a/cloud/tests/test_mcp_coverage.py +++ b/cloud/tests/test_mcp_coverage.py @@ -68,7 +68,7 @@ class WebSearchMcpTest(unittest.TestCase): [t["name"] for t in listed["result"]["tools"]]) def test_tools_call_and_errors(self): - fake_search = lambda q, limit=5, provider="auto": { # noqa: E731 + fake_search = lambda q, limit=5, provider="auto", scope="general": { # noqa: E731 "results": [{"title": q}]} # 工具执行一律用注入的 fake,不调真实 search(不联网)。 resp = ws_handle({"jsonrpc": "2.0", "id": 2, "method": "tools/call", diff --git a/cloud/websearch.py b/cloud/websearch.py index 92d1930..d6a4323 100644 --- a/cloud/websearch.py +++ b/cloud/websearch.py @@ -58,6 +58,7 @@ import html as _html import ipaddress import json import os +import socket import urllib.error import urllib.parse import urllib.request