dsh-vision-router 2.2.6 → 2.2.8

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 (41) hide show
  1. package/README.md +2 -2
  2. package/README.zh.md +2 -2
  3. package/docs/architecture/dsh-020-rc2-adaptation.md +23 -0
  4. package/docs/architecture/dsh-compatibility-matrix.md +4 -3
  5. package/docs/architecture/dsh-support-window.md +7 -4
  6. package/docs/architecture/host-first-proxy-convergence.md +1 -1
  7. package/docs/releases/v2.2.7.md +22 -0
  8. package/docs/releases/v2.2.8.md +25 -0
  9. package/lib/artifact-io.js +11 -3
  10. package/lib/client-host-compat-prelude.js +7 -12
  11. package/lib/client-presentation-boundary-main.js +7 -15
  12. package/lib/client-presentation-boundary.js +7 -12
  13. package/lib/client-script-carrier.js +90 -0
  14. package/lib/client.js +7 -2
  15. package/lib/dsh-support-window.js +5 -3
  16. package/lib/guide-vision-toggle-highlight.js +7 -10
  17. package/lib/live-model-client-prelude.js +7 -14
  18. package/lib/live-model-discovery.js +2 -2
  19. package/lib/local-remote-settings-permission.js +8 -9
  20. package/lib/session-vision-mode-boundary.js +43 -8
  21. package/lib/settings-client-017-compat.js +4 -0
  22. package/lib/settings-client-rc8-lifecycle.js +11 -12
  23. package/lib/settings-factory-lifecycle.js +25 -14
  24. package/lib/settings-ia-client-prelude.js +12 -12
  25. package/lib/settings-limit-client-prelude.js +7 -9
  26. package/lib/strict-live-model-client-prelude.js +7 -10
  27. package/lib/tesseract-exec-compat.js +28 -6
  28. package/lib/v2-settings-ia-integration.js +21 -6
  29. package/lib/vision-background-benchmark.js +3 -5
  30. package/lib/vision-background-stop-store.js +2 -1
  31. package/lib/vision-capability-benchmark-client.js +7 -10
  32. package/lib/vision-capability-probe.js +2 -1
  33. package/lib/vision-exact-check-client.js +13 -8
  34. package/lib/vision-image-input-verdict.js +2 -1
  35. package/lib/vision-model-visibility-boundary-main.js +7 -11
  36. package/lib/vision-model-visibility-boundary.js +7 -12
  37. package/lib/vision-routing-settings-prelude.js +7 -11
  38. package/lib/vision-toggle-root-hardening.js +28 -3
  39. package/lib/vision-turn-budget-client-prelude.js +7 -10
  40. package/lib/web/remote-settings-client.js +11 -12
  41. package/package.json +2 -5
@@ -1,4 +1,4 @@
1
- import { htmlHasScriptMarker } from './html-script-marker.js'
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
2
2
 
3
3
  const CLIENT_MARK = 'data-vision-router-capability-benchmark'
4
4
 
@@ -412,17 +412,14 @@ export const CAPABILITY_BENCHMARK_CLIENT = String.raw`(function(){
412
412
  })();`
413
413
 
