tianshu-mcp 0.5.0 → 0.5.2
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/CHANGELOG.en.md +48 -10
- package/CHANGELOG.md +48 -10
- package/README.en.md +12 -5
- package/README.md +13 -6
- package/dist/agents/zcode/cdp.js +49 -4
- package/dist/agents/zcode/dom.js +57 -0
- package/dist/agents/zcode/references.js +18 -5
- package/dist/agents/zcode/run.js +320 -169
- package/dist/agents/zcode/selectors.js +9 -0
- package/dist/config/schema.js +23 -1
- package/dist/loop/fix-loop.js +42 -20
- package/dist/mcp/context.js +2 -0
- package/dist/mcp/handlers.js +78 -0
- package/dist/tasks/task-manager.js +14 -3
- package/dist/tasks/task.js +10 -0
- package/dist/version.generated.js +1 -1
- package/dist/visual/manage.js +12 -0
- package/docs/visual-validation.en.md +11 -1
- package/docs/visual-validation.md +11 -1
- package/package.json +1 -1
- package/skills/tianshu-mcp/SKILL.md +55 -30
- package/skills/tianshu-mcp/usage-examples.md +54 -5
package/CHANGELOG.en.md
CHANGED
|
@@ -10,24 +10,62 @@ Chinese version: [CHANGELOG.md](CHANGELOG.md)
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
-
### Tests
|
|
14
|
-
|
|
15
|
-
- Two additional real-browser-gated visual cases (added after v0.5.0): screenshots succeed when the project path contains CJK characters and spaces; a main-document 302 redirect to a non-allowlisted origin is blocked by policy and passes once explicitly allowed. Full suite: **486 passed / 10 skipped**.
|
|
16
|
-
- New `npm run evidence:visual:windows` (`scripts/evidence-visual-windows.mjs`): collects the full Windows 10 local functional matrix (existing/static/command sources, port conflict that blocks without terminating another service, bounded readiness failure that cleans up the child process, local Edge isolated instance and version mismatch, missing-browser blocker), 9/9 passed.
|
|
17
|
-
- Collected macOS 13+ platform evidence: on macOS 15 hardware runners, Intel x64 and Apple Silicon arm64 (Node 20/22/24) each passed 10 files with 51 cases; raw records are committed under `docs/visual-validation-evidence/`.
|
|
18
|
-
|
|
19
|
-
### Docs
|
|
20
|
-
|
|
21
|
-
- `docs/visual-validation{,.en}.md` rewritten with full platform evidence tables (system, Node, browser version, command, result), plus the new `docs/visual-validation-evidence/` raw machine-readable records.
|
|
22
|
-
|
|
23
13
|
### Planned
|
|
24
14
|
|
|
15
|
+
- **Visual acceptance phase 2 — AI visual content validation** (issue #13): validate whether image/page-screenshot *content* matches the task description (logo elements, style match, page semantics, etc.). Marked in issue #3 as an "optional extension"; its pixel-comparison phase 1 shipped with v0.5.0. Requires settling the model/credential source (without breaking the "zero credential management" red line), judgement debouncing, and gate placement (warning-only by default is suggested).
|
|
25
16
|
- More external AI-Agent adapters (a new agent = one profile + an optional adapter file).
|
|
26
17
|
- TraeWork executable discovery and native-dialog driving on macOS (currently fail-closed).
|
|
27
18
|
- Optional project-level skill seeding (by default nothing is written into target repos).
|
|
28
19
|
- Cancel/rework/new-project matrices for the Codex and ZCode GUI drivers on macOS (both remain `research` on darwin).
|
|
29
20
|
- Best-effort stop of a GUI-side pending session (via a temporary CDP connection) when cancelling
|
|
30
21
|
a task in the `needs_user` state.
|
|
22
|
+
- Real-machine verification of project-less dispatch on macOS (this round covers Windows 10 only).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## [0.5.2] — 2026-09-14
|
|
27
|
+
|
|
28
|
+
**Project-less dispatch for ZCode (issue #12)**: `run_task`'s `projectPath` is now optional, letting ZCode run tasks in its `default` workspace; the companion `allowCreateProject` can forbid automatic project import. See the [v0.5.2 release notes](docs/release-v0.5.2.en.md) and the [Windows 10 acceptance record](docs/zcode-issue-12-windows-evidence.en.md).
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **Project-less dispatch for ZCode (issue #12)**: `run_task`'s `projectPath` is now optional. When omitted, ZCode runs the task in its `default` workspace — no directory assigned, no project registered or imported, no Git baseline, no project snapshot freeze, no project lock, no project acceptance. On success the task is marked structurally as `not_applicable: no_project` and the terminal message states "no project acceptance performed". `query_task` / `list_tasks` display such tasks normally; `verify_task` / `get_task_report` return an explicit not-applicable explanation instead of deriving a directory from cwd.
|
|
33
|
+
- **`allowCreateProject` (ZCode-only, optional boolean)**: omitted keeps the existing "auto-import when the target is unregistered" behaviour; explicit `false` stops dispatch **before any import side effect** when the target is unregistered, returning a recognisable `project_not_registered` reason with remediation (no native folder dialog, no project added). Other agents passing this parameter get an explicit "not supported" error rather than a silent ignore.
|
|
34
|
+
- **Windows 10 hardware acceptance record** (`docs/zcode-issue-12-windows-evidence{,.en}.md`): complete evidence for project-less dispatch and `allowCreateProject=false` on ZCode 3.11.2.6792, including the before/after comparison "ZCode project entries 34 → 34, 0 added / 0 removed".
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **Divergent project-trigger readiness criteria (issue #12 §5)**: waiting used `exists` (element has width/height only) while clicking went through `pick` (exactly one unclipped visible node in the winning tier), so an `exists=true` / `click=false` window existed. Waiting and clicking now share one **structured probe** that distinguishes not-mounted / mounted-but-invisible-or-clipped / ambiguous / disabled / covered / ready, plus a post-click condition: the project menu must actually open, and `menu-not-open` is classified separately.
|
|
39
|
+
- **Error message contradicting behaviour**: "waiting for the project trigger timed out" is no longer used for early exits (multiple matches, disabled) or a menu that never opened; failure text carries `selector`, match count and minimal hit-node attributes, and diagnostics log attempt count, elapsed time and remaining budget.
|
|
40
|
+
- **Centralised timeout**: new `gui.projectTriggerTimeoutMs` (default 15s) replaces the two hard-coded `15_000` literals; the whole "wait → one sidebar fallback → wait" sequence shares a single deadline, retries do not reset the budget, and it is clamped by the setup-recovery budget and the task deadline.
|
|
41
|
+
- **`projectPath` was never opened up in the MCP schema (found on hardware)**: the handler already had the project-less branch, but `RunTaskParamsSchema.projectPath` was still required, so a real `run_task` was rejected by the SDK with `-32602 Required at projectPath`. Unit tests call the handler directly and therefore bypass `inputSchema`, which is why a green suite missed it. Changed to `AbsPath.optional()`, plus a protocol-level regression case in `test/integration/task-flow.test.ts` asserting neither `-32602` nor `Input validation error` appears.
|
|
42
|
+
- **No "work outside a project" switch, and the menu click was undone by toggle semantics (found on hardware)**: ZCode's "New task" inherits the previous binding, so project-less dispatch parked at `needs_user` forever; meanwhile `clickProjectTriggerAndConfirm` kept clicking the trigger even when the project menu was **already open**, closing the Radix dropdown and then polling until its deadline, misreported as "the project menu did not open". Added the `workOutsideProject` selector and `enterDefaultWorkspace()` for an explicit switch (confirmed by `workspaceBinding` read-back, not by click success), made the click check the menu state first, and made `confirmDefaultWorkspace` return immediately for "definitely bound to a project".
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## [0.5.1] — 2026-09-14
|
|
47
|
+
|
|
48
|
+
Documentation and validation-evidence completion; **no runtime behaviour changes**. See the [v0.5.1 release notes](docs/release-v0.5.1.en.md) for details.
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- `npm run evidence:visual:windows` (`scripts/evidence-visual-windows.mjs`): collects the full Windows 10 local functional matrix (existing/static/command sources, port conflict that blocks without terminating another service, bounded readiness failure that cleans up the child process, local Edge isolated instance and version mismatch, missing-browser blocker), 9/9 passed.
|
|
53
|
+
- `docs/visual-validation-evidence/`: raw machine-readable validation records (Windows 10 matrix JSON and test output, macOS dual-architecture `environment.json`, macOS CI summaries), distributed with the package.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Stale `package-lock.json` root version: the lockfile still said `0.4.1` at the v0.5.0 release while `package.json` said `0.5.0`; both are now synced to `0.5.1`.
|
|
58
|
+
|
|
59
|
+
### Tests
|
|
60
|
+
|
|
61
|
+
- Two additional real-browser-gated visual cases: screenshots succeed when the project path contains CJK characters and spaces; a main-document 302 redirect to a non-allowlisted origin is blocked by policy and passes once explicitly allowed. Full suite: **486 passed / 10 skipped**.
|
|
62
|
+
- Collected macOS 13+ platform evidence: on macOS 15 hardware runners, Intel x64 and Apple Silicon arm64 (Node 20/22/24) each passed 10 files with 51 cases.
|
|
63
|
+
|
|
64
|
+
### Docs
|
|
65
|
+
|
|
66
|
+
- **Skill docs (`skills/tianshu-mcp/`) aligned with the code**: `SKILL.md` now lists all 11 tools with capability/approval columns (including `prepare_visual_baseline`/`approve_visual_baseline`), gives visual acceptance its own section (blockers do not trigger repair; `rework_task` re-verifies first; baseline approval and freezing), adds `setup_recovery` and the `errorType` value set to the error table, corrects agent status semantics (`traework` is always `ready`; `codex` is platform-dependent) and notes that `continue_task` only supports codex/zcode. `usage-examples.md` fixes the claim that `get_task_report` carries a meta block, removes the mis-listed `reasoningLevel` from the meta table, distinguishes the auto repair-plan location per agent (codex writes inside the project's `.zcode/plans/`; others write to the task directory), and adds the actual `list_tasks` output columns plus the visual CLI commands.
|
|
67
|
+
- `docs/visual-validation{,.en}.md` rewritten with full platform evidence tables (system, Node, browser version, command, result).
|
|
68
|
+
- Bilingual README and HANDOFF updated against the current code and commit history.
|
|
31
69
|
|
|
32
70
|
---
|
|
33
71
|
|
package/CHANGELOG.md
CHANGED
|
@@ -9,23 +9,61 @@
|
|
|
9
9
|
|
|
10
10
|
## [未发布]
|
|
11
11
|
|
|
12
|
-
### 测试
|
|
13
|
-
|
|
14
|
-
- 视觉验收补两条真实浏览器门禁用例(v0.5.0 之后补充):项目路径含中文与空格时截图正常;主文档 302 跳转到未放行来源时按策略拦截,显式放行后通过。全量测试 **486 passed / 10 skipped**。
|
|
15
|
-
- 新增 `npm run evidence:visual:windows`(`scripts/evidence-visual-windows.mjs`):在 Windows 10 本机采集完整功能矩阵证据(`existing`/静态/命令三种来源、端口冲突阻塞且不结束他人服务、就绪失败有界阻塞并清理子进程、本机 Edge 独立实例与版本不匹配、缺浏览器阻塞),9/9 通过。
|
|
16
|
-
- 采集 macOS 13+ 平台证据:macOS 15 真机 runner 上 Intel x64 与 Apple Silicon arm64(Node 20/22/24)各跑通 10 文件 51 用例;原始记录随 `docs/visual-validation-evidence/` 入库。
|
|
17
|
-
|
|
18
|
-
### 文档
|
|
19
|
-
|
|
20
|
-
- `docs/visual-validation{,.en}.md` 重写为完整平台证据表(系统、Node、浏览器版本、命令、结果),并新增 `docs/visual-validation-evidence/` 原始机器可读记录。
|
|
21
|
-
|
|
22
12
|
### 计划中
|
|
23
13
|
|
|
14
|
+
- **视觉验收第二阶段——AI 视觉内容校验**(issue #13):校验图片/页面截图**内容**是否符合任务描述(Logo 元素、风格匹配、页面语义等)。issue #3 中标注为「可选扩展」,其像素级对比第一阶段已随 v0.5.0 完成。需先确认模型与凭证来源(不得破坏「凭证零管理」红线)、判定防抖与门禁定位(建议默认仅告警)。
|
|
24
15
|
- 更多外部 AI-Agent 适配(新 agent = 一个 profile +(如需)一个 adapter 文件)。
|
|
25
16
|
- TraeWork 在 macOS 下的可执行探测与原生对话框驱动(当前 macOS 分支 fail-closed)。
|
|
26
17
|
- 可选的项目级技能播种(默认不写入目标项目仓库)。
|
|
27
18
|
- Codex 与 ZCode GUI 的 macOS 取消/返修/新建项目矩阵(当前两者 darwin 均保持 `research`)。
|
|
28
19
|
- `needs_user` 状态下取消任务时经临时 CDP 连接尽力停止 GUI 内等待中的会话。
|
|
20
|
+
- ZCode 无项目派发在 macOS 上的真机验证(本轮仅 Windows 10 实测)。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## [0.5.2] — 2026-09-14
|
|
25
|
+
|
|
26
|
+
**ZCode 无项目派发(issue #12)**:`run_task` 的 `projectPath` 变为可选,ZCode 在 `default` 工作区承接任务;配套 `allowCreateProject` 可禁止自动导入项目。完整说明见 [v0.5.2 发布说明](docs/release-v0.5.2.md),真机证据见 [Windows 10 验收记录](docs/zcode-issue-12-windows-evidence.md)。
|
|
27
|
+
|
|
28
|
+
### 新增
|
|
29
|
+
|
|
30
|
+
- **ZCode 无项目派发(issue #12)**:`run_task` 的 `projectPath` 改为可选。省略时 ZCode 在 `default` 工作区承接任务——不分配目录、不登记/导入项目、不采集 Git 基线、不冻结项目快照、不进入项目锁与项目验收;成功后以结构化字段标注 `not_applicable: no_project`,终态文案明示「未进行项目验收」。`query_task` / `list_tasks` 正常展示该类任务;`verify_task` / `get_task_report` 返回明确的不适用说明,不从 cwd 推导目录。
|
|
31
|
+
- **`allowCreateProject`(ZCode 专用,可选布尔)**:省略 = 保持既有「目标未登记即自动导入」行为;显式 `false` 时,目标目录未登记即在**任何导入副作用之前**停止派发,返回可识别的 `project_not_registered` 与处理说明(不打开原生文件夹对话框、不添加项目)。其他 agent 显式传入该参数会得到明确的「不支持」错误,而不是被静默忽略。
|
|
32
|
+
- **Windows 10 真机验收记录**(`docs/zcode-issue-12-windows-evidence{,.en}.md`):ZCode 3.11.2.6792 上无项目派发与 `allowCreateProject=false` 的完整证据,含「派发前后 ZCode 项目条目 34 → 34、新增 0 / 消失 0」的对比。
|
|
33
|
+
|
|
34
|
+
### 修复
|
|
35
|
+
|
|
36
|
+
- **ZCode 项目触发器就绪判据不一致(issue #12 §五)**:等待用的是 `exists`(只看元素宽高),点击走的是 `pick`(要求该优先级层恰好一个未被裁剪的可见节点),两者判据不同,因此存在 `exists=true` 但 `click=false` 的窗口。现在等待与点击**共用同一份结构化探测**,区分未挂载 / 已挂载但不可见或被裁剪 / 不唯一 / 禁用 / 被遮挡 / 就绪;并新增点击后置检查——项目菜单必须真正打开,`menu-not-open` 单独归类。
|
|
37
|
+
- **错误信息与行为失实**:「等待项目触发器超时」不再被用来描述早退(多匹配、禁用)或菜单未打开;失败文案携带 `selector`、匹配数与命中节点最小属性,诊断日志记录尝试次数、实际耗时与剩余预算。
|
|
38
|
+
- **集中超时**:新增 `gui.projectTriggerTimeoutMs`(默认 15s)替换原先写死的两处 `15_000`;整个「等待 → 回退一次侧栏新建任务 → 再等待」共享同一截止时间,重试不重置预算,并被 setup 恢复预算与任务总时限夹住。
|
|
39
|
+
- **`projectPath` 未在 MCP schema 层放开(真机发现)**:handler 已支持无项目分支,但 `RunTaskParamsSchema.projectPath` 仍是必填,真实 `run_task` 会在协议层被 SDK 拒成 `-32602 Required at projectPath`;而单元测试直接调 handler、绕过了 `inputSchema`,所以全绿也没抓到。已改为 `AbsPath.optional()`,并在 `test/integration/task-flow.test.ts` 补协议层回归用例(断言文本不出现 `-32602` / `Input validation error`)。
|
|
40
|
+
- **缺少「不在项目中工作」切换,且项目菜单已开时点击被 toggle 反噬(真机发现)**:ZCode「新建任务」会继承上一次绑定,使无项目派发永久停在 `needs_user`;同时 `clickProjectTriggerAndConfirm` 在项目菜单**已经打开**时仍点击触发器,把 Radix 下拉关掉后一路轮询到 deadline,误报「项目菜单未打开」。现新增 `workOutsideProject` 选择器与 `enterDefaultWorkspace()` 显式切换(切换后以 `workspaceBinding` 回读为准),点击前先查菜单是否已开;`confirmDefaultWorkspace` 对「明确绑定着项目」立即返回而非空等。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [0.5.1] — 2026-09-14
|
|
45
|
+
|
|
46
|
+
文档与验证证据补齐;**无运行时行为变更**。完整说明见 [v0.5.1 发布说明](docs/release-v0.5.1.md)。
|
|
47
|
+
|
|
48
|
+
### 新增
|
|
49
|
+
|
|
50
|
+
- `npm run evidence:visual:windows`(`scripts/evidence-visual-windows.mjs`):在 Windows 10 本机采集完整功能矩阵证据(`existing`/静态/命令三种来源、端口冲突阻塞且不结束他人服务、就绪失败有界阻塞并清理子进程、本机 Edge 独立实例与版本不匹配、缺浏览器阻塞),9/9 通过。
|
|
51
|
+
- `docs/visual-validation-evidence/`:视觉验收验证的原始机器可读记录(Windows 10 矩阵 JSON 与测试输出、macOS 双架构 `environment.json`、macOS CI 摘要),随包分发。
|
|
52
|
+
|
|
53
|
+
### 修复
|
|
54
|
+
|
|
55
|
+
- `package-lock.json` 根包版本滞后:v0.5.0 发布时锁文件仍为 `0.4.1`(与 `package.json` 的 `0.5.0` 不一致),本版本同步为 `0.5.1`。
|
|
56
|
+
|
|
57
|
+
### 测试
|
|
58
|
+
|
|
59
|
+
- 视觉验收补两条真实浏览器门禁用例:项目路径含中文与空格时截图正常;主文档 302 跳转到未放行来源时按策略拦截,显式放行后通过。全量测试 **486 passed / 10 skipped**。
|
|
60
|
+
- 采集 macOS 13+ 平台证据:macOS 15 真机 runner 上 Intel x64 与 Apple Silicon arm64(Node 20/22/24)各跑通 10 文件 51 用例。
|
|
61
|
+
|
|
62
|
+
### 文档
|
|
63
|
+
|
|
64
|
+
- **技能文档(`skills/tianshu-mcp/`)对齐代码实况**:`SKILL.md` 补全 11 个工具表与能力/审批列(含 `prepare_visual_baseline`/`approve_visual_baseline`),视觉验收独立成节(阻塞不触发返修、`rework_task` 先重新验收、基准审批与冻结),错误码表补 `setup_recovery` 与 `errorType` 取值,修正 agent 状态语义(`traework` 恒为 `ready`、`codex` 平台相关)与 `continue_task` 仅支持 codex/zcode;`usage-examples.md` 修正 `get_task_report` 不带 meta 块、移除 meta 表误列的 `reasoningLevel`、按 agent 区分自动修复计划落盘位置(codex 在项目内 `.zcode/plans/`、其余在任务目录),并补 `list_tasks` 实际输出列与视觉 CLI 命令。
|
|
65
|
+
- `docs/visual-validation{,.en}.md` 重写为完整平台证据表(系统、Node、浏览器版本、命令、结果)。
|
|
66
|
+
- 双语 README 与 HANDOFF 按当前代码与提交历史更新。
|
|
29
67
|
|
|
30
68
|
---
|
|
31
69
|
|
package/README.en.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
# tianshu-mcp
|
|
10
10
|
|
|
11
|
-
Visual acceptance (v0.5.0): [English guide](docs/visual-acceptance.en.md) · [Validation record](docs/visual-validation.en.md) · [
|
|
11
|
+
Visual acceptance (since v0.5.0): [English guide](docs/visual-acceptance.en.md) · [Validation record](docs/visual-validation.en.md) · [Latest release notes](<docs/release-v0.5.1.en.md>).
|
|
12
12
|
|
|
13
13
|
**Tianshu × AI-Agent orchestration MCP server**
|
|
14
14
|
|
|
@@ -36,12 +36,13 @@ Registered by Tianshu as a standard MCP server, it dispatches external AI-Agents
|
|
|
36
36
|
|
|
37
37
|
Tianshu plays the role of the overall commander; this MCP server is the **scheduler + execution surface + objective acceptance gate**; the external AI-Agent (Codex / TraeWork / ZCode GUI) is the "worker" that does the development.
|
|
38
38
|
|
|
39
|
-
- **
|
|
39
|
+
- **11 MCP tools**: `run_task / continue_task / query_task / list_tasks / get_task_report / cancel_task / verify_task / rework_task / get_profiles`, plus `prepare_visual_baseline / approve_visual_baseline` for visual acceptance
|
|
40
40
|
- **Async contract**: `run_task` returns a `taskId` immediately; long-running work is polled via `query_task` (never blocks `tools/call`).
|
|
41
41
|
- **Objective acceptance**: automated command checks (typecheck/lint/test/build — skipped when absent, plus tech-stack derivation) + programmatic code analysis (changed-file list / diffstat / suspicious signals such as TODO, debugger, secret-like patterns), all relative to a **git baseline**; never auto-commits or stashes. The acceptance engine is **fail-closed**: a test check fails when its output reports zero executed tests even if the exit code is 0; git projects must produce changes relative to the pre-work baseline by default (pure analysis tasks can opt out with `"requireChanges": false` in `.tianshu-mcp/acceptance.json`).
|
|
42
42
|
- **Acceptance parallelism**: command checks run **bounded-parallel** by default (`verifyConcurrency`, default 2, range 1–4). When checks depend on an order (a later check reading build output, `--fix`, shared cache dirs), set it to `1` for fully serial behaviour; a project can override it in `.tianshu-mcp/acceptance.json`, and the server level lives in `config.json`. Report and log formats are unchanged (results are returned in declaration order).
|
|
43
43
|
- **Rework loop**: automatic rework (`autoFixRounds`) + manual `rework_task`; on verification failure a repair-plan file is generated and fed back to the agent; when rounds run out → `needs_attention` awaiting Tianshu's verdict.
|
|
44
44
|
- **Execution surfaces**: `driver: "gui"` selects an explicit, isolated Codex/TraeWork/ZCode CDP adapter; `driver: "spawn"` runs an external CLI child process.
|
|
45
|
+
- **Project-less dispatch (ZCode, issue #12)**: `run_task`'s `projectPath` may be omitted — ZCode runs the task in its `default` workspace without registering/importing a project, collecting a Git baseline, or running project acceptance (the result is marked structurally as `verificationNotApplicable: "no_project"` and `verify_task`/`get_task_report` return a not-applicable explanation). The companion `allowCreateProject: false` stops dispatch before any import side effect when the target directory is unregistered. See the [ZCode CDP adapter](docs/zcode-cdp.en.md).
|
|
45
46
|
- **Scheduling discipline**: per-project serial queue + global concurrency cap (default 2, configurable).
|
|
46
47
|
- **No key handling**: each agent uses its own login state; this server never stores or forwards any API key.
|
|
47
48
|
- **Extensible**: a new agent = one profile (data) + (if needed) one adapter file — no changes to the orchestration core.
|
|
@@ -195,6 +196,7 @@ Use `server.log` when troubleshooting connections; do not treat stderr output it
|
|
|
195
196
|
| [docs/codex-gui-cdp.en.md](docs/codex-gui-cdp.en.md) | Codex desktop GUI driver: MSIX COM activation, CDP attach, selectors, run detection, verify/repair |
|
|
196
197
|
| [docs/codex-windows-smoke.en.md](docs/codex-windows-smoke.en.md) | Codex Windows hardware record (incl. verify-fail → auto plan → repair-pass loop) |
|
|
197
198
|
| [docs/release-v0.3.4.en.md](<docs/release-v0.3.4.en.md>) | v0.3.4 release notes (ZCode project/model read-back, initialization recovery, session dispatch confirmation, issues #8/#9/#10) |
|
|
199
|
+
| [docs/release-v0.5.1.en.md](<docs/release-v0.5.1.en.md>) | v0.5.1 release notes (skill/validation docs, archived platform evidence, lockfile version sync; no runtime changes) |
|
|
198
200
|
| [docs/release-v0.5.0.en.md](<docs/release-v0.5.0.en.md>) | v0.5.0 release notes (optional visual acceptance: screenshots, image specs, baseline approval, offline report) |
|
|
199
201
|
| [docs/visual-acceptance.en.md](<docs/visual-acceptance.en.md>) | Visual acceptance primer and full configuration: three page sources, baseline candidates/approval, rule freezing, thresholds and troubleshooting |
|
|
200
202
|
| [docs/visual-validation.en.md](<docs/visual-validation.en.md>) | Visual acceptance validation progress: full Windows 10 matrix and macOS Intel/Apple Silicon platform evidence (system/Node/browser/command/result) |
|
|
@@ -236,9 +238,9 @@ Use `server.log` when troubleshooting connections; do not treat stderr output it
|
|
|
236
238
|
- Zcode headless entry (Z1) verified: ZCode desktop ships no headless CLI → unsupported
|
|
237
239
|
- **R1–R8 / S1–S6 — two acceptance hardening rounds** ✅ (cancel / timeout / baseline attribution / parameter semantics / hot reload / CI hardening) — **72 tests**
|
|
238
240
|
- **Engineering / CI** ✅
|
|
239
|
-
- GitHub Actions: `CI` (`build-test` ubuntu/windows/macos × Node 20/22/24 + `pack-check`, plus a `visual-browser` real-browser matrix ubuntu/windows/macos-15-intel/macos-15 × Node 20/22/24, all green with the v0.5.
|
|
241
|
+
- GitHub Actions: `CI` (`build-test` ubuntu/windows/macos × Node 20/22/24 + `pack-check`, plus a `visual-browser` real-browser matrix ubuntu/windows/macos-15-intel/macos-15 × Node 20/22/24, all green with the v0.5.1 tag) and `Release` (tag-triggered) both green
|
|
240
242
|
- Skill self-install verified idempotent on this machine's real `~/.rivet/skills/tianshu-mcp`
|
|
241
|
-
- npm package name `tianshu-mcp` published continuously since v0.1.1 (currently `0.5.
|
|
243
|
+
- npm package name `tianshu-mcp` published continuously since v0.1.1 (currently `0.5.1`)
|
|
242
244
|
- **Real Tianshu host integration (DoD #6)** ✅ (2026-09-07)
|
|
243
245
|
- Configured the local mode in the real `D:\Tianshu` desktop host `mcp.servers` → sidecar reported `MCP: 2 servers connected, 10 tools` (including this server's 8 tools), spawned the child process and connected over stdio
|
|
244
246
|
- Exposed and fixed a skill-install source-path bug (fileURLToPath, commit 55cf2d0)
|
|
@@ -307,6 +309,11 @@ Use `server.log` when troubleshooting connections; do not treat stderr output it
|
|
|
307
309
|
- **MCP/CLI**: new `prepare_visual_baseline` / `approve_visual_baseline` and the `tianshu-mcp visual` subcommand family, dispatched before the stdio connection
|
|
308
310
|
- **Reports and recovery**: `VerifyReport` gains an optional `visual` section and offline HTML (status filter, opacity overlay, region location); visual blockers enter `needs_attention` and `rework_task` re-verifies first so only real defects consume repair budget
|
|
309
311
|
- **Gates**: CI adds a four-system, three-Node real-browser matrix plus isolated production-package consumer acceptance; release requires a successful CI for the target commit and blocks when Gitee credentials are missing rather than claiming success
|
|
312
|
+
- **M20 — skill/validation docs aligned + platform evidence archived + v0.5.1** (2026-09-14) — **486 tests**
|
|
313
|
+
- Skill docs aligned item by item with the code: a full 11-tool table with capability/approval columns, visual acceptance given its own section, `setup_recovery` added to the error table, and fixes to agent status semantics plus the `get_task_report`/`repair-plan` doc drift
|
|
314
|
+
- Visual acceptance platform evidence archived: Windows 10 local full functional matrix **9/9** (`npm run evidence:visual:windows`), and macOS 15 hardware Intel x64 plus Apple Silicon arm64 with 10 files / 51 cases each
|
|
315
|
+
- Fixed the stale `package-lock.json` root version (was `0.4.1` at v0.5.0)
|
|
316
|
+
- **No runtime behaviour changes**; no migration needed
|
|
310
317
|
|
|
311
318
|
## Agent support status
|
|
312
319
|
|
|
@@ -379,7 +386,7 @@ Behavior and limits:
|
|
|
379
386
|
|
|
380
387
|
| Document | Content |
|
|
381
388
|
|---|---|
|
|
382
|
-
| [CHANGELOG.en.md](<CHANGELOG.en.md>) | Version history (v0.1.0 → v0.5.
|
|
389
|
+
| [CHANGELOG.en.md](<CHANGELOG.en.md>) | Version history (v0.1.0 → v0.5.1) |
|
|
383
390
|
| [CONTRIBUTING.en.md](CONTRIBUTING.en.md) | Dev setup, conventions, commit/release flow, adding an agent |
|
|
384
391
|
| [SECURITY.en.md](SECURITY.en.md) | Security model (zero credentials / command whitelist / process & desktop-automation boundaries) and private reporting |
|
|
385
392
|
| [CODE_OF_CONDUCT.en.md](CODE_OF_CONDUCT.en.md) | Contributor Code of Conduct |
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
# tianshu-mcp
|
|
10
10
|
|
|
11
|
-
视觉验收(v0.5.0
|
|
11
|
+
视觉验收(v0.5.0 起):[中文指南](docs/visual-acceptance.md) · [验证记录](docs/visual-validation.md) · [最新发布说明](<docs/release-v0.5.1.md>)。
|
|
12
12
|
|
|
13
13
|
**天枢 × AI-Agent 编排 MCP server**
|
|
14
14
|
|
|
@@ -36,12 +36,13 @@
|
|
|
36
36
|
|
|
37
37
|
天枢的角色是总指挥;本 MCP server 是**调度层 + 执行面 + 客观验收仪**;外部 AI-Agent(Codex / TraeWork / ZCode GUI)是执行开发的「工人」。
|
|
38
38
|
|
|
39
|
-
- **
|
|
39
|
+
- **11 个 MCP 工具**:`run_task / continue_task / query_task / list_tasks / get_task_report / cancel_task / verify_task / rework_task / get_profiles`,外加视觉验收的 `prepare_visual_baseline / approve_visual_baseline`
|
|
40
40
|
- **异步契约**:`run_task` 秒回 `taskId`,长任务用 `query_task` 轮询(长任务不卡 `tools/call`)。
|
|
41
41
|
- **客观验收**:自动命令检查(typecheck/lint/test/build,缺则跳过 + 技术栈推导)+ 程序化代码分析(变更清单/diffstat/TODO·debugger·密钥形态等可疑标记),全部相对 **git 基线**,不自动 commit/stash。验收引擎 **fail-closed**:测试命令退出码为 0 但输出显示零用例时判失败;git 项目默认要求相对动工前基线产生变更(纯分析任务可在 `.tianshu-mcp/acceptance.json` 设 `"requireChanges": false` 显式关闭)。
|
|
42
42
|
- **验收并行度**:命令检查默认**有界并行**(`verifyConcurrency`,默认 2、范围 1–4)。检查项之间有顺序依赖时(后续检查读取 build 产物、带 `--fix`、共享缓存目录)请设 `1` 完全退化为串行;项目级 `.tianshu-mcp/acceptance.json` 可覆盖,server 级在 `config.json`。报告与日志格式不变(结果按声明顺序返回)。
|
|
43
43
|
- **失败返修闭环**:自动返修(`autoFixRounds`)+ 手动 `rework_task`;验收失败时自动生成修复计划文件并回填给 agent;轮次用尽 → `needs_attention` 等天枢裁决。
|
|
44
44
|
- **执行面**:`driver: "gui"` 由显式 adapter 驱动桌面 UI(Codex / TraeWork / ZCode 各自使用隔离的 CDP 流程);`driver: "spawn"` 走外部 CLI 子进程。
|
|
45
|
+
- **无项目派发(ZCode,issue #12)**:`run_task` 的 `projectPath` 可省略——ZCode 在 `default` 工作区承接任务,不登记/导入项目、不采集 Git 基线、不执行项目验收(结果以 `verificationNotApplicable: "no_project"` 结构化标注,`verify_task`/`get_task_report` 返回不适用说明)。配套 `allowCreateProject: false` 可在目标目录未登记时于任何导入副作用之前停止派发。详见 [ZCode CDP 适配器](docs/zcode-cdp.md)。
|
|
45
46
|
- **调度纪律**:每项目串行队列 + 全局并发上限(默认 2,可配)。
|
|
46
47
|
- **不碰密钥**:各 agent 用自己的登录态;本 server 不保存/转发任何 API key。
|
|
47
48
|
- **可扩展**:新 agent = 一个 profile(数据)+(如需)一个 adapter 文件,零改编排核心。
|
|
@@ -88,7 +89,7 @@ npm install -g tianshu-mcp
|
|
|
88
89
|
| 命令 | `npx` | `node` |
|
|
89
90
|
| 参数(空格分隔) | `-y tianshu-mcp` | `<仓库绝对路径>/dist/index.js` |
|
|
90
91
|
|
|
91
|
-
> - 服务器 ID 即工具前缀:填 `tianshu-mcp` 后工具名为 `mcp__tianshu-mcp__run_task` 等
|
|
92
|
+
> - 服务器 ID 即工具前缀:填 `tianshu-mcp` 后工具名为 `mcp__tianshu-mcp__run_task` 等 11 个。
|
|
92
93
|
> - 参数按空格分隔填写,**不要加引号**;本地开发模式请把 `<仓库绝对路径>` 换成真实绝对路径(如 `D:/Trae项目/tianshu-mcp/dist/index.js`)。
|
|
93
94
|
> - 界面未提供环境变量输入框;如需自定义数据目录,改用下面的 `config.json` 方式设置 `TIANSHU_MCP_HOME`。
|
|
94
95
|
> - 添加后连接成功即完成;新开会话即可看到 11 个工具。
|
|
@@ -190,6 +191,7 @@ ZCode 提问、需要登录、旧实例无 CDP、系统权限不足,或自动
|
|
|
190
191
|
| [docs/zcode-windows-smoke.md](docs/zcode-windows-smoke.md) | ZCode Windows 真机开发、同会话返修与提问续跑验收记录 |
|
|
191
192
|
| [docs/codex-gui-cdp.md](docs/codex-gui-cdp.md) | Codex 桌面端 GUI 驱动:MSIX COM 激活、CDP 接管、选择器、运行检测、验收返修 |
|
|
192
193
|
| [docs/codex-windows-smoke.md](docs/codex-windows-smoke.md) | Codex Windows 真机验收记录(含验收失败→自动生成计划→返修通过闭环) |
|
|
194
|
+
| [docs/release-v0.5.1.md](<docs/release-v0.5.1.md>) | v0.5.1 发布说明(技能/验证文档补齐、平台证据归档、锁文件版本同步;无运行时变更) |
|
|
193
195
|
| [docs/release-v0.5.0.md](<docs/release-v0.5.0.md>) | v0.5.0 发布说明(可选视觉验收模块:截图对比、图片规格、基准批准、离线报告) |
|
|
194
196
|
| [docs/visual-acceptance.md](<docs/visual-acceptance.md>) | 视觉验收入门与完整配置:三种页面来源、基准候选/批准、规则冻结、阈值与排查 |
|
|
195
197
|
| [docs/visual-validation.md](<docs/visual-validation.md>) | 视觉验收验证进度:Windows 10 完整功能矩阵与 macOS Intel/Apple Silicon 平台证据(系统/Node/浏览器/命令/结果) |
|
|
@@ -235,9 +237,9 @@ ZCode 提问、需要登录、旧实例无 CDP、系统权限不足,或自动
|
|
|
235
237
|
- Zcode 无头接口(Z1)实测定论:ZCode 桌面无随包 headless CLI → unsupported
|
|
236
238
|
- **R1–R8 / S1–S6 — 两轮验收整改** ✅(取消/超时/基线归因/参数语义/热加载/CI 加固)— **72 测试**
|
|
237
239
|
- **工程 / CI** ✅
|
|
238
|
-
- GitHub Actions:`CI`(`build-test` ubuntu/windows/macos × Node 20/22/24 + `pack-check`,另加 `visual-browser` 真实浏览器矩阵 ubuntu/windows/macos-15-intel/macos-15 × Node 20/22/24,随 v0.5.
|
|
240
|
+
- GitHub Actions:`CI`(`build-test` ubuntu/windows/macos × Node 20/22/24 + `pack-check`,另加 `visual-browser` 真实浏览器矩阵 ubuntu/windows/macos-15-intel/macos-15 × Node 20/22/24,随 v0.5.1 tag 全绿)与 `Release`(tag 触发)均绿
|
|
239
241
|
- 技能自检安装已在本机真实 `~/.rivet/skills/tianshu-mcp` 验证生效且幂等
|
|
240
|
-
- npm 包名 `tianshu-mcp` 自 v0.1.1 起持续发布(当前 `0.5.
|
|
242
|
+
- npm 包名 `tianshu-mcp` 自 v0.1.1 起持续发布(当前 `0.5.1`)
|
|
241
243
|
- **天枢宿主真实接入(DoD #6)** ✅(2026-09-07,[host-integration-record.md](docs/host-integration-record.md))
|
|
242
244
|
- 在真实 `D:\Tianshu` 桌面宿主 `mcp.servers` 配置本地模式 → sidecar `MCP: 2 servers connected, 10 tools`(含本 server 8 工具),spawn 子进程并 stdio 连通
|
|
243
245
|
- 实测暴露并修复技能安装源路径 bug(fileURLToPath,提交 55cf2d0)
|
|
@@ -306,6 +308,11 @@ ZCode 提问、需要登录、旧实例无 CDP、系统权限不足,或自动
|
|
|
306
308
|
- **MCP/CLI**:新增 `prepare_visual_baseline` / `approve_visual_baseline` 与 `tianshu-mcp visual` 子命令族;CLI 在 stdio 连接前分流
|
|
307
309
|
- **报告与恢复**:`VerifyReport` 新增可选 `visual` 与离线 HTML(状态过滤、透明叠加、区域定位);视觉阻塞进 `needs_attention`,`rework_task` 先重新验收、仅真实缺陷才消耗返修预算
|
|
308
310
|
- **门禁**:CI 新增真实浏览器四系统三 Node 矩阵与生产包独立消费者验收;release 要求目标提交存在成功 CI,缺少 Gitee 凭据时阻塞不冒充成功
|
|
311
|
+
- **M20 — 技能/验证文档对齐 + 平台证据归档 + v0.5.1**(2026-09-14)— **486 测试**
|
|
312
|
+
- 技能文档逐项对齐代码实况:11 工具表(补能力/审批列)、视觉验收独立成节、错误码补 `setup_recovery`、修正 agent 状态语义与 `get_task_report`/`repair-plan` 的文档偏差
|
|
313
|
+
- 归档视觉验收平台证据:Windows 10 本机完整功能矩阵 **9/9**(`npm run evidence:visual:windows`)、macOS 15 真机 Intel x64 与 Apple Silicon arm64 各 10 文件 51 用例
|
|
314
|
+
- 修复 `package-lock.json` 根包版本滞后(v0.5.0 时为 `0.4.1`)
|
|
315
|
+
- 本版本**无运行时行为变更**,升级无需迁移
|
|
309
316
|
|
|
310
317
|
## Agent 适配现状
|
|
311
318
|
|
|
@@ -379,7 +386,7 @@ run_task(projectPath=/path/to/项目, agentId=codex-cli, task="任务书", autoV
|
|
|
379
386
|
| 文档 | 内容 |
|
|
380
387
|
|---|---|
|
|
381
388
|
| [HANDOFF.md](HANDOFF.md) | 项目交接文档:当前状态快照、架构导览、硬性红线、已知限制、接手建议 |
|
|
382
|
-
| [CHANGELOG.md](<CHANGELOG.md>) | 版本变更日志(v0.1.0 → v0.5.
|
|
389
|
+
| [CHANGELOG.md](<CHANGELOG.md>) | 版本变更日志(v0.1.0 → v0.5.1) |
|
|
383
390
|
| [CONTRIBUTING.md](CONTRIBUTING.md) | 开发环境、工程规范、提交与发布流程、如何新增 agent |
|
|
384
391
|
| [SECURITY.md](SECURITY.md) | 安全模型(凭证零管理/命令白名单/进程与桌面自动化边界)与私密报告渠道 |
|
|
385
392
|
| [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) | 贡献者行为准则 |
|
package/dist/agents/zcode/cdp.js
CHANGED
|
@@ -2,7 +2,7 @@ import { TraeworkCdpClient, CdpDisconnectedError, CdpUnavailableError, } from ".
|
|
|
2
2
|
import { candidateExpr } from "./selectors.js";
|
|
3
3
|
import { projectDisplayName } from "./project.js";
|
|
4
4
|
import { normalizeZcodeModelSelection } from "./model.js";
|
|
5
|
-
import { projectTriggerDom, workspaceBindingExpression, modelSelectionExpression, sendButtonPointExpression, } from "./dom.js";
|
|
5
|
+
import { projectTriggerDom, projectTriggerProbeExpression, projectMenuOpenExpression, workOutsideProjectExpression, workspaceBindingExpression, modelSelectionExpression, sendButtonPointExpression, } from "./dom.js";
|
|
6
6
|
export { CdpDisconnectedError, CdpUnavailableError };
|
|
7
7
|
export async function retryZcodeEvaluation(operation, sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
8
8
|
for (let attempt = 0;; attempt++) {
|
|
@@ -18,6 +18,8 @@ export async function retryZcodeEvaluation(operation, sleep = (ms) => new Promis
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
/** 点击后确认菜单打开的轮询间隔(不是独立超时;窗口由调用方从集中配置与总预算算出)。 */
|
|
22
|
+
const PROJECT_MENU_POLL_MS = 100;
|
|
21
23
|
export class ZcodeCdpClient {
|
|
22
24
|
selectors;
|
|
23
25
|
inner;
|
|
@@ -86,10 +88,11 @@ export class ZcodeCdpClient {
|
|
|
86
88
|
}
|
|
87
89
|
async click(key) {
|
|
88
90
|
if (key === "projectTrigger") {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
// 与等待共用同一就绪判据:多匹配、不可见、禁用、被遮挡一律不算就绪,不发鼠标事件。
|
|
92
|
+
const probe = await this.probeProjectTrigger();
|
|
93
|
+
if (!probe.ready || !probe.point)
|
|
91
94
|
return false;
|
|
92
|
-
await this.clickAt(point.x, point.y);
|
|
95
|
+
await this.clickAt(probe.point.x, probe.point.y);
|
|
93
96
|
return true;
|
|
94
97
|
}
|
|
95
98
|
const point = await this.evaluate(`(function(){for(const s of ${candidateExpr(key, this.selectors)}){for(const e of document.querySelectorAll(s)){const r=e.getBoundingClientRect();if(r.width&&r.height)return {x:r.left+r.width/2,y:r.top+r.height/2}}}return null})()`);
|
|
@@ -98,6 +101,48 @@ export class ZcodeCdpClient {
|
|
|
98
101
|
await this.clickAt(point.x, point.y);
|
|
99
102
|
return true;
|
|
100
103
|
}
|
|
104
|
+
/** 项目触发器结构化探测(只读,不发事件)。 */
|
|
105
|
+
async probeProjectTrigger() {
|
|
106
|
+
return this.evaluate(projectTriggerProbeExpression(this.selectors));
|
|
107
|
+
}
|
|
108
|
+
/** 项目菜单是否已真正可见(点击后置条件)。 */
|
|
109
|
+
async projectMenuOpen() {
|
|
110
|
+
return this.evaluate(projectMenuOpenExpression());
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 探测 → 点击 → 确认项目菜单打开。事件发出不算成功:菜单没开就返回 menu-not-open。
|
|
114
|
+
* deadline 由调用方从集中配置与 setup/task 总预算取上限(重试不重置截止时间)。
|
|
115
|
+
*/
|
|
116
|
+
async clickProjectTriggerAndConfirm(deadline) {
|
|
117
|
+
const probe = await this.probeProjectTrigger();
|
|
118
|
+
// 菜单可能**已经开着**(上一次尝试或外部操作的残留)。Radix 下拉是 toggle:此时再点
|
|
119
|
+
// 触发器会把它关掉,随后整段等待都会落到 menu-not-open(3.11.2 真机实测踩过)。
|
|
120
|
+
// 所以先查后点。
|
|
121
|
+
if (await this.projectMenuOpen())
|
|
122
|
+
return { opened: true, probe };
|
|
123
|
+
if (!probe.ready || !probe.point)
|
|
124
|
+
return { opened: false, reason: "not-ready", probe };
|
|
125
|
+
await this.clickAt(probe.point.x, probe.point.y);
|
|
126
|
+
while (Date.now() < deadline) {
|
|
127
|
+
// eslint-disable-next-line no-await-in-loop
|
|
128
|
+
if (await this.projectMenuOpen())
|
|
129
|
+
return { opened: true, probe };
|
|
130
|
+
// eslint-disable-next-line no-await-in-loop
|
|
131
|
+
await new Promise((resolve) => setTimeout(resolve, PROJECT_MENU_POLL_MS));
|
|
132
|
+
}
|
|
133
|
+
return { opened: false, reason: "menu-not-open", probe };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 点击「不在项目中工作」(要求该层唯一可见):进入 ZCode 的 default(无项目)工作区。
|
|
137
|
+
* 新建任务会继承上一次绑定,所以无项目派发必须先显式执行这一步。
|
|
138
|
+
*/
|
|
139
|
+
async clickWorkOutsideProject() {
|
|
140
|
+
const found = await this.evaluate(workOutsideProjectExpression(this.selectors));
|
|
141
|
+
if (!found.point)
|
|
142
|
+
return { clicked: false, count: found.count };
|
|
143
|
+
await this.clickAt(found.point.x, found.point.y);
|
|
144
|
+
return { clicked: true, count: 1 };
|
|
145
|
+
}
|
|
101
146
|
async clickExact(key, value) {
|
|
102
147
|
const found = await this.evaluate(`(async function(){const norm=s=>(s||'').normalize('NFKC').trim().toLocaleLowerCase();const target=norm(${JSON.stringify(value)});const sels=${candidateExpr(key, this.selectors)};const visible=e=>{const r=e.getBoundingClientRect();if(!(r.width>0&&r.height>0&&r.bottom>0&&r.right>0&&r.top<innerHeight&&r.left<innerWidth))return false;const x=Math.max(0,Math.min(innerWidth-1,r.left+r.width/2)),y=Math.max(0,Math.min(innerHeight-1,r.top+r.height/2)),hit=document.elementFromPoint(x,y);return !!hit&&(hit===e||e.contains(hit))};const items=()=>{const out=[];for(const s of sels)for(const e of document.querySelectorAll(s))if(visible(e)&&!out.includes(e))out.push(e);return out};const leafTexts=e=>[...e.querySelectorAll('*')].filter(n=>n.children.length===0).map(n=>(n.textContent||'').trim()).filter(Boolean);const label=e=>(e.getAttribute('data-value')||e.getAttribute('data-model')||e.getAttribute('data-provider')||leafTexts(e)[0]||e.textContent||'').trim();let nodes=items();let scroller=nodes[0];while(scroller&&scroller!==document.body&&scroller.scrollHeight<=scroller.clientHeight)scroller=scroller.parentElement;const start=scroller?.scrollTop||0;if(scroller)scroller.scrollTop=0;const seen=new Map(),seenTestids=new Map(),matches=new Map();for(let i=0;i<60;i++){await new Promise(r=>setTimeout(r,25));nodes=items();for(const e of nodes){const text=label(e);const testid=e.getAttribute('data-testid')||'';const id=e.getAttribute('data-id')||e.getAttribute('data-model-id')||e.getAttribute('data-value')||e.getAttribute('data-model')||e.getAttribute('data-provider')||testid||text;const key=norm(id)+'|'+norm(text);if(testid)seenTestids.set(key,testid);if(!text)continue;seen.set(key,text);if(norm(text)===target)matches.set(key,{top:scroller?.scrollTop||0,text})}if(!scroller||scroller.scrollTop+scroller.clientHeight>=scroller.scrollHeight-1)break;const before=scroller.scrollTop;scroller.scrollTop=Math.min(scroller.scrollTop+Math.max(100,scroller.clientHeight*.8),scroller.scrollHeight);if(scroller.scrollTop===before)break}const result={available:[...seen.values()],testids:[...seenTestids.values()]};const matchesFound=[...matches.values()];if(matchesFound.length===1){if(scroller)scroller.scrollTop=matchesFound[0].top;await new Promise(r=>setTimeout(r,50));const exact=items().filter(e=>norm(label(e))===target);if(exact.length===1){exact[0].scrollIntoView({block:'center'});const r=exact[0].getBoundingClientRect();return {count:1,...result,point:{x:r.left+r.width/2,y:r.top+r.height/2}}}}if(scroller)scroller.scrollTop=start;return {count:matchesFound.length,...result}})()`);
|
|
103
148
|
if (!found.point)
|
package/dist/agents/zcode/dom.js
CHANGED
|
@@ -74,3 +74,60 @@ export function sendButtonPointExpression(overrides) {
|
|
|
74
74
|
return hit && (hit===e || e.contains(hit)) ? {x,y} : null;
|
|
75
75
|
})()`;
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* 项目触发器结构化探测:等待与点击共用这一份就绪判据,消除「exists 说有、click 说没有」
|
|
79
|
+
* (exists 只看宽高,pick 还要求该优先级层唯一且未被祖先裁剪)。
|
|
80
|
+
*
|
|
81
|
+
* 返回 selector / 该层匹配数 count / 全部候选命中的挂载数 mounted / 命中节点最小诊断属性,
|
|
82
|
+
* 让上层区分未挂载、不可见、不唯一、禁用、遮挡与真实超时,而不是统统归成「等待超时」。
|
|
83
|
+
* 只用于项目触发器;登录页等其它 exists 调用语义不变。
|
|
84
|
+
*/
|
|
85
|
+
export function projectTriggerProbeExpression(overrides) {
|
|
86
|
+
return `(function(){${ZCODE_DOM}
|
|
87
|
+
const describe = e => e ? String(e.tagName || '')
|
|
88
|
+
+ (e.getAttribute('data-testid') ? '#' + e.getAttribute('data-testid') : '')
|
|
89
|
+
+ (e.getAttribute('aria-label') ? '[' + e.getAttribute('aria-label') + ']' : '') : '';
|
|
90
|
+
const sels = ${candidateExpr("projectTrigger", overrides)};
|
|
91
|
+
const mountedNodes = new Set();
|
|
92
|
+
for (const s of sels) for (const e of document.querySelectorAll(s)) mountedNodes.add(e);
|
|
93
|
+
const mounted = mountedNodes.size;
|
|
94
|
+
const m = pick(sels);
|
|
95
|
+
const base = { selector: m.selector, count: m.count, mounted, ready: false };
|
|
96
|
+
if (!mounted) return Object.assign({}, base, { state: 'missing' });
|
|
97
|
+
if (m.count === 0)
|
|
98
|
+
return Object.assign({}, base, { state: 'hidden', detail: describe(mountedNodes.values().next().value) });
|
|
99
|
+
if (m.count > 1) return Object.assign({}, base, { state: 'ambiguous' });
|
|
100
|
+
const node = m.node;
|
|
101
|
+
if (node.disabled || node.getAttribute('aria-disabled') === 'true')
|
|
102
|
+
return Object.assign({}, base, { state: 'disabled', detail: describe(node) });
|
|
103
|
+
const r = node.getBoundingClientRect(), x = r.left + r.width / 2, y = r.top + r.height / 2;
|
|
104
|
+
const hit = document.elementFromPoint(x, y);
|
|
105
|
+
// 命中目标本身或其子树才算命中目标;被别的元素盖住不是可点击状态。
|
|
106
|
+
if (!hit || !(hit === node || node.contains(hit)))
|
|
107
|
+
return Object.assign({}, base, { state: 'covered', detail: describe(hit) });
|
|
108
|
+
return Object.assign({}, base, { state: 'ready', ready: true, point: { x, y }, detail: describe(node) });
|
|
109
|
+
})()`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 点击项目触发器后的后置条件:项目菜单必须真正可见。
|
|
113
|
+
* 鼠标事件发出去本身不算成功——菜单没开就说明这次点击没有生效。
|
|
114
|
+
*/
|
|
115
|
+
export function projectMenuOpenExpression() {
|
|
116
|
+
return `(function(){${ZCODE_DOM}
|
|
117
|
+
if ([...document.querySelectorAll('[role="menu"]')].some(visible)) return true;
|
|
118
|
+
return [...document.querySelectorAll('[role="menuitemcheckbox"]')].some(visible);
|
|
119
|
+
})()`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 「不在项目中工作」菜单项(`composer-work-outside-project`):ZCode 用它进入 default
|
|
123
|
+
* (无项目)工作区。要求命中层唯一可见,否则不点击——多匹配说明菜单结构已漂移,
|
|
124
|
+
* 猜一个点会把任务送到错误的工作区。
|
|
125
|
+
*/
|
|
126
|
+
export function workOutsideProjectExpression(overrides) {
|
|
127
|
+
return `(function(){${ZCODE_DOM}
|
|
128
|
+
const found = pick(${candidateExpr("workOutsideProject", overrides)});
|
|
129
|
+
if (!found.node) return { count: found.count };
|
|
130
|
+
const r = found.node.getBoundingClientRect();
|
|
131
|
+
return { count: found.count, point: { x: r.left + r.width / 2, y: r.top + r.height / 2 } };
|
|
132
|
+
})()`;
|
|
133
|
+
}
|
|
@@ -4,18 +4,31 @@ function inside(root, candidate) {
|
|
|
4
4
|
const rel = path.relative(root, candidate);
|
|
5
5
|
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
/** 从任务书/上下文中抽取「像本地路径」的候选值(URL、模型名、命令文本等已被排除)。 */
|
|
8
|
+
export function collectLocalReferences(task, context) {
|
|
8
9
|
const text = `${task}\n${context ?? ""}`;
|
|
9
10
|
const values = new Set();
|
|
10
11
|
for (const m of text.matchAll(/`([^`]+)`/g))
|
|
11
12
|
values.add(m[1].trim());
|
|
12
13
|
for (const m of text.matchAll(/(?:^|\s)((?:[A-Za-z]:[\\/]|\/|\.\.?[\\/])[^\s,。;;]+)/gm))
|
|
13
14
|
values.add(m[1].trim());
|
|
15
|
+
return [...values].filter((source) => path.isAbsolute(source) || /^\.\.?[\\/]/.test(source) || /[\\/]/.test(source));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 校验任务书里的本地引用。
|
|
19
|
+
*
|
|
20
|
+
* `projectRoot` 缺失(无项目模式,issue #12)时**不得**退回 cwd / 主目录 / 日志目录去解析:
|
|
21
|
+
* 识别到明确引用就直接说明需要 projectPath,没有引用则返回空表。
|
|
22
|
+
*/
|
|
23
|
+
export function validateTaskReferences(task, context, projectRoot) {
|
|
24
|
+
const candidates = collectLocalReferences(task, context);
|
|
25
|
+
if (!projectRoot) {
|
|
26
|
+
if (candidates.length)
|
|
27
|
+
throw new Error(`任务书包含本地文件引用(${candidates.slice(0, 5).join("、")}${candidates.length > 5 ? ` 等 ${candidates.length} 项` : ""});无项目模式无法解析路径,请提供 projectPath`);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
14
30
|
const out = [];
|
|
15
|
-
for (const source of
|
|
16
|
-
// Backticks frequently contain identifiers/commands. Only path-like values are interpreted.
|
|
17
|
-
if (!path.isAbsolute(source) && !/^\.\.?[\\/]/.test(source) && !/[\\/]/.test(source))
|
|
18
|
-
continue;
|
|
31
|
+
for (const source of candidates) {
|
|
19
32
|
const absolutePath = path.resolve(projectRoot, source);
|
|
20
33
|
if (!inside(path.resolve(projectRoot), absolutePath))
|
|
21
34
|
throw new Error(`引用路径越出项目范围:${source}`);
|