Skip to content

Commit ea86459

Browse files
committed
Add cancellable diagnostics with owned tasks and scoped I/O
1 parent 246a1d5 commit ea86459

42 files changed

Lines changed: 1659 additions & 161 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ it shipped into a `## [x.y.z] - date` section of their own; the tag's
1313

1414
## Unreleased
1515

16+
- Run Diagnostics through the shared owner-bound controller with localized
17+
progress/stop/retry states and no late updates after close. Add scoped
18+
cancellation primitives to both SDK namespaces and the previously absent
19+
active ac_diagnose MCP entry point. Supported Wayland socket/helper/native
20+
waits observe scoped cancellation and retain bounded owned cleanup;
21+
unscoped calls and existing diagnostic signatures remain compatible.
22+
1623
- Add owner-bound shared GUI task infrastructure with cooperative cancellation,
1724
typed progress/outcomes, captured context and refreshed identity. Late owner
1825
results are dropped, failures do not retain traceback objects, and a failed

‎Progress.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414

1515
`WIP` — 改版仍缺以下內容;原生平台與正式環境驗收缺口另列於後。
1616
計畫 D1 仍缺 portal session 關閉/恢復、compositor 重啟的狀態與原生驗收、
17-
擷取結果與擁有者 context 的接合,以及主動診斷與原生 session 的重試/取消/停止控制。
17+
擷取結果與擁有者 context 的接合,以及原生 session 的重試/取消/停止控制。
1818
D2 的原生 EI 釋放驗證與 D3 的錄製/全域停止/Windows 原生崩潰證據仍缺,詳見計畫與下方生命週期待辦。
1919
計畫 E(Android/iOS)、G(MCP 逐步揭露)、H(型別深化與總驗收)尚未開始。F 還缺:
2020

2121
- **Remote Desktop 與 Script Builder 仍在啟動時建立**(預設開啟),啟動時間 2.6–2.7 秒裡大半是它們與門面匯入。
2222
- **F1 的遺留面板釋放**:擁有者直接建立的核心表單與 Remote Desktop 在關閉時仍保留 widget;需隨 F3 遷移直接控制項引用、執行中工作與連線生命週期,再啟用銷毀。
2323
- **F2 其餘**:計畫指定的 `WorkspaceShell` 介面、右側可收合詳情,以及各面板的空白/錯誤/permission states 還沒全面交付。
24-
- **F3** 還缺共用 `TaskController` 接入各面板、backend timeout/cancel 傳遞與關閉生命週期遷移,
24+
- **F3** 還缺共用 `TaskController` 接入其餘面板、backend timeout/cancel 傳遞與關閉生命週期遷移,
2525
以及 `webrtc_panel.py` 的 dialog/worker/session 拆分。
2626
- **F4**(啟動/記憶體基準、mixed-DPI、功能對等測試)尚未開始。
2727
- **F3 Windows 原生釋放驗收**:`test/unit_test/headless/test_remote_desktop_host_id.py` 的 freed-thread-state abort 尚缺 Windows 原生堆疊與獨立根因確認。

‎README.md‎

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ under a relative name are written below that directory.
338338

339339
| Surface | Start it with | Notes |
340340
|---|---|---|
341-
| **MCP server** | `je_auto_control_mcp` (stdio) or `AC_start_mcp_http_server` | 710 tools for Claude Desktop / Claude Code / custom tool loops: the full `ac_*` surface plus short model-friendly aliases for common GUI actions. Speaks the stateless MCP 2026-07-28 beside the `initialize`-based revisions. Bearer auth, TLS, audit log, rate limit, plugin hot-reload, CI fake backend. |
341+
| **MCP server** | `je_auto_control_mcp` (stdio) or `AC_start_mcp_http_server` | 711 tools for Claude Desktop / Claude Code / custom tool loops: the full `ac_*` surface plus short model-friendly aliases for common GUI actions. Speaks the stateless MCP 2026-07-28 beside the `initialize`-based revisions. Bearer auth, TLS, audit log, rate limit, plugin hot-reload, CI fake backend. |
342342
| **REST API** | `je_auto_control start-rest` | Bearer token, per-IP rate limit + lockout, SQLite audit hook, `/metrics`, `/openapi.json`, `/docs` Swagger UI, `/dashboard`. |
343343
| **TCP socket server** | `je_auto_control start-server` | Newline-framed JSON action lists. Binds `127.0.0.1` by default. |
344344
| **pytest plugin** | installed automatically | Fixtures plus a Gherkin step library for pytest-bdd / behave. |
@@ -511,8 +511,8 @@ distinct from automatic fallback after observed optional native absence;
511511
permission/pause/revocation/failure metadata cannot imply CLI fallback.
512512
Capture helper and portal selection are diagnosed independently. Rendering and
513513
language changes reuse the snapshot without probing. Native portal restore,
514-
compositor restart, capture-result/context integration and cancelable active
515-
diagnostics remain in `Progress.md`.
514+
compositor restart, capture-result/context integration and native session
515+
controls remain in `Progress.md`.
516516

