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.
Files changed (112) hide show
  1. package/dist/assets/{activity-page-DWHZ8_sJ.js → activity-page-BdeoV3N4.js} +1 -1
  2. package/dist/assets/{ai-surface-workspace-DPygfyhc.js → ai-surface-workspace-BCbQUekv.js} +1 -1
  3. package/dist/assets/{atlas-panel-D261RUQF.js → atlas-panel-DTnRBOZx.js} +1 -1
  4. package/dist/assets/{calendar-page-BQbJkdPF.js → calendar-page-YDexXy_e.js} +1 -1
  5. package/dist/assets/{calendar-rules-BoFsuvZ8.js → calendar-rules-B_aOcMi3.js} +1 -1
  6. package/dist/assets/{calendar-week-toolbar-LetevPI7.js → calendar-week-toolbar-BTbIzq3e.js} +1 -1
  7. package/dist/assets/{companion-sync-lab-page-Bid-4B8W.js → companion-sync-lab-page-DKouMut9.js} +1 -1
  8. package/dist/assets/{daily-metrics-dashboard-CqnGJNeI.js → daily-metrics-dashboard-B3UCGG1t.js} +1 -1
  9. package/dist/assets/{entity-note-count-link-VMURwBMi.js → entity-note-count-link-DUxobQUt.js} +1 -1
  10. package/dist/assets/{entity-notes-surface-DGXcyNzo.js → entity-notes-surface-BdHBn8rx.js} +1 -1
  11. package/dist/assets/{execution-board-BGf6zZqJ.js → execution-board-R5-oyf-Z.js} +1 -1
  12. package/dist/assets/{faceted-token-search-CAsZrhZ4.js → faceted-token-search-DtO6OUwQ.js} +1 -1
  13. package/dist/assets/{flagship-signal-deck-DJsq3jn2.js → flagship-signal-deck-B9k46sWA.js} +1 -1
  14. package/dist/assets/{floating-action-menu-B3tQStUN.js → floating-action-menu-DBzfnJOx.js} +1 -1
  15. package/dist/assets/{goal-detail-page-DBs-9wpk.js → goal-detail-page-Mr_gnZ2l.js} +1 -1
  16. package/dist/assets/{goals-page-CPmhjsG-.js → goals-page-BG7FuqK1.js} +1 -1
  17. package/dist/assets/{habits-page-DkW8zT6_.js → habits-page-CGdaOqL3.js} +1 -1
  18. package/dist/assets/{index-BhkubYaC.js → index-BP9__l6C.js} +2 -2
  19. package/dist/assets/{insight-flow-dialog-BvgRjkPi.js → insight-flow-dialog-BUv06Vn-.js} +1 -1
  20. package/dist/assets/{insights-page-Dtij6pm5.js → insights-page-BgD1_1we.js} +1 -1
  21. package/dist/assets/{kanban-page-R1x5hUU-.js → kanban-page-DvZSN-Bi.js} +1 -1
  22. package/dist/assets/{knowledge-graph-page-BRBB5Vvz.js → knowledge-graph-page-BXWXtPvo.js} +1 -1
  23. package/dist/assets/{life-force-page-DGPWKM9I.js → life-force-page-CwjHvpzu.js} +1 -1
  24. package/dist/assets/{life-force-workspace-DoRIQoU_.js → life-force-workspace-Ct70SsNQ.js} +1 -1
  25. package/dist/assets/{metric-tile-NJiFcFxW.js → metric-tile-DCxLxNli.js} +1 -1
  26. package/dist/assets/{movement-page-Dk8aV737.js → movement-page-C06ebiYk.js} +1 -1
  27. package/dist/assets/{note-markdown-CZHjJDve.js → note-markdown-3wB52NOn.js} +1 -1
  28. package/dist/assets/{note-tags-input-DFpxZHPg.js → note-tags-input-Blg5Gqz_.js} +1 -1
  29. package/dist/assets/{notes-page-r3kymlqg.js → notes-page-CSkjizyK.js} +1 -1
  30. package/dist/assets/{open-in-graph-button-B_XHtHZD.js → open-in-graph-button-CDHxzS8B.js} +1 -1
  31. package/dist/assets/{orbit-map-C_xy4kYC.js → orbit-map-OV-GcUZl.js} +1 -1
  32. package/dist/assets/{overview-page-Dwg4uYe9.js → overview-page-Cw3pI34n.js} +1 -1
  33. package/dist/assets/{page-hero-DzEsy8i5.js → page-hero-DgnhI5es.js} +1 -1
  34. package/dist/assets/{pill-cluster-DcBUeEMT.js → pill-cluster-DIGkIvKN.js} +1 -1
  35. package/dist/assets/{preference-entity-handoff-button-BX2n07ob.js → preference-entity-handoff-button-LT_GBuqB.js} +1 -1
  36. package/dist/assets/{preferences-page-BSnwiWBt.js → preferences-page-Dkvz7nkU.js} +1 -1
  37. package/dist/assets/{project-collections-BR6YdlCZ.js → project-collections-BsAT8WYE.js} +1 -1
  38. package/dist/assets/{project-detail-page-DeYshcCb.js → project-detail-page-DsJUWg8k.js} +1 -1
  39. package/dist/assets/{project-management-hierarchy-page-Bhdt79Ea.js → project-management-hierarchy-page-CIy0wAp8.js} +1 -1
  40. package/dist/assets/{project-management-section-nav-DnXuWUfe.js → project-management-section-nav-ClB2S1FW.js} +1 -1
  41. package/dist/assets/{projects-page-BA9W0ZPk.js → projects-page-Da1bZLSH.js} +1 -1
  42. package/dist/assets/{psyche-behaviors-page-DpTj53GI.js → psyche-behaviors-page-D0uwf78o.js} +1 -1
  43. package/dist/assets/{psyche-flashcards-page-CV58hAJA.js → psyche-flashcards-page-e_qwwsOf.js} +1 -1
  44. package/dist/assets/{psyche-goal-map-page-C07CALFg.js → psyche-goal-map-page-BIY028Wx.js} +1 -1
  45. package/dist/assets/{psyche-graph-CP7mxfMP.js → psyche-graph-Y1UKALEm.js} +1 -1
  46. package/dist/assets/{psyche-metrics-page-CY8e9R0D.js → psyche-metrics-page-DDkGJzo_.js} +1 -1
  47. package/dist/assets/{psyche-mode-guide-page-DYt6AmHl.js → psyche-mode-guide-page-C7mD9uiv.js} +1 -1
  48. package/dist/assets/{psyche-modes-page-Dd77kTtJ.js → psyche-modes-page-RUdaOQWr.js} +1 -1
  49. package/dist/assets/{psyche-page-DNXZjIKp.js → psyche-page-D3FZy__c.js} +1 -1
  50. package/dist/assets/{psyche-patterns-page-DxGzpeT5.js → psyche-patterns-page-BSD35F41.js} +1 -1
  51. package/dist/assets/{psyche-questionnaire-builder-page-5EQctRHO.js → psyche-questionnaire-builder-page-BpgUTMgj.js} +1 -1
  52. package/dist/assets/{psyche-questionnaire-detail-page-W8nhUGAc.js → psyche-questionnaire-detail-page-DwjyjNhg.js} +1 -1
  53. package/dist/assets/{psyche-questionnaire-run-detail-page-DVwzSuqg.js → psyche-questionnaire-run-detail-page-mJ-DgeB-.js} +1 -1
  54. package/dist/assets/{psyche-questionnaire-run-page-BHResQgL.js → psyche-questionnaire-run-page-YuMBkH1G.js} +1 -1
  55. package/dist/assets/{psyche-questionnaires-page-DFTOXpyp.js → psyche-questionnaires-page-CNglToKh.js} +1 -1
  56. package/dist/assets/{psyche-report-detail-page-BqDE_tf7.js → psyche-report-detail-page-CV6tbLxz.js} +1 -1
  57. package/dist/assets/{psyche-reports-page-B75pDz0l.js → psyche-reports-page-BEOe8OPA.js} +1 -1
  58. package/dist/assets/{psyche-schemas-beliefs-page-BjSO4tYL.js → psyche-schemas-beliefs-page-KIRqmO8C.js} +1 -1
  59. package/dist/assets/{psyche-screen-time-page-B7lKf1g7.js → psyche-screen-time-page-DvXuwgU1.js} +1 -1
  60. package/dist/assets/{psyche-self-observation-page-C6RMThwc.js → psyche-self-observation-page-E6yDPBm1.js} +1 -1
  61. package/dist/assets/{psyche-values-page-1O158mIJ.js → psyche-values-page-CSLG7C6a.js} +1 -1
  62. package/dist/assets/{report-chain-fields-CyJ_VFY5.js → report-chain-fields-BYEp3tRr.js} +1 -1
  63. package/dist/assets/{rewards-page-sPlDYuVo.js → rewards-page-pAa_MIte.js} +1 -1
  64. package/dist/assets/{scheduling-rules-editor-DGgcBs1W.js → scheduling-rules-editor-BmGrjC9q.js} +1 -1
  65. package/dist/assets/{schema-badge-Do-YvNHm.js → schema-badge-IVJ4SoeC.js} +1 -1
  66. package/dist/assets/{select-menu-CAM7rMdO.js → select-menu-BE5AIdgO.js} +1 -1
  67. package/dist/assets/{settings-agents-page-BsZY71kz.js → settings-agents-page-hqI0IaNx.js} +1 -1
  68. package/dist/assets/{settings-bin-page-kB3jtHo_.js → settings-bin-page-2bPjFtZ3.js} +1 -1
  69. package/dist/assets/{settings-calendar-page-C-IGNk3_.js → settings-calendar-page-u_TfZJEh.js} +1 -1
  70. package/dist/assets/{settings-data-page-CFGSL9g3.js → settings-data-page-DSQ14F2i.js} +1 -1
  71. package/dist/assets/{settings-logs-page-C7e9FIN_.js → settings-logs-page-BU0CJhDM.js} +1 -1
  72. package/dist/assets/{settings-mobile-page-DzKeZQDM.js → settings-mobile-page-B1fQ61BB.js} +1 -1
  73. package/dist/assets/{settings-models-page-dFhaOV3E.js → settings-models-page-B0Dis_c_.js} +1 -1
  74. package/dist/assets/{settings-page-C0fSyYUx.js → settings-page-V4ibXIp9.js} +1 -1
  75. package/dist/assets/{settings-rewards-page-D-LuZHhv.js → settings-rewards-page-DeCGBNn5.js} +1 -1
  76. package/dist/assets/{settings-section-nav-kFFQSJEe.js → settings-section-nav-DV5umEkp.js} +1 -1
  77. package/dist/assets/{settings-users-page-CX797HPB.js → settings-users-page-BB8Dzd_P.js} +1 -1
  78. package/dist/assets/{settings-wiki-page-CWLAvcsf.js → settings-wiki-page-B0k0KRsU.js} +1 -1
  79. package/dist/assets/{sleep-page-QgBkKyk_.js → sleep-page-CPwUb-em.js} +1 -1
  80. package/dist/assets/{sports-page-C8tLMl7V.js → sports-page-Cl4vZVwh.js} +1 -1
  81. package/dist/assets/{strategies-page-CGgh-KXu.js → strategies-page-DhFXf-g3.js} +1 -1
  82. package/dist/assets/{strategy-detail-page-CnzqjjoD.js → strategy-detail-page-B2gotRKI.js} +1 -1
  83. package/dist/assets/{strategy-dialog-C6AThZ9L.js → strategy-dialog-DD1bbrRB.js} +1 -1
  84. package/dist/assets/{surface-CIDhCEsF.js → surface-98myBzix.js} +1 -1
  85. package/dist/assets/{task-detail-page-Dp0r_qZP.js → task-detail-page-nx4eQbMW.js} +1 -1
  86. package/dist/assets/{timebox-planning-dialog-B3uaSsWI.js → timebox-planning-dialog-DoZ9zUra.js} +1 -1
  87. package/dist/assets/{today-page-CTnMYrPi.js → today-page-7BH7Yne1.js} +1 -1
  88. package/dist/assets/{training-load-page-D0WB5_Tq.js → training-load-page-E82pNn1-.js} +1 -1
  89. package/dist/assets/{vitals-page-0vg8nqwj.js → vitals-page-D64WlwVv.js} +1 -1
  90. package/dist/assets/{weekly-review-page-CSSKlkbH.js → weekly-review-page-BkRxxm7Q.js} +1 -1
  91. package/dist/assets/weight-loss-page-DPbg7rTC.js +5 -0
  92. package/dist/assets/{wiki-article-markdown-CBFvfJx_.js → wiki-article-markdown-B0Q6082A.js} +1 -1
  93. package/dist/assets/{wiki-editor-page-CL1uxpih.js → wiki-editor-page-Tkb50wEA.js} +1 -1
  94. package/dist/assets/{wiki-ingest-history-page-XX8DeNCC.js → wiki-ingest-history-page-CcQzkZRr.js} +1 -1
  95. package/dist/assets/{wiki-ingest-modal-j-ftDmzp.js → wiki-ingest-modal-D6yft0Qb.js} +1 -1
  96. package/dist/assets/{wiki-page-B46TQYpy.js → wiki-page-DEND1jmD.js} +1 -1
  97. package/dist/assets/{workbench-flow-page-CicEuBKq.js → workbench-flow-page-CkNI03j_.js} +1 -1
  98. package/dist/assets/{workbench-page-tXezYLh_.js → workbench-page-W3zQpeWr.js} +1 -1
  99. package/dist/assets/{workout-detail-page-BTO5X0Of.js → workout-detail-page-BVSZv53z.js} +1 -1
  100. package/dist/index.html +1 -1
  101. package/dist/server/server/src/app.js +2 -0
  102. package/dist/server/server/src/discovery-advertiser.js +5 -2
  103. package/dist/server/server/src/health-weight-loss.js +160 -10
  104. package/dist/server/server/src/services/devrage-scanner.js +948 -0
  105. package/dist/server/server/src/services/devrage.js +1 -1
  106. package/dist/server/src/lib/weight-loss-energy-model.js +64 -0
  107. package/openclaw.plugin.json +1 -1
  108. package/package.json +1 -1
  109. package/skills/forge-openclaw/SKILL.md +10 -0
  110. package/skills/forge-openclaw/entity_conversation_playbooks.md +33 -0
  111. package/skills/forge-openclaw/psyche_entity_playbooks.md +31 -0
  112. 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 metricTotal(metrics, key) {
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
- const record = metric;
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 restingEnergyAverage = average(dailyHealthKit.map((day) => day.restingEnergyKcal));
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 todayTargetAdjustmentKcal = todayActiveCalories - baselineActiveCalories;
481
- const estimatedTdeeKcal = activeBurnKcal != null && restingEnergyAverage != null
482
- ? round(activeBurnKcal + restingEnergyAverage, 0)
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
- restingEnergyAverage != null ||
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: restingEnergyAverage != null ? round(restingEnergyAverage, 0) : null,
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 + Math.abs(n(target.weeklyRateGoalKg)) * 1100, 0)
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);