fiberpath 0.7.3__tar.gz → 0.7.4__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.
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/gui-ci.yml +3 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/release.yml +15 -12
- {fiberpath-0.7.3 → fiberpath-0.7.4}/CHANGELOG.md +17 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/PKG-INFO +2 -2
- {fiberpath-0.7.3 → fiberpath-0.7.4}/README.md +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/index.md +7 -7
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/config/schemas.py +9 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/config/validator.py +9 -2
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/gcode/generator.py +1 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/validators.py +10 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/routes/simulate.py +8 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/routes/stream.py +6 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/plot.py +3 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/simulate.py +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/stream.py +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/package-lock.json +2 -2
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/package.json +2 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/helicalValidation.test.ts +70 -4
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/helicalValidation.ts +21 -3
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/schemas.ts +8 -5
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/components.ts +5 -4
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/Cargo.lock +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/Cargo.toml +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/src/main.rs +23 -2
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/src/marlin.rs +99 -4
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/tauri.conf.json +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/pyproject.toml +1 -1
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/api/test_simulate_route.py +28 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/api/test_stream_route_errors.py +11 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cli/test_cli_json.py +12 -0
- fiberpath-0.7.4/tests/config/test_validator.py +124 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/gcode/test_generator.py +11 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/test_validators.py +11 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/uv.lock +1 -1
- fiberpath-0.7.3/tests/config/test_validator.py +0 -55
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.gitattributes +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/actions/setup-node/action.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/actions/setup-python/action.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/actions/setup-rust/action.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/backend-ci.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/ci-check.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/dependency-audit.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/gui-e2e-smoke.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.github/workflows/gui-packaging.yml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.gitignore +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.pre-commit-config.yaml +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.vscode/extensions.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.vscode/launch.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/.vscode/settings.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/LICENSE +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/architecture/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/architecture/axis-system.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/architecture/overview.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/ci-cd.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/contributing.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/dependency-policy.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/feature-backlog.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/packaging.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/release-process.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/roadmap.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/development/tooling.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/getting-started.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/guides/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/guides/axis-mapping.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/guides/marlin-streaming.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/guides/visualization.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/guides/wind-format.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/reference/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/reference/api.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/reference/concepts.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/reference/planner-math.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/troubleshooting.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/docs/vm-testing.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/README.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/multi_layer/README.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/multi_layer/input.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/AvBay(470mm)single.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/AvBay(470mm)triple.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/AvBay(470mm)triple.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/CarbonMotorTube(1295mm).gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/CarbonMotorTube(1295mm).wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/MainChute(585mm).gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/rocketry/MainChute(585mm).wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/simple_cylinder/README.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/simple_cylinder/input.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/sized_simple_cylinder/README.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/examples/sized_simple_cylinder/input.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/config/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/execution/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/execution/marlin.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/gcode/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/gcode/dialects.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/math_utils.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/calculations.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/exceptions.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/helpers.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/layer_strategies.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/machine.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/planning/planner.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/simulation/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/simulation/simulator.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/visualization/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/visualization/export_json.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath/visualization/plotter.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/main.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/package-lock.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/path_policy.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/routes/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/routes/plan.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/routes/validate.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_api/schemas.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/__main__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/interactive.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/main.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/output.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/plan.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_cli/validate.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/.gitignore +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/.nvmrc +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/.stylelintrc.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/README.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/bundled-cli/.gitkeep +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/architecture/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/architecture/cli-integration.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/architecture/state-management.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/architecture/streaming-state.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/architecture/tech-stack.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/development.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/guides/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/guides/performance.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/guides/schemas.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/guides/styling.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/overview.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/reference/.pages +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/reference/type-safety.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/docs/testing.md +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/generate-types.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/index.html +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/perf/bundle-baseline.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/schemas/wind-schema.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/scripts/check-bundle-budget.mjs +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/scripts/check-css-vars.mjs +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/App.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/CliHealthWarning.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/ErrorBoundary.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/ErrorBoundary.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/MenuBar.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StatusBar.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StatusBar.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ConnectionSection.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ConnectionSection.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ConnectionSection.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/FileStreamingSection.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/FileStreamingSection.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/FileStreamingSection.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/KeyboardShortcuts.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/KeyboardShortcuts.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/KeyboardShortcuts.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ManualControlSection.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ManualControlSection.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/ManualControlSection.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamControls.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamControls.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamLog.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamLog.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamLog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamTab.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/StreamTab/StreamTab.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/TabBar.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/TabBar.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/Toast/ToastContainer.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/Toast/ToastContainer.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/Toast/ToastContainer.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/CanvasControls.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/CanvasControls.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/CenterCanvas.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/LayerScrubber.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/LayerScrubber.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/canvas/VisualizationCanvas.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/AboutDialog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/BaseDialog.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/BaseDialog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/CliUnavailableDialog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/DiagnosticsDialog.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/DiagnosticsDialog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/dialogs/ExportConfirmationDialog.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/HelicalLayerEditor.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/HelicalLayerEditor.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/HoopLayerEditor.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/HoopLayerEditor.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/LayerNumericField.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/SkipLayerEditor.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/editors/SkipLayerEditor.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/MachineSettingsForm.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/MachineSettingsForm.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/MandrelForm.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/MandrelForm.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/TowForm.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/forms/TowForm.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/layers/LayerRow.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/layers/LayerRow.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/layers/LayerStack.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/layers/LayerStack.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/panels/BottomPanel.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/panels/LeftPanel.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/panels/RightPanel.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/panels/panels.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/tabs/MainTab.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/components/tabs/MainTab.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/contexts/CliHealthContext.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/contexts/CliHealthContext.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/canvas/usePreviewGeneration.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/canvas/usePreviewGeneration.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useConnectionActions.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useConnectionActions.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useManualCommandActions.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useManualCommandActions.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useStreamingActions.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/stream/useStreamingActions.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useCliHealth.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useCliHealth.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useDebouncedValue.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useDebouncedValue.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useFileOperations.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useFileOperations.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useKeyboardShortcuts.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useKeyboardShortcuts.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useMenubarInteractions.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useMenubarInteractions.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useStreamEvents.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useTheme.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/hooks/useTheme.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/layouts/MainLayout.test.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/layouts/MainLayout.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/commands.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/commands.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/constants.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/fileOperations.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/fileOperations.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/marlin-api.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/marlin-api.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/menuConfig.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/menuConfig.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/numericFields.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/numericFields.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/recentFiles.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/recentFiles.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/retry.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/retry.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/schemas.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/streamFeedback.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/streamFeedback.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/tauri-types.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/toastMessages.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/validation.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/validation.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/validationErrors.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/lib/validationErrors.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/main.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/stores/projectStore.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/stores/projectStore.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/stores/streamStore.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/stores/toastStore.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/stores/toastStore.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/buttons.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/canvas.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/dialogs.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/forms.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/index.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/layout.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/notifications.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/panels.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/reset.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/tabs.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/tokens.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/styles/typography.css +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/integration/streamLifecycle.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/integration/workflows.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/renderWithProviders.tsx +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/setup.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/storeUtils.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/tests/tauriMocks.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/converters.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/converters.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/project.test.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/project.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src/types/wind-schema.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/build.rs +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/capabilities/default.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/icons/128x128.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/icons/256x256.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/icons/32x32.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/icons/512x512.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/icons/icon.ico +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/src/cli_path.rs +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/src-tauri/src/cli_process.rs +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/tsconfig.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/tsconfig.node.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/vite.config.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/fiberpath_gui/vitest.config.ts +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/package-lock.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/renovate.json +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/e2e-check-artifacts.ps1 +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/e2e-check-artifacts.sh +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/e2e-cli-smoke.ps1 +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/e2e-cli-smoke.sh +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/extract-package-runtime.ps1 +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/extract-package-runtime.sh +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/find-bundled-cli.ps1 +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/ci/find-bundled-cli.sh +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/export_schema.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/freeze_cli.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/scripts/generate_schema.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/setup.cfg +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/api/test_path_policy.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/api/test_plan_route.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/api/test_stream_route.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cli/test_axis_format.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cli/test_cli_smoke.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cli/test_stream_command.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/config/__init__.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/inputs/helical-balanced.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/inputs/simple-hoop.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/inputs/skip-bias.wind +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/helical-balanced/output.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/helical-balanced/preview.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/simple-hoop/output.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/simple-hoop/preview.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/skip-bias/output.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/cyclone_reference_runs/outputs/skip-bias/preview.png +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/execution/test_marlin_streamer.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/gcode/test_dialects.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/_generate_fixtures.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/fixtures/helical_layer.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/fixtures/hoop_layer.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/fixtures/hoop_only_program.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/fixtures/skip_layer.gcode +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/test_axis_mapping.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/test_helpers_machine.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/test_layer_strategies.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/planning/test_planner_smoke.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/simulation/test_simulator.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/simulation/test_simulator_axis_detection.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/tauri/test_marlin_integration.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/tauri/test_port_discovery.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/visualization/test_export_json.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/visualization/test_plotter.py +0 -0
- {fiberpath-0.7.3 → fiberpath-0.7.4}/tests/visualization/test_plotter_axis_detection.py +0 -0
|
@@ -135,16 +135,19 @@ jobs:
|
|
|
135
135
|
|
|
136
136
|
let notes = '';
|
|
137
137
|
|
|
138
|
-
// Desktop installers section
|
|
138
|
+
// Desktop installers section. Asset names match Tauri's bundle
|
|
139
|
+
// output: the productName "FiberPath GUI" yields a space that
|
|
140
|
+
// GitHub renders as `.` in the release asset filename, and the
|
|
141
|
+
// macOS dmg is built for Apple Silicon (aarch64) on macos-latest.
|
|
139
142
|
notes += `## Desktop Installers\n\n`;
|
|
140
143
|
notes += `**Windows:**\n`;
|
|
141
|
-
notes += `- \`
|
|
142
|
-
notes += `- \`
|
|
143
|
-
notes += `**macOS:**\n`;
|
|
144
|
-
notes += `- \`
|
|
144
|
+
notes += `- \`FiberPath.GUI_${version}_x64_en-US.msi\` (recommended)\n`;
|
|
145
|
+
notes += `- \`FiberPath.GUI_${version}_x64-setup.exe\`\n\n`;
|
|
146
|
+
notes += `**macOS (Apple Silicon):**\n`;
|
|
147
|
+
notes += `- \`FiberPath.GUI_${version}_aarch64.dmg\`\n\n`;
|
|
145
148
|
notes += `**Linux:**\n`;
|
|
146
|
-
notes += `- \`
|
|
147
|
-
notes += `- \`
|
|
149
|
+
notes += `- \`FiberPath.GUI_${version}_amd64.deb\`\n`;
|
|
150
|
+
notes += `- \`FiberPath.GUI_${version}_amd64.AppImage\`\n\n`;
|
|
148
151
|
notes += `📚 [Installation Guide](https://fiberpath.org/fiberpath/getting-started/) | `;
|
|
149
152
|
notes += `🆘 [Troubleshooting](https://fiberpath.org/fiberpath/troubleshooting/)\n\n`;
|
|
150
153
|
|
|
@@ -165,11 +168,11 @@ jobs:
|
|
|
165
168
|
run: |
|
|
166
169
|
VERSION="${{ inputs.version }}"
|
|
167
170
|
echo "Expected release assets for v$VERSION:"
|
|
168
|
-
echo " -
|
|
169
|
-
echo " -
|
|
170
|
-
echo " -
|
|
171
|
-
echo " -
|
|
172
|
-
echo " -
|
|
171
|
+
echo " - FiberPath.GUI_${VERSION}_x64_en-US.msi"
|
|
172
|
+
echo " - FiberPath.GUI_${VERSION}_x64-setup.exe"
|
|
173
|
+
echo " - FiberPath.GUI_${VERSION}_aarch64.dmg"
|
|
174
|
+
echo " - FiberPath.GUI_${VERSION}_amd64.deb"
|
|
175
|
+
echo " - FiberPath.GUI_${VERSION}_amd64.AppImage"
|
|
173
176
|
echo "Assets will be uploaded by build-gui-installers workflow"
|
|
174
177
|
|
|
175
178
|
- name: Create GitHub Release
|
|
@@ -8,6 +8,23 @@ The format is based on Keep a Changelog, and this project follows semantic versi
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.7.4] - 2026-06-25
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Marlin desktop commands no longer hang forever if the underlying CLI subprocess dies or emits a non-JSON line: when the response reader stops, in-flight requests are failed (the command returns an error) instead of leaving the UI spinner stuck permanently.
|
|
16
|
+
- Desktop preview/validate temp files now use process- and counter-unique names, fixing rare collisions when commands fired in the same millisecond could delete or clobber each other's temp file (intermittent "file not found" / corrupted preview).
|
|
17
|
+
- The Marlin desktop integration now recovers if its helper subprocess dies: a dead process is detected and respawned on the next command instead of reusing it forever, and the subprocess is killed on app shutdown so it no longer lingers as an orphan holding the serial port open.
|
|
18
|
+
- Helical layer editor and save-gate validation now match the planner's bounds, so the editor no longer accepts values the backend rejects with a 422: `lockDegrees`, `leadInMM`, and `leadOutDegrees` must be positive (were allowed to be `0`), `skipIndex` must be a positive integer (the save gate allowed `0`), and the wind angle is constrained to `[1°, 89°]` (was `(0°, 90°)`; the engine clamps to `[1, 89]` because `90°` gives `cos = 0`).
|
|
19
|
+
- Helical layer geometry hint no longer renders "not divisible by pattern number (NaN)" while the Pattern Number field is mid-edit (emptied to `NaN`); no hint is shown until the field holds a valid positive integer.
|
|
20
|
+
- The streaming API (`POST /stream/`) now returns 400 for empty/whitespace-only G-code instead of 502; an empty program is a client error, not an upstream device failure (502 is reserved for genuine transport errors).
|
|
21
|
+
- Simulating a G-code path that is a directory or non-UTF-8/binary file now returns a 4xx (API `/simulate/from-file`) or a clean usage error (CLI `simulate`/`plot`/`stream` reject directories) instead of an HTTP 500 / raw `IsADirectoryError`/`UnicodeDecodeError` traceback.
|
|
22
|
+
- Loading a wind definition that is a directory, an unreadable file, or non-UTF-8/binary content now reports a clean error instead of crashing. Previously these raised an unmapped `IsADirectoryError`/`UnicodeDecodeError`, surfacing as an HTTP 500 from the API (`/plan/from-file`, `/validate/from-file`) or a raw traceback from the CLI; they are now mapped to the standard `WindFileError` (4xx / clean CLI message).
|
|
23
|
+
- `fiberpath plan --output <dir>/<file>.gcode` into a directory that does not exist now creates the parent directories instead of crashing with a `FileNotFoundError` traceback (matching the existing `plot` behavior). `write_gcode` creates the destination's parent directory.
|
|
24
|
+
- A helical layer whose `leadInMM` is greater than or equal to the mandrel `windLength` is now rejected during planning. Previously it passed validation and generated G-code that drove the carriage off the end of the mandrel into negative coordinates (inverting the main-pass rotation), risking an end-stop collision.
|
|
25
|
+
- Non-finite numeric inputs (`NaN`, `Infinity`) in a `.wind` file are now rejected at load instead of being silently accepted. Previously a `NaN` value could be emitted into generated G-code as a literal `Anan` axis word, and an `Infinity` geometry value crashed the planner with an uncaught `OverflowError` (HTTP 500 / CLI traceback).
|
|
26
|
+
- Helical layer editor no longer crashes the app ("Maximum call stack size exceeded") when the Pattern Number or Skip Index field is emptied. The emptied field became `NaN`, and the cross-field coprime check recursed forever in `gcd()`; the check now skips non-integer values and the field reports its own validation error instead.
|
|
27
|
+
|
|
11
28
|
## [0.7.3] - 2026-06-25
|
|
12
29
|
|
|
13
30
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fiberpath
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.4
|
|
4
4
|
Summary: Modern filament winding planner, simulator, and G-code toolkit.
|
|
5
5
|
Author: Cameron K. Brooks
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -705,7 +705,7 @@ Description-Content-Type: text/markdown
|
|
|
705
705
|
|
|
706
706
|
**Plan, simulate, and manufacture composite parts with precision fiber winding.**
|
|
707
707
|
|
|
708
|
-
[](https://github.com/fiberpath/fiberpath/releases)
|
|
709
709
|
[](LICENSE)
|
|
710
710
|
[](https://github.com/fiberpath/fiberpath/actions/workflows/backend-ci.yml)
|
|
711
711
|
[](https://github.com/fiberpath/fiberpath/actions/workflows/gui-ci.yml)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**Plan, simulate, and manufacture composite parts with precision fiber winding.**
|
|
6
6
|
|
|
7
|
-
[](https://github.com/fiberpath/fiberpath/releases)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](https://github.com/fiberpath/fiberpath/actions/workflows/backend-ci.yml)
|
|
10
10
|
[](https://github.com/fiberpath/fiberpath/actions/workflows/gui-ci.yml)
|
|
@@ -36,7 +36,7 @@ hide:
|
|
|
36
36
|
|
|
37
37
|
---
|
|
38
38
|
|
|
39
|
-
**Latest Release:** [v0.7.
|
|
39
|
+
**Latest Release:** [v0.7.4](https://github.com/fiberpath/fiberpath/releases/latest){ target=_blank }
|
|
40
40
|
|
|
41
41
|
- **Desktop GUI** – Windows, macOS, Linux installers (no Python required)
|
|
42
42
|
- **Python Package** – `pip install fiberpath`
|
|
@@ -44,16 +44,16 @@ hide:
|
|
|
44
44
|
|
|
45
45
|
[:octicons-arrow-right-24: Installation Guide](getting-started.md)
|
|
46
46
|
|
|
47
|
-
- :material-new-box:{ .lg .middle } **What's New in v0.7.
|
|
47
|
+
- :material-new-box:{ .lg .middle } **What's New in v0.7.4**
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Bug-fix release hardening input validation and the desktop integration:
|
|
52
52
|
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
53
|
+
- Reject non-finite (`NaN`/`Infinity`) inputs and a lead-in longer than the mandrel (which produced unsafe negative-coordinate G-code)
|
|
54
|
+
- Cleaner errors (4xx, not 500/tracebacks) for directory/binary file inputs across the API and CLI
|
|
55
|
+
- Marlin desktop commands no longer hang if the helper process dies, and recover by respawning
|
|
56
|
+
- Helical editor validation now matches the planner's bounds; fixed a crash and a "(NaN)" hint while editing
|
|
57
57
|
|
|
58
58
|
Builds on the v0.7 baseline; no runtime API changes.
|
|
59
59
|
|
|
@@ -11,7 +11,15 @@ from pydantic import BaseModel, ConfigDict, Field, PositiveFloat, PositiveInt
|
|
|
11
11
|
class BaseFiberPathModel(BaseModel):
|
|
12
12
|
"""Base class that applies shared Pydantic configuration."""
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
# allow_inf_nan=False rejects NaN/Infinity on every float field. JSON
|
|
15
|
+
# permits the NaN/Infinity literals, and unguarded non-finite values
|
|
16
|
+
# otherwise propagate into the generated G-code (a literal "Anan" axis word)
|
|
17
|
+
# or overflow math.ceil in the planner (uncaught OverflowError).
|
|
18
|
+
model_config = ConfigDict(
|
|
19
|
+
populate_by_name=True,
|
|
20
|
+
str_strip_whitespace=True,
|
|
21
|
+
allow_inf_nan=False,
|
|
22
|
+
)
|
|
15
23
|
|
|
16
24
|
|
|
17
25
|
class MandrelParameters(BaseFiberPathModel):
|
|
@@ -21,8 +21,15 @@ def load_wind_definition(path: str | Path) -> WindDefinition:
|
|
|
21
21
|
if not location.exists():
|
|
22
22
|
raise WindFileError(f"No wind definition found at {location}")
|
|
23
23
|
try:
|
|
24
|
-
|
|
25
|
-
except
|
|
24
|
+
raw = location.read_text(encoding="utf-8")
|
|
25
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
26
|
+
# Directory, unreadable file, or non-UTF-8/binary content. Surface as a
|
|
27
|
+
# WindFileError so callers map it to a 4xx / clean CLI error instead of
|
|
28
|
+
# leaking a raw IsADirectoryError / UnicodeDecodeError (HTTP 500).
|
|
29
|
+
raise WindFileError(f"Could not read wind definition at {location}: {exc}") from exc
|
|
30
|
+
try:
|
|
31
|
+
payload = json.loads(raw)
|
|
32
|
+
except json.JSONDecodeError as exc:
|
|
26
33
|
raise WindFileError(f"Invalid JSON in {location}: {exc}") from exc
|
|
27
34
|
|
|
28
35
|
try:
|
|
@@ -22,5 +22,6 @@ def sanitize_program(commands: Iterable[str]) -> list[str]:
|
|
|
22
22
|
def write_gcode(program: GCodeProgram | Sequence[str], destination: str | Path) -> Path:
|
|
23
23
|
target = Path(destination)
|
|
24
24
|
lines = program.commands if isinstance(program, GCodeProgram) else list(program)
|
|
25
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
25
26
|
target.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
26
27
|
return target
|
|
@@ -77,6 +77,16 @@ def validate_helical_layer(
|
|
|
77
77
|
"skipIndex and patternNumber must be coprime for full coverage",
|
|
78
78
|
)
|
|
79
79
|
|
|
80
|
+
if layer.lead_in_mm >= mandrel.wind_length:
|
|
81
|
+
raise LayerValidationError(
|
|
82
|
+
layer_index,
|
|
83
|
+
(
|
|
84
|
+
f"leadInMM ({layer.lead_in_mm}mm) must be less than the mandrel "
|
|
85
|
+
f"windLength ({mandrel.wind_length}mm); a longer lead-in drives the "
|
|
86
|
+
"carriage off the mandrel into negative coordinates"
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
|
|
80
90
|
kinematics = compute_helical_kinematics(layer, mandrel, tow)
|
|
81
91
|
if kinematics.num_circuits % layer.pattern_number != 0:
|
|
82
92
|
raise LayerValidationError(
|
|
@@ -16,7 +16,14 @@ def simulate_from_file(payload: FilePathRequest) -> SimulationResponse:
|
|
|
16
16
|
target = enforce_input_path_policy(payload.path)
|
|
17
17
|
if not target.exists():
|
|
18
18
|
raise HTTPException(status_code=404, detail=f"No file found at {payload.path}")
|
|
19
|
-
|
|
19
|
+
if not target.is_file():
|
|
20
|
+
raise HTTPException(status_code=400, detail=f"Not a file: {payload.path}")
|
|
21
|
+
try:
|
|
22
|
+
commands = target.read_text(encoding="utf-8").splitlines()
|
|
23
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
24
|
+
raise HTTPException(
|
|
25
|
+
status_code=400, detail=f"Could not read {payload.path}: {exc}"
|
|
26
|
+
) from exc
|
|
20
27
|
result = simulate_program(commands)
|
|
21
28
|
return SimulationResponse(
|
|
22
29
|
commands=result.commands_executed,
|
|
@@ -35,6 +35,12 @@ def start_stream(payload: StreamRequest) -> StreamResponse:
|
|
|
35
35
|
raise HTTPException(status_code=400, detail="port is required when dry_run is false")
|
|
36
36
|
|
|
37
37
|
commands = payload.gcode.splitlines()
|
|
38
|
+
if not any(line.strip() for line in commands):
|
|
39
|
+
# Empty/whitespace-only input is a client error, not an upstream device
|
|
40
|
+
# failure — return 400 rather than letting the streamer raise a
|
|
41
|
+
# StreamError that maps to 502.
|
|
42
|
+
raise HTTPException(status_code=400, detail="gcode contained no commands")
|
|
43
|
+
|
|
38
44
|
streamer = MarlinStreamer(port=payload.port, baud_rate=payload.baud_rate)
|
|
39
45
|
|
|
40
46
|
try:
|
|
@@ -10,7 +10,9 @@ from rich.console import Console
|
|
|
10
10
|
|
|
11
11
|
console = Console()
|
|
12
12
|
|
|
13
|
-
GCODE_ARGUMENT = typer.Argument(
|
|
13
|
+
GCODE_ARGUMENT = typer.Argument(
|
|
14
|
+
..., exists=True, readable=True, file_okay=True, dir_okay=False, help="Input G-code file"
|
|
15
|
+
)
|
|
14
16
|
OUTPUT_OPTION = typer.Option(Path("plot.png"), "--output", "-o", help="PNG destination")
|
|
15
17
|
SCALE_OPTION = typer.Option(
|
|
16
18
|
1.0, "--scale", help="Pixels per millimeter along carriage axis", min=0.1, max=5.0
|
|
@@ -10,7 +10,7 @@ from fiberpath.simulation import SimulationError, simulate_program
|
|
|
10
10
|
|
|
11
11
|
from .output import echo_json
|
|
12
12
|
|
|
13
|
-
GCODE_ARGUMENT = typer.Argument(..., exists=True, readable=True)
|
|
13
|
+
GCODE_ARGUMENT = typer.Argument(..., exists=True, readable=True, file_okay=True, dir_okay=False)
|
|
14
14
|
JSON_OPTION = typer.Option(False, "--json", help="Emit machine-readable JSON summary")
|
|
15
15
|
|
|
16
16
|
|
|
@@ -9,7 +9,7 @@ from fiberpath.execution import MarlinStreamer, StreamError, StreamProgress
|
|
|
9
9
|
|
|
10
10
|
from .output import echo_json
|
|
11
11
|
|
|
12
|
-
GCODE_ARGUMENT = typer.Argument(..., exists=True, readable=True)
|
|
12
|
+
GCODE_ARGUMENT = typer.Argument(..., exists=True, readable=True, file_okay=True, dir_okay=False)
|
|
13
13
|
PROGRESS_INTERVAL = 25
|
|
14
14
|
|
|
15
15
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fiberpath-gui",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "fiberpath-gui",
|
|
9
|
-
"version": "0.7.
|
|
9
|
+
"version": "0.7.4",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@hello-pangea/dnd": "^18.0.1",
|
|
12
12
|
"@tauri-apps/api": "^2.11.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fiberpath-gui",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"format:check": "cd src-tauri && cargo fmt --check",
|
|
20
20
|
"format:fix": "cd src-tauri && cargo fmt",
|
|
21
21
|
"clippy": "cd src-tauri && cargo clippy -- -D warnings",
|
|
22
|
+
"test:rust": "cd src-tauri && cargo test",
|
|
22
23
|
"check:all": "npm run lint && npm run lint:css && npm run lint:css:vars && npm run format:check && npm run clippy",
|
|
23
24
|
"test": "vitest",
|
|
24
25
|
"test:ui": "vitest --ui",
|
|
@@ -29,6 +29,14 @@ describe("helicalValidation", () => {
|
|
|
29
29
|
validateHelicalField("wind_angle", 91, defaultHelical),
|
|
30
30
|
).toBeDefined();
|
|
31
31
|
});
|
|
32
|
+
|
|
33
|
+
it("rejects 90 and sub-1 angles, accepts the [1, 89] bounds", () => {
|
|
34
|
+
// The planner enforces [1, 89] (90° -> cos = 0). The editor must match.
|
|
35
|
+
expect(validateHelicalField("wind_angle", 90, defaultHelical)).toBeDefined();
|
|
36
|
+
expect(validateHelicalField("wind_angle", 0.5, defaultHelical)).toBeDefined();
|
|
37
|
+
expect(validateHelicalField("wind_angle", 1, defaultHelical)).toBeUndefined();
|
|
38
|
+
expect(validateHelicalField("wind_angle", 89, defaultHelical)).toBeUndefined();
|
|
39
|
+
});
|
|
32
40
|
});
|
|
33
41
|
|
|
34
42
|
describe("pattern_number", () => {
|
|
@@ -75,11 +83,49 @@ describe("helicalValidation", () => {
|
|
|
75
83
|
});
|
|
76
84
|
});
|
|
77
85
|
|
|
86
|
+
// Regression: emptying a numeric input yields NaN. Re-validating the
|
|
87
|
+
// sibling field then ran the coprime check (gcd) against the NaN value,
|
|
88
|
+
// which recursed forever and crashed the app with
|
|
89
|
+
// "RangeError: Maximum call stack size exceeded".
|
|
90
|
+
describe("does not crash when a pattern/skip field is mid-edit", () => {
|
|
91
|
+
it("returns a range error (not a stack overflow) for a NaN skip index", () => {
|
|
92
|
+
expect(() =>
|
|
93
|
+
validateHelicalField("skip_index", NaN, defaultHelical),
|
|
94
|
+
).not.toThrow();
|
|
95
|
+
expect(validateHelicalField("skip_index", NaN, defaultHelical)).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("does not crash validating pattern_number when skip_index is NaN", () => {
|
|
99
|
+
const layer: HelicalLayer = { ...defaultHelical, skip_index: NaN };
|
|
100
|
+
expect(() =>
|
|
101
|
+
validateHelicalField("pattern_number", 3, layer),
|
|
102
|
+
).not.toThrow();
|
|
103
|
+
// pattern itself is valid; the coprime check is skipped while the
|
|
104
|
+
// sibling is invalid, so no spurious error is reported here.
|
|
105
|
+
expect(validateHelicalField("pattern_number", 3, layer)).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("does not crash validating skip_index when pattern_number is NaN", () => {
|
|
109
|
+
const layer: HelicalLayer = { ...defaultHelical, pattern_number: NaN };
|
|
110
|
+
expect(() =>
|
|
111
|
+
validateHelicalField("skip_index", 2, layer),
|
|
112
|
+
).not.toThrow();
|
|
113
|
+
expect(validateHelicalField("skip_index", 2, layer)).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("does not crash on non-integer pattern/skip values", () => {
|
|
117
|
+
const layer: HelicalLayer = { ...defaultHelical, skip_index: 2.5 };
|
|
118
|
+
expect(() =>
|
|
119
|
+
validateHelicalField("pattern_number", 3, layer),
|
|
120
|
+
).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
78
124
|
describe("lock_degrees", () => {
|
|
79
|
-
it("
|
|
125
|
+
it("rejects zero (planner requires a positive value)", () => {
|
|
80
126
|
expect(
|
|
81
127
|
validateHelicalField("lock_degrees", 0, defaultHelical),
|
|
82
|
-
).
|
|
128
|
+
).toBeDefined();
|
|
83
129
|
});
|
|
84
130
|
|
|
85
131
|
it("accepts positive value", () => {
|
|
@@ -96,9 +142,15 @@ describe("helicalValidation", () => {
|
|
|
96
142
|
});
|
|
97
143
|
|
|
98
144
|
describe("lead_out_degrees", () => {
|
|
99
|
-
it("
|
|
145
|
+
it("rejects zero (planner requires a positive value)", () => {
|
|
100
146
|
expect(
|
|
101
147
|
validateHelicalField("lead_out_degrees", 0, defaultHelical),
|
|
148
|
+
).toBeDefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("accepts positive value", () => {
|
|
152
|
+
expect(
|
|
153
|
+
validateHelicalField("lead_out_degrees", 30, defaultHelical),
|
|
102
154
|
).toBeUndefined();
|
|
103
155
|
});
|
|
104
156
|
|
|
@@ -110,9 +162,15 @@ describe("helicalValidation", () => {
|
|
|
110
162
|
});
|
|
111
163
|
|
|
112
164
|
describe("lead_in_mm", () => {
|
|
113
|
-
it("
|
|
165
|
+
it("rejects zero (planner requires a positive value)", () => {
|
|
114
166
|
expect(
|
|
115
167
|
validateHelicalField("lead_in_mm", 0, defaultHelical),
|
|
168
|
+
).toBeDefined();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("accepts positive value", () => {
|
|
172
|
+
expect(
|
|
173
|
+
validateHelicalField("lead_in_mm", 10, defaultHelical),
|
|
116
174
|
).toBeUndefined();
|
|
117
175
|
});
|
|
118
176
|
|
|
@@ -134,6 +192,14 @@ describe("helicalValidation", () => {
|
|
|
134
192
|
expect(getHelicalGeometryHint(layer, 150, 12.7)).toMatch(/skip index/i);
|
|
135
193
|
});
|
|
136
194
|
|
|
195
|
+
it("does not emit a '(NaN)' hint while pattern_number is mid-edit", () => {
|
|
196
|
+
// Emptying the Pattern Number input makes it NaN; circuitCount % NaN is
|
|
197
|
+
// NaN (!== 0), which previously rendered "not divisible by pattern
|
|
198
|
+
// number (NaN)". A non-integer pattern means the hint is undefined.
|
|
199
|
+
const layer: HelicalLayer = { ...defaultHelical, pattern_number: NaN };
|
|
200
|
+
expect(getHelicalGeometryHint(layer, 150, 50)).toBeUndefined();
|
|
201
|
+
});
|
|
202
|
+
|
|
137
203
|
it("returns undefined when mandrel diameter is zero", () => {
|
|
138
204
|
expect(
|
|
139
205
|
getHelicalGeometryHint(defaultHelical, 0, 12.7),
|
|
@@ -16,6 +16,15 @@ const gcd = (a: number, b: number): number => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const validateCoprime = (pattern: number, skip: number): string | undefined => {
|
|
19
|
+
// Coprimality is only defined for two positive integers. While a sibling
|
|
20
|
+
// field is mid-edit it can be NaN (an emptied input) or a non-integer; in
|
|
21
|
+
// that case skip the cross-field check — the offending field reports its own
|
|
22
|
+
// range error. This guard also prevents gcd() from infinite-recursing on
|
|
23
|
+
// NaN (Math.abs(NaN) is NaN, NaN === 0 is false, and NaN % NaN is NaN, so it
|
|
24
|
+
// never terminates), which previously crashed the app with a stack overflow.
|
|
25
|
+
if (!Number.isInteger(pattern) || !Number.isInteger(skip)) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
19
28
|
if (gcd(pattern, skip) !== 1) {
|
|
20
29
|
return "Pattern and skip must be coprime (GCD = 1)";
|
|
21
30
|
}
|
|
@@ -79,12 +88,14 @@ export function validateHelicalField(
|
|
|
79
88
|
|
|
80
89
|
case "lock_degrees":
|
|
81
90
|
case "lead_out_degrees":
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
// The planner requires these to be strictly positive (PositiveFloat);
|
|
92
|
+
// accepting 0 here only defers a 422 from the backend.
|
|
93
|
+
return value <= 0
|
|
94
|
+
? `${field.replace("_", " ")} must be positive`
|
|
84
95
|
: undefined;
|
|
85
96
|
|
|
86
97
|
case "lead_in_mm":
|
|
87
|
-
return value
|
|
98
|
+
return value <= 0 ? "Lead-in must be positive" : undefined;
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
|
|
@@ -97,6 +108,13 @@ export function getHelicalGeometryHint(
|
|
|
97
108
|
return "Skip index should be less than pattern number to avoid invalid routing.";
|
|
98
109
|
}
|
|
99
110
|
|
|
111
|
+
// While the field is mid-edit pattern_number can be NaN/0/non-integer; the
|
|
112
|
+
// divisibility check below would compute `% NaN` and render a "(NaN)" hint.
|
|
113
|
+
// The field surfaces its own validation error, so emit no geometry hint here.
|
|
114
|
+
if (!Number.isInteger(helical.pattern_number) || helical.pattern_number <= 0) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
|
|
100
118
|
const circuitCount = computeCircuitCount(helical, mandrelDiameter, towWidth);
|
|
101
119
|
if (!circuitCount) {
|
|
102
120
|
return undefined;
|
|
@@ -105,12 +105,15 @@ export const WindHoopLayerSchema = z.object({
|
|
|
105
105
|
*/
|
|
106
106
|
export const WindHelicalLayerSchema = z.object({
|
|
107
107
|
windType: z.literal("helical"),
|
|
108
|
-
|
|
108
|
+
// Bounds match the planner contract (PositiveFloat/PositiveInt; wind angle
|
|
109
|
+
// is enforced to [1, 89]). Keeping these in sync avoids the save gate
|
|
110
|
+
// accepting values the engine later rejects with a 422.
|
|
111
|
+
windAngle: z.number().min(1).max(89),
|
|
109
112
|
patternNumber: z.number().int().positive(),
|
|
110
|
-
skipIndex: z.number().int().
|
|
111
|
-
lockDegrees: z.number().
|
|
112
|
-
leadInMM: z.number().
|
|
113
|
-
leadOutDegrees: z.number().
|
|
113
|
+
skipIndex: z.number().int().positive(),
|
|
114
|
+
lockDegrees: z.number().positive(),
|
|
115
|
+
leadInMM: z.number().positive(),
|
|
116
|
+
leadOutDegrees: z.number().positive(),
|
|
114
117
|
skipInitialNearLock: z.boolean().optional(),
|
|
115
118
|
});
|
|
116
119
|
|
|
@@ -81,11 +81,12 @@ export interface NumericRange {
|
|
|
81
81
|
* These constants ensure consistency in validation across components.
|
|
82
82
|
*/
|
|
83
83
|
export const NUMERIC_RANGES = {
|
|
84
|
-
/** Wind angle:
|
|
84
|
+
/** Wind angle: 1° to 89° (inclusive), matching the planner's enforced bounds
|
|
85
|
+
* (90° gives cos = 0; the engine clamps to [1, 89]). */
|
|
85
86
|
WIND_ANGLE: {
|
|
86
|
-
min:
|
|
87
|
-
max:
|
|
88
|
-
inclusive: { min:
|
|
87
|
+
min: 1,
|
|
88
|
+
max: 89,
|
|
89
|
+
inclusive: { min: true, max: true },
|
|
89
90
|
} as NumericRange,
|
|
90
91
|
|
|
91
92
|
/** Feed rate: 1 to 10000 mm/min */
|
|
@@ -9,6 +9,7 @@ use marlin::MarlinState;
|
|
|
9
9
|
use serde_json::Value;
|
|
10
10
|
use std::fs;
|
|
11
11
|
use std::process::Output;
|
|
12
|
+
use std::sync::atomic::{AtomicU64, Ordering};
|
|
12
13
|
use std::sync::{Arc, Mutex};
|
|
13
14
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
14
15
|
use tauri::{AppHandle, Manager};
|
|
@@ -208,13 +209,23 @@ async fn plot_definition(
|
|
|
208
209
|
})
|
|
209
210
|
}
|
|
210
211
|
|
|
212
|
+
/// Monotonic counter ensuring temp file names are unique within the process
|
|
213
|
+
/// even when several are created in the same millisecond.
|
|
214
|
+
static TEMP_COUNTER: AtomicU64 = AtomicU64::new(0);
|
|
215
|
+
|
|
211
216
|
fn temp_path(extension: &str) -> String {
|
|
212
217
|
let mut path = std::env::temp_dir();
|
|
213
218
|
let millis = SystemTime::now()
|
|
214
219
|
.duration_since(UNIX_EPOCH)
|
|
215
220
|
.unwrap_or_default()
|
|
216
221
|
.as_millis();
|
|
217
|
-
|
|
222
|
+
// A millisecond-only name collides when rapid commands (e.g. validate /
|
|
223
|
+
// preview firing on edits) create temp files in the same millisecond — one
|
|
224
|
+
// call's TempFile::Drop then deletes another's file. The PID plus a
|
|
225
|
+
// monotonic counter make every name unique within and across processes.
|
|
226
|
+
let pid = std::process::id();
|
|
227
|
+
let seq = TEMP_COUNTER.fetch_add(1, Ordering::Relaxed);
|
|
228
|
+
path.push(format!("fiberpath-{pid}-{millis}-{seq}.{extension}"));
|
|
218
229
|
path.to_string_lossy().into_owned()
|
|
219
230
|
}
|
|
220
231
|
|
|
@@ -520,10 +531,20 @@ fn main() {
|
|
|
520
531
|
|
|
521
532
|
#[cfg(test)]
|
|
522
533
|
mod tests {
|
|
523
|
-
use super::TempFile;
|
|
534
|
+
use super::{temp_path, TempFile};
|
|
535
|
+
use std::collections::HashSet;
|
|
524
536
|
use std::fs;
|
|
525
537
|
use std::path::Path;
|
|
526
538
|
|
|
539
|
+
// Regression: a millisecond-only temp name collided when many temp files
|
|
540
|
+
// were created in the same millisecond, so one call's TempFile::Drop could
|
|
541
|
+
// delete another's file. Rapidly generated paths must all be unique.
|
|
542
|
+
#[test]
|
|
543
|
+
fn temp_path_is_unique_under_rapid_calls() {
|
|
544
|
+
let paths: HashSet<String> = (0..1000).map(|_| temp_path("gcode")).collect();
|
|
545
|
+
assert_eq!(paths.len(), 1000, "temp_path produced duplicate names");
|
|
546
|
+
}
|
|
547
|
+
|
|
527
548
|
#[test]
|
|
528
549
|
fn temp_file_is_removed_on_drop() {
|
|
529
550
|
let path = {
|