Commit graph

21 commits

Author SHA1 Message Date
ac2d2ad0ff fix: rewrite health-sync.js for Scripting app API
- fetch() instead of new Request() + req.loadJSON() (Scriptable API)
- Notification.schedule({title, body}) instead of new Notification() + n.schedule()
- allowInsecureRequest: true for HTTP (Scripting app blocks HTTP by default)
- This was the real reason 'nothing happened' — Scriptable API doesn't exist in Scripting app
2026-08-22 22:51:28 +01:00
067bf7a769 fix: health-sync.js HealthUnit method names + serve as inline text
- HealthUnit.gram(prefix) → HealthUnit.gramUnit(prefix) (Scripting app API)
- HealthUnit.millimeterOfMercury() → HealthUnit.fromString('mmHg')
- Updated header: Scriptable → Scripting app
- content-disposition: inline instead of attachment (fixes download issue)
2026-08-22 22:43:16 +01:00
3319a6b233 bd init: initialize beads issue tracking 2026-08-22 22:31:27 +01:00
ba706a3f1f fix: translate friendly nutrient keys to OFF keys in log_custom_food
log_custom_food's schema documents keys like 'protein', 'fat', 'salt' but
sum_nutriments() looks for OFF-style keys ('proteins_100g', 'fat_100g',
'salt_100g'). Nutrients passed with friendly keys were silently dropped
from daily totals. Now translates friendly keys to OFF keys before
storing. Both key styles work.
2026-08-21 21:09:03 +01:00
d0b7b003f9 feat: fallback nutrient estimation for potassium/calcium/magnesium
OFF data is sparse for fresh produce — spinach, oats, most frozen fruit
have no potassium. Added a curated fallback table (114 foods, USDA-sourced)
that injects estimated K/Ca/Mg at log time when OFF has no data.

How it works:
- data/fallback_nutrients.json: 114 foods with mg/100g values
- FallbackTable: case-insensitive exact + substring name matching
- log_food: injects _est keys (potassium_100g_est etc.) when OFF missing
- sum_nutriments: tries OFF value first (grams×1000), then _est (already mg)

Results for today's smoothie + lunch:
- Potassium: 691mg → 2,530mg (47% of 5400mg goal)
- Calcium: 14mg → 304mg (30% of 1000mg goal)
- Magnesium: 61mg → 330mg (73% of 450mg goal)

38 tests passing (7 new: fallback lookup, est fallback, OFF vs est priority)
2026-08-21 11:36:14 +01:00
a072c6ba5e fix: potassium/calcium/magnesium unit conversion (g → mg)
OFF stores potassium_100g, calcium_100g, magnesium_100g in grams.
Goals are in mg. sum_nutriments now multiplies these by 1000.

Before: potassium showed 0.7mg (was 0.0007g displayed as mg)
After:  potassium shows 691.2mg (banana: 0.32g/100g × 216g × 1000)

Added MG_NUTRIENTS const to db.rs. Updated test assertions.
31 tests passing.
2026-08-21 10:10:22 +01:00
e8bdea78bb feat: scriptable script + /ingest endpoint + smoothie recipe
- POST /ingest endpoint for Apple Health vitals (src/ingest.rs)
- GET /scriptable/health-sync.js for phone download
- recipes/daily-smoothie.json — Atrdeus's daily smoothie with barcodes
- Scriptable script reads HealthKit and POSTs to /ingest

Closes nutrition-mcp-aav
2026-08-21 09:30:20 +01:00
51b864438b fix: use Scripting app API (Health.queryQuantitySamples + HealthUnit) 2026-08-21 00:19:27 +01:00
e01c0b92e3 debug: add console.log at every step to trace execution 2026-08-21 00:14:41 +01:00
aa05c9c8d4 fix: await Notification.schedule() so notification fires before script exits 2026-08-21 00:10:45 +01:00
2b5751d50e fix: remove Script.done() — not a function in Scriptable 2026-08-21 00:08:31 +01:00
c65affc66c fix: use Scriptable Health API (new Health with string units) 2026-08-21 00:05:56 +01:00
191f5f473b fix: rewrite health-sync.js for current Scripting API
Old script used deprecated Health.read() with Health.Types.* and .quantity
— every read silently failed in try/catch, so no samples were ever collected.

Rewrote to use Health.queryQuantitySamples() with string type identifiers
and .quantityValue(unit) per current Scripting app docs. Added proper units
(kg, mmHg, count/min, count, percent) for each metric type.

