arrayview 0.29.1__tar.gz → 0.29.2__tar.gz
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.
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/lifecycle.md +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/PKG-INFO +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/pyproject.toml +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/scripts/release.sh +25 -16
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_launcher.py +6 -4
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_viewer.html +24 -88
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_vscode_extension.py +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_vscode_signal.py +111 -43
- arrayview-0.29.2/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_api.py +67 -4
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_lifecycle_contract.py +49 -5
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_view_component_integration.py +22 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/uv.lock +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/extension.js +13 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/lifecycle_helpers.js +5 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/package.json +1 -1
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/test_lifecycle_helpers.js +6 -0
- arrayview-0.29.1/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/frontend-designer/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/invocation-consistency/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/running-code.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/session-management.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/tracing.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/todo-workflow/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/ui-consistency-audit/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.agents/skills/visual-bug-fixing/SKILL.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.github/copilot-instructions.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.github/workflows/docs.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.github/workflows/python-publish.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.gitignore +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.ignore +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/AGENTS.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/ROUTER.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/SETUP.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/SYNC.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/architecture.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/conventions.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/decisions.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/frontend.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/project-state.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/render-pipeline.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/setup.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/context/stack.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/INDEX.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/README.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/add-file-format.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/add-server-endpoint.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/animation-verify.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/debug-render.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/debug-vscode-extension-python.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/extend-compare-mode.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/extract-server-route-module.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/patterns/frontend-change.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/setup.sh +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.mex/sync.sh +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.opencode/opencode.json +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T18-46-49-737Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T18-48-21-979Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T18-51-35-665Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-07-01-393Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-14-37-969Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-21-30-940Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-23-08-126Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-29-33-155Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-31-25-336Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-31-53-789Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-39-12-257Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T19-39-16-449Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T20-15-25-513Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T20-25-13-179Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T20-39-01-435Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-01-27-659Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-01-41-283Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-03-00-625Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-04-12-887Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-33-39-044Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-38-01-530Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-45-20-383Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-55-11-545Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-56-03-307Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-56-35-733Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-57-12-181Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-57-37-748Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T21-58-13-679Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-06T22-37-23-895Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T00-39-18-637Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T01-41-46-243Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T04-31-48-472Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-14-15-632Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-14-47-582Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-16-23-471Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-17-10-247Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-18-24-707Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-20-06-164Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-20-28-342Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-21-54-962Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-22-34-666Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-23-11-336Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-23-36-260Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-24-09-267Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-24-35-434Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-25-57-010Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-34-48-823Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-46-46-468Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-48-17-930Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-49-26-400Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-50-31-563Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/page-2026-05-07T12-56-45-568Z.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.playwright-cli/theme-dark.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.python-version +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/.vscode/settings.json +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/AGENTS.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/CONTRIBUTING.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/DESIGN.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/LICENSE +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/README.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/comparing.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/configuration.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/display.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/index.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/launch-routing-refactor.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/lifecycle.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/loading.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/logo.png +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/measurement.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/remote.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/stylesheets/extra.css +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/viewing.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/docs/vscode-window-routing-plan.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/experiments/ws_tunnel_diag/ws_tunnel_diag.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/matlab/arrayview.m +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/mkdocs.yml +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/2026-04-14-immersive-animation.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/2026-05-07-unified-colormap-picker.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/arrayview_tool_menu_fix_prompt.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/arrayview_tool_menu_implementation_plan.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/egg-placement-mockup.html +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/refactoring_plan.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/roi-analysis-requirements.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/plans/webview/LOG.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/scripts/demo.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/ARCHITECTURE.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/__init__.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/__main__.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_analysis.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_app.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_codex_open.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_config.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_diff.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_icon.png +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_imaging.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_io.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_launch_plan.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_lifecycle.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_overlays.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_platform.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_render.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_analysis.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_export.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_loading.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_persistence.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_preload.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_query.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_rendering.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_segmentation.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_state.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_vectorfield.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_routes_websocket.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_segmentation.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_server.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_session.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_shell.html +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_synthetic_mri.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_torch.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_vectorfield.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_vscode.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/_vscode_browser.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/src/arrayview/gsap.min.js +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/capture_v_animation.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/conftest.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/lifecycle_matrix.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_backend_shared.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_browser.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_cli.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_colorbar_hover_highlight.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_command_reachability.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_config.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_cross_mode_parametrized.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_interactions.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_io.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_large_arrays.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_launch_plan.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_loading_server.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_mode_consistency.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_mode_matrix.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_mode_roundtrip.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_nifti_meta.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_nifti_series.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_rgb_pixel_art.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_torch.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/test_view_component_unit.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/ui_audit.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/v_anim_frames/.gitkeep +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/tests/visual_smoke.py +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/AGENTS.md +0 -0
- {arrayview-0.29.1 → arrayview-0.29.2}/vscode-extension/LICENSE +0 -0
|
@@ -60,7 +60,7 @@ This contract describes who owns the backend, when it starts, and what closes it
|
|
|
60
60
|
|
|
61
61
|
- Remote or tunnel launches may persist when `--serve` or tunnel display ownership requires it.
|
|
62
62
|
- VS Code tunnel display uses forwarded localhost URLs; the extension should configure the port, promote privacy when available, and resolve the URL with `asExternalUri`.
|
|
63
|
-
- With multiple registered tunnel windows, a missing or stale `ARRAYVIEW_WINDOW_ID`
|
|
63
|
+
- With multiple registered tunnel windows, a missing or stale `ARRAYVIEW_WINDOW_ID` uses the shared broadcast signal; only the focused VS Code window may claim it.
|
|
64
64
|
- An exact registered `ARRAYVIEW_WINDOW_ID` wins; do not redirect it to a newer same-parent registration because live tunnel windows can share ancestry.
|
|
65
65
|
- Plain SSH should use `localhost` forwarding guidance and stay transient unless a shared server was explicitly requested.
|
|
66
66
|
|
|
@@ -8,7 +8,7 @@ set -euo pipefail
|
|
|
8
8
|
BUMP="minor"
|
|
9
9
|
DRY_RUN=true
|
|
10
10
|
NO_AI=false
|
|
11
|
-
AI_TOOL="
|
|
11
|
+
AI_TOOL="codex"
|
|
12
12
|
|
|
13
13
|
usage() {
|
|
14
14
|
cat <<EOF
|
|
@@ -16,7 +16,7 @@ Usage: $(basename "$0") [OPTIONS]
|
|
|
16
16
|
|
|
17
17
|
Options:
|
|
18
18
|
--bump {major,minor,patch} Version bump type (default: minor)
|
|
19
|
-
--ai {claude,codex} AI tool for release notes (default:
|
|
19
|
+
--ai {claude,codex} AI tool for release notes (default: codex)
|
|
20
20
|
--execute Actually run (default is dry-run)
|
|
21
21
|
--no-ai Skip AI release notes, use GitHub's --generate-notes
|
|
22
22
|
-h, --help Show this help
|
|
@@ -116,9 +116,13 @@ Rules:
|
|
|
116
116
|
if command -v "$CODEX_BIN" &>/dev/null; then
|
|
117
117
|
echo "Generating release notes with Codex..."
|
|
118
118
|
tmpfile=$(mktemp)
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
errfile=$(mktemp)
|
|
120
|
+
trap 'rm -f "$tmpfile" "$errfile"' EXIT
|
|
121
|
+
if printf '%s\n' "$PROMPT" | "$CODEX_BIN" exec --output-last-message "$tmpfile" - >/dev/null 2>"$errfile"; then
|
|
121
122
|
NOTES=$(<"$tmpfile")
|
|
123
|
+
elif [[ -s "$errfile" ]]; then
|
|
124
|
+
echo "Codex release notes failed:"
|
|
125
|
+
sed 's/^/ /' "$errfile"
|
|
122
126
|
fi
|
|
123
127
|
fi
|
|
124
128
|
;;
|
|
@@ -127,7 +131,19 @@ fi
|
|
|
127
131
|
|
|
128
132
|
if [[ -z "$NOTES" ]]; then
|
|
129
133
|
if [[ "$NO_AI" == false ]]; then
|
|
130
|
-
echo "AI notes unavailable, falling back to
|
|
134
|
+
echo "AI notes unavailable, falling back to commit-based notes"
|
|
135
|
+
fi
|
|
136
|
+
NOTES="## What's new in $TAG"
|
|
137
|
+
if [[ -n "$COMMITS" ]]; then
|
|
138
|
+
while IFS= read -r commit; do
|
|
139
|
+
[[ -z "$commit" ]] && continue
|
|
140
|
+
message="${commit#* }"
|
|
141
|
+
NOTES+=$'\n'
|
|
142
|
+
NOTES+="- ${message}"
|
|
143
|
+
done <<< "$COMMITS"
|
|
144
|
+
else
|
|
145
|
+
NOTES+=$'\n'
|
|
146
|
+
NOTES+="- Maintenance release."
|
|
131
147
|
fi
|
|
132
148
|
fi
|
|
133
149
|
|
|
@@ -146,17 +162,10 @@ run git push origin main
|
|
|
146
162
|
run git tag "$TAG"
|
|
147
163
|
run git push origin "$TAG"
|
|
148
164
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
--prerelease
|
|
154
|
-
else
|
|
155
|
-
run gh release create "$TAG" \
|
|
156
|
-
--title "$TAG" \
|
|
157
|
-
--generate-notes \
|
|
158
|
-
--prerelease
|
|
159
|
-
fi
|
|
165
|
+
run gh release create "$TAG" \
|
|
166
|
+
--title "$TAG" \
|
|
167
|
+
--notes "$NOTES" \
|
|
168
|
+
--prerelease
|
|
160
169
|
|
|
161
170
|
if [[ "$DRY_RUN" == true ]]; then
|
|
162
171
|
echo ""
|
|
@@ -677,9 +677,7 @@ def _activate_early_cli_native_shell(
|
|
|
677
677
|
notified = bool(notify_result.get("notified"))
|
|
678
678
|
except Exception:
|
|
679
679
|
notified = False
|
|
680
|
-
if notified and
|
|
681
|
-
port, viewer_before=viewer_before
|
|
682
|
-
):
|
|
680
|
+
if notified and _wait_for_viewer_connection(port, before=viewer_before):
|
|
683
681
|
return True
|
|
684
682
|
_vprint(
|
|
685
683
|
"[ArrayView] Native window did not connect to the backend; falling back to browser",
|
|
@@ -1216,8 +1214,12 @@ def _handle_cli_spawned_daemon(
|
|
|
1216
1214
|
and not is_remote
|
|
1217
1215
|
and not overlay_files
|
|
1218
1216
|
and not compare_files
|
|
1217
|
+
and not sys.platform.startswith("linux")
|
|
1219
1218
|
):
|
|
1220
|
-
|
|
1219
|
+
# Linux QtWebEngine denies sessionStorage to the viewer iframe when its
|
|
1220
|
+
# parent shell was created from inline data. Let Linux open the normal
|
|
1221
|
+
# HTTP shell after the daemon is listening instead.
|
|
1222
|
+
url_shell_early = f"http://{_LOOPBACK_HOST}:{port}/shell"
|
|
1221
1223
|
early_native_shell_opened, early_native_shell_proc = _open_webview_cli_tracked(
|
|
1222
1224
|
url_shell_early, 1400, 900, shell_port=port
|
|
1223
1225
|
)
|
|
@@ -439,7 +439,6 @@
|
|
|
439
439
|
#mv-cb { border: none; }
|
|
440
440
|
.highlight { color: var(--highlight); font-weight: bold; }
|
|
441
441
|
.dim-size { opacity: 0.28; font-size: 0.68em; font-weight: normal; }
|
|
442
|
-
.dim-hover-idx { font-size: 0.68em; font-weight: normal; color: var(--dim-hover, #777); opacity: 1; }
|
|
443
442
|
.active-dim { font-weight: bold; }
|
|
444
443
|
.playing-dim { font-weight: bold; }
|
|
445
444
|
.vfield-t-dim { color: var(--vfield-t-dim); }
|
|
@@ -3338,6 +3337,7 @@
|
|
|
3338
3337
|
#mv-panes.mv-crosshair-active .mv-pane::after {
|
|
3339
3338
|
content: ''; position: absolute; inset: 0; z-index: 4;
|
|
3340
3339
|
box-shadow: inset 0 0 0 var(--mv-plane-border-width, 1px) var(--mv-plane-border, var(--active-dim));
|
|
3340
|
+
opacity: 0.45;
|
|
3341
3341
|
border-radius: inherit; box-sizing: border-box;
|
|
3342
3342
|
pointer-events: none;
|
|
3343
3343
|
}
|
|
@@ -13885,7 +13885,6 @@
|
|
|
13885
13885
|
if (!['circle', 'rect', 'freehand', 'floodfill'].includes(_roiShape)) _roiShape = 'circle';
|
|
13886
13886
|
_roiVisible = true;
|
|
13887
13887
|
hideAllPixelInfo();
|
|
13888
|
-
_resetDimbarHover();
|
|
13889
13888
|
canvas.style.cursor = 'crosshair';
|
|
13890
13889
|
if (qmriActive) qmriViews.forEach(v => { v.canvas.style.cursor = 'crosshair'; });
|
|
13891
13890
|
if (multiViewActive) mvViews.forEach(v => { v.canvas.style.cursor = 'crosshair'; });
|
|
@@ -16481,38 +16480,6 @@
|
|
|
16481
16480
|
_updateMvPaneFill();
|
|
16482
16481
|
}
|
|
16483
16482
|
|
|
16484
|
-
function _dimHoverPadded(val, maxVal) {
|
|
16485
|
-
const maxStr = String(maxVal);
|
|
16486
|
-
const valStr = String(val);
|
|
16487
|
-
const padLen = maxStr.length - valStr.length;
|
|
16488
|
-
if (padLen <= 0) return '/' + valStr;
|
|
16489
|
-
return '/<span style="opacity:0.28">' + '0'.repeat(padLen) + '</span>' + valStr;
|
|
16490
|
-
}
|
|
16491
|
-
function _updateDimbarHover(px, py, xLabel, yLabel, pz) {
|
|
16492
|
-
// xLabel/yLabel: 'x','y','z' — which dimbar label to update (default x,y)
|
|
16493
|
-
// pz: optional z index (for mosaic mode)
|
|
16494
|
-
const xl = xLabel || 'x', yl = yLabel || 'y';
|
|
16495
|
-
const xEl = document.getElementById('dim-' + xl + '-size');
|
|
16496
|
-
const yEl = document.getElementById('dim-' + yl + '-size');
|
|
16497
|
-
const zEl = document.getElementById('dim-z-size');
|
|
16498
|
-
// Resolve label to shape dim index for padding width
|
|
16499
|
-
const labelToDim = (multiViewActive || compareMvActive)
|
|
16500
|
-
? { x: (multiViewActive ? mvDims : compareMvDims)[0], y: (multiViewActive ? mvDims : compareMvDims)[1], z: (multiViewActive ? mvDims : compareMvDims)[2] }
|
|
16501
|
-
: { x: dim_x, y: dim_y, z: dim_z };
|
|
16502
|
-
const xMax = labelToDim[xl] >= 0 ? shape[labelToDim[xl]] : 1;
|
|
16503
|
-
const yMax = labelToDim[yl] >= 0 ? shape[labelToDim[yl]] : 1;
|
|
16504
|
-
if (xEl) { xEl.innerHTML = _dimHoverPadded(px, xMax); xEl.className = 'dim-hover-idx'; }
|
|
16505
|
-
if (yEl) { yEl.innerHTML = _dimHoverPadded(py, yMax); yEl.className = 'dim-hover-idx'; }
|
|
16506
|
-
if (zEl && pz != null) {
|
|
16507
|
-
const zMax = dim_z >= 0 ? shape[dim_z] : 1;
|
|
16508
|
-
zEl.innerHTML = _dimHoverPadded(pz + 1, zMax); zEl.className = 'dim-hover-idx';
|
|
16509
|
-
}
|
|
16510
|
-
}
|
|
16511
|
-
function _resetDimbarHover() {
|
|
16512
|
-
// Re-render dimbar to restore correct max sizes for all modes
|
|
16513
|
-
renderInfo();
|
|
16514
|
-
}
|
|
16515
|
-
|
|
16516
16483
|
// Gnomon visibility: shown while a dim-bar token is hovered, or flashed
|
|
16517
16484
|
// briefly when activeDim changes via h/l/←/→. Hidden otherwise.
|
|
16518
16485
|
// In oblique mode the x/y labels no longer name axis-aligned directions,
|
|
@@ -17711,13 +17678,18 @@
|
|
|
17711
17678
|
|
|
17712
17679
|
function saveState() {
|
|
17713
17680
|
if (!sid) return;
|
|
17714
|
-
|
|
17681
|
+
try {
|
|
17682
|
+
sessionStorage.setItem('av_' + sid, JSON.stringify(collectStateSnapshot()));
|
|
17683
|
+
} catch (e) {
|
|
17684
|
+
// Some embedded webviews deny storage access. Viewing must keep
|
|
17685
|
+
// working even when this optional convenience is unavailable.
|
|
17686
|
+
}
|
|
17715
17687
|
}
|
|
17716
17688
|
|
|
17717
17689
|
function restoreStateFromSessionStorage() {
|
|
17718
|
-
const raw = sessionStorage.getItem('av_' + sid);
|
|
17719
|
-
if (!raw) return false;
|
|
17720
17690
|
try {
|
|
17691
|
+
const raw = sessionStorage.getItem('av_' + sid);
|
|
17692
|
+
if (!raw) return false;
|
|
17721
17693
|
return applyStateSnapshot(JSON.parse(raw));
|
|
17722
17694
|
} catch (e) {
|
|
17723
17695
|
return false;
|
|
@@ -20117,7 +20089,6 @@
|
|
|
20117
20089
|
showPixelInfo(document.getElementById('main-pixel-info'), { valueText: _pixelFmt(d.value, _activeNumericContext()), rawX, rawY }, e.clientX, e.clientY);
|
|
20118
20090
|
}).catch(() => {});
|
|
20119
20091
|
}
|
|
20120
|
-
_updateDimbarHover(localX, localY, null, null, zIdx);
|
|
20121
20092
|
return;
|
|
20122
20093
|
}
|
|
20123
20094
|
|
|
@@ -20131,11 +20102,6 @@
|
|
|
20131
20102
|
imgW: canvas.width,
|
|
20132
20103
|
imgH: canvas.height,
|
|
20133
20104
|
displayEl: document.getElementById('main-pixel-info'),
|
|
20134
|
-
onResult: (d, px, py) => {
|
|
20135
|
-
if (_pixelInfoActive() && !multiViewActive && !compareActive) {
|
|
20136
|
-
_updateDimbarHover(px, py);
|
|
20137
|
-
}
|
|
20138
|
-
},
|
|
20139
20105
|
});
|
|
20140
20106
|
});
|
|
20141
20107
|
canvas.addEventListener('mouseleave', () => {
|
|
@@ -20154,8 +20120,7 @@
|
|
|
20154
20120
|
if (_pixelInfoHeld) {
|
|
20155
20121
|
_pixelInfoHeld = false;
|
|
20156
20122
|
if (!_pixelInfoVisible) {
|
|
20157
|
-
|
|
20158
|
-
if (piEl) piEl.style.display = 'none';
|
|
20123
|
+
hideAllPixelInfo();
|
|
20159
20124
|
}
|
|
20160
20125
|
}
|
|
20161
20126
|
});
|
|
@@ -20924,7 +20889,6 @@
|
|
|
20924
20889
|
if (!_pixelInfoVisible) {
|
|
20925
20890
|
_clearHoverPins();
|
|
20926
20891
|
hideAllPixelInfo();
|
|
20927
|
-
_resetDimbarHover();
|
|
20928
20892
|
const axEl = document.getElementById('main-axes-svg');
|
|
20929
20893
|
if (axEl) {
|
|
20930
20894
|
axEl.querySelector('.axes-lbl-x').textContent = 'x';
|
|
@@ -26047,21 +26011,6 @@
|
|
|
26047
26011
|
imgH: view.lastH,
|
|
26048
26012
|
view,
|
|
26049
26013
|
displayEl: view.pixelInfoEl,
|
|
26050
|
-
onResult: (d, px, py) => {
|
|
26051
|
-
if (_pixelInfoActive()) {
|
|
26052
|
-
// Map pane dims to dimbar x/y/z labels
|
|
26053
|
-
const labels = ['x','y','z'];
|
|
26054
|
-
const activeDims = multiViewActive ? mvDims : (compareMvActive ? compareMvDims : []);
|
|
26055
|
-
const posX = activeDims.indexOf(view.dimX);
|
|
26056
|
-
const posY = activeDims.indexOf(view.dimY);
|
|
26057
|
-
const lblX = labels[posX] || 'x';
|
|
26058
|
-
const lblY = labels[posY] || 'y';
|
|
26059
|
-
const elX = document.getElementById('dim-' + lblX + '-size');
|
|
26060
|
-
const elY = document.getElementById('dim-' + lblY + '-size');
|
|
26061
|
-
if (elX) { elX.textContent = '/' + px; elX.className = 'dim-hover-idx'; }
|
|
26062
|
-
if (elY) { elY.textContent = '/' + py; elY.className = 'dim-hover-idx'; }
|
|
26063
|
-
}
|
|
26064
|
-
},
|
|
26065
26014
|
});
|
|
26066
26015
|
});
|
|
26067
26016
|
cv.addEventListener('mouseleave', () => {
|
|
@@ -26072,7 +26021,6 @@
|
|
|
26072
26021
|
if (tq) tq.classList.remove('visible');
|
|
26073
26022
|
_roiSuppressPixelInfo = false;
|
|
26074
26023
|
if (!mvDraggingView && view.pixelInfoEl) view.pixelInfoEl.style.display = 'none';
|
|
26075
|
-
if (_pixelInfoActive()) _resetDimbarHover();
|
|
26076
26024
|
});
|
|
26077
26025
|
// Click-to-copy: multiview canvases
|
|
26078
26026
|
let _mvClickDown = null;
|
|
@@ -26935,7 +26883,6 @@
|
|
|
26935
26883
|
view,
|
|
26936
26884
|
onResult: (d, px, py) => {
|
|
26937
26885
|
if (_pixelInfoActive()) {
|
|
26938
|
-
_updateDimbarHover(px, py);
|
|
26939
26886
|
return; // hover mode: only show hovered pane's value
|
|
26940
26887
|
}
|
|
26941
26888
|
// Non-hover: fetch for all other qmri views at same pixel
|
|
@@ -26962,10 +26909,9 @@
|
|
|
26962
26909
|
});
|
|
26963
26910
|
});
|
|
26964
26911
|
cv.addEventListener('mouseleave', () => {
|
|
26965
|
-
|
|
26966
|
-
|
|
26967
|
-
|
|
26968
|
-
});
|
|
26912
|
+
if (_qmriLoupeDrag && _qmriLoupeDrag.canvas === cv) _endQmriLoupe();
|
|
26913
|
+
qmriViews.forEach(v => { if (v.pixelInfoEl) v.pixelInfoEl.style.display = 'none'; });
|
|
26914
|
+
});
|
|
26969
26915
|
// ROI drawing on qMRI canvases
|
|
26970
26916
|
if (rectRoiMode) cv.style.cursor = 'crosshair';
|
|
26971
26917
|
cv.addEventListener('mousemove', (e) => {
|
|
@@ -27029,6 +26975,11 @@
|
|
|
27029
26975
|
}
|
|
27030
26976
|
});
|
|
27031
26977
|
cv.addEventListener('mousedown', (e) => {
|
|
26978
|
+
if (!rectRoiMode && e.button === 0 && !e.shiftKey && !e.metaKey && !e.ctrlKey && !e.altKey
|
|
26979
|
+
&& !_cropActive && !_segMode && !_rulerMode) {
|
|
26980
|
+
_pixelInfoHeld = true;
|
|
26981
|
+
cv.dispatchEvent(new MouseEvent('mousemove', { clientX: e.clientX, clientY: e.clientY, bubbles: true }));
|
|
26982
|
+
}
|
|
27032
26983
|
if (!rectRoiMode || e.button !== 0 || e.shiftKey || e.metaKey) return;
|
|
27033
26984
|
e.preventDefault(); sink.focus();
|
|
27034
26985
|
const rect = cv.getBoundingClientRect();
|
|
@@ -27449,15 +27400,17 @@
|
|
|
27449
27400
|
view,
|
|
27450
27401
|
displayEl: view.pixelInfoEl,
|
|
27451
27402
|
qmriRole: view.qmriRole,
|
|
27452
|
-
onResult: (d, px, py) => {
|
|
27453
|
-
if (_pixelInfoActive()) _updateDimbarHover(px, py);
|
|
27454
|
-
},
|
|
27455
27403
|
});
|
|
27456
27404
|
});
|
|
27405
|
+
cv.addEventListener('mousedown', (e) => {
|
|
27406
|
+
if (e.button !== 0 || e.shiftKey || e.metaKey || e.ctrlKey || e.altKey
|
|
27407
|
+
|| _cropActive || _segMode || _rulerMode) return;
|
|
27408
|
+
_pixelInfoHeld = true;
|
|
27409
|
+
cv.dispatchEvent(new MouseEvent('mousemove', { clientX: e.clientX, clientY: e.clientY, bubbles: true }));
|
|
27410
|
+
});
|
|
27457
27411
|
cv.addEventListener('mouseleave', () => {
|
|
27458
27412
|
if (_qmriLoupeDrag && _qmriLoupeDrag.canvas === cv) _endQmriLoupe();
|
|
27459
27413
|
compareQmriViews.forEach(v => { if (v.pixelInfoEl) v.pixelInfoEl.style.display = 'none'; });
|
|
27460
|
-
if (_pixelInfoActive()) _resetDimbarHover();
|
|
27461
27414
|
});
|
|
27462
27415
|
if (!httpTransport) {
|
|
27463
27416
|
view.ws = createTransport(sidVal,
|
|
@@ -27936,20 +27889,6 @@
|
|
|
27936
27889
|
imgH: view.lastH,
|
|
27937
27890
|
view,
|
|
27938
27891
|
displayEl: view.pixelInfoEl,
|
|
27939
|
-
onResult: (d, px, py) => {
|
|
27940
|
-
if (_pixelInfoActive()) {
|
|
27941
|
-
const labels = ['x','y','z'];
|
|
27942
|
-
const activeDims = compareMvDims || [];
|
|
27943
|
-
const posX = activeDims.indexOf(view.dimX);
|
|
27944
|
-
const posY = activeDims.indexOf(view.dimY);
|
|
27945
|
-
const lblX = labels[posX] || 'x';
|
|
27946
|
-
const lblY = labels[posY] || 'y';
|
|
27947
|
-
const elX = document.getElementById('dim-' + lblX + '-size');
|
|
27948
|
-
const elY = document.getElementById('dim-' + lblY + '-size');
|
|
27949
|
-
if (elX) { elX.textContent = '/' + px; elX.className = 'dim-hover-idx'; }
|
|
27950
|
-
if (elY) { elY.textContent = '/' + py; elY.className = 'dim-hover-idx'; }
|
|
27951
|
-
}
|
|
27952
|
-
},
|
|
27953
27892
|
});
|
|
27954
27893
|
});
|
|
27955
27894
|
cv.addEventListener('mouseleave', () => {
|
|
@@ -27957,7 +27896,6 @@
|
|
|
27957
27896
|
if (!cmvDraggingView) {
|
|
27958
27897
|
compareMvViews.forEach(v => { if (v.pixelInfoEl) v.pixelInfoEl.style.display = 'none'; });
|
|
27959
27898
|
}
|
|
27960
|
-
if (_pixelInfoActive()) _resetDimbarHover();
|
|
27961
27899
|
});
|
|
27962
27900
|
// Click-to-copy: compare-multiview canvases
|
|
27963
27901
|
let _cmvClickDown = null;
|
|
@@ -30116,7 +30054,6 @@
|
|
|
30116
30054
|
displayEl: piEl,
|
|
30117
30055
|
onResult: (d, px, py) => {
|
|
30118
30056
|
if (!_pixelInfoActive()) return;
|
|
30119
|
-
_updateDimbarHover(px, py);
|
|
30120
30057
|
// Show value on other compare panes at the same pixel
|
|
30121
30058
|
const ver = indices.join(',') + ':' + dim_x + ':' + dim_y + ':' + complexMode + ':' + logScale;
|
|
30122
30059
|
compareCanvases.forEach((ocv, j) => {
|
|
@@ -30145,7 +30082,6 @@
|
|
|
30145
30082
|
cv.addEventListener('mouseleave', () => {
|
|
30146
30083
|
_comparePiEls.forEach(p => { if (p) p.style.display = 'none'; });
|
|
30147
30084
|
hideCompareCrosshairs();
|
|
30148
|
-
if (_pixelInfoActive()) _resetDimbarHover();
|
|
30149
30085
|
});
|
|
30150
30086
|
});
|
|
30151
30087
|
// Click-to-copy: compare canvases
|
|
@@ -44,7 +44,7 @@ def _vscode_app_bundle() -> str | None:
|
|
|
44
44
|
|
|
45
45
|
_VSCODE_EXT_INSTALLED = False # cached so we only check once per process
|
|
46
46
|
_VSCODE_EXT_FRESH_INSTALL = False # True if we just installed it this session
|
|
47
|
-
_VSCODE_EXT_VERSION = "0.14.
|
|
47
|
+
_VSCODE_EXT_VERSION = "0.14.35" # current bundled extension version
|
|
48
48
|
|
|
49
49
|
def _bundled_vscode_vsix_version(vsix_path: str) -> str | None:
|
|
50
50
|
"""Return the bundled opener extension version recorded inside the VSIX."""
|
|
@@ -323,6 +323,38 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
323
323
|
data.setdefault("maxAgeMs", _VSCODE_SIGNAL_MAX_AGE_MS)
|
|
324
324
|
data.setdefault("requestId", uuid.uuid4().hex)
|
|
325
325
|
|
|
326
|
+
def _focused_window_fallback() -> tuple[str, ...]:
|
|
327
|
+
"""Let the focused extension window claim an untargeted request."""
|
|
328
|
+
data["broadcast"] = True
|
|
329
|
+
return (
|
|
330
|
+
(_VSCODE_SIGNAL_FILENAME,)
|
|
331
|
+
if skip_compat
|
|
332
|
+
else (_VSCODE_SIGNAL_FILENAME, *_VSCODE_COMPAT_SIGNAL_FILENAMES)
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
def _registrations_are_remote(window_files: list[str]) -> bool:
|
|
336
|
+
"""Return whether every registration belongs to a remote extension host."""
|
|
337
|
+
if not window_files:
|
|
338
|
+
return False
|
|
339
|
+
for window_file in window_files:
|
|
340
|
+
try:
|
|
341
|
+
with open(os.path.join(signal_dir, window_file)) as registration:
|
|
342
|
+
registration_data = json.load(registration)
|
|
343
|
+
remote_name = registration_data.get("remoteName")
|
|
344
|
+
if remote_name:
|
|
345
|
+
continue
|
|
346
|
+
pid = int(registration_data["pid"])
|
|
347
|
+
with open(f"/proc/{pid}/cmdline", "rb") as command_file:
|
|
348
|
+
command = command_file.read().replace(b"\0", b" ").decode()
|
|
349
|
+
if (
|
|
350
|
+
"/.vscode/cli/servers/" not in command
|
|
351
|
+
and "/.vscode-server/" not in command
|
|
352
|
+
):
|
|
353
|
+
return False
|
|
354
|
+
except Exception:
|
|
355
|
+
return False
|
|
356
|
+
return True
|
|
357
|
+
|
|
326
358
|
# --- Primary: ARRAYVIEW_WINDOW_ID (all platforms) ---
|
|
327
359
|
# The extension injects this env var into every terminal via
|
|
328
360
|
# EnvironmentVariableCollection. It uniquely identifies the VS Code
|
|
@@ -381,15 +413,25 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
381
413
|
flush=True,
|
|
382
414
|
)
|
|
383
415
|
elif len(_all_windows) > 1:
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
416
|
+
if _registrations_are_remote(_all_windows):
|
|
417
|
+
filenames = _focused_window_fallback()
|
|
418
|
+
targeted_via_env = True
|
|
419
|
+
_vprint(
|
|
420
|
+
"[ArrayView] signal: stale ARRAYVIEW_WINDOW_ID with "
|
|
421
|
+
f"{len(_all_windows)} remote windows; "
|
|
422
|
+
"using focused-window fallback",
|
|
423
|
+
flush=True,
|
|
424
|
+
)
|
|
425
|
+
else:
|
|
426
|
+
print(
|
|
427
|
+
"[ArrayView] VS Code window is ambiguous: "
|
|
428
|
+
f"ARRAYVIEW_WINDOW_ID={env_wid!r} is not registered "
|
|
429
|
+
f"and {len(_all_windows)} VS Code windows are active. "
|
|
430
|
+
"Open a fresh terminal in the target VS Code window "
|
|
431
|
+
"and run ArrayView again.",
|
|
432
|
+
flush=True,
|
|
433
|
+
)
|
|
434
|
+
return False
|
|
393
435
|
# else: 0 windows — fall through to subsequent targeting
|
|
394
436
|
|
|
395
437
|
if targeted_via_env:
|
|
@@ -444,16 +486,30 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
444
486
|
except Exception:
|
|
445
487
|
pass
|
|
446
488
|
if len(_wfiles) > 1:
|
|
447
|
-
|
|
448
|
-
"[
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
489
|
+
_window_files = [
|
|
490
|
+
f"window-{name.split('-', 3)[-1][:-5]}.json"
|
|
491
|
+
for name in _wfiles
|
|
492
|
+
]
|
|
493
|
+
if _registrations_are_remote(_window_files):
|
|
494
|
+
filenames = _focused_window_fallback()
|
|
495
|
+
_vprint(
|
|
496
|
+
"[ArrayView] signal: no exact match for local "
|
|
497
|
+
f"terminal with {len(_wfiles)} remote windows; "
|
|
498
|
+
"using focused-window fallback",
|
|
499
|
+
flush=True,
|
|
500
|
+
)
|
|
501
|
+
else:
|
|
502
|
+
print(
|
|
503
|
+
"[ArrayView] VS Code window is ambiguous: "
|
|
504
|
+
"no exact ARRAYVIEW_WINDOW_ID or PID match is available "
|
|
505
|
+
f"and {len(_wfiles)} VS Code windows are active. "
|
|
506
|
+
"Open a fresh terminal in the target VS Code window "
|
|
507
|
+
"and run ArrayView again.",
|
|
508
|
+
flush=True,
|
|
509
|
+
)
|
|
510
|
+
return False
|
|
511
|
+
else:
|
|
512
|
+
filenames = tuple(_wfiles) if _wfiles else (_VSCODE_SIGNAL_FILENAME,)
|
|
457
513
|
else:
|
|
458
514
|
filenames = (
|
|
459
515
|
_VSCODE_SIGNAL_FILENAME,
|
|
@@ -494,18 +550,33 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
494
550
|
except Exception:
|
|
495
551
|
pass
|
|
496
552
|
if len(window_files) > 1:
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
553
|
+
_registration_files = [
|
|
554
|
+
fname
|
|
555
|
+
for fname in os.listdir(signal_dir_temp)
|
|
556
|
+
if fname.startswith("window-") and fname.endswith(".json")
|
|
557
|
+
]
|
|
558
|
+
if _registrations_are_remote(_registration_files):
|
|
559
|
+
filenames = _focused_window_fallback()
|
|
560
|
+
_vprint(
|
|
561
|
+
"[ArrayView] signal: local terminal has no exact "
|
|
562
|
+
f"match among {len(window_files)} remote windows; "
|
|
563
|
+
"using focused-window fallback",
|
|
564
|
+
flush=True,
|
|
565
|
+
)
|
|
566
|
+
else:
|
|
567
|
+
print(
|
|
568
|
+
"[ArrayView] VS Code window is ambiguous: "
|
|
569
|
+
"no exact ARRAYVIEW_WINDOW_ID or PID match is available "
|
|
570
|
+
f"and {len(window_files)} VS Code windows are active. "
|
|
571
|
+
"Open a fresh terminal in the target VS Code window "
|
|
572
|
+
"and run ArrayView again.",
|
|
573
|
+
flush=True,
|
|
574
|
+
)
|
|
575
|
+
return False
|
|
576
|
+
else:
|
|
577
|
+
filenames = (
|
|
578
|
+
tuple(window_files) if window_files else (_VSCODE_SIGNAL_FILENAME,)
|
|
504
579
|
)
|
|
505
|
-
return False
|
|
506
|
-
filenames = (
|
|
507
|
-
tuple(window_files) if window_files else (_VSCODE_SIGNAL_FILENAME,)
|
|
508
|
-
)
|
|
509
580
|
else:
|
|
510
581
|
# Not in VS Code terminal: use shared file
|
|
511
582
|
filenames = (
|
|
@@ -568,15 +639,13 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
568
639
|
flush=True,
|
|
569
640
|
)
|
|
570
641
|
elif len(_all_windows_r) > 1:
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
f"
|
|
575
|
-
"
|
|
576
|
-
"and run ArrayView again.",
|
|
642
|
+
filenames = _focused_window_fallback()
|
|
643
|
+
_vprint(
|
|
644
|
+
"[ArrayView] signal: stale remote ARRAYVIEW_WINDOW_ID with "
|
|
645
|
+
f"{len(_all_windows_r)} registered windows; "
|
|
646
|
+
"using focused-window fallback",
|
|
577
647
|
flush=True,
|
|
578
648
|
)
|
|
579
|
-
return False
|
|
580
649
|
else:
|
|
581
650
|
env_wid = None # 0 windows: keep existing fallback
|
|
582
651
|
|
|
@@ -603,14 +672,13 @@ def _write_vscode_signal(payload: dict, delay: float = 0.0, skip_compat: bool =
|
|
|
603
672
|
flush=True,
|
|
604
673
|
)
|
|
605
674
|
elif len(_all_windows_r) > 1:
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
"
|
|
675
|
+
filenames = _focused_window_fallback()
|
|
676
|
+
_vprint(
|
|
677
|
+
"[ArrayView] signal: remote window ID unavailable with "
|
|
678
|
+
f"{len(_all_windows_r)} registered windows; "
|
|
679
|
+
"using focused-window fallback",
|
|
611
680
|
flush=True,
|
|
612
681
|
)
|
|
613
|
-
return False
|
|
614
682
|
else:
|
|
615
683
|
_vprint(f"[ArrayView] signal: no registered remote window, using shared fallback", flush=True)
|
|
616
684
|
filenames = (
|
|
Binary file
|