dsh-vision-router 2.1.2 → 2.1.4

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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/docs/architecture/compat-inventory.md +6 -6
  4. package/docs/architecture/dsh-compatibility-matrix.md +7 -6
  5. package/docs/architecture/dsh-support-window.md +36 -16
  6. package/docs/architecture/p3-compat-retirement.md +7 -5
  7. package/docs/architecture/p3-host-native-seams.md +3 -1
  8. package/docs/doctor.md +4 -1
  9. package/docs/releases/v2.1.3.md +34 -0
  10. package/docs/releases/v2.1.4.md +34 -0
  11. package/docs/v2-capability-routing.md +20 -11
  12. package/index.js +156 -129
  13. package/lib/catalog-corrections.js +2 -0
  14. package/lib/client-presentation-boundary-main.js +478 -2
  15. package/lib/client-presentation-boundary.js +121 -1
  16. package/lib/client.js +4 -4
  17. package/lib/depth-guidance.js +4 -4
  18. package/lib/doctor-cli-p0.js +3 -1
  19. package/lib/doctor-cli.js +4 -1
  20. package/lib/doctor-runtime.js +8 -3
  21. package/lib/dsh-support-window.js +15 -7
  22. package/lib/live-model-discovery.js +20 -13
  23. package/lib/local-vision-stabilizer.js +1 -1
  24. package/lib/mixed-router.js +8 -8
  25. package/lib/pi-ai-bridge-wire-compat.js +69 -10
  26. package/lib/runtime-i18n-boundary.js +27 -2
  27. package/lib/runtime-i18n.js +6 -6
  28. package/lib/session-affinity-runtime.js +104 -0
  29. package/lib/session-affinity.js +93 -0
  30. package/lib/settings-ia-client-prelude.js +1 -1
  31. package/lib/structured-bootstrap.js +2 -2
  32. package/lib/structured-flow-hardening.js +159 -158
  33. package/lib/tesseract-exec-compat.js +9 -36
  34. package/lib/vision-backend-runtime-policy.js +1 -0
  35. package/lib/vision-background-benchmark.js +79 -52
  36. package/lib/vision-background-failure-policy.js +1 -24
  37. package/lib/vision-background-stop-store.js +10 -13
  38. package/lib/vision-capability-benchmark-service.js +14 -2
  39. package/lib/vision-tool-runtime-boundary.js +20 -3
  40. package/lib/windows-desktop-capture.js +247 -0
  41. package/package.json +5 -5
  42. package/lib/windows-screenshot-dpi-compat.js +0 -148
