Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
1c8ce52
chore(release): initialize v2.4.0-beta.1
hessius Mar 25, 2026
3be47f6
feat(pwa): Phase 1 — MachineService abstraction layer
hessius Mar 21, 2026
fddfbce
feat(pwa): Phase 2 — AI service abstraction layer
hessius Mar 21, 2026
8370f92
feat(pwa): Phase 3 — IndexedDB persistence layer
hessius Mar 21, 2026
da7c197
feat(pwa): Phase 4 — unified telemetry hook
hessius Mar 21, 2026
7284157
feat(pwa): Phase 5 — feature triage flags
hessius Mar 21, 2026
d412ff6
feat(pwa): Phase 6 — dual build config & service worker
hessius Mar 21, 2026
aa27008
feat(pwa): Phase 7 — machine installation scripts
hessius Mar 21, 2026
0be42e9
feat(ci): add machine PWA build workflow and release artifact
hessius Mar 21, 2026
efcd362
test: add comprehensive tests for PWA service layer
hessius Mar 21, 2026
7fc50ab
fix(pwa): wire services into app and address code review findings
hessius Mar 22, 2026
9dad05c
fix(pwa): handle randomized machine hostnames and improve install docs
hessius Mar 22, 2026
0ec8448
fix(scripts): use wget instead of curl for machine compatibility
hessius Mar 22, 2026
4a85f78
fix(scripts): support machines without curl/wget, add --local install…
hessius Mar 22, 2026
1ae7364
fix(scripts): avoid self-copy when --local tarball is already in /tmp
hessius Mar 22, 2026
6b59078
fix(pwa): handle CJS default export interop for espresso-api
hessius Mar 22, 2026
fd24dba
chore: remove accidental tarball from repo, add to gitignore
hessius Mar 22, 2026
11c7e57
fix(build): export VITE_MACHINE_MODE so it reaches vite build
hessius Mar 22, 2026
de84a11
fix(pwa): resolve base URL paths and skip proxy API calls in direct mode
hessius Mar 22, 2026
1f533e2
fix(pwa): global fetch interceptor for direct mode proxy API calls
hessius Mar 22, 2026
bd8bf3e
fix(pwa): smart API translation layer for direct mode
hessius Mar 22, 2026
6fb05b2
feat(pwa): add run-profile, import, and command translations to direc…
hessius Mar 22, 2026
ba2a74f
fix(pwa): stop purge on run, add preheat/schedule translations
hessius Mar 22, 2026
5394562
fix(pwa): telemetry unit conversion, profile name, catalogue and history
hessius Mar 22, 2026
ef9969e
fix(pwa): direct mode API interceptor — profile load body parsing and…
hessius Mar 23, 2026
2ebe8fb
feat(pwa): browser AI service and machine service for direct mode
hessius Mar 23, 2026
f8d3a5b
fix(pwa): component adaptations for direct mode
hessius Mar 23, 2026
1123241
fix(i18n): add direct mode translation keys across all locales
hessius Mar 23, 2026
721f9d4
fix(pwa): iOS safe area — show background through notch
hessius Mar 23, 2026
3fc8c69
chore: update bun.lock and testing docs
hessius Mar 23, 2026
36ee287
fix(pwa): iOS homescreen 404, port 80 serving, profile catalogue navi…
hessius Mar 23, 2026
3bbe4db
feat(pwa): static profile description generation in direct mode
hessius Mar 23, 2026
9ff317f
fix: machineMode env var leak breaking tests, remove unused import
hessius Mar 23, 2026
15008c6
fix: hide redundant 'In catalogue' badge in direct mode
hessius Mar 23, 2026
5b909ed
docs: add machine PWA install guide, auto-patch Tornado route
hessius Mar 23, 2026
d50520e
refactor: rename install script to install-direct.sh, add release TODO
hessius Mar 25, 2026
28d2bcc
security: remove SSH credentials from documentation
hessius Mar 25, 2026
16c2689
fix: address automated and manual code review findings
hessius Mar 25, 2026
a1e03b8
fix: address code review issues — hooks, error types, CI branches
hessius Mar 25, 2026
9219e02
fix: E2E test specificity, honest scheduling error in direct mode
hessius Mar 25, 2026
7c82c3f
fix: resolve build failures — missing brace in RunShotView, unused pa…
hessius Mar 25, 2026
c8cc045
fix: address second round of automated code review findings
hessius Mar 25, 2026
c29de55
feat: Machine-Hosted PWA — three-pronged deployment model (#316)
hessius Mar 25, 2026
2acd2a9
feat: mobile home screen above-the-fold layout (#287)
hessius Mar 25, 2026
b683067
feat: select Gemini model in settings (#180)
hessius Mar 25, 2026
8596dc4
feat: iOS and Material You platform themes (#288, #291)
hessius Mar 25, 2026
9962826
feat: import profiles from URL (#96)
hessius Mar 25, 2026
8fe78c7
fix: address code review findings for #321
hessius Mar 25, 2026
0ef3ef4
fix: address code review findings for #322 (security + validation)
hessius Mar 25, 2026
5e51ea9
fix: address code review findings for #320
hessius Mar 25, 2026
d7b9eb4
Merge pull request #319 from hessius/feature/287-mobile-layout
hessius Mar 26, 2026
98eba1e
Merge pull request #320 from hessius/feature/180-select-model
hessius Mar 26, 2026
de9eafc
Merge pull request #321 from hessius/feature/288-291-platform-themes
hessius Mar 26, 2026
af247c3
Merge pull request #322 from hessius/feature/96-import-from-link
hessius Mar 26, 2026
ecc93d2
chore(deps): update all frontend dependencies
hessius Mar 26, 2026
6d96ab4
Merge pull request #323 from hessius/chore/update-dependencies
hessius Mar 26, 2026
c17e268
fix(css): reorder platform theme imports after Tailwind
hessius Mar 27, 2026
655aa0b
Merge pull request #325 from hessius/fix/platform-theme-cascade
hessius Mar 27, 2026
36a9aeb
Merge remote-tracking branch 'origin/main' into version/2.4.0
hessius Mar 27, 2026
a000ec0
refactor(home): streamline mobile home screen layout
hessius Mar 27, 2026
1990010
feat(konsta): foundation — install Konsta UI, add KonstaProvider, rem…
hessius Mar 27, 2026
911f863
feat(konsta): adaptive UI components — all shadcn components render K…
hessius Mar 27, 2026
0866aa3
fix: address code review findings for Konsta UI integration
hessius Mar 27, 2026
539575d
Merge pull request #331 from hessius/fix/home-screen-redesign
hessius Mar 27, 2026
82ee815
fix: address code review findings for konsta adaptive components
hessius Mar 27, 2026
b40de19
fix: address code review findings for konsta foundation
hessius Mar 27, 2026
3daafeb
refactor: extract fetch interceptor from main.tsx (#335)
hessius Mar 27, 2026
d02e69f
merge: resolve conflicts with version/2.4.0 (interceptor extraction)
hessius Mar 27, 2026
5a6153a
feat(konsta): foundation — KonstaProvider, hooks, theme CSS removal (…
hessius Mar 27, 2026
24b7e0b
merge: resolve conflicts with version/2.4.0 (foundation + interceptor)
hessius Mar 27, 2026
6226a79
feat(konsta): adaptive UI components — Konsta rendering on mobile (#334)
hessius Mar 27, 2026
d7196c9
fix(konsta): temporarily disable Konsta UI due to layout conflicts (#…
hessius Mar 28, 2026
7706e99
fix: profile catalogue offline fallback and import button
hessius Apr 1, 2026
c8aef18
fix: complete profile catalogue deletion and detail regressions
hessius Apr 1, 2026
7d9e8e7
fix(server): restore API startup by correcting profile_data dict inde…
hessius Apr 1, 2026
557f6d2
fix(catalogue): resolve history ids from /api/history and fix swipe c…
hessius Apr 1, 2026
86d4453
fix(ui): redesign delete profile dialog and fix restore endpoint
hessius Apr 7, 2026
a35467e
fix(pourover): stop icon, bloom target in free mode, auto-start sensi…
hessius Apr 7, 2026
dbc95ea
fix(sync): store content_hash at profile creation so sync detects cha…
hessius Apr 1, 2026
a0b706e
fix(i18n): rewrite espresso compass golden rules for progressive, non…
hessius Apr 1, 2026
d2f4db1
refactor(settings): reorganize into collapsible sections with auto-save
hessius Apr 1, 2026
3d72ed0
fix(ui): close 768-1023px viewport gap where control center disappears
hessius Apr 1, 2026
3400c13
test(parity): comprehensive feature parity test suite for server vs d…
hessius Apr 1, 2026
d6bddef
chore(deps): absorb all 17 Dependabot PRs into v2.4.0
hessius Apr 7, 2026
f983184
fix: correct CollapsibleSection closing tag in SettingsView themes se…
hessius Apr 7, 2026
d3d2a35
fix: resolve race conditions and debounce eviction in AppDatabase
hessius Apr 7, 2026
fcf20c1
feat(#326): complete OEM TypeScript package integration
hessius Apr 7, 2026
0c5a16e
fix: address all automated code review findings
hessius Apr 7, 2026
3aaf9b2
feat(ios): Capacitor iOS app scaffolding (#253)
hessius Apr 8, 2026
d215cd6
ci: add iOS build workflow for Capacitor app (#253)
hessius Apr 8, 2026
21f86cf
fix(ios): Xcode 16.2 compatibility for Capacitor 8.x build
hessius Apr 8, 2026
7eda5d6
fix(ios): fix translations, settings, notch background, and web inspe…
hessius Apr 9, 2026
17c5b5d
feat(capacitor): add ShotDataService and CatalogueService abstractions
hessius Apr 9, 2026
5a952b0
feat(capacitor): add onboarding wizard for first-run setup
hessius Apr 9, 2026
39629aa
feat(capacitor): expand DirectModeInterceptor for full direct-mode co…
hessius Apr 10, 2026
6363062
fix: Swedish translations, golden rules rendering, settings layout, v…
hessius Apr 10, 2026
9526589
fix: address code review findings and CI failures for v2.4.0
hessius Apr 10, 2026
d7f679e
fix(build): use sh instead of bash in postinstall for Docker compatib…
hessius Apr 10, 2026
420efef
fix(build): skip postinstall when script not yet copied in Docker
hessius Apr 10, 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
4 changes: 1 addition & 3 deletions .github/skills/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ Expected: 277+ tests passing. 0 lint errors (warnings OK per issue #256).

4. Build container from local source and start

cd ../.. && docker compose -f docker-compose.yml -f docker-compose.dev.yml build --no-cache

&& docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
cd ../.. && docker compose -f docker-compose.yml -f docker-compose.dev.yml build --no-cache && docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

5. Health check

Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,29 @@ jobs:
echo "changelog<<$EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "$EOF" >> $GITHUB_OUTPUT

- name: Setup Bun for PWA build
if: steps.check_tag.outputs.exists == 'false'
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Build machine PWA artifact
if: steps.check_tag.outputs.exists == 'false'
run: |
cd apps/web
bun install --frozen-lockfile
VITE_MACHINE_MODE=direct bun run build
tar -czf ../../meticai-web.tar.gz -C dist .
echo "📦 Machine PWA: $(du -sh dist/ | cut -f1)"

- name: Create Release
if: steps.check_tag.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.version }}
name: MeticAI v${{ steps.version.outputs.version }}
files: meticai-web.tar.gz
body: |
## MeticAI v${{ steps.version.outputs.version }}

Expand All @@ -86,6 +102,11 @@ jobs:
docker pull ghcr.io/hessius/meticai:v${{ steps.version.outputs.version }}
```

**Machine-Hosted PWA:**
```bash
curl -fsSL https://raw.githubusercontent.com/hessius/MeticAI/main/scripts/install-direct.sh | bash
```

**Upgrading from v1.x:**
```bash
curl -fsSL https://raw.githubusercontent.com/hessius/MeticAI/main/scripts/migrate-to-unified.sh | bash
Expand Down
83 changes: 83 additions & 0 deletions .github/workflows/build-ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Build iOS App

on:
push:
branches: [main]
paths:
- 'apps/web/**'
- 'VERSION'
pull_request:
branches: [main]
paths:
- 'apps/web/**'
workflow_dispatch:

permissions:
contents: read

jobs:
build-ios:
name: Build Capacitor iOS
runs-on: macos-15
defaults:
run:
working-directory: apps/web

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Bun (attempt 1)
id: setup_bun_1
continue-on-error: true
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Setup Bun (attempt 2)
id: setup_bun_2
if: steps.setup_bun_1.outcome == 'failure'
continue-on-error: true
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Setup Bun (attempt 3)
if: steps.setup_bun_2.outcome == 'failure'
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Build web app for Capacitor
run: VITE_MACHINE_MODE=capacitor bun run build

- name: Sync Capacitor
run: npx cap sync ios

- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.3.app

- name: Build iOS (no code signing)
run: |
xcodebuild build \
-project ios/App/App.xcodeproj \
-scheme App \
-destination 'generic/platform=iOS Simulator' \
-configuration Release \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY="" \
| tail -20

- name: Report build result
if: always()
run: |
if [ -d ios/App/build ]; then
SIZE=$(du -sh ios/App/build/ | cut -f1)
echo "📱 iOS build: ${SIZE}"
else
echo "📱 iOS build completed (simulator target)"
fi
77 changes: 77 additions & 0 deletions .github/workflows/build-machine-pwa.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Build Machine PWA

on:
push:
branches: [main, "feat/machine-hosted-pwa"]
paths:
- 'apps/web/**'
- 'VERSION'
pull_request:
branches: [main]
paths:
- 'apps/web/**'
workflow_dispatch:

permissions:
contents: read

jobs:
build-machine-pwa:
name: Build Machine-Hosted PWA
runs-on: ubuntu-latest
defaults:
run:
working-directory: apps/web

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Bun (attempt 1)
id: setup_bun_1
continue-on-error: true
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Setup Bun (attempt 2)
id: setup_bun_2
if: steps.setup_bun_1.outcome == 'failure'
continue-on-error: true
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Setup Bun (attempt 3)
if: steps.setup_bun_2.outcome == 'failure'
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.10

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Run linter
run: bun run lint

- name: Run tests (direct mode)
run: VITE_MACHINE_MODE=direct bun run test:run

- name: Build for machine
run: bun run build:machine

- name: Report build size
run: |
SIZE=$(du -sh dist/ | cut -f1)
FILES=$(find dist/ -type f | wc -l)
echo "📦 Machine PWA build: ${SIZE}, ${FILES} files"

- name: Create release tarball
run: tar -czf meticai-web.tar.gz -C dist .

- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: meticai-web
path: apps/web/meticai-web.tar.gz
retention-days: 90
2 changes: 1 addition & 1 deletion .github/workflows/build-macos-installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
branches:
- main
- develop
- version/2.0.0
- "version/*"
pull_request:
paths:
- 'macos-installer/**'
Expand Down
11 changes: 7 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Test Suite

on:
push:
branches: [main, develop, version/2.0.0]
branches: [main, develop, "version/*", "feat/machine-hosted-pwa"]
pull_request:
branches: [main, develop, version/2.0.0]
branches: [main, develop, "version/*"]

jobs:
# ============================================================================
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
--cov-report=xml --cov-report=term-missing

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
files: ./apps/server/coverage.xml
flags: relay
Expand Down Expand Up @@ -107,11 +107,14 @@ jobs:
- name: Run unit tests
run: bun run test:run

- name: Run direct-mode tests
run: bun run test:direct

- name: Generate coverage report
run: bun run test:coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v6
with:
files: ./apps/web/coverage/coverage-final.json
flags: web
Expand Down
72 changes: 72 additions & 0 deletions .release-notes-beta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
## MeticAI v2.4.0-beta.1 — Machine-Hosted PWA & iOS Foundation

### 🚀 New Features

#### Espresso Compass (#261)
Interactive 2D taste input (sour/bitter, weak/strong) with descriptor selection. After pulling a shot, tell MeticAI how it tasted and get AI-powered recommendations for your next attempt.

#### Temporary Variable Adjustments (#281)
Tweak profile variables (dose, temperature, pressure, flow targets) before running a shot — without saving changes to the profile. Run-without-saving support plus "Save as New" option for keepers.

#### Profile Recommendations (#95)
AI recommends profiles based on tag similarity scoring. "Find Similar" overlay in the profile catalogue helps you discover related profiles.

#### Analysis-to-Edit Pipeline (#258)
Shot analysis now generates structured, actionable recommendations. Select which suggestions to apply — edits are made directly to the profile.

#### Profile Catalogue Edit Mode
Export, rename, and delete buttons are now behind an Edit toggle — cleaner default view, full control when you need it. Bulk delete support included.

#### Profile Image Improvements
Download profile images, auto-scroll gallery, and improved prompt generation.

### ♿ Accessibility (#186)
- Landmarks, skip navigation, and live regions throughout the app
- All icon-only buttons have descriptive aria-labels
- Charts have role="img" with descriptive labels
- prefers-reduced-motion support across all animations
- 25+ accessibility i18n keys across all 6 locales

### ⚡ Performance
- **Code-splitting:** 13 views lazy-loaded (main bundle 1,807 KB → 516 KB, **71% reduction**)
- Recharts and framer-motion in separate async chunks
- Granular error boundaries on all lazy-loaded views

### 🐛 Bug Fixes
- Variable adjust panel: reliability improvements, correct grouping (base vs. custom), unused variable warnings, emoji info variables filtered out
- Pour-over: dose and brew ratio now persist across sessions
- Preheat: subtitle no longer shows when preheat is disabled; profile pre-selected during preheat phase
- Live view: removed Power line from chart (not useful for espresso)
- Recommendation dialog: improved mobile layout
- Profile catalogue: image caching, thumbnail improvements
- Scroll-to-top on all intra-component view transitions
- 50+ hardcoded English error strings replaced with i18n t() calls

### 📦 Dependencies
- Vite 8.0.0 (Rolldown-based builds)
- React 19.2.4, framer-motion 12.37.0, tailwindcss 4.2.1
- 31 dependency bumps total (Python + NPM)

### 📊 Stats
- 105 files changed, 15,336 insertions, 3,743 deletions
- 6 locales fully updated (en, de, es, fr, it, sv)
- 0 lint errors, all tests passing

---

### Installation (Beta Channel)

**Docker (beta tag):**
```bash
docker pull ghcr.io/hessius/meticai:beta
```

**Pin to this exact version:**
```bash
docker pull ghcr.io/hessius/meticai:2.4.0-beta.1
```

⚠️ This is a pre-release. The `latest` tag is unchanged — stable users are not affected.

---
Built from commit: 1a57c72bbb3b7745bdfc3931154e4e9cb39b4037
26 changes: 26 additions & 0 deletions IOS_SHORTCUTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,29 @@ Same as Photo workflow but use endpoint: `http://<SERVER_IP>:3550/api/analyze_co
- **Connection fails** — Ensure your phone is on the same network. Test `http://<SERVER_IP>:3550/docs` in Safari.
- **Invalid response** — Check field names are exactly `file` and/or `user_prefs` (case-sensitive).
- **Photo won't upload** — Ensure the form field key is `file` and value comes from the Take Photo action.

## Import Profile from Share Sheet

Share a profile URL (`.json` or `.met`) from any app to import it directly into MeticAI.

### Setup

| # | Action | Configuration |
|---|--------|---------------|
| 1 | **Receive** | URLs from Share Sheet |
| 2 | **URL Encode** | Encode Shortcut Input |
| 3 | **URL** | `http://<SERVER_IP>:3550/?import=` appended with URL Encoded Text |
| 4 | **Open URLs** | Open the URL from step 3 |

### How It Works

MeticAI supports a `?import=<url>` query parameter. When the app loads with this parameter, it automatically opens the import dialog and begins importing the profile from the given URL.

### Alternative: Direct API Import

| # | Action | Configuration |
|---|--------|---------------|
| 1 | **Receive** | URLs from Share Sheet |
| 2 | **Get Contents of URL** | URL: `http://<SERVER_IP>:3550/api/import-from-url`, Method: POST, Body: JSON, `url` = Shortcut Input |
| 3 | **Get Dictionary Value** | Key: `profile_name` |
| 4 | **Show Notification** | Text: "Imported: " + Dictionary Value |
Loading
Loading