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 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: 56 tests, 8 suites (el smoke del helper corre en Windows)
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: 56 टेस्ट, 8 सुइट (हेल्पर स्मोक Windows पर चलता है)
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: 56 tests, 8 suites (helper smoke runs on Windows)
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: 56 testes, 8 suítes (o smoke do helper roda no Windows)
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:56 个测试、8 个套件(helper 冒烟在 Windows 上运行)
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
 
@@ -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 | `0.1.1-rc.2` (peer) | See packages | Official harness seams (`dsh-tools`, `dsh-session`, `dsh-subprocess`, `dsh-llm`, `dsh-attachment`, `dsh-agent`, `dsh-user-approval`) |
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.1.3";
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, and register
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: new ActionExecutor({
1807
- ctx,
1808
- config: resolved,
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 };
@@ -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":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
@@ -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, and register
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
@@ -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;AAIlD,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAA;AAMnD,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;AAE5F;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAYxD"}
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"}
@@ -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
@@ -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;CACjC;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;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,qDAW9C"}
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"}
@@ -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.1.3";
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.1.3",
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",