@@ -0,0 +1,247 @@
1
+ import { execFile as importedExecFile } from 'node:child_process'
2
+ import { mkdtemp, rm } from 'node:fs/promises'
3
+ import { tmpdir } from 'node:os'
4
+ import path from 'node:path'
5
+
6
+ function quotePowerShellSingle(value) {
7
+ return `'${String(value).replace(/'/g, "''")}'`
8
+ }
9
+
10
+ export function buildPerMonitorWindowsScreenshotScript(outputPath) {
11
+ const quotedPath = quotePowerShellSingle(outputPath)
12
+ const source = String.raw`using System;
13
+ using System.Drawing;
14
+ using System.Runtime.InteropServices;
15
+ using System.Windows.Forms;
16
+
17
+ public static class DshVisionDesktopCapture
18
+ {
19
+ private static readonly IntPtr PerMonitorV2 = new IntPtr(-4);
20
+ private static readonly IntPtr PerMonitorV1 = new IntPtr(-3);
21
+
22
+ [DllImport("user32.dll")]
23
+ private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);
24
+
25
+ private static IntPtr TrySetContext(IntPtr context)
26
+ {
27
+ try
28
+ {
29
+ return SetThreadDpiAwarenessContext(context);
30
+ }
31
+ catch (EntryPointNotFoundException)
32
+ {
33
+ return IntPtr.Zero;
34
+ }
35
+ catch (DllNotFoundException)
36
+ {
37
+ return IntPtr.Zero;
38
+ }
39
+ }
40
+
41
+ private static IntPtr EnterPerMonitorContext()
42
+ {
43
+ IntPtr previous = TrySetContext(PerMonitorV2);
44
+ if (previous == IntPtr.Zero)
45
+ {
46
+ previous = TrySetContext(PerMonitorV1);
47
+ }
48
+ if (previous == IntPtr.Zero)
49
+ {
50
+ throw new InvalidOperationException(
51
+ "could not enter a per-monitor DPI awareness context; refusing to return a potentially misaligned screenshot");
52
+ }
53
+ return previous;
54
+ }
55
+
56
+ private static void RestoreContext(IntPtr previous)
57
+ {
58
+ try
59
+ {
60
+ SetThreadDpiAwarenessContext(previous);
61
+ }
62
+ catch
63
+ {
64
+ // The helper process exits immediately after capture. Restoration
65
+ // is still attempted so this method is correct if reused.
66
+ }
67
+ }
68
+
69
+ public static void ValidateDpiContext()
70
+ {
71
+ IntPtr previous = EnterPerMonitorContext();
72
+ RestoreContext(previous);
73
+ }
74
+
75
+ public static void Capture(string outputPath)
76
+ {
77
+ IntPtr previous = EnterPerMonitorContext();
78
+ try
79
+ {
80
+ Rectangle bounds = SystemInformation.VirtualScreen;
81
+ if (bounds.Width <= 0 || bounds.Height <= 0)
82
+ {
83
+ throw new InvalidOperationException("the Windows virtual screen has no drawable area");
84
+ }
85
+
86
+ using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
87
+ using (var graphics = Graphics.FromImage(bitmap))
88
+ {
89
+ graphics.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size);
90
+ bitmap.Save(outputPath);
91
+ }
92
+ }
93
+ finally
94
+ {
95
+ RestoreContext(previous);
96
+ }
97
+ }
98
+ }`
99
+
100
+ return [
101
+ 'Add-Type -AssemblyName System.Windows.Forms,System.Drawing',
102
+ `$__dshVisionCaptureSource = @'\n${source}\n'@`,
103
+ 'try {',
104
+ " Add-Type -TypeDefinition $__dshVisionCaptureSource -ReferencedAssemblies 'System.Windows.Forms.dll','System.Drawing.dll' -ErrorAction Stop",
105
+ '} catch {',
106
+ " throw ('vision_screenshot: failed to initialize the Windows DPI-aware capture helper: ' + $_.Exception.Message)",
107
+ '}',
108
+ `[DshVisionDesktopCapture]::Capture(${quotedPath})`,
109
+ ].join('\n')
110
+ }
111
+
112
+ // Snapshot the native function at module evaluation. Screenshot correctness
113
+ // must not depend on the process-wide promisify(execFile) compatibility seam
114
+ // used by legacy Tesseract stdin support.
115
+ const nativeExecFile = importedExecFile
116
+
117
+ function execFileAsync(file, args, options) {
118
+ return new Promise((resolve, reject) => {
119
+ nativeExecFile(file, args, options, (error, stdout, stderr) => {
120
+ if (error) {
121
+ if (error && typeof error === 'object') {
122
+ try {
123
+ error.stdout = stdout
124
+ error.stderr = stderr
125
+ } catch {
126
+ /* preserve the original child-process error */
127
+ }
128
+ }
129
+ reject(error)
130
+ return
131
+ }
132
+ resolve({ stdout, stderr })
133
+ })
134
+ })
135
+ }
136
+
137
+ export function isAsciiWindowsPath(value) {
138
+ return typeof value === 'string' && value !== '' && /^[\x20-\x7e]+$/.test(value)
139
+ }
140
+
141
+ function captureTempRoots(env, tmpRoot) {
142
+ const roots = []
143
+ const add = (value) => {
144
+ if (!isAsciiWindowsPath(value) || roots.includes(value)) return
145
+ roots.push(value)
146
+ }
147
+ add(tmpRoot)
148
+ add(env?.TEMP)
149
+ add(env?.TMP)
150
+ if (isAsciiWindowsPath(env?.SystemRoot)) add(path.win32.join(env.SystemRoot, 'Temp'))
151
+ if (isAsciiWindowsPath(env?.WINDIR)) add(path.win32.join(env.WINDIR, 'Temp'))
152
+ return roots
153
+ }
154
+
155
+ /**
156
+ * CodeDom-backed PowerShell Add-Type uses TEMP/TMP while compiling the small
157
+ * DPI-aware C# helper. On Windows profiles whose temp path contains non-ASCII
158
+ * characters that compilation can fail before capture starts (#409). Pick a
159
+ * writable ASCII scratch directory without ever mutating process.env.
160
+ */
161
+ export async function createWindowsCaptureTempDir(options = {}) {
162
+ const env = options.env ?? (typeof process !== 'undefined' ? process.env : {})
163
+ const tmpRoot = options.tmpRoot ?? tmpdir()
164
+ const makeTempDir = options.mkdtemp ?? mkdtemp
165
+ const roots = captureTempRoots(env, tmpRoot)
166
+ const failures = []
167
+
168
+ for (const root of roots) {
169
+ try {
170
+ return await makeTempDir(path.win32.join(root, 'dsh-vision-router-capture-'))
171
+ } catch (error) {
172
+ failures.push(error && error.message ? error.message : String(error))
173
+ }
174
+ }
175
+
176
+ const error = new Error(
177
+ 'vision_screenshot: no writable ASCII temporary directory is available for the Windows DPI-aware capture helper',
178
+ )
179
+ error.code = 'WINDOWS_CAPTURE_TEMP_UNAVAILABLE'
180
+ if (failures.length > 0) error.cause = new Error(failures.join(' | '))
181
+ throw error
182
+ }
183
+
184
+ /**
185
+ * Capture the Windows virtual desktop with per-monitor DPI awareness.
186
+ *
187
+ * This is the production owner of the Windows screenshot operation. It calls
188
+ * the PMv2 -> PMv1 helper directly and fails closed if a correct DPI context
189
+ * cannot be entered; it never falls back to the known-broken logical-coordinate
190
+ * legacy script. macOS/Linux capture remains owned by index.js.
191
+ */
192
+ export async function captureWindowsDesktop(outputPath, options = {}) {
193
+ const env = options.env ?? (typeof process !== 'undefined' ? process.env : {})
194
+ const removeTempDir = options.rm ?? rm
195
+ const run = options.execFileAsync ?? execFileAsync
196
+ let scratchDir
197
+
198
+ try {
199
+ scratchDir = await createWindowsCaptureTempDir({
200
+ env,
201
+ tmpRoot: options.tmpRoot,
202
+ mkdtemp: options.mkdtemp,
203
+ })
204
+ const script = buildPerMonitorWindowsScreenshotScript(outputPath)
205
+ const execOptions = {
206
+ windowsHide: true,
207
+ cwd: scratchDir,
208
+ env: {
209
+ ...env,
210
+ TEMP: scratchDir,
211
+ TMP: scratchDir,
212
+ },
213
+ ...(Number.isFinite(options.timeoutMs) && options.timeoutMs > 0
214
+ ? { timeout: options.timeoutMs }
215
+ : {}),
216
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
217
+ }
218
+ await run(
219
+ options.powershell ?? 'powershell.exe',
220
+ ['-NoProfile', '-NonInteractive', '-STA', '-Command', script],
221
+ execOptions,
222
+ )
223
+ } catch (error) {
224
+ if (error?.code === 'WINDOWS_CAPTURE_TEMP_UNAVAILABLE') throw error
225
+ if (error?.name === 'AbortError' || error?.code === 'ABORT_ERR') throw error
226
+ const wrapped = new Error(
227
+ `vision_screenshot: Windows DPI-aware capture failed (${error && error.message ? error.message : String(error)})`,
228
+ )
229
+ wrapped.code = 'WINDOWS_DPI_CAPTURE_FAILED'
230
+ wrapped.cause = error
231
+ throw wrapped
232
+ } finally {
233
+ if (scratchDir) {
234
+ try {
235
+ await removeTempDir(scratchDir, {
236
+ recursive: true,
237
+ force: true,
238
+ maxRetries: 3,
239
+ retryDelay: 50,
240
+ })
241
+ } catch {
242
+ // Antivirus/indexing can briefly retain CodeDom files. Cleanup is
243
+ // best-effort and must not turn a valid screenshot into a failure.
244
+ }
245
+ }
246
+ }
247
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vision-router",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "Eyes for text-only DeepSeek Harness agents: built-in free vision chain (no key) + pixel-level vision tools (Q&A, grounding, crop, pixel diff, colors, OCR, SVG trace, cutout, screenshots). One-command install, no Python, image turns work like ordinary tool-calling turns.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -54,8 +54,8 @@
54
54
  "undici": "^7.29.0"
55
55
  },
