forge-openclaw-plugin 0.3.4 → 0.3.6

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 (156) hide show
  1. package/dist/assets/{action-bar-CMGr_Uv_.js → action-bar-CsDQF9d4.js} +1 -1
  2. package/dist/assets/{activity-page-DwGKkJtr.js → activity-page-CACf1Sd5.js} +1 -1
  3. package/dist/assets/{ai-surface-workspace-UtnoNmjq.js → ai-surface-workspace-Vn5fqCAT.js} +1 -1
  4. package/dist/assets/{atlas-panel-f1kc-LkD.js → atlas-panel-GdK1oyxo.js} +1 -1
  5. package/dist/assets/{board-CLOHbg6t.js → board-CuxQRKPJ.js} +1 -1
  6. package/dist/assets/{calendar-page-C4YqeVrC.js → calendar-page-CcVGbvfY.js} +1 -1
  7. package/dist/assets/{calendar-rules-BQppCPiN.js → calendar-rules-Dlq0KT93.js} +1 -1
  8. package/dist/assets/{calendar-week-toolbar-DdPuHUwd.js → calendar-week-toolbar-BVFb1_2G.js} +1 -1
  9. package/dist/assets/{charts-DwTguE_x.js → charts-BzT4pUPg.js} +1 -1
  10. package/dist/assets/{companion-sync-lab-page-N3cR33GS.js → companion-sync-lab-page-Dgvtdc4i.js} +1 -1
  11. package/dist/assets/{daily-metrics-dashboard-CXnAtN2T.js → daily-metrics-dashboard-ChQVbNJI.js} +1 -1
  12. package/dist/assets/date-keys-BnZV4PNO.js +1 -0
  13. package/dist/assets/{define-workbench-box-DkffygDU.js → define-workbench-box-DWAqqjvH.js} +1 -1
  14. package/dist/assets/{entity-link-multiselect-wuyJ8BbW.js → entity-link-multiselect-Do5DTju7.js} +1 -1
  15. package/dist/assets/{entity-note-count-link-CEtKyMAl.js → entity-note-count-link-CV3eOv66.js} +1 -1
  16. package/dist/assets/{entity-notes-surface-iKNiierJ.js → entity-notes-surface-CiUgAVl7.js} +1 -1
  17. package/dist/assets/{execution-board-DesFZ1f5.js → execution-board-ClaXVQ0H.js} +1 -1
  18. package/dist/assets/{faceted-token-search-D4Okr-Kr.js → faceted-token-search-DoSsb7qT.js} +1 -1
  19. package/dist/assets/{flagship-signal-deck-CW91n6u9.js → flagship-signal-deck-B2s7TrIN.js} +1 -1
  20. package/dist/assets/{floating-action-menu-GCeuOdYZ.js → floating-action-menu-DGkHCmvI.js} +1 -1
  21. package/dist/assets/{forms-C5d5hTf2.js → forms-D1qJ3oOP.js} +1 -1
  22. package/dist/assets/{generic-node-view-COhU_Wm3.js → generic-node-view-CgLkbts-.js} +1 -1
  23. package/dist/assets/{goal-detail-page-Bd8JU3IK.js → goal-detail-page-JRcEYpeA.js} +1 -1
  24. package/dist/assets/{goal-dialog-CLz5fYhO.js → goal-dialog-6R2uYWPQ.js} +1 -1
  25. package/dist/assets/{goals-page-CZHNVyY-.js → goals-page-CYestXkp.js} +1 -1
  26. package/dist/assets/{graph-Cd5WF3lw.js → graph-BF4IsheG.js} +1 -1
  27. package/dist/assets/{habits-page-CXiBB7_N.js → habits-page-B27lnyKu.js} +1 -1
  28. package/dist/assets/{health-boxes-BUcsxDLh.js → health-boxes-CeqSGyZ3.js} +1 -1
  29. package/dist/assets/index-DGYIFHgo.js +2 -0
  30. package/dist/assets/{index-CEgIwgk9.css → index-UzsVTD1W.css} +1 -1
  31. package/dist/assets/{inline-note-fields-CcRDO3pd.js → inline-note-fields-CJ9ukqFp.js} +1 -1
  32. package/dist/assets/{insight-flow-dialog-DUBk2MR8.js → insight-flow-dialog-BgaJRYGX.js} +1 -1
  33. package/dist/assets/{insights-page-8fLhCYsM.js → insights-page-Dc5bilGE.js} +1 -1
  34. package/dist/assets/{kanban-boxes-CH7plRk1.js → kanban-boxes-qIwmQlRq.js} +1 -1
  35. package/dist/assets/{kanban-page-Bq-aYwUL.js → kanban-page-BGnVLHeN.js} +1 -1
  36. package/dist/assets/{knowledge-graph-page-DYFfWh4Y.js → knowledge-graph-page-B7IsVVO_.js} +1 -1
  37. package/dist/assets/{life-force-page-D80rgBBR.js → life-force-page-B5N4DknK.js} +1 -1
  38. package/dist/assets/{life-force-workspace-CcmZRRfU.js → life-force-workspace-Da-dmoRX.js} +1 -1
  39. package/dist/assets/{maps-D0Mm6WPG.js → maps-BTVHALP8.js} +1 -1
  40. package/dist/assets/{metric-tile-DysHMgM3.js → metric-tile-BVuj7mc3.js} +1 -1
  41. package/dist/assets/{motion-DwjmC9aq.js → motion-DcgUnXhY.js} +1 -1
  42. package/dist/assets/{movement-boxes-BH3botKt.js → movement-boxes-BZrdIh8b.js} +1 -1
  43. package/dist/assets/{movement-page-D5KLMKS9.js → movement-page-CY2XLgp_.js} +1 -1
  44. package/dist/assets/{note-markdown-Byd_vNkS.js → note-markdown-BZHBOkEd.js} +1 -1
  45. package/dist/assets/{note-tags-input-DYAFDq8Q.js → note-tags-input-DucocvNH.js} +1 -1
  46. package/dist/assets/{notes-boxes-CPiPps1e.js → notes-boxes-DAQ6KBkJ.js} +1 -1
  47. package/dist/assets/{notes-page-DehVrOOb.js → notes-page-CSCfdDJl.js} +1 -1
  48. package/dist/assets/{open-in-graph-button-L21MKsb5.js → open-in-graph-button-ObO3m8yd.js} +1 -1
  49. package/dist/assets/{orbit-map-ChJOQ8CN.js → orbit-map-Bteg-ola.js} +1 -1
  50. package/dist/assets/overview-page-ckfN_sLZ.js +1 -0
  51. package/dist/assets/{page-hero-DlHEJ0Yt.js → page-hero-BkrRTu-t.js} +1 -1
  52. package/dist/assets/pill-cluster-COzv8VgR.js +1 -0
  53. package/dist/assets/{preference-entity-handoff-button-ugHU2us9.js → preference-entity-handoff-button-BpVAeFmY.js} +1 -1
  54. package/dist/assets/{preferences-page-BTTXeSDR.js → preferences-page-DseOh9AP.js} +1 -1
  55. package/dist/assets/{project-collections-USb6PUe0.js → project-collections-C7yU5PSi.js} +1 -1
  56. package/dist/assets/{project-detail-page-1tD6tUsB.js → project-detail-page-Crt46y_7.js} +1 -1
  57. package/dist/assets/{project-dialog-BaHhJqP6.js → project-dialog-YYxtlqg8.js} +1 -1
  58. package/dist/assets/{project-management-hierarchy-page-D4HV8QXs.js → project-management-hierarchy-page-DnojKHzy.js} +1 -1
  59. package/dist/assets/{project-management-section-nav-9OV6_ifH.js → project-management-section-nav-Ctjd348W.js} +1 -1
  60. package/dist/assets/{projects-boxes-AyudWls3.js → projects-boxes-D8lLFGBC.js} +1 -1
  61. package/dist/assets/{projects-page-DizVVzbt.js → projects-page-CV_2em8d.js} +1 -1
  62. package/dist/assets/{psyche-behaviors-page-CX5MJjWj.js → psyche-behaviors-page-CYCNk0rz.js} +1 -1
  63. package/dist/assets/{psyche-flashcards-page-DzCGy-FV.js → psyche-flashcards-page-DwmjBixN.js} +1 -1
  64. package/dist/assets/{psyche-goal-map-page-BcKR792E.js → psyche-goal-map-page-CdMhyBKh.js} +1 -1
  65. package/dist/assets/{psyche-graph-BNllZR67.js → psyche-graph-BcrZcJrq.js} +1 -1
  66. package/dist/assets/{psyche-metrics-page-CpEKlZLO.js → psyche-metrics-page-D5bX1mNX.js} +1 -1
  67. package/dist/assets/{psyche-mode-guide-page-DXKSE2o7.js → psyche-mode-guide-page-BmX9EOOB.js} +1 -1
  68. package/dist/assets/{psyche-modes-page-Bh6eeNm1.js → psyche-modes-page-CTHFDyLE.js} +1 -1
  69. package/dist/assets/{psyche-page-B44RJrrC.js → psyche-page-DRR3Fjv-.js} +1 -1
  70. package/dist/assets/{psyche-patterns-page-Bm7T5FMJ.js → psyche-patterns-page-BAS38xYf.js} +1 -1
  71. package/dist/assets/{psyche-questionnaire-builder-page-BNtMNjY8.js → psyche-questionnaire-builder-page-DpSi-zg3.js} +1 -1
  72. package/dist/assets/{psyche-questionnaire-detail-page-BnMXErRK.js → psyche-questionnaire-detail-page-BcXIiV4E.js} +1 -1
  73. package/dist/assets/{psyche-questionnaire-run-detail-page-CWKxbdwZ.js → psyche-questionnaire-run-detail-page-DvccwzWO.js} +1 -1
  74. package/dist/assets/{psyche-questionnaire-run-page-DwH7Sk52.js → psyche-questionnaire-run-page-vcyon8IZ.js} +1 -1
  75. package/dist/assets/{psyche-questionnaires-page-B1t_a8QU.js → psyche-questionnaires-page-B0DDTner.js} +1 -1
  76. package/dist/assets/{psyche-report-detail-page-x2AtC99e.js → psyche-report-detail-page-BgBA3xIO.js} +1 -1
  77. package/dist/assets/{psyche-reports-page-KiwCgWPa.js → psyche-reports-page-Ce1vEEqW.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-CIEoAJAp.js → psyche-schemas-beliefs-page-D-IHHohY.js} +1 -1
  80. package/dist/assets/{psyche-screen-time-page-DO6UycL9.js → psyche-screen-time-page-DOKW3m8B.js} +1 -1
  81. package/dist/assets/{psyche-self-observation-page-CPcpUSdm.js → psyche-self-observation-page-j7Sk6Ns1.js} +1 -1
  82. package/dist/assets/{psyche-values-page-BAgNeo4L.js → psyche-values-page-NfzdWUyb.js} +1 -1
  83. package/dist/assets/{question-flow-dialog-BByFV8Yw.js → question-flow-dialog-CLHVmFON.js} +1 -1
  84. package/dist/assets/{report-chain-fields-BpRWMp7h.js → report-chain-fields-C9MuyBha.js} +1 -1
  85. package/dist/assets/{rewards-page-kIiX8SHn.js → rewards-page-CVxOBP6m.js} +1 -1
  86. package/dist/assets/{scheduling-rules-editor-oQXGcL5l.js → scheduling-rules-editor-BmbOHH_R.js} +1 -1
  87. package/dist/assets/{schema-badge-BoNjw3h4.js → schema-badge-BAiS_OAp.js} +1 -1
  88. package/dist/assets/{schemas-IBbtdPzn.js → schemas-B0AXfuOr.js} +1 -1
  89. package/dist/assets/{select-menu-U-YryCwP.js → select-menu-Bl5MILOj.js} +1 -1
  90. package/dist/assets/{settings-agents-page-CbHeMq3e.js → settings-agents-page-BIRP02mt.js} +1 -1
  91. package/dist/assets/{settings-bin-page-LxS2YPsA.js → settings-bin-page-DxJKeM28.js} +1 -1
  92. package/dist/assets/{settings-calendar-page-CZc-I-HK.js → settings-calendar-page-aMBtwvO_.js} +1 -1
  93. package/dist/assets/{settings-data-page-m-aBRMR9.js → settings-data-page-nHNergsh.js} +1 -1
  94. package/dist/assets/{settings-logs-page-BUEGWlQu.js → settings-logs-page-CFotPoFy.js} +1 -1
  95. package/dist/assets/{settings-mobile-page-C_5CHjHl.js → settings-mobile-page-Bf_1D-bN.js} +1 -1
  96. package/dist/assets/{settings-models-page-B4HQu8kL.js → settings-models-page-BbFNmnik.js} +1 -1
  97. package/dist/assets/{settings-page-CY8N-fNV.js → settings-page-CalbNbcg.js} +1 -1
  98. package/dist/assets/{settings-rewards-page-C0XQoWjb.js → settings-rewards-page-ByDfCzP5.js} +1 -1
  99. package/dist/assets/{settings-section-nav-CkqqtM0F.js → settings-section-nav-x_JXfzL9.js} +1 -1
  100. package/dist/assets/{settings-users-page-COCBOq7d.js → settings-users-page-N1jl9hWV.js} +1 -1
  101. package/dist/assets/{settings-wiki-page-Dy1d7-z-.js → settings-wiki-page-Bn2Qr94L.js} +1 -1
  102. package/dist/assets/{sleep-page-1kKicdFq.js → sleep-page-DyU635jb.js} +1 -1
  103. package/dist/assets/{sports-page-DJErRii_.js → sports-page-DbK4yGrR.js} +1 -1
  104. package/dist/assets/{state-BtwEvpO6.js → state-Bpe5dF3T.js} +1 -1
  105. package/dist/assets/{strategies-page-CWNFb9vv.js → strategies-page-AUBlFCZ9.js} +1 -1
  106. package/dist/assets/{strategy-detail-page-D9rFVXRS.js → strategy-detail-page-DCF8mVaL.js} +1 -1
  107. package/dist/assets/{strategy-dialog-BIVHfUR6.js → strategy-dialog-50xKlqcz.js} +1 -1
  108. package/dist/assets/{surface-B3oXO1No.js → surface-BjT1dIAF.js} +1 -1
  109. package/dist/assets/{table-BuONJH1s.js → table-U7otr5go.js} +1 -1
  110. package/dist/assets/{task-detail-page-r8ipOpAF.js → task-detail-page-Dsll2LCX.js} +1 -1
  111. package/dist/assets/{task-dialog-C3kkWtcT.js → task-dialog-BfPkbIPE.js} +1 -1
  112. package/dist/assets/{timebox-planning-dialog-BadS5tEr.js → timebox-planning-dialog-BTKUS6Jj.js} +1 -1
  113. package/dist/assets/{today-boxes-CiccN0Gw.js → today-boxes-BPi9bDHM.js} +1 -1
  114. package/dist/assets/{today-page-DvQredbl.js → today-page-BSXSA-Ts.js} +1 -1
  115. package/dist/assets/{training-load-page-CkX-nSoe.js → training-load-page-BD0s8-Zm.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-BKzwGZDd.js → user-badge-ap1PvOxd.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-DvxKA6dI.js → utility-widgets-Cq508sqJ.js} +1 -1
  122. package/dist/assets/{vendor-Cpmju3nw.js → vendor-BwL6m4SE.js} +216 -211
  123. package/dist/assets/{vitals-page-CRIsr_C7.js → vitals-page-BnXk8OzN.js} +1 -1
  124. package/dist/assets/{weekly-review-page-CNqxLRCd.js → weekly-review-page-CnmSGnEC.js} +1 -1
  125. package/dist/assets/weight-loss-page-Bn6lAXNf.js +5 -0
  126. package/dist/assets/{wiki-article-markdown-C9VKineE.js → wiki-article-markdown-BDnkdNDC.js} +1 -1
  127. package/dist/assets/{wiki-editor-page-DxGsKvF7.js → wiki-editor-page-CHEETB0G.js} +1 -1
  128. package/dist/assets/{wiki-ingest-history-page-CFmP7K1F.js → wiki-ingest-history-page-CisvtAzm.js} +1 -1
  129. package/dist/assets/{wiki-ingest-modal-BLw2PSWP.js → wiki-ingest-modal-C2faIjzj.js} +1 -1
  130. package/dist/assets/{wiki-page-BiQ-jAuz.js → wiki-page-CELe_6qL.js} +1 -1
  131. package/dist/assets/{workbench-flow-page-D960hXu_.js → workbench-flow-page-JBVim3L0.js} +1 -1
  132. package/dist/assets/{workbench-page-BWlY-FiL.js → workbench-page-q7Z3sQtz.js} +1 -1
  133. package/dist/assets/{workout-detail-page-G32yJoE9.js → workout-detail-page-9I_3DPYU.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 -14
  137. package/dist/server/server/src/health-weight-loss.js +48 -6
  138. package/dist/server/server/src/health.js +348 -112
  139. package/dist/server/server/src/openapi.js +31 -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 +8 -1
  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-BejvcRGb.js +0 -2
  154. package/dist/assets/overview-page-D_ewyeWF.js +0 -1
  155. package/dist/assets/pill-cluster-DhOR4m7X.js +0 -1
  156. package/dist/assets/weight-loss-page-SSsCp1Yw.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();
@@ -7482,7 +7535,11 @@ export async function buildServer(options = {}) {
7482
7535
  app.get("/api/v1/openapi.json", async () => buildOpenApiDocument());
7483
7536
  app.get("/api/v1/context", async (request) => {
7484
7537
  const auth = authenticateRequest(request.headers);
7485
- return buildV1Context(resolveEffectiveReadScope(request.query, auth));
7538
+ const query = request.query;
7539
+ const context = buildV1Context(resolveEffectiveReadScope(query, auth));
7540
+ return shouldUseShellContextProfile(query)
7541
+ ? compactV1ContextForShell(context)
7542
+ : context;
7486
7543
  });
7487
7544
  app.get("/api/v1/life-force", async (request) => ({
7488
7545
  lifeForce: buildLifeForcePayload(new Date(), resolveScopedUserIds(request.query)),
@@ -7586,7 +7643,10 @@ export async function buildServer(options = {}) {
7586
7643
  return detail;
7587
7644
  });
7588
7645
  app.get("/api/v1/health/fitness", async (request) => ({
7589
- fitness: getFitnessViewData(resolveScopedUserIds(request.query))
7646
+ fitness: getFitnessViewData(resolveScopedUserIds(request.query), {
7647
+ compact: request.query.compact === "1" ||
7648
+ request.query.compact === "true"
7649
+ })
7590
7650
  }));
7591
7651
  app.get("/api/v1/health/training-load", async (request) => ({
7592
7652
  trainingLoad: getTrainingLoadViewData(resolveScopedUserIds(request.query))
@@ -7608,11 +7668,15 @@ export async function buildServer(options = {}) {
7608
7668
  z.string().datetime().safeParse(query.dayEndAt).success
7609
7669
  ? query.dayEndAt
7610
7670
  : undefined;
7671
+ const timeZone = typeof query.timeZone === "string" && query.timeZone.trim().length > 0
7672
+ ? query.timeZone
7673
+ : undefined;
7611
7674
  return {
7612
7675
  weightLoss: getWeightLossViewData(resolveScopedUserIds(query), {
7613
7676
  dateKey,
7614
7677
  dayStartAt,
7615
- dayEndAt
7678
+ dayEndAt,
7679
+ timeZone
7616
7680
  })
7617
7681
  };
7618
7682
  });
@@ -8245,13 +8309,39 @@ export async function buildServer(options = {}) {
8245
8309
  error: "Recorded moves are immutable in product UI. Create or edit a user-defined movement box instead."
8246
8310
  };
8247
8311
  });
8312
+ function estimatedJsonBytes(value) {
8313
+ try {
8314
+ return Buffer.byteLength(JSON.stringify(value ?? null), "utf8");
8315
+ }
8316
+ catch {
8317
+ return 0;
8318
+ }
8319
+ }
8320
+ function watchRouteMeasurement(operation, startedAt, requestBody, responseBody, extra = {}) {
8321
+ return {
8322
+ operation,
8323
+ backendDurationMs: Number((Number(process.hrtime.bigint() - startedAt) / 1_000_000).toFixed(2)),
8324
+ requestBytes: estimatedJsonBytes(requestBody),
8325
+ responseBytes: estimatedJsonBytes(responseBody),
8326
+ ...extra
8327
+ };
8328
+ }
8248
8329
  app.post("/api/v1/mobile/watch/bootstrap", async (request) => {
8330
+ const startedAt = process.hrtime.bigint();
8249
8331
  const parsed = mobileWatchBootstrapSchema.parse(request.body ?? {});
8250
8332
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8251
8333
  assertWatchReady(pairing);
8252
- return {
8334
+ const responseBody = {
8253
8335
  watch: buildWatchBootstrap(pairing)
8254
8336
  };
8337
+ return {
8338
+ ...responseBody,
8339
+ measurement: watchRouteMeasurement("watch.bootstrap", startedAt, request.body ?? {}, responseBody, {
8340
+ surfaceCount: responseBody.watch.surfaces.length,
8341
+ habitCount: responseBody.watch.habits.length,
8342
+ promptCount: responseBody.watch.pendingPrompts.length
8343
+ })
8344
+ };
8255
8345
  });
8256
8346
  app.post("/api/v1/mobile/watch/habits/:id/check-ins", async (request, reply) => {
8257
8347
  const parsed = mobileWatchHabitCheckInSchema.parse(request.body ?? {});
@@ -8277,22 +8367,45 @@ export async function buildServer(options = {}) {
8277
8367
  };
8278
8368
  });
8279
8369
  app.post("/api/v1/mobile/watch/capture-events:batch", async (request) => {
8370
+ const startedAt = process.hrtime.bigint();
8280
8371
  const parsed = mobileWatchCaptureBatchSchema.parse(request.body ?? {});
8281
8372
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8282
8373
  assertWatchReady(pairing);
8283
- return {
8284
- receipt: ingestWatchCaptureBatch(pairing, parsed),
8374
+ const receipt = ingestWatchCaptureBatch(pairing, parsed);
8375
+ const responseBody = {
8376
+ receipt,
8285
8377
  watch: buildWatchBootstrap(pairing)
8286
8378
  };
8379
+ return {
8380
+ ...responseBody,
8381
+ measurement: watchRouteMeasurement("watch.capture_batch", startedAt, request.body ?? {}, responseBody, {
8382
+ eventCount: parsed.events.length,
8383
+ storedCount: receipt.storedCount,
8384
+ duplicateCount: receipt.duplicateCount,
8385
+ projectedCount: receipt.projectedCount,
8386
+ projectionFailedCount: receipt.projectionFailedCount
8387
+ })
8388
+ };
8287
8389
  });
8288
8390
  app.post("/api/v1/mobile/watch/actions:batch", async (request) => {
8391
+ const startedAt = process.hrtime.bigint();
8289
8392
  const parsed = mobileWatchCommandBatchSchema.parse(request.body ?? {});
8290
8393
  const pairing = requireValidPairing(parsed.sessionId, parsed.pairingToken);
8291
8394
  assertWatchReady(pairing);
8292
- return {
8293
- receipt: ingestWatchCommandBatch(pairing, parsed),
8395
+ const receipt = ingestWatchCommandBatch(pairing, parsed);
8396
+ const responseBody = {
8397
+ receipt,
8294
8398
  watch: buildWatchBootstrap(pairing)
8295
8399
  };
8400
+ return {
8401
+ ...responseBody,
8402
+ measurement: watchRouteMeasurement("watch.action_batch", startedAt, request.body ?? {}, responseBody, {
8403
+ commandCount: parsed.commands.length,
8404
+ processedCount: receipt.processedCount,
8405
+ replayedCount: receipt.replayedCount,
8406
+ failedCount: receipt.failedCount
8407
+ })
8408
+ };
8296
8409
  });
8297
8410
  app.post("/api/v1/mobile/healthkit/sync-sessions", async (request) => ({
8298
8411
  upload: startMobileHealthSyncSession(mobileHealthSyncSessionStartSchema.parse(request.body ?? {}))
@@ -8302,7 +8415,19 @@ export async function buildServer(options = {}) {
8302
8415
  const query = z
8303
8416
  .object({
8304
8417
  sessionId: z.string().trim().min(1),
8305
- pairingToken: z.string().trim().min(1)
8418
+ pairingToken: z.string().trim().min(1),
8419
+ includeReceivedChunkIds: z
8420
+ .enum(["true", "false"])
8421
+ .optional()
8422
+ .transform((value) => value !== "false"),
8423
+ includeWorkoutImportExternalUids: z
8424
+ .enum(["true", "false"])
8425
+ .optional()
8426
+ .transform((value) => value !== "false"),
8427
+ includeWorkoutImportState: z
8428
+ .enum(["true", "false"])
8429
+ .optional()
8430
+ .transform((value) => value !== "false")
8306
8431
  })
8307
8432
  .parse(request.query ?? {});
8308
8433
  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);