517517
The GUI task infrastructure provides `gui.task_controller.TaskController`:
518518
`submit(work, owner=widget)` returns a caller-owned `TaskHandle` with
@@ -530,16 +530,43 @@ thread. Cancellation does not forcibly interrupt an uncooperative call
530530
or relabel a successful committed return. Errors/progress use the captured
531531
secret scope; terminal errors retain no exception traceback. Failed thread
532532
starts roll back both registries and preserve the original failure.
533-
This is shared infrastructure: Diagnostics and other panels still await
534-
controller/timeout/stop integration, tracked in `Progress.md`.
535-
536-
Active diagnostics stop immediately when a check raises explicit cancellation
537-
or a hard control signal, including an explicit exception cause chain.
538-
The original object propagates through the core, SDK, CLI and Diagnostics
539-
action; it is not logged or converted into a failed report row, and later
540-
checks do not run. Ordinary probe errors still produce failed rows and
541-
allow remaining checks. A canceled GUI run can be retried explicitly.
542-
Background workers and cooperative stop controls remain pending.
533+
Diagnostics now adopts this controller. Remaining panel/backend migrations
534+
and native session operations stay in `Progress.md`.
535+
536+
Active **Diagnostics → Actions → Run diagnostics** uses the shared task
537+
controller off the GUI thread. **Stop diagnostics** requests cooperative stop;
538+
the view distinguishes running, stopping, canceled and failed states in four
539+
languages. Progress counts completed checks. Duplicate runs are ignored, close
540+
abandons late progress/results, and a deliberate retry starts a new owned run.
541+
GUI cancellation is a typed outcome without retained exception tracebacks;
542+
headless core/SDK/CLI and the MCP handler preserve original direct/wrapped controls.
543+
Ordinary probe failures still become report rows and allow remaining checks.
544+
545+
`CancellationToken`, `TaskProgress` and `cancellation_scope` are exported by both
546+
SDK namespaces. Bind `with cancellation_scope(token): report = run_diagnostics()`;
547+
the owning caller can call `token.cancel()` from another thread. The existing
548+
no-argument diagnostics signature remains. Scope binding grants no authority;
549+
`cancellation_scope(None)` only suspends cancellation for bounded owned cleanup.
550+
`AC_diagnose` and the new read-only `ac_diagnose` share the report. The MCP tool
551+
accepts no arguments, uses request cancellation/progress and requires
552+
`read_screen`, as does the explicit GUI action. Caller-supplied tokens or
553+
authority metadata are rejected. These are active checks: capture may request
554+
consent. `ac_probe_capabilities` remains the separate passive alternative.
555+
556+
Scoped Wayland D-Bus connect/read/partial-write waits poll at intervals capped
557+
at 0.1s within the original total deadline. Cancellation attempts Request.Close
558+
on the originating bus with its separate 0.25s budget, then releases that
559+
connection; a canceled returned image is discarded. Scoped CLI captures stop
560+
and reap their newly owned helper/process group with bounded cleanup, preserving
561+
the original control even if pipe close fails; reaped numeric PIDs are never
562+
signaled. liboeffis acquisition observes scoped stop and releases its own context.
563+
Uncooperative/native calls are not forcibly preempted; the GUI remains responsive
564+
while cleanup completes. Restore/restart, native session controls, capture-owner
565+
metadata and remaining panel/backend migrations stay in `Progress.md`.
566+
567+
`python -m examples.cancellable_diagnostics` runs a controlled cancellation demo
568+
without providers. `--active --cancel-after 2` explicitly runs diagnostics and
569+
requests stop after two seconds; native/device/API acceptance remains separate.
543570

544571
Opening Diagnostics displays a localized not-run state and performs no checks.
545572
Choose **Actions → Run diagnostics** to start the existing active checks, which
@@ -590,7 +617,7 @@ ignore synthetic input, and fall back silently when the driver is absent.
590617

