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)
This commit is contained in:
parent
3319a6b233
commit
067bf7a769
3 changed files with 32 additions and 21 deletions
|
|
@ -13,3 +13,4 @@
|
|||
{"id":"int-b0e97dffd303b9e4f164830ebcbe2085","kind":"field_change","created_at":"2026-08-20T15:56:04.581867751Z","actor":"Anthony Merlo","issue_id":"nutrition-mcp-aea","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Hermes skill created at ~/.hermes/skills/productivity/nutrition-tracker/SKILL.md with workflow guidance, meal auto-detection, portion handling, protein estimation guide, and gout/hypertension health context."}}
|
||||
{"id":"int-c69e98d9ab404dbe46f1b088e3453677","kind":"field_change","created_at":"2026-08-20T16:25:47.847889101Z","actor":"Anthony Merlo","issue_id":"nutrition-mcp-45t","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"25 integration tests added, all passing. Covers: DB init, goals seeding, FTS5 cache search, upsert, portion scaling, sum_nutriments (with no-data handling), meal detection, date format, log entry round trips, goals update, weight log + upsert. Also fixed sum_nutriments display key bug (was using OFF field names instead of display names) and weight_log UNIQUE constraint."}}
|
||||
{"id":"int-80ae42f606a6a22aef6d8883d3462f72","kind":"field_change","created_at":"2026-08-20T21:57:03.081085913Z","actor":"Anthony Merlo","issue_id":"nutrition-mcp-aav","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"POST /ingest endpoint implemented in src/ingest.rs. Accepts array of health samples (weight, BP, HR, steps, sleep, SpO2). Auth via Bearer token. Tested: 4 samples ingested (weight, BP, steps, HR), 401 on missing auth. 31 tests passing. Server restarted and live. Dependency on 3nl was for vitals tables — ingest uses a generic vitals table with JSON value column, no need to wait for individual table tooling."}}
|
||||
{"id":"int-d36257ef0a5cb2afb18ece95e6b92bc7","kind":"field_change","created_at":"2026-08-22T21:35:47.560297Z","actor":"Anthony Merlo","issue_id":"hm-zy2.1","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed 3 API bugs in health-sync.js. Server side verified working. Needs on-device test to fully confirm."}}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,25 @@
|
|||
// Health Sync — reads Apple Health and POSTs to nutrition-mcp server
|
||||
// Health Sync — reads Apple Health via Scripting app and POSTs to health-mcp server
|
||||
// Run via Scripting app automation at 9:30am daily
|
||||
// Server: http://chronos:9432/ingest
|
||||
//
|
||||
// Uses Scripting app's Health API: Health.queryQuantitySamples() with HealthUnit.
|
||||
// Uses Scripting app's Health API:
|
||||
// Health.queryQuantitySamples(type, options) — returns samples
|
||||
// sample.quantityValue(unit) — extracts numeric value
|
||||
// HealthUnit / HealthMetricPrefix — unit construction
|
||||
//
|
||||
// Docs: https://scriptingapp.github.io/guide/Device%20Capabilities/Health/
|
||||
|
||||
// Variables used by Scripting app. These must be at the very top of the file.
|
||||
// icon-color: deep-blue; icon-glyph: heart;
|
||||
|
||||
const SERVER_URL = "http://chronos:9432/ingest";
|
||||
const API_KEY = "333f09ce904e9cbbe3b578fda393be92869122c7222dbccd";
|
||||
|
||||
// --- Units for each quantity type ---
|
||||
// HealthUnit API: https://scriptingapp.github.io/guide/Device%20Capabilities/Health/HealthUnit
|
||||
const U = {
|
||||
kg: HealthUnit.gram(HealthMetricPrefix.kilo),
|
||||
mmHg: HealthUnit.millimeterOfMercury(),
|
||||
kg: HealthUnit.gramUnit(HealthMetricPrefix.kilo),
|
||||
mmHg: HealthUnit.fromString("mmHg"),
|
||||
bpm: HealthUnit.count().divided(HealthUnit.minute()),
|
||||
count: HealthUnit.count(),
|
||||
percent: HealthUnit.percent()
|
||||
|
|
@ -153,22 +162,22 @@ if (samples.length === 0) {
|
|||
await notify("No health data found today");
|
||||
} else {
|
||||
|
||||
const req = new Request(SERVER_URL);
|
||||
req.method = "POST";
|
||||
req.headers = {
|
||||
"Authorization": `Bearer ${API_KEY}`,
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
req.body = JSON.stringify({ samples: samples });
|
||||
const req = new Request(SERVER_URL);
|
||||
req.method = "POST";
|
||||
req.headers = {
|
||||
"Authorization": `Bearer ${API_KEY}`,
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
req.body = JSON.stringify({ samples: samples });
|
||||
|
||||
try {
|
||||
const res = await req.loadJSON();
|
||||
console.log(`Server response: ${JSON.stringify(res)}`);
|
||||
await notify(`Sent ${res.ingested || samples.length} samples`);
|
||||
} catch (e) {
|
||||
console.log(`POST error: ${e}`);
|
||||
await notify(`Error: ${e.message || e}`);
|
||||
}
|
||||
try {
|
||||
const res = await req.loadJSON();
|
||||
console.log(`Server response: ${JSON.stringify(res)}`);
|
||||
await notify(`Sent ${res.ingested || samples.length} samples`);
|
||||
} catch (e) {
|
||||
console.log(`POST error: ${e}`);
|
||||
await notify(`Error: ${e.message || e}`);
|
||||
}
|
||||
|
||||
} // end else
|
||||
console.log("=== Health Sync done ===");
|
||||
|
|
@ -108,14 +108,15 @@ async fn health_check() -> &'static str {
|
|||
"OK"
|
||||
}
|
||||
|
||||
/// Serve the Scriptable health-sync.js file for easy phone download.
|
||||
/// Serve the health-sync.js script for easy phone access.
|
||||
/// No auth — it's just a script, no sensitive data.
|
||||
/// Served as inline text so Safari displays it for copy-paste into Scripting app.
|
||||
async fn serve_scriptable_script() -> impl axum::response::IntoResponse {
|
||||
let script = include_str!("../scripts/health-sync.js");
|
||||
(
|
||||
[
|
||||
("content-type", "text/javascript; charset=utf-8"),
|
||||
("content-disposition", "attachment; filename=\"health-sync.js\""),
|
||||
("content-disposition", "inline"),
|
||||
],
|
||||
script,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue