Bundle
dsh-computer-control
dsh bundle for computer-control: desktop control (screen capture, pointer/keyboard injection, accessibility-tree semantic actions, safety guards) bridged to the harness over stdio JSON-RPC.
- Source
- JohnXu22786
- stars
- 1 stars
- License
- MIT
- Updated
- Updated yesterday
Readme
[简体中文](README.zh.md)
# computer-control — Desktop Control Plugin (for dsh)
Lets an agent operate the computer desktop directly: screenshot observation, mouse/keyboard injection, semantic actions via the accessibility tree (semantics first, pixel-coordinate fallback), with built-in safety guards — emergency stop, allow/deny rules, confirmation flow and idle standby.
The plugin is self-contained and loadable by dsh directly: it declares tools and events via `manifest.json`, speaks **line-delimited JSON-RPC 2.0** (stdio) as its transport protocol, and `python -m computer_control serve` is the entry point.
---
## Feature Overview
| Capability | Description |
| --- | --- |
| Screenshot `screen.capture` | Full-screen or region capture, PNG/JPEG, scaling, grayscale — token costs under control |
| Mouse `pointer.*` | Move, left/middle/right click (double/triple), drag, scroll (horizontal/vertical) |
| Keyboard `keyboard.*` | Single keys, chords (scancode injection, layout-independent), arbitrary Unicode text input |
| Wait `wait.pause` | Pause between actions so the UI can settle before the next screenshot |
| Semantic actions `a11y.*` | Hierarchical accessibility-tree summaries (skeleton/standard/full), semantic activate/input — UIA mode first, automatic fallback to bounding-box pixel clicks |
| Batch `batch.execute` | Run several actions in one call to reduce model round trips; confirmable as a whole, can continue on error |
| Capability broadcast | `tools.list` / `system.status` report per-backend availability; semantic tools are only exposed when UIA is available |
Safety guards (see the "Safety" section):
- **Emergency stop**: triple trigger — global hotkey (default `Ctrl+Alt+F12`, configurable), protocol command, panic file; a STOP banner shows in the screen corner
- **Allow/deny rules**: matched by tool name and arguments, deny always wins; whitelist mode switchable
- **Confirmation flow**: high-risk actions (including chords with `win` or `ctrl+alt`) wait for human approval, auto-denied on timeout
- **Idle standby**: no activity past a threshold puts the session into standby, rejecting all actions until resumed
- **Dry-run mode**: `platform: "dry-run"` logs actions without executing them, for safe rehearsals
## Directory Structure
```
computer-control/
├── manifest.json # dsh plugin manifest (tools/events/entry/transport)
├── pyproject.toml # packaging metadata and dependency declarations
├── requirements.txt # core dependencies (Pillow only)
├── requirements-optional.txt# optional capability deps (UIA/mss/hotkey)
├── README.md
├── docs/ # integration / protocol / actions / configuration
├── examples/ # config examples, session examples, demo scripts
├── computer_control/ # plugin implementation (Python package)
│ ├── cli.py __main__.py # entry: serve / check / list
│ ├── session.py # session lifecycle and serial action execution
│ ├── engine.py # action execution engine (coordinate mapping, events)
│ ├── policy.py # safety gate: rules/confirmation/panic/watchdog
│ ├── actions.py # action registry and argument validation
│ ├── geometry.py # model canvas <-> physical pixel mapping
│ ├── protocol.py server.py# JSON-RPC routing and stdio/HTTP transports
│ ├── client.py # client for harness/scripts
│ ├── overlay.py # emergency-stop visual banner (optional, tkinter)
│ ├── drivers/ # execution-layer abstraction + windows impl + dry-run driver
│ └── a11y/ # accessibility-tree summaries + Windows UIA bridge
└── tests/ # pure-logic and protocol tests (no real hardware)
```
## Installing in DSH
```bash
dsh plugin --profile demo add github:JohnXu22786/computer-control
```
Remove with:
```bash
dsh plugin --profile demo remove computer-control
```
### dsh bundle
The repo also ships a Cordis bundle so anything that consumes `dsh.bundle`
manifests can install it the same way: `package.json` declares
`dsh.bundle.patch` pointing at `cordis.patch.yml`, and `index.js` is the bridge
a dsh profile loads. It spawns `python -m computer_control serve` as a child
process and re-exposes every tool from `manifest.json` to the harness over the
stdio protocol — the Python core is left untouched. Profile-level settings can
be pinned through the patch row's `config` (e.g. `platform.name: dry-run` for a
rehearsal-only install).
Requirements for the bridge: `node >= 18` and a Python 3.9+ interpreter with
this package installed (`pip install -r requirements.txt` is enough for the
core tools).
## Installation
Requirements: **Python 3.9+**, Windows 10/11 (full functionality); other platforms see "Platform Support".
```powershell
# Core (screenshot + input injection)
pip install -r requirements.txt
# Optional capabilities (recommended):
# comtypes -> accessibility-tree (UIA) semantic actions
# mss -> faster multi-monitor screenshot backend
pip install -r requirements-optional.txt
```
Environment self-check:
```powershell
python -m computer_control check
```
Prints diagnostics for platform, DPI mode, virtual-desktop geometry, screenshot backend, UIA availability, hotkeys, etc.
## Quick Start
```powershell
# List declared tools and events
python -m computer_control list
# Start the plugin service (stdio, for dsh to load)
python -m computer_control serve
```
Run a rehearsal session with `examples/demo.py` (defaults to `dry-run`, touches nothing on the real desktop):
```powershell
python examples/demo.py
```
## dsh Integration (Summary)
Full integration notes: [`docs/integration.md`](docs/integration.md).
1. **Loading**: dsh reads `manifest.json`, starts the process via `entry.command`, and establishes a stdio pipe (UTF-8, one JSON object per line).
2. **Lifecycle**: send `session.start` (optionally with config) → wait for the `session.started` event, then call tools; send `session.stop` at the end.
3. **Calling actions**: `tools.call` (single) or `tools.call_batch` (batch). Responses use a unified `{ok, result, error, meta}` envelope.
4. **Events**: the server pushes `action.started/finished`, `safety.confirmation_requested`, etc. as `event` notifications.
5. **Confirmation flow**: high-risk actions return `awaiting_confirmation` and emit a confirmation event; the harness should surface a human approval prompt, then reply via `session.confirm`; timed out confirmations are auto-denied.
The recommended model loop: `screen.capture` to observe → execute `pointer.*` / `a11y.*` on canvas coordinates → `wait.pause` (if needed) → a fresh screenshot to verify the result.
## Action Reference (Summary)
All actions, parameters and examples: [`docs/actions.md`](docs/actions.md).
| Action | Purpose | Risk |
| --- | --- | --- |
| `screen.capture` | Screenshot (region/format/scale/grayscale) | none |
| `pointer.move` | Move pointer | moderate |
| `pointer.click` | Single/double/triple click, optional position | moderate |
| `pointer.drag` | Press and drag | moderate |
| `pointer.scroll` | Wheel (horizontal/vertical) | moderate |
| `keyboard.press` | Single key | moderate |
| `keyboard.combo` | Chord (upgrades to high when it includes win or ctrl+alt) | moderate/high |
| `keyboard.type` | Text input (Unicode) | moderate |
| `wait.pause` | Pause | none |
| `a11y.snapshot` | Hierarchical accessibility-tree summary | none |
| `a11y.activate` | Semantic activation (pattern first, pixel fallback) | moderate |
| `a11y.input` | Semantic text input (value pattern first) | moderate |
| `batch.execute` | Batch execution | max of items |
### Coordinate Contract
The model sees a **canvas**, not the raw screen: screenshots are scaled to an aspect-preserving canvas whose width is `display_width_px` (default 1920), and coordinates returned by the model live on that canvas; the plugin maps them back to physical pixels uniformly via `scale = physical width / canvas width`. The `screen.capture` result carries a `canvas` field along with `display_width_px/display_height_px` as the source of truth. Multi-monitor setups (including negative-coordinate regions left/above the primary display) and per-monitor DPI are handled in the execution layer.
## Safety
See [`docs/configuration.md`](docs/configuration.md#safety) and the points below:
- **Emergency stop (triple)**: default global hotkey `Ctrl+Alt+F12` (configurable via `safety.emergency_hotkey`, set empty to disable); protocol method `control.panic`; panic file (`safety.panic_file`, presence stops everything). After a panic all actions return `safety_stopped`; `session.resume` or pressing the hotkey again restores operation. A red STOP banner shows in the screen corner while engaged (`safety.visual_indicator`).
- **Allow/deny rules** (`safety.rules`): `{match: {tool: "keyboard.*", argument: {name, matcher, value}}, effect: "deny"}`; deny rules always win over allow rules. `safety.default_rule: "deny"` switches to whitelist mode (anything not explicitly allowed is denied). Rules can be adjusted at runtime via `session.configure`.
- **Confirmation flow**: `safety.confirm_threshold` (default `high`) decides which risk levels need human approval; `safety.confirm_timeout_s` (default 30s) auto-denies on timeout. Approved actions execute normally and emit `action.finished`.
- **Idle standby**: enabled when `safety.idle_timeout_s` > 0; after no activity for the timeout the session enters standby (emits `session.idle`), `session.resume` restores it; `idle_action: "none"` only emits the event without pausing.
- **Dry-run mode**: with `platform: "dry-run"` every action is logged but never executed — handy for integration debugging and safety rehearsals.
## Platform Support
| Platform | Driver | Notes |
| --- | --- | --- |
| Windows | `drivers/windows.py` | Full implementation: SendInput scancode injection, per-monitor DPI awareness, virtual-desktop coordinates, mss/Pillow screenshots, UIA semantic layer |
| macOS / Linux | interface abstracted | `drivers/base.py` defines the complete driver contract (capture/pointer/keys/a11y/hotkey); implement it per platform to plug in (`drivers/windows.py` is a complete example). Until implemented, `platform: "auto"` fails with a clear error |
| Any platform | `drivers/dummy.py` | Dry-run driver: records every action, touches no hardware |
**Dependencies and degradation**:
- `Pillow` (required): screenshots and encoding. The plugin refuses to start without it.
- `mss` (optional): faster and more reliable on multi-monitor Windows; falls back to Pillow ImageGrab when missing.
- `comtypes` (optional): UIA semantic actions. When missing, `a11y.*` tools are marked unavailable in `tools.list` and calls return `backend_unavailable` — the pixel-coordinate path (screenshot + click) is unaffected.
- `keyboard` (optional, reserved): global hotkeys on macOS/Linux drivers will depend on it; only the Windows and dry-run drivers ship today, and Windows uses built-in `GetAsyncKeyState` polling, so the package is not needed.
**Known limitations**:
- Secure attention sequences (e.g. `Ctrl+Alt+Del`) cannot be triggered via input injection — an OS-level protection that the plugin cannot bypass either.
- UIA depends on the target program exposing an accessibility interface; programs that do not (some games, self-drawn UIs) can only use the pixel path.
- Keyboard scancode injection works better with DirectInput/raw-input programs, but some anti-cheat programs may still reject it (normal protective behavior).
## Testing
```powershell
python -m unittest discover -s tests -v
```
Tests use only pure logic and the dry-run driver — no real input is injected, no real hardware is touched; the real Windows chain is verified manually via `python -m computer_control check` and `examples/demo.py --live`.
## License
MIT — see [LICENSE](LICENSE). Copyright (c) 2026 JohnXu22786.
Install
dsh plugin --profile web add github:JohnXu22786/computer-control#aeedb67348db55e8402e987463e4766629adac80
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-computer-control from the hub