56
56
  "peerDependencies": {
57
- "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8 || ^0.1.1-rc.1",
58
- "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8 || ^0.1.1-rc.1",
57
+ "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8 || ^0.1.1-rc.1 || ^0.1.3-alpha.2",
58
+ "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8 || ^0.1.1-rc.1 || ^0.1.3-alpha.2",
59
59
  "sharp": ">=0.35.3 <1"
60
60
  },
61
61
  "peerDependenciesMeta": {
@@ -69,13 +69,13 @@
69
69
  "sharp": "^0.35.3"
70
70
  },
71
71
  "scripts": {
72
- "test": "node --test tests/adapter-prepare-call-compat.test.js tests/core.test.js tests/issue-374-delegated-call-config.test.js tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/capability-advisory.test.js tests/vision-execution-policy.test.js tests/vision-backend-diagnostics.test.js tests/live-model-discovery.test.js tests/live-model-credential-resolution.test.js tests/vision-model-registry.test.js tests/live-model-client-stability.test.js tests/providers-persistence.test.js tests/provider-directory-fallback.test.js tests/model-catalog-policy.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-fj.test.js tests/settings-ia-acceptance-regression.test.js tests/settings-migration.test.js tests/settings-section-order.test.js tests/attachment-admission-policy.test.js tests/vision-resilience.test.js tests/vision-resilience-lifecycle.test.js tests/vision-breaker-readonly.test.js tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/client.test.js tests/issue-307-regression.test.js tests/issue-284-vision-mode-toggle.test.js tests/issue-284-vision-mode-hardening.test.js tests/issue-284-attachment-id-hint.test.js tests/issue-284-model-visibility.test.js tests/issue-284-vision-selection-effort.test.js tests/client-presentation-boundary.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/remote-settings-risk-confirmation.test.js tests/local-remote-settings-permission.test.js tests/rc6-real-settings-persistence.test.js tests/artifact-path-security.test.js tests/http-compat.test.js tests/catalog-corrections.test.js tests/update-check.test.js tests/update-check-signal-lifecycle.test.js tests/self-update.test.js tests/doctor.test.js tests/doctor-cli.test.js tests/legacy-session-repair.test.js tests/profile-pnpm-diagnostics.test.js tests/doctor-v2.test.js tests/doctor-cli-v2.test.js tests/doctor-runtime.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/session-repair-v2.test.js tests/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/twin-image-capability-fallback.test.js tests/twin-image-custom-wrapper.test.js tests/adversarial-hardening.test.js tests/vision-adversarial-hardening-v2.test.js tests/vision-capability-benchmark-visual-proof.test.js tests/wrapper-directory.test.js tests/logging-ui.test.js tests/manifest-dependencies.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js tests/local-ollama.test.js tests/ollama-cold-start.test.js tests/ollama-cold-start-loaded.test.js tests/zero-regression-gate.test.js tests/runtime-e2e.test.js tests/local-vision-stabilizer.test.js tests/local-connection-probe.test.js tests/repetition-guard.test.js tests/guide-scroll-gate.test.js tests/settings-scroll-jank-regression.test.js tests/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-compat.test.js tests/native-image-coexistence.test.js tests/issue-276-session-image-ownership.test.js tests/issue-276-entry-policy-bridge.test.js tests/issue-276-policy-hardening.test.js tests/issue-289-native-nonintervention.test.js tests/pi-ai-bridge-wire-compat.test.js tests/mixed-router.test.js tests/depth-tier.test.js tests/depth-quota-behavior.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-budget-activation.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js tests/vision-routing-product.test.js tests/vision-runtime-performance.test.js tests/vision-routing-settings-prelude.test.js tests/v2-settings-ia-integration.test.js tests/vision-capability-router.test.js tests/vision-capability-reference.test.js tests/vision-capability-benchmark.test.js tests/vision-capability-grounding-proof-contract.test.js tests/vision-capability-probe.test.js tests/vision-capability-axis-freshness.test.js tests/vision-capability-shadow-health.test.js tests/vision-capability-benchmark-service.test.js tests/vision-capability-preflight-hardening.test.js tests/vision-capability-benchmark-contract.test.js tests/vision-capability-benchmark-client.test.js tests/vision-capability-benchmark-client-productization.test.js tests/vision-capability-adapter-route.test.js tests/vision-background-benchmark.test.js tests/vision-background-lifecycle.test.js tests/vision-background-benchmark-productization.test.js tests/vision-capability-benchmark-budget.test.js tests/vision-image-input-verdict.test.js tests/vision-capability-failure-classification.test.js tests/vision-capability-gate-client.test.js tests/v2-product-review-fixes.test.js tests/qa-top5-reliability.test.js tests/qa-screenshot-runtime.test.js tests/qa-runtime-identity.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js tests/qa-reliability-tail.test.js tests/qa-endpoint-route-alias.test.js tests/settings-native-card-semantics.test.js tests/settings-native-card-lazy-data.test.js tests/settings-invalid-staged-dirty.test.js tests/vision-toggle-root-hardening.test.js && node --test tests/vision-backend-runtime-policy.test.js",
72
+ "test": "node --test tests/adapter-prepare-call-compat.test.js tests/core.test.js tests/issue-374-delegated-call-config.test.js tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/capability-advisory.test.js tests/vision-execution-policy.test.js tests/vision-backend-diagnostics.test.js tests/live-model-discovery.test.js tests/live-model-credential-resolution.test.js tests/vision-model-registry.test.js tests/live-model-client-stability.test.js tests/providers-persistence.test.js tests/provider-directory-fallback.test.js tests/model-catalog-policy.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-fj.test.js tests/settings-ia-acceptance-regression.test.js tests/settings-migration.test.js tests/settings-section-order.test.js tests/attachment-admission-policy.test.js tests/vision-resilience.test.js tests/vision-resilience-lifecycle.test.js tests/vision-breaker-readonly.test.js tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/vision-mode-toggle-injection.test.js tests/client.test.js tests/issue-307-regression.test.js tests/issue-284-vision-mode-toggle.test.js tests/issue-284-vision-mode-hardening.test.js tests/issue-284-attachment-id-hint.test.js tests/issue-284-model-visibility.test.js tests/issue-284-vision-selection-effort.test.js tests/client-presentation-boundary.test.js tests/clipboard-image-paste-compat.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/remote-settings-risk-confirmation.test.js tests/local-remote-settings-permission.test.js tests/rc6-real-settings-persistence.test.js tests/artifact-path-security.test.js tests/http-compat.test.js tests/catalog-corrections.test.js tests/update-check.test.js tests/update-check-signal-lifecycle.test.js tests/self-update.test.js tests/doctor.test.js tests/doctor-cli.test.js tests/legacy-session-repair.test.js tests/profile-pnpm-diagnostics.test.js tests/doctor-v2.test.js tests/doctor-cli-v2.test.js tests/doctor-runtime.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/session-repair-v2.test.js tests/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/twin-image-capability-fallback.test.js tests/twin-image-custom-wrapper.test.js tests/adversarial-hardening.test.js tests/vision-adversarial-hardening-v2.test.js tests/vision-capability-benchmark-visual-proof.test.js tests/wrapper-directory.test.js tests/logging-ui.test.js tests/manifest-dependencies.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js tests/vision-model-guidance-contract.test.js tests/local-ollama.test.js tests/ollama-cold-start.test.js tests/ollama-cold-start-loaded.test.js tests/zero-regression-gate.test.js tests/runtime-e2e.test.js tests/local-vision-stabilizer.test.js tests/local-connection-probe.test.js tests/repetition-guard.test.js tests/guide-scroll-gate.test.js tests/settings-scroll-jank-regression.test.js tests/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-compat.test.js tests/native-image-coexistence.test.js tests/issue-276-session-image-ownership.test.js tests/issue-276-entry-policy-bridge.test.js tests/issue-276-policy-hardening.test.js tests/issue-289-native-nonintervention.test.js tests/pi-ai-bridge-wire-compat.test.js tests/mixed-router.test.js tests/depth-tier.test.js tests/depth-quota-behavior.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-budget-activation.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js tests/vision-routing-product.test.js tests/vision-runtime-performance.test.js tests/vision-routing-settings-prelude.test.js tests/v2-settings-ia-integration.test.js tests/vision-capability-router.test.js tests/vision-capability-reference.test.js tests/vision-capability-benchmark.test.js tests/vision-capability-grounding-proof-contract.test.js tests/vision-capability-probe.test.js tests/vision-capability-axis-freshness.test.js tests/vision-capability-shadow-health.test.js tests/vision-capability-benchmark-service.test.js tests/vision-capability-preflight-hardening.test.js tests/vision-capability-benchmark-contract.test.js tests/vision-capability-benchmark-client.test.js tests/vision-capability-benchmark-client-productization.test.js tests/vision-capability-adapter-route.test.js tests/vision-background-benchmark.test.js tests/vision-background-lifecycle.test.js tests/vision-background-benchmark-productization.test.js tests/vision-capability-benchmark-budget.test.js tests/vision-image-input-verdict.test.js tests/vision-capability-failure-classification.test.js tests/vision-capability-gate-client.test.js tests/v2-product-review-fixes.test.js tests/qa-top5-reliability.test.js tests/qa-screenshot-runtime.test.js tests/qa-runtime-identity.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js tests/qa-reliability-tail.test.js tests/qa-endpoint-route-alias.test.js tests/settings-native-card-semantics.test.js tests/settings-native-card-lazy-data.test.js tests/settings-invalid-staged-dirty.test.js tests/vision-toggle-root-hardening.test.js && node --test tests/vision-backend-runtime-policy.test.js",
73
73
  "test:core": "node --test tests/core.test.js tests/runtime-e2e.test.js tests/structured-bootstrap.test.js tests/structured-flow-hardening.test.js tests/structured-flow-adversarial.test.js tests/vision-execution-policy.test.js tests/vision-backend-runtime-policy.test.js",
74
74
  "test:routing": "node --test tests/issue-374-delegated-call-config.test.js tests/twin-image-capability-fallback.test.js tests/twin-image-custom-wrapper.test.js tests/vision-routing-product.test.js tests/vision-capability-router.test.js tests/vision-capability-probe.test.js tests/vision-capability-shadow-health.test.js tests/vision-runtime-performance.test.js tests/vision-background-benchmark.test.js tests/vision-image-input-verdict.test.js",
75
75
  "test:session": "node --test tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/replay-delegation.test.js tests/legacy-session-repair.test.js tests/session-repair-v2.test.js tests/issue-276-session-image-ownership.test.js",
76
76
  "test:resources": "node --test tests/artifact-path-security.test.js tests/image-resource-governor.test.js tests/resource-retention-lifecycle.test.js tests/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/qa-turn-budget-cancellation.test.js tests/qa-cancellation-publication.test.js",
77
77
  "test:compat": "node --test tests/adapter-prepare-call-compat.test.js tests/attachment-admission-policy.test.js tests/rc6-rc7-compat.test.js tests/rc6-real-settings-persistence.test.js tests/android-attachment-compat.test.js tests/http-compat.test.js tests/pi-ai-bridge-wire-compat.test.js tests/native-image-coexistence.test.js tests/tesseract-node24-boot.test.js tests/dsh-host-capabilities.test.js",
78
- "test:web": "node --test tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/client.test.js tests/client-presentation-boundary.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-acceptance-regression.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/local-remote-settings-permission.test.js tests/v2-settings-ia-integration.test.js tests/logging-ui.test.js",
78
+ "test:web": "node --test tests/alpha1-browser-lifecycle-integration.test.js tests/issue-367-remote-session-inject.test.js tests/vision-mode-toggle-injection.test.js tests/client.test.js tests/client-presentation-boundary.test.js tests/clipboard-image-paste-compat.test.js tests/settings-ia-client-prelude.test.js tests/settings-ia-acceptance-regression.test.js tests/remote-settings-bridge.test.js tests/remote-settings-v2-contract.test.js tests/local-remote-settings-permission.test.js tests/v2-settings-ia-integration.test.js tests/logging-ui.test.js",
79
79
  "test:contract": "node --test tests/manifest-dependencies.test.js tests/bundle-defaults.test.js tests/zero-regression-gate.test.js tests/issue-289-native-nonintervention.test.js tests/issue-374-delegated-call-config.test.js tests/runtime-boundary-fixes.test.js tests/runtime-i18n.test.js tests/adapter-prepare-call-compat.test.js tests/rc6-rc7-compat.test.js tests/attachment-admission-policy.test.js tests/dsh-host-capabilities.test.js tests/doctor-host-capabilities.test.js tests/structured-bootstrap.test.js tests/structured-bootstrap-gate.test.js",
80
80
  "test:grounding": "node --test tests/grounding-coordinate-frame.test.js tests/grounding-coordinate-runtime.test.js tests/vision-capability-grounding-proof-contract.test.js",
81
81
  "test:stress": "node scripts/image-resource-stress.mjs && node --test tests/large-image-resource-integration.test.js tests/resource-retention-lifecycle.test.js"
@@ -1,148 +0,0 @@
1
- const VIRTUAL_SCREEN_MARKER = '[System.Windows.Forms.SystemInformation]::VirtualScreen'
2
- const COPY_FROM_SCREEN_MARKER = '$g.CopyFromScreen($b.X,$b.Y,0,0,$bmp.Size)'
3
- const SAVE_PATTERN = /\$bmp\.Save\('((?:''|[^'])*)'\)/
4
-
5
- function powerShellBasename(file) {
6
- return String(file ?? '').replace(/\\/g, '/').split('/').pop().toLowerCase()
7
- }
8
-
9
- function quotePowerShellSingle(value) {
10
- return `'${String(value).replace(/'/g, "''")}'`
11
- }
12
-
13
- function savedPathFromLegacyScript(script) {
14
- const match = SAVE_PATTERN.exec(String(script ?? ''))
15
- return match ? match[1].replace(/''/g, "'") : undefined
16
- }
17
-
18
- export function isLegacyWindowsScreenshotScript(script) {
19
- const source = String(script ?? '')
20
- return (
21
- source.includes('Add-Type -AssemblyName System.Windows.Forms,System.Drawing') &&
22
- source.includes(VIRTUAL_SCREEN_MARKER) &&
23
- source.includes('[System.Drawing.Graphics]::FromImage($bmp)') &&
24
- source.includes(COPY_FROM_SCREEN_MARKER) &&
25
- savedPathFromLegacyScript(source) !== undefined
26
- )
27
- }
28
-
29
- export function buildPerMonitorWindowsScreenshotScript(outputPath) {
30
- const quotedPath = quotePowerShellSingle(outputPath)
31
- const source = String.raw`using System;
32
- using System.Drawing;
33
- using System.Runtime.InteropServices;
34
- using System.Windows.Forms;
35
-
36
- public static class DshVisionDesktopCapture
37
- {
38
- private static readonly IntPtr PerMonitorV2 = new IntPtr(-4);
39
- private static readonly IntPtr PerMonitorV1 = new IntPtr(-3);
40
-
41
- [DllImport("user32.dll")]
42
- private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);
43
-
44
- private static IntPtr TrySetContext(IntPtr context)
45
- {
46
- try
47
- {
48
- return SetThreadDpiAwarenessContext(context);
49
- }
50
- catch (EntryPointNotFoundException)
51
- {
52
- return IntPtr.Zero;
53
- }
54
- catch (DllNotFoundException)
55
- {
56
- return IntPtr.Zero;
57
- }
58
- }
59
-
60
- private static IntPtr EnterPerMonitorContext()
61
- {
62
- IntPtr previous = TrySetContext(PerMonitorV2);
63
- if (previous == IntPtr.Zero)
64
- {
65
- previous = TrySetContext(PerMonitorV1);
66
- }
67
- if (previous == IntPtr.Zero)
68
- {
69
- throw new InvalidOperationException(
70
- "could not enter a per-monitor DPI awareness context; refusing to return a potentially misaligned screenshot");
71
- }
72
- return previous;
73
- }
74
-
75
- private static void RestoreContext(IntPtr previous)
76
- {
77
- try
78
- {
79
- SetThreadDpiAwarenessContext(previous);
80
- }
81
- catch
82
- {
83
- // The helper process exits immediately after capture. Restoration
84
- // is still attempted so this method is correct if reused.
85
- }
86
- }
87
-
88
- public static void ValidateDpiContext()
89
- {
90
- IntPtr previous = EnterPerMonitorContext();
91
- RestoreContext(previous);
92
- }
93
-
94
- public static void Capture(string outputPath)
95
- {
96
- IntPtr previous = EnterPerMonitorContext();
97
- try
98
- {
99
- Rectangle bounds = SystemInformation.VirtualScreen;
100
- if (bounds.Width <= 0 || bounds.Height <= 0)
101
- {
102
- throw new InvalidOperationException("the Windows virtual screen has no drawable area");
103
- }
104
-
105
- using (var bitmap = new Bitmap(bounds.Width, bounds.Height))
106
- using (var graphics = Graphics.FromImage(bitmap))
107
- {
108
- graphics.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size);
109
- bitmap.Save(outputPath);
110
- }
111
- }
112
- finally
113
- {
114
- RestoreContext(previous);
115
- }
116
- }
117
- }`
118
-
119
- return [
120
- 'Add-Type -AssemblyName System.Windows.Forms,System.Drawing',
121
- `$__dshVisionCaptureSource = @'\n${source}\n'@`,
122
- 'try {',
123
- " Add-Type -TypeDefinition $__dshVisionCaptureSource -ReferencedAssemblies 'System.Windows.Forms.dll','System.Drawing.dll' -ErrorAction Stop",
124
- '} catch {',
125
- " throw ('vision_screenshot: failed to initialize the Windows DPI-aware capture helper: ' + $_.Exception.Message)",
126
- '}',
127
- `[DshVisionDesktopCapture]::Capture(${quotedPath})`,
128
- ].join('\n')
129
- }
130
-
131
- export function rewriteWindowsScreenshotExecArgs(file, args, options = {}) {
132
- const platform = options.platform ?? (typeof process !== 'undefined' ? process.platform : '')
133
- if (platform !== 'win32') return args
134
- const executable = powerShellBasename(file)
135
- if (executable !== 'powershell.exe' && executable !== 'powershell') return args
136
- if (!Array.isArray(args)) return args
137
-
138
- const commandIndex = args.findIndex((arg) => String(arg).toLowerCase() === '-command')
139
- if (commandIndex < 0 || commandIndex + 1 >= args.length) return args
140
- const script = args[commandIndex + 1]
141
- if (!isLegacyWindowsScreenshotScript(script)) return args
142
-
143
- const outputPath = savedPathFromLegacyScript(script)
144
- if (outputPath === undefined) return args
145
- const rewritten = args.slice()
146
- rewritten[commandIndex + 1] = buildPerMonitorWindowsScreenshotScript(outputPath)
147
- return rewritten
148
- }