Repository navigation
Merge 1.2.0 alpha cycle into main - #23
Open
GhostTypes wants to merge 59 commits into
Open
GhostTypes wants to merge 59 commits into
GhostTypes wants to merge 59 commits into
Conversation
…ration, SSH settings, and remote reboot - Brings over the desktop app's SSH-based features in one pass: printer file browsing and management, the full calibration assistant, per-printer SSH settings, and one-click printer reboot with live progress - Passwords can be changed but never read back from the browser - Only works on Adventurer 5M / 5M Pro / AD5X printers set up with the EasySSH USB tool; buttons stay hidden on other models - Fixed the calibration window being too narrow and its export button rendering comically large Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WacnY1aZDjPC1VTFoDuJxf
data/config.json and data/printer_details.json were committed to the repo, so a fresh clone shipped with the maintainer's local settings and saved printers. printer_details.json in particular carried real IPs, serials and check codes -- the check code is a printer's LAN auth credential. It also meant every local run left the working tree dirty. Ignore data/ wholesale, keeping only data/*.example.json, and add sanitized config.example.json and printer_details.example.json to document the schema for headless deployments. Neither file is read by the app: ConfigManager falls back to DEFAULT_CONFIG and PrinterDetailsManager starts with an empty printer map, and both write themselves out on first save. Also records the already-shipped PrinterDiscovery delegation in the changelog and updates CLAUDE.md, which documented the old data/runtime/-only ignore.
PORTING_TODO.md records what the 2026-07-10 SSH sync brought over from FlashForgeUI-Electron, the port-specific caveats (SecureStorage is base64-only here, passwords stay write-only over REST), and the known remaining drift -- notably the ifs-station -> material-station rename this repo has not taken yet. research-tcp-probe-discovery.md is the analysis behind 1fc1f1c: the UDP broadcast already carries the product ID and serial the probe was consulted for, so the probe is only required for genuine legacy printers. Both were written alongside shipped commits but never committed.
The displayed completion time was computed as now + remaining on every poll, which only holds still while the firmware counts estimatedTime down. It freezes that field the moment the print stops advancing, so the ETA stepped forward a minute every minute and receded for as long as the pause lasted. The dashboard panel and the Discord embed both kept recomputing with nothing to suppress them. Each now shows --:-- (and the Discord embed omits the ETA field) unless the print is actually advancing, via the new isPrintAdvancing predicate in types/polling.ts, mirrored browser-side in webui/static/shared/formatting.ts. Heating is excluded along with the paused states: the pre-print warmup does not advance the job either and drifts identically, just for minutes rather than hours.
Creator 5 / Creator 5 Pro firmware neither sends nor accepts material mappings over the HTTP API, so starting a previously uploaded local or recent job dead-ends at material selection. Only a fresh .3mf upload and start works. - webui panels: gate the start controls via the hasMultiTool feature flag with a title tooltip - webui dialogs: guard the file-list load with a toast - standardized message: "Local job management is not available on this printer."
Brings the standalone WebUI to parity with FlashForgeUI-Electron's browser E2E. Ported from that suite with the same hard rule: no stubs or fixtures. The harness boots real flashforge-emulator-v2 instances, seeds an isolated DATA_DIR (printer_details.json + deterministic auth config), launches the real built server (node dist/index.js --all-saved-printers), and waits for its HTTP API and connected printer contexts. - webui-auth.spec.ts: bad password, login + websocket auth gate, remembered-token session restore, anonymous/forged-token 401s, logout revocation - webui-smoke.spec.ts: versioned assets, every referenced asset served, printer context switching verified against the server's own active-context state - webui-creator5-gating.spec.ts: pins the Creator 5 series local-job gating (commit 27c67ca) across 5M Pro / Creator 5 / Creator 5 Pro emulated printers, including the HTTP-only Home Axes gate - playwright.config.ts pins workers:1 (specs boot emulators on fixed ports; parallel workers collide with EADDRINUSE) - type-check now covers tsconfig.e2e.json; new test:e2e script Two real bugs the suite caught on its first runs, now fixed: - SECURITY: /api/auth/logout never revoked tokens. The route runs without the auth middleware, so req.auth was never populated and the revocation branch was dead code; a logged-out token kept full API access. The token is now extracted from the Authorization header via the same helper the middleware uses (mirrors FlashForgeUI-Electron). - BasePrinterBackend.buildFeatureSet() hardcoded gcodeCommands and statusMonitoring as always available, silently discarding child backend declarations - Creator5Backend's gcode-unavailable flag never reached the feature set. The builder now honors child values with the old defaults as fallback (mirrors FFUI-E commit 113613e). The login rate limiter (5 attempts / 15 min / IP, successes count) gives each spec file an exact login budget; every spec documents its spend so a future test knows to shave one first. Validation: 11/11 browser tests against real emulated printers, jest 388/388, type-check (app + e2e) and biome clean.
…and browser E2E suite under [Unreleased]
Port the desktop Upload Job dialog to the WebUI, 1:1. Users can now send a .gcode, .gx, or .3mf file from the browser and start it. Before this, only files already on the printer could be started. A browser knows no local file path, so the upload runs in three steps: POST /api/jobs/upload/stage takes the bytes, parses the file, and returns an upload handle plus the metadata. POST /api/jobs/upload/start hands the printer backend a real path. POST /api/jobs/upload/cancel drops the staged file. Material matching reuses the existing dialog through new optional onConfirm and onCancel hooks, so the resident-job start path is unchanged. The Creator 5 series is not gated: a fresh 3MF carries its own tool data, so upload is the one job path those printers support. Staged files are capped at 512 MB, live in one temp directory each, expire after 30 minutes, and are removed on server stop. The server accepts only a bare .gcode, .gx, or .3mf name. Bump @parallel-7/slicer-meta to 1.5.0 for the layer height, infill, layer count, first layer time, and warning fields.
Mirror the FFUI-Electron material-matching and upload dialog rework (c9506a9) in the standalone WebUI. - Matching dialog: the confirm button now reads Confirm instead of Start Print, a dedicated card lists every color mismatch, and mapping rows show color swatches on both sides. - Upload dialog: confirmed mappings show as chips (tool, slot, material, swatches), the primary button reads Start Print with Start Now ticked and Send File otherwise, slice warnings moved to their own card, the print-time highlight became a full-width banner, and phone layout stacks the preview above the metadata. - Add a headless UI screenshot harness: scripts/ui-shot.mjs plus fixtures for the upload and matching dialogs, the ui:shot npm script, and .ui-shots/ in .gitignore, so layout changes can be checked without launching the app. - Shorten the AD5X color difference warning text in createColorDifferenceWarning. - Record the rework under [Unreleased] in CHANGELOG.md. Verified: type-check (app + e2e), 24 jest suites / 388 tests. The .pi/settings.json deletion in the working tree is unrelated local noise and is not part of this commit.
Remove the ui-shot headless screenshot harness that commit 62ddd44 added. The harness served the built WebUI over a throwaway HTTP server, applied a fixture that filled the dialog DOM with representative data, and captured PNGs in headless Chromium. It no longer earns its keep, so it goes. Deleted: - scripts/ui-shot.mjs, the runner - scripts/ui-shot-fixtures/upload.mjs and matching.mjs, the two dialog fixtures - the "ui:shot" npm script - the .ui-shots/ ignore block from .gitignore No CHANGELOG changes needed — the harness was never mentioned in the changelog entries. The .pi/settings.json deletion in the working tree remains unrelated local noise, not part of this commit.
…ss printers The four single-extruder temperature routes sent raw ~M140/~M104 G-code through executeGCodeCommand, which hard-fails on HTTP-only backends -- so bed and extruder temps could not be set on the Creator 5 series at all (real firmware runs no TCP service on those printers). Bed/extruder set/cancel are now proper backend methods that branch on legacy client presence: dual-API printers keep the legacy TCP wire command (identical bytes to before), HTTP-only printers (Creator 5 / 5 Pro) use the ff-api tempControl endpoints with no TCP attempt, and GenericLegacyBackend (AD3/AD4) keeps its G-code path unchanged. Verified against live emulator instances: Creator 5 and AD5M Pro, all four routes per printer, asserting each emulator's /detail target temps (and the C5 four-nozzle array) reflect the commands.
Add .github/workflows/ci.yml for FlashForgeWebUI with two jobs. verify: type-check, lint, build, and unit tests on Node 20. Sets up GitHub Packages auth for the @GhostTypes and @Parallel-7 scopes so npm ci can install the scoped deps. e2e-emulator: browser E2E with Playwright chromium against flashforge-emulator-v2, checked out at pinned tag v0.2.0 (overridable via the emulator-ref workflow_dispatch input). The emulator supplies the printers, so no real hardware is needed. Its install skips the Electron binary because only the headless Node runtime is used; this track drives dist/index.js, not an Electron window. Playwright test-results and report upload as artifacts on failure. Triggers on push and pull_request to main/alpha, ignores doc-only paths, and cancels in-progress runs per ref.
Change the file mode of all five bundled go2rtc binaries (darwin-arm64, darwin-x64, linux-arm, linux-arm64, linux-x64) from 100644 to 100755. Contents are unchanged; only permissions differ.
The binaries are committed to the repo, so a fresh Linux/macOS checkout restores them without the executable bit, and the postinstall downloader skips chmod because the files already exist ("Already exists" early return). Spawning go2rtc then fails with EACCES and server startup aborts with "[Fatal] go2rtc process exited during startup".
This broke the new CI e2e-emulator job (dist/index.js on ubuntu-latest) while Windows local runs stayed green, since Windows has no exec bit. The pkg track never hit it because extractBundledBinary() already chmods after unpacking.
Fixes the mode at the source so every checkout, git archive, and clone gets executable binaries on Unix platforms.
Expand the standalone WebUI browser E2E suite from 14 to 38 tests, mirroring FlashForgeUI-Electron's per-model emulator track, and refactor it onto shared infrastructure. - helpers/targets.ts: four-model emulator matrix (Adventurer 5M Pro, AD5X, Creator 5, Creator 5 Pro) with capability flags (isCreator5Series, hasMaterialStation, productId, printerModel). Specs loop this list so every model is covered everywhere by construction, exactly like FFUI-Electron's support/track.ts. The matrix, never the printer's /detail, is the source of truth - stock Creator 5 firmware no longer reports the material station in /detail but still has one and still requires mappings on a fresh upload. - New upload spec (mirrors FFUI-E's upload.spec.ts): browser-driven upload through the real dialog per model, material matching dialog must appear for every 3MF on station printers (AD5X, Creator 5, Creator 5 Pro, single tool included) and never on 5M-series (bounded 10s wait), tool-to-slot assignment then confirm, Start Now unchecked, file-landed assertion via the recent-jobs list (the printer's /gcodeList), and an assertNotPrinting safety gate reading the emulator's own /detail. API-level three-call upload for all models pins the gcode-refused-on-station gate and the mapping payload. - New connect spec: auto-connect of the saved printer on boot, per-model manual connect via POST /printers/connect (productId for HTTP-only models), wrong check-code rejection leaving no context, UDP discovery finding every instance with the saved one flagged known. - New LED spec: on/off cycle per model asserted in the emulator's /detail lightStatus. - helpers/api.ts: shared token fetch, context resolution, raw/JSON POST, remembered-token page open, printer switch. Tests open pages via the remembered-token restore path to stay inside the server's 5-logins-per-15-minutes rate limit. - standalone-server harness: seedPrinters option to boot emulators without auto-connecting them (used by the connect spec). - Gating and heater specs refactored onto the shared matrix: gating now covers AD5X too, heaters cover all four models plus the nozzles-array contract on both Creator 5s. - Fixtures copied from FlashForgeUI-Electron: ad5x-single-tool.3mf and adventurer5m-single-color.gcode. Full suite: 38 passed in 2.0m locally against emulator v0.2.0.
- Per-tool estimates captured at upload (3mf filament data; AD5X toolData fallback), stored per printer serial - Deduction at terminal states only: full on completion, progress-fraction on cancel, none on pause/resume - Slot-to-spool assignments persisted per serial; Spoolman panel re-enabled with per-slot view - Exactly-once via reserve-first ledger; Spoolman errors never affect printing - AD5X without station now supported via the standard single-spool flow
- Captures printer-reported total filament weight at print start for stored single-material jobs - Deducts to the sole assigned slot's spool; ambiguous or multi-material stays untracked - One delayed retry for recent-list propagation lag; capture never blocks the start response
Material-station printers report no per-tool filament use. The old flow kept a spool per slot for each printer serial, but the spools on the printer can change at any time and the app cannot see that. Now the matching dialog asks for the spool of each tool, or "Do not track". The choice applies to that one print only. The app deletes it when the print ends. - Add a spool picker to the matching dialog for app-started jobs. - Charge the full slicer estimate per tool when a print completes. - Charge a cancelled print per tool from the 3MF gcode. The printer reports progress as the gcode byte position, so each tool gets the part it printed up to that point. - Charge the last saved progress, marked approximate, when a print ended while the app was not running. - Track AD5X multi-material stored files that start through the matching dialog. Charge a cancel linearly by progress. - Remove the slot-to-spool store, its route, and single-material stored-file tracking. - Send the gcode tool number (filament id - 1), not the list position. A plate with filaments 1 and 3 printed its second tool from the wrong slot. - Let the matching dialog wait up to 15 s for the station status. - Add unit tests and emulator e2e tests with a tool-change fixture.
The per-job Spoolman e2e tests need 3MF slice weights per tool and AD5X tool ids 0-3. Emulator v0.4.0 adds both.
Move the unreleased CHANGELOG entries into a dated 1.2.0-alpha.8 section. Bump the package version to match. Correct the CI entry: the emulator pin is v0.4.0, not v0.2.0. Add a note that Creator 5 tracking is not yet tested on a real printer.
Port of FlashForgeUI-Electron e4d9e9c (from FlashForgeUI-Electron PR #80). startWebUI() enables auto-start right before it calls start(), so a configUpdated event during startup starts a second attempt. The two attempts race to bind the same port, and the loser's cleanupFailedStart() closes the winner's sockets. - Make start() share one in-flight attempt. Clear it in a finally() callback so a failed attempt can be retried. - Make stop() wait for an in-flight start, so the start cannot mark the server running again after the stop. - Clear the close-timeout timer in stop(). A clean close left it armed, which kept the process open for the rest of the timeout. - Kill go2rtc on process exit. The startup-failure and hard-deadline paths call process.exit(), which skips the graceful shutdown, so go2rtc was orphaned holding its ports. - Add lifecycle tests for concurrent starts, retry after a failed start, and stop during a start. Co-Authored-By: jsalmon00 <jsalmon00@users.noreply.github.com>
A top-bar info button opens an About modal showing the running version, with links to releases, source, and the issue tracker. The version is stamped into index.html from package.json by copy-webui-assets.js at build time, so packaged binaries and source builds both report it. Co-Authored-By: Claude Code <noreply@anthropic.com>
Clears the runtime advisories pnpm audit reports against the shipped dependencies: axios 1.13.6 -> 1.20.0, express 5.1.0 -> 5.3.0 (and its proxy-addr, path-to-regexp, qs, body-parser), ws 8.18.3 -> 8.22.0, form-data 4.0.5 -> 4.0.6. The package.json floors are raised so a fresh resolve cannot land on a vulnerable version. Only these packages moved; nothing else in the lockfile changed. The remaining runtime advisory is adm-zip 0.5.x via @parallel-7/slicer-meta, which needs a slicer-meta release that widens its adm-zip range to ^0.6. Co-Authored-By: Claude Code <noreply@anthropic.com>
PREVIOUS_TAG took the newest older tag, so v1.2.0's "Compare changes since" link would have pointed at v1.2.0-alpha.8. Git's default version sort also ranks v1.2.0-alpha.8 above v1.2.0, so v1.3.0-alpha.1 would have compared against alpha.8 as well. Sort with versionsort.suffix=- so a prerelease ranks below its release, and skip prerelease tags when cutting a stable release. The greps get `|| true` because the step runs under pipefail and grep exits 1 when nothing matches. Co-Authored-By: Claude Code <noreply@anthropic.com>
README: feature table now covers job upload, the material station, the SSH tools, Discord notifications, per-job Spoolman tracking, and the authenticated camera proxy. Binary names gain the .bin suffix the release assets actually use. Adds the missing config keys, the About window as the way to check the version, the E2E suite, troubleshooting rows for remote camera access and the GitHub Packages 401 (#18), and a Contributing pointer. CONTRIBUTING.md: work from alpha and target PRs at alpha; the alpha -> main -> stable release cycle; setup, pre-PR checks, conventions, bug report details, and the maintainer release steps. CLAUDE.md: scoped packages now resolve from public npm, and note the adm-zip advisory that rides in on slicer-meta. Co-Authored-By: Claude Code <noreply@anthropic.com>
Move the unreleased CHANGELOG entries into a dated 1.2.0 section and bump the package version to match. This is the first stable release since 1.1.0, and the workflow uses this section as the release page, so it opens with highlights from the whole alpha cycle and upgrade notes for 1.1.0 users: untracked data/ files on git pull, public-npm installs (#18), go2rtc port forwarding, and the serial number now required for manual and CLI connects. Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the 1.2.0 alpha cycle (alpha.1 through alpha.8, plus the changes since alpha.8) into
mainahead of the 1.2.0 stable release.Highlights since 1.1.0
.gcode,.gx, and.3mf, with the thumbnail, slicer details, and tool-to-slot material matching.?ip=/?serial=), and an About window that shows the version (Version info #22).Unknown, logout revokes the session token, and WebUI start and shutdown races are fixed.Security
axios,express(withproxy-addr,path-to-regexp,qs, andbody-parser),ws, andform-dataare updated past their advisories.fast-xml-parserandfast-xml-builderare already at fixed versions on alpha.package-lock.json, which all 86 open Dependabot alerts onmainare filed against. Dependabot then rescanspnpm-lock.yaml.adm-zip0.5.x via@parallel-7/slicer-meta. It needs a slicer-meta release that moves toadm-zip^0.6. Low exposure: slicer-meta only reads zip entries in memory, and only logged-in users can upload.Upgrade notes for users coming from 1.1.0
data/config.jsonanddata/printer_details.jsonare no longer tracked. Back them up beforegit pull.1984.creator-5/creator-5-protype and its serial.Before merging
alpha: the## [1.2.0]CHANGELOG section andpackage.json->1.2.0(chore(release): prepare 1.2.0).alphacan fast-forward tomainafterwards.After the merge: dispatch Build and Release on
mainwith1.2.0and pre-release unchecked, then fast-forwardalphatomain.Co-Authored-By: Claude Code noreply@anthropic.com