Skip to content

Release 1.0.5 - #82

Open
GhostTypes wants to merge 99 commits into
mainfrom
alpha
Open

GhostTypes wants to merge 99 commits into
mainfrom
alpha

Conversation

@GhostTypes

Copy link
Copy Markdown
Member

Release PR for FlashForgeUI 1.0.5 stable. It promotes the 1.0.5 alpha cycle (alpha.1 through alpha.13, plus the headless/go2rtc fixes from #80) to main.

Merge with a merge commit, not a squash, so main and alpha keep a shared history.

What's in it

  • Version: package.json is set to 1.0.5, so the updater channel is latest.
  • CHANGELOG: a ## [1.0.5] - 2026-10-10 section rolls up the whole alpha cycle. The release workflow reads its notes from this section.
  • Security: dependency overrides and bumps patch the newly published advisories. pnpm audit goes from 104 findings (5 critical) to 9 (8 high, 1 moderate), and pnpm audit --prod reports none. What remains:
    • 4 Electron 39 advisories. These are fixed only in Electron 41.10.6 and later; the Electron 44 upgrade is planned for the 1.0.6 alpha cycle. The app's exposure is low: no <webview>, contextIsolation on, nodeIntegration off, and only local content is loaded.
    • 5 dev/install-time-only advisories with no published fix (braces via jest; extract-zip, http-cache-semantics and sprintf-js via @electron/get).
  • Docs: a new CONTRIBUTING.md describing the alpha → main workflow, and a README refresh with fixed wiki links, new feature rows, Creator 5 notes and build prerequisites.
  • CI: the default emulator ref for manual runs is now v0.4.0.

Verification (local, Windows)

  • type-check, lint and build pass.
  • Jest: 1965 of 1965 pass.
  • Browser E2E: 20 of 20 pass.
  • Electron emulator E2E: 31 passed and 2 skipped on the final runs. Earlier runs had intermittent failures: 6 port-in-use (EADDRINUSE) failures and 2 Creator 5 failures.
  • build:win produces FlashForgeUI-Setup-1.0.5.exe and latest.yml.
  • pnpm install --frozen-lockfile succeeds.

Before cutting the release

  • CI is green on this PR
  • Live GUI test on real printers
  • Merge (merge commit)
  • gh workflow run release.yml --ref main -f version=1.0.5 -f prerelease=false
  • Sync main back into alpha and bump to 1.0.6-alpha.1

GhostTypes and others added 30 commits May 31, 2026 12:08
chore(deps): resolve all 67 Dependabot alerts (security)
chore: remove stale security-audit doc
docs(changelog): document unreleased work since 1.0.4-alpha.4
Following the 1.0.4 stable release:
- Bump version 1.0.4-alpha.4 -> 1.0.5-alpha.1 (per CLAUDE.md lesson #9:
  never continue 1.0.4-alpha.N after 1.0.4 stable, or electron-updater
  404s on the missing alpha.yml). Channel resolves to "alpha"/prerelease.
- Sync CHANGELOG with main: consolidated [1.0.4] - 2026-05-31 entry plus a
  fresh empty [Unreleased]; alpha CHANGELOG is now identical to main.

Verified: electron-builder reports "Channel: alpha (prerelease: true)";
pnpm install --frozen-lockfile passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chore(release): open 1.0.5-alpha.1 cycle on alpha
Edit mode was only reachable via the undocumented CTRL+E shortcut, while
the WebUI already exposed a visible toggle. Add an "Edit Layout" entry to
the hamburger dropdown that toggles GridStack edit mode, mirroring the
WebUI for discoverability (issue #62).

- New menu item with a pencil icon and platform-aware Ctrl+E / Cmd+E hint
- Dynamic label: flips between "Edit Layout" and "Exit Edit Mode"
- Disabled when no printer is connected, matching edit mode availability
- EditModeController gains an onStateChange subscription so the label stays
  in sync regardless of trigger (menu, CTRL+E, reset, printer disconnect)
- Disabled menu-item styling added

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The name implied dead code or a tie to legacy *printers*, but the class is
the active window chrome (window controls, hamburger menu, loading overlay)
and unrelated to legacy hardware. There is no parallel "old" UI system; the
component/GridStack stack is the sole renderer for printer data.

- Move src/renderer/src/ui/legacy/LegacyUiController.ts to
  src/renderer/src/ui/shell/ShellController.ts and rename the class
- Update the @fileoverview to describe it accurately as window chrome
- Update references in renderer.ts and ai_docs/UI_COMPONENTS.md
- Drop the stale "fallback to legacy update system" comment that referenced
  the already-removed updateAllPanels path

No behavior change. "Legacy printer" terminology (Adventurer 3/4) is left
intact as a legitimate domain term.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- emitStateChange iterates a copy of the listener array so a listener that
  unsubscribes during its callback is not skipped
- Edit Layout menu item uses the ARIA-correct toggle semantics
  (role="menuitemcheckbox" + aria-checked) instead of aria-pressed, which is
  invalid on role="menuitem"

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(ui): add Edit Layout menu item + rename LegacyUiController to ShellController
Add a "Set from Spoolman" affordance to the IFS material-station
component. Clicking a slot opens a popover; the user picks a spool from
the existing Spoolman picker, the spool's material/color are snapped to
the AD5X's fixed 14-material / 24-color palette, and applied to the slot
via the library's configureSlot (msConfig_cmd).

- src/shared/ifs-palette.ts: pure palette + nearestColor (CIEDE2000) +
  nearestMaterial (exact-then-leading-token), with a Jest spec.
- Apply path: renderer -> preload (material.configureSlot) -> IPC
  material:configure-slot -> PrinterBackendManager.configureMaterialSlot
  -> AD5XBackend.configureSlot -> control.configureSlot.
- Spool picker reused via a `purpose` flag; slot-config mode returns the
  picked spool without changing the tracked active spool.
- Color falls back color_hex -> first multi_color_hexes; an unrecognized
  material keeps the slot's current material. Gated on AD5X + Spoolman.

Bumps @ghosttypes/ff-api to ^1.3.2 for configureSlot/SlotAction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the small "Set from Spoolman" popover with a full slot editor
dialog: a material dropdown (14 recognized materials) and a grid of the
24 recognized color swatches, pre-seeded from the slot's current
material/color. Works with Spoolman disabled.

- material:set-slot IPC + material.setSlot preload: apply an explicit
  material + color to a slot (no Spoolman dependency).
- Gate the "Set from Spoolman" shortcut on the global Spoolman config
  (enabled + URL), not on spoolman.getStatus() - which the backend
  hard-disables for AD5X material-station printers, i.e. exactly the
  printers this feature targets. When used it pre-fills the dialog from
  the picked spool (snapped to the palette) for review before Apply.
- SpoolmanIntegrationService.isContextSupported now detects AD5X via the
  firmware PID (FiveMClient.isAD5X) + material-station capability instead
  of the brittle printerModel.startsWith('AD5') string match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Discovery model detection was name-based: detectPrinterFamily only matched
"5m"/"ad5x", so a Creator 5 fell through to the legacy connection path and
failed with "Failed to establish final connection" despite speaking the same
modern HTTP + check-code protocol.

Route on the authoritative, firmware-set USB product ID (discovery packet
offset 0x88) instead, falling back to the immutable Machine Type (TypeName)
only for manual IP connections - never the user-editable Machine Name.

- DiscoveredPrinter now carries productId/productType; PrinterDiscoveryService
  propagates them from the ff-api discovery result (previously dropped).
- Add NEW_API_PRODUCT_IDS map and detectPrinterFamilyFromId /
  detectPrinterModelTypeFromId; use them in ConnectionFlowManager.
- Cover PID-first routing with PrinterUtils tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…uting

Route the Creator 5 series to a dedicated backend and surface its per-tool
temperatures in the UI. Builds on @ghosttypes/ff-api 1.3.4.

- Creator5Backend extends AD5XBackend: inherits the 4-slot material station and
  dual HTTP + TCP transport, and adds per-tool nozzle temps in status, built-in
  camera, a Creator 5 Pro filtration override (its /product under-reports the
  fans), door-sensor gating (Pro only), and native /printGcode job starting.
- Route creator-5 / creator-5-pro to Creator5Backend (was the interim 5M backend).
- Add a tool-temps grid component showing the 4 nozzle temperatures; register it
  in the component catalog and both component factories.
- Thread toolTemps through PrinterStatus and PrinterDataTransformer so the card
  (and the web UI's status data) receive per-tool temperatures.
- Bump @ghosttypes/ff-api to ^1.3.4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Creator 5 / 5 Pro are HTTP-only (no legacy TCP on 8899), which is what was
breaking the old TCP-first connect. This wires them up properly and cleans up the
material handling around them.

- Detect C5/5 Pro by USB product ID, use the FiveMClient in httpOnly mode (ff-api ^1.3.6)
- Route temperature control over HTTP when there's no TCP client
- Add C5-specific filament palette (24 colors, 21 materials)
- Renamed ifs-station to material-station

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump version and add changelog for the Creator 5 connection fix and
material-station updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A Creator 5 / 5 Pro saved as legacy under an older build still failed to
connect: the saved forceLegacyMode flag routed it down the legacy TCP path,
which hangs forever because these printers have no TCP server on 8899.

HTTP-only models now always connect over HTTP regardless of forceLegacyMode (in
both the discovery and saved-details paths), and the bad flag is healed on the
next successful connect. Adds regression tests for the override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Accidentally added in the previous commit; this is a local working note that
should not be in the repo. Keeps the file on disk, untracked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…very

Carry the product ID through the discovery selection so the Creator 5 / 5 Pro
is identified and connects over HTTP instead of falling back to legacy TCP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expose material slot-config API in component dialog preload (material namespace + slot-config Spoolman flow parity).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-card migration

Resolve the remaining Creator 5 / 5 Pro control gaps and the layout migration that
left the generic temperature card in place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The per-tool Off button now turns the tool head off: ff-api 1.6.1 writes 0 to the
nozzle instead of the -100 sentinel the Creator 5 firmware ignores in the nozzles
array. Tool heads are also now displayed as T1-T4 to match the printer's own UI
(the wire protocol/index stays 0-based).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Multi-tool temperature card (per-tool + bed + chamber), read-only TVOC display, and a general material-station card/slot editor for the built-in WebUI, at parity with the desktop Creator 5 implementation.
The range check already rejects values above CHAMBER_MAX_TEMP, so the follow-up Math.min was dead code. Flagged by Gemini Code Assist on the standalone WebUI PR.
GhostTypes and others added 28 commits August 19, 2026 18:06
Comment-only cleanup across 8 files; no code behavior changes.

- Remove dead commented-out code: the MainProcessPollingCoordinator import in index.ts and the DevTools auto-open block in WindowConfig.ts. The setupDevTools no-op now says why it stays.
- Delete stale notes that no longer match behavior: Web UI polling remarks in WebUIManager.ts and the palette drag-forwarding note in palette-handlers.ts.
- Fix the handler path in DialogHandlers.ts to the real location, src/main/ipc/handlers/.
- Replace the hardcoded per-dialog size list in DialogWindowFactory.ts with a pointer to WINDOW_SIZES, so the docs cannot drift from the source of truth.
- Reword the job-selected TODO in job-handlers.ts and the factory note in gridController.ts for clarity. Both still reference issue #77 where relevant.
Rewrote 27 oversized @fileoverview JSDoc headers (36-77 lines each) into short 5-12 line summaries that keep the operative facts and drop the boilerplate: feature bullet lists, usage code samples, redundant export inventories, and prose size/symbol tables that duplicated WindowTypes.ts and the export statements.

The old headers were a second source of truth that had already drifted: stale enum lists (missing 7 window types), wrong dialog sizes (e.g. Settings "600x500" vs actual 820x820), a claim of automatic DevTools that is now an intentional no-op, a 30s poll claim vs the real 3000ms constant, and a described nested-path helper that does not exist. The condensed headers keep non-obvious constraints (destroyed-window rule, security invariants, polling pause rationale) and point to the real sources of truth.

Continues the comment-hygiene series (RE-term scrub, stacked-header dedupe, stale-comment fixes). Comment-only change: -1288/+165 lines, no executable code touched.
Normalize file headers to the single-tag @fileoverview convention:

- Strip redundant JSDoc @module tags from 96 files where they only restated the file path next to an existing @fileoverview. Kept @module only in the two ambient declaration files (global.d.ts, global-main.d.ts) where the tag genuinely names the module for consumers.
- Drop the 9 "@author FlashForgeUI Team" lines (component-dialog / shortcut-config cluster).
- Convert AutoConnectService.ts's lone old-generation essay header to the standard short @fileoverview style.

97 files, comments only (-215/+4). The repo's own docs:check gate (scripts/check-fileoverview.go) passes.
Comment-only cleanup; no code behavior changes.

- Remove 32 narration comments from the three MultiContext main-process services (NotificationCoordinator, SpoolmanTracker, TemperatureMonitor). Each comment restated the line directly below it ("Emit event", "Store tracker", "Clear map", etc.) and carried no why or caveat.
- Replace duplicated override JSDoc with {@inheritdoc BaseComponent.update} in five renderer UI components (additional-info, filtration-controls, model-preview, printer-status, temperature-controls), plus {@inheritdoc BaseComponent.setupEventListeners} in the two display-only components. The base class already carries the canonical documentation.

Final stage of the comment-hygiene series (RE-term scrub, stacked-header dedupe, stale-comment fixes, header condensing, @module/@author normalization).
Remove the dead `/// <reference types="../../types/global.d.ts" />` directives from component-dialog.ts, shortcut-config-dialog.ts, and spoolman-dialog-renderer.ts.

The directives pointed at a path that no longer exists (global.d.ts moved to src/shared/types/), and `types=` resolves against @types packages rather than relative paths, so they were silent no-ops. The global Window augmentations already load ambient via the tsconfig.web.json include of `src/shared/**/*`, so no replacement is needed — full typecheck (web + e2e) passes.
Consolidate the twice-vendored VideoRTC player (two identical 701-line copies) into one canonical copy at src/shared/lib/video-rtc.js.

- Renderer: camera-preview.ts imports via the existing @shared alias (rename-detected move, history preserved)
- WebUI: copy-webui-assets.cjs vendors from the shared path; the static copy at src/main/webui/static/lib/ is deleted, runtime URL and version stamping unchanged
- Drop 4 commented-out console.debug lines from the moved file; neutral @fileoverview covering both consumption paths

Verified: full typecheck, webui build (?v= stamp confirmed), electron-vite build, 55 jest suites / 1899 tests, and a live GUI run against a real AD5X.
Matching dialog: the confirm button now reads Confirm on the desktop dialog and the built-in WebUI. It previously read Start Print and promised an action the dialog does not perform. Color mismatches now fill a warning card of their own above the two lists; the card rebuilds on every change, so every mismatch stays visible instead of only the most recent one. Mapping rows gained a color swatch on both sides.

Upload dialog: confirmed mappings show as chips with tool, slot, material name, and a swatch per side. The primary button is named after what it does: Start Print with Start Now ticked, Send File otherwise (it read OK before). Slicer warnings moved into their own card, and the print-time highlight became a full-width banner. On phone widths the WebUI stacks the preview above the metadata and keeps both checkboxes on one line.

Desktop uploader: the window is taller, its minimum height was raised, and the metadata pane shows a slim scrollbar instead of hiding overflow.

Added scripts/ui-shot.mjs, a headless Playwright harness that screenshots dialogs and WebUI screens from fixtures without running the app. It ships four fixtures, the ui:shot npm script, and a .gitignore entry for .ui-shots/. CHANGELOG.md records the rework under [Unreleased].

Verified: type-check (app + e2e), 55 jest suites / 1899 tests, live GUI test against a real AD5X with a material-station 3MF.
Remove the headless ui-shot screenshot harness added in c9506a9. The tool turned out not to be worth keeping.

Deleted scripts/ui-shot.mjs, its four DOM fixtures under scripts/ui-shot-fixtures/, and the ui:shot npm script. Removed the .gitignore block that ignored .ui-shots/ and cleaned the local .ui-shots/ output directory.

No CHANGELOG changes needed — the harness was never mentioned in the changelog entries.
The emulator E2E job checked out flashforge-emulator-v2 at the branch head,
so any emulator change could silently break or silently change this CI with
no ref to bisect against. Pin to the v0.2.0 release tag (bump deliberately;
workflow_dispatch accepts emulator-ref to test against another ref).

The emulator's npm ci now runs with ELECTRON_SKIP_BINARY_DOWNLOAD=1: only
the headless runtime is used here, and the app-under-test gets its Electron
binary from this repo's node_modules, so the emulator's ~110 MB download was
pure waste.
- Port of FlashForgeWebUI bf00b8b: per-tool upload estimates, serial-keyed stores, terminal-only deduction
- Completion deducts full estimates; cancel deducts progress fraction; pause/resume deduct nothing
- Slot-to-spool assignments via IPC + embedded-webui routes, exposed in both preload surfaces
- Exactly-once via reserve-first ledger; Spoolman errors never affect printing
- Port of FlashForgeWebUI 7182227: printer-reported capture at print start, exactly-one-spool rule
- Hooks both start paths (IPC + embedded-webui) behind startNow gating; capture never blocks the start
- One delayed retry for recent-list propagation lag; job-picker indicator with themed styling
Port of FlashForgeWebUI 5149204. 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", in the desktop dialog and the built-in WebUI. The choice
applies to that one print only. The app deletes it when the print
ends.

- Add a spool picker to the desktop and WebUI matching dialogs.
- Charge the full slicer estimate per tool when a print completes.
- Charge a cancelled print per tool from the 3MF gcode, which the
  printer reports progress against by byte position.
- Charge the last saved progress, marked approximate, when a print
  ended while the app was not running.
- Track AD5X stored files that start through the matching dialog.
- Remove the slot-to-spool store, its IPC channel and route, and the
  slot assignment in the Material Station editor.
- Send the gcode tool number (filament id - 1), not the list position,
  from the desktop uploader and the built-in WebUI.
- Let the WebUI 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.0.5-alpha.13
section. Bump the package version to match.

Add a note that Creator 5 tracking is not yet tested on a real
printer.
From PR #80. In headless mode the backend-ready startForPrinter() and
HeadlessManager.startWebUI() both call start(). Two independent
attempts race to bind the same port, the loser fails with EADDRINUSE,
and headless exits.

- Make start() share one in-flight attempt. Clear it in a finally()
  callback, which always runs after the assignment, so a failed
  attempt can be retried. The PR cleared it synchronously, which left
  a settled attempt in place when start() failed before its first
  await.
- Make stop() wait for an in-flight start, so the start cannot mark
  the server running again after the stop.
- Kill go2rtc on process exit. will-quit does not fire on
  process.exit(), which the headless failure paths use, so go2rtc was
  orphaned holding its ports. Register the listener once in the
  constructor, not on every start.
- Add tests for concurrent starts, retry after a failed start, and
  stop during a start.

Co-Authored-By: jsalmon00 <jsalmon00@users.noreply.github.com>
Sync main's post-1.0.4 commits back into alpha ahead of the 1.0.5 stable
release so the alpha -> main PR merges cleanly. Alpha already carried the
Dependabot fixes and a newer README, so every conflict resolves to alpha.
return raw;
}
if (entry.method === 8) {
return raw.pipe(zlib.createInflateRaw());
Comment on lines +29 to +34
import {
DEFAULT_HEADLESS_PRINTERS,
type HeadlessPrinter,
type HeadlessWebUI,
startHeadlessWebUI,
} from './helpers/headless-webui';
@GhostTypes GhostTypes self-assigned this Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant