forge-openclaw-plugin 0.3.5 → 0.3.8

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 (157) hide show
  1. package/dist/assets/{action-bar-DBZ38L_6.js → action-bar-BFjWjRIM.js} +1 -1
  2. package/dist/assets/{activity-page-BJxUR9bD.js → activity-page-D-6yBWuZ.js} +1 -1
  3. package/dist/assets/{ai-surface-workspace-ehzBjTsW.js → ai-surface-workspace-BEfo9bRO.js} +1 -1
  4. package/dist/assets/{atlas-panel-BFUeVT69.js → atlas-panel-BfMyJXxQ.js} +1 -1
  5. package/dist/assets/{board-CLOHbg6t.js → board-CuxQRKPJ.js} +1 -1
  6. package/dist/assets/{calendar-page-Bg8W-YQ-.js → calendar-page-D4tQNJ2V.js} +1 -1
  7. package/dist/assets/{calendar-rules-9XQLoI96.js → calendar-rules-C-6O_uGU.js} +1 -1
  8. package/dist/assets/{calendar-week-toolbar-BeYnx1pE.js → calendar-week-toolbar-_NzeKsYx.js} +1 -1
  9. package/dist/assets/{charts-DwTguE_x.js → charts-BzT4pUPg.js} +1 -1
  10. package/dist/assets/{companion-sync-lab-page-BRKYkIrs.js → companion-sync-lab-page-D1Oqsf6M.js} +1 -1
  11. package/dist/assets/{daily-metrics-dashboard-Jt0nAHU5.js → daily-metrics-dashboard-DtE3pVOl.js} +1 -1
  12. package/dist/assets/date-keys-BnZV4PNO.js +1 -0
  13. package/dist/assets/{define-workbench-box-5h-dyvJY.js → define-workbench-box-D-32C8nM.js} +1 -1
  14. package/dist/assets/{entity-link-multiselect-Bb4De_e3.js → entity-link-multiselect-DcCvkesQ.js} +1 -1
  15. package/dist/assets/{entity-note-count-link-BzWnsOmI.js → entity-note-count-link-Cjsk5oT2.js} +1 -1
  16. package/dist/assets/{entity-notes-surface-CagOwdng.js → entity-notes-surface-DQQPLjxd.js} +1 -1
  17. package/dist/assets/{execution-board-DTmAtmqZ.js → execution-board-agWQbN-y.js} +1 -1
  18. package/dist/assets/{faceted-token-search-DJPRm9AY.js → faceted-token-search-DldM3-ru.js} +1 -1
  19. package/dist/assets/{flagship-signal-deck-CJbGZF7I.js → flagship-signal-deck-BlLYW9Kz.js} +1 -1
  20. package/dist/assets/{floating-action-menu-K77jh8XZ.js → floating-action-menu-D9-psbha.js} +1 -1
  21. package/dist/assets/{forms-C5d5hTf2.js → forms-D1qJ3oOP.js} +1 -1
  22. package/dist/assets/{generic-node-view-p5ePSFuG.js → generic-node-view-CcepUVhP.js} +1 -1
  23. package/dist/assets/{goal-detail-page-DGu_khEK.js → goal-detail-page-DP1n5-Hk.js} +1 -1
  24. package/dist/assets/{goal-dialog-BWD7cOv9.js → goal-dialog-Oxx8WqbZ.js} +1 -1
  25. package/dist/assets/{goals-page-Bgj3sj0f.js → goals-page-CUt1a4Y2.js} +1 -1
  26. package/dist/assets/{graph-Cd5WF3lw.js → graph-BF4IsheG.js} +1 -1
  27. package/dist/assets/{habits-page-Ctut1tuX.js → habits-page-5REbWAlo.js} +1 -1
  28. package/dist/assets/{health-boxes-Ie3horXx.js → health-boxes-sHNML3tm.js} +1 -1
  29. package/dist/assets/index-CQ5r7ZUz.js +2 -0
  30. package/dist/assets/index-FxgNSuZX.css +1 -0
  31. package/dist/assets/{inline-note-fields-DE6WM9uM.js → inline-note-fields-Bql_KfR9.js} +1 -1
  32. package/dist/assets/{insight-flow-dialog-XL8I74eJ.js → insight-flow-dialog-CN-CMSB7.js} +1 -1
  33. package/dist/assets/{insights-page-Bz1FLbp5.js → insights-page-B1u6ONtQ.js} +1 -1
  34. package/dist/assets/{kanban-boxes-BBziel7P.js → kanban-boxes-DB1kuUlY.js} +1 -1
  35. package/dist/assets/{kanban-page-DdQP73I3.js → kanban-page-BBW9_vMu.js} +1 -1
  36. package/dist/assets/{knowledge-graph-page-DdHWj4Dj.js → knowledge-graph-page-CoJaydZb.js} +1 -1
  37. package/dist/assets/{life-force-page-BRN-93cI.js → life-force-page-DBYbA1GF.js} +1 -1
  38. package/dist/assets/{life-force-workspace-BowvP5R4.js → life-force-workspace-BiD9xOEt.js} +1 -1
  39. package/dist/assets/{maps-D0Mm6WPG.js → maps-BTVHALP8.js} +1 -1
  40. package/dist/assets/{metric-tile-B6aJueRo.js → metric-tile-CuP9DOYm.js} +1 -1
  41. package/dist/assets/{motion-DwjmC9aq.js → motion-DcgUnXhY.js} +1 -1
  42. package/dist/assets/{movement-boxes-5cjWjIdR.js → movement-boxes-DZg_qPPg.js} +1 -1
  43. package/dist/assets/{movement-page-Dy53RWtB.js → movement-page-CmwsQGR_.js} +1 -1
  44. package/dist/assets/{note-markdown-CvEQCfoi.js → note-markdown-B82ncnFt.js} +1 -1
  45. package/dist/assets/{note-tags-input-Cg5zBXos.js → note-tags-input-C_x5WdK5.js} +1 -1
  46. package/dist/assets/{notes-boxes-CgZyf7mV.js → notes-boxes-BEFlp9yd.js} +1 -1
  47. package/dist/assets/{notes-page-Cbdcv0Ej.js → notes-page-B6Vl-GPf.js} +1 -1
  48. package/dist/assets/{open-in-graph-button-D31ZOEhA.js → open-in-graph-button-C-bJekoH.js} +1 -1
  49. package/dist/assets/{orbit-map-8eNDWek8.js → orbit-map-DHeTM15g.js} +1 -1
  50. package/dist/assets/{overview-page-CZ6q52Qj.js → overview-page-BRWje1F9.js} +1 -1
  51. package/dist/assets/{page-hero-C0MpI3MM.js → page-hero-8bITsx_x.js} +1 -1
  52. package/dist/assets/pill-cluster-XQjm-wPc.js +1 -0
  53. package/dist/assets/{preference-entity-handoff-button-CJhr5AXl.js → preference-entity-handoff-button-DwYF_5i3.js} +1 -1
  54. package/dist/assets/{preferences-page-8vszDNFX.js → preferences-page-C7DBPpNb.js} +1 -1
  55. package/dist/assets/{project-collections-sC7eAAhS.js → project-collections-mtxanSMf.js} +1 -1
  56. package/dist/assets/{project-detail-page-BKdnMjJy.js → project-detail-page-BT87Goqc.js} +1 -1
  57. package/dist/assets/{project-dialog-BiHZpOo1.js → project-dialog-DnZe757y.js} +1 -1
  58. package/dist/assets/{project-management-hierarchy-page-VW-hykAI.js → project-management-hierarchy-page-B3R2lNFI.js} +1 -1
  59. package/dist/assets/{project-management-section-nav-BEZ5zihs.js → project-management-section-nav-DyBWxHbe.js} +1 -1
  60. package/dist/assets/{projects-boxes-Ca6rpYeE.js → projects-boxes-CxZj3P29.js} +1 -1
  61. package/dist/assets/{projects-page-D86pjpTf.js → projects-page-Bec11c0x.js} +1 -1
  62. package/dist/assets/{psyche-behaviors-page-YLJB6CRU.js → psyche-behaviors-page-DWRpYvl1.js} +1 -1
  63. package/dist/assets/{psyche-flashcards-page-D3gdHLUw.js → psyche-flashcards-page-CX4rcsXZ.js} +1 -1
  64. package/dist/assets/{psyche-goal-map-page-DJiqSiCx.js → psyche-goal-map-page-Y6b3lCvV.js} +1 -1
  65. package/dist/assets/{psyche-graph-Tke0qFdt.js → psyche-graph-CQuCWKIp.js} +1 -1
  66. package/dist/assets/{psyche-metrics-page-DoLnvmC2.js → psyche-metrics-page-DadDJOnm.js} +1 -1
  67. package/dist/assets/{psyche-mode-guide-page-_Zbvg_HL.js → psyche-mode-guide-page-B1nz0uCg.js} +1 -1
  68. package/dist/assets/{psyche-modes-page-eAkaAzJc.js → psyche-modes-page-i3uSuhKA.js} +1 -1
  69. package/dist/assets/{psyche-page-CwmuBVjA.js → psyche-page-Y_s-BE2m.js} +1 -1
  70. package/dist/assets/{psyche-patterns-page-D7B4Ykjq.js → psyche-patterns-page-DaaOLIlN.js} +1 -1
  71. package/dist/assets/{psyche-questionnaire-builder-page-CHJlvCzX.js → psyche-questionnaire-builder-page-CuF7rXOv.js} +1 -1
  72. package/dist/assets/{psyche-questionnaire-detail-page-Bg3ll-D4.js → psyche-questionnaire-detail-page-BfFEMkRY.js} +1 -1
  73. package/dist/assets/{psyche-questionnaire-run-detail-page-CIEerczF.js → psyche-questionnaire-run-detail-page-BoQTvd7Q.js} +1 -1
  74. package/dist/assets/{psyche-questionnaire-run-page-DyxIk6Qx.js → psyche-questionnaire-run-page-C0qKiNZN.js} +1 -1
  75. package/dist/assets/{psyche-questionnaires-page-ZlqUxuIl.js → psyche-questionnaires-page-B6hfD448.js} +1 -1
  76. package/dist/assets/{psyche-report-detail-page-B2jgYnQ5.js → psyche-report-detail-page-BlFL8moM.js} +1 -1
  77. package/dist/assets/{psyche-reports-page-DlXr52yr.js → psyche-reports-page-DAAcYENp.js} +1 -1
  78. package/dist/assets/{psyche-schemas-Dtskzvv1.js → psyche-schemas-DDol0j-g.js} +1 -1
  79. package/dist/assets/{psyche-schemas-beliefs-page-BhrTZN9B.js → psyche-schemas-beliefs-page-CsxKSrKM.js} +1 -1
  80. package/dist/assets/{psyche-screen-time-page-WNGcdusx.js → psyche-screen-time-page-n4b0e58x.js} +1 -1
  81. package/dist/assets/{psyche-self-observation-page-XsCOglo4.js → psyche-self-observation-page-BaxEQ2-3.js} +1 -1
  82. package/dist/assets/{psyche-values-page-NvHI6zWK.js → psyche-values-page-DTv5NMSU.js} +1 -1
  83. package/dist/assets/{question-flow-dialog-Bj4PxpjS.js → question-flow-dialog-CskCt5NZ.js} +1 -1
  84. package/dist/assets/{report-chain-fields-mWFikZzT.js → report-chain-fields-D132-EMh.js} +1 -1
  85. package/dist/assets/{rewards-page-DyjwXsQN.js → rewards-page-C533lVP-.js} +1 -1
  86. package/dist/assets/{scheduling-rules-editor-C6FEYOxd.js → scheduling-rules-editor-CDpontGp.js} +1 -1
  87. package/dist/assets/{schema-badge-CCe4zkSN.js → schema-badge-B3DiMnjB.js} +1 -1
  88. package/dist/assets/{schemas-Cjwn6ooR.js → schemas-CH1_ngUX.js} +1 -1
  89. package/dist/assets/{select-menu-DeJhCsd8.js → select-menu-BOF-k4Ln.js} +1 -1
  90. package/dist/assets/{settings-agents-page-DYDxyKu-.js → settings-agents-page-B5OQtlZX.js} +1 -1
  91. package/dist/assets/{settings-bin-page-BWLfKVW1.js → settings-bin-page-D_bk3Kcu.js} +1 -1
  92. package/dist/assets/{settings-calendar-page-Ci-wXhCv.js → settings-calendar-page-PuSj9_kM.js} +1 -1
  93. package/dist/assets/{settings-data-page-DxIw-fWn.js → settings-data-page-EwFMaeq6.js} +1 -1
  94. package/dist/assets/{settings-logs-page-inpyIdu6.js → settings-logs-page-BKkse0DX.js} +1 -1
  95. package/dist/assets/{settings-mobile-page-BcJGLax8.js → settings-mobile-page-BrIVmdeB.js} +1 -1
  96. package/dist/assets/{settings-models-page-OWTRhfkj.js → settings-models-page-Mg84D_0K.js} +1 -1
  97. package/dist/assets/{settings-page-DXxF3qK2.js → settings-page-D-kul92f.js} +1 -1
  98. package/dist/assets/{settings-rewards-page-CCXin1n_.js → settings-rewards-page-waNyCcX_.js} +1 -1
  99. package/dist/assets/{settings-section-nav-CwSDNC3W.js → settings-section-nav-BmJWnrYk.js} +1 -1
  100. package/dist/assets/{settings-users-page-B4NEACwR.js → settings-users-page-DBgC6y56.js} +1 -1
  101. package/dist/assets/{settings-wiki-page-BNRK1SYc.js → settings-wiki-page-CM0te9dI.js} +1 -1
  102. package/dist/assets/sleep-page-C_krRE59.js +1 -0
  103. package/dist/assets/{sports-page-BawekFKD.js → sports-page-eg5Rfc_E.js} +1 -1
  104. package/dist/assets/{state-BtwEvpO6.js → state-Bpe5dF3T.js} +1 -1
  105. package/dist/assets/{strategies-page-BEl3NGAU.js → strategies-page-D4AqvFNW.js} +1 -1
  106. package/dist/assets/{strategy-detail-page-DPPI_8Ub.js → strategy-detail-page-BlYVkXaW.js} +1 -1
  107. package/dist/assets/{strategy-dialog-DU6wbBkQ.js → strategy-dialog-FO9Oa0dB.js} +1 -1
  108. package/dist/assets/{surface-BVYp-Wq9.js → surface-MVeeZGKB.js} +1 -1
  109. package/dist/assets/{table-BuONJH1s.js → table-U7otr5go.js} +1 -1
  110. package/dist/assets/{task-detail-page-BsMVAsbb.js → task-detail-page-Dy-aRyY6.js} +1 -1
  111. package/dist/assets/{task-dialog-BGzPc6TW.js → task-dialog-DrA9pba7.js} +1 -1
  112. package/dist/assets/{timebox-planning-dialog-4_XWuqkw.js → timebox-planning-dialog-C_gnfxFx.js} +1 -1
  113. package/dist/assets/{today-boxes-5pCvh5zS.js → today-boxes-BFOws_iC.js} +1 -1
  114. package/dist/assets/{today-page-BGurICpl.js → today-page-BoPj6a6q.js} +1 -1
  115. package/dist/assets/{training-load-page-BkoYKZ9_.js → training-load-page-DGU40Zfl.js} +1 -1
  116. package/dist/assets/{ui-B9O-eUim.js → ui-B9TWEtCx.js} +1 -1
  117. package/dist/assets/{use-anchored-overlay-position-BrQ4cqKn.js → use-anchored-overlay-position-BY4kNzPj.js} +1 -1
  118. package/dist/assets/{use-psyche-focus-target-Cuxni3SK.js → use-psyche-focus-target-BhNedCZB.js} +1 -1
  119. package/dist/assets/{user-badge-DfDv87j7.js → user-badge-CZWtYeMw.js} +1 -1
  120. package/dist/assets/{user-select-field-BNqv8-wd.js → user-select-field-fx129Uh6.js} +1 -1
  121. package/dist/assets/{utility-widgets-CbYj32he.js → utility-widgets-B3wWGxQc.js} +1 -1
  122. package/dist/assets/{vendor-Cpmju3nw.js → vendor-BwL6m4SE.js} +216 -211
  123. package/dist/assets/{vitals-page-DlxMk-L7.js → vitals-page-BXRZEP_8.js} +1 -1
  124. package/dist/assets/{weekly-review-page-VrEvAl1T.js → weekly-review-page-D5cebA5x.js} +1 -1
  125. package/dist/assets/weight-loss-page-BuUdFh9z.js +5 -0
  126. package/dist/assets/{wiki-article-markdown-DxTkiQRy.js → wiki-article-markdown-CvaCjg_t.js} +1 -1
  127. package/dist/assets/{wiki-editor-page-Beu92YnZ.js → wiki-editor-page-Dco79SLY.js} +1 -1
  128. package/dist/assets/{wiki-ingest-history-page-Cq_soygm.js → wiki-ingest-history-page-uvKRkRDF.js} +1 -1
  129. package/dist/assets/{wiki-ingest-modal-D6xs2sEn.js → wiki-ingest-modal-BW6AJPea.js} +1 -1
  130. package/dist/assets/{wiki-page-yF3Flgtg.js → wiki-page-BIL5zMqv.js} +1 -1
  131. package/dist/assets/{workbench-flow-page-CZZGg3a8.js → workbench-flow-page-Dx_nq8R_.js} +1 -1
  132. package/dist/assets/{workbench-page-DKENZ5Nz.js → workbench-page-BJnt_Zzf.js} +1 -1
  133. package/dist/assets/{workout-detail-page-CeN4QiYQ.js → workout-detail-page-CKgqyB-y.js} +2 -2
  134. package/dist/index.html +8 -8
  135. package/dist/server/server/migrations/070_health_mobile_sync_completion_index.sql +16 -0
  136. package/dist/server/server/src/app.js +139 -13
  137. package/dist/server/server/src/health-weight-loss.js +48 -6
  138. package/dist/server/server/src/health.js +345 -96
  139. package/dist/server/server/src/openapi.js +62 -0
  140. package/dist/server/server/src/repositories/gamification.js +25 -0
  141. package/dist/server/server/src/repositories/tasks.js +82 -17
  142. package/dist/server/server/src/services/dashboard.js +5 -4
  143. package/dist/server/server/src/services/gamification.js +47 -19
  144. package/dist/server/server/src/services/life-force.js +99 -0
  145. package/dist/server/src/lib/api.js +4 -0
  146. package/dist/server/src/lib/snapshot-normalizer.js +42 -23
  147. package/openclaw.plugin.json +1 -1
  148. package/package.json +1 -1
  149. package/server/migrations/070_health_mobile_sync_completion_index.sql +16 -0
  150. package/skills/forge-openclaw/SKILL.md +1 -0
  151. package/skills/forge-openclaw/psyche_entity_playbooks.md +8 -0
  152. package/dist/assets/date-keys-Cj1G3TOn.js +0 -1
  153. package/dist/assets/index-BaiwtAgo.js +0 -2
  154. package/dist/assets/index-CEgIwgk9.css +0 -1
  155. package/dist/assets/pill-cluster-DGwKZQKF.js +0 -1
  156. package/dist/assets/sleep-page-Bara54nB.js +0 -1
  157. package/dist/assets/weight-loss-page-DJDnjxKF.js +0 -5
