forge-openclaw-plugin 0.2.108 → 0.2.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{activity-page-DWHZ8_sJ.js → activity-page-BdeoV3N4.js} +1 -1
- package/dist/assets/{ai-surface-workspace-DPygfyhc.js → ai-surface-workspace-BCbQUekv.js} +1 -1
- package/dist/assets/{atlas-panel-D261RUQF.js → atlas-panel-DTnRBOZx.js} +1 -1
- package/dist/assets/{calendar-page-BQbJkdPF.js → calendar-page-YDexXy_e.js} +1 -1
- package/dist/assets/{calendar-rules-BoFsuvZ8.js → calendar-rules-B_aOcMi3.js} +1 -1
- package/dist/assets/{calendar-week-toolbar-LetevPI7.js → calendar-week-toolbar-BTbIzq3e.js} +1 -1
- package/dist/assets/{companion-sync-lab-page-Bid-4B8W.js → companion-sync-lab-page-DKouMut9.js} +1 -1
- package/dist/assets/{daily-metrics-dashboard-CqnGJNeI.js → daily-metrics-dashboard-B3UCGG1t.js} +1 -1
- package/dist/assets/{entity-note-count-link-VMURwBMi.js → entity-note-count-link-DUxobQUt.js} +1 -1
- package/dist/assets/{entity-notes-surface-DGXcyNzo.js → entity-notes-surface-BdHBn8rx.js} +1 -1
- package/dist/assets/{execution-board-BGf6zZqJ.js → execution-board-R5-oyf-Z.js} +1 -1
- package/dist/assets/{faceted-token-search-CAsZrhZ4.js → faceted-token-search-DtO6OUwQ.js} +1 -1
- package/dist/assets/{flagship-signal-deck-DJsq3jn2.js → flagship-signal-deck-B9k46sWA.js} +1 -1
- package/dist/assets/{floating-action-menu-B3tQStUN.js → floating-action-menu-DBzfnJOx.js} +1 -1
- package/dist/assets/{goal-detail-page-DBs-9wpk.js → goal-detail-page-Mr_gnZ2l.js} +1 -1
- package/dist/assets/{goals-page-CPmhjsG-.js → goals-page-BG7FuqK1.js} +1 -1
- package/dist/assets/{habits-page-DkW8zT6_.js → habits-page-CGdaOqL3.js} +1 -1
- package/dist/assets/{index-BhkubYaC.js → index-BP9__l6C.js} +2 -2
- package/dist/assets/{insight-flow-dialog-BvgRjkPi.js → insight-flow-dialog-BUv06Vn-.js} +1 -1
- package/dist/assets/{insights-page-Dtij6pm5.js → insights-page-BgD1_1we.js} +1 -1
- package/dist/assets/{kanban-page-R1x5hUU-.js → kanban-page-DvZSN-Bi.js} +1 -1
- package/dist/assets/{knowledge-graph-page-BRBB5Vvz.js → knowledge-graph-page-BXWXtPvo.js} +1 -1
- package/dist/assets/{life-force-page-DGPWKM9I.js → life-force-page-CwjHvpzu.js} +1 -1
- package/dist/assets/{life-force-workspace-DoRIQoU_.js → life-force-workspace-Ct70SsNQ.js} +1 -1
- package/dist/assets/{metric-tile-NJiFcFxW.js → metric-tile-DCxLxNli.js} +1 -1
- package/dist/assets/{movement-page-Dk8aV737.js → movement-page-C06ebiYk.js} +1 -1
- package/dist/assets/{note-markdown-CZHjJDve.js → note-markdown-3wB52NOn.js} +1 -1
- package/dist/assets/{note-tags-input-DFpxZHPg.js → note-tags-input-Blg5Gqz_.js} +1 -1
- package/dist/assets/{notes-page-r3kymlqg.js → notes-page-CSkjizyK.js} +1 -1
- package/dist/assets/{open-in-graph-button-B_XHtHZD.js → open-in-graph-button-CDHxzS8B.js} +1 -1
- package/dist/assets/{orbit-map-C_xy4kYC.js → orbit-map-OV-GcUZl.js} +1 -1
- package/dist/assets/{overview-page-Dwg4uYe9.js → overview-page-Cw3pI34n.js} +1 -1
- package/dist/assets/{page-hero-DzEsy8i5.js → page-hero-DgnhI5es.js} +1 -1
- package/dist/assets/{pill-cluster-DcBUeEMT.js → pill-cluster-DIGkIvKN.js} +1 -1
- package/dist/assets/{preference-entity-handoff-button-BX2n07ob.js → preference-entity-handoff-button-LT_GBuqB.js} +1 -1
- package/dist/assets/{preferences-page-BSnwiWBt.js → preferences-page-Dkvz7nkU.js} +1 -1
- package/dist/assets/{project-collections-BR6YdlCZ.js → project-collections-BsAT8WYE.js} +1 -1
- package/dist/assets/{project-detail-page-DeYshcCb.js → project-detail-page-DsJUWg8k.js} +1 -1
- package/dist/assets/{project-management-hierarchy-page-Bhdt79Ea.js → project-management-hierarchy-page-CIy0wAp8.js} +1 -1
- package/dist/assets/{project-management-section-nav-DnXuWUfe.js → project-management-section-nav-ClB2S1FW.js} +1 -1
- package/dist/assets/{projects-page-BA9W0ZPk.js → projects-page-Da1bZLSH.js} +1 -1
- package/dist/assets/{psyche-behaviors-page-DpTj53GI.js → psyche-behaviors-page-D0uwf78o.js} +1 -1
- package/dist/assets/{psyche-flashcards-page-CV58hAJA.js → psyche-flashcards-page-e_qwwsOf.js} +1 -1
- package/dist/assets/{psyche-goal-map-page-C07CALFg.js → psyche-goal-map-page-BIY028Wx.js} +1 -1
- package/dist/assets/{psyche-graph-CP7mxfMP.js → psyche-graph-Y1UKALEm.js} +1 -1
- package/dist/assets/{psyche-metrics-page-CY8e9R0D.js → psyche-metrics-page-DDkGJzo_.js} +1 -1
- package/dist/assets/{psyche-mode-guide-page-DYt6AmHl.js → psyche-mode-guide-page-C7mD9uiv.js} +1 -1
- package/dist/assets/{psyche-modes-page-Dd77kTtJ.js → psyche-modes-page-RUdaOQWr.js} +1 -1
- package/dist/assets/{psyche-page-DNXZjIKp.js → psyche-page-D3FZy__c.js} +1 -1
- package/dist/assets/{psyche-patterns-page-DxGzpeT5.js → psyche-patterns-page-BSD35F41.js} +1 -1
- package/dist/assets/{psyche-questionnaire-builder-page-5EQctRHO.js → psyche-questionnaire-builder-page-BpgUTMgj.js} +1 -1
- package/dist/assets/{psyche-questionnaire-detail-page-W8nhUGAc.js → psyche-questionnaire-detail-page-DwjyjNhg.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-detail-page-DVwzSuqg.js → psyche-questionnaire-run-detail-page-mJ-DgeB-.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-page-BHResQgL.js → psyche-questionnaire-run-page-YuMBkH1G.js} +1 -1
- package/dist/assets/{psyche-questionnaires-page-DFTOXpyp.js → psyche-questionnaires-page-CNglToKh.js} +1 -1
- package/dist/assets/{psyche-report-detail-page-BqDE_tf7.js → psyche-report-detail-page-CV6tbLxz.js} +1 -1
- package/dist/assets/{psyche-reports-page-B75pDz0l.js → psyche-reports-page-BEOe8OPA.js} +1 -1
- package/dist/assets/{psyche-schemas-beliefs-page-BjSO4tYL.js → psyche-schemas-beliefs-page-KIRqmO8C.js} +1 -1
- package/dist/assets/{psyche-screen-time-page-B7lKf1g7.js → psyche-screen-time-page-DvXuwgU1.js} +1 -1
- package/dist/assets/{psyche-self-observation-page-C6RMThwc.js → psyche-self-observation-page-E6yDPBm1.js} +1 -1
- package/dist/assets/{psyche-values-page-1O158mIJ.js → psyche-values-page-CSLG7C6a.js} +1 -1
- package/dist/assets/{report-chain-fields-CyJ_VFY5.js → report-chain-fields-BYEp3tRr.js} +1 -1
- package/dist/assets/{rewards-page-sPlDYuVo.js → rewards-page-pAa_MIte.js} +1 -1
- package/dist/assets/{scheduling-rules-editor-DGgcBs1W.js → scheduling-rules-editor-BmGrjC9q.js} +1 -1
- package/dist/assets/{schema-badge-Do-YvNHm.js → schema-badge-IVJ4SoeC.js} +1 -1
- package/dist/assets/{select-menu-CAM7rMdO.js → select-menu-BE5AIdgO.js} +1 -1
- package/dist/assets/{settings-agents-page-BsZY71kz.js → settings-agents-page-hqI0IaNx.js} +1 -1
- package/dist/assets/{settings-bin-page-kB3jtHo_.js → settings-bin-page-2bPjFtZ3.js} +1 -1
- package/dist/assets/{settings-calendar-page-C-IGNk3_.js → settings-calendar-page-u_TfZJEh.js} +1 -1
- package/dist/assets/{settings-data-page-CFGSL9g3.js → settings-data-page-DSQ14F2i.js} +1 -1
- package/dist/assets/{settings-logs-page-C7e9FIN_.js → settings-logs-page-BU0CJhDM.js} +1 -1
- package/dist/assets/{settings-mobile-page-DzKeZQDM.js → settings-mobile-page-B1fQ61BB.js} +1 -1
- package/dist/assets/{settings-models-page-dFhaOV3E.js → settings-models-page-B0Dis_c_.js} +1 -1
- package/dist/assets/{settings-page-C0fSyYUx.js → settings-page-V4ibXIp9.js} +1 -1
- package/dist/assets/{settings-rewards-page-D-LuZHhv.js → settings-rewards-page-DeCGBNn5.js} +1 -1
- package/dist/assets/{settings-section-nav-kFFQSJEe.js → settings-section-nav-DV5umEkp.js} +1 -1
- package/dist/assets/{settings-users-page-CX797HPB.js → settings-users-page-BB8Dzd_P.js} +1 -1
- package/dist/assets/{settings-wiki-page-CWLAvcsf.js → settings-wiki-page-B0k0KRsU.js} +1 -1
- package/dist/assets/{sleep-page-QgBkKyk_.js → sleep-page-CPwUb-em.js} +1 -1
- package/dist/assets/{sports-page-C8tLMl7V.js → sports-page-Cl4vZVwh.js} +1 -1
- package/dist/assets/{strategies-page-CGgh-KXu.js → strategies-page-DhFXf-g3.js} +1 -1
- package/dist/assets/{strategy-detail-page-CnzqjjoD.js → strategy-detail-page-B2gotRKI.js} +1 -1
- package/dist/assets/{strategy-dialog-C6AThZ9L.js → strategy-dialog-DD1bbrRB.js} +1 -1
- package/dist/assets/{surface-CIDhCEsF.js → surface-98myBzix.js} +1 -1
- package/dist/assets/{task-detail-page-Dp0r_qZP.js → task-detail-page-nx4eQbMW.js} +1 -1
- package/dist/assets/{timebox-planning-dialog-B3uaSsWI.js → timebox-planning-dialog-DoZ9zUra.js} +1 -1
- package/dist/assets/{today-page-CTnMYrPi.js → today-page-7BH7Yne1.js} +1 -1
- package/dist/assets/{training-load-page-D0WB5_Tq.js → training-load-page-E82pNn1-.js} +1 -1
- package/dist/assets/{vitals-page-0vg8nqwj.js → vitals-page-D64WlwVv.js} +1 -1
- package/dist/assets/{weekly-review-page-CSSKlkbH.js → weekly-review-page-BkRxxm7Q.js} +1 -1
- package/dist/assets/weight-loss-page-DPbg7rTC.js +5 -0
- package/dist/assets/{wiki-article-markdown-CBFvfJx_.js → wiki-article-markdown-B0Q6082A.js} +1 -1
- package/dist/assets/{wiki-editor-page-CL1uxpih.js → wiki-editor-page-Tkb50wEA.js} +1 -1
- package/dist/assets/{wiki-ingest-history-page-XX8DeNCC.js → wiki-ingest-history-page-CcQzkZRr.js} +1 -1
- package/dist/assets/{wiki-ingest-modal-j-ftDmzp.js → wiki-ingest-modal-D6yft0Qb.js} +1 -1
- package/dist/assets/{wiki-page-B46TQYpy.js → wiki-page-DEND1jmD.js} +1 -1
- package/dist/assets/{workbench-flow-page-CicEuBKq.js → workbench-flow-page-CkNI03j_.js} +1 -1
- package/dist/assets/{workbench-page-tXezYLh_.js → workbench-page-W3zQpeWr.js} +1 -1
- package/dist/assets/{workout-detail-page-BTO5X0Of.js → workout-detail-page-BVSZv53z.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/server/server/src/app.js +2 -0
- package/dist/server/server/src/discovery-advertiser.js +5 -2
- package/dist/server/server/src/health-weight-loss.js +160 -10
- package/dist/server/server/src/services/devrage-scanner.js +948 -0
- package/dist/server/server/src/services/devrage.js +1 -1
- package/dist/server/src/lib/weight-loss-energy-model.js +64 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/forge-openclaw/SKILL.md +10 -0
- package/skills/forge-openclaw/entity_conversation_playbooks.md +33 -0
- package/skills/forge-openclaw/psyche_entity_playbooks.md +31 -0
- package/dist/assets/weight-loss-page-Dcr4wjjy.js +0 -5
|
@@ -4,6 +4,7 @@ import { getDatabase, runInTransaction } from "./db.js";
|
|
|
4
4
|
import { getSettings } from "./repositories/settings.js";
|
|
5
5
|
import { getDefaultUser, resolveUserForMutation } from "./repositories/users.js";
|
|
6
6
|
import { readEncryptedSecret } from "./repositories/calendar.js";
|
|
7
|
+
import { hallNiddkWeeklyRateKgToDailyEnergyAdjustment } from "../../src/lib/weight-loss-energy-model.js";
|
|
7
8
|
const optionalNumberSchema = z
|
|
8
9
|
.union([z.coerce.number().finite(), z.null()])
|
|
9
10
|
.optional();
|
|
@@ -269,12 +270,31 @@ function average(values) {
|
|
|
269
270
|
}
|
|
270
271
|
return real.reduce((sum, value) => sum + value, 0) / real.length;
|
|
271
272
|
}
|
|
272
|
-
function
|
|
273
|
+
function median(values) {
|
|
274
|
+
const sorted = values
|
|
275
|
+
.filter((value) => Number.isFinite(value))
|
|
276
|
+
.sort((left, right) => left - right);
|
|
277
|
+
if (sorted.length === 0) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const middle = Math.floor(sorted.length / 2);
|
|
281
|
+
if (sorted.length % 2 === 1) {
|
|
282
|
+
return sorted[middle] ?? null;
|
|
283
|
+
}
|
|
284
|
+
return ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2;
|
|
285
|
+
}
|
|
286
|
+
function metricRecord(metrics, key) {
|
|
273
287
|
const metric = metrics[key];
|
|
274
288
|
if (!metric || typeof metric !== "object") {
|
|
275
289
|
return null;
|
|
276
290
|
}
|
|
277
|
-
|
|
291
|
+
return metric;
|
|
292
|
+
}
|
|
293
|
+
function metricTotal(metrics, key) {
|
|
294
|
+
const record = metricRecord(metrics, key);
|
|
295
|
+
if (!record) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
278
298
|
for (const field of ["total", "average", "latest"]) {
|
|
279
299
|
const value = record[field];
|
|
280
300
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -283,6 +303,31 @@ function metricTotal(metrics, key) {
|
|
|
283
303
|
}
|
|
284
304
|
return null;
|
|
285
305
|
}
|
|
306
|
+
function metricSampleCount(metrics, key) {
|
|
307
|
+
const value = metricRecord(metrics, key)?.sampleCount;
|
|
308
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
309
|
+
}
|
|
310
|
+
function metricLatestSampleAt(metrics, key) {
|
|
311
|
+
const value = metricRecord(metrics, key)?.latestSampleAt;
|
|
312
|
+
return typeof value === "string" && value.trim().length > 0
|
|
313
|
+
? value.trim()
|
|
314
|
+
: null;
|
|
315
|
+
}
|
|
316
|
+
function sampleHourOfDay(value) {
|
|
317
|
+
if (!value) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const match = value.match(/T(\d{2}):/);
|
|
321
|
+
if (match?.[1]) {
|
|
322
|
+
const parsed = Number(match[1]);
|
|
323
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
324
|
+
}
|
|
325
|
+
const date = new Date(value);
|
|
326
|
+
if (Number.isNaN(date.getTime())) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
return date.getHours();
|
|
330
|
+
}
|
|
286
331
|
function parsePlanNoteNumber(notes, key) {
|
|
287
332
|
if (!notes) {
|
|
288
333
|
return null;
|
|
@@ -292,6 +337,30 @@ function parsePlanNoteNumber(notes, key) {
|
|
|
292
337
|
const parsed = Number(match?.[1]?.trim());
|
|
293
338
|
return Number.isFinite(parsed) ? parsed : null;
|
|
294
339
|
}
|
|
340
|
+
function parsePlanNoteText(notes, key) {
|
|
341
|
+
if (!notes) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
345
|
+
const match = notes.match(new RegExp(`${escapedKey}=([^;]+)`));
|
|
346
|
+
return match?.[1]?.trim() ?? null;
|
|
347
|
+
}
|
|
348
|
+
function mifflinStJeorRestingKcal(input) {
|
|
349
|
+
if ((input.sex !== "male" && input.sex !== "female") ||
|
|
350
|
+
input.ageYears == null ||
|
|
351
|
+
input.ageYears <= 0 ||
|
|
352
|
+
input.heightCm == null ||
|
|
353
|
+
input.heightCm <= 0 ||
|
|
354
|
+
input.weightKg == null ||
|
|
355
|
+
input.weightKg <= 0) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const sexAdjustment = input.sex === "male" ? 5 : -161;
|
|
359
|
+
return (10 * input.weightKg +
|
|
360
|
+
6.25 * input.heightCm -
|
|
361
|
+
5 * input.ageYears +
|
|
362
|
+
sexAdjustment);
|
|
363
|
+
}
|
|
295
364
|
function estimateStepActiveCaloriesKcal(input) {
|
|
296
365
|
if (input.stepCount == null ||
|
|
297
366
|
input.stepCount <= 0 ||
|
|
@@ -344,6 +413,8 @@ function buildStoredEnergyModel(input) {
|
|
|
344
413
|
dateKey: row.date_key,
|
|
345
414
|
activeEnergyKcal: metricTotal(metrics, "activeEnergyBurned"),
|
|
346
415
|
restingEnergyKcal: metricTotal(metrics, "basalEnergyBurned"),
|
|
416
|
+
restingSampleCount: metricSampleCount(metrics, "basalEnergyBurned"),
|
|
417
|
+
restingLatestSampleAt: metricLatestSampleAt(metrics, "basalEnergyBurned"),
|
|
347
418
|
exerciseMinutes: metricTotal(metrics, "appleExerciseTime"),
|
|
348
419
|
stepCount: metricTotal(metrics, "stepCount")
|
|
349
420
|
};
|
|
@@ -396,7 +467,59 @@ function buildStoredEnergyModel(input) {
|
|
|
396
467
|
.get(input.userId, input.dayStartAt, input.dayEndAt)
|
|
397
468
|
: null;
|
|
398
469
|
const activeEnergyAverage = average(dailyHealthKit.map((day) => day.activeEnergyKcal));
|
|
399
|
-
const
|
|
470
|
+
const restingEvidenceDays = dailyHealthKit.filter((day) => day.restingEnergyKcal != null);
|
|
471
|
+
const restingExclusionReasons = [];
|
|
472
|
+
const qualifiedRestingDays = restingEvidenceDays.filter((day) => {
|
|
473
|
+
const reasons = [];
|
|
474
|
+
if (day.dateKey >= todayKey) {
|
|
475
|
+
reasons.push("current_day_or_future_day");
|
|
476
|
+
}
|
|
477
|
+
if ((day.restingSampleCount ?? 0) < 24) {
|
|
478
|
+
reasons.push(`sample_count_${day.restingSampleCount ?? 0}_below_24`);
|
|
479
|
+
}
|
|
480
|
+
const latestSampleHour = sampleHourOfDay(day.restingLatestSampleAt);
|
|
481
|
+
if (latestSampleHour == null) {
|
|
482
|
+
reasons.push("missing_latest_basal_sample");
|
|
483
|
+
}
|
|
484
|
+
else if (latestSampleHour < 20) {
|
|
485
|
+
reasons.push(`latest_basal_sample_hour_${latestSampleHour}_before_20`);
|
|
486
|
+
}
|
|
487
|
+
if (input.formulaRestingKcal != null && day.restingEnergyKcal != null) {
|
|
488
|
+
const lowThreshold = Math.max(input.formulaRestingKcal * 0.75, 1000);
|
|
489
|
+
if (day.restingEnergyKcal < lowThreshold) {
|
|
490
|
+
reasons.push(`basal_${round(day.restingEnergyKcal, 0)}_below_${round(lowThreshold, 0)}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (reasons.length > 0) {
|
|
494
|
+
restingExclusionReasons.push(`${day.dateKey}: ${reasons.join(",")}`);
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
return true;
|
|
498
|
+
});
|
|
499
|
+
const wearableRestingKcal = median(qualifiedRestingDays
|
|
500
|
+
.map((day) => day.restingEnergyKcal)
|
|
501
|
+
.filter((value) => value != null));
|
|
502
|
+
const chosenRestingKcal = input.formulaRestingKcal ?? input.savedRestingKcal ?? null;
|
|
503
|
+
const chosenRestingSource = input.formulaRestingKcal != null
|
|
504
|
+
? "mifflin_profile_baseline"
|
|
505
|
+
: input.savedRestingKcal != null
|
|
506
|
+
? "saved_plan_legacy"
|
|
507
|
+
: null;
|
|
508
|
+
const restingConfidence = (() => {
|
|
509
|
+
if (input.formulaRestingKcal == null && input.savedRestingKcal != null) {
|
|
510
|
+
return "low";
|
|
511
|
+
}
|
|
512
|
+
if (input.formulaRestingKcal == null) {
|
|
513
|
+
return "low";
|
|
514
|
+
}
|
|
515
|
+
if (wearableRestingKcal != null &&
|
|
516
|
+
Math.abs(wearableRestingKcal - input.formulaRestingKcal) /
|
|
517
|
+
input.formulaRestingKcal >
|
|
518
|
+
0.15) {
|
|
519
|
+
return "review";
|
|
520
|
+
}
|
|
521
|
+
return qualifiedRestingDays.length > 0 ? "high" : "medium";
|
|
522
|
+
})();
|
|
400
523
|
const workoutEnergyAverage = average([...workoutByDay.values()]);
|
|
401
524
|
const movementCaloriesAverage = average([...movementByDay.values()]);
|
|
402
525
|
const fallbackActiveBurn = workoutEnergyAverage != null || movementCaloriesAverage != null
|
|
@@ -477,13 +600,15 @@ function buildStoredEnergyModel(input) {
|
|
|
477
600
|
const todayActiveCalories = input.dailyActiveOverride?.activeCaloriesKcal ??
|
|
478
601
|
todayObservedActiveCalories ??
|
|
479
602
|
baselineActiveCalories;
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
|
|
603
|
+
const todayActiveSurplusKcal = Math.max(0, todayActiveCalories - baselineActiveCalories);
|
|
604
|
+
const todayActivityBufferKcal = todayActiveSurplusKcal * input.activityEatBackFraction;
|
|
605
|
+
const todayTargetAdjustmentKcal = todayActivityBufferKcal;
|
|
606
|
+
const estimatedTdeeKcal = activeBurnKcal != null && chosenRestingKcal != null
|
|
607
|
+
? round(activeBurnKcal + chosenRestingKcal, 0)
|
|
483
608
|
: input.inferredTdee;
|
|
484
609
|
const hasHealthKitDailyActiveEnergy = activeEnergyAverage != null;
|
|
485
610
|
const hasHealthKitEnergy = hasHealthKitDailyActiveEnergy ||
|
|
486
|
-
|
|
611
|
+
wearableRestingKcal != null ||
|
|
487
612
|
workoutEnergyAverage != null;
|
|
488
613
|
const hasMovementEnergy = movementCaloriesAverage != null;
|
|
489
614
|
const sourceConfidence = activeEnergyAverage != null
|
|
@@ -493,7 +618,18 @@ function buildStoredEnergyModel(input) {
|
|
|
493
618
|
: "target_inference_only";
|
|
494
619
|
return {
|
|
495
620
|
activeEnergyCalories: activeEnergyAverage != null ? round(activeEnergyAverage, 0) : null,
|
|
496
|
-
restingEnergyCalories:
|
|
621
|
+
restingEnergyCalories: chosenRestingKcal != null ? round(chosenRestingKcal, 0) : null,
|
|
622
|
+
formulaRestingKcal: input.formulaRestingKcal != null
|
|
623
|
+
? round(input.formulaRestingKcal, 0)
|
|
624
|
+
: null,
|
|
625
|
+
wearableRestingKcal: wearableRestingKcal != null ? round(wearableRestingKcal, 0) : null,
|
|
626
|
+
wearableRestingSource: wearableRestingKcal != null ? "healthkit_basal_energy" : null,
|
|
627
|
+
wearableRestingDayCount: restingEvidenceDays.length,
|
|
628
|
+
wearableRestingCoverageQualifiedDayCount: qualifiedRestingDays.length,
|
|
629
|
+
chosenRestingKcal: chosenRestingKcal != null ? round(chosenRestingKcal, 0) : null,
|
|
630
|
+
chosenRestingSource,
|
|
631
|
+
restingConfidence,
|
|
632
|
+
restingExclusionReasons,
|
|
497
633
|
wearableConfidence: hasHealthKitEnergy
|
|
498
634
|
? "measured_directional"
|
|
499
635
|
: "directional",
|
|
@@ -507,6 +643,9 @@ function buildStoredEnergyModel(input) {
|
|
|
507
643
|
: null,
|
|
508
644
|
todayActiveCaloriesSource: todayActiveSource,
|
|
509
645
|
todayTargetAdjustmentKcal: round(todayTargetAdjustmentKcal, 0),
|
|
646
|
+
todayActiveSurplusKcal: round(todayActiveSurplusKcal, 0),
|
|
647
|
+
todayActivityBufferKcal: round(todayActivityBufferKcal, 0),
|
|
648
|
+
activityEatBackFraction: round(input.activityEatBackFraction, 2),
|
|
510
649
|
todayWorkoutEnergyKcal: todayWorkoutEnergy != null ? round(todayWorkoutEnergy, 0) : null,
|
|
511
650
|
todayMovementCaloriesKcal: todayMovementCalories != null ? round(todayMovementCalories, 0) : null,
|
|
512
651
|
todayHealthKitActiveCaloriesKcal: todayHealthKitActive != null ? round(todayHealthKitActive, 0) : null,
|
|
@@ -1539,9 +1678,17 @@ export function getWeightLossViewData(userIds, options = {}) {
|
|
|
1539
1678
|
? round(recentTotals.calories / recentTrackedDays, 0)
|
|
1540
1679
|
: 0;
|
|
1541
1680
|
const inferredTdee = target.calorieTarget != null
|
|
1542
|
-
? round(target.calorieTarget +
|
|
1681
|
+
? round(target.calorieTarget +
|
|
1682
|
+
Math.abs(hallNiddkWeeklyRateKgToDailyEnergyAdjustment(target.weeklyRateGoalKg) ?? 0), 0)
|
|
1543
1683
|
: null;
|
|
1544
1684
|
const defaultActiveCalories = parsePlanNoteNumber(target.notes, "activity_kcal");
|
|
1685
|
+
const formulaRestingKcal = mifflinStJeorRestingKcal({
|
|
1686
|
+
sex: parsePlanNoteText(target.notes, "sex"),
|
|
1687
|
+
ageYears: parsePlanNoteNumber(target.notes, "age_years"),
|
|
1688
|
+
heightCm: parsePlanNoteNumber(target.notes, "height_cm"),
|
|
1689
|
+
weightKg: weightTrend.latestWeightKg
|
|
1690
|
+
});
|
|
1691
|
+
const activityEatBackFraction = Math.min(1, Math.max(0, parsePlanNoteNumber(target.notes, "eat_back_fraction") ?? 0.5));
|
|
1545
1692
|
const dailyActiveOverride = getDailyEnergyOverride(userId, todayKey);
|
|
1546
1693
|
const energyModel = buildStoredEnergyModel({
|
|
1547
1694
|
userId,
|
|
@@ -1554,7 +1701,10 @@ export function getWeightLossViewData(userIds, options = {}) {
|
|
|
1554
1701
|
recentFoodLogDayCount: recentTrackedDays,
|
|
1555
1702
|
defaultActiveCalories,
|
|
1556
1703
|
latestWeightKg: weightTrend.latestWeightKg,
|
|
1557
|
-
dailyActiveOverride
|
|
1704
|
+
dailyActiveOverride,
|
|
1705
|
+
formulaRestingKcal,
|
|
1706
|
+
savedRestingKcal: parsePlanNoteNumber(target.notes, "resting_kcal"),
|
|
1707
|
+
activityEatBackFraction
|
|
1558
1708
|
});
|
|
1559
1709
|
const todayTargetCalories = Math.max(0, round(target.calorieTarget + energyModel.todayTargetAdjustmentKcal, 0));
|
|
1560
1710
|
const todayLedger = buildTodayLedger(logs, target, todayKey, todayTargetCalories, energyModel.todayTargetAdjustmentKcal, energyModel.todayActiveCaloriesSource);
|