dsh-click 0.1.3 → 0.2.0
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.md +12 -0
- package/README.es.md +3 -1
- package/README.hi.md +3 -1
- package/README.md +3 -1
- package/README.pt.md +3 -1
- package/README.zh.md +3 -1
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/cordis.patch.yml +9 -0
- package/lib/index.js +411 -13
- package/lib/types/config.d.ts +21 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/index.d.ts +6 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/tools.d.ts +17 -0
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/version.d.ts +1 -1
- package/lib/types/vision/grounding.d.ts +46 -0
- package/lib/types/vision/grounding.d.ts.map +1 -0
- package/lib/types/vision/index.d.ts +41 -0
- package/lib/types/vision/index.d.ts.map +1 -0
- package/lib/types/vision/ocr.d.ts +89 -0
- package/lib/types/vision/ocr.d.ts.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2026-08-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- OCR and visual grounding providers for no-UIA windows.
|
|
13
|
+
|
|
14
|
+
## [0.1.4] - 2026-08-23
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Three-interface assertions (model schema + canonical value + content blocks) for `screen_shot` and `click`, completing the U2 tool-surface coverage alongside the existing `screen_read` assertion.
|
|
19
|
+
|
|
8
20
|
## [0.1.3] - 2026-08-22
|
|
9
21
|
|
|
10
22
|
### Changed
|
package/README.es.md
CHANGED
|
@@ -103,6 +103,7 @@ Todos los ajustes son campos `Config` de Schemastery (modificables desde cordis.
|
|
|
103
103
|
| `maxTreeDepth` | `32` | Profundidad máxima del recorrido del árbol de accesibilidad (1..64) |
|
|
104
104
|
| `maxTextLength` | `200` | Longitud de truncado de las cadenas visibles para el modelo (16..10000) |
|
|
105
105
|
| `rollbackEnabled` | `true` | Respaldar y restaurar el texto del control cuando `type` falla |
|
|
106
|
+
| `ocr.enabled` / `command` / `language` | `true` / `tesseract` / `eng` | OCR opcional para `screen_find` (probado al montar; degrada a no disponible sin tesseract) |
|
|
106
107
|
|
|
107
108
|
Ejemplo de sobrescritura en el parche de tu perfil:
|
|
108
109
|
|
|
@@ -157,7 +158,7 @@ Ejemplo de sobrescritura en el parche de tu perfil:
|
|
|
157
158
|
pnpm install # node ^22.19 || >=24
|
|
158
159
|
pnpm run typecheck # tsc: src + tests contra el checkout local del harness
|
|
159
160
|
pnpm run typecheck:ci # tsc contra los tipos publicados 0.1.1-rc.2 (sin paths)
|
|
160
|
-
pnpm test # vitest:
|
|
161
|
+
pnpm test # vitest: 66 tests, 11 archivos (el smoke del helper corre en Windows)
|
|
161
162
|
pnpm run build # bundle tsdown + declaraciones tsc (lib/)
|
|
162
163
|
pnpm run verify:self-contained # las especificaciones de dependencias resuelven desde el registry
|
|
163
164
|
pnpm run verify:artifacts # cara ESM construida + helper nativo presentes
|
|
@@ -171,6 +172,7 @@ pnpm pack # el tarball publicado
|
|
|
171
172
|
## Contributors
|
|
172
173
|
|
|
173
174
|
- [@PerryLink](https://github.com/PerryLink) — creador y mantenedor: superficie de herramientas, frontera de seguridad de acciones, helper nativo de Windows, sanitizadores y la documentación en cinco idiomas.
|
|
175
|
+
- [@Mchsd](https://github.com/Mchsd) — añadió la opción `auditSessionEvents` para harnesses cuyo lector de sesión rechaza los eventos de auditoría de `dsh-click` (#2).
|
|
174
176
|
|
|
175
177
|
## PerryLink DSH Plugin Family
|
|
176
178
|
|
package/README.hi.md
CHANGED
|
@@ -103,6 +103,7 @@ dsh --profile web --dump-config | grep -A2 'id: dsh-click'
|
|
|
103
103
|
| `maxTreeDepth` | `32` | एक्सेसिबिलिटी ट्री-वॉक की अधिकतम गहराई (1..64) |
|
|
104
104
|
| `maxTextLength` | `200` | सैनिटाइज़्ड मॉडल-दृश्य स्ट्रिंग्स की काट-छाँट लंबाई (16..10000) |
|
|
105
105
|
| `rollbackEnabled` | `true` | `type` विफल होने पर नियंत्रण टेक्स्ट का बैकअप और पुनर्स्थापन |
|
|
106
|
+
| `ocr.enabled` / `command` / `language` | `true` / `tesseract` / `eng` | `screen_find` के लिए वैकल्पिक OCR (माउंट पर जाँच; tesseract अनुपस्थित होने पर अनुपलब्ध) |
|
|
106
107
|
|
|
107
108
|
आपके प्रोफ़ाइल पैच में ओवरराइड उदाहरण:
|
|
108
109
|
|
|
@@ -157,7 +158,7 @@ dsh --profile web --dump-config | grep -A2 'id: dsh-click'
|
|
|
157
158
|
pnpm install # node ^22.19 || >=24
|
|
158
159
|
pnpm run typecheck # tsc: src + tests स्थानीय हार्नेस चेकआउट के विरुद्ध
|
|
159
160
|
pnpm run typecheck:ci # tsc प्रकाशित 0.1.1-rc.2 प्रकारों के विरुद्ध (बिना paths)
|
|
160
|
-
pnpm test # vitest:
|
|
161
|
+
pnpm test # vitest: 66 टेस्ट, 11 फ़ाइलें (हेल्पर स्मोक Windows पर चलता है)
|
|
161
162
|
pnpm run build # tsdown बंडल + tsc घोषणाएँ (lib/)
|
|
162
163
|
pnpm run verify:self-contained # निर्भरता स्पेक registry से हल होती हैं
|
|
163
164
|
pnpm run verify:artifacts # निर्मित ESM फ़ेस + नेटिव हेल्पर मौजूद
|
|
@@ -171,6 +172,7 @@ pnpm pack # प्रकाशित tarball
|
|
|
171
172
|
## Contributors
|
|
172
173
|
|
|
173
174
|
- [@PerryLink](https://github.com/PerryLink) — निर्माता और मेंटेनर: टूल सतह, क्रिया सुरक्षा सीमा, Windows नेटिव हेल्पर, सैनिटाइज़र और पाँच-भाषा दस्तावेज़।
|
|
175
|
+
- [@Mchsd](https://github.com/Mchsd) — उन harnesses के लिए `auditSessionEvents` ऑप्ट-आउट जोड़ा जिनका सत्र रीडर `dsh-click` ऑडिट इवेंट को अस्वीकार करता है (#2)।
|
|
174
176
|
|
|
175
177
|
## PerryLink DSH Plugin Family
|
|
176
178
|
|
package/README.md
CHANGED
|
@@ -104,6 +104,7 @@ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id
|
|
|
104
104
|
| `maxTreeDepth` | `32` | Maximum accessibility tree-walk depth (1..64) |
|
|
105
105
|
| `maxTextLength` | `200` | Truncation length for sanitized model-visible strings (16..10000) |
|
|
106
106
|
| `rollbackEnabled` | `true` | Back up and restore control text when `type` fails |
|
|
107
|
+
| `ocr.enabled` / `command` / `language` | `true` / `tesseract` / `eng` | Optional OCR for the `screen_find` path (probed at mount; degrades to unavailable when tesseract is absent) |
|
|
107
108
|
|
|
108
109
|
Example override in your profile patch:
|
|
109
110
|
|
|
@@ -158,7 +159,7 @@ Example override in your profile patch:
|
|
|
158
159
|
pnpm install # node ^22.19 || >=24
|
|
159
160
|
pnpm run typecheck # tsc: src + tests against the local harness checkout
|
|
160
161
|
pnpm run typecheck:ci # tsc against the published 0.1.1-rc.2 types (no paths)
|
|
161
|
-
pnpm test # vitest:
|
|
162
|
+
pnpm test # vitest: 66 tests, 11 files (helper smoke runs on Windows)
|
|
162
163
|
pnpm run build # tsdown bundle + tsc declarations (lib/)
|
|
163
164
|
pnpm run verify:self-contained # dependency specs resolve from the registry
|
|
164
165
|
pnpm run verify:artifacts # built ESM face + native helper present
|
|
@@ -172,6 +173,7 @@ pnpm pack # the published tarball
|
|
|
172
173
|
## Contributors
|
|
173
174
|
|
|
174
175
|
- [@PerryLink](https://github.com/PerryLink) — creator and maintainer: tool surface, action safety boundary, Windows native helper, sanitizers, and the five-language docs.
|
|
176
|
+
- [@Mchsd](https://github.com/Mchsd) — added the `auditSessionEvents` opt-out for harnesses whose session reader rejects the `dsh-click` audit events (#2).
|
|
175
177
|
|
|
176
178
|
## PerryLink DSH Plugin Family
|
|
177
179
|
|
package/README.pt.md
CHANGED
|
@@ -103,6 +103,7 @@ Todos os ajustes são campos `Config` do Schemastery (alteráveis pelo cordis.ym
|
|
|
103
103
|
| `maxTreeDepth` | `32` | Profundidade máxima do percurso da árvore de acessibilidade (1..64) |
|
|
104
104
|
| `maxTextLength` | `200` | Comprimento de truncamento das strings visíveis ao modelo (16..10000) |
|
|
105
105
|
| `rollbackEnabled` | `true` | Fazer backup e restaurar o texto do controle quando `type` falha |
|
|
106
|
+
| `ocr.enabled` / `command` / `language` | `true` / `tesseract` / `eng` | OCR opcional para `screen_find` (detectado na montagem; degrada para indisponível sem tesseract) |
|
|
106
107
|
|
|
107
108
|
Exemplo de sobrescrita no patch do seu perfil:
|
|
108
109
|
|
|
@@ -157,7 +158,7 @@ Exemplo de sobrescrita no patch do seu perfil:
|
|
|
157
158
|
pnpm install # node ^22.19 || >=24
|
|
158
159
|
pnpm run typecheck # tsc: src + tests contra o checkout local do harness
|
|
159
160
|
pnpm run typecheck:ci # tsc contra os tipos publicados 0.1.1-rc.2 (sem paths)
|
|
160
|
-
pnpm test # vitest:
|
|
161
|
+
pnpm test # vitest: 66 testes, 11 arquivos (o smoke do helper roda no Windows)
|
|
161
162
|
pnpm run build # bundle tsdown + declarações tsc (lib/)
|
|
162
163
|
pnpm run verify:self-contained # especificações de dependências resolvem pelo registry
|
|
163
164
|
pnpm run verify:artifacts # face ESM construída + helper nativo presentes
|
|
@@ -171,6 +172,7 @@ pnpm pack # o tarball publicado
|
|
|
171
172
|
## Contributors
|
|
172
173
|
|
|
173
174
|
- [@PerryLink](https://github.com/PerryLink) — criador e mantenedor: superfície de ferramentas, fronteira de segurança das ações, helper nativo do Windows, sanitizadores e a documentação em cinco idiomas.
|
|
175
|
+
- [@Mchsd](https://github.com/Mchsd) — adicionou a opção `auditSessionEvents` para harnesses cujo leitor de sessão rejeita os eventos de auditoria do `dsh-click` (#2).
|
|
174
176
|
|
|
175
177
|
## PerryLink DSH Plugin Family
|
|
176
178
|
|
package/README.zh.md
CHANGED
|
@@ -103,6 +103,7 @@ dsh --profile web --dump-config | grep -A2 'id: dsh-click'
|
|
|
103
103
|
| `maxTreeDepth` | `32` | 无障碍树遍历最大深度(1..64) |
|
|
104
104
|
| `maxTextLength` | `200` | 脱敏后模型可见字符串的截断长度(16..10000) |
|
|
105
105
|
| `rollbackEnabled` | `true` | `type` 失败时备份并还原控件文本 |
|
|
106
|
+
| `ocr.enabled` / `command` / `language` | `true` / `tesseract` / `eng` | `screen_find` 的可选 OCR(挂载时探测;无 tesseract 时降级为不可用) |
|
|
106
107
|
|
|
107
108
|
profile patch 中的覆盖示例:
|
|
108
109
|
|
|
@@ -157,7 +158,7 @@ profile patch 中的覆盖示例:
|
|
|
157
158
|
pnpm install # node ^22.19 || >=24
|
|
158
159
|
pnpm run typecheck # tsc:src + tests,对照本地 harness checkout
|
|
159
160
|
pnpm run typecheck:ci # tsc:对照已发布的 0.1.1-rc.2 类型(无 paths)
|
|
160
|
-
pnpm test # vitest:
|
|
161
|
+
pnpm test # vitest:66 个测试、11 个文件(helper 冒烟在 Windows 上运行)
|
|
161
162
|
pnpm run build # tsdown bundle + tsc 声明(lib/)
|
|
162
163
|
pnpm run verify:self-contained # 依赖声明全部来自 registry
|
|
163
164
|
pnpm run verify:artifacts # 构建产物 ESM 面 + 原生 helper 齐全
|
|
@@ -171,6 +172,7 @@ pnpm pack # 发布用 tarball
|
|
|
171
172
|
## Contributors
|
|
172
173
|
|
|
173
174
|
- [@PerryLink](https://github.com/PerryLink) —— 创建者与维护者:工具面、操作安全边界、Windows 原生 helper、脱敏层与五语文档。
|
|
175
|
+
- [@Mchsd](https://github.com/Mchsd) —— 新增 `auditSessionEvents` 开关,供会话读取器拒绝 `dsh-click` 审计事件的主机退出审计追加(#2)。
|
|
174
176
|
|
|
175
177
|
## PerryLink DSH Plugin Family
|
|
176
178
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -14,7 +14,7 @@ published tarball; these are install-time dependencies:
|
|
|
14
14
|
| [typescript](https://github.com/microsoft/TypeScript) | `^5.9.0` | Apache-2.0 | Build-time declaration emission (`lib/types/`) |
|
|
15
15
|
| [@deepseek-ai/cordis](https://www.npmjs.com/package/@deepseek-ai/cordis) | `^4.0.1` (peer) | See package | The plugin runtime |
|
|
16
16
|
| [@deepseek-ai/schemastery](https://www.npmjs.com/package/@deepseek-ai/schemastery) | `^3.18.0` (peer) | See package | Configuration schema |
|
|
17
|
-
| `@deepseek-ai/dsh-*` peers |
|
|
17
|
+
| `@deepseek-ai/dsh-*` peers | `>=0.1.0-rc.8 <0.2.0` | See packages | Official harness seams (`dsh-tools`, `dsh-session`, `dsh-subprocess`, `dsh-llm`, `dsh-attachment`, `dsh-agent`, `dsh-user-approval`) |
|
|
18
18
|
|
|
19
19
|
At runtime the plugin only talks to the harness services listed as
|
|
20
20
|
peerDependencies; it performs no network requests of its own.
|
package/cordis.patch.yml
CHANGED
|
@@ -51,3 +51,12 @@
|
|
|
51
51
|
# Back up and restore control text when `type` fails (true = restore
|
|
52
52
|
# the original text; false = leave the partially typed text).
|
|
53
53
|
rollbackEnabled: true
|
|
54
|
+
# Optical character recognition for windows without a UIA tree.
|
|
55
|
+
ocr:
|
|
56
|
+
# Enable the OCR path in screen_find (true = probe tesseract at
|
|
57
|
+
# mount and use it when available).
|
|
58
|
+
enabled: true
|
|
59
|
+
# tesseract executable name.
|
|
60
|
+
command: tesseract
|
|
61
|
+
# tesseract language tag.
|
|
62
|
+
language: eng
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
4
|
+
import path, { join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
7
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
7
9
|
//#region src/events.ts
|
|
8
10
|
/** The observation audit event type. */
|
|
9
11
|
const OBSERVED_EVENT = "dsh-click/observed";
|
|
@@ -348,7 +350,12 @@ const Config = z.object({
|
|
|
348
350
|
maxElements: z.number().min(1).max(MAX_ELEMENTS).default(500),
|
|
349
351
|
maxTreeDepth: z.number().min(1).max(64).default(32),
|
|
350
352
|
maxTextLength: z.number().min(16).max(MAX_TEXT_LENGTH).default(200),
|
|
351
|
-
rollbackEnabled: z.boolean().default(true)
|
|
353
|
+
rollbackEnabled: z.boolean().default(true),
|
|
354
|
+
ocr: z.object({
|
|
355
|
+
enabled: z.boolean().default(true),
|
|
356
|
+
command: z.string().min(1).max(256).default("tesseract"),
|
|
357
|
+
language: z.string().min(1).max(32).default("eng")
|
|
358
|
+
})
|
|
352
359
|
});
|
|
353
360
|
/** Throw the standard fail-loud config error for one invalid field. */
|
|
354
361
|
function invalid(field, detail) {
|
|
@@ -398,6 +405,12 @@ function resolveConfig(config) {
|
|
|
398
405
|
if (!Number.isInteger(maxTextLength) || maxTextLength < 16 || maxTextLength > 1e4) invalid("maxTextLength", `must be an integer between 16 and ${MAX_TEXT_LENGTH}`);
|
|
399
406
|
const rollbackEnabled = config?.rollbackEnabled ?? true;
|
|
400
407
|
if (typeof rollbackEnabled !== "boolean") invalid("rollbackEnabled", "must be a boolean");
|
|
408
|
+
const ocrEnabled = config?.ocr?.enabled ?? true;
|
|
409
|
+
if (typeof ocrEnabled !== "boolean") invalid("ocr.enabled", "must be a boolean");
|
|
410
|
+
const ocrCommand = config?.ocr?.command ?? "tesseract";
|
|
411
|
+
if (typeof ocrCommand !== "string" || ocrCommand.length === 0 || ocrCommand.length > 256) invalid("ocr.command", "must be a non-empty string of at most 256 characters");
|
|
412
|
+
const ocrLanguage = config?.ocr?.language ?? "eng";
|
|
413
|
+
if (typeof ocrLanguage !== "string" || ocrLanguage.length === 0 || ocrLanguage.length > 32) invalid("ocr.language", "must be a non-empty string of at most 32 characters");
|
|
401
414
|
return Object.freeze({
|
|
402
415
|
requireApproval,
|
|
403
416
|
autoApproveMatchers: Object.freeze(autoApproveMatchers),
|
|
@@ -413,7 +426,12 @@ function resolveConfig(config) {
|
|
|
413
426
|
maxElements,
|
|
414
427
|
maxTreeDepth,
|
|
415
428
|
maxTextLength,
|
|
416
|
-
rollbackEnabled
|
|
429
|
+
rollbackEnabled,
|
|
430
|
+
ocr: Object.freeze({
|
|
431
|
+
enabled: ocrEnabled,
|
|
432
|
+
command: ocrCommand,
|
|
433
|
+
language: ocrLanguage
|
|
434
|
+
})
|
|
417
435
|
});
|
|
418
436
|
}
|
|
419
437
|
//#endregion
|
|
@@ -538,7 +556,7 @@ var ObservationStore = class {
|
|
|
538
556
|
* @module dsh-click/version
|
|
539
557
|
*/
|
|
540
558
|
/** Plugin version advertised in the helper-protocol handshake. */
|
|
541
|
-
const VERSION = "0.
|
|
559
|
+
const VERSION = "0.2.0";
|
|
542
560
|
/** The helper protocol revision; bump only on incompatible wire changes. */
|
|
543
561
|
const HELPER_PROTOCOL_VERSION = 1;
|
|
544
562
|
//#endregion
|
|
@@ -922,6 +940,209 @@ async function sessionAcceptsImages(agent, ctx, signal) {
|
|
|
922
940
|
}
|
|
923
941
|
}
|
|
924
942
|
//#endregion
|
|
943
|
+
//#region src/vision/ocr.ts
|
|
944
|
+
/**
|
|
945
|
+
* Optical character recognition seam for windows without a UIA tree. OCR is
|
|
946
|
+
* optional and probed at mount: the `tesseract` provider is used only when the
|
|
947
|
+
* binary resolves through the subprocess service, otherwise an unavailable
|
|
948
|
+
* provider fails closed with a model-readable reason. Recognized words carry
|
|
949
|
+
* their pixel boxes, which `screen_find` maps to screen coordinates for the
|
|
950
|
+
* coordinate-based `click` path.
|
|
951
|
+
*
|
|
952
|
+
* @module dsh-click/vision/ocr
|
|
953
|
+
*/
|
|
954
|
+
/** Bytes cap for one tesseract TSV stdout. */
|
|
955
|
+
const OCR_STDOUT_BYTES = 16777216;
|
|
956
|
+
/**
|
|
957
|
+
* Build the tesseract command line: write words as TSV to stdout.
|
|
958
|
+
* @param command - tesseract executable.
|
|
959
|
+
* @param imagePath - absolute PNG path.
|
|
960
|
+
* @param language - tesseract language tag.
|
|
961
|
+
* @returns the argv (argv[0] is the executable).
|
|
962
|
+
*/
|
|
963
|
+
function tesseractArgv(command, imagePath, language) {
|
|
964
|
+
return [
|
|
965
|
+
command,
|
|
966
|
+
imagePath,
|
|
967
|
+
"stdout",
|
|
968
|
+
"-l",
|
|
969
|
+
language,
|
|
970
|
+
"tsv"
|
|
971
|
+
];
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Parse tesseract TSV output into word boxes. Non-word rows, empty text, and
|
|
975
|
+
* malformed numeric fields are skipped; a hostile or truncated stdout cannot
|
|
976
|
+
* produce bogus coordinates.
|
|
977
|
+
* @param tsv - tesseract TSV text from stdout.
|
|
978
|
+
* @returns the recognized words.
|
|
979
|
+
*/
|
|
980
|
+
function parseTesseractTsv(tsv) {
|
|
981
|
+
const words = [];
|
|
982
|
+
for (const line of tsv.split(/\r?\n/u)) {
|
|
983
|
+
if (line === "" || line.startsWith("level")) continue;
|
|
984
|
+
const columns = line.split(" ");
|
|
985
|
+
if (columns.length < 12 || columns[0] !== "5") continue;
|
|
986
|
+
const left = Number(columns[6]);
|
|
987
|
+
const top = Number(columns[7]);
|
|
988
|
+
const width = Number(columns[8]);
|
|
989
|
+
const height = Number(columns[9]);
|
|
990
|
+
const confidence = Number(columns[10]);
|
|
991
|
+
const text = columns[11] ?? "";
|
|
992
|
+
if (text.trim() === "") continue;
|
|
993
|
+
if (!Number.isFinite(left) || !Number.isFinite(top) || !Number.isFinite(width) || !Number.isFinite(height)) continue;
|
|
994
|
+
words.push({
|
|
995
|
+
text: text.trim(),
|
|
996
|
+
box: {
|
|
997
|
+
x: left,
|
|
998
|
+
y: top,
|
|
999
|
+
width,
|
|
1000
|
+
height
|
|
1001
|
+
},
|
|
1002
|
+
confidence: Number.isFinite(confidence) ? confidence : 0
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
return words;
|
|
1006
|
+
}
|
|
1007
|
+
/** A provider that cannot run: `recognize` fails closed with the given reason. */
|
|
1008
|
+
var UnavailableOcrProvider = class {
|
|
1009
|
+
id;
|
|
1010
|
+
reason;
|
|
1011
|
+
available = false;
|
|
1012
|
+
/** @param id - provider id. @param reason - model-readable unavailability reason. */
|
|
1013
|
+
constructor(id, reason) {
|
|
1014
|
+
this.id = id;
|
|
1015
|
+
this.reason = reason;
|
|
1016
|
+
}
|
|
1017
|
+
get unavailableReason() {
|
|
1018
|
+
return this.reason;
|
|
1019
|
+
}
|
|
1020
|
+
recognize(_pngBase64, _signal) {
|
|
1021
|
+
return Promise.reject(new DshClickError(`OCR unavailable: ${this.reason}`, "OCR_UNAVAILABLE"));
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
/** The tesseract OCR provider over `ctx.subprocess`. */
|
|
1025
|
+
var TesseractOcrProvider = class {
|
|
1026
|
+
subprocess;
|
|
1027
|
+
command;
|
|
1028
|
+
language;
|
|
1029
|
+
id = "tesseract";
|
|
1030
|
+
available = true;
|
|
1031
|
+
/**
|
|
1032
|
+
* @param subprocess - the subprocess service that runs tesseract.
|
|
1033
|
+
* @param command - tesseract executable name.
|
|
1034
|
+
* @param language - tesseract language tag.
|
|
1035
|
+
*/
|
|
1036
|
+
constructor(subprocess, command, language) {
|
|
1037
|
+
this.subprocess = subprocess;
|
|
1038
|
+
this.command = command;
|
|
1039
|
+
this.language = language;
|
|
1040
|
+
}
|
|
1041
|
+
async recognize(pngBase64, signal) {
|
|
1042
|
+
const dir = await mkdtemp(join(tmpdir(), "dsh-click-ocr-"));
|
|
1043
|
+
const imagePath = join(dir, "shot.png");
|
|
1044
|
+
try {
|
|
1045
|
+
await writeFile(imagePath, Buffer.from(pngBase64, "base64"));
|
|
1046
|
+
const handle = this.subprocess.spawn({
|
|
1047
|
+
argv: tesseractArgv(this.command, imagePath, this.language),
|
|
1048
|
+
cwd: tmpdir(),
|
|
1049
|
+
stdio: {
|
|
1050
|
+
stdin: "ignore",
|
|
1051
|
+
stdout: { maxBytes: OCR_STDOUT_BYTES },
|
|
1052
|
+
stderr: { maxBytes: 65536 }
|
|
1053
|
+
},
|
|
1054
|
+
graceMs: 5e3,
|
|
1055
|
+
...signal === void 0 ? {} : { signal }
|
|
1056
|
+
});
|
|
1057
|
+
const outcome = await handle.done;
|
|
1058
|
+
const stdout = handle.collected.stdout?.readFrom(0).text ?? "";
|
|
1059
|
+
const stderr = handle.collected.stderr?.readFrom(0).text ?? "";
|
|
1060
|
+
if (outcome.exitCode !== 0) throw new DshClickError(`tesseract exited ${String(outcome.exitCode)}: ${sanitizeText(stderr, 500)}`, "OCR_FAILED");
|
|
1061
|
+
return parseTesseractTsv(stdout);
|
|
1062
|
+
} finally {
|
|
1063
|
+
await rm(dir, {
|
|
1064
|
+
recursive: true,
|
|
1065
|
+
force: true
|
|
1066
|
+
}).catch(() => {});
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
/**
|
|
1071
|
+
* Probe tesseract through the subprocess service and return a provider.
|
|
1072
|
+
* A missing binary degrades to an unavailable provider (fail closed), never a
|
|
1073
|
+
* crash, so the zero-dependency desktop path keeps working.
|
|
1074
|
+
*
|
|
1075
|
+
* @param subprocess - the subprocess service.
|
|
1076
|
+
* @param command - tesseract executable name.
|
|
1077
|
+
* @param language - tesseract language tag.
|
|
1078
|
+
* @returns the probed OCR provider.
|
|
1079
|
+
*/
|
|
1080
|
+
async function probeTesseract(subprocess, command, language) {
|
|
1081
|
+
try {
|
|
1082
|
+
await subprocess.resolveExecutable(command);
|
|
1083
|
+
return new TesseractOcrProvider(subprocess, command, language);
|
|
1084
|
+
} catch {
|
|
1085
|
+
return new UnavailableOcrProvider("tesseract", `tesseract (${command}) is not installed`);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
//#endregion
|
|
1089
|
+
//#region src/vision/grounding.ts
|
|
1090
|
+
/**
|
|
1091
|
+
* Visual grounding seam: turning a screenshot plus a natural-language prompt
|
|
1092
|
+
* into labeled bounding boxes. Kept as an independent provider so a vision
|
|
1093
|
+
* model (or an external grounding service) can plug in later without touching
|
|
1094
|
+
* the desktop backend or the tool surface. The default is unavailable — the
|
|
1095
|
+
* OCR path (`screen_find`) already yields text targets, and a grounding
|
|
1096
|
+
* provider is optional and probed through the `dsh-click/grounding` seam.
|
|
1097
|
+
*
|
|
1098
|
+
* @module dsh-click/vision/grounding
|
|
1099
|
+
*/
|
|
1100
|
+
/** A provider that cannot run: `ground` fails closed with the given reason. */
|
|
1101
|
+
var UnavailableGroundingProvider = class {
|
|
1102
|
+
id;
|
|
1103
|
+
reason;
|
|
1104
|
+
available = false;
|
|
1105
|
+
/** @param id - provider id. @param reason - model-readable unavailability reason. */
|
|
1106
|
+
constructor(id = "unavailable", reason = "no visual grounding provider configured") {
|
|
1107
|
+
this.id = id;
|
|
1108
|
+
this.reason = reason;
|
|
1109
|
+
}
|
|
1110
|
+
get unavailableReason() {
|
|
1111
|
+
return this.reason;
|
|
1112
|
+
}
|
|
1113
|
+
ground(_pngBase64, _width, _height, _prompt, _signal) {
|
|
1114
|
+
return Promise.reject(new DshClickError(`visual grounding unavailable: ${this.reason}`, "GROUNDING_UNAVAILABLE"));
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
//#endregion
|
|
1118
|
+
//#region src/vision/index.ts
|
|
1119
|
+
/**
|
|
1120
|
+
* Map one screenshot box (possibly downscaled by `maxScreenshotSide`) to its
|
|
1121
|
+
* screen-space box, centering on the window's screen rect origin.
|
|
1122
|
+
* @param rect - the window's screen rectangle.
|
|
1123
|
+
* @param imageWidth - screenshot width in pixels.
|
|
1124
|
+
* @param imageHeight - screenshot height in pixels.
|
|
1125
|
+
* @param box - the screenshot-space box.
|
|
1126
|
+
* @returns the screen-space box.
|
|
1127
|
+
*/
|
|
1128
|
+
function screenBoxFor(rect, imageWidth, imageHeight, box) {
|
|
1129
|
+
const scaleX = rect.width > 0 && imageWidth > 0 ? rect.width / imageWidth : 1;
|
|
1130
|
+
const scaleY = rect.height > 0 && imageHeight > 0 ? rect.height / imageHeight : 1;
|
|
1131
|
+
return {
|
|
1132
|
+
x: rect.x + box.x * scaleX,
|
|
1133
|
+
y: rect.y + box.y * scaleY,
|
|
1134
|
+
width: box.width * scaleX,
|
|
1135
|
+
height: box.height * scaleY
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
/** Center point of a screen-space box (the coordinate `click` addresses). */
|
|
1139
|
+
function centerOf(box) {
|
|
1140
|
+
return {
|
|
1141
|
+
x: Math.round(box.x + box.width / 2),
|
|
1142
|
+
y: Math.round(box.y + box.height / 2)
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
//#endregion
|
|
925
1146
|
//#region src/tools.ts
|
|
926
1147
|
/** Sanitize one snapshot into the model-visible window value. */
|
|
927
1148
|
function observedWindow(snapshot, maxTextLength) {
|
|
@@ -1291,6 +1512,177 @@ function screenReadTool(services) {
|
|
|
1291
1512
|
}
|
|
1292
1513
|
});
|
|
1293
1514
|
}
|
|
1515
|
+
/**
|
|
1516
|
+
* `screen_find` — find clickable text/visual targets in a window whose
|
|
1517
|
+
* accessibility tree is empty (no UIA elements). It captures the window,
|
|
1518
|
+
* runs OCR (when the probed provider is available) and, when a grounding
|
|
1519
|
+
* provider is mounted and a query is given, visual grounding, then returns
|
|
1520
|
+
* screen-coordinate targets plus an observationId for the coordinate-based
|
|
1521
|
+
* `click` path. Read-only: never needs approval.
|
|
1522
|
+
*
|
|
1523
|
+
* @param services - runtime services.
|
|
1524
|
+
* @returns the tool definition.
|
|
1525
|
+
*/
|
|
1526
|
+
function screenFindTool(services) {
|
|
1527
|
+
const { config, backend, observations, ocr, grounding } = services;
|
|
1528
|
+
return defineTool({
|
|
1529
|
+
name: "screen_find",
|
|
1530
|
+
description: "Find clickable text (or a described visual target) in a desktop window that exposes no accessibility tree, via OCR and optional visual grounding. Returns screen-coordinate targets plus an observationId; later `click` calls address a target by its (x, y) coordinates and cite this observationId in `basedOn`. Read-only: never needs approval.",
|
|
1531
|
+
parameters: {
|
|
1532
|
+
target: {
|
|
1533
|
+
type: "object",
|
|
1534
|
+
description: "Which window to search (windowId, windowTitle, or processId); omitted = the foreground window.",
|
|
1535
|
+
properties: {
|
|
1536
|
+
windowId: {
|
|
1537
|
+
type: "integer",
|
|
1538
|
+
description: "Native window handle from app_list."
|
|
1539
|
+
},
|
|
1540
|
+
windowTitle: {
|
|
1541
|
+
type: "string",
|
|
1542
|
+
description: "Visible window title (matched case-insensitively by substring)."
|
|
1543
|
+
},
|
|
1544
|
+
processId: {
|
|
1545
|
+
type: "integer",
|
|
1546
|
+
description: "Owning process id."
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
additionalProperties: false
|
|
1550
|
+
},
|
|
1551
|
+
query: {
|
|
1552
|
+
type: "string",
|
|
1553
|
+
description: "Optional substring to filter OCR text by, or the visual target description for grounding."
|
|
1554
|
+
},
|
|
1555
|
+
maxSide: {
|
|
1556
|
+
type: "integer",
|
|
1557
|
+
description: "Longest side in pixels; larger captures are downscaled."
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
output: {
|
|
1561
|
+
schema: {
|
|
1562
|
+
type: "object",
|
|
1563
|
+
properties: {
|
|
1564
|
+
ok: {
|
|
1565
|
+
type: "boolean",
|
|
1566
|
+
const: true
|
|
1567
|
+
},
|
|
1568
|
+
observationId: { type: "string" },
|
|
1569
|
+
window: {
|
|
1570
|
+
type: "object",
|
|
1571
|
+
properties: {
|
|
1572
|
+
windowId: { type: "integer" },
|
|
1573
|
+
processId: { type: "integer" },
|
|
1574
|
+
title: { type: "string" },
|
|
1575
|
+
className: { type: "string" },
|
|
1576
|
+
executablePath: { oneOf: [{ type: "string" }, { type: "null" }] },
|
|
1577
|
+
rect: {
|
|
1578
|
+
type: "object",
|
|
1579
|
+
properties: {
|
|
1580
|
+
x: { type: "integer" },
|
|
1581
|
+
y: { type: "integer" },
|
|
1582
|
+
width: { type: "integer" },
|
|
1583
|
+
height: { type: "integer" }
|
|
1584
|
+
},
|
|
1585
|
+
additionalProperties: false
|
|
1586
|
+
},
|
|
1587
|
+
foreground: { type: "boolean" }
|
|
1588
|
+
},
|
|
1589
|
+
additionalProperties: false
|
|
1590
|
+
},
|
|
1591
|
+
ocrAvailable: { type: "boolean" },
|
|
1592
|
+
targets: {
|
|
1593
|
+
type: "array",
|
|
1594
|
+
items: {
|
|
1595
|
+
type: "object",
|
|
1596
|
+
properties: {
|
|
1597
|
+
text: { type: "string" },
|
|
1598
|
+
x: { type: "integer" },
|
|
1599
|
+
y: { type: "integer" },
|
|
1600
|
+
width: { type: "integer" },
|
|
1601
|
+
height: { type: "integer" },
|
|
1602
|
+
confidence: { type: "number" },
|
|
1603
|
+
source: {
|
|
1604
|
+
type: "string",
|
|
1605
|
+
enum: ["ocr", "grounding"]
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
additionalProperties: false
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
additionalProperties: false
|
|
1613
|
+
},
|
|
1614
|
+
render(_args, value) {
|
|
1615
|
+
const result = value;
|
|
1616
|
+
const lines = [
|
|
1617
|
+
`Text/visual targets in ${windowLine(result.window)}:`,
|
|
1618
|
+
`observationId: ${result.observationId}`,
|
|
1619
|
+
`OCR available: ${result.ocrAvailable}`,
|
|
1620
|
+
`${result.targets.length} target(s):`
|
|
1621
|
+
];
|
|
1622
|
+
for (const target of result.targets) lines.push(`- ${JSON.stringify(target.text)} at (${target.x}, ${target.y}) ${target.width}x${target.height} [${target.source}]`);
|
|
1623
|
+
lines.push("cite this observationId in click `basedOn` and address a target by its (x, y) coordinates.");
|
|
1624
|
+
return [{
|
|
1625
|
+
type: "text",
|
|
1626
|
+
text: lines.join("\n")
|
|
1627
|
+
}];
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
timeoutMs: config.helperTimeoutMs + 3e4,
|
|
1631
|
+
async execute(args, exec) {
|
|
1632
|
+
backendGuard(services);
|
|
1633
|
+
const parsed = args;
|
|
1634
|
+
const requestedSide = parsed.maxSide;
|
|
1635
|
+
const maxSide = requestedSide === void 0 ? config.maxScreenshotSide : Math.min(requestedSide, config.maxScreenshotSide);
|
|
1636
|
+
const shot = await backend.shot(parsed.target ?? {}, maxSide, exec.signal);
|
|
1637
|
+
const sanitized = observedWindow(shot.snapshot, config.maxTextLength);
|
|
1638
|
+
const record = observations.record(shot.snapshot);
|
|
1639
|
+
const targets = [];
|
|
1640
|
+
if (ocr.available) for (const word of await ocr.recognize(shot.pngBase64, exec.signal)) {
|
|
1641
|
+
const box = screenBoxFor(shot.snapshot.rect, shot.width, shot.height, word.box);
|
|
1642
|
+
const center = centerOf(box);
|
|
1643
|
+
targets.push({
|
|
1644
|
+
text: sanitizeVisible(word.text, config.maxTextLength),
|
|
1645
|
+
x: center.x,
|
|
1646
|
+
y: center.y,
|
|
1647
|
+
width: Math.round(box.width),
|
|
1648
|
+
height: Math.round(box.height),
|
|
1649
|
+
confidence: word.confidence / 100,
|
|
1650
|
+
source: "ocr"
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
const query = parsed.query?.trim() ?? "";
|
|
1654
|
+
if (grounding.available && query !== "") for (const target of await grounding.ground(shot.pngBase64, shot.width, shot.height, query, exec.signal)) {
|
|
1655
|
+
const box = screenBoxFor(shot.snapshot.rect, shot.width, shot.height, target.box);
|
|
1656
|
+
const center = centerOf(box);
|
|
1657
|
+
targets.push({
|
|
1658
|
+
text: sanitizeVisible(target.label, config.maxTextLength),
|
|
1659
|
+
x: center.x,
|
|
1660
|
+
y: center.y,
|
|
1661
|
+
width: Math.round(box.width),
|
|
1662
|
+
height: Math.round(box.height),
|
|
1663
|
+
confidence: target.confidence,
|
|
1664
|
+
source: "grounding"
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
const filtered = query === "" ? targets : targets.filter((target) => target.text.toLowerCase().includes(query.toLowerCase()));
|
|
1668
|
+
auditObservation(exec, {
|
|
1669
|
+
observationId: record.id,
|
|
1670
|
+
windowId: shot.snapshot.windowId,
|
|
1671
|
+
processId: shot.snapshot.processId,
|
|
1672
|
+
executablePath: sanitized.executablePath,
|
|
1673
|
+
windowTitle: sanitized.title,
|
|
1674
|
+
elementCount: 0
|
|
1675
|
+
}, config.auditSessionEvents);
|
|
1676
|
+
return {
|
|
1677
|
+
ok: true,
|
|
1678
|
+
observationId: record.id,
|
|
1679
|
+
window: sanitized,
|
|
1680
|
+
ocrAvailable: ocr.available,
|
|
1681
|
+
targets: filtered
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1294
1686
|
/** The shared window-action output schema (click/scroll/key). */
|
|
1295
1687
|
function actionOutputSchema(withRestored) {
|
|
1296
1688
|
return {
|
|
@@ -1773,6 +2165,7 @@ function allTools(services) {
|
|
|
1773
2165
|
return [
|
|
1774
2166
|
screenShotTool(services),
|
|
1775
2167
|
screenReadTool(services),
|
|
2168
|
+
screenFindTool(services),
|
|
1776
2169
|
clickTool(services),
|
|
1777
2170
|
typeTool(services),
|
|
1778
2171
|
scrollTool(services),
|
|
@@ -1787,30 +2180,35 @@ const name = "dsh-click";
|
|
|
1787
2180
|
/** Hard services: the tool registry every contribution lands in. */
|
|
1788
2181
|
const inject = ["tools"];
|
|
1789
2182
|
/**
|
|
1790
|
-
* Mount the plugin: resolve config, select the platform backend,
|
|
2183
|
+
* Mount the plugin: resolve config, select the platform backend, probe the
|
|
2184
|
+
* optional OCR provider, read the optional visual-grounding seam, and register
|
|
1791
2185
|
* every tool through `ctx.tools.register` (each registration is an effect
|
|
1792
2186
|
* whose disposer removes exactly that tool on stop/HMR).
|
|
1793
2187
|
*
|
|
1794
2188
|
* @param ctx - context carrying the tools registry.
|
|
1795
2189
|
* @param config - raw loader config; defaults applied through {@link resolveConfig}.
|
|
1796
2190
|
*/
|
|
1797
|
-
function apply(ctx, config) {
|
|
2191
|
+
async function apply(ctx, config) {
|
|
1798
2192
|
const resolved = resolveConfig(config);
|
|
1799
2193
|
const backend = ctx.get("dsh-click/backend") ?? createBackend(ctx, resolved);
|
|
1800
2194
|
const observations = new ObservationStore(resolved);
|
|
2195
|
+
const actions = new ActionExecutor({
|
|
2196
|
+
ctx,
|
|
2197
|
+
config: resolved,
|
|
2198
|
+
backend,
|
|
2199
|
+
observations
|
|
2200
|
+
});
|
|
2201
|
+
const subprocess = ctx.get("subprocess");
|
|
1801
2202
|
const services = {
|
|
1802
2203
|
ctx,
|
|
1803
2204
|
config: resolved,
|
|
1804
2205
|
backend,
|
|
1805
2206
|
observations,
|
|
1806
|
-
actions
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
backend,
|
|
1810
|
-
observations
|
|
1811
|
-
})
|
|
2207
|
+
actions,
|
|
2208
|
+
ocr: resolved.ocr.enabled && subprocess !== void 0 ? await probeTesseract(subprocess, resolved.ocr.command, resolved.ocr.language) : new UnavailableOcrProvider("ocr-disabled", resolved.ocr.enabled ? "the subprocess service is not mounted" : "OCR is disabled by config"),
|
|
2209
|
+
grounding: ctx.get("dsh-click/grounding") ?? new UnavailableGroundingProvider()
|
|
1812
2210
|
};
|
|
1813
2211
|
for (const tool of allTools(services)) ctx.effect(() => ctx.tools.register(tool), `dsh-click: ${tool.name} tool`);
|
|
1814
2212
|
}
|
|
1815
2213
|
//#endregion
|
|
1816
|
-
export { ACTION_EVENT, ActionExecutor, Config, DshClickError, HELPER_PROTOCOL_VERSION, HelperBackend, OBSERVED_EVENT, ObservationStore, UnavailableBackend, VERSION, allTools, apply, createBackend, inject, name, observationIdOf, redactSensitive, resolveConfig, sanitizePath, sanitizeText, sanitizeVisible };
|
|
2214
|
+
export { ACTION_EVENT, ActionExecutor, Config, DshClickError, HELPER_PROTOCOL_VERSION, HelperBackend, OBSERVED_EVENT, ObservationStore, TesseractOcrProvider, UnavailableBackend, UnavailableGroundingProvider, UnavailableOcrProvider, VERSION, allTools, apply, centerOf, createBackend, inject, name, observationIdOf, parseTesseractTsv, probeTesseract, redactSensitive, resolveConfig, sanitizePath, sanitizeText, sanitizeVisible, screenBoxFor, tesseractArgv };
|
package/lib/types/config.d.ts
CHANGED
|
@@ -45,6 +45,19 @@ export declare const MAX_TREE_DEPTH = 64;
|
|
|
45
45
|
export declare const DEFAULT_MAX_TEXT_LENGTH = 200;
|
|
46
46
|
/** Ceiling on the sanitization truncation length. */
|
|
47
47
|
export declare const MAX_TEXT_LENGTH = 10000;
|
|
48
|
+
/** Default tesseract executable for the optional OCR path. */
|
|
49
|
+
export declare const DEFAULT_OCR_COMMAND = "tesseract";
|
|
50
|
+
/** Default OCR language (tesseract language data). */
|
|
51
|
+
export declare const DEFAULT_OCR_LANGUAGE = "eng";
|
|
52
|
+
/** Optical character recognition (optional; probed at mount). */
|
|
53
|
+
export interface OcrConfig {
|
|
54
|
+
/** Enable OCR-based text finding when a window has no UIA tree (default true). */
|
|
55
|
+
enabled?: boolean;
|
|
56
|
+
/** tesseract executable name (default "tesseract"). */
|
|
57
|
+
command?: string;
|
|
58
|
+
/** tesseract language tag (default "eng"). */
|
|
59
|
+
language?: string;
|
|
60
|
+
}
|
|
48
61
|
/** Configuration for the dsh-click desktop-control tools. */
|
|
49
62
|
export interface Config {
|
|
50
63
|
/** Gate every mutating action (click/type/scroll/key/app_launch) behind approval (default true). */
|
|
@@ -84,6 +97,8 @@ export interface Config {
|
|
|
84
97
|
maxTextLength?: number;
|
|
85
98
|
/** Back up and restore control text when `type` fails (default true). */
|
|
86
99
|
rollbackEnabled?: boolean;
|
|
100
|
+
/** Optical character recognition (optional; probed at mount). */
|
|
101
|
+
ocr?: OcrConfig;
|
|
87
102
|
}
|
|
88
103
|
/** Fully resolved configuration captured at plugin load. */
|
|
89
104
|
export interface ResolvedConfig {
|
|
@@ -117,6 +132,12 @@ export interface ResolvedConfig {
|
|
|
117
132
|
maxTextLength: number;
|
|
118
133
|
/** Whether `type` backs up and restores control text on failure. */
|
|
119
134
|
rollbackEnabled: boolean;
|
|
135
|
+
/** OCR configuration (probed at mount). */
|
|
136
|
+
ocr: {
|
|
137
|
+
enabled: boolean;
|
|
138
|
+
command: string;
|
|
139
|
+
language: string;
|
|
140
|
+
};
|
|
120
141
|
}
|
|
121
142
|
/** Schemastery schema for loader-validated configuration. */
|
|
122
143
|
export declare const Config: z<Config>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,+EAA+E;AAC/E,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,CAAA;AAEvC,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,CAAA;AAE7C,uDAAuD;AACvD,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAE/C,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,SAAU,CAAA;AAE5C,sFAAsF;AACtF,eAAO,MAAM,+BAA+B,QAAmB,CAAA;AAE/D,sCAAsC;AACtC,eAAO,MAAM,uBAAuB,QAAmB,CAAA;AAEvD,2FAA2F;AAC3F,eAAO,MAAM,2BAA2B,OAAO,CAAA;AAE/C,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,MAAM,CAAA;AACtC,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAEvC,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B,QAAS,CAAA;AAEpD,sCAAsC;AACtC,eAAO,MAAM,sBAAsB,OAAQ,CAAA;AAC3C,eAAO,MAAM,sBAAsB,SAAU,CAAA;AAE7C,4EAA4E;AAC5E,eAAO,MAAM,+BAA+B,IAAI,CAAA;AAEhD,sCAAsC;AACtC,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC,kCAAkC;AAClC,eAAO,MAAM,YAAY,OAAQ,CAAA;AAEjC,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC,iCAAiC;AACjC,eAAO,MAAM,cAAc,KAAK,CAAA;AAEhC,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAE1C,qDAAqD;AACrD,eAAO,MAAM,eAAe,QAAS,CAAA;AAErC,6DAA6D;AAC7D,MAAM,WAAW,MAAM;IACrB,oGAAoG;IACpG,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,sGAAsG;IACtG,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,8GAA8G;IAC9G,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,iGAAiG;IACjG,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,+FAA+F;IAC/F,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,8CAA8C;IAC9C,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -27,13 +27,17 @@ export { HelperBackend } from './platform/runner.js';
|
|
|
27
27
|
export { allTools, type ToolServices } from './tools.js';
|
|
28
28
|
export { OBSERVED_EVENT, ACTION_EVENT, type ObservedEvent, type ActionEvent, type ProcessFacts } from './events.js';
|
|
29
29
|
export { sanitizeText, sanitizePath, redactSensitive, sanitizeVisible } from './sanitize.js';
|
|
30
|
+
export { TesseractOcrProvider, UnavailableOcrProvider, parseTesseractTsv, probeTesseract, tesseractArgv, type OcrBox, type OcrProvider, type OcrWord, } from './vision/ocr.js';
|
|
31
|
+
export { UnavailableGroundingProvider, type GroundingBox, type GroundingTarget, type VisualGroundingProvider, } from './vision/grounding.js';
|
|
32
|
+
export { centerOf, screenBoxFor } from './vision/index.js';
|
|
30
33
|
/**
|
|
31
|
-
* Mount the plugin: resolve config, select the platform backend,
|
|
34
|
+
* Mount the plugin: resolve config, select the platform backend, probe the
|
|
35
|
+
* optional OCR provider, read the optional visual-grounding seam, and register
|
|
32
36
|
* every tool through `ctx.tools.register` (each registration is an effect
|
|
33
37
|
* whose disposer removes exactly that tool on stop/HMR).
|
|
34
38
|
*
|
|
35
39
|
* @param ctx - context carrying the tools registry.
|
|
36
40
|
* @param config - raw loader config; defaults applied through {@link resolveConfig}.
|
|
37
41
|
*/
|
|
38
|
-
export declare function apply(ctx: Context, config: Config): void
|
|
42
|
+
export declare function apply(ctx: Context, config: Config): Promise<void>;
|
|
39
43
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAA;AAQnD,eAAO,MAAM,IAAI,cAAc,CAAA;AAE/B,oEAAoE;AACpE,eAAO,MAAM,MAAM,UAAY,CAAA;AAE/B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/G,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AACnH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,OAAO,GACb,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,4BAA4B,EAC5B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,uBAAuB,GAC7B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAE1D;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BvE"}
|
package/lib/types/tools.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
14
14
|
import { ActionExecutor } from './actions.js';
|
|
15
15
|
import type { ResolvedConfig } from './config.js';
|
|
16
16
|
import { ObservationStore } from './observe.js';
|
|
17
|
+
import { type OcrProvider, type VisualGroundingProvider } from './vision/index.js';
|
|
17
18
|
import type { DesktopBackend, Rect } from './platform/types.js';
|
|
18
19
|
/** Everything one tool needs at runtime; injected by `src/index.ts`. */
|
|
19
20
|
export interface ToolServices {
|
|
@@ -27,6 +28,10 @@ export interface ToolServices {
|
|
|
27
28
|
readonly observations: ObservationStore;
|
|
28
29
|
/** The action executor. */
|
|
29
30
|
readonly actions: ActionExecutor;
|
|
31
|
+
/** The probed OCR provider (optional). */
|
|
32
|
+
readonly ocr: OcrProvider;
|
|
33
|
+
/** The optional visual grounding provider. */
|
|
34
|
+
readonly grounding: VisualGroundingProvider;
|
|
30
35
|
}
|
|
31
36
|
/** The sanitized, model-visible window facts shared by observer outputs. */
|
|
32
37
|
export interface ObservedWindowValue {
|
|
@@ -57,6 +62,18 @@ export declare function screenShotTool(services: ToolServices): import("@deepsee
|
|
|
57
62
|
* @returns the tool definition.
|
|
58
63
|
*/
|
|
59
64
|
export declare function screenReadTool(services: ToolServices): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
65
|
+
/**
|
|
66
|
+
* `screen_find` — find clickable text/visual targets in a window whose
|
|
67
|
+
* accessibility tree is empty (no UIA elements). It captures the window,
|
|
68
|
+
* runs OCR (when the probed provider is available) and, when a grounding
|
|
69
|
+
* provider is mounted and a query is given, visual grounding, then returns
|
|
70
|
+
* screen-coordinate targets plus an observationId for the coordinate-based
|
|
71
|
+
* `click` path. Read-only: never needs approval.
|
|
72
|
+
*
|
|
73
|
+
* @param services - runtime services.
|
|
74
|
+
* @returns the tool definition.
|
|
75
|
+
*/
|
|
76
|
+
export declare function screenFindTool(services: ToolServices): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
60
77
|
/**
|
|
61
78
|
* `click` — click an element (by elementId) or a coordinate inside the
|
|
62
79
|
* observed window. Never steals foreground focus; delivery is UIA invoke
|
package/lib/types/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAG/C,OAAO,KAAK,EAAE,cAAc,EAA0B,IAAI,EAAyC,MAAM,qBAAqB,CAAA;AAE9H,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,6BAA6B;IAC7B,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAA;IACvC,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAG/C,OAAO,EAA0B,KAAK,WAAW,EAAE,KAAK,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC1G,OAAO,KAAK,EAAE,cAAc,EAA0B,IAAI,EAAyC,MAAM,qBAAqB,CAAA;AAE9H,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,6BAA6B;IAC7B,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAA;IACvC,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,uBAAuB,CAAA;CAC5C;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,IAAI,EAAE,IAAI,CAAA;IACV,UAAU,EAAE,OAAO,CAAA;CACpB;AAgFD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,mDAoIpD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,mDA+IpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,mDAsJpD;AAiED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,mDAoD/C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,mDAyC9C;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,mDA0ChD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,YAAY,mDAkC7C;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,mDA+EjD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,mDAwCnD;AAED,oDAAoD;AACpD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,YAAY,qDAY9C"}
|
package/lib/types/version.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module dsh-click/version
|
|
8
8
|
*/
|
|
9
9
|
/** Plugin version advertised in the helper-protocol handshake. */
|
|
10
|
-
export declare const VERSION = "0.
|
|
10
|
+
export declare const VERSION = "0.2.0";
|
|
11
11
|
/** The helper protocol revision; bump only on incompatible wire changes. */
|
|
12
12
|
export declare const HELPER_PROTOCOL_VERSION = 1;
|
|
13
13
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual grounding seam: turning a screenshot plus a natural-language prompt
|
|
3
|
+
* into labeled bounding boxes. Kept as an independent provider so a vision
|
|
4
|
+
* model (or an external grounding service) can plug in later without touching
|
|
5
|
+
* the desktop backend or the tool surface. The default is unavailable — the
|
|
6
|
+
* OCR path (`screen_find`) already yields text targets, and a grounding
|
|
7
|
+
* provider is optional and probed through the `dsh-click/grounding` seam.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-click/vision/grounding
|
|
10
|
+
*/
|
|
11
|
+
/** One grounded box in screenshot pixel coordinates. */
|
|
12
|
+
export interface GroundingBox {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
}
|
|
18
|
+
/** One grounded target: a label plus its box and confidence. */
|
|
19
|
+
export interface GroundingTarget {
|
|
20
|
+
label: string;
|
|
21
|
+
box: GroundingBox;
|
|
22
|
+
/** 0..1 confidence. */
|
|
23
|
+
confidence: number;
|
|
24
|
+
}
|
|
25
|
+
/** One visual grounding provider. */
|
|
26
|
+
export interface VisualGroundingProvider {
|
|
27
|
+
/** Stable provider id. */
|
|
28
|
+
readonly id: string;
|
|
29
|
+
/** Whether the provider can run. */
|
|
30
|
+
readonly available: boolean;
|
|
31
|
+
/** Why the provider is unavailable, when it is. */
|
|
32
|
+
readonly unavailableReason?: string;
|
|
33
|
+
/** Ground one screenshot for the given prompt. */
|
|
34
|
+
ground(pngBase64: string, width: number, height: number, prompt: string, signal?: AbortSignal): Promise<GroundingTarget[]>;
|
|
35
|
+
}
|
|
36
|
+
/** A provider that cannot run: `ground` fails closed with the given reason. */
|
|
37
|
+
export declare class UnavailableGroundingProvider implements VisualGroundingProvider {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly reason: string;
|
|
40
|
+
readonly available = false;
|
|
41
|
+
/** @param id - provider id. @param reason - model-readable unavailability reason. */
|
|
42
|
+
constructor(id?: string, reason?: string);
|
|
43
|
+
get unavailableReason(): string;
|
|
44
|
+
ground(_pngBase64: string, _width: number, _height: number, _prompt: string, _signal?: AbortSignal): Promise<GroundingTarget[]>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=grounding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounding.d.ts","sourceRoot":"","sources":["../../../src/vision/grounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,YAAY,CAAA;IACjB,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,qCAAqC;AACrC,MAAM,WAAW,uBAAuB;IACtC,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,kDAAkD;IAClD,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;CAC3H;AAED,+EAA+E;AAC/E,qBAAa,4BAA6B,YAAW,uBAAuB;IAI9D,QAAQ,CAAC,EAAE;IAAkB,QAAQ,CAAC,MAAM;IAHxD,QAAQ,CAAC,SAAS,SAAQ;IAE1B,qFAAqF;gBAChE,EAAE,SAAgB,EAAW,MAAM,SAA4C;IAEpG,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;CAGhI"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vision seam index: re-exports the OCR and visual-grounding providers and the
|
|
3
|
+
* shared pixel→screen coordinate mapping the `screen_find` tool uses to turn
|
|
4
|
+
* screenshot boxes into clickable screen coordinates.
|
|
5
|
+
*
|
|
6
|
+
* @module dsh-click/vision
|
|
7
|
+
*/
|
|
8
|
+
import type { Rect } from '../platform/types.js';
|
|
9
|
+
export { TesseractOcrProvider, UnavailableOcrProvider, parseTesseractTsv, probeTesseract, tesseractArgv, type OcrBox, type OcrProvider, type OcrWord, } from './ocr.js';
|
|
10
|
+
export { UnavailableGroundingProvider, type GroundingBox, type GroundingTarget, type VisualGroundingProvider, } from './grounding.js';
|
|
11
|
+
/**
|
|
12
|
+
* Map one screenshot box (possibly downscaled by `maxScreenshotSide`) to its
|
|
13
|
+
* screen-space box, centering on the window's screen rect origin.
|
|
14
|
+
* @param rect - the window's screen rectangle.
|
|
15
|
+
* @param imageWidth - screenshot width in pixels.
|
|
16
|
+
* @param imageHeight - screenshot height in pixels.
|
|
17
|
+
* @param box - the screenshot-space box.
|
|
18
|
+
* @returns the screen-space box.
|
|
19
|
+
*/
|
|
20
|
+
export declare function screenBoxFor(rect: Rect, imageWidth: number, imageHeight: number, box: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
}): {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
/** Center point of a screen-space box (the coordinate `click` addresses). */
|
|
32
|
+
export declare function centerOf(box: {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
width: number;
|
|
36
|
+
height: number;
|
|
37
|
+
}): {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vision/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAEhD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,OAAO,GACb,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,4BAA4B,EAC5B,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,uBAAuB,GAC7B,MAAM,gBAAgB,CAAA;AAEvB;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CASzD;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,GAAG,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAE/G"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optical character recognition seam for windows without a UIA tree. OCR is
|
|
3
|
+
* optional and probed at mount: the `tesseract` provider is used only when the
|
|
4
|
+
* binary resolves through the subprocess service, otherwise an unavailable
|
|
5
|
+
* provider fails closed with a model-readable reason. Recognized words carry
|
|
6
|
+
* their pixel boxes, which `screen_find` maps to screen coordinates for the
|
|
7
|
+
* coordinate-based `click` path.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-click/vision/ocr
|
|
10
|
+
*/
|
|
11
|
+
import type { SubprocessRuntime } from '@deepseek-ai/dsh-subprocess';
|
|
12
|
+
/** One OCR word box, in screenshot pixel coordinates. */
|
|
13
|
+
export interface OcrBox {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
/** One recognized word plus its box and confidence. */
|
|
20
|
+
export interface OcrWord {
|
|
21
|
+
text: string;
|
|
22
|
+
box: OcrBox;
|
|
23
|
+
/** 0..100 tesseract confidence, or 0 when unknown. */
|
|
24
|
+
confidence: number;
|
|
25
|
+
}
|
|
26
|
+
/** One OCR provider (probed at mount). */
|
|
27
|
+
export interface OcrProvider {
|
|
28
|
+
/** Stable provider id. */
|
|
29
|
+
readonly id: string;
|
|
30
|
+
/** Whether the provider can run. */
|
|
31
|
+
readonly available: boolean;
|
|
32
|
+
/** Why the provider is unavailable, when it is. */
|
|
33
|
+
readonly unavailableReason?: string;
|
|
34
|
+
/** Recognize text in one PNG screenshot. */
|
|
35
|
+
recognize(pngBase64: string, signal?: AbortSignal): Promise<OcrWord[]>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build the tesseract command line: write words as TSV to stdout.
|
|
39
|
+
* @param command - tesseract executable.
|
|
40
|
+
* @param imagePath - absolute PNG path.
|
|
41
|
+
* @param language - tesseract language tag.
|
|
42
|
+
* @returns the argv (argv[0] is the executable).
|
|
43
|
+
*/
|
|
44
|
+
export declare function tesseractArgv(command: string, imagePath: string, language: string): readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* Parse tesseract TSV output into word boxes. Non-word rows, empty text, and
|
|
47
|
+
* malformed numeric fields are skipped; a hostile or truncated stdout cannot
|
|
48
|
+
* produce bogus coordinates.
|
|
49
|
+
* @param tsv - tesseract TSV text from stdout.
|
|
50
|
+
* @returns the recognized words.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseTesseractTsv(tsv: string): OcrWord[];
|
|
53
|
+
/** A provider that cannot run: `recognize` fails closed with the given reason. */
|
|
54
|
+
export declare class UnavailableOcrProvider implements OcrProvider {
|
|
55
|
+
readonly id: string;
|
|
56
|
+
readonly reason: string;
|
|
57
|
+
readonly available = false;
|
|
58
|
+
/** @param id - provider id. @param reason - model-readable unavailability reason. */
|
|
59
|
+
constructor(id: string, reason: string);
|
|
60
|
+
get unavailableReason(): string;
|
|
61
|
+
recognize(_pngBase64: string, _signal?: AbortSignal): Promise<OcrWord[]>;
|
|
62
|
+
}
|
|
63
|
+
/** The tesseract OCR provider over `ctx.subprocess`. */
|
|
64
|
+
export declare class TesseractOcrProvider implements OcrProvider {
|
|
65
|
+
private readonly subprocess;
|
|
66
|
+
private readonly command;
|
|
67
|
+
private readonly language;
|
|
68
|
+
readonly id = "tesseract";
|
|
69
|
+
readonly available = true;
|
|
70
|
+
/**
|
|
71
|
+
* @param subprocess - the subprocess service that runs tesseract.
|
|
72
|
+
* @param command - tesseract executable name.
|
|
73
|
+
* @param language - tesseract language tag.
|
|
74
|
+
*/
|
|
75
|
+
constructor(subprocess: SubprocessRuntime, command: string, language: string);
|
|
76
|
+
recognize(pngBase64: string, signal?: AbortSignal): Promise<OcrWord[]>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Probe tesseract through the subprocess service and return a provider.
|
|
80
|
+
* A missing binary degrades to an unavailable provider (fail closed), never a
|
|
81
|
+
* crash, so the zero-dependency desktop path keeps working.
|
|
82
|
+
*
|
|
83
|
+
* @param subprocess - the subprocess service.
|
|
84
|
+
* @param command - tesseract executable name.
|
|
85
|
+
* @param language - tesseract language tag.
|
|
86
|
+
* @returns the probed OCR provider.
|
|
87
|
+
*/
|
|
88
|
+
export declare function probeTesseract(subprocess: SubprocessRuntime, command: string, language: string): Promise<OcrProvider>;
|
|
89
|
+
//# sourceMappingURL=ocr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../../src/vision/ocr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAIpE,yDAAyD;AACzD,MAAM,WAAW,MAAM;IACrB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,uDAAuD;AACvD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,4CAA4C;IAC5C,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CACvE;AAKD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAErG;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE,CAqBxD;AAED,kFAAkF;AAClF,qBAAa,sBAAuB,YAAW,WAAW;IAI5C,QAAQ,CAAC,EAAE,EAAE,MAAM;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM;IAHxD,QAAQ,CAAC,SAAS,SAAQ;IAE1B,qFAAqF;gBAChE,EAAE,EAAE,MAAM,EAAW,MAAM,EAAE,MAAM;IAExD,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAGzE;AAED,wDAAwD;AACxD,qBAAa,oBAAqB,YAAW,WAAW;IAUpD,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,QAAQ,CAAC,EAAE,eAAc;IACzB,QAAQ,CAAC,SAAS,QAAO;IAEzB;;;;OAIG;gBAEgB,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM;IAG7B,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CA2B7E;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAO3H"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-click",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Cross-platform native desktop control tools for DeepSeek Harness (Windows first): screen_shot, screen_read (accessibility tree + pixel description for text-only models), click/type/scroll/key, and app_list/app_launch — every mutating action gated by approval, never stealing foreground focus, with stale-observation rejection and process-identity checks",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|