@@ -5459,7 +5459,7 @@ function buildAgentOnboardingPayload(request) {
5459
5459
  reviewShortcutRule: "When the user is reviewing or correcting an existing record, ask what practical question they want the read or correction to answer, then narrow the saved object, timeframe, or route family first. Use the correct read posture before asking write-shaped questions: shared batch search or read hints for normal entities, wiki/calendar dedicated reads for specialized CRUD, read-model routes for overviews, and Movement, Life Force, or Workbench dedicated reads for those domain surfaces. After the read, answer the practical question before asking for any save, correction, link, run, enrichment, or publish detail. Do not reopen the whole intake unless the user is actually redefining the record.",
5460
5460
  readModelWriteRule: "Self-observation is note-backed and should be written through observed notes with frontmatter.observedAt only when a lightweight episode observation is the right container. Do not use it as the default bucket for Psyche material: prefer trigger_report for one emotionally meaningful episode, behavior_pattern for functional analysis of a recurring loop, behavior for one repeated move, belief_entry for a core sentence, mode_guide_session or mode_profile for a central part-state, and wiki_page for durable memory such as books, articles, concepts, sources, or personal manuals. Sleep and workout sessions stay on batch CRUD by default; use the reflective review helpers only when enriching one already-known record after review.",
5461
5461
  psycheOpeningQuestionRule: "Prefer a concrete opening question tied to the entity: ask when the value mattered, what happened the last time the pattern appeared, what cue or body signal came first before the behavior, what the belief starts saying about self or outcome, what feels most at risk inside the mode, what the part is trying to get the user to do or stop doing, or where the shift began in the incident. Reflect briefly before the question, choose one follow-up lane at a time, say what is becoming clearer before the next deeper question, and if several Psyche entities are visible hold the adjacent ones lightly until the main container is clear.",
5462
- psycheHypothesisRule: "When one concrete Psyche example is visible, a helpful hypothesis should start from evidence in the user's own example, offer one testable interpretation, name the function without blame such as protection, prediction, relief, or cost, and ask whether the danger, need, or wording fits. Use the hypothesis timing checkpoint before asking a second or third deepening question: offer a hypothesis when one concrete episode, body cue, belief sentence, behavior, or mode voice is visible and the hypothesis would change the record shape, wording, links, or next action. Do not hypothesize yet when no concrete moment is visible, the user only wants a direct mechanical save, the user is flooded or unsafe, or the only available interpretation would be diagnosis-like, an origin story, or a certainty claim. Do not present schema, mode, belief, or pattern language as a verdict. If the user corrects the hypothesis, revise it once and move toward the saveable record shape instead of asking for another broad story.",
5462
+ psycheHypothesisRule: "When one concrete Psyche example is visible, a helpful hypothesis should start from evidence in the user's own example, offer one testable interpretation, name the function without blame such as protection, prediction, relief, or cost, and ask whether the danger, need, or wording fits. Use the hypothesis timing checkpoint before asking a second or third deepening question: offer a hypothesis when one concrete episode, body cue, belief sentence, behavior, or mode voice is visible and the hypothesis would change the record shape, wording, links, or next action. Do not keep asking broad exploratory Psyche questions after the cue, meaning, protection, payoff, or cost is already visible. For behavior_pattern, belief_entry, mode_profile, mode_guide_session, and trigger_report, the next helpful move is usually one active formulation plus one correction question, not another passive reflection. Do not hypothesize yet when no concrete moment is visible, the user only wants a direct mechanical save, the user is flooded or unsafe, or the only available interpretation would be diagnosis-like, an origin story, or a certainty claim. Do not present schema, mode, belief, or pattern language as a verdict. If the user corrects the hypothesis, revise it once and move toward the saveable record shape instead of asking for another broad story.",
5463
5463
  mixedIntentSequencingRule: "When one user message combines several Forge jobs, identify the primary job and the order of operations before asking a follow-up. If a read changes the truth of a later write, read first: Movement timeline or box detail before correction, Workbench run or node detail before editing or publishing, and Life Force overview before changing durable assumptions when the current energy picture is uncertain. If the user asks to understand and save Psyche material plus create a support record, formulate the primary Psyche record first, then derive the flashcard, note, link, task, or habit from the accepted wording. If the user already gave the concrete action, do not ask a broad lane question; say the product sequence briefly and ask only for the missing span, wording, flow, run, node, weekday, or link that changes the next action.",
5464
5464
  duplicateDisambiguationRule: "Before creating or updating a normal stored entity when duplicate risk is plausible, search the shared batch entity route by entity type, distinctive title or wording, owner scope, and linked content. If a likely existing record appears, ask whether the user wants to update that record, link to it, or save a separate new record; do not reopen the whole create flow. For Psyche records, a similar belief, pattern, mode, trigger report, value, or flashcard is a formulation choice, not a duplicate error: compare the sentence, cue/payoff/cost, protective job, episode, urge sentence, or message and let the user choose update, link, or new version. For wiki_page and calendar_connection, use dedicated search/list/read routes before creating another page or connection. For Movement, Life Force, and Workbench, use the dedicated read lanes instead of batch duplicate search.",
5465
5465
  destructiveActionRule: "Before deleting, archiving, invalidating, overwriting, disconnecting, or substantially replacing a Forge record or specialized object, confirm the exact target and what should remain understandable. Prefer normal soft-delete for stored entities unless the user explicitly asks for permanent removal. For Psyche records, preserve therapeutic history by asking whether the old belief, pattern, mode, trigger report, value, or flashcard should be updated, linked as history, archived, or kept distinct; do not delete it just because a cleaner formulation exists. For Movement, distinguish user-defined overlay deletion from automatic-box invalidation and stay/trip/point deletion, and read the specific span first when the target is uncertain. For calendar connections, Workbench flows, wiki pages, and questionnaire instruments, ask what downstream sync, published output, backlinks, run history, or completed runs should remain understandable before deleting or replacing the saved object.",
@@ -5880,7 +5880,13 @@ function buildV1Context(scope = {
5880
5880
  ].filter((value) => typeof value === "string" && value.length > 0)));
