dsh-vision-router 1.7.0 → 1.7.1

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/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  </p>
17
17
 
18
18
  <p align="center">
19
- <a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.7.0"><img src="https://img.shields.io/badge/release-v1.7.0-5B4CF0?style=flat-square" alt="Release v1.7.0" /></a>
19
+ <a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.7.1"><img src="https://img.shields.io/badge/release-v1.7.1-5B4CF0?style=flat-square" alt="Release v1.7.1" /></a>
20
20
  <a href="tests"><img src="https://img.shields.io/badge/verified-657%20tests-2EA44F?style=flat-square" alt="Verified: 657 tests" /></a>
21
21
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
22
22
  <a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&amp;logo=nodedotjs&amp;logoColor=white" alt="Node.js >=22" /></a>
@@ -29,9 +29,9 @@
29
29
  <p align="center">💬 <strong>QQ community group: 1105463028</strong></p>
30
30
 
31
31
  > [!WARNING]
32
- > 📌 **Announcement (v1.7.0)**
32
+ > 📌 **Announcement (v1.7.1)**
33
33
  >
34
- > **v1.7.0:** Live model discovery, stronger settings, session recovery, and Ollama cold-start fixes.
34
+ > **v1.7.1:** Remote settings can now be enabled after an explicit risk confirmation.
35
35
 
36
36
  <p align="center">
37
37
  <img src="assets/vision-demo.gif" width="640" alt="Demo: paste an image, the agent locates the send button with vision_ground / vision_crop / vision_pixel_diff and answers with coordinates" />
package/README.zh.md CHANGED
@@ -16,7 +16,7 @@
16
16
  </p>
17
17
 
18
18
  <p align="center">
19
- <a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.7.0"><img src="https://img.shields.io/badge/release-v1.7.0-5B4CF0?style=flat-square" alt="Release v1.7.0" /></a>
19
+ <a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.7.1"><img src="https://img.shields.io/badge/release-v1.7.1-5B4CF0?style=flat-square" alt="Release v1.7.1" /></a>
20
20
  <a href="tests"><img src="https://img.shields.io/badge/verified-657%20tests-2EA44F?style=flat-square" alt="Verified: 657 tests" /></a>
21
21
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
22
22
  <a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&amp;logo=nodedotjs&amp;logoColor=white" alt="Node.js >=22" /></a>
@@ -29,9 +29,9 @@
29
29
  <p align="center">💬 <strong>QQ 用户交流群:1105463028</strong></p>
30
30
 
31
31
  > [!WARNING]
32
- > 📌 **公告(v1.7.0)**
32
+ > 📌 **公告(v1.7.1)**
33
33
  >
34
- > **v1.7.0:模型发现、设置、会话恢复与 Ollama 冷启动全面升级。**
34
+ > **v1.7.1:远程设置现可在风险确认后开启。**
35
35
 
36
36
  <p align="center">
37
37
  <img src="assets/vision-demo.gif" width="640" alt="演示:粘贴图片,Agent 用 vision_ground / vision_crop / vision_pixel_diff 定位发送按钮并给出坐标" />
@@ -178,7 +178,7 @@ opencode-go + 自动识图 ← 发图片时选这个
178
178
  | Intern AI(上海AI实验室) | `internvl-latest` · `internvl3.5-latest` | 30 RPM,**9000 万 token/月** | ✅ | chat.intern-ai.org.cn |
179
179
  | Groq | `meta-llama/llama-4-scout-17b-16e-instruct`(原生多模态,最多 5 张图) | 30 RPM / 14,400 次/天,免卡 | ❌ 需代理 | console.groq.com |
180
180
  | Google AI Studio | `gemini-2.5-flash` · `gemini-2.5-flash-lite` | 10–30 RPM / 500–1,500 次/天 | ❌ 需代理 | aistudio.google.com |
181
- | NVIDIA NIM | `meta/llama-3.2-11b-vision-instruct` · `nvidia/nemotron-nano-12b-v2-vl` | 40 RPM,免卡 | ⚠️ | build.nvidia.com |
181
+ | NVIDIA NIM | `meta-llama/llama-3.2-11b-vision-instruct` · `nvidia/nemotron-nano-12b-v2-vl` | 40 RPM,免卡 | ⚠️ | build.nvidia.com |
182
182
  | OpenCode Zen | `mimo-v2.5-free`(视觉 + 代码) | 30 RPM / 500 次/天 | ⚠️ | opencode.ai/zen |