591618
| Resource | What's in it |
592619
|---|---|
593-
| [`examples/`](examples/) | 42 self-contained scripts: screenshot + click, OCR, scheduler, remote desktop, agent loop, observability, recording, variables, hotkeys, triggers, reports, MCP, REST, secrets, plugins, computer use, Wayland, cross-host DAGs, chat-ops, pytest/BDD, anchor locators, action journals. |
620+
| [`examples/`](examples/) | 43 self-contained scripts: screenshot + click, OCR, scheduler, remote desktop, agent loop, observability, recording, variables, hotkeys, triggers, reports, MCP, REST, secrets, plugins, computer use, Wayland, cross-host DAGs, chat-ops, pytest/BDD, anchor locators, action journals. |
594621
| [Read the Docs](https://autocontrol.readthedocs.io/en/latest/) | Full API reference, English and 中文. |
595622
| [architecture_explore.md](architecture_explore.md) | Every module's responsibility, layer by layer. |
596623
| [docs/CAPABILITY_MATRIX.md](docs/CAPABILITY_MATRIX.md) | Capability × platform matrix. |

‎README/README_zh-CN.md‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ je_auto_control version
319319

320320
| 接口 | 启动方式 | 说明 |
321321
|---|---|---|
322-
| **MCP 服务器** | `je_auto_control_mcp`(stdio)或 `AC_start_mcp_http_server` | 710 个工具,供 Claude Desktop/Claude Code/自定义 tool loop 使用:完整的 `ac_*` 工具接口,以及常用 GUI 操作的短名称 alias。除了以 `initialize` 握手的各版协议,也支持无状态的 MCP 2026-07-28。Bearer 认证、TLS、审计日志、限流、插件热重载、CI 假后端。 |
322+
| **MCP 服务器** | `je_auto_control_mcp`(stdio)或 `AC_start_mcp_http_server` | 711 个工具,供 Claude Desktop/Claude Code/自定义 tool loop 使用:完整的 `ac_*` 工具接口,以及常用 GUI 操作的短名称 alias。除了以 `initialize` 握手的各版协议,也支持无状态的 MCP 2026-07-28。Bearer 认证、TLS、审计日志、限流、插件热重载、CI 假后端。 |
323323
| **REST API** | `je_auto_control start-rest` | Bearer token、按 IP 限流与锁定、SQLite 审计 hook、`/metrics`、`/openapi.json`、`/docs` Swagger UI、`/dashboard`。 |
324324
| **TCP socket 服务器** | `je_auto_control start-server` | 以换行分隔的 JSON 动作列表。默认绑定 `127.0.0.1`。 |
325325
| **pytest 插件** | 安装后自动生效 | 提供 fixture 与供 pytest-bdd/behave 使用的 Gherkin step library。 |
@@ -462,7 +462,7 @@ Context 会复制环境/工具数据,可由拥有者提供无原生对象的
462462
默认本机结果不含环境值、命令参数、可执行文件路径或原生错误文字;AC/MCP 不接受外部提供观察。
463463
显式选择 CLI 与观察到可选原生依赖缺失后的自动备用分开;拒绝、暂停、撤销与失败不表示改走 CLI。
464464
截取工具/portal 选择独立诊断,重绘与切换语言只使用现有快照。原生 portal 恢复、compositor 重启、
465-
截取结果与 context 的接合,以及可取消的主动诊断仍列于 `Progress.md`。
465+
截取结果与 context 的接合,以及原生 session 的重试/取消/停止控制仍列于 `Progress.md`。
466466

467467
GUI 工作基础提供 `gui.task_controller.TaskController`:
468468
`submit(work, owner=widget)` 返回调用者持有的 `TaskHandle`,通过
@@ -474,12 +474,30 @@ GUI 工作基础提供 `gui.task_controller.TaskController`:
474474
拥有者、handle 或 controller 销毁时会请求协作式停止并丢弃延迟结果;每项工作有独立 ID/token,
475475
回调在 GUI 线程执行。不强制中断不配合的调用,也不把已成功提交的结果改标为取消。
476476
错误与进度使用捕获的秘密遮罩 scope,终态不保留异常 traceback;线程启动失败会恢复两层登记并保留原失败。
477-
这是共用基础;Diagnostics 与其余面板的 controller/timeout/停止控制整合仍列于 `Progress.md`。
478-
479-
主动诊断的检查若抛出显式取消或中断控制(含显式的异常原因链),立即停止,
480-
并由核心、SDK、CLI 与 Diagnostics 操作传递原始对象,不记录为普通错误或失败报告行,
481-
也不执行后续检查。普通检查错误仍产生失败行并继续其余项目;GUI 取消后可显式重试。
482-
后台 worker 与协作式停止控制仍待完成。
477+
Diagnostics 已接入此共用控制器;其余面板/backend 迁移与原生 session 操作仍列于 `Progress.md`。
478+
479+
主动 **Diagnostics → Actions → 运行诊断** 以共用控制器在 GUI 线程外运行。
480+
**停止诊断** 请求协作式停止;四种语言的状态区分运行中、清理中、已取消和失败,并显示已完成检查数。
481+
重复运行不另开工作,关闭后丢弃延迟进度/结果,显式重试会建立新的拥有者工作。
482+
GUI 以不保留异常 traceback 的 typed outcome 呈现取消;核心/SDK/CLI 与 MCP handler
483+
保持原始直接/包装取消对象。普通检查错误仍计入报告并继续其余项目。
484+
485+
两个 SDK namespace 导出 `CancellationToken`、`TaskProgress`、`cancellation_scope`。
486+
使用 `with cancellation_scope(token): report = run_diagnostics()`,拥有者可由另一线程调用
487+
`token.cancel()`;现有无参数诊断签名不变。Scope 不授予权限,`cancellation_scope(None)`
488+
只在有时限的自有资源清理期间暂停取消。`AC_diagnose` 与新增的只读 `ac_diagnose` 共用报告;
489+
MCP 不接受参数,使用请求取消/进度,与显式 GUI 操作同样需要 `read_screen`,拒绝外部 token/授权数据。
490+
这些是主动检查,截取可能请求同意;`ac_probe_capabilities` 保持独立的被动选项。
491+
492+
Scoped Wayland D-Bus 的连接/读取/部分写入,以最多 0.1 秒的间隔轮询,保持原本总时限。
493+
取消时在原 bus 以独立 0.25 秒预算尝试 Request.Close,再释放连接;取消的已返回图片会删除。
494+
Scoped CLI 截取会停止并回收自己建立的 helper/process group,清理有时限,pipe close 失败也不覆盖原取消,
495+
已回收的数字 PID 不再作为信号目标。liboeffis 获取 session 时会观察停止并释放自身 context。
496+
不强制中断不配合或原生调用,清理期间 GUI 仍可操作;restore/重启、原生 session 控制、
497+
截取拥有者 metadata 与其余面板/backend 迁移保留于 `Progress.md`。
498+
499+
`python -m examples.cancellable_diagnostics` 默认只做受控取消示例,不调用 provider。
500+
`--active --cancel-after 2` 才显式运行诊断并在两秒后请求停止;真机/设备/API 验收另外列管。
483501

484502
打开 Diagnostics 只显示已翻译的「尚未运行」状态,不执行检查。
485503
选择 **Actions → 运行诊断** 才会启动现有主动检查,可能截取屏幕或需要 portal 同意;
@@ -521,7 +539,7 @@ Windows、macOS(pyobjc)与 X11(含 XWayland);纯 Wayland 会话的协
521539

522540
| 资源 | 内容 |
523541
|---|---|
524-
| [`examples/`](../examples/) | 42 个自包含脚本:截图点击、OCR、调度器、远程桌面、agent loop、可观测性、录制、变量、热键、触发器、报表、MCP、REST、密钥、插件、computer use、Wayland、跨主机 DAG、chat-ops、pytest/BDD、锚点定位、动作日志。 |
542+
| [`examples/`](../examples/) | 43 个自包含脚本:截图点击、OCR、调度器、远程桌面、agent loop、可观测性、录制、变量、热键、触发器、报表、MCP、REST、密钥、插件、computer use、Wayland、跨主机 DAG、chat-ops、pytest/BDD、锚点定位、动作日志。 |
525543
| [Read the Docs](https://autocontrol.readthedocs.io/en/latest/) | 完整 API 参考,含英文与中文。 |
526544
| [architecture_explore.md](../architecture_explore.md) | 逐层记录每个模块的职责。 |
527545
| [docs/CAPABILITY_MATRIX.md](../docs/CAPABILITY_MATRIX.md) | 能力 × 平台对照矩阵。 |

0 commit comments

Comments
 (0)