Also adds /scriptable/health-sync.js endpoint to serve the script directly.
2026-08-20 23:54:08 +01:00
5d8976ef37 feat: POST /ingest endpoint + recent_vitals MCP tool for Apple Health
- Add vitals table (type, timestamp_utc, value JSON, source) with UNIQUE
  (type,timestamp_utc) for idempotent upserts.
- POST /ingest: Bearer-protected HTTP endpoint accepting batched health
  samples (weight, blood_pressure, heart_rate, spo2, steps, sleep, ...).
  Weight samples are mirrored into weight_log so existing weight tools see them.
- recent_vitals MCP tool: reads back ingested vitals, grouped by type with
  min/avg/max/units over a configurable window.
- 6 new tests (31 integration + 2 unit total, all passing).
- Verify live: /ingest POST -> recent_vitals round-trip over MCP protocol.
2026-08-20 21:32:19 +01:00
171c8a0490 fix: get_goals inputSchema now {type: object} not {}
Parameter-less tools in rmcp generated inputSchema: {} (empty dict
with no type field), which the Hermes MCP client rejects — one bad
tool fails the entire tools/list response.

Fix: added NoParams struct (empty, derives JsonSchema) and changed
get_goals to accept Parameters<NoParams>. schemars generates
{"type": "object", ...} for empty structs, which is valid.
2026-08-20 17:37:10 +01:00
ebb44fd712 test: add 25-test suite + fix sum_nutriments display keys
- 25 integration tests: DB init, default goals, FTS5 cache, upsert,
  portion scaling (100g/50g/200g/empty/non-numeric), sum_nutriments
  (single/multiple/empty/partial/no-data), meal detection, date format,
  log entry + summary round trip, custom food + sum, delete entry,
  goals get/update, weight log + history + upsert
- Fix: sum_nutriments now uses TRACKED_NUTRIENTS display names (first
  tuple element) instead of deriving from OFF field names — fixes
  proteins→protein, energy-kcal→energy_kcal mismatches
- Fix: weight_log.date is now UNIQUE for proper upsert behavior
- Fix: build_daily_summary remaining keys use display names
- Added lib.rs for integration test access
- Added regex dev-dependency

Closes nutrition-mcp-45t
2026-08-20 17:25:41 +01:00
2eaa67145c fix: correct Search-a-licious URL + nutriments_estimated fallback
- Search URL: search.openfoodfacts.org/search (not /api/v1/search)
- Search-a-licious returns no nutriments in hits — fetch each via v3 API
- Fall back to nutriments_estimated when no_nutrition_data is set
  or nutriments object has <3 keys (common for fresh produce)
- Handle brands as array or string from search API
2026-08-20 17:16:28 +01:00
2bda46ca17 feat: deploy + Hermes skill + git remote
- systemd user service deployed on Pi5 (port 9432, API key auth)
- Registered with Hermes via mcp_servers config
- Hermes skill at ~/.hermes/skills/productivity/nutrition-tracker/
- Git remote: git.darkmark.co.uk/amerlo/nutrition-mcp

Closes nutrition-mcp-foe, nutrition-mcp-aea
2026-08-20 16:56:12 +01:00
5beef81d70 docs: README.md, AGENTS.md, CLAUDE.md
- README: human-facing with tech stack, 14 nutrient table, 13 tools,
  env vars, build/run/deploy instructions, Hermes integration
- AGENTS/CLAUDE: build commands, architecture, module map, SQLite
  schema, conventions, tracked nutrients, session protocol

Closes nutrition-mcp-yd5, nutrition-mcp-4lv
2026-08-20 16:53:33 +01:00
244e141053 feat: scaffold nutrition-mcp server with all 13 tools
Rust MCP server using rmcp SDK with streamable HTTP transport.
- Config from env vars (bind, api_key, db_path, off_user_agent)
- SQLite schema: products (FTS5), entries, daily_goal, weight_log
- OFF API client: Search-a-licious + v3 barcode + SQLite caching
- 13 MCP tools: search_food, get_food_by_barcode, log_food,
  log_custom_food, delete_entry, daily_summary, history,
  list_entries, get_goals, set_goals, log_weight, weight_history,
  bulk_import (stub)
- 14 tracked nutrients (gout + hypertension aware)
- Bearer token auth middleware
- Smoke tested: health, initialize, tools/list, get_goals, daily_summary

Closes nutrition-mcp-dfl
2026-08-20 16:52:11 +01:00
7990757bb3 bd init: initialize beads issue tracking 2026-08-20 16:39:21 +01:00