183
183
  | OpenRouter | `google/gemma-4-26b-a4b-it:free` · `google/gemma-4-31b-it:free` | 未充值账户 50 次/天 | ❌ 需代理 | openrouter.ai |
184
184
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  Vision Router uses a dedicated DSH Connection RPC channel at `/vision-router-settings/*` because the global DSH settings/credentials plane is intentionally loopback-only.
4
4
 
5
- Remote editing is off by default. Enable it only from the loopback Vision Router settings page. DSH `trustedHosts` protects the browser carrier against Host/Origin/DNS-rebinding attacks; it is **not user authentication**. Vision Router therefore exposes only an explicit allow-list of low-risk preferences remotely. Network/proxy settings, credential-bearing HTTP providers, local Ollama/LM Studio endpoints, artifact paths, desktop capture, stealth/route ownership and the remote permission itself remain loopback-only.
5
+ Remote editing is off by default. When a Vision Router settings page is opened through a DSH trusted host while the permission is still disabled, the page shows an explicit risk confirmation. Cancelling leaves remote editing disabled and writes nothing. Confirming enables only `allowRemoteSettings`, then reloads the scoped Vision Router settings immediately. The same permission can still be enabled or revoked from the loopback settings page.
6
+
7
+ DSH `trustedHosts` protects the browser carrier against Host/Origin/DNS-rebinding attacks; it is **not user authentication**. Enable remote editing only when you trust the clients that can reach the DSH instance. Ordinary remote mutations remain restricted to the explicit Vision Router allow-list. Credential-bearing HTTP providers, local Ollama/LM Studio configuration, artifact paths and every other field not present in that allow-list stay unavailable remotely. `allowRemoteSettings` itself is not added to the ordinary mutation allow-list: it can be enabled only through the explicit risk-confirmation flow (or from the loopback settings page).
6
8
 
7
9
  If DSH is behind Nginx, Caddy or another reverse proxy, forward `/vision-router-settings/*` to the same DSH origin in addition to the normal DSH routes. The UI detects a 404 on this channel and shows this requirement directly.
@@ -1,9 +1,11 @@
1
1
  import { installLocalRemoteSettingsPermissionBridge } from './local-remote-settings-permission.js'
2
+ import { installRemoteSettingsRiskConfirmationBridge } from './remote-settings-risk-confirmation.js'
2
3
 
3
4
  const SETTINGS_NS = 'vision-router'
4
5
 
5
6
  export const REMOTE_SETTINGS_CHANNEL = '/vision-router-settings'
6
7
  export const REMOTE_SETTINGS_PERMISSION = 'allowRemoteSettings'
8
+ export const REMOTE_SETTINGS_AUTHORIZE_ENDPOINT = 'authorize'
7
9
 
8
10
  // Remote DSH pages are deliberately less privileged than the loopback settings UI.
9
11
  // This is a capability allow-list, not a blacklist: a future Config field is local-only
@@ -117,6 +119,51 @@ function conflictResult(error) {
117
119
  }
118
120
  }
119
121
 