5881
5881
  const habits = applyHabitScope(filterOwnedEntities("habit", listHabits(), scopedUserIdsForReads), scope, new Set(goals.map((goal) => goal.id)), new Set(tasks.map((task) => task.id)));
5882
5882
  const strategies = applyStrategyScope(listStrategies({ userIds: scopedUserIdsForReads }), scope, new Set(goals.map((goal) => goal.id)));
5883
- const dashboard = getDashboard({ userIds: scopedUserIdsForReads });
5883
+ const dashboard = getDashboard({
5884
+ userIds: scopedUserIdsForReads,
5885
+ goals,
5886
+ projects,
5887
+ tasks,
5888
+ habits
5889
+ });
5884
5890
  const selectedUsers = validScopedUserIds !== undefined
5885
5891
  ? users.filter((user) => validScopedUserIds.includes(user.id))
5886
5892
  : users;
@@ -5892,9 +5898,7 @@ function buildV1Context(scope = {
5892
5898
  backend: "forge-node-runtime",
5893
5899
  mode: "transitional-node"
5894
5900
  },
5895
- metrics: buildGamificationProfile(goals, tasks, habits, now, {
5896
- userIds: scopedUserIdsForReads
5897
- }),
5901
+ metrics: dashboard.gamification,
5898
5902
  dashboard,
5899
5903
  overview: getOverviewContext(now, {
5900
5904
  userIds: scopedUserIdsForReads,
@@ -5932,6 +5936,55 @@ function buildV1Context(scope = {
5932
5936
  lifeForce: buildLifeForcePayload(now, scopedUserIdsForReads)
5933
5937
  };
5934
5938
  }
5939
+ function compactV1ContextForShell(context) {
5940
+ const stripTaskPeople = (task) => {
5941
+ const { user: _user, ownerUser: _ownerUser, assignees: _assignees, ...compactTask } = task;
5942
+ return compactTask;
5943
+ };
5944
+ const stripOptionalTaskPeople = (task) => task ? stripTaskPeople(task) : task;
5945
+ return {
5946
+ ...context,
5947
+ tasks: context.tasks.map(stripTaskPeople),
5948
+ dashboard: {
5949
+ ...context.dashboard,
5950
+ projects: undefined,
5951
+ tasks: undefined,
5952
+ habits: undefined,
5953
+ tags: undefined,
5954
+ recentActivity: undefined,
5955
+ executionBuckets: context.dashboard.executionBuckets.map((bucket) => ({
5956
+ ...bucket,
5957
+ tasks: bucket.tasks.map(stripTaskPeople)
5958
+ }))
5959
+ },
5960
+ overview: {
5961
+ ...context.overview,
5962
+ topTasks: context.overview.topTasks.map(stripTaskPeople)
5963
+ },
5964
+ today: {
5965
+ ...context.today,
5966
+ directive: {
5967
+ ...context.today.directive,
5968
+ task: stripOptionalTaskPeople(context.today.directive.task)
5969
+ },
5970
+ timeline: context.today.timeline.map((bucket) => ({
5971
+ ...bucket,
5972
+ tasks: bucket.tasks.map(stripTaskPeople)
5973
+ }))
5974
+ },
5975
+ risk: {
5976
+ ...context.risk,
5977
+ overdueTasks: context.risk.overdueTasks.map(stripTaskPeople),
5978
+ blockedTasks: context.risk.blockedTasks.map(stripTaskPeople)
5979
+ },
5980
+ activity: undefined
5981
+ };
5982
+ }
5983
+ function shouldUseShellContextProfile(query) {
5984
+ const profile = typeof query.profile === "string" ? query.profile.trim() : "";
5985
+ const compact = typeof query.compact === "string" ? query.compact.trim() : query.compact;
5986
+ return profile === "shell" || compact === "1" || compact === true;
5987
+ }
5935
5988
  function buildXpMetricsPayload(input = {}) {
5936
5989
  const goals = input.goals ?? listGoals();
5937
5990
  const tasks = input.tasks ?? listTasks();
@@ -6413,10 +6466,14 @@ function compactOperatorContext(context) {
6413
6466
  function compactSleep(sleep) {
6414
6467
  return {
6415
6468
  summary: sleep.summary,
6469
+ latestNightFreshness: sleep.latestNightFreshness,
6416
6470
  latestNight: sleep.latestNight
6417
6471
  ? {
6418
6472
  id: sleep.latestNight.sleepId,
6419
6473
  dateKey: sleep.latestNight.dateKey,
6474
+ expectedDateKey: sleep.latestNight.expectedDateKey,
6475
+ isExpectedLastNight: sleep.latestNight.isExpectedLastNight,
6476
+ freshnessStatus: sleep.latestNight.freshnessStatus,
6420
6477
  startedAt: sleep.latestNight.startedAt,
6421
6478
  endedAt: sleep.latestNight.endedAt,
6422
6479
  sleepScore: sleep.latestNight.score,
@@ -7482,7 +7539,11 @@ export async function buildServer(options = {}) {
7482
7539
  app.get("/api/v1/openapi.json", async () => buildOpenApiDocument());
7483
7540
  app.get("/api/v1/context", async (request) => {
7484
7541
  const auth = authenticateRequest(request.headers);
7485
- return buildV1Context(resolveEffectiveReadScope(request.query, auth));
7542
+ const query = request.query;
7543
+ const context = buildV1Context(resolveEffectiveReadScope(query, auth));
7544
+ return shouldUseShellContextProfile(query)
7545
+ ? compactV1ContextForShell(context)
7546
+ : context;
7486
7547
  });
7487
7548
  app.get("/api/v1/life-force", async (request) => ({
7488
7549
  lifeForce: buildLifeForcePayload(new Date(), resolveScopedUserIds(request.query)),
@@ -7611,11 +7672,15 @@ export async function buildServer(options = {}) {
7611
7672
  z.string().datetime().safeParse(query.dayEndAt).success
7612
7673
  ? query.dayEndAt
7613
7674
  : undefined;
7675
+ const timeZone = typeof query.timeZone === "string" && query.timeZone.trim().length > 0
7676
+ ? query.timeZone
7677
+ : undefined;
7614
7678
  return {
7615
7679
  weightLoss: getWeightLossViewData(resolveScopedUserIds(query), {
7616
7680
  dateKey,
7617
7681
  dayStartAt,
7618
- dayEndAt
7682
+ dayEndAt,
7683
+ timeZone
7619
7684
  })
7620
7685
  };
7621
7686
  });
@@ -8248,13 +8313,39 @@ export async function buildServer(options = {}) {
8248
8313
  error: "Recorded moves are immutable in product UI. Create or edit a user-defined movement box instead."
8249
8314
  };
8250
8315
  });
8316
+ function estimatedJsonBytes(value) {
8317
+ try {
8318
+ return Buffer.byteLength(JSON.stringify(value ?? null), "utf8");
8319
+ }
8320
+ catch {
8321
+ return 0;
8322
+ }
8323
+ }
8324
+ function watchRouteMeasurement(operation, startedAt, requestBody, responseBody, extra = {}) {
8325
+ return {
8326
+ operation,
8327
+ backendDurationMs: Number((Number(process.hrtime.bigint() - startedAt) / 1_000_000).toFixed(2)),
8328
+ requestBytes: estimatedJsonBytes(requestBody),
8329
+ responseBytes: estimatedJsonBytes(responseBody),
8330
+ ...extra
8331
+ };
8332
+ }
8251
8333
  app.post("/api/v1/mobile/watch/bootstrap", async (request) => {
8334
+ const startedAt = process.hrtime.bigint();
8252
8335
  const parsed = mobileWatchBootstrapSchema.parse(request.body ?? {});
8253
8336
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8254
8337
  assertWatchReady(pairing);
8255
- return {
8338
+ const responseBody = {
8256
8339
  watch: buildWatchBootstrap(pairing)
8257
8340
  };
8341
+ return {
8342
+ ...responseBody,
8343
+ measurement: watchRouteMeasurement("watch.bootstrap", startedAt, request.body ?? {}, responseBody, {
8344
+ surfaceCount: responseBody.watch.surfaces.length,
8345
+ habitCount: responseBody.watch.habits.length,
8346
+ promptCount: responseBody.watch.pendingPrompts.length
8347
+ })
8348
+ };
8258
8349
  });
8259
8350
  app.post("/api/v1/mobile/watch/habits/:id/check-ins", async (request, reply) => {
8260
8351
  const parsed = mobileWatchHabitCheckInSchema.parse(request.body ?? {});
@@ -8280,22 +8371,45 @@ export async function buildServer(options = {}) {
8280
8371
  };
8281
8372
  });
8282
8373
  app.post("/api/v1/mobile/watch/capture-events:batch", async (request) => {
8374
+ const startedAt = process.hrtime.bigint();
8283
8375
  const parsed = mobileWatchCaptureBatchSchema.parse(request.body ?? {});
8284
8376
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8285
8377
  assertWatchReady(pairing);
8286
- return {
8287
- receipt: ingestWatchCaptureBatch(pairing, parsed),
8378
+ const receipt = ingestWatchCaptureBatch(pairing, parsed);
8379
+ const responseBody = {
8380
+ receipt,
8288
8381
  watch: buildWatchBootstrap(pairing)
8289
8382
  };
8383
+ return {
8384
+ ...responseBody,
8385
+ measurement: watchRouteMeasurement("watch.capture_batch", startedAt, request.body ?? {}, responseBody, {
8386
+ eventCount: parsed.events.length,
8387
+ storedCount: receipt.storedCount,
8388
+ duplicateCount: receipt.duplicateCount,
8389
+ projectedCount: receipt.projectedCount,
8390
+ projectionFailedCount: receipt.projectionFailedCount
8391
+ })
8392
+ };
8290
8393
  });
8291
8394
  app.post("/api/v1/mobile/watch/actions:batch", async (request) => {
8395
+ const startedAt = process.hrtime.bigint();
8292
8396
  const parsed = mobileWatchCommandBatchSchema.parse(request.body ?? {});
8293
8397
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8294
8398
  assertWatchReady(pairing);
8295
- return {
8296
- receipt: ingestWatchCommandBatch(pairing, parsed),
8399
+ const receipt = ingestWatchCommandBatch(pairing, parsed);
8400
+ const responseBody = {
8401
+ receipt,
8297
8402
  watch: buildWatchBootstrap(pairing)
8298
8403
  };
8404
+ return {
8405
+ ...responseBody,
8406
+ measurement: watchRouteMeasurement("watch.action_batch", startedAt, request.body ?? {}, responseBody, {
8407
+ commandCount: parsed.commands.length,
8408
+ processedCount: receipt.processedCount,
8409
+ replayedCount: receipt.replayedCount,
8410
+ failedCount: receipt.failedCount
8411
+ })
8412
+ };
8299
8413
  });
8300
8414
  app.post("/api/v1/mobile/healthkit/sync-sessions", async (request) => ({
8301
8415
  upload: startMobileHealthSyncSession(mobileHealthSyncSessionStartSchema.parse(request.body ?? {}))
@@ -8305,7 +8419,19 @@ export async function buildServer(options = {}) {
8305
8419
  const query = z
8306
8420
  .object({
8307
8421
  sessionId: z.string().trim().min(1),
8308
- pairingToken: z.string().trim().min(1)
8422
+ pairingToken: z.string().trim().min(1),
8423
+ includeReceivedChunkIds: z
8424
+ .enum(["true", "false"])
8425
+ .optional()
8426
+ .transform((value) => value !== "false"),
8427
+ includeWorkoutImportExternalUids: z
8428
+ .enum(["true", "false"])
8429
+ .optional()
8430
+ .transform((value) => value !== "false"),
8431
+ includeWorkoutImportState: z
8432
+ .enum(["true", "false"])
8433
+ .optional()
8434
+ .transform((value) => value !== "false")
8309
8435
  })
8310
8436
  .parse(request.query ?? {});
8311
8437
  return {
@@ -107,6 +107,7 @@ export const nutritionDailyActiveCaloriesUpdateSchema = z.object({
107
107
  .string()
108
108
  .regex(/^\d{4}-\d{2}-\d{2}$/)
109
109
  .optional(),
110
+ timeZone: z.string().trim().optional(),
110
111
  activeCaloriesKcal: z
111
112
  .union([z.null(), z.coerce.number().finite().min(0)])
112
113
  .optional(),
@@ -120,6 +121,7 @@ export const nutritionFoodLogCreateSchema = z.object({
120
121
  .regex(/^\d{4}-\d{2}-\d{2}$/)
121
122
  .nullable()
122
123
  .optional(),
124
+ timeZone: z.string().trim().optional(),
123
125
  mealLabel: z.string().trim().default(""),
124
126
  source: z
125
127
  .enum(["manual", "search", "barcode", "chatgpt", "photo", "saved_meal"])
@@ -242,8 +244,47 @@ function newId(prefix) {
242
244
  function dayKey(value) {
243
245
  return value.slice(0, 10);
244
246
  }
245
- function normalizeDayKey(value, fallbackIso) {
246
- return value ?? dayKey(fallbackIso);
247
+ function resolveTimeZone(timeZone) {
248
+ const candidate = timeZone?.trim();
249
+ if (!candidate) {
250
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
251
+ }
252
+ try {
253
+ new Intl.DateTimeFormat("en-US", { timeZone: candidate }).format(new Date());
254
+ return candidate;
255
+ }
256
+ catch {
257
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
258
+ }
259
+ }
260
+ function localDateParts(value, timeZone) {
261
+ const formatter = new Intl.DateTimeFormat("en-CA", {
262
+ timeZone,
263
+ year: "numeric",
264
+ month: "2-digit",
265
+ day: "2-digit",
266
+ hour: "2-digit",
267
+ minute: "2-digit",
268
+ second: "2-digit",
269
+ hour12: false
270
+ });
271
+ const parts = formatter.formatToParts(new Date(value));
272
+ const read = (type) => parts.find((part) => part.type === type)?.value ?? "00";
273
+ return {
274
+ year: read("year"),
275
+ month: read("month"),
276
+ day: read("day"),
277
+ hour: read("hour"),
278
+ minute: read("minute"),
279
+ second: read("second")
280
+ };
281
+ }
282
+ function localDateKey(value, timeZone) {
283
+ const parts = localDateParts(value, resolveTimeZone(timeZone));
284
+ return `${parts.year}-${parts.month}-${parts.day}`;
285
+ }
286
+ function normalizeDayKey(value, fallbackIso, timeZone) {
287
+ return value ?? localDateKey(fallbackIso, resolveTimeZone(timeZone));
247
288
  }
248
289
  function jsonString(value) {
249
290
  return JSON.stringify(value ?? null);
@@ -1058,7 +1099,7 @@ export function createNutritionFoodLog(input) {
1058
1099
  const parsed = nutritionFoodLogCreateSchema.parse(input);
1059
1100
  const userId = resolveWriteUser(parsed.userId);
1060
1101
  const loggedAt = parsed.loggedAt ?? nowIso();
1061
- const logDayKey = normalizeDayKey(parsed.dayKey, loggedAt);
1102
+ const logDayKey = normalizeDayKey(parsed.dayKey, loggedAt, parsed.timeZone);
1062
1103
  const id = newId("meal");
1063
1104
  const now = nowIso();
1064
1105
  runInTransaction(() => {
@@ -1084,7 +1125,7 @@ export function patchNutritionFoodLog(logId, input) {
1084
1125
  return null;
1085
1126
  }
1086
1127
  const nextLoggedAt = parsed.loggedAt ?? existing.loggedAt;
1087
- const nextDayKey = normalizeDayKey(parsed.dayKey, nextLoggedAt);
1128
+ const nextDayKey = normalizeDayKey(parsed.dayKey, nextLoggedAt, parsed.timeZone);
1088
1129
  const nextConfirmationState = parsed.confirmationState ?? existing.confirmationState;
1089
1130
  const now = nowIso();
1090
1131
  runInTransaction(() => {
@@ -1168,7 +1209,7 @@ export function updateNutritionTarget(input) {
1168
1209
  export function updateNutritionDailyActiveCalories(input) {
1169
1210
  const parsed = nutritionDailyActiveCaloriesUpdateSchema.parse(input);
1170
1211
  const userId = resolveWriteUser(parsed.userId);
1171
- const dateKey = parsed.dayKey ?? new Date().toISOString().slice(0, 10);
1212
+ const dateKey = parsed.dayKey ?? localDateKey(new Date(), resolveTimeZone(parsed.timeZone));
1172
1213
  const now = nowIso();
1173
1214
  if (parsed.activeCaloriesKcal == null) {
1174
1215
  getDatabase()
@@ -1682,7 +1723,8 @@ function buildGeneratedHypotheses(logs, subjective, gut, appearance) {
1682
1723
  export function getWeightLossViewData(userIds, options = {}) {
1683
1724
  const generatedAt = new Date().toISOString();
1684
1725
  const userId = resolveReadUser(userIds);
1685
- const todayKey = options.dateKey ?? generatedAt.slice(0, 10);
1726
+ const timeZone = resolveTimeZone(options.timeZone);
1727
+ const todayKey = options.dateKey ?? localDateKey(generatedAt, timeZone);
1686
1728
  const targetRow = getDatabase()
1687
1729
  .prepare(`SELECT * FROM nutrition_targets WHERE user_id = ?`)
1688
1730
  .get(userId);