Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
eb03322
ci(release): generate release notes from CHANGELOG.md section
GhostTypes Jul 4, 2026
65eeed6
chore(release): 1.2.0-alpha.1
GhostTypes Jul 4, 2026
e66c3e9
fix(webui): show TVOC reading on filtration card, disable controls fo…
GhostTypes Jul 5, 2026
cca37e8
feat(webui): add thumbnail previews to the file dialog with a persist…
GhostTypes Jul 5, 2026
4a1a811
chore(release): 1.2.0-alpha.2
GhostTypes Jul 5, 2026
f4d0ea6
feat: port the SSH toolset from the desktop app - file manager, calib…
GhostTypes Jul 10, 2026
502bd8b
feat(webui): fix manually adding HTTP-only (Creator 5) printers
GhostTypes Jul 23, 2026
1fc1f1c
Detect modern printers from the discovery product ID instead of the T…
GhostTypes Jul 24, 2026
e157c92
Report raw G-code availability and gate Home Axes on HTTP-only printers
GhostTypes Jul 24, 2026
541b0b6
fix: tighten material-station slot-config
GhostTypes Jul 24, 2026
f18316d
refactor(discovery): delegate to ff-api PrinterDiscovery instead of a…
GhostTypes Jul 24, 2026
d6c6335
chore(data): stop tracking generated runtime state
GhostTypes Jul 25, 2026
5eb4b9b
docs: track FFUI drift and the TCP-probe discovery research
GhostTypes Jul 25, 2026
30a31c7
fix: remove the untyped manual-IP connection path
GhostTypes Jul 26, 2026
6da3cfa
chore(release): 1.2.0-alpha.3 with ff-api 1.7.1
GhostTypes Jul 26, 2026
15aa8fd
docs: changelog the SSH toolset port that shipped undocumented
GhostTypes Jul 26, 2026
cc33fe1
chore(release): 1.2.0-alpha.4 with UI hotfixes
GhostTypes Jul 26, 2026
ea38af8
fix: unknown /api routes return 404 not 401
GhostTypes Jul 26, 2026
224d003
chore(release): 1.2.0-alpha.5 with /api 404 routing fix
GhostTypes Jul 27, 2026
31eac06
ci(release): tag the dispatched commit instead of the default branch
GhostTypes Jul 27, 2026
c5b97be
fix: suppress the wall-clock ETA while the print is not advancing
GhostTypes Aug 10, 2026
37ea5ba
chore(release): 1.2.0-alpha.6
GhostTypes Aug 10, 2026
26c8c94
docs(claude): record the advancing-print ETA gate and the ff-api 2.0.…
GhostTypes Aug 10, 2026
b902ba0
fix: source the print ETA from the library CompletionTime
GhostTypes Aug 13, 2026
27c67ca
fix: disable local and recent job start for the Creator 5 series
GhostTypes Aug 14, 2026
ff4aad6
test: add real-server browser E2E suite with Creator 5 gating coverage
GhostTypes Aug 14, 2026
19bdbb9
docs(changelog): record the Creator 5 gating, logout-revocation fix, …
GhostTypes Aug 14, 2026
ea18776
feat(webui): add Upload Job with AD5X and Creator 5 material matching
GhostTypes Aug 19, 2026
835f108
docs(changelog): record the WebUI Upload Job port under [Unreleased]
GhostTypes Aug 19, 2026
42f38cf
docs: remove stale comments and dead legacy methods in src
GhostTypes Aug 19, 2026
bce8a59
docs: strip noise comments and useless banners across src
GhostTypes Aug 19, 2026
356bc87
docs: fix backoff mislabels and standardize contextId JSDoc across src
GhostTypes Aug 19, 2026
3efb626
ci: fix SIGPIPE flake in e2e grep checks
GhostTypes Aug 19, 2026
62ddd44
feat(webui): rework upload and matching dialogs
GhostTypes Aug 21, 2026
da6a095
chore: remove ui-shot screenshot harness
GhostTypes Aug 21, 2026
fedc2a9
chore(release): 1.2.0-alpha.7
GhostTypes Aug 21, 2026
8f007ff
fix(webui): route bed/extruder heater commands through HTTP on TCP-le…
GhostTypes Aug 22, 2026
3984d67
ci: add GitHub Actions CI with emulator E2E track
GhostTypes Aug 22, 2026
19cb81c
fix: mark bundled go2rtc binaries as executable
GhostTypes Aug 22, 2026
f8c41f1
test: add per-model connect, LED, upload E2E matrix
GhostTypes Aug 22, 2026
16b4842
build: migrate to pnpm; bump ff-api to 2.0.1
GhostTypes Sep 12, 2026
aeed7d8
fix(ci): use pkg bin name with pnpm exec
GhostTypes Sep 12, 2026
a447ab8
test: cover C5 tool and chamber heater routes
GhostTypes Sep 13, 2026
fe1f8c5
fix(e2e): add chamberTargetTemp to EmulatorDetail
GhostTypes Sep 13, 2026
cd450b1
build: resolve scoped deps from public npm
GhostTypes Sep 13, 2026
c417e79
docs: no auth needed to build from source
GhostTypes Sep 13, 2026
bf00b8b
feat(spoolman): estimate-based per-spool tracking for station printers
GhostTypes Sep 13, 2026
d9f66e9
ci: bump emulator pin to v0.3.0 for spoolman e2e
GhostTypes Sep 13, 2026
7182227
feat(spoolman): track single-material AD5X stored-file prints
GhostTypes Sep 13, 2026
5149204
feat(spoolman): track station jobs per job, not per slot
GhostTypes Sep 24, 2026
cbf07fe
docs(spoolman): describe station tracking as per-job
GhostTypes Sep 24, 2026
93772ef
ci: pin the emulator to v0.4.0
GhostTypes Sep 24, 2026
11ce4f7
chore(release): prepare 1.2.0-alpha.8
GhostTypes Sep 26, 2026
21e9e32
fix(webui): share one WebUI start between concurrent callers
GhostTypes Oct 7, 2026
8685bdb
feat(webui): add About popup with version (#22)
GhostTypes Oct 11, 2026
a4648b8
build(deps): update axios, express, ws, form-data
GhostTypes Oct 11, 2026
bdb46da
ci(release): compare stable releases against the previous stable
GhostTypes Oct 11, 2026
829b05c
docs: refresh README, add CONTRIBUTING
GhostTypes Oct 11, 2026
6bcf1f9
chore(release): prepare 1.2.0
GhostTypes Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .claude/agents/code-quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ When invoked, you will:

1. **Identify Changed Files**: Determine which files have been modified or created in the current work session.

2. **Run Linter**: Execute `npm run lint` (Biome) on changed files. Capture all errors and warnings.
2. **Run Linter**: Execute `pnpm run lint` (Biome) on changed files. Capture all errors and warnings.

3. **Run Formatter**: Apply `npm run format:fix` to all changed files using project-configured Biome formatter.
3. **Run Formatter**: Apply `pnpm run format:fix` to all changed files using project-configured Biome formatter.

4. **Type Check**: Run `npm run type-check` (tsc --noEmit) to catch type errors.
4. **Type Check**: Run `pnpm run type-check` (tsc --noEmit) to catch type errors.

5. **Analyze Project Patterns**: Review code against established FlashForgeWebUI patterns (see checklist below).

Expand Down Expand Up @@ -144,7 +144,7 @@ Verify Biome configuration is respected:
- **Semicolons**: As configured
- **Line width**: Respect configured limit

Run with `npm run lint` and `npm run format` to apply project settings.
Run with `pnpm run lint` and `pnpm run format` to apply project settings.

## Behavioral Boundaries

Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/documenter.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ When processing multiple files:

Always use this command to find files needing documentation:
```bash
npm run docs:check
pnpm run docs:check
```

This checks all .ts, .tsx, .js, .jsx files in src/ for @fileoverview in the first 20 lines.
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/primary-engineer.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ When invoked, you will:
- Use EventEmitter with typed event maps
- Follow existing backend structure for printer integrations

5. **Verify and Refine**: Review your implementation for type safety, correctness, and adherence to patterns. Run `npm run type-check` and `npm run lint` to verify.
5. **Verify and Refine**: Review your implementation for type safety, correctness, and adherence to patterns. Run `pnpm run type-check` and `pnpm run lint` to verify.

## Decision Framework

Expand Down
134 changes: 134 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: CI

on:
push:
branches: [main, alpha]
paths-ignore:
- '**.md'
- 'LICENSE'
- '.gitignore'
- '.gitattributes'
- '.editorconfig'
pull_request:
branches: [main, alpha]
paths-ignore:
- '**.md'
- 'LICENSE'
- '.gitignore'
- '.gitattributes'
- '.editorconfig'
workflow_dispatch:
inputs:
emulator-ref:
description: 'flashforge-emulator-v2 git ref to run the E2E track against'
required: false
default: 'v0.3.0'
type: string

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
verify:
name: Type-check, lint, build, test
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout FlashForgeWebUI
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.23.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'


- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile

- name: Type check
run: pnpm run type-check

- name: Lint
run: pnpm run lint

- name: Build (backend + webui)
run: pnpm run build

- name: Unit tests
run: pnpm test

e2e-emulator:
name: E2E (emulator + browser)
runs-on: ubuntu-latest
needs: verify
timeout-minutes: 40
steps:
- name: Checkout FlashForgeWebUI
uses: actions/checkout@v4

# The emulator lives in a separate public repo and provides the printers this
# track drives, so no real hardware is needed. Pinned to a release tag so an
# emulator change cannot silently break or silently change this CI; bump the
# tag (or dispatch with emulator-ref) to pick up a new emulator release.
- name: Checkout flashforge-emulator-v2
uses: actions/checkout@v4
with:
repository: GhostTypes/flashforge-emulator-v2
ref: ${{ inputs.emulator-ref || 'v0.4.0' }}
path: emulator

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.23.0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'


- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile

- name: Install emulator dependencies
working-directory: emulator
run: npm ci
env:
# Only the emulator's headless runtime is used here; skip the large
# Electron binary download this repo's e2e-tests track never launches.
ELECTRON_SKIP_BINARY_DOWNLOAD: '1'

# The browser track needs the chromium binary itself, not just its system libraries.
- name: Install Playwright chromium
run: pnpm exec playwright install --with-deps chromium

# Unlike FlashForgeUI-Electron's CI there is no xvfb-run and no chrome-sandbox
# fixup here: this track drives the plain Node server (dist/index.js) with
# headless Chromium, never a real Electron window.
- name: Run browser E2E against the emulator
run: pnpm run test:e2e
env:
FF_EMULATOR_ROOT: ${{ github.workspace }}/emulator

- name: Upload Playwright artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-e2e-artifacts
path: |
test-results/
playwright-report/
retention-days: 7
if-no-files-found: ignore
53 changes: 33 additions & 20 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,16 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.23.0

- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
cache: 'pnpm'

- name: Cache pkg fetch
uses: actions/cache@v4
Expand All @@ -77,19 +82,8 @@ jobs:
restore-keys: |
${{ runner.os }}-pkg-

- name: Configure GitHub Packages
shell: bash
run: |
echo "@ghosttypes:registry=https://npm.pkg.github.com" >> .npmrc
echo "@parallel-7:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> .npmrc
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install dependencies
run: npm ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm install --frozen-lockfile

- name: Pre-download ARMv7 Node.js Binary
if: matrix.arch == 'armv7'
Expand All @@ -102,15 +96,15 @@ jobs:
- name: Build application
shell: bash
run: |
npm run build
pnpm run build
if [[ "${{ matrix.platform }}" == "win" ]]; then
npx @yao-pkg/pkg . --targets node20-win-${{ matrix.arch }} --output dist/${{ matrix.output }}
pnpm exec pkg . --targets node20-win-${{ matrix.arch }} --output dist/${{ matrix.output }}
elif [[ "${{ matrix.platform }}" == "mac" ]]; then
npx @yao-pkg/pkg . --targets node20-macos-${{ matrix.arch }} --output dist/${{ matrix.output }}
pnpm exec pkg . --targets node20-macos-${{ matrix.arch }} --output dist/${{ matrix.output }}
elif [[ "${{ matrix.arch }}" == "armv7" ]]; then
npx @yao-pkg/pkg . --targets node20-linuxstatic-armv7 --output dist/${{ matrix.output }}
pnpm exec pkg . --targets node20-linuxstatic-armv7 --output dist/${{ matrix.output }}
else
npx @yao-pkg/pkg . --targets node20-linux-${{ matrix.arch }} --output dist/${{ matrix.output }}
pnpm exec pkg . --targets node20-linux-${{ matrix.arch }} --output dist/${{ matrix.output }}
fi

- name: Verify binary size
Expand All @@ -130,6 +124,25 @@ jobs:
fi
echo "✓ Binary size: $size bytes"

# Write a deterministic config so the E2E auth assertions do not depend on the
# current DEFAULT_CONFIG values. Auth is explicitly enabled with the password
# the login step posts below ("changeme"). ConfigManager merges any omitted
# keys from DEFAULT_CONFIG at load time, so only auth-relevant keys are pinned.
- name: Write deterministic test config
if: matrix.can_execute == true
shell: bash
run: |
mkdir -p data
cat > data/config.json <<'EOF'
{
"WebUIEnabled": true,
"WebUIPort": 3000,
"WebUIPassword": "changeme",
"WebUIPasswordRequired": true
}
EOF
echo "✓ Wrote deterministic data/config.json"

# Windows: use cmd wrapper to redirect output while keeping process detached
- name: Start binary (Windows)
if: matrix.can_execute == true && runner.os == 'Windows'
Expand Down Expand Up @@ -204,7 +217,7 @@ jobs:
fi

# Test index.html contains expected content
if ! curl -sf http://127.0.0.1:3000/ | grep -q "FlashForge Web UI"; then
if ! curl -sf http://127.0.0.1:3000/ | grep "FlashForge Web UI" > /dev/null; then
echo "::error::GET / did not contain 'FlashForge Web UI'"
curl -s http://127.0.0.1:3000/ | head -20
exit 1
Expand Down Expand Up @@ -296,7 +309,7 @@ jobs:
shell: bash
run: |
if [[ "${{ runner.os }}" == "Windows" ]]; then
if tasklist /FI "IMAGENAME eq ${{ matrix.output }}" 2>/dev/null | grep -q "${{ matrix.output }}"; then
if tasklist /FI "IMAGENAME eq ${{ matrix.output }}" 2>/dev/null | grep "${{ matrix.output }}" > /dev/null; then
echo "::error::Binary left zombie processes"
exit 1
fi
Expand Down
Loading
Loading