122
+ export async function authorizeRemoteSettingsAfterRiskConfirmation(settings, payload, logger) {
123
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload) || payload.acceptedRisk !== true) {
124
+ return badRequest('acceptedRisk must be true')
125
+ }
126
+
127
+ let descriptor
128
+ try {
129
+ descriptor = namespaceDescriptor(settings)
130
+ } catch (error) {
131
+ logger?.warn?.('vision-router: remote settings authorization describe failed: %s', error?.message ?? String(error))
132
+ return settingsRejected('Vision Router settings could not be read')
133
+ }
134
+ if (!descriptor) return settingsRejected('Vision Router settings namespace is unavailable')
135
+ if (settings.writable !== true) return settingsRejected('Vision Router settings provider is read-only')
136
+
137
+ const value = descriptor.value
138
+ if (value && typeof value === 'object' && value[REMOTE_SETTINGS_PERMISSION] === true) {
139
+ return { ok: true, value: accessSnapshot(settings) }
140
+ }
141
+ if (!Number.isInteger(descriptor.revision) || descriptor.revision < 0) {
142
+ return settingsRejected('Vision Router settings revision is unavailable')
143
+ }
144
+
145
+ try {
146
+ await settings.mutate(
147
+ SETTINGS_NS,
148
+ [{ op: 'set', path: [REMOTE_SETTINGS_PERMISSION], value: true }],
149
+ descriptor.revision,
150
+ )
151
+ } catch (error) {
152
+ const conflict = conflictResult(error)
153
+ if (conflict) return conflict
154
+ logger?.warn?.('vision-router: remote settings authorization rejected: %s', error?.message ?? String(error))
155
+ return settingsRejected(error?.message ?? 'Vision Router remote settings authorization was rejected')
156
+ }
157
+
158
+ try {
159
+ const access = accessSnapshot(settings)
160
+ if (access.enabled !== true) return settingsRejected('Vision Router remote settings authorization did not persist')
161
+ return { ok: true, value: access }
162
+ } catch {
163
+ return settingsRejected('Vision Router remote settings were enabled but could not be read back')
164
+ }
165
+ }
166
+
120
167
  export function createVisionRouterRemoteSettingsHandler(settings, logger) {
121
168
  return async (endpoint, payload) => {
122
169
  if (endpoint === 'describe') {
@@ -126,6 +173,9 @@ export function createVisionRouterRemoteSettingsHandler(settings, logger) {
126
173
  return settingsRejected('Vision Router settings could not be read')
127
174
  }
128
175
  }
176
+ if (endpoint === REMOTE_SETTINGS_AUTHORIZE_ENDPOINT) {
177
+ return authorizeRemoteSettingsAfterRiskConfirmation(settings, payload, logger)
178
+ }
129
179
  if (endpoint !== 'mutate') return badRequest('unknown Vision Router remote settings endpoint ' + JSON.stringify(endpoint))
130
180
 
131
181
  let descriptor
@@ -163,5 +213,6 @@ export function installVisionRouterRemoteSettingsBridge(ctx, logger) {
163
213
  'vision-router: opt-in remote settings channel',
164
214
  )
165
215
  })
216
+ installRemoteSettingsRiskConfirmationBridge(ctx)
166
217
  installLocalRemoteSettingsPermissionBridge(ctx, logger)
167
218
  }