414
414
  export function injectCapabilityBenchmarkClient(html) {
415
- if (typeof html !== 'string' || htmlHasScriptMarker(html, CLIENT_MARK)) return html
416
- const script = `<script ${CLIENT_MARK}>${CAPABILITY_BENCHMARK_CLIENT.replace(/<\/script/gi, '<\\/script')}</script>`
417
- const head = html.indexOf('<head>')
418
- return head === -1 ? `${script}${html}` : `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
415
+ return injectClientCarrierHtml(html, CLIENT_MARK, CAPABILITY_BENCHMARK_CLIENT)
419
416
  }
420
417
 
421
418
  export function installCapabilityBenchmarkClient(ctx) {
422
- ctx?.inject?.(['webServer'], (webCtx) => {
423
- webCtx.effect(
424
- () => webCtx.webServer.tapIndex(injectCapabilityBenchmarkClient),
425
- 'vision-router: capability benchmark Host presentation client controls',
426
- )
419
+ installClientScriptCarriers(ctx, {
420
+ marker: CLIENT_MARK,
421
+ prelude: CAPABILITY_BENCHMARK_CLIENT,
422
+ label: 'vision-router: capability benchmark client',
423
+ injectHtml: injectCapabilityBenchmarkClient,
427
424
  })
428
425
  }
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto'
1
2
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
2
3
  import path from 'node:path'
3
4
  import process from 'node:process'
@@ -374,7 +375,7 @@ async function loadCache(file, fsOps, maxEntries) {
374
375
 
375
376
  async function saveCache(file, records, fsOps, maxEntries) {
376
377
  const directory = path.dirname(file)
377
- const temporary = `${file}.${process.pid}.${Date.now()}.tmp`
378
+ const temporary = `${file}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`
378
379
  const profiles = selectRetainedCapabilityProfiles(records.values(), maxEntries)
379
380
  await fsOps.mkdir(directory, { recursive: true })
380
381
  await fsOps.writeFile(temporary, JSON.stringify(cacheEnvelope(profiles)), { encoding: 'utf8', mode: 0o600 })
@@ -1,4 +1,4 @@
1
- import { htmlHasScriptMarker } from './html-script-marker.js'
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
2
2
 
3
3
  const CLIENT_MARK = 'data-vision-router-exact-check'
4
4
 
@@ -19,8 +19,8 @@ export const VISION_EXACT_CHECK_CLIENT = String.raw`(function(){
19
19
  function text(cn,en){ return zh() ? cn : en; }
20
20
  function localPage(){
21
21
  try {
22
- var host=String(window.location.hostname||'').toLowerCase();
23
- return host==='localhost'||host.endsWith('.localhost')||host==='::1'||host==='[::1]'||/^127(?:\.\d{1,3}){3}$/.test(host);
22
+ var location=window.location||{},host=String(location.hostname||'').toLowerCase(),protocol=String(location.protocol||'').toLowerCase();
23
+ return (protocol==='dsh-app:'&&host==='app')||host==='localhost'||host.endsWith('.localhost')||host==='::1'||host==='[::1]'||/^127(?:\.\d{1,3}){3}$/.test(host);
24
24
  } catch (_) { return false; }
25
25
  }
26
26
  function rowSelection(row){
@@ -185,9 +185,14 @@ export const VISION_EXACT_CHECK_CLIENT = String.raw`(function(){
185
185
  })();`
186
186
 
187
187
  export function injectVisionExactCheckClient(html) {
188
- if (typeof html !== 'string' || htmlHasScriptMarker(html, CLIENT_MARK)) return html
189
- const script = `<script ${CLIENT_MARK}>${VISION_EXACT_CHECK_CLIENT.replace(/<\/script/gi, '<\\/script')}</script>`
190
- const closeHead = html.indexOf('</head>')
191
- if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
192
- return `${html}${script}`
188
+ return injectClientCarrierHtml(html, CLIENT_MARK, VISION_EXACT_CHECK_CLIENT)
189
+ }
190
+
191
+ export function installVisionExactCheckClient(ctx) {
192
+ installClientScriptCarriers(ctx, {
193
+ marker: CLIENT_MARK,
194
+ prelude: VISION_EXACT_CHECK_CLIENT,
195
+ label: 'vision-router: exact image check product control',
196
+ injectHtml: injectVisionExactCheckClient,
197
+ })
193
198
  }
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto'
1
2
  import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
2
3
  import path from 'node:path'
3
4
  import process from 'node:process'
@@ -69,7 +70,7 @@ async function load(file, fsOps) {
69
70
  }
70
71
 
71
72
  async function save(file, records, fsOps) {
72
- const temporary = `${file}.${process.pid}.${Date.now()}.tmp`
73
+ const temporary = `${file}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`
73
74
  const verdicts = selectRetainedVerdicts(records.values())
74
75
  await fsOps.mkdir(path.dirname(file), { recursive: true })
75
76
  await fsOps.writeFile(temporary, JSON.stringify({ version: CACHE_VERSION, verdicts }), { encoding: 'utf8', mode: 0o600 })
@@ -1,3 +1,4 @@
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
1
2
  const VISION_MODE_WRAPPER_SOURCE = 'deepseek-official'
2
3
  const DEFAULT_WRAPPER_ROUTE = 'deepseek-vision'
3
4
  const MODEL_SELECTION_TARGET = '@deepseek-ai/dsh-client-ui-model-selection'
@@ -454,19 +455,14 @@ export const VISION_MODEL_VISIBILITY_PRELUDE = String.raw`(function(){
454
455
  })();`
455
456
 
456
457
  export function injectVisionModelVisibilityBoundary(html) {
457
- if (typeof html !== 'string' || html.includes(VISIBILITY_MARK)) return html
458
- const safe = VISION_MODEL_VISIBILITY_PRELUDE.replace(/<\/script/gi, '<\\/script')
459
- const script = `<script ${VISIBILITY_MARK}>${safe}</script>`
460
- const closeHead = html.indexOf('</head>')
461
- if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
462
- return `${html}${script}`
458
+ return injectClientCarrierHtml(html, VISIBILITY_MARK, VISION_MODEL_VISIBILITY_PRELUDE)
463
459
  }
464
460
 
465
461
  export function installVisionModelVisibilityBoundary(ctx) {
466
- ctx?.inject?.(['webServer'], (webCtx) => {
467
- webCtx.effect(
468
- () => webCtx.webServer.tapIndex(injectVisionModelVisibilityBoundary),
469
- 'vision-router: model visibility boundary',
470
- )
462
+ installClientScriptCarriers(ctx, {
463
+ marker: VISIBILITY_MARK,
464
+ prelude: VISION_MODEL_VISIBILITY_PRELUDE,
465
+ label: 'vision-router: model visibility boundary',
466
+ injectHtml: injectVisionModelVisibilityBoundary,
471
467
  })
472
468
  }
@@ -1,4 +1,4 @@
1
- import { htmlHasScriptMarker } from './html-script-marker.js'
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
2
2
  import { VISION_MODEL_VISIBILITY_PRELUDE } from './vision-model-visibility-boundary-main.js'
3
3
 
4
4
  const VISIBILITY_MARK = 'data-vision-router-model-visibility-boundary'
@@ -10,19 +10,14 @@ export {
10
10
  } from './vision-model-visibility-boundary-main.js'
11
11
 
12
12
  export function injectVisionModelVisibilityBoundary(html) {
13
- if (typeof html !== 'string' || htmlHasScriptMarker(html, VISIBILITY_MARK)) return html
14
- const safe = VISION_MODEL_VISIBILITY_PRELUDE.replace(/<\/script/gi, '<\\/script')
15
- const script = `<script ${VISIBILITY_MARK}>${safe}</script>`
16
- const closeHead = html.indexOf('</head>')
17
- if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
18
- return `${html}${script}`
13
+ return injectClientCarrierHtml(html, VISIBILITY_MARK, VISION_MODEL_VISIBILITY_PRELUDE)
19
14
  }
20
15
 
21
16
  export function installVisionModelVisibilityBoundary(ctx) {
22
- ctx?.inject?.(['webServer'], (webCtx) => {
23
- webCtx.effect(
24
- () => webCtx.webServer.tapIndex(injectVisionModelVisibilityBoundary),
25
- 'vision-router: model visibility boundary',
26
- )
17
+ installClientScriptCarriers(ctx, {
18
+ marker: VISIBILITY_MARK,
19
+ prelude: VISION_MODEL_VISIBILITY_PRELUDE,
20
+ label: 'vision-router: model visibility boundary',
21
+ injectHtml: injectVisionModelVisibilityBoundary,
27
22
  })
28
23
  }
@@ -1,4 +1,4 @@
1
- import { htmlHasScriptMarker } from './html-script-marker.js'
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
2
2
 
3
3
  const ROUTING_SETTINGS_PRELUDE_MARK = 'data-vision-router-routing-settings'
4
4
 
@@ -536,18 +536,14 @@ export const VISION_ROUTING_SETTINGS_PRELUDE = String.raw`(function(){
536
536
  })();`
537
537
 
538
538
  export function injectVisionRoutingSettingsPrelude(html) {
539
- if (typeof html !== 'string' || htmlHasScriptMarker(html, ROUTING_SETTINGS_PRELUDE_MARK)) return html
540
- const script = `<script ${ROUTING_SETTINGS_PRELUDE_MARK}>${VISION_ROUTING_SETTINGS_PRELUDE.replace(/<\/script/gi, '<\\/script')}</script>`
541
- const closeHead = html.indexOf('</head>')
542
- if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
543
- return `${html}${script}`
539
+ return injectClientCarrierHtml(html, ROUTING_SETTINGS_PRELUDE_MARK, VISION_ROUTING_SETTINGS_PRELUDE)
544
540
  }
545
541
 
546
542
  export function installVisionRoutingSettingsPrelude(ctx) {
547
- ctx?.inject?.(['webServer'], (webCtx) => {
548
- webCtx.effect(
549
- () => webCtx.webServer.tapIndex(injectVisionRoutingSettingsPrelude),
550
- 'vision-router: v2 routing settings product panel',
551
- )
543
+ installClientScriptCarriers(ctx, {
544
+ marker: ROUTING_SETTINGS_PRELUDE_MARK,
545
+ prelude: VISION_ROUTING_SETTINGS_PRELUDE,
546
+ label: 'vision-router: Vision routing Settings prelude',
547
+ injectHtml: injectVisionRoutingSettingsPrelude,
552
548
  })
553
549
  }
@@ -331,9 +331,9 @@ function replaceAll(source, before, after) {
331
331
  return source.includes(before) ? source.split(before).join(after) : source
332
332
  }
333
333
 
334
- export function hardenVisionToggleHtml(html) {
335
- if (typeof html !== 'string') return html
336
- let next = html
334
+ export function hardenVisionClientSource(source) {
335
+ if (typeof source !== 'string') return source
336
+ let next = source
337
337
 
338
338
  next = replaceAll(
339
339
  next,
@@ -430,6 +430,13 @@ export function hardenVisionToggleHtml(html) {
430
430
  ` var hardening = window.__dshVisionRouterRootHardening;\n var recovery = hardening ? hardening.recoveryFor(directory) : undefined;\n var store = wrapStore(directory.store, settings, recovery);`,
431
431
  )
432
432
 
433
+ return next
434
+ }
435
+
436
+ export function hardenVisionToggleHtml(html) {
437
+ if (typeof html !== 'string') return html
438
+ let next = hardenVisionClientSource(html)
439
+
433
440
  if (!next.includes(OWNERSHIP_MARK)) {
434
441
  const safe = CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')
435
442
  const script = `<script ${OWNERSHIP_MARK}>${safe}</script>`
@@ -474,6 +481,24 @@ export function createVisionToggleRootHardening(ctx, config = {}) {
474
481
  }),
475
482
  'vision-router: route ownership',
476
483
  )
484
+ if (typeof webCtx.on === 'function') {
485
+ webCtx.on('webserver/index-inject', (table) => {
486
+ if (!Array.isArray(table)) return
487
+ for (const row of table) {
488
+ if (row?.kind === 'script' && typeof row.text === 'string') {
489
+ row.text = hardenVisionClientSource(row.text)
490
+ }
491
+ }
492
+ const signature = `/* ${OWNERSHIP_MARK} */`
493
+ if (!table.some((row) => row?.kind === 'script' && typeof row.text === 'string' && row.text.includes(signature))) {
494
+ table.push({
495
+ kind: 'script',
496
+ placement: 'head',
497
+ text: `${signature}\n${CLIENT_PRELUDE}`,
498
+ })
499
+ }
500
+ })
501
+ }
477
502
  webCtx.effect(
478
503
  () => webCtx.webServer.tapIndex(hardenVisionToggleHtml),
479
504
  'vision-router: vision toggle root hardening',
@@ -1,3 +1,4 @@
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from './client-script-carrier.js'
1
2
  const CLIENT_PRELUDE_MARK = 'data-vision-router-turn-budget'
2
3
 
3
4
  export const VISION_TURN_BUDGET_CLIENT_PRELUDE = String.raw`(function(){
@@ -259,18 +260,14 @@ export const VISION_TURN_BUDGET_CLIENT_PRELUDE = String.raw`(function(){
259
260
  })();`
260
261
 
261
262
  export function injectVisionTurnBudgetClientPrelude(html) {
262
- if (typeof html !== 'string' || html.includes(CLIENT_PRELUDE_MARK)) return html
263
- const script = `<script ${CLIENT_PRELUDE_MARK}>${VISION_TURN_BUDGET_CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')}</script>`
264
- const closeHead = html.indexOf('</head>')
265
- if (closeHead !== -1) return `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
266
- return `${html}${script}`
263
+ return injectClientCarrierHtml(html, CLIENT_PRELUDE_MARK, VISION_TURN_BUDGET_CLIENT_PRELUDE)
267
264
  }
268
265
 
269
266
  export function installVisionTurnBudgetClientPrelude(ctx) {
270
- ctx?.inject?.(['webServer'], (webCtx) => {
271
- webCtx.effect(
272
- () => webCtx.webServer.tapIndex(injectVisionTurnBudgetClientPrelude),
273
- 'vision-router: turn budget client prelude',
274
- )
267
+ installClientScriptCarriers(ctx, {
268
+ marker: CLIENT_PRELUDE_MARK,
269
+ prelude: VISION_TURN_BUDGET_CLIENT_PRELUDE,
270
+ label: 'vision-router: turn budget client prelude',
271
+ injectHtml: injectVisionTurnBudgetClientPrelude,
275
272
  })
276
273
  }
@@ -1,4 +1,4 @@
1
- import { htmlHasScriptMarker } from '../html-script-marker.js'
1
+ import { injectClientCarrierHtml, installClientScriptCarriers } from '../client-script-carrier.js'
2
2
  import { installVisionRouterRemoteSettingsBridge } from '../remote-settings-bridge.js'
3
3
  import { installSettingsRc8ClientLifecycle } from '../settings-client-rc8-lifecycle.js'
4
4
 
@@ -34,6 +34,10 @@ export const SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE = String.raw`(function(){
34
34
  var hostname = locationLike && typeof locationLike.hostname === 'string'
35
35
  ? locationLike.hostname.toLowerCase().replace(/^\[|\]$/g, '')
36
36
  : '';
37
+ var protocol = locationLike && typeof locationLike.protocol === 'string'
38
+ ? locationLike.protocol.toLowerCase()
39
+ : '';
40
+ if (protocol === 'dsh-app:' && hostname === 'app') return true;
37
41
  if (hostname === 'localhost' || hostname.endsWith('.localhost') || hostname === '::1') return true;
38
42
  return /^127(?:\.\d{1,3}){3}$/.test(hostname);
39
43
  }
@@ -183,20 +187,15 @@ export const SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE = String.raw`(function(){
183
187
  })();`
184
188
 
185
189
  export function injectSettingsConfigFormsCompatPrelude(html) {
186
- if (typeof html !== 'string' || htmlHasScriptMarker(html, SETTINGS_CONFIG_FORMS_MARK)) return html
187
- const safe = SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE.replace(/<\/script/gi, '<\\/script')
188
- const script = `<script ${SETTINGS_CONFIG_FORMS_MARK}>${safe}</script>`
189
- const closeHead = html.indexOf('</head>')
190
- return closeHead === -1 ? `${html}${script}` : `${html.slice(0, closeHead)}${script}${html.slice(closeHead)}`
190
+ return injectClientCarrierHtml(html, SETTINGS_CONFIG_FORMS_MARK, SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE)
191
191
  }
192
192
 
193
193
  export function installSettingsConfigFormsCompat(ctx) {
194
- if (!ctx || typeof ctx.inject !== 'function') return
195
- ctx.inject(['webServer'], (webCtx) => {
196
- webCtx.effect(
197
- () => webCtx.webServer.tapIndex(injectSettingsConfigFormsCompatPrelude),
198
- 'vision-router: settings configForms compatibility',
199
- )
194
+ installClientScriptCarriers(ctx, {
195
+ marker: SETTINGS_CONFIG_FORMS_MARK,
196
+ prelude: SETTINGS_CONFIG_FORMS_CLIENT_PRELUDE,
197
+ label: 'vision-router: settings configForms compatibility',
198
+ injectHtml: injectSettingsConfigFormsCompatPrelude,
200
199
  })
201
200
  }
202
201
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vision-router",
3
- "version": "2.2.6",
3
+ "version": "2.2.8",
4
4
  "description": "Eyes for text-only DeepSeek Harness agents: built-in free vision chain + pixel-level tools. Remote vision providers, including the default free fallback, receive image content unless strict local-only use is configured.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -70,7 +70,7 @@
70
70
  "sharp": "^0.35.4"
71
71
  },
72
72
  "scripts": {
73
- "test": "node --test tests/index-modularization.test.js 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/degraded-local-evidence.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/release-registry-identity.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/official-deepseek-catalog.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/local-only-vision.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/issue-512-tool-restriction.test.js tests/pi-ai-bridge-wire-compat.test.js tests/fetch-wrapper-lifecycle.test.js tests/fetch-wrapper-composition.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/security-resource-boundaries.test.js tests/security-property-fuzz.test.js tests/security-adversarial-fuzz-contract.test.js tests/runtime-i18n.test.js tests/long-ocr-empty-retry.test.js tests/tesseract-adaptive-ocr.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/session-vision-event-feed.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
+ "test": "node --test tests/index-modularization.test.js 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/cache-atomic-write-concurrency.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/degraded-local-evidence.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/release-registry-identity.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/official-deepseek-catalog.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/local-only-vision.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/issue-512-tool-restriction.test.js tests/pi-ai-bridge-wire-compat.test.js tests/fetch-wrapper-lifecycle.test.js tests/fetch-wrapper-composition.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/security-resource-boundaries.test.js tests/security-property-fuzz.test.js tests/security-adversarial-fuzz-contract.test.js tests/runtime-i18n.test.js tests/long-ocr-empty-retry.test.js tests/tesseract-adaptive-ocr.test.js tests/tesseract-node24-boot.test.js tests/session-vision-state.test.js tests/session-vision-state-integration.test.js tests/session-vision-event-feed.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",
74
74
  "test:core": "node --test tests/core.test.js tests/degraded-local-evidence.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",
75
75
  "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",
76
76
  "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",
@@ -88,9 +88,6 @@
88
88
  "quality:round2:run": "node quality/vision-round2/run-host-api.mjs",
89
89
  "quality:round2:report": "node quality/vision-round2/report-results.mjs"
90
90
  },
91
- "pnpm": {
92
- "onlyBuiltDependencies": ["sharp"]
93
- },
94
91
  "dsh": {
95
92
  "client": {
96
93
  "platform": "web",