@@ -0,0 +1,195 @@
1
+ const RISK_PRELUDE_MARK = 'data-vision-router-remote-settings-risk-confirmation'
2
+
3
+ export const REMOTE_SETTINGS_RISK_CLIENT_PRELUDE = String.raw`(function(){
4
+ 'use strict';
5
+ var CHANNEL = '/vision-router-settings';
6
+ var AUTHORIZE_ENDPOINT = 'authorize';
7
+ var connectionCache = typeof WeakMap === 'function' ? new WeakMap() : undefined;
8
+ var rpcCache = typeof WeakMap === 'function' ? new WeakMap() : undefined;
9
+ var contextCache = typeof WeakMap === 'function' ? new WeakMap() : undefined;
10
+ var authorizationPromise;
11
+
12
+ function chineseLocale() {
13
+ var lang = '';
14
+ try {
15
+ lang = String((document && document.documentElement && document.documentElement.lang) || (navigator && navigator.language) || '').toLowerCase();
16
+ } catch (_) {}
17
+ return lang === '' || lang.indexOf('zh') === 0;
18
+ }
19
+
20
+ function riskMessage() {
21
+ return chineseLocale()
22
+ ? '启用远程设置?\n\n当前页面通过远程地址访问 DSH。启用后,能够访问此 trusted host 的客户端可以修改 Vision Router 已开放的设置。\n\nDSH trustedHosts 不是身份认证,请仅在你信任当前网络和访问者时继续。API Key、HTTP Provider 凭据、本地 Ollama / LM Studio、产物路径等未列入远程白名单的敏感配置仍不会开放。\n\n确定要允许远程修改设置吗?'
23
+ : 'Enable remote settings?\n\nThis page is accessing DSH through a remote address. After enabling this, clients that can reach this trusted host can change the Vision Router settings exposed by the remote allow-list.\n\nDSH trustedHosts is not authentication. Continue only if you trust the current network and its users. Sensitive settings outside the remote allow-list, including API keys, HTTP-provider credentials, local Ollama / LM Studio, and artifact paths, remain unavailable remotely.\n\nAllow remote settings?';
24
+ }
25
+
26
+ function isPermissionDisabledDescribe(channel, endpoint, result) {
27
+ return channel === CHANNEL
28
+ && endpoint === 'describe'
29
+ && result && result.ok === true
30
+ && result.value && result.value.enabled !== true
31
+ && result.value.reason === 'permission-disabled';
32
+ }
33
+
34
+ async function authorizeAndRefresh(target, call) {
35
+ if (authorizationPromise) return authorizationPromise;
36
+ authorizationPromise = (async function(){
37
+ if (typeof window.confirm !== 'function' || window.confirm(riskMessage()) !== true) return undefined;
38
+ var authorized = await call.call(target, CHANNEL, AUTHORIZE_ENDPOINT, { acceptedRisk: true });
39
+ if (!authorized || authorized.ok !== true) {
40
+ var message = authorized && authorized.error && authorized.error.message
41
+ ? authorized.error.message
42
+ : 'Vision Router could not enable remote settings.';
43
+ try { if (typeof window.alert === 'function') window.alert(message); } catch (_) {}
44
+ return undefined;
45
+ }
46
+ return call.call(target, CHANNEL, 'describe', {});
47
+ })();
48
+ try { return await authorizationPromise; }
49
+ finally { authorizationPromise = undefined; }
50
+ }
51
+
52
+ function wrapRpc(rpc) {
53
+ if (!rpc || (typeof rpc !== 'object' && typeof rpc !== 'function')) return rpc;
54
+ if (rpcCache && rpcCache.has(rpc)) return rpcCache.get(rpc);
55
+ var wrapped = new Proxy(rpc, {
56
+ get: function(target, property) {
57
+ if (property === 'call') {
58
+ var call = Reflect.get(target, property, target);
59
+ if (typeof call !== 'function') return call;
60
+ return async function(channel, endpoint) {
61
+ var result = await call.apply(target, arguments);
62
+ if (!isPermissionDisabledDescribe(channel, endpoint, result)) return result;
63
+ var refreshed = await authorizeAndRefresh(target, call);
64
+ return refreshed || result;
65
+ };
66
+ }
67
+ var value = Reflect.get(target, property, target);
68
+ return typeof value === 'function' ? value.bind(target) : value;
69
+ }
70
+ });
71
+ if (rpcCache) rpcCache.set(rpc, wrapped);
72
+ return wrapped;
73
+ }
74
+
75
+ function wrapConnection(connection) {
76
+ if (!connection || (typeof connection !== 'object' && typeof connection !== 'function')) return connection;
77
+ if (connectionCache && connectionCache.has(connection)) return connectionCache.get(connection);
78
+ var wrapped = new Proxy(connection, {
79
+ get: function(target, property) {
80
+ if (property === 'rpc') return wrapRpc(Reflect.get(target, property, target));
81
+ var value = Reflect.get(target, property, target);
82
+ return typeof value === 'function' ? value.bind(target) : value;
83
+ }
84
+ });
85
+ if (connectionCache) connectionCache.set(connection, wrapped);
86
+ return wrapped;
87
+ }
88
+
89
+ function wrapContext(ctx) {
90
+ if (!ctx || typeof ctx !== 'object') return ctx;
91
+ if (contextCache && contextCache.has(ctx)) return contextCache.get(ctx);
92
+ var wrapped = new Proxy(ctx, {
93
+ get: function(target, property) {
94
+ if (property === 'get') {
95
+ var get = Reflect.get(target, property, target);
96
+ if (typeof get !== 'function') return get;
97
+ return function(name) {
98
+ var value = get.apply(target, arguments);
99
+ return name === 'connection' ? wrapConnection(value) : value;
100
+ };
101
+ }
102
+ var value = Reflect.get(target, property, target);
103
+ return typeof value === 'function' ? value.bind(target) : value;
104
+ }
105
+ });
106
+ if (contextCache) contextCache.set(ctx, wrapped);
107
+ return wrapped;
108
+ }
109
+
110
+ function patchLoader(loader) {
111
+ if (!loader || typeof loader.load !== 'function' || loader.load.__visionRouterRemoteRiskConfirmation) return;
112
+ var original = loader.load;
113
+ function load(spec) {
114
+ if (spec && spec.id === 'dsh-vision-router' && typeof spec.factory === 'function') {
115
+ var factory = spec.factory;
116
+ spec = Object.assign({}, spec, {
117
+ factory: function(require) {
118
+ var exports = factory(require);
119
+ if (exports && typeof exports.apply === 'function' && !exports.apply.__visionRouterRemoteRiskConfirmation) {
120
+ var apply = exports.apply;
121
+ var wrappedApply = function(ctx) {
122
+ var rest = Array.prototype.slice.call(arguments, 1);
123
+ return apply.apply(exports, [wrapContext(ctx)].concat(rest));
124
+ };
125
+ Object.defineProperty(wrappedApply, '__visionRouterRemoteRiskConfirmation', { value: true });
126
+ exports.apply = wrappedApply;
127
+ }
128
+ return exports;
129
+ }
130
+ });
131
+ }
132
+ return original.call(loader, spec);
133
+ }
134
+ Object.defineProperty(load, '__visionRouterRemoteRiskConfirmation', { value: true });
135
+ loader.load = load;
136
+ }
137
+
138
+ function install() {
139
+ if (window.__ModuleLoader__) {
140
+ patchLoader(window.__ModuleLoader__);
141
+ return;
142
+ }
143
+ var descriptor = Object.getOwnPropertyDescriptor(window, '__ModuleLoader__');
144
+ if (descriptor && descriptor.configurable === false) return;
145
+ if (descriptor && typeof descriptor.set === 'function') {
146
+ var previousGet = descriptor.get;
147
+ var previousSet = descriptor.set;
148
+ Object.defineProperty(window, '__ModuleLoader__', {
149
+ configurable: true,
150
+ enumerable: descriptor.enumerable !== false,
151
+ get: function(){ return previousGet ? previousGet.call(window) : undefined; },
152
+ set: function(value) {
153
+ previousSet.call(window, value);
154
+ try { patchLoader(window.__ModuleLoader__ || value); } catch (_) {}
155
+ }
156
+ });
157
+ return;
158
+ }
159
+ var stored;
160
+ Object.defineProperty(window, '__ModuleLoader__', {
161
+ configurable: true,
162
+ enumerable: true,
163
+ get: function(){ return stored; },
164
+ set: function(value) {
165
+ stored = value;
166
+ patchLoader(value);
167
+ Object.defineProperty(window, '__ModuleLoader__', {
168
+ configurable: true,
169
+ enumerable: true,
170
+ writable: true,
171
+ value: stored
172
+ });
173
+ }
174
+ });
175
+ }
176
+
177
+ try { install(); } catch (_) {}
178
+ })();`
179
+
180
+ export function injectRemoteSettingsRiskConfirmationPrelude(html) {
181
+ if (typeof html !== 'string' || html.includes(RISK_PRELUDE_MARK)) return html
182
+ const script = `<script ${RISK_PRELUDE_MARK}>${REMOTE_SETTINGS_RISK_CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')}</script>`
183
+ const endHead = html.indexOf('</head>')
184
+ return endHead === -1 ? `${html}${script}` : `${html.slice(0, endHead)}${script}${html.slice(endHead)}`
185
+ }
186
+
187
+ export function installRemoteSettingsRiskConfirmationBridge(ctx) {
188
+ if (!ctx || typeof ctx.inject !== 'function') return
189
+ ctx.inject(['webServer'], (webCtx) => {
190
+ webCtx.effect(
191
+ () => webCtx.webServer.tapIndex(injectRemoteSettingsRiskConfirmationPrelude),
192
+ 'vision-router: remote settings risk confirmation client shim',
193
+ )
194
+ })
195
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vision-router",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
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": {
@@ -75,7 +75,7 @@
75
75
  "sharp": "^0.35.3"
76
76
  },
77
77
  "scripts": {
78
- "test": "node --test tests/core.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/provider-directory-fallback.test.js tests/settings-section-order.test.js tests/vision-resilience.test.js tests/client.test.js tests/remote-settings-bridge.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/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/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/adversarial-hardening.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/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-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/vision-budget-activation.test.js tests/runtime-boundary-fixes.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/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js"
78
+ "test": "node --test tests/core.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/provider-directory-fallback.test.js tests/settings-section-order.test.js tests/vision-resilience.test.js tests/client.test.js tests/remote-settings-bridge.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/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/bundle-defaults.test.js tests/file-logger.test.js tests/replay-delegation.test.js tests/adversarial-hardening.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/android-attachment-compat.test.js tests/free-cloud-first.test.js tests/rc6-rc7-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/vision-budget-activation.test.js tests/runtime-boundary-fixes.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/pixel-diff-stream.test.js tests/large-image-resource-integration.test.js tests/structured-guard-idempotency.test.js"
79
79
  },
80
80
  "pnpm": {
81
81
  "onlyBuiltDependencies": [